commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] r8741 - in gnuradio/branches/developers/jblum/gr-wxglg


From: jblum
Subject: [Commit-gnuradio] r8741 - in gnuradio/branches/developers/jblum/gr-wxglgui/src: . python
Date: Fri, 27 Jun 2008 15:40:04 -0600 (MDT)

Author: jblum
Date: 2008-06-27 15:40:03 -0600 (Fri, 27 Jun 2008)
New Revision: 8741

Added:
   gnuradio/branches/developers/jblum/gr-wxglgui/src/Makefile.am
   gnuradio/branches/developers/jblum/gr-wxglgui/src/python/Makefile.am
   gnuradio/branches/developers/jblum/gr-wxglgui/src/python/__init__.py
   gnuradio/branches/developers/jblum/gr-wxglgui/src/python/common.py
Modified:
   gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py
   gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py
Log:
added Makefiles, fft sink callbacks, common module

Added: gnuradio/branches/developers/jblum/gr-wxglgui/src/Makefile.am
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/Makefile.am               
                (rev 0)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/Makefile.am       
2008-06-27 21:40:03 UTC (rev 8741)
@@ -0,0 +1,24 @@
+#
+# 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.
+# 
+
+include $(top_srcdir)/Makefile.common
+
+SUBDIRS = python

Added: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/Makefile.am
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/Makefile.am        
                        (rev 0)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/Makefile.am        
2008-06-27 21:40:03 UTC (rev 8741)
@@ -0,0 +1,36 @@
+#
+# 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.
+# 
+
+include $(top_srcdir)/Makefile.common
+
+# Install this stuff so that it ends up as the gnuradio.wxglgui module
+# This usually ends up at:
+#   ${prefix}/lib/python${python_version}/site-packages/gnuradio/wxglgui
+
+ourpythondir = $(grpythondir)/wxglgui
+ourlibdir    = $(grpyexecdir)/wxglgui
+
+ourpython_PYTHON = \
+       __init__.py \
+       gltext.py \
+       plotter.py \
+       common.py \
+       fftsink.py

Added: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/__init__.py
===================================================================

Added: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/common.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/common.py          
                (rev 0)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/common.py  
2008-06-27 21:40:03 UTC (rev 8741)
@@ -0,0 +1,54 @@
+#
+# 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.
+# 
+
+import threading
+import wx
+
+class LabelText(wx.StaticText):        
+       """!
+       Label text to give the wx plots a uniform look.
+       Get the default label text and set the font bold.
+       """
+       
+       def __init__(self, window, label):
+               wx.StaticText.__init__(self, window, -1, label)
+               font = self.GetFont()
+               font.SetWeight(wx.FONTWEIGHT_BOLD)
+               font.SetUnderlined(True)
+               self.SetFont(font)
+
+class input_watcher(threading.Thread):
+       """!
+       Input watcher thread runs forever.
+       Read messages from the message queue.
+       Forward messages to the message handler.
+       """
+       
+       def __init__ (self, msgq, handle_msg):
+               threading.Thread.__init__(self)
+               self.setDaemon(1)
+               self.msgq = msgq
+               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())

Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py 
2008-06-27 18:53:10 UTC (rev 8740)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py 
2008-06-27 21:40:03 UTC (rev 8741)
@@ -24,15 +24,16 @@
 ##################################################
 from gnuradio import gr, window
 import plotter
+import common
 import wx
 import math
-import threading
 import numpy
 
 ##################################################
 # Constants
 ##################################################
 DEFAULT_FFT_RATE = gr.prefs().get_long('wxgui', 'fft_rate', 15)
+DEFAULT_WIN_SIZE = (640, 240)
 DIV_LEVELS = (1, 2, 5, 10, 20)
 
 ##################################################
@@ -43,14 +44,6 @@
        A control panel with wx widgits to control the plotter and fft block 
chain.
        """
        
-       class LabelText(wx.StaticText): 
-               def __init__(self, window, label):
-                       wx.StaticText.__init__(self, window, -1, label)
-                       font = self.GetFont()
-                       font.SetWeight(wx.FONTWEIGHT_BOLD)
-                       font.SetUnderlined(True)
-                       self.SetFont(font)
-       
        def __init__(self, parent):
                """!
                Create a new control panel.
