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

Reply via email to