Imported Upstream version 3.0
[debian/gnuradio] / gnuradio-examples / python / usrp / usrp_rx_nogui.py
1 #!/usr/bin/env python
2
3 from gnuradio import gr, gru, usrp, optfir, audio, eng_notation, blks
4 from gnuradio.eng_option import eng_option
5 from optparse import OptionParser
6
7 """
8 This example application demonstrates receiving and demodulating 
9 different types of signals using the USRP. 
10
11 A receive chain is built up of the following signal processing
12 blocks:
13
14 USRP  - Daughter board source generating complex baseband signal.
15 CHAN  - Low pass filter to select channel bandwidth
16 RFSQL - RF squelch zeroing output when input power below threshold
17 AGC   - Automatic gain control leveling signal at [-1.0, +1.0]
18 DEMOD - Demodulation block appropriate to selected signal type.
19         This converts the complex baseband to real audio frequencies,
20         and applies an appropriate low pass decimating filter.
21 CTCSS - Optional tone squelch zeroing output when tone is not present.
22 RSAMP - Resampler block to convert audio sample rate to user specified
23         sound card output rate.
24 AUDIO - Audio sink for playing final output to speakers.
25
26 The following are required command line parameters:
27
28 -f FREQ         USRP receive frequency
29 -m MOD          Modulation type, select from AM, FM, or WFM
30
31 The following are optional command line parameters:
32
33 -R SUBDEV       Daughter board specification, defaults to first found
34 -c FREQ         Calibration offset.  Gets added to receive frequency.
35                 Defaults to 0.0 Hz.
36 -g GAIN         Daughterboard gain setting. Defaults to mid-range.
37 -o RATE         Sound card output rate. Defaults to 32000. Useful if
38                 your sound card only accepts particular sample rates.
39 -r RFSQL        RF squelch in db. Defaults to -50.0.
40 -p FREQ         CTCSS frequency.  Opens squelch when tone is present.
41
42 Once the program is running, ctrl-break (Ctrl-C) stops operation.
43
44 Please see fm_demod.py and am_demod.py for details of the demodulation
45 blocks.
46 """
47
48 # (usrp_decim, channel_decim, audio_decim, channel_pass, channel_stop, demod)
49 demod_params = {
50                 'AM'  : (250, 16, 1,  5000,   8000, blks.demod_10k0a3e_cf),
51                 'FM'  : (250,  8, 4,  8000,   9000, blks.demod_20k0f3e_cf),
52                 'WFM' : (250,  1, 8, 90000, 100000, blks.demod_200kf3e_cf)
53                }
54
55 class usrp_source_c(gr.hier_block):
56     """
57     Create a USRP source object supplying complex floats.
58     
59     Selects user supplied subdevice or chooses first available one.
60
61     Calibration value is the offset from the tuned frequency to 
62     the actual frequency.       
63     """
64     def __init__(self, fg, subdev_spec, decim, gain=None, calibration=0.0):
65         self._decim = decim
66         self._src = usrp.source_c()
67         if subdev_spec is None:
68             subdev_spec = usrp.pick_rx_subdevice(self._src)
69         self._subdev = usrp.selected_subdev(self._src, subdev_spec)
70         self._src.set_mux(usrp.determine_rx_mux_value(self._src, subdev_spec))
71         self._src.set_decim_rate(self._decim)
72
73         # If no gain specified, set to midrange
74         if gain is None:
75             g = self._subdev.gain_range()
76             gain = (g[0]+g[1])/2.0
77
78         self._subdev.set_gain(gain)
79         self._cal = calibration
80         gr.hier_block.__init__(self, fg, self._src, self._src)
81
82     def tune(self, freq):
83         result = usrp.tune(self._src, 0, self._subdev, freq+self._cal)
84         # TODO: deal with residual
85
86     def rate(self):
87         return self._src.adc_rate()/self._decim
88
89 class app_flow_graph(gr.flow_graph):
90     def __init__(self, options, args):
91         gr.flow_graph.__init__(self)
92         self.options = options
93         self.args = args
94
95         (usrp_decim, channel_decim, audio_decim, 
96          channel_pass, channel_stop, demod) = demod_params[options.modulation]
97
98         USRP = usrp_source_c(self,                  # Flow graph
99                             options.rx_subdev_spec, # Daugherboard spec
100                             usrp_decim,             # IF decimation ratio
101                             options.gain,           # Receiver gain
102                             options.calibration)    # Frequency offset
103         USRP.tune(options.frequency)
104
105         if_rate = USRP.rate()
106         channel_rate = if_rate // channel_decim
107         audio_rate = channel_rate // audio_decim
108
109         CHAN_taps = optfir.low_pass(1.0,         # Filter gain
110                                    if_rate,      # Sample rate
111                                    channel_pass, # One sided modulation bandwidth
112                                    channel_stop, # One sided channel bandwidth
113                                    0.1,          # Passband ripple
114                                    60)           # Stopband attenuation
115
116         CHAN = gr.freq_xlating_fir_filter_ccf(channel_decim, # Decimation rate
117                                               CHAN_taps,     # Filter taps
118                                               0.0,           # Offset frequency
119                                               if_rate)       # Sample rate
120
121         RFSQL = gr.pwr_squelch_cc(options.rf_squelch,    # Power threshold
122                                   125.0/channel_rate,    # Time constant
123                                   channel_rate/20,       # 50ms rise/fall
124                                   False)                 # Zero, not gate output
125
126         AGC = gr.agc_cc(1.0/channel_rate,  # Time constant
127                         1.0,               # Reference power 
128                         1.0,               # Initial gain
129                         1.0)               # Maximum gain
130
131         DEMOD = demod(self, channel_rate, audio_decim)
132
133         # From RF to audio
134         self.connect(USRP, CHAN, RFSQL, AGC, DEMOD)
135
136         # Optionally add CTCSS and RSAMP if needed
137         tail = DEMOD
138         if options.ctcss != None and options.ctcss > 60.0:
139             CTCSS = gr.ctcss_squelch_ff(audio_rate,    # Sample rate
140                                         options.ctcss) # Squelch tone
141             self.connect(DEMOD, CTCSS)
142             tail = CTCSS
143
144         if options.output_rate != audio_rate:
145             out_lcm = gru.lcm(audio_rate, options.output_rate)
146             out_interp = int(out_lcm // audio_rate)
147             out_decim = int(out_lcm // options.output_rate)
148             RSAMP = blks.rational_resampler_fff(self, out_interp, out_decim)
149             self.connect(tail, RSAMP)
150             tail = RSAMP 
151
152         # Send to default audio output
153         AUDIO = audio.sink(options.output_rate, "")
154         self.connect(tail, AUDIO)
155         
156 def main():
157     parser = OptionParser(option_class=eng_option)
158     parser.add_option("-f", "--frequency", type="eng_float",
159                       help="set receive frequency to Hz", metavar="Hz")
160     parser.add_option("-R", "--rx-subdev-spec", type="subdev",
161                       help="select USRP Rx side A or B", metavar="SUBDEV")
162     parser.add_option("-c",   "--calibration", type="eng_float", default=0.0,
163                       help="set frequency offset to Hz", metavar="Hz")
164     parser.add_option("-g", "--gain", type="int", default=None,
165                       help="set RF gain", metavar="dB")
166     parser.add_option("-m", "--modulation", type="choice", choices=('AM','FM','WFM'),
167                       help="set modulation type (AM,FM)", metavar="TYPE")
168     parser.add_option("-o", "--output-rate", type="int", default=32000,
169                       help="set audio output rate to RATE", metavar="RATE")
170     parser.add_option("-r", "--rf-squelch", type="eng_float", default=-50.0,
171                       help="set RF squelch to dB", metavar="dB")
172     parser.add_option("-p", "--ctcss", type="float",
173                       help="set CTCSS squelch to FREQ", metavar="FREQ")
174     (options, args) = parser.parse_args()
175
176     if options.frequency < 1e6:
177         options.frequency *= 1e6
178         
179     fg = app_flow_graph(options, args)
180     try:
181         fg.run()
182     except KeyboardInterrupt:
183         pass
184
185 if __name__ == "__main__":
186     main()