Changeset 8581

Show
Ignore:
Timestamp:
06/11/08 18:29:56
Author:
jblum
Message:

fft sink gui with control panel

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • gnuradio/trunk/gr-wxgui/src/python/fftsink2.py

    r8279 r8581  
    6969        else: 
    7070            self.avg.set_taps(1.0) 
    71        self.win.peak_vals = None 
    72          
     71        self.win.peak_vals = None 
     72         
    7373    def set_peak_hold(self, enable): 
    7474        self.peak_hold = enable 
     
    121121        # FIXME  We need to add 3dB to all bins but the DC bin 
    122122        self.log = gr.nlog10_ff(20, self.fft_size, 
    123                                -10*math.log10(self.fft_size)           # Adjust for number of bins 
    124                               -10*math.log10(power/self.fft_size)      # Adjust for windowing loss 
    125                               -20*math.log10(ref_scale/2))             # Adjust for reference scale 
    126                                
     123                               -10*math.log10(self.fft_size)                # Adjust for number of bins 
     124                               -10*math.log10(power/self.fft_size)        # Adjust for windowing loss 
     125                               -20*math.log10(ref_scale/2))                # Adjust for reference scale 
     126                                
    127127        self.sink = gr.message_sink(gr.sizeof_float * self.fft_size, self.msgq, True) 
    128        self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink) 
     128        self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink) 
    129129 
    130130        self.win = fft_window(self, parent, size=size) 
    131131        self.set_average(self.average) 
    132  
     132        self.set_peak_hold(self.peak_hold) 
    133133 
    134134class fft_sink_c(gr.hier_block2, fft_sink_base): 
     
    164164        # FIXME  We need to add 3dB to all bins but the DC bin 
    165165        self.log = gr.nlog10_ff(20, self.fft_size, 
    166                                 -10*math.log10(self.fft_size)          # Adjust for number of bins 
    167                                -10*math.log10(power/self.fft_size)     # Adjust for windowing loss 
    168                                -20*math.log10(ref_scale/2))            # Adjust for reference scale 
    169                                  
     166                                -10*math.log10(self.fft_size)                # Adjust for number of bins 
     167                                -10*math.log10(power/self.fft_size)        # Adjust for windowing loss 
     168                                -20*math.log10(ref_scale/2))                # Adjust for reference scale 
     169                                 
    170170        self.sink = gr.message_sink(gr.sizeof_float * self.fft_size, self.msgq, True) 
    171        self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink) 
     171        self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink) 
    172172 
    173173        self.win = fft_window(self, parent, size=size) 
    174174        self.set_average(self.average) 
     175        self.set_peak_hold(self.peak_hold) 
    175176 
    176177 
     
    219220            wx.PostEvent (self.event_receiver, de) 
    220221            del de 
     222 
     223class LabelText(wx.StaticText): 
     224    """Label text class for uniform labels among all controls.""" 
    221225     
    222  
    223 class fft_window (plot.PlotCanvas): 
     226    def __init__(self, window, label): 
     227        wx.StaticText.__init__(self, window, -1, str(label)) 
     228        font = self.GetFont() 
     229        font.SetWeight(wx.FONTWEIGHT_BOLD) 
     230        font.SetUnderlined(True) 
     231        self.SetFont(font) 
     232 
     233DIV_LEVELS = (1, 2, 5, 10, 20) 
     234 
     235class control_panel(wx.Panel): 
     236    def __init__(self, parent): 
     237        self.parent = parent 
     238        wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)     
     239        control_box = wx.BoxSizer(wx.VERTICAL) 
     240         
     241        #checkboxes for average and peak hold 
     242        control_box.Add(LabelText(self, 'Options'), 0, wx.ALIGN_CENTER) 
     243        self.average_check_box = wx.CheckBox(parent=self, style=wx.CHK_2STATE, label="Average") 
     244        self.average_check_box.SetValue(parent.fftsink.average) 
     245        self.average_check_box.Bind(wx.EVT_CHECKBOX, parent.on_average) 
     246        control_box.Add(self.average_check_box, 0, wx.EXPAND) 
     247        self.peak_hold_check_box = wx.CheckBox(parent=self, style=wx.CHK_2STATE, label="Peak Hold") 
     248        self.peak_hold_check_box.SetValue(parent.fftsink.peak_hold) 
     249        self.peak_hold_check_box.Bind(wx.EVT_CHECKBOX, parent.on_peak_hold)  
     250        control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND) 
     251        
     252        #radio buttons for div size 
     253        control_box.Add(LabelText(self, 'Set dB/div'), 0, wx.ALIGN_CENTER) 
     254        radio_box = wx.BoxSizer(wx.VERTICAL) 
     255        self.radio_buttons = list() 
     256        for y_per_div in DIV_LEVELS: 
     257            radio_button = wx.RadioButton(self, -1, "%d dB/div"%y_per_div) 
     258            radio_button.SetValue(parent.fftsink.y_per_div == y_per_div) 
     259            radio_button.Bind(wx.EVT_RADIOBUTTON, self.on_radio_button_change) 
     260            self.radio_buttons.append(radio_button) 
     261            radio_box.Add(radio_button, 0, wx.ALIGN_LEFT) 
     262        control_box.Add(radio_box, 0, wx.EXPAND) 
     263         
     264        #ref lvl buttons 
     265        control_box.Add(LabelText(self, 'Adj Ref Lvl'), 0, wx.ALIGN_CENTER) 
     266        button_box = wx.BoxSizer(wx.HORIZONTAL)         
     267        self.ref_plus_button = wx.Button(self, -1, '+', style=wx.BU_EXACTFIT) 
     268        self.ref_plus_button.Bind(wx.EVT_BUTTON, parent.on_incr_ref_level) 
     269        button_box.Add(self.ref_plus_button, 0, wx.ALIGN_CENTER) 
     270        self.ref_minus_button = wx.Button(self, -1, ' - ', style=wx.BU_EXACTFIT) 
     271        self.ref_minus_button.Bind(wx.EVT_BUTTON, parent.on_decr_ref_level) 
     272        button_box.Add(self.ref_minus_button, 0, wx.ALIGN_CENTER) 
     273        control_box.Add(button_box, 0, wx.ALIGN_CENTER) 
     274        #set sizer 
     275        self.SetSizerAndFit(control_box) 
     276         
     277    def on_radio_button_change(self, evt): 
     278        selected_radio_button = filter(lambda rb: rb.GetValue(), self.radio_buttons)[0]  
     279        index = self.radio_buttons.index(selected_radio_button) 
     280        self.parent.fftsink.set_y_per_div(DIV_LEVELS[index]) 
     281 
     282class fft_window (wx.Panel): 
    224283    def __init__ (self, fftsink, parent, id = -1, 
    225284                  pos = wx.DefaultPosition, size = wx.DefaultSize, 
    226285                  style = wx.DEFAULT_FRAME_STYLE, name = ""): 
    227         plot.PlotCanvas.__init__ (self, parent, id, pos, size, style, name) 
    228  
     286         
     287        self.fftsink = fftsink 
     288        #init panel and plot  
     289        wx.Panel.__init__(self, parent, -1)                   
     290        self.plot = plot.PlotCanvas(self, id, pos, size, style, name)        
     291        #setup the box with plot and controls 
     292        self.control_panel = control_panel(self) 
     293        main_box = wx.BoxSizer (wx.HORIZONTAL) 
     294        main_box.Add (self.plot, 1, wx.EXPAND) 
     295        main_box.Add (self.control_panel, 0, wx.EXPAND) 
     296        self.SetSizerAndFit(main_box) 
     297         
    229298        self.y_range = None 
    230         self.fftsink = fftsink 
    231299        self.peak_hold = False 
    232300        self.peak_vals = None 
    233301         
    234         self.SetEnableGrid (True) 
     302        self.plot.SetEnableGrid (True) 
    235303        # self.SetEnableZoom (True) 
    236304        # self.SetBackgroundColour ('black') 
    237305         
    238306        self.build_popup_menu() 
    239        self.set_baseband_freq(0.0) 
    240                 
     307        self.set_baseband_freq(0.0) 
     308                 
    241309        EVT_DATA_EVENT (self, self.set_data) 
    242310        wx.EVT_CLOSE (self, self.on_close_window) 
    243         self.Bind(wx.EVT_RIGHT_UP, self.on_right_click) 
    244         self.Bind(wx.EVT_MOTION, self.evt_motion) 
    245          
     311        self.plot.Bind(wx.EVT_RIGHT_UP, self.on_right_click) 
     312        self.plot.Bind(wx.EVT_MOTION, self.evt_motion) 
     313         
    246314        self.input_watcher = input_watcher(fftsink.msgq, fftsink.fft_size, self) 
    247315 
    248316    def set_scale(self, freq): 
    249         x = max(abs(self.fftsink.sample_rate), abs(self.fftsink.baseband_freq))  
     317        x = max(abs(self.fftsink.sample_rate), abs(self.fftsink.baseband_freq))         
    250318        if x >= 1e9: 
    251319            self._scale_factor = 1e-9 
    252320            self._units = "GHz" 
    253            self._format = "%3.6f" 
     321            self._format = "%3.6f" 
    254322        elif x >= 1e6: 
    255323            self._scale_factor = 1e-6 
    256324            self._units = "MHz" 
    257            self._format = "%3.3f" 
     325            self._format = "%3.3f" 
    258326        else: 
    259327            self._scale_factor = 1e-3 
    260328            self._units = "kHz" 
    261            self._format = "%3.3f" 
     329            self._format = "%3.3f" 
    262330 
    263331    def set_baseband_freq(self, baseband_freq): 
    264        if self.peak_hold: 
    265            self.peak_vals = None 
    266        self.set_scale(baseband_freq) 
    267        self.fftsink.set_baseband_freq(baseband_freq) 
    268          
     332        if self.peak_hold: 
     333            self.peak_vals = None 
     334        self.set_scale(baseband_freq) 
     335        self.fftsink.set_baseband_freq(baseband_freq) 
     336         
    269337    def on_close_window (self, event): 
    270338        print "fft_window:on_close_window" 
     
    284352        if self.fftsink.input_is_real:     # only plot 1/2 the points 
    285353            x_vals = ((numpy.arange (L/2) * (self.fftsink.sample_rate  
    286                       * self._scale_factor / L)) 
     354                       * self._scale_factor / L)) 
    287355                      + self.fftsink.baseband_freq * self._scale_factor) 
    288356            self._points = numpy.zeros((len(x_vals), 2), numpy.float64) 
    289357            self._points[:,0] = x_vals 
    290358            self._points[:,1] = dB[0:L/2] 
    291            if self.peak_hold: 
    292                self._peak_points = numpy.zeros((len(x_vals), 2), numpy.float64) 
    293                self._peak_points[:,0] = x_vals 
    294                self._peak_points[:,1] = self.peak_vals[0:L/2] 
     359            if self.peak_hold: 
     360                self._peak_points = numpy.zeros((len(x_vals), 2), numpy.float64) 
     361                self._peak_points[:,0] = x_vals 
     362                self._peak_points[:,1] = self.peak_vals[0:L/2] 
    295363        else: 
    296364            # the "negative freqs" are in the second half of the array 
     
    301369            self._points[:,0] = x_vals 
    302370            self._points[:,1] = numpy.concatenate ((dB[L/2:], dB[0:L/2])) 
    303            if self.peak_hold: 
    304                self._peak_points = numpy.zeros((len(x_vals), 2), numpy.float64) 
    305                self._peak_points[:,0] = x_vals 
    306                self._peak_points[:,1] = numpy.concatenate ((self.peak_vals[L/2:], self.peak_vals[0:L/2])) 
     371            if self.peak_hold: 
     372                self._peak_points = numpy.zeros((len(x_vals), 2), numpy.float64) 
     373                self._peak_points[:,0] = x_vals 
     374                self._peak_points[:,1] = numpy.concatenate ((self.peak_vals[L/2:], self.peak_vals[0:L/2])) 
    307375 
    308376        lines = [plot.PolyLine (self._points, colour='BLUE'),] 
    309        if self.peak_hold: 
    310            lines.append(plot.PolyLine (self._peak_points, colour='GREEN')) 
     377        if self.peak_hold: 
     378            lines.append(plot.PolyLine (self._peak_points, colour='GREEN')) 
    311379 
    312380        graphics = plot.PlotGraphics (lines, 
     
    314382                                      xLabel = self._units, yLabel = "dB") 
    315383 
    316         self.Draw (graphics, xAxis=None, yAxis=self.y_range) 
     384        self.plot.Draw (graphics, xAxis=None, yAxis=self.y_range) 
    317385        self.update_y_range () 
    318386 
     
    325393        ymax = self.fftsink.ref_level 
    326394        ymin = self.fftsink.ref_level - self.fftsink.y_per_div * self.fftsink.y_divs 
    327         self.y_range = self._axisInterval ('min', ymin, ymax) 
     395        self.y_range = self.plot._axisInterval ('min', ymin, ymax) 
    328396 
    329397    def on_average(self, evt): 
     
    372440            item = menu.FindItemById(id) 
    373441            item.Check(pred()) 
    374         self.PopupMenu(menu, event.GetPosition()) 
     442        self.plot.PopupMenu(menu, event.GetPosition()) 
    375443 
    376444    def evt_motion(self, event): 
    377445        if not hasattr(self, "_points"): 
    378            return # Got here before first window data update 
    379             
    380        # Clip to plotted values 
    381         (ux, uy) = self.GetXY(event)      # Scaled position 
     446            return # Got here before first window data update 
     447             
     448        # Clip to plotted values 
     449        (ux, uy) = self.plot.GetXY(event)      # Scaled position 
    382450        x_vals = numpy.array(self._points[:,0]) 
    383451        if ux < x_vals[0] or ux > x_vals[-1]: 
     
    411479        self.id_average = wx.NewId() 
    412480        self.id_peak_hold = wx.NewId() 
    413          
    414         self.Bind(wx.EVT_MENU, self.on_average, id=self.id_average) 
    415         self.Bind(wx.EVT_MENU, self.on_peak_hold, id=self.id_peak_hold) 
    416         self.Bind(wx.EVT_MENU, self.on_incr_ref_level, id=self.id_incr_ref_level) 
    417         self.Bind(wx.EVT_MENU, self.on_decr_ref_level, id=self.id_decr_ref_level) 
    418         self.Bind(wx.EVT_MENU, self.on_incr_y_per_div, id=self.id_incr_y_per_div) 
    419         self.Bind(wx.EVT_MENU, self.on_decr_y_per_div, id=self.id_decr_y_per_div) 
    420         self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_1) 
    421         self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_2) 
    422         self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_5) 
    423         self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_10) 
    424         self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_20) 
     481         
     482        self.plot.Bind(wx.EVT_MENU, self.on_average, id=self.id_average) 
     483        self.plot.Bind(wx.EVT_MENU, self.on_peak_hold, id=self.id_peak_hold) 
     484        self.plot.Bind(wx.EVT_MENU, self.on_incr_ref_level, id=self.id_incr_ref_level) 
     485        self.plot.Bind(wx.EVT_MENU, self.on_decr_ref_level, id=self.id_decr_ref_level) 
     486        self.plot.Bind(wx.EVT_MENU, self.on_incr_y_per_div, id=self.id_incr_y_per_div) 
     487        self.plot.Bind(wx.EVT_MENU, self.on_decr_y_per_div, id=self.id_decr_y_per_div) 
     488        self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_1) 
     489        self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_2) 
     490        self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_5) 
     491        self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_10) 
     492        self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_20) 
    425493         
    426494        # make a menu 
     
    500568        vbox.Add (sink1.win, 1, wx.EXPAND) 
    501569 
    502        self.connect(src1, thr1, sink1) 
     570        self.connect(src1, thr1, sink1) 
    503571 
    504572        #src2 = gr.sig_source_f (input_rate, gr.GR_SIN_WAVE, 2e3, 1) 
     
    510578        vbox.Add (sink2.win, 1, wx.EXPAND) 
    511579 
    512        self.connect(src2, thr2, sink2) 
     580        self.connect(src2, thr2, sink2) 
    513581 
    514582def main ():