summaryrefslogtreecommitdiff
path: root/gr-wxgui/src/python
diff options
context:
space:
mode:
Diffstat (limited to 'gr-wxgui/src/python')
-rw-r--r--gr-wxgui/src/python/Makefile.am7
-rwxr-xr-xgr-wxgui/src/python/fftsink.py488
-rwxr-xr-xgr-wxgui/src/python/numbersink.py614
-rwxr-xr-xgr-wxgui/src/python/scopesink.py650
-rw-r--r--gr-wxgui/src/python/stdgui.py90
-rwxr-xr-xgr-wxgui/src/python/waterfallsink.py475
6 files changed, 1 insertions, 2323 deletions
diff --git a/gr-wxgui/src/python/Makefile.am b/gr-wxgui/src/python/Makefile.am
index f466db163..bda7c362c 100644
--- a/gr-wxgui/src/python/Makefile.am
+++ b/gr-wxgui/src/python/Makefile.am
@@ -1,5 +1,5 @@
#
-# Copyright 2004,2005 Free Software Foundation, Inc.
+# Copyright 2004,2005,2008 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -31,16 +31,11 @@ ourlibdir = $(grpyexecdir)/wxgui
ourpython_PYTHON = \
__init__.py \
form.py \
- fftsink.py \
fftsink2.py \
plot.py \
powermate.py \
- scopesink.py \
scopesink2.py \
- waterfallsink.py \
waterfallsink2.py \
slider.py \
- stdgui.py \
stdgui2.py \
- numbersink.py \
numbersink2.py
diff --git a/gr-wxgui/src/python/fftsink.py b/gr-wxgui/src/python/fftsink.py
deleted file mode 100755
index 85e3a1f9e..000000000
--- a/gr-wxgui/src/python/fftsink.py
+++ /dev/null
@@ -1,488 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2003,2004,2005,2006,2007 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.
-#
-
-from gnuradio import gr, gru, window
-from gnuradio.wxgui import stdgui
-import wx
-import gnuradio.wxgui.plot as plot
-import numpy
-import threading
-import math
-
-default_fftsink_size = (640,240)
-default_fft_rate = gr.prefs().get_long('wxgui', 'fft_rate', 15)
-
-class fft_sink_base(object):
- def __init__(self, input_is_real=False, baseband_freq=0, y_per_div=10, ref_level=50,
- sample_rate=1, fft_size=512,
- fft_rate=default_fft_rate,
- average=False, avg_alpha=None, title='', peak_hold=False):
-
- # initialize common attributes
- self.baseband_freq = baseband_freq
- self.y_divs = 8
- self.y_per_div=y_per_div
- self.ref_level = ref_level
- self.sample_rate = sample_rate
- self.fft_size = fft_size
- self.fft_rate = fft_rate
- self.average = average
- if avg_alpha is None:
- self.avg_alpha = 2.0 / fft_rate
- else:
- self.avg_alpha = avg_alpha
- self.title = title
- self.peak_hold = peak_hold
- self.input_is_real = input_is_real
- self.msgq = gr.msg_queue(2) # queue that holds a maximum of 2 messages
-
- def set_y_per_div(self, y_per_div):
- self.y_per_div = y_per_div
-
- def set_ref_level(self, ref_level):
- self.ref_level = ref_level
-
- def set_average(self, average):
- self.average = average
- if average:
- self.avg.set_taps(self.avg_alpha)
- self.set_peak_hold(False)
- else:
- self.avg.set_taps(1.0)
-
- def set_peak_hold(self, enable):
- self.peak_hold = enable
- if enable:
- self.set_average(False)
- self.win.set_peak_hold(enable)
-
- def set_avg_alpha(self, avg_alpha):
- self.avg_alpha = avg_alpha
-
- def set_baseband_freq(self, baseband_freq):
- self.baseband_freq = baseband_freq
-
- def set_sample_rate(self, sample_rate):
- self.sample_rate = sample_rate
- self._set_n()
-
- def _set_n(self):
- self.one_in_n.set_n(max(1, int(self.sample_rate/self.fft_size/self.fft_rate)))
-
-
-class fft_sink_f(gr.hier_block, fft_sink_base):
- def __init__(self, fg, parent, baseband_freq=0,
- y_per_div=10, ref_level=50, sample_rate=1, fft_size=512,
- fft_rate=default_fft_rate, average=False, avg_alpha=None,
- title='', size=default_fftsink_size, peak_hold=False):
-
- fft_sink_base.__init__(self, input_is_real=True, baseband_freq=baseband_freq,
- y_per_div=y_per_div, ref_level=ref_level,
- sample_rate=sample_rate, fft_size=fft_size,
- fft_rate=fft_rate,
- average=average, avg_alpha=avg_alpha, title=title,
- peak_hold=peak_hold)
-
- s2p = gr.stream_to_vector(gr.sizeof_float, self.fft_size)
- self.one_in_n = gr.keep_one_in_n(gr.sizeof_float * self.fft_size,
- max(1, int(self.sample_rate/self.fft_size/self.fft_rate)))
-
- mywindow = window.blackmanharris(self.fft_size)
- fft = gr.fft_vfc(self.fft_size, True, mywindow)
- power = 0
- for tap in mywindow:
- power += tap*tap
-
- c2mag = gr.complex_to_mag(self.fft_size)
- self.avg = gr.single_pole_iir_filter_ff(1.0, self.fft_size)
-
- # FIXME We need to add 3dB to all bins but the DC bin
- log = gr.nlog10_ff(20, self.fft_size,
- -20*math.log10(self.fft_size)-10*math.log10(power/self.fft_size))
- sink = gr.message_sink(gr.sizeof_float * self.fft_size, self.msgq, True)
-
- fg.connect (s2p, self.one_in_n, fft, c2mag, self.avg, log, sink)
- gr.hier_block.__init__(self, fg, s2p, sink)
-
- self.win = fft_window(self, parent, size=size)
- self.set_average(self.average)
-
-
-class fft_sink_c(gr.hier_block, fft_sink_base):
- def __init__(self, fg, parent, baseband_freq=0,
- y_per_div=10, ref_level=50, sample_rate=1, fft_size=512,
- fft_rate=default_fft_rate, average=False, avg_alpha=None,
- title='', size=default_fftsink_size, peak_hold=False):
-
- fft_sink_base.__init__(self, input_is_real=False, baseband_freq=baseband_freq,
- y_per_div=y_per_div, ref_level=ref_level,
- sample_rate=sample_rate, fft_size=fft_size,
- fft_rate=fft_rate,
- average=average, avg_alpha=avg_alpha, title=title,
- peak_hold=peak_hold)
-
- s2p = gr.stream_to_vector(gr.sizeof_gr_complex, self.fft_size)
- self.one_in_n = gr.keep_one_in_n(gr.sizeof_gr_complex * self.fft_size,
- max(1, int(self.sample_rate/self.fft_size/self.fft_rate)))
- mywindow = window.blackmanharris(self.fft_size)
- power = 0
- for tap in mywindow:
- power += tap*tap
-
- fft = gr.fft_vcc(self.fft_size, True, mywindow)
- c2mag = gr.complex_to_mag(fft_size)
- self.avg = gr.single_pole_iir_filter_ff(1.0, fft_size)
- log = gr.nlog10_ff(20, self.fft_size,
- -20*math.log10(self.fft_size)-10*math.log10(power/self.fft_size))
- sink = gr.message_sink(gr.sizeof_float * fft_size, self.msgq, True)
-
- fg.connect(s2p, self.one_in_n, fft, c2mag, self.avg, log, sink)
- gr.hier_block.__init__(self, fg, s2p, sink)
-
- self.win = fft_window(self, parent, size=size)
- self.set_average(self.average)
-
-
-# ------------------------------------------------------------------------
-
-myDATA_EVENT = wx.NewEventType()
-EVT_DATA_EVENT = wx.PyEventBinder (myDATA_EVENT, 0)
-
-
-class DataEvent(wx.PyEvent):
- def __init__(self, data):
- wx.PyEvent.__init__(self)
- self.SetEventType (myDATA_EVENT)
- self.data = data
-
- def Clone (self):
- self.__class__ (self.GetId())
-
-
-class input_watcher (threading.Thread):
- def __init__ (self, msgq, fft_size, event_receiver, **kwds):
- threading.Thread.__init__ (self, **kwds)
- self.setDaemon (1)
- self.msgq = msgq
- self.fft_size = fft_size
- self.event_receiver = event_receiver
- 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 FFT frame in the message.
- # If so, we take only the last one
- if nitems > 1:
- start = itemsize * (nitems - 1)
- s = s[start:start+itemsize]
-
- complex_data = numpy.fromstring (s, numpy.float32)
- de = DataEvent (complex_data)
- wx.PostEvent (self.event_receiver, de)
- del de
-
-
-class fft_window (plot.PlotCanvas):
- def __init__ (self, fftsink, parent, id = -1,
- pos = wx.DefaultPosition, size = wx.DefaultSize,
- style = wx.DEFAULT_FRAME_STYLE, name = ""):
- plot.PlotCanvas.__init__ (self, parent, id, pos, size, style, name)
-
- self.y_range = None
- self.fftsink = fftsink
- self.peak_hold = False
- self.peak_vals = None
-
- self.SetEnableGrid (True)
- # self.SetEnableZoom (True)
- # self.SetBackgroundColour ('black')
-
- self.build_popup_menu()
-
- EVT_DATA_EVENT (self, self.set_data)
- wx.EVT_CLOSE (self, self.on_close_window)
- self.Bind(wx.EVT_RIGHT_UP, self.on_right_click)
-
- self.input_watcher = input_watcher(fftsink.msgq, fftsink.fft_size, self)
-
-
- def on_close_window (self, event):
- print "fft_window:on_close_window"
- self.keep_running = False
-
-
- def set_data (self, evt):
- dB = evt.data
- L = len (dB)
-
- if self.peak_hold:
- if self.peak_vals is None:
- self.peak_vals = dB
- else:
- self.peak_vals = numpy.maximum(dB, self.peak_vals)
- dB = self.peak_vals
-
- x = max(abs(self.fftsink.sample_rate), abs(self.fftsink.baseband_freq))
- if x >= 1e9:
- sf = 1e-9
- units = "GHz"
- elif x >= 1e6:
- sf = 1e-6
- units = "MHz"
- else:
- sf = 1e-3
- units = "kHz"
-
- if self.fftsink.input_is_real: # only plot 1/2 the points
- x_vals = ((numpy.arange (L/2)
- * (self.fftsink.sample_rate * sf / L))
- + self.fftsink.baseband_freq * sf)
- points = numpy.zeros((len(x_vals), 2), numpy.float64)
- points[:,0] = x_vals
- points[:,1] = dB[0:L/2]
- else:
- # the "negative freqs" are in the second half of the array
- x_vals = ((numpy.arange (-L/2, L/2)
- * (self.fftsink.sample_rate * sf / L))
- + self.fftsink.baseband_freq * sf)
- points = numpy.zeros((len(x_vals), 2), numpy.float64)
- points[:,0] = x_vals
- points[:,1] = numpy.concatenate ((dB[L/2:], dB[0:L/2]))
-
-
- lines = plot.PolyLine (points, colour='BLUE')
-
- graphics = plot.PlotGraphics ([lines],
- title=self.fftsink.title,
- xLabel = units, yLabel = "dB")
-
- self.Draw (graphics, xAxis=None, yAxis=self.y_range)
- self.update_y_range ()
-
- def set_peak_hold(self, enable):
- self.peak_hold = enable
- self.peak_vals = None
-
- def update_y_range (self):
- ymax = self.fftsink.ref_level
- ymin = self.fftsink.ref_level - self.fftsink.y_per_div * self.fftsink.y_divs
- self.y_range = self._axisInterval ('min', ymin, ymax)
-
- def on_average(self, evt):
- # print "on_average"
- self.fftsink.set_average(evt.IsChecked())
-
- def on_peak_hold(self, evt):
- # print "on_peak_hold"
- self.fftsink.set_peak_hold(evt.IsChecked())
-
- def on_incr_ref_level(self, evt):
- # print "on_incr_ref_level"
- self.fftsink.set_ref_level(self.fftsink.ref_level
- + self.fftsink.y_per_div)
-
- def on_decr_ref_level(self, evt):
- # print "on_decr_ref_level"
- self.fftsink.set_ref_level(self.fftsink.ref_level
- - self.fftsink.y_per_div)
-
- def on_incr_y_per_div(self, evt):
- # print "on_incr_y_per_div"
- self.fftsink.set_y_per_div(next_up(self.fftsink.y_per_div, (1,2,5,10,20)))
-
- def on_decr_y_per_div(self, evt):
- # print "on_decr_y_per_div"
- self.fftsink.set_y_per_div(next_down(self.fftsink.y_per_div, (1,2,5,10,20)))
-
- def on_y_per_div(self, evt):
- # print "on_y_per_div"
- Id = evt.GetId()
- if Id == self.id_y_per_div_1:
- self.fftsink.set_y_per_div(1)
- elif Id == self.id_y_per_div_2:
- self.fftsink.set_y_per_div(2)
- elif Id == self.id_y_per_div_5:
- self.fftsink.set_y_per_div(5)
- elif Id == self.id_y_per_div_10:
- self.fftsink.set_y_per_div(10)
- elif Id == self.id_y_per_div_20:
- self.fftsink.set_y_per_div(20)
-
-
- def on_right_click(self, event):
- menu = self.popup_menu
- for id, pred in self.checkmarks.items():
- item = menu.FindItemById(id)
- item.Check(pred())
- self.PopupMenu(menu, event.GetPosition())
-
-
- def build_popup_menu(self):
- self.id_incr_ref_level = wx.NewId()
- self.id_decr_ref_level = wx.NewId()
- self.id_incr_y_per_div = wx.NewId()
- self.id_decr_y_per_div = wx.NewId()
- self.id_y_per_div_1 = wx.NewId()
- self.id_y_per_div_2 = wx.NewId()
- self.id_y_per_div_5 = wx.NewId()
- self.id_y_per_div_10 = wx.NewId()
- self.id_y_per_div_20 = wx.NewId()
- self.id_average = wx.NewId()
- self.id_peak_hold = wx.NewId()
-
- self.Bind(wx.EVT_MENU, self.on_average, id=self.id_average)
- self.Bind(wx.EVT_MENU, self.on_peak_hold, id=self.id_peak_hold)
- self.Bind(wx.EVT_MENU, self.on_incr_ref_level, id=self.id_incr_ref_level)
- self.Bind(wx.EVT_MENU, self.on_decr_ref_level, id=self.id_decr_ref_level)
- self.Bind(wx.EVT_MENU, self.on_incr_y_per_div, id=self.id_incr_y_per_div)
- self.Bind(wx.EVT_MENU, self.on_decr_y_per_div, id=self.id_decr_y_per_div)
- self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_1)
- self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_2)
- self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_5)
- self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_10)
- self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_20)
-
-
- # make a menu
- menu = wx.Menu()
- self.popup_menu = menu
- menu.AppendCheckItem(self.id_average, "Average")
- menu.AppendCheckItem(self.id_peak_hold, "Peak Hold")
- menu.Append(self.id_incr_ref_level, "Incr Ref Level")
- menu.Append(self.id_decr_ref_level, "Decr Ref Level")
- # menu.Append(self.id_incr_y_per_div, "Incr dB/div")
- # menu.Append(self.id_decr_y_per_div, "Decr dB/div")
- menu.AppendSeparator()
- # we'd use RadioItems for these, but they're not supported on Mac
- menu.AppendCheckItem(self.id_y_per_div_1, "1 dB/div")
- menu.AppendCheckItem(self.id_y_per_div_2, "2 dB/div")
- menu.AppendCheckItem(self.id_y_per_div_5, "5 dB/div")
- menu.AppendCheckItem(self.id_y_per_div_10, "10 dB/div")
- menu.AppendCheckItem(self.id_y_per_div_20, "20 dB/div")
-
- self.checkmarks = {
- self.id_average : lambda : self.fftsink.average,
- self.id_peak_hold : lambda : self.fftsink.peak_hold,
- self.id_y_per_div_1 : lambda : self.fftsink.y_per_div == 1,
- self.id_y_per_div_2 : lambda : self.fftsink.y_per_div == 2,
- self.id_y_per_div_5 : lambda : self.fftsink.y_per_div == 5,
- self.id_y_per_div_10 : lambda : self.fftsink.y_per_div == 10,
- self.id_y_per_div_20 : lambda : self.fftsink.y_per_div == 20,
- }
-
-
-def next_up(v, seq):
- """
- Return the first item in seq that is > v.
- """
- for s in seq:
- if s > v:
- return s
- return v
-
-def next_down(v, seq):
- """
- Return the last item in seq that is < v.
- """
- rseq = list(seq[:])
- rseq.reverse()
-
- for s in rseq:
- if s < v:
- return s
- return v
-
-
-# ----------------------------------------------------------------
-# Deprecated interfaces
-# ----------------------------------------------------------------
-
-# returns (block, win).
-# block requires a single input stream of float
-# win is a subclass of wxWindow
-
-def make_fft_sink_f(fg, parent, title, fft_size, input_rate, ymin = 0, ymax=50):
-
- block = fft_sink_f(fg, parent, title=title, fft_size=fft_size, sample_rate=input_rate,
- y_per_div=(ymax - ymin)/8, ref_level=ymax)
- return (block, block.win)
-
-# returns (block, win).
-# block requires a single input stream of gr_complex
-# win is a subclass of wxWindow
-
-def make_fft_sink_c(fg, parent, title, fft_size, input_rate, ymin=0, ymax=50):
- block = fft_sink_c(fg, parent, title=title, fft_size=fft_size, sample_rate=input_rate,
- y_per_div=(ymax - ymin)/8, ref_level=ymax)
- return (block, block.win)
-
-
-# ----------------------------------------------------------------
-# Standalone test app
-# ----------------------------------------------------------------
-
-class test_app_flow_graph (stdgui.gui_flow_graph):
- def __init__(self, frame, panel, vbox, argv):
- stdgui.gui_flow_graph.__init__ (self, frame, panel, vbox, argv)
-
- fft_size = 256
-
- # build our flow graph
- input_rate = 20.48e3
-
- # Generate a complex sinusoid
- #src1 = gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 2e3, 1)
- src1 = gr.sig_source_c (input_rate, gr.GR_CONST_WAVE, 5.75e3, 1)
-
- # We add these throttle blocks so that this demo doesn't
- # suck down all the CPU available. Normally you wouldn't use these.
- thr1 = gr.throttle(gr.sizeof_gr_complex, input_rate)
-
- sink1 = fft_sink_c (self, panel, title="Complex Data", fft_size=fft_size,
- sample_rate=input_rate, baseband_freq=100e3,
- ref_level=0, y_per_div=20)
- vbox.Add (sink1.win, 1, wx.EXPAND)
- self.connect (src1, thr1, sink1)
-
- #src2 = gr.sig_source_f (input_rate, gr.GR_SIN_WAVE, 2e3, 1)
- src2 = gr.sig_source_f (input_rate, gr.GR_CONST_WAVE, 5.75e3, 1)
- thr2 = gr.throttle(gr.sizeof_float, input_rate)
- sink2 = fft_sink_f (self, panel, title="Real Data", fft_size=fft_size*2,
- sample_rate=input_rate, baseband_freq=100e3,
- ref_level=0, y_per_div=20)
- vbox.Add (sink2.win, 1, wx.EXPAND)
- self.connect (src2, thr2, sink2)
-
-def main ():
- app = stdgui.stdapp (test_app_flow_graph,
- "FFT Sink Test App")
- app.MainLoop ()
-
-if __name__ == '__main__':
- main ()
diff --git a/gr-wxgui/src/python/numbersink.py b/gr-wxgui/src/python/numbersink.py
deleted file mode 100755
index 5427d2a40..000000000
--- a/gr-wxgui/src/python/numbersink.py
+++ /dev/null
@@ -1,614 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2003,2004,2005,2006,2007 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., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-#
-
-from gnuradio import gr, gru, window
-from gnuradio.wxgui import stdgui
-import wx
-#from wx import StaticText
-import gnuradio.wxgui.plot as plot
-import numpy
-import threading
-import math
-
-default_numbersink_size = (640,240)
-default_number_rate = gr.prefs().get_long('wxgui', 'number_rate', 15)
-
-class number_sink_base(object):
- def __init__(self, input_is_real=False, unit='',base_value=0, minval=-100.0,maxval=100.0,factor=1.0,decimal_places=10, ref_level=50,
- sample_rate=1,
- number_rate=default_number_rate,
- average=False, avg_alpha=None, label='', peak_hold=False):
-
- # initialize common attributes
- self.unit=unit
- self.base_value = base_value
- self.minval=minval
- self.maxval=maxval
- self.factor=factor
- self.y_divs = 8
- self.decimal_places=decimal_places
- self.ref_level = ref_level
- self.sample_rate = sample_rate
- number_size=1
- self.number_size = number_size
- self.number_rate = number_rate
- self.average = average
- if avg_alpha is None:
- self.avg_alpha = 2.0 / number_rate
- else:
- self.avg_alpha = avg_alpha
- self.label = label
- self.peak_hold = peak_hold
- self.show_gauge = True
- self.input_is_real = input_is_real
- self.msgq = gr.msg_queue(2) # queue that holds a maximum of 2 messages
-
- def set_decimal_places(self, decimal_places):
- self.decimal_places = decimal_places
-
- def set_ref_level(self, ref_level):
- self.ref_level = ref_level
-
- def print_current_value(self, comment):
- print comment,self.win.current_value
-
- def set_average(self, average):
- self.average = average
- if average:
- self.avg.set_taps(self.avg_alpha)
- self.set_peak_hold(False)
- else:
- self.avg.set_taps(1.0)
-
- def set_peak_hold(self, enable):
- self.peak_hold = enable
- if enable:
- self.set_average(False)
- self.win.set_peak_hold(enable)
-
- def set_show_gauge(self, enable):
- self.show_gauge = enable
- self.win.set_show_gauge(enable)
-
- def set_avg_alpha(self, avg_alpha):
- self.avg_alpha = avg_alpha
-
- def set_base_value(self, base_value):
- self.base_value = base_value
-
-
-class number_sink_f(gr.hier_block, number_sink_base):
- def __init__(self, fg, parent, unit='',base_value=0,minval=-100.0,maxval=100.0,factor=1.0,
- decimal_places=10, ref_level=50, sample_rate=1, #number_size=512,
- number_rate=default_number_rate, average=False, avg_alpha=None,
- label='', size=default_numbersink_size, peak_hold=False):
-
- number_sink_base.__init__(self, unit=unit, input_is_real=True, base_value=base_value,
- minval=minval,maxval=maxval,factor=factor,
- decimal_places=decimal_places, ref_level=ref_level,
- sample_rate=sample_rate, #number_size=number_size,
- number_rate=number_rate,
- average=average, avg_alpha=avg_alpha, label=label,
- peak_hold=peak_hold)
-
- number_size=1
- #s2p = gr.stream_to_vector(gr.sizeof_float, number_size)
- one_in_n = gr.keep_one_in_n(gr.sizeof_float,
- max(1, int(sample_rate/number_rate)))
-
-
- #c2mag = gr.complex_to_mag(number_size)
- self.avg = gr.single_pole_iir_filter_ff(1.0, number_size)
-
- # FIXME We need to add 3dB to all bins but the DC bin
- #log = gr.nlog10_ff(20, number_size,
- # -20*math.log10(number_size)-10*math.log10(power/number_size))
- sink = gr.message_sink(gr.sizeof_float , self.msgq, True)
-
- #fg.connect (s2p, one_in_n, fft, c2mag, self.avg, log, sink)
- fg.connect(self.avg,one_in_n,sink)
- gr.hier_block.__init__(self, fg, self.avg, sink)
- self.win = number_window(self, parent, size=size,label=label)
- self.set_average(self.average)
-
-
-class number_sink_c(gr.hier_block, number_sink_base):
- def __init__(self, fg, parent, unit='',base_value=0,minval=-100.0,maxval=100.0,factor=1.0,
- decimal_places=10, ref_level=50, sample_rate=1, #number_size=512,
- number_rate=default_number_rate, average=False, avg_alpha=None,
- label='', size=default_numbersink_size, peak_hold=False):
-
- number_sink_base.__init__(self, unit=unit, input_is_real=False, base_value=base_value,factor=factor,
- minval=minval,maxval=maxval,decimal_places=decimal_places, ref_level=ref_level,
- sample_rate=sample_rate, #number_size=number_size,
- number_rate=number_rate,
- average=average, avg_alpha=avg_alpha, label=label,
- peak_hold=peak_hold)
-
- number_size=1
- one_in_n = gr.keep_one_in_n(gr.sizeof_gr_complex,
- max(1, int(sample_rate/number_rate)))
-
-
- #c2mag = gr.complex_to_mag(number_size)
- self.avg = gr.single_pole_iir_filter_cc(1.0, number_size)
-
- # FIXME We need to add 3dB to all bins but the DC bin
- #log = gr.nlog10_ff(20, number_size,
- # -20*math.log10(number_size)-10*math.log10(power/number_size))
- sink = gr.message_sink(gr.sizeof_gr_complex , self.msgq, True)
-
- #fg.connect (s2p, one_in_n, fft, c2mag, self.avg, log, sink)
- fg.connect(self.avg,one_in_n,sink)
- gr.hier_block.__init__(self, fg, self.avg, sink)
- self.win = number_window(self, parent, size=size,label=label)
- self.set_average(self.average)
-
-
-# ------------------------------------------------------------------------
-
-myDATA_EVENT = wx.NewEventType()
-EVT_DATA_EVENT = wx.PyEventBinder (myDATA_EVENT, 0)
-
-
-class DataEvent(wx.PyEvent):
- def __init__(self, data):
- wx.PyEvent.__init__(self)
- self.SetEventType (myDATA_EVENT)
- self.data = data
-
- def Clone (self):
- self.__class__ (self.GetId())
-
-
-class input_watcher (threading.Thread):
- def __init__ (self, msgq, number_size, event_receiver, **kwds):
- threading.Thread.__init__ (self, **kwds)
- self.setDaemon (1)
- self.msgq = msgq
- self.number_size = number_size
- self.event_receiver = event_receiver
- 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 number in the message.
- # If so, we take only the last one
- if nitems > 1:
- start = itemsize * (nitems - 1)
- s = s[start:start+itemsize]
-
- complex_data = numpy.fromstring (s, numpy.float32)
- de = DataEvent (complex_data)
- wx.PostEvent (self.event_receiver, de)
- del de
-
-#========================================================================================
-class static_text_window (wx.StaticText): #plot.PlotCanvas):
- def __init__ (self, parent, numbersink,id = -1,label="number",
- pos = wx.DefaultPosition, size = wx.DefaultSize,
- style = wx.DEFAULT_FRAME_STYLE, name = ""):
- #plot.PlotCanvas.__init__ (self, parent, id, pos, size, style, name)
- wx.StaticText.__init__(self, parent, id, label, pos, size, style, name)
- #self.static_text=wx.StaticText( parent, id, label, pos, (size[0]/2,size[1]/2), style, name)
- #gauge_style = wx.GA_HORIZONTAL
- #self.gauge=wx.Gauge( parent, id, range=1000, pos=(pos[0],pos[1]+size[1]/2),size=(size[0]/2,size[1]/2), style=gauge_style, name = "gauge")
- #wx.BoxSizer.__init__ (self,wx.VERTICAL)
- #self.Add (self.static_text, 0, wx.EXPAND)
- #self.Add (self.gauge, 1, wx.EXPAND)
- self.parent=parent
- self.label=label
- #self.y_range = None
- self.numbersink = numbersink
- self.peak_hold = False
- self.peak_vals = None
-
- #self.SetEnableGrid (True)
- # self.SetEnableZoom (True)
- # self.SetBackgroundColour ('black')
-
- self.build_popup_menu()
-
- #EVT_DATA_EVENT (self, self.set_data)
- #wx.EVT_CLOSE (self, self.on_close_window)
- #self.Bind(wx.EVT_RIGHT_UP, self.on_right_click)
- self.Bind(wx.EVT_RIGHT_UP, self.on_right_click)
-
- #self.input_watcher = input_watcher(numbersink.msgq, numbersink.number_size, self)
-
-
- def on_close_window (self, event):
- print "number_window:on_close_window"
- self.keep_running = False
-
-
- def set_peak_hold(self, enable):
- self.peak_hold = enable
- self.peak_vals = None
-
- def update_y_range (self):
- ymax = self.numbersink.ref_level
- ymin = self.numbersink.ref_level - self.numbersink.decimal_places * self.numbersink.y_divs
- self.y_range = self._axisInterval ('min', ymin, ymax)
-
- def on_average(self, evt):
- # print "on_average"
- self.numbersink.set_average(evt.IsChecked())
-
- def on_peak_hold(self, evt):
- # print "on_peak_hold"
- self.numbersink.set_peak_hold(evt.IsChecked())
-
- def on_show_gauge(self, evt):
- # print "on_show_gauge"
- #if evt.IsChecked():
- self.numbersink.set_show_gauge(evt.IsChecked())
- print evt.IsChecked()
- # print "show gauge"
- #else:
- # self.parent.gauge.Hide()
- # print "hide gauge"
-
- def on_incr_ref_level(self, evt):
- # print "on_incr_ref_level"
- self.numbersink.set_ref_level(self.numbersink.ref_level
- + self.numbersink.decimal_places)
-
- def on_decr_ref_level(self, evt):
- # print "on_decr_ref_level"
- self.numbersink.set_ref_level(self.numbersink.ref_level
- - self.numbersink.decimal_places)
-
- def on_incr_decimal_places(self, evt):
- # print "on_incr_decimal_places"
- self.numbersink.set_decimal_places(self.numbersink.decimal_places+1) #next_up(self.numbersink.decimal_places, (1,2,5,10,20)))
-
- def on_decr_decimal_places(self, evt):
- # print "on_decr_decimal_places"
- self.numbersink.set_decimal_places(max(self.numbersink.decimal_places-1,0)) #next_down(self.numbersink.decimal_places, (1,2,5,10,20)))
-
- def on_decimal_places(self, evt):
- # print "on_decimal_places"
- Id = evt.GetId()
- if Id == self.id_decimal_places_0:
- self.numbersink.set_decimal_places(0)
- elif Id == self.id_decimal_places_1:
- self.numbersink.set_decimal_places(1)
- elif Id == self.id_decimal_places_2:
- self.numbersink.set_decimal_places(2)
- elif Id == self.id_decimal_places_3:
- self.numbersink.set_decimal_places(3)
- elif Id == self.id_decimal_places_6:
- self.numbersink.set_decimal_places(6)
- elif Id == self.id_decimal_places_9:
- self.numbersink.set_decimal_places(9)
-
-
- def on_right_click(self, event):
- menu = self.popup_menu
- for id, pred in self.checkmarks.items():
- item = menu.FindItemById(id)
- item.Check(pred())
- self.PopupMenu(menu, event.GetPosition())
-
-
- def build_popup_menu(self):
- #self.id_hide_gauge = wx.NewId()
- self.id_show_gauge = wx.NewId()
- self.id_incr_ref_level = wx.NewId()
- self.id_decr_ref_level = wx.NewId()
- self.id_incr_decimal_places = wx.NewId()
- self.id_decr_decimal_places = wx.NewId()
- self.id_decimal_places_0 = wx.NewId()
- self.id_decimal_places_1 = wx.NewId()
- self.id_decimal_places_2 = wx.NewId()
- self.id_decimal_places_3 = wx.NewId()
- self.id_decimal_places_6 = wx.NewId()
- self.id_decimal_places_9 = wx.NewId()
- self.id_average = wx.NewId()
- self.id_peak_hold = wx.NewId()
-
- self.Bind(wx.EVT_MENU, self.on_average, id=self.id_average)
- self.Bind(wx.EVT_MENU, self.on_peak_hold, id=self.id_peak_hold)
- #self.Bind(wx.EVT_MENU, self.on_hide_gauge, id=self.id_hide_gauge)
- self.Bind(wx.EVT_MENU, self.on_show_gauge, id=self.id_show_gauge)
- self.Bind(wx.EVT_MENU, self.on_incr_ref_level, id=self.id_incr_ref_level)
- self.Bind(wx.EVT_MENU, self.on_decr_ref_level, id=self.id_decr_ref_level)
- self.Bind(wx.EVT_MENU, self.on_incr_decimal_places, id=self.id_incr_decimal_places)
- self.Bind(wx.EVT_MENU, self.on_decr_decimal_places, id=self.id_decr_decimal_places)
- self.Bind(wx.EVT_MENU, self.on_decimal_places, id=self.id_decimal_places_0)
- self.Bind(wx.EVT_MENU, self.on_decimal_places, id=self.id_decimal_places_1)
- self.Bind(wx.EVT_MENU, self.on_decimal_places, id=self.id_decimal_places_2)
- self.Bind(wx.EVT_MENU, self.on_decimal_places, id=self.id_decimal_places_3)
- self.Bind(wx.EVT_MENU, self.on_decimal_places, id=self.id_decimal_places_6)
- self.Bind(wx.EVT_MENU, self.on_decimal_places, id=self.id_decimal_places_9)
-
-
- # make a menu
- menu = wx.Menu()
- self.popup_menu = menu
- menu.AppendCheckItem(self.id_average, "Average")
- menu.AppendCheckItem(self.id_peak_hold, "Peak Hold")
- #menu.Append(self.id_hide_gauge, "Hide gauge")
- menu.AppendCheckItem(self.id_show_gauge, "Show gauge")
- menu.Append(self.id_incr_ref_level, "Incr Ref Level")
- menu.Append(self.id_decr_ref_level, "Decr Ref Level")
- menu.Append(self.id_incr_decimal_places, "Incr decimal places")
- menu.Append(self.id_decr_decimal_places, "Decr decimal places")
- menu.AppendSeparator()
- # we'd use RadioItems for these, but they're not supported on Mac
- menu.AppendCheckItem(self.id_decimal_places_0, "0 decimal places")
- menu.AppendCheckItem(self.id_decimal_places_1, "1 decimal places")
- menu.AppendCheckItem(self.id_decimal_places_2, "2 decimal places")
- menu.AppendCheckItem(self.id_decimal_places_3, "3 decimal places")
- menu.AppendCheckItem(self.id_decimal_places_6, "6 decimal places")
- menu.AppendCheckItem(self.id_decimal_places_9, "9 decimal places")
-
- self.checkmarks = {
- self.id_average : lambda : self.numbersink.average,
- self.id_peak_hold : lambda : self.numbersink.peak_hold,# self.id_hide_gauge : lambda : self.numbersink.hide_gauge,
- self.id_show_gauge : lambda : self.numbersink.show_gauge,
- self.id_decimal_places_0 : lambda : self.numbersink.decimal_places == 0,
- self.id_decimal_places_1 : lambda : self.numbersink.decimal_places == 1,
- self.id_decimal_places_2 : lambda : self.numbersink.decimal_places == 2,
- self.id_decimal_places_3 : lambda : self.numbersink.decimal_places == 3,
- self.id_decimal_places_6 : lambda : self.numbersink.decimal_places == 6,
- self.id_decimal_places_9 : lambda : self.numbersink.decimal_places == 9,
- }
-
-
-def next_up(v, seq):
- """
- Return the first item in seq that is > v.
- """
- for s in seq:
- if s > v:
- return s
- return v
-
-def next_down(v, seq):
- """
- Return the last item in seq that is < v.
- """
- rseq = list(seq[:])
- rseq.reverse()
-
- for s in rseq:
- if s < v:
- return s
- return v
-
-
-#========================================================================================
-class number_window (plot.PlotCanvas):
- def __init__ (self, numbersink, parent, id = -1,label="number",
- pos = wx.DefaultPosition, size = wx.DefaultSize,
- style = wx.DEFAULT_FRAME_STYLE, name = ""):
- plot.PlotCanvas.__init__ (self, parent, id, pos, size, style, name)
- #wx.StaticText.__init__(self, parent, id, label, pos, (size[0]/2,size[1]/2), style, name)
- #print 'parent',parent
- self.static_text=static_text_window( self, numbersink,id, label, pos, (size[0]/2,size[1]/2), style, name)
- gauge_style = wx.GA_HORIZONTAL
- vbox=wx.BoxSizer(wx.VERTICAL)
- vbox.Add (self.static_text, 0, wx.EXPAND)
- self.current_value=None
- if numbersink.input_is_real:
- self.gauge=wx.Gauge( self, id, range=1000, pos=(pos[0],pos[1]+size[1]/2),size=(size[0]/2,size[1]/2), style=gauge_style, name = "gauge")
- vbox.Add (self.gauge, 1, wx.EXPAND)
- else:
- self.gauge=wx.Gauge( self, id, range=1000, pos=(pos[0],pos[1]+size[1]/3),size=(size[0]/2,size[1]/3), style=gauge_style, name = "gauge")
- #hbox=wx.BoxSizer(wx.HORIZONTAL)
- self.gauge_imag=wx.Gauge( self, id, range=1000, pos=(pos[0],pos[1]+size[1]*2/3),size=(size[0]/2,size[1]/3), style=gauge_style, name = "gauge_imag")
- vbox.Add (self.gauge, 1, wx.EXPAND)
- vbox.Add (self.gauge_imag, 1, wx.EXPAND)
- #vbox.Add (hbox, 1, wx.EXPAND)
- self.sizer = vbox
- self.SetSizer (self.sizer)
- self.SetAutoLayout (True)
- self.sizer.Fit (self)
-
- self.label=label
- #self.y_range = None
- self.numbersink = numbersink
- self.peak_hold = False
- self.peak_vals = None
-
- #self.SetEnableGrid (True)
- # self.SetEnableZoom (True)
- # self.SetBackgroundColour ('black')
-
- #self.build_popup_menu()
-
- EVT_DATA_EVENT (self, self.set_data)
- wx.EVT_CLOSE (self, self.on_close_window)
- #self.Bind(wx.EVT_RIGHT_UP, self.on_right_click)
- #self.Bind(wx.EVT_RIGHT_UP, self.on_right_click)
-
- self.input_watcher = input_watcher(numbersink.msgq, numbersink.number_size, self)
-
-
- def on_close_window (self, event):
- print "number_window:on_close_window"
- self.keep_running = False
-
- def set_show_gauge(self, enable):
- self.show_gauge = enable
- if enable:
- self.gauge.Show()
- if not self.numbersink.input_is_real:
- self.gauge_imag.Show()
- #print 'show'
- else:
- self.gauge.Hide()
- if not self.numbersink.input_is_real:
- self.gauge_imag.Hide()
- #print 'hide'
-
- def set_data (self, evt):
- numbers = evt.data
- L = len (numbers)
-
- if self.peak_hold:
- if self.peak_vals is None:
- self.peak_vals = numbers
- else:
- self.peak_vals = numpy.maximum(numbers, self.peak_vals)
- numbers = self.peak_vals
-
- if self.numbersink.input_is_real:
- real_value=numbers[0]*self.numbersink.factor + self.numbersink.base_value
- imag_value=0.0
- self.current_value=real_value
- else:
- real_value=numbers[0]*self.numbersink.factor + self.numbersink.base_value
- imag_value=numbers[1]*self.numbersink.factor + self.numbersink.base_value
- self.current_value=complex(real_value,imag_value)
- #x = max(abs(self.numbersink.sample_rate), abs(self.numbersink.base_value))
- x = max(real_value, imag_value)
- if x >= 1e9:
- sf = 1e-9
- unit_prefix = "G"
- elif x >= 1e6:
- sf = 1e-6
- unit_prefix = "M"
- elif x>= 1e3:
- sf = 1e-3
- unit_prefix = "k"
- else :
- sf = 1
- unit_prefix = ""
- #self.update_y_range ()
- if self.numbersink.input_is_real:
- showtext = "%s: %.*f %s%s" % (self.label, self.numbersink.decimal_places,real_value*sf,unit_prefix,self.numbersink.unit)
- else:
- showtext = "%s: %.*f,%.*f %s%s" % (self.label, self.numbersink.decimal_places,real_value*sf,
- self.numbersink.decimal_places,imag_value*sf,unit_prefix,self.numbersink.unit)
- self.static_text.SetLabel(showtext)
- #print (int(float((real_value-self.numbersink.base_value)*1000.0/(self.numbersink.maxval-self.numbersink.minval)))+500)
- self.gauge.SetValue(int(float((real_value-self.numbersink.base_value)*1000.0/(self.numbersink.maxval-self.numbersink.minval)))+500)
- if not self.numbersink.input_is_real:
- self.gauge.SetValue(int(float((imag_value-self.numbersink.base_value)*1000.0/(self.numbersink.maxval-self.numbersink.minval)))+500)
-
- def set_peak_hold(self, enable):
- self.peak_hold = enable
- self.peak_vals = None
-
- def update_y_range (self):
- ymax = self.numbersink.ref_level
- ymin = self.numbersink.ref_level - self.numbersink.decimal_places * self.numbersink.y_divs
- self.y_range = self._axisInterval ('min', ymin, ymax)
-
- def on_average(self, evt):
- # print "on_average"
- self.numbersink.set_average(evt.IsChecked())
-
- def on_peak_hold(self, evt):
- # print "on_peak_hold"
- self.numbersink.set_peak_hold(evt.IsChecked())
-
-
-
-
-
-
-
-
-
-
-# ----------------------------------------------------------------
-# Deprecated interfaces
-# ----------------------------------------------------------------
-
-# returns (block, win).
-# block requires a single input stream of float
-# win is a subclass of wxWindow
-
-def make_number_sink_f(fg, parent, label, number_size, input_rate, ymin = 0, ymax=50):
-
- block = number_sink_f(fg, parent, label=label, number_size=number_size, sample_rate=input_rate,
- decimal_places=(ymax - ymin)/8, ref_level=ymax)
- return (block, block.win)
-
-# returns (block, win).
-# block requires a single input stream of gr_complex
-# win is a subclass of wxWindow
-
-def make_number_sink_c(fg, parent, label, number_size, input_rate, ymin=0, ymax=50):
- block = number_sink_c(fg, parent, label=label, number_size=number_size, sample_rate=input_rate,
- decimal_places=(ymax - ymin)/8, ref_level=ymax)
- return (block, block.win)
-
-
-# ----------------------------------------------------------------
-# Standalone test app
-# ----------------------------------------------------------------
-
-class test_app_flow_graph (stdgui.gui_flow_graph):
- def __init__(self, frame, panel, vbox, argv):
- stdgui.gui_flow_graph.__init__ (self, frame, panel, vbox, argv)
-
- #number_size = 256
-
- # build our flow graph
- input_rate = 20.48e3
-
- # Generate a complex sinusoid
- src1 = gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 2e3, 1)
- #src1 = gr.sig_source_c (input_rate, gr.GR_CONST_WAVE, 5.75e3, 1)
-
- # We add these throttle blocks so that this demo doesn't
- # suck down all the CPU available. Normally you wouldn't use these.
- thr1 = gr.throttle(gr.sizeof_gr_complex, input_rate)
-
- #sink1 = number_sink_c (self, panel, label="Complex Data", number_size=number_size,
- # sample_rate=input_rate, base_value=100e3,
- # ref_level=0, decimal_places=3)
- #vbox.Add (sink1.win, 1, wx.EXPAND)
- #self.connect (src1, thr1, sink1)
-
- src2 = gr.sig_source_f (input_rate, gr.GR_SIN_WAVE, 2e3, 1)
- #src2 = gr.sig_source_f (input_rate, gr.GR_CONST_WAVE, 5.75e3, 1)
- thr2 = gr.throttle(gr.sizeof_float, input_rate)
- sink2 = number_sink_f (self, panel, unit='Hz',label="Real Data", avg_alpha=0.001,#number_size=number_size*2,
- sample_rate=input_rate, base_value=100e3,
- ref_level=0, decimal_places=3)
- vbox.Add (sink2.win, 1, wx.EXPAND)
- sink3 = number_sink_c (self, panel, unit='V',label="Complex Data", avg_alpha=0.001,#number_size=number_size*2,
- sample_rate=input_rate, base_value=0,
- ref_level=0, decimal_places=3)
- vbox.Add (sink3.win, 1, wx.EXPAND)
- self.connect (src2, thr2, sink2)
- self.connect (src1, thr1, sink3)
-def main ():
- app = stdgui.stdapp (test_app_flow_graph,
- "Number Sink Test App")
- app.MainLoop ()
-
-if __name__ == '__main__':
- main ()
diff --git a/gr-wxgui/src/python/scopesink.py b/gr-wxgui/src/python/scopesink.py
deleted file mode 100755
index ffd4529bc..000000000
--- a/gr-wxgui/src/python/scopesink.py
+++ /dev/null
@@ -1,650 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2003,2004,2006,2007 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.
-#
-
-from gnuradio import gr, gru, eng_notation
-from gnuradio.wxgui import stdgui
-import wx
-import gnuradio.wxgui.plot as plot
-import numpy
-import threading
-import struct
-
-default_scopesink_size = (640, 240)
-default_v_scale = 1000
-default_frame_decim = gr.prefs().get_long('wxgui', 'frame_decim', 1)
-
-class scope_sink_f(gr.hier_block):
- def __init__(self, fg, parent, title='', sample_rate=1,
- size=default_scopesink_size, frame_decim=default_frame_decim,
- v_scale=default_v_scale, t_scale=None):
- msgq = gr.msg_queue(2) # message queue that holds at most 2 messages
- self.guts = gr.oscope_sink_f(sample_rate, msgq)
- gr.hier_block.__init__(self, fg, self.guts, self.guts)
- self.win = scope_window(win_info (msgq, sample_rate, frame_decim,
- v_scale, t_scale, self.guts, title), parent)
-
- def set_sample_rate(self, sample_rate):
- self.guts.set_sample_rate(sample_rate)
- self.win.info.set_sample_rate(sample_rate)
-
-class scope_sink_c(gr.hier_block):
- def __init__(self, fg, parent, title='', sample_rate=1,
- size=default_scopesink_size, frame_decim=default_frame_decim,
- v_scale=default_v_scale, t_scale=None):
- msgq = gr.msg_queue(2) # message queue that holds at most 2 messages
- c2f = gr.complex_to_float()
- self.guts = gr.oscope_sink_f(sample_rate, msgq)
- fg.connect((c2f, 0), (self.guts, 0))
- fg.connect((c2f, 1), (self.guts, 1))
- gr.hier_block.__init__(self, fg, c2f, self.guts)
- self.win = scope_window(win_info(msgq, sample_rate, frame_decim,
- v_scale, t_scale, self.guts, title), parent)
-
- def set_sample_rate(self, sample_rate):
- self.guts.set_sample_rate(sample_rate)
- self.win.info.set_sample_rate(sample_rate)
-
-# ========================================================================
-# This is the deprecated interface, retained for compatibility...
-#
-# returns (block, win).
-# block requires a N input stream of float
-# win is a subclass of wxWindow
-
-def make_scope_sink_f (fg, parent, label, input_rate):
- block = scope_sink_f(fg, parent, title=label, sample_rate=input_rate)
- return (block, block.win)
-
-# ========================================================================
-
-
-time_base_list = [ # time / division
- 1.0e-7, # 100ns / div
- 2.5e-7,
- 5.0e-7,
- 1.0e-6, # 1us / div
- 2.5e-6,
- 5.0e-6,
- 1.0e-5, # 10us / div
- 2.5e-5,
- 5.0e-5,
- 1.0e-4, # 100us / div
- 2.5e-4,
- 5.0e-4,
- 1.0e-3, # 1ms / div
- 2.5e-3,
- 5.0e-3,
- 1.0e-2, # 10ms / div
- 2.5e-2,
- 5.0e-2
- ]
-
-v_scale_list = [ # counts / div, LARGER gains are SMALLER /div, appear EARLIER
- 2.0e-3, # 2m / div, don't call it V/div it's actually counts/div
- 5.0e-3,
- 1.0e-2,
- 2.0e-2,
- 5.0e-2,
- 1.0e-1,
- 2.0e-1,
- 5.0e-1,
- 1.0e+0,
- 2.0e+0,
- 5.0e+0,
- 1.0e+1,
- 2.0e+1,
- 5.0e+1,
- 1.0e+2,
- 2.0e+2,
- 5.0e+2,
- 1.0e+3,
- 2.0e+3,
- 5.0e+3,
- 1.0e+4 # 10000 /div, USRP full scale is -/+ 32767
- ]
-
-
-wxDATA_EVENT = wx.NewEventType()
-
-def EVT_DATA_EVENT(win, func):
- win.Connect(-1, -1, wxDATA_EVENT, func)
-
-class DataEvent(wx.PyEvent):
- def __init__(self, data):
- wx.PyEvent.__init__(self)
- self.SetEventType (wxDATA_EVENT)
- self.data = data
-
- def Clone (self):
- self.__class__ (self.GetId())
-
-
-class win_info (object):
- __slots__ = ['msgq', 'sample_rate', 'frame_decim', 'v_scale',
- 'scopesink', 'title',
- 'time_scale_cursor', 'v_scale_cursor', 'marker', 'xy',
- 'autorange', 'running']
-
- def __init__ (self, msgq, sample_rate, frame_decim, v_scale, t_scale,
- scopesink, title = "Oscilloscope"):
- self.msgq = msgq
- self.sample_rate = sample_rate
- self.frame_decim = frame_decim
- self.scopesink = scopesink
- self.title = title;
-
- self.time_scale_cursor = gru.seq_with_cursor(time_base_list, initial_value = t_scale)
- self.v_scale_cursor = gru.seq_with_cursor(v_scale_list, initial_value = v_scale)
-
- self.marker = 'line'
- self.xy = False
- if v_scale == None: # 0 and None are both False, but 0 != None
- self.autorange = True
- else:
- self.autorange = False # 0 is a valid v_scale
- self.running = True
-
- def get_time_per_div (self):
- return self.time_scale_cursor.current ()
-
- def get_volts_per_div (self):
- return self.v_scale_cursor.current ()
-
- def set_sample_rate(self, sample_rate):
- self.sample_rate = sample_rate
-
- def get_sample_rate (self):
- return self.sample_rate
-
- def get_decimation_rate (self):
- return 1.0
-
- def set_marker (self, s):
- self.marker = s
-
- def get_marker (self):
- return self.marker
-
-
-class input_watcher (threading.Thread):
- def __init__ (self, msgq, event_receiver, frame_decim, **kwds):
- threading.Thread.__init__ (self, **kwds)
- self.setDaemon (1)
- self.msgq = msgq
- self.event_receiver = event_receiver
- self.frame_decim = frame_decim
- self.iscan = 0
- self.keep_running = True
- self.start ()
-
- def run (self):
- # print "input_watcher: pid = ", os.getpid ()
- while (self.keep_running):
- msg = self.msgq.delete_head() # blocking read of message queue
- if self.iscan == 0: # only display at frame_decim
- self.iscan = self.frame_decim
-
- nchan = int(msg.arg1()) # number of channels of data in msg
- nsamples = int(msg.arg2()) # number of samples in each channel
-
- s = msg.to_string() # get the body of the msg as a string
-
- bytes_per_chan = nsamples * gr.sizeof_float
-
- records = []
- for ch in range (nchan):
-
- start = ch * bytes_per_chan
- chan_data = s[start:start+bytes_per_chan]
- rec = numpy.fromstring (chan_data, numpy.float32)
- records.append (rec)
-
- # print "nrecords = %d, reclen = %d" % (len (records),nsamples)
-
- de = DataEvent (records)
- wx.PostEvent (self.event_receiver, de)
- records = []
- del de
-
- # end if iscan == 0
- self.iscan -= 1
-
-
-class scope_window (wx.Panel):
-
- def __init__ (self, info, parent, id = -1,
- pos = wx.DefaultPosition, size = wx.DefaultSize, name = ""):
- wx.Panel.__init__ (self, parent, -1)
- self.info = info
-
- vbox = wx.BoxSizer (wx.VERTICAL)
-
- self.graph = graph_window (info, self, -1)
-
- vbox.Add (self.graph, 1, wx.EXPAND)
- vbox.Add (self.make_control_box(), 0, wx.EXPAND)
- vbox.Add (self.make_control2_box(), 0, wx.EXPAND)
-
- self.sizer = vbox
- self.SetSizer (self.sizer)
- self.SetAutoLayout (True)
- self.sizer.Fit (self)
- self.set_autorange(self.info.autorange)
-
-
- # second row of control buttons etc. appears BELOW control_box
- def make_control2_box (self):
- ctrlbox = wx.BoxSizer (wx.HORIZONTAL)
-
- self.inc_v_button = wx.Button (self, 1101, " < ", style=wx.BU_EXACTFIT)
- self.inc_v_button.SetToolTipString ("Increase vertical range")
- wx.EVT_BUTTON (self, 1101, self.incr_v_scale) # ID matches button ID above
-
- self.dec_v_button = wx.Button (self, 1100, " > ", style=wx.BU_EXACTFIT)
- self.dec_v_button.SetToolTipString ("Decrease vertical range")
- wx.EVT_BUTTON (self, 1100, self.decr_v_scale)
-
- self.v_scale_label = wx.StaticText (self, 1002, "None") # vertical /div
- self.update_v_scale_label ()
-
- self.autorange_checkbox = wx.CheckBox (self, 1102, "Autorange")
- self.autorange_checkbox.SetToolTipString ("Select autorange on/off")
- wx.EVT_CHECKBOX(self, 1102, self.autorange_checkbox_event)
-
- ctrlbox.Add ((5,0) ,0) # left margin space
- ctrlbox.Add (self.inc_v_button, 0, wx.EXPAND)
- ctrlbox.Add (self.dec_v_button, 0, wx.EXPAND)
- ctrlbox.Add (self.v_scale_label, 0, wx.ALIGN_CENTER)
- ctrlbox.Add ((20,0) ,0) # spacer
- ctrlbox.Add (self.autorange_checkbox, 0, wx.ALIGN_CENTER)
-
- return ctrlbox
-
- def make_control_box (self):
- ctrlbox = wx.BoxSizer (wx.HORIZONTAL)
-
- tb_left = wx.Button (self, 1001, " < ", style=wx.BU_EXACTFIT)
- tb_left.SetToolTipString ("Increase time base")
- wx.EVT_BUTTON (self, 1001, self.incr_timebase)
-
-
- tb_right = wx.Button (self, 1000, " > ", style=wx.BU_EXACTFIT)
- tb_right.SetToolTipString ("Decrease time base")
- wx.EVT_BUTTON (self, 1000, self.decr_timebase)
-
- self.time_base_label = wx.StaticText (self, 1002, "")
- self.update_timebase_label ()
-
- ctrlbox.Add ((5,0) ,0)
- # ctrlbox.Add (wx.StaticText (self, -1, "Horiz Scale: "), 0, wx.ALIGN_CENTER)
- ctrlbox.Add (tb_left, 0, wx.EXPAND)
- ctrlbox.Add (tb_right, 0, wx.EXPAND)
- ctrlbox.Add (self.time_base_label, 0, wx.ALIGN_CENTER)
-
- ctrlbox.Add ((10,0) ,1) # stretchy space
-
- ctrlbox.Add (wx.StaticText (self, -1, "Trig: "), 0, wx.ALIGN_CENTER)
- self.trig_chan_choice = wx.Choice (self, 1004,
- choices = ['Ch1', 'Ch2', 'Ch3', 'Ch4'])
- self.trig_chan_choice.SetToolTipString ("Select channel for trigger")
- wx.EVT_CHOICE (self, 1004, self.trig_chan_choice_event)
- ctrlbox.Add (self.trig_chan_choice, 0, wx.ALIGN_CENTER)
-
- self.trig_mode_choice = wx.Choice (self, 1005,
- choices = ['Auto', 'Pos', 'Neg'])
- self.trig_mode_choice.SetToolTipString ("Select trigger slope or Auto (untriggered roll)")
- wx.EVT_CHOICE (self, 1005, self.trig_mode_choice_event)
- ctrlbox.Add (self.trig_mode_choice, 0, wx.ALIGN_CENTER)
-
- trig_level50 = wx.Button (self, 1006, "50%")
- trig_level50.SetToolTipString ("Set trigger level to 50%")
- wx.EVT_BUTTON (self, 1006, self.set_trig_level50)
- ctrlbox.Add (trig_level50, 0, wx.EXPAND)
-
- run_stop = wx.Button (self, 1007, "Run/Stop")
- run_stop.SetToolTipString ("Toggle Run/Stop mode")
- wx.EVT_BUTTON (self, 1007, self.run_stop)
- ctrlbox.Add (run_stop, 0, wx.EXPAND)
-
- ctrlbox.Add ((10, 0) ,1) # stretchy space
-
- ctrlbox.Add (wx.StaticText (self, -1, "Fmt: "), 0, wx.ALIGN_CENTER)
- self.marker_choice = wx.Choice (self, 1002, choices = self._marker_choices)
- self.marker_choice.SetToolTipString ("Select plotting with lines, pluses or dots")
- wx.EVT_CHOICE (self, 1002, self.marker_choice_event)
- ctrlbox.Add (self.marker_choice, 0, wx.ALIGN_CENTER)
-
- self.xy_choice = wx.Choice (self, 1003, choices = ['X:t', 'X:Y'])
- self.xy_choice.SetToolTipString ("Select X vs time or X vs Y display")
- wx.EVT_CHOICE (self, 1003, self.xy_choice_event)
- ctrlbox.Add (self.xy_choice, 0, wx.ALIGN_CENTER)
-
- return ctrlbox
-
- _marker_choices = ['line', 'plus', 'dot']
-
- def update_timebase_label (self):
- time_per_div = self.info.get_time_per_div ()
- s = ' ' + eng_notation.num_to_str (time_per_div) + 's/div'
- self.time_base_label.SetLabel (s)
-
- def decr_timebase (self, evt):
- self.info.time_scale_cursor.prev ()
- self.update_timebase_label ()
-
- def incr_timebase (self, evt):
- self.info.time_scale_cursor.next ()
- self.update_timebase_label ()
-
- def update_v_scale_label (self):
- volts_per_div = self.info.get_volts_per_div ()
- s = ' ' + eng_notation.num_to_str (volts_per_div) + '/div' # Not V/div
- self.v_scale_label.SetLabel (s)
-
- def decr_v_scale (self, evt):
- self.info.v_scale_cursor.prev ()
- self.update_v_scale_label ()
-
- def incr_v_scale (self, evt):
- self.info.v_scale_cursor.next ()
- self.update_v_scale_label ()
-
- def marker_choice_event (self, evt):
- s = evt.GetString ()
- self.set_marker (s)
-
- def set_autorange(self, on):
- if on:
- self.v_scale_label.SetLabel(" (auto)")
- self.info.autorange = True
- self.autorange_checkbox.SetValue(True)
- self.inc_v_button.Enable(False)
- self.dec_v_button.Enable(False)
- else:
- if self.graph.y_range:
- (l,u) = self.graph.y_range # found by autorange
- self.info.v_scale_cursor.set_index_by_value((u-l)/8.0)
- self.update_v_scale_label()
- self.info.autorange = False
- self.autorange_checkbox.SetValue(False)
- self.inc_v_button.Enable(True)
- self.dec_v_button.Enable(True)
-
- def autorange_checkbox_event(self, evt):
- if evt.Checked():
- self.set_autorange(True)
- else:
- self.set_autorange(False)
-
- def set_marker (self, s):
- self.info.set_marker (s) # set info for drawing routines
- i = self.marker_choice.FindString (s)
- assert i >= 0, "Hmmm, set_marker problem"
- self.marker_choice.SetSelection (i)
-
- def set_format_line (self):
- self.set_marker ('line')
-
- def set_format_dot (self):
- self.set_marker ('dot')
-
- def set_format_plus (self):
- self.set_marker ('plus')
-
- def xy_choice_event (self, evt):
- s = evt.GetString ()
- self.info.xy = s == 'X:Y'
-
- def trig_chan_choice_event (self, evt):
- s = evt.GetString ()
- ch = int (s[-1]) - 1
- self.info.scopesink.set_trigger_channel (ch)
-
- def trig_mode_choice_event (self, evt):
- sink = self.info.scopesink
- s = evt.GetString ()
- if s == 'Pos':
- sink.set_trigger_mode (gr.gr_TRIG_POS_SLOPE)
- elif s == 'Neg':
- sink.set_trigger_mode (gr.gr_TRIG_NEG_SLOPE)
- elif s == 'Auto':
- sink.set_trigger_mode (gr.gr_TRIG_AUTO)
- else:
- assert 0, "Bad trig_mode_choice string"
-
- def set_trig_level50 (self, evt):
- self.info.scopesink.set_trigger_level_auto ()
-
- def run_stop (self, evt):
- self.info.running = not self.info.running
-
-
-class graph_window (plot.PlotCanvas):
-
- channel_colors = ['BLUE', 'RED',
- 'CYAN', 'MAGENTA', 'GREEN', 'YELLOW']
-
- def __init__ (self, info, parent, id = -1,
- pos = wx.DefaultPosition, size = (640, 240),
- style = wx.DEFAULT_FRAME_STYLE, name = ""):
- plot.PlotCanvas.__init__ (self, parent, id, pos, size, style, name)
-
- self.SetXUseScopeTicks (True)
- self.SetEnableGrid (True)
- self.SetEnableZoom (True)
- self.SetEnableLegend(True)
- # self.SetBackgroundColour ('black')
-
- self.info = info;
- self.y_range = None
- self.x_range = None
- self.avg_y_min = None
- self.avg_y_max = None
- self.avg_x_min = None
- self.avg_x_max = None
-
- EVT_DATA_EVENT (self, self.format_data)
-
- self.input_watcher = input_watcher (info.msgq, self, info.frame_decim)
-
- def channel_color (self, ch):
- return self.channel_colors[ch % len(self.channel_colors)]
-
- def format_data (self, evt):
- if not self.info.running:
- return
-
- if self.info.xy:
- self.format_xy_data (evt)
- return
-
- info = self.info
- records = evt.data
- nchannels = len (records)
- npoints = len (records[0])
-
- objects = []
-
- Ts = 1.0 / (info.get_sample_rate () / info.get_decimation_rate ())
- x_vals = Ts * numpy.arange (-npoints/2, npoints/2)
-
- # preliminary clipping based on time axis here, instead of in graphics code
- time_per_window = self.info.get_time_per_div () * 10
- n = int (time_per_window / Ts + 0.5)
- n = n & ~0x1 # make even
- n = max (2, min (n, npoints))
-
- self.SetXUseScopeTicks (True) # use 10 divisions, no labels
-
- for ch in range(nchannels):
- r = records[ch]
-
- # plot middle n points of record
-
- lb = npoints/2 - n/2
- ub = npoints/2 + n/2
- # points = zip (x_vals[lb:ub], r[lb:ub])
- points = numpy.zeros ((ub-lb, 2), numpy.float64)
- points[:,0] = x_vals[lb:ub]
- points[:,1] = r[lb:ub]
-
- m = info.get_marker ()
- if m == 'line':
- objects.append (plot.PolyLine (points,
- colour=self.channel_color (ch),
- legend=('Ch%d' % (ch+1,))))
- else:
- objects.append (plot.PolyMarker (points,
- marker=m,
- colour=self.channel_color (ch),
- legend=('Ch%d' % (ch+1,))))
-
- graphics = plot.PlotGraphics (objects,
- title=self.info.title,
- xLabel = '', yLabel = '')
-
- time_per_div = info.get_time_per_div ()
- x_range = (-5.0 * time_per_div, 5.0 * time_per_div) # ranges are tuples!
- volts_per_div = info.get_volts_per_div ()
- if not self.info.autorange:
- self.y_range = (-4.0 * volts_per_div, 4.0 * volts_per_div)
- self.Draw (graphics, xAxis=x_range, yAxis=self.y_range)
- self.update_y_range () # autorange to self.y_range
-
-
- def format_xy_data (self, evt):
- info = self.info
- records = evt.data
- nchannels = len (records)
- npoints = len (records[0])
-
- if nchannels < 2:
- return
-
- objects = []
- # points = zip (records[0], records[1])
- points = numpy.zeros ((len(records[0]), 2), numpy.float32)
- points[:,0] = records[0]
- points[:,1] = records[1]
-
- self.SetXUseScopeTicks (False)
-
- m = info.get_marker ()
- if m == 'line':
- objects.append (plot.PolyLine (points,
- colour=self.channel_color (0)))
- else:
- objects.append (plot.PolyMarker (points,
- marker=m,
- colour=self.channel_color (0)))
-
- graphics = plot.PlotGraphics (objects,
- title=self.info.title,
- xLabel = 'I', yLabel = 'Q')
-
- self.Draw (graphics, xAxis=self.x_range, yAxis=self.y_range)
- self.update_y_range ()
- self.update_x_range ()
-
-
- def update_y_range (self):
- alpha = 1.0/25
- graphics = self.last_draw[0]
- p1, p2 = graphics.boundingBox () # min, max points of graphics
-
- if self.avg_y_min: # prevent vertical scale from jumping abruptly --?
- self.avg_y_min = p1[1] * alpha + self.avg_y_min * (1 - alpha)
- self.avg_y_max = p2[1] * alpha + self.avg_y_max * (1 - alpha)
- else: # initial guess
- self.avg_y_min = p1[1] # -500.0 workaround, sometimes p1 is ~ 10^35
- self.avg_y_max = p2[1] # 500.0
-
- self.y_range = self._axisInterval ('auto', self.avg_y_min, self.avg_y_max)
- # print "p1 %s p2 %s y_min %s y_max %s y_range %s" \
- # % (p1, p2, self.avg_y_min, self.avg_y_max, self.y_range)
-
-
- def update_x_range (self):
- alpha = 1.0/25
- graphics = self.last_draw[0]
- p1, p2 = graphics.boundingBox () # min, max points of graphics
-
- if self.avg_x_min:
- self.avg_x_min = p1[0] * alpha + self.avg_x_min * (1 - alpha)
- self.avg_x_max = p2[0] * alpha + self.avg_x_max * (1 - alpha)
- else:
- self.avg_x_min = p1[0]
- self.avg_x_max = p2[0]
-
- self.x_range = self._axisInterval ('auto', self.avg_x_min, self.avg_x_max)
-
-
-# ----------------------------------------------------------------
-# Stand-alone test application
-# ----------------------------------------------------------------
-
-class test_app_flow_graph (stdgui.gui_flow_graph):
- def __init__(self, frame, panel, vbox, argv):
- stdgui.gui_flow_graph.__init__ (self, frame, panel, vbox, argv)
-
- if len(argv) > 1:
- frame_decim = int(argv[1])
- else:
- frame_decim = 1
-
- if len(argv) > 2:
- v_scale = float(argv[2]) # start up at this v_scale value
- else:
- v_scale = None # start up in autorange mode, default
-
- if len(argv) > 3:
- t_scale = float(argv[3]) # start up at this t_scale value
- else:
- t_scale = None # old behavior
-
- print "frame decim %s v_scale %s t_scale %s" % (frame_decim,v_scale,t_scale)
-
- input_rate = 1e6
-
- # Generate a complex sinusoid
- src0 = gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 25.1e3, 1e3)
-
- # We add this throttle block so that this demo doesn't suck down
- # all the CPU available. You normally wouldn't use it...
- throttle = gr.throttle(gr.sizeof_gr_complex, input_rate)
-
- scope = scope_sink_c (self, panel,"Secret Data",sample_rate=input_rate,
- frame_decim=frame_decim,
- v_scale=v_scale, t_scale=t_scale)
- vbox.Add (scope.win, 1, wx.EXPAND)
-
- # wire the blocks together
- self.connect (src0, throttle, scope)
-
-def main ():
- app = stdgui.stdapp (test_app_flow_graph, "O'Scope Test App")
- app.MainLoop ()
-
-if __name__ == '__main__':
- main ()
-
-# ----------------------------------------------------------------
diff --git a/gr-wxgui/src/python/stdgui.py b/gr-wxgui/src/python/stdgui.py
deleted file mode 100644
index 178739547..000000000
--- a/gr-wxgui/src/python/stdgui.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#
-# Copyright 2004 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.
-#
-
-'''A simple wx gui for GNU Radio applications'''
-
-import wx
-import sys
-from gnuradio import gr
-
-
-class stdapp (wx.App):
- def __init__ (self, flow_graph_maker, title="GNU Radio", nstatus=2):
- self.flow_graph_maker = flow_graph_maker
- self.title = title
- self._nstatus = nstatus
- # All our initialization must come before calling wx.App.__init__.
- # OnInit is called from somewhere in the guts of __init__.
- wx.App.__init__ (self, redirect=False)
-
- def OnInit (self):
- frame = stdframe (self.flow_graph_maker, self.title, self._nstatus)
- frame.Show (True)
- self.SetTopWindow (frame)
- return True
-
-
-class stdframe (wx.Frame):
- def __init__ (self, flow_graph_maker, title="GNU Radio", nstatus=2):
- # print "stdframe.__init__"
- wx.Frame.__init__(self, None, -1, title)
-
- self.CreateStatusBar (nstatus)
- mainmenu = wx.MenuBar ()
-
- menu = wx.Menu ()
- item = menu.Append (200, 'E&xit', 'Exit')
- self.Bind (wx.EVT_MENU, self.OnCloseWindow, item)
- mainmenu.Append (menu, "&File")
- self.SetMenuBar (mainmenu)
-
- self.Bind (wx.EVT_CLOSE, self.OnCloseWindow)
- self.panel = stdpanel (self, self, flow_graph_maker)
- vbox = wx.BoxSizer(wx.VERTICAL)
- vbox.Add(self.panel, 1, wx.EXPAND)
- self.SetSizer(vbox)
- self.SetAutoLayout(True)
- vbox.Fit(self)
-
- def OnCloseWindow (self, event):
- self.flow_graph().stop()
- self.Destroy ()
-
- def flow_graph (self):
- return self.panel.fg
-
-class stdpanel (wx.Panel):
- def __init__ (self, parent, frame, flow_graph_maker):
- # print "stdpanel.__init__"
- wx.Panel.__init__ (self, parent, -1)
- self.frame = frame
-
- vbox = wx.BoxSizer (wx.VERTICAL)
- self.fg = flow_graph_maker (frame, self, vbox, sys.argv)
- self.SetSizer (vbox)
- self.SetAutoLayout (True)
- vbox.Fit (self)
-
- self.fg.start ()
-
-class gui_flow_graph (gr.flow_graph):
- def __init__ (self, *ignore):
- gr.flow_graph.__init__ (self)
diff --git a/gr-wxgui/src/python/waterfallsink.py b/gr-wxgui/src/python/waterfallsink.py
deleted file mode 100755
index 4803cbeb2..000000000
--- a/gr-wxgui/src/python/waterfallsink.py
+++ /dev/null
@@ -1,475 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2003,2004,2005,2007 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.
-#
-
-from gnuradio import gr, gru, window
-from gnuradio.wxgui import stdgui
-import wx
-import gnuradio.wxgui.plot as plot
-import numpy
-import os
-import threading
-import math
-
-default_fftsink_size = (640,240)
-default_fft_rate = gr.prefs().get_long('wxgui', 'fft_rate', 15)
-
-class waterfall_sink_base(object):
- def __init__(self, input_is_real=False, baseband_freq=0,
- sample_rate=1, fft_size=512,
- fft_rate=default_fft_rate,
- average=False, avg_alpha=None, title=''):
-
- # initialize common attributes
- self.baseband_freq = baseband_freq
- self.sample_rate = sample_rate
- self.fft_size = fft_size
- self.fft_rate = fft_rate
- self.average = average
- if avg_alpha is None:
- self.avg_alpha = 2.0 / fft_rate
- else:
- self.avg_alpha = avg_alpha
- self.title = title
- self.input_is_real = input_is_real
- self.msgq = gr.msg_queue(2) # queue up to 2 messages
-
- def set_average(self, average):
- self.average = average
- if average:
- self.avg.set_taps(self.avg_alpha)
- else:
- self.avg.set_taps(1.0)
-
- def set_avg_alpha(self, avg_alpha):
- self.avg_alpha = avg_alpha
-
- def set_baseband_freq(self, baseband_freq):
- self.baseband_freq = baseband_freq
-
- def set_sample_rate(self, sample_rate):
- self.sample_rate = sample_rate
- self._set_n()
-
- def _set_n(self):
- self.one_in_n.set_n(max(1, int(self.sample_rate/self.fft_size/self.fft_rate)))
-
-class waterfall_sink_f(gr.hier_block, waterfall_sink_base):
- def __init__(self, fg, parent, baseband_freq=0,
- y_per_div=10, ref_level=50, sample_rate=1, fft_size=512,
- fft_rate=default_fft_rate, average=False, avg_alpha=None,
- title='', size=default_fftsink_size):
-
- waterfall_sink_base.__init__(self, input_is_real=True, baseband_freq=baseband_freq,
- sample_rate=sample_rate, fft_size=fft_size,
- fft_rate=fft_rate,
- average=average, avg_alpha=avg_alpha, title=title)
-
- s2p = gr.serial_to_parallel(gr.sizeof_float, self.fft_size)
- self.one_in_n = gr.keep_one_in_n(gr.sizeof_float * self.fft_size,
- max(1, int(self.sample_rate/self.fft_size/self.fft_rate)))
- mywindow = window.blackmanharris(self.fft_size)
- fft = gr.fft_vfc(self.fft_size, True, mywindow)
- c2mag = gr.complex_to_mag(self.fft_size)
- self.avg = gr.single_pole_iir_filter_ff(1.0, self.fft_size)
- log = gr.nlog10_ff(20, self.fft_size, -20*math.log10(self.fft_size))
- sink = gr.message_sink(gr.sizeof_float * self.fft_size, self.msgq, True)
-
- fg.connect (s2p, self.one_in_n, fft, c2mag, self.avg, log, sink)
- gr.hier_block.__init__(self, fg, s2p, sink)
-
- self.win = waterfall_window(self, parent, size=size)
- self.set_average(self.average)
-
-
-class waterfall_sink_c(gr.hier_block, waterfall_sink_base):
- def __init__(self, fg, parent, baseband_freq=0,
- y_per_div=10, ref_level=50, sample_rate=1, fft_size=512,
- fft_rate=default_fft_rate, average=False, avg_alpha=None,
- title='', size=default_fftsink_size):
-
- waterfall_sink_base.__init__(self, input_is_real=False, baseband_freq=baseband_freq,
- sample_rate=sample_rate, fft_size=fft_size,
- fft_rate=fft_rate,
- average=average, avg_alpha=avg_alpha, title=title)
-
- s2p = gr.serial_to_parallel(gr.sizeof_gr_complex, self.fft_size)
- self.one_in_n = gr.keep_one_in_n(gr.sizeof_gr_complex * self.fft_size,
- max(1, int(self.sample_rate/self.fft_size/self.fft_rate)))
-
- mywindow = window.blackmanharris(self.fft_size)
- fft = gr.fft_vcc(self.fft_size, True, mywindow)
- c2mag = gr.complex_to_mag(self.fft_size)
- self.avg = gr.single_pole_iir_filter_ff(1.0, self.fft_size)
- log = gr.nlog10_ff(20, self.fft_size, -20*math.log10(self.fft_size))
- sink = gr.message_sink(gr.sizeof_float * self.fft_size, self.msgq, True)
-
- fg.connect(s2p, self.one_in_n, fft, c2mag, self.avg, log, sink)
- gr.hier_block.__init__(self, fg, s2p, sink)
-
- self.win = waterfall_window(self, parent, size=size)
- self.set_average(self.average)
-
-
-# ------------------------------------------------------------------------
-
-myDATA_EVENT = wx.NewEventType()
-EVT_DATA_EVENT = wx.PyEventBinder (myDATA_EVENT, 0)
-
-
-class DataEvent(wx.PyEvent):
- def __init__(self, data):
- wx.PyEvent.__init__(self)
- self.SetEventType (myDATA_EVENT)
- self.data = data
-
- def Clone (self):
- self.__class__ (self.GetId())
-
-
-class input_watcher (threading.Thread):
- def __init__ (self, msgq, fft_size, event_receiver, **kwds):
- threading.Thread.__init__ (self, **kwds)
- self.setDaemon (1)
- self.msgq = msgq
- self.fft_size = fft_size
- self.event_receiver = event_receiver
- 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 FFT frame in the message.
- # If so, we take only the last one
- if nitems > 1:
- start = itemsize * (nitems - 1)
- s = s[start:start+itemsize]
-
- complex_data = numpy.fromstring (s, numpy.float32)
- de = DataEvent (complex_data)
- wx.PostEvent (self.event_receiver, de)
- del de
-
-
-class waterfall_window (wx.Panel):
- def __init__ (self, fftsink, parent, id = -1,
- pos = wx.DefaultPosition, size = wx.DefaultSize,
- style = wx.DEFAULT_FRAME_STYLE, name = ""):
- wx.Panel.__init__(self, parent, id, pos, size, style, name)
-
- self.fftsink = fftsink
- self.bm = wx.EmptyBitmap(self.fftsink.fft_size, 300, -1)
-
- self.scale_factor = 5.0 # FIXME should autoscale, or set this
-
- dc1 = wx.MemoryDC()
- dc1.SelectObject(self.bm)
- dc1.Clear()
-
- self.pens = self.make_pens()
-
- wx.EVT_PAINT( self, self.OnPaint )
- wx.EVT_CLOSE (self, self.on_close_window)
- EVT_DATA_EVENT (self, self.set_data)
-
- self.build_popup_menu()
-
- wx.EVT_CLOSE (self, self.on_close_window)
- self.Bind(wx.EVT_RIGHT_UP, self.on_right_click)
-
- self.input_watcher = input_watcher(fftsink.msgq, fftsink.fft_size, self)
-
-
- def on_close_window (self, event):
- print "waterfall_window: on_close_window"
- self.keep_running = False
-
- def const_list(self,const,len):
- return [const] * len
-
- def make_colormap(self):
- r = []
- r.extend(self.const_list(0,96))
- r.extend(range(0,255,4))
- r.extend(self.const_list(255,64))
- r.extend(range(255,128,-4))
-
- g = []
- g.extend(self.const_list(0,32))
- g.extend(range(0,255,4))
- g.extend(self.const_list(255,64))
- g.extend(range(255,0,-4))
- g.extend(self.const_list(0,32))
-
- b = range(128,255,4)
- b.extend(self.const_list(255,64))
- b.extend(range(255,0,-4))
- b.extend(self.const_list(0,96))
- return (r,g,b)
-
- def make_pens(self):
- (r,g,b) = self.make_colormap()
- pens = []
- for i in range(0,256):
- colour = wx.Colour(r[i], g[i], b[i])
- pens.append( wx.Pen(colour, 2, wx.SOLID))
- return pens
-
- def OnPaint(self, event):
- dc = wx.PaintDC(self)
- self.DoDrawing(dc)
-
- def DoDrawing(self, dc=None):
- if dc is None:
- dc = wx.ClientDC(self)
- dc.DrawBitmap(self.bm, 0, 0, False )
-
-
- def const_list(self,const,len):
- a = [const]
- for i in range(1,len):
- a.append(const)
- return a
-
- def make_colormap(self):
- r = []
- r.extend(self.const_list(0,96))
- r.extend(range(0,255,4))
- r.extend(self.const_list(255,64))
- r.extend(range(255,128,-4))
-
- g = []
- g.extend(self.const_list(0,32))
- g.extend(range(0,255,4))
- g.extend(self.const_list(255,64))
- g.extend(range(255,0,-4))
- g.extend(self.const_list(0,32))
-
- b = range(128,255,4)
- b.extend(self.const_list(255,64))
- b.extend(range(255,0,-4))
- b.extend(self.const_list(0,96))
- return (r,g,b)
-
- def set_data (self, evt):
- dB = evt.data
- L = len (dB)
-
- dc1 = wx.MemoryDC()
- dc1.SelectObject(self.bm)
- dc1.Blit(0,1,self.fftsink.fft_size,300,dc1,0,0,wx.COPY,False,-1,-1)
-
- x = max(abs(self.fftsink.sample_rate), abs(self.fftsink.baseband_freq))
- if x >= 1e9:
- sf = 1e-9
- units = "GHz"
- elif x >= 1e6:
- sf = 1e-6
- units = "MHz"
- else:
- sf = 1e-3
- units = "kHz"
-
-
- if self.fftsink.input_is_real: # only plot 1/2 the points
- d_max = L/2
- p_width = 2
- else:
- d_max = L/2
- p_width = 1
-
- scale_factor = self.scale_factor
- if self.fftsink.input_is_real: # real fft
- for x_pos in range(0, d_max):
- value = int(dB[x_pos] * scale_factor)
- value = min(255, max(0, value))
- dc1.SetPen(self.pens[value])
- dc1.DrawRectangle(x_pos*p_width, 0, p_width, 1)
- else: # complex fft
- for x_pos in range(0, d_max): # positive freqs
- value = int(dB[x_pos] * scale_factor)
- value = min(255, max(0, value))
- dc1.SetPen(self.pens[value])
- dc1.DrawRectangle(x_pos*p_width + d_max, 0, p_width, 1)
- for x_pos in range(0 , d_max): # negative freqs
- value = int(dB[x_pos+d_max] * scale_factor)
- value = min(255, max(0, value))
- dc1.SetPen(self.pens[value])
- dc1.DrawRectangle(x_pos*p_width, 0, p_width, 1)
-
- self.DoDrawing (None)
-
- def on_average(self, evt):
- # print "on_average"
- self.fftsink.set_average(evt.IsChecked())
-
- def on_right_click(self, event):
- menu = self.popup_menu
- for id, pred in self.checkmarks.items():
- item = menu.FindItemById(id)
- item.Check(pred())
- self.PopupMenu(menu, event.GetPosition())
-
-
- def build_popup_menu(self):
- self.id_incr_ref_level = wx.NewId()
- self.id_decr_ref_level = wx.NewId()
- self.id_incr_y_per_div = wx.NewId()
- self.id_decr_y_per_div = wx.NewId()
- self.id_y_per_div_1 = wx.NewId()
- self.id_y_per_div_2 = wx.NewId()
- self.id_y_per_div_5 = wx.NewId()
- self.id_y_per_div_10 = wx.NewId()
- self.id_y_per_div_20 = wx.NewId()
- self.id_average = wx.NewId()
-
- self.Bind(wx.EVT_MENU, self.on_average, id=self.id_average)
- #self.Bind(wx.EVT_MENU, self.on_incr_ref_level, id=self.id_incr_ref_level)
- #self.Bind(wx.EVT_MENU, self.on_decr_ref_level, id=self.id_decr_ref_level)
- #self.Bind(wx.EVT_MENU, self.on_incr_y_per_div, id=self.id_incr_y_per_div)
- #self.Bind(wx.EVT_MENU, self.on_decr_y_per_div, id=self.id_decr_y_per_div)
- #self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_1)
- #self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_2)
- #self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_5)
- #self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_10)
- #self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_20)
-
-
- # make a menu
- menu = wx.Menu()
- self.popup_menu = menu
- menu.AppendCheckItem(self.id_average, "Average")
- # menu.Append(self.id_incr_ref_level, "Incr Ref Level")
- # menu.Append(self.id_decr_ref_level, "Decr Ref Level")
- # menu.Append(self.id_incr_y_per_div, "Incr dB/div")
- # menu.Append(self.id_decr_y_per_div, "Decr dB/div")
- # menu.AppendSeparator()
- # we'd use RadioItems for these, but they're not supported on Mac
- #menu.AppendCheckItem(self.id_y_per_div_1, "1 dB/div")
- #menu.AppendCheckItem(self.id_y_per_div_2, "2 dB/div")
- #menu.AppendCheckItem(self.id_y_per_div_5, "5 dB/div")
- #menu.AppendCheckItem(self.id_y_per_div_10, "10 dB/div")
- #menu.AppendCheckItem(self.id_y_per_div_20, "20 dB/div")
-
- self.checkmarks = {
- self.id_average : lambda : self.fftsink.average
- #self.id_y_per_div_1 : lambda : self.fftsink.y_per_div == 1,
- #self.id_y_per_div_2 : lambda : self.fftsink.y_per_div == 2,
- #self.id_y_per_div_5 : lambda : self.fftsink.y_per_div == 5,
- #self.id_y_per_div_10 : lambda : self.fftsink.y_per_div == 10,
- #self.id_y_per_div_20 : lambda : self.fftsink.y_per_div == 20,
- }
-
-
-def next_up(v, seq):
- """
- Return the first item in seq that is > v.
- """
- for s in seq:
- if s > v:
- return s
- return v
-
-def next_down(v, seq):
- """
- Return the last item in seq that is < v.
- """
- rseq = list(seq[:])
- rseq.reverse()
-
- for s in rseq:
- if s < v:
- return s
- return v
-
-
-# ----------------------------------------------------------------
-# Deprecated interfaces
-# ----------------------------------------------------------------
-
-# returns (block, win).
-# block requires a single input stream of float
-# win is a subclass of wxWindow
-
-def make_waterfall_sink_f(fg, parent, title, fft_size, input_rate):
-
- block = waterfall_sink_f(fg, parent, title=title, fft_size=fft_size,
- sample_rate=input_rate)
- return (block, block.win)
-
-# returns (block, win).
-# block requires a single input stream of gr_complex
-# win is a subclass of wxWindow
-
-def make_waterfall_sink_c(fg, parent, title, fft_size, input_rate):
- block = waterfall_sink_c(fg, parent, title=title, fft_size=fft_size,
- sample_rate=input_rate)
- return (block, block.win)
-
-
-# ----------------------------------------------------------------
-# Standalone test app
-# ----------------------------------------------------------------
-
-class test_app_flow_graph (stdgui.gui_flow_graph):
- def __init__(self, frame, panel, vbox, argv):
- stdgui.gui_flow_graph.__init__ (self, frame, panel, vbox, argv)
-
- fft_size = 512
-
- # build our flow graph
- input_rate = 20.000e3
-
- # Generate a complex sinusoid
- src1 = gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 5.75e3, 1000)
- #src1 = gr.sig_source_c (input_rate, gr.GR_CONST_WAVE, 5.75e3, 1000)
-
- # We add these throttle blocks so that this demo doesn't
- # suck down all the CPU available. Normally you wouldn't use these.
- thr1 = gr.throttle(gr.sizeof_gr_complex, input_rate)
-
- sink1 = waterfall_sink_c (self, panel, title="Complex Data", fft_size=fft_size,
- sample_rate=input_rate, baseband_freq=100e3)
- vbox.Add (sink1.win, 1, wx.EXPAND)
- self.connect (src1, thr1, sink1)
-
- # generate a real sinusoid
- src2 = gr.sig_source_f (input_rate, gr.GR_SIN_WAVE, 5.75e3, 1000)
- #src2 = gr.sig_source_f (input_rate, gr.GR_CONST_WAVE, 5.75e3, 1000)
- thr2 = gr.throttle(gr.sizeof_float, input_rate)
- sink2 = waterfall_sink_f (self, panel, title="Real Data", fft_size=fft_size,
- sample_rate=input_rate, baseband_freq=100e3)
- vbox.Add (sink2.win, 1, wx.EXPAND)
- self.connect (src2, thr2, sink2)
-
-def main ():
- app = stdgui.stdapp (test_app_flow_graph,
- "Waterfall Sink Test App")
- app.MainLoop ()
-
-if __name__ == '__main__':
- main ()