[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r8893 - gnuradio/branches/features/experimental-gui
From: |
jblum |
Subject: |
[Commit-gnuradio] r8893 - gnuradio/branches/features/experimental-gui |
Date: |
Tue, 15 Jul 2008 16:52:01 -0600 (MDT) |
Author: jblum
Date: 2008-07-15 16:51:59 -0600 (Tue, 15 Jul 2008)
New Revision: 8893
Added:
gnuradio/branches/features/experimental-gui/grc_scopesink_test.py
gnuradio/branches/features/experimental-gui/scope_window.py
Modified:
gnuradio/branches/features/experimental-gui/common.py
gnuradio/branches/features/experimental-gui/fft_controller.py
gnuradio/branches/features/experimental-gui/fft_gui.py
gnuradio/branches/features/experimental-gui/fft_window.py
gnuradio/branches/features/experimental-gui/fftsink.py
gnuradio/branches/features/experimental-gui/prop_val.py
gnuradio/branches/features/experimental-gui/scopesink.py
Log:
scope sink window + block wrapper + scope test
Modified: gnuradio/branches/features/experimental-gui/common.py
===================================================================
--- gnuradio/branches/features/experimental-gui/common.py 2008-07-15
22:00:46 UTC (rev 8892)
+++ gnuradio/branches/features/experimental-gui/common.py 2008-07-15
22:51:59 UTC (rev 8893)
@@ -38,12 +38,12 @@
threading.Thread.__init__(self)
self.setDaemon(1)
self.msgq = msgq
- self.handle_msg = handle_msg
+ self._handle_msg = handle_msg
self.keep_running = True
self.start()
def run(self):
- while self.keep_running:
self.handle_msg(self.msgq.delete_head())
+ while self.keep_running:
self._handle_msg(self.msgq.delete_head().to_string())
##################################################
# WX Shared Classes
@@ -87,7 +87,7 @@
self._incr_button.Disable()
self._decr_button.Disable()
- def Disable(self): self.Enable(False)
+ def Disable(self, disable=True): self.Enable(not disable)
class RunStopButtonController(wx.Button):
def __init__(self, parent, controller, control_key):
@@ -128,7 +128,7 @@
self._slider.Disable()
self._label.Disable()
- def Disable(self): self.Enable(False)
+ def Disable(self, disable=True): self.Enable(not disable)
##################################################
# Shared Functions
Modified: gnuradio/branches/features/experimental-gui/fft_controller.py
===================================================================
--- gnuradio/branches/features/experimental-gui/fft_controller.py
2008-07-15 22:00:46 UTC (rev 8892)
+++ gnuradio/branches/features/experimental-gui/fft_controller.py
2008-07-15 22:51:59 UTC (rev 8893)
@@ -115,7 +115,7 @@
"""
while self._keep_running:
msg = self._tb.queue().delete_head()
- self['fft'] = msg
+ self['fft'] = msg.to_string()
def on_exit(self):
"""
Modified: gnuradio/branches/features/experimental-gui/fft_gui.py
===================================================================
--- gnuradio/branches/features/experimental-gui/fft_gui.py 2008-07-15
22:00:46 UTC (rev 8892)
+++ gnuradio/branches/features/experimental-gui/fft_gui.py 2008-07-15
22:51:59 UTC (rev 8893)
@@ -46,7 +46,8 @@
average_key='average',
avg_alpha_key='avg_alpha',
peak_hold=True,
- msg_key='fft')
+ msg_key='fft',
+ fft_size=512,)
self.Add(self._win)
Modified: gnuradio/branches/features/experimental-gui/fft_window.py
===================================================================
--- gnuradio/branches/features/experimental-gui/fft_window.py 2008-07-15
22:00:46 UTC (rev 8892)
+++ gnuradio/branches/features/experimental-gui/fft_window.py 2008-07-15
22:51:59 UTC (rev 8893)
@@ -40,8 +40,6 @@
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'
@@ -70,7 +68,7 @@
#checkboxes for average and peak hold
control_box.AddStretchSpacer()
control_box.Add(common.LabelText(self, 'Options'), 0,
wx.ALIGN_CENTER)
- self.average_check_box = common.CheckBoxController(self,
'Average', parent.controller, AVERAGE_KEY)
+ self.average_check_box = common.CheckBoxController(self,
'Average', parent.ext_controller, parent.average_key)
control_box.Add(self.average_check_box, 0, wx.EXPAND)
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)
@@ -78,9 +76,9 @@
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.ext_controller, parent.avg_alpha_key,
)
- parent.controller.add_listener(AVERAGE_KEY,
self.avg_alpha_slider.Enable)
+ parent.ext_controller.add_listener(parent.average_key,
self.avg_alpha_slider.Enable)
control_box.Add(self.avg_alpha_slider, 0, wx.EXPAND)
#radio buttons for div size
@@ -141,6 +139,7 @@
size,
title,
real,
+ fft_size,
baseband_freq,
sample_rate_key,
y_per_div,
@@ -157,6 +156,7 @@
#setup
self.ext_controller = controller
self.real = real
+ self.fft_size = fft_size
self.sample_rate_key = sample_rate_key
self.average_key = average_key
self.avg_alpha_key = avg_alpha_key
@@ -172,17 +172,9 @@
main_box.Add(self.plotter, 1, wx.EXPAND)
main_box.Add(self.control_panel, 0, wx.EXPAND)
self.SetSizerAndFit(main_box)
- #bind internal & external keys
- def bind_controller_keys(controller_master, controller_slave,
master_key, slave_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_average(self.ext_controller[average_key])
- self.set_avg_alpha(self.ext_controller[avg_alpha_key])
+ self.set_average(self.ext_controller[self.average_key])
+ self.set_avg_alpha(self.ext_controller[self.avg_alpha_key])
self.set_baseband_freq(baseband_freq)
self.set_peak_hold(peak_hold)
self.set_y_per_div(y_per_div)
@@ -192,20 +184,20 @@
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())
+ self.ext_controller.add_listener(self.sample_rate_key,
self.update_grid)
+ for key in (
+ BASEBAND_FREQ_KEY,
+ Y_PER_DIV_KEY, X_DIVS_KEY,
+ Y_DIVS_KEY, REF_LEVEL_KEY,
+ ): self.controller.add_listener(key, self.update_grid)
#initial update
self.update_grid()
##################################################
# Set parameters on-the-fly
##################################################
- def set_average(self, average): self.controller[AVERAGE_KEY] = average
- def set_avg_alpha(self, avg_alpha): self.controller[AVG_ALPHA_KEY] =
avg_alpha
+ def set_average(self, average): self.ext_controller[self.average_key] =
average
+ def set_avg_alpha(self, avg_alpha):
self.ext_controller[self.avg_alpha_key] = avg_alpha
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
@@ -224,16 +216,8 @@
@param msg the fft array as a character array
"""
if not self.controller[RUNNING_KEY]: return
- itemsize = int(msg.arg1())
- nitems = int(msg.arg2())
- s = msg.to_string()
- # There may be more than one frame in the message.
- # If so, we take only the last one
- if nitems > 1:
- start = itemsize * (nitems - 1)
- s = s[start:start+itemsize]
#convert to floating point numbers
- samples = numpy.fromstring(s, numpy.float32)
+ samples = numpy.fromstring(msg, numpy.float32)[:self.fft_size]
#only take first frame
num_samps = len(samples)
#reorder fft
if self.real: samples = samples[:num_samps/2]
@@ -258,7 +242,7 @@
#update the plotter
self.plotter.update()
- def update_grid(self):
+ def update_grid(self, *args):
"""!
Update the plotter grid.
This update method is dependent on the variables below.
Modified: gnuradio/branches/features/experimental-gui/fftsink.py
===================================================================
--- gnuradio/branches/features/experimental-gui/fftsink.py 2008-07-15
22:00:46 UTC (rev 8892)
+++ gnuradio/branches/features/experimental-gui/fftsink.py 2008-07-15
22:51:59 UTC (rev 8893)
@@ -36,7 +36,7 @@
MSG_KEY = 'msg'
##################################################
-# FFT Sink Class (wrapper for old wxgui)
+# FFT sink block (wrapper for old wxgui)
##################################################
class _fft_sink_base(gr.hier_block2):
"""!
@@ -86,11 +86,11 @@
#controller
self.controller = prop_val_interface()
self.controller.add_listener(AVERAGE_KEY, fft.set_average)
- self.controller.set_provider(AVERAGE_KEY, lambda: fft.average())
+ self.controller.set_provider(AVERAGE_KEY, fft.average)
self.controller.add_listener(AVG_ALPHA_KEY, fft.set_avg_alpha)
- self.controller.set_provider(AVG_ALPHA_KEY, lambda:
fft.avg_alpha())
+ self.controller.set_provider(AVG_ALPHA_KEY, fft.avg_alpha)
self.controller.add_listener(SAMPLE_RATE_KEY,
fft.set_sample_rate)
- self.controller.set_provider(SAMPLE_RATE_KEY, lambda:
fft._sd.sample_rate()) #FIXME
+ self.controller.set_provider(SAMPLE_RATE_KEY,
fft._sd.sample_rate) #FIXME
#start input watcher
common.input_watcher(msgq, lambda x:
self.controller.set(MSG_KEY, x))
#create window
@@ -99,7 +99,8 @@
controller=self.controller,
size=size,
title=title,
- real = self.real,
+ real=self.real,
+ fft_size=fft_size,
baseband_freq=baseband_freq,
sample_rate_key=SAMPLE_RATE_KEY,
y_per_div=y_per_div,
@@ -121,7 +122,7 @@
self.set_y_divs = self.win.set_y_divs
self.set_x_divs = self.win.set_x_divs
self.set_running = self.win.set_running
-
+
def set_sample_rate(self, sample_rate):
self.controller[SAMPLE_RATE_KEY] = sample_rate
Added: gnuradio/branches/features/experimental-gui/grc_scopesink_test.py
===================================================================
--- gnuradio/branches/features/experimental-gui/grc_scopesink_test.py
(rev 0)
+++ gnuradio/branches/features/experimental-gui/grc_scopesink_test.py
2008-07-15 22:51:59 UTC (rev 8893)
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: untitled
+# Author: unknown
+# Description: untitled flow graph
+# Generated: Tue Jul 15 12:24:12 2008
+##################################################
+
+from gnuradio import gr
+import scopesink
+from grc_gnuradio import wxgui as grc_wxgui
+import wx
+
+ampl = 1
+freq = 1000
+offset = [-1, 0, 1][1]
+samp_rate = 32000
+
+class scope_test(grc_wxgui.top_block_gui):
+
+ def __init__(self, ampl=ampl, freq=freq, offset=offset,
samp_rate=samp_rate):
+ grc_wxgui.top_block_gui.__init__(
+ self,
+ title="GRC - Executing: untitled",
+
icon="/usr/lib/python2.5/site-packages/grc/data/grc-icon-32.png",
+ )
+
+ ##################################################
+ # Variables
+ ##################################################
+ self.ampl = ampl
+ _ampl_control = grc_wxgui.slider_horizontal_control(
+ window=self.GetWin(),
+ callback=self.set_ampl,
+ label="Amplitude",
+ value=ampl,
+ min=0,
+ max=20,
+ num_steps=100,
+ )
+ self.Add(_ampl_control)
+ self.freq = freq
+ _freq_control = grc_wxgui.slider_horizontal_control(
+ window=self.GetWin(),
+ callback=self.set_freq,
+ label="Frequency",
+ value=freq,
+ min=0,
+ max=samp_rate/2,
+ num_steps=100,
+ )
+ self.Add(_freq_control)
+ self.offset = offset
+ _offset_control = grc_wxgui.radio_buttons_horizontal_control(
+ window=self.GetWin(),
+ callback=self.set_offset,
+ label="Offset",
+ index=1,
+ choices=[-1, 0, 1],
+ labels=['Neg', 'Zero', 'Pos'],
+ )
+ self.Add(_offset_control)
+ self.samp_rate = samp_rate
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.gr_sig_source_x = gr.sig_source_f(samp_rate,
gr.GR_COS_WAVE, freq, ampl, offset*ampl)
+ self.gr_sig_source_x0 = gr.sig_source_f(samp_rate,
gr.GR_SIN_WAVE, freq, ampl, offset*ampl)
+ self.gr_throttle = gr.throttle(gr.sizeof_float*1, samp_rate)
+ self.wxgui_scopesink2 = scopesink.scope_sink_f(
+ self.GetWin(),
+ title="Scope Plot",
+ sample_rate=samp_rate,
+ frame_rate=30,
+ v_scale=None,
+ t_scale=.001,
+ num_inputs=2,
+ )
+ self.GridAdd(self.wxgui_scopesink2.win, 0, 0, 1, 1)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.gr_throttle, 0), (self.wxgui_scopesink2, 0))
+ self.connect((self.gr_sig_source_x, 0), (self.gr_throttle, 0))
+ self.connect((self.gr_sig_source_x0, 0),
(self.wxgui_scopesink2, 1))
+
+ def set_ampl(self, ampl):
+ self.ampl = ampl
+ self.gr_sig_source_x.set_amplitude(self.ampl)
+ self.gr_sig_source_x.set_offset(self.offset*self.ampl)
+ self.gr_sig_source_x0.set_amplitude(self.ampl)
+ self.gr_sig_source_x0.set_offset(self.offset*self.ampl)
+
+ def set_freq(self, freq):
+ self.freq = freq
+ self.gr_sig_source_x.set_frequency(self.freq)
+ self.gr_sig_source_x0.set_frequency(self.freq)
+
+ def set_offset(self, offset):
+ self.offset = offset
+ self.gr_sig_source_x.set_offset(self.offset*self.ampl)
+ self.gr_sig_source_x0.set_offset(self.offset*self.ampl)
+
+ def set_samp_rate(self, samp_rate):
+ self.samp_rate = samp_rate
+ self.wxgui_scopesink2.set_sample_rate(self.samp_rate)
+ self.gr_sig_source_x.set_sampling_freq(self.samp_rate)
+ self.gr_sig_source_x0.set_sampling_freq(self.samp_rate)
+
+if __name__ == '__main__':
+ tb = scope_test()
+ tb.Run()
+
Property changes on:
gnuradio/branches/features/experimental-gui/grc_scopesink_test.py
___________________________________________________________________
Name: svn:executable
+ *
Modified: gnuradio/branches/features/experimental-gui/prop_val.py
===================================================================
--- gnuradio/branches/features/experimental-gui/prop_val.py 2008-07-15
22:00:46 UTC (rev 8892)
+++ gnuradio/branches/features/experimental-gui/prop_val.py 2008-07-15
22:51:59 UTC (rev 8893)
@@ -63,7 +63,7 @@
with the new value. If there is no provider for the property, the
value will be cached.
"""
- if self._cache == value: return
+ #if self._cache == value: return
(handler, obj) = self._provider
if handler is None:
self._cache = value
Copied: gnuradio/branches/features/experimental-gui/scope_window.py (from rev
8888, gnuradio/branches/features/experimental-gui/scopesink.py)
===================================================================
--- gnuradio/branches/features/experimental-gui/scope_window.py
(rev 0)
+++ gnuradio/branches/features/experimental-gui/scope_window.py 2008-07-15
22:51:59 UTC (rev 8893)
@@ -0,0 +1,382 @@
+#
+# 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 plotter
+import common
+import wx
+import numpy
+import time
+import prop_val
+
+##################################################
+# Constants
+##################################################
+DEFAULT_FRAME_RATE = 30
+DEFAULT_WIN_SIZE = (600, 300)
+DEFAULT_V_SCALE = 1000
+TRIGGER_MODES = (
+ ('Auto', 0),
+ ('Neg', -1),
+ ('Pos', +1),
+)
+TRIGGER_LEVELS = (
+ ('Auto', None),
+ ('+High', 0.75),
+ ('+Med', 0.5),
+ ('+Low', 0.25),
+ ('Zero', 0.0),
+ ('-Low', -0.25),
+ ('-Med', -0.5),
+ ('-High', -0.75),
+)
+CHANNEL_COLOR_SPECS = (
+ (0, 0, 1),
+ (0, 1, 0),
+ (1, 0, 0),
+ (1, 0, 1),
+)
+AUTORANGE_UPDATE_RATE = 0.5 #sec
+RUNNING_KEY = 'running'
+AUTORANGE_KEY = 'autorange'
+AC_COUPLE_KEY = 'ac_couple'
+X_PER_DIV_KEY = 'x_per_div'
+Y_PER_DIV_KEY = 'y_per_div'
+X_OFF_KEY = 'x_off'
+Y_OFF_KEY = 'y_off'
+Y_DIVS_KEY = 'y_divs'
+X_DIVS_KEY = 'x_divs'
+FRAME_RATE_KEY = 'frame_rate'
+
+##################################################
+# Scope window control panel
+##################################################
+class control_panel(wx.Panel):
+ """!
+ A control panel with wx widgits to control the plotter and scope block.
+ """
+ def __init__(self, parent):
+ """!
+ Create a new control panel.
+ @param parent the wx parent window
+ """
+ self.parent = parent
+ wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
+ control_box = wx.BoxSizer(wx.VERTICAL)
+ #trigger defaults
+ self.trigger_channel_index = 0 #ch 1
+ self.trigger_mode_index = 1 #not auto
+ self.trigger_level_index = 0 #auto
+ #trigger options
+ control_box.AddStretchSpacer()
+ control_box.Add(common.LabelText(self, 'Trigger Options'), 0,
wx.ALIGN_CENTER)
+ control_box.AddSpacer(2)
+ #trigger mode
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ control_box.Add(hbox, 0, wx.EXPAND)
+ hbox.Add(wx.StaticText(self, -1, ' Channel '), 1,
wx.ALIGN_CENTER_VERTICAL)
+ self.trigger_channel_chooser = wx.Choice(self, -1,
choices=["Ch%d"%ch for ch in range(1, parent.num_inputs+1)])
+ self.trigger_channel_chooser.Bind(wx.EVT_CHOICE,
self._on_trigger_channel)
+ hbox.Add(self.trigger_channel_chooser, 0,
wx.ALIGN_CENTER_VERTICAL)
+ #trigger mode
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ control_box.Add(hbox, 0, wx.EXPAND)
+ hbox.Add(wx.StaticText(self, -1, ' Mode '), 1,
wx.ALIGN_CENTER_VERTICAL)
+ self.trigger_mode_chooser = wx.Choice(self, -1, choices=[tm[0]
for tm in TRIGGER_MODES])
+ self.trigger_mode_chooser.Bind(wx.EVT_CHOICE,
self._on_trigger_mode)
+ hbox.Add(self.trigger_mode_chooser, 0, wx.ALIGN_CENTER_VERTICAL)
+ #trigger level
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ control_box.Add(hbox, 0, wx.EXPAND)
+ hbox.Add(wx.StaticText(self, -1, ' Level '), 1,
wx.ALIGN_CENTER_VERTICAL)
+ self.trigger_level_chooser = wx.Choice(self, -1, choices=[tl[0]
for tl in TRIGGER_LEVELS])
+ self.trigger_level_chooser.Bind(wx.EVT_CHOICE,
self._on_trigger_level)
+ hbox.Add(self.trigger_level_chooser, 0,
wx.ALIGN_CENTER_VERTICAL)
+ #axes options
+ SPACING = 15
+ control_box.AddStretchSpacer()
+ control_box.Add(common.LabelText(self, 'Axes Options'), 0,
wx.ALIGN_CENTER)
+ #x axis divs
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ control_box.Add(hbox, 0, wx.EXPAND)
+ hbox.Add(wx.StaticText(self, -1, ' Secs/Div '), 1,
wx.ALIGN_CENTER_VERTICAL)
+ self.x_buttons = common.IncrDecrButtons(self,
self._on_incr_x_divs, self._on_decr_x_divs)
+ hbox.Add(self.x_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
+ hbox.AddSpacer(SPACING)
+ #y axis divs
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ control_box.Add(hbox, 0, wx.EXPAND)
+ hbox.Add(wx.StaticText(self, -1, ' Units/Div '), 1,
wx.ALIGN_CENTER_VERTICAL)
+ self.y_buttons = common.IncrDecrButtons(self,
self._on_incr_y_divs, self._on_decr_y_divs)
+ parent.controller.add_listener(AUTORANGE_KEY,
self.y_buttons.Disable)
+ hbox.Add(self.y_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
+ hbox.AddSpacer(SPACING)
+ #y axis ref lvl
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ control_box.Add(hbox, 0, wx.EXPAND)
+ hbox.Add(wx.StaticText(self, -1, ' Y Offset '), 1,
wx.ALIGN_CENTER_VERTICAL)
+ self.y_off_buttons = common.IncrDecrButtons(self,
self._on_incr_y_off, self._on_decr_y_off)
+ parent.controller.add_listener(AUTORANGE_KEY,
self.y_off_buttons.Disable)
+ hbox.Add(self.y_off_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
+ hbox.AddSpacer(SPACING)
+ #misc options
+ control_box.AddStretchSpacer()
+ control_box.Add(common.LabelText(self, 'Range Options'), 0,
wx.ALIGN_CENTER)
+ #ac couple check box
+ self.ac_couple_check_box = common.CheckBoxController(self, 'AC
Couple', parent.controller, AC_COUPLE_KEY)
+ control_box.Add(self.ac_couple_check_box, 0, wx.ALIGN_LEFT)
+ #autorange check box
+ self.autorange_check_box = common.CheckBoxController(self,
'Autorange', parent.controller, AUTORANGE_KEY)
+ control_box.Add(self.autorange_check_box, 0, wx.ALIGN_LEFT)
+ #run/stop
+ control_box.AddStretchSpacer()
+ 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)
+ #initial update
+ self.update_trigger_menu()
+
+ def update_trigger_menu(self, *args):
+
self.trigger_channel_chooser.SetSelection(self.trigger_channel_index)
+ self.parent.trigger_channel = self.trigger_channel_index
+ self.trigger_mode_chooser.SetSelection(self.trigger_mode_index)
+ self.parent.trigger_mode =
TRIGGER_MODES[self.trigger_mode_index][1]
+
self.trigger_level_chooser.SetSelection(self.trigger_level_index)
+ self.parent.trigger_level =
TRIGGER_LEVELS[self.trigger_level_index][1]
+
+ ##################################################
+ # Event handlers
+ ##################################################
+ def _on_trigger_channel(self, event):
+ self.trigger_channel_index =
self.trigger_channel_chooser.GetSelection()
+ self.update_trigger_menu()
+ def _on_trigger_mode(self, event):
+ self.trigger_mode_index =
self.trigger_mode_chooser.GetSelection()
+ self.update_trigger_menu()
+ def _on_trigger_level(self, event):
+ self.trigger_level_index =
self.trigger_level_chooser.GetSelection()
+ self.update_trigger_menu()
+
+ def _on_incr_x_divs(self, event):
+ self.parent.set_x_per_div(
+
common.get_clean_incr(self.parent.controller[X_PER_DIV_KEY]))
+ def _on_decr_x_divs(self, event):
+ self.parent.set_x_per_div(
+
common.get_clean_decr(self.parent.controller[X_PER_DIV_KEY]))
+ def _on_incr_y_divs(self, event):
+ self.parent.set_y_per_div(
+
common.get_clean_incr(self.parent.controller[Y_PER_DIV_KEY]))
+ def _on_decr_y_divs(self, event):
+ self.parent.set_y_per_div(
+
common.get_clean_decr(self.parent.controller[Y_PER_DIV_KEY]))
+ def _on_incr_y_off(self, event):
+ self.parent.set_y_off(
+ self.parent.controller[Y_OFF_KEY] +
self.parent.controller[Y_PER_DIV_KEY])
+ def _on_decr_y_off(self, event):
+ self.parent.set_y_off(
+ self.parent.controller[Y_OFF_KEY] -
self.parent.controller[Y_PER_DIV_KEY])
+
+##################################################
+# Scope window with plotter and control panel
+##################################################
+class scope_window(wx.Panel):
+ def __init__(
+ self,
+ parent,
+ controller,
+ size,
+ title,
+ frame_rate,
+ num_inputs,
+ sample_rate_key,
+ x_per_div,
+ y_per_div,
+ ac_couple,
+ scope_trigger_level_key,
+ scope_trigger_mode_key,
+ scope_trigger_channel_key,
+ scope_num_samples_key,
+ msg_key,
+ ):
+ self.controller = prop_val.prop_val_interface()
+ #check num inputs
+ assert num_inputs <= len(CHANNEL_COLOR_SPECS)
+ #setup
+ self.ext_controller = controller
+ self.num_inputs = num_inputs
+ self.sample_rate_key = sample_rate_key
+ autorange = y_per_div is None
+ self.autorange_ts = 0
+ if y_per_div is None: y_per_div = 1
+ self.frame_counter = 0
+ self._init = False #HACK
+ #scope keys
+ self.scope_trigger_level_key = scope_trigger_level_key
+ self.scope_trigger_mode_key = scope_trigger_mode_key
+ self.scope_trigger_channel_key = scope_trigger_channel_key
+ self.scope_num_samples_key = scope_num_samples_key
+ #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_legend(self.num_inputs > 1)
+ #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)
+ #initial setup
+ self.set_running(True)
+ self.set_ac_couple(ac_couple)
+ self.set_autorange(autorange)
+ self.set_x_per_div(x_per_div)
+ self.set_y_per_div(y_per_div)
+ self.set_x_off(0)
+ self.set_y_off(0)
+ self.set_x_divs(8)
+ self.set_y_divs(8)
+ self.set_frame_rate(frame_rate)
+ #register events
+ self.ext_controller.add_listener(msg_key, self.handle_msg)
+ self.ext_controller.add_listener(sample_rate_key,
self.update_decim)
+ self.controller.add_listener(FRAME_RATE_KEY, self.update_decim)
+ for key in (
+ X_PER_DIV_KEY, Y_PER_DIV_KEY,
+ X_OFF_KEY, Y_OFF_KEY,
+ X_DIVS_KEY, Y_DIVS_KEY,
+ ): self.controller.add_listener(key, self.update_grid)
+ #initial update, dont do this here, wait for handle_msg #HACK
+ #self.update_grid()
+ #self.update_decim()
+
+ ##################################################
+ # Set parameters on-the-fly
+ ##################################################
+ def set_running(self, running): self.controller[RUNNING_KEY] = running
+ def set_ac_couple(self, ac_couple): self.controller[AC_COUPLE_KEY] =
ac_couple
+ def set_autorange(self, autorange): self.controller[AUTORANGE_KEY] =
autorange
+ def set_x_per_div(self, x_per_div): self.controller[X_PER_DIV_KEY] =
x_per_div
+ def set_y_per_div(self, y_per_div): self.controller[Y_PER_DIV_KEY] =
y_per_div
+ def set_x_off(self, x_off): self.controller[X_OFF_KEY] = x_off
+ def set_y_off(self, y_off): self.controller[Y_OFF_KEY] = y_off
+ def set_x_divs(self, x_divs): self.controller[X_DIVS_KEY] = x_divs
+ def set_y_divs(self, y_divs): self.controller[Y_DIVS_KEY] = y_divs
+ def set_frame_rate(self, frame_rate): self.controller[FRAME_RATE_KEY] =
frame_rate
+
+ def handle_msg(self, msg):
+ """!
+ Handle the message from the scope sink message queue.
+ Plot the list of arrays of samples onto the grid.
+ Each samples array gets its own channel.
+ @param msg the time domain data as a character array
+ """
+ if not self.controller[RUNNING_KEY]: return
+ #convert to floating point numbers
+ samples = numpy.fromstring(msg, numpy.float32)
+ samps_per_ch = len(samples)/self.num_inputs
+ sampleses = [samples[samps_per_ch*i:samps_per_ch*(i+1)] for i
in range(self.num_inputs)]
+ if not self._init: #HACK
+ self._init = True
+ self.update_grid()
+ self.update_decim()
+ if self.frame_counter == 0: #decimate
+ #trigger level (must do before ac coupling)
+ self.ext_controller[self.scope_trigger_channel_key] =
self.trigger_channel
+ self.ext_controller[self.scope_trigger_mode_key] =
self.trigger_mode
+ if self.trigger_level is None:
+
self.ext_controller[self.scope_trigger_level_key] = ''
+ else:
+ samples = sampleses[self.trigger_channel]
+
self.ext_controller[self.scope_trigger_level_key] = \
+
self.trigger_level*(numpy.max(samples)-numpy.min(samples))/2 +
numpy.average(samples)
+ #ac coupling
+ if self.controller[AC_COUPLE_KEY]:
+ sampleses = [samples - numpy.average(samples)
for samples in sampleses]
+ #autorange
+ if self.controller[AUTORANGE_KEY] and time.time() -
self.autorange_ts > AUTORANGE_UPDATE_RATE:
+ bounds = [common.get_min_max(samples) for
samples in sampleses]
+ y_min = min(*[bound[0] for bound in bounds])
+ y_max = max(*[bound[1] for bound in bounds])
+ #adjust the y per div
+ y_per_div =
common.get_clean_num((y_max-y_min)/self.controller[Y_DIVS_KEY])
+ if y_per_div != self.controller[Y_PER_DIV_KEY]:
self.set_y_per_div(y_per_div)
+ #adjust the y offset
+ y_off =
y_per_div*round((y_max+y_min)/2/y_per_div)
+ if y_off != self.controller[Y_OFF_KEY]:
self.set_y_off(y_off)
+ self.autorange_ts = time.time()
+ #plot each waveform
+ for i, samples in enumerate(sampleses):
+ #number of samples to scale to the screen
+ num_samps =
int(self.controller[X_PER_DIV_KEY]*self.controller[X_DIVS_KEY]*self.ext_controller[self.sample_rate_key])
+ #handle num samps out of bounds
+ while num_samps > len(samples): samples =
numpy.concatenate((samples, samples))
+ if num_samps < 2: num_samps = 0
+ #plot samples
+ self.plotter.set_waveform(
+ channel=i+1,
+ samples=samples[:num_samps],
+ color_spec=CHANNEL_COLOR_SPECS[i],
+ )
+ #update the plotter
+ self.plotter.update()
+ self.frame_counter = (self.frame_counter + 1)%self.decim
+
+ def update_decim(self, *args):
+ """!
+ Update the frame decimation when the frame rate or sample rate
changes.
+ """
+ decim =
self.ext_controller[self.sample_rate_key]/self.ext_controller[self.scope_num_samples_key]/self.controller[FRAME_RATE_KEY]
+ self.decim = max(1, int(decim))
+
+ def update_grid(self, *args):
+ #grid parameters
+ x_per_div = self.controller[X_PER_DIV_KEY]
+ y_per_div = self.controller[Y_PER_DIV_KEY]
+ x_off = self.controller[X_OFF_KEY]
+ y_off = self.controller[Y_OFF_KEY]
+ x_divs = self.controller[X_DIVS_KEY]
+ y_divs = self.controller[Y_DIVS_KEY]
+ #update the x axis
+ exp = common.get_exp(x_per_div)
+ if exp > -2: x_units, scalar = 's', 1e0
+ elif exp > -5: x_units, scalar = 'ms', 1e3
+ elif exp > -8: x_units, scalar = 'us', 1e6
+ else: x_units, scalar = 'ns', 1e9
+ self.plotter.set_x_units('Time (%s)'%x_units)
+ self.plotter.set_x_grid(
+ scalar*x_off,
+ scalar*x_per_div*x_divs + scalar*x_off,
+ scalar*x_per_div,
+ )
+ #update the y axis
+ self.plotter.set_y_units('Units')
+ self.plotter.set_y_grid(
+ -1*y_per_div*y_divs/2.0 + y_off,
+ y_per_div*y_divs/2.0 + y_off,
+ y_per_div,
+ )
+ #update plotter
+ self.plotter.update()
Modified: gnuradio/branches/features/experimental-gui/scopesink.py
===================================================================
--- gnuradio/branches/features/experimental-gui/scopesink.py 2008-07-15
22:00:46 UTC (rev 8892)
+++ gnuradio/branches/features/experimental-gui/scopesink.py 2008-07-15
22:51:59 UTC (rev 8893)
@@ -22,353 +22,24 @@
##################################################
# Imports
##################################################
-from gnuradio import gr
-import plotter
+import scope_window
import common
-import wx
-import numpy
-import time
+from gnuradio import gr
+from prop_val import prop_val_interface
##################################################
# Constants
##################################################
-DEFAULT_FRAME_RATE = 30
-DEFAULT_WIN_SIZE = (640, 240)
-DEFAULT_V_SCALE = 1000
-TRIGGER_MODES = (
- ('Auto', gr.gr_TRIG_AUTO),
- ('Neg', gr.gr_TRIG_NEG_SLOPE),
- ('Pos', gr.gr_TRIG_POS_SLOPE),
-)
-TRIGGER_LEVELS = (
- ('Auto', None),
- ('+High', 0.75),
- ('+Med', 0.5),
- ('+Low', 0.25),
- ('Zero', 0.0),
- ('-Low', -0.25),
- ('-Med', -0.5),
- ('-High', -0.75),
-)
-CHANNEL_COLOR_SPECS = (
- (0, 0, 1),
- (0, 1, 0),
- (1, 0, 0),
- (1, 0, 1),
-)
-AUTORANGE_UPDATE_RATE = 0.5 #sec
+MSG_KEY = 'msg'
+SAMPLE_RATE_KEY = 'sample_rate'
+SCOPE_TRIGGER_LEVEL_KEY = 'scope_trigger_level'
+SCOPE_TRIGGER_MODE_KEY = 'scope_trigger_mode'
+SCOPE_TRIGGER_CHANNEL_KEY = 'scope_trigger_channel'
+SCOPE_NUM_SAMPLES_KEY = 'scope_num_samples'
##################################################
-# Scope window control panel
+# Scope sink block (wrapper for old wxgui)
##################################################
-class control_panel(wx.Panel):
- """!
- A control panel with wx widgits to control the plotter and scope block.
- """
- def __init__(self, parent):
- """!
- Create a new control panel.
- @param parent the wx parent window
- """
- self.parent = parent
- wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
- control_box = wx.BoxSizer(wx.VERTICAL)
-
- #trigger options
- control_box.AddStretchSpacer()
- control_box.Add(common.LabelText(self, 'Trigger Options'), 0,
wx.ALIGN_CENTER)
- control_box.AddSpacer(2)
- #trigger mode
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- control_box.Add(hbox, 0, wx.EXPAND)
- hbox.Add(wx.StaticText(self, -1, ' Channel '), 1,
wx.ALIGN_CENTER_VERTICAL)
- self.trigger_channel_chooser = wx.Choice(self, -1,
choices=["Ch%d"%ch for ch in range(1, parent.num_inputs+1)])
- self.trigger_channel_chooser.Bind(wx.EVT_CHOICE,
self._on_trigger_channel)
- hbox.Add(self.trigger_channel_chooser, 0,
wx.ALIGN_CENTER_VERTICAL)
- #trigger mode
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- control_box.Add(hbox, 0, wx.EXPAND)
- hbox.Add(wx.StaticText(self, -1, ' Mode '), 1,
wx.ALIGN_CENTER_VERTICAL)
- self.trigger_mode_chooser = wx.Choice(self, -1, choices=[tm[0]
for tm in TRIGGER_MODES])
- self.trigger_mode_chooser.Bind(wx.EVT_CHOICE,
self._on_trigger_mode)
- hbox.Add(self.trigger_mode_chooser, 0, wx.ALIGN_CENTER_VERTICAL)
- #trigger level
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- control_box.Add(hbox, 0, wx.EXPAND)
- hbox.Add(wx.StaticText(self, -1, ' Level '), 1,
wx.ALIGN_CENTER_VERTICAL)
- self.trigger_level_chooser = wx.Choice(self, -1, choices=[tl[0]
for tl in TRIGGER_LEVELS])
- self.trigger_level_chooser.Bind(wx.EVT_CHOICE,
self._on_trigger_level)
- hbox.Add(self.trigger_level_chooser, 0,
wx.ALIGN_CENTER_VERTICAL)
-
- #axes options
- SPACING = 15
- control_box.AddStretchSpacer()
- control_box.Add(common.LabelText(self, 'Axes Options'), 0,
wx.ALIGN_CENTER)
- #x axis divs
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- control_box.Add(hbox, 0, wx.EXPAND)
- hbox.Add(wx.StaticText(self, -1, ' Secs/Div '), 1,
wx.ALIGN_CENTER_VERTICAL)
- self.x_buttons = common.IncrDecrButtons(self,
self._on_incr_x_divs, self._on_decr_x_divs)
- hbox.Add(self.x_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
- hbox.AddSpacer(SPACING)
- #y axis divs
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- control_box.Add(hbox, 0, wx.EXPAND)
- hbox.Add(wx.StaticText(self, -1, ' Units/Div '), 1,
wx.ALIGN_CENTER_VERTICAL)
- self.y_buttons = common.IncrDecrButtons(self,
self._on_incr_y_divs, self._on_decr_y_divs)
- hbox.Add(self.y_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
- hbox.AddSpacer(SPACING)
- #y axis ref lvl
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- control_box.Add(hbox, 0, wx.EXPAND)
- hbox.Add(wx.StaticText(self, -1, ' Y Offset '), 1,
wx.ALIGN_CENTER_VERTICAL)
- self.y_off_buttons = common.IncrDecrButtons(self,
self._on_incr_y_off, self._on_decr_y_off)
- hbox.Add(self.y_off_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
- hbox.AddSpacer(SPACING)
-
- #misc options
- control_box.AddStretchSpacer()
- control_box.Add(common.LabelText(self, 'Range Options'), 0,
wx.ALIGN_CENTER)
- #ac couple check box
- self.ac_couple_check_box = wx.CheckBox(parent=self,
style=wx.CHK_2STATE, label="AC Couple")
- self.ac_couple_check_box.Bind(wx.EVT_CHECKBOX,
self._on_ac_couple)
- control_box.Add(self.ac_couple_check_box, 0, wx.ALIGN_LEFT)
- #autorange check box
- self.autorange_check_box = wx.CheckBox(parent=self,
style=wx.CHK_2STATE, label="Autorange")
- self.autorange_check_box.Bind(wx.EVT_CHECKBOX,
self._on_autorange)
- control_box.Add(self.autorange_check_box, 0, wx.ALIGN_LEFT)
- #Run button
- control_box.AddStretchSpacer()
- self.run_button = wx.Button(self, -1, '', style=wx.BU_EXACTFIT)
- self.run_button.Bind(wx.EVT_BUTTON, self._on_run)
- control_box.Add(self.run_button, 0, wx.EXPAND)
-
- #set sizer
- self.SetSizerAndFit(control_box)
- #update
- self.update()
-
- def update(self):
- """!
- Read the state of the scope plot settings and update the
control panel.
- """
- #update the ac couple check box
- self.ac_couple_check_box.SetValue(self.parent.ac_couple)
- #update the autorange check box
- self.autorange_check_box.SetValue(self.parent.autorange)
- #update trigger menu
-
self.trigger_channel_chooser.SetSelection(self.parent.trigger_channel_index)
-
self.trigger_mode_chooser.SetSelection(self.parent.trigger_mode_index)
-
self.trigger_level_chooser.SetSelection(self.parent.trigger_level_index)
- #update the run/stop button
- if self.parent.running: self.run_button.SetLabel('Stop')
- else: self.run_button.SetLabel('Run')
- #update the y adj buttons
- if self.parent.autorange:
- self.y_buttons.Disable()
- self.y_off_buttons.Disable()
- else:
- self.y_buttons.Enable()
- self.y_off_buttons.Enable()
-
- ##################################################
- # Event handlers
- ##################################################
- def _on_channel(self, event):
self.parent.set_input_index(self.channel_chooser.GetSelection())
- def _on_ac_couple(self, event):
self.parent.set_ac_couple(event.IsChecked())
- def _on_autorange(self, event):
self.parent.set_autorange(event.IsChecked())
- def _on_trigger_channel(self, event):
self.parent.set_trigger_channel_index(self.trigger_channel_chooser.GetSelection())
- def _on_trigger_mode(self, event):
self.parent.set_trigger_mode_index(self.trigger_mode_chooser.GetSelection())
- def _on_trigger_level(self, event):
self.parent.set_trigger_level_index(self.trigger_level_chooser.GetSelection())
- def _on_incr_x_divs(self, event):
self.parent.set_x_per_div(common.get_clean_incr(self.parent.x_per_div))
- def _on_decr_x_divs(self, event):
self.parent.set_x_per_div(common.get_clean_decr(self.parent.x_per_div))
- def _on_incr_y_divs(self, event):
self.parent.set_y_per_div(common.get_clean_incr(self.parent.y_per_div))
- def _on_decr_y_divs(self, event):
self.parent.set_y_per_div(common.get_clean_decr(self.parent.y_per_div))
- def _on_incr_y_off(self, event):
self.parent.set_y_off(self.parent.y_off + self.parent.y_per_div)
- def _on_decr_y_off(self, event):
self.parent.set_y_off(self.parent.y_off - self.parent.y_per_div)
- def _on_run(self, event): self.parent.set_run(not self.parent.running)
-
-##################################################
-# Scope window with plotter and control panel
-##################################################
-class scope_window(wx.Panel):
- def __init__(
- self,
- parent,
- size,
- title,
- scope,
- frame_rate,
- num_inputs,
- sample_rate,
- x_per_div,
- y_per_div,
- ac_couple,
- ):
- #check num inputs
- assert num_inputs <= len(CHANNEL_COLOR_SPECS)
- #setup
- self.running = True
- self.num_inputs = num_inputs
- self.sample_rate = sample_rate
- self.ac_couple = ac_couple
- self.autorange = y_per_div is None
- self.autorange_ts = 0
- self.input_index = 0
- #triggering
- self.trigger_channel_index = 0
- self.trigger_mode_index = 1
- self.trigger_level_index = 0
- #x grid settings
- self.x_divs = 8
- self.x_per_div = x_per_div
- self.x_off = 0
- #y grid settings
- self.y_divs = 8
- if y_per_div is None: self.y_per_div = 1
- else: self.y_per_div = y_per_div
- self.y_off = 0
- self.scope = scope
- self.frame_rate = frame_rate
- self.frame_counter = 0
- self._init = False #HACK
- #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_legend(self.num_inputs > 1)
- #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)
- #update
- self.update()
-
- def plot(self, sampleses):
- """!
- Plot the list of arrays of samples onto the grid.
- Each samples array gets its own channel.
- @param sampleses the array of arrays
- """
- if not self._init: #HACK
- self._init = True
- self.update()
- if not self.running: return
- if self.frame_counter == 0: #decimate
- #trigger level (must do before ac coupling)
- samples = sampleses[self.trigger_level_index]
- trigger_level =
TRIGGER_LEVELS[self.trigger_level_index][1]
- if trigger_level is None:
self.scope.set_trigger_level_auto()
- else:
self.scope.set_trigger_level(trigger_level*(numpy.max(samples)-numpy.min(samples))/2
+ numpy.average(samples))
- #ac coupling
- if self.ac_couple:
- sampleses = [samples - numpy.average(samples)
for samples in sampleses]
- #autorange
- if self.autorange and time.time() - self.autorange_ts >
AUTORANGE_UPDATE_RATE:
- bounds = [common.get_min_max(samples) for
samples in sampleses]
- y_min = min(*[bound[0] for bound in bounds])
- y_max = max(*[bound[1] for bound in bounds])
- #adjust the y per div
- y_per_div =
common.get_clean_num((y_max-y_min)/self.y_divs)
- if self.y_per_div != y_per_div:
self.set_y_per_div(y_per_div)
- #adjust the y offset
- y_off =
self.y_per_div*round((y_max+y_min)/2/self.y_per_div)
- if self.y_off != y_off: self.set_y_off(y_off)
- self.autorange_ts = time.time()
- #plot each waveform
- for i, samples in enumerate(sampleses):
- #number of samples to scale to the screen
- num_samps =
int(self.x_per_div*self.x_divs*self.sample_rate)
- #handle num samps out of bounds
- while num_samps > len(samples): samples =
numpy.concatenate((samples, samples))
- if num_samps < 2: num_samps = 0
- #plot samples
- self.plotter.set_waveform(
- channel=i+1,
- samples=samples[:num_samps],
- color_spec=CHANNEL_COLOR_SPECS[i],
- )
- #update the plotter
- self.plotter.update()
- self.frame_counter = (self.frame_counter + 1)%self.decim
-
- def update(self):
- #update the frame decimation
- self.decim = max(1,
int(self.sample_rate/self.scope.get_samples_per_output_record()/self.frame_rate))
- #update the scope
- if self._init: #HACK avoid segfaults, only set after a sample
has arrived
-
self.scope.set_trigger_channel(self.trigger_channel_index)
-
self.scope.set_trigger_mode(TRIGGER_MODES[self.trigger_mode_index][1])
- self.scope.set_sample_rate(self.sample_rate)
- #update the x axis
- exp = common.get_exp(self.x_per_div)
- if exp > -2: x_units, scalar = 's', 1e0
- elif exp > -5: x_units, scalar = 'ms', 1e3
- elif exp > -8: x_units, scalar = 'us', 1e6
- else: x_units, scalar = 'ns', 1e9
- self.plotter.set_x_units('Time (%s)'%x_units)
- self.plotter.set_x_grid(
- scalar*self.x_off,
- scalar*self.x_per_div*self.x_divs + scalar*self.x_off,
- scalar*self.x_per_div,
- )
- #update the y axis
- self.plotter.set_y_units('Units')
- self.plotter.set_y_grid(
- -1*self.y_per_div*self.y_divs/2.0 + self.y_off,
- self.y_per_div*self.y_divs/2.0 + self.y_off,
- self.y_per_div,
- )
- #update control panel and plotter
- self.control_panel.update()
- self.plotter.update()
-
- ##################################################
- # Set parameters on-the-fly
- ##################################################
- def set_x_per_div(self, x_per_div):
- self.x_per_div = x_per_div
- self.update()
- def set_x_off(self, x_off):
- self.x_off = x_off
- self.update()
- def set_y_per_div(self, y_per_div):
- self.y_per_div = y_per_div
- self.update()
- def set_y_off(self, y_off):
- self.y_off = y_off
- self.update()
- def set_trigger_channel_index(self, trigger_channel_index):
- self.trigger_channel_index = trigger_channel_index
- self.update()
- def set_trigger_mode_index(self, trigger_mode_index):
- self.trigger_mode_index = trigger_mode_index
- self.update()
- def set_trigger_level_index(self, trigger_level_index):
- self.trigger_level_index = trigger_level_index
- self.update()
- def set_trigger_index(self, trigger_index):
- self.trigger_index = trigger_index
- self.update()
- def set_run(self, running):
- self.running = running
- self.update()
- def set_ac_couple(self, ac_couple):
- self.ac_couple = ac_couple
- self.update()
- def set_autorange(self, autorange):
- self.autorange = autorange
- self.update()
- def set_sample_rate(self, sample_rate):
- self.sample_rate = sample_rate
- self.update()
-
-##################################################
-# Scope sink block
-##################################################
class scope_sink_f(gr.hier_block2):
"""!
A scope block with a gui window.
@@ -379,9 +50,9 @@
parent,
title='',
sample_rate=1,
- size=DEFAULT_WIN_SIZE,
- frame_rate=DEFAULT_FRAME_RATE,
- v_scale=DEFAULT_V_SCALE,
+ size=scope_window.DEFAULT_WIN_SIZE,
+ frame_rate=scope_window.DEFAULT_FRAME_RATE,
+ v_scale=scope_window.DEFAULT_V_SCALE,
t_scale=None,
num_inputs=1,
ac_couple=False,
@@ -399,28 +70,54 @@
#connect
for i in range(num_inputs):
self.connect((self, i), (scope, i))
+ #controller
+ self.controller = prop_val_interface()
+ self.controller.add_listener(SAMPLE_RATE_KEY,
scope.set_sample_rate)
+ self.controller.set_provider(SAMPLE_RATE_KEY, scope.sample_rate)
+ def set_trigger_level(level):
+ if level == '': scope.set_trigger_level_auto()
+ else: scope.set_trigger_level(level)
+ self.controller.add_listener(SCOPE_TRIGGER_LEVEL_KEY,
set_trigger_level)
+ def set_trigger_mode(mode):
+ if mode == 0: mode = gr.gr_TRIG_AUTO
+ elif mode < 0: mode = gr.gr_TRIG_NEG_SLOPE
+ elif mode > 0: mode = gr.gr_TRIG_POS_SLOPE
+ else: return
+ scope.set_trigger_mode(mode)
+ self.controller.add_listener(SCOPE_TRIGGER_MODE_KEY,
set_trigger_mode)
+ self.controller.add_listener(SCOPE_TRIGGER_CHANNEL_KEY,
scope.set_trigger_channel)
+ self.controller.set_provider(SCOPE_NUM_SAMPLES_KEY,
scope.get_samples_per_output_record)
+ #start input watcher
+ common.input_watcher(msgq, lambda x:
self.controller.set(MSG_KEY, x))
#create window
- self.win = scope_window(
+ self.win = scope_window.scope_window(
parent=parent,
+ controller=self.controller,
size=size,
title=title,
- scope=scope,
frame_rate=frame_rate,
num_inputs=num_inputs,
- sample_rate=sample_rate,
+ sample_rate_key=SAMPLE_RATE_KEY,
x_per_div=t_scale,
y_per_div=v_scale,
ac_couple=ac_couple,
+ scope_trigger_level_key=SCOPE_TRIGGER_LEVEL_KEY,
+ scope_trigger_mode_key=SCOPE_TRIGGER_MODE_KEY,
+ scope_trigger_channel_key=SCOPE_TRIGGER_CHANNEL_KEY,
+ scope_num_samples_key=SCOPE_NUM_SAMPLES_KEY,
+ msg_key=MSG_KEY,
)
#register callbacks from window for external use
- self.set_sample_rate = self.win.set_sample_rate
- #setup the input watcher
- common.input_watcher(msgq, self._handle_msg)
+ self.set_running = self.win.set_running
+ self.set_ac_couple = self.win.set_ac_couple
+ self.set_autorange = self.win.set_autorange
+ self.set_x_per_div = self.win.set_x_per_div
+ self.set_y_per_div = self.win.set_y_per_div
+ self.set_x_off = self.win.set_x_off
+ self.set_y_off = self.win.set_y_off
+ self.set_x_divs = self.win.set_x_divs
+ self.set_y_divs = self.win.set_y_divs
+ self.set_frame_rate = self.win.set_frame_rate
- def _handle_msg(self, msg):
- nchan = int(msg.arg1()) # number of channels of data in msg
- nsamples = int(msg.arg2()) # number of samples in each channel
- s = msg.to_string() # get the body of the msg as a string
- samples = numpy.fromstring(s, numpy.float32)
- samps_per_ch = len(samples)/nchan
- self.win.plot([samples[samps_per_ch*i:samps_per_ch*(i+1)] for i
in range(nchan)])
+ def set_sample_rate(self, sample_rate):
+ self.controller[SAMPLE_RATE_KEY] = sample_rate
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r8893 - gnuradio/branches/features/experimental-gui,
jblum <=