@@ -62,17 +55,17 @@
                
                #checkboxes for average and peak hold
                control_box.AddStretchSpacer()
-               control_box.Add(self.LabelText(self, 'Options'), 0, 
wx.ALIGN_CENTER)
+               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, parent.on_average)
+               self.average_check_box.Bind(wx.EVT_CHECKBOX, self.on_average)
                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, 
parent.on_peak_hold) 
+               self.peak_hold_check_box.Bind(wx.EVT_CHECKBOX, 
self.on_peak_hold) 
                control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND)
           
                #radio buttons for div size
                control_box.AddStretchSpacer()
-               control_box.Add(self.LabelText(self, 'Set dB/div'), 0, 
wx.ALIGN_CENTER)
+               control_box.Add(common.LabelText(self, 'Set dB/div'), 0, 
wx.ALIGN_CENTER)
                radio_box = wx.BoxSizer(wx.VERTICAL)
                self.radio_buttons = list()
                for y_per_div in DIV_LEVELS:
@@ -84,14 +77,14 @@
                
                #ref lvl buttons
                control_box.AddStretchSpacer()
-               control_box.Add(self.LabelText(self, 'Adj Ref Lvl'), 0, 
wx.ALIGN_CENTER)
+               control_box.Add(common.LabelText(self, 'Adj Ref Lvl'), 0, 
wx.ALIGN_CENTER)
                control_box.AddSpacer(2)
                button_box = wx.BoxSizer(wx.HORIZONTAL)         
                self.ref_plus_button = wx.Button(self, -1, '+', 
style=wx.BU_EXACTFIT)
-               self.ref_plus_button.Bind(wx.EVT_BUTTON, 
parent.on_incr_ref_level)
+               self.ref_plus_button.Bind(wx.EVT_BUTTON, self.on_incr_ref_level)
                button_box.Add(self.ref_plus_button, 0, wx.ALIGN_CENTER)
                self.ref_minus_button = wx.Button(self, -1, ' - ', 
style=wx.BU_EXACTFIT)
-               self.ref_minus_button.Bind(wx.EVT_BUTTON, 
parent.on_decr_ref_level)
+               self.ref_minus_button.Bind(wx.EVT_BUTTON, 
self.on_decr_ref_level)
                button_box.Add(self.ref_minus_button, 0, wx.ALIGN_CENTER)
                control_box.Add(button_box, 0, wx.ALIGN_CENTER)
                control_box.AddStretchSpacer()
@@ -113,10 +106,17 @@
                        self.radio_buttons[index].SetValue(True)
                except: pass
        
+       ##################################################
+       # Event handlers
+       ##################################################
        def on_radio_button_change(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])
+               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()
 
 ##################################################
 # FFT window with plotter and control panel
@@ -124,7 +124,8 @@
 class fft_window(wx.Panel):
        def __init__(
                self, 
-               parent, 
+               parent,
+               size, 
                title,
                real,
                baseband_freq,
@@ -139,41 +140,23 @@
                #ensure y_per_div
                if y_per_div not in DIV_LEVELS: y_per_div = DIV_LEVELS[0]
                #setup
+               self.real = real
+               self.baseband_freq = baseband_freq
+               self.sample_rate = sample_rate
+               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 = average
                self.peak_hold = peak_hold
-               self.set_average = set_average
+               self.fft_set_average = set_average
                self.peak_vals = []
-               #determine best fitting x_per_div
-               x_divs = 8.0 #appoximate 
-               if real: x_width = sample_rate/2.0
-               else: x_width = sample_rate
-               exp = math.floor(math.log10(x_width/x_divs))            
-               x_per_divs = numpy.array((1, 2, 5, 10))*10**exp         
-               x_per_div = x_per_divs[numpy.argmin(numpy.abs(x_per_divs - 
x_width/x_divs))]                    
-               #calculate units and scalar
-               if exp >= 9: units, power = 'GHz', 9
-               elif exp >= 6: units, power = 'MHz', 6
-               elif exp >= 3: units, power = 'KHz', 3
-               else: units, power = 'Hz', 0
-               scalar = 10**(-1*power)
                #init panel and plot 
                wx.Panel.__init__(self, parent, -1)                             
  
-               self.plotter = plotter.grid_plotter(self, title, 
'Frequency(%s)'%units, 'Amplitude(dB)', 35, 10, 40, 60)  
-               if real: 
-                       self.plotter.set_x_grid(
-                               scalar*baseband_freq, 
-                               scalar*baseband_freq + scalar*sample_rate/2.0, 
-                               scalar*x_per_div,
-                       ) 
-               else:
-                       self.plotter.set_x_grid(
-                               scalar*baseband_freq - scalar*sample_rate/2.0, 
-                               scalar*baseband_freq + scalar*sample_rate/2.0, 
-                               scalar*x_per_div,
-                       )
+               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)
@@ -184,6 +167,11 @@
                self.update()
                
        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
