Statistics
| Branch: | Tag: | Revision:

root / gr-uhd / examples / python / usrp_am_mw_rcv.py @ 7dc08ba2

History | View | Annotate | Download (12.1 kB)

1
#!/usr/bin/env python
2
#
3
# Copyright 2005-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, eng_notation, optfir
24
from gnuradio import audio
25
from gnuradio import uhd
26
from gnuradio import blks2
27
from gnuradio.eng_option import eng_option
28
from gnuradio.wxgui import slider, powermate
29
from gnuradio.wxgui import stdgui2, fftsink2, form
30
from optparse import OptionParser
31
import sys
32
import math
33
import wx
34
35
class wfm_rx_block (stdgui2.std_top_block):
36
    def __init__(self, frame, panel, vbox, argv):
37
        stdgui2.std_top_block.__init__ (self, frame, panel, vbox, argv)
38
39
        parser=OptionParser(option_class=eng_option)
40
        parser.add_option("-a", "--args", type="string", default="",
41
                          help="UHD device address args [default=%default]")
42
        parser.add_option("", "--spec", type="string", default=None,
43
                          help="Subdevice of UHD device where appropriate")
44
        parser.add_option("-A", "--antenna", type="string", default=None,
45
                          help="select Rx Antenna where appropriate")
46
        parser.add_option("-s", "--samp-rate", type="eng_float", default=1e6,
47
                          help="set sample rate (bandwidth) [default=%default]")
48
        parser.add_option("-f", "--freq", type="eng_float", default=1008.0e3,
49
                          help="set frequency to FREQ", metavar="FREQ")
50
        parser.add_option("-I", "--use-if-freq", action="store_true", default=False,
51
                          help="use intermediate freq (compensates DC problems in quadrature boards)" )
52
        parser.add_option("-g", "--gain", type="eng_float", default=None,
53
                          help="set gain in dB (default is maximum)")
54
        parser.add_option("-V", "--volume", type="eng_float", default=None,
55
                          help="set volume (default is midpoint)")
56
        parser.add_option("-O", "--audio-output", type="string", default="",
57
                          help="pcm device name.  E.g., hw:0,0 or surround51 or /dev/dsp")
58
59
        (options, args) = parser.parse_args()
60
        if len(args) != 0:
61
            parser.print_help()
62
            sys.exit(1)
63
        
64
        self.frame = frame
65
        self.panel = panel
66
        self.use_IF=options.use_if_freq
67
        if self.use_IF:
68
          self.IF_freq=64000.0 
69
        else:
70
          self.IF_freq=0.0
71
        
72
        self.vol = 0
73
        self.state = "FREQ"
74
        self.freq = 0
75
76
        # build graph
77
        self.u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
78
79
        # Set the subdevice spec
80
        if(options.spec):
81
            self.u.set_subdev_spec(options.spec, 0)
82
83
        # Set the antenna
84
        if(options.antenna):
85
            self.u.set_antenna(options.antenna, 0)
86
87
        usrp_rate  = 256e3
88
        demod_rate = 64e3
89
        audio_rate = 32e3
