diff options
Diffstat (limited to 'gr-uhd/apps')
-rw-r--r-- | gr-uhd/apps/Makefile.am | 10 | ||||
-rw-r--r-- | gr-uhd/apps/hf_explorer/.gitignore | 3 | ||||
-rw-r--r-- | gr-uhd/apps/hf_explorer/Makefile.am | 31 | ||||
-rw-r--r-- | gr-uhd/apps/hf_explorer/README | 42 | ||||
-rwxr-xr-x | gr-uhd/apps/hf_explorer/hfx.py | 823 | ||||
-rw-r--r-- | gr-uhd/apps/hf_explorer/hfx_help | 180 | ||||
-rw-r--r-- | gr-uhd/apps/hf_radio/.gitignore | 3 | ||||
-rw-r--r-- | gr-uhd/apps/hf_radio/Makefile.am | 39 | ||||
-rw-r--r-- | gr-uhd/apps/hf_radio/README.TXT | 60 | ||||
-rw-r--r-- | gr-uhd/apps/hf_radio/hfir.sci | 59 | ||||
-rw-r--r-- | gr-uhd/apps/hf_radio/input.py | 78 | ||||
-rw-r--r-- | gr-uhd/apps/hf_radio/output.py | 42 | ||||
-rwxr-xr-x | gr-uhd/apps/hf_radio/radio.py | 319 | ||||
-rw-r--r-- | gr-uhd/apps/hf_radio/radio.xml | 441 | ||||
-rw-r--r-- | gr-uhd/apps/hf_radio/ssb_taps | 1023 | ||||
-rw-r--r-- | gr-uhd/apps/hf_radio/ssbagc.py | 70 | ||||
-rw-r--r-- | gr-uhd/apps/hf_radio/ssbdemod.py | 116 | ||||
-rw-r--r-- | gr-uhd/apps/hf_radio/startup.py | 1 | ||||
-rwxr-xr-x | gr-uhd/apps/hf_radio/ui.py | 316 | ||||
-rwxr-xr-x | gr-uhd/apps/uhd_fft.py | 58 | ||||
-rwxr-xr-x | gr-uhd/apps/uhd_rx_nogui.py | 233 | ||||
-rwxr-xr-x | gr-uhd/apps/uhd_siggen.py | 350 | ||||
-rwxr-xr-x | gr-uhd/apps/uhd_siggen_gui.py | 318 |
23 files changed, 4583 insertions, 32 deletions
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() |