+               """
                #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)
@@ -206,9 +194,35 @@
        
        def update(self):
                #update average
-               self.set_average(self.average)
+               self.fft_set_average(self.average)
                #update peak hold
-               if not self.peak_hold: self.peak_vals = []
+               if not self.peak_hold: self.peak_vals = []              
+               #determine best fitting x_per_div
+               if self.real: x_width = self.sample_rate/2.0
+               else: x_width = self.sample_rate
+               exp = math.floor(math.log10(x_width/self.x_divs))               
+               x_per_divs = numpy.array((1, 2, 5, 10))*10**exp         
+               x_per_div = x_per_divs[numpy.argmin(numpy.abs(x_per_divs - 
x_width/self.x_divs))]                       
+               #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
+               else: x_units, scalar = 'Hz', 1e-0
+               #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*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*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 if non-gui changes occured
@@ -216,25 +230,26 @@
                #update the plotter
                self.plotter.update()
        
-       def on_average(self, event):
-               self.average = event.IsChecked()
+       ##################################################
+       # 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.average = average
                self.update()           
-               
-       def on_peak_hold(self, event):
-               self.peak_hold = event.IsChecked()
+       def set_peak_hold(self, peak_hold):
+               self.peak_hold = peak_hold
                self.update()
-               
-       def on_incr_ref_level(self, event):
-               self.ref_level = self.ref_level + self.y_per_div
-               self.update()
-               
-       def on_decr_ref_level(self, event):
-               self.ref_level = self.ref_level - self.y_per_div
-               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)
 
 ##################################################
 # FFT blocks chain: input -> message sink
@@ -295,35 +310,6 @@
                else: self._avg.set_taps(1.0)
 
 ##################################################
-# Input watcher for msg queue
-##################################################
-class input_watcher(threading.Thread):
-       def __init__ (self, msgq, handle_samples):
-               threading.Thread.__init__(self)
-               self.setDaemon(1)
-               self.msgq = msgq
-               self.handle_samples = handle_samples
-               self.keep_running = True
-               self.start()
-
-       def run(self):          
-               while self.keep_running:
-                       msg = self.msgq.delete_head() #blocking read of message 
queue
-                       itemsize = int(msg.arg1())
-                       nitems = int(msg.arg2())
-
-                       s = msg.to_string() #get the body of the msg as a 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]
-
-                       samples = numpy.fromstring(s, numpy.float32)
-                       self.handle_samples(samples)
-
-##################################################
 # FFT sink base block for real and complex types
 ##################################################     
 class _fft_sink_base(gr.hier_block2):
@@ -347,6 +333,7 @@
                average=False, 
                avg_alpha=None, 
                title='', 
+               size=DEFAULT_WIN_SIZE,
                peak_hold=False,
        ): 
                self.real = self.item_size == gr.sizeof_float
@@ -374,6 +361,7 @@
                #create window
                self.win = fft_window(
                        parent=parent, 
+                       size=size,
                        title=title,
                        real = self.real,
                        baseband_freq=baseband_freq,
@@ -385,18 +373,37 @@
                        peak_hold=peak_hold,
                        set_average=fft.set_average,    
                )
+               #register callbacks from window for external use
+               self.set_baseband_freq = self.win.set_baseband_freq
+               self.set_average = self.win.set_average
+               self.set_peak_hold = self.win.set_peak_hold
+               self.set_y_per_div = self.win.set_y_per_div
+               self.set_ref_level = self.win.set_ref_level
                #setup the input watcher
-               input_watcher(fft.msgq, self._handle_samples)
+               common.input_watcher(fft.msgq, self._handle_msg)
                
-       def _handle_samples(self, samples):
+       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.
-               @param samples an array of fft samples
+               @param msg the fft array as a character array
                """
