summaryrefslogtreecommitdiff
path: root/gr-uhd/examples/python
diff options
context:
space:
mode:
Diffstat (limited to 'gr-uhd/examples/python')
-rw-r--r--gr-uhd/examples/python/CMakeLists.txt42
-rwxr-xr-xgr-uhd/examples/python/fm_tx4.py208
-rwxr-xr-xgr-uhd/examples/python/fm_tx_2_daughterboards.py212
-rwxr-xr-xgr-uhd/examples/python/max_power.py140
-rwxr-xr-xgr-uhd/examples/python/usrp_am_mw_rcv.py315
-rwxr-xr-xgr-uhd/examples/python/usrp_nbfm_ptt.py489
-rwxr-xr-xgr-uhd/examples/python/usrp_nbfm_rcv.py380
-rwxr-xr-xgr-uhd/examples/python/usrp_spectrum_sense.py258
-rwxr-xr-xgr-uhd/examples/python/usrp_tv_rcv.py443
-rwxr-xr-xgr-uhd/examples/python/usrp_tv_rcv_nogui.py214
-rwxr-xr-xgr-uhd/examples/python/usrp_wfm_rcv.py286
-rwxr-xr-xgr-uhd/examples/python/usrp_wfm_rcv2_nogui.py154
-rwxr-xr-xgr-uhd/examples/python/usrp_wfm_rcv_fmdet.py349
-rwxr-xr-xgr-uhd/examples/python/usrp_wfm_rcv_nogui.py175
-rwxr-xr-xgr-uhd/examples/python/usrp_wfm_rcv_pll.py346
-rwxr-xr-xgr-uhd/examples/python/usrp_wfm_rcv_sca.py403
-rwxr-xr-xgr-uhd/examples/python/usrp_wxapt_rcv.py282
17 files changed, 4696 insertions, 0 deletions
diff --git a/gr-uhd/examples/python/CMakeLists.txt b/gr-uhd/examples/python/CMakeLists.txt
new file mode 100644
index 000000000..7642b536b
--- /dev/null
+++ b/gr-uhd/examples/python/CMakeLists.txt
@@ -0,0 +1,42 @@
+# Copyright 2011 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.
+
+include(GrPython)
+
+GR_PYTHON_INSTALL(
+ PROGRAMS
+ fm_tx4.py
+ fm_tx_2_daughterboards.py
+ max_power.py
+ usrp_am_mw_rcv.py
+ usrp_nbfm_ptt.py
+ usrp_nbfm_rcv.py
+ usrp_spectrum_sense.py
+ usrp_tv_rcv_nogui.py
+ usrp_tv_rcv.py
+ usrp_wfm_rcv2_nogui.py
+ usrp_wfm_rcv_fmdet.py
+ usrp_wfm_rcv_nogui.py
+ usrp_wfm_rcv_pll.py
+ usrp_wfm_rcv.py
+ usrp_wfm_rcv_sca.py
+ usrp_wxapt_rcv.py
+ DESTINATION ${GR_PKG_UHD_EXAMPLES_DIR}
+ COMPONENT "uhd_python"
+)
diff --git a/gr-uhd/examples/python/fm_tx4.py b/gr-uhd/examples/python/fm_tx4.py
new file mode 100755
index 000000000..f412ffb5d
--- /dev/null
+++ b/gr-uhd/examples/python/fm_tx4.py
@@ -0,0 +1,208 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 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.
+#
+
+"""
+Transmit N simultaneous narrow band FM signals.
+
+They will be centered at the frequency specified on the command line,
+and will spaced at 25kHz steps from there.
+
+The program opens N files with names audio-N.dat where N is in [0,7].
+These files should contain floating point audio samples in the range [-1,1]
+sampled at 32kS/sec. You can create files like this using
+audio_to_file.py
+"""
+
+from gnuradio import gr, eng_notation
+from gnuradio import uhd
+from gnuradio import blks2
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import math
+import sys
+
+from gnuradio.wxgui import stdgui2, fftsink2
+import wx
+
+
+########################################################
+# instantiate one transmit chain for each call
+
+class pipeline(gr.hier_block2):
+ def __init__(self, filename, lo_freq, audio_rate, if_rate):
+
+ gr.hier_block2.__init__(self, "pipeline",
+ gr.io_signature(0, 0, 0),
+ gr.io_signature(1, 1, gr.sizeof_gr_complex))
+
+ try:
+ src = gr.file_source (gr.sizeof_float, filename, True)
+ except RuntimeError:
+ sys.stderr.write(("\nError: Could not open file '%s'\n\n" % \
+ filename))
+ sys.exit(1)
+
+ print audio_rate, if_rate
+ fmtx = blks2.nbfm_tx (audio_rate, if_rate, max_dev=5e3, tau=75e-6)
+
+ # Local oscillator
+ lo = gr.sig_source_c (if_rate, # sample rate
+ gr.GR_SIN_WAVE, # waveform type
+ lo_freq, #frequency
+ 1.0, # amplitude
+ 0) # DC Offset
+ mixer = gr.multiply_cc ()
+
+ self.connect (src, fmtx, (mixer, 0))
+ self.connect (lo, (mixer, 1))
+ self.connect (mixer, self)
+
+class fm_tx_block(stdgui2.std_top_block):
+ def __init__(self, frame, panel, vbox, argv):
+ MAX_CHANNELS = 7
+ stdgui2.std_top_block.__init__ (self, frame, panel, vbox, argv)
+
+ parser = OptionParser (option_class=eng_option)
+ 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=400e3,
+ help="set sample rate (bandwidth) [default=%default]")
+ parser.add_option("-f", "--freq", type="eng_float", default=None,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-n", "--nchannels", type="int", default=4,
+ help="number of Tx channels [1,4]")
+ #parser.add_option("","--debug", action="store_true", default=False,
+ # help="Launch Tx debugger")
+ (options, args) = parser.parse_args ()
+
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+ if options.nchannels < 1 or options.nchannels > MAX_CHANNELS:
+ sys.stderr.write ("fm_tx4: nchannels out of range. Must be in [1,%d]\n" % MAX_CHANNELS)
+ sys.exit(1)
+
+ if options.freq is None:
+ sys.stderr.write("fm_tx4: must specify frequency with -f FREQ\n")
+ parser.print_help()
+ sys.exit(1)
+
+ # ----------------------------------------------------------------
+ # Set up constants and parameters
+
+ self.u = uhd.usrp_sink(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ self.usrp_rate = options.samp_rate
+ self.u.set_samp_rate(self.usrp_rate)
+ self.usrp_rate = self.u.get_samp_rate()
+
+ self.sw_interp = 10
+ self.audio_rate = self.usrp_rate / self.sw_interp # 32 kS/s
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2
+
+ self.set_gain(options.gain)
+ self.set_freq(options.freq)
+
+ self.sum = gr.add_cc ()
+
+ # Instantiate N NBFM channels
+ step = 25e3
+ offset = (0 * step, 1 * step, -1 * step,
+ 2 * step, -2 * step, 3 * step, -3 * step)
+
+ for i in range (options.nchannels):
+ t = pipeline("audio-%d.dat" % (i % 4), offset[i],
+ self.audio_rate, self.usrp_rate)
+ self.connect(t, (self.sum, i))
+
+ self.gain = gr.multiply_const_cc (1.0 / options.nchannels)
+
+ # connect it all
+ self.connect (self.sum, self.gain)
+ self.connect (self.gain, self.u)
+
+ # plot an FFT to verify we are sending what we want
+ if 1:
+ post_mod = fftsink2.fft_sink_c(panel, title="Post Modulation",
+ fft_size=512,
+ sample_rate=self.usrp_rate,
+ y_per_div=20,
+ ref_level=40)
+ self.connect (self.gain, post_mod)
+ vbox.Add (post_mod.win, 1, wx.EXPAND)
+
+
+ #if options.debug:
+ # self.debugger = tx_debug_gui.tx_debug_gui(self.subdev)
+ # self.debugger.Show(True)
+
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+
+ Tuning is a two step process. First we ask the front-end to
+ tune as close to the desired frequency as it can. Then we use
+ the result of that operation and our target_frequency to
+ determine the value for the digital up converter. Finally, we feed
+ any residual_freq to the s/w freq translater.
+ """
+
+ r = self.u.set_center_freq(target_freq, 0)
+ if r:
+ print "Frequency =", eng_notation.num_to_str(self.u.get_center_freq())
+ return True
+
+ return False
+
+ def set_gain(self, gain):
+ self.u.set_gain(gain, 0)
+
+
+def main ():
+ app = stdgui2.stdapp(fm_tx_block, "Multichannel FM Tx", nstatus=1)
+ app.MainLoop ()
+
+if __name__ == '__main__':
+ main ()
diff --git a/gr-uhd/examples/python/fm_tx_2_daughterboards.py b/gr-uhd/examples/python/fm_tx_2_daughterboards.py
new file mode 100755
index 000000000..b5763e8e1
--- /dev/null
+++ b/gr-uhd/examples/python/fm_tx_2_daughterboards.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 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.
+#
+
+"""
+Transmit 2 signals, one out each daughterboard.
+
+Outputs SSB (USB) signals on side A and side B at frequencies
+specified on command line.
+
+Side A is 600 Hz tone.
+Side B is 350 + 440 Hz tones.
+"""
+
+from gnuradio import gr, uhd, blks2
+from gnuradio.eng_notation import num_to_str, str_to_num
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import math
+import sys
+
+
+class example_signal_0(gr.hier_block2):
+ """
+ Sinusoid at 600 Hz.
+ """
+ def __init__(self, sample_rate):
+ gr.hier_block2.__init__(self, "example_signal_0",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ src = gr.sig_source_c (sample_rate, # sample rate
+ gr.GR_SIN_WAVE, # waveform type
+ 600, # frequency
+ 1.0, # amplitude
+ 0) # DC Offset
+
+ self.connect(src, self)
+
+
+class example_signal_1(gr.hier_block2):
+ """
+ North American dial tone (350 + 440 Hz).
+ """
+ def __init__(self, sample_rate):
+ gr.hier_block2.__init__(self, "example_signal_1",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ src0 = gr.sig_source_c (sample_rate, # sample rate
+ gr.GR_SIN_WAVE, # waveform type
+ 350, # frequency
+ 1.0, # amplitude
+ 0) # DC Offset
+
+ src1 = gr.sig_source_c (sample_rate, # sample rate
+ gr.GR_SIN_WAVE, # waveform type
+ 440, # frequency
+ 1.0, # amplitude
+ 0) # DC Offset
+ sum = gr.add_cc()
+ self.connect(src0, (sum, 0))
+ self.connect(src1, (sum, 1))
+ self.connect(sum, self)
+
+class my_top_block(gr.top_block):
+
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ usage="%prog: [options] tx-freq0 tx-freq1"
+ 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=320e3,
+ help="set sample rate [default=%default]")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ (options, args) = parser.parse_args ()
+
+ if len(args) != 2:
+ parser.print_help()
+ raise SystemExit
+ else:
+ freq0 = str_to_num(args[0])
+ freq1 = str_to_num(args[1])
+
+ # ----------------------------------------------------------------
+ # Set up USRP to transmit on both daughterboards
+
+ d = uhd.find_devices(uhd.device_addr(options.args))
+ uhd_type = d[0].get('type')
+
+ stream_args = uhd.stream_args('fc32', channels=range(2))
+ self.u = uhd.usrp_sink(device_addr=options.args, stream_args=stream_args)
+
+ # Set up USRP system based on type
+ if(uhd_type == "usrp"):
+ self.u.set_subdev_spec("A:0 B:0")
+ tr0 = uhd.tune_request(freq0)
+ tr1 = uhd.tune_request(freq1)
+
+ else:
+ if abs(freq0 - freq1) > 5.5e6:
+ sys.stderr.write("\nError: When not using two separate d'boards, frequencies must bewithin 5.5MHz of each other.\n")
+ raise SystemExit
+
+ self.u.set_subdev_spec("A:0 A:0")
+
+ mid_freq = (freq0 + freq1)/2.0
+ tr0 = uhd.tune_request(freq0, rf_freq=mid_freq,
+ rf_freq_policy=uhd.tune_request.POLICY_MANUAL)
+
+ tr1 = uhd.tune_request(freq1, rf_freq=mid_freq,
+ rf_freq_policy=uhd.tune_request.POLICY_MANUAL)
+
+ # Use the tune requests to tune each channel
+ self.set_freq(tr0, 0)
+ self.set_freq(tr1, 1)
+
+ self.usrp_rate = options.samp_rate
+
+ self.u.set_samp_rate(self.usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ # ----------------------------------------------------------------
+ # build two signal sources, interleave them, amplify and
+ # connect them to usrp
+
+ sig0 = example_signal_0(self.usrp_rate)
+ sig1 = example_signal_1(self.usrp_rate)
+
+ intl = gr.interleave(gr.sizeof_gr_complex)
+ self.connect(sig0, (intl, 0))
+ self.connect(sig1, (intl, 1))
+
+ # Correct for any difference in requested and actual rates
+ rrate = self.usrp_rate / dev_rate
+ resamp = blks2.pfb_arb_resampler_ccf(rrate)
+
+ # and wire them up
+ self.connect(intl, resamp, self.u)
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2.0
+
+ self.set_gain(options.gain, 0)
+ self.set_gain(options.gain, 1)
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+ self.u.set_antenna(options.antenna, 1)
+
+ def set_freq(self, target_freq, chan):
+ """
+ Set the center frequency we're interested in.
+
+ @param side: 0 = side A, 1 = side B
+ @param target_freq: frequency in Hz
+ @rtype: bool
+ """
+
+ print "Tuning channel %s to %sHz" % \
+ (chan, num_to_str(target_freq))
+
+ r = self.u.set_center_freq(target_freq, chan)
+
+ if r:
+ return True
+
+ else:
+ print " Set Frequency Failed!"
+
+ return False
+
+ def set_gain(self, gain, chan):
+ self.u.set_gain(gain, chan)
+
+if __name__ == '__main__':
+ try:
+ my_top_block().run()
+ except KeyboardInterrupt:
+ pass
diff --git a/gr-uhd/examples/python/max_power.py b/gr-uhd/examples/python/max_power.py
new file mode 100755
index 000000000..5d23f16af
--- /dev/null
+++ b/gr-uhd/examples/python/max_power.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+#
+# Copyright 2004,2007,2011 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.
+#
+
+"""
+Setup USRP for maximum power consumption.
+"""
+
+
+from gnuradio import gr
+from gnuradio import uhd
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+from gnuradio import eng_notation
+
+n2s = eng_notation.num_to_str
+
+# Set this to a huge number; UHD will adjust to the
+# maximum the USRP xxxx device can handle
+MAX_RATE = 1000e6
+
+class build_block(gr.top_block):
+ def __init__(self, args, tx_enable, rx_enable):
+ gr.top_block.__init__(self)
+
+ d = uhd.find_devices(uhd.device_addr(args))
+ uhd_type = d[0].get('type')
+
+ print "\nFound '%s' at args '%s'" % \
+ (uhd_type, args)
+
+ # Test the type of USRP; if it's a USRP (v1), it has
+ # 2 channels; otherwise, it has 1 channel
+ if uhd_type == "usrp":
+ tx_nchan = 2
+ rx_nchan = 2
+ else:
+ tx_nchan = 1
+ rx_nchan = 1
+
+ if tx_enable:
+ print "\nTRANSMIT CHAIN"
+ stream_args = uhd.stream_args('fc32', channels=range(tx_nchan))
+ self.u_tx = uhd.usrp_sink(device_addr=args, stream_args=stream_args)
+ self.u_tx.set_samp_rate(MAX_RATE)
+
+ self.tx_src0 = gr.sig_source_c(self.u_tx.get_samp_rate(),
+ gr.GR_CONST_WAVE,
+ 0, 1.0, 0)
+
+ # Get dboard gain range and select maximum
+ tx_gain_range = self.u_tx.get_gain_range()
+ tx_gain = tx_gain_range.stop()
+
+ # Get dboard freq range and select midpoint
+ tx_freq_range = self.u_tx.get_freq_range()
+ tx_freq_mid = (tx_freq_range.start() + tx_freq_range.stop())/2.0
+
+ for i in xrange(tx_nchan):
+ self.u_tx.set_center_freq (tx_freq_mid + i*1e6, i)
+ self.u_tx.set_gain(tx_gain, i)
+
+ print "\nTx Sample Rate: %ssps" % (n2s(self.u_tx.get_samp_rate()))
+ for i in xrange(tx_nchan):
+ print "Tx Channel %d: " % (i)
+ print "\tFrequency = %sHz" % \
+ (n2s(self.u_tx.get_center_freq(i)))
+ print "\tGain = %f dB" % (self.u_tx.get_gain(i))
+ print ""
+
+ self.connect (self.tx_src0, self.u_tx)
+
+ if rx_enable:
+ print "\nRECEIVE CHAIN"
+ self.u_rx = uhd.usrp_source(device_addr=args,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=rx_nchan)
+ self.rx_dst0 = gr.null_sink (gr.sizeof_gr_complex)
+
+ self.u_rx.set_samp_rate(MAX_RATE)
+
+ # Get dboard gain range and select maximum
+ rx_gain_range = self.u_rx.get_gain_range()
+ rx_gain = rx_gain_range.stop()
+
+ # Get dboard freq range and select midpoint
+ rx_freq_range = self.u_rx.get_freq_range()
+ rx_freq_mid = (rx_freq_range.start() + rx_freq_range.stop())/2.0
+
+ for i in xrange(tx_nchan):
+ self.u_rx.set_center_freq (rx_freq_mid + i*1e6, i)
+ self.u_rx.set_gain(rx_gain, i)
+
+ print "\nRx Sample Rate: %ssps" % (n2s(self.u_rx.get_samp_rate()))
+ for i in xrange(rx_nchan):
+ print "Rx Channel %d: " % (i)
+ print "\tFrequency = %sHz" % \
+ (n2s(self.u_rx.get_center_freq(i)))
+ print "\tGain = %f dB" % (self.u_rx.get_gain(i))
+ print ""
+
+ self.connect (self.u_rx, self.rx_dst0)
+
+def main ():
+ parser = OptionParser (option_class=eng_option)
+ parser.add_option("-a", "--args", type="string", default="",
+ help="UHD device address args [default=%default]")
+ parser.add_option("-t", action="store_true", dest="tx_enable",
+ default=False, help="enable Tx path")
+ parser.add_option("-r", action="store_true", dest="rx_enable",
+ default=False, help="enable Rx path")
+ (options, args) = parser.parse_args ()
+
+ tb = build_block (options.args, options.tx_enable, options.rx_enable)
+
+ tb.start ()
+ raw_input ('Press Enter to quit: ')
+ tb.stop ()
+
+if __name__ == '__main__':
+ main ()
diff --git a/gr-uhd/examples/python/usrp_am_mw_rcv.py b/gr-uhd/examples/python/usrp_am_mw_rcv.py
new file mode 100755
index 000000000..28262f2bd
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_am_mw_rcv.py
@@ -0,0 +1,315 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 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.
+#
+
+from gnuradio import gr, eng_notation, optfir
+from gnuradio import audio
+from gnuradio import uhd
+from gnuradio import blks2
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import slider, powermate
+from gnuradio.wxgui import stdgui2, fftsink2, form
+from optparse import OptionParser
+import sys
+import math
+import wx
+
+class wfm_rx_block (stdgui2.std_top_block):
+ def __init__(self, frame, panel, vbox, argv):
+ stdgui2.std_top_block.__init__ (self, frame, panel, vbox, argv)
+
+ parser=OptionParser(option_class=eng_option)
+ 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("-f", "--freq", type="eng_float", default=1008.0e3,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-I", "--use-if-freq", action="store_true", default=False,
+ help="use intermediate freq (compensates DC problems in quadrature boards)" )
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is maximum)")
+ parser.add_option("-V", "--volume", type="eng_float", default=None,
+ help="set volume (default is midpoint)")
+ parser.add_option("-O", "--audio-output", type="string", default="",
+ help="pcm device name. E.g., hw:0,0 or surround51 or /dev/dsp")
+
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+ self.frame = frame
+ self.panel = panel
+ self.use_IF=options.use_if_freq
+ if self.use_IF:
+ self.IF_freq=64000.0
+ else:
+ self.IF_freq=0.0
+
+ self.vol = 0
+ self.state = "FREQ"
+ self.freq = 0
+
+ # build graph
+ self.u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ usrp_rate = 256e3
+ demod_rate = 64e3
+ audio_rate = 32e3
+ chanfilt_decim = int(usrp_rate // demod_rate)
+ audio_decim = int(demod_rate // audio_rate)
+
+ self.u.set_samp_rate(usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ # Resample signal to exactly self.usrp_rate
+ # FIXME: make one of the follow-on filters an arb resampler
+ rrate = usrp_rate / dev_rate
+ self.resamp = blks2.pfb_arb_resampler_ccf(rrate)
+
+ chan_filt_coeffs = gr.firdes.low_pass_2 (1, # gain
+ usrp_rate, # sampling rate
+ 8e3, # passband cutoff
+ 4e3, # transition bw
+ 60) # stopband attenuation
+
+ if self.use_IF:
+ # Turn If to baseband and filter.
+ self.chan_filt = gr.freq_xlating_fir_filter_ccf (chanfilt_decim,
+ chan_filt_coeffs,
+ self.IF_freq,
+ usrp_rate)
+ else:
+ self.chan_filt = gr.fir_filter_ccf (chanfilt_decim, chan_filt_coeffs)
+
+ self.agc = gr.agc_cc(0.1, 1, 1, 100000)
+ self.am_demod = gr.complex_to_mag()
+ self.volume_control = gr.multiply_const_ff(self.vol)
+
+ audio_filt_coeffs = gr.firdes.low_pass_2 (1, # gain
+ demod_rate, # sampling rate
+ 8e3, # passband cutoff
+ 2e3, # transition bw
+ 60) # stopband attenuation
+ self.audio_filt=gr.fir_filter_fff(audio_decim, audio_filt_coeffs)
+
+ # sound card as final sink
+ self.audio_sink = audio.sink (int (audio_rate),
+ options.audio_output,
+ False) # ok_to_block
+
+ # now wire it all together
+ self.connect (self.u, self.resamp, self.chan_filt, self.agc,
+ self.am_demod, self.audio_filt,
+ self.volume_control, self.audio_sink)
+
+ self._build_gui(vbox, usrp_rate, demod_rate, audio_rate)
+
+ if options.gain is None:
+ g = self.u.get_gain_range()
+ if True:
+ # if no gain was specified, use the mid gain
+ options.gain = (g.start() + g.stop())/2.0
+ options.gain = g.stop()
+
+ if options.volume is None:
+ v = self.volume_range()
+ options.volume = float(v[0]*3+v[1])/4.0
+
+ if abs(options.freq) < 1e3:
+ options.freq *= 1e3
+
+ # set initial values
+
+ self.set_gain(options.gain)
+ self.set_vol(options.volume)
+ if not(self.set_freq(options.freq)):
+ self._set_status_msg("Failed to set initial frequency")
+
+ def _set_status_msg(self, msg, which=0):
+ self.frame.GetStatusBar().SetStatusText(msg, which)
+
+
+ def _build_gui(self, vbox, usrp_rate, demod_rate, audio_rate):
+
+ def _form_set_freq(kv):
+ return self.set_freq(kv['freq'])
+
+
+ if 0:
+ self.src_fft = fftsink2.fft_sink_c(self.panel, title="Data from USRP",
+ fft_size=512, sample_rate=usrp_rate,
+ ref_scale=32768.0, ref_level=0.0, y_divs=12)
+ self.connect (self.u, self.src_fft)
+ vbox.Add (self.src_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ self.post_filt_fft = fftsink2.fft_sink_c(self.panel, title="Post Channel filter",
+ fft_size=512, sample_rate=demod_rate)
+ self.connect (self.chan_filt, self.post_filt_fft)
+ vbox.Add (self.post_filt_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ post_demod_fft = fftsink2.fft_sink_f(self.panel, title="Post Demod",
+ fft_size=1024, sample_rate=demod_rate,
+ y_per_div=10, ref_level=0)
+ self.connect (self.am_demod, post_demod_fft)
+ vbox.Add (post_demod_fft.win, 4, wx.EXPAND)
+
+ if 1:
+ audio_fft = fftsink2.fft_sink_f(self.panel, title="Audio",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=20)
+ self.connect (self.audio_filt, audio_fft)
+ vbox.Add (audio_fft.win, 4, wx.EXPAND)
+
+
+ # control area form at bottom
+ self.myform = myform = form.form()
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+ myform['freq'] = form.float_field(
+ parent=self.panel, sizer=hbox, label="Freq", weight=1,
+ callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
+
+ hbox.Add((5,0), 0)
+ myform['freq_slider'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3,
+ range=(520.0e3, 1611.0e3, 1.0e3),
+ callback=self.set_freq)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+
+ myform['volume'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Volume",
+ weight=3, range=self.volume_range(),
+ callback=self.set_vol)
+ hbox.Add((5,0), 1)
+
+ g = self.u.get_gain_range()
+ myform['gain'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Gain",
+ weight=3, range=(g.start(), g.stop(), g.step()),
+ callback=self.set_gain)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ try:
+ self.knob = powermate.powermate(self.frame)
+ self.rot = 0
+ powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate)
+ powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button)
+ except:
+ print "FYI: No Powermate or Contour Knob found"
+
+
+ def on_rotate (self, event):
+ self.rot += event.delta
+ if (self.state == "FREQ"):
+ if self.rot >= 3:
+ self.set_freq(self.freq + .1e6)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_freq(self.freq - .1e6)
+ self.rot += 3
+ else:
+ step = self.volume_range()[2]
+ if self.rot >= 3:
+ self.set_vol(self.vol + step)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_vol(self.vol - step)
+ self.rot += 3
+
+ def on_button (self, event):
+ if event.value == 0: # button up
+ return
+ self.rot = 0
+ if self.state == "FREQ":
+ self.state = "VOL"
+ else:
+ self.state = "FREQ"
+ self.update_status_bar ()
+
+
+ def set_vol (self, vol):
+ g = self.volume_range()
+ self.vol = max(g[0], min(g[1], vol))
+ self.volume_control.set_k(10**(self.vol/10))
+ self.myform['volume'].set_value(self.vol)
+ self.update_status_bar ()
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+ """
+ r = self.u.set_center_freq(target_freq + self.IF_freq, 0)
+
+ if r:
+ self.freq = target_freq
+ self.myform['freq'].set_value(target_freq) # update displayed value
+ self.myform['freq_slider'].set_value(target_freq) # update displayed value
+ self.update_status_bar()
+ self._set_status_msg("OK", 0)
+ return True
+
+ self._set_status_msg("Failed", 0)
+ return False
+
+ def set_gain(self, gain):
+ self.myform['gain'].set_value(gain) # update displayed value
+ self.u.set_gain(gain)
+
+ def update_status_bar (self):
+ msg = "Volume:%r Setting:%s" % (self.vol, self.state)
+ self._set_status_msg(msg, 1)
+ try:
+ self.src_fft.set_baseband_freq(self.freq)
+ except:
+ None
+
+ def volume_range(self):
+ return (-40.0, 0.0, 0.5)
+
+
+if __name__ == '__main__':
+ app = stdgui2.stdapp (wfm_rx_block, "USRP Broadcast AM MW RX")
+ app.MainLoop ()
diff --git a/gr-uhd/examples/python/usrp_nbfm_ptt.py b/gr-uhd/examples/python/usrp_nbfm_ptt.py
new file mode 100755
index 000000000..8d26e656e
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_nbfm_ptt.py
@@ -0,0 +1,489 @@
+#!/usr/bin/env python
+#
+# Copyright 2005,2007,2011 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.
+#
+
+import math
+import sys
+import wx
+from optparse import OptionParser
+
+from gnuradio import gr, audio, blks2, uhd
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import stdgui2, fftsink2, scopesink2, slider, form
+
+from numpy import convolve, array
+
+#import os
+#print "pid =", os.getpid()
+#raw_input('Press Enter to continue: ')
+
+# ////////////////////////////////////////////////////////////////////////
+# Control Stuff
+# ////////////////////////////////////////////////////////////////////////
+
+class ptt_block(stdgui2.std_top_block):
+ def __init__(self, frame, panel, vbox, argv):
+ stdgui2.std_top_block.__init__ (self, frame, panel, vbox, argv)
+
+ self.frame = frame
+ self.space_bar_pressed = False
+
+ parser = OptionParser (option_class=eng_option)
+ 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 ("-f", "--freq", type="eng_float", default=442.1e6,
+ help="set Tx and Rx frequency to FREQ", metavar="FREQ")
+ parser.add_option ("-g", "--rx-gain", type="eng_float", default=None,
+ help="set rx gain [default=midpoint in dB]")
+ parser.add_option ("", "--tx-gain", type="eng_float", default=None,
+ help="set tx gain [default=midpoint in dB]")
+ parser.add_option("-I", "--audio-input", type="string", default="",
+ help="pcm input device name. E.g., hw:0,0 or /dev/dsp")
+ parser.add_option("-O", "--audio-output", type="string", default="",
+ help="pcm output device name. E.g., hw:0,0 or /dev/dsp")
+ parser.add_option ("-N", "--no-gui", action="store_true", default=False)
+ (options, args) = parser.parse_args ()
+
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+ if options.freq < 1e6:
+ options.freq *= 1e6
+
+ self.txpath = transmit_path(options.args, options.spec,
+ options.antenna, options.tx_gain,
+ options.audio_input)
+ self.rxpath = receive_path(options.args, options.spec,
+ options.antenna, options.rx_gain,
+ options.audio_output)
+ self.connect(self.txpath)
+ self.connect(self.rxpath)
+
+ self._build_gui(frame, panel, vbox, argv, options.no_gui)
+
+ self.set_transmit(False)
+ self.set_freq(options.freq)
+ self.set_rx_gain(self.rxpath.gain) # update gui
+ self.set_volume(self.rxpath.volume) # update gui
+ self.set_squelch(self.rxpath.threshold()) # update gui
+
+
+ def set_transmit(self, enabled):
+ self.txpath.set_enable(enabled)
+ self.rxpath.set_enable(not(enabled))
+ if enabled:
+ self.frame.SetStatusText ("Transmitter ON", 1)
+ else:
+ self.frame.SetStatusText ("Receiver ON", 1)
+
+
+ def set_rx_gain(self, gain):
+ self.myform['rx_gain'].set_value(gain) # update displayed value
+ self.rxpath.set_gain(gain)
+
+ def set_tx_gain(self, gain):
+ self.txpath.set_gain(gain)
+
+ def set_squelch(self, threshold):
+ self.rxpath.set_squelch(threshold)
+ self.myform['squelch'].set_value(self.rxpath.threshold())
+
+ def set_volume (self, vol):
+ self.rxpath.set_volume(vol)
+ self.myform['volume'].set_value(self.rxpath.volume)
+ #self.update_status_bar ()
+
+ def set_freq(self, freq):
+ r1 = self.txpath.set_freq(freq)
+ r2 = self.rxpath.set_freq(freq)
+ #print "txpath.set_freq =", r1
+ #print "rxpath.set_freq =", r2
+ if r1 and r2:
+ self.myform['freq'].set_value(freq) # update displayed value
+ return r1 and r2
+
+ def _build_gui(self, frame, panel, vbox, argv, no_gui):
+
+ def _form_set_freq(kv):
+ return self.set_freq(kv['freq'])
+
+ self.panel = panel
+
+ # FIXME This REALLY needs to be replaced with a hand-crafted button
+ # that sends both button down and button up events
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((10,0), 1)
+ self.status_msg = wx.StaticText(panel, -1, "Press Space Bar to Transmit")
+ of = self.status_msg.GetFont()
+ self.status_msg.SetFont(wx.Font(15, of.GetFamily(), of.GetStyle(), of.GetWeight()))
+ hbox.Add(self.status_msg, 0, wx.ALIGN_CENTER)
+ hbox.Add((10,0), 1)
+ vbox.Add(hbox, 0, wx.EXPAND | wx.ALIGN_CENTER)
+
+ panel.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
+ panel.Bind(wx.EVT_KEY_UP, self._on_key_up)
+ panel.Bind(wx.EVT_KILL_FOCUS, self._on_kill_focus)
+ panel.SetFocus()
+
+ if 1 and not(no_gui):
+ rx_fft = fftsink2.fft_sink_c(panel, title="Rx Input", fft_size=512,
+ sample_rate=self.rxpath.if_rate,
+ ref_level=80, y_per_div=20)
+ self.connect (self.rxpath.u, rx_fft)
+ vbox.Add (rx_fft.win, 1, wx.EXPAND)
+
+ if 1 and not(no_gui):
+ rx_fft = fftsink2.fft_sink_c(panel, title="Post s/w Resampler",
+ fft_size=512, sample_rate=self.rxpath.quad_rate,
+ ref_level=80, y_per_div=20)
+ self.connect (self.rxpath.resamp, rx_fft)
+ vbox.Add (rx_fft.win, 1, wx.EXPAND)
+
+ if 0 and not(no_gui):
+ foo = scopesink2.scope_sink_f(panel, title="Squelch",
+ sample_rate=32000)
+ self.connect (self.rxpath.fmrx.div, (foo,0))
+ self.connect (self.rxpath.fmrx.gate, (foo,1))
+ self.connect (self.rxpath.fmrx.squelch_lpf, (foo,2))
+ vbox.Add (foo.win, 1, wx.EXPAND)
+
+ if 0 and not(no_gui):
+ tx_fft = fftsink2.fft_sink_c(panel, title="Tx Output",
+ fft_size=512, sample_rate=self.txpath.usrp_rate)
+ self.connect (self.txpath.amp, tx_fft)
+ vbox.Add (tx_fft.win, 1, wx.EXPAND)
+
+
+ # add control area at the bottom
+
+ self.myform = myform = form.form()
+
+ # first row
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0, 0)
+ myform['freq'] = form.float_field(
+ parent=panel, sizer=hbox, label="Freq", weight=1,
+ callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
+
+ hbox.Add((5,0), 0, 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+
+ # second row
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ myform['volume'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Volume",
+ weight=3, range=self.rxpath.volume_range(),
+ callback=self.set_volume)
+ hbox.Add((5,0), 0)
+ myform['squelch'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Squelch",
+ weight=3, range=self.rxpath.squelch_range(),
+ callback=self.set_squelch)
+
+ g = self.rxpath.u.get_gain_range()
+ hbox.Add((5,0), 0)
+ myform['rx_gain'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Rx Gain",
+ weight=3, range=(g.start(), g.stop(), g.step()),
+ callback=self.set_rx_gain)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+
+ self._build_subpanel(vbox)
+
+ def _build_subpanel(self, vbox_arg):
+ # build a secondary information panel (sometimes hidden)
+
+ # FIXME figure out how to have this be a subpanel that is always
+ # created, but has its visibility controlled by foo.Show(True/False)
+
+ #if not(self.show_debug_info):
+ # return
+
+ panel = self.panel
+ vbox = vbox_arg
+ myform = self.myform
+
+ #panel = wx.Panel(self.panel, -1)
+ #vbox = wx.BoxSizer(wx.VERTICAL)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+ #myform['decim'] = form.static_float_field(
+ # parent=panel, sizer=hbox, label="Decim")
+
+ #hbox.Add((5,0), 1)
+ #myform['fs@usb'] = form.static_float_field(
+ # parent=panel, sizer=hbox, label="Fs@USB")
+
+ #hbox.Add((5,0), 1)
+ #myform['dbname'] = form.static_text_field(
+ # parent=panel, sizer=hbox)
+
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+
+ def _set_status_msg(self, msg, which=0):
+ self.frame.GetStatusBar().SetStatusText(msg, which)
+
+ def _on_key_down(self, evt):
+ # print "key_down:", evt.m_keyCode
+ if evt.m_keyCode == wx.WXK_SPACE and not(self.space_bar_pressed):
+ self.space_bar_pressed = True
+ self.set_transmit(True)
+
+ def _on_key_up(self, evt):
+ # print "key_up", evt.m_keyCode
+ if evt.m_keyCode == wx.WXK_SPACE:
+ self.space_bar_pressed = False
+ self.set_transmit(False)
+
+ def _on_kill_focus(self, evt):
+ # if we lose the keyboard focus, turn off the transmitter
+ self.space_bar_pressed = False
+ self.set_transmit(False)
+
+
+# ////////////////////////////////////////////////////////////////////////
+# Transmit Path
+# ////////////////////////////////////////////////////////////////////////
+
+class transmit_path(gr.hier_block2):
+ def __init__(self, args, spec, antenna, gain, audio_input):
+ gr.hier_block2.__init__(self, "transmit_path",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(0, 0, 0)) # Output signature
+
+ self.u = uhd.usrp_sink(device_addr=args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(spec):
+ self.u.set_subdev_spec(spec, 0)
+
+ # Set the antenna
+ if(antenna):
+ self.u.set_antenna(antenna, 0)
+
+ self.if_rate = 320e3
+ self.audio_rate = 32e3
+
+ self.u.set_samp_rate(self.if_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ self.audio_gain = 10
+ self.normal_gain = 32000
+
+ self.audio = audio.source(int(self.audio_rate), audio_input)
+ self.audio_amp = gr.multiply_const_ff(self.audio_gain)
+
+ lpf = gr.firdes.low_pass (1, # gain
+ self.audio_rate, # sampling rate
+ 3800, # low pass cutoff freq
+ 300, # width of trans. band
+ gr.firdes.WIN_HANN) # filter type
+
+ hpf = gr.firdes.high_pass (1, # gain
+ self.audio_rate, # sampling rate
+ 325, # low pass cutoff freq
+ 50, # width of trans. band
+ gr.firdes.WIN_HANN) # filter type
+
+ audio_taps = convolve(array(lpf),array(hpf))
+ self.audio_filt = gr.fir_filter_fff(1,audio_taps)
+
+ self.pl = blks2.ctcss_gen_f(self.audio_rate,123.0)
+ self.add_pl = gr.add_ff()
+ self.connect(self.pl,(self.add_pl,1))
+
+ self.fmtx = blks2.nbfm_tx(self.audio_rate, self.if_rate)
+ self.amp = gr.multiply_const_cc (self.normal_gain)
+
+ rrate = dev_rate / self.if_rate
+ self.resamp = blks2.pfb_arb_resampler_ccf(rrate)
+
+ self.connect(self.audio, self.audio_amp, self.audio_filt,
+ (self.add_pl,0), self.fmtx, self.amp,
+ self.resamp, self.u)
+
+ if gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ gain = float(g.start() + g.stop())/2.0
+
+ self.set_gain(gain)
+
+ self.set_enable(False)
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+ """
+ r = self.u.set_center_freq(target_freq)
+ if r:
+ return True
+ return False
+
+ def set_gain(self, gain):
+ self.gain = gain
+ self.u.set_gain(gain)
+
+ def set_enable(self, enable):
+ if enable:
+ self.amp.set_k (self.normal_gain)
+ else:
+ self.amp.set_k (0)
+
+
+
+# ////////////////////////////////////////////////////////////////////////
+# Receive Path
+# ////////////////////////////////////////////////////////////////////////
+
+class receive_path(gr.hier_block2):
+ def __init__(self, args, gain, audio_output):
+ gr.hier_block2.__init__(self, "receive_path",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(0, 0, 0)) # Output signature
+
+ self.u = uhd.usrp_source(device_addr=args,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ self.if_rate = 256e3
+ self.quad_rate = 64e3
+ self.audio_rate = 32e3
+
+ self.u.set_samp_rate(self.if_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ # Create filter to get actual channel we want
+ nfilts = 32
+ chan_coeffs = gr.firdes.low_pass (nfilts, # gain
+ nfilts*dev_rate, # sampling rate
+ 13e3, # low pass cutoff freq
+ 4e3, # width of trans. band
+ gr.firdes.WIN_HANN) # filter type
+
+ rrate = self.quad_rate / dev_rate
+ self.resamp = blks2.pfb_arb_resampler_ccf(rrate, chan_coeffs, nfilts)
+
+ # instantiate the guts of the single channel receiver
+ self.fmrx = blks2.nbfm_rx(self.audio_rate, self.quad_rate)
+
+ # standard squelch block
+ self.squelch = blks2.standard_squelch(self.audio_rate)
+
+ # audio gain / mute block
+ self._audio_gain = gr.multiply_const_ff(1.0)
+
+ # sound card as final sink
+ audio_sink = audio.sink (int(self.audio_rate), audio_output)
+
+ # now wire it all together
+ self.connect (self.u, self.resamp, self.fmrx, self.squelch,
+ self._audio_gain, audio_sink)
+
+ if gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ gain = float(g.start() + g.stop())/2.0
+
+ self.enabled = True
+ self.set_gain(gain)
+ v = self.volume_range()
+ self.set_volume((v[0]+v[1])/2)
+ s = self.squelch_range()
+ self.set_squelch((s[0]+s[1])/2)
+
+ # Set the subdevice spec
+ if(spec):
+ self.u.set_subdev_spec(spec, 0)
+
+ # Set the antenna
+ if(antenna):
+ self.u.set_antenna(antenna, 0)
+
+ def volume_range(self):
+ return (-20.0, 0.0, 0.5)
+
+ def set_volume (self, vol):
+ g = self.volume_range()
+ self.volume = max(g[0], min(g[1], vol))
+ self._update_audio_gain()
+
+ def set_enable(self, enable):
+ self.enabled = enable
+ self._update_audio_gain()
+
+ def _update_audio_gain(self):
+ if self.enabled:
+ self._audio_gain.set_k(10**(self.volume/10))
+ else:
+ self._audio_gain.set_k(0)
+
+ def squelch_range(self):
+ return self.squelch.squelch_range()
+
+ def set_squelch(self, threshold):
+ print "SQL =", threshold
+ self.squelch.set_threshold(threshold)
+
+ def threshold(self):
+ return self.squelch.threshold()
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+ """
+ r = self.u.set_center_freq(target_freq)
+ if r:
+ return True
+ return False
+
+ def set_gain(self, gain):
+ self.gain = gain
+ self.u.set_gain(gain)
+
+
+# ////////////////////////////////////////////////////////////////////////
+# Main
+# ////////////////////////////////////////////////////////////////////////
+
+def main():
+ app = stdgui2.stdapp(ptt_block, "NBFM Push to Talk")
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
diff --git a/gr-uhd/examples/python/usrp_nbfm_rcv.py b/gr-uhd/examples/python/usrp_nbfm_rcv.py
new file mode 100755
index 000000000..571abe8c9
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_nbfm_rcv.py
@@ -0,0 +1,380 @@
+#!/usr/bin/env python
+#
+# Copyright 2005,2007,2011 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.
+#
+
+from gnuradio import gr, audio, blks2, uhd
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import slider, powermate
+from gnuradio.wxgui import stdgui2, fftsink2, form
+from optparse import OptionParser
+import sys
+import math
+import wx
+
+#////////////////////////////////////////////////////////////////////////
+# Control Stuff
+#////////////////////////////////////////////////////////////////////////
+
+class my_top_block (stdgui2.std_top_block):
+ def __init__(self,frame,panel,vbox,argv):
+ stdgui2.std_top_block.__init__ (self,frame,panel,vbox,argv)
+
+ parser=OptionParser(option_class=eng_option)
+ 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("-f", "--freq", type="eng_float", default=146.585e6,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-V", "--volume", type="eng_float", default=None,
+ help="set volume (default is midpoint)")
+ parser.add_option("-O", "--audio-output", type="string", default="",
+ help="pcm device name. E.g., hw:0,0 or surround51 or /dev/dsp")
+ parser.add_option("-N", "--no-gui", action="store_true", default=False)
+
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+ if options.freq < 1e6:
+ options.freq *= 1e6
+
+ self.frame = frame
+ self.panel = panel
+
+ self.state = "FREQ"
+ self.freq = 0
+ self.freq_step = 25e3
+
+ self.rxpath = receive_path(options.args, options.spec, options.antenna,
+ options.gain, options.audio_output)
+ self.connect(self.rxpath)
+
+ self._build_gui(vbox, options.no_gui)
+
+ # set initial values
+
+ if options.volume is not None:
+ self.set_volume(options.volume)
+
+ if not(self.set_freq(options.freq)):
+ self._set_status_msg("Failed to set initial frequency")
+
+ self.set_gain(self.rxpath.gain) # update gui
+ self.set_volume(self.rxpath.volume) # update gui
+ self.set_squelch(self.rxpath.threshold()) # update gui
+
+
+ def _set_status_msg(self, msg, which=0):
+ self.frame.GetStatusBar().SetStatusText(msg, which)
+
+
+ def _build_gui(self, vbox, no_gui):
+
+ def _form_set_freq(kv):
+ return self.set_freq(kv['freq'])
+
+
+ self.src_fft = None
+ if 0 and not(no_gui):
+ self.src_fft = fftsink2.fft_sink_c(self.panel,
+ title="Data from USRP",
+ fft_size=512,
+ sample_rate=self.rxpath.if_rate,
+ ref_scale=32768.0,
+ ref_level=0,
+ y_per_div=10,
+ y_divs=12)
+ self.connect (self.rxpath.u, self.src_fft)
+ vbox.Add (self.src_fft.win, 4, wx.EXPAND)
+ if 1 and not(no_gui):
+ rx_fft = fftsink2.fft_sink_c(self.panel,
+ title="Post s/w Resampling",
+ fft_size=512,
+ sample_rate=self.rxpath.quad_rate,
+ ref_level=80,
+ y_per_div=20)
+ self.connect (self.rxpath.resamp, rx_fft)
+ vbox.Add (rx_fft.win, 4, wx.EXPAND)
+
+ if 1 and not(no_gui):
+ post_deemph_fft = fftsink2.fft_sink_f(self.panel,
+ title="Post Deemph",
+ fft_size=512,
+ sample_rate=self.rxpath.audio_rate,
+ y_per_div=10,
+ ref_level=-40)
+ self.connect (self.rxpath.fmrx.deemph, post_deemph_fft)
+ vbox.Add (post_deemph_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ post_filt_fft = fftsink2.fft_sink_f(self.panel,
+ title="Post Filter",
+ fft_size=512,
+ sample_rate=audio_rate,
+ y_per_div=10,
+ ref_level=-40)
+ self.connect (self.guts.audio_filter, post_filt)
+ vbox.Add (fft_win4, 4, wx.EXPAND)
+
+ # control area form at bottom
+ self.myform = myform = form.form()
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+ myform['freq'] = form.float_field(
+ parent=self.panel, sizer=hbox, label="Freq", weight=1,
+ callback=myform.check_input_and_call(_form_set_freq,
+ self._set_status_msg))
+
+ #hbox.Add((5,0), 0)
+ #myform['freq_slider'] = \
+ # form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3,
+ # range=(87.9e6, 108.1e6, 0.1e6),
+ # callback=self.set_freq)
+
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+
+ myform['volume'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Volume",
+ weight=3, range=self.volume_range(),
+ callback=self.set_volume)
+ hbox.Add((5,0), 0)
+ myform['squelch'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Squelch",
+ weight=3, range=self.rxpath.squelch_range(),
+ callback=self.set_squelch)
+ g = self.rxpath.u.get_gain_range()
+ hbox.Add((5,0), 0)
+ myform['gain'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Gain",
+ weight=3, range=(g.start(), g.stop(), g.step()),
+ callback=self.set_gain)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ try:
+ self.knob = powermate.powermate(self.frame)
+ self.rot = 0
+ powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate)
+ powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button)
+ except:
+ print "FYI: No Powermate or Contour Knob found"
+
+
+ def on_rotate (self, event):
+ self.rot += event.delta
+ if (self.state == "FREQ"):
+ if self.rot >= 3:
+ self.set_freq(self.freq + self.freq_step)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_freq(self.freq - self.freq_step)
+ self.rot += 3
+ else:
+ step = self.volume_range()[2]
+ if self.rot >= 3:
+ self.set_volume(self.rxpath.volume + step)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_volume(self.rxpath.volume - step)
+ self.rot += 3
+
+ def on_button (self, event):
+ if event.value == 0: # button up
+ return
+ self.rot = 0
+ if self.state == "FREQ":
+ self.state = "VOL"
+ else:
+ self.state = "FREQ"
+ self.update_status_bar ()
+
+
+ def set_squelch(self, threshold_in_db):
+ self.rxpath.set_squelch(threshold_in_db)
+ self.myform['squelch'].set_value(self.rxpath.threshold())
+
+ def set_volume (self, vol):
+ self.rxpath.set_volume(vol)
+ self.myform['volume'].set_value(self.rxpath.volume)
+ self.update_status_bar ()
+
+ def set_freq(self, target_freq):
+ r = self.rxpath.set_freq(target_freq)
+ if r:
+ self.freq = target_freq
+ self.myform['freq'].set_value(target_freq) # update displayed value
+ #self.myform['freq_slider'].set_value(target_freq) # update displayed value
+ self.update_status_bar()
+ self._set_status_msg("OK", 0)
+ return True
+
+ self._set_status_msg("Failed", 0)
+ return False
+
+ def set_gain(self, gain):
+ self.myform['gain'].set_value(gain) # update displayed value
+ self.rxpath.set_gain(gain)
+
+ def update_status_bar (self):
+ msg = "Volume:%r Setting:%s" % (self.rxpath.volume, self.state)
+ self._set_status_msg(msg, 1)
+ if self.src_fft:
+ self.src_fft.set_baseband_freq(self.freq)
+
+ def volume_range(self):
+ return (-20.0, 0.0, 0.5)
+
+
+#////////////////////////////////////////////////////////////////////////
+# Receive Path
+#////////////////////////////////////////////////////////////////////////
+
+USE_SIMPLE_SQUELCH = False
+
+class receive_path(gr.hier_block2):
+ def __init__(self, args, spec, antenna, gain, audio_output):
+ gr.hier_block2.__init__(self, "receive_path",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(0, 0, 0)) # Output signature
+
+ self.u = uhd.usrp_source(device_addr=args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(spec):
+ self.u.set_subdev_spec(spec, 0)
+
+ # Set the antenna
+ if(antenna):
+ self.u.set_antenna(antenna, 0)
+
+ self.if_rate = 256e3
+ self.quad_rate = 64e3
+ self.audio_rate = 32e3
+
+ self.u.set_samp_rate(self.if_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ # Create filter to get actual channel we want
+ nfilts = 32
+ chan_coeffs = gr.firdes.low_pass (nfilts, # gain
+ nfilts*dev_rate, # sampling rate
+ 8e3, # low pass cutoff freq
+ 2e3, # width of trans. band
+ gr.firdes.WIN_HANN) # filter type
+ rrate = self.quad_rate / dev_rate
+ self.resamp = blks2.pfb_arb_resampler_ccf(rrate, chan_coeffs, nfilts)
+
+ if USE_SIMPLE_SQUELCH:
+ self.squelch = gr.simple_squelch_cc(20)
+ else:
+ self.squelch = blks2.standard_squelch(self.audio_rate)
+
+ # instantiate the guts of the single channel receiver
+ self.fmrx = blks2.nbfm_rx(self.audio_rate, self.quad_rate)
+
+ # audio gain / mute block
+ self._audio_gain = gr.multiply_const_ff(1.0)
+
+ # sound card as final sink
+ audio_sink = audio.sink (int(self.audio_rate), audio_output)
+
+ # now wire it all together
+ if USE_SIMPLE_SQUELCH:
+ self.connect (self.u, self.resamp, self.squelch, self.fmrx,
+ self._audio_gain, audio_sink)
+ else:
+ self.connect (self.u, self.resamp, self.fmrx, self.squelch,
+ self._audio_gain, audio_sink)
+
+ if gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ gain = float(g.start()+g.stop())/2
+
+ self.set_gain(gain)
+
+ v = self.volume_range()
+ self.set_volume((v[0]+v[1])/2)
+
+ s = self.squelch_range()
+ self.set_squelch((s[0]+s[1])/2)
+
+ def volume_range(self):
+ return (-20.0, 0.0, 0.5)
+
+ def set_volume (self, vol):
+ g = self.volume_range()
+ self.volume = max(g[0], min(g[1], vol))
+ self._update_audio_gain()
+
+ def _update_audio_gain(self):
+ self._audio_gain.set_k(10**(self.volume/10))
+
+ def squelch_range(self):
+ r = self.squelch.squelch_range()
+ #print "squelch_range: ", r
+ return r
+
+ def set_squelch(self, threshold):
+ #print "SQL =", threshold
+ self.squelch.set_threshold(threshold)
+
+ def threshold(self):
+ t = self.squelch.threshold()
+ #print "t =", t
+ return t
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+ """
+
+ r = self.u.set_center_freq(target_freq)
+ if r:
+ return True
+ return False
+
+ def set_gain(self, gain):
+ self.gain = gain
+ self.u.set_gain(gain)
+
+
+# ////////////////////////////////////////////////////////////////////////
+# Main
+# ////////////////////////////////////////////////////////////////////////
+
+if __name__ == '__main__':
+ app = stdgui2.stdapp (my_top_block, "USRP NBFM RX")
+ app.MainLoop ()
diff --git a/gr-uhd/examples/python/usrp_spectrum_sense.py b/gr-uhd/examples/python/usrp_spectrum_sense.py
new file mode 100755
index 000000000..32980adbf
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_spectrum_sense.py
@@ -0,0 +1,258 @@
+#!/usr/bin/env python
+#
+# Copyright 2005,2007,2011 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.
+#
+
+from gnuradio import gr, eng_notation, window
+from gnuradio import audio
+from gnuradio import uhd
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+import math
+import struct
+import threading
+
+sys.stderr.write("Warning: this may have issues on some machines+Python version combinations to seg fault due to the callback in bin_statitics.\n\n")
+
+class ThreadClass(threading.Thread):
+ def run(self):
+ return
+
+class tune(gr.feval_dd):
+ """
+ This class allows C++ code to callback into python.
+ """
+ def __init__(self, tb):
+ gr.feval_dd.__init__(self)
+ self.tb = tb
+
+ def eval(self, ignore):
+ """
+ This method is called from gr.bin_statistics_f when it wants
+ to change the center frequency. This method tunes the front
+ end to the new center frequency, and returns the new frequency
+ as its result.
+ """
+
+ try:
+ # We use this try block so that if something goes wrong
+ # from here down, at least we'll have a prayer of knowing
+ # what went wrong. Without this, you get a very
+ # mysterious:
+ #
+ # terminate called after throwing an instance of
+ # 'Swig::DirectorMethodException' Aborted
+ #
+ # message on stderr. Not exactly helpful ;)
+
+ new_freq = self.tb.set_next_freq()
+ return new_freq
+
+ except Exception, e:
+ print "tune: Exception: ", e
+
+
+class parse_msg(object):
+ def __init__(self, msg):
+ self.center_freq = msg.arg1()
+ self.vlen = int(msg.arg2())
+ assert(msg.length() == self.vlen * gr.sizeof_float)
+
+ # FIXME consider using NumPy array
+ t = msg.to_string()
+ self.raw_data = t
+ self.data = struct.unpack('%df' % (self.vlen,), t)
+
+
+class my_top_block(gr.top_block):
+
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ usage = "usage: %prog [options] min_freq max_freq"
+ parser = OptionParser(option_class=eng_option, usage=usage)
+ parser.add_option("-a", "--args", type="string", default="",
+ help="UHD device 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 [default=%default]")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("", "--tune-delay", type="eng_float",
+ default=1e-3, metavar="SECS",
+ help="time to delay (in seconds) after changing frequency [default=%default]")
+ parser.add_option("", "--dwell-delay", type="eng_float",
+ default=10e-3, metavar="SECS",
+ help="time to dwell (in seconds) at a given frequncy [default=%default]")
+ parser.add_option("-F", "--fft-size", type="int", default=256,
+ help="specify number of FFT bins [default=%default]")
+ parser.add_option("", "--real-time", action="store_true", default=False,
+ help="Attempt to enable real-time scheduling")
+
+ (options, args) = parser.parse_args()
+ if len(args) != 2:
+ parser.print_help()
+ sys.exit(1)
+
+ self.min_freq = eng_notation.str_to_num(args[0])
+ self.max_freq = eng_notation.str_to_num(args[1])
+
+ if self.min_freq > self.max_freq:
+ # swap them
+ self.min_freq, self.max_freq = self.max_freq, self.min_freq
+
+ self.fft_size = options.fft_size
+
+ if not options.real_time:
+ realtime = False
+ else:
+ # Attempt to enable realtime scheduling
+ r = gr.enable_realtime_scheduling()
+ if r == gr.RT_OK:
+ realtime = True
+ else:
+ realtime = False
+ print "Note: failed to enable realtime scheduling"
+
+ # build graph
+ self.u = uhd.usrp_source(device_addr=options.args,
+ stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ usrp_rate = options.samp_rate
+ self.u.set_samp_rate(usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ s2v = gr.stream_to_vector(gr.sizeof_gr_complex, self.fft_size)
+
+ mywindow = window.blackmanharris(self.fft_size)
+ fft = gr.fft_vcc(self.fft_size, True, mywindow)
+ power = 0
+ for tap in mywindow:
+ power += tap*tap
+
+ c2mag = gr.complex_to_mag_squared(self.fft_size)
+
+ # FIXME the log10 primitive is dog slow
+ log = gr.nlog10_ff(10, self.fft_size,
+ -20*math.log10(self.fft_size)-10*math.log10(power/self.fft_size))
+
+ # Set the freq_step to 75% of the actual data throughput.
+ # This allows us to discard the bins on both ends of the spectrum.
+
+ self.freq_step = 0.75 * usrp_rate
+ self.min_center_freq = self.min_freq + self.freq_step/2
+ nsteps = math.ceil((self.max_freq - self.min_freq) / self.freq_step)
+ self.max_center_freq = self.min_center_freq + (nsteps * self.freq_step)
+
+ self.next_freq = self.min_center_freq
+
+ tune_delay = max(0, int(round(options.tune_delay * usrp_rate / self.fft_size))) # in fft_frames
+ dwell_delay = max(1, int(round(options.dwell_delay * usrp_rate / self.fft_size))) # in fft_frames
+
+ self.msgq = gr.msg_queue(16)
+ self._tune_callback = tune(self) # hang on to this to keep it from being GC'd
+ stats = gr.bin_statistics_f(self.fft_size, self.msgq,
+ self._tune_callback, tune_delay,
+ dwell_delay)
+
+ # FIXME leave out the log10 until we speed it up
+ #self.connect(self.u, s2v, fft, c2mag, log, stats)
+ self.connect(self.u, s2v, fft, c2mag, stats)
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2.0
+
+ self.set_gain(options.gain)
+ print "gain =", options.gain
+
+ def set_next_freq(self):
+ target_freq = self.next_freq
+ self.next_freq = self.next_freq + self.freq_step
+ if self.next_freq >= self.max_center_freq:
+ self.next_freq = self.min_center_freq
+
+ if not self.set_freq(target_freq):
+ print "Failed to set frequency to", target_freq
+ sys.exit(1)
+
+ return target_freq
+
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+ """
+ r = self.u.set_center_freq(target_freq)
+ if r:
+ return True
+
+ return False
+
+ def set_gain(self, gain):
+ self.u.set_gain(gain)
+
+
+def main_loop(tb):
+ while 1:
+
+ # Get the next message sent from the C++ code (blocking call).
+ # It contains the center frequency and the mag squared of the fft
+ m = parse_msg(tb.msgq.delete_head())
+
+ # Print center freq so we know that something is happening...
+ print m.center_freq
+
+ # FIXME do something useful with the data...
+
+ # m.data are the mag_squared of the fft output (they are in the
+ # standard order. I.e., bin 0 == DC.)
+ # You'll probably want to do the equivalent of "fftshift" on them
+ # m.raw_data is a string that contains the binary floats.
+ # You could write this as binary to a file.
+
+
+if __name__ == '__main__':
+ t = ThreadClass()
+ t.start()
+
+ tb = my_top_block()
+ try:
+ tb.start()
+ main_loop(tb)
+
+ except KeyboardInterrupt:
+ pass
diff --git a/gr-uhd/examples/python/usrp_tv_rcv.py b/gr-uhd/examples/python/usrp_tv_rcv.py
new file mode 100755
index 000000000..b49a5ea71
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_tv_rcv.py
@@ -0,0 +1,443 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 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.
+#
+
+"""
+Realtime capture and display of analog Tv stations.
+
+Can also use a file as source or sink
+
+When you use an output file you can show the results frame-by-frame
+using ImageMagick
+
+When you want to use the realtime sdl display window you must first
+install gr-video-sdl.
+
+When you use a file source, instead of the usrp, make sure you
+capture interleaved shorts. (Use usrp_rx_file.py, or use
+usrp_rx_cfile.py --output-shorts if you have a recent enough
+usrp_rx_cfile.py)
+
+There is no synchronisation yet. The sync blocks are in development
+but not yet in cvs.
+"""
+
+from gnuradio import gr
+try:
+ from gnuradio import video_sdl
+except:
+ print "FYI: gr-video-sdl is not installed"
+ print "realtime SDL video output window will not be available"
+from gnuradio import uhd
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import slider, powermate
+from gnuradio.wxgui import stdgui2, fftsink2, form
+from optparse import OptionParser
+import sys
+import wx
+
+
+class tv_rx_block (stdgui2.std_top_block):
+ def __init__(self,frame,panel,vbox,argv):
+ stdgui2.std_top_block.__init__ (self,frame,panel,vbox,argv)
+
+ usage="%prog: [options] [input_filename]. \n If you don't specify an input filename the usrp will be used as source\n " \
+ "Make sure your input capture file containes interleaved shorts not complex floats"
+ 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")
+ parser.add_option("-f", "--freq", type="eng_float", default=519.25e6,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-c", "--contrast", type="eng_float", default=1.0,
+ help="set contrast (default is 1.0)")
+ parser.add_option("-b", "--brightness", type="eng_float", default=0.0,
+ help="set brightness (default is 0)")
+ parser.add_option("-p", "--pal", action="store_true", default=False,
+ help="PAL video format (this is the default)")
+ parser.add_option("-n", "--ntsc", action="store_true", default=False,
+ help="NTSC video format")
+ parser.add_option("-o", "--out-filename", type="string", default="sdl",
+ help="For example out_raw_uchar.gray. If you don't specify an output filename you will get a video_sink_sdl realtime output window. You then need to have gr-video-sdl installed)")
+ parser.add_option("-r", "--repeat", action="store_false", default=True,
+ help="repeat file in a loop")
+ parser.add_option("", "--freq-min", type="eng_float", default=50.25e6,
+ help="Set a minimum frequency [default=%default]")
+ parser.add_option("", "--freq-max", type="eng_float", default=900.25e6,
+ help="Set a maximum frequency [default=%default]")
+
+ (options, args) = parser.parse_args()
+ if not ((len(args) == 1) or (len(args) == 0)):
+ parser.print_help()
+ sys.exit(1)
+
+ if len(args) == 1:
+ filename = args[0]
+ else:
+ filename = None
+
+ self.frame = frame
+ self.panel = panel
+
+ self.contrast = options.contrast
+ self.brightness = options.brightness
+ self.state = "FREQ"
+ self.freq = 0
+
+ self.tv_freq_min = options.freq_min
+ self.tv_freq_max = options.freq_max
+
+ # build graph
+ self.u=None
+
+ if not (options.out_filename=="sdl"):
+ options.repeat=False
+
+ usrp_rate = options.samp_rate
+
+ if not ((filename is None) or (filename=="usrp")):
+ # file is data source
+ self.filesource = gr.file_source(gr.sizeof_short,filename,options.repeat)
+ self.istoc = gr.interleaved_short_to_complex()
+ self.connect(self.filesource,self.istoc)
+ self.src=self.istoc
+
+ options.gain=0.0
+ self.gain=0.0
+
+ else: # use a UHD device
+ self.u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ self.u.set_samp_rate(usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2.0
+
+ self.src=self.u
+
+ self.gain = options.gain
+
+ f2uc=gr.float_to_uchar()
+
+ # sdl window as final sink
+ if not (options.pal or options.ntsc):
+ options.pal=True #set default to PAL
+
+ if options.pal:
+ lines_per_frame=625.0
+ frames_per_sec=25.0
+ show_width=768
+
+ elif options.ntsc:
+ lines_per_frame=525.0
+ frames_per_sec=29.97002997
+ show_width=640
+
+ width=int(usrp_rate/(lines_per_frame*frames_per_sec))
+ height=int(lines_per_frame)
+
+ if (options.out_filename=="sdl"):
+ #Here comes the tv screen, you have to build and install
+ #gr-video-sdl for this (subproject of gnuradio, only in cvs
+ #for now)
+ try:
+ video_sink = video_sdl.sink_uc ( frames_per_sec, width, height, 0,
+ show_width, height)
+ except:
+ print "gr-video-sdl is not installed"
+ print "realtime \"sdl\" video output window is not available"
+ raise SystemExit, 1
+ self.dst=video_sink
+ else:
+ print "You can use the imagemagick display tool to show the resulting imagesequence"
+ print "use the following line to show the demodulated TV-signal:"
+ print "display -depth 8 -size " +str(width)+ "x" + str(height) \
+ + " gray:" + options.out_filename
+ print "(Use the spacebar to advance to next frames)"
+ options.repeat=False
+ file_sink=gr.file_sink(gr.sizeof_char, options.out_filename)
+ self.dst =file_sink
+
+ self.agc=gr.agc_cc(1e-7,1.0,1.0) #1e-7
+ self.am_demod = gr.complex_to_mag ()
+ self.set_blacklevel=gr.add_const_ff(0.0)
+ self.invert_and_scale = gr.multiply_const_ff (0.0) #-self.contrast *128.0*255.0/(200.0)
+
+ # now wire it all together
+ #sample_rate=options.width*options.height*options.framerate
+
+ process_type='do_no_sync'
+ if process_type=='do_no_sync':
+ self.connect (self.src, self.agc,self.am_demod,
+ self.invert_and_scale, self.set_blacklevel,
+ f2uc,self.dst)
+ elif process_type=='do_tv_sync_adv':
+ #defaults: gr.tv_sync_adv (double sampling_freq, unsigned
+ #int tv_format,bool output_active_video_only=false, bool
+ #do_invert=false, double wanted_black_level=0.0, double
+ #wanted_white_level=255.0, double avg_alpha=0.1, double
+ #initial_gain=1.0, double initial_offset=0.0,bool
+ #debug=false)
+
+ #note, this block is not yet in cvs
+ self.tv_sync_adv=gr.tv_sync_adv(usrp_rate, 0, False, False,
+ 0.0, 255.0, 0.01, 1.0, 0.0, False)
+ self.connect (self.src, self.am_demod, self.invert_and_scale,
+ self.tv_sync_adv, s2f, f2uc, self.dst)
+
+ elif process_type=='do_nullsink':
+ #self.connect (self.src, self.am_demod,self.invert_and_scale,f2uc,video_sink)
+ c2r=gr.complex_to_real()
+ nullsink=gr.null_sink(gr.sizeof_float)
+ self.connect (self.src, c2r,nullsink) #video_sink)
+ elif process_type=='do_tv_sync_corr':
+ frame_size=width*height #int(usrp_rate/25.0)
+ nframes=10# 32
+ search_window=20*nframes
+ debug=False
+ video_alpha=0.3 #0.1
+ corr_alpha=0.3
+
+ #Note: this block is not yet in cvs
+ tv_corr=gr.tv_correlator_ff(frame_size,nframes, search_window,
+ video_alpha, corr_alpha,debug)
+ shift=gr.add_const_ff(-0.7)
+
+ self.connect (self.src, self.agc, self.am_demod, tv_corr,
+ self.invert_and_scale, self.set_blacklevel,
+ f2uc, self.dst)
+ else: # process_type=='do_test_image':
+ src_vertical_bars = gr.sig_source_f (usrp_rate, gr.GR_SIN_WAVE,
+ 10.0 *usrp_rate/320, 255,128)
+ self.connect(src_vertical_bars, f2uc, self.dst)
+
+ self._build_gui(vbox, usrp_rate, usrp_rate, usrp_rate)
+
+
+ frange = self.u.get_freq_range()
+ if(frange.start() > self.tv_freq_max or frange.stop() < self.tv_freq_min):
+ sys.stderr.write("Radio does not support required frequency range.\n")
+ sys.exit(1)
+ if(options.freq < self.tv_freq_min or options.freq > self.tv_freq_max):
+ sys.stderr.write("Requested frequency is outside of required frequency range.\n")
+ sys.exit(1)
+
+ # set initial values
+ self.set_gain(options.gain)
+ self.set_contrast(self.contrast)
+ self.set_brightness(options.brightness)
+ if not(self.set_freq(options.freq)):
+ self._set_status_msg("Failed to set initial frequency")
+
+
+ def _set_status_msg(self, msg, which=0):
+ self.frame.GetStatusBar().SetStatusText(msg, which)
+
+
+ def _build_gui(self, vbox, usrp_rate, demod_rate, audio_rate):
+
+ def _form_set_freq(kv):
+ return self.set_freq(kv['freq'])
+
+
+ if 0:
+ self.src_fft = fftsink.fft_sink_c (self, self.panel, title="Data from USRP",
+ fft_size=512, sample_rate=usrp_rate)
+ self.connect (self.src, self.src_fft)
+ vbox.Add (self.src_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ post_demod_fft = fftsink.fft_sink_f (self, self.panel, title="Post Demod",
+ fft_size=512, sample_rate=demod_rate,
+ y_per_div=10, ref_level=-40)
+ self.connect (self.am_demod, post_demod_fft)
+ vbox.Add (post_demod_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ post_filt_fft = fftsink.fft_sink_f (self, self.panel, title="Post Filter",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=-40)
+ self.connect (self.set_blacklevel, post_filt)
+ vbox.Add (fft_win4, 4, wx.EXPAND)
+
+
+ # control area form at bottom
+ self.myform = myform = form.form()
+
+ if not (self.u is None):
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+ myform['freq'] = form.float_field(
+ parent=self.panel, sizer=hbox, label="Freq", weight=1,
+ callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
+
+ hbox.Add((5,0), 0)
+ myform['freq_slider'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3,
+ range=(self.tv_freq_min, self.tv_freq_max, 0.25e6),
+ callback=self.set_freq)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+
+ myform['contrast'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Contrast",
+ weight=3, range=(-2.0, 2.0, 0.1),
+ callback=self.set_contrast)
+ hbox.Add((5,0), 1)
+
+ myform['brightness'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Brightness",
+ weight=3, range=(-255.0, 255.0, 1.0),
+ callback=self.set_brightness)
+ hbox.Add((5,0), 0)
+
+ if not (self.u is None):
+ g = self.u.get_gain_range()
+ myform['gain'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Gain",
+ weight=3, range=(g.start(), g.stop(), g.step()),
+ callback=self.set_gain)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ try:
+ self.knob = powermate.powermate(self.frame)
+ self.rot = 0
+ powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate)
+ powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button)
+ except:
+ print "FYI: No Powermate or Contour Knob found"
+
+
+ def on_rotate (self, event):
+ self.rot += event.delta
+ if (self.state == "FREQ"):
+ if self.rot >= 3:
+ self.set_freq(self.freq + .1e6)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_freq(self.freq - .1e6)
+ self.rot += 3
+ elif (self.state == "CONTRAST"):
+ step = 0.1
+ if self.rot >= 3:
+ self.set_contrast(self.contrast + step)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_contrast(self.contrast - step)
+ self.rot += 3
+ else:
+ step = 1
+ if self.rot >= 3:
+ self.set_brightness(self.brightness + step)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_brightness(self.brightness - step)
+ self.rot += 3
+
+ def on_button (self, event):
+ if event.value == 0: # button up
+ return
+ self.rot = 0
+ if self.state == "FREQ":
+ self.state = "CONTRAST"
+ elif self.state == "CONTRAST":
+ self.state = "BRIGHTNESS"
+ else:
+ self.state = "FREQ"
+ self.update_status_bar ()
+
+
+ def set_contrast (self, contrast):
+ self.contrast = contrast
+ self.invert_and_scale.set_k(-self.contrast *128.0*255.0/(200.0))
+ self.myform['contrast'].set_value(self.contrast)
+ self.update_status_bar ()
+
+ def set_brightness (self, brightness):
+ self.brightness = brightness
+ self.set_blacklevel.set_k(self.brightness +255.0)
+ self.myform['brightness'].set_value(self.brightness)
+ self.update_status_bar ()
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+
+ Tuning is a two step process. First we ask the front-end to
+ tune as close to the desired frequency as it can. Then we use
+ the result of that operation and our target_frequency to
+ determine the value for the digital down converter.
+ """
+ if not (self.u is None):
+ r = self.u.set_center_freq(target_freq)
+ if r:
+ self.freq = target_freq
+ self.myform['freq'].set_value(target_freq) # update displayed value
+ self.myform['freq_slider'].set_value(target_freq) # update displayed value
+ self.update_status_bar()
+ self._set_status_msg("OK", 0)
+ return True
+
+ self._set_status_msg("Failed", 0)
+ return False
+
+ def set_gain(self, gain):
+ if not (self.u is None):
+ self.gain=gain
+ self.myform['gain'].set_value(gain) # update displayed value
+ self.u.set_gain(gain)
+ self.update_status_bar()
+
+ def update_status_bar (self):
+ msg = "Setting:%s Contrast:%r Brightness:%r Gain: %r" % \
+ (self.state, self.contrast,self.brightness,self.gain)
+ self._set_status_msg(msg, 1)
+ #self.src_fft.set_baseband_freq(self.freq)
+
+
+if __name__ == '__main__':
+ app = stdgui2.stdapp (tv_rx_block, "USRP TV RX black-and-white")
+ app.MainLoop ()
diff --git a/gr-uhd/examples/python/usrp_tv_rcv_nogui.py b/gr-uhd/examples/python/usrp_tv_rcv_nogui.py
new file mode 100755
index 000000000..cfb36222c
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_tv_rcv_nogui.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 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.
+#
+
+"""
+Reads from a file and generates PAL TV pictures in black and white
+which can be displayed using ImageMagick or realtime using
+gr-video-sdl (To capture the input file Use usrp_rx_file.py, or use
+usrp_rx_cfile.py --output-shorts if you have a recent enough
+usrp_rx_cfile.py)
+
+Can also use usrp directly as capture source, but then you need a
+higher decimation factor (64) and thus get a lower horizontal
+resulution. There is no synchronisation yet. The sync blocks are in
+development but not yet in cvs.
+
+"""
+
+from gnuradio import gr, eng_notation
+from gnuradio import audio
+from gnuradio import uhd
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+
+try:
+ from gnuradio import video_sdl
+except:
+ print "FYI: gr-video-sdl is not installed"
+ print "realtime \"sdl\" video output window will not be available"
+
+
+class my_top_block(gr.top_block):
+
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ usage=("%prog: [options] output_filename.\nSpecial output_filename" + \
+ "\"sdl\" will use video_sink_sdl as realtime output window. " + \
+ "You then need to have gr-video-sdl installed.\n" +\
+ "Make sure your input capture file containes interleaved " + \
+ "shorts not complex floats")
+ 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")
+ parser.add_option("-c", "--contrast", type="eng_float", default=1.0,
+ help="set contrast (default is 1.0)")
+ parser.add_option("-b", "--brightness", type="eng_float", default=0.0,
+ help="set brightness (default is 0)")
+ parser.add_option("-i", "--in-filename", type="string", default=None,
+ help="Use input file as source. samples must be " + \
+ "interleaved shorts \n Use usrp_rx_file.py or " + \
+ "usrp_rx_cfile.py --output-shorts.\n Special " + \
+ "name \"usrp\" results in realtime capturing " + \
+ "and processing using usrp.\n" + \
+ "You then probably need a decimation factor of 64 or higher.")
+ parser.add_option("-f", "--freq", type="eng_float", default=519.25e6,
+ help="set frequency to FREQ.\nNote that the frequency of the video carrier is not at the middle of the TV channel", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-p", "--pal", action="store_true", default=False,
+ help="PAL video format (this is the default)")
+ parser.add_option("-n", "--ntsc", action="store_true", default=False,
+ help="NTSC video format")
+ parser.add_option("-r", "--repeat", action="store_false", default=True,
+ help="repeat in_file in a loop")
+ parser.add_option("-N", "--nframes", type="eng_float", default=None,
+ help="number of frames to collect [default=+inf]")
+ parser.add_option("", "--freq-min", type="eng_float", default=50.25e6,
+ help="Set a minimum frequency [default=%default]")
+ parser.add_option("", "--freq-max", type="eng_float", default=900.25e6,
+ help="Set a maximum frequency [default=%default]")
+ (options, args) = parser.parse_args ()
+ if not (len(args) == 1):
+ parser.print_help()
+ sys.stderr.write('You must specify the output. FILENAME or sdl \n');
+ sys.exit(1)
+
+ filename = args[0]
+
+ self.tv_freq_min = options.freq_min
+ self.tv_freq_max = options.freq_max
+
+ if options.in_filename is None:
+ parser.print_help()
+ sys.stderr.write('You must specify the input -i FILENAME or -i usrp\n');
+ raise SystemExit, 1
+
+ if not (filename=="sdl"):
+ options.repeat=False
+
+ input_rate = options.samp_rate
+ print "video sample rate %s" % (eng_notation.num_to_str(input_rate))
+
+ if not (options.in_filename=="usrp"):
+ # file is data source, capture with usr_rx_csfile.py
+ self.filesource = gr.file_source(gr.sizeof_short,
+ options.in_filename,
+ options.repeat)
+ self.istoc = gr.interleaved_short_to_complex()
+ self.connect(self.filesource,self.istoc)
+ self.src=self.istoc
+ else:
+ if options.freq is None:
+ parser.print_help()
+ sys.stderr.write('You must specify the frequency with -f FREQ\n');
+ raise SystemExit, 1
+
+ # build the graph
+ self.u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ self.u.set_samp_rate(input_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ self.src=self.u
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2.0
+ self.u.set_gain(options.gain)
+
+ r = self.u.set_center_freq(options.freq)
+ if not r:
+ sys.stderr.write('Failed to set frequency\n')
+ raise SystemExit, 1
+
+
+ self.agc = gr.agc_cc(1e-7,1.0,1.0) #1e-7
+ self.am_demod = gr.complex_to_mag ()
+ self.set_blacklevel = gr.add_const_ff(options.brightness +255.0)
+ self.invert_and_scale = gr.multiply_const_ff (-options.contrast *128.0*255.0/(200.0))
+ self.f2uc = gr.float_to_uchar()
+
+ # sdl window as final sink
+ if not (options.pal or options.ntsc):
+ options.pal=True #set default to PAL
+ if options.pal:
+ lines_per_frame=625.0
+ frames_per_sec=25.0
+ show_width=768
+ elif options.ntsc:
+ lines_per_frame=525.0
+ frames_per_sec=29.97002997
+ show_width=640
+ width=int(input_rate/(lines_per_frame*frames_per_sec))
+ height=int(lines_per_frame)
+
+ if filename=="sdl":
+ #Here comes the tv screen, you have to build and install
+ #gr-video-sdl for this (subproject of gnuradio, only in cvs
+ #for now)
+ try:
+ video_sink = video_sdl.sink_uc(frames_per_sec, width, height, 0,
+ show_width,height)
+ except:
+ print "gr-video-sdl is not installed"
+ print "realtime \"sdl\" video output window is not available"
+ raise SystemExit, 1
+ self.dst=video_sink
+ else:
+ print "You can use the imagemagick display tool to show the resulting imagesequence"
+ print "use the following line to show the demodulated TV-signal:"
+ print "display -depth 8 -size " +str(width)+ "x" + str(height) + " gray:" +filename
+ print "(Use the spacebar to advance to next frames)"
+ file_sink=gr.file_sink(gr.sizeof_char, filename)
+ self.dst =file_sink
+
+ if options.nframes is None:
+ self.connect(self.src, self.agc)
+ else:
+ self.head = gr.head(gr.sizeof_gr_complex, int(options.nframes*width*height))
+ self.connect(self.src, self.head, self.agc)
+
+ self.connect (self.agc, self.am_demod, self.invert_and_scale,
+ self.set_blacklevel, self.f2uc, self.dst)
+
+if __name__ == '__main__':
+ try:
+ my_top_block().run()
+ except KeyboardInterrupt:
+ pass
diff --git a/gr-uhd/examples/python/usrp_wfm_rcv.py b/gr-uhd/examples/python/usrp_wfm_rcv.py
new file mode 100755
index 000000000..bbb599033
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_wfm_rcv.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2009,2011 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.
+#
+
+from gnuradio import gr, optfir, audio, blks2, uhd
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import slider, powermate
+from gnuradio.wxgui import stdgui2, fftsink2, form
+from optparse import OptionParser
+import sys
+import wx
+
+
+class wfm_rx_block (stdgui2.std_top_block):
+ def __init__(self,frame,panel,vbox,argv):
+ stdgui2.std_top_block.__init__ (self,frame,panel,vbox,argv)
+
+ parser=OptionParser(option_class=eng_option)
+ 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("-f", "--freq", type="eng_float", default=100.1e6,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=40,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-V", "--volume", type="eng_float", default=None,
+ help="set volume (default is midpoint)")
+ parser.add_option("-O", "--audio-output", type="string", default="",
+ help="pcm device name. E.g., hw:0,0 or surround51 or /dev/dsp")
+ parser.add_option("", "--freq-min", type="eng_float", default=87.9e6,
+ help="Set a minimum frequency [default=%default]")
+ parser.add_option("", "--freq-max", type="eng_float", default=108.1e6,
+ help="Set a maximum frequency [default=%default]")
+
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+ self.frame = frame
+ self.panel = panel
+
+ self.vol = 0
+ self.state = "FREQ"
+ self.freq = 0
+
+ self.fm_freq_min = options.freq_min
+ self.fm_freq_max = options.freq_max
+
+ # build graph
+ self.u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ usrp_rate = 320e3
+ demod_rate = 320e3
+ audio_rate = 32e3
+ audio_decim = int(demod_rate / audio_rate)
+
+ self.u.set_samp_rate(usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ nfilts = 32
+ chan_coeffs = optfir.low_pass (nfilts, # gain
+ nfilts*usrp_rate, # sampling rate
+ 80e3, # passband cutoff
+ 115e3, # stopband cutoff
+ 0.1, # passband ripple
+ 60) # stopband attenuation
+ rrate = usrp_rate / dev_rate
+ self.chan_filt = blks2.pfb_arb_resampler_ccf(rrate, chan_coeffs, nfilts)
+
+ self.guts = blks2.wfm_rcv (demod_rate, audio_decim)
+
+ self.volume_control = gr.multiply_const_ff(self.vol)
+
+ # sound card as final sink
+ self.audio_sink = audio.sink (int (audio_rate),
+ options.audio_output,
+ False) # ok_to_block
+
+ # now wire it all together
+ self.connect (self.u, self.chan_filt, self.guts,
+ self.volume_control, self.audio_sink)
+
+ self._build_gui(vbox, usrp_rate, demod_rate, audio_rate)
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2
+
+ if options.volume is None:
+ g = self.volume_range()
+ options.volume = float(g[0]+g[1])/2
+
+ frange = self.u.get_freq_range()
+ if(frange.start() > self.fm_freq_max or frange.stop() < self.fm_freq_min):
+ sys.stderr.write("Radio does not support required frequency range.\n")
+ sys.exit(1)
+ if(options.freq < self.fm_freq_min or options.freq > self.fm_freq_max):
+ sys.stderr.write("Requested frequency is outside of required frequency range.\n")
+ sys.exit(1)
+
+
+ # set initial values
+
+ self.set_gain(options.gain)
+ self.set_vol(options.volume)
+ if not(self.set_freq(options.freq)):
+ self._set_status_msg("Failed to set initial frequency")
+
+ def _set_status_msg(self, msg, which=0):
+ self.frame.GetStatusBar().SetStatusText(msg, which)
+
+
+ def _build_gui(self, vbox, usrp_rate, demod_rate, audio_rate):
+
+ def _form_set_freq(kv):
+ return self.set_freq(kv['freq'])
+
+
+ if 1:
+ self.src_fft = fftsink2.fft_sink_c(self.panel, title="Data from USRP",
+ fft_size=512, sample_rate=usrp_rate,
+ ref_scale=32768.0, ref_level=0, y_divs=12)
+ self.connect (self.u, self.src_fft)
+ vbox.Add (self.src_fft.win, 4, wx.EXPAND)
+
+ if 1:
+ post_filt_fft = fftsink2.fft_sink_f(self.panel, title="Post Demod",
+ fft_size=1024, sample_rate=usrp_rate,
+ y_per_div=10, ref_level=0)
+ self.connect (self.guts.fm_demod, post_filt_fft)
+ vbox.Add (post_filt_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ post_deemph_fft = fftsink2.fft_sink_f(self.panel, title="Post Deemph",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=-20)
+ self.connect (self.guts.deemph, post_deemph_fft)
+ vbox.Add (post_deemph_fft.win, 4, wx.EXPAND)
+
+
+ # control area form at bottom
+ self.myform = myform = form.form()
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+ myform['freq'] = form.float_field(
+ parent=self.panel, sizer=hbox, label="Freq", weight=1,
+ callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
+
+ hbox.Add((5,0), 0)
+ myform['freq_slider'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3,
+ range=(self.fm_freq_min, self.fm_freq_max, 0.1e6),
+ callback=self.set_freq)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+
+ myform['volume'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Volume",
+ weight=3, range=self.volume_range(),
+ callback=self.set_vol)
+ hbox.Add((5,0), 1)
+
+ g = self.u.get_gain_range()
+ myform['gain'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Gain",
+ weight=3, range=(g.start(), g.stop(), g.step()),
+ callback=self.set_gain)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ try:
+ self.knob = powermate.powermate(self.frame)
+ self.rot = 0
+ powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate)
+ powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button)
+ except:
+ print "FYI: No Powermate or Contour Knob found"
+
+
+ def on_rotate (self, event):
+ self.rot += event.delta
+ if (self.state == "FREQ"):
+ if self.rot >= 3:
+ self.set_freq(self.freq + .1e6)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_freq(self.freq - .1e6)
+ self.rot += 3
+ else:
+ step = self.volume_range()[2]
+ if self.rot >= 3:
+ self.set_vol(self.vol + step)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_vol(self.vol - step)
+ self.rot += 3
+
+ def on_button (self, event):
+ if event.value == 0: # button up
+ return
+ self.rot = 0
+ if self.state == "FREQ":
+ self.state = "VOL"
+ else:
+ self.state = "FREQ"
+ self.update_status_bar ()
+
+
+ def set_vol (self, vol):
+ g = self.volume_range()
+ self.vol = max(g[0], min(g[1], vol))
+ self.volume_control.set_k(10**(self.vol/10))
+ self.myform['volume'].set_value(self.vol)
+ self.update_status_bar ()
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+ """
+
+ r = self.u.set_center_freq(target_freq)
+ if r:
+ self.freq = target_freq
+ self.myform['freq'].set_value(target_freq) # update displayed value
+ self.myform['freq_slider'].set_value(target_freq) # update displayed value
+ self.update_status_bar()
+ self._set_status_msg("OK", 0)
+ return True
+
+ self._set_status_msg("Failed", 0)
+ return False
+
+ def set_gain(self, gain):
+ self.myform['gain'].set_value(gain) # update displayed value
+ self.u.set_gain(gain)
+
+ def update_status_bar (self):
+ msg = "Volume:%r Setting:%s" % (self.vol, self.state)
+ self._set_status_msg(msg, 1)
+ self.src_fft.set_baseband_freq(self.freq)
+
+ def volume_range(self):
+ return (-20.0, 0.0, 0.5)
+
+
+if __name__ == '__main__':
+ app = stdgui2.stdapp (wfm_rx_block, "USRP WFM RX")
+ app.MainLoop ()
diff --git a/gr-uhd/examples/python/usrp_wfm_rcv2_nogui.py b/gr-uhd/examples/python/usrp_wfm_rcv2_nogui.py
new file mode 100755
index 000000000..f7e72ae6f
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_wfm_rcv2_nogui.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 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.
+#
+
+from gnuradio import gr, optfir, audio, blks2, uhd
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+import math
+
+class wfm_rx_block (gr.top_block):
+
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ parser=OptionParser(option_class=eng_option)
+ parser.add_option("-a", "--args", type="string", default="",
+ help="UHD device address args [default=%default]")
+ parser.add_option("", "--spec", type="string", default="A:0 A:0",
+ 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("", "--f1", type="eng_float", default=100.7e6,
+ help="set 1st station frequency to FREQ", metavar="FREQ")
+ parser.add_option("", "--f2", type="eng_float", default=102.5e6,
+ help="set 2nd station freq to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=40,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-O", "--audio-output", type="string", default="",
+ help="pcm device name. E.g., hw:0,0 or surround51 or /dev/dsp")
+ parser.add_option("", "--freq-min", type="eng_float", default=87.9e6,
+ help="Set a minimum frequency [default=%default]")
+ parser.add_option("", "--freq-max", type="eng_float", default=108.1e6,
+ help="Set a maximum frequency [default=%default]")
+
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+ if abs(options.f1 - options.f2) > 5.5e6:
+ print "Sorry, two stations must be within 5.5MHz of each other"
+ raise SystemExit
+
+ f = (options.f1, options.f2)
+
+ self.vol = .1
+ self.state = "FREQ"
+
+ self.fm_freq_min = options.freq_min
+ self.fm_freq_max = options.freq_max
+
+ # build graph
+ stream_args = uhd.stream_args('fc32', channels=range(2))
+ self.u = uhd.usrp_source(device_addr=options.args, stream_args=stream_args)
+
+ # Set front end channel mapping
+ self.u.set_subdev_spec(options.spec)
+
+ usrp_rate = 320e3
+ demod_rate = 320e3
+ audio_rate = 32e3
+ audio_decim = int(demod_rate / audio_rate)
+
+ self.u.set_samp_rate(usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ # Make sure dboard can suppor the required frequencies
+ frange = self.u.get_freq_range()
+ if(frange.start() > self.fm_freq_max or frange.stop() < self.fm_freq_min):
+ sys.stderr.write("Radio does not support required frequency range.\n")
+ sys.exit(1)
+
+ # sound card as final sink
+ self.audio_sink = audio.sink(int(audio_rate), options.audio_output)
+
+ # taps for channel filter
+ nfilts = 32
+ chan_coeffs = optfir.low_pass (nfilts, # gain
+ nfilts*usrp_rate, # sampling rate
+ 80e3, # passband cutoff
+ 115e3, # stopband cutoff
+ 0.1, # passband ripple
+ 60) # stopband attenuation
+ rrate = usrp_rate / dev_rate
+
+ # set front end PLL to middle frequency
+ mid_freq = (f[0] + f[1]) / 2.0
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2.0
+
+ for n in range(2):
+ chan_filt = blks2.pfb_arb_resampler_ccf(rrate, chan_coeffs, nfilts)
+ guts = blks2.wfm_rcv (demod_rate, audio_decim)
+ volume_control = gr.multiply_const_ff(self.vol)
+
+ #self.connect((self.di, n), chan_filt)
+ self.connect((self.u, n), chan_filt)
+ self.connect(chan_filt, guts, volume_control)
+ self.connect(volume_control, (self.audio_sink, n))
+
+ # Test the the requested frequencies are in range
+ if(f[n] < self.fm_freq_min or f[n] > self.fm_freq_max):
+ sys.stderr.write("Requested frequency is outside of required frequency range.\n")
+ sys.exit(1)
+
+ # Tune each channel by setting the RF freq to mid_freq and the
+ # DDC freq to f[n].
+ tr = uhd.tune_request(f[n], rf_freq=mid_freq,
+ rf_freq_policy=uhd.tune_request.POLICY_MANUAL)
+ self.u.set_center_freq(tr, n)
+
+ # Set gain for each channel
+ self.set_gain(options.gain, n)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, n)
+
+ def set_vol (self, vol):
+ self.vol = vol
+ self.volume_control.set_k(self.vol)
+
+
+ def set_gain(self, gain, n):
+ self.u.set_gain(gain, n)
+
+if __name__ == '__main__':
+ tb = wfm_rx_block()
+ try:
+ tb.run()
+ except KeyboardInterrupt:
+ pass
diff --git a/gr-uhd/examples/python/usrp_wfm_rcv_fmdet.py b/gr-uhd/examples/python/usrp_wfm_rcv_fmdet.py
new file mode 100755
index 000000000..514bd4faf
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_wfm_rcv_fmdet.py
@@ -0,0 +1,349 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 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.
+#
+
+from gnuradio import gr, optfir, audio, blks2, uhd
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import slider, powermate
+from gnuradio.wxgui import stdgui2, fftsink2, form, scopesink2
+from optparse import OptionParser
+import sys
+import wx
+
+class wfm_rx_block (stdgui2.std_top_block):
+ def __init__(self,frame,panel,vbox,argv):
+ stdgui2.std_top_block.__init__ (self,frame,panel,vbox,argv)
+
+ parser=OptionParser(option_class=eng_option)
+ 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("-f", "--freq", type="eng_float", default=100.1e6,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=65,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-s", "--squelch", type="eng_float", default=0,
+ help="set squelch level (default is 0)")
+ parser.add_option("-V", "--volume", type="eng_float", default=None,
+ help="set volume (default is midpoint)")
+ parser.add_option("-O", "--audio-output", type="string", default="",
+ help="pcm device name. E.g., hw:0,0 or surround51 or /dev/dsp")
+ parser.add_option("", "--freq-min", type="eng_float", default=87.9e6,
+ help="Set a minimum frequency [default=%default]")
+ parser.add_option("", "--freq-max", type="eng_float", default=108.1e6,
+ help="Set a maximum frequency [default=%default]")
+
+
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+ self.frame = frame
+ self.panel = panel
+
+ self.vol = 0
+ self.state = "FREQ"
+ self.freq = 0
+
+ self.fm_freq_min = options.freq_min
+ self.fm_freq_max = options.freq_max
+
+ # build graph
+ self.u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ usrp_rate = 320e3
+ demod_rate = 320e3
+ audio_rate = 48e3
+ audio_decim = 10
+
+ self.u.set_samp_rate(usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ nfilts = 32
+ chan_coeffs = gr.firdes.low_pass_2(10*nfilts, # gain
+ nfilts*usrp_rate, # sampling rate
+ 90e3, # passband cutoff
+ 30e3, # transition bw
+ 70) # stopband attenuation
+ rrate = usrp_rate / dev_rate
+ self.chan_filt = blks2.pfb_arb_resampler_ccf(rrate, chan_coeffs, nfilts)
+
+ self.guts = blks2.wfm_rcv_fmdet (demod_rate, audio_decim)
+
+ chan_rate = audio_rate / (demod_rate/audio_decim)
+ self.rchan_filt = blks2.pfb_arb_resampler_fff(chan_rate)
+ self.lchan_filt = blks2.pfb_arb_resampler_fff(chan_rate)
+
+ # FIXME rework {add,multiply}_const_* to handle multiple streams
+ self.volume_control_l = gr.multiply_const_ff(self.vol)
+ self.volume_control_r = gr.multiply_const_ff(self.vol)
+
+ # sound card as final sink
+ self.audio_sink = audio.sink (int (audio_rate),
+ options.audio_output,
+ False) # ok_to_block
+
+ # now wire it all together
+ self.connect (self.u, self.chan_filt, self.guts)
+ self.connect((self.guts, 0), self.lchan_filt,
+ self.volume_control_l, (self.audio_sink,0))
+ self.connect((self.guts, 1), self.rchan_filt,
+ self.volume_control_r, (self.audio_sink,1))
+
+ try:
+ self.guts.stereo_carrier_pll_recovery.squelch_enable(True)
+ except:
+ print "FYI: This implementation of the stereo_carrier_pll_recovery has no squelch implementation yet"
+
+
+ self._build_gui(vbox, usrp_rate, demod_rate, audio_rate)
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2.0
+
+ if options.volume is None:
+ g = self.volume_range()
+ options.volume = float(g[0]+g[1])/2
+
+ if abs(options.freq) < 1e6:
+ options.freq *= 1e6
+
+ frange = self.u.get_freq_range()
+ if(frange.start() > self.fm_freq_max or frange.stop() < self.fm_freq_min):
+ sys.stderr.write("Radio does not support required frequency range.\n")
+ sys.exit(1)
+ if(options.freq < self.fm_freq_min or options.freq > self.fm_freq_max):
+ sys.stderr.write("Requested frequency is outside of required frequency range.\n")
+ sys.exit(1)
+
+ # set initial values
+ self.set_gain(options.gain)
+ self.set_vol(options.volume)
+ try:
+ self.guts.stereo_carrier_pll_recovery.set_lock_threshold(options.squelch)
+ except:
+ print "FYI: This implementation of the stereo_carrier_pll_recovery has no squelch implementation yet"
+
+ if not(self.set_freq(options.freq)):
+ self._set_status_msg("Failed to set initial frequency")
+
+ def _set_status_msg(self, msg, which=0):
+ self.frame.GetStatusBar().SetStatusText(msg, which)
+
+
+ def _build_gui(self, vbox, usrp_rate, demod_rate, audio_rate):
+
+ def _form_set_freq(kv):
+ return self.set_freq(kv['freq'])
+
+
+ if 1:
+ self.src_fft = fftsink2.fft_sink_c(self.panel, title="Data from USRP",
+ fft_size=512, sample_rate=usrp_rate,
+ ref_scale=32768.0, ref_level=0, y_divs=12)
+ self.connect (self.u, self.src_fft)
+ vbox.Add (self.src_fft.win, 4, wx.EXPAND)
+
+ if 1:
+ post_fm_demod_fft = fftsink2.fft_sink_f(self.panel, title="Post FM Demod",
+ fft_size=512, sample_rate=demod_rate,
+ y_per_div=10, ref_level=0)
+ self.connect (self.guts.fm_demod, post_fm_demod_fft)
+ vbox.Add (post_fm_demod_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ post_stereo_carrier_generator_fft = fftsink2.fft_sink_c (self.panel, title="Post Stereo_carrier_generator",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=0)
+ self.connect (self.guts.stereo_carrier_generator, post_stereo_carrier_generator_fft)
+ vbox.Add (post_stereo_carrier_generator_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ post_deemphasis_left = fftsink2.fft_sink_f (self.panel, title="Post_Deemphasis_Left",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=0)
+ self.connect (self.guts.deemph_Left, post_deemphasis_left)
+ vbox.Add (post_deemphasis_left.win, 4, wx.EXPAND)
+
+ if 0:
+ post_deemphasis_right = fftsink2.fft_sink_f(self.panel, title="Post_Deemphasis_Right",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=-20)
+ self.connect (self.guts.deemph_Left, post_deemphasis_right)
+ vbox.Add (post_deemphasis_right.win, 4, wx.EXPAND)
+
+
+ if 0:
+ LmR_fft = fftsink2.fft_sink_f(self.panel, title="LmR",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=-20)
+ self.connect (self.guts.LmR_real,LmR_fft)
+ vbox.Add (LmR_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ self.scope = scopesink2.scope_sink_f(self.panel, sample_rate=demod_rate)
+ self.connect (self.guts.fm_demod,self.scope)
+ vbox.Add (self.scope.win,4,wx.EXPAND)
+
+ # control area form at bottom
+ self.myform = myform = form.form()
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+ myform['freq'] = form.float_field(
+ parent=self.panel, sizer=hbox, label="Freq", weight=1,
+ callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
+
+ hbox.Add((5,0), 0)
+ myform['freq_slider'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3,
+ range=(self.fm_freq_min, self.fm_freq_max, 0.1e6),
+ callback=self.set_freq)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+
+ myform['volume'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Volume",
+ weight=3, range=self.volume_range(),
+ callback=self.set_vol)
+ hbox.Add((5,0), 1)
+
+ g = self.u.get_gain_range()
+ myform['gain'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Gain",
+ weight=3, range=(g.start(), g.stop(), g.step()),
+ callback=self.set_gain)
+ hbox.Add((5,0), 0)
+
+ myform['sqlch_thrsh'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Stereo Squelch Threshold",
+ weight=3, range=(0.0,1.0,0.01),
+ callback=self.set_squelch)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ try:
+ self.knob = powermate.powermate(self.frame)
+ self.rot = 0
+ powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate)
+ powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button)
+ except:
+ print "FYI: No Powermate or Contour Knob found"
+
+
+ def on_rotate (self, event):
+ self.rot += event.delta
+ if (self.state == "FREQ"):
+ if self.rot >= 3:
+ self.set_freq(self.freq + .1e6)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_freq(self.freq - .1e6)
+ self.rot += 3
+ else:
+ step = self.volume_range()[2]
+ if self.rot >= 3:
+ self.set_vol(self.vol + step)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_vol(self.vol - step)
+ self.rot += 3
+
+ def on_button (self, event):
+ if event.value == 0: # button up
+ return
+ self.rot = 0
+ if self.state == "FREQ":
+ self.state = "VOL"
+ else:
+ self.state = "FREQ"
+ self.update_status_bar ()
+
+
+ def set_vol (self, vol):
+ g = self.volume_range()
+ self.vol = max(g[0], min(g[1], vol))
+ self.volume_control_l.set_k(10**(self.vol/10))
+ self.volume_control_r.set_k(10**(self.vol/10))
+ self.myform['volume'].set_value(self.vol)
+ self.update_status_bar ()
+
+ def set_squelch(self,squelch_threshold):
+ try:
+ self.guts.stereo_carrier_pll_recovery.set_lock_threshold(squelch_threshold);
+ except:
+ print "FYI: This implementation of the stereo_carrier_pll_recovery has no squelch implementation yet"
+
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+ """
+
+ r = self.u.set_center_freq(target_freq)
+
+ if r:
+ self.freq = target_freq
+ self.myform['freq'].set_value(target_freq) # update displayed value
+ self.myform['freq_slider'].set_value(target_freq) # update displayed value
+ self.update_status_bar()
+ self._set_status_msg("OK", 0)
+ return True
+
+ self._set_status_msg("Failed", 0)
+ return False
+
+ def set_gain(self, gain):
+ self.myform['gain'].set_value(gain) # update displayed value
+ self.u.set_gain(gain)
+
+ def update_status_bar (self):
+ msg = "Volume:%r Setting:%s" % (self.vol, self.state)
+ self._set_status_msg(msg, 1)
+ self.src_fft.set_baseband_freq(self.freq)
+
+ def volume_range(self):
+ return (-20.0, 0.0, 0.5)
+
+
+if __name__ == '__main__':
+ app = stdgui2.stdapp (wfm_rx_block, "USRP WFM RX")
+ app.MainLoop ()
diff --git a/gr-uhd/examples/python/usrp_wfm_rcv_nogui.py b/gr-uhd/examples/python/usrp_wfm_rcv_nogui.py
new file mode 100755
index 000000000..7d042983e
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_wfm_rcv_nogui.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 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.
+#
+
+from gnuradio import gr, optfir, audio, blks2, uhd
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+
+class wfm_rx_block (gr.top_block):
+
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ parser=OptionParser(option_class=eng_option)
+ 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("-f", "--freq", type="eng_float", default=100.1e6,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-V", "--volume", type="eng_float", default=None,
+ help="set volume (default is midpoint)")
+ parser.add_option("-O", "--audio-output", type="string", default="",
+ help="pcm device name. E.g., hw:0,0 or surround51 or /dev/dsp")
+ parser.add_option("", "--freq-min", type="eng_float", default=87.9e6,
+ help="Set a minimum frequency [default=%default]")
+ parser.add_option("", "--freq-max", type="eng_float", default=108.1e6,
+ help="Set a maximum frequency [default=%default]")
+
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+ self.state = "FREQ"
+ self.freq = 0
+
+ self.fm_freq_min = options.freq_min
+ self.fm_freq_max = options.freq_max
+
+ # build graph
+ self.u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ usrp_rate = 320e3
+ demod_rate = 320e3
+ audio_rate = 32e3
+ audio_decim = int(demod_rate / audio_rate)
+
+ self.u.set_samp_rate(usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ nfilts = 32
+ chan_coeffs = optfir.low_pass (nfilts, # gain
+ nfilts*usrp_rate, # sampling rate
+ 80e3, # passband cutoff
+ 115e3, # stopband cutoff
+ 0.1, # passband ripple
+ 60) # stopband attenuation
+ rrate = usrp_rate / dev_rate
+ self.chan_filt = blks2.pfb_arb_resampler_ccf(rrate, chan_coeffs, nfilts)
+
+ self.guts = blks2.wfm_rcv (demod_rate, audio_decim)
+
+ self.volume_control = gr.multiply_const_ff(1)
+
+ # sound card as final sink
+ self.audio_sink = audio.sink(int(audio_rate),
+ options.audio_output,
+ False) # ok_to_block
+
+ # now wire it all together
+ self.connect (self.u, self.chan_filt, self.guts,
+ self.volume_control, self.audio_sink)
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2.0
+
+ if options.volume is None:
+ g = self.volume_range()
+ options.volume = float(g[0]+g[1])/2
+
+ frange = self.u.get_freq_range()
+ if(frange.start() > self.fm_freq_max or frange.stop() < self.fm_freq_min):
+ sys.stderr.write("Radio does not support required frequency range.\n")
+ sys.exit(1)
+ if(options.freq < self.fm_freq_min or options.freq > self.fm_freq_max):
+ sys.stderr.write("Requested frequency is outside of required frequency range.\n")
+ sys.exit(1)
+
+ # set initial values
+ self.set_gain(options.gain)
+ self.set_vol(options.volume)
+ if not(self.set_freq(options.freq)):
+ self._set_status_msg("Failed to set initial frequency")
+
+ def set_vol (self, vol):
+ g = self.volume_range()
+ self.vol = max(g[0], min(g[1], vol))
+ self.volume_control.set_k(10**(self.vol/10))
+ self.update_status_bar ()
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+ """
+
+ r = self.u.set_center_freq(target_freq)
+
+ if r:
+ self.freq = target_freq
+ self.update_status_bar()
+ self._set_status_msg("OK", 0)
+ return True
+
+ self._set_status_msg("Failed", 0)
+ return False
+
+ def set_gain(self, gain):
+ self.u.set_gain(gain)
+
+ def update_status_bar (self):
+ msg = "Freq: %s Volume:%f Setting:%s" % (
+ eng_notation.num_to_str(self.freq), self.vol, self.state)
+ self._set_status_msg(msg, 1)
+
+ def _set_status_msg(self, msg, which=0):
+ print msg
+
+ def volume_range(self):
+ return (-20.0, 0.0, 0.5)
+
+
+if __name__ == '__main__':
+ tb = wfm_rx_block()
+ try:
+ tb.run()
+ except KeyboardInterrupt:
+ pass
diff --git a/gr-uhd/examples/python/usrp_wfm_rcv_pll.py b/gr-uhd/examples/python/usrp_wfm_rcv_pll.py
new file mode 100755
index 000000000..53b1e6fea
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_wfm_rcv_pll.py
@@ -0,0 +1,346 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 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.
+#
+
+from gnuradio import gr, optfir, audio, blks2, uhd
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import slider, powermate
+from gnuradio.wxgui import stdgui2, fftsink2, form, scopesink2
+from optparse import OptionParser
+import sys
+import wx
+
+class wfm_rx_block (stdgui2.std_top_block):
+ def __init__(self,frame,panel,vbox,argv):
+ stdgui2.std_top_block.__init__ (self,frame,panel,vbox,argv)
+
+ parser=OptionParser(option_class=eng_option)
+ 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("-f", "--freq", type="eng_float", default=100.1e6,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=65,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-s", "--squelch", type="eng_float", default=0,
+ help="set squelch level (default is 0)")
+ parser.add_option("-V", "--volume", type="eng_float", default=None,
+ help="set volume (default is midpoint)")
+ parser.add_option("-O", "--audio-output", type="string", default="",
+ help="pcm device name. E.g., hw:0,0 or surround51 or /dev/dsp")
+ parser.add_option("", "--freq-min", type="eng_float", default=87.9e6,
+ help="Set a minimum frequency [default=%default]")
+ parser.add_option("", "--freq-max", type="eng_float", default=108.1e6,
+ help="Set a maximum frequency [default=%default]")
+
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+ self.frame = frame
+ self.panel = panel
+
+ self.vol = 0
+ self.state = "FREQ"
+ self.freq = 0
+
+ self.fm_freq_min = options.freq_min
+ self.fm_freq_max = options.freq_max
+
+ # build graph
+ self.u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ usrp_rate = 320e3
+ demod_rate = 320e3
+ audio_rate = 48e3
+ audio_decim = 10
+
+ self.u.set_samp_rate(usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ nfilts = 32
+ chan_coeffs = gr.firdes.low_pass_2 (nfilts, # gain
+ nfilts*usrp_rate, # sampling rate
+ 90e3, # passband cutoff
+ 30e3, # stopband cutoff
+ 70) # stopband attenuation
+ rrate = usrp_rate / dev_rate
+ self.chan_filt = blks2.pfb_arb_resampler_ccf(rrate, chan_coeffs, nfilts)
+
+
+ self.guts = blks2.wfm_rcv_pll (demod_rate, audio_decim)
+
+ chan_rate = audio_rate / (demod_rate/audio_decim)
+ self.rchan_filt = blks2.pfb_arb_resampler_fff(chan_rate)
+ self.lchan_filt = blks2.pfb_arb_resampler_fff(chan_rate)
+
+ # FIXME rework {add,multiply}_const_* to handle multiple streams
+ self.volume_control_l = gr.multiply_const_ff(self.vol)
+ self.volume_control_r = gr.multiply_const_ff(self.vol)
+
+ # sound card as final sink
+ self.audio_sink = audio.sink (int (audio_rate),
+ options.audio_output,
+ False) # ok_to_block
+
+ # now wire it all together
+ self.connect (self.u, self.chan_filt, self.guts)
+ self.connect((self.guts, 0), self.lchan_filt,
+ self.volume_control_l, (self.audio_sink,0))
+ self.connect((self.guts, 1), self.rchan_filt,
+ self.volume_control_r, (self.audio_sink,1))
+
+ try:
+ self.guts.stereo_carrier_pll_recovery.squelch_enable(True)
+ except:
+ print "FYI: This implementation of the stereo_carrier_pll_recovery has no squelch implementation yet"
+
+
+ self._build_gui(vbox, usrp_rate, demod_rate, audio_rate)
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2.0
+
+ if options.volume is None:
+ g = self.volume_range()
+ options.volume = float(g[0]+g[1])/2
+
+ frange = self.u.get_freq_range()
+ if(frange.start() > self.fm_freq_max or frange.stop() < self.fm_freq_min):
+ sys.stderr.write("Radio does not support required frequency range.\n")
+ sys.exit(1)
+ if(options.freq < self.fm_freq_min or options.freq > self.fm_freq_max):
+ sys.stderr.write("Requested frequency is outside of required frequency range.\n")
+ sys.exit(1)
+
+ # set initial values
+ self.set_gain(options.gain)
+ self.set_vol(options.volume)
+ try:
+ self.guts.stereo_carrier_pll_recovery.set_lock_threshold(options.squelch)
+ except:
+ print "FYI: This implementation of the stereo_carrier_pll_recovery has no squelch implementation yet"
+
+ if not(self.set_freq(options.freq)):
+ self._set_status_msg("Failed to set initial frequency")
+
+ def _set_status_msg(self, msg, which=0):
+ self.frame.GetStatusBar().SetStatusText(msg, which)
+
+
+ def _build_gui(self, vbox, usrp_rate, demod_rate, audio_rate):
+
+ def _form_set_freq(kv):
+ return self.set_freq(kv['freq'])
+
+
+ if 1:
+ self.src_fft = fftsink2.fft_sink_c(self.panel, title="Data from USRP",
+ fft_size=512, sample_rate=usrp_rate,
+ ref_scale=32768.0, ref_level=0, y_divs=12)
+ self.connect (self.u, self.src_fft)
+ vbox.Add (self.src_fft.win, 4, wx.EXPAND)
+
+ if 1:
+ post_fm_demod_fft = fftsink2.fft_sink_f(self.panel, title="Post FM Demod",
+ fft_size=512, sample_rate=demod_rate,
+ y_per_div=10, ref_level=0)
+ self.connect (self.guts.fm_demod, post_fm_demod_fft)
+ vbox.Add (post_fm_demod_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ post_stereo_carrier_generator_fft = fftsink2.fft_sink_c (self.panel, title="Post Stereo_carrier_generator",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=0)
+ self.connect (self.guts.stereo_carrier_generator, post_stereo_carrier_generator_fft)
+ vbox.Add (post_stereo_carrier_generator_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ post_deemphasis_left = fftsink2.fft_sink_f (self.panel, title="Post_Deemphasis_Left",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=0)
+ self.connect (self.guts.deemph_Left, post_deemphasis_left)
+ vbox.Add (post_deemphasis_left.win, 4, wx.EXPAND)
+
+ if 0:
+ post_deemphasis_right = fftsink2.fft_sink_f(self.panel, title="Post_Deemphasis_Right",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=-20)
+ self.connect (self.guts.deemph_Left, post_deemphasis_right)
+ vbox.Add (post_deemphasis_right.win, 4, wx.EXPAND)
+
+
+ if 0:
+ LmR_fft = fftsink2.fft_sink_f(self.panel, title="LmR",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=-20)
+ self.connect (self.guts.LmR_real,LmR_fft)
+ vbox.Add (LmR_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ self.scope = scopesink2.scope_sink_f(self.panel, sample_rate=demod_rate)
+ self.connect (self.guts.fm_demod,self.scope)
+ vbox.Add (self.scope.win,4,wx.EXPAND)
+
+ # control area form at bottom
+ self.myform = myform = form.form()
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+ myform['freq'] = form.float_field(
+ parent=self.panel, sizer=hbox, label="Freq", weight=1,
+ callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
+
+ hbox.Add((5,0), 0)
+ myform['freq_slider'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3,
+ range=(self.fm_freq_min, self.fm_freq_max, 0.1e6),
+ callback=self.set_freq)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+
+ myform['volume'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Volume",
+ weight=3, range=self.volume_range(),
+ callback=self.set_vol)
+ hbox.Add((5,0), 1)
+
+ g = self.u.get_gain_range()
+ myform['gain'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Gain",
+ weight=3, range=(g.start(), g.stop(), g.step()),
+ callback=self.set_gain)
+ hbox.Add((5,0), 0)
+
+ myform['sqlch_thrsh'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Stereo Squelch Threshold",
+ weight=3, range=(0.0,1.0,0.01),
+ callback=self.set_squelch)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ try:
+ self.knob = powermate.powermate(self.frame)
+ self.rot = 0
+ powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate)
+ powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button)
+ except:
+ print "FYI: No Powermate or Contour Knob found"
+
+
+ def on_rotate (self, event):
+ self.rot += event.delta
+ if (self.state == "FREQ"):
+ if self.rot >= 3:
+ self.set_freq(self.freq + .1e6)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_freq(self.freq - .1e6)
+ self.rot += 3
+ else:
+ step = self.volume_range()[2]
+ if self.rot >= 3:
+ self.set_vol(self.vol + step)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_vol(self.vol - step)
+ self.rot += 3
+
+ def on_button (self, event):
+ if event.value == 0: # button up
+ return
+ self.rot = 0
+ if self.state == "FREQ":
+ self.state = "VOL"
+ else:
+ self.state = "FREQ"
+ self.update_status_bar ()
+
+
+ def set_vol (self, vol):
+ g = self.volume_range()
+ self.vol = max(g[0], min(g[1], vol))
+ self.volume_control_l.set_k(10**(self.vol/10))
+ self.volume_control_r.set_k(10**(self.vol/10))
+ self.myform['volume'].set_value(self.vol)
+ self.update_status_bar ()
+
+ def set_squelch(self,squelch_threshold):
+ try:
+ self.guts.stereo_carrier_pll_recovery.set_lock_threshold(squelch_threshold);
+ except:
+ print "FYI: This implementation of the stereo_carrier_pll_recovery has no squelch implementation yet"
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+ """
+
+ r = self.u.set_center_freq(target_freq)
+
+ if r:
+ self.freq = target_freq
+ self.myform['freq'].set_value(target_freq) # update displayed value
+ self.myform['freq_slider'].set_value(target_freq) # update displayed value
+ self.update_status_bar()
+ self._set_status_msg("OK", 0)
+ return True
+
+ self._set_status_msg("Failed", 0)
+ return False
+
+ def set_gain(self, gain):
+ self.myform['gain'].set_value(gain) # update displayed value
+ self.u.set_gain(gain)
+
+ def update_status_bar (self):
+ msg = "Volume:%r Setting:%s" % (self.vol, self.state)
+ self._set_status_msg(msg, 1)
+ self.src_fft.set_baseband_freq(self.freq)
+
+ def volume_range(self):
+ return (-20.0, 0.0, 0.5)
+
+
+if __name__ == '__main__':
+ app = stdgui2.stdapp (wfm_rx_block, "USRP WFM RX")
+ app.MainLoop ()
diff --git a/gr-uhd/examples/python/usrp_wfm_rcv_sca.py b/gr-uhd/examples/python/usrp_wfm_rcv_sca.py
new file mode 100755
index 000000000..646fe8587
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_wfm_rcv_sca.py
@@ -0,0 +1,403 @@
+#!/usr/bin/env python
+#
+# Copyright 2006,2007,2011 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 this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+"""
+Here is a bit of code that will receive SCA analog subcarriers of FM
+Broadcast Stations using the USRP. It is a modified version of
+usrp_wfm_rcv.py.
+
+Common SCA frequencies are 67 kHz and 92 kHz. SCA is used for Reading
+Services for the Blind, Background Music, Foreign Language Services, and
+other services. Remember you may hear static when tuned to a FM station
+because this code only outputs SCA audio.
+
+The USRP gain is critical for good decoding. Adjust for minimum noise.
+ I use the Post FM Demod FFT to check for SCA subcarriers and to adjust
+the USRP gain for the lowest noise floor. The stereo pilot at 19 KHz,
+the stereo difference signal around 38 KHz, and RDS at 57 KHz are also
+displayed on the Post FM Demod FFT if present.
+
+The range below 67 kHz is used for SCA only when Stereo is not used.
+
+The SCA recieve range is not as far as the main FM carrier receive range
+so tune in strong local stations first.
+
+I tried to comment the code with the various parameters. There seems to
+be several choices for a couple of them. I coded the common ones I see
+here.
+
+In the local area there are a couple of stations using digital SCA.
+These look similar to narrow DRM signals and I wonder if they are using
+OFDM.
+"""
+
+
+from gnuradio import gr, optfir, audio, blks2, uhd
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import slider, powermate
+from gnuradio.wxgui import stdgui2, fftsink2, form
+from optparse import OptionParser
+import sys
+import math
+import wx
+
+class wfm_rx_sca_block (stdgui2.std_top_block):
+ def __init__(self,frame,panel,vbox,argv):
+ stdgui2.std_top_block.__init__ (self,frame,panel,vbox,argv)
+
+ parser=OptionParser(option_class=eng_option)
+ 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("-f", "--freq", type="eng_float", default=100.1e6,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=40,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-V", "--volume", type="eng_float", default=None,
+ help="set volume (default is midpoint)")
+ parser.add_option("-O", "--audio-output", type="string", default="",
+ help="pcm device name. E.g., hw:0,0 or surround51 or /dev/dsp")
+ parser.add_option("", "--freq-min", type="eng_float", default=87.9e6,
+ help="Set a minimum frequency [default=%default]")
+ parser.add_option("", "--freq-max", type="eng_float", default=108.1e6,
+ help="Set a maximum frequency [default=%default]")
+
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+ self.frame = frame
+ self.panel = panel
+
+ self.vol = 0
+ self.state = "FREQ"
+ self.freq = 0
+
+ self.fm_freq_min = options.freq_min
+ self.fm_freq_max = options.freq_max
+
+ # build graph
+
+ self.u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ usrp_rate = 320e3
+ demod_rate = 320e3
+ audio_rate = 32e3
+ sca_demod_rate = 64e3
+ audio_decim = int(demod_rate / audio_rate)
+ sca_chanfilt_decim = int(demod_rate / sca_demod_rate)
+
+ self.u.set_samp_rate(usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ nfilts = 32
+ chan_coeffs = optfir.low_pass (nfilts, # gain
+ nfilts*usrp_rate, # sampling rate
+ 100e3, # passband cutoff
+ 140e3, # stopband cutoff
+ 0.1, # passband ripple
+ 60) # stopband attenuation
+ rrate = usrp_rate / dev_rate
+ self.chan_filt = blks2.pfb_arb_resampler_ccf(rrate, chan_coeffs, nfilts)
+
+ #Create demodulator block for Main FM Channel
+ max_dev = 75e3
+ fm_demod_gain = demod_rate/(2*math.pi*max_dev)
+ self.fm_demod = gr.quadrature_demod_cf (fm_demod_gain)
+
+ # Note - deemphasis is not applied to the Main FM Channel as
+ # main audio is not decoded
+
+ # SCA Devation is 10% of carrier but some references say 20%
+ # if mono with one SCA (6 KHz seems typical)
+ max_sca_dev = 6e3
+
+ # Create filter to get SCA channel we want
+ sca_chan_coeffs = gr.firdes.low_pass (1.0, # gain
+ demod_rate, # sampling rate
+ max_sca_dev, # cutoff freq
+ max_sca_dev/3, # trans. band
+ gr.firdes.WIN_HANN) # filter type
+
+ self.ddc = gr.freq_xlating_fir_filter_fcf(sca_chanfilt_decim, # decim rate
+ sca_chan_coeffs, # taps
+ 0, # freq translation amount (Gets set by the UI)
+ demod_rate) # input sample rate
+
+ #Create demodulator block for SCA Channel
+ sca_demod_gain = sca_demod_rate/(2*math.pi*max_sca_dev)
+ self.fm_demod_sca = gr.quadrature_demod_cf (sca_demod_gain)
+
+
+ # SCA analog audio is bandwidth limited to 5 KHz
+ max_sca_audio_freq = 5.0e3
+
+ # SCA analog deephasis is 150 uS (75 uS may be used)
+ sca_tau = 150e-6
+
+ # compute FIR filter taps for SCA audio filter
+ audio_coeffs = gr.firdes.low_pass (1.0, # gain
+ sca_demod_rate, # sampling rate
+ max_sca_audio_freq, # cutoff freq
+ max_sca_audio_freq/2.5, # trans. band
+ gr.firdes.WIN_HAMMING)
+
+ # input: float; output: float
+ self.audio_filter = gr.fir_filter_fff (audio_decim, audio_coeffs)
+
+ # Create deemphasis block that is applied after SCA demodulation
+ self.deemph = blks2.fm_deemph (audio_rate, sca_tau)
+
+ self.volume_control = gr.multiply_const_ff(self.vol)
+
+ # sound card as final sink
+ self.audio_sink = audio.sink (int (audio_rate),
+ options.audio_output,
+ False) # ok_to_block
+
+ # now wire it all together
+ self.connect (self.u, self.chan_filt, self.fm_demod,
+ self.ddc, self.fm_demod_sca)
+ self.connect (self.fm_demod_sca, self.audio_filter,
+ self.deemph, self.volume_control,
+ self.audio_sink)
+
+ self._build_gui(vbox, usrp_rate, demod_rate, sca_demod_rate, audio_rate)
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2
+
+ if options.volume is None:
+ g = self.volume_range()
+ options.volume = float(g[0]+g[1])/2
+
+ frange = self.u.get_freq_range()
+ if(frange.start() > self.fm_freq_max or frange.stop() < self.fm_freq_min):
+ sys.stderr.write("Radio does not support required frequency range.\n")
+ sys.exit(1)
+ if(options.freq < self.fm_freq_min or options.freq > self.fm_freq_max):
+ sys.stderr.write("Requested frequency is outside of required frequency range.\n")
+ sys.exit(1)
+
+ # set initial values
+
+ self.set_gain(options.gain)
+ self.set_vol(options.volume)
+ if not(self.set_freq(options.freq)):
+ self._set_status_msg("Failed to set initial frequency")
+ self.set_sca_freq(67000) # A common SCA Frequency
+
+ def _set_status_msg(self, msg, which=0):
+ self.frame.GetStatusBar().SetStatusText(msg, which)
+
+
+ def _build_gui(self, vbox, usrp_rate, demod_rate, sca_demod_rate, audio_rate):
+
+ def _form_set_freq(kv):
+ return self.set_freq(kv['freq'])
+
+ def _form_set_sca_freq(kv):
+ return self.set_sca_freq(kv['sca_freq'])
+
+ if 1:
+ self.src_fft = fftsink2.fft_sink_c(self.panel, title="Data from USRP",
+ fft_size=512, sample_rate=usrp_rate,
+ ref_scale=32768.0, ref_level=0, y_divs=12)
+ self.connect (self.u, self.src_fft)
+ vbox.Add (self.src_fft.win, 4, wx.EXPAND)
+
+ if 1:
+ post_demod_fft = fftsink2.fft_sink_f(self.panel, title="Post FM Demod",
+ fft_size=2048, sample_rate=demod_rate,
+ y_per_div=10, ref_level=0)
+ self.connect (self.fm_demod, post_demod_fft)
+ vbox.Add (post_demod_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ post_demod_sca_fft = fftsink2.fft_sink_f(self.panel, title="Post SCA Demod",
+ fft_size=1024, sample_rate=sca_demod_rate,
+ y_per_div=10, ref_level=0)
+ self.connect (self.fm_demod_sca, post_demod_sca_fft)
+ vbox.Add (post_demod_sca_fft.win, 4, wx.EXPAND)
+
+ if 0:
+ post_deemph_fft = fftsink2.fft_sink_f (self.panel, title="Post SCA Deemph",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=-20)
+ self.connect (self.deemph, post_deemph_fft)
+ vbox.Add (post_deemph_fft.win, 4, wx.EXPAND)
+
+
+ # control area form at bottom
+ self.myform = myform = form.form()
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+ myform['freq'] = form.float_field(
+ parent=self.panel, sizer=hbox, label="Freq", weight=1,
+ callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
+
+ hbox.Add((5,0), 0)
+ myform['freq_slider'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3,
+ range=(self.fm_freq_min, self.fm_freq_max, 0.1e6),
+ callback=self.set_freq)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+ myform['sca_freq'] = form.float_field(
+ parent=self.panel, sizer=hbox, label="SCA", weight=1,
+ callback=myform.check_input_and_call(_form_set_sca_freq, self._set_status_msg))
+
+ hbox.Add((5,0), 0)
+ myform['sca_freq_slider'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3,
+ range=(38e3, 100e3, 1.0e3),
+ callback=self.set_sca_freq)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+
+ myform['volume'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Volume",
+ weight=3, range=self.volume_range(),
+ callback=self.set_vol)
+ hbox.Add((5,0), 1)
+
+ g = self.u.get_gain_range()
+ myform['gain'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Gain",
+ weight=3, range=(g.start(), g.stop(), g.step()),
+ callback=self.set_gain)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ try:
+ self.knob = powermate.powermate(self.frame)
+ self.rot = 0
+ powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate)
+ powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button)
+ except:
+ print "FYI: No Powermate or Contour Knob found"
+
+
+ def on_rotate (self, event):
+ self.rot += event.delta
+ if (self.state == "FREQ"):
+ if self.rot >= 3:
+ self.set_freq(self.freq + .1e6)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_freq(self.freq - .1e6)
+ self.rot += 3
+ else:
+ step = self.volume_range()[2]
+ if self.rot >= 3:
+ self.set_vol(self.vol + step)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_vol(self.vol - step)
+ self.rot += 3
+
+ def on_button (self, event):
+ if event.value == 0: # button up
+ return
+ self.rot = 0
+ if self.state == "FREQ":
+ self.state = "VOL"
+ else:
+ self.state = "FREQ"
+ self.update_status_bar ()
+
+
+ def set_vol (self, vol):
+ g = self.volume_range()
+ self.vol = max(g[0], min(g[1], vol))
+ self.volume_control.set_k(10**(self.vol/10))
+ self.myform['volume'].set_value(self.vol)
+ self.update_status_bar ()
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+
+ Tuning is a two step process. First we ask the front-end to
+ tune as close to the desired frequency as it can. Then we use
+ the result of that operation and our target_frequency to
+ determine the value for the digital down converter.
+ """
+ r = self.u.set_center_freq(target_freq)
+ if r:
+ self.freq = target_freq
+ self.myform['freq'].set_value(target_freq) # update displayed value
+ self.myform['freq_slider'].set_value(target_freq) # update displayed value
+ self.update_status_bar()
+ self._set_status_msg("OK", 0)
+ return True
+ self._set_status_msg("Failed", 0)
+ return False
+
+ def set_sca_freq(self, target_sca_freq):
+
+ self.ddc.set_center_freq(-target_sca_freq)
+ self.myform['sca_freq'].set_value(target_sca_freq) # update displayed value
+ self.myform['sca_freq_slider'].set_value(target_sca_freq) # update displayed value
+ self.update_status_bar()
+ self._set_status_msg("OK", 0)
+ return True
+
+ def set_gain(self, gain):
+ self.myform['gain'].set_value(gain) # update displayed value
+ self.u.set_gain(gain)
+
+ def update_status_bar (self):
+ msg = "Volume:%r Setting:%s" % (self.vol, self.state)
+ self._set_status_msg(msg, 1)
+ self.src_fft.set_baseband_freq(self.freq)
+
+ def volume_range(self):
+ return (-20.0, 0.0, 0.5)
+
+
+if __name__ == '__main__':
+ app = stdgui2.stdapp (wfm_rx_sca_block, "USRP WFM SCA RX")
+ app.MainLoop ()
diff --git a/gr-uhd/examples/python/usrp_wxapt_rcv.py b/gr-uhd/examples/python/usrp_wxapt_rcv.py
new file mode 100755
index 000000000..6b57de3bc
--- /dev/null
+++ b/gr-uhd/examples/python/usrp_wxapt_rcv.py
@@ -0,0 +1,282 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 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.
+#
+
+from gnuradio import gr, audio, blks2, uhd
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import slider, powermate
+from gnuradio.wxgui import stdgui2, fftsink2, form
+from optparse import OptionParser
+import sys
+import wx
+
+
+class wxapt_rx_block (stdgui2.std_top_block):
+ def __init__(self,frame,panel,vbox,argv):
+ stdgui2.std_top_block.__init__ (self,frame,panel,vbox,argv)
+
+ parser=OptionParser(option_class=eng_option)
+ 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("-f", "--freq", type="eng_float", default=137.5e6,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-V", "--volume", type="eng_float", default=None,
+ help="set volume (default is midpoint)")
+ parser.add_option("-O", "--audio-output", type="string", default="",
+ help="pcm device name. E.g., hw:0,0 or surround51 or /dev/dsp")
+ parser.add_option("", "--freq-min", type="eng_float", default=137e6,
+ help="Set a minimum frequency [default=%default]")
+ parser.add_option("", "--freq-max", type="eng_float", default=138e6,
+ help="Set a maximum frequency [default=%default]")
+
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+
+ self.frame = frame
+ self.panel = panel
+
+ self.vol = 0
+ self.state = "FREQ"
+ self.freq = 0
+
+ self.freq_min = options.freq_min
+ self.freq_max = options.freq_max
+
+ # build graph
+ self.u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
+
+ # Set the subdevice spec
+ if(options.spec):
+ self.u.set_subdev_spec(options.spec, 0)
+
+ # Set the antenna
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ usrp_rate = 320e3
+ demod_rate = 320e3
+ audio_rate = 32e3
+ audio_decim = int(demod_rate / audio_rate)
+
+ self.u.set_samp_rate(usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ nfilts = 32
+ chan_coeffs = gr.firdes.low_pass_2 (nfilts, # gain
+ nfilts*usrp_rate, # sampling rate
+ 40e3, # passband cutoff
+ 20e3, # transition bw
+ 60) # stopband attenuation
+ rrate = usrp_rate / dev_rate
+ self.chan_filt = blks2.pfb_arb_resampler_ccf(rrate, chan_coeffs, nfilts)
+
+ self.guts = blks2.wfm_rcv (demod_rate, audio_decim)
+
+ self.volume_control = gr.multiply_const_ff(self.vol)
+
+ # sound card as final sink
+ self.audio_sink = audio.sink (int (audio_rate), options.audio_output)
+
+ # now wire it all together
+ self.connect (self.u, self.chan_filt, self.guts,
+ self.volume_control, self.audio_sink)
+
+ self._build_gui(vbox, usrp_rate, demod_rate, audio_rate)
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2.0
+
+ if options.volume is None:
+ g = self.volume_range()
+ options.volume = float(g[0]+g[1])/2
+
+ frange = self.u.get_freq_range()
+ if(frange.start() > self.freq_max or frange.stop() < self.freq_min):
+ sys.stderr.write("Radio does not support required frequency range.\n")
+ sys.exit(1)
+ if(options.freq < self.freq_min or options.freq > self.freq_max):
+ sys.stderr.write("Requested frequency is outside of required frequency range.\n")
+ sys.exit(1)
+
+ # set initial values
+ self.set_gain(options.gain)
+ self.set_vol(options.volume)
+ if not(self.set_freq(options.freq)):
+ self._set_status_msg("Failed to set initial frequency")
+
+ def _set_status_msg(self, msg, which=0):
+ self.frame.GetStatusBar().SetStatusText(msg, which)
+
+
+ def _build_gui(self, vbox, usrp_rate, demod_rate, audio_rate):
+
+ def _form_set_freq(kv):
+ return self.set_freq(kv['freq'])
+
+
+ if 1:
+ self.src_fft = fftsink2.fft_sink_c (self.panel, title="Data from USRP",
+ fft_size=512, sample_rate=usrp_rate,
+ ref_scale=32768.0, ref_level=0, y_divs=12)
+ self.connect (self.u, self.src_fft)
+ vbox.Add (self.src_fft.win, 4, wx.EXPAND)
+
+ if 1:
+ post_deemph_fft = fftsink2.fft_sink_f (self.panel, title="Post Deemph",
+ fft_size=512, sample_rate=demod_rate,
+ y_per_div=10, ref_level=-20)
+ self.connect (self.guts.deemph, post_deemph_fft)
+ vbox.Add (post_deemph_fft.win, 4, wx.EXPAND)
+
+ if 1:
+ post_filt_fft = fftsink2.fft_sink_f (self.panel, title="Post Filter",
+ fft_size=512, sample_rate=audio_rate,
+ y_per_div=10, ref_level=0)
+ self.connect (self.guts.audio_filter, post_filt_fft)
+ vbox.Add (post_filt_fft.win, 4, wx.EXPAND)
+
+
+ # control area form at bottom
+ self.myform = myform = form.form()
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+ myform['freq'] = form.float_field(
+ parent=self.panel, sizer=hbox, label="Freq", weight=1,
+ callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
+
+ hbox.Add((5,0), 0)
+ myform['freq_slider'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3,
+ range=(self.freq_min, self.freq_max, 0.0005e6),
+ callback=self.set_freq)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0)
+
+ myform['volume'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Volume",
+ weight=3, range=self.volume_range(),
+ callback=self.set_vol)
+ hbox.Add((5,0), 1)
+
+ g = self.u.get_gain_range()
+ myform['gain'] = \
+ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Gain",
+ weight=3, range=(g.start(), g.start(), g.step()),
+ callback=self.set_gain)
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ try:
+ self.knob = powermate.powermate(self.frame)
+ self.rot = 0
+ powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate)
+ powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button)
+ except:
+ print "FYI: No Powermate or Contour Knob found"
+
+
+ def on_rotate (self, event):
+ self.rot += event.delta
+ if (self.state == "FREQ"):
+ if self.rot >= 3:
+ self.set_freq(self.freq + .1e6)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_freq(self.freq - .1e6)
+ self.rot += 3
+ else:
+ step = self.volume_range()[2]
+ if self.rot >= 3:
+ self.set_vol(self.vol + step)
+ self.rot -= 3
+ elif self.rot <=-3:
+ self.set_vol(self.vol - step)
+ self.rot += 3
+
+ def on_button (self, event):
+ if event.value == 0: # button up
+ return
+ self.rot = 0
+ if self.state == "FREQ":
+ self.state = "VOL"
+ else:
+ self.state = "FREQ"
+ self.update_status_bar ()
+
+
+ def set_vol (self, vol):
+ g = self.volume_range()
+ self.vol = max(g[0], min(g[1], vol))
+ self.volume_control.set_k(10**(self.vol/10))
+ self.myform['volume'].set_value(self.vol)
+ self.update_status_bar ()
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+ """
+
+ r = self.u.set_center_freq(target_freq)
+
+ if r:
+ self.freq = target_freq
+ self.myform['freq'].set_value(target_freq) # update displayed value
+ self.myform['freq_slider'].set_value(target_freq) # update displayed value
+ self.update_status_bar()
+ self._set_status_msg("OK", 0)
+ return True
+
+ self._set_status_msg("Failed", 0)
+ return False
+
+ def set_gain(self, gain):
+ self.myform['gain'].set_value(gain) # update displayed value
+ self.u.set_gain(gain)
+
+ def update_status_bar (self):
+ msg = "Volume:%r Setting:%s" % (self.vol, self.state)
+ self._set_status_msg(msg, 1)
+ self.src_fft.set_baseband_freq(self.freq)
+
+ def volume_range(self):
+ return (-20.0, 0.0, 0.5)
+
+
+if __name__ == '__main__':
+ app = stdgui2.stdapp (wxapt_rx_block, "USRP WXAPT RX")
+ app.MainLoop ()