summaryrefslogtreecommitdiff
path: root/gr-utils/python
diff options
context:
space:
mode:
Diffstat (limited to 'gr-utils/python')
-rw-r--r--gr-utils/python/CMakeLists.txt56
-rw-r--r--gr-utils/python/README.plot97
-rwxr-xr-xgr-utils/python/create-gnuradio-out-of-tree-project69
-rwxr-xr-xgr-utils/python/gr_plot_char58
-rwxr-xr-xgr-utils/python/gr_plot_const250
-rw-r--r--gr-utils/python/gr_plot_fft42
-rwxr-xr-xgr-utils/python/gr_plot_fft_c46
-rwxr-xr-xgr-utils/python/gr_plot_fft_f46
-rwxr-xr-xgr-utils/python/gr_plot_float58
-rwxr-xr-xgr-utils/python/gr_plot_int58
-rwxr-xr-xgr-utils/python/gr_plot_iq178
-rw-r--r--gr-utils/python/gr_plot_psd42
-rwxr-xr-xgr-utils/python/gr_plot_psd_c47
-rwxr-xr-xgr-utils/python/gr_plot_psd_f47
-rwxr-xr-xgr-utils/python/gr_plot_qt729
-rwxr-xr-xgr-utils/python/gr_plot_short58
-rw-r--r--gr-utils/python/gr_read_file_metadata87
-rwxr-xr-xgr-utils/python/grcc66
-rw-r--r--gr-utils/python/plot_data.py168
-rwxr-xr-xgr-utils/python/plot_fft_base.py249
-rwxr-xr-xgr-utils/python/plot_psd_base.py292
-rw-r--r--gr-utils/python/pyqt_filter.py435
-rw-r--r--gr-utils/python/pyqt_filter.ui687
-rw-r--r--gr-utils/python/pyqt_plot.py211
-rw-r--r--gr-utils/python/pyqt_plot.ui399
25 files changed, 4475 insertions, 0 deletions
diff --git a/gr-utils/python/CMakeLists.txt b/gr-utils/python/CMakeLists.txt
new file mode 100644
index 0000000000..4b956904f3
--- /dev/null
+++ b/gr-utils/python/CMakeLists.txt
@@ -0,0 +1,56 @@
+# Copyright 2011 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.
+
+########################################################################
+# Install python files and apps
+########################################################################
+include(GrPython)
+
+GR_PYTHON_INSTALL(
+ FILES
+ plot_data.py
+ plot_fft_base.py
+ plot_psd_base.py
+ pyqt_plot.py
+ pyqt_filter.py
+ DESTINATION ${GR_PYTHON_DIR}/gnuradio
+ COMPONENT "utils"
+)
+
+GR_PYTHON_INSTALL(
+ PROGRAMS
+ create-gnuradio-out-of-tree-project
+ gr_plot_char
+ gr_plot_const
+ gr_plot_fft
+ gr_plot_fft_c
+ gr_plot_fft_f
+ gr_plot_psd
+ gr_plot_psd_c
+ gr_plot_psd_f
+ gr_plot_float
+ gr_plot_int
+ gr_plot_iq
+ gr_plot_short
+ gr_plot_qt
+ gr_read_file_metadata
+ grcc
+ DESTINATION ${GR_RUNTIME_DIR}
+ COMPONENT "utils"
+)
diff --git a/gr-utils/python/README.plot b/gr-utils/python/README.plot
new file mode 100644
index 0000000000..60f14c669c
--- /dev/null
+++ b/gr-utils/python/README.plot
@@ -0,0 +1,97 @@
+* gr_plot_*:
+These are a collection of Python scripts to enable viewing and
+analysis of files produced by GNU Radio flow graphs. Most of them work
+off complex data produced by digital waveforms.
+
+
+** gr_plot_float:
+Takes a GNU Radio floating point binary file and displays the samples
+versus time. You can set the block size to specify how many points to
+read in at a time and the start position in the file.
+
+By default, the system assumes a sample rate of 1, so in time, each
+sample is plotted versus the sample number. To set a true time axis,
+set the sample rate (-R or --sample-rate) to the sample rate used when
+capturing the samples.
+
+
+
+** gr_plot_iq:
+Takes a GNU Radio complex binary file and displays the I&Q data versus
+time. You can set the block size to specify how many points to read in
+at a time and the start position in the file.
+
+By default, the system assumes a sample rate of 1, so in time, each
+sample is plotted versus the sample number. To set a true time axis,
+set the sample rate (-R or --sample-rate) to the sample rate used when
+capturing the samples.
+
+
+
+** gr_plot_const:
+Takes a GNU Radio complex binary file and displays the I&Q data versus
+time and the constellation plot (I vs. Q). You can set the block size
+to specify how many points to read in at a time and the start position
+in the file.
+
+By default, the system assumes a sample rate of 1, so in time, each
+sample is plotted versus the sample number. To set a true time axis,
+set the sample rate (-R or --sample-rate) to the sample rate used when
+capturing the samples.
+
+
+
+** gr_plot_fft_c:
+Takes a GNU Radio complex binary file and displays the I&Q data versus
+time as well as the frequency domain (FFT) plot. The y-axis values are
+plotted assuming volts as the amplitude of the I&Q streams and
+converted into dBm in the frequency domain (the 1/N power adjustment
+out of the FFT is performed internally).
+
+The script plots a certain block of data at a time, specified on the
+command line as -B or --block. This value defaults to 1000. The start
+position in the file can be set by specifying -s or --start and
+defaults to 0 (the start of the file).
+
+By default, the system assumes a sample rate of 1, so in time, each
+sample is plotted versus the sample number. To set a true time and
+frequency axis, set the sample rate (-R or --sample-rate) to the
+sample rate used when capturing the samples.
+
+
+
+** gr_plot_fft_f:
+Takes a GNU Radio floating point binary file and displays the samples
+versus time as well as the frequency domain (FFT) plot. The y-axis
+values are plotted assuming volts as the amplitude of the I&Q streams
+and converted into dBm in the frequency domain (the 1/N power
+adjustment out of the FFT is performed internally).
+
+The script plots a certain block of data at a time, specified on the
+command line as -B or --block. This value defaults to 1000. The start
+position in the file can be set by specifying -s or --start and
+defaults to 0 (the start of the file).
+
+By default, the system assumes a sample rate of 1, so in time, each
+sample is plotted versus the sample number. To set a true time and
+frequency axis, set the sample rate (-R or --sample-rate) to the
+sample rate used when capturing the samples.
+
+
+** gr_plot_fft:
+Takes a GNU Radio binary file (the datatype is specified using the -d
+option and defaults to complex64) and displays the samples versus time
+as well as the frequency domain (FFT) plot. The y-axis values are
+plotted assuming volts as the amplitude of the I&Q streams and
+converted into dBm in the frequency domain (the 1/N power adjustment
+out of the FFT is performed internally).
+
+The script plots a certain block of data at a time, specified on the
+command line as -B or --block. This value defaults to 1000. The start
+position in the file can be set by specifying -s or --start and
+defaults to 0 (the start of the file).
+
+By default, the system assumes a sample rate of 1, so in time, each
+sample is plotted versus the sample number. To set a true time and
+frequency axis, set the sample rate (-R or --sample-rate) to the
+sample rate used when capturing the samples.
diff --git a/gr-utils/python/create-gnuradio-out-of-tree-project b/gr-utils/python/create-gnuradio-out-of-tree-project
new file mode 100755
index 0000000000..d5e32c92b8
--- /dev/null
+++ b/gr-utils/python/create-gnuradio-out-of-tree-project
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+
+from optparse import OptionParser
+import os
+import re
+import sys
+import subprocess
+
+tarball_url="http://gnuradio.org/releases/gnuradio/gr-howto-write-a-block-3.3git-651-g642252d8.tar.gz"
+
+def open_tarball(tarball_name=None):
+ """Return a readable fileobject that references the tarball.
+ If tarball_name is None, download from the net
+ """
+ if tarball_name:
+ return open(tarball_name, 'r')
+ p = subprocess.Popen(["wget", "-O", "-", tarball_url],
+ close_fds=True, stdout=subprocess.PIPE)
+ return p.stdout
+
+def extract_and_rename_files(tarball, module_name):
+ # Requires GNU tar.
+ tar_cmd = 'tar xz --strip-components=1 --transform="s/howto/%s/g"' % (module_name,)
+ p = subprocess.Popen(tar_cmd, shell=True, stdin=tarball, close_fds=True)
+ sts = os.waitpid(p.pid, 0)
+ return sts == 0
+
+def main():
+ usage = "%prog: [options] new_module_name"
+ description="Create a prototype 'out of tree' GNU Radio project"
+ parser = OptionParser(usage=usage, description=description)
+ parser.add_option("-T", "--tarball", type="string", default=None,
+ help="path to gr-howto-build-a-block gzipped tarball [default=<get from web>]")
+ (options, args) = parser.parse_args()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit,2
+ module_name = args[0]
+ if not re.match(r'[_a-z][_a-z0-9]*$', module_name):
+ sys.stderr.write("module_name '%s' may only contain [a-z0-9_]\n" % (module_name))
+ raise SystemExit, 1
+
+ # Ensure there's no file or directory called <module_name>
+ if os.path.exists(module_name):
+ sys.stderr.write("A file or directory named '%s' already exists\n" % (module_name,))
+ raise SystemExit, 1
+
+ os.mkdir(module_name)
+ os.chdir(module_name)
+
+ ok = extract_and_rename_files(open_tarball(options.tarball), module_name)
+
+ # rename file contents
+ upper_module_name = module_name.upper()
+ sed_cmd = 'sed -i -e "s/howto-write-a-block/%s/g" -e "s/howto/%s/g" -e "s/HOWTO/%s/g"' % (module_name, module_name, \
+ upper_module_name)
+ os.system('find . -type f -print0 | xargs -0 ' + sed_cmd)
+
+ sys.stdout.write("""
+Project '%s' is now ready to build.
+
+ $ ./bootstrap
+ $ ./configure --prefix=/home/[user]/install
+ $ (make && make check && make install) 2>&1 | tee make.log
+
+""" % (module_name,))
+
+if __name__ == '__main__':
+ main()
diff --git a/gr-utils/python/gr_plot_char b/gr-utils/python/gr_plot_char
new file mode 100755
index 0000000000..a2b93a63c6
--- /dev/null
+++ b/gr-utils/python/gr_plot_char
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2008 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.
+#
+
+try:
+ import scipy
+except ImportError:
+ print "Please install SciPy to run this script (http://www.scipy.org/)"
+ raise SystemExit, 1
+
+from optparse import OptionParser
+from gnuradio.plot_data import plot_data
+
+def main():
+ usage="%prog: [options] input_filenames"
+ description = "Takes a GNU Radio byte/char binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+ parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+ parser.add_option("-B", "--block", type="int", default=1000,
+ help="Specify the block size [default=%default]")
+ parser.add_option("-s", "--start", type="int", default=0,
+ help="Specify where to start in the file [default=%default]")
+ parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+ help="Set the sampler rate of the data [default=%default]")
+
+ (options, args) = parser.parse_args ()
+ if len(args) < 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filenames = args
+
+ datatype=scipy.int8
+ dc = plot_data(datatype, filenames, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
diff --git a/gr-utils/python/gr_plot_const b/gr-utils/python/gr_plot_const
new file mode 100755
index 0000000000..749ad035b5
--- /dev/null
+++ b/gr-utils/python/gr_plot_const
@@ -0,0 +1,250 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2008,2011 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.
+#
+
+try:
+ import scipy
+except ImportError:
+ print "Please install SciPy to run this script (http://www.scipy.org/)"
+ raise SystemExit, 1
+
+try:
+ from pylab import *
+ from matplotlib.font_manager import fontManager, FontProperties
+except ImportError:
+ print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)"
+ raise SystemExit, 1
+
+from optparse import OptionParser
+
+class draw_constellation:
+ def __init__(self, filename, options):
+ self.hfile = open(filename, "r")
+ self.block_length = options.block
+ self.start = options.start
+ self.sample_rate = options.sample_rate
+
+ self.datatype = scipy.complex64
+ self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file
+
+ self.axis_font_size = 16
+ self.label_font_size = 18
+ self.title_font_size = 20
+
+ # Setup PLOT
+ self.fig = figure(1, figsize=(16, 9), facecolor='w')
+ rcParams['xtick.labelsize'] = self.axis_font_size
+ rcParams['ytick.labelsize'] = self.axis_font_size
+
+ self.text_file = figtext(0.10, 0.95, ("File: %s" % filename), weight="heavy", size=16)
+ self.text_file_pos = figtext(0.10, 0.90, "File Position: ", weight="heavy", size=16)
+ self.text_block = figtext(0.40, 0.90, ("Block Size: %d" % self.block_length),
+ weight="heavy", size=16)
+ self.text_sr = figtext(0.60, 0.90, ("Sample Rate: %.2f" % self.sample_rate),
+ weight="heavy", size=16)
+ self.make_plots()
+
+ self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+ self.button_left = Button(self.button_left_axes, "<")
+ self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+ self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+ self.button_right = Button(self.button_right_axes, ">")
+ self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+ self.xlim = self.sp_iq.get_xlim()
+
+ self.manager = get_current_fig_manager()
+ connect('draw_event', self.zoom)
+ connect('key_press_event', self.click)
+ connect('button_press_event', self.mouse_button_callback)
+ show()
+
+ def get_data(self):
+ self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data))
+ try:
+ iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length)
+ except MemoryError:
+ print "End of File"
+ else:
+ # retesting length here as newer version of scipy does not throw a MemoryError, just
+ # returns a zero-length array
+ if(len(iq) > 0):
+ self.reals = scipy.array([r.real for r in iq])
+ self.imags = scipy.array([i.imag for i in iq])
+
+ self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))])
+ return True
+ else:
+ print "End of File"
+ return False
+
+ def make_plots(self):
+ # if specified on the command-line, set file pointer
+ self.hfile.seek(self.sizeof_data*self.start, 1)
+
+ r = self.get_data()
+
+ # Subplot for real and imaginary parts of signal
+ self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6])
+ self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold")
+ self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+ self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+ self.plot_iq = self.sp_iq.plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-')
+
+ # Subplot for constellation plot
+ self.sp_const = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6])
+ self.sp_const.set_title(("Constellation"), fontsize=self.title_font_size, fontweight="bold")
+ self.sp_const.set_xlabel("Inphase", fontsize=self.label_font_size, fontweight="bold")
+ self.sp_const.set_ylabel("Qaudrature", fontsize=self.label_font_size, fontweight="bold")
+ self.plot_const = self.sp_const.plot(self.reals, self.imags, 'bo')
+
+ # Add plots to mark current location of point between time and constellation plots
+ self.indx = 0
+ self.plot_iq += self.sp_iq.plot([self.time[self.indx],], [self.reals[self.indx],], 'mo', ms=8)
+ self.plot_iq += self.sp_iq.plot([self.time[self.indx],], [self.imags[self.indx],], 'mo', ms=8)
+ self.plot_const += self.sp_const.plot([self.reals[self.indx],], [self.imags[self.indx],], 'mo', ms=12)
+
+ # Adjust axis
+ self.sp_iq.axis([self.time.min(), self.time.max(),
+ 1.5*min([self.reals.min(), self.imags.min()]),
+ 1.5*max([self.reals.max(), self.imags.max()])])
+ self.sp_const.axis([-2, 2, -2, 2])
+
+ draw()
+
+ def update_plots(self):
+ self.plot_iq[0].set_data([self.time, self.reals])
+ self.plot_iq[1].set_data([self.time, self.imags])
+ self.sp_iq.axis([self.time.min(), self.time.max(),
+ 1.5*min([self.reals.min(), self.imags.min()]),
+ 1.5*max([self.reals.max(), self.imags.max()])])
+
+ self.plot_const[0].set_data([self.reals, self.imags])
+ self.sp_const.axis([-2, 2, -2, 2])
+ draw()
+
+ def zoom(self, event):
+ newxlim = scipy.array(self.sp_iq.get_xlim())
+ curxlim = scipy.array(self.xlim)
+ if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]):
+ self.xlim = newxlim
+ r = self.reals[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))]
+ i = self.imags[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))]
+
+ self.plot_const[0].set_data(r, i)
+ self.sp_const.axis([-2, 2, -2, 2])
+ self.manager.canvas.draw()
+ draw()
+
+ def click(self, event):
+ forward_valid_keys = [" ", "down", "right"]
+ backward_valid_keys = ["up", "left"]
+ trace_forward_valid_keys = [">",]
+ trace_backward_valid_keys = ["<",]
+
+ if(find(event.key, forward_valid_keys)):
+ self.step_forward()
+
+ elif(find(event.key, backward_valid_keys)):
+ self.step_backward()
+
+ elif(find(event.key, trace_forward_valid_keys)):
+ self.indx = min(self.indx+1, len(self.time)-1)
+ self.set_trace(self.indx)
+
+ elif(find(event.key, trace_backward_valid_keys)):
+ self.indx = max(0, self.indx-1)
+ self.set_trace(self.indx)
+
+ def button_left_click(self, event):
+ self.step_backward()
+
+ def button_right_click(self, event):
+ self.step_forward()
+
+ def step_forward(self):
+ r = self.get_data()
+ if(r):
+ self.update_plots()
+
+ def step_backward(self):
+ # Step back in file position
+ if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ):
+ self.hfile.seek(-2*self.sizeof_data*self.block_length, 1)
+ else:
+ self.hfile.seek(-self.hfile.tell(),1)
+ r = self.get_data()
+ if(r):
+ self.update_plots()
+
+
+ def mouse_button_callback(self, event):
+ x, y = event.xdata, event.ydata
+
+ if x is not None and y is not None:
+ if(event.inaxes == self.sp_iq):
+ self.indx = searchsorted(self.time, [x])
+ self.set_trace(self.indx)
+
+
+ def set_trace(self, indx):
+ self.plot_iq[2].set_data(self.time[indx], self.reals[indx])
+ self.plot_iq[3].set_data(self.time[indx], self.imags[indx])
+ self.plot_const[1].set_data(self.reals[indx], self.imags[indx])
+ draw()
+
+
+def find(item_in, list_search):
+ try:
+ return list_search.index(item_in) != None
+ except ValueError:
+ return False
+
+
+def main():
+ usage="%prog: [options] input_filename"
+ description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time and the constellation plot (I vs. Q). You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+ parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+ parser.add_option("-B", "--block", type="int", default=1000,
+ help="Specify the block size [default=%default]")
+ parser.add_option("-s", "--start", type="int", default=0,
+ help="Specify where to start in the file [default=%default]")
+ parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+ help="Set the sampler rate of the data [default=%default]")
+
+ (options, args) = parser.parse_args ()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filename = args[0]
+
+ dc = draw_constellation(filename, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
+
+
diff --git a/gr-utils/python/gr_plot_fft b/gr-utils/python/gr_plot_fft
new file mode 100644
index 0000000000..4343481645
--- /dev/null
+++ b/gr-utils/python/gr_plot_fft
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 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.plot_fft_base import plot_fft_base
+
+# This is a wrapper program for plot_fft_base. It handles any data
+# type and defaults to complex64.
+
+def main():
+ parser = plot_fft_base.setup_options()
+ (options, args) = parser.parse_args ()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filename = args[0]
+
+ dc = plot_fft_base(options.data_type, filename, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
diff --git a/gr-utils/python/gr_plot_fft_c b/gr-utils/python/gr_plot_fft_c
new file mode 100755
index 0000000000..43e808d95a
--- /dev/null
+++ b/gr-utils/python/gr_plot_fft_c
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2008 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.plot_fft_base import plot_fft_base
+
+# This is a wrapper program for plot_fft_base specifically for complex data
+
+def main():
+ parser = plot_fft_base.setup_options()
+ parser.remove_option("--data-type")
+
+ (options, args) = parser.parse_args ()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filename = args[0]
+
+ dc = plot_fft_base("complex64", filename, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
+
+
diff --git a/gr-utils/python/gr_plot_fft_f b/gr-utils/python/gr_plot_fft_f
new file mode 100755
index 0000000000..dee9b17dea
--- /dev/null
+++ b/gr-utils/python/gr_plot_fft_f
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2008 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.plot_fft_base import plot_fft_base
+
+# This is a wrapper program for plot_fft_base specifically for float data
+
+def main():
+ parser = plot_fft_base.setup_options()
+ parser.remove_option("--data-type")
+
+ (options, args) = parser.parse_args ()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filename = args[0]
+
+ dc = plot_fft_base("float32", filename, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
+
+
diff --git a/gr-utils/python/gr_plot_float b/gr-utils/python/gr_plot_float
new file mode 100755
index 0000000000..22806e48ae
--- /dev/null
+++ b/gr-utils/python/gr_plot_float
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2008 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.
+#
+
+try:
+ import scipy
+except ImportError:
+ print "Please install SciPy to run this script (http://www.scipy.org/)"
+ raise SystemExit, 1
+
+from optparse import OptionParser
+from gnuradio.plot_data import plot_data
+
+def main():
+ usage="%prog: [options] input_filenames"
+ description = "Takes a GNU Radio floating point binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+ parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+ parser.add_option("-B", "--block", type="int", default=1000,
+ help="Specify the block size [default=%default]")
+ parser.add_option("-s", "--start", type="int", default=0,
+ help="Specify where to start in the file [default=%default]")
+ parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+ help="Set the sampler rate of the data [default=%default]")
+
+ (options, args) = parser.parse_args ()
+ if len(args) < 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filenames = args
+
+ datatype=scipy.float32
+ dc = plot_data(datatype, filenames, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
diff --git a/gr-utils/python/gr_plot_int b/gr-utils/python/gr_plot_int
new file mode 100755
index 0000000000..355ddf0189
--- /dev/null
+++ b/gr-utils/python/gr_plot_int
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2008 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.
+#
+
+try:
+ import scipy
+except ImportError:
+ print "Please install SciPy to run this script (http://www.scipy.org/)"
+ raise SystemExit, 1
+
+from optparse import OptionParser
+from gnuradio.plot_data import plot_data
+
+def main():
+ usage="%prog: [options] input_filenames"
+ description = "Takes a GNU Radio integer binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+ parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+ parser.add_option("-B", "--block", type="int", default=1000,
+ help="Specify the block size [default=%default]")
+ parser.add_option("-s", "--start", type="int", default=0,
+ help="Specify where to start in the file [default=%default]")
+ parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+ help="Set the sampler rate of the data [default=%default]")
+
+ (options, args) = parser.parse_args ()
+ if len(args) < 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filenames = args
+
+ datatype=scipy.int32
+ dc = plot_data(datatype, filenames, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
diff --git a/gr-utils/python/gr_plot_iq b/gr-utils/python/gr_plot_iq
new file mode 100755
index 0000000000..bf8077b6b4
--- /dev/null
+++ b/gr-utils/python/gr_plot_iq
@@ -0,0 +1,178 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2008,2011 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.
+#
+
+try:
+ import scipy
+except ImportError:
+ print "Please install SciPy to run this script (http://www.scipy.org/)"
+ raise SystemExit, 1
+
+try:
+ from pylab import *
+except ImportError:
+ print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)"
+ raise SystemExit, 1
+
+from optparse import OptionParser
+
+class draw_iq:
+ def __init__(self, filename, options):
+ self.hfile = open(filename, "r")
+ self.block_length = options.block
+ self.start = options.start
+ self.sample_rate = options.sample_rate
+
+ self.datatype = scipy.complex64
+ self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file
+
+ self.axis_font_size = 16
+ self.label_font_size = 18
+ self.title_font_size = 20
+ self.text_size = 22
+
+ # Setup PLOT
+ self.fig = figure(1, figsize=(16, 9), facecolor='w')
+ rcParams['xtick.labelsize'] = self.axis_font_size
+ rcParams['ytick.labelsize'] = self.axis_font_size
+
+ self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size)
+ self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size)
+ self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length),
+ weight="heavy", size=self.text_size)
+ self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate),
+ weight="heavy", size=self.text_size)
+ self.make_plots()
+
+ self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+ self.button_left = Button(self.button_left_axes, "<")
+ self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+ self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+ self.button_right = Button(self.button_right_axes, ">")
+ self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+ self.xlim = self.sp_iq.get_xlim()
+
+ self.manager = get_current_fig_manager()
+ connect('key_press_event', self.click)
+ show()
+
+ def get_data(self):
+ self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data))
+ try:
+ self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length)
+ except MemoryError:
+ print "End of File"
+ else:
+ self.reals = scipy.array([r.real for r in self.iq])
+ self.imags = scipy.array([i.imag for i in self.iq])
+ self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))])
+
+ def make_plots(self):
+ # if specified on the command-line, set file pointer
+ self.hfile.seek(self.sizeof_data*self.start, 1)
+
+ self.get_data()
+
+ # Subplot for real and imaginary parts of signal
+ self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.14, 0.85, 0.67])
+ self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold")
+ self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+ self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+ self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-')
+ self.sp_iq.set_ylim([1.5*min([self.reals.min(), self.imags.min()]),
+ 1.5*max([self.reals.max(), self.imags.max()])])
+ self.sp_iq.set_xlim(self.time.min(), self.time.max())
+ draw()
+
+ def update_plots(self):
+ self.plot_iq[0].set_data([self.time, self.reals])
+ self.plot_iq[1].set_data([self.time, self.imags])
+ self.sp_iq.set_ylim([1.5*min([self.reals.min(), self.imags.min()]),
+ 1.5*max([self.reals.max(), self.imags.max()])])
+ self.sp_iq.set_xlim(self.time.min(), self.time.max())
+ draw()
+
+ def click(self, event):
+ forward_valid_keys = [" ", "down", "right"]
+ backward_valid_keys = ["up", "left"]
+
+ if(find(event.key, forward_valid_keys)):
+ self.step_forward()
+
+ elif(find(event.key, backward_valid_keys)):
+ self.step_backward()
+
+ def button_left_click(self, event):
+ self.step_backward()
+
+ def button_right_click(self, event):
+ self.step_forward()
+
+ def step_forward(self):
+ self.get_data()
+ self.update_plots()
+
+ def step_backward(self):
+ # Step back in file position
+ if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ):
+ self.hfile.seek(-2*self.sizeof_data*self.block_length, 1)
+ else:
+ self.hfile.seek(-self.hfile.tell(),1)
+ self.get_data()
+ self.update_plots()
+
+
+def find(item_in, list_search):
+ try:
+ return list_search.index(item_in) != None
+ except ValueError:
+ return False
+
+def main():
+ usage="%prog: [options] input_filename"
+ description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+ parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+ parser.add_option("-B", "--block", type="int", default=1000,
+ help="Specify the block size [default=%default]")
+ parser.add_option("-s", "--start", type="int", default=0,
+ help="Specify where to start in the file [default=%default]")
+ parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+ help="Set the sampler rate of the data [default=%default]")
+
+ (options, args) = parser.parse_args ()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filename = args[0]
+
+ dc = draw_iq(filename, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
+
+
diff --git a/gr-utils/python/gr_plot_psd b/gr-utils/python/gr_plot_psd
new file mode 100644
index 0000000000..059ca6b645
--- /dev/null
+++ b/gr-utils/python/gr_plot_psd
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 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.plot_psd_base import plot_psd_base
+
+# This is a wrapper program for plot_psd_base. It handles any data
+# type and defaults to complex64.
+
+def main():
+ parser = plot_psd_base.setup_options()
+ (options, args) = parser.parse_args ()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filename = args[0]
+
+ dc = plot_psd_base(options.data_type, filename, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
diff --git a/gr-utils/python/gr_plot_psd_c b/gr-utils/python/gr_plot_psd_c
new file mode 100755
index 0000000000..fff2bff0f2
--- /dev/null
+++ b/gr-utils/python/gr_plot_psd_c
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+#
+# Copyright 2008 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 optparse import OptionParser
+from gnuradio.plot_psd_base import plot_psd_base
+
+# This is a wrapper program for plot_psd_base specifically for complex data
+
+def main():
+ parser = plot_psd_base.setup_options()
+ parser.remove_option("--data-type")
+
+ (options, args) = parser.parse_args ()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filename = args[0]
+
+ dc = plot_psd_base("complex64", filename, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
+
+
diff --git a/gr-utils/python/gr_plot_psd_f b/gr-utils/python/gr_plot_psd_f
new file mode 100755
index 0000000000..ec67994797
--- /dev/null
+++ b/gr-utils/python/gr_plot_psd_f
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+#
+# Copyright 2008 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 optparse import OptionParser
+from gnuradio.plot_psd_base import plot_psd_base
+
+# This is a wrapper program for gr_plot_psd specifically for floating point data
+
+def main():
+ parser = plot_psd_base.setup_options()
+ parser.remove_option("--data-type")
+
+ (options, args) = parser.parse_args ()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filename = args[0]
+
+ dc = plot_psd_base("float32", filename, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
+
+
diff --git a/gr-utils/python/gr_plot_qt b/gr-utils/python/gr_plot_qt
new file mode 100755
index 0000000000..153359f0c6
--- /dev/null
+++ b/gr-utils/python/gr_plot_qt
@@ -0,0 +1,729 @@
+#!/usr/bin/env python
+
+try:
+ import scipy
+ from scipy import fftpack
+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 gnuradio.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 optparse import OptionParser
+from gnuradio import eng_notation
+
+
+class SpectrogramData(Qwt.QwtRasterData):
+
+ def __init__(self, f, t):
+ Qwt.QwtArrayData.__init__(self, Qt.QRectF(0, 0, 0, 0))
+ self.sp = scipy.array([[0], [0]])
+
+ def set_data(self, xfreq, ytime, data):
+ self.sp = data
+ self.freq = xfreq
+ self.time = ytime
+ boundingBox = Qt.QRectF(self.freq.min(), self.time.min(),
+ self.freq.max() - self.freq.min(),
+ self.time.max() - self.time.min())
+ self.setBoundingRect(boundingBox)
+
+ def rasterHint(self, rect):
+ return Qt.QSize(self.sp.shape[0], self.sp.shape[1])
+
+ def copy(self):
+ return self
+
+ def range(self):
+
+ return Qwt.QwtDoubleInterval(self.sp.min(), self.sp.max())
+
+ def value(self, x, y):
+ 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):
+ def __init__(self, qapp, filename, options, parent=None):
+ QtGui.QWidget.__init__(self, parent)
+ 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
+ self.psdfftsize = options.psd_size
+ self.specfftsize = options.spec_size
+ self.winfunc = scipy.blackman
+ self.sizeof_data = 8
+ self.datatype = scipy.complex64
+ self.pen_width = 1
+ self.iq = list()
+ self.time = list()
+
+ # Set up basic plot attributes
+ self.gui.timePlot.setAxisTitle(self.gui.timePlot.xBottom, "Time (sec)")
+ self.gui.timePlot.setAxisTitle(self.gui.timePlot.yLeft, "Amplitude (V)")
+ self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.xBottom, "Frequency (Hz)")
+ self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.yLeft, "Magnitude (dB)")
+ self.gui.specPlot.setAxisTitle(self.gui.specPlot.xBottom, "Frequency (Hz)")
+ self.gui.specPlot.setAxisTitle(self.gui.specPlot.yLeft, "Time (sec)")
+
+ # Set up FFT size combo box
+ self.fftsizes = ["128", "256", "512", "1024", "2048",
+ "4096", "8192", "16384", "32768"]
+ self.gui.psdFFTComboBox.addItems(self.fftsizes)
+ self.gui.specFFTComboBox.addItems(self.fftsizes)
+ pos = self.gui.psdFFTComboBox.findText(Qt.QString("%1").arg(self.psdfftsize))
+ self.gui.psdFFTComboBox.setCurrentIndex(pos)
+ pos = self.gui.specFFTComboBox.findText(Qt.QString("%1").arg(self.specfftsize))
+ self.gui.specFFTComboBox.setCurrentIndex(pos)
+
+ self.connect(self.gui.psdFFTComboBox,
+ Qt.SIGNAL("activated (const QString&)"),
+ self.psdFFTComboBoxEdit)
+ self.connect(self.gui.specFFTComboBox,
+ Qt.SIGNAL("activated (const QString&)"),
+ self.specFFTComboBoxEdit)
+
+ # Set up color scheme box
+ self.color_modes = {"Black on White" : self.color_black_on_white,
+ "White on Black" : self.color_white_on_black,
+ "Blue on Black" : self.color_blue_on_black,
+ "Green on Black" : self.color_green_on_black}
+ self.gui.colorComboBox.addItems(self.color_modes.keys())
+ pos = self.gui.colorComboBox.findText("Blue on Black")
+ self.gui.colorComboBox.setCurrentIndex(pos)
+ self.connect(self.gui.colorComboBox,
+ Qt.SIGNAL("activated (const QString&)"),
+ 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,
+ Qwt.QwtPicker.PointSelection,
+ Qwt.QwtPicker.AlwaysOn,
+ self.gui.timePlot.canvas())
+
+ self.freqZoomer = Qwt.QwtPlotZoomer(self.gui.freqPlot.xBottom,
+ self.gui.freqPlot.yLeft,
+ Qwt.QwtPicker.PointSelection,
+ Qwt.QwtPicker.AlwaysOn,
+ self.gui.freqPlot.canvas())
+
+ self.specZoomer = Qwt.QwtPlotZoomer(self.gui.specPlot.xBottom,
+ self.gui.specPlot.yLeft,
+ Qwt.QwtPicker.PointSelection,
+ Qwt.QwtPicker.AlwaysOn,
+ self.gui.specPlot.canvas())
+
+ # Set up action when tab is changed
+ self.connect(self.gui.tabGroup,
+ Qt.SIGNAL("currentChanged (int)"),
+ self.tabChanged)
+
+ # Add a legend to the Time plot
+ legend_real = Qwt.QwtLegend()
+ self.gui.timePlot.insertLegend(legend_real)
+
+ # Set up slider
+ self.gui.plotHBar.setSingleStep(1)
+ self.gui.plotHBar.setPageStep(self.block_length)
+ self.gui.plotHBar.setMinimum(0)
+ self.gui.plotHBar.setMaximum(self.block_length)
+ self.connect(self.gui.plotHBar,
+ Qt.SIGNAL("valueChanged(int)"),
+ self.sliderMoved)
+
+ # Connect Open action to Open Dialog box
+ 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.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,
+ Qt.SIGNAL("editingFinished()"),
+ self.file_position_changed)
+ self.connect(self.gui.filePosStopLineEdit,
+ Qt.SIGNAL("editingFinished()"),
+ self.file_position_changed)
+ self.connect(self.gui.filePosLengthLineEdit,
+ Qt.SIGNAL("editingFinished()"),
+ self.file_length_changed)
+
+ self.connect(self.gui.fileTimeStartLineEdit,
+ Qt.SIGNAL("editingFinished()"),
+ self.file_time_changed)
+ self.connect(self.gui.fileTimeStopLineEdit,
+ Qt.SIGNAL("editingFinished()"),
+ self.file_time_changed)
+ self.connect(self.gui.fileTimeLengthLineEdit,
+ 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)
+
+ self.psdcurve = Qwt.QwtPlotCurve("PSD")
+ self.psdcurve.attach(self.gui.freqPlot)
+
+ # Set up specTab plot as a spectrogram
+ self.specdata = SpectrogramData(range(0, 10), range(0, 10))
+
+ colorMap = Qwt.QwtLinearColorMap(Qt.Qt.darkCyan, Qt.Qt.red)
+ colorMap.addColorStop(0.1, Qt.Qt.cyan)
+ colorMap.addColorStop(0.6, Qt.Qt.green)
+ colorMap.addColorStop(0.95, Qt.Qt.yellow)
+
+ self.spec = Qwt.QwtPlotSpectrogram()
+ self.spec.setColorMap(colorMap)
+ self.spec.attach(self.gui.specPlot)
+ self.spec.setDisplayMode(Qwt.QwtPlotSpectrogram.ImageMode, True)
+ self.spec.setData(self.specdata)
+
+ self.rightAxis = self.gui.specPlot.axisWidget(Qwt.QwtPlot.yRight)
+ self.rightAxis.setTitle("Magnitude (dBm)")
+ self.rightAxis.setColorBarEnabled(True)
+ self.rightAxis.setColorMap(self.spec.data().range(),
+ self.spec.colorMap())
+ self.gui.specPlot.enableAxis(Qwt.QwtPlot.yRight)
+
+ # 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,
+ Qt.SIGNAL("editingFinished()"),
+ self.sample_rate_changed)
+
+ if(filename is not None):
+ self.initialize(filename)
+
+ self.show()
+
+ def open_file(self):
+ filename = Qt.QFileDialog.getOpenFileName(self, "Open", ".")
+ if(filename != ""):
+ #print filename
+ self.initialize(filename)
+
+ def reload_file(self):
+ if(self.filename):
+ self.initialize(self.filename)
+
+ def initialize(self, filename):
+ self.filename = filename
+ self.hfile = open(filename, "r")
+
+ self.setWindowTitle(("GNU Radio File Plot Utility: %s" % filename))
+
+ self.gui.filePosStartLineEdit.setText("0")
+ self.gui.filePosStopLineEdit.setText("0")
+ self.gui.fileTimeStartLineEdit.setText("0")
+ self.gui.fileTimeStopLineEdit.setText("0")
+
+ self.cur_start = 0
+ self.cur_stop = self.block_length
+
+ self.init_data_input()
+ self.get_data(self.cur_start, self.cur_stop)
+ self.get_psd()
+ self.get_specgram()
+ self.gui.plotHBar.setSliderPosition(0)
+ self.gui.plotHBar.setMaximum(self.signal_size-self.block_length)
+
+
+ self.update_time_curves()
+ self.update_psd_curves()
+ self.update_specgram_curves()
+
+ 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
+ self.hfile.seek(0, os.SEEK_SET)
+
+ def get_data(self, start, end):
+ if(end > start):
+ self.hfile.seek(start*self.sizeof_data, os.SEEK_SET)
+ self.position = start
+ try:
+ iq = scipy.fromfile(self.hfile, dtype=self.datatype,
+ count=end-start)
+
+ if(len(iq) < (end-start)):
+ end = start + len(iq)
+ self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(len(iq)))
+ self.file_length_changed()
+
+ tstep = 1.0 / self.sample_rate
+ self.iq = iq
+ self.time = [tstep*(self.position + i) for i in xrange(len(self.iq))]
+
+ self.set_file_pos_box(start, end)
+ except MemoryError:
+ pass
+ else:
+ # Do we want to do anything about this?
+ pass
+
+ def get_psd(self):
+ winpoints = self.winfunc(self.psdfftsize)
+ iq_psd, freq = mlab.psd(self.iq, Fs=self.sample_rate,
+ NFFT=self.psdfftsize,
+ noverlap=self.psdfftsize/4.0,
+ window=winpoints,
+ scale_by_freq=False)
+
+ self.iq_psd = 10.0*scipy.log10(abs(fftpack.fftshift(iq_psd)))
+ self.freq = freq - self.sample_rate/2.0
+
+ def get_specgram(self):
+ winpoints = self.winfunc(self.specfftsize)
+ iq_spec, f, t = mlab.specgram(self.iq, Fs=self.sample_rate,
+ NFFT=self.specfftsize,
+ noverlap=self.specfftsize/4.0,
+ window=winpoints,
+ scale_by_freq=False)
+
+ self.iq_spec = 10.0*scipy.log10(abs(iq_spec))
+ self.spec_f = f
+ self.spec_t = t
+
+ def psdFFTComboBoxEdit(self, fftSize):
+ self.psdfftsize = fftSize.toInt()[0]
+ self.get_psd()
+ self.update_psd_curves()
+
+ def specFFTComboBoxEdit(self, fftSize):
+ self.specfftsize = fftSize.toInt()[0]
+ self.get_specgram()
+ self.update_specgram_curves()
+
+ def colorComboBoxEdit(self, colorSelection):
+ colorstr = str(colorSelection.toAscii())
+ 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()
+
+ self.get_data(pos_start, pos_end)
+ self.get_psd()
+ self.get_specgram()
+ self.update_time_curves()
+ self.update_psd_curves()
+ self.update_specgram_curves()
+
+ def set_sample_rate(self, sr):
+ self.sample_rate = sr
+ srstr = eng_notation.num_to_str(self.sample_rate)
+ self.gui.sampleRateLineEdit.setText(Qt.QString("%1").arg(srstr))
+
+ def sample_rate_changed(self):
+ srstr = self.gui.sampleRateLineEdit.text().toAscii()
+ self.sample_rate = eng_notation.str_to_num(srstr)
+ self.set_file_pos_box(self.cur_start, self.cur_stop)
+ self.get_data(self.cur_start, self.cur_stop)
+ self.get_psd()
+ self.get_specgram()
+ self.update_time_curves()
+ self.update_psd_curves()
+ self.update_specgram_curves()
+
+ def set_file_pos_box(self, start, end):
+ tstart = start / self.sample_rate
+ tend = end / self.sample_rate
+
+ self.gui.filePosStartLineEdit.setText(Qt.QString("%1").arg(start))
+ self.gui.filePosStopLineEdit.setText(Qt.QString("%1").arg(end))
+ self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(end-start))
+
+ self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart))
+ self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend))
+ self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tend-tstart))
+
+ def file_position_changed(self):
+ start = self.gui.filePosStartLineEdit.text().toInt()
+ end = self.gui.filePosStopLineEdit.text().toInt()
+ if((start[1] == True) and (end[1] == True)):
+ self.cur_start = start[0]
+ self.cur_stop = end[0]
+
+ tstart = self.cur_start / self.sample_rate
+ tend = self.cur_stop / self.sample_rate
+ self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart))
+ self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend))
+
+ self.get_data(self.cur_start, self.cur_stop)
+
+ self.update_time_curves()
+ self.update_psd_curves()
+ self.update_specgram_curves()
+
+ # If there's a non-digit character, reset box
+ else:
+ 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()
+ tstop = self.gui.fileTimeStopLineEdit.text().toDouble()
+ if((tstart[1] == True) and (tstop[1] == True)):
+ self.cur_start = int(tstart[0] * self.sample_rate)
+ self.cur_stop = int(tstop[0] * self.sample_rate)
+ self.get_data(self.cur_start, self.cur_stop)
+
+ self.gui.filePosStartLineEdit.setText(Qt.QString("%1").arg(self.cur_start))
+ self.gui.filePosStopLineEdit.setText(Qt.QString("%1").arg(self.cur_stop))
+
+ self.update_time_curves()
+ self.update_psd_curves()
+ self.update_specgram_curves()
+ # If there's a non-digit character, reset box
+ else:
+ self.set_file_pos_box(self.cur_start, self.cur_stop)
+
+ def file_length_changed(self):
+ start = self.gui.filePosStartLineEdit.text().toInt()
+ length = self.gui.filePosLengthLineEdit.text().toInt()
+
+ if((start[1] == True) and (length[1] == True)):
+ self.cur_start = start[0]
+ self.block_length = length[0]
+ self.cur_stop = self.cur_start + self.block_length
+
+ tstart = self.cur_start / self.sample_rate
+ tend = self.cur_stop / self.sample_rate
+ tlen = self.block_length / self.sample_rate
+ self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart))
+ self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend))
+ self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tlen))
+
+ self.gui.plotHBar.setPageStep(self.block_length)
+
+ self.get_data(self.cur_start, self.cur_stop)
+ self.get_psd()
+ self.get_specgram()
+
+ self.update_time_curves()
+ self.update_psd_curves()
+ self.update_specgram_curves()
+ # If there's a non-digit character, reset box
+ else:
+ self.set_file_pos_box(self.cur_start, self.cur_stop)
+
+ def file_time_length_changed(self):
+ tstart = self.gui.fileTimeStartLineEdit.text().toDouble()
+ tlength = self.gui.fileTimeLengthLineEdit.text().toDouble()
+ if((tstart[1] == True) and (tlength[1] == True)):
+ self.cur_start = int(tstart[0] * self.sample_rate)
+ self.block_length = int(tlength[0] * self.sample_rate)
+ self.cur_stop = self.cur_start + self.block_length
+
+ tstart = self.cur_start / self.sample_rate
+ tend = self.cur_stop / self.sample_rate
+ tlen = self.block_length / self.sample_rate
+ self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart))
+ self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend))
+ self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tlen))
+
+ self.get_data(self.cur_start, self.cur_stop)
+ self.get_psd()
+ self.get_specgram()
+
+ self.update_time_curves()
+ self.update_psd_curves()
+ self.update_specgram_curves()
+ # If there's a non-digit character, reset box
+ else:
+ self.set_file_pos_box(self.cur_start, self.cur_stop)
+
+
+ def update_time_curves(self):
+ self.icurve.setData(self.time, self.iq.imag)
+ self.rcurve.setData(self.time, self.iq.real)
+
+ # Reset the x-axis to the new time scale
+ iqmax = 1.5 * max(max(self.iq.real), max(self.iq.imag))
+ iqmin = 1.5 * min(min(self.iq.real), min(self.iq.imag))
+ self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom,
+ min(self.time),
+ max(self.time))
+ self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft,
+ iqmin,
+ iqmax)
+
+ # Set the zoomer base to unzoom to the new axis
+ self.timeZoomer.setZoomBase()
+
+ self.gui.timePlot.replot()
+
+ def update_psd_curves(self):
+ self.psdcurve.setData(self.freq, self.iq_psd)
+
+ self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom,
+ min(self.freq),
+ max(self.freq))
+
+ # Set the zoomer base to unzoom to the new axis
+ self.freqZoomer.setZoomBase()
+
+ self.gui.freqPlot.replot()
+
+ def update_specgram_curves(self):
+ # We don't have to reset the data for the speccurve here
+ # since this is taken care of in the SpectrogramData class
+ self.specdata.set_data(self.spec_f, self.spec_t, self.iq_spec)
+
+ # Set the color map based on the new data
+ self.rightAxis.setColorMap(self.spec.data().range(),
+ self.spec.colorMap())
+
+ # Set the new axis base; include right axis for the intenisty color bar
+ self.gui.specPlot.setAxisScale(self.gui.specPlot.xBottom,
+ min(self.spec_f),
+ max(self.spec_f))
+ self.gui.specPlot.setAxisScale(self.gui.specPlot.yLeft,
+ min(self.spec_t),
+ max(self.spec_t))
+ self.gui.specPlot.setAxisScale(self.gui.specPlot.yRight,
+ self.iq_spec.min(),
+ self.iq_spec.max())
+
+ # Set the zoomer base to unzoom to the new axis
+ self.specZoomer.setZoomBase()
+
+ self.gui.specPlot.replot()
+
+ 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)
+
+ 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.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()
+
+ def color_white_on_black(self):
+ white = QtGui.qRgb(0xFF, 0xFF, 0xFF)
+ red = QtGui.qRgb(0xFF, 0x00, 0x00)
+
+ whiteBrush = Qt.QBrush(Qt.QColor("white"))
+ whiteBrush = Qt.QBrush(Qt.QColor(white))
+ redBrush = Qt.QBrush(Qt.QColor(red))
+
+ self.gui.timePlot.setCanvasBackground(QtGui.QColor("black"))
+ self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black"))
+ 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()
+
+
+ def color_green_on_black(self):
+ green = QtGui.qRgb(0x00, 0xFF, 0x00)
+ red = QtGui.qRgb(0xFF, 0x00, 0x50)
+
+ whiteBrush = Qt.QBrush(Qt.QColor("white"))
+ greenBrush = Qt.QBrush(Qt.QColor(green))
+ redBrush = Qt.QBrush(Qt.QColor(red))
+
+ self.gui.timePlot.setCanvasBackground(QtGui.QColor("black"))
+ self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black"))
+ 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()
+
+ def color_blue_on_black(self):
+ blue = QtGui.qRgb(0x00, 0x00, 0xFF)
+ red = QtGui.qRgb(0xFF, 0x00, 0x00)
+
+ whiteBrush = Qt.QBrush(Qt.QColor("white"))
+ blueBrush = Qt.QBrush(Qt.QColor(blue))
+ redBrush = Qt.QBrush(Qt.QColor(red))
+
+ self.gui.timePlot.setCanvasBackground(QtGui.QColor("black"))
+ self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black"))
+ 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()
+
+def setup_options():
+ usage="%prog: [options] (input_filename)"
+ description = ""
+
+ parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+ parser.add_option("-B", "--block-length", type="int", default=8192,
+ help="Specify the block size [default=%default]")
+ parser.add_option("-s", "--start", type="int", default=0,
+ help="Specify where to start in the file [default=%default]")
+ parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+ help="Set the sampler rate of the data [default=%default]")
+ parser.add_option("", "--psd-size", type="int", default=2048,
+ help="Set the size of the PSD FFT [default=%default]")
+ parser.add_option("", "--spec-size", type="int", default=2048,
+ help="Set the size of the spectrogram FFT [default=%default]")
+
+ return parser
+
+def main(args):
+ parser = setup_options()
+ (options, args) = parser.parse_args ()
+
+ if(len(args) == 1):
+ filename = args[0]
+ else:
+ filename = None
+
+ app = Qt.QApplication(args)
+ gplt = gr_plot_qt(app, filename, options)
+ app.exec_()
+
+if __name__ == '__main__':
+ main(sys.argv)
+
diff --git a/gr-utils/python/gr_plot_short b/gr-utils/python/gr_plot_short
new file mode 100755
index 0000000000..702a2a94a6
--- /dev/null
+++ b/gr-utils/python/gr_plot_short
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2008 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.
+#
+
+try:
+ import scipy
+except ImportError:
+ print "Please install SciPy to run this script (http://www.scipy.org/)"
+ raise SystemExit, 1
+
+from optparse import OptionParser
+from gnuradio.plot_data import plot_data
+
+def main():
+ usage="%prog: [options] input_filenames"
+ description = "Takes a GNU Radio short integer binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+ parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+ parser.add_option("-B", "--block", type="int", default=1000,
+ help="Specify the block size [default=%default]")
+ parser.add_option("-s", "--start", type="int", default=0,
+ help="Specify where to start in the file [default=%default]")
+ parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+ help="Set the sampler rate of the data [default=%default]")
+
+ (options, args) = parser.parse_args ()
+ if len(args) < 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filenames = args
+
+ datatype=scipy.int16
+ dc = plot_data(datatype, filenames, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
diff --git a/gr-utils/python/gr_read_file_metadata b/gr-utils/python/gr_read_file_metadata
new file mode 100644
index 0000000000..cf0cd5b116
--- /dev/null
+++ b/gr-utils/python/gr_read_file_metadata
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 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 sys
+from optparse import OptionParser
+
+from gruel import pmt
+from gnuradio.blocks import parse_file_metadata
+
+def main(filename, detached=False):
+ handle = open(filename, "rb")
+
+ nheaders = 0
+ nread = 0
+ while(True):
+ # read out next header bytes
+ hdr_start = handle.tell()
+ header_str = handle.read(parse_file_metadata.HEADER_LENGTH)
+ if(len(header_str) == 0):
+ break
+
+ # Convert from string to PMT (should be a dictionary)
+ try:
+ header = pmt.pmt_deserialize_str(header_str)
+ except RuntimeError:
+ sys.stderr.write("Could not deserialize header: invalid or corrupt data file.\n")
+ sys.exit(1)
+
+ print "HEADER {0}".format(nheaders)
+ info = parse_file_metadata.parse_header(header, True)
+
+ if(info["extra_len"] > 0):
+ extra_str = handle.read(info["extra_len"])
+ if(len(extra_str) == 0):
+ break
+
+ try:
+ extra = pmt.pmt_deserialize_str(extra_str)
+ except RuntimeError:
+ sys.stderr.write("Could not deserialize extras: invalid or corrupt data file.\n")
+ sys.exit(1)
+
+ print "\nExtra Header:"
+ extra_info = parse_file_metadata.parse_extra_dict(extra, info, True)
+
+ nheaders += 1
+ nread += parse_file_metadata.HEADER_LENGTH + info["extra_len"]
+ if(not detached):
+ nread += info['nbytes']
+ handle.seek(nread, 0)
+ print "\n\n"
+
+if __name__ == "__main__":
+ usage="%prog: [options] filename"
+ description = "Read in a GNU Radio file with meta data, extracts the header and prints it."
+
+ parser = OptionParser(conflict_handler="resolve",
+ usage=usage, description=description)
+ parser.add_option("-D", "--detached", action="store_true", default=False,
+ help="Used if header is detached.")
+ (options, args) = parser.parse_args ()
+
+ if(len(args) < 1):
+ sys.stderr.write("No filename given\n")
+ sys.exit(1)
+
+ filename = args[0]
+ main(filename, options.detached)
diff --git a/gr-utils/python/grcc b/gr-utils/python/grcc
new file mode 100755
index 0000000000..7e5665dc05
--- /dev/null
+++ b/gr-utils/python/grcc
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 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.
+#
+
+try:
+ from grc.python.Platform import Platform
+except ImportError:
+ from gnuradio.grc.python.Platform import Platform
+
+from optparse import OptionParser
+import os, sys
+
+class grcc:
+ def __init__(self, grcfile, out_dir):
+ self.out_dir = out_dir
+ self.platform = Platform()
+ data = self.platform.parse_flow_graph(grcfile)
+
+ self.fg = self.platform.get_new_flow_graph()
+ self.fg.import_data(data)
+ self.fg.validate()
+
+ self.gen = self.platform.get_generator()(self.fg, out_dir)
+ self.gen.write()
+
+ def exec_program(self):
+ progname = self.fg.get_option('id')
+ os.system("{0}/{1}.py".format(self.out_dir, progname))
+
+if __name__ == "__main__":
+ usage="%prog: [options] filename"
+ description = "Compiles a GRC file (.grc) into a GNU Radio Python program. The program is stored in ~/.grc_gnuradio by default, but this location can be changed with the -d option."
+
+ parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+ parser.add_option("-d", "--directory", type="string", default='{0}/.grc_gnuradio/'.format(os.environ["HOME"]),
+ help="Specify the directory to output the compile program [default=%default]")
+ parser.add_option("-e", "--execute", action="store_true", default=False,
+ help="Run the program after compiling [default=%default]")
+ (options, args) = parser.parse_args ()
+
+ if(len(args) != 1):
+ sys.stderr.write("Please specify a GRC file name to compile.\n")
+ sys.exit(1)
+
+ g = grcc(args[0], options.directory+"/")
+
+ if(options.execute):
+ g.exec_program()
diff --git a/gr-utils/python/plot_data.py b/gr-utils/python/plot_data.py
new file mode 100644
index 0000000000..2ae3b1d5b3
--- /dev/null
+++ b/gr-utils/python/plot_data.py
@@ -0,0 +1,168 @@
+#
+# Copyright 2007,2008,2011 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.
+#
+"""
+Utility to help plotting data from files.
+"""
+
+try:
+ import scipy
+except ImportError:
+ print "Please install SciPy to run this script (http://www.scipy.org/)"
+ raise SystemExit, 1
+
+try:
+ from pylab import *
+except ImportError:
+ print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)"
+ raise SystemExit, 1
+
+from optparse import OptionParser
+
+class plot_data:
+ def __init__(self, datatype, filenames, options):
+ self.hfile = list()
+ self.legend_text = list()
+ for f in filenames:
+ self.hfile.append(open(f, "r"))
+ self.legend_text.append(f)
+
+ self.block_length = options.block
+ self.start = options.start
+ self.sample_rate = options.sample_rate
+
+ self.datatype = datatype
+ self.sizeof_data = datatype().nbytes # number of bytes per sample in file
+
+ self.axis_font_size = 16
+ self.label_font_size = 18
+ self.title_font_size = 20
+ self.text_size = 22
+
+ # Setup PLOT
+ self.fig = figure(1, figsize=(16, 9), facecolor='w')
+ rcParams['xtick.labelsize'] = self.axis_font_size
+ rcParams['ytick.labelsize'] = self.axis_font_size
+
+ self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size)
+ self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length),
+ weight="heavy", size=self.text_size)
+ self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate),
+ weight="heavy", size=self.text_size)
+ self.make_plots()
+
+ self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+ self.button_left = Button(self.button_left_axes, "<")
+ self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+ self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+ self.button_right = Button(self.button_right_axes, ">")
+ self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+ self.xlim = self.sp_f.get_xlim()
+
+ self.manager = get_current_fig_manager()
+ connect('key_press_event', self.click)
+ show()
+
+ def get_data(self, hfile):
+ self.text_file_pos.set_text("File Position: %d" % (hfile.tell()//self.sizeof_data))
+ try:
+ f = scipy.fromfile(hfile, dtype=self.datatype, count=self.block_length)
+ except MemoryError:
+ print "End of File"
+ else:
+ self.f = scipy.array(f)
+ self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.f))])
+
+ def make_plots(self):
+ self.sp_f = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.875, 0.6])
+ self.sp_f.set_title(("Amplitude"), fontsize=self.title_font_size, fontweight="bold")
+ self.sp_f.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+ self.sp_f.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+ self.plot_f = list()
+
+ maxval = -1e12
+ minval = 1e12
+
+ for hf in self.hfile:
+ # if specified on the command-line, set file pointer
+ hf.seek(self.sizeof_data*self.start, 1)
+
+ self.get_data(hf)
+
+ # Subplot for real and imaginary parts of signal
+ self.plot_f += plot(self.time, self.f, 'o-')
+ maxval = max(maxval, self.f.max())
+ minval = min(minval, self.f.min())
+
+ self.sp_f.set_ylim([1.5*minval, 1.5*maxval])
+
+ self.leg = self.sp_f.legend(self.plot_f, self.legend_text)
+
+ draw()
+
+ def update_plots(self):
+ maxval = -1e12
+ minval = 1e12
+ for hf,p in zip(self.hfile,self.plot_f):
+ self.get_data(hf)
+ p.set_data([self.time, self.f])
+ maxval = max(maxval, self.f.max())
+ minval = min(minval, self.f.min())
+
+ self.sp_f.set_ylim([1.5*minval, 1.5*maxval])
+
+ draw()
+
+ def click(self, event):
+ forward_valid_keys = [" ", "down", "right"]
+ backward_valid_keys = ["up", "left"]
+
+ if(find(event.key, forward_valid_keys)):
+ self.step_forward()
+
+ elif(find(event.key, backward_valid_keys)):
+ self.step_backward()
+
+ def button_left_click(self, event):
+ self.step_backward()
+
+ def button_right_click(self, event):
+ self.step_forward()
+
+ def step_forward(self):
+ self.update_plots()
+
+ def step_backward(self):
+ for hf in self.hfile:
+ # Step back in file position
+ if(hf.tell() >= 2*self.sizeof_data*self.block_length ):
+ hf.seek(-2*self.sizeof_data*self.block_length, 1)
+ else:
+ hf.seek(-hf.tell(),1)
+ self.update_plots()
+
+
+def find(item_in, list_search):
+ try:
+ return list_search.index(item_in) != None
+ except ValueError:
+ return False
diff --git a/gr-utils/python/plot_fft_base.py b/gr-utils/python/plot_fft_base.py
new file mode 100755
index 0000000000..4afdc3a360
--- /dev/null
+++ b/gr-utils/python/plot_fft_base.py
@@ -0,0 +1,249 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2008,2011 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.
+#
+
+try:
+ import scipy
+ from scipy import fftpack
+except ImportError:
+ print "Please install SciPy to run this script (http://www.scipy.org/)"
+ raise SystemExit, 1
+
+try:
+ from pylab import *
+except ImportError:
+ print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)"
+ raise SystemExit, 1
+
+from optparse import OptionParser
+
+class plot_fft_base:
+ def __init__(self, datatype, filename, options):
+ self.hfile = open(filename, "r")
+ self.block_length = options.block
+ self.start = options.start
+ self.sample_rate = options.sample_rate
+
+ self.datatype = getattr(scipy, datatype)
+ self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file
+
+ self.axis_font_size = 16
+ self.label_font_size = 18
+ self.title_font_size = 20
+ self.text_size = 22
+
+ # Setup PLOT
+ self.fig = figure(1, figsize=(16, 12), facecolor='w')
+ rcParams['xtick.labelsize'] = self.axis_font_size
+ rcParams['ytick.labelsize'] = self.axis_font_size
+
+ self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size)
+ self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size)
+ self.text_block = figtext(0.35, 0.88, ("Block Size: %d" % self.block_length),
+ weight="heavy", size=self.text_size)
+ self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate),
+ weight="heavy", size=self.text_size)
+ self.make_plots()
+
+ self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+ self.button_left = Button(self.button_left_axes, "<")
+ self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+ self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+ self.button_right = Button(self.button_right_axes, ">")
+ self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+ self.xlim = self.sp_iq.get_xlim()
+
+ self.manager = get_current_fig_manager()
+ connect('draw_event', self.zoom)
+ connect('key_press_event', self.click)
+ show()
+
+ def get_data(self):
+ self.position = self.hfile.tell()/self.sizeof_data
+ self.text_file_pos.set_text("File Position: %d" % (self.position))
+ try:
+ self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length)
+ except MemoryError:
+ print "End of File"
+ else:
+ self.iq_fft = self.dofft(self.iq)
+
+ tstep = 1.0 / self.sample_rate
+ #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))])
+ self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))])
+
+ self.freq = self.calc_freq(self.time, self.sample_rate)
+
+ def dofft(self, iq):
+ N = len(iq)
+ iq_fft = scipy.fftpack.fftshift(scipy.fft(iq)) # fft and shift axis
+ iq_fft = 20*scipy.log10(abs((iq_fft+1e-15)/N)) # convert to decibels, adjust power
+ # adding 1e-15 (-300 dB) to protect against value errors if an item in iq_fft is 0
+ return iq_fft
+
+ def calc_freq(self, time, sample_rate):
+ N = len(time)
+ Fs = 1.0 / (time.max() - time.min())
+ Fn = 0.5 * sample_rate
+ freq = scipy.array([-Fn + i*Fs for i in xrange(N)])
+ return freq
+
+ def make_plots(self):
+ # if specified on the command-line, set file pointer
+ self.hfile.seek(self.sizeof_data*self.start, 1)
+
+ # Subplot for real and imaginary parts of signal
+ self.sp_iq = self.fig.add_subplot(2,2,1, position=[0.075, 0.2, 0.4, 0.6])
+ self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold")
+ self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+ self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+
+ # Subplot for FFT plot
+ self.sp_fft = self.fig.add_subplot(2,2,2, position=[0.575, 0.2, 0.4, 0.6])
+ self.sp_fft.set_title(("FFT"), fontsize=self.title_font_size, fontweight="bold")
+ self.sp_fft.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold")
+ self.sp_fft.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold")
+
+ self.get_data()
+
+ self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals
+ self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags
+ self.draw_time() # draw the plot
+
+ self.plot_fft = self.sp_fft.plot([], 'bo-') # make plot for FFT
+ self.draw_fft() # draw the plot
+
+ draw()
+
+ def draw_time(self):
+ reals = self.iq.real
+ imags = self.iq.imag
+ self.plot_iq[0].set_data([self.time, reals])
+ self.plot_iq[1].set_data([self.time, imags])
+ self.sp_iq.set_xlim(self.time.min(), self.time.max())
+ self.sp_iq.set_ylim([1.5*min([reals.min(), imags.min()]),
+ 1.5*max([reals.max(), imags.max()])])
+
+ def draw_fft(self):
+ self.plot_fft[0].set_data([self.freq, self.iq_fft])
+ self.sp_fft.set_xlim(self.freq.min(), self.freq.max())
+ self.sp_fft.set_ylim([self.iq_fft.min()-10, self.iq_fft.max()+10])
+
+ def update_plots(self):
+ self.draw_time()
+ self.draw_fft()
+
+ self.xlim = self.sp_iq.get_xlim()
+ draw()
+
+ def zoom(self, event):
+ newxlim = scipy.array(self.sp_iq.get_xlim())
+ curxlim = scipy.array(self.xlim)
+ if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]):
+ self.xlim = newxlim
+ #xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position))))
+ #xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq))
+ xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0]))))
+ xmax = min(int(ceil(self.sample_rate*(self.xlim[1]))), len(self.iq))
+
+ iq = self.iq[xmin : xmax]
+ time = self.time[xmin : xmax]
+
+ iq_fft = self.dofft(iq)
+ freq = self.calc_freq(time, self.sample_rate)
+
+ self.plot_fft[0].set_data(freq, iq_fft)
+ self.sp_fft.axis([freq.min(), freq.max(),
+ iq_fft.min()-10, iq_fft.max()+10])
+
+ draw()
+
+ def click(self, event):
+ forward_valid_keys = [" ", "down", "right"]
+ backward_valid_keys = ["up", "left"]
+
+ if(find(event.key, forward_valid_keys)):
+ self.step_forward()
+
+ elif(find(event.key, backward_valid_keys)):
+ self.step_backward()
+
+ def button_left_click(self, event):
+ self.step_backward()
+
+ def button_right_click(self, event):
+ self.step_forward()
+
+ def step_forward(self):
+ self.get_data()
+ self.update_plots()
+
+ def step_backward(self):
+ # Step back in file position
+ if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ):
+ self.hfile.seek(-2*self.sizeof_data*self.block_length, 1)
+ else:
+ self.hfile.seek(-self.hfile.tell(),1)
+ self.get_data()
+ self.update_plots()
+
+ @staticmethod
+ def setup_options():
+ usage="%prog: [options] input_filename"
+ description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+ parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+ parser.add_option("-d", "--data-type", type="string", default="complex64",
+ help="Specify the data type (complex64, float32, (u)int32, (u)int16, (u)int8) [default=%default]")
+ parser.add_option("-B", "--block", type="int", default=1000,
+ help="Specify the block size [default=%default]")
+ parser.add_option("-s", "--start", type="int", default=0,
+ help="Specify where to start in the file [default=%default]")
+ parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+ help="Set the sampler rate of the data [default=%default]")
+ return parser
+
+def find(item_in, list_search):
+ try:
+ return list_search.index(item_in) != None
+ except ValueError:
+ return False
+
+def main():
+ parser = plot_fft_base.setup_options()
+ (options, args) = parser.parse_args ()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filename = args[0]
+
+ dc = plot_fft_base(options.data_type, filename, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
+
+
diff --git a/gr-utils/python/plot_psd_base.py b/gr-utils/python/plot_psd_base.py
new file mode 100755
index 0000000000..fe3c9e12b7
--- /dev/null
+++ b/gr-utils/python/plot_psd_base.py
@@ -0,0 +1,292 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2008,2010,2011 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.
+#
+
+try:
+ import scipy
+ from scipy import fftpack
+except ImportError:
+ print "Please install SciPy to run this script (http://www.scipy.org/)"
+ raise SystemExit, 1
+
+try:
+ from pylab import *
+except ImportError:
+ print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)"
+ raise SystemExit, 1
+
+from optparse import OptionParser
+from scipy import log10
+from gnuradio.eng_option import eng_option
+
+class plot_psd_base:
+ def __init__(self, datatype, filename, options):
+ self.hfile = open(filename, "r")
+ self.block_length = options.block
+ self.start = options.start
+ self.sample_rate = options.sample_rate
+ self.psdfftsize = options.psd_size
+ self.specfftsize = options.spec_size
+
+ self.dospec = options.enable_spec # if we want to plot the spectrogram
+
+ self.datatype = getattr(scipy, datatype) #scipy.complex64
+ self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file
+
+ self.axis_font_size = 16
+ self.label_font_size = 18
+ self.title_font_size = 20
+ self.text_size = 22
+
+ # Setup PLOT
+ self.fig = figure(1, figsize=(16, 12), facecolor='w')
+ rcParams['xtick.labelsize'] = self.axis_font_size
+ rcParams['ytick.labelsize'] = self.axis_font_size
+
+ self.text_file = figtext(0.10, 0.95, ("File: %s" % filename),
+ weight="heavy", size=self.text_size)
+ self.text_file_pos = figtext(0.10, 0.92, "File Position: ",
+ weight="heavy", size=self.text_size)
+ self.text_block = figtext(0.35, 0.92, ("Block Size: %d" % self.block_length),
+ weight="heavy", size=self.text_size)
+ self.text_sr = figtext(0.60, 0.915, ("Sample Rate: %.2f" % self.sample_rate),
+ weight="heavy", size=self.text_size)
+ self.make_plots()
+
+ self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+ self.button_left = Button(self.button_left_axes, "<")
+ self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+ self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+ self.button_right = Button(self.button_right_axes, ">")
+ self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+ self.xlim = scipy.array(self.sp_iq.get_xlim())
+
+ self.manager = get_current_fig_manager()
+ connect('draw_event', self.zoom)
+ connect('key_press_event', self.click)
+ show()
+
+ def get_data(self):
+ self.position = self.hfile.tell()/self.sizeof_data
+ self.text_file_pos.set_text("File Position: %d" % self.position)
+ try:
+ self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length)
+ except MemoryError:
+ print "End of File"
+ return False
+ else:
+ # retesting length here as newer version of scipy does not throw a MemoryError, just
+ # returns a zero-length array
+ if(len(self.iq) > 0):
+ tstep = 1.0 / self.sample_rate
+ #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))])
+ self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))])
+
+ self.iq_psd, self.freq = self.dopsd(self.iq)
+ return True
+ else:
+ print "End of File"
+ return False
+
+ def dopsd(self, iq):
+ ''' Need to do this here and plot later so we can do the fftshift '''
+ overlap = self.psdfftsize/4
+ winfunc = scipy.blackman
+ psd,freq = mlab.psd(iq, self.psdfftsize, self.sample_rate,
+ window = lambda d: d*winfunc(self.psdfftsize),
+ noverlap = overlap)
+ psd = 10.0*log10(abs(psd))
+ return (psd, freq)
+
+ def make_plots(self):
+ # if specified on the command-line, set file pointer
+ self.hfile.seek(self.sizeof_data*self.start, 1)
+
+ iqdims = [[0.075, 0.2, 0.4, 0.6], [0.075, 0.55, 0.4, 0.3]]
+ psddims = [[0.575, 0.2, 0.4, 0.6], [0.575, 0.55, 0.4, 0.3]]
+ specdims = [0.2, 0.125, 0.6, 0.3]
+
+ # Subplot for real and imaginary parts of signal
+ self.sp_iq = self.fig.add_subplot(2,2,1, position=iqdims[self.dospec])
+ self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold")
+ self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+ self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+
+ # Subplot for PSD plot
+ self.sp_psd = self.fig.add_subplot(2,2,2, position=psddims[self.dospec])
+ self.sp_psd.set_title(("PSD"), fontsize=self.title_font_size, fontweight="bold")
+ self.sp_psd.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold")
+ self.sp_psd.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold")
+
+ r = self.get_data()
+
+ self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals
+ self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags
+ self.draw_time(self.time, self.iq) # draw the plot
+
+ self.plot_psd = self.sp_psd.plot([], 'b') # make plot for PSD
+ self.draw_psd(self.freq, self.iq_psd) # draw the plot
+
+
+ if self.dospec:
+ # Subplot for spectrogram plot
+ self.sp_spec = self.fig.add_subplot(2,2,3, position=specdims)
+ self.sp_spec.set_title(("Spectrogram"), fontsize=self.title_font_size, fontweight="bold")
+ self.sp_spec.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+ self.sp_spec.set_ylabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold")
+
+ self.draw_spec(self.time, self.iq)
+
+ draw()
+
+ def draw_time(self, t, iq):
+ reals = iq.real
+ imags = iq.imag
+ self.plot_iq[0].set_data([t, reals])
+ self.plot_iq[1].set_data([t, imags])
+ self.sp_iq.set_xlim(t.min(), t.max())
+ self.sp_iq.set_ylim([1.5*min([reals.min(), imags.min()]),
+ 1.5*max([reals.max(), imags.max()])])
+
+ def draw_psd(self, f, p):
+ self.plot_psd[0].set_data([f, p])
+ self.sp_psd.set_ylim([p.min()-10, p.max()+10])
+ self.sp_psd.set_xlim([f.min(), f.max()])
+
+ def draw_spec(self, t, s):
+ overlap = self.specfftsize/4
+ winfunc = scipy.blackman
+ self.sp_spec.clear()
+ self.sp_spec.specgram(s, self.specfftsize, self.sample_rate,
+ window = lambda d: d*winfunc(self.specfftsize),
+ noverlap = overlap, xextent=[t.min(), t.max()])
+
+ def update_plots(self):
+ self.draw_time(self.time, self.iq)
+ self.draw_psd(self.freq, self.iq_psd)
+
+ if self.dospec:
+ self.draw_spec(self.time, self.iq)
+
+ self.xlim = scipy.array(self.sp_iq.get_xlim()) # so zoom doesn't get called
+
+ draw()
+
+ def zoom(self, event):
+ newxlim = scipy.array(self.sp_iq.get_xlim())
+ curxlim = scipy.array(self.xlim)
+ if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]):
+ #xmin = max(0, int(ceil(self.sample_rate*(newxlim[0] - self.position))))
+ #xmax = min(int(ceil(self.sample_rate*(newxlim[1] - self.position))), len(self.iq))
+ xmin = max(0, int(ceil(self.sample_rate*(newxlim[0]))))
+ xmax = min(int(ceil(self.sample_rate*(newxlim[1]))), len(self.iq))
+
+ iq = scipy.array(self.iq[xmin : xmax])
+ time = scipy.array(self.time[xmin : xmax])
+
+ iq_psd, freq = self.dopsd(iq)
+
+ self.draw_psd(freq, iq_psd)
+ self.xlim = scipy.array(self.sp_iq.get_xlim())
+
+ draw()
+
+ def click(self, event):
+ forward_valid_keys = [" ", "down", "right"]
+ backward_valid_keys = ["up", "left"]
+
+ if(find(event.key, forward_valid_keys)):
+ self.step_forward()
+
+ elif(find(event.key, backward_valid_keys)):
+ self.step_backward()
+
+ def button_left_click(self, event):
+ self.step_backward()
+
+ def button_right_click(self, event):
+ self.step_forward()
+
+ def step_forward(self):
+ r = self.get_data()
+ if(r):
+ self.update_plots()
+
+ def step_backward(self):
+ # Step back in file position
+ if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ):
+ self.hfile.seek(-2*self.sizeof_data*self.block_length, 1)
+ else:
+ self.hfile.seek(-self.hfile.tell(),1)
+ r = self.get_data()
+ if(r):
+ self.update_plots()
+
+ @staticmethod
+ def setup_options():
+ usage="%prog: [options] input_filename"
+ description = "Takes a GNU Radio binary file (with specified data type using --data-type) and displays the I&Q data versus time as well as the power spectral density (PSD) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. Finally, the size of the FFT to use for the PSD and spectrogram plots can be set independently with --psd-size and --spec-size, respectively. The spectrogram plot does not display by default and is turned on with -S or --enable-spec."
+
+ parser = OptionParser(option_class=eng_option, conflict_handler="resolve",
+ usage=usage, description=description)
+ parser.add_option("-d", "--data-type", type="string", default="complex64",
+ help="Specify the data type (complex64, float32, (u)int32, (u)int16, (u)int8) [default=%default]")
+ parser.add_option("-B", "--block", type="int", default=8192,
+ help="Specify the block size [default=%default]")
+ parser.add_option("-s", "--start", type="int", default=0,
+ help="Specify where to start in the file [default=%default]")
+ parser.add_option("-R", "--sample-rate", type="eng_float", default=1.0,
+ help="Set the sampler rate of the data [default=%default]")
+ parser.add_option("", "--psd-size", type="int", default=1024,
+ help="Set the size of the PSD FFT [default=%default]")
+ parser.add_option("", "--spec-size", type="int", default=256,
+ help="Set the size of the spectrogram FFT [default=%default]")
+ parser.add_option("-S", "--enable-spec", action="store_true", default=False,
+ help="Turn on plotting the spectrogram [default=%default]")
+
+ return parser
+
+def find(item_in, list_search):
+ try:
+ return list_search.index(item_in) != None
+ except ValueError:
+ return False
+
+def main():
+ parser = plot_psd_base.setup_options()
+ (options, args) = parser.parse_args ()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit, 1
+ filename = args[0]
+
+ dc = plot_psd_base(options.data_type, filename, options)
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
+
+
diff --git a/gr-utils/python/pyqt_filter.py b/gr-utils/python/pyqt_filter.py
new file mode 100644
index 0000000000..0c781f2347
--- /dev/null
+++ b/gr-utils/python/pyqt_filter.py
@@ -0,0 +1,435 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'pyqt_filter.ui'
+#
+# Created: Thu Mar 17 10:51:17 2011
+# by: PyQt4 UI code generator 4.7.4
+#
+# WARNING! All changes made in this file will be lost!
+
+from PyQt4 import QtCore, QtGui
+
+class Ui_MainWindow(object):
+ def setupUi(self, MainWindow):
+ MainWindow.setObjectName("MainWindow")
+ MainWindow.resize(1124, 696)
+ self.centralwidget = QtGui.QWidget(MainWindow)
+ self.centralwidget.setObjectName("centralwidget")
+ self.gridLayout = QtGui.QGridLayout(self.centralwidget)
+ self.gridLayout.setObjectName("gridLayout")
+ self.filterFrame = QtGui.QFrame(self.centralwidget)
+ self.filterFrame.setMinimumSize(QtCore.QSize(300, 0))
+ self.filterFrame.setMaximumSize(QtCore.QSize(300, 16777215))
+ self.filterFrame.setFrameShape(QtGui.QFrame.StyledPanel)
+ self.filterFrame.setFrameShadow(QtGui.QFrame.Raised)
+ self.filterFrame.setObjectName("filterFrame")
+ self.verticalLayout = QtGui.QVBoxLayout(self.filterFrame)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.filterTypeComboBox = QtGui.QComboBox(self.filterFrame)
+ self.filterTypeComboBox.setObjectName("filterTypeComboBox")
+ self.filterTypeComboBox.addItem("")
+ self.filterTypeComboBox.addItem("")
+ self.filterTypeComboBox.addItem("")
+ self.filterTypeComboBox.addItem("")
+ self.filterTypeComboBox.addItem("")
+ self.filterTypeComboBox.addItem("")
+ self.filterTypeComboBox.addItem("")
+ self.verticalLayout.addWidget(self.filterTypeComboBox)
+ self.filterDesignTypeComboBox = QtGui.QComboBox(self.filterFrame)
+ self.filterDesignTypeComboBox.setObjectName("filterDesignTypeComboBox")
+ self.filterDesignTypeComboBox.addItem("")
+ self.filterDesignTypeComboBox.addItem("")
+ self.filterDesignTypeComboBox.addItem("")
+ self.filterDesignTypeComboBox.addItem("")
+ self.filterDesignTypeComboBox.addItem("")
+ self.filterDesignTypeComboBox.addItem("")
+ self.filterDesignTypeComboBox.addItem("")
+ self.verticalLayout.addWidget(self.filterDesignTypeComboBox)
+ self.globalParamsLayout = QtGui.QFormLayout()
+ self.globalParamsLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow)
+ self.globalParamsLayout.setObjectName("globalParamsLayout")
+ self.sampleRateLabel = QtGui.QLabel(self.filterFrame)
+ self.sampleRateLabel.setMaximumSize(QtCore.QSize(16777215, 30))
+ self.sampleRateLabel.setObjectName("sampleRateLabel")
+ self.globalParamsLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.sampleRateLabel)
+ self.sampleRateEdit = QtGui.QLineEdit(self.filterFrame)
+ self.sampleRateEdit.setMaximumSize(QtCore.QSize(16777215, 30))
+ self.sampleRateEdit.setObjectName("sampleRateEdit")
+ self.globalParamsLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.sampleRateEdit)
+ self.filterGainLabel = QtGui.QLabel(self.filterFrame)
+ self.filterGainLabel.setObjectName("filterGainLabel")
+ self.globalParamsLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.filterGainLabel)
+ self.filterGainEdit = QtGui.QLineEdit(self.filterFrame)
+ self.filterGainEdit.setObjectName("filterGainEdit")
+ self.globalParamsLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.filterGainEdit)
+ self.verticalLayout.addLayout(self.globalParamsLayout)
+ self.filterTypeWidget = QtGui.QStackedWidget(self.filterFrame)
+ self.filterTypeWidget.setObjectName("filterTypeWidget")
+ self.firlpfPage = QtGui.QWidget()
+ self.firlpfPage.setObjectName("firlpfPage")
+ self.formLayout = QtGui.QFormLayout(self.firlpfPage)
+ self.formLayout.setObjectName("formLayout")
+ self.endofLpfPassBandLabel = QtGui.QLabel(self.firlpfPage)
+ self.endofLpfPassBandLabel.setObjectName("endofLpfPassBandLabel")
+ self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.endofLpfPassBandLabel)
+ self.endofLpfPassBandEdit = QtGui.QLineEdit(self.firlpfPage)
+ self.endofLpfPassBandEdit.setObjectName("endofLpfPassBandEdit")
+ self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.endofLpfPassBandEdit)
+ self.startofLpfStopBandLabel = QtGui.QLabel(self.firlpfPage)
+ self.startofLpfStopBandLabel.setObjectName("startofLpfStopBandLabel")
+ self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.startofLpfStopBandLabel)
+ self.startofLpfStopBandEdit = QtGui.QLineEdit(self.firlpfPage)
+ self.startofLpfStopBandEdit.setObjectName("startofLpfStopBandEdit")
+ self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.startofLpfStopBandEdit)
+ self.lpfStopBandAttenLabel = QtGui.QLabel(self.firlpfPage)
+ self.lpfStopBandAttenLabel.setObjectName("lpfStopBandAttenLabel")
+ self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.lpfStopBandAttenLabel)
+ self.lpfStopBandAttenEdit = QtGui.QLineEdit(self.firlpfPage)
+ self.lpfStopBandAttenEdit.setObjectName("lpfStopBandAttenEdit")
+ self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.lpfStopBandAttenEdit)
+ self.lpfPassBandRippleEdit = QtGui.QLineEdit(self.firlpfPage)
+ self.lpfPassBandRippleEdit.setObjectName("lpfPassBandRippleEdit")
+ self.formLayout.setWidget(3, QtGui.QFormLayout.FieldRole, self.lpfPassBandRippleEdit)
+ self.lpfPassBandRippleLabel = QtGui.QLabel(self.firlpfPage)
+ self.lpfPassBandRippleLabel.setObjectName("lpfPassBandRippleLabel")
+ self.formLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.lpfPassBandRippleLabel)
+ self.filterTypeWidget.addWidget(self.firlpfPage)
+ self.firbpfPage = QtGui.QWidget()
+ self.firbpfPage.setObjectName("firbpfPage")
+ self.formLayout_2 = QtGui.QFormLayout(self.firbpfPage)
+ self.formLayout_2.setObjectName("formLayout_2")
+ self.startofBpfPassBandLabel = QtGui.QLabel(self.firbpfPage)
+ self.startofBpfPassBandLabel.setObjectName("startofBpfPassBandLabel")
+ self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.startofBpfPassBandLabel)
+ self.startofBpfPassBandEdit = QtGui.QLineEdit(self.firbpfPage)
+ self.startofBpfPassBandEdit.setObjectName("startofBpfPassBandEdit")
+ self.formLayout_2.setWidget(0, QtGui.QFormLayout.FieldRole, self.startofBpfPassBandEdit)
+ self.endofBpfPassBandLabel = QtGui.QLabel(self.firbpfPage)
+ self.endofBpfPassBandLabel.setObjectName("endofBpfPassBandLabel")
+ self.formLayout_2.setWidget(1, QtGui.QFormLayout.LabelRole, self.endofBpfPassBandLabel)
+ self.endofBpfPassBandEdit = QtGui.QLineEdit(self.firbpfPage)
+ self.endofBpfPassBandEdit.setObjectName("endofBpfPassBandEdit")
+ self.formLayout_2.setWidget(1, QtGui.QFormLayout.FieldRole, self.endofBpfPassBandEdit)
+ self.bpfStopBandAttenEdit = QtGui.QLineEdit(self.firbpfPage)
+ self.bpfStopBandAttenEdit.setObjectName("bpfStopBandAttenEdit")
+ self.formLayout_2.setWidget(3, QtGui.QFormLayout.FieldRole, self.bpfStopBandAttenEdit)
+ self.bpfStopBandAttenLabel = QtGui.QLabel(self.firbpfPage)
+ self.bpfStopBandAttenLabel.setObjectName("bpfStopBandAttenLabel")
+ self.formLayout_2.setWidget(3, QtGui.QFormLayout.LabelRole, self.bpfStopBandAttenLabel)
+ self.bpfTransitionLabel = QtGui.QLabel(self.firbpfPage)
+ self.bpfTransitionLabel.setObjectName("bpfTransitionLabel")
+ self.formLayout_2.setWidget(2, QtGui.QFormLayout.LabelRole, self.bpfTransitionLabel)
+ self.bpfTransitionEdit = QtGui.QLineEdit(self.firbpfPage)
+ self.bpfTransitionEdit.setObjectName("bpfTransitionEdit")
+ self.formLayout_2.setWidget(2, QtGui.QFormLayout.FieldRole, self.bpfTransitionEdit)
+ self.bpfPassBandRippleEdit = QtGui.QLineEdit(self.firbpfPage)
+ self.bpfPassBandRippleEdit.setObjectName("bpfPassBandRippleEdit")
+ self.formLayout_2.setWidget(4, QtGui.QFormLayout.FieldRole, self.bpfPassBandRippleEdit)
+ self.bpfPassBandRippleLabel = QtGui.QLabel(self.firbpfPage)
+ self.bpfPassBandRippleLabel.setObjectName("bpfPassBandRippleLabel")
+ self.formLayout_2.setWidget(4, QtGui.QFormLayout.LabelRole, self.bpfPassBandRippleLabel)
+ self.filterTypeWidget.addWidget(self.firbpfPage)
+ self.firbnfPage = QtGui.QWidget()
+ self.firbnfPage.setObjectName("firbnfPage")
+ self.formLayout_5 = QtGui.QFormLayout(self.firbnfPage)
+ self.formLayout_5.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow)
+ self.formLayout_5.setObjectName("formLayout_5")
+ self.startofBnfStopBandLabel = QtGui.QLabel(self.firbnfPage)
+ self.startofBnfStopBandLabel.setObjectName("startofBnfStopBandLabel")
+ self.formLayout_5.setWidget(0, QtGui.QFormLayout.LabelRole, self.startofBnfStopBandLabel)
+ self.startofBnfStopBandEdit = QtGui.QLineEdit(self.firbnfPage)
+ self.startofBnfStopBandEdit.setObjectName("startofBnfStopBandEdit")
+ self.formLayout_5.setWidget(0, QtGui.QFormLayout.FieldRole, self.startofBnfStopBandEdit)
+ self.endofBnfStopBandLabel = QtGui.QLabel(self.firbnfPage)
+ self.endofBnfStopBandLabel.setObjectName("endofBnfStopBandLabel")
+ self.formLayout_5.setWidget(1, QtGui.QFormLayout.LabelRole, self.endofBnfStopBandLabel)
+ self.endofBnfStopBandEdit = QtGui.QLineEdit(self.firbnfPage)
+ self.endofBnfStopBandEdit.setObjectName("endofBnfStopBandEdit")
+ self.formLayout_5.setWidget(1, QtGui.QFormLayout.FieldRole, self.endofBnfStopBandEdit)
+ self.bnfTransitionLabel = QtGui.QLabel(self.firbnfPage)
+ self.bnfTransitionLabel.setObjectName("bnfTransitionLabel")
+ self.formLayout_5.setWidget(2, QtGui.QFormLayout.LabelRole, self.bnfTransitionLabel)
+ self.bnfTransitionEdit = QtGui.QLineEdit(self.firbnfPage)
+ self.bnfTransitionEdit.setObjectName("bnfTransitionEdit")
+ self.formLayout_5.setWidget(2, QtGui.QFormLayout.FieldRole, self.bnfTransitionEdit)
+ self.bnfStopBandAttenLabel = QtGui.QLabel(self.firbnfPage)
+ self.bnfStopBandAttenLabel.setObjectName("bnfStopBandAttenLabel")
+ self.formLayout_5.setWidget(3, QtGui.QFormLayout.LabelRole, self.bnfStopBandAttenLabel)
+ self.bnfStopBandAttenEdit = QtGui.QLineEdit(self.firbnfPage)
+ self.bnfStopBandAttenEdit.setObjectName("bnfStopBandAttenEdit")
+ self.formLayout_5.setWidget(3, QtGui.QFormLayout.FieldRole, self.bnfStopBandAttenEdit)
+ self.bnfPassBandRippleLabel = QtGui.QLabel(self.firbnfPage)
+ self.bnfPassBandRippleLabel.setObjectName("bnfPassBandRippleLabel")
+ self.formLayout_5.setWidget(4, QtGui.QFormLayout.LabelRole, self.bnfPassBandRippleLabel)
+ self.bnfPassBandRippleEdit = QtGui.QLineEdit(self.firbnfPage)
+ self.bnfPassBandRippleEdit.setObjectName("bnfPassBandRippleEdit")
+ self.formLayout_5.setWidget(4, QtGui.QFormLayout.FieldRole, self.bnfPassBandRippleEdit)
+ self.filterTypeWidget.addWidget(self.firbnfPage)
+ self.firhpfPage = QtGui.QWidget()
+ self.firhpfPage.setObjectName("firhpfPage")
+ self.formLayout_3 = QtGui.QFormLayout(self.firhpfPage)
+ self.formLayout_3.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow)
+ self.formLayout_3.setObjectName("formLayout_3")
+ self.endofHpfStopBandLabel = QtGui.QLabel(self.firhpfPage)
+ self.endofHpfStopBandLabel.setObjectName("endofHpfStopBandLabel")
+ self.formLayout_3.setWidget(0, QtGui.QFormLayout.LabelRole, self.endofHpfStopBandLabel)
+ self.endofHpfStopBandEdit = QtGui.QLineEdit(self.firhpfPage)
+ self.endofHpfStopBandEdit.setObjectName("endofHpfStopBandEdit")
+ self.formLayout_3.setWidget(0, QtGui.QFormLayout.FieldRole, self.endofHpfStopBandEdit)
+ self.startofHpfPassBandLabel = QtGui.QLabel(self.firhpfPage)
+ self.startofHpfPassBandLabel.setObjectName("startofHpfPassBandLabel")
+ self.formLayout_3.setWidget(1, QtGui.QFormLayout.LabelRole, self.startofHpfPassBandLabel)
+ self.startofHpfPassBandEdit = QtGui.QLineEdit(self.firhpfPage)
+ self.startofHpfPassBandEdit.setObjectName("startofHpfPassBandEdit")
+ self.formLayout_3.setWidget(1, QtGui.QFormLayout.FieldRole, self.startofHpfPassBandEdit)
+ self.hpfStopBandAttenLabel = QtGui.QLabel(self.firhpfPage)
+ self.hpfStopBandAttenLabel.setObjectName("hpfStopBandAttenLabel")
+ self.formLayout_3.setWidget(2, QtGui.QFormLayout.LabelRole, self.hpfStopBandAttenLabel)
+ self.hpfStopBandAttenEdit = QtGui.QLineEdit(self.firhpfPage)
+ self.hpfStopBandAttenEdit.setObjectName("hpfStopBandAttenEdit")
+ self.formLayout_3.setWidget(2, QtGui.QFormLayout.FieldRole, self.hpfStopBandAttenEdit)
+ self.hpfPassBandRippleLabel = QtGui.QLabel(self.firhpfPage)
+ self.hpfPassBandRippleLabel.setObjectName("hpfPassBandRippleLabel")
+ self.formLayout_3.setWidget(3, QtGui.QFormLayout.LabelRole, self.hpfPassBandRippleLabel)
+ self.hpfPassBandRippleEdit = QtGui.QLineEdit(self.firhpfPage)
+ self.hpfPassBandRippleEdit.setObjectName("hpfPassBandRippleEdit")
+ self.formLayout_3.setWidget(3, QtGui.QFormLayout.FieldRole, self.hpfPassBandRippleEdit)
+ self.filterTypeWidget.addWidget(self.firhpfPage)
+ self.rrcPage = QtGui.QWidget()
+ self.rrcPage.setObjectName("rrcPage")
+ self.formLayout_6 = QtGui.QFormLayout(self.rrcPage)
+ self.formLayout_6.setObjectName("formLayout_6")
+ self.rrcSymbolRateLabel = QtGui.QLabel(self.rrcPage)
+ self.rrcSymbolRateLabel.setObjectName("rrcSymbolRateLabel")
+ self.formLayout_6.setWidget(0, QtGui.QFormLayout.LabelRole, self.rrcSymbolRateLabel)
+ self.rrcAlphaLabel = QtGui.QLabel(self.rrcPage)
+ self.rrcAlphaLabel.setObjectName("rrcAlphaLabel")
+ self.formLayout_6.setWidget(1, QtGui.QFormLayout.LabelRole, self.rrcAlphaLabel)
+ self.rrcNumTapsLabel = QtGui.QLabel(self.rrcPage)
+ self.rrcNumTapsLabel.setObjectName("rrcNumTapsLabel")
+ self.formLayout_6.setWidget(2, QtGui.QFormLayout.LabelRole, self.rrcNumTapsLabel)
+ self.rrcSymbolRateEdit = QtGui.QLineEdit(self.rrcPage)
+ self.rrcSymbolRateEdit.setObjectName("rrcSymbolRateEdit")
+ self.formLayout_6.setWidget(0, QtGui.QFormLayout.FieldRole, self.rrcSymbolRateEdit)
+ self.rrcAlphaEdit = QtGui.QLineEdit(self.rrcPage)
+ self.rrcAlphaEdit.setObjectName("rrcAlphaEdit")
+ self.formLayout_6.setWidget(1, QtGui.QFormLayout.FieldRole, self.rrcAlphaEdit)
+ self.rrcNumTapsEdit = QtGui.QLineEdit(self.rrcPage)
+ self.rrcNumTapsEdit.setObjectName("rrcNumTapsEdit")
+ self.formLayout_6.setWidget(2, QtGui.QFormLayout.FieldRole, self.rrcNumTapsEdit)
+ self.filterTypeWidget.addWidget(self.rrcPage)
+ self.gausPage = QtGui.QWidget()
+ self.gausPage.setObjectName("gausPage")
+ self.formLayout_7 = QtGui.QFormLayout(self.gausPage)
+ self.formLayout_7.setObjectName("formLayout_7")
+ self.gausSymbolRateLabel = QtGui.QLabel(self.gausPage)
+ self.gausSymbolRateLabel.setObjectName("gausSymbolRateLabel")
+ self.formLayout_7.setWidget(0, QtGui.QFormLayout.LabelRole, self.gausSymbolRateLabel)
+ self.gausSymbolRateEdit = QtGui.QLineEdit(self.gausPage)
+ self.gausSymbolRateEdit.setObjectName("gausSymbolRateEdit")
+ self.formLayout_7.setWidget(0, QtGui.QFormLayout.FieldRole, self.gausSymbolRateEdit)
+ self.gausBTLabel = QtGui.QLabel(self.gausPage)
+ self.gausBTLabel.setObjectName("gausBTLabel")
+ self.formLayout_7.setWidget(1, QtGui.QFormLayout.LabelRole, self.gausBTLabel)
+ self.gausBTEdit = QtGui.QLineEdit(self.gausPage)
+ self.gausBTEdit.setObjectName("gausBTEdit")
+ self.formLayout_7.setWidget(1, QtGui.QFormLayout.FieldRole, self.gausBTEdit)
+ self.gausNumTapsLabel = QtGui.QLabel(self.gausPage)
+ self.gausNumTapsLabel.setObjectName("gausNumTapsLabel")
+ self.formLayout_7.setWidget(2, QtGui.QFormLayout.LabelRole, self.gausNumTapsLabel)
+ self.gausNumTapsEdit = QtGui.QLineEdit(self.gausPage)
+ self.gausNumTapsEdit.setObjectName("gausNumTapsEdit")
+ self.formLayout_7.setWidget(2, QtGui.QFormLayout.FieldRole, self.gausNumTapsEdit)
+ self.filterTypeWidget.addWidget(self.gausPage)
+ self.verticalLayout.addWidget(self.filterTypeWidget)
+ self.filterPropsBox = QtGui.QGroupBox(self.filterFrame)
+ self.filterPropsBox.setObjectName("filterPropsBox")
+ self.formLayout_8 = QtGui.QFormLayout(self.filterPropsBox)
+ self.formLayout_8.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow)
+ self.formLayout_8.setObjectName("formLayout_8")
+ self.nTapsLabel = QtGui.QLabel(self.filterPropsBox)
+ self.nTapsLabel.setMinimumSize(QtCore.QSize(150, 0))
+ self.nTapsLabel.setObjectName("nTapsLabel")
+ self.formLayout_8.setWidget(1, QtGui.QFormLayout.LabelRole, self.nTapsLabel)
+ self.nTapsEdit = QtGui.QLabel(self.filterPropsBox)
+ self.nTapsEdit.setMaximumSize(QtCore.QSize(100, 16777215))
+ self.nTapsEdit.setFrameShape(QtGui.QFrame.Box)
+ self.nTapsEdit.setFrameShadow(QtGui.QFrame.Raised)
+ self.nTapsEdit.setText("")
+ self.nTapsEdit.setObjectName("nTapsEdit")
+ self.formLayout_8.setWidget(1, QtGui.QFormLayout.FieldRole, self.nTapsEdit)
+ self.verticalLayout.addWidget(self.filterPropsBox)
+ self.sysParamsBox = QtGui.QGroupBox(self.filterFrame)
+ self.sysParamsBox.setObjectName("sysParamsBox")
+ self.formLayout_4 = QtGui.QFormLayout(self.sysParamsBox)
+ self.formLayout_4.setObjectName("formLayout_4")
+ self.nfftEdit = QtGui.QLineEdit(self.sysParamsBox)
+ self.nfftEdit.setObjectName("nfftEdit")
+ self.formLayout_4.setWidget(1, QtGui.QFormLayout.FieldRole, self.nfftEdit)
+ self.nfftLabel = QtGui.QLabel(self.sysParamsBox)
+ self.nfftLabel.setMinimumSize(QtCore.QSize(150, 0))
+ self.nfftLabel.setObjectName("nfftLabel")
+ self.formLayout_4.setWidget(1, QtGui.QFormLayout.LabelRole, self.nfftLabel)
+ self.verticalLayout.addWidget(self.sysParamsBox)
+ self.designButton = QtGui.QPushButton(self.filterFrame)
+ self.designButton.setMinimumSize(QtCore.QSize(0, 0))
+ self.designButton.setMaximumSize(QtCore.QSize(200, 16777215))
+ self.designButton.setAutoDefault(True)
+ self.designButton.setDefault(True)
+ self.designButton.setObjectName("designButton")
+ self.verticalLayout.addWidget(self.designButton)
+ self.gridLayout.addWidget(self.filterFrame, 1, 0, 1, 1)
+ self.tabGroup = QtGui.QTabWidget(self.centralwidget)
+ self.tabGroup.setMinimumSize(QtCore.QSize(800, 0))
+ self.tabGroup.setObjectName("tabGroup")
+ self.freqTab = QtGui.QWidget()
+ self.freqTab.setObjectName("freqTab")
+ self.horizontalLayout_2 = QtGui.QHBoxLayout(self.freqTab)
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ self.freqPlot = QwtPlot(self.freqTab)
+ self.freqPlot.setObjectName("freqPlot")
+ self.horizontalLayout_2.addWidget(self.freqPlot)
+ self.tabGroup.addTab(self.freqTab, "")
+ self.timeTab = QtGui.QWidget()
+ self.timeTab.setObjectName("timeTab")
+ self.horizontalLayout = QtGui.QHBoxLayout(self.timeTab)
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.timePlot = QwtPlot(self.timeTab)
+ self.timePlot.setObjectName("timePlot")
+ self.horizontalLayout.addWidget(self.timePlot)
+ self.tabGroup.addTab(self.timeTab, "")
+ self.phaseTab = QtGui.QWidget()
+ self.phaseTab.setObjectName("phaseTab")
+ self.horizontalLayout_3 = QtGui.QHBoxLayout(self.phaseTab)
+ self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+ self.phasePlot = QwtPlot(self.phaseTab)
+ self.phasePlot.setObjectName("phasePlot")
+ self.horizontalLayout_3.addWidget(self.phasePlot)
+ self.tabGroup.addTab(self.phaseTab, "")
+ self.groupTab = QtGui.QWidget()
+ self.groupTab.setObjectName("groupTab")
+ self.horizontalLayout_4 = QtGui.QHBoxLayout(self.groupTab)
+ self.horizontalLayout_4.setObjectName("horizontalLayout_4")
+ self.groupPlot = QwtPlot(self.groupTab)
+ self.groupPlot.setObjectName("groupPlot")
+ self.horizontalLayout_4.addWidget(self.groupPlot)
+ self.tabGroup.addTab(self.groupTab, "")
+ self.gridLayout.addWidget(self.tabGroup, 1, 1, 1, 1)
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QtGui.QMenuBar(MainWindow)
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 1124, 27))
+ self.menubar.setObjectName("menubar")
+ self.menu_File = QtGui.QMenu(self.menubar)
+ self.menu_File.setObjectName("menu_File")
+ MainWindow.setMenuBar(self.menubar)
+ self.statusbar = QtGui.QStatusBar(MainWindow)
+ self.statusbar.setObjectName("statusbar")
+ MainWindow.setStatusBar(self.statusbar)
+ self.action_exit = QtGui.QAction(MainWindow)
+ self.action_exit.setObjectName("action_exit")
+ self.action_save = QtGui.QAction(MainWindow)
+ self.action_save.setObjectName("action_save")
+ self.action_open = QtGui.QAction(MainWindow)
+ self.action_open.setObjectName("action_open")
+ self.menu_File.addAction(self.action_open)
+ self.menu_File.addAction(self.action_save)
+ self.menu_File.addAction(self.action_exit)
+ self.menubar.addAction(self.menu_File.menuAction())
+
+ self.retranslateUi(MainWindow)
+ self.filterTypeWidget.setCurrentIndex(5)
+ self.tabGroup.setCurrentIndex(0)
+ QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+ MainWindow.setTabOrder(self.filterTypeComboBox, self.filterDesignTypeComboBox)
+ MainWindow.setTabOrder(self.filterDesignTypeComboBox, self.sampleRateEdit)
+ MainWindow.setTabOrder(self.sampleRateEdit, self.filterGainEdit)
+ MainWindow.setTabOrder(self.filterGainEdit, self.endofLpfPassBandEdit)
+ MainWindow.setTabOrder(self.endofLpfPassBandEdit, self.startofLpfStopBandEdit)
+ MainWindow.setTabOrder(self.startofLpfStopBandEdit, self.lpfStopBandAttenEdit)
+ MainWindow.setTabOrder(self.lpfStopBandAttenEdit, self.lpfPassBandRippleEdit)
+ MainWindow.setTabOrder(self.lpfPassBandRippleEdit, self.startofBpfPassBandEdit)
+ MainWindow.setTabOrder(self.startofBpfPassBandEdit, self.endofBpfPassBandEdit)
+ MainWindow.setTabOrder(self.endofBpfPassBandEdit, self.bpfTransitionEdit)
+ MainWindow.setTabOrder(self.bpfTransitionEdit, self.bpfStopBandAttenEdit)
+ MainWindow.setTabOrder(self.bpfStopBandAttenEdit, self.bpfPassBandRippleEdit)
+ MainWindow.setTabOrder(self.bpfPassBandRippleEdit, self.startofBnfStopBandEdit)
+ MainWindow.setTabOrder(self.startofBnfStopBandEdit, self.endofBnfStopBandEdit)
+ MainWindow.setTabOrder(self.endofBnfStopBandEdit, self.bnfTransitionEdit)
+ MainWindow.setTabOrder(self.bnfTransitionEdit, self.bnfStopBandAttenEdit)
+ MainWindow.setTabOrder(self.bnfStopBandAttenEdit, self.bnfPassBandRippleEdit)
+ MainWindow.setTabOrder(self.bnfPassBandRippleEdit, self.endofHpfStopBandEdit)
+ MainWindow.setTabOrder(self.endofHpfStopBandEdit, self.startofHpfPassBandEdit)
+ MainWindow.setTabOrder(self.startofHpfPassBandEdit, self.hpfStopBandAttenEdit)
+ MainWindow.setTabOrder(self.hpfStopBandAttenEdit, self.hpfPassBandRippleEdit)
+ MainWindow.setTabOrder(self.hpfPassBandRippleEdit, self.rrcSymbolRateEdit)
+ MainWindow.setTabOrder(self.rrcSymbolRateEdit, self.rrcAlphaEdit)
+ MainWindow.setTabOrder(self.rrcAlphaEdit, self.rrcNumTapsEdit)
+ MainWindow.setTabOrder(self.rrcNumTapsEdit, self.gausSymbolRateEdit)
+ MainWindow.setTabOrder(self.gausSymbolRateEdit, self.gausBTEdit)
+ MainWindow.setTabOrder(self.gausBTEdit, self.gausNumTapsEdit)
+ MainWindow.setTabOrder(self.gausNumTapsEdit, self.nfftEdit)
+ MainWindow.setTabOrder(self.nfftEdit, self.designButton)
+ MainWindow.setTabOrder(self.designButton, self.tabGroup)
+
+ def retranslateUi(self, MainWindow):
+ MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "GNU Radio Filter Design Tool", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterTypeComboBox.setItemText(0, QtGui.QApplication.translate("MainWindow", "Low Pass", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterTypeComboBox.setItemText(1, QtGui.QApplication.translate("MainWindow", "Band Pass", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterTypeComboBox.setItemText(2, QtGui.QApplication.translate("MainWindow", "Complex Band Pass", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterTypeComboBox.setItemText(3, QtGui.QApplication.translate("MainWindow", "Band Notch", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterTypeComboBox.setItemText(4, QtGui.QApplication.translate("MainWindow", "High Pass", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterTypeComboBox.setItemText(5, QtGui.QApplication.translate("MainWindow", "Root Raised Cosine", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterTypeComboBox.setItemText(6, QtGui.QApplication.translate("MainWindow", "Gaussian", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterDesignTypeComboBox.setItemText(0, QtGui.QApplication.translate("MainWindow", "Hamming Window", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterDesignTypeComboBox.setItemText(1, QtGui.QApplication.translate("MainWindow", "Hann Window", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterDesignTypeComboBox.setItemText(2, QtGui.QApplication.translate("MainWindow", "Blackman Window", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterDesignTypeComboBox.setItemText(3, QtGui.QApplication.translate("MainWindow", "Rectangular Window", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterDesignTypeComboBox.setItemText(4, QtGui.QApplication.translate("MainWindow", "Kaiser Window", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterDesignTypeComboBox.setItemText(5, QtGui.QApplication.translate("MainWindow", "Blackman-harris Window", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterDesignTypeComboBox.setItemText(6, QtGui.QApplication.translate("MainWindow", "Equiripple", None, QtGui.QApplication.UnicodeUTF8))
+ self.sampleRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Sample Rate (sps)", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterGainLabel.setText(QtGui.QApplication.translate("MainWindow", "Filter Gain", None, QtGui.QApplication.UnicodeUTF8))
+ self.endofLpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "End of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8))
+ self.startofLpfStopBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8))
+ self.lpfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8))
+ self.lpfPassBandRippleLabel.setText(QtGui.QApplication.translate("MainWindow", "Pass Band Ripple (dB)", None, QtGui.QApplication.UnicodeUTF8))
+ self.startofBpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8))
+ self.endofBpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "End of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8))
+ self.bpfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8))
+ self.bpfTransitionLabel.setText(QtGui.QApplication.translate("MainWindow", "Transition Width (Hz)", None, QtGui.QApplication.UnicodeUTF8))
+ self.bpfPassBandRippleLabel.setText(QtGui.QApplication.translate("MainWindow", "Pass Band Ripple (dB)", None, QtGui.QApplication.UnicodeUTF8))
+ self.startofBnfStopBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8))
+ self.endofBnfStopBandLabel.setText(QtGui.QApplication.translate("MainWindow", "End of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8))
+ self.bnfTransitionLabel.setText(QtGui.QApplication.translate("MainWindow", "Transition Width (Hz)", None, QtGui.QApplication.UnicodeUTF8))
+ self.bnfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8))
+ self.bnfPassBandRippleLabel.setText(QtGui.QApplication.translate("MainWindow", "Pass Band Ripple (dB)", None, QtGui.QApplication.UnicodeUTF8))
+ self.endofHpfStopBandLabel.setText(QtGui.QApplication.translate("MainWindow", "End of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8))
+ self.startofHpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8))
+ self.hpfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8))
+ self.hpfPassBandRippleLabel.setText(QtGui.QApplication.translate("MainWindow", "Pass Band Ripple (dB)", None, QtGui.QApplication.UnicodeUTF8))
+ self.rrcSymbolRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Symbol Rate (sps)", None, QtGui.QApplication.UnicodeUTF8))
+ self.rrcAlphaLabel.setText(QtGui.QApplication.translate("MainWindow", "Roll-off Factor", None, QtGui.QApplication.UnicodeUTF8))
+ self.rrcNumTapsLabel.setText(QtGui.QApplication.translate("MainWindow", "Number of Taps", None, QtGui.QApplication.UnicodeUTF8))
+ self.gausSymbolRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Symbol Rate (sps)", None, QtGui.QApplication.UnicodeUTF8))
+ self.gausBTLabel.setText(QtGui.QApplication.translate("MainWindow", "Roll-off Factor", None, QtGui.QApplication.UnicodeUTF8))
+ self.gausNumTapsLabel.setText(QtGui.QApplication.translate("MainWindow", "Number of Taps", None, QtGui.QApplication.UnicodeUTF8))
+ self.filterPropsBox.setTitle(QtGui.QApplication.translate("MainWindow", "Filter Properties", None, QtGui.QApplication.UnicodeUTF8))
+ self.nTapsLabel.setText(QtGui.QApplication.translate("MainWindow", "Number of Taps:", None, QtGui.QApplication.UnicodeUTF8))
+ self.sysParamsBox.setTitle(QtGui.QApplication.translate("MainWindow", "System Parameters", None, QtGui.QApplication.UnicodeUTF8))
+ self.nfftLabel.setText(QtGui.QApplication.translate("MainWindow", "Num FFT points", None, QtGui.QApplication.UnicodeUTF8))
+ self.designButton.setText(QtGui.QApplication.translate("MainWindow", "Design", None, QtGui.QApplication.UnicodeUTF8))
+ self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8))
+ self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8))
+ self.tabGroup.setTabText(self.tabGroup.indexOf(self.phaseTab), QtGui.QApplication.translate("MainWindow", "Phase", None, QtGui.QApplication.UnicodeUTF8))
+ self.tabGroup.setTabText(self.tabGroup.indexOf(self.groupTab), QtGui.QApplication.translate("MainWindow", "Group Delay", None, QtGui.QApplication.UnicodeUTF8))
+ self.menu_File.setTitle(QtGui.QApplication.translate("MainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8))
+ self.action_exit.setText(QtGui.QApplication.translate("MainWindow", "E&xit", None, QtGui.QApplication.UnicodeUTF8))
+ self.action_save.setText(QtGui.QApplication.translate("MainWindow", "&Save", None, QtGui.QApplication.UnicodeUTF8))
+ self.action_save.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+S", None, QtGui.QApplication.UnicodeUTF8))
+ self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8))
+ self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8))
+
+#from qwt_plot import QwtPlot
+from PyQt4.Qwt5 import QwtPlot
+
diff --git a/gr-utils/python/pyqt_filter.ui b/gr-utils/python/pyqt_filter.ui
new file mode 100644
index 0000000000..9853352e2e
--- /dev/null
+++ b/gr-utils/python/pyqt_filter.ui
@@ -0,0 +1,687 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1124</width>
+ <height>696</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>GNU Radio Filter Design Tool</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="0">
+ <widget class="QFrame" name="filterFrame">
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>300</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QComboBox" name="filterTypeComboBox">
+ <item>
+ <property name="text">
+ <string>Low Pass</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Band Pass</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Complex Band Pass</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Band Notch</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>High Pass</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Root Raised Cosine</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Gaussian</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="filterDesignTypeComboBox">
+ <item>
+ <property name="text">
+ <string>Hamming Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Hann Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Blackman Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Rectangular Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Kaiser Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Blackman-harris Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Equiripple</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <layout class="QFormLayout" name="globalParamsLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="sampleRateLabel">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Sample Rate (sps)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="sampleRateEdit">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>30</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="filterGainLabel">
+ <property name="text">
+ <string>Filter Gain</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="filterGainEdit"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="filterTypeWidget">
+ <property name="currentIndex">
+ <number>5</number>
+ </property>
+ <widget class="QWidget" name="firlpfPage">
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="endofLpfPassBandLabel">
+ <property name="text">
+ <string>End of Pass Band (Hz)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="endofLpfPassBandEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="startofLpfStopBandLabel">
+ <property name="text">
+ <string>Start of Stop Band (Hz)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="startofLpfStopBandEdit"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="lpfStopBandAttenLabel">
+ <property name="text">
+ <string>Stop Band Attenuation (dB)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="lpfStopBandAttenEdit"/>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="lpfPassBandRippleEdit"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="lpfPassBandRippleLabel">
+ <property name="text">
+ <string>Pass Band Ripple (dB)</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="firbpfPage">
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="startofBpfPassBandLabel">
+ <property name="text">
+ <string>Start of Pass Band (Hz)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="startofBpfPassBandEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="endofBpfPassBandLabel">
+ <property name="text">
+ <string>End of Pass Band (Hz)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="endofBpfPassBandEdit"/>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="bpfStopBandAttenEdit"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="bpfStopBandAttenLabel">
+ <property name="text">
+ <string>Stop Band Attenuation (dB)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="bpfTransitionLabel">
+ <property name="text">
+ <string>Transition Width (Hz)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="bpfTransitionEdit"/>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="bpfPassBandRippleEdit"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="bpfPassBandRippleLabel">
+ <property name="text">
+ <string>Pass Band Ripple (dB)</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="firbnfPage">
+ <layout class="QFormLayout" name="formLayout_5">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="startofBnfStopBandLabel">
+ <property name="text">
+ <string>Start of Stop Band (Hz)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="startofBnfStopBandEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="endofBnfStopBandLabel">
+ <property name="text">
+ <string>End of Stop Band (Hz)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="endofBnfStopBandEdit"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="bnfTransitionLabel">
+ <property name="text">
+ <string>Transition Width (Hz)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="bnfTransitionEdit"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="bnfStopBandAttenLabel">
+ <property name="text">
+ <string>Stop Band Attenuation (dB)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="bnfStopBandAttenEdit"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="bnfPassBandRippleLabel">
+ <property name="text">
+ <string>Pass Band Ripple (dB)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="bnfPassBandRippleEdit"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="firhpfPage">
+ <layout class="QFormLayout" name="formLayout_3">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="endofHpfStopBandLabel">
+ <property name="text">
+ <string>End of Stop Band (Hz)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="endofHpfStopBandEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="startofHpfPassBandLabel">
+ <property name="text">
+ <string>Start of Pass Band (Hz)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="startofHpfPassBandEdit"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="hpfStopBandAttenLabel">
+ <property name="text">
+ <string>Stop Band Attenuation (dB)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="hpfStopBandAttenEdit"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="hpfPassBandRippleLabel">
+ <property name="text">
+ <string>Pass Band Ripple (dB)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="hpfPassBandRippleEdit"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="rrcPage">
+ <layout class="QFormLayout" name="formLayout_6">
+ <item row="0" column="0">
+ <widget class="QLabel" name="rrcSymbolRateLabel">
+ <property name="text">
+ <string>Symbol Rate (sps)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="rrcAlphaLabel">
+ <property name="text">
+ <string>Roll-off Factor</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="rrcNumTapsLabel">
+ <property name="text">
+ <string>Number of Taps</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="rrcSymbolRateEdit"/>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="rrcAlphaEdit"/>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="rrcNumTapsEdit"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="gausPage">
+ <layout class="QFormLayout" name="formLayout_7">
+ <item row="0" column="0">
+ <widget class="QLabel" name="gausSymbolRateLabel">
+ <property name="text">
+ <string>Symbol Rate (sps)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="gausSymbolRateEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="gausBTLabel">
+ <property name="text">
+ <string>Roll-off Factor</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="gausBTEdit"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="gausNumTapsLabel">
+ <property name="text">
+ <string>Number of Taps</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="gausNumTapsEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="filterPropsBox">
+ <property name="title">
+ <string>Filter Properties</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_8">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <item row="1" column="0">
+ <widget class="QLabel" name="nTapsLabel">
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Number of Taps:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="nTapsEdit">
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::Box</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="sysParamsBox">
+ <property name="title">
+ <string>System Parameters</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_4">
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="nfftEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="nfftLabel">
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Num FFT points</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="designButton">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>200</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Design</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QTabWidget" name="tabGroup">
+ <property name="minimumSize">
+ <size>
+ <width>800</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="freqTab">
+ <attribute name="title">
+ <string>Frequency Domain</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QwtPlot" name="freqPlot"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="timeTab">
+ <attribute name="title">
+ <string>Time Domain</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QwtPlot" name="timePlot"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="phaseTab">
+ <attribute name="title">
+ <string>Phase</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QwtPlot" name="phasePlot"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="groupTab">
+ <attribute name="title">
+ <string>Group Delay</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QwtPlot" name="groupPlot"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1124</width>
+ <height>27</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menu_File">
+ <property name="title">
+ <string>&amp;File</string>
+ </property>
+ <addaction name="action_open"/>
+ <addaction name="action_save"/>
+ <addaction name="action_exit"/>
+ </widget>
+ <addaction name="menu_File"/>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ <action name="action_exit">
+ <property name="text">
+ <string>E&amp;xit</string>
+ </property>
+ </action>
+ <action name="action_save">
+ <property name="text">
+ <string>&amp;Save</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+S</string>
+ </property>
+ </action>
+ <action name="action_open">
+ <property name="text">
+ <string>&amp;Open</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+O</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QwtPlot</class>
+ <extends>QFrame</extends>
+ <header>qwt_plot.h</header>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>filterTypeComboBox</tabstop>
+ <tabstop>filterDesignTypeComboBox</tabstop>
+ <tabstop>sampleRateEdit</tabstop>
+ <tabstop>filterGainEdit</tabstop>
+ <tabstop>endofLpfPassBandEdit</tabstop>
+ <tabstop>startofLpfStopBandEdit</tabstop>
+ <tabstop>lpfStopBandAttenEdit</tabstop>
+ <tabstop>lpfPassBandRippleEdit</tabstop>
+ <tabstop>startofBpfPassBandEdit</tabstop>
+ <tabstop>endofBpfPassBandEdit</tabstop>
+ <tabstop>bpfTransitionEdit</tabstop>
+ <tabstop>bpfStopBandAttenEdit</tabstop>
+ <tabstop>bpfPassBandRippleEdit</tabstop>
+ <tabstop>startofBnfStopBandEdit</tabstop>
+ <tabstop>endofBnfStopBandEdit</tabstop>
+ <tabstop>bnfTransitionEdit</tabstop>
+ <tabstop>bnfStopBandAttenEdit</tabstop>
+ <tabstop>bnfPassBandRippleEdit</tabstop>
+ <tabstop>endofHpfStopBandEdit</tabstop>
+ <tabstop>startofHpfPassBandEdit</tabstop>
+ <tabstop>hpfStopBandAttenEdit</tabstop>
+ <tabstop>hpfPassBandRippleEdit</tabstop>
+ <tabstop>rrcSymbolRateEdit</tabstop>
+ <tabstop>rrcAlphaEdit</tabstop>
+ <tabstop>rrcNumTapsEdit</tabstop>
+ <tabstop>gausSymbolRateEdit</tabstop>
+ <tabstop>gausBTEdit</tabstop>
+ <tabstop>gausNumTapsEdit</tabstop>
+ <tabstop>nfftEdit</tabstop>
+ <tabstop>designButton</tabstop>
+ <tabstop>tabGroup</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>action_exit</sender>
+ <signal>activated()</signal>
+ <receiver>MainWindow</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>399</x>
+ <y>347</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/gr-utils/python/pyqt_plot.py b/gr-utils/python/pyqt_plot.py
new file mode 100644
index 0000000000..5650135abf
--- /dev/null
+++ b/gr-utils/python/pyqt_plot.py
@@ -0,0 +1,211 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'pyqt_plot.ui'
+#
+# 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!
+
+from PyQt4 import QtCore, QtGui
+
+class Ui_MainWindow(object):
+ def setupUi(self, MainWindow):
+ MainWindow.setObjectName("MainWindow")
+ MainWindow.resize(927, 696)
+ self.centralwidget = QtGui.QWidget(MainWindow)
+ self.centralwidget.setObjectName("centralwidget")
+ self.gridLayout = QtGui.QGridLayout(self.centralwidget)
+ self.gridLayout.setObjectName("gridLayout")
+ self.plotHBar = QtGui.QScrollBar(self.centralwidget)
+ self.plotHBar.setOrientation(QtCore.Qt.Horizontal)
+ self.plotHBar.setObjectName("plotHBar")
+ self.gridLayout.addWidget(self.plotHBar, 2, 0, 1, 2)
+ self.tabGroup = QtGui.QTabWidget(self.centralwidget)
+ self.tabGroup.setObjectName("tabGroup")
+ self.timeTab = QtGui.QWidget()
+ self.timeTab.setObjectName("timeTab")
+ self.horizontalLayout = QtGui.QHBoxLayout(self.timeTab)
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.timePlot = Qwt5.QwtPlot(self.timeTab)
+ self.timePlot.setObjectName("timePlot")
+ self.horizontalLayout.addWidget(self.timePlot)
+ self.tabGroup.addTab(self.timeTab, "")
+ self.freqTab = QtGui.QWidget()
+ self.freqTab.setObjectName("freqTab")
+ self.horizontalLayout_2 = QtGui.QHBoxLayout(self.freqTab)
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ self.fftPropBox = QtGui.QGroupBox(self.freqTab)
+ self.fftPropBox.setMinimumSize(QtCore.QSize(160, 0))
+ self.fftPropBox.setObjectName("fftPropBox")
+ self.formLayout_4 = QtGui.QFormLayout(self.fftPropBox)
+ self.formLayout_4.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow)
+ self.formLayout_4.setObjectName("formLayout_4")
+ self.psdFFTComboBox = QtGui.QComboBox(self.fftPropBox)
+ self.psdFFTComboBox.setMinimumSize(QtCore.QSize(96, 0))
+ self.psdFFTComboBox.setMaximumSize(QtCore.QSize(96, 16777215))
+ self.psdFFTComboBox.setObjectName("psdFFTComboBox")
+ self.formLayout_4.setWidget(0, QtGui.QFormLayout.FieldRole, self.psdFFTComboBox)
+ self.psdFFTSizeLabel = QtGui.QLabel(self.fftPropBox)
+ self.psdFFTSizeLabel.setObjectName("psdFFTSizeLabel")
+ self.formLayout_4.setWidget(0, QtGui.QFormLayout.LabelRole, self.psdFFTSizeLabel)
+ self.horizontalLayout_2.addWidget(self.fftPropBox)
+ self.freqPlot = Qwt5.QwtPlot(self.freqTab)
+ self.freqPlot.setObjectName("freqPlot")
+ self.horizontalLayout_2.addWidget(self.freqPlot)
+ self.tabGroup.addTab(self.freqTab, "")
+ self.specTab = QtGui.QWidget()
+ self.specTab.setObjectName("specTab")
+ self.horizontalLayout_3 = QtGui.QHBoxLayout(self.specTab)
+ self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+ self.groupBox = QtGui.QGroupBox(self.specTab)
+ self.groupBox.setObjectName("groupBox")
+ self.formLayout_3 = QtGui.QFormLayout(self.groupBox)
+ self.formLayout_3.setObjectName("formLayout_3")
+ self.specFFTLabel = QtGui.QLabel(self.groupBox)
+ self.specFFTLabel.setObjectName("specFFTLabel")
+ self.formLayout_3.setWidget(1, QtGui.QFormLayout.LabelRole, self.specFFTLabel)
+ self.specFFTComboBox = QtGui.QComboBox(self.groupBox)
+ self.specFFTComboBox.setMinimumSize(QtCore.QSize(96, 0))
+ self.specFFTComboBox.setMaximumSize(QtCore.QSize(96, 16777215))
+ self.specFFTComboBox.setObjectName("specFFTComboBox")
+ self.formLayout_3.setWidget(1, QtGui.QFormLayout.FieldRole, self.specFFTComboBox)
+ self.horizontalLayout_3.addWidget(self.groupBox)
+ self.specPlot = Qwt5.QwtPlot(self.specTab)
+ self.specPlot.setObjectName("specPlot")
+ self.horizontalLayout_3.addWidget(self.specPlot)
+ self.tabGroup.addTab(self.specTab, "")
+ self.gridLayout.addWidget(self.tabGroup, 1, 0, 1, 1)
+ self.filePosBox = QtGui.QGroupBox(self.centralwidget)
+ self.filePosBox.setMinimumSize(QtCore.QSize(0, 120))
+ self.filePosBox.setObjectName("filePosBox")
+ self.formLayoutWidget_2 = QtGui.QWidget(self.filePosBox)
+ self.formLayoutWidget_2.setGeometry(QtCore.QRect(0, 20, 160, 92))
+ self.formLayoutWidget_2.setObjectName("formLayoutWidget_2")
+ self.filePosLayout = QtGui.QFormLayout(self.formLayoutWidget_2)
+ self.filePosLayout.setObjectName("filePosLayout")
+ self.filePosStartLabel = QtGui.QLabel(self.formLayoutWidget_2)
+ self.filePosStartLabel.setObjectName("filePosStartLabel")
+ self.filePosLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.filePosStartLabel)
+ self.filePosStartLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2)
+ self.filePosStartLineEdit.setObjectName("filePosStartLineEdit")
+ self.filePosLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.filePosStartLineEdit)
+ self.filePosStopLabel = QtGui.QLabel(self.formLayoutWidget_2)
+ self.filePosStopLabel.setObjectName("filePosStopLabel")
+ self.filePosLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.filePosStopLabel)
+ self.filePosStopLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2)
+ self.filePosStopLineEdit.setObjectName("filePosStopLineEdit")
+ self.filePosLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.filePosStopLineEdit)
+ self.filePosLengthLabel = QtGui.QLabel(self.formLayoutWidget_2)
+ self.filePosLengthLabel.setObjectName("filePosLengthLabel")
+ self.filePosLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.filePosLengthLabel)
+ self.filePosLengthLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2)
+ self.filePosLengthLineEdit.setObjectName("filePosLengthLineEdit")
+ self.filePosLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.filePosLengthLineEdit)
+ self.formLayoutWidget_4 = QtGui.QWidget(self.filePosBox)
+ self.formLayoutWidget_4.setGeometry(QtCore.QRect(180, 20, 231, 92))
+ self.formLayoutWidget_4.setObjectName("formLayoutWidget_4")
+ self.fileTimeLayout = QtGui.QFormLayout(self.formLayoutWidget_4)
+ self.fileTimeLayout.setObjectName("fileTimeLayout")
+ self.fileTimeStartLabel = QtGui.QLabel(self.formLayoutWidget_4)
+ self.fileTimeStartLabel.setObjectName("fileTimeStartLabel")
+ self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.fileTimeStartLabel)
+ self.fileTimeStartLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4)
+ self.fileTimeStartLineEdit.setObjectName("fileTimeStartLineEdit")
+ self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.fileTimeStartLineEdit)
+ self.fileTimeStopLabel = QtGui.QLabel(self.formLayoutWidget_4)
+ self.fileTimeStopLabel.setObjectName("fileTimeStopLabel")
+ self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.fileTimeStopLabel)
+ self.fileTimeStopLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4)
+ self.fileTimeStopLineEdit.setObjectName("fileTimeStopLineEdit")
+ self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.fileTimeStopLineEdit)
+ self.fileTimeLengthLabel = QtGui.QLabel(self.formLayoutWidget_4)
+ self.fileTimeLengthLabel.setObjectName("fileTimeLengthLabel")
+ self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.fileTimeLengthLabel)
+ self.fileTimeLengthLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4)
+ self.fileTimeLengthLineEdit.setObjectName("fileTimeLengthLineEdit")
+ self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.fileTimeLengthLineEdit)
+ self.sysGroupBox = QtGui.QGroupBox(self.filePosBox)
+ self.sysGroupBox.setGeometry(QtCore.QRect(530, 0, 200, 120))
+ self.sysGroupBox.setMinimumSize(QtCore.QSize(200, 0))
+ self.sysGroupBox.setObjectName("sysGroupBox")
+ self.formLayoutWidget_3 = QtGui.QWidget(self.sysGroupBox)
+ self.formLayoutWidget_3.setGeometry(QtCore.QRect(0, 20, 191, 91))
+ self.formLayoutWidget_3.setObjectName("formLayoutWidget_3")
+ self.formLayout_2 = QtGui.QFormLayout(self.formLayoutWidget_3)
+ self.formLayout_2.setObjectName("formLayout_2")
+ self.sampleRateLabel = QtGui.QLabel(self.formLayoutWidget_3)
+ self.sampleRateLabel.setObjectName("sampleRateLabel")
+ self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.sampleRateLabel)
+ self.sampleRateLineEdit = QtGui.QLineEdit(self.formLayoutWidget_3)
+ self.sampleRateLineEdit.setMinimumSize(QtCore.QSize(0, 0))
+ self.sampleRateLineEdit.setObjectName("sampleRateLineEdit")
+ self.formLayout_2.setWidget(0, QtGui.QFormLayout.FieldRole, self.sampleRateLineEdit)
+ self.displayGroupBox = QtGui.QGroupBox(self.filePosBox)
+ self.displayGroupBox.setGeometry(QtCore.QRect(730, 0, 170, 120))
+ self.displayGroupBox.setMinimumSize(QtCore.QSize(170, 0))
+ self.displayGroupBox.setObjectName("displayGroupBox")
+ self.verticalLayoutWidget = QtGui.QWidget(self.displayGroupBox)
+ self.verticalLayoutWidget.setGeometry(QtCore.QRect(0, 20, 160, 91))
+ self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
+ self.verticalLayout = QtGui.QVBoxLayout(self.verticalLayoutWidget)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.colorComboBox = QtGui.QComboBox(self.verticalLayoutWidget)
+ self.colorComboBox.setObjectName("colorComboBox")
+ self.verticalLayout.addWidget(self.colorComboBox)
+ spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
+ self.verticalLayout.addItem(spacerItem)
+ self.gridLayout.addWidget(self.filePosBox, 3, 0, 1, 1)
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QtGui.QMenuBar(MainWindow)
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 927, 25))
+ self.menubar.setObjectName("menubar")
+ self.menu_File = QtGui.QMenu(self.menubar)
+ self.menu_File.setObjectName("menu_File")
+ MainWindow.setMenuBar(self.menubar)
+ self.statusbar = QtGui.QStatusBar(MainWindow)
+ self.statusbar.setObjectName("statusbar")
+ MainWindow.setStatusBar(self.statusbar)
+ self.action_open = QtGui.QAction(MainWindow)
+ self.action_open.setObjectName("action_open")
+ self.action_exit = QtGui.QAction(MainWindow)
+ self.action_exit.setObjectName("action_exit")
+ self.action_reload = QtGui.QAction(MainWindow)
+ self.action_reload.setObjectName("action_reload")
+ self.menu_File.addAction(self.action_open)
+ self.menu_File.addAction(self.action_reload)
+ self.menu_File.addAction(self.action_exit)
+ self.menubar.addAction(self.menu_File.menuAction())
+
+ self.retranslateUi(MainWindow)
+ self.tabGroup.setCurrentIndex(0)
+ QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+ def retranslateUi(self, MainWindow):
+ MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
+ self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8))
+ self.fftPropBox.setTitle(QtGui.QApplication.translate("MainWindow", "FFT Properties", None, QtGui.QApplication.UnicodeUTF8))
+ self.psdFFTSizeLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8))
+ self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8))
+ self.groupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Spectrogram Properties", None, QtGui.QApplication.UnicodeUTF8))
+ self.specFFTLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8))
+ self.tabGroup.setTabText(self.tabGroup.indexOf(self.specTab), QtGui.QApplication.translate("MainWindow", "Spectrogram", None, QtGui.QApplication.UnicodeUTF8))
+ self.filePosBox.setTitle(QtGui.QApplication.translate("MainWindow", "File Position", None, QtGui.QApplication.UnicodeUTF8))
+ self.filePosStartLabel.setText(QtGui.QApplication.translate("MainWindow", "Start", None, QtGui.QApplication.UnicodeUTF8))
+ self.filePosStopLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop", None, QtGui.QApplication.UnicodeUTF8))
+ self.filePosLengthLabel.setText(QtGui.QApplication.translate("MainWindow", "Length", None, QtGui.QApplication.UnicodeUTF8))
+ self.fileTimeStartLabel.setText(QtGui.QApplication.translate("MainWindow", "time start (sec)", None, QtGui.QApplication.UnicodeUTF8))
+ self.fileTimeStopLabel.setText(QtGui.QApplication.translate("MainWindow", "time stop (sec)", None, QtGui.QApplication.UnicodeUTF8))
+ self.fileTimeLengthLabel.setText(QtGui.QApplication.translate("MainWindow", "time length (sec)", None, QtGui.QApplication.UnicodeUTF8))
+ self.sysGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "System Properties", None, QtGui.QApplication.UnicodeUTF8))
+ self.sampleRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Sample Rate", None, QtGui.QApplication.UnicodeUTF8))
+ self.displayGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Display Properties", None, QtGui.QApplication.UnicodeUTF8))
+ self.menu_File.setTitle(QtGui.QApplication.translate("MainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8))
+ self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8))
+ self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8))
+ self.action_exit.setText(QtGui.QApplication.translate("MainWindow", "E&xit", None, QtGui.QApplication.UnicodeUTF8))
+ self.action_reload.setText(QtGui.QApplication.translate("MainWindow", "&Reload", None, QtGui.QApplication.UnicodeUTF8))
+ self.action_reload.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+R", None, QtGui.QApplication.UnicodeUTF8))
+
+from PyQt4 import Qwt5
diff --git a/gr-utils/python/pyqt_plot.ui b/gr-utils/python/pyqt_plot.ui
new file mode 100644
index 0000000000..55c72fda26
--- /dev/null
+++ b/gr-utils/python/pyqt_plot.ui
@@ -0,0 +1,399 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>927</width>
+ <height>696</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="2" column="0" colspan="2">
+ <widget class="QScrollBar" name="plotHBar">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QTabWidget" name="tabGroup">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="timeTab">
+ <attribute name="title">
+ <string>Time Domain</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QwtPlot" name="timePlot"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="freqTab">
+ <attribute name="title">
+ <string>Frequency Domain</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="fftPropBox">
+ <property name="minimumSize">
+ <size>
+ <width>160</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>FFT Properties</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_4">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="psdFFTComboBox">
+ <property name="minimumSize">
+ <size>
+ <width>96</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>96</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="psdFFTSizeLabel">
+ <property name="text">
+ <string>FFT Size</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QwtPlot" name="freqPlot"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="specTab">
+ <attribute name="title">
+ <string>Spectrogram</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Spectrogram Properties</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_3">
+ <item row="1" column="0">
+ <widget class="QLabel" name="specFFTLabel">
+ <property name="text">
+ <string>FFT Size</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="specFFTComboBox">
+ <property name="minimumSize">
+ <size>
+ <width>96</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>96</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QwtPlot" name="specPlot"/>
+ </item>
+ </layout>
+ <zorder>specPlot</zorder>
+ <zorder>groupBox</zorder>
+ </widget>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QGroupBox" name="filePosBox">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>120</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>File Position</string>
+ </property>
+ <widget class="QWidget" name="formLayoutWidget_2">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>20</y>
+ <width>160</width>
+ <height>92</height>
+ </rect>
+ </property>
+ <layout class="QFormLayout" name="filePosLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="filePosStartLabel">
+ <property name="text">
+ <string>Start</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="filePosStartLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="filePosStopLabel">
+ <property name="text">
+ <string>Stop</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="filePosStopLineEdit"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="filePosLengthLabel">
+ <property name="text">
+ <string>Length</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="filePosLengthLineEdit"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="formLayoutWidget_4">
+ <property name="geometry">
+ <rect>
+ <x>180</x>
+ <y>20</y>
+ <width>231</width>
+ <height>92</height>
+ </rect>
+ </property>
+ <layout class="QFormLayout" name="fileTimeLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="fileTimeStartLabel">
+ <property name="text">
+ <string>time start (sec)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="fileTimeStartLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="fileTimeStopLabel">
+ <property name="text">
+ <string>time stop (sec)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="fileTimeStopLineEdit"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="fileTimeLengthLabel">
+ <property name="text">
+ <string>time length (sec)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="fileTimeLengthLineEdit"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QGroupBox" name="sysGroupBox">
+ <property name="geometry">
+ <rect>
+ <x>530</x>
+ <y>0</y>
+ <width>200</width>
+ <height>120</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>200</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>System Properties</string>
+ </property>
+ <widget class="QWidget" name="formLayoutWidget_3">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>20</y>
+ <width>191</width>
+ <height>91</height>
+ </rect>
+ </property>
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="sampleRateLabel">
+ <property name="text">
+ <string>Sample Rate</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="sampleRateLineEdit">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" name="displayGroupBox">
+ <property name="geometry">
+ <rect>
+ <x>730</x>
+ <y>0</y>
+ <width>170</width>
+ <height>120</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>170</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Display Properties</string>
+ </property>
+ <widget class="QWidget" name="verticalLayoutWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>20</y>
+ <width>160</width>
+ <height>91</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QComboBox" name="colorComboBox"/>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>927</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menu_File">
+ <property name="title">
+ <string>&amp;File</string>
+ </property>
+ <addaction name="action_open"/>
+ <addaction name="action_reload"/>
+ <addaction name="action_exit"/>
+ </widget>
+ <addaction name="menu_File"/>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ <action name="action_open">
+ <property name="text">
+ <string>&amp;Open</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+O</string>
+ </property>
+ </action>
+ <action name="action_exit">
+ <property name="text">
+ <string>E&amp;xit</string>
+ </property>
+ </action>
+ <action name="action_reload">
+ <property name="text">
+ <string>&amp;Reload</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+R</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QwtPlot</class>
+ <extends>QFrame</extends>
+ <header>qwt_plot.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>action_exit</sender>
+ <signal>activated()</signal>
+ <receiver>MainWindow</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>399</x>
+ <y>347</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>