-               num_samples = len(samples)
-               if self.real: samples = samples[:num_samples/2]
-               else: samples = numpy.concatenate((samples[num_samples/2+1:], 
samples[:num_samples/2]))
+               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)    
+               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.win.plot(samples)
 
 class fft_sink_f(_fft_sink_base): item_size = gr.sizeof_float

Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py 
2008-06-27 18:53:10 UTC (rev 8740)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py 
2008-06-27 21:40:03 UTC (rev 8741)
@@ -43,6 +43,8 @@
 UNITS_TEXT_COLOR_SPEC = (0, 0, 0) #black
 UNITS_TEXT_FONT_SIZE = 9
 
+PADDING = 35, 10, 40, 60 #top, right, bottom, left
+
 class _plotter_base(wx.glcanvas.GLCanvas):
        """!
        Plotter base class for all plot types.
@@ -97,26 +99,47 @@
 
 class grid_plotter(_plotter_base):
        
-       def __init__(self, parent, title, x_units, y_units, padding_top, 
padding_right, padding_bottom, padding_left):
+       def __init__(self, parent):
                """!
                Create a new grid plotter.
                """             
                self.grid_compiled_list_id = wx.NewId()
                self.channels = dict()  
-               #store title and unit strings   
-               self.title = title
-               self.x_units = x_units
-               self.y_units = y_units  
+               #store title and unit strings
+               self.set_title('Title')
+               self.set_x_units('X Units (xx)')        
+               self.set_y_units('Y Units (yy)')
                #store padding  
-               self.padding_top = padding_top
-               self.padding_right = padding_right
-               self.padding_bottom = padding_bottom
-               self.padding_left = padding_left        
+               self.padding_top, self.padding_right, self.padding_bottom, 
self.padding_left = PADDING
                #init the grid to some value    
                self.set_x_grid(-1, 1, 1)               
                self.set_y_grid(-1, 1, 1)               
                _plotter_base.__init__(self, parent)
+               
+       def set_title(self, title):
+               """!
+               Set the title.
+               @param title the title string
+               """
+               self.title = title
+               self._changed = True
 
+       def set_x_units(self, x_units):
+               """!
+               Set the x_units.
+               @param x_units the x_units string
+               """
+               self.x_units = x_units
+               self._changed = True
+
+       def set_y_units(self, y_units):
+               """!
+               Set the y_units.
+               @param y_units the y_units string
+               """
+               self.y_units = y_units
+               self._changed = True
+
        def set_x_grid(self, x_min, x_max, x_step):
                """!
                Set the x grid parameters.
@@ -339,12 +362,12 @@
        frame = wx.Frame(None, -1, 'Demo', wx.DefaultPosition)
        vbox = wx.BoxSizer(wx.VERTICAL)
        
-       plotter = grid_plotter(frame, 'Demo Grid1', 'Frequency(Hz)', 
'Amplitude(dB)', 35, 10, 40, 60)
+       plotter = grid_plotter(frame)
        plotter.set_x_grid(-1, 1, .2)           
        plotter.set_y_grid(-1, 1, .4)
        vbox.Add(plotter, 1, wx.EXPAND)
        
-       plotter = grid_plotter(frame, 'Demo Grid2', 'Frequency(Hz)', 
'Amplitude(dB)', 35, 10, 40, 60)
+       plotter = grid_plotter(frame)
        plotter.set_x_grid(-1, 1, .2)           
        plotter.set_y_grid(-1, 1, .4)
        vbox.Add(plotter, 1, wx.EXPAND)





reply via email to

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