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

Revision 363, 17.2 KB (checked in by sriram, 15 years ago)

Adding a print statement

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
24############## imports specific to spectrum sense #######################
25from gnuradio import optfir, window
26from gnuradio import audio
27from gnuradio.eng_option import eng_option
28from optparse import OptionParser
29from usrpm import usrp_dbid
30import math
31import struct
32#########################################################################
33from gnuradio import usrp
34from gnuradio import eng_notation
35import copy
36import sys
37from numpy import random
38# from current dir
39from pick_bitrate import pick_rx_bitrate
40import usrp_options
41import random
42
43# /////////////////////////////////////////////////////////////////////////////
44#                              receive path
45# /////////////////////////////////////////////////////////////////////////////
46
47class receive_path(gr.hier_block2):
48    def __init__(self, demod_class, rx_callback, options):
49
50        gr.hier_block2.__init__(self, "receive_path",
51                                gr.io_signature(0, 0, 0), # Input signature
52                                gr.io_signature(0, 0, 0)) # Output signature
53
54        options = copy.copy(options)    # make a copy so we can destructively modify
55
56        self._verbose            = options.verbose
57        self._rx_freq            = options.rx_freq         # receiver's center frequency
58        self._rx_gain            = options.rx_gain         # receiver's gain
59        self._bitrate            = options.bitrate         # desired bit rate
60        self._decim              = options.decim           # Decimating rate for the USRP (prelim)
61        self._samples_per_symbol = options.samples_per_symbol  # desired samples/symbol
62
63        self._rx_callback   = rx_callback      # this callback is fired when there's a packet available
64        self._demod_class   = demod_class      # the demodulator_class we're using
65
66        if self._rx_freq is None:
67            sys.stderr.write("-f FREQ or --freq FREQ or --rx-freq FREQ must be specified\n")
68            raise SystemExit
69
70        # Set up USRP source; also adjusts decim, samples_per_symbol, and bitrate
71        self._setup_usrp_source(options)
72
73        if options.show_rx_gain_range:
74            print "Rx Gain Range: minimum = %g, maximum = %g, step size = %g"%tuple(self.u.gain_range())
75
76        self.set_gain(options.rx_gain)
77
78        # Set RF frequency
79        ok = self.set_freq(self._rx_freq)
80        if not ok:
81            print "Failed to set Rx frequency to %s" % (eng_notation.num_to_str(self._rx_freq))
82            raise ValueError, eng_notation.num_to_str(self._rx_freq)
83
84        # copy the final answers back into options for use by demodulator
85        options.samples_per_symbol = self._samples_per_symbol
86        options.bitrate = self._bitrate
87        options.decim = self._decim
88
89        # Get demod_kwargs
90        demod_kwargs = self._demod_class.extract_kwargs_from_options(options)
91
92        # Design filter to get actual channel we want
93        sw_decim = 1
94        chan_coeffs = gr.firdes.low_pass (1.0,                  # gain
95                                          sw_decim * self._samples_per_symbol, # sampling rate
96                                          1.0,                  # midpoint of trans. band
97                                          0.5,                  # width of trans. band
98                                          gr.firdes.WIN_HANN)   # filter type
99
100        # Decimating channel filter
101        # complex in and out, float taps
102        self.chan_filt = gr.fft_filter_ccc(sw_decim, chan_coeffs)
103        #self.chan_filt = gr.fir_filter_ccf(sw_decim, chan_coeffs)
104
105        # receiver
106        self.packet_receiver = \
107            blks2.demod_pkts(self._demod_class(**demod_kwargs),
108                             access_code=None,
109                             callback=self._rx_callback,
110                             threshold=-1)
111   
112        # Carrier Sensing Blocks
113        alpha = 0.001
114        thresh = 30   # in dB, will have to adjust
115
116        if options.log_rx_power == True:
117            self.probe = gr.probe_avg_mag_sqrd_cf(thresh,alpha)
118            self.power_sink = gr.file_sink(gr.sizeof_float, "rxpower.dat")
119            self.connect(self.chan_filt, self.probe, self.power_sink)
120        else:
121            self.probe = gr.probe_avg_mag_sqrd_c(thresh,alpha)
122            self.connect(self.chan_filt, self.probe)
123
124        # Display some information about the setup
125        if self._verbose:
126            self._print_verbage()
127
128        #################################spectrum sense specific code#############################
129
130
131        self.min_freq = 462.4825e6 # setting min and max frequency inside the init rather than taking it from the command line
132        self.max_freq = 462.6425e6
133
134        if self.min_freq > self.max_freq:
135            self.min_freq, self.max_freq = self.max_freq, self.min_freq   # swap them
136
137        self.fft_size = 512
138
139
140        #if not options.real_time:
141        #    realtime = False
142
143        #else:
144        #    # Attempt to enable realtime scheduling
145        #    r = gr.enable_realtime_scheduling()
146        #    if r == gr.RT_OK:
147        #        realtime = True
148        #    else:
149        #        realtime = False
150        #        print "Note: failed to enable realtime scheduling"
151
152        # If the user hasn't set the fusb_* parameters on the command line,
153        # pick some values that will reduce latency.
154
155        #if 1:
156        #    if options.fusb_block_size == 0 and options.fusb_nblocks == 0:
157        #        if realtime:                        # be more aggressive
158        #            options.fusb_block_size = gr.prefs().get_long('fusb', 'rt_block_size', 1024)
159        #            options.fusb_nblocks    = gr.prefs().get_long('fusb', 'rt_nblocks', 16)
160        #        else:
161        #            options.fusb_block_size = gr.prefs().get_long('fusb', 'block_size', 4096)
162        #            options.fusb_nblocks    = gr.prefs().get_long('fusb', 'nblocks', 16)
163   
164        #print "fusb_block_size =", options.fusb_block_size
165        #print "fusb_nblocks    =", options.fusb_nblocks
166
167        # build graph
168       
169        #self.u = usrp_options.create_usrp_source(options)
170
171
172        #adc_rate = self.u.adc_rate()                # 64 MS/s
173        #usrp_decim = options.decim
174        #self.u.set_decim_rate(usrp_decim)
175        usrp_rate = self.adc_rate / self._decim
176
177        #self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec))
178        #self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
179        #print "Using RX d'board %s" % (self.subdev.side_and_name(),)
180
181
182       
183        s2v = gr.stream_to_vector(gr.sizeof_gr_complex, self.fft_size)
184
185        mywindow = window.blackmanharris(self.fft_size)
186        fft = gr.fft_vcc(self.fft_size, True, mywindow)
187        power = 0
188        for tap in mywindow:
189            power += tap*tap
190
191       
192        c2mag = gr.complex_to_mag_squared(self.fft_size)
193        print "print c2mag ",c2mag,"\n"
194        # FIXME the log10 primitive is dog slow
195        log = gr.nlog10_ff(10, self.fft_size,
196                           -20*math.log10(self.fft_size)-10*math.log10(power/self.fft_size))
197               
198        # Set the freq_step to 75% of the actual data throughput.
199        # This allows us to discard the bins on both ends of the spectrum.
200
201        self.freq_step = 0.75 * usrp_rate
202        self.min_center_freq = self.min_freq + self.freq_step/2
203        nsteps = math.ceil((self.max_freq - self.min_freq) / self.freq_step)
204        self.max_center_freq = self.min_center_freq + (nsteps * self.freq_step)
205
206        self.next_freq = self.min_center_freq
207        tune_delay = 1e-3
208        dwell_delay = 1e-2
209        tune_delay  = max(0, int(round(tune_delay * usrp_rate / self.fft_size)))  # in fft_frames
210        dwell_delay = max(1, int(round(dwell_delay * usrp_rate / self.fft_size))) # in fft_frames
211
212        self.msgq = gr.msg_queue(16)
213        self._tune_callback = tune(self)        # hang on to this to keep it from being GC'd
214               
215        stats = gr.bin_statistics_f(self.fft_size, self.msgq,
216                                    self._tune_callback, tune_delay, dwell_delay)
217
218
219
220        # FIXME leave out the log10 until we speed it up
221        #self.connect(self.u, s2v, fft, c2mag, log, stats)
222        #self.connect(self.u, s2v, fft, c2mag, stats)
223       
224        #if options.gain is None:
225        #    # if no gain was specified, use the mid-point in dB
226        #    g = self.subdev.gain_range()
227        #    options.gain = float(g[0]+g[1])/2
228
229        #self.set_gain(options.gain)
230        #print "gain =", options.gain
231       
232        ##########################################################################################
233           
234        self.connect(self.u, self.chan_filt, self.packet_receiver)
235        self.connect(self.u, s2v, fft, c2mag, stats)
236
237    def _setup_usrp_source(self, options):
238
239        self.u = usrp_options.create_usrp_source(options)
240        self.adc_rate = self.u.adc_rate()
241
242        # derive values of bitrate, samples_per_symbol, and decim from desired info
243        (self._bitrate, self._samples_per_symbol, self._decim) = \
244            pick_rx_bitrate(self._bitrate, self._demod_class.bits_per_symbol(), \
245                            self._samples_per_symbol, self._decim, self.adc_rate)
246
247        self.u.set_decim(self._decim)
248
249    def set_freq(self, target_freq):
250        """
251        Set the center frequency we're interested in.
252
253        @param target_freq: frequency in Hz
254        @rypte: bool
255
256        Tuning is a two step process.  First we ask the front-end to
257        tune as close to the desired frequency as it can.  Then we use
258        the result of that operation and our target_frequency to
259        determine the value for the digital up converter.
260        """
261        return self.u.set_center_freq(target_freq)
262
263    def set_gain(self, gain):
264        """
265        Sets the analog gain in the USRP
266        """
267        return self.u.set_gain(gain)
268       
269    def bitrate(self):
270        return self._bitrate
271
272    def samples_per_symbol(self):
273        return self._samples_per_symbol
274
275    def decim(self):
276        return self._decim
277
278    def carrier_sensed(self):
279        """
280        Return True if we think carrier is present.
281        """
282        #return self.probe.level() > X
283        return self.probe.unmuted()
284
285    def carrier_threshold(self):
286        """
287        Return current setting in dB.
288        """
289        return self.probe.threshold()
290
291    def set_carrier_threshold(self, threshold_in_db):
292        """
293        Set carrier threshold.
294
295        @param threshold_in_db: set detection threshold
296        @type threshold_in_db:  float (dB)
297        """
298        self.probe.set_threshold(threshold_in_db)
299   
300    @staticmethod
301    def add_options(normal, expert):
302        """
303        Adds receiver-specific options to the Options Parser
304        """
305        add_freq_option(normal)
306        if not normal.has_option("--bitrate"):
307            normal.add_option("-r", "--bitrate", type="eng_float", default=None,
308                              help="specify bitrate.  samples-per-symbol and interp/decim will be derived.")
309        usrp_options.add_rx_options(normal, expert)
310        normal.add_option("-v", "--verbose", action="store_true", default=False)
311        expert.add_option("-S", "--samples-per-symbol", type="int", default=None,
312                          help="set samples/symbol [default=%default]")
313        expert.add_option("", "--rx-freq", type="eng_float", default=None,
314                          help="set Rx frequency to FREQ [default=%default]", metavar="FREQ")
315        expert.add_option("", "--log", action="store_true", default=False,
316                          help="Log all parts of flow graph to files (CAUTION: lots of data)")
317        expert.add_option("", "--log-rx-power", action="store_true", default=False,
318                          help="Log receive signal power to file (CAUTION: lots of data)")
319
320    def set_next_freq(self):
321        target_freq = self.next_freq
322        self.next_freq = self.next_freq + self.freq_step
323        if self.next_freq >= self.max_center_freq:
324            self.next_freq = self.min_center_freq
325
326        if not self.set_freq(target_freq):
327            print "Failed to set frequency to", target_freq
328
329        return target_freq
330
331    def _print_verbage(self):
332        """
333        Prints information about the receive path
334        """
335        print "\nReceive Path:"
336        print "USRP %s"    % (self.u,)
337        print "Rx gain:         %g"    % (self.u.gain(),)
338        print "modulation:      %s"    % (self._demod_class.__name__)
339        print "bitrate:         %sb/s" % (eng_notation.num_to_str(self._bitrate))
340        print "samples/symbol:  %3d"   % (self._samples_per_symbol)
341        print "decim:           %3d"   % (self._decim)
342        print "Rx Frequency:    %s"    % (eng_notation.num_to_str(self._rx_freq))
343
344    #Getting spectrum information
345    #Arguments... threshold - Minimum power equivalent available in spectrum
346#                 trials - Fft frames...should be 1
347#                 exceed count - Number of times threshold is exceeded...useless
348
349    def get_spec_stats(self,threshold,trials):
350        power_sum = 0 #sum of powers(each power value is determined by adding the 'fft square' points..these fft square points are essentially points from the PSD curve...and adding them gives us the power contained in the spectrum)
351        counter = 0
352        #exceed = 0
353        while counter < trials:
354                # Get the next message sent from the C++ code (blocking call).
355                # It contains the center frequency and the mag squared of the fft
356                m = parse_msg(self.msgq.delete_head())
357                #print "printing mag sq of fft ",sum(m.data),"\n"
358                power_sum = power_sum + sum(m.data)
359                #if sum(m.data) > threshold
360                #       exceed+=1
361                #print sum(m.data),"\n"
362                # Print center freq so we know that something is happening...
363                #print m.center_freq
364                counter +=1
365        # FIXME do something useful with the data...
366       
367       
368        # m.data are the mag_squared of the fft output (they are in the
369        # standard order.  I.e., bin 0 == DC.)
370        # You'll probably want to do the equivalent of "fftshift" on them
371        # m.raw_data is a string that contains the binary floats.
372        # You could write this as binary to a file.
373        print "here"
374        avg_power = power_sum/trials
375        print "avg power ",avg_power,"\n"
376        #ch = int(random.choice('17'))
377        if avg_power >= threshold:
378                return True
379                #return 1,ch
380        else:
381                return False
382                #return 0,"no"
383        #print "printing average power ",avg_power,"\n"
384        #if exceed >= exceed_count:
385        #       return avg_power,True
386        #       return avg_power,True #True = primary user is present at this frequency
387        #else
388        #       return avg_power,False
389        #       return avg_power,False #False = primary user is NOT present at this frequency
390
391def add_freq_option(parser):
392    """
393    Hackery that has the -f / --freq option set both tx_freq and rx_freq
394    """
395    def freq_callback(option, opt_str, value, parser):
396        parser.values.rx_freq = value
397        parser.values.tx_freq = value
398
399    if not parser.has_option('--freq'):
400        parser.add_option('-f', '--freq', type="eng_float",
401                          action="callback", callback=freq_callback,
402                          help="set Tx and/or Rx frequency to FREQ [default=%default]",
403                          metavar="FREQ")
404
405
406##################### Spectrum sense specific classes##################################
407
408class tune(gr.feval_dd):
409    """
410    This class allows C++ code to callback into python.
411    """
412    def __init__(self, tb):
413        gr.feval_dd.__init__(self)
414        self.tb = tb
415
416    def eval(self, ignore):
417        """
418        This method is called from gr.bin_statistics_f when it wants to change
419        the center frequency.  This method tunes the front end to the new center
420        frequency, and returns the new frequency as its result.
421        """
422        try:
423            # We use this try block so that if something goes wrong from here
424            # down, at least we'll have a prayer of knowing what went wrong.
425            # Without this, you get a very mysterious:
426            #
427            #   terminate called after throwing an instance of 'Swig::DirectorMethodException'
428            #   Aborted
429            #
430            # message on stderr.  Not exactly helpful ;)
431
432            new_freq = self.tb.set_next_freq()
433            return new_freq
434
435        except Exception, e:
436            print "tune: Exception: ", e
437
438
439class parse_msg(object):
440    def __init__(self, msg):
441        self.center_freq = msg.arg1()
442        self.vlen = int(msg.arg2())
443        assert(msg.length() == self.vlen * gr.sizeof_float)
444
445        # FIXME consider using Numarray or NumPy vector
446        t = msg.to_string()
447        self.raw_data = t
448        self.data = struct.unpack('%df' % (self.vlen,), t)
449
450
451########################################################################################
Note: See TracBrowser for help on using the browser.