90
        chanfilt_decim = int(usrp_rate // demod_rate)
91
        audio_decim = int(demod_rate // audio_rate)
92
        
93
        self.u.set_samp_rate(usrp_rate)
94
        dev_rate = self.u.get_samp_rate()
95
96
        # Resample signal to exactly self.usrp_rate
97
        # FIXME: make one of the follow-on filters an arb resampler
98
        rrate = usrp_rate / dev_rate
99
        self.resamp = blks2.pfb_arb_resampler_ccf(rrate)
100
        
101
        chan_filt_coeffs = gr.firdes.low_pass_2 (1,          # gain
102
                                                 usrp_rate,  # sampling rate
103
                                                 8e3,        # passband cutoff
104
                                                 4e3,        # transition bw
105
                                                 60)         # stopband attenuation
106
107
        if self.use_IF:
108
          # Turn If to baseband and filter.
109
          self.chan_filt = gr.freq_xlating_fir_filter_ccf (chanfilt_decim,
110
                                                           chan_filt_coeffs,
111
                                                           self.IF_freq,
112
                                                           usrp_rate)
113
        else:
114
          self.chan_filt = gr.fir_filter_ccf (chanfilt_decim, chan_filt_coeffs)
115
116
        self.agc = gr.agc_cc(0.1, 1, 1, 100000)
117
        self.am_demod = gr.complex_to_mag()
118
        self.volume_control = gr.multiply_const_ff(self.vol)
119
120
        audio_filt_coeffs = gr.firdes.low_pass_2 (1,          # gain
121
                                                  demod_rate, # sampling rate
122
                                                  8e3,        # passband cutoff
123
                                                  2e3,        # transition bw
124
                                                  60)         # stopband attenuation
125
        self.audio_filt=gr.fir_filter_fff(audio_decim, audio_filt_coeffs)
126
127
        # sound card as final sink
128
        self.audio_sink = audio.sink (int (audio_rate),
129
                                      options.audio_output,
130
                                      False)  # ok_to_block
131
        
132
        # now wire it all together
133
        self.connect (self.u, self.resamp, self.chan_filt, self.agc,
134
                      self.am_demod, self.audio_filt, 
135
                      self.volume_control, self.audio_sink)
136
137
        self._build_gui(vbox, usrp_rate, demod_rate, audio_rate)
138
139
        if options.gain is None:
140
            g = self.u.get_gain_range()
141
            if True:
142
                # if no gain was specified, use the mid gain
143
                options.gain = (g.start() + g.stop())/2.0
144
                options.gain = g.stop()
145
146
        if options.volume is None:
147
            v = self.volume_range()
148
            options.volume = float(v[0]*3+v[1])/4.0
149
            
150
        if abs(options.freq) < 1e3:
151
            options.freq *= 1e3
152
153
        # set initial values
154
155
        self.set_gain(options.gain)
156
        self.set_vol(options.volume)
157
        if not(self.set_freq(options.freq)):
158
            self._set_status_msg("Failed to set initial frequency")
159
160
    def _set_status_msg(self, msg, which=0):
161
        self.frame.GetStatusBar().SetStatusText(msg, which)
162
163
164
    def _build_gui(self, vbox, usrp_rate, demod_rate, audio_rate):
165
166
        def _form_set_freq(kv):
167
            return self.set_freq(kv['freq'])
168
169
170
        if 0:
171
            self.src_fft = fftsink2.fft_sink_c(self.panel, title="Data from USRP",
172
                                               fft_size=512, sample_rate=usrp_rate,
173
                                               ref_scale=32768.0, ref_level=0.0, y_divs=12)
174
            self.connect (self.u, self.src_fft)
175
            vbox.Add (self.src_fft.win, 4, wx.EXPAND)
176
177
        if 0:
178
            self.post_filt_fft = fftsink2.fft_sink_c(self.panel, title="Post Channel filter",
179
                                               fft_size=512, sample_rate=demod_rate)
180
            self.connect (self.chan_filt, self.post_filt_fft)
181
            vbox.Add (self.post_filt_fft.win, 4, wx.EXPAND)
182
183
        if 0:
184
            post_demod_fft = fftsink2.fft_sink_f(self.panel, title="Post Demod", 
185
                                                fft_size=1024, sample_rate=demod_rate,
186
                                                y_per_div=10, ref_level=0)
187
            self.connect (self.am_demod, post_demod_fft)
188
            vbox.Add (post_demod_fft.win, 4, wx.EXPAND)
189
190
        if 1:
191
            audio_fft = fftsink2.fft_sink_f(self.panel, title="Audio",
192
                                                  fft_size=512, sample_rate=audio_rate,
193
                                                  y_per_div=10, ref_level=20)
194
            self.connect (self.audio_filt, audio_fft)
195
            vbox.Add (audio_fft.win, 4, wx.EXPAND)
196
197
        
198
        # control area form at bottom
199
        self.myform = myform = form.form()
200
201
        hbox = wx.BoxSizer(wx.HORIZONTAL)
202
        hbox.Add((5,0), 0)
203
        myform['freq'] = form.float_field(
204
            parent=self.panel, sizer=hbox, label="Freq", weight=1,
205
            callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
206
207
        hbox.Add((5,0), 0)
208
        myform['freq_slider'] = \
209
            form.quantized_slider_field(parent=self.panel, sizer=hbox, weight=3,
210
                                        range=(520.0e3, 1611.0e3, 1.0e3),
211
                                        callback=self.set_freq)
212
        hbox.Add((5,0), 0)
213
        vbox.Add(hbox, 0, wx.EXPAND)
214
215
        hbox = wx.BoxSizer(wx.HORIZONTAL)
216
        hbox.Add((5,0), 0)
217
218
        myform['volume'] = \
219
            form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Volume",
220
                                        weight=3, range=self.volume_range(),
221
                                        callback=self.set_vol)
222
        hbox.Add((5,0), 1)
223
224
        g = self.u.get_gain_range()
225
        myform['gain'] = \
226
            form.quantized_slider_field(parent=self.panel, sizer=hbox, label="Gain",
227
                                        weight=3, range=(g.start(), g.stop(), g.step()),
228
                                        callback=self.set_gain)
229
        hbox.Add((5,0), 0)
230
        vbox.Add(hbox, 0, wx.EXPAND)
231
232
        try:
233
            self.knob = powermate.powermate(self.frame)
234
            self.rot = 0
235
            powermate.EVT_POWERMATE_ROTATE (self.frame, self.on_rotate)
236
            powermate.EVT_POWERMATE_BUTTON (self.frame, self.on_button)
237
        except:
238
            print "FYI: No Powermate or Contour Knob found"
239
240
241
    def on_rotate (self, event):
242
        self.rot += event.delta
243
        if (self.state == "FREQ"):
244
            if self.rot >= 3:
245
                self.set_freq(self.freq + .1e6)
246
                self.rot -= 3
247
            elif self.rot <=-3:
248
                self.set_freq(self.freq - .1e6)
249
                self.rot += 3
250
        else:
251
            step = self.volume_range()[2]
252
            if self.rot >= 3:
253
                self.set_vol(self.vol + step)
254
                self.rot -= 3
255
            elif self.rot <=-3:
256
                self.set_vol(self.vol - step)
257
                self.rot += 3
258
            
259
    def on_button (self, event):
260
        if event.value == 0:        # button up
261
            return
262
        self.rot = 0
263
        if self.state == "FREQ":
264
            self.state = "VOL"
265
        else:
266
            self.state = "FREQ"
267
        self.update_status_bar ()
268
        
269
270
    def set_vol (self, vol):
271
        g = self.volume_range()
272
        self.vol = max(g[0], min(g[1], vol))
273
        self.volume_control.set_k(10**(self.vol/10))
274
        self.myform['volume'].set_value(self.vol)
275
        self.update_status_bar ()
276
                                        
277
    def set_freq(self, target_freq):
278
        """
279
        Set the center frequency we're interested in.
280
281
        @param target_freq: frequency in Hz
282
        @rypte: bool
283
        """
284
        r = self.u.set_center_freq(target_freq  + self.IF_freq, 0)
285
        
286
        if r:
287
            self.freq = target_freq
288
            self.myform['freq'].set_value(target_freq)         # update displayed value
289
            self.myform['freq_slider'].set_value(target_freq)  # update displayed value
290
            self.update_status_bar()
291
            self._set_status_msg("OK", 0)
292
            return True
293
294
        self._set_status_msg("Failed", 0)
295
        return False
296
297
    def set_gain(self, gain):
298
        self.myform['gain'].set_value(gain)     # update displayed value
299
        self.u.set_gain(gain)
300
301
    def update_status_bar (self):
302
        msg = "Volume:%r  Setting:%s" % (self.vol, self.state)
303
        self._set_status_msg(msg, 1)
304
        try:
305
          self.src_fft.set_baseband_freq(self.freq)
306
        except:
307
          None
308
          
309
    def volume_range(self):
310
        return (-40.0, 0.0, 0.5)
311
        
312
313
if __name__ == '__main__':
314
    app = stdgui2.stdapp (wfm_rx_block, "USRP Broadcast AM MW RX")
315
    app.MainLoop ()