[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r8758 - gnuradio/branches/developers/jblum/gr-wxglgui/
From: |
jblum |
Subject: |
[Commit-gnuradio] r8758 - gnuradio/branches/developers/jblum/gr-wxglgui/src/python |
Date: |
Mon, 30 Jun 2008 18:28:47 -0600 (MDT) |
Author: jblum
Date: 2008-06-30 18:28:46 -0600 (Mon, 30 Jun 2008)
New Revision: 8758
Added:
gnuradio/branches/developers/jblum/gr-wxglgui/src/python/constsink.py
Modified:
gnuradio/branches/developers/jblum/gr-wxglgui/src/python/Makefile.am
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:
work on constsink, split fft block chain into fft + stream decimator for reuse
Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/Makefile.am
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/Makefile.am
2008-07-01 00:26:53 UTC (rev 8757)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/Makefile.am
2008-07-01 00:28:46 UTC (rev 8758)
@@ -33,5 +33,6 @@
gltext.py \
plotter.py \
common.py \
+ constsink.py \
fftsink.py \
scopesink.py
Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/common.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/common.py
2008-07-01 00:26:53 UTC (rev 8757)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/common.py
2008-07-01 00:28:46 UTC (rev 8758)
@@ -26,8 +26,49 @@
import wx
##################################################
-# FFT blocks chain: input -> message sink
+# Stream decimator chain
##################################################
+class stream_decimator(gr.hier_block2):
+ """!
+ Convert the stream to a vector, decimate the vector to achieve the
vector rate.
+ """
+
+ def __init__(self, item_size, sample_rate, vec_rate, vec_len):
+ """!
+ Create the block chain.
+ @param item_size the number of bytes per sample
+ @param sample_rate the rate of incoming samples
+ @param vec_rate the rate of outgoing vectors
+ @param vec_len the length of the outgoing vectors
+ """
+ self.vec_rate = vec_rate
+ self.vec_len = vec_len
+ #init
+ gr.hier_block2.__init__(
+ self,
+ "stream_decimator_block",
+ gr.io_signature(1, 1, item_size),
+ gr.io_signature(1, 1, item_size*vec_len),
+ )
+ #create blocks
+ s2v = gr.stream_to_vector(item_size, vec_len)
+ self.one_in_n = gr.keep_one_in_n(item_size * vec_len, 1)
+ #connect
+ self.connect(self, s2v, self.one_in_n, self)
+ #initial update
+ self.set_sample_rate(sample_rate)
+
+ def set_sample_rate(self, sample_rate):
+ """!
+ Set the new sampling rate and update the decimator.
+ @param sample_rate the new rate
+ """
+ self.sample_rate = sample_rate
+ self.one_in_n.set_n(max(1,
int(self.sample_rate/self.vec_len/self.vec_rate)))
+
+##################################################
+# FFT block chain
+##################################################
class _fft_chain_base(gr.hier_block2):
"""!
Create an fft block chain, with real/complex input.
@@ -38,22 +79,23 @@
def __init__(self, sample_rate, fft_size, frame_rate, ref_scale,
avg_alpha, average):
"""!
Create an fft block.
- Write the samples to a message sink.
- Provide access to the msg queue, setting the filter, and sample
rate.
+ Provide access to the setting the filter and sample rate.
@param sample_rate, fft_size, frame_rate, ref_scale, avg_alpha,
average the fft parameters
"""
- self.fft_size = fft_size
- self.frame_rate = frame_rate
#init
gr.hier_block2.__init__(
self,
"fft_block",
gr.io_signature(1, 1, self.item_size),
- gr.io_signature(0, 0, 0),
+ gr.io_signature(1, 1, gr.sizeof_float*fft_size),
)
#create blocks
- s2p = gr.stream_to_vector(self.item_size, fft_size)
- self.one_in_n = gr.keep_one_in_n(self.item_size * fft_size, 1)
+ self.sd = stream_decimator(
+ item_size=self.item_size,
+ sample_rate=sample_rate,
+ vec_rate=frame_rate,
+ vec_len=fft_size,
+ )
#create fft
fft_window = window.blackmanharris(fft_size)
fft = self.fft_block[0](fft_size, True, fft_window)
@@ -68,13 +110,11 @@
-10*math.log10(power/fft_size) # Adjust for windowing
loss
-20*math.log10(ref_scale/2) # Adjust for reference scale
)
- #message sink
- self.msgq = gr.msg_queue(2)
- sink = gr.message_sink(gr.sizeof_float*fft_size, self.msgq,
True)
#connect
- self.connect(self, s2p, self.one_in_n, fft, c2mag, self.avg,
log, sink)
+ self.connect(self, self.sd, fft, c2mag, self.avg, log, self)
+ #register
+ self.set_sample_rate = self.sd.set_sample_rate
#initial update
- self.set_sample_rate(sample_rate)
self.set_average(average)
self.set_avg_alpha(avg_alpha)
Added: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/constsink.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/constsink.py
(rev 0)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/constsink.py
2008-07-01 00:28:46 UTC (rev 8758)
@@ -0,0 +1,202 @@
+#
+# 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
+##################################################
+from gnuradio import gr
+import plotter
+import common
+import wx
+import numpy
+import time
+
+##################################################
+# Constants
+##################################################
+DEFAULT_FRAME_RATE = 30
+DEFAULT_WIN_SIZE = (400, 400)
+DEFAULT_CONST_SIZE = 1024
+CONST_PLOT_COLOR_SPEC = (0, 0, 1)
+
+##################################################
+# Constellation window control panel
+##################################################
+class control_panel(wx.Panel):
+ """!
+ A control panel with wx widgits to control the plotter.
+ """
+ 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.HORIZONTAL)
+
+ #begin control box
+ 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.EXPAND)
+ #end control box
+ control_box.AddSpacer(2)
+ #set sizer
+ self.SetSizerAndFit(control_box)
+ #update
+ self.update()
+
+ def update(self):
+ #update the run/stop button
+ if self.parent.running: self.run_button.SetLabel('Stop')
+ else: self.run_button.SetLabel('Run')
+
+ ##################################################
+ # Event handlers
+ ##################################################
+ def _on_run(self, event): self.parent.set_run(not self.parent.running)
+
+##################################################
+# Constellation window with plotter and control panel
+##################################################
+class const_window(wx.Panel):
+ def __init__(
+ self,
+ parent,
+ size,
+ title,
+ frame_rate,
+ sample_rate,
+ ):
+ #setup
+ self.running = True
+ self.sample_rate = sample_rate
+ self.x_divs = 8
+ self.x_per_div = 1
+ self.x_off = 0
+ self.y_divs = 8
+ self.y_per_div = 1
+ self.y_off = 0
+ #init panel and plot
+ wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
+ self.plotter = plotter.grid_plotter(self)
+ self.plotter.SetSize(wx.Size(*size))
+ self.plotter.set_title(title)
+ self.plotter.set_x_units('Inphase')
+ self.plotter.set_y_units('Quadrature')
+ #setup the box with plot and controls
+ self.control_panel = control_panel(self)
+ main_box = wx.BoxSizer(wx.VERTICAL)
+ main_box.Add(self.plotter, 1, wx.EXPAND)
+ main_box.Add(self.control_panel, 0, wx.EXPAND)
+ self.SetSizerAndFit(main_box)
+ #update
+ self.update()
+
+ def plot(self, samples):
+ """!
+ Plot the samples onto the complex grid.
+ @param samples the array of complex samples
+ """
+ if not self.running: return
+ real = numpy.real(samples)
+ imag = numpy.imag(samples)
+ samples = zip((real, imag))
+ self.plotter.set_waveform(
+ channel=0,
+ samples=samples,
+ color_spec=CONST_PLOT_COLOR_SPEC,
+ )
+
+ def update(self):
+ #update the grid
+ #update control panel and plotter
+ self.control_panel.update()
+ self.plotter.update()
+
+ ##################################################
+ # Set parameters on-the-fly
+ ##################################################
+ def set_run(self, running):
+ self.running = running
+ self.update()
+
+##################################################
+# Constellation sink block
+##################################################
+class const_sink_c(gr.hier_block2):
+ """!
+ A constellation block with a gui window.
+ """
+
+ def __init__(
+ self,
+ parent,
+ title='',
+ sample_rate=1,
+ size=DEFAULT_WIN_SIZE,
+ frame_rate=DEFAULT_FRAME_RATE,
+ const_size=DEFAULT_CONST_SIZE,
+ ):
+ #init
+ gr.hier_block2.__init__(
+ self,
+ "const_sink",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex),
+ gr.io_signature(0, 0, 0),
+ )
+ #blocks
+ sd = common.stream_decimator(
+ item_size=gr.sizeof_gr_complex,
+ sample_rate=sample_rate,
+ vec_rate=frame_rate,
+ vec_len=const_size,
+ )
+ msgq = gr.msg_queue(2)
+ sink = gr.message_sink(gr.sizeof_gr_complex*const_size, msgq,
True)
+ #connect
+ self.connect(self, sd, sink)
+ #create window
+ self.win = const_window(
+ parent=parent,
+ size=size,
+ title=title,
+ frame_rate=frame_rate,
+ sample_rate=sample_rate,
+ )
+ #register callbacks from window for external use
+ self.set_sample_rate = sd.set_sample_rate
+ #setup the input watcher
+ common.input_watcher(msgq, self._handle_msg)
+
+ def _handle_msg(self, msg):
+ 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 complex floating point numbers
+ samples = numpy.fromstring(s, numpy.complex64)
+ self.win.plot(samples)
Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py
2008-07-01 00:26:53 UTC (rev 8757)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py
2008-07-01 00:28:46 UTC (rev 8758)
@@ -26,7 +26,6 @@
import plotter
import common
import wx
-import math
import numpy
##################################################
@@ -52,7 +51,7 @@
@param parent the wx parent window
"""
self.parent = parent
- wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
+ wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
control_box = wx.BoxSizer(wx.VERTICAL)
#checkboxes for average and peak hold
@@ -156,7 +155,7 @@
self.fft_set_sample_rate = set_sample_rate
self.peak_vals = []
#init panel and plot
- wx.Panel.__init__(self, parent, -1)
+ wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
self.plotter = plotter.grid_plotter(self)
self.plotter.SetSize(wx.Size(*size))
self.plotter.set_title(title)
@@ -228,9 +227,8 @@
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
+ #update control panel and plotter
self.control_panel.update()
- #update the plotter
self.plotter.update()
##################################################
@@ -291,8 +289,8 @@
gr.io_signature(1, 1, self.item_size),
gr.io_signature(0, 0, 0),
)
+ #blocks
copy = gr.kludge_copy(self.item_size)
- #fft block
fft = self.fft_chain(
sample_rate=sample_rate,
fft_size=fft_size,
@@ -301,8 +299,10 @@
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)
+ self.connect(self, copy, fft, sink)
#create window
self.win = fft_window(
parent=parent,
@@ -328,7 +328,7 @@
self.set_avg_alpha = fft.set_avg_alpha
self.set_sample_rate = self.win.set_sample_rate
#setup the input watcher
- common.input_watcher(fft.msgq, self._handle_msg)
+ common.input_watcher(msgq, self._handle_msg)
def _handle_msg(self, msg):
"""!
Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py
2008-07-01 00:26:53 UTC (rev 8757)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py
2008-07-01 00:28:46 UTC (rev 8758)
@@ -26,6 +26,7 @@
from OpenGL.GLU import *
from OpenGL.GL import *
+import threading
import gltext
import common
import math
@@ -38,7 +39,7 @@
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
+PADDING = 35, 15, 40, 60 #top, right, bottom, left
class _plotter_base(wx.glcanvas.GLCanvas):
"""!
@@ -68,7 +69,7 @@
"""!
Respond to paint events, call update.
Initialize GL if this is the first paint event.
- """
+ """
self.SetCurrent()
#check if gl was initialized
if not self._gl_init_flag:
@@ -97,7 +98,8 @@
def __init__(self, parent):
"""!
Create a new grid plotter.
- """
+ """
+ self.semaphore = threading.Semaphore(1)
self.grid_compiled_list_id = wx.NewId()
self.channels = dict()
#store title and unit strings
@@ -117,32 +119,40 @@
Set the legend on/off.
@param legend true to turn on
"""
+ self.semaphore.acquire(True)
self.legend = legend
- self._changed = True
+ self._changed = True
+ self.semaphore.release()
def set_title(self, title):
"""!
Set the title.
@param title the title string
"""
+ self.semaphore.acquire(True)
self.title = title
self._changed = True
+ self.semaphore.release()
def set_x_units(self, x_units):
"""!
Set the x_units.
@param x_units the x_units string
"""
+ self.semaphore.acquire(True)
self.x_units = x_units
self._changed = True
+ self.semaphore.release()
def set_y_units(self, y_units):
"""!
Set the y_units.
@param y_units the y_units string
"""
+ self.semaphore.acquire(True)
self.y_units = y_units
self._changed = True
+ self.semaphore.release()
def set_x_grid(self, x_min, x_max, x_step):
"""!
@@ -151,10 +161,12 @@
@param x_max the right-most value
@param x_step the grid spacing
"""
+ self.semaphore.acquire(True)
self.x_min = float(x_min)
self.x_max = float(x_max)
self.x_step = float(x_step)
self._changed = True
+ self.semaphore.release()
def set_y_grid(self, y_min, y_max, y_step):
"""!
@@ -163,15 +175,18 @@
@param y_max the top-most value
@param y_step the grid spacing
"""
+ self.semaphore.acquire(True)
self.y_min = float(y_min)
self.y_max = float(y_max)
self.y_step = float(y_step)
self._changed = True
+ self.semaphore.release()
def draw(self):
"""!
Draw the grid and waveforms.
"""
+ self.semaphore.acquire(True)
self.clear()
#store the grid drawing operations
if self._changed:
@@ -184,6 +199,7 @@
glCallList(self.grid_compiled_list_id)
glFlush()
self.SwapBuffers()
+ self.semaphore.release()
def _draw_waveforms(self):
"""!
@@ -233,17 +249,6 @@
glEnd()
##################################################
- # Draw Outter Border
- ##################################################
- glColor3f(*GRID_LINE_COLOR_SPEC)
- glBegin(GL_LINE_LOOP)
- glVertex3f(1, 1, 0)
- glVertex3f(self.width, 1, 0)
- glVertex3f(self.width, self.height, 0)
- glVertex3f(1, self.height, 0)
- glEnd()
-
- ##################################################
# Draw Grid X
##################################################
for tick in self._get_ticks(self.x_min, self.x_max,
self.x_step):
@@ -285,10 +290,18 @@
font.SetWeight(wx.FONTWEIGHT_BOLD)
#draw x units
txt = gltext.Text(self.x_units, font=font,
font_size=UNITS_TEXT_FONT_SIZE, centered=True)
- txt.draw_text(wx.Point(self.width/2.0,
self.height-.25*self.padding_bottom))
+ txt.draw_text(wx.Point(
+
(self.width-self.padding_left-self.padding_right)/2.0 + self.padding_left,
+ self.height-.25*self.padding_bottom,
+ )
+ )
#draw y units
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)
+ txt.draw_text(wx.Point(
+ .25*self.padding_left,
+
(self.height-self.padding_top-self.padding_bottom)/2.0 + self.padding_top,
+ ), rotation=90,
+ )
##################################################
# Draw Legend
Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/scopesink.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/scopesink.py
2008-07-01 00:26:53 UTC (rev 8757)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/scopesink.py
2008-07-01 00:28:46 UTC (rev 8758)
@@ -26,10 +26,8 @@
import plotter
import common
import wx
-import math
import numpy
import time
-import mutex
##################################################
# Constants
@@ -73,7 +71,7 @@
@param parent the wx parent window
"""
self.parent = parent
- wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
+ wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
control_box = wx.BoxSizer(wx.VERTICAL)
#begin control box
@@ -235,7 +233,6 @@
#check num inputs
assert num_inputs <= len(CHANNEL_COLOR_SPECS)
#setup
- self.mutex = mutex.mutex()
self.running = True
self.num_inputs = num_inputs
self.sample_rate = sample_rate
@@ -262,7 +259,7 @@
self.frame_counter = 0
self._init = False #HACK
#init panel and plot
- wx.Panel.__init__(self, parent, -1)
+ wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
self.plotter = plotter.grid_plotter(self)
self.plotter.SetSize(wx.Size(*size))
self.plotter.set_title(title)
@@ -322,8 +319,7 @@
self.plotter.update()
self.frame_counter = (self.frame_counter + 1)%self.decim
- def update(self): self.mutex.lock(self._update, None)
- def _update(self, arg=None):
+ def update(self):
#update the frame decimation
self.decim = max(1,
int(self.sample_rate/self.scope.get_samples_per_output_record()/self.frame_rate))
#update the scope
@@ -353,8 +349,6 @@
#update control panel and plotter
self.control_panel.update()
self.plotter.update()
- #unlock mutex
- self.mutex.unlock()
##################################################
# Set parameters on-the-fly
@@ -417,8 +411,7 @@
t_scale=None,
num_inputs=1,
ac_couple=False,
- ):
- self.num_inputs = num_inputs
+ ):
#init
gr.hier_block2.__init__(
self,
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r8758 - gnuradio/branches/developers/jblum/gr-wxglgui/src/python,
jblum <=