summaryrefslogtreecommitdiff
path: root/gr-wxgui/src/python/number_window.py
diff options
context:
space:
mode:
Diffstat (limited to 'gr-wxgui/src/python/number_window.py')
-rw-r--r--gr-wxgui/src/python/number_window.py213
1 files changed, 213 insertions, 0 deletions
diff --git a/gr-wxgui/src/python/number_window.py b/gr-wxgui/src/python/number_window.py
new file mode 100644
index 000000000..ab9d1ebc0
--- /dev/null
+++ b/gr-wxgui/src/python/number_window.py
@@ -0,0 +1,213 @@
+#
+# 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.
+#
+
+##################################################
+# Imports
+##################################################
+import common
+import numpy
+import wx
+import pubsub
+from constants import *
+from gnuradio import gr #for gr.prefs
+import forms
+
+##################################################
+# Constants
+##################################################
+NEG_INF = float('-inf')
+SLIDER_STEPS = 100
+AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP = -3, 0
+DEFAULT_NUMBER_RATE = gr.prefs().get_long('wxgui', 'number_rate', 5)
+DEFAULT_WIN_SIZE = (300, 300)
+DEFAULT_GAUGE_RANGE = 1000
+VALUE_REPR_KEY = 'value_repr'
+VALUE_REAL_KEY = 'value_real'
+VALUE_IMAG_KEY = 'value_imag'
+
+##################################################
+# Number window control panel
+##################################################
+class control_panel(wx.Panel):
+ """
+ A control panel with wx widgits to control the averaging.
+ """
+
+ def __init__(self, parent):
+ """
+ Create a new control panel.
+ @param parent the wx parent window
+ """
+ self.parent = parent
+ wx.Panel.__init__(self, parent)
+ parent[SHOW_CONTROL_PANEL_KEY] = True
+ parent.subscribe(SHOW_CONTROL_PANEL_KEY, self.Show)
+ control_box = wx.BoxSizer(wx.VERTICAL)
+ #checkboxes for average and peak hold
+ control_box.AddStretchSpacer()
+ options_box = forms.static_box_sizer(
+ parent=self, sizer=control_box, label='Options',
+ bold=True, orient=wx.VERTICAL,
+ )
+ forms.check_box(
+ sizer=options_box, parent=self, label='Peak Hold',
+ ps=parent, key=PEAK_HOLD_KEY,
+ )
+ forms.check_box(
+ sizer=options_box, parent=self, label='Average',
+ ps=parent, key=AVERAGE_KEY,
+ )
+ #static text and slider for averaging
+ avg_alpha_text = forms.static_text(
+ sizer=options_box, parent=self, label='Avg Alpha',
+ converter=forms.float_converter(lambda x: '%.4f'%x),
+ ps=parent, key=AVG_ALPHA_KEY, width=50,
+ )
+ avg_alpha_slider = forms.log_slider(
+ sizer=options_box, parent=self,
+ min_exp=AVG_ALPHA_MIN_EXP,
+ max_exp=AVG_ALPHA_MAX_EXP,
+ num_steps=SLIDER_STEPS,
+ ps=parent, key=AVG_ALPHA_KEY,
+ )
+ for widget in (avg_alpha_text, avg_alpha_slider):
+ parent.subscribe(AVERAGE_KEY, widget.Enable)
+ widget.Enable(parent[AVERAGE_KEY])
+ #run/stop
+ control_box.AddStretchSpacer()
+ forms.toggle_button(
+ sizer=control_box, parent=self,
+ true_label='Stop', false_label='Run',
+ ps=parent, key=RUNNING_KEY,
+ )
+ #set sizer
+ self.SetSizerAndFit(control_box)
+
+##################################################
+# Numbersink window with label and gauges
+##################################################
+class number_window(wx.Panel, pubsub.pubsub):
+ def __init__(
+ self,
+ parent,
+ controller,
+ size,
+ title,
+ units,
+ show_gauge,
+ real,
+ minval,
+ maxval,
+ decimal_places,
+ average_key,
+ avg_alpha_key,
+ peak_hold,
+ msg_key,
+ sample_rate_key,
+ ):
+ pubsub.pubsub.__init__(self)
+ wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
+ #setup
+ self.peak_val_real = NEG_INF
+ self.peak_val_imag = NEG_INF
+ self.real = real
+ self.units = units
+ self.decimal_places = decimal_places
+ #proxy the keys
+ self.proxy(MSG_KEY, controller, msg_key)
+ self.proxy(AVERAGE_KEY, controller, average_key)
+ self.proxy(AVG_ALPHA_KEY, controller, avg_alpha_key)
+ self.proxy(SAMPLE_RATE_KEY, controller, sample_rate_key)
+ #initialize values
+ self[PEAK_HOLD_KEY] = peak_hold
+ self[RUNNING_KEY] = True
+ self[VALUE_REAL_KEY] = minval
+ self[VALUE_IMAG_KEY] = minval
+ #setup the box with display and controls
+ self.control_panel = control_panel(self)
+ main_box = wx.BoxSizer(wx.HORIZONTAL)
+ sizer = forms.static_box_sizer(
+ parent=self, sizer=main_box, label=title,
+ bold=True, orient=wx.VERTICAL, proportion=1,
+ )
+ main_box.Add(self.control_panel, 0, wx.EXPAND)
+ sizer.AddStretchSpacer()
+ forms.static_text(
+ parent=self, sizer=sizer,
+ ps=self, key=VALUE_REPR_KEY, width=size[0],
+ converter=forms.str_converter(),
+ )
+ sizer.AddStretchSpacer()
+ self.gauge_real = forms.gauge(
+ parent=self, sizer=sizer, style=wx.GA_HORIZONTAL,
+ ps=self, key=VALUE_REAL_KEY, length=size[0],
+ minimum=minval, maximum=maxval, num_steps=DEFAULT_GAUGE_RANGE,
+ )
+ self.gauge_imag = forms.gauge(
+ parent=self, sizer=sizer, style=wx.GA_HORIZONTAL,
+ ps=self, key=VALUE_IMAG_KEY, length=size[0],
+ minimum=minval, maximum=maxval, num_steps=DEFAULT_GAUGE_RANGE,
+ )
+ #hide/show gauges
+ self.show_gauges(show_gauge)
+ self.SetSizerAndFit(main_box)
+ #register events
+ self.subscribe(MSG_KEY, self.handle_msg)
+
+ def show_gauges(self, show_gauge):
+ """
+ Show or hide the gauges.
+ If this is real, never show the imaginary gauge.
+ @param show_gauge true to show
+ """
+ self.gauge_real.ShowItems(show_gauge)
+ self.gauge_imag.ShowItems(show_gauge and not self.real)
+
+ def handle_msg(self, msg):
+ """
+ Handle a message from the message queue.
+ Convert the string based message into a float or complex.
+ If more than one number was read, only take the last number.
+ Perform peak hold operations, set the gauges and display.
+ @param event event.data is the number sample as a character array
+ """
+ if not self[RUNNING_KEY]: return
+ format_string = "%%.%df"%self.decimal_places
+ if self.real:
+ sample = numpy.fromstring(msg, numpy.float32)[-1]
+ if self[PEAK_HOLD_KEY]: sample = self.peak_val_real = max(self.peak_val_real, sample)
+ label_text = "%s %s"%(format_string%sample, self.units)
+ self[VALUE_REAL_KEY] = sample
+ else:
+ sample = numpy.fromstring(msg, numpy.complex64)[-1]
+ if self[PEAK_HOLD_KEY]:
+ self.peak_val_real = max(self.peak_val_real, sample.real)
+ self.peak_val_imag = max(self.peak_val_imag, sample.imag)
+ sample = self.peak_val_real + self.peak_val_imag*1j
+ label_text = "%s + %sj %s"%(format_string%sample.real, format_string%sample.imag, self.units)
+ self[VALUE_REAL_KEY] = sample.real
+ self[VALUE_IMAG_KEY] = sample.imag
+ #set label text
+ self[VALUE_REPR_KEY] = label_text
+ #clear peak hold
+ if not self[PEAK_HOLD_KEY]:
+ self.peak_val_real = NEG_INF
+ self.peak_val_imag = NEG_INF