commit-gnuradio
[Top][All Lists]
Advanced

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

[Commit-gnuradio] r9244 - gnuradio/branches/developers/jblum/glwxgui/gr-


From: jblum
Subject: [Commit-gnuradio] r9244 - gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python
Date: Mon, 11 Aug 2008 18:17:37 -0600 (MDT)

Author: jblum
Date: 2008-08-11 18:17:37 -0600 (Mon, 11 Aug 2008)
New Revision: 9244

Added:
   
gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/waterfall_window.py
   
gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/waterfallsink_gl.py
Modified:
   gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/Makefile.am
Log:
waterfall imported

Modified: 
gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/Makefile.am
===================================================================
--- gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/Makefile.am  
2008-08-12 00:06:06 UTC (rev 9243)
+++ gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/Makefile.am  
2008-08-12 00:17:37 UTC (rev 9244)
@@ -43,6 +43,8 @@
        pubsub.py                       \
        scopesink2.py                   \
        waterfallsink2.py               \
+       waterfallsink_gl.py             \
+       waterfall_window.py             \
        slider.py                       \
        stdgui2.py                      \
        numbersink2.py

Copied: 
gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/waterfall_window.py
 (from rev 9243, 
gnuradio/branches/features/experimental-gui/waterfall_window.py)
===================================================================
--- 
gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/waterfall_window.py
                          (rev 0)
+++ 
gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/waterfall_window.py
  2008-08-12 00:17:37 UTC (rev 9244)
