[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r8979 - in gnuradio/branches/features/experimental-gui
From: |
jblum |
Subject: |
[Commit-gnuradio] r8979 - in gnuradio/branches/features/experimental-gui: . plotter |
Date: |
Tue, 22 Jul 2008 16:39:50 -0600 (MDT) |
Author: jblum
Date: 2008-07-22 16:39:49 -0600 (Tue, 22 Jul 2008)
New Revision: 8979
Added:
gnuradio/branches/features/experimental-gui/grc_waterfallsink_test.py
gnuradio/branches/features/experimental-gui/waterfall_window.py
gnuradio/branches/features/experimental-gui/waterfallsink.py
Modified:
gnuradio/branches/features/experimental-gui/plotter/channel_plotter.py
gnuradio/branches/features/experimental-gui/plotter/plotter_base.py
gnuradio/branches/features/experimental-gui/plotter/waterfall_plotter.py
Log:
waterfallsink working
Added: gnuradio/branches/features/experimental-gui/grc_waterfallsink_test.py
===================================================================
--- gnuradio/branches/features/experimental-gui/grc_waterfallsink_test.py
(rev 0)
+++ gnuradio/branches/features/experimental-gui/grc_waterfallsink_test.py
2008-07-22 22:39:49 UTC (rev 8979)
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: untitled
+# Author: unknown
+# Description: gnuradio flow graph
+# Generated: Mon Jul 21 13:34:59 2008
+##################################################
+
+from gnuradio import blks2
+from gnuradio import gr
+from gnuradio.gr import firdes
+import waterfallsink
+from grc_gnuradio import wxgui as grc_wxgui
+import numpy
+import wx
+
+const = 1, -1j, -1, 1j
+freq_off = 0
+noise = .1
+samp_rate = 25e3
+samples_per_symbol = 4
+
+class waterfall_test(grc_wxgui.top_block_gui):
+
+ def __init__(self, const=const, freq_off=freq_off, noise=noise,
samp_rate=samp_rate, samples_per_symbol=samples_per_symbol):
+ grc_wxgui.top_block_gui.__init__(
+ self,
+ title="GRC - Executing: untitled",
+
icon="/usr/local/lib/python2.5/site-packages/grc/data/grc-icon-32.png",
+ )
+
+ ##################################################
+ # Variables
+ ##################################################
+ self.const = const
+ self.freq_off = freq_off
+ _freq_off_control = grc_wxgui.slider_horizontal_control(
+ window=self.GetWin(),
+ callback=self.set_freq_off,
+ label="Frequency Offset",
+ value=freq_off,
+ min=-samp_rate/2,
+ max=samp_rate/2,
+ num_steps=100,
+ )
+ self.Add(_freq_off_control)
+ self.noise = noise
+ _noise_control = grc_wxgui.slider_horizontal_control(
+ window=self.GetWin(),
+ callback=self.set_noise,
+ label="Noise Voltage",
+ value=noise,
+ min=0,
+ max=2,
+ num_steps=100,
+ )
+ self.Add(_noise_control)
+ self.samp_rate = samp_rate
+ self.samples_per_symbol = samples_per_symbol
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.blks2_channel_model = blks2.channel_model(
+ noise_voltage=noise,
+ frequency_offset=freq_off/samp_rate,
+ epsilon=1.0,
+ taps=(1, ),
+ noise_seed=42,
+ )
+ self.gr_chunks_to_symbols_xx = gr.chunks_to_symbols_bc((const),
1)
+ self.gr_fir_filter_xxx = gr.fir_filter_ccc(1,
([1]*samples_per_symbol))
+ self.gr_repeat = gr.repeat(gr.sizeof_gr_complex*1,
samples_per_symbol)
+ self.gr_throttle = gr.throttle(gr.sizeof_gr_complex*1,
samp_rate)
+ self.random_source_x =
gr.vector_source_b(numpy.random.randint(0, 4, 1000), True)
+ self.wxgui_fftsink2 = waterfallsink.waterfall_sink_c(
+ self.GetWin(),
+ baseband_freq=0,
+ y_per_div=5,
+ y_divs=8,
+ ref_level=-20,
+ sample_rate=samp_rate,
+ fft_size=512,
+ frame_rate=30,
+ average=False,
+ avg_alpha=None,
+ title="Waterfall Plot",
+ )
+ self.Add(self.wxgui_fftsink2.win)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.random_source_x, 0),
(self.gr_chunks_to_symbols_xx, 0))
+ self.connect((self.gr_chunks_to_symbols_xx, 0),
(self.gr_throttle, 0))
+ self.connect((self.gr_throttle, 0), (self.gr_repeat, 0))
+ self.connect((self.gr_repeat, 0), (self.gr_fir_filter_xxx, 0))
+ self.connect((self.gr_fir_filter_xxx, 0),
(self.blks2_channel_model, 0))
+ self.connect((self.blks2_channel_model, 0),
(self.wxgui_fftsink2, 0))
+
+ def set_const(self, const):
+ self.const = const
+
+ def set_freq_off(self, freq_off):
+ self.freq_off = freq_off
+
self.blks2_channel_model.set_frequency_offset(self.freq_off/self.samp_rate)
+
+ def set_noise(self, noise):
+ self.noise = noise
+ self.blks2_channel_model.set_noise_voltage(self.noise)
+
+ def set_samp_rate(self, samp_rate):
+ self.samp_rate = samp_rate
+
self.blks2_channel_model.set_frequency_offset(self.freq_off/self.samp_rate)
+
+ def set_samples_per_symbol(self, samples_per_symbol):
+ self.samples_per_symbol = samples_per_symbol
+ self.gr_fir_filter_xxx.set_taps(([1]*self.samples_per_symbol))
+
+if __name__ == '__main__':
+ tb = waterfall_test()
+ tb.Run()
+
Property changes on:
gnuradio/branches/features/experimental-gui/grc_waterfallsink_test.py
___________________________________________________________________
Name: svn:executable
+ *
Modified: gnuradio/branches/features/experimental-gui/plotter/channel_plotter.py
===================================================================
--- gnuradio/branches/features/experimental-gui/plotter/channel_plotter.py
2008-07-22 18:23:25 UTC (rev 8978)
+++ gnuradio/branches/features/experimental-gui/plotter/channel_plotter.py
2008-07-22 22:39:49 UTC (rev 8979)
@@ -48,7 +48,7 @@
Run gl initialization tasks.
"""
glEnableClientState(GL_VERTEX_ARRAY)
- self.grid_compiled_list_id = glGenLists(1)
+ self._grid_compiled_list_id = glGenLists(1)
def set_legend(self, legend):
"""!
@@ -68,13 +68,13 @@
self.clear()
#store the grid drawing operations
if self.changed():
- glNewList(self.grid_compiled_list_id, GL_COMPILE)
+ glNewList(self._grid_compiled_list_id, GL_COMPILE)
self._draw_grid()
self._draw_legend()
glEndList()
self.changed(False)
#draw the grid
- glCallList(self.grid_compiled_list_id)
+ glCallList(self._grid_compiled_list_id)
#use scissor to prevent drawing outside grid
glEnable(GL_SCISSOR_TEST)
glScissor(
Modified: gnuradio/branches/features/experimental-gui/plotter/plotter_base.py
===================================================================
--- gnuradio/branches/features/experimental-gui/plotter/plotter_base.py
2008-07-22 18:23:25 UTC (rev 8978)
+++ gnuradio/branches/features/experimental-gui/plotter/plotter_base.py
2008-07-22 22:39:49 UTC (rev 8979)
@@ -46,6 +46,7 @@
Initialize GL and register events.
@param parent the parent widgit
"""
+ self.semaphore = threading.Semaphore(1)
wx.glcanvas.GLCanvas.__init__(self, parent, -1)
self.changed(False)
self._gl_init_flag = False
@@ -73,13 +74,18 @@
self._gl_init_flag = True
#check for a change in window size
if self._resized_flag:
+ self.semaphore.acquire(True)
self.width, self.height = self.GetSize()
glViewport(0, 0, self.width, self.height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, self.width, self.height, 0, 1, 0)
+ glMatrixMode(GL_MODELVIEW)
+ glLoadIdentity()
+ glViewport(0, 0, self.width, self.height)
self._resized_flag = False
self.changed(True)
+ self.semaphore.release()
self.draw()
def update(self): wx.PostEvent(self, wx.PaintEvent())
@@ -100,7 +106,7 @@
class grid_plotter_base(_plotter_base):
def __init__(self, parent, padding):
- self.semaphore = threading.Semaphore(1)
+ _plotter_base.__init__(self, parent)
self.padding_top, self.padding_right, self.padding_bottom,
self.padding_left = padding
#store title and unit strings
self.set_title('Title')
@@ -109,7 +115,6 @@
#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):
"""!
Modified:
gnuradio/branches/features/experimental-gui/plotter/waterfall_plotter.py
===================================================================
--- gnuradio/branches/features/experimental-gui/plotter/waterfall_plotter.py
2008-07-22 18:23:25 UTC (rev 8978)
+++ gnuradio/branches/features/experimental-gui/plotter/waterfall_plotter.py
2008-07-22 22:39:49 UTC (rev 8979)
@@ -25,7 +25,7 @@
import numpy
import gltext
-PADDING = 35, 35, 40, 60 #top, right, bottom, left
+PADDING = 35, 60, 40, 60 #top, right, bottom, left
##################################################
# Waterfall Plotter
@@ -37,13 +37,18 @@
"""
#init
grid_plotter_base.__init__(self, parent, PADDING)
+ self._fft_size = None #must be None on init
+ self._num_frames = 256
+ self._frame_ptr = 0
+ self._waterfall_buffer_bottom = GLuint(0)
+ self._waterfall_buffer_top = GLuint(0)
def _gl_init(self):
"""!
Run gl initialization tasks.
"""
- self.grid_compiled_list_id = glGenLists(1)
-
+ self._grid_compiled_list_id = glGenLists(1)
+
def draw(self):
"""!
Draw the grid and waveforms.
@@ -51,15 +56,112 @@
self.semaphore.acquire(True)
self.clear()
#store the grid drawing operations
- if self._changed:
- glNewList(self.grid_compiled_list_id, GL_COMPILE)
+ if self.changed():
+ glNewList(self._grid_compiled_list_id, GL_COMPILE)
self._draw_grid()
glEndList()
- self._changed = False
+ self.changed(False)
#draw the grid
- glCallList(self.grid_compiled_list_id)
+ glCallList(self._grid_compiled_list_id)
+ #use scissor to prevent drawing outside grid
+ glEnable(GL_SCISSOR_TEST)
+ glScissor(
+ self.padding_left+1,
+ self.padding_bottom+1,
+ self.width-self.padding_left-self.padding_right-1,
+ self.height-self.padding_top-self.padding_bottom-1,
+ )
#draw the waterfall
- #TODO
+ self._draw_waterfall()
+ glDisable(GL_SCISSOR_TEST)
#swap buffer into display
self.SwapBuffers()
self.semaphore.release()
+
+ def _draw_waterfall(self):
+ """!
+ Draw the waterfall display using pixels from the PBO.
+ The pixels will be scaled to fit within the grid area.
+ """
+ if self._fft_size is None: return
+ #pixel zoom
+ x_zoom =
float(self.width-self.padding_left-self.padding_right)/self._fft_size
+ y_zoom =
float(self.height-self.padding_top-self.padding_bottom+1)/self._num_frames
+ glRasterPos2f(self.padding_left+1,
self.padding_top+((self._num_frames-self._frame_ptr)*y_zoom)-1)
+ #draw top portion
+ glPixelZoom(x_zoom, y_zoom)
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, self._waterfall_buffer_top)
+ glDrawPixels(self._fft_size, self._num_frames-self._frame_ptr,
GL_RGBA, GL_UNSIGNED_BYTE, None)
+ #draw bottom portion
+ glPixelZoom(x_zoom, -y_zoom)
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER,
self._waterfall_buffer_bottom)
+ glDrawPixels(self._fft_size, self._frame_ptr, GL_RGBA,
GL_UNSIGNED_BYTE, None)
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) #unbind
+
+ def _to_rgba(self, sample):
+ """!
+ Convert the sample into rgba color data.
+ @param sample a normalized floating point sample
+ @return a color array rgba with component values between 0 and 1
+ """
+ if sample < 0.5:
+ colors = (0, 2*sample, 1 - 2*sample, 0)
+ else:
+ colors = (2*sample - 1, 2 - 2*sample, 0, 0)
+ #color data
+ return numpy.array(colors, numpy.float32)
+
+ def plot_samples(self, samples, min, max):
+ """!
+ Plot the samples onto a time slice of the waterfall.
+ Create or recreate the PBO when the fft size or number of
frames changes.
+ Convert the samples to color data.
+ @param samples the array of floats
+ @param min the minimum value to scale
+ @param max the maximum value to scale
+ """
+ self.semaphore.acquire(True)
+ #init or reinit the pixel buffer
+ if len(samples) != self._fft_size:
+ if self._fft_size is not None:
+ glDeleteBuffers(1, self._waterfall_buffer_top)
+ glDeleteBuffers(1,
self._waterfall_buffer_bottom)
+ self._fft_size = len(samples)
+ glGenBuffers(1, self._waterfall_buffer_top)
+ glGenBuffers(1, self._waterfall_buffer_bottom)
+ #initial data
+ data = (chr(0) + chr(0) + chr(0) + chr(0)) *
self._fft_size*self._num_frames
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER,
self._waterfall_buffer_top)
+ glBufferData(
+ GL_PIXEL_UNPACK_BUFFER,
+ len(data), data,
+ GL_DYNAMIC_DRAW,
+ )
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER,
self._waterfall_buffer_bottom)
+ glBufferData(
+ GL_PIXEL_UNPACK_BUFFER,
+ len(data), data,
+ GL_DYNAMIC_DRAW,
+ )
+ #normalize the samples to min/max
+ samples = (samples - min)/(max-min)
+ samples = numpy.minimum(samples, 1)
+ samples = numpy.maximum(samples, 0)
+ data = numpy.array(255*numpy.concatenate(map(self._to_rgba,
samples)), numpy.uint8).tostring()
+ #load the color data into the pixel buffers
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, self._waterfall_buffer_top)
+ glBufferSubData(
+ GL_PIXEL_UNPACK_BUFFER,
+ (self._num_frames-self._frame_ptr-1)*self._fft_size*4,
+ len(data), data,
+ )
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER,
self._waterfall_buffer_bottom)
+ glBufferSubData(
+ GL_PIXEL_UNPACK_BUFFER,
+ self._frame_ptr*self._fft_size*4,
+ len(data), data,
+ )
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0) #unbind
+ #increment the pointer
+ self._frame_ptr = (self._frame_ptr + 1)%self._num_frames
+ self.semaphore.release()
Copied: gnuradio/branches/features/experimental-gui/waterfall_window.py (from
rev 8963, gnuradio/branches/features/experimental-gui/fft_window.py)
===================================================================
--- gnuradio/branches/features/experimental-gui/waterfall_window.py
(rev 0)
+++ gnuradio/branches/features/experimental-gui/waterfall_window.py
2008-07-22 22:39:49 UTC (rev 8979)
@@ -0,0 +1,244 @@
+#
+# 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 prop_val
+
+##################################################
+# Constants
+##################################################
+SLIDER_STEPS = 100
+AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP = -3, 0
+DEFAULT_FRAME_RATE = 30
+DEFAULT_WIN_SIZE = (600, 300)
+DIV_LEVELS = (1, 2, 5, 10, 20)
+Y_PER_DIV_KEY = 'y_per_div'
+Y_DIVS_KEY = 'y_divs'
+X_DIVS_KEY = 'x_divs'
+REF_LEVEL_KEY = 'ref_level'
+BASEBAND_FREQ_KEY = 'baseband_freq'
+RUNNING_KEY = 'running'
+
+##################################################
+# 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)
+ #checkboxes for average
+ control_box.AddStretchSpacer()
+ control_box.Add(common.LabelText(self, 'Options'), 0,
wx.ALIGN_CENTER)
+ 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.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
+ control_box.AddStretchSpacer()
+ 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:
+ radio_button = wx.RadioButton(self, -1, "%d
dB/div"%y_per_div)
+ radio_button.Bind(wx.EVT_RADIOBUTTON,
self._on_y_per_div)
+ self.radio_buttons.append(radio_button)
+ radio_box.Add(radio_button, 0, wx.ALIGN_LEFT)
+ parent.controller.add_listener(Y_PER_DIV_KEY,
self._on_set_y_per_div)
+ control_box.Add(radio_box, 0, wx.EXPAND)
+ #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)
+ #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)
+
+ ##################################################
+ # Event handlers
+ ##################################################
+ def _on_set_y_per_div(self, y_per_div):
+ try:
+ index = list(DIV_LEVELS).index(y_per_div)
+ self.radio_buttons[index].SetValue(True)
+ except: pass
+ def _on_y_per_div(self, event):
+ selected_radio_button = filter(lambda rb: rb.GetValue(),
self.radio_buttons)[0]
+ index = self.radio_buttons.index(selected_radio_button)
+ self.parent.controller[Y_PER_DIV_KEY] = DIV_LEVELS[index]
+ def _on_incr_ref_level(self, event):
+ self.parent.set_ref_level(
+ self.parent.controller[REF_LEVEL_KEY] +
self.parent.controller[Y_PER_DIV_KEY])
+ def _on_decr_ref_level(self, event):
+ self.parent.set_ref_level(
+ self.parent.controller[REF_LEVEL_KEY] -
self.parent.controller[Y_PER_DIV_KEY])
+
+##################################################
+# Waterfall window with plotter and control panel
+##################################################
+class waterfall_window(wx.Panel, common.prop_setter):
+ def __init__(
+ self,
+ parent,
+ controller,
+ size,
+ title,
+ real,
+ fft_size,
+ baseband_freq,
+ sample_rate_key,
+ y_per_div,
+ y_divs,
+ ref_level,
+ average_key,
+ avg_alpha_key,
+ msg_key,
+ ):
+ self.controller = prop_val.prop_val_interface()
+ #ensure y_per_div
+ if y_per_div not in DIV_LEVELS: y_per_div = DIV_LEVELS[0]
+ #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
+ #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)
+ #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.controller, Y_PER_DIV_KEY,
y_per_div)
+ self._register_set_prop(self.controller, Y_DIVS_KEY, y_divs)
+ self._register_set_prop(self.controller, X_DIVS_KEY, 8)
#approximate
+ self._register_set_prop(self.controller, REF_LEVEL_KEY,
ref_level)
+ self._register_set_prop(self.controller, BASEBAND_FREQ_KEY,
baseband_freq)
+ self._register_set_prop(self.controller, RUNNING_KEY, True)
+ #register events
+ self.ext_controller.add_listener(msg_key, self.handle_msg)
+ self.ext_controller.add_listener(self.sample_rate_key,
self.update_grid)
+ self.controller.add_listener(BASEBAND_FREQ_KEY,
self.update_grid)
+ self.controller.add_listener(X_DIVS_KEY, self.update_grid)
+ #initial update
+ self.update_grid()
+
+ 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.controller[RUNNING_KEY]: return
+ #convert to floating point numbers
+ 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+1:],
samples[:num_samps/2]))
+ #plot the fft
+ self.plotter.plot_samples(
+ samples, self.controller[REF_LEVEL_KEY],
+
self.controller[Y_PER_DIV_KEY]*self.controller[Y_DIVS_KEY] +
self.controller[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]
+ baseband_freq = self.controller[BASEBAND_FREQ_KEY]
+ x_divs = self.controller[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_units('Frequency (%s)'%x_units)
+ #update y grid
+ self.plotter.set_y_grid(0, 10, 1)
+ #update y units
+ self.plotter.set_y_units('Time (s)')
+ #update plotter
+ self.plotter.update()
Copied: gnuradio/branches/features/experimental-gui/waterfallsink.py (from rev
8962, gnuradio/branches/features/experimental-gui/fftsink.py)
===================================================================
--- gnuradio/branches/features/experimental-gui/waterfallsink.py
(rev 0)
+++ gnuradio/branches/features/experimental-gui/waterfallsink.py
2008-07-22 22:39:49 UTC (rev 8979)
@@ -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 prop_val import prop_val_interface
+
+##################################################
+# Constants
+##################################################
+SAMPLE_RATE_KEY = 'sample_rate'
+AVERAGE_KEY = 'average'
+AVG_ALPHA_KEY = 'avg_alpha'
+MSG_KEY = 'msg'
+
+##################################################
+# 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,
+ ref_scale=2.0,
+ y_per_div=10,
+ y_divs=8,
+ ref_level=50,
+ sample_rate=1,
+ fft_size=512,
+ frame_rate=waterfall_window.DEFAULT_FRAME_RATE,
+ average=False,
+ avg_alpha=None,
+ title='',
+ size=waterfall_window.DEFAULT_WIN_SIZE,
+ ):
+ #ensure avg alpha
+ if avg_alpha is None: avg_alpha = 2.0/frame_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=frame_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 = prop_val_interface()
+ self.controller.add_listener(AVERAGE_KEY, fft.set_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, fft.avg_alpha)
+ self.controller.add_listener(SAMPLE_RATE_KEY,
fft.set_sample_rate)
+ 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
+ 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,
+ sample_rate_key=SAMPLE_RATE_KEY,
+ y_per_div=y_per_div,
+ y_divs=y_divs,
+ 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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r8979 - in gnuradio/branches/features/experimental-gui: . plotter,
jblum <=