discuss-gnuradio
[Top][All Lists]
Advanced

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

Re: [Discuss-gnuradio] Simple display sink in wx


From: Martin Dvh
Subject: Re: [Discuss-gnuradio] Simple display sink in wx
Date: Mon, 19 Feb 2007 00:06:12 +0100
User-agent: Debian Thunderbird 1.0.2 (X11/20070113)

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
>>>>> address@hidden
>>>>> 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       
>>>
>>>
>>>
>>
>>
> 





reply via email to

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