summaryrefslogtreecommitdiff
path: root/gr-uhd
diff options
context:
space:
mode:
Diffstat (limited to 'gr-uhd')
-rw-r--r--gr-uhd/Makefile.am2
-rw-r--r--gr-uhd/apps/Makefile.am10
-rw-r--r--gr-uhd/apps/hf_explorer/.gitignore3
-rw-r--r--gr-uhd/apps/hf_explorer/Makefile.am31
-rw-r--r--gr-uhd/apps/hf_explorer/README42
-rwxr-xr-xgr-uhd/apps/hf_explorer/hfx.py823
-rw-r--r--gr-uhd/apps/hf_explorer/hfx_help180
-rw-r--r--gr-uhd/apps/hf_radio/.gitignore3
-rw-r--r--gr-uhd/apps/hf_radio/Makefile.am39
-rw-r--r--gr-uhd/apps/hf_radio/README.TXT60
-rw-r--r--gr-uhd/apps/hf_radio/hfir.sci59
-rw-r--r--gr-uhd/apps/hf_radio/input.py78
-rw-r--r--gr-uhd/apps/hf_radio/output.py42
-rwxr-xr-xgr-uhd/apps/hf_radio/radio.py319
-rw-r--r--gr-uhd/apps/hf_radio/radio.xml441
-rw-r--r--gr-uhd/apps/hf_radio/ssb_taps1023
-rw-r--r--gr-uhd/apps/hf_radio/ssbagc.py70
-rw-r--r--gr-uhd/apps/hf_radio/ssbdemod.py116
-rw-r--r--gr-uhd/apps/hf_radio/startup.py1
-rwxr-xr-xgr-uhd/apps/hf_radio/ui.py316
-rwxr-xr-xgr-uhd/apps/uhd_fft.py58
-rwxr-xr-xgr-uhd/apps/uhd_rx_nogui.py233
-rwxr-xr-xgr-uhd/apps/uhd_siggen.py350
-rwxr-xr-xgr-uhd/apps/uhd_siggen_gui.py318
-rw-r--r--gr-uhd/doc/.gitignore2
-rw-r--r--gr-uhd/doc/Makefile.am27
-rw-r--r--gr-uhd/doc/README.uhd14
-rw-r--r--gr-uhd/doc/uhd.dox35
-rw-r--r--gr-uhd/examples/.gitignore5
-rw-r--r--gr-uhd/examples/Makefile.am44
-rwxr-xr-xgr-uhd/examples/fm_tx4.py205
-rwxr-xr-xgr-uhd/examples/fm_tx_2_daughterboards.py203
-rwxr-xr-xgr-uhd/examples/max_power.py142
-rw-r--r--gr-uhd/examples/multi-antenna/.gitignore11
-rw-r--r--gr-uhd/examples/multi-antenna/Makefile.am29
-rwxr-xr-xgr-uhd/examples/multi-antenna/multi_fft.py152
-rwxr-xr-xgr-uhd/examples/multi-antenna/multi_file.py134
-rwxr-xr-xgr-uhd/examples/multi-antenna/multi_scope.py139
-rwxr-xr-xgr-uhd/examples/usrp_am_mw_rcv.py312
-rwxr-xr-xgr-uhd/examples/usrp_nbfm_ptt.py474
-rwxr-xr-xgr-uhd/examples/usrp_nbfm_rcv.py376
-rwxr-xr-xgr-uhd/examples/usrp_spectrum_sense.py243
-rwxr-xr-xgr-uhd/examples/usrp_tv_rcv.py436
-rwxr-xr-xgr-uhd/examples/usrp_tv_rcv_nogui.py206
-rwxr-xr-xgr-uhd/examples/usrp_wfm_rcv.py280
-rwxr-xr-xgr-uhd/examples/usrp_wfm_rcv2_nogui.py151
-rwxr-xr-xgr-uhd/examples/usrp_wfm_rcv_fmdet.py347
-rwxr-xr-xgr-uhd/examples/usrp_wfm_rcv_nogui.py168
-rwxr-xr-xgr-uhd/examples/usrp_wfm_rcv_pll.py340
-rwxr-xr-xgr-uhd/examples/usrp_wfm_rcv_sca.py397
-rwxr-xr-xgr-uhd/examples/usrp_wxapt_rcv.py276
-rw-r--r--gr-uhd/include/gr_uhd_amsg_source.h4
-rw-r--r--gr-uhd/include/gr_uhd_usrp_sink.h1
-rw-r--r--gr-uhd/include/gr_uhd_usrp_source.h1
-rw-r--r--gr-uhd/swig/Makefile.swig.gen2
-rw-r--r--gr-uhd/swig/__init__.py6
56 files changed, 9745 insertions, 34 deletions
diff --git a/gr-uhd/Makefile.am b/gr-uhd/Makefile.am
index ea16c863c..56829e9c4 100644
--- a/gr-uhd/Makefile.am
+++ b/gr-uhd/Makefile.am
@@ -21,7 +21,7 @@
include $(top_srcdir)/Makefile.common
-SUBDIRS = include lib apps
+SUBDIRS = include lib apps examples doc
if PYTHON
SUBDIRS += swig grc
diff --git a/gr-uhd/apps/Makefile.am b/gr-uhd/apps/Makefile.am
index 9bb9b6cdd..c30a143c2 100644
--- a/gr-uhd/apps/Makefile.am
+++ b/gr-uhd/apps/Makefile.am
@@ -24,9 +24,13 @@ include $(top_srcdir)/Makefile.common
EXTRA_DIST += \
$(bin_SCRIPTS)
+SUBDIRS = hf_explorer hf_radio
+
ourpythondir = $(grpythondir)
bin_SCRIPTS = \
- uhd_fft.py \
- uhd_rx_cfile.py
-
+ uhd_fft.py \
+ uhd_rx_cfile.py \
+ uhd_siggen.py \
+ uhd_siggen_gui.py \
+ uhd_rx_nogui.py
diff --git a/gr-uhd/apps/hf_explorer/.gitignore b/gr-uhd/apps/hf_explorer/.gitignore
new file mode 100644
index 000000000..b6950912c
--- /dev/null
+++ b/gr-uhd/apps/hf_explorer/.gitignore
@@ -0,0 +1,3 @@
+/Makefile
+/Makefile.in
+/*.pyc
diff --git a/gr-uhd/apps/hf_explorer/Makefile.am b/gr-uhd/apps/hf_explorer/Makefile.am
new file mode 100644
index 000000000..c8e7ecb25
--- /dev/null
+++ b/gr-uhd/apps/hf_explorer/Makefile.am
@@ -0,0 +1,31 @@
+#
+# Copyright 2006,2009 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 $(top_srcdir)/Makefile.common
+
+ourdatadir = $(exampledir)/hf_explorer
+
+dist_ourdata_DATA = \
+ README \
+ hfx_help
+
+dist_ourdata_SCRIPTS = \
+ hfx.py
diff --git a/gr-uhd/apps/hf_explorer/README b/gr-uhd/apps/hf_explorer/README
new file mode 100644
index 000000000..57f45ceba
--- /dev/null
+++ b/gr-uhd/apps/hf_explorer/README
@@ -0,0 +1,42 @@
+hfx.py is meant to be a full-featured Long Wave / Medium Wave
+and Short Wave (250kHz to 30Mhz) AM and Single Sideband receiver.
+It uses the USRP with a Basic RX board, and will need an
+antenna and some preamps, about 30db gain will work. See the
+'Help' menu or hfx_help for more info.
+
+----------------------------------------------------------
+
+Powermate knob supported but not required, tooltip frequency display,
+single click tuning, AGC, record to disk, play from disk and record
+audio. Ability to tailor the audio passband with two sliders over the
+spectrum display. The sliders almost align with the actual
+frequency. Preset filter settings for LSB (-3000 to 0kHz), USB (0 to
++3000kHz), CW (-400 to -800Hz) and AM (-5kHz from carrier to +5kHz).
+
+AM now switches in a synchronous PLL detector with the carriers at
+7.5kHz. The PLL carrier is displayed in the bottom display and helps
+show where on the upper spectrum the demodulated signal
+lies. Everything gets shifted up 7.5kHz in AM, center frequency,
+tooltips, etc. The target AM carrier needs to be closely tuned in, it
+will have a hollow sound untill it is locked, and then the PLL carrier
+in the bottom display will jump up and remain relatively
+constant. There is a slider "AM sync carrier" to play with different
+levels to mix with the signal for demodulation. The filter in AM is
+preset to 2500/12500 (7.5kHz +/- 5kHz) and is handy for removing
+adjacent channel interference. Change AM_SYNC_DISPLAY in script for
+whether to show AM Sync carrier or not.
+
+Run with "-h" for command line help with setting USRP ddc center
+frequency, decimation, rf data record, playback and audio data
+recording.
+
+There are some controls for controlling a varactor and tuning an
+antenna - just ignore them unless you want to build a voltage tuned
+antenna to track frequency.
+
+There is also code for Web based control of frequency and volume - so
+I can tune the radio with an Ipaq from bed. Disabled by default - it
+takes a web server, some directories and scripts to use.
+
+
+
diff --git a/gr-uhd/apps/hf_explorer/hfx.py b/gr-uhd/apps/hf_explorer/hfx.py
new file mode 100755
index 000000000..687adf82b
--- /dev/null
+++ b/gr-uhd/apps/hf_explorer/hfx.py
@@ -0,0 +1,823 @@
+#!/usr/bin/env python
+# generated by wxGlade 0.4 on Tue Mar 14 10:16:06 2006
+#
+# Copyright 2006,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.
+#
+#-----------------------------------------------------------------
+#
+# +-->(fft)
+# |
+# (src)->(xlate)--+->(audio filter)--+-->(sel_am)-+--------------+
+# | | |
+# | (pll) |
+# | | |
+# | (pll_carrier_scale) |
+# | | |
+# | (pll_carrier_filter) |
+# | | |
+# | +--(fft2) |
+# | | |
+# | +--(c2f3)--+ |
+# | | | |
+# | (phaser1) (phaser2) |
+# | | | |
+# | +--(f2c)---+ |
+# | | V
+# V +---------->(am_det)
+# (c2f) |
+# | (c2f2)
+# | |
+# +-->(sel_sb)------------>(combine)
+# |
+# V
+# +--------------------------(scale)
+# | |
+# | |
+# | +++
+# V | |
+# (agc)<--(offset)<--(intr)<---(sqr1)
+# |
+# V
+# (dst)
+#
+#----------------------------------------------------------------------
+#
+# Versions 2.2.1 adds loop antenna automatic tuner
+#
+# 2.3.1 adds web control, made AM Sync display optional,
+# added more comments.
+#
+# 2.4.1 updates usrp interface to support auto subdev
+#
+# 2.8.1 changed saved file format from 8-byte complex to
+# 4-byte short for obvious storage space savings.
+
+# Web server control disabled by default. Do not enable
+# until directory structure and scripts are in place.
+WEB_CONTROL = False
+
+# Controls display of AM Sync Carrier - turn off for smaller
+# window if not needed
+AM_SYNC_DISPLAY = False
+
+import os, wx, sys, math
+import wx.lib.evtmgr as em
+from gnuradio.wxgui import powermate, fftsink2
+from gnuradio import gr, audio, eng_notation
+from gnuradio.eng_option import eng_option
+from gnuradio import uhd
+from optparse import OptionParser
+
+n2s = eng_notation.num_to_str
+
+ID_BUTTON_1 = wx.NewId() # LSB button
+ID_BUTTON_2 = wx.NewId() # USB
+ID_BUTTON_3 = wx.NewId() # AM
+ID_BUTTON_4 = wx.NewId() # CW
+ID_BUTTON_5 = wx.NewId() # Powermate controls: Upper audio freq cutoff
+ID_BUTTON_6 = wx.NewId() # " Lower audio freq cutoff
+ID_BUTTON_7 = wx.NewId() # " Frequency
+ID_BUTTON_8 = wx.NewId() # " Volume
+ID_BUTTON_9 = wx.NewId() # " Time
+ID_BUTTON_10 = wx.NewId() # Time Seek Forwards
+ID_BUTTON_11 = wx.NewId() # Time Seek Backwards
+ID_BUTTON_12 = wx.NewId() # Automatic Antenna Tune (AT) enable
+ID_BUTTON_13 = wx.NewId() # AT Calibrate point
+ID_BUTTON_14 = wx.NewId() # AT Reset
+ID_TEXT_1 = wx.NewId() # Band Center, USRP ddc Freq
+ID_SPIN_1 = wx.NewId() # Frequency display and control
+ID_SLIDER_1 = wx.NewId() # Upper audio freq cutoff
+ID_SLIDER_2 = wx.NewId() # Lower audio freq cutoff
+ID_SLIDER_3 = wx.NewId() # Frequency
+ID_SLIDER_4 = wx.NewId() # Volume
+ID_SLIDER_5 = wx.NewId() # Programmable Gain Amp, PGA, RF gain
+ID_SLIDER_6 = wx.NewId() # AM Sync carrier level
+ID_SLIDER_7 = wx.NewId() # AT control voltage output
+ID_EXIT = wx.NewId() # Menu Exit
+
+
+class MyFrame(wx.Frame):
+ def __init__(self, *args, **kwds):
+ # begin wxGlade: MyFrame.__init__
+ kwds["style"] = wx.DEFAULT_FRAME_STYLE
+ wx.Frame.__init__(self, *args, **kwds)
+
+ # Menu Bar
+ self.frame_1_menubar = wx.MenuBar()
+ self.SetMenuBar(self.frame_1_menubar)
+ wxglade_tmp_menu = wx.Menu()
+ self.Exit = wx.MenuItem(wxglade_tmp_menu, ID_EXIT, "Exit",
+ "Exit", wx.ITEM_NORMAL)
+ wxglade_tmp_menu.AppendItem(self.Exit)
+ self.frame_1_menubar.Append(wxglade_tmp_menu, "File")
+ # Menu Bar end
+ self.panel_1 = wx.Panel(self, -1)
+ self.button_1 = wx.Button(self, ID_BUTTON_1, "LSB")
+ self.button_2 = wx.Button(self, ID_BUTTON_2, "USB")
+ self.button_3 = wx.Button(self, ID_BUTTON_3, "AM")
+ self.button_4 = wx.Button(self, ID_BUTTON_4, "CW")
+ self.button_5 = wx.ToggleButton(self, ID_BUTTON_5, "Upper")
+ self.slider_fcutoff_hi = wx.Slider(self, ID_SLIDER_1, 0, -15798, 15799,
+ style=wx.SL_HORIZONTAL|wx.SL_LABELS)
+ self.button_6 = wx.ToggleButton(self, ID_BUTTON_6, "Lower")
+ self.slider_fcutoff_lo = wx.Slider(self, ID_SLIDER_2, 0, -15799, 15798,
+ style=wx.SL_HORIZONTAL|wx.SL_LABELS)
+ self.panel_5 = wx.Panel(self, -1)
+ self.label_1 = wx.StaticText(self, -1, " Band\nCenter")
+ self.text_ctrl_1 = wx.TextCtrl(self, ID_TEXT_1, "")
+ self.panel_6 = wx.Panel(self, -1)
+ self.panel_7 = wx.Panel(self, -1)
+ self.panel_2 = wx.Panel(self, -1)
+ self.button_7 = wx.ToggleButton(self, ID_BUTTON_7, "Freq")
+ self.slider_3 = wx.Slider(self, ID_SLIDER_3, 3000, 0, 6000)
+ self.spin_ctrl_1 = wx.SpinCtrl(self, ID_SPIN_1, "", min=0, max=100)
+ self.button_8 = wx.ToggleButton(self, ID_BUTTON_8, "Vol")
+ self.slider_4 = wx.Slider(self, ID_SLIDER_4, 0, 0, 500)
+ self.slider_5 = wx.Slider(self, ID_SLIDER_5, 0, 0, 20)
+ self.button_9 = wx.ToggleButton(self, ID_BUTTON_9, "Time")
+ self.button_11 = wx.Button(self, ID_BUTTON_11, "Rew")
+ self.button_10 = wx.Button(self, ID_BUTTON_10, "Fwd")
+ self.panel_3 = wx.Panel(self, -1)
+ self.label_2 = wx.StaticText(self, -1, "PGA ")
+ self.panel_4 = wx.Panel(self, -1)
+ self.panel_8 = wx.Panel(self, -1)
+ self.panel_9 = wx.Panel(self, -1)
+ self.label_3 = wx.StaticText(self, -1, "AM Sync\nCarrier")
+ self.slider_6 = wx.Slider(self, ID_SLIDER_6, 50, 0, 200,
+ style=wx.SL_HORIZONTAL|wx.SL_LABELS)
+ self.label_4 = wx.StaticText(self, -1, "Antenna Tune")
+ self.slider_7 = wx.Slider(self, ID_SLIDER_7, 1575, 950, 2200,
+ style=wx.SL_HORIZONTAL|wx.SL_LABELS)
+ self.panel_10 = wx.Panel(self, -1)
+ self.button_12 = wx.ToggleButton(self, ID_BUTTON_12, "Auto Tune")
+ self.button_13 = wx.Button(self, ID_BUTTON_13, "Calibrate")
+ self.button_14 = wx.Button(self, ID_BUTTON_14, "Reset")
+ self.panel_11 = wx.Panel(self, -1)
+ self.panel_12 = wx.Panel(self, -1)
+
+ self.__set_properties()
+ self.__do_layout()
+ # end wxGlade
+
+ parser = OptionParser (option_class=eng_option)
+ parser.add_option("", "--address", type="string", default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ parser.add_option ("-c", "--ddc-freq", type="eng_float", default=3.9e6,
+ help="set Rx DDC frequency to FREQ", metavar="FREQ")
+ parser.add_option ("-s", "--samp-rate", type="eng_float", default=256e3,
+ help="set sample rate (bandwidth) [default=%default]")
+ parser.add_option ("-a", "--audio_file", default="",
+ help="audio output file", metavar="FILE")
+ parser.add_option ("-r", "--radio_file", default="",
+ help="radio output file", metavar="FILE")
+ parser.add_option ("-i", "--input_file", default="",
+ help="radio input file", metavar="FILE")
+ parser.add_option ("-O", "--audio-output", type="string", default="",
+ help="audio output device name. E.g., hw:0,0, /dev/dsp, or pulse")
+
+ (options, args) = parser.parse_args ()
+
+ self.usrp_center = options.ddc_freq
+ input_rate = options.samp_rate
+ self.slider_range = input_rate * 0.9375
+ self.f_lo = self.usrp_center - (self.slider_range/2)
+ self.f_hi = self.usrp_center + (self.slider_range/2)
+ self.af_sample_rate = 32000
+ fir_decim = long (input_rate / self.af_sample_rate)
+
+ # data point arrays for antenna tuner
+ self.xdata = []
+ self.ydata = []
+
+ self.tb = gr.top_block()
+
+ # radio variables, initial conditions
+ self.frequency = self.usrp_center
+ # these map the frequency slider (0-6000) to the actual range
+ self.f_slider_offset = self.f_lo
+ self.f_slider_scale = 10000
+ self.spin_ctrl_1.SetRange(self.f_lo,self.f_hi)
+ self.text_ctrl_1.SetValue(str(int(self.usrp_center)))
+ self.slider_5.SetValue(0)
+ self.AM_mode = False
+
+ self.slider_3.SetValue((self.frequency-self.f_slider_offset)/self.f_slider_scale)
+ self.spin_ctrl_1.SetValue(int(self.frequency))
+
+ POWERMATE = True
+ try:
+ self.pm = powermate.powermate(self)
+ except:
+ sys.stderr.write("Unable to find PowerMate or Contour Shuttle\n")
+ POWERMATE = False
+
+ if POWERMATE:
+ powermate.EVT_POWERMATE_ROTATE(self, self.on_rotate)
+ powermate.EVT_POWERMATE_BUTTON(self, self.on_pmButton)
+ self.active_button = 7
+
+ # command line options
+ if options.audio_file == "": SAVE_AUDIO_TO_FILE = False
+ else: SAVE_AUDIO_TO_FILE = True
+ if options.radio_file == "": SAVE_RADIO_TO_FILE = False
+ else: SAVE_RADIO_TO_FILE = True
+ if options.input_file == "": self.PLAY_FROM_USRP = True
+ else: self.PLAY_FROM_USRP = False
+
+ if self.PLAY_FROM_USRP:
+ self.src = uhd.usrp_source(device_addr=options.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+ self.src.set_samp_rate(input_rate)
+ input_rate = self.src.get_samp_rate()
+
+ self.src.set_center_freq(self.usrp_center, 0)
+ self.tune_offset = 0
+
+ else:
+ self.src = gr.file_source (gr.sizeof_short,options.input_file)
+ self.tune_offset = 2200 # 2200 works for 3.5-4Mhz band
+
+ # convert rf data in interleaved short int form to complex
+ s2ss = gr.stream_to_streams(gr.sizeof_short,2)
+ s2f1 = gr.short_to_float()
+ s2f2 = gr.short_to_float()
+ src_f2c = gr.float_to_complex()
+ self.tb.connect(self.src,s2ss)
+ self.tb.connect((s2ss,0),s2f1)
+ self.tb.connect((s2ss,1),s2f2)
+ self.tb.connect(s2f1,(src_f2c,0))
+ self.tb.connect(s2f2,(src_f2c,1))
+
+ # save radio data to a file
+ if SAVE_RADIO_TO_FILE:
+ radio_file = gr.file_sink(gr.sizeof_short, options.radio_file)
+ self.tb.connect (self.src, radio_file)
+
+ # 2nd DDC
+ xlate_taps = gr.firdes.low_pass ( \
+ 1.0, input_rate, 16e3, 4e3, gr.firdes.WIN_HAMMING )
+ self.xlate = gr.freq_xlating_fir_filter_ccf ( \
+ fir_decim, xlate_taps, self.tune_offset, input_rate )
+
+ # Complex Audio filter
+ audio_coeffs = gr.firdes.complex_band_pass (
+ 1.0, # gain
+ self.af_sample_rate, # sample rate
+ -3000, # low cutoff
+ 0, # high cutoff
+ 100, # transition
+ gr.firdes.WIN_HAMMING) # window
+ self.slider_fcutoff_hi.SetValue(0)
+ self.slider_fcutoff_lo.SetValue(-3000)
+
+ self.audio_filter = gr.fir_filter_ccc(1, audio_coeffs)
+
+ # Main +/- 16Khz spectrum display
+ self.fft = fftsink2.fft_sink_c(self.panel_2, fft_size=512,
+ sample_rate=self.af_sample_rate,
+ average=True, size=(640,240))
+
+ # AM Sync carrier
+ if AM_SYNC_DISPLAY:
+ self.fft2 = fftsink.fft_sink_c(self.tb, self.panel_9,
+ y_per_div=20, fft_size=512,
+ sample_rate=self.af_sample_rate,
+ average=True, size=(640,240))
+
+ c2f = gr.complex_to_float()
+
+ # AM branch
+ self.sel_am = gr.multiply_const_cc(0)
+ # the following frequencies turn out to be in radians/sample
+ # gr.pll_refout_cc(alpha,beta,min_freq,max_freq)
+ # suggested alpha = X, beta = .25 * X * X
+ pll = gr.pll_refout_cc(.5,.0625,(2.*math.pi*7.5e3/self.af_sample_rate),
+ (2.*math.pi*6.5e3/self.af_sample_rate))
+ self.pll_carrier_scale = gr.multiply_const_cc(complex(10,0))
+ am_det = gr.multiply_cc()
+ # these are for converting +7.5kHz to -7.5kHz
+ # for some reason gr.conjugate_cc() adds noise ??
+ c2f2 = gr.complex_to_float()
+ c2f3 = gr.complex_to_float()
+ f2c = gr.float_to_complex()
+ phaser1 = gr.multiply_const_ff(1)
+ phaser2 = gr.multiply_const_ff(-1)
+
+ # filter for pll generated carrier
+ pll_carrier_coeffs = gr.firdes.complex_band_pass (
+ 2.0, # gain
+ self.af_sample_rate, # sample rate
+ 7400, # low cutoff
+ 7600, # high cutoff
+ 100, # transition
+ gr.firdes.WIN_HAMMING) # window
+
+ self.pll_carrier_filter = gr.fir_filter_ccc (1, pll_carrier_coeffs)
+
+ self.sel_sb = gr.multiply_const_ff(1)
+ combine = gr.add_ff()
+
+ #AGC
+ sqr1 = gr.multiply_ff()
+ intr = gr.iir_filter_ffd ( [.004, 0], [0, .999] )
+ offset = gr.add_const_ff(1)
+ agc = gr.divide_ff()
+
+ self.scale = gr.multiply_const_ff(0.00001)
+ dst = audio.sink(long(self.af_sample_rate),
+ options.audio_output)
+
+
+ if self.PLAY_FROM_USRP:
+ self.tb.connect(self.src, self.xlate, self.fft)
+ else:
+ self.tb.connect(src_f2c, self.xlate, self.fft)
+
+ self.tb.connect(self.xlate,self.audio_filter,self.sel_am,(am_det,0))
+ self.tb.connect(self.sel_am,pll,self.pll_carrier_scale,
+ self.pll_carrier_filter,c2f3)
+ self.tb.connect((c2f3,0),phaser1,(f2c,0))
+ self.tb.connect((c2f3,1),phaser2,(f2c,1))
+ self.tb.connect(f2c,(am_det,1))
+ self.tb.connect(am_det,c2f2,(combine,0))
+ self.tb.connect(self.audio_filter,c2f,
+ self.sel_sb,(combine,1))
+
+ if AM_SYNC_DISPLAY:
+ self.tb.connect(self.pll_carrier_filter,self.fft2)
+
+ self.tb.connect(combine,self.scale)
+ self.tb.connect(self.scale,(sqr1,0))
+ self.tb.connect(self.scale,(sqr1,1))
+ self.tb.connect(sqr1, intr, offset, (agc, 1))
+ self.tb.connect(self.scale,(agc, 0))
+ self.tb.connect(agc,dst)
+
+ if SAVE_AUDIO_TO_FILE:
+ f_out = gr.file_sink(gr.sizeof_short,options.audio_file)
+ sc1 = gr.multiply_const_ff(64000)
+ f2s1 = gr.float_to_short()
+ self.tb.connect(agc,sc1,f2s1,f_out)
+
+ self.tb.start()
+
+ # for mouse position reporting on fft display
+ self.fft.win.Bind(wx.EVT_LEFT_UP, self.Mouse)
+ # and left click to re-tune
+ self.fft.win.Bind(wx.EVT_LEFT_DOWN, self.Click)
+
+ # start a timer to check for web commands
+ if WEB_CONTROL:
+ self.timer = UpdateTimer(self, 1000) # every 1000 mSec, 1 Sec
+
+
+ wx.EVT_BUTTON(self,ID_BUTTON_1,self.set_lsb)
+ wx.EVT_BUTTON(self,ID_BUTTON_2,self.set_usb)
+ wx.EVT_BUTTON(self,ID_BUTTON_3,self.set_am)
+ wx.EVT_BUTTON(self,ID_BUTTON_4,self.set_cw)
+ wx.EVT_BUTTON(self,ID_BUTTON_10,self.fwd)
+ wx.EVT_BUTTON(self,ID_BUTTON_11,self.rew)
+ wx.EVT_BUTTON(self, ID_BUTTON_13, self.AT_calibrate)
+ wx.EVT_BUTTON(self, ID_BUTTON_14, self.AT_reset)
+ wx.EVT_TOGGLEBUTTON(self,ID_BUTTON_5,self.on_button)
+ wx.EVT_TOGGLEBUTTON(self,ID_BUTTON_6,self.on_button)
+ wx.EVT_TOGGLEBUTTON(self,ID_BUTTON_7,self.on_button)
+ wx.EVT_TOGGLEBUTTON(self,ID_BUTTON_8,self.on_button)
+ wx.EVT_TOGGLEBUTTON(self,ID_BUTTON_9,self.on_button)
+ wx.EVT_SLIDER(self,ID_SLIDER_1,self.set_filter)
+ wx.EVT_SLIDER(self,ID_SLIDER_2,self.set_filter)
+ wx.EVT_SLIDER(self,ID_SLIDER_3,self.slide_tune)
+ wx.EVT_SLIDER(self,ID_SLIDER_4,self.set_volume)
+ wx.EVT_SLIDER(self,ID_SLIDER_5,self.set_pga)
+ wx.EVT_SLIDER(self,ID_SLIDER_6,self.am_carrier)
+ wx.EVT_SLIDER(self,ID_SLIDER_7,self.antenna_tune)
+ wx.EVT_SPINCTRL(self,ID_SPIN_1,self.spin_tune)
+
+ wx.EVT_MENU(self, ID_EXIT, self.TimeToQuit)
+
+ def __set_properties(self):
+ # begin wxGlade: MyFrame.__set_properties
+ self.SetTitle("HF Explorer")
+ self.slider_fcutoff_hi.SetMinSize((450, 38))
+ self.slider_fcutoff_lo.SetMinSize((450, 38))
+ self.panel_2.SetMinSize((640, 240))
+ self.button_7.SetValue(1)
+ self.slider_3.SetMinSize((450, 19))
+ self.slider_4.SetMinSize((275, 19))
+ self.slider_5.SetMinSize((275, 19))
+ if AM_SYNC_DISPLAY:
+ self.panel_9.SetMinSize((640, 240))
+ self.slider_6.SetMinSize((300, 38))
+ self.slider_7.SetMinSize((400, 38))
+ # end wxGlade
+
+ def __do_layout(self):
+ # begin wxGlade: MyFrame.__do_layout
+ sizer_1 = wx.BoxSizer(wx.VERTICAL)
+ grid_sizer_1 = wx.FlexGridSizer(11, 2, 0, 0)
+ sizer_7 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_5 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_6 = wx.BoxSizer(wx.VERTICAL)
+ sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
+ grid_sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0)
+ sizer_2.Add(self.button_1, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_2.Add(self.button_2, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_2.Add(self.button_3, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_2.Add(self.button_4, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(self.button_5, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(self.slider_fcutoff_hi, 0,
+ wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(self.button_6, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(self.slider_fcutoff_lo, 0,
+ wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE, 0)
+ sizer_6.Add(self.panel_5, 1, wx.EXPAND, 0)
+ sizer_6.Add(self.label_1, 0,
+ wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE, 0)
+ sizer_6.Add(self.text_ctrl_1, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_6.Add(self.panel_6, 1, wx.EXPAND, 0)
+ sizer_6.Add(self.panel_7, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(sizer_6, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(self.panel_2, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(self.button_7, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_3.Add(self.slider_3, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_3.Add(self.spin_ctrl_1, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(sizer_3, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(self.button_8, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_4.Add(self.slider_4, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_4.Add(self.slider_5, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(sizer_4, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(self.button_9, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_5.Add(self.button_11, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_5.Add(self.button_10, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_5.Add(self.panel_3, 1, wx.EXPAND, 0)
+ sizer_5.Add(self.label_2, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_5.Add(self.panel_4, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(sizer_5, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(self.panel_8, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(self.panel_9, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(self.label_3, 0,
+ wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(self.slider_6, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(self.label_4, 0,
+ wx.ALIGN_BOTTOM|wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(self.slider_7, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(self.panel_10, 1, wx.EXPAND, 0)
+ sizer_7.Add(self.button_12, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_7.Add(self.button_13, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_7.Add(self.button_14, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_7.Add(self.panel_11, 1, wx.EXPAND, 0)
+ sizer_7.Add(self.panel_12, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(sizer_7, 1, wx.EXPAND, 0)
+ sizer_1.Add(grid_sizer_1, 1, wx.EXPAND, 0)
+ self.SetAutoLayout(True)
+ self.SetSizer(sizer_1)
+ sizer_1.Fit(self)
+ sizer_1.SetSizeHints(self)
+ self.Layout()
+ # end wxGlade
+
+ # Menu exit
+ def TimeToQuit(self, event):
+ self.tb.stop()
+ self.Close(True)
+
+ # Powermate being turned
+ def on_rotate(self, event):
+ if self.active_button == 5:
+ self.slider_fcutoff_hi.SetValue(self.slider_fcutoff_hi.GetValue()+event.delta)
+ if self.slider_fcutoff_lo.GetValue() > (self.slider_fcutoff_hi.GetValue() - 200) :
+ self.slider_fcutoff_lo.SetValue(self.slider_fcutoff_hi.GetValue() - 200)
+ self.filter()
+ if self.active_button == 6:
+ self.slider_fcutoff_lo.SetValue(self.slider_fcutoff_lo.GetValue()+event.delta)
+ if self.slider_fcutoff_hi.GetValue() < (self.slider_fcutoff_lo.GetValue() + 200) :
+ self.slider_fcutoff_hi.SetValue(self.slider_fcutoff_lo.GetValue() + 200)
+ self.filter()
+ if self.active_button == 7:
+ new = max(0, min(6000, self.slider_3.GetValue() + event.delta))
+ self.slider_3.SetValue(new)
+ self.frequency = (self.f_slider_scale * new) + self.f_slider_offset
+ self.spin_ctrl_1.SetValue(self.frequency)
+ if self.AM_mode == False:
+ self.xlate.set_center_freq( self.usrp_center - (self.frequency - self.tune_offset))
+ else:
+ self.xlate.set_center_freq( self.usrp_center - (self.frequency - self.tune_offset - 7.5e3))
+ if self.button_12.GetValue():
+ self.auto_antenna_tune()
+ if self.active_button == 8:
+ new = max(0, min(500, self.slider_4.GetValue() + event.delta))
+ self.slider_4.SetValue(new)
+ self.scale.set_k(math.pow(10.,((self.slider_4.GetValue()-500.)/100.)))
+ if self.active_button == 9:
+ if self.PLAY_FROM_USRP == False:
+ if event.delta == -1:
+ self.src.seek(-1000000,gr.SEEK_CUR)
+ elif event.delta == 1:
+ self.src.seek(1000000,gr.SEEK_CUR)
+
+
+ # Powermate pressed to switch controlled function
+ def on_pmButton(self, event):
+ if event.value == 0:
+ if self.active_button == 5:
+ self.active_button = 6
+ self.button_5.SetValue(False)
+ self.button_6.SetValue(True)
+ elif self.active_button == 6:
+ self.active_button = 7
+ self.button_6.SetValue(False)
+ self.button_7.SetValue(True)
+ elif self.active_button == 7:
+ self.active_button = 8
+ self.button_7.SetValue(False)
+ self.button_8.SetValue(True)
+ elif self.active_button == 8:
+ self.active_button = 9
+ self.button_8.SetValue(False)
+ self.button_9.SetValue(True)
+ elif self.active_button == 9:
+ self.active_button = 5
+ self.button_9.SetValue(False)
+ self.button_5.SetValue(True)
+
+ # Clicking one PM control button turns the rest off
+ def on_button(self, event):
+ id = event.GetId()
+ if id == ID_BUTTON_5:
+ self.active_button = 5
+ self.button_6.SetValue(False)
+ self.button_7.SetValue(False)
+ self.button_8.SetValue(False)
+ self.button_9.SetValue(False)
+ if id == ID_BUTTON_6:
+ self.active_button = 6
+ self.button_5.SetValue(False)
+ self.button_7.SetValue(False)
+ self.button_8.SetValue(False)
+ self.button_9.SetValue(False)
+ if id == ID_BUTTON_7:
+ self.active_button = 7
+ self.button_5.SetValue(False)
+ self.button_6.SetValue(False)
+ self.button_8.SetValue(False)
+ self.button_9.SetValue(False)
+ if id == ID_BUTTON_8:
+ self.active_button = 8
+ self.button_5.SetValue(False)
+ self.button_6.SetValue(False)
+ self.button_7.SetValue(False)
+ self.button_9.SetValue(False)
+ if id == ID_BUTTON_9:
+ self.active_button = 9
+ self.button_5.SetValue(False)
+ self.button_6.SetValue(False)
+ self.button_7.SetValue(False)
+ self.button_8.SetValue(False)
+
+ # Make sure filter settings are legal
+ def set_filter(self, event):
+ slider = event.GetId()
+ slider1 = self.slider_fcutoff_hi.GetValue()
+ slider2 = self.slider_fcutoff_lo.GetValue()
+ if slider == ID_SLIDER_1:
+ if slider2 > (self.slider_fcutoff_hi.GetValue() - 200) :
+ self.slider_fcutoff_lo.SetValue(slider1 - 200)
+ elif slider == ID_SLIDER_2:
+ if slider1 < (self.slider_fcutoff_lo.GetValue() + 200) :
+ self.slider_fcutoff_hi.SetValue(slider2 + 200)
+ self.filter()
+
+ # Calculate taps and apply
+ def filter(self):
+ audio_coeffs = gr.firdes.complex_band_pass (
+ 1.0, # gain
+ self.af_sample_rate, # sample rate
+ self.slider_fcutoff_lo.GetValue(), # low cutoff
+ self.slider_fcutoff_hi.GetValue(), # high cutoff
+ 100, # transition
+ gr.firdes.WIN_HAMMING) # window
+ self.audio_filter.set_taps(audio_coeffs)
+
+ def set_lsb(self, event):
+ self.AM_mode = False
+ self.xlate.set_center_freq( self.usrp_center - (self.frequency - self.tune_offset))
+ self.sel_sb.set_k(1)
+ self.sel_am.set_k(0)
+ self.slider_fcutoff_hi.SetValue(0)
+ self.slider_fcutoff_lo.SetValue(-3000)
+ self.filter()
+
+ def set_usb(self, event):
+ self.AM_mode = False
+ self.xlate.set_center_freq( self.usrp_center - (self.frequency - self.tune_offset))
+ self.sel_sb.set_k(1)
+ self.sel_am.set_k(0)
+ self.slider_fcutoff_hi.SetValue(3000)
+ self.slider_fcutoff_lo.SetValue(0)
+ self.filter()
+
+ def set_am(self, event):
+ self.AM_mode = True
+ self.xlate.set_center_freq( self.usrp_center - (self.frequency - self.tune_offset - 7.5e3))
+ self.sel_sb.set_k(0)
+ self.sel_am.set_k(1)
+ self.slider_fcutoff_hi.SetValue(12500)
+ self.slider_fcutoff_lo.SetValue(2500)
+ self.filter()
+
+ def set_cw(self, event):
+ self.AM_mode = False
+ self.xlate.set_center_freq( self.usrp_center - (self.frequency - self.tune_offset))
+ self.AM_mode = False
+ self.sel_sb.set_k(1)
+ self.sel_am.set_k(0)
+ self.slider_fcutoff_hi.SetValue(-400)
+ self.slider_fcutoff_lo.SetValue(-800)
+ self.filter()
+
+ def set_volume(self, event):
+ self.scale.set_k(math.pow(10.,((self.slider_4.GetValue()-500.)/100.)))
+
+ def set_pga(self,event):
+ if self.PLAY_FROM_USRP:
+ self.src.set_gain(self.slider_5.GetValue())
+
+ def slide_tune(self, event):
+ self.frequency = (self.f_slider_scale * self.slider_3.GetValue()) + self.f_slider_offset
+ if self.AM_mode == False:
+ self.xlate.set_center_freq( self.usrp_center - (self.frequency - self.tune_offset))
+ else:
+ self.xlate.set_center_freq( self.usrp_center - (self.frequency - self.tune_offset - 7.5e3))
+ self.spin_ctrl_1.SetValue(self.frequency)
+ if self.button_12.GetValue():
+ self.auto_antenna_tune()
+
+ def spin_tune(self, event):
+ self.frequency = self.spin_ctrl_1.GetValue()
+ if self.AM_mode == False:
+ self.xlate.set_center_freq( self.usrp_center - (self.frequency - self.tune_offset))
+ else:
+ self.xlate.set_center_freq( self.usrp_center - (self.frequency - self.tune_offset - 7.5e3))
+ self.slider_3.SetValue(int((self.frequency-self.f_slider_offset)/self.f_slider_scale))
+ if self.button_12.GetValue():
+ self.auto_antenna_tune()
+
+ # Seek forwards in file
+ def fwd(self, event):
+ if self.PLAY_FROM_USRP == False:
+ self.src.seek(10000000,gr.SEEK_CUR)
+
+ # Seek backwards in file
+ def rew(self, event):
+ if self.PLAY_FROM_USRP == False:
+ self.src.seek(-10000000,gr.SEEK_CUR)
+
+ # Mouse over fft display - show frequency in tooltip
+ def Mouse(self,event):
+ if self.AM_mode:
+ fRel = ( event.GetX() - 330. ) / 14.266666 - 7.5
+ else:
+ fRel = ( event.GetX() - 330. ) / 14.266666
+ self.fft.win.SetToolTip(wx.ToolTip(eng_notation.num_to_str(self.frequency + (fRel*1e3))))
+
+ # Mouse clicked on fft display - change frequency
+ def Click(self,event):
+ fRel = ( event.GetX() - 330. ) / 14.266666
+ if self.AM_mode == False:
+ self.frequency = self.frequency + (fRel*1e3)
+ else:
+ self.frequency = self.frequency + (fRel*1e3) - 7.5e3
+ self.spin_ctrl_1.SetValue(int(self.frequency))
+ self.slider_3.SetValue(int((self.frequency-self.f_slider_offset)/self.f_slider_scale))
+ if self.AM_mode == False:
+ self.xlate.set_center_freq ( self.usrp_center - ( self.frequency - self.tune_offset ))
+ else:
+ self.xlate.set_center_freq( self.usrp_center - (self.frequency - self.tune_offset - 7.5e3))
+
+ # Set power of AM sync carrier
+ def am_carrier(self,event):
+ scale = math.pow(10,(self.slider_6.GetValue())/50.)
+ self.pll_carrier_scale.set_k(complex(scale,0))
+
+ # Reset AT data and start calibrate over
+ def AT_reset(self, event):
+ self.xdata = []
+ self.ydata = []
+
+ # Save AT setting for a particular frequency
+ def AT_calibrate(self, event):
+ self.xdata.append(float(self.frequency))
+ self.ydata.append(self.slider_7.GetValue())
+ if len(self.xdata) > 1:
+ self.m = []
+ self.b = []
+ for i in range(0,len(self.xdata)-1):
+ self.m.append( (self.ydata[i+1] - self.ydata[i]) / (self.xdata[i+1] - self.xdata[i]) )
+ self.b.append( self.ydata[i] - self.m[i] * self.xdata[i] )
+
+ # Lookup calibrated points and calculate interpolated antenna tune voltage.
+ # This is to automatically tune a narrowband loop antenna when the freq
+ # is changed, to keep signals peaked.
+ def auto_antenna_tune(self):
+ for i in range(0,len(self.xdata)-1):
+ if (self.frequency > self.xdata[i]) & (self.frequency < self.xdata[i+1]):
+ self.slider_7.SetValue(self.m[i]*self.frequency + self.b[i])
+ self.antenna_tune(0)
+
+ # Slider to set loop antenna capacitance
+ def antenna_tune(self, evt):
+ if self.PLAY_FROM_USRP:
+ dev = self.src.get_dboard_iface()
+ dev.write_aux_dac(uhd.dboard_iface.UNIT_RX,
+ uhd.dboard_iface.AUX_DAC_C,
+ float(self.slider_7.GetValue()))
+
+ # Timer events - check for web commands
+ def OnUpdate(self):
+ cmds = os.listdir("/var/www/cgi-bin/commands/")
+ if cmds!=[]:
+ if cmds[0]=='chfreq':
+ fd=open("/var/www/cgi-bin/commands/chfreq","r")
+ new=fd.readline()
+ fd.close()
+ if new!='':
+ os.unlink("/var/www/cgi-bin/commands/chfreq")
+ if ( int(new) >= self.f_lo ) & ( int(new) <= self.f_hi ):
+ self.frequency = int(new)
+ self.slider_3.SetValue(( self.frequency - self.f_slider_offset) / self.f_slider_scale )
+ self.spin_ctrl_1.SetValue(self.frequency)
+ if self.button_12.GetValue():
+ self.auto_antenna_tune()
+ if self.AM_mode:
+ self.xlate.set_center_freq ( self.usrp_center - ( self.frequency - self.tune_offset - 7.5e3 ))
+ else:
+ self.xlate.set_center_freq ( self.usrp_center - ( self.frequency - self.tune_offset ))
+
+ if cmds[0]=='chvolume':
+ fd=open("/var/www/cgi-bin/commands/chvolume","r")
+ new=fd.readline()
+ fd.close()
+ if new!='':
+ os.unlink("/var/www/cgi-bin/commands/chvolume")
+ if ( int(new) >= 0 ) & ( int(new) <= 500 ):
+ self.volume = int(new)
+ self.slider_4.SetValue(self.volume)
+ self.scale.set_k(math.pow(10.,((self.slider_4.GetValue()-500.)/100.)))
+
+ else: # no new web commands, update state
+ fh = open("/var/www/cgi-bin/state/freq","w")
+ fh.write(str(int(self.frequency))+'\n')
+ fh.close()
+ fh = open("/var/www/cgi-bin/state/volume","w")
+ fh.write(str(self.slider_4.GetValue())+'\n')
+ fh.close()
+
+
+# end of class MyFrame
+
+# wx.Timer to check for web updates
+class UpdateTimer(wx.Timer):
+ def __init__(self, target, dur=1000):
+ wx.Timer.__init__(self)
+ self.target = target
+ self.Start(dur)
+
+ def Notify(self):
+ """Called every timer interval"""
+ if self.target:
+ self.target.OnUpdate()
+
+
+class MyApp(wx.App):
+ def OnInit(self):
+ frame = MyFrame(None, -1, "HF Explorer")
+ frame.Show(True)
+ self.SetTopWindow(frame)
+ return True
+
+
+if __name__ == "__main__":
+ app = MyApp(0)
+ app.MainLoop()
+
diff --git a/gr-uhd/apps/hf_explorer/hfx_help b/gr-uhd/apps/hf_explorer/hfx_help
new file mode 100644
index 000000000..9a52dd2bb
--- /dev/null
+++ b/gr-uhd/apps/hf_explorer/hfx_help
@@ -0,0 +1,180 @@
+
+ HF Explorer Help
+
+ -----------------------------------------------------------------------
+
+ Command Line Switches:
+
+ -c DDC center frequency, set band.
+ -c 7.2e6 or -c 7.2M for 40 meter ham band.
+ Default is 3.9e6 80 meter ham band.
+ Example:
+
+ hfx.py -c 9500k
+
+ starts up in the 31 meter band.
+
+ -a Audio output file. Output file for 32kHz two channel
+ signed word audio. Two channels are used for
+ independent sideband. This file can be converted
+ to a wav file with sox. Example:
+
+ sox -c 2 -r 3200 file.sw file.wav
+
+ sox needs the .sw extension to indicate file type.
+ If not specified no audio file is created.
+
+ -r Radio output file. File to write RF data to for later
+ demodulation. Records the entire band to disk, width
+ determined by sample rate/decimation. Be sure to
+ note the decimation and center freq for later use!
+ Example:
+
+ hfx.py -c 900e3 -d 80 -r rf_data_AM-c900e3-d80
+
+ writes a pre-demod rf file centered on 900kHz with a
+ bandwidth of 800kHz (That's 80 AM stations!). The
+ center and decimation could be put in the filename for
+ proper use later.
+ If not specified no rf data file is created.
+ At default 250 decimation disk usage is about
+ 8Gb / hour.
+
+ -i Radio input file. Use to play back a previously
+ recorded rf data file. Example:
+
+ hfx.py -c 900e3 -d 80 -i rf_data_AM-c900e3-d80
+
+ plays back the previously recorded band, no
+ usrp hardware needed. Tune about the 800kHz wide band.
+ When playing a recorded file, time controls
+ fast-forward and rewind are available.
+
+ -d Decimation. Sets sample rate and bandwidth.
+ This is the factor that the usrp sample rate, 64e6,
+ is divided by. Default is 250 for 256kHz bandwidth
+ which is enough to record a ham band without
+ eating up disk space too fast. The 64e6 sample
+ rate limits the upper practical frequency to 32MHz.
+ The Basic RX transformer limits the lower frequency
+ to about 200kHz.
+
+
+ Powermate Knob:
+
+ A Powermate knob is recommended but not necessary. If a knob
+ is used, it is in one of 3 or 4 modes controlling frequency,
+ volume, filter and (if playing a recorded file) time.
+ Pushing the knob switches mode and the buttons on the HFX panel
+ change to show which mode is in effect. Then just turn the knob
+ to set frequency, volume, filter or go fast forward or rewind.
+
+
+ Bandswitch:
+
+ Across the top are a set of predefined bands and buttons
+ to rapidly switch to the center of that band. To change a band,
+ type the frequency in Hz into the box under "Center Frequency",
+ then press "Set" on the left, then the button you want to
+ program. From then on (untill the program is exited) pushing
+ that button takes you to that band. To make a band button
+ permenant edit the hfx.py script with whatever frequency you
+ want assigned to what button.
+
+
+ Frequency:
+
+ There are 6 ways to set the frequency.
+ 1) Move the slider with the mouse
+ 2) Use the Spin Control up/down arrows (very fine 1Hz control)
+ 3) Type the frequency in Hz into the Spin Control
+ 4) Turn the Powermate knob
+ 5) Web control.
+ 6) Clicking on the FFT display to set demod center. This is very
+ convenient for tuning +-15kHz when you see a signal on the
+ display. If in Lower Sideband, clicking just to the right of
+ a signal will tune to it immediately. Clicking several times
+ on the far right right or left of the display will rapidly
+ tune up or down the band.
+
+
+ Volume:
+
+ Move the volume slider with the mouse, or push the Powermate knob
+ untill the volume button is active, or click on the volume button,
+ then turn the knob. Volume can also be set by web control if web
+ control is setup and enabled.
+
+
+ Filter:
+
+ Similar to volume, switches in any of 30 audio filters from 600
+ to 3600Hz in Sideband or up to 5kHz in AM.
+
+
+ Mode:
+
+ Demodulation modes are chosen by clicking on the buttons for
+ Lower Sideband, Upper Sideband, or AM.
+
+
+ PGA:
+
+ PGA slider sets the rf gain in the Analog-to-Digital converter
+ before digitizing. 0 to 20db gain easily shows up on the FFT
+ display.
+
+
+ Time:
+
+ When playing back a recorded RF data file, you can enjoy the
+ freedom of rewinding or fast-forwarding. Replay a weak signal
+ or skip through annoying AM commercials.
+
+
+ Antennas and Preamps:
+
+ The USRP Basic RX board is not sensitive enough for anything but
+ the strongest signals. In my experience about 40 db of small
+ signal gain is required to make the HFX as sensitive as other
+ receivers. Some working amplifiers are the Ramsey PR-2 with 20db
+ gain, fairly low noise and more bandwidth than we can use here.
+ Also the amp modules from Advanced Receiver Research are nice.
+ I use an ARR 7-7.4MHz GaAsFET 29db amp with .5db noise at the
+ apex of a 40 meter dipole with excellent results. Another
+ amp I like is a Minicircuits ZHL-32A 29db amp but they are
+ expensive and hard to find. Also it may help to use some filters
+ to keep strong local signals from the ADC, or limit rf input
+ to the band of interest, etc.
+ Resonant outdoor antennas, like a dipole, in a low-noise (away
+ from consumer electronics) environment are nice. Long random wires
+ with a tuner work. I like a small indoor tuned loop made from 10ft
+ of 1/4" copper tube, a 365pf tuning cap and a pickup loop connected
+ to rg-58.
+
+
+ Web Control:
+
+ To control your radio remotely, ensure you have a web server
+ (Apache, etc) working and a compatible directory structure in
+ place. Directories /var/www/cgi-bin/commands and
+ /var/www/cgi-bin/state must already exist. You will need a
+ home page with forms and a set of scripts to put commands in
+ and put the current state on the home page. email me for further
+ help. Setting WEB_CONTROL to True in hfx.py turns on the timers
+ that check for commands and update the state.
+
+
+ IF Output:
+
+ There is a provision for outputting un-demodulated complex
+ through the audio out in stereo for use with Digital Radio
+ Mondial (DRM) or using a seperate demodulation program like
+ SDRadio (by I2PHD).
+ Set IF_OUTPUT to True in weaver_isb_am1_usrp4.py.
+
+
+ --Good luck and happy LW/MW/SW Exploring.
+ Chuck
+ chuckek@musicriver.homeunix.com
+
diff --git a/gr-uhd/apps/hf_radio/.gitignore b/gr-uhd/apps/hf_radio/.gitignore
new file mode 100644
index 000000000..b6950912c
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/.gitignore
@@ -0,0 +1,3 @@
+/Makefile
+/Makefile.in
+/*.pyc
diff --git a/gr-uhd/apps/hf_radio/Makefile.am b/gr-uhd/apps/hf_radio/Makefile.am
new file mode 100644
index 000000000..e514076f6
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/Makefile.am
@@ -0,0 +1,39 @@
+#
+# Copyright 2006,2009 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 $(top_srcdir)/Makefile.common
+
+ourdatadir = $(exampledir)/hf_radio
+
+dist_ourdata_DATA = \
+ hfir.sci \
+ radio.xml \
+ input.py \
+ output.py \
+ README.TXT \
+ ssbagc.py \
+ ssbdemod.py \
+ startup.py \
+ ssb_taps
+
+dist_ourdata_SCRIPTS = \
+ radio.py \
+ ui.py
diff --git a/gr-uhd/apps/hf_radio/README.TXT b/gr-uhd/apps/hf_radio/README.TXT
new file mode 100644
index 000000000..7c7edf5e0
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/README.TXT
@@ -0,0 +1,60 @@
+# 2008-02-07
+#
+# These files have not yet been update to use the new top_block/hier_block2
+# interfaces. Until someone does that, this files will no longer run.
+#
+
+
+The files in this directory implement a fairly simple HF radio that works
+with the basic rx daughter board on the USRP.
+
+Many thanks to the Gnu Radio folks for a great new way to waste large blocks
+of time in infinitely tweaking a huge number of free parameters.
+
+Start the receiver by running the radio.py in this directory. Or from the
+Python prompt type "from radio import *" and you'll get the prompt back
+with the receiver running. You can then poke around to see what's going on.
+
+There are two spectrum displays. One is the output of the USRP and displays
+about 300KHz of bandwidth centered at the current tuning freq. The other
+displays the output spectrum of the demodulator.
+
+The demodulator does AM demod using the complex modulus block from gr. It
+does SSB demod using the frequency translating fir filter as a complex
+hilbert transformer. The taps for this filter were generated using a program
+called Scilab and the Scilab program in the file hfir.sci. More details in
+the associated files.
+
+Tune the receiver using the spin buttons under the big frequency display.
+
+The agc block is a roll your own. The standard agc in the newer CVS updates
+seems to work but doesn't seem to have adjustable time constants or provide
+access to internal signal nodes which are used for the RSSI.
+
+The AGC authority (a sort of gain parameter) and the reference level used
+in the power to dB computagion can be adjusted using the spin buttons.
+
+The audio bandwidth can be similarly adjusted from about 50Hz to 10KHz.
+
+The GUI layout was produced using wxGlade. The file radio.xml is the GUI
+specification. It will produce a file called ui.py which is subclassed
+by classes defined in radio.py. The ui.py is purely generated by wxGlade
+all app specific code for the GUI is in radio.py.
+
+Most of the actual signal processing code is built up in the other included
+files using the hierarchical block facilities. This organization should
+make it easier to tweak to your heart's content.
+
+Known bugs weakness and other
+
+wxPython and wxGlade seem to conspire to insure that the layout can never
+be exactly what you have in mind.
+
+Some of the controls don't behave as one might like. wx spin controls
+and spin boxes only support integers so it is rather a nuisance to make
+units come out nice. In the process of development I came up with a reasonable
+kluge so there is a mixture of approaches.
+
+Enjoy.
+
+M. Revnell 2006-Jan-06
diff --git a/gr-uhd/apps/hf_radio/hfir.sci b/gr-uhd/apps/hf_radio/hfir.sci
new file mode 100644
index 000000000..a2d5e2a62
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/hfir.sci
@@ -0,0 +1,59 @@
+// designs a complex tap fir filter akin to the hilbert transformer.
+//
+// The hilbert transformer is classified as a linear phase fir
+// with allpass magnitude response and 90 degree phase response for
+// positive frequencies and -90 degrees phase for negative frequencies.
+// Or, if you prefer, normalized frequencies between .5 and 1 since
+// negative frequencies don't really have much meaning outside the complex
+// domain.
+//
+// Normally one would use the hilbert transformer in one leg of a complex
+// processing block and a compensating delay in the other.
+//
+// This one differs in the following respects:
+// It is low pass with a cutoff of .078125
+// The filter is a lowpass kaiser windowed filter with parameter 3
+// The phase response is 45 degrees for positive frequencies and -45
+// for negative frequencies.
+// The coefficent set is used in one path and the same coefficients
+// are used time reversed in the other. This results in the net effect
+// of +/- 90 degrees as in the usual hilbert application.
+//
+// The coefficient set can be used in the gnuradio frequency translating
+// fir filter for ssb demodulation.
+//
+// This isn't as computationally efficient as using the hilbert transformer
+// and compensating delay but fascinating none the less.
+//
+// This program is for the scilab language a very powerful free math
+// package similar to Matlab with infinitely better price/performace.
+//
+// compute the prototype lowpass fir
+// length is 255 (odd) for the same symmetry reasons as the hilbert transformer
+
+len = 1023;
+l2 = floor(len/2);
+md = l2 + 1;
+l3 = md + 1;
+
+h = wfir( 'lp', len, [10.0/256 0], 'kr', [3 0] );
+
+H = fft(h);
+
+H(1:l2)=H(1:l2)*exp(%i*%pi/4);
+H(md)=0+%i*0;
+H(l3:len)=H(l3:len)*exp(-%i*%pi/4);
+
+j=real(ifft(H));
+k(1:len)=j(len:-1:1);
+x=j+%i.*k;
+X=fft(x);
+plot(abs(X))
+
+f = file('open','taps')
+for i=(1:len)
+ fprintf( f, '%f%+fj', j(i), k(i) )
+end
+
+file('close',f)
+
diff --git a/gr-uhd/apps/hf_radio/input.py b/gr-uhd/apps/hf_radio/input.py
new file mode 100644
index 000000000..2626ddfb5
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/input.py
@@ -0,0 +1,78 @@
+# 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.
+#
+
+# Basic USRP setup and control.
+# It's only ever been tried with a basic rx daughter card.
+#
+# Imagine that the gnuradio boilerplate is here.
+#
+# M. Revnell 2005-Dec
+
+from gnuradio import gr
+from gnuradio import uhd
+
+class uhd_input(gr.hier_block2):
+ def __init__( self, address, samp_rate):
+ gr.hier_block2.__init__(self, "uhd_input",
+ gr.io_signature(0,0,0),
+ gr.io_signature(1,1,gr.sizeof_gr_complex))
+
+ self.src = uhd.usrp_source(device_addr=address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ self.src.set_samp_rate(samp_rate)
+ self.usrp_rate = self.src.get_samp_rate()
+
+ self.connect(self.src, self)
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency.
+
+ @param target_freq: frequency in Hz
+ @type: bool
+ """
+ r = self.src.set_center_freq(target_freq, 0)
+
+ if r:
+ self.freq = target_freq
+ return True
+ else:
+ return False
+
+ def get_freq(self):
+ return self.src.get_center_freq(0)
+
+ def set_gain(self, gain):
+ self.gain = gain
+ self.src.set_gain(gain, 0)
+
+ def add_options(parser):
+ parser.add_option("-a", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ parser.add_option("-A", "--antenna", type="string", default=None,
+ help="select Rx Antenna where appropriate")
+ 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)")
+ add_options = staticmethod(add_options)
diff --git a/gr-uhd/apps/hf_radio/output.py b/gr-uhd/apps/hf_radio/output.py
new file mode 100644
index 000000000..8ee7dc54c
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/output.py
@@ -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.
+#
+
+
+# Audio output with a volume control.
+#
+# M. Revnell 2005-Dec
+
+from gnuradio import gr, gru
+from gnuradio import audio
+
+class output( gr.hier_block2 ):
+ def __init__( self, rate, device ):
+ gr.hier_block2.__init__(self, "output",
+ gr.io_signature(1,1,gr.sizeof_float),
+ gr.io_signature(0,0,0))
+
+ self.vol = gr.multiply_const_ff( 0.1 )
+ self.out = audio.sink( int(rate), device )
+
+ self.connect( self, self.vol, self.out )
+
+ def set( self, val ):
+ self.vol.set_k( val )
+
diff --git a/gr-uhd/apps/hf_radio/radio.py b/gr-uhd/apps/hf_radio/radio.py
new file mode 100755
index 000000000..32e26c7eb
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/radio.py
@@ -0,0 +1,319 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+# GUI interactions and high level connections handled here.
+#
+# Interacts with classes defined by wxGlade in ui.py.
+#
+# M. Revnell 2006-Jan
+
+from threading import *
+import wx
+import wx.lib.evtmgr as em
+import time
+
+from gnuradio import gr, gru, eng_notation, optfir
+from gnuradio import audio
+from gnuradio import uhd
+from gnuradio import blks2
+from gnuradio.wxgui import fftsink2
+from gnuradio.wxgui import waterfallsink2
+from gnuradio.wxgui import scopesink2
+
+from input import *
+from output import *
+from ssbdemod import *
+from ssbagc import *
+from ui import *
+from math import log10
+
+class radio_top_block( gr.top_block ):
+ def __init__( self ):
+ gr.top_block.__init__(self, "radio_top_block")
+
+ self.address = "addr=192.168.11.2"
+ self.samp_rate = 256e3
+ self.freq = -2.5e6
+ self.gain = 0
+ self.src = uhd_input( self.address,
+ self.samp_rate)
+ self.src.set_freq(self.freq)
+ self.src.set_gain(self.gain)
+
+ self.fe_rate = self.src.usrp_rate
+ self.filter_decim = 1
+ self.audio_decim = 16
+ self.demod_rate = self.fe_rate / self.filter_decim
+ self.audio_rate = self.demod_rate / self.audio_decim
+ self.audio_dev = "pulse"
+
+ self.demod = ssb_demod( self.demod_rate, self.audio_rate )
+ self.agc = agc()
+ self.out = output( self.audio_rate, self.audio_dev )
+
+ self.connect( self.src, self.demod, self.agc, self.out )
+
+ def tune( self, freq ):
+ fe_target = -freq
+ self.src.set_freq( fe_target )
+ demod_cf = fe_target - self.src.get_freq()
+ self.demod.tune( demod_cf )
+
+class radio_frame( ui_frame ):
+ def __init__( self, block, *args, **kwds ):
+ ui_frame.__init__( self, *args, **kwds )
+ self.block = block
+ self.freq_disp.SetRange(0, 30e6)
+ f = self.block.src.freq
+ self.freq_disp.SetValue( -f )
+ self.volume.SetRange( 0, 20 )
+ self.pga.SetRange( 0, 20 )
+ self.rssi_range = 1
+ self.rssi.SetRange( self.rssi_range )
+ self.agc_max.SetValue( str( self.rssi_range ) )
+ self.spin_e0.SetValue( 50 )
+ self.spin_e1.SetValue( 50 )
+ self.spin_e2.SetValue( 50 )
+ self.spin_e3.SetValue( 50 )
+ self.spin_e4.SetValue( 50 )
+ self.spin_e5.SetValue( 50 )
+ self.spin_e6.SetValue( 50 )
+ bw = 3.3e3
+ self.bandwidth.SetValue( str( bw ) )
+ self.block.demod.set_bw( bw )
+ self.bw_spin.SetValue( 5 )
+ agc_gain = self.block.agc.gain.k()
+ self.agc_gain_s.SetValue( 5 )
+ self.agc_gain.SetValue( str( agc_gain ) )
+ agc_ref = self.block.agc.offs.k()
+ self.agc_ref.SetValue( str( agc_ref ) )
+ self.agc_ref_s.SetValue( 5 )
+
+ self.fespectrum = fftsink2.fft_sink_c(
+ self.fe_panel,
+ fft_size=512,
+ sample_rate = block.fe_rate,
+ ref_scale = 1.0,
+ ref_level = 20.0,
+ y_divs = 12,
+ avg_alpha = 0.1)
+
+ self.ifspectrum = fftsink2.fft_sink_c(
+ self.if_panel,
+ fft_size=512,
+ sample_rate = block.audio_rate,
+ ref_scale = 1.0,
+ ref_level = 20.0,
+ y_divs = 12,
+ avg_alpha = 0.1)
+
+ self.fespectrum.win.Bind( wx.EVT_MOTION, self.fe_mouse)
+ self.fespectrum.win.Bind( wx.EVT_LEFT_DOWN, self.fe_click)
+
+ block.connect( block.src.src, self.fespectrum )
+ block.connect( block.demod.xlate, self.ifspectrum )
+
+ def agc_ref_up( self, event ):
+ self.agc_ref_s.SetValue( 5 )
+ r = float( self.agc_ref.GetValue() )
+ r = r + 5
+ self.agc_ref.SetValue( str( r ) )
+ self.block.agc.offs.set_k( r )
+
+ def agc_ref_down( self, event ):
+ self.agc_ref_s.SetValue( 5 )
+ r = float( self.agc_ref.GetValue() )
+ r = r - 5
+ self.agc_ref.SetValue( str( r ) )
+ self.block.agc.offs.set_k( r )
+
+ def agc_gain_up( self, event ):
+ self.agc_gain_s.SetValue( 5 )
+ g = float(self.agc_gain.GetValue())
+ g = g + 10
+ self.agc_gain.SetValue( str( g ) )
+ self.block.agc.gain.set_k( g )
+
+ def agc_gain_down( self, event ):
+ self.agc_gain_s.SetValue( 5 )
+ g = float(self.agc_gain.GetValue())
+ g = g - 10
+ self.agc_gain.SetValue( str( g ) )
+ self.block.agc.gain.set_k( g )
+
+ def fe_mouse( self, event ):
+ f = int(self.freq_disp.GetValue())
+ f = f+((event.GetX()-346.)*(400./610.))*1000
+ self.fespectrum.win.SetToolTip(
+ wx.ToolTip( eng_notation.num_to_str(f)))
+
+ def fe_click( self, event ):
+ f = int(self.freq_disp.GetValue())
+ f = f+((event.GetX()-346.)*(400./610.))*1000
+ self.tune( f )
+
+ def setrssi( self, level ):
+ if level < 0:
+ level = 0
+ if level > self.rssi_range:
+ self.rssi_range = level
+ self.rssi.SetRange( level )
+ self.agc_max.SetValue( str( level ))
+ self.rssi.SetValue( level )
+ self.agc_level.SetValue( str( level ))
+
+ def tune_evt( self, event ):
+ f = self.freq_disp.GetValue()
+ self.tune( f )
+
+ def tune( self, frequency ):
+ self.freq_disp.SetValue( frequency )
+ self.block.tune( frequency )
+
+ def up_e0( self, event ):
+ self.spin_e0.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() + 1e0 )
+
+ def down_e0( self, event ):
+ self.spin_e0.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() - 1e0 )
+
+ def up_e1( self, event ):
+ self.spin_e1.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() + 1e1 )
+
+ def down_e1( self, event ):
+ self.spin_e1.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() - 1e1 )
+
+ def up_e2( self, event ):
+ self.spin_e2.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() + 1e2 )
+
+ def down_e2( self, event ):
+ self.spin_e2.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() - 1e2 )
+
+ def up_e3( self, event ):
+ self.spin_e3.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() + 1e3 )
+
+ def down_e3( self, event ):
+ self.spin_e3.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() - 1e3 )
+
+ def up_e4( self, event ):
+ self.spin_e4.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() + 1e4 )
+
+ def down_e4( self, event ):
+ self.spin_e4.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() - 1e4 )
+
+ def up_e5( self, event ):
+ self.spin_e5.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() + 1e5 )
+
+ def down_e5( self, event ):
+ self.spin_e5.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() - 1e5 )
+
+ def up_e6( self, event ):
+ self.spin_e6.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() + 1e6 )
+
+ def down_e6( self, event ):
+ self.spin_e6.SetValue( 50 )
+ self.tune( self.freq_disp.GetValue() - 1e6 )
+
+ def event_pga( self, event ):
+ self.block.src.set_gain(self.pga.GetValue())
+
+ def event_vol( self, event ):
+ self.block.out.set( self.volume.GetValue()/20.0 )
+
+ def set_usb( self, event ):
+ self.block.demod.upper_sb()
+
+ def set_lsb( self, event ):
+ self.block.demod.lower_sb()
+
+ def set_am( self, event ):
+ self.block.demod.set_am()
+
+ def bw_up( self, event ):
+ self.bw_spin.SetValue( 5 )
+ bw = float(self.bandwidth.GetValue())
+ bw = bw + 20.0
+ if bw > 10e3:
+ bw = 10e3
+ self.bandwidth.SetValue( str( bw ) )
+ self.block.demod.set_bw( bw )
+
+ def bw_down( self, event ):
+ self.bw_spin.SetValue( 5 )
+ bw = float(self.bandwidth.GetValue())
+ bw = bw - 20.0
+ if bw < 50:
+ bw = 50
+ self.bandwidth.SetValue( str( bw ) )
+ self.block.demod.set_bw( bw )
+
+
+class radio( wx.App ):
+ def OnInit( self ):
+ self.block = radio_top_block()
+ self.frame = radio_frame( self.block, None, -1, "HF Receiver" )
+ self.frame.Show( True )
+ self.SetTopWindow( self.frame )
+ self.block.start()
+ return True
+
+def rssi_function():
+ global radio_obj
+ global sig_probe
+
+ go = True
+ while go:
+ try:
+ level = sig_probe.level()
+ wx.CallAfter( radio_obj.frame.setrssi, level )
+ time.sleep( .1 )
+ except:
+ go = False
+
+def main():
+ global radio_obj, sig_probe
+
+ radio_obj = radio( 0 )
+ sig_probe = gr.probe_signal_f()
+ radio_obj.block.connect(radio_obj.block.agc.offs, sig_probe)
+
+ thread2 = Thread( target = rssi_function )
+ thread2.start()
+
+ radio_obj.MainLoop()
+
+
+if __name__ == "__main__":
+ main()
+
diff --git a/gr-uhd/apps/hf_radio/radio.xml b/gr-uhd/apps/hf_radio/radio.xml
new file mode 100644
index 000000000..81daa19b0
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/radio.xml
@@ -0,0 +1,441 @@
+<?xml version="1.0"?>
+<!-- generated by wxGlade 0.4 on Fri Jan 6 09:51:36 2006 -->
+
+<application path="/root/radio/ui.py" name="" class="" option="0" language="python" top_window="" encoding="UTF-8" use_gettext="0" overwrite="0" use_new_namespace="1" for_version="2.6">
+ <object class="ui_frame" name="frame_1" base="EditFrame">
+ <style>wxDEFAULT_FRAME_STYLE</style>
+ <title>frame_1</title>
+ <object class="wxStaticBoxSizer" name="sizer_1" base="EditStaticBoxSizer">
+ <orient>wxVERTICAL</orient>
+ <label>sizer_1</label>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxBoxSizer" name="sizer_2" base="EditBoxSizer">
+ <orient>wxHORIZONTAL</orient>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxBoxSizer" name="sizer_3" base="EditBoxSizer">
+ <orient>wxVERTICAL</orient>
+ <object class="sizeritem">
+ <flag>wxEXPAND|wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxSpinCtrl" name="freq_disp" base="EditSpinCtrl">
+ <font>
+ <size>32</size>
+ <family>default</family>
+ <style>normal</style>
+ <weight>normal</weight>
+ <underlined>0</underlined>
+ <face></face>
+ </font>
+ <events>
+ <handler event="EVT_SPINCTRL">tune_evt</handler>
+ </events>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxGridSizer" name="grid_sizer_1" base="EditGridSizer">
+ <hgap>0</hgap>
+ <rows>2</rows>
+ <cols>3</cols>
+ <vgap>0</vgap>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxGridSizer" name="grid_sizer_2" base="EditGridSizer">
+ <hgap>0</hgap>
+ <rows>1</rows>
+ <cols>7</cols>
+ <vgap>0</vgap>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinButton" name="spin_e6" base="EditSpinButton">
+ <events>
+ <handler event="EVT_SPIN_UP">up_e6</handler>
+ <handler event="EVT_SPIN_DOWN">down_e6</handler>
+ </events>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinButton" name="spin_e5" base="EditSpinButton">
+ <events>
+ <handler event="EVT_SPIN_UP">up_e5</handler>
+ <handler event="EVT_SPIN_DOWN">down_e5</handler>
+ </events>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinButton" name="spin_e4" base="EditSpinButton">
+ <events>
+ <handler event="EVT_SPIN_UP">up_e4</handler>
+ <handler event="EVT_SPIN_DOWN">down_e4</handler>
+ </events>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinButton" name="spin_e3" base="EditSpinButton">
+ <events>
+ <handler event="EVT_SPIN_UP">up_e3</handler>
+ <handler event="EVT_SPIN_DOWN">down_e3</handler>
+ </events>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinButton" name="spin_e2" base="EditSpinButton">
+ <events>
+ <handler event="EVT_SPIN_UP">up_e2</handler>
+ <handler event="EVT_SPIN_DOWN">down_e2</handler>
+ </events>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinButton" name="spin_e1" base="EditSpinButton">
+ <events>
+ <handler event="EVT_SPIN_UP">up_e1</handler>
+ <handler event="EVT_SPIN_DOWN">down_e1</handler>
+ </events>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinButton" name="spin_e0" base="EditSpinButton">
+ <events>
+ <handler event="EVT_SPIN_UP">up_e0</handler>
+ <handler event="EVT_SPIN_DOWN">down_e0</handler>
+ </events>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxPanel" name="panel_1" base="EditPanel">
+ <style>wxTAB_TRAVERSAL</style>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxPanel" name="panel_2" base="EditPanel">
+ <style>wxTAB_TRAVERSAL</style>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxButton" name="button_lsb" base="EditButton">
+ <label>LSB</label>
+ <events>
+ <handler event="EVT_BUTTON">set_lsb</handler>
+ </events>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxButton" name="button_usb" base="EditButton">
+ <label>USB</label>
+ <events>
+ <handler event="EVT_BUTTON">set_usb</handler>
+ </events>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxButton" name="button_am" base="EditButton">
+ <label>AM</label>
+ <events>
+ <handler event="EVT_BUTTON">set_am</handler>
+ </events>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxBoxSizer" name="sizer_4" base="EditBoxSizer">
+ <orient>wxVERTICAL</orient>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxGridSizer" name="grid_sizer_3" base="EditGridSizer">
+ <hgap>0</hgap>
+ <rows>2</rows>
+ <cols>4</cols>
+ <vgap>0</vgap>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxStaticText" name="label_1" base="EditStaticText">
+ <attribute>1</attribute>
+ <label>VOLUME</label>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxStaticText" name="label_2" base="EditStaticText">
+ <attribute>1</attribute>
+ <label>PGA</label>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxTextCtrl" name="agc_level" base="EditTextCtrl">
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxStaticText" name="label_6" base="EditStaticText">
+ <attribute>1</attribute>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinCtrl" name="volume" base="EditSpinCtrl">
+ <events>
+ <handler event="EVT_SPINCTRL">event_vol</handler>
+ </events>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinCtrl" name="pga" base="EditSpinCtrl">
+ <events>
+ <handler event="EVT_SPINCTRL">event_pga</handler>
+ </events>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxTextCtrl" name="agc_max" base="EditTextCtrl">
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxStaticText" name="label_7" base="EditStaticText">
+ <attribute>1</attribute>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxGridSizer" name="grid_sizer_4" base="EditGridSizer">
+ <hgap>0</hgap>
+ <rows>2</rows>
+ <cols>4</cols>
+ <vgap>0</vgap>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxStaticText" name="label_4" base="EditStaticText">
+ <attribute>1</attribute>
+ <label>AGC AUTHORITY</label>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxStaticText" name="label_5" base="EditStaticText">
+ <attribute>1</attribute>
+ <label>AGC REF LVL</label>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxStaticText" name="label_3" base="EditStaticText">
+ <attribute>1</attribute>
+ <label>BANDWIDTH</label>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxStaticText" name="label_8" base="EditStaticText">
+ <attribute>1</attribute>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxBoxSizer" name="sizer_6" base="EditBoxSizer">
+ <orient>wxHORIZONTAL</orient>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxTextCtrl" name="agc_gain" base="EditTextCtrl">
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinButton" name="agc_gain_s" base="EditSpinButton">
+ <events>
+ <handler event="EVT_SPIN_UP">agc_gain_up</handler>
+ <handler event="EVT_SPIN_DOWN">agc_gain_down</handler>
+ </events>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxBoxSizer" name="sizer_7" base="EditBoxSizer">
+ <orient>wxHORIZONTAL</orient>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxTextCtrl" name="agc_ref" base="EditTextCtrl">
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinButton" name="agc_ref_s" base="EditSpinButton">
+ <events>
+ <handler event="EVT_SPIN_UP">agc_ref_up</handler>
+ <handler event="EVT_SPIN_DOWN">agc_ref_down</handler>
+ </events>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxBoxSizer" name="sizer_5" base="EditBoxSizer">
+ <orient>wxHORIZONTAL</orient>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxTextCtrl" name="bandwidth" base="EditTextCtrl">
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxSpinButton" name="bw_spin" base="EditSpinButton">
+ <events>
+ <handler event="EVT_SPIN_UP">bw_up</handler>
+ <handler event="EVT_SPIN_DOWN">bw_down</handler>
+ </events>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>0</option>
+ <object class="wxStaticText" name="label_9" base="EditStaticText">
+ <attribute>1</attribute>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxEXPAND|wxADJUST_MINSIZE</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxGauge" name="rssi" base="EditGauge">
+ <foreground>#ff0000</foreground>
+ <style>wxGA_HORIZONTAL|wxGA_SMOOTH</style>
+ <range>10</range>
+ <size>315, 10</size>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxPanel" name="fe_panel" base="EditPanel">
+ <style>wxTAB_TRAVERSAL</style>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <flag>wxEXPAND</flag>
+ <border>0</border>
+ <option>1</option>
+ <object class="wxPanel" name="if_panel" base="EditPanel">
+ <style>wxTAB_TRAVERSAL</style>
+ </object>
+ </object>
+ </object>
+ </object>
+</application>
diff --git a/gr-uhd/apps/hf_radio/ssb_taps b/gr-uhd/apps/hf_radio/ssb_taps
new file mode 100644
index 000000000..0ef3bbf26
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/ssb_taps
@@ -0,0 +1,1023 @@
+-0.000035-0.000009j
+-0.000066-0.000020j
+-0.000080-0.000044j
+-0.000084-0.000071j
+-0.000077-0.000100j
+-0.000063-0.000127j
+-0.000041-0.000150j
+-0.000013-0.000167j
+0.000020-0.000177j
+0.000054-0.000180j
+0.000089-0.000174j
+0.000121-0.000161j
+0.000150-0.000140j
+0.000173-0.000113j
+0.000188-0.000081j
+0.000196-0.000046j
+0.000194-0.000011j
+0.000184+0.000022j
+0.000165+0.000052j
+0.000139+0.000077j
+0.000107+0.000093j
+0.000071+0.000102j
+0.000034+0.000101j
+-0.000002+0.000090j
+-0.000036+0.000070j
+-0.000064+0.000042j
+-0.000086+0.000006j
+-0.000098-0.000034j
+-0.000101-0.000077j
+-0.000093-0.000120j
+-0.000076-0.000161j
+-0.000049-0.000197j
+-0.000014-0.000227j
+0.000026-0.000248j
+0.000071-0.000259j
+0.000117-0.000259j
+0.000162-0.000249j
+0.000203-0.000228j
+0.000237-0.000199j
+0.000263-0.000162j
+0.000279-0.000120j
+0.000284-0.000075j
+0.000278-0.000031j
+0.000260+0.000010j
+0.000232+0.000045j
+0.000196+0.000073j
+0.000153+0.000090j
+0.000106+0.000095j
+0.000059+0.000089j
+0.000014+0.000071j
+-0.000027+0.000041j
+-0.000059+0.000002j
+-0.000082-0.000046j
+-0.000093-0.000098j
+-0.000091-0.000152j
+-0.000077-0.000206j
+-0.000050-0.000255j
+-0.000012-0.000298j
+0.000034-0.000330j
+0.000088-0.000351j
+0.000145-0.000359j
+0.000202-0.000354j
+0.000256-0.000335j
+0.000304-0.000304j
+0.000343-0.000262j
+0.000370-0.000213j
+0.000384-0.000158j
+0.000384-0.000102j
+0.000369-0.000048j
+0.000341+0.000002j
+0.000302+0.000042j
+0.000252+0.000072j
+0.000196+0.000088j
+0.000137+0.000089j
+0.000078+0.000075j
+0.000024+0.000047j
+-0.000023+0.000005j
+-0.000059-0.000048j
+-0.000082-0.000109j
+-0.000090-0.000175j
+-0.000081-0.000242j
+-0.000058-0.000306j
+-0.000019-0.000364j
+0.000032-0.000411j
+0.000093-0.000445j
+0.000161-0.000465j
+0.000232-0.000467j
+0.000301-0.000453j
+0.000365-0.000423j
+0.000419-0.000379j
+0.000461-0.000323j
+0.000487-0.000259j
+0.000497-0.000190j
+0.000489-0.000121j
+0.000464-0.000056j
+0.000423+0.000001j
+0.000369+0.000046j
+0.000304+0.000076j
+0.000233+0.000089j
+0.000160+0.000083j
+0.000089+0.000060j
+0.000025+0.000018j
+-0.000027-0.000038j
+-0.000065-0.000107j
+-0.000086-0.000185j
+-0.000088-0.000266j
+-0.000071-0.000347j
+-0.000035-0.000422j
+0.000019-0.000487j
+0.000086-0.000538j
+0.000164-0.000573j
+0.000248-0.000588j
+0.000334-0.000582j
+0.000415-0.000557j
+0.000488-0.000513j
+0.000548-0.000452j
+0.000592-0.000379j
+0.000616-0.000297j
+0.000619-0.000213j
+0.000600-0.000130j
+0.000561-0.000054j
+0.000504+0.000010j
+0.000432+0.000058j
+0.000350+0.000086j
+0.000261+0.000093j
+0.000173+0.000078j
+0.000090+0.000040j
+0.000017-0.000017j
+-0.000040-0.000092j
+-0.000078-0.000180j
+-0.000095-0.000275j
+-0.000088-0.000374j
+-0.000058-0.000469j
+-0.000006-0.000555j
+0.000065-0.000627j
+0.000152-0.000681j
+0.000250-0.000712j
+0.000352-0.000720j
+0.000454-0.000703j
+0.000548-0.000663j
+0.000630-0.000601j
+0.000694-0.000521j
+0.000737-0.000428j
+0.000755-0.000327j
+0.000748-0.000225j
+0.000715-0.000128j
+0.000659-0.000042j
+0.000582+0.000028j
+0.000490+0.000077j
+0.000387+0.000101j
+0.000280+0.000099j
+0.000175+0.000070j
+0.000080+0.000015j
+-0.000001-0.000063j
+-0.000061-0.000159j
+-0.000097-0.000268j
+-0.000106-0.000385j
+-0.000087-0.000501j
+-0.000040-0.000611j
+0.000032-0.000708j
+0.000125-0.000786j
+0.000235-0.000839j
+0.000354-0.000866j
+0.000477-0.000863j
+0.000595-0.000831j
+0.000702-0.000772j
+0.000792-0.000688j
+0.000859-0.000585j
+0.000898-0.000469j
+0.000907-0.000347j
+0.000886-0.000227j
+0.000835-0.000115j
+0.000757-0.000019j
+0.000657+0.000055j
+0.000540+0.000102j
+0.000415+0.000119j
+0.000287+0.000103j
+0.000165+0.000056j
+0.000058-0.000020j
+-0.000029-0.000122j
+-0.000090-0.000243j
+-0.000121-0.000378j
+-0.000118-0.000517j
+-0.000082-0.000653j
+-0.000014-0.000778j
+0.000082-0.000885j
+0.000201-0.000966j
+0.000337-0.001017j
+0.000481-0.001034j
+0.000626-0.001016j
+0.000762-0.000965j
+0.000882-0.000882j
+0.000978-0.000772j
+0.001044-0.000643j
+0.001076-0.000501j
+0.001072-0.000355j
+0.001032-0.000215j
+0.000958-0.000089j
+0.000854+0.000016j
+0.000726+0.000091j
+0.000582+0.000133j
+0.000431+0.000138j
+0.000281+0.000105j
+0.000143+0.000035j
+0.000024-0.000068j
+-0.000068-0.000199j
+-0.000126-0.000350j
+-0.000147-0.000513j
+-0.000128-0.000677j
+-0.000070-0.000834j
+0.000024-0.000974j
+0.000150-0.001089j
+0.000300-0.001171j
+0.000465-0.001216j
+0.000637-0.001219j
+0.000805-0.001182j
+0.000960-0.001105j
+0.001091-0.000993j
+0.001191-0.000853j
+0.001253-0.000692j
+0.001274-0.000521j
+0.001252-0.000350j
+0.001188-0.000189j
+0.001085-0.000049j
+0.000950+0.000062j
+0.000790+0.000136j
+0.000614+0.000168j
+0.000435+0.000156j
+0.000261+0.000099j
+0.000105+0.000000j
+-0.000024-0.000136j
+-0.000117-0.000301j
+-0.000169-0.000486j
+-0.000175-0.000680j
+-0.000134-0.000872j
+-0.000048-0.001051j
+0.000079-0.001206j
+0.000240-0.001326j
+0.000426-0.001406j
+0.000626-0.001439j
+0.000829-0.001424j
+0.001022-0.001361j
+0.001195-0.001252j
+0.001336-0.001106j
+0.001437-0.000929j
+0.001491-0.000733j
+0.001496-0.000529j
+0.001449-0.000330j
+0.001354-0.000148j
+0.001217+0.000005j
+0.001044+0.000120j
+0.000846+0.000188j
+0.000635+0.000206j
+0.000424+0.000170j
+0.000226+0.000083j
+0.000053-0.000053j
+-0.000084-0.000228j
+-0.000176-0.000434j
+-0.000216-0.000659j
+-0.000201-0.000889j
+-0.000131-0.001111j
+-0.000009-0.001312j
+0.000158-0.001480j
+0.000362-0.001604j
+0.000590-0.001677j
+0.000829-0.001694j
+0.001066-0.001653j
+0.001286-0.001556j
+0.001477-0.001408j
+0.001626-0.001219j
+0.001724-0.001000j
+0.001765-0.000762j
+0.001746-0.000522j
+0.001668-0.000293j
+0.001534-0.000090j
+0.001353+0.000075j
+0.001135+0.000190j
+0.000893+0.000247j
+0.000642+0.000243j
+0.000396+0.000176j
+0.000172+0.000049j
+-0.000017-0.000131j
+-0.000159-0.000355j
+-0.000244-0.000609j
+-0.000266-0.000880j
+-0.000222-0.001151j
+-0.000114-0.001406j
+0.000053-0.001630j
+0.000270-0.001810j
+0.000524-0.001934j
+0.000802-0.001994j
+0.001087-0.001987j
+0.001362-0.001911j
+0.001611-0.001772j
+0.001819-0.001576j
+0.001973-0.001336j
+0.002063-0.001065j
+0.002084-0.000779j
+0.002033-0.000497j
+0.001914-0.000236j
+0.001732-0.000011j
+0.001498+0.000162j
+0.001225+0.000272j
+0.000931+0.000312j
+0.000633+0.000277j
+0.000349+0.000168j
+0.000097-0.000009j
+-0.000107-0.000246j
+-0.000250-0.000528j
+-0.000322-0.000841j
+-0.000316-0.001166j
+-0.000233-0.001484j
+-0.000076-0.001775j
+0.000148-0.002024j
+0.000426-0.002213j
+0.000743-0.002332j
+0.001080-0.002373j
+0.001418-0.002332j
+0.001736-0.002211j
+0.002017-0.002017j
+0.002241-0.001760j
+0.002397-0.001457j
+0.002473-0.001124j
+0.002464-0.000783j
+0.002371-0.000453j
+0.002198-0.000156j
+0.001954+0.000091j
+0.001654+0.000269j
+0.001316+0.000369j
+0.000959+0.000381j
+0.000606+0.000303j
+0.000279+0.000139j
+-0.000003-0.000103j
+-0.000220-0.000411j
+-0.000359-0.000768j
+-0.000408-0.001152j
+-0.000365-0.001542j
+-0.000229-0.001915j
+-0.000006-0.002248j
+0.000292-0.002522j
+0.000648-0.002719j
+0.001042-0.002826j
+0.001452-0.002837j
+0.001853-0.002750j
+0.002223-0.002569j
+0.002537-0.002304j
+0.002778-0.001971j
+0.002930-0.001588j
+0.002984-0.001179j
+0.002933-0.000770j
+0.002782-0.000384j
+0.002538-0.000046j
+0.002215+0.000222j
+0.001831+0.000402j
+0.001410+0.000481j
+0.000976+0.000452j
+0.000557+0.000316j
+0.000179+0.000077j
+-0.000134-0.000252j
+-0.000362-0.000654j
+-0.000490-0.001105j
+-0.000506-0.001580j
+-0.000407-0.002052j
+-0.000197-0.002492j
+0.000113-0.002875j
+0.000508-0.003176j
+0.000966-0.003377j
+0.001460-0.003464j
+0.001963-0.003432j
+0.002444-0.003281j
+0.002876-0.003019j
+0.003231-0.002659j
+0.003488-0.002224j
+0.003631-0.001739j
+0.003649-0.001233j
+0.003540-0.000737j
+0.003309-0.000282j
+0.002969+0.000103j
+0.002539+0.000393j
+0.002044+0.000568j
+0.001515+0.000614j
+0.000982+0.000525j
+0.000480+0.000304j
+0.000039-0.000039j
+-0.000311-0.000487j
+-0.000547-0.001016j
+-0.000652-0.001595j
+-0.000615-0.002193j
+-0.000436-0.002773j
+-0.000122-0.003301j
+0.000311-0.003746j
+0.000842-0.004081j
+0.001440-0.004282j
+0.002071-0.004338j
+0.002700-0.004243j
+0.003289-0.004000j
+0.003803-0.003622j
+0.004210-0.003132j
+0.004485-0.002556j
+0.004610-0.001930j
+0.004574-0.001291j
+0.004379-0.000679j
+0.004034-0.000133j
+0.003558+0.000313j
+0.002977+0.000627j
+0.002327+0.000787j
+0.001647+0.000779j
+0.000977+0.000598j
+0.000360+0.000250j
+-0.000163-0.000249j
+-0.000559-0.000872j
+-0.000799-0.001587j
+-0.000864-0.002354j
+-0.000744-0.003129j
+-0.000442-0.003866j
+0.000031-0.004522j
+0.000651-0.005057j
+0.001385-0.005437j
+0.002193-0.005637j
+0.003030-0.005643j
+0.003848-0.005451j
+0.004597-0.005069j
+0.005234-0.004519j
+0.005718-0.003830j
+0.006019-0.003044j
+0.006114-0.002206j
+0.005997-0.001368j
+0.005669-0.000583j
+0.005147+0.000099j
+0.004460+0.000631j
+0.003647+0.000975j
+0.002757+0.001105j
+0.001842+0.001003j
+0.000961+0.000668j
+0.000168+0.000111j
+-0.000482-0.000643j
+-0.000944-0.001555j
+-0.001183-0.002578j
+-0.001176-0.003656j
+-0.000912-0.004727j
+-0.000397-0.005728j
+0.000346-0.006601j
+0.001284-0.007292j
+0.002368-0.007755j
+0.003540-0.007959j
+0.004735-0.007886j
+0.005885-0.007535j
+0.006922-0.006922j
+0.007782-0.006078j
+0.008412-0.005050j
+0.008769-0.003898j
+0.008825-0.002691j
+0.008572-0.001504j
+0.008016-0.000412j
+0.007185+0.000510j
+0.006123+0.001196j
+0.004891+0.001591j
+0.003560+0.001657j
+0.002212+0.001372j
+0.000933+0.000734j
+-0.000192-0.000236j
+-0.001083-0.001500j
+-0.001672-0.002998j
+-0.001905-0.004655j
+-0.001747-0.006384j
+-0.001182-0.008090j
+-0.000222-0.009676j
+0.001101-0.011045j
+0.002732-0.012114j
+0.004593-0.012810j
+0.006591-0.013081j
+0.008621-0.012896j
+0.010571-0.012253j
+0.012328-0.011175j
+0.013785-0.009712j
+0.014847-0.007941j
+0.015438-0.005962j
+0.015507-0.003893j
+0.015029-0.001863j
+0.014011-0.000011j
+0.012494+0.001529j
+0.010549+0.002630j
+0.008277+0.003179j
+0.005809+0.003090j
+0.003294+0.002304j
+0.000896+0.000795j
+-0.001212-0.001423j
+-0.002859-0.004299j
+-0.003886-0.007744j
+-0.004151-0.011630j
+-0.003539-0.015799j
+-0.001969-0.020066j
+0.000601-0.024225j
+0.004168-0.028064j
+0.008684-0.031367j
+0.014056-0.033927j
+0.020145-0.035558j
+0.026775-0.036101j
+0.033735-0.035433j
+0.040789-0.033475j
+0.047684-0.030197j
+0.054164-0.025619j
+0.059974-0.019815j
+0.064878-0.012907j
+0.068665-0.005067j
+0.071159+0.003494j
+0.072228+0.012531j
+0.071791+0.021776j
+0.069818+0.030947j
+0.066339+0.039761j
+0.061435+0.047944j
+0.055243+0.055243j
+0.047944+0.061435j
+0.039761+0.066339j
+0.030947+0.069818j
+0.021776+0.071791j
+0.012531+0.072228j
+0.003494+0.071159j
+-0.005067+0.068665j
+-0.012907+0.064878j
+-0.019815+0.059974j
+-0.025619+0.054164j
+-0.030197+0.047684j
+-0.033475+0.040789j
+-0.035433+0.033735j
+-0.036101+0.026775j
+-0.035558+0.020145j
+-0.033927+0.014056j
+-0.031367+0.008684j
+-0.028064+0.004168j
+-0.024225+0.000601j
+-0.020066-0.001969j
+-0.015799-0.003539j
+-0.011630-0.004151j
+-0.007744-0.003886j
+-0.004299-0.002859j
+-0.001423-0.001212j
+0.000795+0.000896j
+0.002304+0.003294j
+0.003090+0.005809j
+0.003179+0.008277j
+0.002630+0.010549j
+0.001529+0.012494j
+-0.000011+0.014011j
+-0.001863+0.015029j
+-0.003893+0.015507j
+-0.005962+0.015438j
+-0.007941+0.014847j
+-0.009712+0.013785j
+-0.011175+0.012328j
+-0.012253+0.010571j
+-0.012896+0.008621j
+-0.013081+0.006591j
+-0.012810+0.004593j
+-0.012114+0.002732j
+-0.011045+0.001101j
+-0.009676-0.000222j
+-0.008090-0.001182j
+-0.006384-0.001747j
+-0.004655-0.001905j
+-0.002998-0.001672j
+-0.001500-0.001083j
+-0.000236-0.000192j
+0.000734+0.000933j
+0.001372+0.002212j
+0.001657+0.003560j
+0.001591+0.004891j
+0.001196+0.006123j
+0.000510+0.007185j
+-0.000412+0.008016j
+-0.001504+0.008572j
+-0.002691+0.008825j
+-0.003898+0.008769j
+-0.005050+0.008412j
+-0.006078+0.007782j
+-0.006922+0.006922j
+-0.007535+0.005885j
+-0.007886+0.004735j
+-0.007959+0.003540j
+-0.007755+0.002368j
+-0.007292+0.001284j
+-0.006601+0.000346j
+-0.005728-0.000397j
+-0.004727-0.000912j
+-0.003656-0.001176j
+-0.002578-0.001183j
+-0.001555-0.000944j
+-0.000643-0.000482j
+0.000111+0.000168j
+0.000668+0.000961j
+0.001003+0.001842j
+0.001105+0.002757j
+0.000975+0.003647j
+0.000631+0.004460j
+0.000099+0.005147j
+-0.000583+0.005669j
+-0.001368+0.005997j
+-0.002206+0.006114j
+-0.003044+0.006019j
+-0.003830+0.005718j
+-0.004519+0.005234j
+-0.005069+0.004597j
+-0.005451+0.003848j
+-0.005643+0.003030j
+-0.005637+0.002193j
+-0.005437+0.001385j
+-0.005057+0.000651j
+-0.004522+0.000031j
+-0.003866-0.000442j
+-0.003129-0.000744j
+-0.002354-0.000864j
+-0.001587-0.000799j
+-0.000872-0.000559j
+-0.000249-0.000163j
+0.000250+0.000360j
+0.000598+0.000977j
+0.000779+0.001647j
+0.000787+0.002327j
+0.000627+0.002977j
+0.000313+0.003558j
+-0.000133+0.004034j
+-0.000679+0.004379j
+-0.001291+0.004574j
+-0.001930+0.004610j
+-0.002556+0.004485j
+-0.003132+0.004210j
+-0.003622+0.003803j
+-0.004000+0.003289j
+-0.004243+0.002700j
+-0.004338+0.002071j
+-0.004282+0.001440j
+-0.004081+0.000842j
+-0.003746+0.000311j
+-0.003301-0.000122j
+-0.002773-0.000436j
+-0.002193-0.000615j
+-0.001595-0.000652j
+-0.001016-0.000547j
+-0.000487-0.000311j
+-0.000039+0.000039j
+0.000304+0.000480j
+0.000525+0.000982j
+0.000614+0.001515j
+0.000568+0.002044j
+0.000393+0.002539j
+0.000103+0.002969j
+-0.000282+0.003309j
+-0.000737+0.003540j
+-0.001233+0.003649j
+-0.001739+0.003631j
+-0.002224+0.003488j
+-0.002659+0.003231j
+-0.003019+0.002876j
+-0.003281+0.002444j
+-0.003432+0.001963j
+-0.003464+0.001460j
+-0.003377+0.000966j
+-0.003176+0.000508j
+-0.002875+0.000113j
+-0.002492-0.000197j
+-0.002052-0.000407j
+-0.001580-0.000506j
+-0.001105-0.000490j
+-0.000654-0.000362j
+-0.000252-0.000134j
+0.000077+0.000179j
+0.000316+0.000557j
+0.000452+0.000976j
+0.000481+0.001410j
+0.000402+0.001831j
+0.000222+0.002215j
+-0.000046+0.002538j
+-0.000384+0.002782j
+-0.000770+0.002933j
+-0.001179+0.002984j
+-0.001588+0.002930j
+-0.001971+0.002778j
+-0.002304+0.002537j
+-0.002569+0.002223j
+-0.002750+0.001853j
+-0.002837+0.001452j
+-0.002826+0.001042j
+-0.002719+0.000648j
+-0.002522+0.000292j
+-0.002248-0.000006j
+-0.001915-0.000229j
+-0.001542-0.000365j
+-0.001152-0.000408j
+-0.000768-0.000359j
+-0.000411-0.000220j
+-0.000103-0.000003j
+0.000139+0.000279j
+0.000303+0.000606j
+0.000381+0.000959j
+0.000369+0.001316j
+0.000269+0.001654j
+0.000091+0.001954j
+-0.000156+0.002198j
+-0.000453+0.002371j
+-0.000783+0.002464j
+-0.001124+0.002473j
+-0.001457+0.002397j
+-0.001760+0.002241j
+-0.002017+0.002017j
+-0.002211+0.001736j
+-0.002332+0.001418j
+-0.002373+0.001080j
+-0.002332+0.000743j
+-0.002213+0.000426j
+-0.002024+0.000148j
+-0.001775-0.000076j
+-0.001484-0.000233j
+-0.001166-0.000316j
+-0.000841-0.000322j
+-0.000528-0.000250j
+-0.000246-0.000107j
+-0.000009+0.000097j
+0.000168+0.000349j
+0.000277+0.000633j
+0.000312+0.000931j
+0.000272+0.001225j
+0.000162+0.001498j
+-0.000011+0.001732j
+-0.000236+0.001914j
+-0.000497+0.002033j
+-0.000779+0.002084j
+-0.001065+0.002063j
+-0.001336+0.001973j
+-0.001576+0.001819j
+-0.001772+0.001611j
+-0.001911+0.001362j
+-0.001987+0.001087j
+-0.001994+0.000802j
+-0.001934+0.000524j
+-0.001810+0.000270j
+-0.001630+0.000053j
+-0.001406-0.000114j
+-0.001151-0.000222j
+-0.000880-0.000266j
+-0.000609-0.000244j
+-0.000355-0.000159j
+-0.000131-0.000017j
+0.000049+0.000172j
+0.000176+0.000396j
+0.000243+0.000642j
+0.000247+0.000893j
+0.000190+0.001135j
+0.000075+0.001353j
+-0.000090+0.001534j
+-0.000293+0.001668j
+-0.000522+0.001746j
+-0.000762+0.001765j
+-0.001000+0.001724j
+-0.001219+0.001626j
+-0.001408+0.001477j
+-0.001556+0.001286j
+-0.001653+0.001066j
+-0.001694+0.000829j
+-0.001677+0.000590j
+-0.001604+0.000362j
+-0.001480+0.000158j
+-0.001312-0.000009j
+-0.001111-0.000131j
+-0.000889-0.000201j
+-0.000659-0.000216j
+-0.000434-0.000176j
+-0.000228-0.000084j
+-0.000053+0.000053j
+0.000083+0.000226j
+0.000170+0.000424j
+0.000206+0.000635j
+0.000188+0.000846j
+0.000120+0.001044j
+0.000005+0.001217j
+-0.000148+0.001354j
+-0.000330+0.001449j
+-0.000529+0.001496j
+-0.000733+0.001491j
+-0.000929+0.001437j
+-0.001106+0.001336j
+-0.001252+0.001195j
+-0.001361+0.001022j
+-0.001424+0.000829j
+-0.001439+0.000626j
+-0.001406+0.000426j
+-0.001326+0.000240j
+-0.001206+0.000079j
+-0.001051-0.000048j
+-0.000872-0.000134j
+-0.000680-0.000175j
+-0.000486-0.000169j
+-0.000301-0.000117j
+-0.000136-0.000024j
+0.000000+0.000105j
+0.000099+0.000261j
+0.000156+0.000435j
+0.000168+0.000614j
+0.000136+0.000790j
+0.000062+0.000950j
+-0.000049+0.001085j
+-0.000189+0.001188j
+-0.000350+0.001252j
+-0.000521+0.001274j
+-0.000692+0.001253j
+-0.000853+0.001191j
+-0.000993+0.001091j
+-0.001105+0.000960j
+-0.001182+0.000805j
+-0.001219+0.000637j
+-0.001216+0.000465j
+-0.001171+0.000300j
+-0.001089+0.000150j
+-0.000974+0.000024j
+-0.000834-0.000070j
+-0.000677-0.000128j
+-0.000513-0.000147j
+-0.000350-0.000126j
+-0.000199-0.000068j
+-0.000068+0.000024j
+0.000035+0.000143j
+0.000105+0.000281j
+0.000138+0.000431j
+0.000133+0.000582j
+0.000091+0.000726j
+0.000016+0.000854j
+-0.000089+0.000958j
+-0.000215+0.001032j
+-0.000355+0.001072j
+-0.000501+0.001076j
+-0.000643+0.001044j
+-0.000772+0.000978j
+-0.000882+0.000882j
+-0.000965+0.000762j
+-0.001016+0.000626j
+-0.001034+0.000481j
+-0.001017+0.000337j
+-0.000966+0.000201j
+-0.000885+0.000082j
+-0.000778-0.000014j
+-0.000653-0.000082j
+-0.000517-0.000118j
+-0.000378-0.000121j
+-0.000243-0.000090j
+-0.000122-0.000029j
+-0.000020+0.000058j
+0.000056+0.000165j
+0.000103+0.000287j
+0.000119+0.000415j
+0.000102+0.000540j
+0.000055+0.000657j
+-0.000019+0.000757j
+-0.000115+0.000835j
+-0.000227+0.000886j
+-0.000347+0.000907j
+-0.000469+0.000898j
+-0.000585+0.000859j
+-0.000688+0.000792j
+-0.000772+0.000702j
+-0.000831+0.000595j
+-0.000863+0.000477j
+-0.000866+0.000354j
+-0.000839+0.000235j
+-0.000786+0.000125j
+-0.000708+0.000032j
+-0.000611-0.000040j
+-0.000501-0.000087j
+-0.000385-0.000106j
+-0.000268-0.000097j
+-0.000159-0.000061j
+-0.000063-0.000001j
+0.000015+0.000080j
+0.000070+0.000175j
+0.000099+0.000280j
+0.000101+0.000387j
+0.000077+0.000490j
+0.000028+0.000582j
+-0.000042+0.000659j
+-0.000128+0.000715j
+-0.000225+0.000748j
+-0.000327+0.000755j
+-0.000428+0.000737j
+-0.000521+0.000694j
+-0.000601+0.000630j
+-0.000663+0.000548j
+-0.000703+0.000454j
+-0.000720+0.000352j
+-0.000712+0.000250j
+-0.000681+0.000152j
+-0.000627+0.000065j
+-0.000555-0.000006j
+-0.000469-0.000058j
+-0.000374-0.000088j
+-0.000275-0.000095j
+-0.000180-0.000078j
+-0.000092-0.000040j
+-0.000017+0.000017j
+0.000040+0.000090j
+0.000078+0.000173j
+0.000093+0.000261j
+0.000086+0.000350j
+0.000058+0.000432j
+0.000010+0.000504j
+-0.000054+0.000561j
+-0.000130+0.000600j
+-0.000213+0.000619j
+-0.000297+0.000616j
+-0.000379+0.000592j
+-0.000452+0.000548j
+-0.000513+0.000488j
+-0.000557+0.000415j
+-0.000582+0.000334j
+-0.000588+0.000248j
+-0.000573+0.000164j
+-0.000538+0.000086j
+-0.000487+0.000019j
+-0.000422-0.000035j
+-0.000347-0.000071j
+-0.000266-0.000088j
+-0.000185-0.000086j
+-0.000107-0.000065j
+-0.000038-0.000027j
+0.000018+0.000025j
+0.000060+0.000089j
+0.000083+0.000160j
+0.000089+0.000233j
+0.000076+0.000304j
+0.000046+0.000369j
+0.000001+0.000423j
+-0.000056+0.000464j
+-0.000121+0.000489j
+-0.000190+0.000497j
+-0.000259+0.000487j
+-0.000323+0.000461j
+-0.000379+0.000419j
+-0.000423+0.000365j
+-0.000453+0.000301j
+-0.000467+0.000232j
+-0.000465+0.000161j
+-0.000445+0.000093j
+-0.000411+0.000032j
+-0.000364-0.000019j
+-0.000306-0.000058j
+-0.000242-0.000081j
+-0.000175-0.000090j
+-0.000109-0.000082j
+-0.000048-0.000059j
+0.000005-0.000023j
+0.000047+0.000024j
+0.000075+0.000078j
+0.000089+0.000137j
+0.000088+0.000196j
+0.000072+0.000252j
+0.000042+0.000302j
+0.000002+0.000341j
+-0.000048+0.000369j
+-0.000102+0.000384j
+-0.000158+0.000384j
+-0.000213+0.000370j
+-0.000262+0.000343j
+-0.000304+0.000304j
+-0.000335+0.000256j
+-0.000354+0.000202j
+-0.000359+0.000145j
+-0.000351+0.000088j
+-0.000330+0.000034j
+-0.000298-0.000012j
+-0.000255-0.000050j
+-0.000206-0.000077j
+-0.000152-0.000091j
+-0.000098-0.000093j
+-0.000046-0.000082j
+0.000002-0.000059j
+0.000041-0.000027j
+0.000071+0.000014j
+0.000089+0.000059j
+0.000095+0.000106j
+0.000090+0.000153j
+0.000073+0.000196j
+0.000045+0.000232j
+0.000010+0.000260j
+-0.000031+0.000278j
+-0.000075+0.000284j
+-0.000120+0.000279j
+-0.000162+0.000263j
+-0.000199+0.000237j
+-0.000228+0.000203j
+-0.000249+0.000162j
+-0.000259+0.000117j
+-0.000259+0.000071j
+-0.000248+0.000026j
+-0.000227-0.000014j
+-0.000197-0.000049j
+-0.000161-0.000076j
+-0.000120-0.000093j
+-0.000077-0.000101j
+-0.000034-0.000098j
+0.000006-0.000086j
+0.000042-0.000064j
+0.000070-0.000036j
+0.000090-0.000002j
+0.000101+0.000034j
+0.000102+0.000071j
+0.000093+0.000107j
+0.000077+0.000139j
+0.000052+0.000165j
+0.000022+0.000184j
+-0.000011+0.000194j
+-0.000046+0.000196j
+-0.000081+0.000188j
+-0.000113+0.000173j
+-0.000140+0.000150j
+-0.000161+0.000121j
+-0.000174+0.000089j
+-0.000180+0.000054j
+-0.000177+0.000020j
+-0.000167-0.000013j
+-0.000150-0.000041j
+-0.000127-0.000063j
+-0.000100-0.000077j
+-0.000071-0.000084j
+-0.000044-0.000080j
+-0.000020-0.000066j
+-0.000009-0.000035j
diff --git a/gr-uhd/apps/hf_radio/ssbagc.py b/gr-uhd/apps/hf_radio/ssbagc.py
new file mode 100644
index 000000000..494712863
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/ssbagc.py
@@ -0,0 +1,70 @@
+# 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.
+
+
+# post detection agc processing
+#
+# This agc strategy is copied more or less verbatim from
+# weaver_isb_am1_usrp3.py by cswiger.
+#
+# Thanks.
+#
+# Then modified in a variety of ways.
+#
+# There doesn't appear to be a way to hook multiple blocks to the
+# input port when building a hier block like this. Thus the
+# split below.
+#
+# Basic operation.
+# Power is estimated by squaring the input.
+# Low pass filter using a 1 pole iir.
+# The time constant can be tweaked by changing the taps.
+# Currently there is no implementation to change this while operating
+# a potentially useful addition.
+# The log block turns this into dB
+# gain adjusts the agc authority.
+#
+# M. Revnell 2006-Jan
+
+from gnuradio import gr
+
+class agc( gr.hier_block2 ):
+ def __init__( self ):
+ gr.hier_block2.__init__(self, "agc",
+ gr.io_signature(1,1,gr.sizeof_float),
+ gr.io_signature(1,1,gr.sizeof_float))
+
+ self.split = gr.multiply_const_ff( 1 )
+ self.sqr = gr.multiply_ff( )
+ self.int0 = gr.iir_filter_ffd( [.004, 0], [0, .999] )
+ self.offs = gr.add_const_ff( -30 )
+ self.gain = gr.multiply_const_ff( 70 )
+ self.log = gr.nlog10_ff( 10, 1 )
+ self.agc = gr.divide_ff( )
+
+ self.connect(self, self.split)
+ self.connect(self.split, (self.agc, 0))
+ self.connect(self.split, (self.sqr, 0))
+ self.connect(self.split, (self.sqr, 1))
+ self.connect(self.sqr, self.int0)
+ self.connect(self.int0, self.log)
+ self.connect(self.log, self.offs)
+ self.connect(self.offs, self.gain)
+ self.connect(self.gain, (self.agc, 1))
+ self.connect(self.agc, self)
diff --git a/gr-uhd/apps/hf_radio/ssbdemod.py b/gr-uhd/apps/hf_radio/ssbdemod.py
new file mode 100644
index 000000000..072d317a2
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/ssbdemod.py
@@ -0,0 +1,116 @@
+# 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.
+#
+
+# This tries to push the hilbert transform for ssb demod back into the
+# freq. xlating filter.
+#
+# The starting point for this was weaver_isb_am1_usrp3.py.
+#
+# The tap coefficients for freq_xlating_fir_filter_ccf were generated
+# externally and are read from a file because I didn't want to learn how
+# to make fir filters with arbitrary phase response using python numeric
+# facilities.
+#
+# They were generated using Scilab which I am already familiar with.
+# M. Revnell Jan 06
+
+from gnuradio import gr
+
+class ssb_demod( gr.hier_block2 ):
+ def __init__( self, if_rate, af_rate ):
+ gr.hier_block2.__init__(self, "ssb_demod",
+ gr.io_signature(1,1,gr.sizeof_gr_complex),
+ gr.io_signature(1,1,gr.sizeof_float))
+
+ self.if_rate = int(if_rate)
+ self.af_rate = int(af_rate)
+ self.if_decim = int(if_rate / af_rate)
+ self.sideband = 1
+
+ self.xlate_taps = ([complex(v) for v in file('ssb_taps').readlines()])
+
+ self.audio_taps = gr.firdes.low_pass(
+ 1.0,
+ self.af_rate,
+ 3e3,
+ 600,
+ gr.firdes.WIN_HAMMING )
+
+ self.xlate = gr.freq_xlating_fir_filter_ccc(
+ self.if_decim,
+ self.xlate_taps,
+ 0,
+ self.if_rate )
+
+ self.split = gr.complex_to_float()
+
+ self.lpf = gr.fir_filter_fff(
+ 1, self.audio_taps )
+
+ self.sum = gr.add_ff( )
+ self.am_sel = gr.multiply_const_ff( 0 )
+ self.sb_sel = gr.multiply_const_ff( 1 )
+ self.mixer = gr.add_ff()
+ self.am_det = gr.complex_to_mag()
+
+ self.connect(self, self.xlate)
+ self.connect(self.xlate, self.split)
+ self.connect((self.split, 0), (self.sum, 0))
+ self.connect((self.split, 1), (self.sum, 1))
+ self.connect(self.sum, self.sb_sel)
+ self.connect(self.xlate, self.am_det)
+ self.connect(self.sb_sel, (self.mixer, 0))
+ self.connect(self.am_det, self.am_sel)
+ self.connect(self.am_sel, (self.mixer, 1))
+ self.connect(self.mixer, self.lpf)
+ self.connect(self.lpf, self)
+
+ def upper_sb( self ):
+ self.xlate.set_taps([v.conjugate() for v in self.xlate_taps])
+ self.sb_sel.set_k( 1.0 )
+ self.am_sel.set_k( 0.0 )
+
+ def lower_sb( self ):
+ self.xlate.set_taps(self.xlate_taps)
+ self.sb_sel.set_k( 1.0 )
+ self.am_sel.set_k( 0.0 )
+
+ def set_am( self ):
+ taps = gr.firdes.low_pass( 1.0,
+ self.if_rate,
+ 5e3,
+ 2e3,
+ gr.firdes.WIN_HAMMING )
+ self.xlate.set_taps( taps )
+ self.sb_sel.set_k( 0.0 )
+ self.am_sel.set_k( 1.0 )
+
+ def set_bw( self, bw ):
+ self.audio_taps = gr.firdes.low_pass(
+ 1.0,
+ self.af_rate,
+ bw,
+ 600,
+ gr.firdes.WIN_HAMMING )
+ self.lpf.set_taps( self.audio_taps )
+
+ def tune( self, freq ):
+ self.xlate.set_center_freq( freq )
+
diff --git a/gr-uhd/apps/hf_radio/startup.py b/gr-uhd/apps/hf_radio/startup.py
new file mode 100644
index 000000000..093369b57
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/startup.py
@@ -0,0 +1 @@
+from radio import *
diff --git a/gr-uhd/apps/hf_radio/ui.py b/gr-uhd/apps/hf_radio/ui.py
new file mode 100755
index 000000000..551a30415
--- /dev/null
+++ b/gr-uhd/apps/hf_radio/ui.py
@@ -0,0 +1,316 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+# -*- coding: UTF-8 -*-
+# generated by wxGlade 0.4 on Mon Jan 2 19:02:03 2006
+
+import wx
+
+class ui_frame(wx.Frame):
+ def __init__(self, *args, **kwds):
+ # begin wxGlade: ui_frame.__init__
+ kwds["style"] = wx.DEFAULT_FRAME_STYLE
+ wx.Frame.__init__(self, *args, **kwds)
+ self.sizer_1_staticbox = wx.StaticBox(self, -1, "sizer_1")
+ self.freq_disp = wx.SpinCtrl(self, -1, "", min=0, max=100)
+ self.spin_e6 = wx.SpinButton(self, -1 )
+ self.spin_e5 = wx.SpinButton(self, -1 )
+ self.spin_e4 = wx.SpinButton(self, -1 )
+ self.spin_e3 = wx.SpinButton(self, -1 )
+ self.spin_e2 = wx.SpinButton(self, -1 )
+ self.spin_e1 = wx.SpinButton(self, -1 )
+ self.spin_e0 = wx.SpinButton(self, -1 )
+ self.panel_1 = wx.Panel(self, -1)
+ self.panel_2 = wx.Panel(self, -1)
+ self.button_lsb = wx.Button(self, -1, "LSB")
+ self.button_usb = wx.Button(self, -1, "USB")
+ self.button_am = wx.Button(self, -1, "AM")
+ self.label_1 = wx.StaticText(self, -1, "VOLUME")
+ self.label_2 = wx.StaticText(self, -1, "PGA")
+ self.agc_level = wx.TextCtrl(self, -1, "")
+ self.label_6 = wx.StaticText(self, -1, "")
+ self.volume = wx.SpinCtrl(self, -1, "", min=0, max=100)
+ self.pga = wx.SpinCtrl(self, -1, "", min=0, max=100)
+ self.agc_max = wx.TextCtrl(self, -1, "")
+ self.label_7 = wx.StaticText(self, -1, "")
+ self.label_4 = wx.StaticText(self, -1, "AGC AUTHORITY")
+ self.label_5 = wx.StaticText(self, -1, "AGC REF LVL")
+ self.label_3 = wx.StaticText(self, -1, "BANDWIDTH")
+ self.label_8 = wx.StaticText(self, -1, "")
+ self.agc_gain = wx.TextCtrl(self, -1, "")
+ self.agc_gain_s = wx.SpinButton(self, -1 )
+ self.agc_ref = wx.TextCtrl(self, -1, "")
+ self.agc_ref_s = wx.SpinButton(self, -1 )
+ self.bandwidth = wx.TextCtrl(self, -1, "")
+ self.bw_spin = wx.SpinButton(self, -1 )
+ self.label_9 = wx.StaticText(self, -1, "")
+ self.rssi = wx.Gauge(self, -1, 10, style=wx.GA_HORIZONTAL|wx.GA_SMOOTH)
+ self.fe_panel = wx.Panel(self, -1)
+ self.if_panel = wx.Panel(self, -1)
+
+ self.__set_properties()
+ self.__do_layout()
+
+ self.Bind(wx.EVT_SPINCTRL, self.tune_evt, self.freq_disp)
+ self.Bind(wx.EVT_SPIN_DOWN, self.down_e6, self.spin_e6)
+ self.Bind(wx.EVT_SPIN_UP, self.up_e6, self.spin_e6)
+ self.Bind(wx.EVT_SPIN_DOWN, self.down_e5, self.spin_e5)
+ self.Bind(wx.EVT_SPIN_UP, self.up_e5, self.spin_e5)
+ self.Bind(wx.EVT_SPIN_DOWN, self.down_e4, self.spin_e4)
+ self.Bind(wx.EVT_SPIN_UP, self.up_e4, self.spin_e4)
+ self.Bind(wx.EVT_SPIN_DOWN, self.down_e3, self.spin_e3)
+ self.Bind(wx.EVT_SPIN_UP, self.up_e3, self.spin_e3)
+ self.Bind(wx.EVT_SPIN_DOWN, self.down_e2, self.spin_e2)
+ self.Bind(wx.EVT_SPIN_UP, self.up_e2, self.spin_e2)
+ self.Bind(wx.EVT_SPIN_DOWN, self.down_e1, self.spin_e1)
+ self.Bind(wx.EVT_SPIN_UP, self.up_e1, self.spin_e1)
+ self.Bind(wx.EVT_SPIN_DOWN, self.down_e0, self.spin_e0)
+ self.Bind(wx.EVT_SPIN_UP, self.up_e0, self.spin_e0)
+ self.Bind(wx.EVT_BUTTON, self.set_lsb, self.button_lsb)
+ self.Bind(wx.EVT_BUTTON, self.set_usb, self.button_usb)
+ self.Bind(wx.EVT_BUTTON, self.set_am, self.button_am)
+ self.Bind(wx.EVT_SPINCTRL, self.event_vol, self.volume)
+ self.Bind(wx.EVT_SPINCTRL, self.event_pga, self.pga)
+ self.Bind(wx.EVT_SPIN_DOWN, self.agc_gain_down, self.agc_gain_s)
+ self.Bind(wx.EVT_SPIN_UP, self.agc_gain_up, self.agc_gain_s)
+ self.Bind(wx.EVT_SPIN_DOWN, self.agc_ref_down, self.agc_ref_s)
+ self.Bind(wx.EVT_SPIN_UP, self.agc_ref_up, self.agc_ref_s)
+ self.Bind(wx.EVT_SPIN_DOWN, self.bw_down, self.bw_spin)
+ self.Bind(wx.EVT_SPIN_UP, self.bw_up, self.bw_spin)
+ # end wxGlade
+
+ def __set_properties(self):
+ # begin wxGlade: ui_frame.__set_properties
+ self.SetTitle("frame_1")
+ self.freq_disp.SetFont(wx.Font(32, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, ""))
+ self.rssi.SetMinSize((315, 10))
+ self.rssi.SetForegroundColour(wx.Colour(255, 0, 0))
+ # end wxGlade
+
+ def __do_layout(self):
+ # begin wxGlade: ui_frame.__do_layout
+ sizer_1 = wx.StaticBoxSizer(self.sizer_1_staticbox, wx.VERTICAL)
+ sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_4 = wx.BoxSizer(wx.VERTICAL)
+ grid_sizer_4 = wx.GridSizer(2, 4, 0, 0)
+ sizer_5 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_7 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_6 = wx.BoxSizer(wx.HORIZONTAL)
+ grid_sizer_3 = wx.GridSizer(2, 4, 0, 0)
+ sizer_3 = wx.BoxSizer(wx.VERTICAL)
+ grid_sizer_1 = wx.GridSizer(2, 3, 0, 0)
+ grid_sizer_2 = wx.GridSizer(1, 7, 0, 0)
+ sizer_3.Add(self.freq_disp, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ grid_sizer_2.Add(self.spin_e6, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_2.Add(self.spin_e5, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_2.Add(self.spin_e4, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_2.Add(self.spin_e3, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_2.Add(self.spin_e2, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_2.Add(self.spin_e1, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_2.Add(self.spin_e0, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(grid_sizer_2, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(self.panel_2, 1, wx.EXPAND, 0)
+ grid_sizer_1.Add(self.button_lsb, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(self.button_usb, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_1.Add(self.button_am, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_3.Add(grid_sizer_1, 1, wx.EXPAND, 0)
+ sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
+ grid_sizer_3.Add(self.label_1, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_3.Add(self.label_2, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_3.Add(self.agc_level, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_3.Add(self.label_6, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_3.Add(self.volume, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_3.Add(self.pga, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_3.Add(self.agc_max, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_3.Add(self.label_7, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_4.Add(grid_sizer_3, 1, wx.EXPAND, 0)
+ grid_sizer_4.Add(self.label_4, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_4.Add(self.label_5, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_4.Add(self.label_3, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_4.Add(self.label_8, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_6.Add(self.agc_gain, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_6.Add(self.agc_gain_s, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_4.Add(sizer_6, 1, wx.EXPAND, 0)
+ sizer_7.Add(self.agc_ref, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_7.Add(self.agc_ref_s, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_4.Add(sizer_7, 1, wx.EXPAND, 0)
+ sizer_5.Add(self.bandwidth, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_5.Add(self.bw_spin, 0, wx.ADJUST_MINSIZE, 0)
+ grid_sizer_4.Add(sizer_5, 1, wx.EXPAND, 0)
+ grid_sizer_4.Add(self.label_9, 0, wx.ADJUST_MINSIZE, 0)
+ sizer_4.Add(grid_sizer_4, 1, wx.EXPAND, 0)
+ sizer_4.Add(self.rssi, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_2.Add(sizer_4, 1, wx.EXPAND, 0)
+ sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
+ sizer_1.Add(self.fe_panel, 1, wx.EXPAND, 0)
+ sizer_1.Add(self.if_panel, 1, wx.EXPAND, 0)
+ self.SetAutoLayout(True)
+ self.SetSizer(sizer_1)
+ sizer_1.Fit(self)
+ sizer_1.SetSizeHints(self)
+ self.Layout()
+ # end wxGlade
+
+ def down_e6(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `down_e6' not implemented"
+ event.Skip()
+
+ def up_e6(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `up_e6' not implemented"
+ event.Skip()
+
+ def down_e5(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `down_e5' not implemented"
+ event.Skip()
+
+ def up_e5(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `up_e5' not implemented"
+ event.Skip()
+
+ def down_e4(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `down_e4' not implemented"
+ event.Skip()
+
+ def up_e4(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `up_e4' not implemented"
+ event.Skip()
+
+ def down_e3(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `down_e3' not implemented"
+ event.Skip()
+
+ def up_e3(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `up_e3' not implemented"
+ event.Skip()
+
+ def down_e2(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `down_e2' not implemented"
+ event.Skip()
+
+ def up_e2(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `up_e2' not implemented"
+ event.Skip()
+
+ def down_e1(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `down_e1' not implemented"
+ event.Skip()
+
+ def up_e1(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `up_e1' not implemented"
+ event.Skip()
+
+ def down_e0(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `down_e0' not implemented"
+ event.Skip()
+
+ def up_e0(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `up_e0' not implemented"
+ event.Skip()
+
+ def event_vol(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `event_vol' not implemented"
+ event.Skip()
+
+ def event_pga(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `event_pga' not implemented"
+ event.Skip()
+
+ def set_lsb(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `set_lsb' not implemented"
+ event.Skip()
+
+ def set_usb(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `set_usb' not implemented"
+ event.Skip()
+
+ def set_am(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `set_am' not implemented"
+ event.Skip()
+
+ def set_bw(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `set_bw' not implemented"
+ event.Skip()
+
+ def tune_evt(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `tune_evt' not implemented"
+ event.Skip()
+
+ def bw_down(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `bw_down' not implemented"
+ event.Skip()
+
+ def bw_up(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `bw_up' not implemented"
+ event.Skip()
+
+ def agc_gain_down(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `agc_gain_down' not implemented"
+ event.Skip()
+
+ def agc_gain_up(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `agc_gain_up' not implemented"
+ event.Skip()
+
+ def agc_ref_down(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `agc_ref_down' not implemented"
+ event.Skip()
+
+ def agc_ref_up(self, event): # wxGlade: ui_frame.<event_handler>
+ print "Event handler `agc_ref_up' not implemented"
+ event.Skip()
+
+# end of class ui_frame
+
+
+class RadioFrame(wx.Frame):
+ def __init__(self, *args, **kwds):
+ # content of this block not found: did you rename this class?
+ pass
+
+ def __set_properties(self):
+ # content of this block not found: did you rename this class?
+ pass
+
+ def __do_layout(self):
+ # content of this block not found: did you rename this class?
+ pass
+
+# end of class RadioFrame
+
+
+class MyFrame(wx.Frame):
+ def __init__(self, *args, **kwds):
+ # content of this block not found: did you rename this class?
+ pass
+
+ def __set_properties(self):
+ # content of this block not found: did you rename this class?
+ pass
+
+ def __do_layout(self):
+ # content of this block not found: did you rename this class?
+ pass
+
+# end of class MyFrame
+
+
diff --git a/gr-uhd/apps/uhd_fft.py b/gr-uhd/apps/uhd_fft.py
index 87952ef3a..0f0c274e8 100755
--- a/gr-uhd/apps/uhd_fft.py
+++ b/gr-uhd/apps/uhd_fft.py
@@ -20,16 +20,23 @@
# Boston, MA 02110-1301, USA.
#
-from gnuradio import gr, gru
+from gnuradio import gr
from gnuradio import uhd
from gnuradio import eng_notation
from gnuradio.eng_option import eng_option
-from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider
from optparse import OptionParser
-import wx
+
import sys
import numpy
+try:
+ from gnuradio.wxgui import stdgui2, form, slider
+ from gnuradio.wxgui import fftsink2, waterfallsink2, scopesink2
+ import wx
+except ImportError:
+ sys.stderr.write("Error importing GNU Radio's wxgui. Please make sure gr-wxgui is installed.\n")
+ sys.exit(1)
+
class app_top_block(stdgui2.std_top_block):
def __init__(self, frame, panel, vbox, argv):
stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)
@@ -38,7 +45,8 @@ class app_top_block(stdgui2.std_top_block):
self.panel = panel
parser = OptionParser(option_class=eng_option)
- parser.add_option("-a", "--address", type="string", default="addr=192.168.10.2",
+ parser.add_option("-a", "--address", type="string",
+ default="addr=192.168.10.2",
help="Address of UHD device, [default=%default]")
parser.add_option("-A", "--antenna", type="string", default=None,
help="select Rx Antenna where appropriate")
@@ -74,7 +82,8 @@ class app_top_block(stdgui2.std_top_block):
if options.waterfall:
self.scope = \
- waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate)
+ waterfallsink2.waterfall_sink_c (panel, fft_size=1024,
+ sample_rate=input_rate)
self.frame.SetMinSize((800, 420))
elif options.oscilloscope:
self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate)
@@ -114,9 +123,8 @@ class app_top_block(stdgui2.std_top_block):
if self.show_debug_info:
self.myform['samprate'].set_value(self.u.get_samp_rate())
- self.myform['fs@gbe'].set_value(input_rate)
- self.myform['baseband'].set_value(0)
- self.myform['ddc'].set_value(0)
+ self.myform['rffreq'].set_value(0)
+ self.myform['dspfreq'].set_value(0)
if not(self.set_freq(options.freq)):
self._set_status_msg("Failed to set initial frequency")
@@ -137,14 +145,16 @@ class app_top_block(stdgui2.std_top_block):
hbox.Add((5,0), 0, 0)
myform['freq'] = form.float_field(
parent=self.panel, sizer=hbox, label="Center freq", weight=1,
- callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
+ callback=myform.check_input_and_call(_form_set_freq,
+ self._set_status_msg))
hbox.Add((5,0), 0, 0)
g = self.u.get_gain_range()
# some configurations don't have gain control
if g.stop() > g.start():
- myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain",
+ myform['gain'] = form.slider_field(parent=self.panel,
+ sizer=hbox, label="Gain",
weight=3,
min=int(g.start()), max=int(g.stop()),
callback=self.set_gain)
@@ -175,19 +185,16 @@ class app_top_block(stdgui2.std_top_block):
hbox.Add((5,0), 0)
myform['samprate'] = form.float_field(
parent=panel, sizer=hbox, label="Sample Rate",
- callback=myform.check_input_and_call(_form_set_samp_rate, self._set_status_msg))
+ callback=myform.check_input_and_call(_form_set_samp_rate,
+ self._set_status_msg))
hbox.Add((5,0), 1)
- myform['fs@gbe'] = form.static_float_field(
- parent=panel, sizer=hbox, label="Fs@GbE")
+ myform['rffreq'] = form.static_float_field(
+ parent=panel, sizer=hbox, label="RF Freq.")
hbox.Add((5,0), 1)
- myform['baseband'] = form.static_float_field(
- parent=panel, sizer=hbox, label="Analog BB")
-
- hbox.Add((5,0), 1)
- myform['ddc'] = form.static_float_field(
- parent=panel, sizer=hbox, label="DDC")
+ myform['dspfreq'] = form.static_float_field(
+ parent=panel, sizer=hbox, label="DSP Freq.")
hbox.Add((5,0), 0)
vbox.Add(hbox, 0, wx.EXPAND)
@@ -198,19 +205,13 @@ class app_top_block(stdgui2.std_top_block):
@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, 0)
if r:
- self.myform['freq'].set_value(target_freq) # update displayed value
- if self.show_debug_info:
- self.myform['baseband'].set_value(r.actual_rf_freq)
- self.myform['ddc'].set_value(r.actual_dsp_freq)
+ self.myform['freq'].set_value(self.u.get_center_freq())
+ self.myform['rffreq'].set_value(r.actual_rf_freq)
+ self.myform['dspfreq'].set_value(r.actual_dsp_freq)
if not self.options.oscilloscope:
self.scope.set_baseband_freq(target_freq)
return True
@@ -228,7 +229,6 @@ class app_top_block(stdgui2.std_top_block):
self.scope.set_sample_rate(input_rate)
if self.show_debug_info: # update displayed values
self.myform['samprate'].set_value(self.u.get_samp_rate())
- self.myform['fs@gbe'].set_value(input_rate)
# uhd set_samp_rate never fails; always falls back to closest requested.
return True
diff --git a/gr-uhd/apps/uhd_rx_nogui.py b/gr-uhd/apps/uhd_rx_nogui.py
new file mode 100755
index 000000000..6f860b820
--- /dev/null
+++ b/gr-uhd/apps/uhd_rx_nogui.py
@@ -0,0 +1,233 @@
+#!/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 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, gru, uhd, optfir, audio, blks2
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+
+"""
+This example application demonstrates receiving and demodulating
+different types of signals using the USRP.
+
+A receive chain is built up of the following signal processing
+blocks:
+
+USRP - Daughter board source generating complex baseband signal.
+CHAN - Low pass filter to select channel bandwidth
+RFSQL - RF squelch zeroing output when input power below threshold
+AGC - Automatic gain control leveling signal at [-1.0, +1.0]
+DEMOD - Demodulation block appropriate to selected signal type.
+ This converts the complex baseband to real audio frequencies,
+ and applies an appropriate low pass decimating filter.
+CTCSS - Optional tone squelch zeroing output when tone is not present.
+RSAMP - Resampler block to convert audio sample rate to user specified
+ sound card output rate.
+AUDIO - Audio sink for playing final output to speakers.
+
+The following are required command line parameters:
+
+-f FREQ USRP receive frequency
+-m MOD Modulation type, select from AM, FM, or WFM
+
+The following are optional command line parameters:
+
+-R SUBDEV Daughter board specification, defaults to first found
+-c FREQ Calibration offset. Gets added to receive frequency.
+ Defaults to 0.0 Hz.
+-g GAIN Daughterboard gain setting. Defaults to mid-range.
+-o RATE Sound card output rate. Defaults to 32000. Useful if
+ your sound card only accepts particular sample rates.
+-r RFSQL RF squelch in db. Defaults to -50.0.
+-p FREQ CTCSS frequency. Opens squelch when tone is present.
+
+Once the program is running, ctrl-break (Ctrl-C) stops operation.
+
+Please see fm_demod.py and am_demod.py for details of the demodulation
+blocks.
+"""
+
+# (device_rate, channel_rate, audio_rate, channel_pass, channel_stop, demod)
+demod_params = {
+ 'AM' : (256e3, 16e3, 16e3, 5000, 8000, blks2.demod_10k0a3e_cf),
+ 'FM' : (256e3, 32e3, 8e3, 8000, 9000, blks2.demod_20k0f3e_cf),
+ 'WFM' : (320e3, 320e3, 32e3, 80000, 115000, blks2.demod_200kf3e_cf)
+ }
+
+class uhd_src(gr.hier_block2):
+ """
+ Create a UHD source object supplying complex floats.
+
+ Selects user supplied subdevice or chooses first available one.
+
+ Calibration value is the offset from the tuned frequency to
+ the actual frequency.
+ """
+ def __init__(self, address, samp_rate, gain=None, calibration=0.0):
+ gr.hier_block2.__init__(self, "uhd_src",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ self._src = uhd.usrp_source(device_addr=address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ self._src.set_samp_rate(samp_rate)
+ dev_rate = self._src.get_samp_rate()
+ self._samp_rate = samp_rate
+
+ # Resampler to get to exactly samp_rate no matter what dev_rate is
+ self._rrate = samp_rate / dev_rate
+ self._resamp = blks2.pfb_arb_resampler_ccf(self._rrate)
+
+ # If no gain specified, set to midrange
+ if gain is None:
+ g = self._src.get_gain_range()
+ gain = (g.start()+g.stop())/2.0
+ print "Using gain: ", gain
+ self._src.set_gain(gain)
+
+ self._cal = calibration
+ self.connect(self._src, self._resamp, self)
+
+ def tune(self, freq):
+ r = self._src.set_center_freq(freq+self._cal, 0)
+
+ def rate(self):
+ return self._samp_rate
+
+class app_top_block(gr.top_block):
+ def __init__(self, options):
+ gr.top_block.__init__(self)
+ self.options = options
+
+ (dev_rate, channel_rate, audio_rate,
+ channel_pass, channel_stop, demod) = demod_params[options.modulation]
+
+ DEV = uhd_src(options.address, # UHD device address
+ dev_rate, # device sample rate
+ options.gain, # Receiver gain
+ options.calibration) # Frequency offset
+ DEV.tune(options.frequency)
+
+ if_rate = DEV.rate()
+ channel_decim = int(if_rate // channel_rate)
+ audio_decim = int(channel_rate // audio_rate)
+
+ CHAN_taps = optfir.low_pass(1.0, # Filter gain
+ if_rate, # Sample rate
+ channel_pass, # One sided modulation bandwidth
+ channel_stop, # One sided channel bandwidth
+ 0.1, # Passband ripple
+ 60) # Stopband attenuation
+
+ CHAN = gr.freq_xlating_fir_filter_ccf(channel_decim, # Decimation rate
+ CHAN_taps, # Filter taps
+ 0.0, # Offset frequency
+ if_rate) # Sample rate
+
+ RFSQL = gr.pwr_squelch_cc(options.rf_squelch, # Power threshold
+ 125.0/channel_rate, # Time constant
+ int(channel_rate/20), # 50ms rise/fall
+ False) # Zero, not gate output
+
+ AGC = gr.agc_cc(1.0/channel_rate, # Time constant
+ 1.0, # Reference power
+ 1.0, # Initial gain
+ 1.0) # Maximum gain
+
+ DEMOD = demod(channel_rate, audio_decim)
+
+ # From RF to audio
+ #self.connect(DEV, CHAN, RFSQL, AGC, DEMOD)
+ self.connect(DEV, CHAN, DEMOD)
+
+ # Optionally add CTCSS and RSAMP if needed
+ tail = DEMOD
+ if options.ctcss != None and options.ctcss > 60.0:
+ CTCSS = gr.ctcss_squelch_ff(audio_rate, # Sample rate
+ options.ctcss) # Squelch tone
+ self.connect(DEMOD, CTCSS)
+ tail = CTCSS
+
+ if options.output_rate != audio_rate:
+ out_lcm = gru.lcm(audio_rate, options.output_rate)
+ out_interp = int(out_lcm // audio_rate)
+ out_decim = int(out_lcm // options.output_rate)
+ RSAMP = blks2.rational_resampler_fff(out_interp, out_decim)
+ self.connect(tail, RSAMP)
+ tail = RSAMP
+
+ # Send to audio output device
+ AUDIO = audio.sink(int(options.output_rate),
+ options.audio_output)
+ self.connect(tail, AUDIO)
+
+def main():
+ parser = OptionParser(option_class=eng_option)
+ parser.add_option("-a", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ parser.add_option("-A", "--antenna", type="string", default=None,
+ help="select Rx Antenna where appropriate [default=%default]")
+ parser.add_option("-f", "--frequency", type="eng_float",
+ default=None, metavar="Hz",
+ help="set receive frequency to Hz [default=%default]")
+ parser.add_option("-c", "--calibration", type="eng_float",
+ default=0.0, metavar="Hz",
+ help="set frequency offset to Hz [default=%default]")
+ parser.add_option("-g", "--gain", type="int",
+ metavar="dB", default=None,
+ help="set RF gain [default is midpoint]")
+ parser.add_option("-m", "--modulation", type="choice", choices=('AM','FM','WFM'),
+ metavar="TYPE", default=None,
+ help="set modulation type (AM,FM) [default=%default]")
+ parser.add_option("-o", "--output-rate", type="eng_float",
+ default=32000, metavar="RATE",
+ help="set audio output rate to RATE [default=%default]")
+ parser.add_option("-r", "--rf-squelch", type="eng_float",
+ default=-50.0, metavar="dB",
+ help="set RF squelch to dB [default=%default]")
+ parser.add_option("-p", "--ctcss", type="float",
+ default=None, metavar="FREQ",
+ help="set CTCSS squelch to FREQ [default=%default]")
+ 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 options.frequency is None:
+ sys.stderr.write("Must supply receive frequency with -f.\n")
+ sys.exit(1)
+
+ if options.modulation is None:
+ sys.stderr.write("Must supply a modulation type (AM, FM, WFM).\n")
+ sys.exit(1)
+
+ tb = app_top_block(options)
+ try:
+ tb.run()
+ except KeyboardInterrupt:
+ pass
+
+if __name__ == "__main__":
+ main()
diff --git a/gr-uhd/apps/uhd_siggen.py b/gr-uhd/apps/uhd_siggen.py
new file mode 100755
index 000000000..921ba44b5
--- /dev/null
+++ b/gr-uhd/apps/uhd_siggen.py
@@ -0,0 +1,350 @@
+#!/usr/bin/env python
+#
+# Copyright 2008,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.
+#
+
+DESC_KEY = 'desc'
+SAMP_RATE_KEY = 'samp_rate'
+LINK_RATE_KEY = 'link_rate'
+GAIN_KEY = 'gain'
+TX_FREQ_KEY = 'tx_freq'
+DSP_FREQ_KEY = 'dsp_freq'
+RF_FREQ_KEY = 'rf_freq'
+AMPLITUDE_KEY = 'amplitude'
+AMPL_RANGE_KEY = 'ampl_range'
+WAVEFORM_FREQ_KEY = 'waveform_freq'
+WAVEFORM_OFFSET_KEY = 'waveform_offset'
+WAVEFORM2_FREQ_KEY = 'waveform2_freq'
+FREQ_RANGE_KEY = 'freq_range'
+GAIN_RANGE_KEY = 'gain_range'
+TYPE_KEY = 'type'
+
+def setter(ps, key, val): ps[key] = val
+
+from gnuradio import gr, uhd, eng_notation
+from gnuradio.gr.pubsub import pubsub
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+import math
+
+n2s = eng_notation.num_to_str
+
+waveforms = { gr.GR_SIN_WAVE : "Complex Sinusoid",
+ gr.GR_CONST_WAVE : "Constant",
+ gr.GR_GAUSSIAN : "Gaussian Noise",
+ gr.GR_UNIFORM : "Uniform Noise",
+ "2tone" : "Two Tone",
+ "sweep" : "Sweep" }
+
+#
+# GUI-unaware GNU Radio flowgraph. This may be used either with command
+# line applications or GUI applications.
+#
+class top_block(gr.top_block, pubsub):
+ def __init__(self, options, args):
+ gr.top_block.__init__(self)
+ pubsub.__init__(self)
+ self._verbose = options.verbose
+
+ #initialize values from options
+ self._setup_usrpx(options)
+ self[SAMP_RATE_KEY] = options.samp_rate
+ self[TX_FREQ_KEY] = options.tx_freq
+ self[AMPLITUDE_KEY] = options.amplitude
+ self[WAVEFORM_FREQ_KEY] = options.waveform_freq
+ self[WAVEFORM_OFFSET_KEY] = options.offset
+ self[WAVEFORM2_FREQ_KEY] = options.waveform2_freq
+ self[DSP_FREQ_KEY] = 0
+ self[RF_FREQ_KEY] = 0
+
+ #subscribe set methods
+ self.subscribe(SAMP_RATE_KEY, self.set_samp_rate)
+ self.subscribe(GAIN_KEY, self.set_gain)
+ self.subscribe(TX_FREQ_KEY, self.set_freq)
+ self.subscribe(AMPLITUDE_KEY, self.set_amplitude)
+ self.subscribe(WAVEFORM_FREQ_KEY, self.set_waveform_freq)
+ self.subscribe(WAVEFORM2_FREQ_KEY, self.set_waveform2_freq)
+ self.subscribe(TYPE_KEY, self.set_waveform)
+
+ #force update on pubsub keys
+ for key in (SAMP_RATE_KEY, GAIN_KEY, TX_FREQ_KEY,
+ AMPLITUDE_KEY, WAVEFORM_FREQ_KEY,
+ WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY):
+ self[key] = self[key]
+ self[TYPE_KEY] = options.type #set type last
+
+ def _setup_usrpx(self, options):
+ self._u = uhd.usrp_sink(device_addr=options.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+ self._u.set_samp_rate(options.samp_rate)
+ if(options.antenna):
+ self._u.set_antenna(options.antenna)
+
+ self.publish(DESC_KEY, lambda: str(self._u))
+ self.publish(FREQ_RANGE_KEY, self._u.get_freq_range)
+ self.publish(GAIN_RANGE_KEY, self._u.get_gain_range)
+ self.publish(GAIN_KEY, self._u.get_gain)
+ if self._verbose:
+ print str(self._u)
+
+ def _set_tx_amplitude(self, ampl):
+ """
+ Sets the transmit amplitude sent to the USRP
+ @param ampl the amplitude or None for automatic
+ """
+ ampl_range = self[AMPL_RANGE_KEY]
+ if ampl is None:
+ ampl = (ampl_range[1] - ampl_range[0])*0.15 + ampl_range[0]
+ self[AMPLITUDE_KEY] = max(ampl_range[0], min(ampl, ampl_range[1]))
+
+ def set_samp_rate(self, sr):
+ self._u.set_samp_rate(sr)
+ sr = self._u.get_samp_rate()
+
+ if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE):
+ self._src.set_sampling_freq(self[SAMP_RATE_KEY])
+ elif self[TYPE_KEY] == "2tone":
+ self._src1.set_sampling_freq(self[SAMP_RATE_KEY])
+ self._src2.set_sampling_freq(self[SAMP_RATE_KEY])
+ elif self[TYPE_KEY] == "sweep":
+ self._src1.set_sampling_freq(self[SAMP_RATE_KEY])
+ self._src2.set_sampling_freq(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY])
+ else:
+ return True # Waveform not yet set
+
+ if self._verbose:
+ print "Set sample rate to:", sr
+
+ return True
+
+ def set_gain(self, gain):
+ if gain is None:
+ g = self[GAIN_RANGE_KEY]
+ gain = float(g[0]+g[1])/2
+ if self._verbose:
+ print "Using auto-calculated mid-point TX gain"
+ self[GAIN_KEY] = gain
+ return
+ self._u.set_gain(gain)
+ if self._verbose:
+ print "Set TX gain to:", gain
+
+ def set_freq(self, target_freq):
+
+ if target_freq is None:
+ f = self[FREQ_RANGE_KEY]
+ target_freq = float(f[0]+f[1])/2.0
+ if self._verbose:
+ print "Using auto-calculated mid-point frequency"
+ self[TX_FREQ_KEY] = target_freq
+ return
+
+ tr = self._u.set_center_freq(target_freq)
+ fs = "%sHz" % (n2s(target_freq),)
+ if tr is not None:
+ self._freq = target_freq
+ self[DSP_FREQ_KEY] = tr.actual_dsp_freq
+ self[RF_FREQ_KEY] = tr.actual_rf_freq
+ if self._verbose:
+ print "Set center frequency to", self._u.get_center_freq()
+ print "Tx RF frequency: %sHz" % (n2s(tr.actual_rf_freq),)
+ print "Tx DSP frequency: %sHz" % (n2s(tr.actual_dsp_freq),)
+ elif self._verbose:
+ print "Failed to set freq."
+ return tr
+
+ def set_waveform_freq(self, freq):
+ if self[TYPE_KEY] == gr.GR_SIN_WAVE:
+ self._src.set_frequency(freq)
+ elif self[TYPE_KEY] == "2tone":
+ self._src1.set_frequency(freq)
+ elif self[TYPE_KEY] == 'sweep':
+ #there is no set sensitivity, redo fg
+ self[TYPE_KEY] = self[TYPE_KEY]
+ return True
+
+ def set_waveform2_freq(self, freq):
+ if freq is None:
+ self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY]
+ return
+ if self[TYPE_KEY] == "2tone":
+ self._src2.set_frequency(freq)
+ elif self[TYPE_KEY] == "sweep":
+ self._src1.set_frequency(freq)
+ return True
+
+ def set_waveform(self, type):
+ self.lock()
+ self.disconnect_all()
+ if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE:
+ self._src = gr.sig_source_c(self[SAMP_RATE_KEY], # Sample rate
+ type, # Waveform type
+ self[WAVEFORM_FREQ_KEY], # Waveform frequency
+ self[AMPLITUDE_KEY], # Waveform amplitude
+ self[WAVEFORM_OFFSET_KEY]) # Waveform offset
+ elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM:
+ self._src = gr.noise_source_c(type, self[AMPLITUDE_KEY])
+ elif type == "2tone":
+ self._src1 = gr.sig_source_c(self[SAMP_RATE_KEY],
+ gr.GR_SIN_WAVE,
+ self[WAVEFORM_FREQ_KEY],
+ self[AMPLITUDE_KEY]/2.0,
+ 0)
+ if(self[WAVEFORM2_FREQ_KEY] is None):
+ self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY]
+
+ self._src2 = gr.sig_source_c(self[SAMP_RATE_KEY],
+ gr.GR_SIN_WAVE,
+ self[WAVEFORM2_FREQ_KEY],
+ self[AMPLITUDE_KEY]/2.0,
+ 0)
+ self._src = gr.add_cc()
+ self.connect(self._src1,(self._src,0))
+ self.connect(self._src2,(self._src,1))
+ elif type == "sweep":
+ # rf freq is center frequency
+ # waveform_freq is total swept width
+ # waveform2_freq is sweep rate
+ # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2)
+ if self[WAVEFORM2_FREQ_KEY] is None:
+ self[WAVEFORM2_FREQ_KEY] = 0.1
+
+ self._src1 = gr.sig_source_f(self[SAMP_RATE_KEY],
+ gr.GR_TRI_WAVE,
+ self[WAVEFORM2_FREQ_KEY],
+ 1.0,
+ -0.5)
+ self._src2 = gr.frequency_modulator_fc(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY])
+ self._src = gr.multiply_const_cc(self[AMPLITUDE_KEY])
+ self.connect(self._src1,self._src2,self._src)
+ else:
+ raise RuntimeError("Unknown waveform type")
+
+ self.connect(self._src, self._u)
+ self.unlock()
+
+ if self._verbose:
+ print "Set baseband modulation to:", waveforms[type]
+ if type == gr.GR_SIN_WAVE:
+ print "Modulation frequency: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),)
+ print "Initial phase:", self[WAVEFORM_OFFSET_KEY]
+ elif type == "2tone":
+ print "Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),)
+ print "Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),)
+ elif type == "sweep":
+ print "Sweeping across %sHz to %sHz" % (n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0))
+ print "Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),)
+ print "TX amplitude:", self[AMPLITUDE_KEY]
+
+
+ def set_amplitude(self, amplitude):
+ if amplitude < 0.0 or amplitude > 1.0:
+ if self._verbose:
+ print "Amplitude out of range:", amplitude
+ return False
+
+ if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, gr.GR_GAUSSIAN, gr.GR_UNIFORM):
+ self._src.set_amplitude(amplitude)
+ elif self[TYPE_KEY] == "2tone":
+ self._src1.set_amplitude(amplitude/2.0)
+ self._src2.set_amplitude(amplitude/2.0)
+ elif self[TYPE_KEY] == "sweep":
+ self._src.set_k(amplitude)
+ else:
+ return True # Waveform not yet set
+
+ if self._verbose:
+ print "Set amplitude to:", amplitude
+ return True
+
+def get_options():
+ usage="%prog: [options]"
+
+ parser = OptionParser(option_class=eng_option, usage=usage)
+ parser.add_option("-a", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ parser.add_option("-A", "--antenna", type="string", default=None,
+ help="select Rx Antenna where appropriate")
+ parser.add_option("-s", "--samp-rate", type="eng_float", default=1e6,
+ help="set sample rate (bandwidth) [default=%default]")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-f", "--tx-freq", type="eng_float", default=None,
+ help="Set carrier frequency to FREQ [default=mid-point]",
+ metavar="FREQ")
+ parser.add_option("-x", "--waveform-freq", type="eng_float", default=0,
+ help="Set baseband waveform frequency to FREQ [default=%default]")
+ parser.add_option("-y", "--waveform2-freq", type="eng_float", default=None,
+ help="Set 2nd waveform frequency to FREQ [default=%default]")
+ parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE,
+ help="Generate a carrier modulated by a complex sine wave",
+ default=gr.GR_SIN_WAVE)
+ parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE,
+ help="Generate a constant carrier")
+ parser.add_option("--offset", type="eng_float", default=0,
+ help="Set waveform phase offset to OFFSET [default=%default]")
+ parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN,
+ help="Generate Gaussian random output")
+ parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM,
+ help="Generate Uniform random output")
+ parser.add_option("--2tone", dest="type", action="store_const", const="2tone",
+ help="Generate Two Tone signal for IMD testing")
+ parser.add_option("--sweep", dest="type", action="store_const", const="sweep",
+ help="Generate a swept sine wave")
+ parser.add_option("", "--amplitude", type="eng_float", default=0.15,
+ help="Set output amplitude to AMPL (0.0-1.0) [default=%default]",
+ metavar="AMPL")
+ parser.add_option("-v", "--verbose", action="store_true", default=False,
+ help="Use verbose console output [default=%default]")
+
+ (options, args) = parser.parse_args()
+
+ return (options, args)
+
+# If this script is executed, the following runs. If it is imported,
+# the below does not run.
+def main():
+ if gr.enable_realtime_scheduling() != gr.RT_OK:
+ print "Note: failed to enable realtime scheduling, continuing"
+
+ # Grab command line options and create top block
+ try:
+ (options, args) = get_options()
+ tb = top_block(options, args)
+
+ except RuntimeError, e:
+ print e
+ sys.exit(1)
+
+ tb.start()
+ raw_input('Press Enter to quit: ')
+ tb.stop()
+ tb.wait()
+
+# Make sure to create the top block (tb) within a function:
+# That code in main will allow tb to go out of scope on return,
+# which will call the decontructor on usrp and stop transmit.
+# Whats odd is that grc works fine with tb in the __main__,
+# perhaps its because the try/except clauses around tb.
+if __name__ == "__main__":
+ main()
diff --git a/gr-uhd/apps/uhd_siggen_gui.py b/gr-uhd/apps/uhd_siggen_gui.py
new file mode 100755
index 000000000..2ef6ea40f
--- /dev/null
+++ b/gr-uhd/apps/uhd_siggen_gui.py
@@ -0,0 +1,318 @@
+#!/usr/bin/env python
+#
+# Copyright 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.
+#
+
+import wx
+from gnuradio import gr
+from gnuradio.gr.pubsub import pubsub
+from gnuradio.wxgui import gui, forms
+import uhd_siggen
+import sys, math
+
+class app_gui(pubsub):
+ def __init__(self, frame, panel, vbox, top_block, options, args):
+ pubsub.__init__(self)
+ self.frame = frame # Use for top-level application window frame
+ self.panel = panel # Use as parent class for created windows
+ self.vbox = vbox # Use as sizer for created windows
+ self.tb = top_block # GUI-unaware flowgraph class
+ self.options = options # Supplied command-line options
+ self.args = args # Supplied command-line arguments
+ self.build_gui()
+
+ # Event response handlers
+ def evt_set_status_msg(self, msg):
+ self.frame.SetStatusText(msg, 0)
+
+ # GUI construction
+ def build_gui(self):
+ self.vbox.AddSpacer(5)
+ self.vbox.AddStretchSpacer()
+ ##################################################
+ # Baseband controls
+ ##################################################
+ bb_vbox = forms.static_box_sizer(parent=self.panel, label="Baseband Modulation", orient=wx.VERTICAL, bold=True)
+ self.vbox.Add(bb_vbox, 0, wx.EXPAND)
+ sine_bb_hbox = wx.BoxSizer(wx.HORIZONTAL)
+ sweep_bb_hbox = wx.BoxSizer(wx.HORIZONTAL)
+ tone_bb_hbox = wx.BoxSizer(wx.HORIZONTAL)
+ self.vbox.AddSpacer(10)
+ self.vbox.AddStretchSpacer()
+ #callback to show/hide forms
+ def set_type(type):
+ sine_bb_hbox.ShowItems(type == gr.GR_SIN_WAVE)
+ sweep_bb_hbox.ShowItems(type == 'sweep')
+ tone_bb_hbox.ShowItems(type == '2tone')
+ self.vbox.Layout()
+ self.tb.subscribe(uhd_siggen.TYPE_KEY, set_type)
+ #create sine forms
+ sine_bb_hbox.AddSpacer(10)
+ forms.text_box(
+ parent=self.panel, sizer=sine_bb_hbox,
+ label='Frequency (Hz)',
+ ps=self.tb,
+ key=uhd_siggen.WAVEFORM_FREQ_KEY,
+ converter=forms.float_converter(),
+ )
+ sine_bb_hbox.AddStretchSpacer()
+ #create sweep forms
+ sweep_bb_hbox.AddSpacer(10)
+ forms.text_box(
+ parent=self.panel, sizer=sweep_bb_hbox,
+ label='Sweep Width (Hz)',
+ ps=self.tb,
+ key=uhd_siggen.WAVEFORM_FREQ_KEY,
+ converter=forms.float_converter(),
+ )
+ sweep_bb_hbox.AddStretchSpacer()
+ forms.text_box(
+ parent=self.panel, sizer=sweep_bb_hbox,
+ label='Sweep Rate (Hz)',
+ ps=self.tb,
+ key=uhd_siggen.WAVEFORM2_FREQ_KEY,
+ converter=forms.float_converter(),
+ )
+ sweep_bb_hbox.AddStretchSpacer()
+ #create 2tone forms
+ tone_bb_hbox.AddSpacer(10)
+ forms.text_box(
+ parent=self.panel, sizer=tone_bb_hbox,
+ label='Tone 1 (Hz)',
+ ps=self.tb,
+ key=uhd_siggen.WAVEFORM_FREQ_KEY,
+ converter=forms.float_converter(),
+ )
+ tone_bb_hbox.AddStretchSpacer()
+ forms.text_box(
+ parent=self.panel, sizer=tone_bb_hbox,
+ label='Tone 2 (Hz)',
+ ps=self.tb,
+ key=uhd_siggen.WAVEFORM2_FREQ_KEY,
+ converter=forms.float_converter(),
+ )
+ tone_bb_hbox.AddStretchSpacer()
+ forms.radio_buttons(
+ parent=self.panel, sizer=bb_vbox,
+ choices=uhd_siggen.waveforms.keys(),
+ labels=uhd_siggen.waveforms.values(),
+ ps=self.tb,
+ key=uhd_siggen.TYPE_KEY,
+ style=wx.NO_BORDER | wx.RA_HORIZONTAL,
+ )
+ bb_vbox.AddSpacer(10)
+ bb_vbox.Add(sine_bb_hbox, 0, wx.EXPAND)
+ bb_vbox.Add(sweep_bb_hbox, 0, wx.EXPAND)
+ bb_vbox.Add(tone_bb_hbox, 0, wx.EXPAND)
+ set_type(self.tb[uhd_siggen.TYPE_KEY])
+
+ ##################################################
+ # Frequency controls
+ ##################################################
+ fc_vbox = forms.static_box_sizer(parent=self.panel,
+ label="Center Frequency",
+ orient=wx.VERTICAL,
+ bold=True)
+ fc_vbox.AddSpacer(5)
+ # First row of frequency controls (center frequency)
+ freq_hbox = wx.BoxSizer(wx.HORIZONTAL)
+ fc_vbox.Add(freq_hbox, 0, wx.EXPAND)
+ fc_vbox.AddSpacer(10)
+ # Second row of frequency controls (results)
+ tr_hbox = wx.BoxSizer(wx.HORIZONTAL)
+ fc_vbox.Add(tr_hbox, 0, wx.EXPAND)
+ fc_vbox.AddSpacer(5)
+ # Add frequency controls to top window sizer
+ self.vbox.Add(fc_vbox, 0, wx.EXPAND)
+ self.vbox.AddSpacer(10)
+ self.vbox.AddStretchSpacer()
+ freq_hbox.AddSpacer(5)
+ forms.text_box(
+ parent=self.panel, sizer=freq_hbox,
+ proportion=1,
+ converter=forms.float_converter(),
+ ps=self.tb,
+ key=uhd_siggen.TX_FREQ_KEY,
+ )
+ freq_hbox.AddSpacer(10)
+
+ forms.slider(
+ parent=self.panel, sizer=freq_hbox,
+ proportion=2,
+ ps=self.tb,
+ key=uhd_siggen.TX_FREQ_KEY,
+ minimum=self.tb[uhd_siggen.FREQ_RANGE_KEY].start(),
+ maximum=self.tb[uhd_siggen.FREQ_RANGE_KEY].stop(),
+ num_steps=100,
+ )
+ freq_hbox.AddSpacer(5)
+ tr_hbox.AddSpacer(5)
+ forms.static_text(
+ parent=self.panel, sizer=tr_hbox,
+ label='RF Frequency',
+ ps=self.tb,
+ key=uhd_siggen.RF_FREQ_KEY,
+ converter=forms.float_converter(),
+ proportion=1,
+ )
+ tr_hbox.AddSpacer(10)
+ forms.static_text(
+ parent=self.panel, sizer=tr_hbox,
+ label='DSP Frequency',
+ ps=self.tb,
+ key=uhd_siggen.DSP_FREQ_KEY,
+ converter=forms.float_converter(),
+ proportion=1,
+ )
+ tr_hbox.AddSpacer(5)
+
+ ##################################################
+ # Amplitude controls
+ ##################################################
+ amp_hbox = forms.static_box_sizer(parent=self.panel,
+ label="Amplitude",
+ orient=wx.VERTICAL,
+ bold=True)
+ amp_hbox.AddSpacer(5)
+ # First row of amp controls (ampl)
+ lvl_hbox = wx.BoxSizer(wx.HORIZONTAL)
+ amp_hbox.Add(lvl_hbox, 0, wx.EXPAND)
+ amp_hbox.AddSpacer(10)
+ # Second row of amp controls (tx gain)
+ gain_hbox = wx.BoxSizer(wx.HORIZONTAL)
+ amp_hbox.Add(gain_hbox, 0, wx.EXPAND)
+ amp_hbox.AddSpacer(5)
+ self.vbox.Add(amp_hbox, 0, wx.EXPAND)
+ self.vbox.AddSpacer(10)
+ self.vbox.AddStretchSpacer()
+ lvl_hbox.AddSpacer(5)
+ forms.text_box(
+ parent=self.panel, sizer=lvl_hbox,
+ proportion=1,
+ converter=forms.float_converter(),
+ ps=self.tb,
+ key=uhd_siggen.AMPLITUDE_KEY,
+ label="Level (0.0-1.0)",
+ )
+ lvl_hbox.AddSpacer(10)
+ forms.log_slider(
+ parent=self.panel, sizer=lvl_hbox,
+ proportion=2,
+ ps=self.tb,
+ key=uhd_siggen.AMPLITUDE_KEY,
+ min_exp=-6,
+ max_exp=0,
+ base=10,
+ num_steps=100,
+ )
+ lvl_hbox.AddSpacer(5)
+ if self.tb[uhd_siggen.GAIN_RANGE_KEY].start() < self.tb[uhd_siggen.GAIN_RANGE_KEY].stop():
+ gain_hbox.AddSpacer(5)
+ forms.text_box(
+ parent=self.panel, sizer=gain_hbox,
+ proportion=1,
+ converter=forms.float_converter(),
+ ps=self.tb,
+ key=uhd_siggen.GAIN_KEY,
+ label="TX Gain (dB)",
+ )
+ gain_hbox.AddSpacer(10)
+ forms.slider(
+ parent=self.panel, sizer=gain_hbox,
+ proportion=2,
+ ps=self.tb,
+ key=uhd_siggen.GAIN_KEY,
+ minimum=self.tb[uhd_siggen.GAIN_RANGE_KEY].start(),
+ maximum=self.tb[uhd_siggen.GAIN_RANGE_KEY].stop(),
+ step_size=self.tb[uhd_siggen.GAIN_RANGE_KEY].step(),
+ )
+ gain_hbox.AddSpacer(5)
+
+ ##################################################
+ # Sample Rate controls
+ ##################################################
+ sam_hbox = forms.static_box_sizer(parent=self.panel,
+ label="Sample Rate",
+ orient=wx.HORIZONTAL,
+ bold=True)
+ self.vbox.Add(sam_hbox, 0, wx.EXPAND)
+ self.vbox.AddSpacer(10)
+ self.vbox.AddStretchSpacer()
+ sam_hbox.AddStretchSpacer(20)
+ forms.static_text(
+ parent=self.panel, sizer=sam_hbox,
+ label='Sample Rate (sps)',
+ ps=self.tb,
+ key=uhd_siggen.SAMP_RATE_KEY,
+ converter=forms.float_converter(),
+ )
+ sam_hbox.AddStretchSpacer(20)
+
+ ##################################################
+ # UHD status
+ ##################################################
+ u2_hbox = forms.static_box_sizer(parent=self.panel,
+ label="UHD Status",
+ orient=wx.HORIZONTAL,
+ bold=True)
+ self.vbox.Add(u2_hbox, 0, wx.EXPAND)
+ self.vbox.AddSpacer(10)
+ self.vbox.AddStretchSpacer()
+ u2_hbox.AddSpacer(10)
+ forms.static_text(
+ parent=self.panel, sizer=u2_hbox,
+ ps=self.tb,
+ key=uhd_siggen.DESC_KEY,
+ converter=forms.str_converter(),
+ )
+ self.vbox.AddSpacer(5)
+ self.vbox.AddStretchSpacer()
+
+def main():
+ try:
+ # Get command line parameters
+ (options, args) = uhd_siggen.get_options()
+
+ # Create the top block using these
+ tb = uhd_siggen.top_block(options, args)
+
+ # Create the GUI application
+ app = gui.app(top_block=tb, # Constructed top block
+ gui=app_gui, # User interface class
+ options=options, # Command line options
+ args=args, # Command line args
+ title="UHD Signal Generator", # Top window title
+ nstatus=1, # Number of status lines
+ start=True, # Whether to start flowgraph
+ realtime=True) # Whether to set realtime priority
+
+ # And run it
+ app.MainLoop()
+
+ except RuntimeError, e:
+ print e
+ sys.exit(1)
+
+# Make sure to create the top block (tb) within a function: That code
+# in main will allow tb to go out of scope on return, which will call
+# the decontructor on uhd device and stop transmit. Whats odd is that
+# grc works fine with tb in the __main__, perhaps its because the
+# try/except clauses around tb.
+if __name__ == "__main__": main()
diff --git a/gr-uhd/doc/.gitignore b/gr-uhd/doc/.gitignore
new file mode 100644
index 000000000..b336cc7ce
--- /dev/null
+++ b/gr-uhd/doc/.gitignore
@@ -0,0 +1,2 @@
+/Makefile
+/Makefile.in
diff --git a/gr-uhd/doc/Makefile.am b/gr-uhd/doc/Makefile.am
new file mode 100644
index 000000000..eee3ebcf6
--- /dev/null
+++ b/gr-uhd/doc/Makefile.am
@@ -0,0 +1,27 @@
+#
+# 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 $(top_srcdir)/Makefile.common
+
+SUBDIRS =
+
+dist_gr_doc_DATA = \
+ README.uhd
diff --git a/gr-uhd/doc/README.uhd b/gr-uhd/doc/README.uhd
new file mode 100644
index 000000000..ec8024c09
--- /dev/null
+++ b/gr-uhd/doc/README.uhd
@@ -0,0 +1,14 @@
+This is the GNU Radio UHD package. It is the interface to the UHD
+library to connect to and send and receive data between the Ettus
+Research, LLC product line. To use the UHD blocks, the Python
+namespaces is in gnuradio.uhd, which would be normally imported
+as:
+
+ from gnuradio import uhd
+
+See the Doxygen documentation for details about the blocks available
+in this package. A quick listing of the details can be found in Python
+after importing by using:
+
+ help(uhd)
+
diff --git a/gr-uhd/doc/uhd.dox b/gr-uhd/doc/uhd.dox
new file mode 100644
index 000000000..f08fe2f06
--- /dev/null
+++ b/gr-uhd/doc/uhd.dox
@@ -0,0 +1,35 @@
+/*! \page page_uhd UHD Interface
+
+\section Introduction
+This is the GNU Radio UHD package. It is the interface to the UHD
+library to connect to and send and receive data between the Ettus
+Research, LLC product line. To use the UHD blocks, the Python
+namespaces is in gnuradio.uhd, which would be normally imported
+as:
+
+\code
+ from gnuradio import uhd
+\endcode
+
+The relevant blocks are listed in the \ref uhd_blk group.
+
+A quick listing of the details can be found in Python after importing
+by using:
+
+\code
+ help(uhd)
+\endcode
+
+
+\section External Documentation
+
+Ettus Research keeps the comprehensive documentation to the underlying UHD driver, which can be found:
+
+ http://files.ettus.com/uhd_docs/manual/html/
+
+The UHD Doxygen page is located:
+
+ http://files.ettus.com/uhd_docs/doxygen/html/index.html
+
+
+*/
diff --git a/gr-uhd/examples/.gitignore b/gr-uhd/examples/.gitignore
new file mode 100644
index 000000000..ad8a13c08
--- /dev/null
+++ b/gr-uhd/examples/.gitignore
@@ -0,0 +1,5 @@
+/Makefile
+/Makefile.in
+*.dat
+*.32f
+*.32fc
diff --git a/gr-uhd/examples/Makefile.am b/gr-uhd/examples/Makefile.am
new file mode 100644
index 000000000..b10b48928
--- /dev/null
+++ b/gr-uhd/examples/Makefile.am
@@ -0,0 +1,44 @@
+#
+# 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 $(top_srcdir)/Makefile.common
+
+SUBDIRS = multi-antenna
+
+ourdatadir = $(exampledir)/uhd
+
+dist_ourdata_SCRIPTS = \
+ 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
diff --git a/gr-uhd/examples/fm_tx4.py b/gr-uhd/examples/fm_tx4.py
new file mode 100755
index 000000000..9b39752c1
--- /dev/null
+++ b/gr-uhd/examples/fm_tx4.py
@@ -0,0 +1,205 @@
+#!/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
+from usrpm import usrp_dbid
+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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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)
+
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ 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/fm_tx_2_daughterboards.py b/gr-uhd/examples/fm_tx_2_daughterboards.py
new file mode 100755
index 000000000..36d237616
--- /dev/null
+++ b/gr-uhd/examples/fm_tx_2_daughterboards.py
@@ -0,0 +1,203 @@
+#!/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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.device_find(uhd.device_addr(options.address))
+ uhd_type = d[0].get('type')
+
+ self.u = uhd.usrp_sink(device_addr=options.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=2)
+
+ # 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)
+
+ 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/max_power.py b/gr-uhd/examples/max_power.py
new file mode 100755
index 000000000..44d3beeee
--- /dev/null
+++ b/gr-uhd/examples/max_power.py
@@ -0,0 +1,142 @@
+#!/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, address, tx_enable, rx_enable):
+ gr.top_block.__init__(self)
+
+ d = uhd.device_find(uhd.device_addr(address))
+ uhd_type = d[0].get('type')
+
+ print "\nFound '%s' at address '%s'" % \
+ (uhd_type, address)
+
+ # 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"
+ self.u_tx = uhd.usrp_sink(device_addr=address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=tx_nchan)
+ 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=address,
+ 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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [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.address, 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/multi-antenna/.gitignore b/gr-uhd/examples/multi-antenna/.gitignore
new file mode 100644
index 000000000..ff40c06f3
--- /dev/null
+++ b/gr-uhd/examples/multi-antenna/.gitignore
@@ -0,0 +1,11 @@
+/Makefile
+/Makefile.in
+/.la
+/.lo
+/.deps
+/.libs
+/*.la
+/*.lo
+/*.pyc
+/*.pyo
+/*.dat
diff --git a/gr-uhd/examples/multi-antenna/Makefile.am b/gr-uhd/examples/multi-antenna/Makefile.am
new file mode 100644
index 000000000..0cb944589
--- /dev/null
+++ b/gr-uhd/examples/multi-antenna/Makefile.am
@@ -0,0 +1,29 @@
+#
+# Copyright 2006,2009 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 $(top_srcdir)/Makefile.common
+
+ourdatadir = $(exampledir)/multi-antenna
+
+dist_ourdata_SCRIPTS = \
+ multi_fft.py \
+ multi_file.py \
+ multi_scope.py
diff --git a/gr-uhd/examples/multi-antenna/multi_fft.py b/gr-uhd/examples/multi-antenna/multi_fft.py
new file mode 100755
index 000000000..d4c878c84
--- /dev/null
+++ b/gr-uhd/examples/multi-antenna/multi_fft.py
@@ -0,0 +1,152 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+from gnuradio import gr, eng_notation
+from gnuradio import uhd
+from gnuradio.eng_option import eng_option
+from gnuradio import eng_notation
+from gnuradio import optfir
+from optparse import OptionParser
+from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2
+from gnuradio.wxgui import scopesink2, form, slider
+import wx
+import time
+import os.path
+import sys
+
+# required FPGA that can do 4 rx channels.
+
+class my_graph(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.panel = panel
+
+ parser = OptionParser (option_class=eng_option)
+ parser.add_option("-a", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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=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("-F", "--filter", action="store_true", default=True,
+ help="Enable channel filter")
+ parser.add_option("-N", "--nchans", type="int", default=1,
+ help="set number of channels (default=%default)")
+ (options, args) = parser.parse_args()
+
+ if len(args) != 0:
+ parser.print_help()
+ raise SystemExit
+
+ self.nchans = options.nchans
+
+ if options.filter:
+ sw_decim = 4
+ else:
+ sw_decim = 1
+
+ self.u = uhd.usrp_source(device_addr=options.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=self.nchans)
+ self.u.set_samp_rate(options.samp_rate)
+ input_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
+
+ if options.freq is None:
+ # if no freq was specified, use the mid-point
+ r = self.u.get_freq_range()
+ options.freq = float(r.start()+r.stop())/2
+
+ self.set_gain(options.gain)
+ self.set_freq(options.freq)
+
+ #if self.u.nddcs() < nchan:
+ # sys.stderr.write('This code requires an FPGA build with %d DDCs. This FPGA has only %d.\n' % (
+ # nchan, self.u.nddcs()))
+ # raise SystemExit
+
+ #if (len (self.subdev) < 4 or
+ # self.u.db(0, 0).dbid() != usrp_dbid.BASIC_RX or
+ # self.u.db(0, 0).dbid() != usrp_dbid.BASIC_RX):
+ # sys.stderr.write('This code requires a Basic Rx board on Sides A & B\n')
+ # sys.exit(1)
+
+ # deinterleave four channels from FPGA
+ di = gr.deinterleave(gr.sizeof_gr_complex)
+
+ self.connect(self.u, di)
+
+ # taps for channel filter
+ chan_filt_coeffs = optfir.low_pass (1, # gain
+ input_rate, # sampling rate
+ 80e3, # passband cutoff
+ 115e3, # stopband cutoff
+ 0.1, # passband ripple
+ 60) # stopband attenuation
+ #print len(chan_filt_coeffs)
+
+ for i in range(self.nchans):
+ scope = fftsink2.fft_sink_c(panel, sample_rate=input_rate/sw_decim,
+ title="Input %d" % (i,),
+ ref_level=80, y_per_div=20)
+ vbox.Add(scope.win, 10, wx.EXPAND)
+
+ if options.filter:
+ chan_filt = gr.fir_filter_ccf(sw_decim, chan_filt_coeffs)
+ self.connect((di, i), chan_filt, scope)
+ else:
+ self.connect((di, i), scope)
+
+ def set_gain(self, gain):
+ for i in range(self.nchans):
+ self.u.set_gain(gain, i)
+
+
+ def set_freq(self, target_freq):
+ for i in range(self.nchans):
+ r = self.u.set_center_freq(target_freq, 0)
+
+ if r:
+ return True
+ else:
+ print "set_freq: failed to set subdev[%d] freq to %f" % \
+ (i, target_freq)
+ return False
+
+def main ():
+ app = stdgui2.stdapp(my_graph, "Multi Scope", nstatus=1)
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main ()
diff --git a/gr-uhd/examples/multi-antenna/multi_file.py b/gr-uhd/examples/multi-antenna/multi_file.py
new file mode 100755
index 000000000..87d9085e3
--- /dev/null
+++ b/gr-uhd/examples/multi-antenna/multi_file.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, gru, eng_notation
+from gnuradio import usrp
+from gnuradio.eng_option import eng_option
+from gnuradio import eng_notation
+from gnuradio import optfir
+from optparse import OptionParser
+from usrpm import usrp_dbid
+import time
+import os.path
+import sys
+
+# required FPGA that can do 4 rx channels.
+
+
+class my_graph(gr.top_block):
+
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ parser = OptionParser (option_class=eng_option)
+ #parser.add_option("-S", "--subdev", type="subdev", default=(0, None),
+ # help="select USRP Rx side A or B (default=A)")
+ parser.add_option("-d", "--decim", type="int", default=128,
+ help="set fgpa decimation rate to DECIM [default=%default]")
+ parser.add_option("-f", "--freq", type="eng_float", default=146.585e6,
+ help="set frequency to FREQ [default=%default])", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=20,
+ help="set gain in dB [default=%default]")
+ parser.add_option("-F", "--filter", action="store_true", default=True,
+ help="Enable channel filter")
+ parser.add_option("-o", "--output", type="string", default=None,
+ help="set output basename")
+ (options, args) = parser.parse_args()
+
+ if len(args) != 0:
+ parser.print_help()
+ raise SystemExit
+
+ if options.output is None:
+ parser.print_help()
+ sys.stderr.write("You must provide an output filename base with -o OUTPUT\n")
+ raise SystemExit
+ else:
+ basename = options.output
+
+ nchan = 4
+ nsecs = 4.0
+
+ if options.filter:
+ sw_decim = 4
+ else:
+ sw_decim = 1
+
+ self.u = usrp.source_c(0, options.decim, fpga_filename="std_4rx_0tx.rbf")
+ if self.u.nddcs() < nchan:
+ sys.stderr.write('This code requires an FPGA build with %d DDCs. This FPGA has only %d.\n' % (
+ nchan, self.u.nddcs()))
+ raise SystemExit
+
+ if not self.u.set_nchannels(nchan):
+ sys.stderr.write('set_nchannels(%d) failed\n' % (nchan,))
+ raise SystemExit
+
+ input_rate = self.u.adc_freq() / self.u.decim_rate()
+ print "USB data rate = %s" % (eng_notation.num_to_str(input_rate),)
+ sink_data_rate = input_rate/sw_decim
+ print "Scope data rate = %s" % (eng_notation.num_to_str(sink_data_rate),)
+
+ self.subdev = self.u.db(0) + self.u.db(1)
+
+ if (len(self.subdev) < 4 or
+ self.u.db(0, 0).dbid() != usrp_dbid.BASIC_RX or
+ self.u.db(1, 0).dbid() != usrp_dbid.BASIC_RX):
+ sys.stderr.write('This code requires a Basic Rx board on Sides A & B\n')
+ sys.exit(1)
+
+ self.u.set_mux(gru.hexint(0xf3f2f1f0))
+
+ # collect 1 second worth of data
+ limit = int(nsecs * input_rate * nchan)
+ print "limit = ", limit
+ head = gr.head(gr.sizeof_gr_complex, limit)
+
+ # deinterleave four channels from FPGA
+ di = gr.deinterleave(gr.sizeof_gr_complex)
+
+ self.connect(self.u, head, di)
+
+ # taps for channel filter
+ chan_filt_coeffs = optfir.low_pass (1, # gain
+ input_rate, # sampling rate
+ 80e3, # passband cutoff
+ 115e3, # stopband cutoff
+ 0.1, # passband ripple
+ 60) # stopband attenuation
+ #print len(chan_filt_coeffs)
+
+ for i in range(nchan):
+
+ sink = gr.file_sink(gr.sizeof_gr_complex,
+ basename + ("-%s-%d.dat" % (eng_notation.num_to_str(sink_data_rate), i)))
+ if options.filter:
+ chan_filt = gr.fir_filter_ccf(sw_decim, chan_filt_coeffs)
+ self.connect((di, i), chan_filt, sink)
+ else:
+ self.connect((di, i), sink)
+
+
+ self.set_gain(options.gain)
+ self.set_freq(options.freq)
+
+ def set_gain(self, gain):
+ for i in range(len(self.subdev)):
+ self.subdev[i].set_gain(gain)
+
+ def set_freq(self, target_freq):
+ ok = True
+ for i in range(len(self.subdev)):
+ r = usrp.tune(self.u, i, self.subdev[i], target_freq)
+ if not r:
+ ok = False
+ print "set_freq: failed to set subdev[%d] freq to %f" % (
+ i, target_freq)
+
+ return ok
+
+
+def main ():
+ my_graph().run()
+
+if __name__ == '__main__':
+ main ()
diff --git a/gr-uhd/examples/multi-antenna/multi_scope.py b/gr-uhd/examples/multi-antenna/multi_scope.py
new file mode 100755
index 000000000..d1e28ad18
--- /dev/null
+++ b/gr-uhd/examples/multi-antenna/multi_scope.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, gru, eng_notation
+from gnuradio import usrp
+from gnuradio.eng_option import eng_option
+from gnuradio import eng_notation
+from gnuradio import optfir
+from optparse import OptionParser
+from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider
+import wx
+from usrpm import usrp_dbid
+import time
+import os.path
+import sys
+
+# required FPGA that can do 4 rx channels.
+
+
+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)
+
+ self.frame = frame
+ self.panel = panel
+
+ parser = OptionParser (option_class=eng_option)
+ #parser.add_option("-S", "--subdev", type="subdev", default=(0, None),
+ # help="select USRP Rx side A or B (default=A)")
+ parser.add_option("-d", "--decim", type="int", default=128,
+ help="set fgpa decimation rate to DECIM [default=%default]")
+ parser.add_option("-f", "--freq", type="eng_float", default=146.585e6,
+ help="set frequency to FREQ [default=%default])", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=20,
+ help="set gain in dB [default=%default]")
+ parser.add_option("-F", "--filter", action="store_true", default=True,
+ help="Enable channel filter")
+ (options, args) = parser.parse_args()
+
+ if len(args) != 0:
+ parser.print_help()
+ raise SystemExit
+
+ nchan = 4
+
+ if options.filter:
+ sw_decim = 4
+ else:
+ sw_decim = 1
+
+ self.u = usrp.source_c(0, options.decim, fpga_filename="std_4rx_0tx.rbf")
+ if self.u.nddcs() < nchan:
+ sys.stderr.write('This code requires an FPGA build with %d DDCs. This FPGA has only %d.\n' % (
+ nchan, self.u.nddcs()))
+ raise SystemExit
+
+ if not self.u.set_nchannels(nchan):
+ sys.stderr.write('set_nchannels(%d) failed\n' % (nchan,))
+ raise SystemExit
+
+ input_rate = self.u.adc_freq() / self.u.decim_rate()
+ print "USB data rate = %s" % (eng_notation.num_to_str(input_rate),)
+ print "Scope data rate = %s" % (eng_notation.num_to_str(input_rate/sw_decim),)
+
+ self.subdev = self.u.db(0) + self.u.db(1)
+
+ if (len(self.subdev) < 4 or
+ self.u.db(0, 0).dbid() != usrp_dbid.BASIC_RX or
+ self.u.db(0, 0).dbid() != usrp_dbid.BASIC_RX):
+ sys.stderr.write('This code requires a Basic Rx board on Sides A & B\n')
+ sys.exit(1)
+
+ self.u.set_mux(gru.hexint(0xf3f2f1f0))
+
+ # deinterleave four channels from FPGA
+ di = gr.deinterleave(gr.sizeof_gr_complex)
+
+ self.connect(self.u, di)
+
+ # our destination (8 float inputs)
+ self.scope = scopesink2.scope_sink_f(panel, sample_rate=input_rate/sw_decim,
+ num_inputs=2*nchan)
+
+ # taps for channel filter
+ chan_filt_coeffs = optfir.low_pass (1, # gain
+ input_rate, # sampling rate
+ 80e3, # passband cutoff
+ 115e3, # stopband cutoff
+ 0.1, # passband ripple
+ 60) # stopband attenuation
+ #print len(chan_filt_coeffs)
+
+ # bust the deinterleaved complex channels into floats
+ for i in range(nchan):
+
+ if options.filter:
+ chan_filt = gr.fir_filter_ccf(sw_decim, chan_filt_coeffs)
+ c2f = gr.complex_to_float()
+ self.connect((di, i), chan_filt, c2f)
+ else:
+ c2f = gr.complex_to_float()
+ self.connect((di, i), c2f)
+
+ self.connect((c2f, 0), (self.scope, 2*i + 0))
+ self.connect((c2f, 1), (self.scope, 2*i + 1))
+
+
+ self._build_gui(vbox)
+
+ self.set_gain(options.gain)
+ self.set_freq(options.freq)
+
+ def set_gain(self, gain):
+ for i in range(len(self.subdev)):
+ self.subdev[i].set_gain(gain)
+
+ def set_freq(self, target_freq):
+ ok = True
+ for i in range(len(self.subdev)):
+ r = usrp.tune(self.u, i, self.subdev[i], target_freq)
+ if not r:
+ ok = False
+ print "set_freq: failed to set subdev[%d] freq to %f" % (
+ i, target_freq)
+
+ return ok
+
+
+ def _build_gui(self, vbox):
+ vbox.Add(self.scope.win, 10, wx.EXPAND)
+
+
+
+def main ():
+ app = stdgui2.stdapp(my_top_block, "Multi Scope", nstatus=1)
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main ()
diff --git a/gr-uhd/examples/usrp_am_mw_rcv.py b/gr-uhd/examples/usrp_am_mw_rcv.py
new file mode 100755
index 000000000..130bdcf56
--- /dev/null
+++ b/gr-uhd/examples/usrp_am_mw_rcv.py
@@ -0,0 +1,312 @@
+#!/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
+from usrpm import usrp_dbid
+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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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")
+
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ 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/usrp_nbfm_ptt.py b/gr-uhd/examples/usrp_nbfm_ptt.py
new file mode 100755
index 000000000..af3b132f4
--- /dev/null
+++ b/gr-uhd/examples/usrp_nbfm_ptt.py
@@ -0,0 +1,474 @@
+#!/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 usrpm import usrp_dbid
+
+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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address, options.tx_gain,
+ options.audio_input)
+ self.rxpath = receive_path(options.address, 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, address, 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=address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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, address, 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=address,
+ 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)
+
+
+ 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/usrp_nbfm_rcv.py b/gr-uhd/examples/usrp_nbfm_rcv.py
new file mode 100755
index 000000000..2dc69423c
--- /dev/null
+++ b/gr-uhd/examples/usrp_nbfm_rcv.py
@@ -0,0 +1,376 @@
+#!/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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address, 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, address, 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=address,
+ 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
+ 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)
+
+ 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 _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/usrp_spectrum_sense.py b/gr-uhd/examples/usrp_spectrum_sense.py
new file mode 100755
index 000000000..e89745b3b
--- /dev/null
+++ b/gr-uhd/examples/usrp_spectrum_sense.py
@@ -0,0 +1,243 @@
+#!/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
+
+sys.stderr.write("Warning: this is known to have issues on some machines+Python version combinations to seg fault due to the callback in bin_statitics. If you figure out why, we'd love to hear about it!\n")
+
+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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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__':
+ tb = my_top_block()
+ try:
+ tb.start()
+ main_loop(tb)
+
+ except KeyboardInterrupt:
+ pass
diff --git a/gr-uhd/examples/usrp_tv_rcv.py b/gr-uhd/examples/usrp_tv_rcv.py
new file mode 100755
index 000000000..a68867365
--- /dev/null
+++ b/gr-uhd/examples/usrp_tv_rcv.py
@@ -0,0 +1,436 @@
+#!/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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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/usrp_tv_rcv_nogui.py b/gr-uhd/examples/usrp_tv_rcv_nogui.py
new file mode 100755
index 000000000..a44e20d39
--- /dev/null
+++ b/gr-uhd/examples/usrp_tv_rcv_nogui.py
@@ -0,0 +1,206 @@
+#!/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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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/usrp_wfm_rcv.py b/gr-uhd/examples/usrp_wfm_rcv.py
new file mode 100755
index 000000000..7b35fbbe4
--- /dev/null
+++ b/gr-uhd/examples/usrp_wfm_rcv.py
@@ -0,0 +1,280 @@
+#!/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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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/usrp_wfm_rcv2_nogui.py b/gr-uhd/examples/usrp_wfm_rcv2_nogui.py
new file mode 100755
index 000000000..013a6864f
--- /dev/null
+++ b/gr-uhd/examples/usrp_wfm_rcv2_nogui.py
@@ -0,0 +1,151 @@
+#!/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
+from usrpm import usrp_dbid
+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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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
+ self.u = uhd.usrp_source(device_addr=options.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=2)
+
+ # Set front end channel mapping
+ self.u.set_subdev_spec("A:0 A: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()
+
+ # 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)
+
+ 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/usrp_wfm_rcv_fmdet.py b/gr-uhd/examples/usrp_wfm_rcv_fmdet.py
new file mode 100755
index 000000000..53ad6edbf
--- /dev/null
+++ b/gr-uhd/examples/usrp_wfm_rcv_fmdet.py
@@ -0,0 +1,347 @@
+#!/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
+
+import os
+print os.getpid()
+raw_input()
+
+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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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/usrp_wfm_rcv_nogui.py b/gr-uhd/examples/usrp_wfm_rcv_nogui.py
new file mode 100755
index 000000000..ffeda4493
--- /dev/null
+++ b/gr-uhd/examples/usrp_wfm_rcv_nogui.py
@@ -0,0 +1,168 @@
+#!/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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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/usrp_wfm_rcv_pll.py b/gr-uhd/examples/usrp_wfm_rcv_pll.py
new file mode 100755
index 000000000..2cb4e4068
--- /dev/null
+++ b/gr-uhd/examples/usrp_wfm_rcv_pll.py
@@ -0,0 +1,340 @@
+#!/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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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/usrp_wfm_rcv_sca.py b/gr-uhd/examples/usrp_wfm_rcv_sca.py
new file mode 100755
index 000000000..1c6154871
--- /dev/null
+++ b/gr-uhd/examples/usrp_wfm_rcv_sca.py
@@ -0,0 +1,397 @@
+#!/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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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/usrp_wxapt_rcv.py b/gr-uhd/examples/usrp_wxapt_rcv.py
new file mode 100755
index 000000000..5b44398d1
--- /dev/null
+++ b/gr-uhd/examples/usrp_wxapt_rcv.py
@@ -0,0 +1,276 @@
+#!/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", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ 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.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ 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 ()
diff --git a/gr-uhd/include/gr_uhd_amsg_source.h b/gr-uhd/include/gr_uhd_amsg_source.h
index bc0feb438..accf15ce2 100644
--- a/gr-uhd/include/gr_uhd_amsg_source.h
+++ b/gr-uhd/include/gr_uhd_amsg_source.h
@@ -28,6 +28,10 @@
class uhd_amsg_source;
+/*!
+ * \brief Make a new USRP asynchronous message-based source block.
+ * \ingroup uhd_blk
+ */
GR_UHD_API boost::shared_ptr<uhd_amsg_source> uhd_make_amsg_source(
const uhd::device_addr_t &device_addr,
gr_msg_queue_sptr msgq
diff --git a/gr-uhd/include/gr_uhd_usrp_sink.h b/gr-uhd/include/gr_uhd_usrp_sink.h
index c1fc3b09e..f11d00063 100644
--- a/gr-uhd/include/gr_uhd_usrp_sink.h
+++ b/gr-uhd/include/gr_uhd_usrp_sink.h
@@ -30,6 +30,7 @@ class uhd_usrp_sink;
/*!
* \brief Make a new USRP sink block.
+ * \ingroup uhd_blk
*
* The USRP sink block reads a stream and transmits the samples.
* The sink block also provides API calls for transmitter settings.
diff --git a/gr-uhd/include/gr_uhd_usrp_source.h b/gr-uhd/include/gr_uhd_usrp_source.h
index f8ac9361e..fecc6e94d 100644
--- a/gr-uhd/include/gr_uhd_usrp_source.h
+++ b/gr-uhd/include/gr_uhd_usrp_source.h
@@ -30,6 +30,7 @@ class uhd_usrp_source;
/*!
* \brief Make a new USRP source block.
+ * \ingroup uhd_blk
*
* The USRP source block receives samples and writes to a stream.
* The source block also provides API calls for receiver settings.
diff --git a/gr-uhd/swig/Makefile.swig.gen b/gr-uhd/swig/Makefile.swig.gen
index b73ccd3c4..62adf8958 100644
--- a/gr-uhd/swig/Makefile.swig.gen
+++ b/gr-uhd/swig/Makefile.swig.gen
@@ -105,7 +105,7 @@ _uhd_swig_la_CXXFLAGS = \
$(uhd_swig_la_swig_cxxflags)
python/uhd_swig.cc: uhd_swig.py
-uhd_swig.py: uhd_swig.i
+uhd_swig.py: uhd_swig.i
# Include the python dependencies for this file
-include python/uhd_swig.d
diff --git a/gr-uhd/swig/__init__.py b/gr-uhd/swig/__init__.py
index 1f82b4a26..c63d3cc57 100644
--- a/gr-uhd/swig/__init__.py
+++ b/gr-uhd/swig/__init__.py
@@ -19,6 +19,12 @@
# Boston, MA 02110-1301, USA.
#
+'''
+This is the GNU Radio UHD package. It is the interface to the UHD
+library to connect to and send and receive data between the Ettus
+Research, LLC product line.
+'''
+
########################################################################
# Prepare uhd swig module to make it more pythonic
########################################################################