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