[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r8750 - gnuradio/branches/developers/jblum/gr-wxglgui/
From: |
jblum |
Subject: |
[Commit-gnuradio] r8750 - gnuradio/branches/developers/jblum/gr-wxglgui/src/python |
Date: |
Sun, 29 Jun 2008 14:22:03 -0600 (MDT) |
Author: jblum
Date: 2008-06-29 14:22:03 -0600 (Sun, 29 Jun 2008)
New Revision: 8750
Modified:
gnuradio/branches/developers/jblum/gr-wxglgui/src/python/common.py
gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py
gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py
gnuradio/branches/developers/jblum/gr-wxglgui/src/python/scopesink.py
Log:
legend, autorange, improved tick number format
Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/common.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/common.py
2008-06-29 19:50:34 UTC (rev 8749)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/common.py
2008-06-29 20:22:03 UTC (rev 8750)
@@ -60,7 +60,8 @@
@param num the floating point number
@return the exponent as an integer
"""
- return int(math.floor(math.log10(num)))
+ if num == 0: return 0
+ return int(math.floor(math.log10(abs(num))))
def get_clean_num(num):
"""!
Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py
2008-06-29 19:50:34 UTC (rev 8749)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py
2008-06-29 20:22:03 UTC (rev 8750)
@@ -175,8 +175,9 @@
@param samples the fft array
"""
#peak hold calculation
- if self.peak_hold and len(self.peak_vals) != len(samples):
self.peak_vals = samples
- if self.peak_hold: self.peak_vals = numpy.maximum(samples,
self.peak_vals)
+ if self.peak_hold:
+ if len(self.peak_vals) != len(samples): self.peak_vals
= samples
+ self.peak_vals = numpy.maximum(samples, self.peak_vals)
#plot the fft
self.plotter.set_waveform(
channel=1,
@@ -205,9 +206,9 @@
x_per_div = common.get_clean_num(x_width/self.x_divs)
exp = common.get_exp(x_per_div)
#calculate units and scalar
- if exp >= 9: x_units, scalar = 'GHz', 1e-9
- elif exp >= 6: x_units, scalar = 'MHz', 1e-6
- elif exp >= 3: x_units, scalar = 'KHz', 1e-3
+ if exp > 7: x_units, scalar = 'GHz', 1e-9
+ elif exp > 4: x_units, scalar = 'MHz', 1e-6
+ elif exp > 1: x_units, scalar = 'KHz', 1e-3
else: x_units, scalar = 'Hz', 1e-0
#update the x grid
if self.real:
Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py
2008-06-29 19:50:34 UTC (rev 8749)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py
2008-06-29 20:22:03 UTC (rev 8750)
@@ -27,22 +27,17 @@
from OpenGL.GL import *
import gltext
-import sys
+import common
import math
import numpy
BACKGROUND_COLOR_SPEC = (1, 0.976, 1, 1) #creamy white
GRID_LINE_COLOR_SPEC = (0, 0, 0) #black
-
-TICK_TEXT_COLOR_SPEC = (0, 0, 0) #black
TICK_TEXT_FONT_SIZE = 9
-
-TITLE_TEXT_COLOR_SPEC = (0, 0, 0) #black
TITLE_TEXT_FONT_SIZE = 13
-
-UNITS_TEXT_COLOR_SPEC = (0, 0, 0) #black
UNITS_TEXT_FONT_SIZE = 9
-
+LEGEND_TEXT_FONT_SIZE = 8
+LEGEND_BOX_WIDTH, LEGEND_BOX_HEIGHT = 26, 20
PADDING = 35, 10, 40, 60 #top, right, bottom, left
class _plotter_base(wx.glcanvas.GLCanvas):
@@ -106,6 +101,7 @@
self.grid_compiled_list_id = wx.NewId()
self.channels = dict()
#store title and unit strings
+ self.set_legend(False)
self.set_title('Title')
self.set_x_units('X Units (xx)')
self.set_y_units('Y Units (yy)')
@@ -116,6 +112,14 @@
self.set_y_grid(-1, 1, 1)
_plotter_base.__init__(self, parent)
+ def set_legend(self, legend):
+ """!
+ Set the legend on/off.
+ @param legend true to turn on
+ """
+ self.legend = legend
+ self._changed = True
+
def set_title(self, title):
"""!
Set the title.
@@ -189,7 +193,8 @@
##################################################
# Draw Waveforms
##################################################
- for channel, (samples, offset, color_spec) in
self.channels.iteritems():
+ for channel in reversed(sorted(self.channels.keys())):
+ samples, offset, color_spec = self.channels[channel]
glColor3f(*color_spec)
glBegin(GL_LINE_STRIP)
num_samps = len(samples)
@@ -267,7 +272,6 @@
##################################################
# Draw Title
##################################################
- glColor3f(*TITLE_TEXT_COLOR_SPEC)
font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
font.SetWeight(wx.FONTWEIGHT_BOLD)
#draw x units
@@ -277,7 +281,6 @@
##################################################
# Draw Units
##################################################
- glColor3f(*UNITS_TEXT_COLOR_SPEC)
font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
font.SetWeight(wx.FONTWEIGHT_BOLD)
#draw x units
@@ -287,15 +290,38 @@
txt = gltext.Text(self.y_units, font=font,
font_size=UNITS_TEXT_FONT_SIZE, centered=True)
txt.draw_text(wx.Point(.25*self.padding_left, self.height/2.0),
rotation=90)
+ ##################################################
+ # Draw Legend
+ ##################################################
+ if self.legend:
+ for i, channel in
enumerate(sorted(self.channels.keys())):
+ x_off =
1.1*LEGEND_BOX_WIDTH*(len(self.channels) - i - 1) + LEGEND_BOX_WIDTH/2
+ samples, offset, color_spec =
self.channels[channel]
+ #draw colored rectangle
+ glColor3f(*color_spec)
+ self._draw_rect(
+ self.width - self.padding_right - x_off
- LEGEND_BOX_WIDTH/2,
+
(self.padding_top-LEGEND_BOX_HEIGHT)/2.0,
+ LEGEND_BOX_WIDTH,
+ LEGEND_BOX_HEIGHT,
+ )
+ #draw label text
+ txt = gltext.Text('Ch%s'%channel,
font_size=LEGEND_TEXT_FONT_SIZE, centered=True)
+ txt.draw_text(wx.Point(self.width -
self.padding_right - x_off, self.padding_top/2.0))
+
def _draw_tick_label(self, tick, coor):
"""!
Format the tick value and draw it at the coordinate.
Intelligently switch between decimal representations.
@param tick the floating point tick value
@param coor the x, y coordinate
- """
- tick_str = '%.3g'%float(tick)
- glColor3f(*TICK_TEXT_COLOR_SPEC)
+ """
+ #format
+ exp = common.get_exp(tick)
+ base = int(tick/10**exp)
+ if abs(exp) >= 3: tick_str = '%de%d'%(base, exp)
+ else: tick_str = '%g'%tick
+ #draw
txt = gltext.Text(tick_str, font_size=TICK_TEXT_FONT_SIZE,
centered=True)
txt.draw_text(wx.Point(*coor))
Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/scopesink.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/scopesink.py
2008-06-29 19:50:34 UTC (rev 8749)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/scopesink.py
2008-06-29 20:22:03 UTC (rev 8750)
@@ -28,6 +28,7 @@
import wx
import math
import numpy
+import time
##################################################
# Constants
@@ -53,8 +54,9 @@
(0, 0, 1),
(0, 1, 0),
(1, 0, 0),
- (1, 1, 0),
+ (1, 0, 1),
)
+AUTORANGE_UPDATE_RATE = 0.5 #sec
##################################################
# Scope window control panel
@@ -73,7 +75,7 @@
control_box = wx.BoxSizer(wx.VERTICAL)
#begin control box
- control_box.AddStretchSpacer()
+ control_box.AddSpacer(2)
control_box.Add(common.LabelText(self, 'Channel Menu'), 0,
wx.ALIGN_CENTER)
control_box.AddSpacer(2)
#channel chooser drop down
@@ -86,11 +88,15 @@
control_box.Add(self.trigger_check_box, 0, wx.ALIGN_LEFT)
#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_set_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)
#trigger menu
- control_box.AddStretchSpacer()
+ control_box.AddSpacer(2)
control_box.Add(common.LabelText(self, 'Trigger Menu'), 0,
wx.ALIGN_CENTER)
control_box.AddSpacer(2)
#trigger mode
@@ -109,7 +115,7 @@
hbox.Add(self.trigger_level_chooser, 0,
wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
#setup axes menu
- control_box.AddStretchSpacer()
+ control_box.AddSpacer(2)
control_box.Add(common.LabelText(self, 'Axes Menu'), 0,
wx.ALIGN_CENTER)
#x axis
hbox = wx.BoxSizer(wx.HORIZONTAL)
@@ -133,15 +139,13 @@
hbox.Add(self.y_minus_button, 0, wx.ALIGN_CENTER_VERTICAL |
wx.ALIGN_LEFT)
#Run button
- control_box.AddStretchSpacer()
+ control_box.AddSpacer(2)
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.ALIGN_CENTER)
- #TODO autorange y axis
-
#end control box
- control_box.AddStretchSpacer()
+ control_box.AddSpacer(2)
#set sizer
self.SetSizerAndFit(control_box)
#update
@@ -160,20 +164,28 @@
else: self.trigger_check_box.Enable()
#update the ac couple check box
self.ac_couple_check_box.SetValue(self.parent.ac_couple[self.parent.input_index])
+ #update the autorange check box
+ self.autorange_check_box.SetValue(self.parent.autorange_index
== self.parent.input_index)
#update trigger mode and level chooser
self.trigger_level_chooser.SetSelection(self.parent.trigger_level_index)
self.trigger_mode_chooser.SetSelection(self.parent.trigger_mode_index)
#update the run/stop button
if self.parent.running: self.run_button.SetLabel('Stop')
else: self.run_button.SetLabel('Run')
- #update the slider
- #TODO
+ #update the y adj buttons
+ if self.parent.autorange_index is None:
+ self.y_plus_button.Enable()
+ self.y_minus_button.Enable()
+ else:
+ self.y_plus_button.Disable()
+ self.y_minus_button.Disable()
##################################################
# Event handlers
##################################################
def _on_channel(self, event):
self.parent.set_input_index(self.channel_chooser.GetSelection())
- def _on_set_ac_couple(self, event):
self.parent.set_ac_couple(self.parent.input_index, event.IsChecked())
+ def _on_ac_couple(self, event):
self.parent.set_ac_couple(self.parent.input_index, event.IsChecked())
+ def _on_autorange(self, event):
self.parent.set_autorange(self.parent.input_index, event.IsChecked())
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_set_trigger(self, event):
@@ -198,6 +210,7 @@
sample_rate,
x_per_div,
y_per_div,
+ ac_couple,
):
#check num inputs
assert num_inputs <= len(CHANNEL_COLOR_SPECS)
@@ -205,7 +218,10 @@
self.running = True
self.num_inputs = num_inputs
self.sample_rate = sample_rate
- self.ac_couple = [False]*num_inputs
+ self.ac_couple = [ac_couple]*num_inputs
+ if y_per_div is None: self.autorange_index = 0
+ else: self.autorange_index = None
+ self.autorange_ts = 0
self.input_index = 0
self.trigger_index = 0
self.trigger_mode_index = 0
@@ -213,7 +229,8 @@
self.x_divs = 8
self.x_per_div = x_per_div
self.y_divs = 8
- self.y_per_div = y_per_div
+ if y_per_div is None: self.y_per_div = 1
+ else: self.y_per_div = y_per_div
self.scope = scope
self._init = False #HACK
#init panel and plot
@@ -221,6 +238,7 @@
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)
@@ -230,19 +248,55 @@
#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
+ 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)
+ #ac coupling
+ if self.ac_couple[i]: samples = samples -
numpy.average(samples)
+ #autorange
+ if self.autorange_index == i and \
+ time.time() - self.autorange_ts >
AUTORANGE_UPDATE_RATE:
+ rms = numpy.average(numpy.square(samples))**.5
+ mean = numpy.average(samples)
+ y_per_div =
common.get_clean_num(4*(rms+mean)/self.y_divs)
+ if self.y_per_div != y_per_div:
self.set_y_per_div(y_per_div)
+ self.autorange_ts = time.time()
+ #handle num samps out of bounds
+ if num_samps > len(samples) or num_samps < 2: continue
+ #plot samples
+ self.plotter.set_waveform(
+ channel=i+1,
+ samples=samples[:num_samps],
+ offset=0.0,
+ color_spec=CHANNEL_COLOR_SPECS[i],
+ )
+ #update the plotter
+ self.plotter.update()
+
def update(self):
- #update the trigger
+ #update the scope
if self._init: #HACK avoid segfaults, only set after a sample
has arrived
self.scope.set_trigger_channel(self.trigger_index)
self.scope.set_trigger_mode(TRIGGER_MODES[self.trigger_mode_index][1])
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*self.y_divs*self.y_per_div/2.0)
+ self.scope.set_sample_rate(self.sample_rate)
#update the x axis
exp = common.get_exp(self.x_per_div)
- if exp >= -0: x_units, scalar = 's', 1e0
- elif exp >= -3: x_units, scalar = 'ms', 1e3
- elif exp >= -6: x_units, scalar = 'us', 1e6
+ 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(0, scalar*self.x_per_div*self.x_divs,
scalar*self.x_per_div)
@@ -254,28 +308,6 @@
#update the plotter
self.plotter.update()
- def plot(self, sampleses):
- if not self._init: #HACK
- self._init = True
- self.update()
- if not self.running: return
- 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)
- #ac coupling
- if self.ac_couple[i]: offset = -1*numpy.average(samples)
- else: offset = 0
- #TODO handle num samps out of bounds
- if num_samps > len(samples) or num_samps < 2: continue
- self.plotter.set_waveform(
- channel=i,
- samples=samples[:num_samps],
- offset=offset,
- color_spec=CHANNEL_COLOR_SPECS[i],
- )
- #update the plotter
- self.plotter.update()
-
##################################################
# Set parameters on-the-fly
##################################################
@@ -303,6 +335,14 @@
def set_ac_couple(self, channel_index, ac_couple):
self.ac_couple[channel_index] = ac_couple
self.update()
+ def set_autorange(self, channel_index, autorange):
+ if autorange: self.autorange_index = channel_index
+ elif not autorange and self.autorange_index == channel_index:
+ self.autorange_index = None
+ self.update()
+ def set_sample_rate(self, sample_rate):
+ self.sample_rate = sample_rate
+ self.update()
##################################################
# Scope sink block
@@ -321,8 +361,8 @@
v_scale=DEFAULT_V_SCALE,
t_scale=None,
num_inputs=1,
+ ac_couple=False,
):
- #TODO t_scale None is autorange
self.num_inputs = num_inputs
#init
gr.hier_block2.__init__(
@@ -347,9 +387,10 @@
sample_rate=sample_rate,
x_per_div=t_scale,
y_per_div=v_scale,
+ ac_couple=ac_couple,
)
#register callbacks from window for external use
- #TODO
+ self.set_sample_rate = self.win.set_sample_rate
#setup the input watcher
common.input_watcher(msgq, self._handle_msg)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r8750 - gnuradio/branches/developers/jblum/gr-wxglgui/src/python,
jblum <=