merged r10942:11199 from digital branch
[debian/gnuradio] / gnuradio-examples / python / digital / receive_path.py
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
23 from gnuradio import gr, gru, blks2
24 from gnuradio import usrp
25 from gnuradio import eng_notation
26 import copy
27 import sys
28
29 # from current dir
30 from pick_bitrate import pick_rx_bitrate
31 import usrp_options
32
33 # /////////////////////////////////////////////////////////////////////////////
34 #                              receive path
35 # /////////////////////////////////////////////////////////////////////////////
36
37 class 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._bitrate            = options.bitrate         # desired bit rate
49         self._decim              = options.decim           # Decimating rate for the USRP (prelim)
50         self._samples_per_symbol = options.samples_per_symbol  # desired samples/symbol
51
52         self._rx_callback   = rx_callback      # this callback is fired when there's a packet available
53         self._demod_class   = demod_class      # the demodulator_class we're using
54
55         if self._rx_freq is None:
56             sys.stderr.write("-f FREQ or --freq FREQ or --rx-freq FREQ must be specified\n")
57             raise SystemExit
58
59         # Set up USRP source; also adjusts decim, samples_per_symbol, and bitrate
60         self._setup_usrp_source(options)
61
62         # Set RF frequency
63         ok = self.set_freq(self._rx_freq)
64         if not ok:
65             print "Failed to set Rx frequency to %s" % (eng_notation.num_to_str(self._rx_freq))
66             raise ValueError, eng_notation.num_to_str(self._rx_freq)
67
68         # copy the final answers back into options for use by demodulator
69         options.samples_per_symbol = self._samples_per_symbol
70         options.bitrate = self._bitrate
71         options.decim = self._decim
72
73         # Get demod_kwargs
74         demod_kwargs = self._demod_class.extract_kwargs_from_options(options)
75
76         # Design filter to get actual channel we want
77         sw_decim = 1
78         chan_coeffs = gr.firdes.low_pass (1.0,                  # gain
79                                           sw_decim * self._samples_per_symbol, # sampling rate
80                                           1.0,                  # midpoint of trans. band
81                                           0.5,                  # width of trans. band
82                                           gr.firdes.WIN_HANN)   # filter type 
83
84         # Decimating channel filter
85         # complex in and out, float taps
86         self.chan_filt = gr.fft_filter_ccc(sw_decim, chan_coeffs)
87         #self.chan_filt = gr.fir_filter_ccf(sw_decim, chan_coeffs)
88
89         # receiver
90         self.packet_receiver = \
91             blks2.demod_pkts(self._demod_class(**demod_kwargs),
92                              access_code=None,
93                              callback=self._rx_callback,
94                              threshold=-1)
95     
96         # Carrier Sensing Blocks
97         alpha = 0.001
98         thresh = 30   # in dB, will have to adjust
99
100         if options.log_rx_power == True:
101             self.probe = gr.probe_avg_mag_sqrd_cf(thresh,alpha)
102             self.power_sink = gr.file_sink(gr.sizeof_float, "rxpower.dat")
103             self.connect(self.chan_filt, self.probe, self.power_sink)
104         else:
105             self.probe = gr.probe_avg_mag_sqrd_c(thresh,alpha)
106             self.connect(self.chan_filt, self.probe)
107
108         # Display some information about the setup
109         if self._verbose:
110             self._print_verbage()
111             
112         self.connect(self.u, self.chan_filt, self.packet_receiver)
113
114     def _setup_usrp_source(self, options):
115
116         self.u = usrp_options.create_usrp_source(options)
117         adc_rate = self.u.adc_rate()
118
119         # derive values of bitrate, samples_per_symbol, and decim from desired info
120         (self._bitrate, self._samples_per_symbol, self._decim) = \
121             pick_rx_bitrate(self._bitrate, self._demod_class.bits_per_symbol(), \
122                             self._samples_per_symbol, self._decim, adc_rate, self.u.get_decim_rates())
123
124         self.u.set_decim(self._decim)
125
126     def set_freq(self, target_freq):
127         """
128         Set the center frequency we're interested in.
129
130         @param target_freq: frequency in Hz
131         @rypte: bool
132
133         Tuning is a two step process.  First we ask the front-end to
134         tune as close to the desired frequency as it can.  Then we use
135         the result of that operation and our target_frequency to
136         determine the value for the digital up converter.
137         """
138         return self.u.set_center_freq(target_freq)
139         
140     def bitrate(self):
141         return self._bitrate
142
143     def samples_per_symbol(self):
144         return self._samples_per_symbol
145
146     def decim(self):
147         return self._decim
148
149     def carrier_sensed(self):
150         """
151         Return True if we think carrier is present.
152         """
153         #return self.probe.level() > X
154         return self.probe.unmuted()
155
156     def carrier_threshold(self):
157         """
158         Return current setting in dB.
159         """
160         return self.probe.threshold()
161
162     def set_carrier_threshold(self, threshold_in_db):
163         """
164         Set carrier threshold.
165
166         @param threshold_in_db: set detection threshold
167         @type threshold_in_db:  float (dB)
168         """
169         self.probe.set_threshold(threshold_in_db)
170     
171     @staticmethod
172     def add_options(normal, expert):
173         """
174         Adds receiver-specific options to the Options Parser
175         """
176         add_freq_option(normal)
177         if not normal.has_option("--bitrate"):
178             normal.add_option("-r", "--bitrate", type="eng_float", default=None,
179                               help="specify bitrate.  samples-per-symbol and interp/decim will be derived.")
180         usrp_options.add_rx_options(normal)
181         normal.add_option("-v", "--verbose", action="store_true", default=False)
182         expert.add_option("-S", "--samples-per-symbol", type="int", default=None,
183                           help="set samples/symbol [default=%default]")
184         expert.add_option("", "--rx-freq", type="eng_float", default=None,
185                           help="set Rx frequency to FREQ [default=%default]", metavar="FREQ")
186         expert.add_option("", "--log", action="store_true", default=False,
187                           help="Log all parts of flow graph to files (CAUTION: lots of data)")
188         expert.add_option("", "--log-rx-power", action="store_true", default=False,
189                           help="Log receive signal power to file (CAUTION: lots of data)")
190
191     def _print_verbage(self):
192         """
193         Prints information about the receive path
194         """
195         print "\nReceive Path:"
196         print "USRP %s"    % (self.u,)
197         print "Rx gain:         %g"    % (self.u.gain(),)
198         print "modulation:      %s"    % (self._demod_class.__name__)
199         print "bitrate:         %sb/s" % (eng_notation.num_to_str(self._bitrate))
200         print "samples/symbol:  %3d"   % (self._samples_per_symbol)
201         print "decim:           %3d"   % (self._decim)
202         print "Rx Frequency:    %s"    % (eng_notation.num_to_str(self._rx_freq))
203
204 def add_freq_option(parser):
205     """
206     Hackery that has the -f / --freq option set both tx_freq and rx_freq
207     """
208     def freq_callback(option, opt_str, value, parser):
209         parser.values.rx_freq = value
210         parser.values.tx_freq = value
211
212     if not parser.has_option('--freq'):
213         parser.add_option('-f', '--freq', type="eng_float",
214                           action="callback", callback=freq_callback,
215                           help="set Tx and/or Rx frequency to FREQ [default=%default]",
216                           metavar="FREQ")