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