Achilleas Anastasopoulos wrote: > Martin, > > I think the display code can be uploaded to the trunk. > All the tests that I have tried work fine. > We can always clean up the code later if needed. > > I can do that if there is no objection > Achilleas Fine with me,
Martin > > > Martin Dvh wrote: > >> Achilleas Anastasopoulos wrote: >> >>> Martin, >>> >>> thanks for the block. >>> Indeed it is exactly what I wanted (and even more)!!! >>> >>> One question: since a throttle is not attached to this block, >>> why do we need separate sample_rate and number_rate parameters? >>> The only place I saw them used is >>> >>> one_in_n = gr.keep_one_in_n(gr.sizeof_float, >>> max(1, int(sample_rate/number_rate))) >>> >>> which implies that only the ratio of sample_rate/number_rate >>> is important. Unless number_rate actually controls the >>> real rate at which numbers are displayed (which I cannot figure out >>> how)... >> >> >> The number_rate limits the outputting of numbers to the screen. >> If this would get more then around 50 numbers/sec this will use up all >> display resources and your gui will freeze. >> (xfree can't display more numbers/sec then your monitors refreshrate >> anyway) >> >> This is the same effect you get when using the fftsink with a too high >> fft_rate. >> >> Martin >> >>> Thanks >>> Achilleas >>> >>> >>> Martin Dvh wrote: >>> >>> >>>> Achilleas Anastasopoulos wrote: >>>> >>>> >>>>> Hi, >>>>> >>>>> it would be very useful to have a >>>>> wx sink that displays the value of its input. >>>>> This way we can check in real time values >>>>> that change slowly (eg, snr, bit error rate, etc.) >>>> >>>> >>>> >>>> Your widh is my command: >>>> Attached is a patch which adds a number_sink_f and number_sink_c to >>>> gr-wxgui. >>>> You must apply it in the root of your gnuradio tree. >>>> patch -p0 <numbersink.patch >>>> >>>> You can also find it in gr-wxgui in my work-in-progress development >>>> tree in svn: >>>> gnuradio/branches/developers/nldudok1/general-wip >>>> >>>> You use it in the following way: >>>> >>>> from gnuradio.wxgui import numbersink >>>> >>>> numsink = numbersink.number_sink_f (self, panel, >>>> unit='volts',label="input level", avg_alpha=1.0e-5,average=True, >>>> sample_rate=input_rate/sw_decim, >>>> factor=1.0,base_value=0, >>>> minval=-100.0, maxval=100.0, >>>> ref_level=0, decimal_places=5,number_rate=15) >>>> vbox.Add (numsink.win, 1, wx.EXPAND) >>>> self.connect(some_float_source,numsink) >>>> >>>> You can set several options by right-mouse-click. >>>> (Show gauge, number of digits, avaraging) >>>> You use it just like an oscope or fft sink. >>>> >>>> the parameters: >>>> fg flowgraph, the flowgraph (use self if you work with a >>>> stdgui.gui_flow_graph) >>>> parent wxguipanel, The wxgui parent (use panel if you work with a >>>> stdgui.gui_flow_graph) >>>> unit string, the unit you want to display, for example 'volt' >>>> or 'Watt', free text. >>>> base_value float, an offset which is added to the value >>>> minval float, min value for the gauge >>>> maxval float, max value for the gauge >>>> factor float, scaling factor, value is multiplied by this (sort >>>> of gain) >>>> decimal_places int, the number of decimal places shown >>>> ref_level ignored (API compatibility with scope and fft-sink) >>>> sample_rate float, samplerate of input >>>> number_rate float or int, rate at which values are displayed >>>> (framerate, default is 15) >>>> average bool, use averaging or not >>>> avg_alpha float, average alpha, determines the speed of averaging >>>> label string, the label which goes with this value (for example >>>> 'frequency' or 'input power') >>>> size default=(640,240), the graphical size of this numbersink >>>> peak_hold bool, hold at peak or not. >>>> >>>> >>>> >>>>> Unfortunately there is no how_to_write_a_wx_block >>>>> so I have no idea how to go about it. >>>>> >>>>> If someone can help me by providing a stripped down >>>>> version of one of the wx sinks (*eg, the oscope, or fft) >>>>> then I can take a crack at it. >>>>> Even better if one can implement this :-) >>>> >>>> >>>> >>>> I hope you like it. >>>> >>>> Eric, is this maybe something for trunk. >>>> I don't know if the code is clean enough. >>>> >>>> Greetings, >>>> Martin >>>> >>>> >>>>> Thanks, >>>>> Achilleas >>>>> >>>>> >>>>> _______________________________________________ >>>>> Discuss-gnuradio mailing list >>>>> [email protected] >>>>> http://lists.gnu.org/mailman/listinfo/discuss-gnuradio >>>>> >>>> >>>> >>>> >>>> ------------------------------------------------------------------------ >>>> >>>> >>>> Index: gr-wxgui/src/python/numbersink.py >>>> =================================================================== >>>> --- gr-wxgui/src/python/numbersink.py (revision 0) >>>> +++ gr-wxgui/src/python/numbersink.py (revision 0) >>>> @@ -0,0 +1,614 @@ >>>> +#!/usr/bin/env python >>>> +# >>>> +# Copyright 2003,2004,2005,2006 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 2, 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 Numeric >>>> +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 = Numeric.fromstring (s, Numeric.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 = Numeric.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 () >>>> >>>> Property changes on: gr-wxgui/src/python/numbersink.py >>>> ___________________________________________________________________ >>>> Name: svn:executable >>>> + * >>>> >>>> Index: gr-wxgui/src/python/Makefile.am >>>> =================================================================== >>>> --- gr-wxgui/src/python/Makefile.am (revision 4343) >>>> +++ gr-wxgui/src/python/Makefile.am (working copy) >>>> @@ -37,4 +37,5 @@ >>>> scopesink.py \ >>>> waterfallsink.py \ >>>> slider.py \ >>>> - stdgui.py + stdgui.py \ >>>> + numbersink.py >>> >>> >>> >> >> > _______________________________________________ Discuss-gnuradio mailing list [email protected] http://lists.gnu.org/mailman/listinfo/discuss-gnuradio
