commit-gnuradio
[Top][All Lists]
Advanced

[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)
                





reply via email to

[Prev in Thread] Current Thread [Next in Thread]