[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] [gnuradio] 02/03: uhd: Updated uhd_siggen_gui (uses QT
From: |
git |
Subject: |
[Commit-gnuradio] [gnuradio] 02/03: uhd: Updated uhd_siggen_gui (uses QT), added GRC siggen example |
Date: |
Thu, 24 Sep 2015 23:53:51 +0000 (UTC) |
This is an automated email from the git hooks/post-receive script.
jcorgan pushed a commit to branch master
in repository gnuradio.
commit 5fe360c6ad5e6b50b00380962a1fbe0b5eaeca34
Author: Martin Braun <address@hidden>
Date: Sun Jun 28 00:23:16 2015 -0700
uhd: Updated uhd_siggen_gui (uses QT), added GRC siggen example
- Added uhd_app.py base class for example apps
- uhd_siggen and uhd_siggen_gui now both use uhd_app
- siggen now also multi-channel capabilities
- siggen_gui fully QT, no more WX
---
gr-uhd/apps/CMakeLists.txt | 1 +
gr-uhd/apps/uhd_app.py | 292 +++++
gr-uhd/apps/uhd_siggen | 34 +-
gr-uhd/apps/uhd_siggen_base.py | 351 ++----
gr-uhd/apps/uhd_siggen_gui | 689 ++++++----
gr-uhd/examples/grc/uhd_siggen_gui.grc | 2154 ++++++++++++++++++++++++++++++++
6 files changed, 2994 insertions(+), 527 deletions(-)
diff --git a/gr-uhd/apps/CMakeLists.txt b/gr-uhd/apps/CMakeLists.txt
index 1d68c00..ebcaf6e 100644
--- a/gr-uhd/apps/CMakeLists.txt
+++ b/gr-uhd/apps/CMakeLists.txt
@@ -25,6 +25,7 @@ include(GrPython)
GR_PYTHON_INSTALL(
FILES
uhd_siggen_base.py
+ uhd_app.py
DESTINATION ${GR_PYTHON_DIR}/gnuradio/uhd
COMPONENT "uhd_python"
)
diff --git a/gr-uhd/apps/uhd_app.py b/gr-uhd/apps/uhd_app.py
new file mode 100644
index 0000000..5af01ad
--- /dev/null
+++ b/gr-uhd/apps/uhd_app.py
@@ -0,0 +1,292 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+"""
+USRP Helper Module: Common tasks for uhd-based apps.
+"""
+
+from __future__ import print_function
+import sys
+import time
+import argparse
+from gnuradio import eng_arg
+from gnuradio import uhd
+from gnuradio import gr
+from gnuradio import gru
+
+COMMAND_DELAY = .2 # Seconds
+
+COMPACT_TPL = "{mb_id} ({mb_serial}), {db_subdev} ({subdev}, {ant}{db_serial})"
+LONG_TPL = """{prefix} Motherboard: {mb_id} ({mb_serial})
+{prefix} Daughterboard: {db_subdev}{db_serial}
+{prefix} Subdev: {subdev}
+{prefix} Antenna: {ant}
+"""
+
+class UHDApp(object):
+ def __init__(self, prefix=None, args=None):
+ self.prefix = prefix
+ self.args = args
+ self.verbose = args.verbose or 0
+ if self.args.sync == 'auto' and len(self.args.channels) > 1:
+ self.args.sync = 'pps'
+
+ def vprint(self, *args):
+ """
+ Print 'string' with 'prefix' prepended if self.verbose is True
+ """
+ if self.verbose:
+ print("[{prefix}]".format(prefix=self.prefix), *args)
+
+ def get_usrp_info_string(self,
+ compact=False,
+ tx_or_rx='rx',
+ chan=0,
+ mboard=0,
+ ):
+ """
+ Return a nice textual description of the USRP we're using.
+ """
+ assert tx_or_rx == 'rx' or tx_or_rx == 'tx'
+ try:
+ info_pp = {}
+ if self.prefix is None:
+ info_pp['prefix'] = ""
+ else:
+ info_pp['prefix'] = "[{prefix}] ".format(prefix=self.prefix)
+ usrp_info = self.usrp.get_usrp_info(chan)
+ info_pp['mb_id'] = usrp_info['mboard_id']
+ info_pp['mb_serial'] = usrp_info['mboard_serial']
+ if info_pp['mb_serial'] == "":
+ info_pp['mb_serial'] = "no serial"
+ info_pp['db_subdev'] =
usrp_info["{xx}_subdev_name".format(xx=tx_or_rx)]
+ info_pp['db_serial'] = ", " +
usrp_info["{xx}_serial".format(xx=tx_or_rx)]
+ if info_pp['db_serial'] == "":
+ info_pp['db_serial'] = "no serial"
+ info_pp['subdev'] = self.usrp.get_subdev_spec(mboard)
+ info_pp['ant'] = self.usrp.get_antenna(chan)
+ if info_pp['mb_id'] in ("B200", "B210", "E310"):
+ # In this case, this is meaningless
+ info_pp['db_serial'] = ""
+ tpl = LONG_TPL
+ if compact:
+ tpl = COMPACT_TPL
+ return tpl.format(**info_pp)
+ except:
+ return "Can't establish USRP info."
+
+ def normalize_antenna_sel(self, args):
+ """
+ Make sure the --antenna option matches the --channels option.
+ """
+ if args.antenna is None:
+ return None
+ antennas = [x.strip() for x in args.antenna.split(",")]
+ if len(antennas) != 1 and len(antennas) != len(args.channels):
+ raise ValueError("Invalid antenna setting for {n} channels:
{a}".format(
+ n=len(self.channels), a=args.antenna,
+ ))
+ if len(antennas) == 1:
+ antennas = [antennas[0],] * len(args.channels)
+ return antennas
+
+ def async_callback(self, msg):
+ """
+ Call this when USRP async metadata needs printing.
+ """
+ md = self.async_src.msg_to_async_metadata_t(msg)
+ print("[{prefix}] Channel: {chan} Time: {t} Event: {e}".format(
+ prefix=self.prefix,
+ chan=md.channel,
+ t=md.time_spec.get_real_secs(),
+ e=md.event_code,
+ ))
+
+ def setup_usrp(self, ctor, args, cpu_format='fc32'):
+ """
+ Instantiate a USRP object; takes care of all kinds of corner cases and
settings.
+ Pop it and some args onto the class that calls this.
+ """
+ self.channels = args.channels
+ self.cpu_format = cpu_format
+ # Create a UHD device object:
+ self.usrp = ctor(
+ device_addr=args.args,
+ stream_args=uhd.stream_args(
+ cpu_format,
+ args.otw_format,
+ args=args.stream_args,
+ channels=self.channels,
+ )
+ )
+ # Set the subdevice spec:
+ if args.spec:
+ for mb_idx in xrange(self.usrp.get_num_mboards()):
+ self.usrp.set_subdev_spec(args.spec, mb_idx)
+ # Sampling rate:
+ self.usrp.set_samp_rate(args.samp_rate)
+ self.samp_rate = self.usrp.get_samp_rate()
+ self.vprint("Using sampling rate: {rate}".format(rate=self.samp_rate))
+ # Set the antenna:
+ self.antenna = self.normalize_antenna_sel(args)
+ if self.antenna is not None:
+ for i, chan in enumerate(self.channels):
+ self.usrp.set_antenna(self.antenna[i], chan)
+ self.vprint("[{prefix}] Channel {chan}: Using antenna
{ant}.".format(
+ prefix=self.prefix, chan=chan,
ant=self.usrp.get_antenna(chan)
+ ))
+ self.antenna = self.usrp.get_antenna(self.channels[0])
+ # Set receive daughterboard gain:
+ self.set_gain(args.gain)
+ # Set frequency (tune request takes lo_offset):
+ if hasattr(args, 'lo_offset') and args.lo_offset is not None:
+ treq = uhd.tune_request(args.freq, args.lo_offset)
+ else:
+ treq = uhd.tune_request(args.freq)
+ # Make sure tuning is synched:
+ if len(self.channels) > 1:
+ if args.sync == 'pps':
+ self.usrp.set_time_unknown_pps(uhd.time_spec())
+ cmd_time = self.usrp.get_time_now() + uhd.time_spec(COMMAND_DELAY)
+ for mb_idx in xrange(self.usrp.get_num_mboards()):
+ self.usrp.set_command_time(cmd_time, mb_idx)
+ for chan in self.channels:
+ self.tr = self.usrp.set_center_freq(treq, chan)
+ if self.tr == None:
+ sys.stderr.write('[{prefix}] [ERROR] Failed to set center
frequency on channel {chan}\n'.format(
+ prefix=self.prefix, chan=chan
+ ))
+ exit(1)
+ if len(self.channels) > 1:
+ for mb_idx in xrange(self.usrp.get_num_mboards()):
+ self.usrp.clear_command_time(mb_idx)
+ print("[{prefix}] Syncing channels...".format(prefix=self.prefix))
+ time.sleep(COMMAND_DELAY)
+ self.freq = self.usrp.get_center_freq(self.channels[0])
+ if args.show_async_msg:
+ self.async_msgq = gr.msg_queue(0)
+ self.async_src = uhd.amsg_source("", self.async_msgq)
+ self.async_rcv = gru.msgq_runner(self.async_msgq,
self.async_callback)
+
+ def set_gain(self, gain):
+ """
+ Safe gain-setter. Catches some special cases:
+ - If gain is None, set to mid-point in dB.
+ - If the USRP is multi-channel, set it on all channels.
+ """
+ if gain is None:
+ if self.args.verbose:
+ self.vprint("Defaulting to mid-point
gains:".format(prefix=self.prefix))
+ for chan in self.channels:
+ self.usrp.set_normalized_gain(.5, chan)
+ if self.args.verbose:
+ self.vprint("Channel {chan} gain: {g} dB".format(
+ prefix=self.prefix, chan=chan,
g=self.usrp.get_gain(chan)
+ ))
+ else:
+ self.vprint("Setting gain to {g} dB.".format(g=gain))
+ for chan in self.channels:
+ self.usrp.set_gain(gain, chan)
+ self.gain = self.usrp.get_gain(self.channels[0])
+
+ def set_freq(self, freq, skip_sync=False):
+ """
+ Safely tune all channels to freq.
+ """
+ self.vprint("Tuning all channels to {freq} MHz.".format(freq=freq/1e6))
+ # Set frequency (tune request takes lo_offset):
+ if hasattr(self.args, 'lo_offset') and self.args.lo_offset is not None:
+ treq = uhd.tune_request(self.args.freq, self.args.lo_offset)
+ else:
+ treq = uhd.tune_request(self.args.freq)
+ # Make sure tuning is synched:
+ if len(self.channels) > 1 and not skip_sync:
+ cmd_time = self.usrp.get_time_now() + uhd.time_spec(COMMAND_DELAY)
+ for mb_idx in xrange(self.usrp.get_num_mboards()):
+ self.usrp.set_command_time(cmd_time, mb_idx)
+ for chan in self.channels:
+ self.tr = self.usrp.set_center_freq(treq, chan)
+ if self.tr == None:
+ sys.stderr.write('[{prefix}] [ERROR] Failed to set center
frequency on channel {chan}\n'.format(
+ prefix=self.prefix, chan=chan
+ ))
+ exit(1)
+ if len(self.channels) > 1 and not skip_sync:
+ for mb_idx in xrange(self.usrp.get_num_mboards()):
+ self.usrp.clear_command_time(mb_idx)
+ self.vprint("Syncing channels...".format(prefix=self.prefix))
+ time.sleep(COMMAND_DELAY)
+
+ @staticmethod
+ def setup_argparser(
+ parser=None,
+ description='USRP App',
+ allow_mimo=True,
+ tx_or_rx="",
+ skip_freq=False,
+ ):
+ """
+ Create or amend an argument parser with typical USRP options.
+ """
+ def cslist(string):
+ """
+ For ArgParser: Turn a comma separated list into an actual list.
+ """
+ try:
+ return [int(x.strip()) for x in string.split(",")]
+ except:
+ raise argparse.ArgumentTypeError("Not a comma-separated list:
{string}".format(string=string))
+ if parser is None:
+ parser = argparse.ArgumentParser(
+ description=description,
+ )
+ tx_or_rx = tx_or_rx.strip() + " "
+ group = parser.add_argument_group('USRP Arguments')
+ group.add_argument("-a", "--args", default="", help="UHD device
address args")
+ group.add_argument("--spec", help="Subdevice of UHD device where
appropriate")
+ group.add_argument("-A", "--antenna", help="Select {xx}Antenna(s)
where appropriate".format(xx=tx_or_rx))
+ group.add_argument("-s", "--samp-rate", type=eng_arg.eng_float,
default=1e6,
+ help="Sample rate")
+ group.add_argument("-g", "--gain", type=eng_arg.eng_float,
default=None,
+ help="Gain (default is midpoint)")
+ group.add_argument("--gain-type", choices=('db', 'normalized'),
default='db',
+ help="Gain Type (applies to -g)")
+ if not skip_freq:
+ group.add_argument("-f", "--freq", type=eng_arg.eng_float,
default=None, required=True,
+ help="Set carrier frequency to FREQ",
+ metavar="FREQ")
+ group.add_argument("--lo-offset", type=eng_arg.eng_float,
default=0.0,
+ help="Set daughterboard LO offset to OFFSET
[default=hw default]")
+ if allow_mimo:
+ group.add_argument("-c", "--channels", default=[0,], type=cslist,
+ help="Select {xx}
Channels".format(xx=tx_or_rx))
+ group.add_argument("--otw-format", choices=['sc16', 'sc12', 'sc8'],
default='sc16',
+ help="Choose over-the-wire data format")
+ group.add_argument("--stream-args", default="", help="Set additional
stream arguments")
+ group.add_argument("-m", "--amplitude", type=eng_arg.eng_float,
default=0.15,
+ help="Set output amplitude to AMPL (0.0-1.0)",
metavar="AMPL")
+ group.add_argument("-v", "--verbose", action="count", help="Use
verbose console output")
+ group.add_argument("--show-async-msg", action="store_true",
+ help="Show asynchronous message notifications from
UHD")
+ group.add_argument("--sync", choices=('default', 'pps', 'auto'),
+ default='auto', help="Set to 'pps' to sync devices
to PPS")
+ return parser
+
diff --git a/gr-uhd/apps/uhd_siggen b/gr-uhd/apps/uhd_siggen
index 52fc249..6e5d465 100755
--- a/gr-uhd/apps/uhd_siggen
+++ b/gr-uhd/apps/uhd_siggen
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2008,2009,2011,2012 Free Software Foundation, Inc.
+# Copyright 2008,2009,2011,2012,2015 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -20,32 +20,10 @@
# Boston, MA 02110-1301, USA.
#
-from gnuradio import gr
-from gnuradio.uhd import uhd_siggen_base as uhd_siggen
-import sys
+try:
+ import uhd_siggen_base as uhd_siggen
+except ImportError:
+ from gnuradio.uhd import uhd_siggen_base as uhd_siggen
-def main():
- if gr.enable_realtime_scheduling() != gr.RT_OK:
- print "Note: failed to enable realtime scheduling, continuing"
-
- # Grab command line options and create top block
- try:
- (options, args) = uhd_siggen.get_options()
- tb = uhd_siggen.top_block(options, args)
-
- except RuntimeError, e:
- print e
- sys.exit(1)
-
- tb.start()
- raw_input('Press Enter to quit: ')
- tb.stop()
- tb.wait()
-
-# Make sure to create the top block (tb) within a function:
-# That code in main will allow tb to go out of scope on return,
-# which will call the decontructor on usrp and stop transmit.
-# Whats odd is that grc works fine with tb in the __main__,
-# perhaps its because the try/except clauses around tb.
if __name__ == "__main__":
- main()
+ uhd_siggen.main()
diff --git a/gr-uhd/apps/uhd_siggen_base.py b/gr-uhd/apps/uhd_siggen_base.py
index 503f49b..31415da 100644
--- a/gr-uhd/apps/uhd_siggen_base.py
+++ b/gr-uhd/apps/uhd_siggen_base.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
#
-# Copyright 2008,2009,2011,2012 Free Software Foundation, Inc.
+# Copyright 2008,2009,2011,2012,2015 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -19,6 +19,9 @@
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
+"""
+Provide a base flow graph for USRP signal generators.
+"""
DESC_KEY = 'desc'
SAMP_RATE_KEY = 'samp_rate'
@@ -36,44 +39,69 @@ FREQ_RANGE_KEY = 'freq_range'
GAIN_RANGE_KEY = 'gain_range'
TYPE_KEY = 'type'
-def setter(ps, key, val): ps[key] = val
+# FIXME figure out if this can be deleted
+#def setter(ps, key, val): ps[key] = val
-from gnuradio import gr, gru, uhd, eng_notation
+import sys
+import math
+import argparse
+try:
+ from uhd_app import UHDApp
+except ImportError:
+ from gnuradio.uhd.uhd_app import UHDApp
+from gnuradio import gr, gru, uhd, eng_notation, eng_arg
from gnuradio import analog
from gnuradio import blocks
from gnuradio.gr.pubsub import pubsub
from gnuradio.eng_option import eng_option
from optparse import OptionParser
-import sys
-import math
n2s = eng_notation.num_to_str
-waveforms = { analog.GR_SIN_WAVE : "Complex Sinusoid",
- analog.GR_CONST_WAVE : "Constant",
- analog.GR_GAUSSIAN : "Gaussian Noise",
- analog.GR_UNIFORM : "Uniform Noise",
- "2tone" : "Two Tone",
- "sweep" : "Sweep" }
-
-#
-# GUI-unaware GNU Radio flowgraph. This may be used either with command
-# line applications or GUI applications.
-#
-class top_block(gr.top_block, pubsub):
- def __init__(self, options, args):
+waveforms = {
+ analog.GR_CONST_WAVE : "Constant",
+ analog.GR_SIN_WAVE : "Complex Sinusoid",
+ analog.GR_GAUSSIAN : "Gaussian Noise",
+ analog.GR_UNIFORM : "Uniform Noise",
+ "2tone" : "Two Tone",
+ "sweep" : "Sweep",
+}
+
+class USRPSiggen(gr.top_block, pubsub, UHDApp):
+ """
+ GUI-unaware GNU Radio flowgraph. This may be used either with command
+ line applications or GUI applications.
+ """
+ def __init__(self, args):
gr.top_block.__init__(self)
pubsub.__init__(self)
- self._verbose = options.verbose
-
- #initialize values from options
- self._setup_usrpx(options)
- self[SAMP_RATE_KEY] = options.samp_rate
- self[TX_FREQ_KEY] = options.tx_freq
- self[AMPLITUDE_KEY] = options.amplitude
- self[WAVEFORM_FREQ_KEY] = options.waveform_freq
- self[WAVEFORM_OFFSET_KEY] = options.offset
- self[WAVEFORM2_FREQ_KEY] = options.waveform2_freq
+ UHDApp.__init__(self, args=args, prefix="UHD-SIGGEN")
+ self.extra_sink = None
+
+ # Initialize device:
+ self.setup_usrp(
+ ctor=uhd.usrp_sink,
+ args=args,
+ )
+ print("[UHD-SIGGEN] UHD Signal Generator")
+ print("[UHD-SIGGEN] UHD Version:
{ver}".format(ver=uhd.get_version_string()))
+ print("[UHD-SIGGEN] Using USRP configuration:")
+ print(self.get_usrp_info_string(tx_or_rx="tx"))
+ self.usrp_description = self.get_usrp_info_string(tx_or_rx="tx",
compact=True)
+
+ ### Set subscribers and publishers:
+ self.publish(SAMP_RATE_KEY, lambda: self.usrp.get_samp_rate())
+ self.publish(DESC_KEY, lambda: self.usrp_description)
+ self.publish(FREQ_RANGE_KEY, lambda:
self.usrp.get_freq_range(self.channels[0]))
+ self.publish(GAIN_RANGE_KEY, lambda:
self.usrp.get_gain_range(self.channels[0]))
+ self.publish(GAIN_KEY, lambda: self.usrp.get_gain(self.channels[0]))
+
+ self[SAMP_RATE_KEY] = args.samp_rate
+ self[TX_FREQ_KEY] = args.freq
+ self[AMPLITUDE_KEY] = args.amplitude
+ self[WAVEFORM_FREQ_KEY] = args.waveform_freq
+ self[WAVEFORM_OFFSET_KEY] = args.offset
+ self[WAVEFORM2_FREQ_KEY] = args.waveform2_freq
self[DSP_FREQ_KEY] = 0
self[RF_FREQ_KEY] = 0
@@ -91,84 +119,15 @@ class top_block(gr.top_block, pubsub):
AMPLITUDE_KEY, WAVEFORM_FREQ_KEY,
WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY):
self[key] = self[key]
- self[TYPE_KEY] = options.type #set type last
-
- def _setup_usrpx(self, options):
- self._u = uhd.usrp_sink(device_addr=options.args,
stream_args=uhd.stream_args('fc32'))
- self._u.set_samp_rate(options.samp_rate)
-
- # Set the subdevice spec
- if(options.spec):
- self._u.set_subdev_spec(options.spec, 0)
-
- # Set the gain on the usrp from options
- if(options.gain):
- self._u.set_gain(options.gain)
-
- # Set the antenna
- if(options.antenna):
- self._u.set_antenna(options.antenna, 0)
+ self[TYPE_KEY] = args.type #set type last
- # Setup USRP Configuration value
- try:
- usrp_info = self._u.get_usrp_info()
- mboard_id = usrp_info["mboard_id"]
- mboard_serial = usrp_info["mboard_serial"]
- if mboard_serial == "":
- mboard_serial = "no serial"
- dboard_subdev_name = usrp_info["tx_subdev_name"]
- dboard_serial = usrp_info["tx_serial"]
- if dboard_serial == "":
- dboard_serial = "no serial"
- subdev = self._u.get_subdev_spec()
- antenna = self._u.get_antenna()
-
- desc_key_str = "Motherboard: %s [%s]\n" % (mboard_id,
mboard_serial)
- if "B200" in mboard_id or "B210" in mboard_id:
- desc_key_str += "Daughterboard: %s\n" % dboard_subdev_name
- else:
- desc_key_str += "Daughterboard: %s [%s]\n" %
(dboard_subdev_name, dboard_serial)
- desc_key_str += "Subdev: %s\n" % subdev
- desc_key_str += "Antenna: %s" % antenna
- except:
- desc_key_str = "USRP configuration output not implemented in this
version"
-
- self.publish(DESC_KEY, lambda: desc_key_str)
- self.publish(FREQ_RANGE_KEY, self._u.get_freq_range)
- self.publish(GAIN_RANGE_KEY, self._u.get_gain_range)
- self.publish(GAIN_KEY, self._u.get_gain)
-
- print "UHD Signal Generator"
- print "Version: %s" % uhd.get_version_string()
- print "\nUsing USRP configuration:"
- print desc_key_str + "\n"
-
- # Direct asynchronous notifications to callback function
- if options.show_async_msg:
- self.async_msgq = gr.msg_queue(0)
- self.async_src = uhd.amsg_source("", self.async_msgq)
- self.async_rcv = gru.msgq_runner(self.async_msgq,
self.async_callback)
-
- def async_callback(self, msg):
- md = self.async_src.msg_to_async_metadata_t(msg)
- print "Channel: %i Time: %f Event: %i" % (md.channel,
md.time_spec.get_real_secs(), md.event_code)
-
- def _set_tx_amplitude(self, ampl):
+ def set_samp_rate(self, sr):
"""
- Sets the transmit amplitude sent to the USRP
-
- Args:
- ampl: the amplitude or None for automatic
+ When sampling rate is updated, also update the signal sources.
"""
- ampl_range = self[AMPL_RANGE_KEY]
- if ampl is None:
- ampl = (ampl_range[1] - ampl_range[0])*0.15 + ampl_range[0]
- self[AMPLITUDE_KEY] = max(ampl_range[0], min(ampl, ampl_range[1]))
-
- def set_samp_rate(self, sr):
- self._u.set_samp_rate(sr)
- sr = self._u.get_samp_rate()
-
+ self.vprint("Setting sampling rate to: {rate}
Msps".format(rate=sr/1e6))
+ self.usrp.set_samp_rate(sr)
+ sr = self.usrp.get_samp_rate()
if self[TYPE_KEY] in (analog.GR_SIN_WAVE, analog.GR_CONST_WAVE):
self._src.set_sampling_freq(self[SAMP_RATE_KEY])
elif self[TYPE_KEY] == "2tone":
@@ -179,48 +138,9 @@ class top_block(gr.top_block, pubsub):
self._src2.set_sampling_freq(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY])
else:
return True # Waveform not yet set
-
- if self._verbose:
- print "Set sample rate to:", sr
-
+ self.vprint("Set sample rate to: {rate} Msps".format(rate=sr/1e6))
return True
- def set_gain(self, gain):
- if gain is None:
- g = self[GAIN_RANGE_KEY]
- gain = float(g.start()+g.stop())/2
- if self._verbose:
- print "Using auto-calculated mid-point TX gain"
- self[GAIN_KEY] = gain
- return
- self._u.set_gain(gain)
- if self._verbose:
- print "Set TX gain to:", gain
-
- def set_freq(self, target_freq):
-
- if target_freq is None:
- f = self[FREQ_RANGE_KEY]
- target_freq = float(f.start()+f.stop())/2.0
- if self._verbose:
- print "Using auto-calculated mid-point frequency"
- self[TX_FREQ_KEY] = target_freq
- return
-
- tr = self._u.set_center_freq(target_freq)
- fs = "%sHz" % (n2s(target_freq),)
- if tr is not None:
- self._freq = target_freq
- self[DSP_FREQ_KEY] = tr.actual_dsp_freq
- self[RF_FREQ_KEY] = tr.actual_rf_freq
- if self._verbose:
- print "Set center frequency to", self._u.get_center_freq()
- print "Tx RF frequency: %sHz" % (n2s(tr.actual_rf_freq),)
- print "Tx DSP frequency: %sHz" % (n2s(tr.actual_dsp_freq),)
- elif self._verbose:
- print "Failed to set freq."
- return tr
-
def set_waveform_freq(self, freq):
if self[TYPE_KEY] == analog.GR_SIN_WAVE:
self._src.set_frequency(freq)
@@ -242,6 +162,7 @@ class top_block(gr.top_block, pubsub):
return True
def set_waveform(self, type):
+ self.vprint("Selecting waveform...")
self.lock()
self.disconnect_all()
if type == analog.GR_SIN_WAVE or type == analog.GR_CONST_WAVE:
@@ -258,9 +179,8 @@ class top_block(gr.top_block, pubsub):
self[WAVEFORM_FREQ_KEY],
self[AMPLITUDE_KEY]/2.0,
0)
- if(self[WAVEFORM2_FREQ_KEY] is None):
+ if self[WAVEFORM2_FREQ_KEY] is None:
self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY]
-
self._src2 = analog.sig_source_c(self[SAMP_RATE_KEY],
analog.GR_SIN_WAVE,
self[WAVEFORM2_FREQ_KEY],
@@ -276,7 +196,6 @@ class top_block(gr.top_block, pubsub):
# will sweep from (rf_freq-waveform_freq/2) to
(rf_freq+waveform_freq/2)
if self[WAVEFORM2_FREQ_KEY] is None:
self[WAVEFORM2_FREQ_KEY] = 0.1
-
self._src1 = analog.sig_source_f(self[SAMP_RATE_KEY],
analog.GR_TRI_WAVE,
self[WAVEFORM2_FREQ_KEY],
@@ -284,33 +203,33 @@ class top_block(gr.top_block, pubsub):
-0.5)
self._src2 =
analog.frequency_modulator_fc(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY])
self._src = blocks.multiply_const_cc(self[AMPLITUDE_KEY])
- self.connect(self._src1,self._src2,self._src)
+ self.connect(self._src1, self._src2, self._src)
else:
- raise RuntimeError("Unknown waveform type")
-
- self.connect(self._src, self._u)
+ raise RuntimeError("[UHD-SIGGEN] Unknown waveform type")
+ for c in xrange(len(self.channels)):
+ self.connect(self._src, (self.usrp, c))
+ if self.extra_sink is not None:
+ self.connect(self._src, self.extra_sink)
self.unlock()
-
- if self._verbose:
- print "Set baseband modulation to:", waveforms[type]
- if type == analog.GR_SIN_WAVE:
- print "Modulation frequency: %sHz" %
(n2s(self[WAVEFORM_FREQ_KEY]),)
- print "Initial phase:", self[WAVEFORM_OFFSET_KEY]
- elif type == "2tone":
- print "Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),)
- print "Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),)
- elif type == "sweep":
- print "Sweeping across %sHz to %sHz" %
(n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0))
- print "Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),)
- print "TX amplitude:", self[AMPLITUDE_KEY]
-
+ self.vprint("Set baseband modulation to:", waveforms[type])
+ if type == analog.GR_SIN_WAVE:
+ self.vprint("Modulation frequency: %sHz" %
(n2s(self[WAVEFORM_FREQ_KEY]),))
+ self.vprint("Initial phase:", self[WAVEFORM_OFFSET_KEY])
+ elif type == "2tone":
+ self.vprint("Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),))
+ self.vprint("Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),))
+ elif type == "sweep":
+ self.vprint("Sweeping across %sHz to %sHz" %
(n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0)))
+ self.vprint("Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),))
+ self.vprint("TX amplitude:", self[AMPLITUDE_KEY])
def set_amplitude(self, amplitude):
+ """
+ amplitude subscriber
+ """
if amplitude < 0.0 or amplitude > 1.0:
- if self._verbose:
- print "Amplitude out of range:", amplitude
+ self.vprint("Amplitude out of range:", amplitude)
return False
-
if self[TYPE_KEY] in (analog.GR_SIN_WAVE, analog.GR_CONST_WAVE,
analog.GR_GAUSSIAN, analog.GR_UNIFORM):
self._src.set_amplitude(amplitude)
elif self[TYPE_KEY] == "2tone":
@@ -320,83 +239,55 @@ class top_block(gr.top_block, pubsub):
self._src.set_k(amplitude)
else:
return True # Waveform not yet set
-
- if self._verbose:
- print "Set amplitude to:", amplitude
+ self.vprint("Set amplitude to:", amplitude)
return True
-def get_options():
- usage="%prog: [options]"
- parser = OptionParser(option_class=eng_option, usage=usage)
- parser.add_option("-a", "--args", type="string", default="",
- help="UHD device address args , [default=%default]")
- parser.add_option("", "--spec", type="string", default=None,
- help="Subdevice of UHD device where appropriate")
- parser.add_option("-A", "--antenna", type="string", default=None,
- help="select Rx Antenna where appropriate")
- parser.add_option("-s", "--samp-rate", type="eng_float", default=1e6,
- help="set sample rate (bandwidth) [default=%default]")
- parser.add_option("-g", "--gain", type="eng_float", default=None,
- help="set gain in dB (default is midpoint)")
- parser.add_option("-f", "--tx-freq", type="eng_float", default=None,
- help="Set carrier frequency to FREQ [default=mid-point]",
- metavar="FREQ")
- parser.add_option("-x", "--waveform-freq", type="eng_float", default=0,
- help="Set baseband waveform frequency to FREQ
[default=%default]")
- parser.add_option("-y", "--waveform2-freq", type="eng_float", default=None,
- help="Set 2nd waveform frequency to FREQ
[default=%default]")
- parser.add_option("--sine", dest="type", action="store_const",
const=analog.GR_SIN_WAVE,
+def setup_argparser():
+ """
+ Create argument parser for signal generator.
+ """
+ parser = UHDApp.setup_argparser(
+ description="USRP Signal Generator.",
+ tx_or_rx="Tx",
+ )
+ group = parser.add_argument_group('Siggen Arguments')
+ group.add_argument("-x", "--waveform-freq", type=eng_arg.eng_float,
default=0.0,
+ help="Set baseband waveform frequency to FREQ")
+ group.add_argument("-y", "--waveform2-freq", type=eng_arg.eng_float,
default=0.0,
+ help="Set 2nd waveform frequency to FREQ")
+ group.add_argument("--sine", dest="type", action="store_const",
const=analog.GR_SIN_WAVE,
help="Generate a carrier modulated by a complex sine
wave",
default=analog.GR_SIN_WAVE)
- parser.add_option("--const", dest="type", action="store_const",
const=analog.GR_CONST_WAVE,
+ group.add_argument("--const", dest="type", action="store_const",
const=analog.GR_CONST_WAVE,
help="Generate a constant carrier")
- parser.add_option("--offset", type="eng_float", default=0,
- help="Set waveform phase offset to OFFSET
[default=%default]")
- parser.add_option("--gaussian", dest="type", action="store_const",
const=analog.GR_GAUSSIAN,
+ group.add_argument("--offset", type=eng_arg.eng_float, default=0,
+ help="Set waveform phase offset to OFFSET",
metavar="OFFSET")
+ group.add_argument("--gaussian", dest="type", action="store_const",
const=analog.GR_GAUSSIAN,
help="Generate Gaussian random output")
- parser.add_option("--uniform", dest="type", action="store_const",
const=analog.GR_UNIFORM,
+ group.add_argument("--uniform", dest="type", action="store_const",
const=analog.GR_UNIFORM,
help="Generate Uniform random output")
- parser.add_option("--2tone", dest="type", action="store_const",
const="2tone",
+ group.add_argument("--2tone", dest="type", action="store_const",
const="2tone",
help="Generate Two Tone signal for IMD testing")
- parser.add_option("--sweep", dest="type", action="store_const",
const="sweep",
+ group.add_argument("--sweep", dest="type", action="store_const",
const="sweep",
help="Generate a swept sine wave")
- parser.add_option("", "--amplitude", type="eng_float", default=0.15,
- help="Set output amplitude to AMPL (0.0-1.0)
[default=%default]",
- metavar="AMPL")
- parser.add_option("-v", "--verbose", action="store_true", default=False,
- help="Use verbose console output [default=%default]")
- parser.add_option("", "--show-async-msg", action="store_true",
default=False,
- help="Show asynchronous message notifications from UHD
[default=%default]")
-
- (options, args) = parser.parse_args()
-
- return (options, args)
+ return parser
-# If this script is executed, the following runs. If it is imported,
-# the below does not run.
-def test_main():
+def main():
if gr.enable_realtime_scheduling() != gr.RT_OK:
- print "Note: failed to enable realtime scheduling, continuing"
-
- # Grab command line options and create top block
+ print("Note: failed to enable realtime scheduling, continuing")
+ # Grab command line args and create top block
try:
- (options, args) = get_options()
- tb = top_block(options, args)
-
- except RuntimeError, e:
- print e
- sys.exit(1)
-
+ parser = setup_argparser()
+ args = parser.parse_args()
+ tb = USRPSiggen(args)
+ except RuntimeError as e:
+ print(e)
+ exit(1)
tb.start()
- raw_input('Press Enter to quit: ')
+ raw_input('[UHD-SIGGEN] Press Enter to quit:\n')
tb.stop()
tb.wait()
-# Make sure to create the top block (tb) within a function:
-# That code in main will allow tb to go out of scope on return,
-# which will call the decontructor on usrp and stop transmit.
-# Whats odd is that grc works fine with tb in the __main__,
-# perhaps its because the try/except clauses around tb.
if __name__ == "__main__":
- test_main()
+ main()
diff --git a/gr-uhd/apps/uhd_siggen_gui b/gr-uhd/apps/uhd_siggen_gui
index 80fcf8e..ab04ccc 100755
--- a/gr-uhd/apps/uhd_siggen_gui
+++ b/gr-uhd/apps/uhd_siggen_gui
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
#
-# Copyright 2009,2011,2012 Free Software Foundation, Inc.
+# Copyright 2015 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -19,301 +19,452 @@
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
+"""
+Signal Generator App
+"""
-import wx
-from gnuradio import gr, uhd
+# Started off with this flow graph:
+##################################################
+# GNU Radio Python Flow Graph
+# Title: UHD Signal Generator
+# Author: Ettus Research
+# Description: Signal Generator for use with USRP Devices
+# Generated: Sun Jun 28 17:21:28 2015
+##################################################
+
+import sip
+import sys
+import threading
+import time
+from distutils.version import StrictVersion
+from PyQt4 import Qt
+from PyQt4.QtCore import QObject, pyqtSlot
from gnuradio import analog
-from gnuradio.gr.pubsub import pubsub
-from gnuradio.wxgui import gui, forms
-from gnuradio.uhd import uhd_siggen_base as uhd_siggen
-import sys, math
+from gnuradio import eng_notation
+from gnuradio import gr
+from gnuradio import qtgui
+from gnuradio import uhd
+from gnuradio.filter import firdes
+from gnuradio.qtgui import Range, RangeWidget
+try:
+ import uhd_siggen_base as uhd_siggen
+except ImportError:
+ from gnuradio.uhd import uhd_siggen_base as uhd_siggen
+
-class app_gui(pubsub):
- def __init__(self, frame, panel, vbox, top_block, options, args):
- pubsub.__init__(self)
- self.frame = frame # Use for top-level application window frame
- self.panel = panel # Use as parent class for created windows
- self.vbox = vbox # Use as sizer for created windows
- self.tb = top_block # GUI-unaware flowgraph class
- self.options = options # Supplied command-line options
- self.args = args # Supplied command-line arguments
- self.build_gui()
+class uhd_siggen_gui(Qt.QWidget):
+ """
+ Signal Generator Flowgraph
+ """
+ def __init__(self, args):
+ ##################################################
+ # Set up the siggen app
+ ##################################################
+ self._sg = uhd_siggen.USRPSiggen(args)
+ self.usrp = self._sg.usrp
- # Event response handlers
- def evt_set_status_msg(self, msg):
- self.frame.SetStatusText(msg, 0)
+ ##################################################
+ # GUI Setup
+ ##################################################
+ Qt.QWidget.__init__(self)
+ self.setWindowTitle("UHD Signal Generator")
+ try:
+ self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
+ except:
+ pass
+ self.top_scroll_layout = Qt.QVBoxLayout()
+ self.setLayout(self.top_scroll_layout)
+ self.top_scroll = Qt.QScrollArea()
+ self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
+ self.top_scroll_layout.addWidget(self.top_scroll)
+ self.top_scroll.setWidgetResizable(True)
+ self.top_widget = Qt.QWidget()
+ self.top_scroll.setWidget(self.top_widget)
+ self.top_layout = Qt.QVBoxLayout(self.top_widget)
+ self.top_grid_layout = Qt.QGridLayout()
+ self.top_layout.addLayout(self.top_grid_layout)
+ self.settings = Qt.QSettings("GNU Radio", "uhd_siggen_gui")
+ self.restoreGeometry(self.settings.value("geometry").toByteArray())
- # GUI construction
- def build_gui(self):
- self.vbox.AddSpacer(5)
- self.vbox.AddStretchSpacer()
##################################################
- # Baseband controls
+ # Widgets + Controls
##################################################
- bb_vbox = forms.static_box_sizer(parent=self.panel, label="Baseband
Modulation", orient=wx.VERTICAL, bold=True)
- self.vbox.Add(bb_vbox, 0, wx.EXPAND)
- sine_bb_hbox = wx.BoxSizer(wx.HORIZONTAL)
- sweep_bb_hbox = wx.BoxSizer(wx.HORIZONTAL)
- tone_bb_hbox = wx.BoxSizer(wx.HORIZONTAL)
- self.vbox.AddSpacer(10)
- self.vbox.AddStretchSpacer()
- #callback to show/hide forms
- def set_type(type):
- sine_bb_hbox.ShowItems(type == analog.GR_SIN_WAVE)
- sweep_bb_hbox.ShowItems(type == 'sweep')
- tone_bb_hbox.ShowItems(type == '2tone')
- self.vbox.Layout()
- self.tb.subscribe(uhd_siggen.TYPE_KEY, set_type)
- #create sine forms
- sine_bb_hbox.AddSpacer(10)
- forms.text_box(
- parent=self.panel, sizer=sine_bb_hbox,
- label='Frequency (Hz)',
- ps=self.tb,
- key=uhd_siggen.WAVEFORM_FREQ_KEY,
- converter=forms.float_converter(),
+ ### Waveform Selector
+ self._waveform_options = uhd_siggen.waveforms.keys()
+ self._waveform_labels = uhd_siggen.waveforms.values()
+ self._waveform_group_box = Qt.QGroupBox("Waveform")
+ self._waveform_box = Qt.QHBoxLayout()
+ class variable_chooser_button_group(Qt.QButtonGroup):
+ def __init__(self, parent=None):
+ Qt.QButtonGroup.__init__(self, parent)
+ @pyqtSlot(int)
+ def updateButtonChecked(self, button_id):
+ self.button(button_id).setChecked(True)
+ self._waveform_button_group = variable_chooser_button_group()
+ self._waveform_group_box.setLayout(self._waveform_box)
+ for i, label in enumerate(self._waveform_labels):
+ radio_button = Qt.QRadioButton(label)
+ self._waveform_box.addWidget(radio_button)
+ self._waveform_button_group.addButton(radio_button, i)
+ self._waveform_callback = lambda i: Qt.QMetaObject.invokeMethod(
+ self._waveform_button_group,
+ "updateButtonChecked",
+ Qt.Q_ARG("int", self._waveform_options.index(i))
)
- sine_bb_hbox.AddStretchSpacer()
- #create sweep forms
- sweep_bb_hbox.AddSpacer(10)
- forms.text_box(
- parent=self.panel, sizer=sweep_bb_hbox,
- label='Sweep Width (Hz)',
- ps=self.tb,
- key=uhd_siggen.WAVEFORM_FREQ_KEY,
- converter=forms.float_converter(),
+ self._waveform_callback(self._sg[uhd_siggen.TYPE_KEY])
+ self._waveform_button_group.buttonClicked[int].connect(
+ lambda i: self.set_waveform(self._waveform_options[i])
)
- sweep_bb_hbox.AddStretchSpacer()
- forms.text_box(
- parent=self.panel, sizer=sweep_bb_hbox,
- label='Sweep Rate (Hz)',
- ps=self.tb,
- key=uhd_siggen.WAVEFORM2_FREQ_KEY,
- converter=forms.float_converter(),
+ self.top_grid_layout.addWidget(self._waveform_group_box, 0,0,1,5)
+ ### Center Frequency Sliders
+ self.freq_coarse = self._sg.usrp.get_center_freq(self._sg.channels[0])
+ self._freq_coarse_range = Range(
+ self.usrp.get_freq_range(self._sg.channels[0]).start(),
+ self.usrp.get_freq_range(self._sg.channels[0]).stop(),
+ 1e3, # Step
+ self.freq_coarse,
+ 200, # Min Width
)
- sweep_bb_hbox.AddStretchSpacer()
- #create 2tone forms
- tone_bb_hbox.AddSpacer(10)
- forms.text_box(
- parent=self.panel, sizer=tone_bb_hbox,
- label='Tone 1 (Hz)',
- ps=self.tb,
- key=uhd_siggen.WAVEFORM_FREQ_KEY,
- converter=forms.float_converter(),
+ self._freq_coarse_win = RangeWidget(
+ self._freq_coarse_range,
+ self.set_freq_coarse,
+ "Center Frequency",
+ "counter_slider",
+ float
)
- tone_bb_hbox.AddStretchSpacer()
- forms.text_box(
- parent=self.panel, sizer=tone_bb_hbox,
- label='Tone 2 (Hz)',
- ps=self.tb,
- key=uhd_siggen.WAVEFORM2_FREQ_KEY,
- converter=forms.float_converter(),
+ self.top_grid_layout.addWidget(self._freq_coarse_win, 1,0,1,5)
+ self.freq_fine = 0.0
+ self._freq_fine_range = Range(
+ -1e6, 1e6, 1e3,
+ self.freq_fine,
+ 200
)
- tone_bb_hbox.AddStretchSpacer()
- forms.radio_buttons(
- parent=self.panel, sizer=bb_vbox,
- choices=uhd_siggen.waveforms.keys(),
- labels=uhd_siggen.waveforms.values(),
- ps=self.tb,
- key=uhd_siggen.TYPE_KEY,
- style=wx.NO_BORDER | wx.RA_HORIZONTAL,
+ self._freq_fine_win = RangeWidget(
+ self._freq_fine_range,
+ self.set_freq_fine,
+ "Fine Tuning",
+ "counter_slider",
+ float
)
- bb_vbox.AddSpacer(10)
- bb_vbox.Add(sine_bb_hbox, 0, wx.EXPAND)
- bb_vbox.Add(sweep_bb_hbox, 0, wx.EXPAND)
- bb_vbox.Add(tone_bb_hbox, 0, wx.EXPAND)
- set_type(self.tb[uhd_siggen.TYPE_KEY])
-
- ##################################################
- # Frequency controls
- ##################################################
- fc_vbox = forms.static_box_sizer(parent=self.panel,
- label="Center Frequency",
- orient=wx.VERTICAL,
- bold=True)
- fc_vbox.AddSpacer(5)
- # First row of frequency controls (center frequency)
- freq_hbox = wx.BoxSizer(wx.HORIZONTAL)
- fc_vbox.Add(freq_hbox, 0, wx.EXPAND)
- fc_vbox.AddSpacer(10)
- # Second row of frequency controls (results)
- tr_hbox = wx.BoxSizer(wx.HORIZONTAL)
- fc_vbox.Add(tr_hbox, 0, wx.EXPAND)
- fc_vbox.AddSpacer(5)
- # Add frequency controls to top window sizer
- self.vbox.Add(fc_vbox, 0, wx.EXPAND)
- self.vbox.AddSpacer(10)
- self.vbox.AddStretchSpacer()
- freq_hbox.AddSpacer(5)
- forms.text_box(
- parent=self.panel, sizer=freq_hbox,
- proportion=1,
- converter=forms.float_converter(),
- ps=self.tb,
- key=uhd_siggen.TX_FREQ_KEY,
+ self.top_grid_layout.addWidget(self._freq_fine_win, 2,0,1,5)
+ self.lo_offset = self._sg.args.lo_offset
+ self._lo_offset_range = Range(
+ -self._sg[uhd_siggen.SAMP_RATE_KEY]/2,
+ self._sg[uhd_siggen.SAMP_RATE_KEY]/2,
+ 1e3,
+ self.lo_offset,
+ 200
)
- freq_hbox.AddSpacer(10)
-
- forms.slider(
- parent=self.panel, sizer=freq_hbox,
- proportion=2,
- ps=self.tb,
- key=uhd_siggen.TX_FREQ_KEY,
- minimum=self.tb[uhd_siggen.FREQ_RANGE_KEY].start(),
- maximum=self.tb[uhd_siggen.FREQ_RANGE_KEY].stop(),
- num_steps=100,
+ self._lo_offset_win = RangeWidget(
+ self._lo_offset_range,
+ self.set_lo_offset,
+ "LO Offset",
+ "counter_slider",
+ float
)
- freq_hbox.AddSpacer(5)
- tr_hbox.AddSpacer(5)
- forms.static_text(
- parent=self.panel, sizer=tr_hbox,
- label='RF Frequency',
- ps=self.tb,
- key=uhd_siggen.RF_FREQ_KEY,
- converter=forms.float_converter(),
- proportion=1,
+ self.top_grid_layout.addWidget(self._lo_offset_win, 3,0,1,5)
+ ### Signal frequencies
+ self._freq1_enable_on = (analog.GR_SIN_WAVE, "2tone", "sweep")
+ self._freq1_offset_range = Range(
+ -self._sg[uhd_siggen.SAMP_RATE_KEY]/4,
+ self._sg[uhd_siggen.SAMP_RATE_KEY]/4,
+ 100,
+ self._sg.args.waveform_freq,
+ 200
)
- tr_hbox.AddSpacer(10)
- forms.static_text(
- parent=self.panel, sizer=tr_hbox,
- label='DSP Frequency',
- ps=self.tb,
- key=uhd_siggen.DSP_FREQ_KEY,
- converter=forms.float_converter(),
- proportion=1,
+ self._freq1_offset_win = RangeWidget(
+ self._freq1_offset_range,
+ self.set_freq1_offset,
+ "Frequency Offset: Signal 1",
+ "counter_slider",
+ float
)
- tr_hbox.AddSpacer(5)
-
- ##################################################
- # Amplitude controls
- ##################################################
- amp_hbox = forms.static_box_sizer(parent=self.panel,
- label="Amplitude",
- orient=wx.VERTICAL,
- bold=True)
- amp_hbox.AddSpacer(5)
- # First row of amp controls (ampl)
- lvl_hbox = wx.BoxSizer(wx.HORIZONTAL)
- amp_hbox.Add(lvl_hbox, 0, wx.EXPAND)
- amp_hbox.AddSpacer(10)
- # Second row of amp controls (tx gain)
- gain_hbox = wx.BoxSizer(wx.HORIZONTAL)
- amp_hbox.Add(gain_hbox, 0, wx.EXPAND)
- amp_hbox.AddSpacer(5)
- self.vbox.Add(amp_hbox, 0, wx.EXPAND)
- self.vbox.AddSpacer(10)
- self.vbox.AddStretchSpacer()
- lvl_hbox.AddSpacer(5)
- forms.text_box(
- parent=self.panel, sizer=lvl_hbox,
- proportion=1,
- converter=forms.float_converter(),
- ps=self.tb,
- key=uhd_siggen.AMPLITUDE_KEY,
- label="Level (0.0-1.0)",
+ self._freq1_offset_win.setEnabled(self._sg[uhd_siggen.TYPE_KEY] in
self._freq1_enable_on)
+ self.top_grid_layout.addWidget(self._freq1_offset_win, 4,0,1,3)
+ self._freq2_enable_on = ("2tone", "sweep")
+ self._freq2_offset_range = Range(
+ -self._sg[uhd_siggen.SAMP_RATE_KEY]/4,
+ self._sg[uhd_siggen.SAMP_RATE_KEY]/4,
+ 100,
+ self._sg.args.waveform2_freq,
+ 200
)
- lvl_hbox.AddSpacer(10)
- forms.log_slider(
- parent=self.panel, sizer=lvl_hbox,
- proportion=2,
- ps=self.tb,
- key=uhd_siggen.AMPLITUDE_KEY,
- min_exp=-6,
- max_exp=0,
- base=10,
- num_steps=100,
+ self._freq2_offset_win = RangeWidget(
+ self._freq2_offset_range,
+ self.set_freq2_offset,
+ "Signal 2 ",
+ "counter_slider",
+ float
)
- lvl_hbox.AddSpacer(5)
- if self.tb[uhd_siggen.GAIN_RANGE_KEY].start() <
self.tb[uhd_siggen.GAIN_RANGE_KEY].stop():
- gain_hbox.AddSpacer(5)
- forms.text_box(
- parent=self.panel, sizer=gain_hbox,
- proportion=1,
- converter=forms.float_converter(),
- ps=self.tb,
- key=uhd_siggen.GAIN_KEY,
- label="TX Gain (dB)",
- )
- gain_hbox.AddSpacer(10)
- forms.slider(
- parent=self.panel, sizer=gain_hbox,
- proportion=2,
- ps=self.tb,
- key=uhd_siggen.GAIN_KEY,
- minimum=self.tb[uhd_siggen.GAIN_RANGE_KEY].start(),
- maximum=self.tb[uhd_siggen.GAIN_RANGE_KEY].stop(),
- step_size=self.tb[uhd_siggen.GAIN_RANGE_KEY].step(),
+ self._freq2_offset_win.setEnabled(self._sg[uhd_siggen.TYPE_KEY] in
self._freq2_enable_on)
+ self.top_grid_layout.addWidget(self._freq2_offset_win, 4,3,1,2)
+ ### Amplitude
+ self._amplitude_range = Range(0, 1, .001, .7, 200)
+ self._amplitude_win = RangeWidget(
+ self._amplitude_range,
+ self.set_amplitude,
+ "Signal Amplitude",
+ "counter_slider",
+ float
+ )
+ self.top_grid_layout.addWidget(self._amplitude_win, 5,0,1,5)
+ ### Gain
+ self._gain_range = Range(
+ self.usrp.get_gain_range(self._sg.channels[0]).start(),
+ self.usrp.get_gain_range(self._sg.channels[0]).stop(),
+ .5,
+ self.usrp.get_gain(self._sg.channels[0]),
+ 200.,
+ )
+ self._gain_win = RangeWidget(
+ self._gain_range,
+ self._sg.set_gain,
+ "TX Gain", "counter_slider", float
+ )
+ self.top_grid_layout.addWidget(self._gain_win, 6,0,1,5)
+ ### Samp rate, LO sync, Antenna Select
+ self.samp_rate = self._sg[uhd_siggen.SAMP_RATE_KEY]
+ self._samp_rate_tool_bar = Qt.QToolBar(self)
+ self._samp_rate_tool_bar.addWidget(Qt.QLabel("Sampling Rate: "))
+ self._samp_rate_line_edit =
Qt.QLineEdit(eng_notation.num_to_str(self._sg[uhd_siggen.SAMP_RATE_KEY]))
+ self._samp_rate_tool_bar.addWidget(self._samp_rate_line_edit)
+ self._samp_rate_line_edit.returnPressed.connect(
+ lambda:
self.set_samp_rate(eng_notation.str_to_num(str(self._samp_rate_line_edit.text().toAscii())))
+ )
+ self.top_grid_layout.addWidget(self._samp_rate_tool_bar, 7,0,1,2)
+ _sync_phases_push_button = Qt.QPushButton("Sync LOs")
+ _sync_phases_push_button.pressed.connect(lambda:
self.set_sync_phases(True))
+ _sync_phases_push_button.setEnabled(bool(len(self._sg.channels) > 1))
+ self.top_grid_layout.addWidget(_sync_phases_push_button, 7,2,1,1)
+ # Antenna Select
+ self._ant_tool_bar = Qt.QToolBar(self)
+ self._ant_tool_bar.addWidget(Qt.QLabel("Antenna: "))
+ self._ant_combo_box = Qt.QComboBox()
+ self._ant_tool_bar.addWidget(self._ant_combo_box)
+ self._ant_options = self.usrp.get_antennas(self._sg.channels[0])
+ for label in self._ant_options:
+ self._ant_combo_box.addItem(label)
+ self._ant_callback = lambda i: Qt.QMetaObject.invokeMethod(
+ self._ant_combo_box, "setCurrentIndex",
+ Qt.Q_ARG("int", self._ant_options.index(i))
+ )
+ self._ant_callback(self.usrp.get_antenna(self._sg.channels[0]))
+ self._ant_combo_box.currentIndexChanged.connect(lambda i:
self.set_ant(self._ant_options[i]))
+ self.top_grid_layout.addWidget(self._ant_tool_bar, 7,4,1,1)
+ # Labels + Lock Sensors
+ self._lo_locked_probe_0_tool_bar = Qt.QToolBar(self)
+ self._lo_locked_probe_0_formatter = lambda x: x
+ self._lo_locked_probe_0_tool_bar.addWidget(Qt.QLabel("LO locked: "))
+ self._lo_locked_probe_0_label = Qt.QLabel(str(False))
+
self._lo_locked_probe_0_tool_bar.addWidget(self._lo_locked_probe_0_label)
+ self.top_grid_layout.addWidget(self._lo_locked_probe_0_tool_bar,
8,0,1,1)
+ def _chan0_lo_locked_probe():
+ while True:
+ val = all([self.usrp.get_sensor('lo_locked', c).to_bool() for
c in range(len(self._sg.channels))])
+ try:
+ self.set_chan0_lo_locked(val)
+ except AttributeError:
+ pass
+ time.sleep(.1)
+ _chan0_lo_locked_thread =
threading.Thread(target=_chan0_lo_locked_probe)
+ _chan0_lo_locked_thread.daemon = True
+ _chan0_lo_locked_thread.start()
+ self.label_rf_freq = self._sg.tr.actual_rf_freq
+ self._label_rf_freq_tool_bar = Qt.QToolBar(self)
+ self._label_rf_freq_formatter = lambda x: x
+ self._label_rf_freq_tool_bar.addWidget(Qt.QLabel("LO freq: "))
+ self._label_rf_freq_label =
Qt.QLabel(str(self._label_rf_freq_formatter(self.label_rf_freq)))
+ self._label_rf_freq_tool_bar.addWidget(self._label_rf_freq_label)
+ self.top_grid_layout.addWidget(self._label_rf_freq_tool_bar, 8,1,1,1)
+ self.label_dsp_freq = self._sg.tr.actual_dsp_freq
+ self._label_dsp_freq_tool_bar = Qt.QToolBar(self)
+ self._label_dsp_freq_formatter = lambda x: x
+ self._label_dsp_freq_tool_bar.addWidget(Qt.QLabel("DSP Freq: "))
+ self._label_dsp_freq_label =
Qt.QLabel(str(self._label_dsp_freq_formatter(self.label_dsp_freq)))
+ self._label_dsp_freq_tool_bar.addWidget(self._label_dsp_freq_label)
+ self.top_grid_layout.addWidget(self._label_dsp_freq_tool_bar, 8,2,1,1)
+ ##################################################
+ # Freq Sink
+ ##################################################
+ if self._sg.args.show_freq_sink:
+ self.qtgui_freq_sink_x_0 = qtgui.freq_sink_c(
+ 1024, #size
+ firdes.WIN_BLACKMAN_hARRIS, #wintype
+ self.freq_coarse + self.freq_fine, #fc
+ self.samp_rate, #bw
+ "", #name
+ 1 #number of inputs
)
- gain_hbox.AddSpacer(5)
-
+ self.qtgui_freq_sink_x_0.set_update_time(0.10)
+ self.qtgui_freq_sink_x_0.set_y_axis(-100, 10)
+ self.qtgui_freq_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE,
0.0, 0, "")
+ self.qtgui_freq_sink_x_0.enable_autoscale(False)
+ self.qtgui_freq_sink_x_0.enable_grid(False)
+ self.qtgui_freq_sink_x_0.set_fft_average(1.0)
+ self.qtgui_freq_sink_x_0.enable_control_panel(False)
+ self.qtgui_freq_sink_x_0.set_line_label(0, "Siggen Spectrum")
+ self.qtgui_freq_sink_x_0.set_line_width(0, 1)
+ self.qtgui_freq_sink_x_0.set_line_color(0, "blue")
+ self.qtgui_freq_sink_x_0.set_line_alpha(0, 1.0)
+ self._qtgui_freq_sink_x_0_win =
sip.wrapinstance(self.qtgui_freq_sink_x_0.pyqwidget(), Qt.QWidget)
+ self.top_grid_layout.addWidget(self._qtgui_freq_sink_x_0_win,
9,0,2,5)
+ # Reconnect:
+ self._sg.extra_sink = self.qtgui_freq_sink_x_0
+ self._sg[uhd_siggen.TYPE_KEY] = self._sg[uhd_siggen.TYPE_KEY]
##################################################
- # Sample Rate controls
+ # Start transmitting
##################################################
- sam_hbox = forms.static_box_sizer(parent=self.panel,
- label="Sample Rate",
- orient=wx.HORIZONTAL,
- bold=True)
- self.vbox.Add(sam_hbox, 0, wx.EXPAND)
- self.vbox.AddSpacer(10)
- self.vbox.AddStretchSpacer()
- sam_hbox.AddStretchSpacer(20)
- forms.static_text(
- parent=self.panel, sizer=sam_hbox,
- label='Sample Rate (sps)',
- ps=self.tb,
- key=uhd_siggen.SAMP_RATE_KEY,
- converter=forms.float_converter(),
+ self._sg.start()
+
+ ##################################################
+ # QT + Flowgraph stuff
+ ##################################################
+ def closeEvent(self, event):
+ self.settings = Qt.QSettings("GNU Radio", "uhd_siggen_gui")
+ self.settings.setValue("geometry", self.saveGeometry())
+ event.accept()
+
+ def stop(self):
+ """
+ Stop flow graph, tear down blocks
+ """
+ self._sg.stop()
+ self._sg.wait()
+ self._sg = None
+
+ ##################################################
+ # Setters
+ ##################################################
+ def set_waveform(self, waveform):
+ self._freq1_offset_win.setEnabled(waveform in self._freq1_enable_on)
+ self._freq2_offset_win.setEnabled(waveform in self._freq2_enable_on)
+ self._sg[uhd_siggen.TYPE_KEY] = waveform
+ self._waveform_callback(waveform)
+
+ def set_freq_coarse(self, freq_coarse):
+ self.freq_coarse = freq_coarse
+ self.update_center_freq()
+
+ def set_freq_fine(self, freq_fine):
+ self.freq_fine = freq_fine
+ self.update_center_freq()
+
+ def set_lo_offset(self, lo_offset):
+ self.lo_offset = lo_offset
+ self.update_center_freq()
+
+ def update_center_freq(self):
+ if hasattr(self, "qtgui_freq_sink_x_0"):
+ self.qtgui_freq_sink_x_0.set_frequency_range(self.freq_coarse +
self.freq_fine, self.samp_rate)
+ self.tune()
+
+ def tune(self):
+ """
+ Multi-channel tune
+ """
+ tune_req = uhd.tune_request(
+ self.freq_fine + self.freq_coarse,
+ self.lo_offset
)
- sam_hbox.AddStretchSpacer(20)
+ for idx, c in enumerate(self._sg.channels):
+ tune_res = self.usrp.set_center_freq(tune_req, c)
+ if idx == 0:
+ self.set_label_dsp_freq(tune_res.actual_dsp_freq)
+ self.set_label_rf_freq(tune_res.actual_rf_freq)
- ##################################################
- # UHD status
- ##################################################
- u2_hbox = forms.static_box_sizer(parent=self.panel,
- label="UHD (%s)" %
(uhd.get_version_string()),
- orient=wx.HORIZONTAL,
- bold=True)
- self.vbox.Add(u2_hbox, 0, wx.EXPAND)
- self.vbox.AddSpacer(10)
- self.vbox.AddStretchSpacer()
- u2_hbox.AddSpacer(10)
- forms.static_text(
- parent=self.panel, sizer=u2_hbox,
- ps=self.tb,
- key=uhd_siggen.DESC_KEY,
- converter=forms.str_converter(),
+ def set_freq1_offset(self, freq1_offset):
+ self._sg[uhd_siggen.WAVEFORM_FREQ_KEY] = freq1_offset
+
+ def set_freq2_offset(self, freq2_offset):
+ self._sg[uhd_siggen.WAVEFORM2_FREQ_KEY] = freq2_offset
+
+ def set_amplitude(self, amplitude):
+ self.amplitude = amplitude
+ self._sg[uhd_siggen.AMPLITUDE_KEY] = amplitude
+
+ def set_sync_phases(self, sync):
+ if sync:
+ self._sg.vprint("Attempting to sync LO phases. This does not work
with all boards.")
+ self._sg.set_freq(self.freq_coarse + self.freq_fine, False)
+
+ def set_ant(self, ant):
+ self.ant = ant
+ self._ant_callback(self.ant)
+
+ def set_samp_rate(self, samp_rate):
+ self.samp_rate = samp_rate
+ Qt.QMetaObject.invokeMethod(
+ self._samp_rate_line_edit, "setText",
+ Qt.Q_ARG("QString", eng_notation.num_to_str(self.samp_rate))
)
- self.vbox.AddSpacer(5)
- self.vbox.AddStretchSpacer()
+ self._sg[uhd_siggen.SAMP_RATE_KEY] = samp_rate
+ self.update_center_freq()
-def main():
- try:
- # Get command line parameters
- (options, args) = uhd_siggen.get_options()
+ def set_label_rf_freq(self, label_rf_freq):
+ self.label_rf_freq = label_rf_freq
+ Qt.QMetaObject.invokeMethod(
+ self._label_rf_freq_label, "setText",
+ Qt.Q_ARG(
+ "QString",
+ eng_notation.num_to_str(self.label_rf_freq)
+ )
+ )
- # Create the top block using these
- tb = uhd_siggen.top_block(options, args)
+ def set_label_dsp_freq(self, label_dsp_freq):
+ self.label_dsp_freq = label_dsp_freq
+ Qt.QMetaObject.invokeMethod(
+ self._label_dsp_freq_label, "setText",
+ Qt.Q_ARG(
+ "QString",
+ eng_notation.num_to_str(self.label_dsp_freq)
+ )
+ )
- # Create the GUI application
- app = gui.app(top_block=tb, # Constructed top block
- gui=app_gui, # User interface class
- options=options, # Command line options
- args=args, # Command line args
- title="UHD Signal Generator", # Top window title
- nstatus=1, # Number of status lines
- start=True, # Whether to start
flowgraph
- realtime=True) # Whether to set
realtime priority
+ def set_chan0_lo_locked(self, chan0_lo_locked):
+ self.set_lo_locked_probe_0(chan0_lo_locked)
- # And run it
- app.MainLoop()
+ def set_lo_locked_probe_0(self, lo_locked_probe_0):
+ Qt.QMetaObject.invokeMethod(
+ self._lo_locked_probe_0_label, "setText",
+ Qt.Q_ARG("QString", str(self.lo_locked_probe_0))
+ )
+
+
+def setup_parser():
+ """
+ Argument parser for siggen_gui
+ """
+ parser = uhd_siggen.setup_argparser()
+ group = parser.add_argument_group('GUI Arguments')
+ group.add_argument(
+ "-q", "--show-freq-sink", action="store_true",
+ help="Show QT Frequency Widget"
+ )
+ return parser
+
+def main():
+ """ Go, go, go! """
+ parser = setup_parser()
+ args = parser.parse_args()
+ if(StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0")):
+ Qt.QApplication.setGraphicsSystem(gr.prefs().get_string('qtgui',
'style', 'raster'))
+ qapp = Qt.QApplication(sys.argv)
+ siggen_gui = uhd_siggen_gui(args)
+ siggen_gui.show()
+ def quitting():
+ siggen_gui.stop()
+ qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting)
+ qapp.exec_()
+ siggen_gui = None #to clean up Qt widgets
- except RuntimeError, e:
- print e
- sys.exit(1)
+if __name__ == '__main__':
+ import ctypes
+ import sys
+ if sys.platform.startswith('linux'):
+ try:
+ x11 = ctypes.cdll.LoadLibrary('libX11.so')
+ x11.XInitThreads()
+ except:
+ print("Warning: failed to XInitThreads()")
+ main()
-# Make sure to create the top block (tb) within a function: That code
-# in main will allow tb to go out of scope on return, which will call
-# the decontructor on uhd device and stop transmit. Whats odd is that
-# grc works fine with tb in the __main__, perhaps its because the
-# try/except clauses around tb.
-if __name__ == "__main__": main()
diff --git a/gr-uhd/examples/grc/uhd_siggen_gui.grc
b/gr-uhd/examples/grc/uhd_siggen_gui.grc
new file mode 100644
index 0000000..27eda7c
--- /dev/null
+++ b/gr-uhd/examples/grc/uhd_siggen_gui.grc
@@ -0,0 +1,2154 @@
+<?xml version='1.0' encoding='utf-8'?>
+<?grc format='1' created='3.7.9'?>
+<flow_graph>
+ <timestamp>Sat Jun 27 12:02:49 2015</timestamp>
+ <block>
+ <key>options</key>
+ <param>
+ <key>author</key>
+ <value>Ettus Research</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>1280, 1024</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>description</key>
+ <value>Signal Generator for use with USRP Devices</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(-8, -11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>qt_gui</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>uhd_siggen_gui</value>
+ </param>
+ <param>
+ <key>max_nouts</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>realtime_scheduling</key>
+ <value></value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>prompt</value>
+ </param>
+ <param>
+ <key>run</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>thread_safe_setters</key>
+ <value></value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>UHD Signal Generator</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>.7</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(984, -2)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>5,0,1,5</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>amplitude</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Signal Amplitude</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>.001</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_chooser</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>RX2</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(304, 175)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>7,4,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>ant</value>
+ </param>
+ <param>
+ <key>label0</key>
+ <value>RX2</value>
+ </param>
+ <param>
+ <key>label1</key>
+ <value>TX/RX</value>
+ </param>
+ <param>
+ <key>label2</key>
+ <value>J1</value>
+ </param>
+ <param>
+ <key>label3</key>
+ <value>J2</value>
+ </param>
+ <param>
+ <key>label4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Antenna</value>
+ </param>
+ <param>
+ <key>labels</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>num_opts</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>option0</key>
+ <value>RX2</value>
+ </param>
+ <param>
+ <key>option1</key>
+ <value>TX/RX</value>
+ </param>
+ <param>
+ <key>option2</key>
+ <value>J1</value>
+ </param>
+ <param>
+ <key>option3</key>
+ <value>J2</value>
+ </param>
+ <param>
+ <key>option4</key>
+ <value>4</value>
+ </param>
+ <param>
+ <key>options</key>
+ <value>[0, 1, 2]</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.QVBoxLayout</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>string</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>combo_box</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_function_probe</key>
+ <param>
+ <key>block_id</key>
+ <value>uhd_usrp_source_0</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>function_args</key>
+ <value>"'lo_locked'"</value>
+ </param>
+ <param>
+ <key>function_name</key>
+ <value>get_sensor</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(0, 110)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>chan0_lo_locked</value>
+ </param>
+ <param>
+ <key>poll_rate</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>uhd.sensor_value("", False, "")</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(656, -2)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>4,0,1,3</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>freq1_offset</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Frequency Offset: Signal 1</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1e6</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>100</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1e6</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(816, -2)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>4,3,1,2</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>freq2_offset</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Signal 2 </value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1e6</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>100</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1e6</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1e9</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(296, -2)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,0,1,5</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>freq_coarse</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Center Frequency</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>1e3</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>2e9</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(440, -2)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>2,0,1,5</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>freq_fine</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Fine Tuning</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1e6</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>1e3</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1e6</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1128, -2)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>6,0,1,5</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>gain</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>TX Gain</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>.5</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>50</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_label</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1e3</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>formatter</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(688, 236)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>8,2,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>label_dsp_freq</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>DSP Freq</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>real</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_label</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1e9</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>formatter</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(576, 236)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>8,1,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>label_lo_freq</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>LO freq</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>real</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_label</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>chan0_lo_locked.to_bool()</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>formatter</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(448, 236)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>8,0,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>lo_locked_probe_0</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>LO locked</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>bool</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(552, -2)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,0,1,5</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>lo_offset</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>LO Offset</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-samp_rate/2</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>samp_rate/2</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1e3</value>
+ </param>
+ <param>
+ <key>rangeType</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_entry</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1e6</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(160, 259)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>7,0,1,2</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Sampling Rate</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>real</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_push_button</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(896, 315)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>7,2,1,1</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>sync_phases</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Sync LOs</value>
+ </param>
+ <param>
+ <key>pressed</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>released</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>bool</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_chooser</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(160, -6)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,0,1,5</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>waveform</value>
+ </param>
+ <param>
+ <key>label0</key>
+ <value>Tone</value>
+ </param>
+ <param>
+ <key>label1</key>
+ <value>Two-Tone</value>
+ </param>
+ <param>
+ <key>label2</key>
+ <value>Uniform Noise</value>
+ </param>
+ <param>
+ <key>label3</key>
+ <value>Two Tone</value>
+ </param>
+ <param>
+ <key>label4</key>
+ <value>Sweep</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Waveform</value>
+ </param>
+ <param>
+ <key>labels</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>num_opts</key>
+ <value>5</value>
+ </param>
+ <param>
+ <key>option0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>option1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>option2</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>option3</key>
+ <value>3</value>
+ </param>
+ <param>
+ <key>option4</key>
+ <value>4</value>
+ </param>
+ <param>
+ <key>options</key>
+ <value>[0, 1, 2]</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.QHBoxLayout</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>int</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>radio_buttons</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_sig_source_x</key>
+ <param>
+ <key>amp</key>
+ <value>amplitude if not sync_phases else 0</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>freq</key>
+ <value>freq1_offset</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(720, 125)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>analog_sig_source_x_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>offset</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>waveform</key>
+ <value>analog.GR_TRI_WAVE</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_freq_sink_x</key>
+ <param>
+ <key>autoscale</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>average</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>bw</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>fc</key>
+ <value>freq_coarse + freq_fine</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>ctrlpanel</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>fftsize</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(920, 220)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>9,0,2,5</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>grid</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>qtgui_freq_sink_x_0</value>
+ </param>
+ <param>
+ <key>legend</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>alpha1</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color1</key>
+ <value>"blue"</value>
+ </param>
+ <param>
+ <key>label1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha10</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color10</key>
+ <value>"dark blue"</value>
+ </param>
+ <param>
+ <key>label10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width10</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha2</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color2</key>
+ <value>"red"</value>
+ </param>
+ <param>
+ <key>label2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width2</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha3</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color3</key>
+ <value>"green"</value>
+ </param>
+ <param>
+ <key>label3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width3</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha4</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color4</key>
+ <value>"black"</value>
+ </param>
+ <param>
+ <key>label4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width4</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha5</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color5</key>
+ <value>"cyan"</value>
+ </param>
+ <param>
+ <key>label5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width5</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha6</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color6</key>
+ <value>"magenta"</value>
+ </param>
+ <param>
+ <key>label6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width6</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha7</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color7</key>
+ <value>"yellow"</value>
+ </param>
+ <param>
+ <key>label7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width7</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha8</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color8</key>
+ <value>"dark red"</value>
+ </param>
+ <param>
+ <key>label8</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width8</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alpha9</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>color9</key>
+ <value>"dark green"</value>
+ </param>
+ <param>
+ <key>label9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width9</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>showports</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>freqhalf</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>tr_chan</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>tr_level</key>
+ <value>0.0</value>
+ </param>
+ <param>
+ <key>tr_mode</key>
+ <value>qtgui.TRIG_MODE_FREE</value>
+ </param>
+ <param>
+ <key>tr_tag</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>wintype</key>
+ <value>firdes.WIN_BLACKMAN_hARRIS</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-140</value>
+ </param>
+ </block>
+ <block>
+ <key>uhd_usrp_sink</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>ant0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain0</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw10</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq10</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain10</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain10</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant11</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw11</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq11</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain11</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain11</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant12</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw12</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq12</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain12</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain12</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant13</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw13</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq13</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain13</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain13</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant14</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw14</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq14</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain14</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain14</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant15</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw15</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq15</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain15</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain15</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant16</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw16</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq16</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain16</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain16</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant17</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw17</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq17</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain17</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain17</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant18</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw18</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq18</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain18</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain18</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant19</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain19</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain1</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant20</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw20</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq20</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain20</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain20</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant21</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw21</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq21</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain21</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain21</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant22</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw22</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq22</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain22</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain22</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant23</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw23</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq23</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain23</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain23</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant24</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw24</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq24</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain24</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain24</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant25</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw25</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq25</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain25</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain25</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant26</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw26</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq26</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain26</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain26</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant27</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain27</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant28</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain28</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant29</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw29</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq29</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain29</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain29</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain2</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant30</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw30</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq30</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain30</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain30</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant31</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain31</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain3</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain4</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain5</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain6</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain7</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant8</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain8</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain9</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>clock_rate</key>
+ <value>0.0</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>dev_addr</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>dev_args</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(960, 125)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>uhd_usrp_sink_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>fc32</value>
+ </param>
+ <param>
+ <key>clock_source0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>nchan</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>num_mboards</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>hide_cmd_port</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>stream_args</key>
+ <value></value>
+ </param>
+ <param>
+ <key>stream_chans</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>sync</key>
+ <value></value>
+ </param>
+ <param>
+ <key>len_tag_name</key>
+ <value></value>
+ </param>
+ <param>
+ <key>otw</key>
+ <value></value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>analog_sig_source_x_0</source_block_id>
+ <sink_block_id>qtgui_freq_sink_x_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_sig_source_x_0</source_block_id>
+ <sink_block_id>uhd_usrp_sink_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>