summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjblum2008-06-12 00:29:56 +0000
committerjblum2008-06-12 00:29:56 +0000
commit77284eb970036e6e71ef984133b5a5839d2a157c (patch)
treef9fd00bb208f795f34c2a8d78a8160771c9e1020
parent5f4532721843902ae3cf3100a6846727864471d2 (diff)
downloadgnuradio-77284eb970036e6e71ef984133b5a5839d2a157c.tar.gz
gnuradio-77284eb970036e6e71ef984133b5a5839d2a157c.tar.bz2
gnuradio-77284eb970036e6e71ef984133b5a5839d2a157c.zip
fft sink gui with control panel
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@8581 221aa14e-8319-0410-a670-987f0aec2ac5
-rwxr-xr-xgr-wxgui/src/python/fftsink2.py196
1 files changed, 132 insertions, 64 deletions
diff --git a/gr-wxgui/src/python/fftsink2.py b/gr-wxgui/src/python/fftsink2.py
index 61906bfa1..276406f9c 100755
--- a/gr-wxgui/src/python/fftsink2.py
+++ b/gr-wxgui/src/python/fftsink2.py
@@ -68,8 +68,8 @@ class fft_sink_base(object):
self.avg.set_taps(self.avg_alpha)
else:
self.avg.set_taps(1.0)
- self.win.peak_vals = None
-
+ self.win.peak_vals = None
+
def set_peak_hold(self, enable):
self.peak_hold = enable
self.win.set_peak_hold(enable)
@@ -120,16 +120,16 @@ class fft_sink_f(gr.hier_block2, fft_sink_base):
# FIXME We need to add 3dB to all bins but the DC bin
self.log = gr.nlog10_ff(20, self.fft_size,
- -10*math.log10(self.fft_size) # Adjust for number of bins
- -10*math.log10(power/self.fft_size) # Adjust for windowing loss
- -20*math.log10(ref_scale/2)) # Adjust for reference scale
-
+ -10*math.log10(self.fft_size) # Adjust for number of bins
+ -10*math.log10(power/self.fft_size) # Adjust for windowing loss
+ -20*math.log10(ref_scale/2)) # Adjust for reference scale
+
self.sink = gr.message_sink(gr.sizeof_float * self.fft_size, self.msgq, True)
- self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink)
+ self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink)
self.win = fft_window(self, parent, size=size)
self.set_average(self.average)
-
+ self.set_peak_hold(self.peak_hold)
class fft_sink_c(gr.hier_block2, fft_sink_base):
def __init__(self, parent, baseband_freq=0, ref_scale=2.0,
@@ -163,15 +163,16 @@ class fft_sink_c(gr.hier_block2, fft_sink_base):
# FIXME We need to add 3dB to all bins but the DC bin
self.log = gr.nlog10_ff(20, self.fft_size,
- -10*math.log10(self.fft_size) # Adjust for number of bins
- -10*math.log10(power/self.fft_size) # Adjust for windowing loss
- -20*math.log10(ref_scale/2)) # Adjust for reference scale
-
+ -10*math.log10(self.fft_size) # Adjust for number of bins
+ -10*math.log10(power/self.fft_size) # Adjust for windowing loss
+ -20*math.log10(ref_scale/2)) # Adjust for reference scale
+
self.sink = gr.message_sink(gr.sizeof_float * self.fft_size, self.msgq, True)
- self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink)
+ self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink)
self.win = fft_window(self, parent, size=size)
self.set_average(self.average)
+ self.set_peak_hold(self.peak_hold)
# ------------------------------------------------------------------------
@@ -218,54 +219,121 @@ class input_watcher (threading.Thread):
de = DataEvent (complex_data)
wx.PostEvent (self.event_receiver, de)
del de
+
+class LabelText(wx.StaticText):
+ """Label text class for uniform labels among all controls."""
+ def __init__(self, window, label):
+ wx.StaticText.__init__(self, window, -1, str(label))
+ font = self.GetFont()
+ font.SetWeight(wx.FONTWEIGHT_BOLD)
+ font.SetUnderlined(True)
+ self.SetFont(font)
+
+DIV_LEVELS = (1, 2, 5, 10, 20)
+
+class control_panel(wx.Panel):
+ def __init__(self, parent):
+ self.parent = parent
+ wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
+ control_box = wx.BoxSizer(wx.VERTICAL)
+
+ #checkboxes for average and peak hold
+ control_box.Add(LabelText(self, 'Options'), 0, wx.ALIGN_CENTER)
+ self.average_check_box = wx.CheckBox(parent=self, style=wx.CHK_2STATE, label="Average")
+ self.average_check_box.SetValue(parent.fftsink.average)
+ self.average_check_box.Bind(wx.EVT_CHECKBOX, parent.on_average)
+ control_box.Add(self.average_check_box, 0, wx.EXPAND)
+ self.peak_hold_check_box = wx.CheckBox(parent=self, style=wx.CHK_2STATE, label="Peak Hold")
+ self.peak_hold_check_box.SetValue(parent.fftsink.peak_hold)
+ self.peak_hold_check_box.Bind(wx.EVT_CHECKBOX, parent.on_peak_hold)
+ control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND)
+
+ #radio buttons for div size
+ control_box.Add(LabelText(self, 'Set dB/div'), 0, wx.ALIGN_CENTER)
+ radio_box = wx.BoxSizer(wx.VERTICAL)
+ self.radio_buttons = list()
+ for y_per_div in DIV_LEVELS:
+ radio_button = wx.RadioButton(self, -1, "%d dB/div"%y_per_div)
+ radio_button.SetValue(parent.fftsink.y_per_div == y_per_div)
+ radio_button.Bind(wx.EVT_RADIOBUTTON, self.on_radio_button_change)
+ self.radio_buttons.append(radio_button)
+ radio_box.Add(radio_button, 0, wx.ALIGN_LEFT)
+ control_box.Add(radio_box, 0, wx.EXPAND)
+
+ #ref lvl buttons
+ control_box.Add(LabelText(self, 'Adj Ref Lvl'), 0, wx.ALIGN_CENTER)
+ button_box = wx.BoxSizer(wx.HORIZONTAL)
+ self.ref_plus_button = wx.Button(self, -1, '+', style=wx.BU_EXACTFIT)
+ self.ref_plus_button.Bind(wx.EVT_BUTTON, parent.on_incr_ref_level)
+ button_box.Add(self.ref_plus_button, 0, wx.ALIGN_CENTER)
+ self.ref_minus_button = wx.Button(self, -1, ' - ', style=wx.BU_EXACTFIT)
+ self.ref_minus_button.Bind(wx.EVT_BUTTON, parent.on_decr_ref_level)
+ button_box.Add(self.ref_minus_button, 0, wx.ALIGN_CENTER)
+ control_box.Add(button_box, 0, wx.ALIGN_CENTER)
+ #set sizer
+ self.SetSizerAndFit(control_box)
+
+ def on_radio_button_change(self, evt):
+ selected_radio_button = filter(lambda rb: rb.GetValue(), self.radio_buttons)[0]
+ index = self.radio_buttons.index(selected_radio_button)
+ self.parent.fftsink.set_y_per_div(DIV_LEVELS[index])
-class fft_window (plot.PlotCanvas):
+class fft_window (wx.Panel):
def __init__ (self, fftsink, parent, id = -1,
pos = wx.DefaultPosition, size = wx.DefaultSize,
style = wx.DEFAULT_FRAME_STYLE, name = ""):
- plot.PlotCanvas.__init__ (self, parent, id, pos, size, style, name)
-
- self.y_range = None
+
self.fftsink = fftsink
+ #init panel and plot
+ wx.Panel.__init__(self, parent, -1)
+ self.plot = plot.PlotCanvas(self, id, pos, size, style, name)
+ #setup the box with plot and controls
+ self.control_panel = control_panel(self)
+ main_box = wx.BoxSizer (wx.HORIZONTAL)
+ main_box.Add (self.plot, 1, wx.EXPAND)
+ main_box.Add (self.control_panel, 0, wx.EXPAND)
+ self.SetSizerAndFit(main_box)
+
+ self.y_range = None
self.peak_hold = False
self.peak_vals = None
- self.SetEnableGrid (True)
+ self.plot.SetEnableGrid (True)
# self.SetEnableZoom (True)
# self.SetBackgroundColour ('black')
self.build_popup_menu()
- self.set_baseband_freq(0.0)
-
+ self.set_baseband_freq(0.0)
+
EVT_DATA_EVENT (self, self.set_data)
wx.EVT_CLOSE (self, self.on_close_window)
- self.Bind(wx.EVT_RIGHT_UP, self.on_right_click)
- self.Bind(wx.EVT_MOTION, self.evt_motion)
-
+ self.plot.Bind(wx.EVT_RIGHT_UP, self.on_right_click)
+ self.plot.Bind(wx.EVT_MOTION, self.evt_motion)
+
self.input_watcher = input_watcher(fftsink.msgq, fftsink.fft_size, self)
def set_scale(self, freq):
- x = max(abs(self.fftsink.sample_rate), abs(self.fftsink.baseband_freq))
+ x = max(abs(self.fftsink.sample_rate), abs(self.fftsink.baseband_freq))
if x >= 1e9:
self._scale_factor = 1e-9
self._units = "GHz"
- self._format = "%3.6f"
+ self._format = "%3.6f"
elif x >= 1e6:
self._scale_factor = 1e-6
self._units = "MHz"
- self._format = "%3.3f"
+ self._format = "%3.3f"
else:
self._scale_factor = 1e-3
self._units = "kHz"
- self._format = "%3.3f"
+ self._format = "%3.3f"
def set_baseband_freq(self, baseband_freq):
- if self.peak_hold:
- self.peak_vals = None
- self.set_scale(baseband_freq)
- self.fftsink.set_baseband_freq(baseband_freq)
-
+ if self.peak_hold:
+ self.peak_vals = None
+ self.set_scale(baseband_freq)
+ self.fftsink.set_baseband_freq(baseband_freq)
+
def on_close_window (self, event):
print "fft_window:on_close_window"
self.keep_running = False
@@ -283,15 +351,15 @@ class fft_window (plot.PlotCanvas):
if self.fftsink.input_is_real: # only plot 1/2 the points
x_vals = ((numpy.arange (L/2) * (self.fftsink.sample_rate
- * self._scale_factor / L))
+ * self._scale_factor / L))
+ self.fftsink.baseband_freq * self._scale_factor)
self._points = numpy.zeros((len(x_vals), 2), numpy.float64)
self._points[:,0] = x_vals
self._points[:,1] = dB[0:L/2]
- if self.peak_hold:
- self._peak_points = numpy.zeros((len(x_vals), 2), numpy.float64)
- self._peak_points[:,0] = x_vals
- self._peak_points[:,1] = self.peak_vals[0:L/2]
+ if self.peak_hold:
+ self._peak_points = numpy.zeros((len(x_vals), 2), numpy.float64)
+ self._peak_points[:,0] = x_vals
+ self._peak_points[:,1] = self.peak_vals[0:L/2]
else:
# the "negative freqs" are in the second half of the array
x_vals = ((numpy.arange (-L/2, L/2)
@@ -300,20 +368,20 @@ class fft_window (plot.PlotCanvas):
self._points = numpy.zeros((len(x_vals), 2), numpy.float64)
self._points[:,0] = x_vals
self._points[:,1] = numpy.concatenate ((dB[L/2:], dB[0:L/2]))
- if self.peak_hold:
- self._peak_points = numpy.zeros((len(x_vals), 2), numpy.float64)
- self._peak_points[:,0] = x_vals
- self._peak_points[:,1] = numpy.concatenate ((self.peak_vals[L/2:], self.peak_vals[0:L/2]))
+ if self.peak_hold:
+ self._peak_points = numpy.zeros((len(x_vals), 2), numpy.float64)
+ self._peak_points[:,0] = x_vals
+ self._peak_points[:,1] = numpy.concatenate ((self.peak_vals[L/2:], self.peak_vals[0:L/2]))
lines = [plot.PolyLine (self._points, colour='BLUE'),]
- if self.peak_hold:
- lines.append(plot.PolyLine (self._peak_points, colour='GREEN'))
+ if self.peak_hold:
+ lines.append(plot.PolyLine (self._peak_points, colour='GREEN'))
graphics = plot.PlotGraphics (lines,
title=self.fftsink.title,
xLabel = self._units, yLabel = "dB")
- self.Draw (graphics, xAxis=None, yAxis=self.y_range)
+ self.plot.Draw (graphics, xAxis=None, yAxis=self.y_range)
self.update_y_range ()
@@ -324,7 +392,7 @@ class fft_window (plot.PlotCanvas):
def update_y_range (self):
ymax = self.fftsink.ref_level
ymin = self.fftsink.ref_level - self.fftsink.y_per_div * self.fftsink.y_divs
- self.y_range = self._axisInterval ('min', ymin, ymax)
+ self.y_range = self.plot._axisInterval ('min', ymin, ymax)
def on_average(self, evt):
# print "on_average"
@@ -371,14 +439,14 @@ class fft_window (plot.PlotCanvas):
for id, pred in self.checkmarks.items():
item = menu.FindItemById(id)
item.Check(pred())
- self.PopupMenu(menu, event.GetPosition())
+ self.plot.PopupMenu(menu, event.GetPosition())
def evt_motion(self, event):
if not hasattr(self, "_points"):
- return # Got here before first window data update
-
- # Clip to plotted values
- (ux, uy) = self.GetXY(event) # Scaled position
+ return # Got here before first window data update
+
+ # Clip to plotted values
+ (ux, uy) = self.plot.GetXY(event) # Scaled position
x_vals = numpy.array(self._points[:,0])
if ux < x_vals[0] or ux > x_vals[-1]:
tip = self.GetToolTip()
@@ -410,18 +478,18 @@ class fft_window (plot.PlotCanvas):
self.id_y_per_div_20 = wx.NewId()
self.id_average = wx.NewId()
self.id_peak_hold = wx.NewId()
-
- self.Bind(wx.EVT_MENU, self.on_average, id=self.id_average)
- self.Bind(wx.EVT_MENU, self.on_peak_hold, id=self.id_peak_hold)
- self.Bind(wx.EVT_MENU, self.on_incr_ref_level, id=self.id_incr_ref_level)
- self.Bind(wx.EVT_MENU, self.on_decr_ref_level, id=self.id_decr_ref_level)
- self.Bind(wx.EVT_MENU, self.on_incr_y_per_div, id=self.id_incr_y_per_div)
- self.Bind(wx.EVT_MENU, self.on_decr_y_per_div, id=self.id_decr_y_per_div)
- self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_1)
- self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_2)
- self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_5)
- self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_10)
- self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_20)
+
+ self.plot.Bind(wx.EVT_MENU, self.on_average, id=self.id_average)
+ self.plot.Bind(wx.EVT_MENU, self.on_peak_hold, id=self.id_peak_hold)
+ self.plot.Bind(wx.EVT_MENU, self.on_incr_ref_level, id=self.id_incr_ref_level)
+ self.plot.Bind(wx.EVT_MENU, self.on_decr_ref_level, id=self.id_decr_ref_level)
+ self.plot.Bind(wx.EVT_MENU, self.on_incr_y_per_div, id=self.id_incr_y_per_div)
+ self.plot.Bind(wx.EVT_MENU, self.on_decr_y_per_div, id=self.id_decr_y_per_div)
+ self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_1)
+ self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_2)
+ self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_5)
+ self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_10)
+ self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_20)
# make a menu
menu = wx.Menu()
@@ -499,7 +567,7 @@ class test_app_block (stdgui2.std_top_block):
ref_level=0, y_per_div=20)
vbox.Add (sink1.win, 1, wx.EXPAND)
- self.connect(src1, thr1, sink1)
+ self.connect(src1, thr1, sink1)
#src2 = gr.sig_source_f (input_rate, gr.GR_SIN_WAVE, 2e3, 1)
src2 = gr.sig_source_f (input_rate, gr.GR_CONST_WAVE, 5.75e3, 1)
@@ -509,7 +577,7 @@ class test_app_block (stdgui2.std_top_block):
ref_level=0, y_per_div=20)
vbox.Add (sink2.win, 1, wx.EXPAND)
- self.connect(src2, thr2, sink2)
+ self.connect(src2, thr2, sink2)
def main ():
app = stdgui2.stdapp (test_app_block, "FFT Sink Test App")