Imported Upstream version 3.2.2
[debian/gnuradio] / gr-utils / src / python / usrp2_siggen.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2008,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, eng_notation, usrp2
24 from gnuradio.eng_option import eng_option
25 from optparse import OptionParser
26 import sys
27 import math
28
29 n2s = eng_notation.num_to_str
30
31 waveforms = { gr.GR_SIN_WAVE   : "Complex Sinusoid",
32               gr.GR_CONST_WAVE : "Constant",
33               gr.GR_GAUSSIAN   : "Gaussian Noise",
34               gr.GR_UNIFORM    : "Uniform Noise",
35               "2tone"          : "Two Tone",
36               "sweep"          : "Sweep" }
37
38 #
39 # GUI-unaware GNU Radio flowgraph.  This may be used either with command
40 # line applications or GUI applications.
41 #
42 class top_block(gr.top_block):
43     def __init__(self, options, args):
44         gr.top_block.__init__(self)
45         self._verbose = options.verbose
46
47         self._interp = 0 
48         self._gain = 0
49         self._freq = None       # Indicates frequency hasn't been successfully set yet
50         self._bb_freq = 0
51         self._ddc_freq = 0
52         self._amplitude = 0
53         self._type = None       # Indicates waveform flowgraph not created yet
54         self._offset = options.offset
55
56         self.set_usrp2(options.interface, options.mac_addr)
57         self.set_interp(options.interp)
58         self.set_gain(options.gain)
59         self.set_freq(options.tx_freq, options.lo_offset)
60         self.set_amplitude(options.amplitude)
61
62         self.set_waveform_freq(options.waveform_freq)
63         self.set_waveform2_freq(options.waveform2_freq)
64         self.set_waveform(options.type)
65
66     def set_usrp2(self, interface, mac_addr):
67         self._u = usrp2.sink_32fc(interface, mac_addr)
68         self._dac_rate = self._u.dac_rate()
69         if self._verbose:
70             print "Network interface:", interface
71             print "Network address:", self._u.mac_addr()
72             print "Daughterboard ID:", hex(self._u.daughterboard_id())
73
74     def set_interp(self, interp):
75         if interp < 4 or interp > 512: # FIXME get from flowgraph
76             if self._verbose: print "Interpolation rate out of range:", interp
77             return False
78
79         if not self._u.set_interp(interp):
80             raise RuntimeError("Failed to set interpolation rate %i" % (interp,))
81
82         self._interp = interp
83         self._eth_rate = self._dac_rate/self._interp
84         if self._verbose:
85             print "USRP2 interpolation rate:", self._interp
86             print "USRP2 IF bandwidth: %sHz" % (n2s(self._eth_rate),)
87
88         if (self._type == gr.GR_SIN_WAVE or 
89             self._type == gr.GR_CONST_WAVE):
90             self._src.set_sampling_freq(self._eth_rate)
91         elif self._type == "2tone":
92             self._src1.set_sampling_freq(self._eth_rate)
93             self._src1.set_sampling_freq(self._eth_rate)
94         elif self._type == "sweep":
95             self._src1.set_sampling_freq(self._eth_rate)
96             self._src1.set_sampling_freq(self._waveform_freq*2*math.pi/self._eth_rate)
97         else:
98             return True # Waveform not yet set
99         
100         if self._verbose: print "Set interpolation rate to:", interp
101         return True
102
103     def set_gain(self, gain):
104         if gain is None:
105             g = self._u.gain_range()
106             gain = float(g[0]+g[1])/2
107             if self._verbose:
108                 print "Using auto-calculated mid-point TX gain"
109         self._u.set_gain(gain)
110         self._gain = gain
111         if self._verbose:
112             print "Set TX gain to:", self._gain
113
114     def set_freq(self, target_freq, lo_offset=None):
115         if lo_offset is not None:
116             self._lo_offset = lo_offset
117             self._u.set_lo_offset(self._lo_offset)
118             if self._verbose:
119                 print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),)
120
121         if target_freq is None:
122             f = self._u.freq_range()
123             target_freq = float(f[0]+f[1])/2.0
124             if self._verbose:
125                 print "Using auto-calculated mid-point frequency"
126
127         tr = self._u.set_center_freq(target_freq)
128         fs = "%sHz" % (n2s(target_freq),)
129         if tr is not None:
130             self._freq = target_freq
131
132         else:
133             return True # Waveform not yet set
134         
135         if self._verbose: print "Set amplitude to:", amplitude
136         return True
137
138     def set_gain(self, gain):
139         if gain is None:
140             g = self._u.gain_range()
141             gain = float(g[0]+g[1])/2
142             if self._verbose:
143                 print "Using auto-calculated mid-point TX gain"
144         self._u.set_gain(gain)
145         self._gain = gain
146         if self._verbose:
147             print "Set TX gain to:", self._gain
148
149     def set_freq(self, target_freq, lo_offset=None):
150         if lo_offset is not None:
151             self._lo_offset = lo_offset
152             self._u.set_lo_offset(self._lo_offset)
153             if self._verbose:
154                 print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),)
155
156         if target_freq is None:
157             f = self._u.freq_range()
158             target_freq = float(f[0]+f[1])/2.0
159             if self._verbose:
160                 print "Using auto-calculated mid-point frequency"
161
162         tr = self._u.set_center_freq(target_freq)
163         fs = "%sHz" % (n2s(target_freq),)
164         if tr is not None:
165             self._freq = target_freq
166             self._ddc_freq = tr.dxc_freq
167             self._bb_freq = tr.baseband_freq
168             if self._verbose:
169                 print "Set center frequency to", fs
170                 print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),)
171                 print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),)
172                 print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),)
173                 
174         return tr
175
176     def set_waveform_freq(self, freq):
177         self._waveform_freq = freq
178         if self._type == gr.GR_SIN_WAVE:
179             self._src.set_frequency(freq)
180         elif self._type == "2tone" or self._type == "sweep":
181             self._src1.set_frequency(freq)
182         return True
183
184     def set_waveform2_freq(self, freq):
185         self._waveform2_freq = freq
186         if self._type == "2tone":
187             self._src2.set_frequency(freq)
188         elif self._type == "sweep":
189             self._src1.set_frequency(freq)
190         return True
191
192     def set_waveform(self, type):
193         self.lock()
194         self.disconnect_all()
195
196         if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE:
197             self._src = gr.sig_source_c(self._eth_rate,      # Sample rate
198                                         type,                # Waveform type
199                                         self._waveform_freq, # Waveform frequency
200                                         self._amplitude,     # Waveform amplitude
201                                         self._offset)        # Waveform offset
202         elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM:
203             self._src = gr.noise_source_c(type, self._amplitude)
204         elif type == "2tone":
205             self._src1 = gr.sig_source_c(self._eth_rate,
206                                          gr.GR_SIN_WAVE,
207                                          self._waveform_freq,
208                                          self._amplitude/2.0,
209                                          0)
210             if(self._waveform2_freq is None):
211                 self._waveform2_freq = -self._waveform_freq
212
213             self._src2 = gr.sig_source_c(self._eth_rate,
214                                          gr.GR_SIN_WAVE,
215                                          self._waveform2_freq,
216                                          self._amplitude/2.0,
217                                          0)
218             self._src = gr.add_cc()
219             self.connect(self._src1,(self._src,0))
220             self.connect(self._src2,(self._src,1))
221         elif type == "sweep":
222             # rf freq is center frequency
223             # waveform_freq is total swept width
224             # waveform2_freq is sweep rate
225             # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2)
226             if self._waveform2_freq is None:
227                 self._waveform2_freq = 0.1
228
229             self._src1 = gr.sig_source_f(self._eth_rate,
230                                          gr.GR_TRI_WAVE,
231                                          self._waveform2_freq,
232                                          1.0,
233                                          -0.5)
234             self._src2 = gr.frequency_modulator_fc(self._waveform_freq*2*math.pi/self._eth_rate)
235             self._src = gr.multiply_const_cc(self._amplitude)
236             self.connect(self._src1,self._src2,self._src)
237         else:
238             raise RuntimeError("Unknown waveform type")
239
240         self.connect(self._src, self._u)
241         self._type = type
242         self.unlock()
243
244         if self._verbose:
245             print "Set baseband modulation to:", waveforms[self._type]
246             if type == gr.GR_SIN_WAVE:
247                 print "Modulation frequency: %sHz" % (n2s(self._waveform_freq),)
248                 print "Initial phase:", self._offset
249             elif type == "2tone":
250                 print "Tone 1: %sHz" % (n2s(self._waveform_freq),)
251                 print "Tone 2: %sHz" % (n2s(self._waveform2_freq),)
252             elif type == "sweep":
253                 print "Sweeping across %sHz to %sHz" % (n2s(-self._waveform_freq/2.0),n2s(self._waveform_freq/2.0))
254                 print "Sweep rate: %sHz" % (n2s(self._waveform2_freq),)
255             print "TX amplitude:", self._amplitude
256
257
258     def set_amplitude(self, amplitude):
259         if amplitude < 0.0 or amplitude > 1.0:
260             if self._verbose: print "Amplitude out of range:", amplitude
261             return False
262
263         self._amplitude = amplitude
264
265         if (self._type == gr.GR_SIN_WAVE or 
266             self._type == gr.GR_CONST_WAVE or
267             self._type == gr.GR_GAUSSIAN or
268             self._type == gr.GR_UNIFORM):
269             self._src.set_amplitude(amplitude)
270         elif self._type == "2tone":
271             self._src1.set_amplitude(amplitude/2.0)
272             self._src2.set_amplitude(amplitude/2.0)
273         elif self._type == "sweep":
274             self._src.set_k(amplitude)
275         else:
276             return True # Waveform not yet set
277         
278         if self._verbose: print "Set amplitude to:", amplitude
279         return True
280
281
282     # Property getters
283
284     def mac_addr(self):
285         return self._u.mac_addr()
286
287     def interface_name(self):
288         return self._u.interface_name()
289
290     def daughterboard_id(self):
291         return self._u.daughterboard_id()
292
293     def interp_rate(self):
294         return self._interp
295
296     def eth_rate(self):
297         return self._eth_rate
298
299     def freq(self):
300         return self._freq
301
302     def freq_range(self):
303         return self._u.freq_range()
304
305     def ddc_freq(self):
306         return self._ddc_freq
307
308     def baseband_freq(self):
309         return self._bb_freq
310
311     def amplitude(self):
312         return self._amplitude
313
314     def waveform_type(self):
315         return self._type
316
317     def waveform_freq(self):
318         return self._waveform_freq
319
320     def waveform2_freq(self):
321         if self._waveform2_freq is None:
322             return -self._waveform_freq
323         else:
324             return self._waveform2_freq
325
326 def get_options():
327     usage="%prog: [options]"
328
329     parser = OptionParser(option_class=eng_option, usage=usage)
330
331     parser.add_option("-e", "--interface", type="string", default="eth0",
332                       help="Use specified Ethernet interface [default=%default]")
333     parser.add_option("-m", "--mac-addr", type="string", default="",
334                       help="Use USRP2 at specified MAC address [default=None]")  
335     parser.add_option("-i", "--interp", type="int", default=16, metavar="INTERP",
336                       help="Set FPGA interpolation rate of INTERP [default=%default]")
337     parser.add_option("-f", "--tx-freq", type="eng_float", default=None,
338                       help="Set carrier frequency to FREQ [default=mid-point]", metavar="FREQ")
339     parser.add_option("--lo-offset", type="eng_float", default=None,
340                       help="set daughterboard LO offset to OFFSET [default=hw default]")
341     parser.add_option("-g", "--gain", type="eng_float", default=None,
342                       help="Set TX gain to GAIN [default=mid-point]")
343     parser.add_option("-w", "--waveform-freq", type="eng_float", default=0,
344                       help="Set baseband waveform frequency to FREQ [default=%default]")
345     parser.add_option("-x", "--waveform2-freq", type="eng_float", default=None,
346                       help="Set 2nd waveform frequency to FREQ [default=%default]")
347     parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE,
348                       help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE)
349     parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, 
350                       help="Generate a constant carrier")
351     parser.add_option("--offset", type="eng_float", default=0,
352                       help="Set waveform phase offset to OFFSET [default=%default]")
353     parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN,
354                       help="Generate Gaussian random output")
355     parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM,
356                       help="Generate Uniform random output")
357     parser.add_option("--2tone", dest="type", action="store_const", const="2tone",
358                       help="Generate Two Tone signal for IMD testing")
359     parser.add_option("--sweep", dest="type", action="store_const", const="sweep",
360                       help="Generate a swept sine wave")
361     parser.add_option("-a", "--amplitude", type="eng_float", default=0.1,
362                       help="Set output amplitude to AMPL (0.0-1.0) [default=%default]", metavar="AMPL")
363     parser.add_option("-v", "--verbose", action="store_true", default=False,
364                       help="Use verbose console output [default=%default]")
365
366     (options, args) = parser.parse_args()
367
368     return (options, args)
369
370 # If this script is executed, the following runs. If it is imported, the below does not run.
371 if __name__ == "__main__":
372     if gr.enable_realtime_scheduling() != gr.RT_OK:
373         print "Note: failed to enable realtime scheduling, continuing"
374     
375     # Grab command line options and create top block
376     try:
377         (options, args) = get_options()
378         tb = top_block(options, args)
379
380     except RuntimeError, e:
381         print e
382         sys.exit(1)
383
384     # Run it
385     try:
386         tb.run()
387
388     except KeyboardInterrupt:
389         pass