diff options
Diffstat (limited to 'gr-utils/src/python/usrp2_siggen.py')
-rwxr-xr-x | gr-utils/src/python/usrp2_siggen.py | 439 |
1 files changed, 321 insertions, 118 deletions
diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py index 9cea2eff1e..71f12cf4af 100755 --- a/gr-utils/src/python/usrp2_siggen.py +++ b/gr-utils/src/python/usrp2_siggen.py @@ -20,8 +20,7 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr, eng_notation -from gnuradio import usrp2 +from gnuradio import gr, eng_notation, usrp2 from gnuradio.eng_option import eng_option from optparse import OptionParser import sys @@ -29,165 +28,369 @@ import math n2s = eng_notation.num_to_str -class siggen_top_block(gr.top_block): - def __init__(self, options): +waveforms = { gr.GR_SIN_WAVE : "Complex Sinusoid", + gr.GR_CONST_WAVE : "Constant", + gr.GR_GAUSSIAN : "Gaussian Noise", + gr.GR_UNIFORM : "Uniform Noise", + "2tone" : "Two Tone", + "sweep" : "Sweep" } + +# +# GUI-unaware GNU Radio flowgraph. This may be used either with command +# line applications or GUI applications. +# +class top_block(gr.top_block): + def __init__(self, options, args): gr.top_block.__init__(self) + self._verbose = options.verbose + + self._interp = 0 + self._gain = 0 + self._freq = None # Indicates frequency hasn't been successfully set yet + self._bb_freq = 0 + self._ddc_freq = 0 + self._amplitude = 0 + self._type = None # Indicates waveform flowgraph not created yet + self._offset = options.offset + + self.set_usrp2(options.interface, options.mac_addr) + self.set_interp(options.interp) + self.set_gain(options.gain) + self.set_freq(options.tx_freq, options.lo_offset) + self.set_amplitude(options.amplitude) + + self.set_waveform_freq(options.waveform_freq) + #self.set_waveform2_freq(options.waveform2_freq) + self._waveform2_freq = options.waveform2_freq + self.set_waveform(options.type) + + def set_usrp2(self, interface, mac_addr): + self._u = usrp2.sink_32fc(interface, mac_addr) + self._dac_rate = self._u.dac_rate() + if self._verbose: + print "Network interface:", interface + print "Network address:", self._u.mac_addr() + print "Daughterboard ID:", hex(self._u.daughterboard_id()) + + def set_interp(self, interp): + if interp < 4 or interp > 512: # FIXME get from flowgraph + if self._verbose: print "Interpolation rate out of range:", interp + return False + + if not self._u.set_interp(interp): + raise RuntimeError("Failed to set interpolation rate %i" % (interp,)) - # Create a USRP2 sink with the requested interpolation rate - self._u = usrp2.sink_32fc(options.interface, options.mac_addr) - self._u.set_interp(options.interp) + self._interp = interp + self._eth_rate = self._dac_rate/self._interp + if self._verbose: + print "USRP2 interpolation rate:", self._interp + print "USRP2 IF bandwidth: %sHz" % (n2s(self._eth_rate),) - # Set the Tx daughterboard gain as requested - if options.gain is None: + if (self._type == gr.GR_SIN_WAVE or + self._type == gr.GR_CONST_WAVE): + self._src.set_sampling_freq(self._eth_rate) + elif self._type == "2tone": + self._src1.set_sampling_freq(self._eth_rate) + self._src1.set_sampling_freq(self._eth_rate) + elif self._type == "sweep": + self._src1.set_sampling_freq(self._eth_rate) + self._src1.set_sampling_freq(self._waveform_freq*2*math.pi/self._eth_rate) + else: + return True # Waveform not yet set + + if self._verbose: print "Set interpolation rate to:", interp + return True + + def set_gain(self, gain): + if gain is None: g = self._u.gain_range() - options.gain = float(g[0]+g[1])/2 - self._u.set_gain(options.gain) + gain = float(g[0]+g[1])/2 + if self._verbose: + print "Using auto-calculated mid-point TX gain" + self._u.set_gain(gain) + self._gain = gain + if self._verbose: + print "Set TX gain to:", self._gain + + def set_freq(self, target_freq, lo_offset=None): + if lo_offset is not None: + self._lo_offset = lo_offset + self._u.set_lo_offset(self._lo_offset) + if self._verbose: + print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),) - # Tune the USRP2 FPGA and daughterboard to the requested center frequency - # and LO offset - if options.lo_offset is not None: - self._u.set_lo_offset(options.lo_offset) + if target_freq is None: + f = self._u.freq_range() + target_freq = float(f[0]+f[1])/2.0 + if self._verbose: + print "Using auto-calculated mid-point frequency" - tr = self._u.set_center_freq(options.tx_freq) - if tr == None: - sys.stderr.write('Failed to set center frequency\n') - raise SystemExit, 1 + tr = self._u.set_center_freq(target_freq) + fs = "%sHz" % (n2s(target_freq),) + if tr is not None: + self._freq = target_freq - eth_rate = self._u.dac_rate()/self._u.interp() + else: + return True # Waveform not yet set - # Create a source for the requested waveform type - if options.type == gr.GR_SIN_WAVE or options.type == gr.GR_CONST_WAVE: - self._src = gr.sig_source_c(eth_rate, # Sample rate - options.type, # Waveform type - options.waveform_freq, # Waveform frequency - options.amplitude, # Waveform amplitude - options.offset) # Waveform offset - - elif options.type == gr.GR_GAUSSIAN or options.type == gr.GR_UNIFORM: - self._src = gr.noise_source_c(options.type, options.amplitude) - elif options.type == "2tone": - self._src1 = gr.sig_source_c(eth_rate, + if self._verbose: print "Set amplitude to:", amplitude + return True + + def set_gain(self, gain): + if gain is None: + g = self._u.gain_range() + gain = float(g[0]+g[1])/2 + if self._verbose: + print "Using auto-calculated mid-point TX gain" + self._u.set_gain(gain) + self._gain = gain + if self._verbose: + print "Set TX gain to:", self._gain + + def set_freq(self, target_freq, lo_offset=None): + if lo_offset is not None: + self._lo_offset = lo_offset + self._u.set_lo_offset(self._lo_offset) + if self._verbose: + print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),) + + if target_freq is None: + f = self._u.freq_range() + target_freq = float(f[0]+f[1])/2.0 + if self._verbose: + print "Using auto-calculated mid-point frequency" + + tr = self._u.set_center_freq(target_freq) + fs = "%sHz" % (n2s(target_freq),) + if tr is not None: + self._freq = target_freq + self._ddc_freq = tr.dxc_freq + self._bb_freq = tr.baseband_freq + if self._verbose: + print "Set center frequency to", fs + print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),) + print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),) + print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),) + + return tr + + def set_waveform_freq(self, freq): + self._waveform_freq = freq + if self._type == gr.GR_SIN_WAVE: + self._src.set_frequency(freq) + elif self._type == "2tone" or self._type == "sweep": + self._src1.set_frequency(freq) + return True + + def set_waveform2_freq(self, freq): + self._waveform2_freq = freq + if self._type == "2tone": + self._src2.set_frequency(freq) + elif self._type == "sweep": + self._src1.set_frequency(freq) + return True + + def set_waveform(self, type): + self.lock() + self.disconnect_all() + + if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: + self._src = gr.sig_source_c(self._eth_rate, # Sample rate + type, # Waveform type + self._waveform_freq, # Waveform frequency + self._amplitude, # Waveform amplitude + self._offset) # Waveform offset + elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: + self._src = gr.noise_source_c(type, self._amplitude) + elif type == "2tone": + self._src1 = gr.sig_source_c(self._eth_rate, gr.GR_SIN_WAVE, - options.waveform_freq, - options.amplitude, + self._waveform_freq, + self._amplitude/2.0, 0) - if(options.waveform2_freq is None): - w2freq = -options.waveform_freq - else: - w2freq = options.waveform2_freq - self._src2 = gr.sig_source_c(eth_rate, + if(self._waveform2_freq is None): + self._waveform2_freq = -self._waveform_freq + + self._src2 = gr.sig_source_c(self._eth_rate, gr.GR_SIN_WAVE, - w2freq, - options.amplitude, + self._waveform2_freq, + self._amplitude/2.0, 0) self._src = gr.add_cc() self.connect(self._src1,(self._src,0)) self.connect(self._src2,(self._src,1)) - elif options.type == "sweep": + elif type == "sweep": # rf freq is center frequency # waveform_freq is total swept width # waveform2_freq is sweep rate - # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) - self._src1 = gr.sig_source_f(eth_rate, + # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) + if self._waveform2_freq is None: + self._waveform2_freq = 0.1 + + self._src1 = gr.sig_source_f(self._eth_rate, gr.GR_TRI_WAVE, - options.waveform2_freq, - 1.0, # options.waveform_freq, + self._waveform2_freq, + 1.0, -0.5) - self._src2 = gr.frequency_modulator_fc(options.waveform_freq*2*math.pi/eth_rate) - self._src = gr.multiply_const_cc(options.amplitude) + self._src2 = gr.frequency_modulator_fc(self._waveform_freq*2*math.pi/self._eth_rate) + self._src = gr.multiply_const_cc(self._amplitude) self.connect(self._src1,self._src2,self._src) else: - sys.stderr.write('Unknown waveform type\n') - raise SystemExit, 1 - - if options.verbose: - print "Network interface:", options.interface - print "USRP2 address:", self._u.mac_addr() - #print "Using TX d'board %s" % (self._u.tx_name(),) - print "Tx gain:", options.gain - print "Tx baseband frequency:", n2s(tr.baseband_freq), "Hz" - print "Tx DDC frequency:", n2s(tr.dxc_freq), "Hz" - print "Tx residual frequency:", n2s(tr.residual_freq), "Hz" - print "Tx interpolation rate:", options.interp - print "Tx GbE sample rate:", n2s(eth_rate), "samples/sec" - if options.type == gr.GR_SIN_WAVE: - print "Baseband waveform type: Sine wave" - print "Baseband waveform frequency:", n2s(options.waveform_freq), "Hz" - elif options.type == gr.GR_CONST_WAVE: - print "Baseband waveform type: Constant" - elif options.type == gr.GR_GAUSSIAN: - print "Baseband waveform type: Gaussian noise" - elif options.type == gr.GR_UNIFORM: - print "Baseband waveform type: Uniform noise" - - # Wire the flowgraph + raise RuntimeError("Unknown waveform type") + self.connect(self._src, self._u) - + self._type = type + self.unlock() + + if self._verbose: + print "Set baseband modulation to:", waveforms[self._type] + if type == gr.GR_SIN_WAVE: + print "Modulation frequency: %sHz" % (n2s(self._waveform_freq),) + print "Initial phase:", self._offset + elif type == "2tone": + print "Tone 1: %sHz" % (n2s(self._waveform_freq),) + print "Tone 2: %sHz" % (n2s(self._waveform2_freq),) + elif type == "sweep": + print "Sweeping across %sHz to %sHz" % (n2s(-self._waveform_freq/2.0),n2s(self._waveform_freq/2.0)) + print "Sweep rate: %sHz" % (n2s(self._waveform2_freq),) + print "TX amplitude:", self._amplitude + + + def set_amplitude(self, amplitude): + if amplitude < 0.0 or amplitude > 1.0: + if self._verbose: print "Amplitude out of range:", amplitude + return False + + self._amplitude = amplitude + + if (self._type == gr.GR_SIN_WAVE or + self._type == gr.GR_CONST_WAVE or + self._type == gr.GR_GAUSSIAN or + self._type == gr.GR_UNIFORM): + self._src.set_amplitude(amplitude) + elif self._type == "2tone": + self._src1.set_amplitude(amplitude/2.0) + self._src2.set_amplitude(amplitude/2.0) + elif self._type == "sweep": + self._src.set_k(amplitude) + else: + return True # Waveform not yet set + + if self._verbose: print "Set amplitude to:", amplitude + return True + + + # Property getters + + #def interface(self): + # return self._u.ifc_name() + + def mac_addr(self): + return self._u.mac_addr() + + def ifc_name(self): + return self._u.ifc_name() + + def daughterboard_id(self): + return self._u.daughterboard_id() + + def interp_rate(self): + return self._interp + + def eth_rate(self): + return self._eth_rate + + def freq(self): + return self._freq + + def freq_range(self): + fr = self._u.freq_range() + if self._u.daughterboard_id() == 0x0000: + fr = (-50e6, 50e6) # DEBUG + return fr + + def ddc_freq(self): + return self._ddc_freq + + def baseband_freq(self): + return self._bb_freq + + def amplitude(self): + return self._amplitude + + def waveform_type(self): + return self._type + + def waveform_freq(self): + return self._waveform_freq + + def waveform2_freq(self): + if self._waveform2_freq is None: + return -self._waveform_freq + else: + return self._waveform2_freq + def get_options(): usage="%prog: [options]" parser = OptionParser(option_class=eng_option, usage=usage) + parser.add_option("-e", "--interface", type="string", default="eth0", - help="use specified Ethernet interface [default=%default]") + help="Use specified Ethernet interface [default=%default]") parser.add_option("-m", "--mac-addr", type="string", default="", - help="use USRP2 at specified MAC address [default=None]") - parser.add_option("-i", "--interp", type="int", default=16, - help="set fgpa decimation rate to DECIM [default=%default]") - parser.add_option("-g", "--gain", type="eng_float", default=None, - help="set output gain to GAIN [default=%default]") + help="Use USRP2 at specified MAC address [default=None]") + parser.add_option("-i", "--interp", type="int", default=16, metavar="INTERP", + help="Set FPGA interpolation rate of INTERP [default=%default]") parser.add_option("-f", "--tx-freq", type="eng_float", default=None, - help="set frequency to FREQ", metavar="FREQ") - parser.add_option("-v", "--verbose", action="store_true", default=False, - help="verbose output") - parser.add_option("-w", "--waveform-freq", type="eng_float", default=0, - help="set waveform frequency to FREQ [default=%default]") - parser.add_option("-x", "--waveform2-freq", type="eng_float", default=None, - help="set waveform frequency to FREQ [default=%default]") - parser.add_option("-a", "--amplitude", type="eng_float", default=0.5, - help="set waveform amplitude to AMPLITUDE (0-1.0) [default=%default]", metavar="AMPL") - parser.add_option("--offset", type="eng_float", default=0, - help="set waveform offset to OFFSET [default=%default]") + help="Set carrier frequency to FREQ [default=mid-point]", metavar="FREQ") parser.add_option("--lo-offset", type="eng_float", default=None, help="set daughterboard LO offset to OFFSET [default=hw default]") + parser.add_option("-g", "--gain", type="eng_float", default=None, + help="Set TX gain to GAIN [default=mid-point]") + parser.add_option("-w", "--waveform-freq", type="eng_float", default=0, + help="Set baseband waveform frequency to FREQ [default=%default]") + parser.add_option("-x", "--waveform2-freq", type="eng_float", default=None, + help="Set 2nd waveform frequency to FREQ [default=%default]") parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, - help="generate a complex sinusoid [default]", default=gr.GR_SIN_WAVE) + help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE) parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, - help="generate a constant output") + help="Generate a constant carrier") + parser.add_option("--offset", type="eng_float", default=0, + help="Set waveform phase offset to OFFSET [default=%default]") parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, - help="generate Gaussian random output") + help="Generate Gaussian random output") parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, - help="generate Uniform random output") + help="Generate Uniform random output") parser.add_option("--2tone", dest="type", action="store_const", const="2tone", - help="generate Two Tone signal for IMD testing") + help="Generate Two Tone signal for IMD testing") parser.add_option("--sweep", dest="type", action="store_const", const="sweep", - help="generate a swept sine wave") - - (options, args) = parser.parse_args () - if len(args) != 0: - parser.print_help() - raise SystemExit, 1 - - if options.tx_freq is None: - parser.print_help() - sys.stderr.write('You must specify the frequency with -f FREQ\n'); - raise SystemExit, 1 - - return options + help="Generate a swept sine wave") + parser.add_option("-a", "--amplitude", type="eng_float", default=0.1, + help="Set output amplitude to AMPL (0.0-1.0) [default=%default]", metavar="AMPL") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="Use verbose console output [default=%default]") + (options, args) = parser.parse_args() -if __name__ == '__main__': - options = get_options() - tb = siggen_top_block(options) + return (options, args) + +# If this script is executed, the following runs. If it is imported, the below does not run. +if __name__ == "__main__": + if gr.enable_realtime_scheduling() != gr.RT_OK: + print "Note: failed to enable realtime scheduling, continuing" - # Attempt to enable realtime scheduling - r = gr.enable_realtime_scheduling() - if r == gr.RT_OK: - realtime = True - else: - realtime = False - print "Note: failed to enable realtime scheduling" + # Grab command line options and create top block + try: + (options, args) = get_options() + tb = top_block(options, args) + except RuntimeError, e: + print e + sys.exit(1) + + # Run it try: tb.run() + except KeyboardInterrupt: pass |