[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r8883 - gnuradio/branches/features/experimental-gui
From: |
jblum |
Subject: |
[Commit-gnuradio] r8883 - gnuradio/branches/features/experimental-gui |
Date: |
Mon, 14 Jul 2008 15:13:27 -0600 (MDT) |
Author: jblum
Date: 2008-07-14 15:13:26 -0600 (Mon, 14 Jul 2008)
New Revision: 8883
Added:
gnuradio/branches/features/experimental-gui/todo.txt
Modified:
gnuradio/branches/features/experimental-gui/common.py
gnuradio/branches/features/experimental-gui/fft_gui.py
gnuradio/branches/features/experimental-gui/fft_top_block.py
gnuradio/branches/features/experimental-gui/fft_window.py
gnuradio/branches/features/experimental-gui/prop_val.py
Log:
fft window has internal controller
Modified: gnuradio/branches/features/experimental-gui/common.py
===================================================================
--- gnuradio/branches/features/experimental-gui/common.py 2008-07-14
17:27:42 UTC (rev 8882)
+++ gnuradio/branches/features/experimental-gui/common.py 2008-07-14
21:13:26 UTC (rev 8883)
@@ -79,42 +79,57 @@
self._decr_button.Bind(wx.EVT_BUTTON, on_decr)
self.Add(self._decr_button, 0, wx.ALIGN_CENTER_VERTICAL)
- def Enable(self):
- self._incr_button.Enable()
- self._decr_button.Enable()
+ def Enable(self, enable=True):
+ if enable:
+ self._incr_button.Enable()
+ self._decr_button.Enable()
+ else:
+ self._incr_button.Disable()
+ self._decr_button.Disable()
- def Disable(self):
- self._incr_button.Disable()
- self._decr_button.Disable()
+ def Disable(self): self.Enable(False)
- def _set_slider_value(self, real_value):
- """!
- Translate the real numerical value into a slider value and,
- write the value to the slider.
- @param real_value the numeric value the slider should represent
- """
- slider_value = (float(real_value) -
self.min)*self.num_steps/(self.max - self.min)
- self.slider.SetValue(slider_value)
+class RunStopButtonController(wx.Button):
+ def __init__(self, parent, controller, control_key):
+ wx.Button.__init__(self, parent, -1, '', style=wx.BU_EXACTFIT)
+ self.Bind(wx.EVT_BUTTON, lambda e: controller.set(control_key,
not controller[control_key]))
+ controller.add_listener(control_key, lambda x: self.SetLabel(x
and 'Stop' or 'Run'))
- def _handle_scroll(self, event=None):
- """!
- A scroll event is detected. Read the slider, call the callback.
- """
- slider_value = self.slider.GetValue()
- new_value = slider_value*(self.max - self.min)/self.num_steps +
self.min
- self.text_box.SetValue(str(new_value))
- self._value = new_value
- self.callback(self._value)
+class CheckBoxController(wx.CheckBox):
+ def __init__(self, parent, label, controller, control_key):
+ wx.CheckBox.__init__(self, parent, style=wx.CHK_2STATE,
label=label)
+ self.Bind(wx.EVT_CHECKBOX, lambda e:
controller.set(control_key, bool(e.IsChecked())))
+ controller.add_listener(control_key, lambda x:
self.SetValue(bool(x)))
- def _handle_enter(self, event=None):
- """!
- An enter key was pressed. Read the text box, call the callback.
- """
- new_value = float(self.text_box.GetValue())
- self._set_slider_value(new_value)
- self._value = new_value
- self.callback(self._value)
+class LogSliderController(wx.BoxSizer):
+ def __init__(self, parent, label, min_exp, max_exp, slider_steps,
controller, control_key, formatter=lambda x: ': %.3g'%x):
+ wx.BoxSizer.__init__(self, wx.VERTICAL)
+ self._label = wx.StaticText(parent, -1, label +
formatter(1/3.0))
+ self.Add(self._label, 0, wx.EXPAND)
+ self._slider = wx.Slider(parent, -1, 0, 0, slider_steps,
style=wx.SL_HORIZONTAL)
+ self.Add(self._slider, 0, wx.EXPAND)
+ def _on_slider_event(event):
+ controller[control_key] = \
+
10**(float(max_exp-min_exp)*self._slider.GetValue()/slider_steps + min_exp)
+ self._slider.Bind(wx.EVT_SLIDER, _on_slider_event)
+ def _on_controller_set(value):
+ self._label.SetLabel(label + formatter(value))
+ slider_value =
slider_steps*(math.log10(value)-min_exp)/(max_exp-min_exp)
+ slider_value = min(max(0, slider_value), slider_steps)
+ if abs(slider_value - self._slider.GetValue()) > 1:
+ self._slider.SetValue(slider_value)
+ controller.add_listener(control_key, _on_controller_set)
+ def Enable(self, enable=True):
+ if enable:
+ self._slider.Enable()
+ self._label.Enable()
+ else:
+ self._slider.Disable()
+ self._label.Disable()
+
+ def Disable(self): self.Enable(False)
+
##################################################
# Shared Functions
##################################################
Modified: gnuradio/branches/features/experimental-gui/fft_gui.py
===================================================================
--- gnuradio/branches/features/experimental-gui/fft_gui.py 2008-07-14
17:27:42 UTC (rev 8882)
+++ gnuradio/branches/features/experimental-gui/fft_gui.py 2008-07-14
21:13:26 UTC (rev 8883)
@@ -30,9 +30,9 @@
"""
class fft_gui(wxgui_app):
- def __init__(self, controller):
- wxgui_app.__init__(self, controller=controller, title='fft demo')
-
+ def __init__(self, controller, title='fft demo'):
+ wxgui_app.__init__(self, controller=controller, title=title)
+
self._win = fft_window(parent=self.GetWin(),
controller=controller,
size=(600, 300),
Modified: gnuradio/branches/features/experimental-gui/fft_top_block.py
===================================================================
--- gnuradio/branches/features/experimental-gui/fft_top_block.py
2008-07-14 17:27:42 UTC (rev 8882)
+++ gnuradio/branches/features/experimental-gui/fft_top_block.py
2008-07-14 21:13:26 UTC (rev 8883)
@@ -33,7 +33,7 @@
"""
def __init__(self,
fft_size=512,
- frame_rate=30,
+ frame_rate=60,
ref_scale=50,
which=0,
decim=16,
Modified: gnuradio/branches/features/experimental-gui/fft_window.py
===================================================================
--- gnuradio/branches/features/experimental-gui/fft_window.py 2008-07-14
17:27:42 UTC (rev 8882)
+++ gnuradio/branches/features/experimental-gui/fft_window.py 2008-07-14
21:13:26 UTC (rev 8883)
@@ -27,17 +27,28 @@
import wx
import numpy
import math
+import prop_val
##################################################
# Constants
##################################################
SLIDER_STEPS = 100
-AVG_ALPHA_SLIDER_MIN, AVG_ALPHA_SLIDER_MAX = -4, 0
+AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP = -3, 0
DEFAULT_FRAME_RATE = 30
DEFAULT_WIN_SIZE = (640, 240)
DIV_LEVELS = (1, 2, 5, 10, 20)
FFT_PLOT_COLOR_SPEC = (0, 0, 1)
PEAK_VALS_COLOR_SPEC = (0, 1, 0)
+NO_PEAK_VALS = list()
+AVERAGE_KEY = 'average'
+AVG_ALPHA_KEY = 'avg_alpha'
+PEAK_HOLD_KEY = 'peak_hold'
+Y_PER_DIV_KEY = 'y_per_div'
+Y_DIVS_KEY = 'y_divs'
+X_DIVS_KEY = 'x_divs'
+REF_LEVEL_KEY = 'ref_level'
+BASEBAND_FREQ_KEY = 'baseband_freq'
+RUNNING_KEY = 'running'
##################################################
# FFT window control panel
@@ -59,17 +70,17 @@
#checkboxes for average and peak hold
control_box.AddStretchSpacer()
control_box.Add(common.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.Bind(wx.EVT_CHECKBOX, self._on_average)
+ self.average_check_box = common.CheckBoxController(self,
'Average', parent.controller, AVERAGE_KEY)
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.Bind(wx.EVT_CHECKBOX,
self._on_peak_hold)
+ self.peak_hold_check_box = common.CheckBoxController(self,
'Peak Hold', parent.controller, PEAK_HOLD_KEY)
control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND)
control_box.AddSpacer(2)
- self.avg_alpha_label = wx.StaticText(self, -1, '0'*15)
- control_box.Add(self.avg_alpha_label, 0, wx.EXPAND)
- self.avg_alpha_slider = wx.Slider(self, -1, 0, 0, SLIDER_STEPS,
style=wx.SL_HORIZONTAL)
- self.avg_alpha_slider.Bind(wx.EVT_SLIDER, self._on_avg_alpha)
+ self.avg_alpha_slider = common.LogSliderController(
+ self, 'Avg Alpha',
+ AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP, SLIDER_STEPS,
+ parent.controller, AVG_ALPHA_KEY,
+ )
+ parent.controller.add_listener(AVERAGE_KEY,
self.avg_alpha_slider.Enable)
control_box.Add(self.avg_alpha_slider, 0, wx.EXPAND)
#radio buttons for div size
@@ -79,9 +90,10 @@
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.Bind(wx.EVT_RADIOBUTTON,
self._on_radio_button_change)
+ radio_button.Bind(wx.EVT_RADIOBUTTON,
self._on_y_per_div)
self.radio_buttons.append(radio_button)
radio_box.Add(radio_button, 0, wx.ALIGN_LEFT)
+ parent.controller.add_listener(Y_PER_DIV_KEY,
self._on_set_y_per_div)
control_box.Add(radio_box, 0, wx.EXPAND)
#ref lvl buttons
@@ -94,54 +106,30 @@
#run/stop
control_box.AddStretchSpacer()
- self.run_button = wx.Button(self, -1, '', style=wx.BU_EXACTFIT)
- self.run_button.Bind(wx.EVT_BUTTON, self._on_run)
+ self.run_button = common.RunStopButtonController(self,
parent.controller, RUNNING_KEY)
control_box.Add(self.run_button, 0, wx.EXPAND)
#set sizer
self.SetSizerAndFit(control_box)
- def update(self):
- """!
- Read the state of the fft plot settings and update the control
panel.
- """
- #update the run/stop button
- if self.parent.running: self.run_button.SetLabel('Stop')
- else: self.run_button.SetLabel('Run')
- #update checkboxes
- self.average_check_box.SetValue(self.parent.average)
- self.peak_hold_check_box.SetValue(self.parent.peak_hold)
- #update avg alpha
- self.avg_alpha_label.SetLabel('Avg Alpha:
%.3g'%self.parent.avg_alpha)
- slider_value =
SLIDER_STEPS*(math.log10(self.parent.avg_alpha)-AVG_ALPHA_SLIDER_MIN)/(AVG_ALPHA_SLIDER_MAX-AVG_ALPHA_SLIDER_MIN)
- if abs(slider_value - self.avg_alpha_slider.GetValue()) > 1:
- self.avg_alpha_slider.SetValue(slider_value)
- if self.parent.average:
- self.avg_alpha_label.Enable()
- self.avg_alpha_slider.Enable()
- else:
- self.avg_alpha_label.Disable()
- self.avg_alpha_slider.Disable()
- #update radio buttons
- try:
- index = list(DIV_LEVELS).index(self.parent.y_per_div)
- self.radio_buttons[index].SetValue(True)
- except: pass
-
##################################################
# Event handlers
##################################################
- def _on_radio_button_change(self, event):
+ def _on_set_y_per_div(self, y_per_div):
+ try:
+ index = list(DIV_LEVELS).index(y_per_div)
+ self.radio_buttons[index].SetValue(True)
+ except: pass
+ def _on_y_per_div(self, event):
selected_radio_button = filter(lambda rb: rb.GetValue(),
self.radio_buttons)[0]
index = self.radio_buttons.index(selected_radio_button)
- self.parent.set_y_per_div(DIV_LEVELS[index])
- def _on_average(self, event): self.parent.set_average(event.IsChecked())
- def _on_peak_hold(self, event):
self.parent.set_peak_hold(event.IsChecked())
- def _on_incr_ref_level(self, event): self.parent.incr_ref_level()
- def _on_decr_ref_level(self, event): self.parent.decr_ref_level()
- def _on_avg_alpha(self, event):
-
self.parent.set_avg_alpha(10**(float(AVG_ALPHA_SLIDER_MAX-AVG_ALPHA_SLIDER_MIN)*self.avg_alpha_slider.GetValue()/SLIDER_STEPS
+ AVG_ALPHA_SLIDER_MIN))
- def _on_run(self, event): self.parent.set_run(not self.parent.running)
+ self.parent.controller[Y_PER_DIV_KEY] = DIV_LEVELS[index]
+ def _on_incr_ref_level(self, event):
+ self.parent.set_ref_level(
+ self.parent.controller[REF_LEVEL_KEY] +
self.parent.controller[Y_PER_DIV_KEY])
+ def _on_decr_ref_level(self, event):
+ self.parent.set_ref_level(
+ self.parent.controller[REF_LEVEL_KEY] -
self.parent.controller[Y_PER_DIV_KEY])
##################################################
# FFT window with plotter and control panel
@@ -164,69 +152,87 @@
peak_hold,
msg_key,
):
+ self.controller = prop_val.prop_val_interface()
#ensure y_per_div
if y_per_div not in DIV_LEVELS: y_per_div = DIV_LEVELS[0]
#setup
- self.controller = controller
- self.running = True
+ self.ext_controller = controller
self.real = real
- self.baseband_freq = baseband_freq
self.sample_rate_key = sample_rate_key
- self.x_divs = 8.0 #approximate
- self.y_per_div = y_per_div
- self.y_divs = y_divs
- self.ref_level = ref_level
self.average_key = average_key
self.avg_alpha_key = avg_alpha_key
- self.peak_hold = peak_hold
- self.peak_vals = []
+ self.peak_vals = NO_PEAK_VALS
#init panel and plot
wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
self.plotter = plotter.grid_plotter(self)
self.plotter.SetSize(wx.Size(*size))
self.plotter.set_title(title)
- self.plotter.set_y_units('Amplitude (dB)')
#setup the box with plot and controls
self.control_panel = control_panel(self)
main_box = wx.BoxSizer(wx.HORIZONTAL)
main_box.Add(self.plotter, 1, wx.EXPAND)
main_box.Add(self.control_panel, 0, wx.EXPAND)
self.SetSizerAndFit(main_box)
- #setup controller
- self.controller.add_listener(msg_key, self.handle_msg)
- self.controller.add_listener(self.sample_rate_key, lambda x:
self.update())
- self.controller.add_listener(self.average_key, lambda x:
self.update())
- self.controller.add_listener(self.avg_alpha_key, lambda x:
self.update())
- #update
- self.update()
-
+ #bind internal & external keys
+ def bind_controller_keys(controller_master, controller_slave,
master_key, slave_key):
+ controller_slave[slave_key] =
controller_master[master_key]
+ controller_slave.add_listener(slave_key, lambda x:
controller_master.set(master_key, x))
+ controller_master.add_listener(master_key, lambda x:
controller_slave.set(slave_key, x))
+ for in_key, ext_key in (
+ (AVERAGE_KEY, average_key),
+ (AVG_ALPHA_KEY, avg_alpha_key),
+ ): bind_controller_keys(self.ext_controller, self.controller,
ext_key, in_key)
+ #initial setup
+ self.set_baseband_freq(baseband_freq)
+ self.set_peak_hold(peak_hold)
+ self.set_y_per_div(y_per_div)
+ self.set_y_divs(y_divs)
+ self.set_x_divs(8) #approximate
+ self.set_ref_level(ref_level)
+ self.set_running(True)
+ #register events
+ self.ext_controller.add_listener(msg_key, self.handle_msg)
+ self.ext_controller.add_listener(self.sample_rate_key, lambda
x: self.update_grid())
+ self.controller.add_listener(BASEBAND_FREQ_KEY, lambda x:
self.update_grid())
+ self.controller.add_listener(Y_PER_DIV_KEY, lambda x:
self.update_grid())
+ self.controller.add_listener(Y_DIVS_KEY, lambda x:
self.update_grid())
+ self.controller.add_listener(X_DIVS_KEY, lambda x:
self.update_grid())
+ self.controller.add_listener(REF_LEVEL_KEY, lambda x:
self.update_grid())
+ #initial update
+ self.update_grid()
+
+ ##################################################
+ # Set parameters on-the-fly
+ ##################################################
+ def set_peak_hold(self, peak_hold): self.controller[PEAK_HOLD_KEY] =
peak_hold
+ def set_y_per_div(self, y_per_div): self.controller[Y_PER_DIV_KEY] =
y_per_div
+ def set_y_divs(self, y_divs): self.controller[Y_DIVS_KEY] = y_divs
+ def set_x_divs(self, x_divs): self.controller[X_DIVS_KEY] = x_divs
+ def set_ref_level(self, ref_level): self.controller[REF_LEVEL_KEY] =
ref_level
+ def set_baseband_freq(self, baseband_freq):
self.controller[BASEBAND_FREQ_KEY] = baseband_freq
+ def set_running(self, running): self.controller[RUNNING_KEY] = running
+
def handle_msg(self, msg):
"""!
Handle the message from the fft sink message queue.
If complex, reorder the fft samples so the negative bins come
first.
If real, keep take only the positive bins.
+ Plot the samples onto the grid as channel 1.
+ If peak hold is enabled, plot peak vals as channel 2.
@param msg the fft array as a character array
"""
+ if not self.controller[RUNNING_KEY]: return
#convert to floating point numbers
samples = numpy.fromstring(msg, numpy.float32)
num_samps = len(samples)
#reorder fft
if self.real: samples = samples[:num_samps/2]
else: samples = numpy.concatenate((samples[num_samps/2+1:],
samples[:num_samps/2]))
- #plot
- self.plot(samples)
-
- def plot(self, samples):
- """!
- Plot the samples onto the grid as channel 1.
- If peak hold is enabled, plot peak vals as channel 2.
- @param samples the fft array
- """
- if not self.running: return
#peak hold calculation
- if self.peak_hold:
+ if self.controller[PEAK_HOLD_KEY]:
if len(self.peak_vals) != len(samples): self.peak_vals
= samples
self.peak_vals = numpy.maximum(samples, self.peak_vals)
+ else: self.peak_vals = NO_PEAK_VALS
#plot the fft
self.plotter.set_waveform(
channel=1,
@@ -242,16 +248,25 @@
#update the plotter
self.plotter.update()
- def update(self):
- self.sample_rate = self.controller[self.sample_rate_key]
- self.average = self.controller[self.average_key]
- self.avg_alpha = self.controller[self.avg_alpha_key]
- #update peak hold
- if not self.peak_hold: self.peak_vals = []
+ def update_grid(self):
+ """!
+ Update the plotter grid.
+ This update method is dependent on the variables below.
+ Determine the x and y axis grid parameters.
+ The x axis depends on sample rate, baseband freq, and x divs.
+ The y axis depends on y per div, y divs, and ref level.
+ """
+ #grid parameters
+ sample_rate = self.ext_controller[self.sample_rate_key]
+ baseband_freq = self.controller[BASEBAND_FREQ_KEY]
+ y_per_div = self.controller[Y_PER_DIV_KEY]
+ y_divs = self.controller[Y_DIVS_KEY]
+ x_divs = self.controller[X_DIVS_KEY]
+ ref_level = self.controller[REF_LEVEL_KEY]
#determine best fitting x_per_div
- if self.real: x_width = self.sample_rate/2.0
- else: x_width = self.sample_rate
- x_per_div = common.get_clean_num(x_width/self.x_divs)
+ if self.real: x_width = sample_rate/2.0
+ else: x_width = sample_rate/1.0
+ x_per_div = common.get_clean_num(x_width/x_divs)
exp = common.get_exp(x_per_div)
#calculate units and scalar
if exp > 7: x_units, scalar = 'GHz', 1e-9
@@ -261,45 +276,21 @@
#update the x grid
if self.real:
self.plotter.set_x_grid(
- scalar*self.baseband_freq,
- scalar*self.baseband_freq +
scalar*self.sample_rate/2.0,
+ scalar*baseband_freq,
+ scalar*baseband_freq + scalar*sample_rate/2.0,
scalar*x_per_div,
)
else:
self.plotter.set_x_grid(
- scalar*self.baseband_freq -
scalar*self.sample_rate/2.0,
- scalar*self.baseband_freq +
scalar*self.sample_rate/2.0,
+ scalar*baseband_freq - scalar*sample_rate/2.0,
+ scalar*baseband_freq + scalar*sample_rate/2.0,
scalar*x_per_div,
)
#update x units
self.plotter.set_x_units('Frequency (%s)'%x_units)
#update y grid
-
self.plotter.set_y_grid(self.ref_level-self.y_per_div*self.y_divs,
self.ref_level, self.y_per_div)
- #update control panel and plotter
- self.control_panel.update()
+ self.plotter.set_y_grid(ref_level-y_per_div*y_divs, ref_level,
y_per_div)
+ #update y units
+ self.plotter.set_y_units('Amplitude (dB)')
+ #update plotter
self.plotter.update()
-
- ##################################################
- # Set parameters on-the-fly
- ##################################################
- def set_baseband_freq(self, baseband_freq):
- self.baseband_freq = baseband_freq
- self.update()
- def set_average(self, average):
- self.controller[self.average_key] = average
- def set_avg_alpha(self, avg_alpha):
- self.controller[self.avg_alpha_key] = avg_alpha
- def set_peak_hold(self, peak_hold):
- self.peak_hold = peak_hold
- self.update()
- def set_y_per_div(self, y_per_div):
- self.y_per_div = y_per_div
- self.update()
- def set_ref_level(self, ref_level):
- self.ref_level = ref_level
- self.update()
- def incr_ref_level(self): self.set_ref_level(self.ref_level +
self.y_per_div)
- def decr_ref_level(self): self.set_ref_level(self.ref_level -
self.y_per_div)
- def set_run(self, running):
- self.running = running
- self.update()
Modified: gnuradio/branches/features/experimental-gui/prop_val.py
===================================================================
--- gnuradio/branches/features/experimental-gui/prop_val.py 2008-07-14
17:27:42 UTC (rev 8882)
+++ gnuradio/branches/features/experimental-gui/prop_val.py 2008-07-14
21:13:26 UTC (rev 8883)
@@ -63,6 +63,7 @@
with the new value. If there is no provider for the property, the
value will be cached.
"""
+ if self._cache == value: return
(handler, obj) = self._provider
if handler is None:
self._cache = value
@@ -96,6 +97,8 @@
"""
def __init__(self):
self._props = { }
+ self.get = self.__getitem__
+ self.set = self.__setitem__
def _get_prop(self, key):
try:
Added: gnuradio/branches/features/experimental-gui/todo.txt
===================================================================
--- gnuradio/branches/features/experimental-gui/todo.txt
(rev 0)
+++ gnuradio/branches/features/experimental-gui/todo.txt 2008-07-14
21:13:26 UTC (rev 8883)
@@ -0,0 +1,6 @@
+TODO List
+
+-controller is a dict
+-controller property with default value for cache
+-use iteritems in cli.py
+-add/remove listener in cli.py
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r8883 - gnuradio/branches/features/experimental-gui,
jblum <=