root/vtcross/branches/sriram/receive_path.py @ 329

Revision 329, 15.0 KB (checked in by sriram, 15 years ago)

Adding changed for spectrum sense

Line 
1#!/usr/bin/env python
2#
3# Copyright 2005,2006,2007,2009 Free Software Foundation, Inc.
4#
5# This file is part of GNU Radio
6#
7# GNU Radio is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 3, or (at your option)
10# any later version.
11#
12# GNU Radio is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with GNU Radio; see the file COPYING.  If not, write to
19# the Free Software Foundation, Inc., 51 Franklin Street,
20# Boston, MA 02110-1301, USA.
21#
22
23from gnuradio import gr, gru, blks2
24from gnuradio import usrp
25from gnuradio import eng_notation
26import copy
27import sys
28
29# from current dir
30from pick_bitrate import pick_rx_bitrate
31import usrp_options
32
33# /////////////////////////////////////////////////////////////////////////////
34#                              receive path
35# /////////////////////////////////////////////////////////////////////////////
36
37class receive_path(gr.hier_block2):
38    def __init__(self, demod_class, rx_callback, options):
39
40        gr.hier_block2.__init__(self, "receive_path",
41                                gr.io_signature(0, 0, 0), # Input signature
42                                gr.io_signature(0, 0, 0)) # Output signature
43
44        options = copy.copy(options)    # make a copy so we can destructively modify
45
46        self._verbose            = options.verbose
47        self._rx_freq            = options.rx_freq         # receiver's center frequency
48        self._rx_gain            = options.rx_gain         # receiver's gain
49        self._bitrate            = options.bitrate         # desired bit rate
50        self._decim              = options.decim           # Decimating rate for the USRP (prelim)
51        self._samples_per_symbol = options.samples_per_symbol  # desired samples/symbol
52
53        self._rx_callback   = rx_callback      # this callback is fired when there's a packet available
54        self._demod_class   = demod_class      # the demodulator_class we're using
55
56        if self._rx_freq is None:
57            sys.stderr.write("-f FREQ or --freq FREQ or --rx-freq FREQ must be specified\n")
58            raise SystemExit
59
60        # Set up USRP source; also adjusts decim, samples_per_symbol, and bitrate
61        self._setup_usrp_source(options)
62
63        if options.show_rx_gain_range:
64            print "Rx Gain Range: minimum = %g, maximum = %g, step size = %g"%tuple(self.u.gain_range())
65
66        self.set_gain(options.rx_gain)
67
68        # Set RF frequency
69        ok = self.set_freq(self._rx_freq)
70        if not ok:
71            print "Failed to set Rx frequency to %s" % (eng_notation.num_to_str(self._rx_freq))
72            raise ValueError, eng_notation.num_to_str(self._rx_freq)
73
74        # copy the final answers back into options for use by demodulator
75        options.samples_per_symbol = self._samples_per_symbol
76        options.bitrate = self._bitrate
77        options.decim = self._decim
78
79        # Get demod_kwargs
80        demod_kwargs = self._demod_class.extract_kwargs_from_options(options)
81
82        # Design filter to get actual channel we want
83        sw_decim = 1
84        chan_coeffs = gr.firdes.low_pass (1.0,                  # gain
85                                          sw_decim * self._samples_per_symbol, # sampling rate
86                                          1.0,                  # midpoint of trans. band
87                                          0.5,                  # width of trans. band
88                                          gr.firdes.WIN_HANN)   # filter type
89
90        # Decimating channel filter
91        # complex in and out, float taps
92        self.chan_filt = gr.fft_filter_ccc(sw_decim, chan_coeffs)
93        #self.chan_filt = gr.fir_filter_ccf(sw_decim, chan_coeffs)
94
95        # receiver
96        self.packet_receiver = \
97            blks2.demod_pkts(self._demod_class(**demod_kwargs),
98                             access_code=None,
99                             callback=self._rx_callback,
100                             threshold=-1)
101   
102        # Carrier Sensing Blocks
103        alpha = 0.001
104        thresh = 30   # in dB, will have to adjust
105
106        if options.log_rx_power == True:
107            self.probe = gr.probe_avg_mag_sqrd_cf(thresh,alpha)
108            self.power_sink = gr.file_sink(gr.sizeof_float, "rxpower.dat")
109            self.connect(self.chan_filt, self.probe, self.power_sink)
110        else:
111            self.probe = gr.probe_avg_mag_sqrd_c(thresh,alpha)
112            self.connect(self.chan_filt, self.probe)
113
114        # Display some information about the setup
115        if self._verbose:
116            self._print_verbage()
117
118        #################################spectrum sense specific code#############################
119
120
121        self.min_freq = 462.4825e6 # setting min and max frequency inside the init rather than taking it from the command line
122        self.max_freq = 462.4825e6
123
124        if self.min_freq > self.max_freq:
125            self.min_freq, self.max_freq = self.max_freq, self.min_freq   # swap them
126
127        self.fft_size = 128
128
129
130        #if not options.real_time:
131        #    realtime = False
132
133        #else:
134        #    # Attempt to enable realtime scheduling
135        #    r = gr.enable_realtime_scheduling()
136        #    if r == gr.RT_OK:
137        #        realtime = True
138        #    else:
139        #        realtime = False
140        #        print "Note: failed to enable realtime scheduling"
141
142        # If the user hasn't set the fusb_* parameters on the command line,
143        # pick some values that will reduce latency.
144
145        #if 1:
146        #    if options.fusb_block_size == 0 and options.fusb_nblocks == 0:
147        #        if realtime:                        # be more aggressive
148        #            options.fusb_block_size = gr.prefs().get_long('fusb', 'rt_block_size', 1024)
149        #            options.fusb_nblocks    = gr.prefs().get_long('fusb', 'rt_nblocks', 16)
150        #        else:
151        #            options.fusb_block_size = gr.prefs().get_long('fusb', 'block_size', 4096)
152        #            options.fusb_nblocks    = gr.prefs().get_long('fusb', 'nblocks', 16)
153   
154        #print "fusb_block_size =", options.fusb_block_size
155        #print "fusb_nblocks    =", options.fusb_nblocks
156
157        # build graph
158       
159        #self.u = usrp_options.create_usrp_source(options)
160
161
162        #adc_rate = self.u.adc_rate()                # 64 MS/s
163        #usrp_decim = options.decim
164        #self.u.set_decim_rate(usrp_decim)
165        usrp_rate = adc_rate / usrp_decim
166
167        self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec))
168        self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
169        print "Using RX d'board %s" % (self.subdev.side_and_name(),)
170
171
172        #s2v = gr.stream_to_vector(gr.sizeof_gr_complex, self.fft_size)
173        self.s2v = gr.stream_to_vector(gr.sizeof_gr_complex, self.fft_size) # making it an attribute of the class
174
175        mywindow = window.blackmanharris(self.fft_size)
176        self.fft = gr.fft_vcc(self.fft_size, True, mywindow) #making it an attribute of the class
177        power = 0
178        for tap in mywindow:
179            power += tap*tap
180
181        #c2mag = gr.complex_to_mag_squared(self.fft_size) # making it an attribute of the class
182        self.c2mag = gr.complex_to_mag_squared(self.fft_size)
183        print "print c2mag ",c2mag,"\n"
184        # FIXME the log10 primitive is dog slow
185        log = gr.nlog10_ff(10, self.fft_size,
186                           -20*math.log10(self.fft_size)-10*math.log10(power/self.fft_size))
187               
188        # Set the freq_step to 75% of the actual data throughput.
189        # This allows us to discard the bins on both ends of the spectrum.
190
191        self.freq_step = 0.75 * usrp_rate
192        self.min_center_freq = self.min_freq + self.freq_step/2
193        nsteps = math.ceil((self.max_freq - self.min_freq) / self.freq_step)
194        self.max_center_freq = self.min_center_freq + (nsteps * self.freq_step)
195
196        self.next_freq = self.min_center_freq
197       
198        tune_delay  = max(0, int(round(options.tune_delay * usrp_rate / self.fft_size)))  # in fft_frames
199        dwell_delay = max(1, int(round(options.dwell_delay * usrp_rate / self.fft_size))) # in fft_frames
200
201        self.msgq = gr.msg_queue(16)
202        self._tune_callback = tune(self)        # hang on to this to keep it from being GC'd
203        #stats = gr.bin_statistics_f(self.fft_size, self.msgq,
204        #                            self._tune_callback, tune_delay, dwell_delay)
205       
206        self.stats = gr.bin_statistics_f(self.fft_size, self.msgq,
207                                    self._tune_callback, tune_delay, dwell_delay) #making it an attribute of the class
208
209
210
211        # FIXME leave out the log10 until we speed it up
212        #self.connect(self.u, s2v, fft, c2mag, log, stats)
213        #self.connect(self.u, s2v, fft, c2mag, stats) # taking care of the connect in benchmark_txrx
214       
215        if options.gain is None:
216            # if no gain was specified, use the mid-point in dB
217            g = self.subdev.gain_range()
218            options.gain = float(g[0]+g[1])/2
219
220        self.set_gain(options.gain)
221        print "gain =", options.gain
222       
223        ##########################################################################################
224           
225        self.connect(self.u, self.chan_filt, self.packet_receiver)
226        self.connect(self.u, s2v)
227
228    def _setup_usrp_source(self, options):
229
230        self.u = usrp_options.create_usrp_source(options)
231        adc_rate = self.u.adc_rate()
232
233        # derive values of bitrate, samples_per_symbol, and decim from desired info
234        (self._bitrate, self._samples_per_symbol, self._decim) = \
235            pick_rx_bitrate(self._bitrate, self._demod_class.bits_per_symbol(), \
236                            self._samples_per_symbol, self._decim, adc_rate)
237
238        self.u.set_decim(self._decim)
239
240    def set_freq(self, target_freq):
241        """
242        Set the center frequency we're interested in.
243
244        @param target_freq: frequency in Hz
245        @rypte: bool
246
247        Tuning is a two step process.  First we ask the front-end to
248        tune as close to the desired frequency as it can.  Then we use
249        the result of that operation and our target_frequency to
250        determine the value for the digital up converter.
251        """
252        return self.u.set_center_freq(target_freq)
253
254    def set_gain(self, gain):
255        """
256        Sets the analog gain in the USRP
257        """
258        return self.u.set_gain(gain)
259       
260    def bitrate(self):
261        return self._bitrate
262
263    def samples_per_symbol(self):
264        return self._samples_per_symbol
265
266    def decim(self):
267        return self._decim
268
269    def carrier_sensed(self):
270        """
271        Return True if we think carrier is present.
272        """
273        #return self.probe.level() > X
274        return self.probe.unmuted()
275
276    def carrier_threshold(self):
277        """
278        Return current setting in dB.
279        """
280        return self.probe.threshold()
281
282    def set_carrier_threshold(self, threshold_in_db):
283        """
284        Set carrier threshold.
285
286        @param threshold_in_db: set detection threshold
287        @type threshold_in_db:  float (dB)
288        """
289        self.probe.set_threshold(threshold_in_db)
290   
291    @staticmethod
292    def add_options(normal, expert):
293        """
294        Adds receiver-specific options to the Options Parser
295        """
296        add_freq_option(normal)
297        if not normal.has_option("--bitrate"):
298            normal.add_option("-r", "--bitrate", type="eng_float", default=None,
299                              help="specify bitrate.  samples-per-symbol and interp/decim will be derived.")
300        usrp_options.add_rx_options(normal, expert)
301        normal.add_option("-v", "--verbose", action="store_true", default=False)
302        expert.add_option("-S", "--samples-per-symbol", type="int", default=None,
303                          help="set samples/symbol [default=%default]")
304        expert.add_option("", "--rx-freq", type="eng_float", default=None,
305                          help="set Rx frequency to FREQ [default=%default]", metavar="FREQ")
306        expert.add_option("", "--log", action="store_true", default=False,
307                          help="Log all parts of flow graph to files (CAUTION: lots of data)")
308        expert.add_option("", "--log-rx-power", action="store_true", default=False,
309                          help="Log receive signal power to file (CAUTION: lots of data)")
310
311    def _print_verbage(self):
312        """
313        Prints information about the receive path
314        """
315        print "\nReceive Path:"
316        print "USRP %s"    % (self.u,)
317        print "Rx gain:         %g"    % (self.u.gain(),)
318        print "modulation:      %s"    % (self._demod_class.__name__)
319        print "bitrate:         %sb/s" % (eng_notation.num_to_str(self._bitrate))
320        print "samples/symbol:  %3d"   % (self._samples_per_symbol)
321        print "decim:           %3d"   % (self._decim)
322        print "Rx Frequency:    %s"    % (eng_notation.num_to_str(self._rx_freq))
323
324def add_freq_option(parser):
325    """
326    Hackery that has the -f / --freq option set both tx_freq and rx_freq
327    """
328    def freq_callback(option, opt_str, value, parser):
329        parser.values.rx_freq = value
330        parser.values.tx_freq = value
331
332    if not parser.has_option('--freq'):
333        parser.add_option('-f', '--freq', type="eng_float",
334                          action="callback", callback=freq_callback,
335                          help="set Tx and/or Rx frequency to FREQ [default=%default]",
336                          metavar="FREQ")
337
338
339##################### Spectrum sense specific classes##################################
340
341class tune(gr.feval_dd):
342    """
343    This class allows C++ code to callback into python.
344    """
345    def __init__(self, tb):
346        gr.feval_dd.__init__(self)
347        self.tb = tb
348
349    def eval(self, ignore):
350        """
351        This method is called from gr.bin_statistics_f when it wants to change
352        the center frequency.  This method tunes the front end to the new center
353        frequency, and returns the new frequency as its result.
354        """
355        try:
356            # We use this try block so that if something goes wrong from here
357            # down, at least we'll have a prayer of knowing what went wrong.
358            # Without this, you get a very mysterious:
359            #
360            #   terminate called after throwing an instance of 'Swig::DirectorMethodException'
361            #   Aborted
362            #
363            # message on stderr.  Not exactly helpful ;)
364
365            new_freq = self.tb.set_next_freq()
366            return new_freq
367
368        except Exception, e:
369            print "tune: Exception: ", e
370
371
372class parse_msg(object):
373    def __init__(self, msg):
374        self.center_freq = msg.arg1()
375        self.vlen = int(msg.arg2())
376        assert(msg.length() == self.vlen * gr.sizeof_float)
377
378        # FIXME consider using Numarray or NumPy vector
379        t = msg.to_string()
380        self.raw_data = t
381        self.data = struct.unpack('%df' % (self.vlen,), t)
382
383
384########################################################################################
Note: See TracBrowser for help on using the browser.