Hi Scott, On Jul 16, 2010, at 7:52 PM, Scott Johnston wrote:
> I have been following this thread because I am attempting to do the same > thing. Can you tell me what the values for "interp" and "decim" are when the > program is working correctly. Also, my system is failing to tune to the > center frequency. Have you come across this problem, or do you have any > solutions to it? Join the club!! :-) This thing requires some heavy perseverance !! So, if you apply the patch that I sent across earlier, and the rational resampler input settings is at 32050, and the output rate setting is at 48000. I have attached the full file below.
#!/usr/bin/env python # # Copyright 2005,2006,2007,2008,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. # from gnuradio import gr, gru, eng_notation, optfir from gnuradio import audio from gnuradio import usrp2 from gnuradio import blks2 from gnuradio.eng_option import eng_option from gnuradio.wxgui import slider, powermate from gnuradio.wxgui import stdgui2, fftsink2, form from optparse import OptionParser import sys import math import wx class wfm_rx_block (stdgui2.std_top_block): def __init__(self,frame,panel,vbox,argv): stdgui2.std_top_block.__init__ (self,frame,panel,vbox,argv) parser = OptionParser(option_class=eng_option) parser.add_option("-e", "--interface", type="string", default="eth0", help="select Ethernet interface, default is eth0") parser.add_option("-m", "--mac-addr", type="string", default="", help="select USRP by MAC address, default is auto-select") #parser.add_option("-A", "--antenna", default=None, # help="select Rx Antenna (only on RFX-series boards)") parser.add_option("-f", "--freq", type="eng_float", default=100.1, help="set frequency to FREQ", metavar="FREQ") parser.add_option("-g", "--gain", type="eng_float", default=None, help="set gain in dB (default is midpoint)") parser.add_option("-V", "--volume", type="eng_float", default=None, help="set volume (default is midpoint)") parser.add_option("-O", "--audio-output", type="string", default="", help="pcm device name. E.g., hw:0,0 or surround51 or /dev/dsp") parser.add_option("-i", "--input-rate", type="eng_float", default=32050, help="set input sample rate to RATE (%default)") parser.add_option("-o", "--output-rate", type="eng_float", default=48000, help="set output sample rate to RATE (%default)") (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() sys.exit(1) self.frame = frame self.panel = panel self.vol = 0 self.state = "FREQ" self.freq = 0 # build graph # USRP2 source self.u = usrp2.source_32fc(options.interface, options.mac_addr) adc_rate = self.u.adc_rate() # 100 MS/s usrp_decim = 312 self.u.set_decim(usrp_decim) usrp_rate = adc_rate / usrp_decim # ~320 kS/s chanfilt_decim = 1 demod_rate = usrp_rate / chanfilt_decim audio_decimation = 10 audio_rate = demod_rate / audio_decimation # ~32 kHz print "audio rate =", audio_rate #FIXME: need named constants and text descriptions available to (gr-)usrp2 even #when usrp(1) module is not built. A usrp_common module, perhaps? dbid = self.u.daughterboard_id() print "Using RX d'board 0x%04X" % (dbid,) if not (dbid == 0x0001 or #usrp_dbid.BASIC_RX dbid == 0x0003 or #usrp_dbid.TV_RX dbid == 0x000c or #usrp_dbid.TV_RX_REV_2 dbid == 0x0040 or #usrp_dbid.TV_RX_REV_3 dbid == 0x0043 or #usrp_dbid.TV_RX_MIMO dbid == 0x0044 or #usrp_dbid.TV_RX_REV_2_MIMO dbid == 0x0045 or #usrp_dbid.TV_RX_REV_3_MIMO dbid == 0x0053 ): #usrp_dbid.WBX print "This daughterboard does not cover the required frequency range" print "for this application. Please use a BasicRX or TVRX daughterboard." raw_input("Press ENTER to continue anyway, or Ctrl-C to exit.") # channel filter co-efficients chan_filt_coeffs = optfir.low_pass (1, # gain usrp_rate, # sampling rate 80e3, # passband cutoff 115e3, # stopband cutoff 0.1, # passband ripple 60) # stopband attenuation #print len(chan_filt_coeffs) chan_filt = gr.fir_filter_ccf (chanfilt_decim, chan_filt_coeffs) # wide-band FM demodulator self.guts = blks2.wfm_rcv (demod_rate, audio_decimation) # rational resampler input_rate = int(options.input_rate) # 32050 Hz default #input_rate = audio_rate # 32051 Hz as computed earlier (line 82), but hangs the application output_rate = int(options.output_rate) # 48 kHz default interp = gru.lcm(input_rate, output_rate) / input_rate decim = gru.lcm(input_rate, output_rate) / output_rate print "interp =", interp print "decim =", decim rr = blks2.rational_resampler_fff(interp, decim) # volume control self.volume_control = gr.multiply_const_ff(self.vol) # sound card as final sink audio_sink = audio.sink (int (output_rate), options.audio_output, False) # ok_to_block # now wire it all together self.connect (self.u, chan_filt, self.guts, rr, self.volume_control, audio_sink) #self.connect (self.u, chan_filt, self.guts, self.volume_control, audio_sink) self._build_gui(vbox, usrp_rate, demod_rate, audio_rate) if options.gain is None: # if no gain was specified, use the mid-point in dB g = self.u.gain_range() options.gain = float(g[0]+g[1])/2 if options.volume is None: g = self.volume_range() options.volume = float(g[0]+g[1])/2 if abs(options.freq) < 1e6: options.freq *= 1e6 # set initial values self.set_gain(options.gain) self.set_vol(options.volume) if not(self.set_freq(options.freq)): self._set_status_msg("Failed to set initial frequency") def _set_status_msg(self, msg, which=0): self.frame.GetStatusBar().SetStatusText(msg, which) def _build_gui(self, vbox, usrp_rate, demod_rate, audio_rate): def _form_set_freq(kv): return self.set_freq(kv['freq']) if 1: self.src_fft = fftsink2.fft_sink_c(self.panel, title="Data from USRP2", fft_size=512, sample_rate=usrp_rate, ref_scale=1.0, ref_level=0, y_divs=12) self.connect (self.u, self.src_fft) vbox.Add (self.src_fft.win, 4, wx.EXPAND) if 1: post_filt_fft = fftsink2.fft_sink_f(self.panel, title="Post Demod", fft_size=1024, sample_rate=usrp_rate, y_per_div=10, ref_level=0) self.connect (self.guts.fm_demod, post_filt_fft) vbox.Add (post_filt_fft.win, 4, wx.EXPAND) if 0: post_deemph_fft = fftsink2.fft_sink_f(self.panel, title="Post Deemph", fft_size=512, sample_rate=audio_rate, y_per_div=10, ref_level=-20) self.connect (self.guts.deemph, post_deemph_fft) vbox.Add (post_deemph_fft.win, 4, wx.EXPAND) # control area form at bottom self.myform = myform = form.form() hbox = wx.BoxSizer(wx.HORIZONTAL) hbox.Add((5,0), 0) myform['freq'] = form.float_field( parent=self.panel, sizer=hbox, label="Freq", weight=1, callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg)) hbox.Add((5,0), 0) myform['freq_slider'] = \ form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3, range=(87.9e6, 108.1e6, 0.1e6), callback=self.set_freq) hbox.Add((5,0), 0) vbox.Add(hbox, 0, wx.EXPAND) hbox = wx.BoxSizer(wx.HORIZONTAL) hbox.Add((5,0), 0) myform['volume'] = \ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Volume", weight=3, range=self.volume_range(), callback=self.set_vol) hbox.Add((5,0), 1) myform['gain'] = \ form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Gain", weight=3, range=self.u.gain_range(), callback=self.set_gain) hbox.Add((5,0), 0) vbox.Add(hbox, 0, wx.EXPAND) try: self.knob = powermate.powermate(self.frame) self.rot = 0 powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate) powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button) except: pass #print "FYI: No Powermate or Contour Knob found" def on_rotate (self, event): self.rot += event.delta if (self.state == "FREQ"): if self.rot >= 3: self.set_freq(self.freq + .1e6) self.rot -= 3 elif self.rot <=-3: self.set_freq(self.freq - .1e6) self.rot += 3 else: step = self.volume_range()[2] if self.rot >= 3: self.set_vol(self.vol + step) self.rot -= 3 elif self.rot <=-3: self.set_vol(self.vol - step) self.rot += 3 def on_button (self, event): if event.value == 0: # button up return self.rot = 0 if self.state == "FREQ": self.state = "VOL" else: self.state = "FREQ" self.update_status_bar () def set_vol (self, vol): g = self.volume_range() self.vol = max(g[0], min(g[1], vol)) self.volume_control.set_k(10**(self.vol/10)) self.myform['volume'].set_value(self.vol) self.update_status_bar () def set_freq(self, target_freq): """ Set the center frequency we're interested in. @param target_freq: frequency in Hz @rypte: bool Tuning is a two step process. First we ask the front-end to tune as close to the desired frequency as it can. Then we use the result of that operation and our target_frequency to determine the value for the digital down converter. """ r = self.u.set_center_freq(target_freq) if r: self.freq = target_freq self.myform['freq'].set_value(target_freq) # update displayed value self.myform['freq_slider'].set_value(target_freq) # update displayed value self.update_status_bar() self._set_status_msg("OK", 0) return True self._set_status_msg("Failed", 0) return False def set_gain(self, gain): self.myform['gain'].set_value(gain) # update displayed value self.u.set_gain(gain) def update_status_bar (self): msg = "Volume:%r Setting:%s" % (self.vol, self.state) self._set_status_msg(msg, 1) self.src_fft.set_baseband_freq(self.freq) def volume_range(self): return (-20.0, 0.0, 0.5) if __name__ == '__main__': app = stdgui2.stdapp (wfm_rx_block, "USRP2 WFM RX") app.MainLoop ()
I just changed my USRP2 driver environment to use the new UHD driver, and so can't run it right now, to tell you the interp and decim values. That would get precomputed depending upon the settings for the rational resampler input and output rates. I'm just waiting for some one to reply with a sample UHD example, so that I can convert the attached program to one that works with the gr-uhd driver, instead of the existing gr-usrp2 driver. The FM reception came out crystal clear, only once, with very few S's and no audio under-runs (aU) All the other attempts, there was a lot of distortion and audio under-runs. You should use a really long piece of wire connected to the inner connector of the RX2 port of the WBX daughter card, via the SMA F connector that comes out in front. Also set the volume (0.0) and gain sliders to max (31.5db) I also observed that of all the possible FM stations, I only got one with sufficient clarity, and all the others were garbled. Not sure if this has something to do with tuning to the center frequency. Best regards, Elvis
_______________________________________________ Discuss-gnuradio mailing list Discuss-gnuradio@gnu.org http://lists.gnu.org/mailman/listinfo/discuss-gnuradio