Matt-
thanks for getting back. I've attached the code as it currently stands.
What parts are out of date? The important parts (formatted slightly to
fit on the screen) are:
**************************************************************************
adc_rate = self.u.adc_rate() # 64 MS/s
usrp_decim = 250
self.u.set_decim_rate(usrp_decim)
usrp_rate = adc_rate / usrp_decim # 256 kS/s
chanfilt_decim = 16
demod_rate = usrp_rate / chanfilt_decim # 16 kHz
audio_decimation = 1
audio_rate = demod_rate / audio_decimation # 16 kHz
chan_filt_coeffs = gr.firdes.low_pass (1, # gain
usrp_rate, # sampling rate
9e3, # passband cutoff
10e3, # stopband cutoff
gr.firdes.WIN_HANN)
self.ddc = \
gr.freq_xlating_fir_filter_ccf(chanfilt_decim,chan_filt_coeffs,0,usrp_rate)
self.magblock = gr.complex_to_mag()
audio_coeffs = gr.firdes.low_pass (1.0, # gain
usrp_rate, # sampling rate
9e3,
4e3,
gr.firdes.WIN_HANN)
audio_filter = gr.fir_filter_fff (audio_decimation, audio_coeffs)
*****************************************************************************
any comments? Particularly on the filter coefficients. I'm not sure yet
how to select these. My requirements at this stage are to demodulate
sidebands with frequencies of up to say 8 kHz riding on a 2 or 3 MHz
carrier. (using the LFRX DC-50MHz daughterboard). Currently I don't care
about the audio port as a sink; I simply want to display the fft's on the
screen. Eventually I may want to capture to file.
thanks!
p.s.- do you have pictures of the enclosure? I just built one using an
extruded aluminum case from Box Enclosures, Inc that has very similar
dimensions. It's a very handsome box, only I couldn't get the TVRX module
to fit; the USRP would only go in one way. If I rotated 90 (which would
have allowed the TVRX to fit) then it wouldn't work because the
motherboard was about 0.03" too big. There are pics of it at
www.nd.edu/~ematlis/z.gnuradio/z.enclosure_pics
************************************
Eric H. Matlis, Ph.D.
Aerospace & Mechanical Engineering Dept.
120 Hessert Center for Aerospace Research
University of Notre Dame
Notre Dame, IN 46556-5684
Phone: (574) 631-6054
Fax: (574) 631-8355
On Thu, 2 Nov 2006, Matt Ettus wrote:
Have you solved this yet? Is it possible that you are decimating too much?
The am_rcv code is very old. I would start fresh if I were you.
Matt
Eric Hill Matlis wrote:
I do have 5 kHz sidebands, and this is verified by the location of the
peaks in the first two fft graphs. It's just the third graph which
showed an aliased signal. Could the filter taps be incorrect?
eric
On Thu, 26 Oct 2006, Matt Ettus wrote:
Eric Hill Matlis wrote:
Hello-
I am attempting to demodulate an A.M. modulated signal using
am_rcv.py, the USRP, an LFRX daughterboard, and the latest svn
gnuradio distribution. At present the signal is being generated by a
function generator (Stanford Research Systems Model DS345) with a 2
MHz carrier and a 5 kHz modulation. I have some questions about the
demodulation being performed by the am_rcv.py program found in the
examples directory for the usrp.
1) The first graph is labeled as "Pre-Demodulation", yet it is
actually not representative of the original waveform as it has been
downshifted to the offset frequency of 30 kHz (as I recall, there is
an issue with the USRP that requires this 30 kHz offset, but I don't
know the particulars about that, perhaps somebody can explain?). I
would like to plot the original waveform. Is there a way of showing
the fft of the original waveform with the carrier at 2 MHz and
sidebands at 1.995 and 2.005 MHz?
We don't need that 30 kHz offset anymore. To show the original
waveform, just follow the code in usrp_fft.py
2) While the second "Post Demodulation" graph correctly shows the
sidebands at +/- 5 kHz, the decimation filters are aliasing the
sideband in the "Post Filter" graph to 2.5 kHz. I have to reduce the
"audio_decimation" from 2 to 1 to prevent this aliasing. Why would
this be happening? The original final decimation of 2 produces an
effective sampling rate of 32 kHz, which should be sufficient to
resolve the sideband at 5 kHz.
Sounds odd. Are you sure you have 5 kHz sidebands?
3) What sets the limits on the axes of these graphs? Is it possible
to modify them?
The x-axis will match the sample rates. The Y-axis can be modified by
right-clicking.
I am hopefully going to be using the USRP and gnuradio to demonstrate
a sensor I am developing that produces AM modulated waveforms at the
Division of Fluid Dynamics APS conference in November, so I would like
to fine-tune this application as much as possible. There will be a
booth for the commercial vendors at the meeting, and it would be cool
if I could use Gnuradio at our display in this conference.
That would be great!
Matt
#!/usr/bin/env python
from gnuradio import gr, gru, eng_notation, optfir
from gnuradio import audio
from gnuradio import usrp
from gnuradio import blks
from gnuradio.eng_option import eng_option
from gnuradio.wxgui import slider, powermate
from gnuradio.wxgui import stdgui, fftsink, form, scopesink
from optparse import OptionParser
import usrp_dbid
import sys
import math
import wx
import wx.lib.evtmgr as em
def pick_subdevice(u):
"""
The user didn't specify a subdevice on the command line.
Try for one of these, in order: TV_RX, BASIC_RX, whatever is on side A.
@return a subdev_spec
"""
return usrp.pick_subdev(u, (usrp_dbid.TV_RX,
usrp_dbid.TV_RX_REV_2,
usrp_dbid.BASIC_RX))
class am_plasma_rx_graph (stdgui.gui_flow_graph):
def __init__(self,frame,panel,vbox,argv):
stdgui.gui_flow_graph.__init__ (self,frame,panel,vbox,argv)
#class MyFrame(wx.Frame):
# def __init__(self, *args, **kwds):
# kwds["style"] = wx.DEFAULT_FRAME_STYLE
# wx.Frame.__init__(self, *args, **kwds)
parser=OptionParser(option_class=eng_option)
parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None,
help="select USRP Rx side A or B (default=A)")
parser.add_option("-f", "--freq", type="eng_float", default=3e6,
help="set frequency to FREQ", metavar="FREQ")
parser.add_option("-g", "--gain", type="eng_float", default=10,
help="set gain in dB (default is midpoint)")
parser.add_option("-O", "--audio-output", type="string", default="",
help="pcm device name. E.g., hw:0,0 or surround51 or
/dev/dsp")
(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
self.u = usrp.source_c() # usrp is data source
adc_rate = self.u.adc_rate() # 64 MS/s
usrp_decim = 250
self.u.set_decim_rate(usrp_decim)
usrp_rate = adc_rate / usrp_decim # 256 kS/s
chanfilt_decim = 16
demod_rate = usrp_rate / chanfilt_decim # 16 kHz
audio_decimation = 1
audio_rate = demod_rate / audio_decimation # 16 kHz
if options.rx_subdev_spec is None:
options.rx_subdev_spec = pick_subdevice(self.u)
self.u.set_mux(usrp.determine_rx_mux_value(self.u,
options.rx_subdev_spec))
self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
chan_filt_coeffs = gr.firdes.low_pass (1, # gain
usrp_rate, # sampling rate
9e3, # passband cutoff
10e3, # stopband cutoff
gr.firdes.WIN_HANN)
self.ddc = gr.freq_xlating_fir_filter_ccf
(chanfilt_decim,chan_filt_coeffs,0,usrp_rate)
self.magblock = gr.complex_to_mag()
self.volume_control = gr.multiply_const_ff(self.vol)
# Deemphasis. Is this necessary on AM?
TAU = 75e-6 # 75us in US, 50us in EUR
fftaps = [ 1 - math.exp(-1/TAU/usrp_rate), 0]
fbtaps= [ 0 , math.exp(-1/TAU/usrp_rate) ]
self.deemph = gr.iir_filter_ffd(fftaps,fbtaps)
# compute FIR filter taps for audio filter
width_of_transition_band = audio_rate / 8
audio_coeffs = gr.firdes.low_pass (1.0, # gain
usrp_rate, # sampling rate
9e3, #audio_rate/2 -
width_of_transition_band,
4e3, #
width_of_transition_band,
gr.firdes.WIN_HANN)
# input: float; output: float
audio_filter = gr.fir_filter_fff (audio_decimation, audio_coeffs)
# sound card as final sink
audio_sink = audio.sink (int (audio_rate),
options.audio_output,
False) # ok_to_block
# now wire it all together
self.connect (self.u, self.ddc)
self.connect (self.ddc, self.magblock)
self.connect (self.magblock, self.volume_control)
self.connect (self.volume_control, audio_filter)
self.connect (audio_filter, (audio_sink, 0))
#self.connect (self.volume_control,self.deemph)
#self.connect (self.deemph,audio_filter)
#self.connect (audio_filter, (audio_sink, 0))
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.subdev.gain_range()
options.gain = float(g[0]+g[1])/2
if abs(options.freq) < 1e6:
options.freq *= 1e6
# set initial values
self.set_gain(options.gain)
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 = fftsink.fft_sink_c (self, self.panel, title="Data
from Sensor",
fft_size=1024,
sample_rate=usrp_rate)
self.connect (self.u, self.src_fft)
vbox.Add (self.src_fft.win, 4, wx.EXPAND)
if 1:
self.post_filt = fftsink.fft_sink_f (self, self.panel, title="AM
Demodulated", fft_size=1024, sample_rate=audio_rate)
self.connect (self.magblock,self.post_filt)
vbox.Add (self.post_filt.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="Carrier 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=(.5e6, 3.5e6, 0.001e6),
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['gain'] = \
form.quantized_slider_field(parent=self.panel, sizer=hbox,
label="Gain",
weight=3,
range=self.subdev.gain_range(),
callback=self.subdev.set_gain)
hbox.Add((5,0), 0)
vbox.Add(hbox, 0, wx.EXPAND)
try:
self.knob = powermate.powermate(self.frame)
self.rot = 0
powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate)
powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button)
except:
print "FYI: No Powermate or Contour Knob found"
def on_rotate (self, event):
self.rot += event.delta
if (self.state == "FREQ"):
if self.rot >= 3:
self.set_freq(self.freq + .001e6)
self.rot -= 3
elif self.rot <=-3:
self.set_freq(self.freq - .001e6)
self.rot += 3
else:
step = self.subdev.gain_range()[2]
if self.rot >= 3:
self.set_gain(self.gain + step)
self.rot -= 3
elif self.rot <=-3:
self.set_gain(self.gain - step)
self.rot += 3
self.update_status_bar ()
def on_button (self, event):
if event.value == 0: # button up
return
self.rot = 0
if self.state == "FREQ":
self.state = "GAIN"
else:
self.state = "FREQ"
self.update_status_bar ()
def set_gain (self, gain):
g = self.subdev.gain_range()
self.gain = max(g[0], min(g[1], gain))
self.myform['gain'].set_value(self.gain)
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 = usrp.tune(self.u, 0, self.subdev, 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.gain=gain
self.myform['gain'].set_value(gain) # update displayed value
self.subdev.set_gain(gain)
def update_status_bar (self):
msg = "Gain:%r Setting:%s" % (self.gain, self.state)
self._set_status_msg(msg, 1)
self.src_fft.set_baseband_freq(self.freq)
def gain_range(self):
return (0, 20, 1)
# for mouse position reporting on fft display
#em.eventManager.Register(self.Mouse, wx.EVT_MOTION, self.fft.win)
# Mouse over fft display - show frequency in tooltip
#def Mouse(self,event):
# fRel = ( event.GetX() - 330. ) / 14.266666 - 7.5
#
self.fft.win.SetToolTip(wx.ToolTip(eng_notation.num_to_str(self.frequency +
(fRel*1e3))))
if __name__ == '__main__':
app = stdgui.stdapp (am_plasma_rx_graph, "USRP PLASMA AM RX")
app.MainLoop ()
_______________________________________________
Discuss-gnuradio mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/discuss-gnuradio