Statistics
| Branch: | Tag: | Revision:

root / gr-uhd / apps / uhd_rx_nogui.py @ 3e7ca8bf

History | View | Annotate | Download (9.5 kB)

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