@@ -0,0 +1,295 @@
+#
+# 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 math
+import pubsub
+from constants import *
+
+##################################################
+# Constants
+##################################################
+SLIDER_STEPS = 100
+AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP = -3, 0
+DEFAULT_FRAME_RATE = 30
+DEFAULT_WIN_SIZE = (600, 400)
+DIV_LEVELS = (1, 2, 5, 10, 20)
+MIN_DYNAMIC_RANGE, MAX_DYNAMIC_RANGE = 10, 200
+COLOR_MODES = (
+       ('RGB1', 'rgb1'),
+       ('RGB2', 'rgb2'),
+       ('RGB3', 'rgb3'),
+       ('Gray', 'gray'),
+)
+
+##################################################
+# Waterfall window control panel
+##################################################
+class control_panel(wx.Panel):
+       """!
+       A control panel with wx widgits to control the plotter and fft block 
chain.
+       """
+
+       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)
+               control_box.AddStretchSpacer()
+               control_box.Add(common.LabelText(self, 'Options'), 0, 
wx.ALIGN_CENTER)
+               #color mode
+               control_box.AddStretchSpacer()
+               self.color_mode_chooser = common.DropDownController(self, 
'Color', COLOR_MODES, parent, COLOR_MODE_KEY)
+               control_box.Add(self.color_mode_chooser, 0, wx.EXPAND)
+               #average
+               control_box.AddStretchSpacer()
+               self.average_check_box = common.CheckBoxController(self, 
'Average', parent.ext_controller, parent.average_key)
+               control_box.Add(self.average_check_box, 0, wx.EXPAND)
+               control_box.AddSpacer(2)
+               self.avg_alpha_slider = common.LogSliderController(
+                       self, 'Avg Alpha',
+                       AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP, SLIDER_STEPS,
+                       parent.ext_controller, parent.avg_alpha_key,
+               )
+               parent.ext_controller.subscribe(parent.average_key, 
self.avg_alpha_slider.Enable)
+               control_box.Add(self.avg_alpha_slider, 0, wx.EXPAND)
+               #dyanmic range buttons
+               control_box.AddStretchSpacer()
+               control_box.Add(common.LabelText(self, 'Dynamic Range'), 0, 
wx.ALIGN_CENTER)
+               control_box.AddSpacer(2)
+               self._dynamic_range_buttons = common.IncrDecrButtons(self, 
self._on_incr_dynamic_range, self._on_decr_dynamic_range)
+               control_box.Add(self._dynamic_range_buttons, 0, wx.ALIGN_CENTER)
+               #ref lvl buttons
+               control_box.AddStretchSpacer()
+               control_box.Add(common.LabelText(self, 'Set Ref Level'), 0, 
wx.ALIGN_CENTER)
+               control_box.AddSpacer(2)
+               self._ref_lvl_buttons = common.IncrDecrButtons(self, 
self._on_incr_ref_level, self._on_decr_ref_level)
+               control_box.Add(self._ref_lvl_buttons, 0, wx.ALIGN_CENTER)
+               #num lines buttons
+               control_box.AddStretchSpacer()
+               control_box.Add(common.LabelText(self, 'Set Time Scale'), 0, 
wx.ALIGN_CENTER)
+               control_box.AddSpacer(2)
+               self._num_lines_buttons = common.IncrDecrButtons(self, 
self._on_incr_num_lines, self._on_decr_num_lines)
+               control_box.Add(self._num_lines_buttons, 0, wx.ALIGN_CENTER)
+               #autoscale
+               control_box.AddStretchSpacer()
+               self.autoscale_button = wx.Button(self, label='Autoscale', 
style=wx.BU_EXACTFIT)
+               self.autoscale_button.Bind(wx.EVT_BUTTON, self.parent.autoscale)
+               control_box.Add(self.autoscale_button, 0, wx.EXPAND)
+               #clear
+               self.clear_button = wx.Button(self, label='Clear', 
style=wx.BU_EXACTFIT)
+               self.clear_button.Bind(wx.EVT_BUTTON, self._on_clear_button)
+               control_box.Add(self.clear_button, 0, wx.EXPAND)
+               #run/stop
+               self.run_button = common.RunStopButtonController(self, parent, 
RUNNING_KEY)
+               control_box.Add(self.run_button, 0, wx.EXPAND)
+               #set sizer
+               self.SetSizerAndFit(control_box)
+
+       ##################################################
+       # Event handlers
+       ##################################################
+       def _on_clear_button(self, event):
+               self.parent.set_num_lines(self.parent[NUM_LINES_KEY])
+       def _on_incr_dynamic_range(self, event):
+               self.parent.set_dynamic_range(
+                       min(self.parent[DYNAMIC_RANGE_KEY] + 10, 
MAX_DYNAMIC_RANGE))
+       def _on_decr_dynamic_range(self, event):
+               self.parent.set_dynamic_range(
+                       max(self.parent[DYNAMIC_RANGE_KEY] - 10, 
MIN_DYNAMIC_RANGE))
+       def _on_incr_ref_level(self, event):
+               self.parent.set_ref_level(
+                       self.parent[REF_LEVEL_KEY] + 
self.parent[DYNAMIC_RANGE_KEY]*.1)
+       def _on_decr_ref_level(self, event):
+               self.parent.set_ref_level(
+                       self.parent[REF_LEVEL_KEY] - 
self.parent[DYNAMIC_RANGE_KEY]*.1)
+       def _on_incr_num_lines(self, event):
+               self.parent.ext_controller[self.parent.decimation_key] += 1
+       def _on_decr_num_lines(self, event):
+               self.parent.ext_controller[self.parent.decimation_key] -= 1
+
+##################################################
+# Waterfall window with plotter and control panel
+##################################################
+class waterfall_window(wx.Panel, pubsub.pubsub, common.prop_setter):
+       def __init__(
+               self,
+               parent,
+               controller,
+               size,
+               title,
+               real,
+               fft_size,
+               decimation_key,
+               baseband_freq,
+               sample_rate_key,
+               frame_rate_key,
+               dynamic_range,
+               ref_level,
+               average_key,
+               avg_alpha_key,
+               msg_key,
+       ):
+               pubsub.pubsub.__init__(self)
+               #setup
+               self.ext_controller = controller
+               self.real = real
+               self.fft_size = fft_size
+               self.decimation_key = decimation_key
+               self.sample_rate_key = sample_rate_key
+               self.frame_rate_key = frame_rate_key
+               self.average_key = average_key
+               self.avg_alpha_key = avg_alpha_key
+               #init panel and plot
+               wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
+               self.plotter = plotter.waterfall_plotter(self)
+               self.plotter.SetSize(wx.Size(*size))
+               self.plotter.set_title(title)
+               #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)
+               #plotter listeners
+               self.subscribe(COLOR_MODE_KEY, self.plotter.set_color_mode)
+               self.subscribe(NUM_LINES_KEY, self.plotter.set_num_lines)
+               #initial setup
+               self.ext_controller[self.average_key] = 
self.ext_controller[self.average_key]
+               self.ext_controller[self.avg_alpha_key] = 
self.ext_controller[self.avg_alpha_key]
+               self._register_set_prop(self, DYNAMIC_RANGE_KEY, dynamic_range)
+               self._register_set_prop(self, NUM_LINES_KEY, 256)
+               self._register_set_prop(self, Y_DIVS_KEY, 8)
+               self._register_set_prop(self, X_DIVS_KEY, 8) #approximate
+               self._register_set_prop(self, REF_LEVEL_KEY, ref_level)
+               self._register_set_prop(self, BASEBAND_FREQ_KEY, baseband_freq)
+               self._register_set_prop(self, COLOR_MODE_KEY, COLOR_MODES[0][1])
+               self._register_set_prop(self, RUNNING_KEY, True)
+               #register events
+               self.ext_controller.subscribe(msg_key, self.handle_msg)
+               self.ext_controller.subscribe(self.decimation_key, 
self.update_grid)
+               self.ext_controller.subscribe(self.sample_rate_key, 
self.update_grid)
+               self.ext_controller.subscribe(self.frame_rate_key, 
self.update_grid)
+               self.subscribe(BASEBAND_FREQ_KEY, self.update_grid)
+               self.subscribe(NUM_LINES_KEY, self.update_grid)
+               self.subscribe(Y_DIVS_KEY, self.update_grid)
+               self.subscribe(X_DIVS_KEY, self.update_grid)
+               #initial update
+               self.update_grid()
+
+       def autoscale(self, *args):
+               """!
+               Autoscale the waterfall plot to the last frame.
+               Set the dynamic range and reference level.
+               Does not affect the current data in the waterfall.
+               """
+               #get the peak level (max of the samples)
+               peak_level = numpy.max(self.samples)
+               #get the noise floor (averge the smallest samples)
+               noise_floor = 
numpy.average(numpy.sort(self.samples)[:len(self.samples)/2])
+               #padding
+               noise_floor -= abs(noise_floor)*.5
+               peak_level += abs(peak_level)*.1
+               #set the range and level
+               self.set_ref_level(noise_floor)
+               self.set_dynamic_range(peak_level - noise_floor)
+
+       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.
+               Send the data to the plotter.
+               @param msg the fft array as a character array
+               """
+               if not self[RUNNING_KEY]: return
+               #convert to floating point numbers
+               self.samples = 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]
+               else: samples = numpy.concatenate((samples[num_samps/2:], 
samples[:num_samps/2]))
+               #plot the fft
+               self.plotter.set_samples(
+                       samples=samples,
+                       minimum=self[REF_LEVEL_KEY], 
+                       maximum=self[DYNAMIC_RANGE_KEY] + self[REF_LEVEL_KEY],
+               )
+               #update the plotter
+               self.plotter.update()
+
+       def update_grid(self, *args):
+               """!
+               Update the plotter grid.
+               This update method is dependent on the variables below.
+               Determine the x and y axis grid parameters.
+               The x axis depends on sample rate, baseband freq, and x divs.
+               The y axis depends on y per div, y divs, and ref level.
+               """
+               #grid parameters
+               sample_rate = self.ext_controller[self.sample_rate_key]
+               frame_rate = self.ext_controller[self.frame_rate_key]
+               baseband_freq = self[BASEBAND_FREQ_KEY]
+               num_lines = self[NUM_LINES_KEY]
+               y_divs = self[Y_DIVS_KEY]
+               x_divs = self[X_DIVS_KEY]
+               #determine best fitting x_per_div
+               if self.real: x_width = sample_rate/2.0
+               else: x_width = sample_rate/1.0
+               x_per_div = common.get_clean_num(x_width/x_divs)
+               exp = common.get_exp(x_per_div)
+               #calculate units and scalar
+               if exp > 7: x_units, scalar = 'GHz', 1e-9
+               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:
+                       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,
+                       )
+               #update x units
+               self.plotter.set_x_label('Frequency', x_units)
+               #update y grid
+               duration = float(num_lines)/frame_rate
+               y_per_div = common.get_clean_num(duration/y_divs)
+               self.plotter.set_y_grid(0, duration, y_per_div)
+               #update y units
+               self.plotter.set_y_label('Time', 's')
+               #update plotter
+               self.plotter.update()

Copied: 
gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/waterfallsink_gl.py
 (from rev 9243, gnuradio/branches/features/experimental-gui/waterfallsink.py)
===================================================================
--- 
gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/waterfallsink_gl.py
                          (rev 0)
+++ 
gnuradio/branches/developers/jblum/glwxgui/gr-wxgui/src/python/waterfallsink_gl.py
  2008-08-12 00:17:37 UTC (rev 9244)
@@ -0,0 +1,126 @@
+#
+# 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 waterfall_window
+import common
+from gnuradio import gr, blks2
+from pubsub import pubsub
+from constants import *
+
+##################################################
+# Waterfall sink block (wrapper for old wxgui)
+##################################################
+class _waterfall_sink_base(gr.hier_block2, common.prop_setter):
+       """!
+       An fft block with real/complex inputs and a gui window.
+       """
+
+       def __init__(
+               self,
+               parent,
+               baseband_freq=0,
+               y_per_div=None, #ignore (old wrapper)
+               ref_level=50,
+               sample_rate=1,
+               fft_size=512,
+               fft_rate=waterfall_window.DEFAULT_FRAME_RATE,
+               average=False,
+               avg_alpha=None,
+               title='',
+               size=waterfall_window.DEFAULT_WIN_SIZE,
+               ref_scale=2.0,
+               dynamic_range=80,
+       ):
+               #ensure avg alpha
+               if avg_alpha is None: avg_alpha = 2.0/fft_rate
+               #init
+               gr.hier_block2.__init__(
+                       self,
+                       "waterfall_sink",
+                       gr.io_signature(1, 1, self._item_size),
+                       gr.io_signature(0, 0, 0),
+               )
+               #blocks
+               copy = gr.kludge_copy(self._item_size)
+               fft = self._fft_chain(
+                       sample_rate=sample_rate,
+                       fft_size=fft_size,
+                       frame_rate=fft_rate,
+                       ref_scale=ref_scale,
+                       avg_alpha=avg_alpha,
+                       average=average,
+               )
+               msgq = gr.msg_queue(2)
+               sink = gr.message_sink(gr.sizeof_float*fft_size, msgq, True)
+               #connect
+               self.connect(self, copy, fft, sink)
+               #controller
+               self.controller = pubsub()
+               self.controller.subscribe(AVERAGE_KEY, fft.set_average)
+               self.controller.publish(AVERAGE_KEY, fft.average)
+               self.controller.subscribe(AVG_ALPHA_KEY, fft.set_avg_alpha)
+               self.controller.publish(AVG_ALPHA_KEY, fft.avg_alpha)
+               self.controller.subscribe(SAMPLE_RATE_KEY, fft.set_sample_rate)
+               self.controller.publish(SAMPLE_RATE_KEY, fft.sample_rate)
+               self.controller.subscribe(DECIMATION_KEY, fft.set_decimation)
+               self.controller.publish(DECIMATION_KEY, fft.decimation)
+               self.controller.publish(FRAME_RATE_KEY, fft.frame_rate)
+               #start input watcher
+               def setter(p, k, x): # lambdas can't have assignments :(
+                   p[k] = x
+               common.input_watcher(msgq, lambda x: setter(self.controller, 
MSG_KEY, x))
+               #create window
+               self.win = waterfall_window.waterfall_window(
+                       parent=parent,
+                       controller=self.controller,
+                       size=size,
+                       title=title,
+                       real=self._real,
+                       fft_size=fft_size,
+                       baseband_freq=baseband_freq,
+                       decimation_key=DECIMATION_KEY,
+                       sample_rate_key=SAMPLE_RATE_KEY,
+                       frame_rate_key=FRAME_RATE_KEY,
+                       dynamic_range=dynamic_range,
+                       ref_level=ref_level,
+                       average_key=AVERAGE_KEY,
+                       avg_alpha_key=AVG_ALPHA_KEY,
+                       msg_key=MSG_KEY,
+               )
+               #register callbacks from window for external use
+               for attr in filter(lambda a: a.startswith('set_'), 
dir(self.win)):
+                       setattr(self, attr, getattr(self.win, attr))
+               self._register_set_prop(self.controller, SAMPLE_RATE_KEY)
+               self._register_set_prop(self.controller, AVERAGE_KEY)
+               self._register_set_prop(self.controller, AVG_ALPHA_KEY)
+
+class waterfall_sink_f(_waterfall_sink_base):
+       _fft_chain = blks2.logpwrfft_f
+       _item_size = gr.sizeof_float
+       _real = True
+
+class waterfall_sink_c(_waterfall_sink_base):
+       _fft_chain = blks2.logpwrfft_c
+       _item_size = gr.sizeof_gr_complex
+       _real = False





reply via email to

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