diff options
Diffstat (limited to 'gr-utils')
-rw-r--r-- | gr-utils/src/python/Makefile.am | 6 | ||||
-rwxr-xr-x | gr-utils/src/python/gr_plot_qt.py | 212 | ||||
-rw-r--r-- | gr-utils/src/python/pyqt_plot.py | 2 | ||||
-rwxr-xr-x | gr-utils/src/python/qr_fft.py | 505 | ||||
-rwxr-xr-x | gr-utils/src/python/usrp2_siggen.py | 389 | ||||
-rwxr-xr-x | gr-utils/src/python/usrp2_siggen_gui.py | 275 | ||||
-rwxr-xr-x | gr-utils/src/python/usrp_siggen.py | 471 | ||||
-rwxr-xr-x | gr-utils/src/python/usrp_siggen_gui.py | 310 |
8 files changed, 747 insertions, 1423 deletions
diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 59ca215a7..fb21e4f44 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -50,17 +50,15 @@ bin_SCRIPTS = \ gr_plot_qt.py \ gr_filter_design.py \ lsusrp \ - qr_fft.py \ usrp_fft.py \ usrp_oscope.py \ usrp_print_db.py \ usrp_rx_cfile.py \ usrp_rx_nogui.py \ usrp_siggen.py \ + usrp_siggen_gui.py \ usrp_test_counting.py \ usrp_test_loopback.py \ usrp2_fft.py \ - usrp2_rx_cfile.py \ - usrp2_siggen.py \ - usrp2_siggen_gui.py + usrp2_rx_cfile.py diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index 5e2b3065c..f3dc472f5 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -7,14 +7,36 @@ except ImportError: print "Please install SciPy to run this script (http://www.scipy.org/)" raise SystemExit, 1 +try: + from matplotlib import mlab +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net)" + raise SystemExit, 1 + +try: + from PyQt4 import Qt, QtCore, QtGui +except ImportError: + print "Please install PyQt4 to run this script (http://www.riverbankcomputing.co.uk/software/pyqt/download)" + raise SystemExit, 1 + +try: + import PyQt4.Qwt5 as Qwt +except ImportError: + print "Please install PyQwt5 to run this script (http://pyqwt.sourceforge.net/)" + raise SystemExit, 1 + +try: + # FIXME: reenable this before committing + #from gnuradio.pyqt_plot import Ui_MainWindow + from pyqt_plot import Ui_MainWindow +except ImportError: + print "Could not import from pyqt_plot. Please build with \"pyuic4 pyqt_plot.ui -o pyqt_plot.py\"" + raise SystemExit, 1 + import sys, os -from PyQt4 import Qt, QtCore, QtGui -import PyQt4.Qwt5 as Qwt -from matplotlib import mlab from optparse import OptionParser from gnuradio import eng_notation -from pyqt_plot import Ui_MainWindow class SpectrogramData(Qwt.QwtRasterData): @@ -42,9 +64,12 @@ class SpectrogramData(Qwt.QwtRasterData): return Qwt.QwtDoubleInterval(self.sp.min(), self.sp.max()) def value(self, x, y): - f = int(self.freq.searchsorted(x)) - t = int(self.time.searchsorted(y)) - return self.sp[f][t-1] + try: + f = int(self.freq.searchsorted(x)) + t = int(self.time.searchsorted(y)) + return self.sp[f][t-1] + except AttributeError: # if no file loaded yet + return 0 class gr_plot_qt(QtGui.QMainWindow): @@ -53,6 +78,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui = Ui_MainWindow() self.gui.setupUi(self) + self.filename = None self.block_length = options.block_length self.start = options.start self.sample_rate = options.sample_rate @@ -61,6 +87,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.winfunc = scipy.blackman self.sizeof_data = 8 self.datatype = scipy.complex64 + self.pen_width = 1 self.iq = list() self.time = list() @@ -102,6 +129,18 @@ class gr_plot_qt(QtGui.QMainWindow): self.colorComboBoxEdit) + # Set up line style combo box + self.line_styles = {"None" : Qwt.QwtSymbol.NoSymbol, + "Circle" : Qwt.QwtSymbol.Ellipse, + "Diamond" : Qwt.QwtSymbol.Rect, + "Triangle" : Qwt.QwtSymbol.Triangle} + self.gui.lineStyleComboBox.addItems(self.line_styles.keys()) + pos = self.gui.lineStyleComboBox.findText("None") + self.gui.lineStyleComboBox.setCurrentIndex(pos) + self.connect(self.gui.lineStyleComboBox, + Qt.SIGNAL("activated (const QString&)"), + self.lineStyleComboBoxEdit) + # Create zoom functionality for the plots self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom, self.gui.timePlot.yLeft, @@ -121,16 +160,6 @@ class gr_plot_qt(QtGui.QMainWindow): Qwt.QwtPicker.AlwaysOn, self.gui.specPlot.canvas()) - self.picker = Qwt.QwtPlotPicker(self.gui.timePlot.xBottom, - self.gui.timePlot.yLeft, - Qwt.QwtPicker.PointSelection, - Qwt.QwtPlotPicker.CrossRubberBand, - Qwt.QwtPicker.AlwaysOn, - self.gui.timePlot.canvas()) - self.picker.connect(self.picker, - Qt.SIGNAL('selected(const QwtDoublePoint&)'), - self.clickMe) - # Set up action when tab is changed self.connect(self.gui.tabGroup, Qt.SIGNAL("currentChanged (int)"), @@ -153,10 +182,13 @@ class gr_plot_qt(QtGui.QMainWindow): self.connect(self.gui.action_open, Qt.SIGNAL("activated()"), self.open_file) - + + # Connect Reload action to reload the file self.connect(self.gui.action_reload, Qt.SIGNAL("activated()"), - self.reload_file) + self.reload_file) + self.gui.action_reload.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+R", + None, QtGui.QApplication.UnicodeUTF8)) # Set up file position boxes to update current figure self.connect(self.gui.filePosStartLineEdit, @@ -179,8 +211,20 @@ class gr_plot_qt(QtGui.QMainWindow): Qt.SIGNAL("editingFinished()"), self.file_time_length_changed) + stylestr = str(self.gui.lineStyleComboBox.currentText().toAscii()) + style = self.line_styles[stylestr] + self.rcurve = Qwt.QwtPlotCurve("Real") self.icurve = Qwt.QwtPlotCurve("Imaginary") + self.rsym = Qwt.QwtSymbol() + self.rsym.setStyle(style) + self.rsym.setSize(10) + self.isym = Qwt.QwtSymbol() + self.isym.setStyle(style) + self.isym.setSize(10) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + self.icurve.attach(self.gui.timePlot) self.rcurve.attach(self.gui.timePlot) @@ -212,6 +256,20 @@ class gr_plot_qt(QtGui.QMainWindow): # Set up initial color scheme self.color_modes["Blue on Black"]() + # When line width spin box changes, update the pen size + self.connect(self.gui.lineWidthSpinBox, + Qt.SIGNAL("valueChanged(int)"), + self.change_pen_width) + self.gui.lineWidthSpinBox.setRange(1, 10) + + # When style size spin box changes, update the pen size + self.connect(self.gui.styleSizeSpinBox, + Qt.SIGNAL("valueChanged(int)"), + self.change_style_size) + self.gui.styleSizeSpinBox.setRange(1, 20) + self.gui.styleSizeSpinBox.setValue(5) + + # Connect a signal for when the sample rate changes self.set_sample_rate(self.sample_rate) self.connect(self.gui.sampleRateLineEdit, @@ -226,12 +284,13 @@ class gr_plot_qt(QtGui.QMainWindow): def open_file(self): filename = Qt.QFileDialog.getOpenFileName(self, "Open", ".") if(filename != ""): - print filename + #print filename self.initialize(filename) def reload_file(self): - initialize(self.filename) - + if(self.filename): + self.initialize(self.filename) + def initialize(self, filename): self.filename = filename self.hfile = open(filename, "r") @@ -251,7 +310,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.get_psd() self.get_specgram() self.gui.plotHBar.setSliderPosition(0) - self.gui.plotHBar.setMaximum(self.signal_size) + self.gui.plotHBar.setMaximum(self.signal_size-self.block_length) self.update_time_curves() @@ -261,7 +320,7 @@ class gr_plot_qt(QtGui.QMainWindow): def init_data_input(self): self.hfile.seek(0, os.SEEK_END) self.signal_size = self.hfile.tell()/self.sizeof_data - print "Sizeof File: ", self.signal_size + #print "Sizeof File: ", self.signal_size self.hfile.seek(0, os.SEEK_SET) def get_data(self, start, end): @@ -273,10 +332,8 @@ class gr_plot_qt(QtGui.QMainWindow): count=end-start) if(len(iq) < (end-start)): - end = len(iq) - self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(end)) - self.gui.plotHBar.setMaximum(end) - self.gui.plotHBar.setSingleStep(end) + end = start + len(iq) + self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(len(iq))) self.file_length_changed() tstep = 1.0 / self.sample_rate @@ -313,9 +370,6 @@ class gr_plot_qt(QtGui.QMainWindow): self.spec_f = f self.spec_t = t - def clickMe(self, qPoint): - print qPoint.x() - def psdFFTComboBoxEdit(self, fftSize): self.psdfftsize = fftSize.toInt()[0] self.get_psd() @@ -331,6 +385,14 @@ class gr_plot_qt(QtGui.QMainWindow): color_func = self.color_modes[colorstr] color_func() + def lineStyleComboBoxEdit(self, styleSelection): + stylestr = str(styleSelection.toAscii()) + self.rsym.setStyle(self.line_styles[stylestr]) + self.isym.setStyle(self.line_styles[stylestr]) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + self.gui.timePlot.replot() + def sliderMoved(self, value): pos_start = value pos_end = value + self.gui.plotHBar.pageStep() @@ -390,7 +452,11 @@ class gr_plot_qt(QtGui.QMainWindow): # If there's a non-digit character, reset box else: - self.set_file_pos_box(self.cur_start, self.cur_stop) + try: + self.set_file_pos_box(self.cur_start, self.cur_stop) + except AttributeError: + pass + def file_time_changed(self): tstart = self.gui.fileTimeStartLineEdit.text().toDouble() @@ -525,25 +591,40 @@ class gr_plot_qt(QtGui.QMainWindow): def tabChanged(self, index): self.gui.timePlot.replot() self.gui.freqPlot.replot() + self.gui.specPlot.replot() + + def change_pen_width(self, width): + self.pen_width = width + colormode = str(self.gui.colorComboBox.currentText().toAscii()) + color_func = self.color_modes[colormode]() + def change_style_size(self, size): + self.rsym.setSize(size) + self.isym.setSize(size) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + self.gui.timePlot.replot() + def color_black_on_white(self): blue = QtGui.qRgb(0x00, 0x00, 0xFF) red = QtGui.qRgb(0xFF, 0x00, 0x00) - blackBrush = Qt.QBrush(Qt.QColor("black")) - blueBrush = Qt.QBrush(Qt.QColor(blue)) - redBrush = Qt.QBrush(Qt.QColor(red)) + blackPen = Qt.QPen(Qt.QBrush(Qt.QColor("black")), self.pen_width) + bluePen = Qt.QPen(Qt.QBrush(Qt.QColor(blue)), self.pen_width) + redPen = Qt.QPen(Qt.QBrush(Qt.QColor(red)), self.pen_width) self.gui.timePlot.setCanvasBackground(Qt.QColor("white")) self.gui.freqPlot.setCanvasBackground(Qt.QColor("white")) - self.picker.setTrackerPen(Qt.QPen(blackBrush, 2)) - self.timeZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(blackBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(blackBrush, 2)) - self.psdcurve.setPen(Qt.QPen(blueBrush, 1)) - self.rcurve.setPen(Qt.QPen(blueBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(blackPen) + self.timeZoomer.setRubberBandPen(blackPen) + self.freqZoomer.setTrackerPen(blackPen) + self.freqZoomer.setRubberBandPen(blackPen) + self.psdcurve.setPen(bluePen) + self.rcurve.setPen(bluePen) + self.icurve.setPen(redPen) + + self.rsym.setPen(bluePen) + self.isym.setPen(redPen) self.gui.timePlot.replot() self.gui.freqPlot.replot() @@ -558,14 +639,13 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.psdcurve.setPen(Qt.QPen(whiteBrush, 1)) - self.rcurve.setPen(Qt.QPen(whiteBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(whiteBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(whiteBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) self.gui.timePlot.replot() self.gui.freqPlot.replot() @@ -581,14 +661,13 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.psdcurve.setPen(Qt.QPen(greenBrush, 1)) - self.rcurve.setPen(Qt.QPen(greenBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(greenBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(greenBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) self.gui.timePlot.replot() self.gui.freqPlot.replot() @@ -603,14 +682,13 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.psdcurve.setPen(Qt.QPen(blueBrush, 1)) - self.rcurve.setPen(Qt.QPen(blueBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(blueBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(blueBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) self.gui.timePlot.replot() self.gui.freqPlot.replot() diff --git a/gr-utils/src/python/pyqt_plot.py b/gr-utils/src/python/pyqt_plot.py index 3b8b4c9e8..5650135ab 100644 --- a/gr-utils/src/python/pyqt_plot.py +++ b/gr-utils/src/python/pyqt_plot.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_plot.ui' # -# Created: Mon Aug 31 22:12:05 2009 +# Created: Tue Oct 6 10:39:58 2009 # by: PyQt4 UI code generator 4.4.4 # # WARNING! All changes made in this file will be lost! diff --git a/gr-utils/src/python/qr_fft.py b/gr-utils/src/python/qr_fft.py deleted file mode 100755 index c2f06d715..000000000 --- a/gr-utils/src/python/qr_fft.py +++ /dev/null @@ -1,505 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004,2005,2007,2008,2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -from gnuradio.wxgui import forms -from gnuradio import gr, gru -from gnuradio import vrt -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider -from gnuradio.gr import pubsub -from optparse import OptionParser -import wx -import sys -import numpy -import time - -class app_top_block(stdgui2.std_top_block, pubsub.pubsub): - def __init__(self, frame, panel, vbox, argv): - stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) - pubsub.pubsub.__init__(self) - self.frame = frame - self.panel = panel - - parser = OptionParser(option_class=eng_option) - #parser.add_option("-e", "--interface", type="string", default="eth0", - # help="select Ethernet interface, default is eth0") - #parser.add_option("-m", "--mac-addr", type="string", default="", - # help="select USRP by MAC address, default is auto-select") - #parser.add_option("-A", "--antenna", default=None, - # help="select Rx Antenna (only on RFX-series boards)") - #parser.add_option("-d", "--decim", type="int", default=16, - # help="set fgpa decimation rate to DECIM [default=%default]") - #parser.add_option("-f", "--freq", type="eng_float", default=None, - # help="set frequency to FREQ", metavar="FREQ") - #parser.add_option("-g", "--gain", type="eng_float", default=None, - # help="set gain in dB (default is midpoint)") - parser.add_option("-W", "--waterfall", action="store_true", default=False, - help="Enable waterfall display") - parser.add_option("-S", "--oscilloscope", action="store_true", default=False, - help="Enable oscilloscope display") - parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, - help="Set fftsink averaging factor, default=[%default]") - parser.add_option("", "--ref-scale", type="eng_float", default=1.0, - help="Set dBFS=0dB input value, default=[%default]") - parser.add_option("--fft-size", type="int", default=1024, - help="Set number of FFT bins [default=%default]") - parser.add_option("--samples-per-pkt", type="int", default=0, - help="Set number of SAMPLES-PER-PKT [default=%default]") - parser.add_option("", "--ip-addr", type="string", default="192.168.10.2", - help="IP address default=[%default]") - (options, args) = parser.parse_args() - if len(args) != 0: - parser.print_help() - sys.exit(1) - self.options = options - self.show_debug_info = True - - self.u = vrt.quadradio_source_32fc(options.ip_addr, - int(62.5e6), options.samples_per_pkt) - #self.u.set_decim(options.decim) - - #input_rate = self.u.adc_rate() / self.u.decim() - input_rate = int(120e6/4) - - if options.waterfall: - self.scope = \ - waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) - elif options.oscilloscope: - self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) - else: - self.scope = fftsink2.fft_sink_c (panel, - fft_size=options.fft_size, - sample_rate=input_rate, - ref_scale=options.ref_scale, - ref_level=20.0, - y_divs = 12, - avg_alpha=options.avg_alpha) - - self.connect(self.u, self.scope) - - self._build_gui(vbox) - self._setup_events() - - # set initial values - - #if options.gain is None: - # # if no gain was specified, use the mid-point in dB - # g = self.u.gain_range() - # options.gain = float(g[0]+g[1])/2 - - #if options.freq is None: - # # if no freq was specified, use the mid-point - # r = self.u.freq_range() - # options.freq = float(r[0]+r[1])/2 - - #self.set_gain(options.gain) - - #if options.antenna is not None: - # print "Selecting antenna %s" % (options.antenna,) - # self.subdev.select_rx_antenna(options.antenna) - - if self.show_debug_info: - # self.myform['decim'].set_value(self.u.decim()) - self.myform['fs@gbe'].set_value(input_rate) - # self.myform['dbname'].set_value("0x%04X" % (self.u.daughterboard_id(),)) # FIXME: add text name - self.myform['baseband'].set_value(0) - self.myform['ddc'].set_value(0) - - #if not(self.set_freq(options.freq)): - # self._set_status_msg("Failed to set initial frequency") - - def _set_status_msg(self, msg): - self.frame.GetStatusBar().SetStatusText(msg, 0) - - def _build_gui(self, vbox): - - def _form_set_freq(kv): - return self.set_freq(kv['freq']) - - vbox.Add(self.scope.win, 10, wx.EXPAND) - - # add control area at the bottom - self.myform = myform = form.form() - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,0), 0, 0) - myform['freq'] = form.float_field( - parent=self.panel, sizer=hbox, label="Center freq", weight=1, - callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg)) - - hbox.Add((5,0), 0, 0) - #g = self.u.gain_range() - - # some configurations don't have gain control - if 0 and g[1] > g[0]: - myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", - weight=3, - min=int(g[0]), max=int(g[1]), - callback=self.set_gain) - - hbox.Add((5,0), 0, 0) - vbox.Add(hbox, 0, wx.EXPAND) - - self._build_subpanel(vbox) - - def _build_subpanel(self, vbox_arg): - # build a secondary information panel (sometimes hidden) - - # FIXME figure out how to have this be a subpanel that is always - # created, but has its visibility controlled by foo.Show(True/False) - - def _form_set_decim(kv): - return self.set_decim(kv['decim']) - - if not(self.show_debug_info): - return - - panel = self.panel - vbox = vbox_arg - myform = self.myform - - #panel = wx.Panel(self.panel, -1) - #vbox = wx.BoxSizer(wx.VERTICAL) - - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,0), 0) - - myform['decim'] = form.int_field( - parent=panel, sizer=hbox, label="Decim", - callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) - - hbox.Add((5,0), 1) - myform['fs@gbe'] = form.static_float_field( - parent=panel, sizer=hbox, label="Fs@GbE") - - hbox.Add((5,0), 1) - myform['dbname'] = form.static_text_field( - parent=panel, sizer=hbox) - - hbox.Add((5,0), 1) - myform['baseband'] = form.static_float_field( - parent=panel, sizer=hbox, label="Analog BB") - - hbox.Add((5,0), 1) - myform['ddc'] = form.static_float_field( - parent=panel, sizer=hbox, label="DDC") - - hbox.Add((5,0), 0) - vbox.Add(hbox, 0, wx.EXPAND) - ##### db control stuff ##### - self.subscribe('cal_div_lo_freq', lambda x: self.u.set_lo_freq(x) and time.sleep(0.01)) - self.subscribe('cal_div_lo_freq', self.u.set_center_freq) #TODO should be combined with set lo freq - self.subscribe('cal_div_cal_freq', lambda x: self.u.set_cal_freq(x) and time.sleep(0.01)) - self.subscribe('db_ctrl_atten0', self.u.set_attenuation0) - self.subscribe('db_ctrl_atten1', self.u.set_attenuation1) - self.subscribe('sys_beaming', self.u.set_beamforming) - #self.subscribe('db_ctrl_10db', self.u.set_10dB_atten) - self.subscribe('db_ctrl_adcgain', self.u.set_adc_gain) - self.subscribe('db_ctrl_diggain', self.u.set_digital_gain) - self.subscribe('db_ctrl_dcoffset', self.u.set_dc_offset_comp) - self.subscribe('db_ctrl_bandsel', self.u.set_band_select) - self.subscribe('db_ctrl_type', self.u.select_rx_antenna) - self.subscribe('db_test_signal', self.u.set_test_signal) - self['db_ctrl_bandsel'] = 'A' - self['cal_div_lo_freq'] = 2.1e9 - self['cal_div_cal_freq'] = 2.102e9 - self['db_ctrl_atten0'] = 0 - self['db_ctrl_atten1'] = 0 - #self['db_ctrl_10db'] = False - self['db_ctrl_adcgain'] = False - self['db_ctrl_dcoffset'] = False - self['db_ctrl_diggain'] = 0.0 - self['db_ctrl_type'] = 'rf' - self['db_test_signal'] = vrt.VRT_TEST_SIG_NORMAL - self['sys_beaming'] = [16.7e6, 0, 0, 0] - #slider and box for freqs - for key, name in (('cal_div_lo_freq', 'LO Freq'), ('cal_div_cal_freq', 'Cal Freq')): - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.AddSpacer(10) - forms.text_box( - label=name, - ps=self, - key=key, - sizer=hbox, - parent=panel, - proportion=0, - converter=forms.float_converter() - ) - hbox.AddSpacer(20) - forms.slider( - ps=self, - key=key, - minimum=0, #TODO get bounds from cal_div, from vrt... - maximum=int(3.5e9), - step_size=int(5e6), - cast=float, - sizer=hbox, - parent=panel, - proportion=2, - ) - hbox.AddSpacer(10) - vbox.Add(hbox, 0, wx.EXPAND) - ############################################ - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.AddSpacer(10) - #create slider for atten - atten0_txt_box = forms.static_text( - label='Attenuation (0)', - ps=self, - key='db_ctrl_atten0', - sizer=hbox, - parent=panel, - proportion=0, - converter=forms.int_converter() - ) - hbox.AddSpacer(20) - atten0_slider = forms.slider( - ps=self, - key='db_ctrl_atten0', - minimum=0, - maximum=31, - step_size=1, - cast=int, - sizer=hbox, - parent=panel, - proportion=2, - ) - hbox.AddSpacer(10) - #create slider for atten - forms.static_text( - label='Attenuation (1)', - ps=self, - key='db_ctrl_atten1', - sizer=hbox, - parent=panel, - proportion=0, - converter=forms.int_converter() - ) - hbox.AddSpacer(20) - forms.slider( - ps=self, - key='db_ctrl_atten1', - minimum=0, - maximum=31, - step_size=1, - cast=int, - sizer=hbox, - parent=panel, - proportion=2, - ) - hbox.AddSpacer(10) - def update_atten0(*args): - for form_obj in (atten0_txt_box, atten0_slider): form_obj.Enable(self['db_ctrl_bandsel'] > 'B') - update_atten0() - self.subscribe('db_ctrl_bandsel', update_atten0) - #create checkbox for 10dB att - #forms.check_box( - # label='10dB Attenuation', - # ps=self, - # key='db_ctrl_10db', - # sizer=hbox, - # parent=panel, - # proportion=1, - #) - #hbox.AddSpacer(10) - vbox.Add(hbox, 0, wx.EXPAND) - hbox2 = wx.BoxSizer(wx.HORIZONTAL) - hbox2.AddSpacer(10) - forms.static_text( - label='ADC Controls', - ps=self, - key='db_ctrl_diggain', - sizer=hbox2, - parent=panel, - proportion=0, - converter=forms.float_converter() - ) - hbox2.AddSpacer(20) - #create checkbox for ADC digital gain - forms.slider( - #label='ADC Digital Gain', - ps=self, - minimum=0, - maximum=6, - step_size=0.5, - key='db_ctrl_diggain', - sizer=hbox2, - parent=panel, - proportion=2, - ) - hbox2.AddSpacer(10) - #create checkbox for 3.5dB ADC gain - forms.check_box( - label='3.5dB ADC Gain', - ps=self, - key='db_ctrl_adcgain', - sizer=hbox2, - parent=panel, - proportion=1, - ) - hbox2.AddSpacer(10) - #create checkbox for DC Offset Correction in ADC - forms.check_box( - label='DC Offset Correction', - ps=self, - key='db_ctrl_dcoffset', - sizer=hbox2, - parent=panel, - proportion=2, - ) - hbox2.AddSpacer(10) - vbox.Add(hbox2, 0, wx.EXPAND) - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.AddSpacer(10) - #create radio buttons for band sel - forms.radio_buttons( - label='Band Select', - ps=self, - key='db_ctrl_bandsel', - choices=['A', 'B', 'C', 'D'], - labels=['A', 'B', 'C', 'D'], - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - forms.radio_buttons( - label='RF Input', - ps=self, - key='db_ctrl_type', - choices=['rf', 'cal'], - labels=['Main RF', 'Calibrator'], - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - #create radio buttons for band sel - types = sorted( - filter(lambda x: x.startswith('VRT_TEST_SIG_'), dir(vrt)), - lambda x, y: cmp(getattr(vrt, x), getattr(vrt, y)), - ) - forms.drop_down( - label='Test Signal', - ps=self, - key='db_test_signal', - choices=map(lambda a: getattr(vrt, a), types), - labels=types, - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - #create radio buttons for type - forms.drop_down( - label='Beamformer', - ps=self, - key='sys_beaming', - choices=[[16.7e6, 0, 0, 0], [0, 16.7e6, 0, 0], [0, 0, 16.7e6, 0], [0, 0, 0, 16.7e6], [4.19e6]*4], - labels=['Ant0', 'Ant1', 'Ant2', 'Ant3', 'Equal Gain'], - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - vbox.Add(hbox, 0, wx.EXPAND) - - def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. - - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital down converter. - """ - return True - - r = self.u.set_center_freq(target_freq) - - if r: - self.myform['freq'].set_value(target_freq) # update displayed value - if self.show_debug_info: - self.myform['baseband'].set_value(r.baseband_freq) - self.myform['ddc'].set_value(r.dxc_freq) - if not self.options.oscilloscope: - self.scope.win.set_baseband_freq(target_freq) - return True - - return False - - def set_gain(self, gain): - return True - - if self.myform.has_key('gain'): - self.myform['gain'].set_value(gain) # update displayed value - self.u.set_gain(gain) - - def set_decim(self, decim): - return True - - ok = self.u.set_decim(decim) - if not ok: - print "set_decim failed" - #input_rate = self.u.adc_rate() / self.u.decim() - input_rate = 120e6/4 - self.scope.set_sample_rate(input_rate) - if self.show_debug_info: # update displayed values - self.myform['decim'].set_value(self.u.decim()) - self.myform['fs@gbe'].set_value(input_rate) - return ok - - def _setup_events(self): - if not self.options.waterfall and not self.options.oscilloscope: - self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick) - - def evt_left_dclick(self, event): - (ux, uy) = self.scope.win.GetXY(event) - if event.CmdDown(): - # Re-center on maximum power - points = self.scope.win._points - if self.scope.win.peak_hold: - if self.scope.win.peak_vals is not None: - ind = numpy.argmax(self.scope.win.peak_vals) - else: - ind = int(points.shape()[0]/2) - else: - ind = numpy.argmax(points[:,1]) - (freq, pwr) = points[ind] - target_freq = freq/self.scope.win._scale_factor - print ind, freq, pwr - self.set_freq(target_freq) - else: - # Re-center on clicked frequency - target_freq = ux/self.scope.win._scale_factor - self.set_freq(target_freq) - - -def main (): - app = stdgui2.stdapp(app_top_block, "QuadRadio FFT", nstatus=1) - app.MainLoop() - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py deleted file mode 100755 index 9ade933c7..000000000 --- a/gr-utils/src/python/usrp2_siggen.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008,2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -from gnuradio import gr, eng_notation, usrp2 -from gnuradio.eng_option import eng_option -from optparse import OptionParser -import sys -import math - -n2s = eng_notation.num_to_str - -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.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,)) - - 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),) - - 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() - 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 - - else: - return True # Waveform not yet set - - 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, - self._waveform_freq, - self._amplitude/2.0, - 0) - 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, - 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 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) - if self._waveform2_freq is None: - self._waveform2_freq = 0.1 - - self._src1 = gr.sig_source_f(self._eth_rate, - gr.GR_TRI_WAVE, - self._waveform2_freq, - 1.0, - -0.5) - 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: - 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 mac_addr(self): - return self._u.mac_addr() - - def interface_name(self): - return self._u.interface_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): - return self._u.freq_range() - - 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]") - 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, metavar="INTERP", - help="Set FPGA interpolation rate of INTERP [default=%default]") - parser.add_option("-f", "--tx-freq", type="eng_float", default=None, - 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 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 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") - parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, - help="Generate Uniform random output") - parser.add_option("--2tone", dest="type", action="store_const", const="2tone", - 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") - 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() - - 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" - - # 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 diff --git a/gr-utils/src/python/usrp2_siggen_gui.py b/gr-utils/src/python/usrp2_siggen_gui.py deleted file mode 100755 index 89bc6e589..000000000 --- a/gr-utils/src/python/usrp2_siggen_gui.py +++ /dev/null @@ -1,275 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -import wx -from gnuradio.wxgui import form, slider, gui -import usrp2_siggen -import sys, math - -class app_gui(object): - def __init__(self, frame, panel, vbox, top_block, options, args): - self.frame = frame # Use for top-level application window frame - self.panel = panel # Use as parent class for created windows - self.vbox = vbox # Use as sizer for created windows - self.tb = top_block # GUI-unaware flowgraph class - self.options = options # Supplied command-line options - self.args = args # Supplied command-line arguments - - freq_range = self.tb.freq_range() - self.min_freq = freq_range[0] - self.max_freq = freq_range[1] - self.freq_step = (self.max_freq-self.min_freq)/100.0 - self._types = dict([v, k] for k, v in usrp2_siggen.waveforms.items()) - - self.build_gui() - - # TODO: turn these into listeners - self.myform['ifc'].set_value(self.tb.interface_name()) - self.myform['mac'].set_value(self.tb.mac_addr()) - dbid = self.tb.daughterboard_id() - self.myform['dbid'].set_value("%04x" % (dbid,)) - - w = usrp2_siggen.waveforms[self.tb.waveform_type()] - self.myform['type'].set_value(w) - self.myform['w1freq'].set_value(self.tb.waveform_freq()) - self.myform['w2freq'].set_value(self.tb.waveform2_freq()) - - freq = self.tb.freq() - if freq is None: - self.evt_set_status_msg("Failed to set initial frequency") - else: - self.myform['freq'].set_value(freq) - self.myform['freq_slider'].set_value(self.tb.freq()) - - amp = self.tb.amplitude() - if (amp > 0.0): - db = 20*math.log10(amp) - else: - db = -100.0 - self.myform['amp'].set_value(amp) - self.myform['amp_slider'].set_value(db) - self.myform['eth'].set_value(self.tb.eth_rate()) - self.myform['gbe'].set_value(self.tb.eth_rate()*32) - self.myform['interp'].set_value(self.tb.interp_rate()) - self.myform['DDC'].set_value(self.tb.ddc_freq()) - self.myform['analog'].set_value(self.tb.baseband_freq()) - - # Event response handlers - def evt_set_status_msg(self, msg): - self.frame.SetStatusText(msg, 0) - - def evt_set_freq1(self, kv): - return self.tb.set_waveform_freq(kv['w1freq']) - - def evt_set_freq2(self, kv): - return self.tb.set_waveform2_freq(kv['w2freq']) - - def evt_set_freq(self, kv): - if type(kv) == type(0.0): # Set from slider - tr = self.tb.set_freq(kv) - if tr is not None: - self.myform['freq'].set_value(kv) - else: # Set from edit box - f = kv['freq'] - tr = self.tb.set_freq(f) - if tr is not None: - self.myform['freq_slider'].set_value(f) - - if tr is not None: - self.myform['DDC'].set_value(tr.dxc_freq) - self.myform['analog'].set_value(tr.baseband_freq) - - return (tr is not None) - - def evt_set_amplitude(self, kv): - if type(kv) == type(0.0): # Set from slider - amp = math.pow(10, kv/20.0) - self.myform['amp'].set_value(amp) - return self.tb.set_amplitude(amp) - else: # Set from edit box - amp = kv['amp'] - if amp < 0.0 or amp > 1.0: - return False - if amp == 0.0: - db = -100.0 - else: - db = 20*math.log10(amp) - self.myform['amp_slider'].set_value(db) - return self.tb.set_amplitude(amp) - - def evt_set_interp(self): - interp = self.myform['interp'].get_value() - if self.tb.set_interp(interp): - eth_rate = self.tb.eth_rate() - self.myform['eth'].set_value(eth_rate) - self.myform['gbe'].set_value(eth_rate*32) - return True - return False - - def evt_set_waveform_type(self, type): - # TODO: update frequency labels - return self.tb.set_waveform(self._types[type]) - - # GUI construction - def build_gui(self): - self.myform = myform = form.form() - - # Baseband controls - bb_sbox = wx.StaticBox(parent=self.panel, label="Baseband Modulation") - bb_vbox = wx.StaticBoxSizer(bb_sbox, wx.VERTICAL) # Holds all baseband controls as unit - - # First row of baseband controls (modulation type) - mod_hbox = wx.BoxSizer(wx.HORIZONTAL) - mod_hbox.Add((10,0), 0, 0) - myform['type'] = form.radiobox_field( - parent=self.panel, label="Type", sizer=mod_hbox, value=None, - callback=self.evt_set_waveform_type, weight=1, major_dimension=0, - choices=usrp2_siggen.waveforms.values() ) - bb_vbox.Add((0,10), 0, 0) - bb_vbox.Add(mod_hbox, 0, wx.EXPAND) - - # Second row of baseband controls (frequencies) - bbf_hbox = wx.BoxSizer(wx.HORIZONTAL) - bbf_hbox.Add((10,0), 0, 0) - myform['w1freq'] = form.float_field( - parent=self.panel, sizer=bbf_hbox, label="Frequency 1 (Hz)", weight=1, - callback=myform.check_input_and_call(self.evt_set_freq1, self.evt_set_status_msg) ) - bbf_hbox.Add((10,0), 0, 0) - myform['w2freq'] = form.float_field( - parent=self.panel, sizer=bbf_hbox, label="Frequency 2 (Hz)", weight=1, - callback=myform.check_input_and_call(self.evt_set_freq2, self.evt_set_status_msg) ) - bbf_hbox.Add((10,0), 0, 0) - - bb_vbox.Add((0,10), 0, 0) - bb_vbox.Add(bbf_hbox, 0, wx.EXPAND) - - # Add baseband controls to top window sizer - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(bb_vbox, 0, wx.EXPAND) - - # Frequency controls - fc_sbox = wx.StaticBox(parent=self.panel, label="Center Frequency") - fc_vbox = wx.StaticBoxSizer(fc_sbox, wx.VERTICAL) # Holds all frequency controls as unit - - # First row of frequency controls (center frequency) - freq_hbox = wx.BoxSizer(wx.HORIZONTAL) - freq_hbox.Add((10,0), 0, 0) - myform['freq'] = form.float_field( - parent=self.panel, sizer=freq_hbox, label=None, weight=1, - callback=myform.check_input_and_call(self.evt_set_freq, self.evt_set_status_msg) ) - freq_hbox.Add((10,0), 0, 0) - myform['freq_slider'] = form.quantized_slider_field( - parent=self.panel, sizer=freq_hbox, label="Min-Max", weight=4, - range = (self.min_freq, self.max_freq, self.freq_step), - callback=self.evt_set_freq) - freq_hbox.Add((10,0), 0, 0) - - fc_vbox.Add((10,0), 0, 0) - fc_vbox.Add(freq_hbox, 0, wx.EXPAND) - - # Second row of frequency controls (results) - tr_hbox = wx.BoxSizer(wx.HORIZONTAL) - tr_hbox.Add((10,0), 0, 0) - myform['analog'] = form.static_float_field( - parent=self.panel, sizer=tr_hbox, label="Daughterboard: (Hz)", weight=1) - tr_hbox.Add((10,0), 0, 0) - myform['DDC'] = form.static_float_field( - parent=self.panel, sizer=tr_hbox, label="USRP2 DDC (Hz)", weight=1) - tr_hbox.Add((10,0), 0, 0) - fc_vbox.Add(tr_hbox, 0, wx.EXPAND) - - # Add frequency controls to top window sizer - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(fc_vbox, 0, wx.EXPAND) - - # Amplitude row - amp_sbox = wx.StaticBox(parent=self.panel, label="Amplitude") - amp_hbox = wx.StaticBoxSizer(amp_sbox, wx.HORIZONTAL) - amp_hbox.Add((10,0), 0, 0) - myform['amp'] = form.float_field( - parent=self.panel, sizer=amp_hbox, label="Linear\n(0.0-1.0)", weight=1, - callback=myform.check_input_and_call(self.evt_set_amplitude, self.evt_set_status_msg) ) - amp_hbox.Add((10,0), 0, 0) - myform['amp_slider'] = form.quantized_slider_field( - parent=self.panel, sizer=amp_hbox, label="dB Full Scale\n(-100-0)", weight=4, - range=(-100.0, 0.0, 1), callback=self.evt_set_amplitude) - amp_hbox.Add((10,0), 0, 0) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(amp_hbox, 0, wx.EXPAND) - - # Sample rate row - sam_sbox = wx.StaticBox(parent=self.panel, label="Sample Rate") - sam_hbox = wx.StaticBoxSizer(sam_sbox, wx.HORIZONTAL) - sam_hbox.Add((10,0), 0, 0) - myform['interp'] = form.int_field( - parent=self.panel, sizer=sam_hbox, label="Interpolation", weight=1, - callback=self.evt_set_interp) - sam_hbox.Add((10,0), 0, 0) - myform['eth'] = form.static_float_field( - parent=self.panel, sizer=sam_hbox, label="Sample Rate (sps)", weight=1) - sam_hbox.Add((10,0), 0, 0) - myform['gbe'] = form.static_float_field( - parent=self.panel, sizer=sam_hbox, label="GbE Rate (bits/sec)", weight=1) - sam_hbox.Add((10,0), 0, 0) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(sam_hbox, 0, wx.EXPAND) - - # USRP2 row - u2_sbox = wx.StaticBox(parent=self.panel, label="USRP2 Hardware") - u2_hbox = wx.StaticBoxSizer(u2_sbox, wx.HORIZONTAL) - u2_hbox.Add((10,0), 0, 0) - myform['ifc'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="Interface", weight=2) - u2_hbox.Add((10,0), 0, 0) - myform['mac'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="MAC Address", weight=2) - u2_hbox.Add((10,0), 0, 0) - myform['dbid'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="Daughterboard ID", weight=1) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(u2_hbox, 0, wx.EXPAND) - self.vbox.Add((0,20), 0, 0) - -if __name__ == "__main__": - try: - # Get command line parameters - (options, args) = usrp2_siggen.get_options() - - # Create the top block using these - tb = usrp2_siggen.top_block(options, args) - - # Create the GUI application - app = gui.app(top_block=tb, # Constructed top block - gui=app_gui, # User interface class - options=options, # Command line options - args=args, # Command line args - title="USRP2 Signal Generator", # Top window title - nstatus=1, # Number of status lines - start=True, # Whether to start flowgraph - realtime=True) # Whether to set realtime priority - - # And run it - app.MainLoop() - - except RuntimeError, e: - print e - sys.exit(1) diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index 8ae2fbfbf..8ee8cfd2a 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2005,2007,2008 Free Software Foundation, Inc. +# Copyright 2008,2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -20,200 +20,307 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr, gru -from gnuradio import usrp +DESC_KEY = 'desc' +SAMP_RATE_KEY = 'samp_rate' +LINK_RATE_KEY = 'link_rate' +DAC_RATE_KEY = 'dac_rate' +INTERP_KEY = 'interp' +GAIN_KEY = 'gain' +TX_FREQ_KEY = 'tx_freq' +DDC_FREQ_KEY = 'ddc_freq' +BB_FREQ_KEY = 'bb_freq' +AMPLITUDE_KEY = 'amplitude' +AMPL_RANGE_KEY = 'ampl_range' +WAVEFORM_FREQ_KEY = 'waveform_freq' +WAVEFORM_OFFSET_KEY = 'waveform_offset' +WAVEFORM2_FREQ_KEY = 'waveform2_freq' +FREQ_RANGE_KEY = 'freq_range' +GAIN_RANGE_KEY = 'gain_range' +TYPE_KEY = 'type' + +def setter(ps, key, val): ps[key] = val + +from gnuradio import gr, eng_notation +from gnuradio.gr.pubsub import pubsub from gnuradio.eng_option import eng_option -from gnuradio import eng_notation +from gnuradio import usrp_options from optparse import OptionParser import sys +import math +n2s = eng_notation.num_to_str -class my_top_block(gr.top_block): - def __init__ (self, nsamples): +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, pubsub): + def __init__(self, options, args): gr.top_block.__init__(self) + pubsub.__init__(self) + self._verbose = options.verbose + #initialize values from options + self._setup_usrpx(options) + self.subscribe(INTERP_KEY, lambda i: setter(self, SAMP_RATE_KEY, self[DAC_RATE_KEY]/i)) + self.subscribe(SAMP_RATE_KEY, lambda e: setter(self, LINK_RATE_KEY, e*32)) + self[INTERP_KEY] = options.interp or 16 + self[TX_FREQ_KEY] = options.tx_freq + self[AMPLITUDE_KEY] = options.amplitude + self[WAVEFORM_FREQ_KEY] = options.waveform_freq + self[WAVEFORM_OFFSET_KEY] = options.offset + self[WAVEFORM2_FREQ_KEY] = options.waveform2_freq + self[BB_FREQ_KEY] = 0 + self[DDC_FREQ_KEY] = 0 + #subscribe set methods + self.subscribe(INTERP_KEY, self.set_interp) + self.subscribe(GAIN_KEY, self.set_gain) + self.subscribe(TX_FREQ_KEY, self.set_freq) + self.subscribe(AMPLITUDE_KEY, self.set_amplitude) + self.subscribe(WAVEFORM_FREQ_KEY, self.set_waveform_freq) + self.subscribe(WAVEFORM2_FREQ_KEY, self.set_waveform2_freq) + self.subscribe(TYPE_KEY, self.set_waveform) + #force update on pubsub keys + for key in (INTERP_KEY, GAIN_KEY, TX_FREQ_KEY, + AMPLITUDE_KEY, WAVEFORM_FREQ_KEY, WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY): + self[key] = self[key] + self[TYPE_KEY] = options.type #set type last + + def _setup_usrpx(self, options): + self._u = usrp_options.create_usrp_sink(options) + self.publish(DESC_KEY, lambda: str(self._u)) + self.publish(DAC_RATE_KEY, self._u.dac_rate) + self.publish(FREQ_RANGE_KEY, self._u.freq_range) + self.publish(GAIN_RANGE_KEY, self._u.gain_range) + self.publish(GAIN_KEY, self._u.gain) + if self._verbose: print str(self._u) + + def _set_tx_amplitude(self, ampl): + """ + Sets the transmit amplitude sent to the USRP + @param ampl the amplitude or None for automatic + """ + ampl_range = self[AMPL_RANGE_KEY] + if ampl is None: ampl = (ampl_range[1] - ampl_range[0])*0.15 + ampl_range[0] + self[AMPLITUDE_KEY] = max(ampl_range[0], min(ampl, ampl_range[1])) + + def set_interp(self, interp): + if not self._u.set_interp(interp): + raise RuntimeError("Failed to set interpolation rate %i" % (interp,)) + + if self._verbose: + print "USRP interpolation rate:", interp + print "USRP IF bandwidth: %sHz" % (n2s(self[SAMP_RATE_KEY]),) + + if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE): + self._src.set_sampling_freq(self[SAMP_RATE_KEY]) + elif self[TYPE_KEY] == "2tone": + self._src1.set_sampling_freq(self[SAMP_RATE_KEY]) + self._src2.set_sampling_freq(self[SAMP_RATE_KEY]) + elif self[TYPE_KEY] == "sweep": + self._src1.set_sampling_freq(self[SAMP_RATE_KEY]) + self._src2.set_sampling_freq(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) + else: + return True # Waveform not yet set - # controllable values - self.interp = 64 - self.waveform_type = gr.GR_SIN_WAVE - self.waveform_ampl = 16000 - self.waveform_freq = 100.12345e3 - self.waveform_offset = 0 - self.nsamples = nsamples - self._instantiate_blocks () - self.set_waveform_type (self.waveform_type) - - def usb_freq (self): - return self.u.dac_freq() / self.interp - - def usb_throughput (self): - return self.usb_freq () * 4 - - def set_waveform_type (self, type): - ''' - valid waveform types are: gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, - gr.GR_UNIFORM and gr.GR_GAUSSIAN - ''' - self._configure_graph (type) - self.waveform_type = type - - def set_waveform_ampl (self, ampl): - self.waveform_ampl = ampl - self.siggen.set_amplitude (ampl) - self.noisegen.set_amplitude (ampl) - - def set_waveform_freq (self, freq): - self.waveform_freq = freq - self.siggen.set_frequency (freq) - - def set_waveform_offset (self, offset): - self.waveform_offset = offset - self.siggen.set_offset (offset) - - def set_interpolator (self, interp): - self.interp = interp - self.siggen.set_sampling_freq (self.usb_freq ()) - self.u.set_interp_rate (interp) - - def _instantiate_blocks (self): - self.src = None - self.u = usrp.sink_c (0, self.interp) - - self.siggen = gr.sig_source_c (self.usb_freq (), - gr.GR_SIN_WAVE, - self.waveform_freq, - self.waveform_ampl, - self.waveform_offset) - - self.noisegen = gr.noise_source_c (gr.GR_UNIFORM, - self.waveform_ampl) - - self.head = None - if self.nsamples > 0: - self.head = gr.head(gr.sizeof_gr_complex, int(self.nsamples)) - - # self.file_sink = gr.file_sink (gr.sizeof_gr_complex, "siggen.dat") - - def _configure_graph (self, type): - try: - self.lock() - self.disconnect_all () - - if self.head: - self.connect(self.head, self.u) - tail = self.head - else: - tail = self.u - - if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: - self.connect (self.siggen, tail) - # self.connect (self.siggen, self.file_sink) - self.siggen.set_waveform (type) - self.src = self.siggen - elif type == gr.GR_UNIFORM or type == gr.GR_GAUSSIAN: - self.connect (self.noisegen, tail) - self.noisegen.set_type (type) - self.src = self.noisegen - else: - raise ValueError, type - finally: - self.unlock() + if self._verbose: print "Set interpolation rate to:", interp + return True + + def set_gain(self, gain): + if gain is None: + g = self[GAIN_RANGE_KEY] + gain = float(g[0]+g[1])/2 + if self._verbose: + print "Using auto-calculated mid-point TX gain" + self[GAIN_KEY] = gain + return + self._u.set_gain(gain) + if self._verbose: + print "Set TX gain to:", gain def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital up converter. - """ - r = self.u.tune(self.subdev.which(), self.subdev, target_freq) - if r: - #print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq) - #print "r.dxc_freq =", eng_notation.num_to_str(r.dxc_freq) - #print "r.residual_freq =", eng_notation.num_to_str(r.residual_freq) - #print "r.inverted =", r.inverted - return True - - return False - - - -def main (): - parser = OptionParser (option_class=eng_option) - parser.add_option ("-T", "--tx-subdev-spec", type="subdev", default=(0, 0), - help="select USRP Tx side A or B") - parser.add_option ("-f", "--rf-freq", type="eng_float", default=None, - help="set RF center frequency to FREQ") - parser.add_option ("-i", "--interp", type="int", default=64, - help="set fgpa interpolation rate to INTERP [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) - parser.add_option ("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, - help="generate a constant output") - parser.add_option ("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, - help="generate Gaussian random output") - parser.add_option ("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, - help="generate Uniform random output") - - parser.add_option ("-w", "--waveform-freq", type="eng_float", default=0, - help="set waveform frequency to FREQ [default=%default]") - parser.add_option ("-a", "--amplitude", type="eng_float", default=16e3, - help="set waveform amplitude to AMPLITUDE [default=%default]", metavar="AMPL") - parser.add_option ("-g", "--gain", type="eng_float", default=None, - help="set output gain to GAIN [default=%default]") - parser.add_option ("-o", "--offset", type="eng_float", default=0, - help="set waveform offset to OFFSET [default=%default]") - parser.add_option ("-N", "--nsamples", type="eng_float", default=0, - help="set number of samples to transmit [default=+inf]") - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - raise SystemExit - - if options.rf_freq is None: - sys.stderr.write("usrp_siggen: must specify RF center frequency with -f RF_FREQ\n") - parser.print_help() - raise SystemExit - - tb = my_top_block(options.nsamples) - tb.set_interpolator (options.interp) - tb.set_waveform_type (options.type) - tb.set_waveform_freq (options.waveform_freq) - tb.set_waveform_ampl (options.amplitude) - tb.set_waveform_offset (options.offset) - - # determine the daughterboard subdevice we're using - if options.tx_subdev_spec is None: - options.tx_subdev_spec = usrp.pick_tx_subdevice(tb.u) - - m = usrp.determine_tx_mux_value(tb.u, options.tx_subdev_spec) - #print "mux = %#04x" % (m,) - tb.u.set_mux(m) - tb.subdev = usrp.selected_subdev(tb.u, options.tx_subdev_spec) - print "Using TX d'board %s" % (tb.subdev.side_and_name(),) - - if options.gain is None: - tb.subdev.set_gain(tb.subdev.gain_range()[1]) # set max Tx gain - else: - tb.subdev.set_gain(options.gain) # set max Tx gain - - if not tb.set_freq(options.rf_freq): - sys.stderr.write('Failed to set RF frequency\n') - raise SystemExit + if target_freq is None: + f = self[FREQ_RANGE_KEY] + target_freq = float(f[0]+f[1])/2.0 + if self._verbose: + print "Using auto-calculated mid-point frequency" + self[TX_FREQ_KEY] = target_freq + return + + 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_KEY] = tr.dxc_freq + self[BB_FREQ_KEY] = 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),) + elif self._verbose: print "Failed to set freq." + return tr + + def set_waveform_freq(self, freq): + if self[TYPE_KEY] == gr.GR_SIN_WAVE: + self._src.set_frequency(freq) + elif self[TYPE_KEY] == "2tone": + self._src1.set_frequency(freq) + elif self[TYPE_KEY] == 'sweep': + #there is no set sensitivity, redo fg + self[TYPE_KEY] = self[TYPE_KEY] + return True + + def set_waveform2_freq(self, freq): + if freq is None: + self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] + return + if self[TYPE_KEY] == "2tone": + self._src2.set_frequency(freq) + elif self[TYPE_KEY] == "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[SAMP_RATE_KEY], # Sample rate + type, # Waveform type + self[WAVEFORM_FREQ_KEY], # Waveform frequency + self[AMPLITUDE_KEY], # Waveform amplitude + self[WAVEFORM_OFFSET_KEY]) # Waveform offset + elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: + self._src = gr.noise_source_c(type, self[AMPLITUDE_KEY]) + elif type == "2tone": + self._src1 = gr.sig_source_c(self[SAMP_RATE_KEY], + gr.GR_SIN_WAVE, + self[WAVEFORM_FREQ_KEY], + self[AMPLITUDE_KEY]/2.0, + 0) + if(self[WAVEFORM2_FREQ_KEY] is None): + self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] + + self._src2 = gr.sig_source_c(self[SAMP_RATE_KEY], + gr.GR_SIN_WAVE, + self[WAVEFORM2_FREQ_KEY], + self[AMPLITUDE_KEY]/2.0, + 0) + self._src = gr.add_cc() + self.connect(self._src1,(self._src,0)) + self.connect(self._src2,(self._src,1)) + 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) + if self[WAVEFORM2_FREQ_KEY] is None: + self[WAVEFORM2_FREQ_KEY] = 0.1 + + self._src1 = gr.sig_source_f(self[SAMP_RATE_KEY], + gr.GR_TRI_WAVE, + self[WAVEFORM2_FREQ_KEY], + 1.0, + -0.5) + self._src2 = gr.frequency_modulator_fc(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) + self._src = gr.multiply_const_cc(self[AMPLITUDE_KEY]) + self.connect(self._src1,self._src2,self._src) + else: + raise RuntimeError("Unknown waveform type") + + self.connect(self._src, self._u) + self.unlock() + + if self._verbose: + print "Set baseband modulation to:", waveforms[type] + if type == gr.GR_SIN_WAVE: + print "Modulation frequency: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) + print "Initial phase:", self[WAVEFORM_OFFSET_KEY] + elif type == "2tone": + print "Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) + print "Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) + elif type == "sweep": + print "Sweeping across %sHz to %sHz" % (n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0)) + print "Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) + print "TX amplitude:", self[AMPLITUDE_KEY] + + + def set_amplitude(self, amplitude): + if amplitude < 0.0 or amplitude > 1.0: + if self._verbose: print "Amplitude out of range:", amplitude + return False + + if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, gr.GR_GAUSSIAN, gr.GR_UNIFORM): + self._src.set_amplitude(amplitude) + elif self[TYPE_KEY] == "2tone": + self._src1.set_amplitude(amplitude/2.0) + self._src2.set_amplitude(amplitude/2.0) + elif self[TYPE_KEY] == "sweep": + self._src.set_k(amplitude) + else: + return True # Waveform not yet set + + if self._verbose: print "Set amplitude to:", amplitude + return True + +def get_options(): + usage="%prog: [options]" + + parser = OptionParser(option_class=eng_option, usage=usage) + usrp_options.add_tx_options(parser) + parser.add_option("-f", "--tx-freq", type="eng_float", default=None, + help="Set carrier frequency to FREQ [default=mid-point]", metavar="FREQ") + parser.add_option("-x", "--waveform-freq", type="eng_float", default=0, + help="Set baseband waveform frequency to FREQ [default=%default]") + parser.add_option("-y", "--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 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 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") + parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, + help="Generate Uniform random output") + parser.add_option("--2tone", dest="type", action="store_const", const="2tone", + 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") + parser.add_option("-A", "--amplitude", type="eng_float", default=0.15, + 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() + + 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" - tb.subdev.set_enable(True) # enable transmitter + # 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 - - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp_siggen_gui.py b/gr-utils/src/python/usrp_siggen_gui.py new file mode 100755 index 000000000..40848fbee --- /dev/null +++ b/gr-utils/src/python/usrp_siggen_gui.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import wx +from gnuradio import gr +from gnuradio.gr.pubsub import pubsub +from gnuradio.wxgui import gui, forms +import usrp_siggen +import sys, math + +class app_gui(pubsub): + def __init__(self, frame, panel, vbox, top_block, options, args): + pubsub.__init__(self) + self.frame = frame # Use for top-level application window frame + self.panel = panel # Use as parent class for created windows + self.vbox = vbox # Use as sizer for created windows + self.tb = top_block # GUI-unaware flowgraph class + self.options = options # Supplied command-line options + self.args = args # Supplied command-line arguments + self.build_gui() + + # Event response handlers + def evt_set_status_msg(self, msg): + self.frame.SetStatusText(msg, 0) + + # GUI construction + def build_gui(self): + self.vbox.AddSpacer(5) + self.vbox.AddStretchSpacer() + ################################################## + # Baseband controls + ################################################## + bb_vbox = forms.static_box_sizer(parent=self.panel, label="Baseband Modulation", orient=wx.VERTICAL, bold=True) + self.vbox.Add(bb_vbox, 0, wx.EXPAND) + sine_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) + sweep_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) + tone_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + #callback to show/hide forms + def set_type(type): + sine_bb_hbox.ShowItems(type == gr.GR_SIN_WAVE) + sweep_bb_hbox.ShowItems(type == 'sweep') + tone_bb_hbox.ShowItems(type == '2tone') + self.vbox.Layout() + self.tb.subscribe(usrp_siggen.TYPE_KEY, set_type) + #create sine forms + sine_bb_hbox.AddSpacer(10) + forms.text_box( + parent=self.panel, sizer=sine_bb_hbox, + label='Frequency (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + sine_bb_hbox.AddStretchSpacer() + #create sweep forms + sweep_bb_hbox.AddSpacer(10) + forms.text_box( + parent=self.panel, sizer=sweep_bb_hbox, + label='Sweep Width (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + sweep_bb_hbox.AddStretchSpacer() + forms.text_box( + parent=self.panel, sizer=sweep_bb_hbox, + label='Sweep Rate (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM2_FREQ_KEY, + converter=forms.float_converter(), + ) + sweep_bb_hbox.AddStretchSpacer() + #create 2tone forms + tone_bb_hbox.AddSpacer(10) + forms.text_box( + parent=self.panel, sizer=tone_bb_hbox, + label='Tone 1 (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + tone_bb_hbox.AddStretchSpacer() + forms.text_box( + parent=self.panel, sizer=tone_bb_hbox, + label='Tone 2 (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM2_FREQ_KEY, + converter=forms.float_converter(), + ) + tone_bb_hbox.AddStretchSpacer() + forms.radio_buttons( + parent=self.panel, sizer=bb_vbox, + choices=usrp_siggen.waveforms.keys(), + labels=usrp_siggen.waveforms.values(), + ps=self.tb, + key=usrp_siggen.TYPE_KEY, + style=wx.NO_BORDER | wx.RA_HORIZONTAL, + ) + bb_vbox.AddSpacer(10) + bb_vbox.Add(sine_bb_hbox, 0, wx.EXPAND) + bb_vbox.Add(sweep_bb_hbox, 0, wx.EXPAND) + bb_vbox.Add(tone_bb_hbox, 0, wx.EXPAND) + set_type(self.tb[usrp_siggen.TYPE_KEY]) + ################################################## + # Frequency controls + ################################################## + fc_vbox = forms.static_box_sizer(parent=self.panel, label="Center Frequency", orient=wx.VERTICAL, bold=True) + fc_vbox.AddSpacer(5) + # First row of frequency controls (center frequency) + freq_hbox = wx.BoxSizer(wx.HORIZONTAL) + fc_vbox.Add(freq_hbox, 0, wx.EXPAND) + fc_vbox.AddSpacer(10) + # Second row of frequency controls (results) + tr_hbox = wx.BoxSizer(wx.HORIZONTAL) + fc_vbox.Add(tr_hbox, 0, wx.EXPAND) + fc_vbox.AddSpacer(5) + # Add frequency controls to top window sizer + self.vbox.Add(fc_vbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + freq_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=freq_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self.tb, + key=usrp_siggen.TX_FREQ_KEY, + ) + freq_hbox.AddSpacer(10) + forms.slider( + parent=self.panel, sizer=freq_hbox, + proportion=2, + ps=self.tb, + key=usrp_siggen.TX_FREQ_KEY, + minimum=self.tb[usrp_siggen.FREQ_RANGE_KEY][0], + maximum=self.tb[usrp_siggen.FREQ_RANGE_KEY][1], + num_steps=100, + ) + freq_hbox.AddSpacer(5) + tr_hbox.AddSpacer(5) + forms.static_text( + parent=self.panel, sizer=tr_hbox, + label='Daughterboard (Hz)', + ps=self.tb, + key=usrp_siggen.BB_FREQ_KEY, + converter=forms.float_converter(), + proportion=1, + ) + tr_hbox.AddSpacer(10) + forms.static_text( + parent=self.panel, sizer=tr_hbox, + label='USRP DDC (Hz)', + ps=self.tb, + key=usrp_siggen.DDC_FREQ_KEY, + converter=forms.float_converter(), + proportion=1, + ) + tr_hbox.AddSpacer(5) + ################################################## + # Amplitude controls + ################################################## + amp_hbox = forms.static_box_sizer(parent=self.panel, label="Amplitude", orient=wx.VERTICAL, bold=True) + amp_hbox.AddSpacer(5) + # First row of amp controls (ampl) + lvl_hbox = wx.BoxSizer(wx.HORIZONTAL) + amp_hbox.Add(lvl_hbox, 0, wx.EXPAND) + amp_hbox.AddSpacer(10) + # Second row of amp controls (tx gain) + gain_hbox = wx.BoxSizer(wx.HORIZONTAL) + amp_hbox.Add(gain_hbox, 0, wx.EXPAND) + amp_hbox.AddSpacer(5) + self.vbox.Add(amp_hbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + lvl_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=lvl_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self.tb, + key=usrp_siggen.AMPLITUDE_KEY, + label="Level (0.0-1.0)", + ) + lvl_hbox.AddSpacer(10) + forms.log_slider( + parent=self.panel, sizer=lvl_hbox, + proportion=2, + ps=self.tb, + key=usrp_siggen.AMPLITUDE_KEY, + min_exp=-6, + max_exp=0, + base=10, + num_steps=100, + ) + lvl_hbox.AddSpacer(5) + if self.tb[usrp_siggen.GAIN_RANGE_KEY][0] < self.tb[usrp_siggen.GAIN_RANGE_KEY][1]: + gain_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=gain_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self.tb, + key=usrp_siggen.GAIN_KEY, + label="TX Gain (dB)", + ) + gain_hbox.AddSpacer(10) + forms.slider( + parent=self.panel, sizer=gain_hbox, + proportion=2, + ps=self.tb, + key=usrp_siggen.GAIN_KEY, + minimum=self.tb[usrp_siggen.GAIN_RANGE_KEY][0], + maximum=self.tb[usrp_siggen.GAIN_RANGE_KEY][1], + step_size=self.tb[usrp_siggen.GAIN_RANGE_KEY][2], + ) + gain_hbox.AddSpacer(5) + ################################################## + # Sample Rate controls + ################################################## + sam_hbox = forms.static_box_sizer(parent=self.panel, label="Sample Rate", orient=wx.HORIZONTAL, bold=True) + self.vbox.Add(sam_hbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + sam_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=sam_hbox, + converter=forms.int_converter(), + ps=self.tb, + key=usrp_siggen.INTERP_KEY, + label="Interpolation", + ) + sam_hbox.AddStretchSpacer(20) + forms.static_text( + parent=self.panel, sizer=sam_hbox, + label='Sample Rate (sps)', + ps=self.tb, + key=usrp_siggen.SAMP_RATE_KEY, + converter=forms.float_converter(), + ) + sam_hbox.AddStretchSpacer(20) + forms.static_text( + parent=self.panel, sizer=sam_hbox, + label='Link Rate (bits/sec)', + ps=self.tb, + key=usrp_siggen.LINK_RATE_KEY, + converter=forms.float_converter(), + ) + sam_hbox.AddSpacer(5) + ################################################## + # USRP status + ################################################## + u2_hbox = forms.static_box_sizer(parent=self.panel, label="USRP Status", orient=wx.HORIZONTAL, bold=True) + self.vbox.Add(u2_hbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + u2_hbox.AddSpacer(10) + forms.static_text( + parent=self.panel, sizer=u2_hbox, + ps=self.tb, + key=usrp_siggen.DESC_KEY, + converter=forms.str_converter(), + ) + self.vbox.AddSpacer(5) + self.vbox.AddStretchSpacer() + +if __name__ == "__main__": + try: + # Get command line parameters + (options, args) = usrp_siggen.get_options() + + # Create the top block using these + tb = usrp_siggen.top_block(options, args) + + # Create the GUI application + app = gui.app(top_block=tb, # Constructed top block + gui=app_gui, # User interface class + options=options, # Command line options + args=args, # Command line args + title="USRP Signal Generator", # Top window title + nstatus=1, # Number of status lines + start=True, # Whether to start flowgraph + realtime=True) # Whether to set realtime priority + + # And run it + app.MainLoop() + + except RuntimeError, e: + print e + sys.exit(1) |