Merge remote branch 'nldudok1/gr-wxgui_emulate_analog' into master
authorJohnathan Corgan <jcorgan@corganenterprises.com>
Thu, 13 May 2010 19:29:59 +0000 (12:29 -0700)
committerJohnathan Corgan <jcorgan@corganenterprises.com>
Thu, 13 May 2010 19:29:59 +0000 (12:29 -0700)
* nldudok1/gr-wxgui_emulate_analog:
  Add analog CRT screen afterglow emulation for gr-wxgui

Conflicts:
gr-wxgui/src/python/fftsink_gl.py
gr-wxgui/src/python/fftsink_nongl.py

1  2 
gr-wxgui/src/python/constants.py
gr-wxgui/src/python/fft_window.py
gr-wxgui/src/python/fftsink_gl.py
gr-wxgui/src/python/fftsink_nongl.py
gr-wxgui/src/python/scope_window.py
gr-wxgui/src/python/scopesink_gl.py

index 825f71c3223369ac43ee263685a4bc38c84702a6,517a552832edfbeb19b09c07542b872690b426c5..2e7f33a0cb3d72a40c14bfd0cc9a06050c187560
@@@ -27,6 -27,8 +27,8 @@@ ALPHA_KEY = 'alpha
  AUTORANGE_KEY = 'autorange'
  AVERAGE_KEY = 'average'
  AVG_ALPHA_KEY = 'avg_alpha'
+ EMULATE_ANALOG_KEY = 'emulate_analog'
+ ANALOG_ALPHA_KEY = 'analog_alpha'
  BASEBAND_FREQ_KEY = 'baseband_freq'
  BETA_KEY = 'beta'
  COLOR_MODE_KEY = 'color_mode'
@@@ -69,4 -71,3 +71,4 @@@ MINIMUM_KEY = 'minimum
  NUM_BINS_KEY = 'num_bins'
  FRAME_SIZE_KEY = 'frame_size'
  CHANNEL_OPTIONS_KEY = 'channel_options'
 +SHOW_CONTROL_PANEL_KEY = 'show_control_panel'
index 4ee5520f76167271af35a699266fd20521e9e6c3,67bb65b26e747d93dd5e80bca92e94a7b68c4475..c56dbd7e6ecdf51d16b137766b712dd2fb5c2857
@@@ -37,6 -37,7 +37,7 @@@ import form
  ##################################################
  SLIDER_STEPS = 100
  AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP = -3, 0
+ ANALOG_ALPHA_MIN_EXP, ANALOG_ALPHA_MAX_EXP = -2, 0
  DEFAULT_WIN_SIZE = (600, 300)
  DEFAULT_FRAME_RATE = gr.prefs().get_long('wxgui', 'fft_rate', 30)
  DB_DIV_MIN, DB_DIV_MAX = 1, 20
@@@ -64,8 -65,6 +65,8 @@@ class control_panel(wx.Panel)
                """
                self.parent = parent
                wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
 +              parent[SHOW_CONTROL_PANEL_KEY] = True
 +              parent.subscribe(SHOW_CONTROL_PANEL_KEY, self.Show)
                control_box = wx.BoxSizer(wx.VERTICAL)
                control_box.AddStretchSpacer()
                #checkboxes for average and peak hold
                for widget in (avg_alpha_text, avg_alpha_slider):
                        parent.subscribe(AVERAGE_KEY, widget.Enable)
                        widget.Enable(parent[AVERAGE_KEY])
+                       parent.subscribe(AVERAGE_KEY, widget.ShowItems)
+                         #allways show initially, so room is reserved for them
+                       widget.ShowItems(True) # (parent[AVERAGE_KEY])
+                 parent.subscribe(AVERAGE_KEY, self._update_layout)
+               forms.check_box(
+                       sizer=options_box, parent=self, label='Emulate Analog',
+                       ps=parent, key=EMULATE_ANALOG_KEY,
+               )
+               #static text and slider for analog alpha
+               analog_alpha_text = forms.static_text(
+                       sizer=options_box, parent=self, label='Analog Alpha',
+                       converter=forms.float_converter(lambda x: '%.4f'%x),
+                       ps=parent, key=ANALOG_ALPHA_KEY, width=50,
+               )
+               analog_alpha_slider = forms.log_slider(
+                       sizer=options_box, parent=self,
+                       min_exp=ANALOG_ALPHA_MIN_EXP,
+                       max_exp=ANALOG_ALPHA_MAX_EXP,
+                       num_steps=SLIDER_STEPS,
+                       ps=parent, key=ANALOG_ALPHA_KEY,
+               )
+               for widget in (analog_alpha_text, analog_alpha_slider):
+                       parent.subscribe(EMULATE_ANALOG_KEY, widget.Enable)
+                       widget.Enable(parent[EMULATE_ANALOG_KEY])
+                       parent.subscribe(EMULATE_ANALOG_KEY, widget.ShowItems)
+                         #allways show initially, so room is reserved for them
+                       widget.ShowItems(True) # (parent[EMULATE_ANALOG_KEY])
                
+                 parent.subscribe(EMULATE_ANALOG_KEY, self._update_layout)
                #trace menu
                for trace in TRACES:
                        trace_box = wx.BoxSizer(wx.HORIZONTAL)
                )
                #set sizer
                self.SetSizerAndFit(control_box)
                #mouse wheel event
                def on_mouse_wheel(event):
                        if event.GetWheelRotation() < 0: self._on_incr_ref_level(event)
                self.parent[Y_PER_DIV_KEY] = min(DB_DIV_MAX, common.get_clean_incr(self.parent[Y_PER_DIV_KEY]))
        def _on_decr_db_div(self, event):
                self.parent[Y_PER_DIV_KEY] = max(DB_DIV_MIN, common.get_clean_decr(self.parent[Y_PER_DIV_KEY]))
+       ##################################################
+       # subscriber handlers
+       ##################################################
+         def _update_layout(self,key):
+           # Just ignore the key value we get
+           # we only need to now that the visability or size of something has changed
+           self.parent.Layout()
+           #self.parent.Fit()          
  
  ##################################################
  # FFT window with plotter and control panel
@@@ -183,7 -222,10 +224,10 @@@ class fft_window(wx.Panel, pubsub.pubsu
                avg_alpha_key,
                peak_hold,
                msg_key,
+                 emulate_analog,
+                 analog_alpha,
        ):
                pubsub.pubsub.__init__(self)
                #setup
                self.samples = EMPTY_TRACE
                self[REF_LEVEL_KEY] = ref_level
                self[BASEBAND_FREQ_KEY] = baseband_freq
                self[RUNNING_KEY] = True
+               self[EMULATE_ANALOG_KEY] = emulate_analog
+               self[ANALOG_ALPHA_KEY] = analog_alpha
                for trace in TRACES:
                        #a function that returns a function
                        #so the function wont use local trace
                self.plotter.enable_legend(True)
                self.plotter.enable_point_label(True)
                self.plotter.enable_grid_lines(True)
+                 self.plotter.set_emulate_analog(emulate_analog)
+                 self.plotter.set_analog_alpha(analog_alpha)
                #setup the box with plot and controls
                self.control_panel = control_panel(self)
                main_box = wx.BoxSizer(wx.HORIZONTAL)
                        Y_PER_DIV_KEY, X_DIVS_KEY,
                        Y_DIVS_KEY, REF_LEVEL_KEY,
                ): self.subscribe(key, self.update_grid)
+               self.subscribe(EMULATE_ANALOG_KEY, self.plotter.set_emulate_analog)
+               self.subscribe(ANALOG_ALPHA_KEY, self.plotter.set_analog_alpha)
                #initial update
                self.update_grid()
  
        def autoscale(self, *args):
                """
                Autoscale the fft plot to the last frame.
index 8ddea9a8e3fd0109a737a8f5f49a28478e604b5d,564764487ea3fccb49f26f429a548e27e3ae5e96..0d725ea14b3063a25f71b121cfd8965d84de63cf
@@@ -1,5 -1,5 +1,5 @@@
  #
 -# Copyright 2008 Free Software Foundation, Inc.
 +# Copyright 2008,2009 Free Software Foundation, Inc.
  #
  # This file is part of GNU Radio
  #
@@@ -27,6 -27,7 +27,7 @@@ import commo
  from gnuradio import gr, blks2
  from pubsub import pubsub
  from constants import *
+ import math
  
  ##################################################
  # FFT sink block (wrapper for old wxgui)
@@@ -52,11 -53,20 +53,22 @@@ class _fft_sink_base(gr.hier_block2, co
                title='',
                size=fft_window.DEFAULT_WIN_SIZE,
                peak_hold=False,
 +              win=None,
+                 emulate_analog=False,
+                 analog_alpha=None,
 +              **kwargs #do not end with a comma
        ):
                #ensure avg alpha
                if avg_alpha is None: avg_alpha = 2.0/fft_rate
+                 #ensure analog alpha
+                 if analog_alpha is None: 
+                   actual_fft_rate=float(sample_rate/fft_size)/float(max(1,int(float((sample_rate/fft_size)/fft_rate))))
+                   #print "requested_fft_rate ",fft_rate
+                   #print "actual_fft_rate    ",actual_fft_rate
+                   analog_cutoff_freq=0.5 # Hertz
+                   #calculate alpha from wanted cutoff freq
+                   analog_alpha = 1.0 - math.exp(-2.0*math.pi*analog_cutoff_freq/actual_fft_rate)
+                   
                #init
                gr.hier_block2.__init__(
                        self,
                        ref_scale=ref_scale,
                        avg_alpha=avg_alpha,
                        average=average,
 +                      win=win,
                )
                msgq = gr.msg_queue(2)
                sink = gr.message_sink(gr.sizeof_float*fft_size, msgq, True)
                #controller
                self.controller = pubsub()
                self.controller.subscribe(AVERAGE_KEY, fft.set_average)
                        avg_alpha_key=AVG_ALPHA_KEY,
                        peak_hold=peak_hold,
                        msg_key=MSG_KEY,
+                         emulate_analog=emulate_analog,
+                         analog_alpha=analog_alpha,
                )
                common.register_access_methods(self, self.win)
                setattr(self.win, 'set_baseband_freq', getattr(self, 'set_baseband_freq')) #BACKWARDS
@@@ -134,11 -147,14 +150,14 @@@ class test_app_block (stdgui2.std_top_b
          fft_size = 256
  
          # build our flow graph
-         input_rate = 20.48e3
+         input_rate = 2048.0e3
+         #Generate some noise
+         noise =gr.noise_source_c(gr.GR_UNIFORM, 1.0/10)
  
          # 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)
+         src1 = gr.sig_source_c (input_rate, gr.GR_CONST_WAVE, 57.50e3, 1)
  
          # We add these throttle blocks so that this demo doesn't
          # suck down all the CPU available.  Normally you wouldn't use these.
                              ref_level=0, y_per_div=20, y_divs=10)
          vbox.Add (sink1.win, 1, wx.EXPAND)
  
-         self.connect(src1, thr1, sink1)
+         combine1=gr.add_cc()
+         self.connect(src1, (combine1,0))
+         self.connect(noise,(combine1,1))
+         self.connect(combine1,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)
+         src2 = gr.sig_source_f (input_rate, gr.GR_CONST_WAVE, 57.50e3, 1)
          thr2 = gr.throttle(gr.sizeof_float, input_rate)
          sink2 = fft_sink_f (panel, title="Real Data", fft_size=fft_size*2,
                              sample_rate=input_rate, baseband_freq=100e3,
                              ref_level=0, y_per_div=20, y_divs=10)
          vbox.Add (sink2.win, 1, wx.EXPAND)
  
-         self.connect(src2, thr2, sink2)
+         combine2=gr.add_ff()
+         c2f2=gr.complex_to_float()
+         self.connect(src2, (combine2,0))
+         self.connect(noise,c2f2,(combine2,1))
+         self.connect(combine2, thr2,sink2)
  
  def main ():
      app = stdgui2.stdapp (test_app_block, "FFT Sink Test App")
index 937eb27cce936ad14c5243ecc66568bb750833cb,f1c1f43964d10f49e685c76ef8fafebba000bec5..8735e98aef391d52cdab64de0ed2d965f33f0a94
@@@ -1,6 -1,6 +1,6 @@@
  #!/usr/bin/env python
  #
 -# Copyright 2003,2004,2005,2006,2007 Free Software Foundation, Inc.
 +# Copyright 2003,2004,2005,2006,2007,2009 Free Software Foundation, Inc.
  # 
  # This file is part of GNU Radio
  # 
@@@ -37,7 -37,7 +37,7 @@@ class fft_sink_base(object)
                   y_divs=8, ref_level=50,
                   sample_rate=1, fft_size=512,
                   fft_rate=default_fft_rate,
-                  average=False, avg_alpha=None, title='', peak_hold=False):
+                  average=False, avg_alpha=None, title='', peak_hold=False,emulate_analog=False,analog_alpha=0.2):
  
          # initialize common attributes
          self.baseband_freq = baseband_freq
@@@ -52,6 -52,9 +52,9 @@@
              self.avg_alpha = 2.0 / fft_rate
          else:
              self.avg_alpha = avg_alpha
+         self.emulate_analog = emulate_analog
+         self.analog_alpha = analog_alpha
          self.title = title
          self.peak_hold = peak_hold
          self.input_is_real = input_is_real
          self.peak_hold = enable
          self.win.set_peak_hold(enable)
  
+     def set_emulate_analog(self, enable):
+         self.emulate_analog = enable
+         self.win.set_emulate_analog(enable)
+     def set_analog_alpha(self, analog_alpha):
+         self.analog_alpha = analog_alpha
+         self.win.set_analog_alpha(analog_alpha)
      def set_avg_alpha(self, avg_alpha):
          self.avg_alpha = avg_alpha
  
@@@ -93,7 -104,7 +104,7 @@@ class fft_sink_f(gr.hier_block2, fft_si
      def __init__(self, parent, baseband_freq=0, ref_scale=2.0,
                   y_per_div=10, y_divs=8, 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, **kwargs):
 -                 title='', size=default_fftsink_size, peak_hold=False, emulate_analog=False,analog_alpha=0.2):
++                 title='', size=default_fftsink_size, peak_hold=False, emulate_analog=False,analog_alpha=0.2, **kwargs):
  
          gr.hier_block2.__init__(self, "fft_sink_f",
                                  gr.io_signature(1, 1, gr.sizeof_float),
                                 sample_rate=sample_rate, fft_size=fft_size,
                                 fft_rate=fft_rate,
                                 average=average, avg_alpha=avg_alpha, title=title,
-                                peak_hold=peak_hold)
+                                peak_hold=peak_hold,emulate_analog=emulate_analog,analog_alpha=analog_alpha)
                                 
          self.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,
          self.win = fft_window(self, parent, size=size)
          self.set_average(self.average)
          self.set_peak_hold(self.peak_hold)
+         self.set_emulate_analog(self.emulate_analog)
+         self.set_analog_alpha(self.analog_alpha)
  
  class fft_sink_c(gr.hier_block2, fft_sink_base):
      def __init__(self, parent, baseband_freq=0, ref_scale=2.0,
                   y_per_div=10, y_divs=8, 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, **kwargs):
 -                 title='', size=default_fftsink_size, peak_hold=False, emulate_analog=False,analog_alpha=0.2):
++                 title='', size=default_fftsink_size, peak_hold=False, emulate_analog=False,analog_alpha=0.2, **kwargs):
  
          gr.hier_block2.__init__(self, "fft_sink_c",
                                  gr.io_signature(1, 1, gr.sizeof_gr_complex),
                                 sample_rate=sample_rate, fft_size=fft_size,
                                 fft_rate=fft_rate,
                                 average=average, avg_alpha=avg_alpha, title=title,
-                                peak_hold=peak_hold)
+                                peak_hold=peak_hold, emulate_analog=emulate_analog,analog_alpha=analog_alpha)
  
          self.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,
  
          self.win = fft_window(self, parent, size=size)
          self.set_average(self.average)
+         self.set_emulate_analog(self.emulate_analog)
+         self.set_analog_alpha(self.analog_alpha)
          self.set_peak_hold(self.peak_hold)
  
  
@@@ -236,6 -251,9 +251,9 @@@ class control_panel(wx.Panel)
          self.average_check_box = wx.CheckBox(parent=self, style=wx.CHK_2STATE, label="Average")
          self.average_check_box.Bind(wx.EVT_CHECKBOX, parent.on_average)
          control_box.Add(self.average_check_box, 0, wx.EXPAND)
+         self.emulate_analog_check_box = wx.CheckBox(parent=self, style=wx.CHK_2STATE, label="Emulate Analog")
+         self.emulate_analog_check_box.Bind(wx.EVT_CHECKBOX, parent.on_emulate_analog)
+         control_box.Add(self.emulate_analog_check_box, 0, wx.EXPAND)
          self.peak_hold_check_box = wx.CheckBox(parent=self, style=wx.CHK_2STATE, label="Peak Hold")
          self.peak_hold_check_box.Bind(wx.EVT_CHECKBOX, parent.on_peak_hold) 
          control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND)
          """
          #update checkboxes
          self.average_check_box.SetValue(self.parent.fftsink.average)
+         self.emulate_analog_check_box.SetValue(self.parent.fftsink.emulate_analog)
          self.peak_hold_check_box.SetValue(self.parent.fftsink.peak_hold)
          #update radio buttons    
          try:
@@@ -306,6 -325,10 +325,10 @@@ class fft_window (wx.Panel)
          
          self.peak_hold = False
          self.peak_vals = None
+         self.emulate_analog=False
+         self.analog_alpha=0.2
          
          self.plot.SetEnableGrid (True)
          # self.SetEnableZoom (True)
          y_range = ymin, ymax
          self.plot.Draw (graphics, xAxis=x_range, yAxis=y_range, step=self.fftsink.y_per_div)        
  
+     def set_emulate_analog(self, enable):
+         self.emulate_analog = enable
+         self.plot.set_emulate_analog( enable)
+     def set_analog_alpha(self, analog_alpha):
+         self.analog_alpha = analog_alpha
+         self.plot.set_analog_alpha(analog_alpha)
      def set_peak_hold(self, enable):
          self.peak_hold = enable
          self.peak_vals = None
          self.fftsink.set_average(evt.IsChecked())
          self.control_panel.update()
  
+     def on_emulate_analog(self, evt):
+         # print "on_analog"
+         self.fftsink.set_emulate_analog(evt.IsChecked())
+         self.control_panel.update()
      def on_peak_hold(self, evt):
          # print "on_peak_hold"
          self.fftsink.set_peak_hold(evt.IsChecked())
          self.id_y_per_div_10 = wx.NewId()
          self.id_y_per_div_20 = wx.NewId()
          self.id_average = wx.NewId()
+         self.id_emulate_analog = wx.NewId()
          self.id_peak_hold = wx.NewId()
          
          self.plot.Bind(wx.EVT_MENU, self.on_average, id=self.id_average)
+         self.plot.Bind(wx.EVT_MENU, self.on_emulate_analog, id=self.id_emulate_analog)
          self.plot.Bind(wx.EVT_MENU, self.on_peak_hold, id=self.id_peak_hold)
          self.plot.Bind(wx.EVT_MENU, self.on_incr_ref_level, id=self.id_incr_ref_level)
          self.plot.Bind(wx.EVT_MENU, self.on_decr_ref_level, id=self.id_decr_ref_level)
          menu = wx.Menu()
          self.popup_menu = menu
          menu.AppendCheckItem(self.id_average, "Average")
+         menu.AppendCheckItem(self.id_emulate_analog, "Emulate Analog")
          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")
  
          self.checkmarks = {
              self.id_average : lambda : self.fftsink.average,
+             self.id_emulate_analog : lambda : self.fftsink.emulate_analog,
              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,
@@@ -561,11 -601,11 +601,11 @@@ class test_app_block (stdgui2.std_top_b
          fft_size = 256
  
          # build our flow graph
-         input_rate = 20.48e3
+         input_rate = 100*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)
+         #src1 = gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 100*2e3, 1)
+         src1 = gr.sig_source_c (input_rate, gr.GR_CONST_WAVE, 100*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.
  
          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)
+         #src2 = gr.sig_source_f (input_rate, gr.GR_SIN_WAVE, 100*2e3, 1)
+         src2 = gr.sig_source_f (input_rate, gr.GR_CONST_WAVE, 100*5.75e3, 1)
          thr2 = gr.throttle(gr.sizeof_float, input_rate)
          sink2 = fft_sink_f (panel, title="Real Data", fft_size=fft_size*2,
                              sample_rate=input_rate, baseband_freq=100e3,
index f7c0ffa82e6174a779b4fe412b3feaf8eb775c64,a6c7bdb412e68e49a3792885d222dac820b1f9d2..aace8688f2a2e46ed65bace7e711b493bd019b8e
@@@ -36,6 -36,8 +36,8 @@@ import form
  # Constants
  ##################################################
  DEFAULT_FRAME_RATE = gr.prefs().get_long('wxgui', 'scope_rate', 30)
+ ANALOG_ALPHA_MIN_EXP, ANALOG_ALPHA_MAX_EXP = -2, 0
+ SLIDER_STEPS = 100
  DEFAULT_WIN_SIZE = (600, 300)
  COUPLING_MODES = (
        ('DC', False),
@@@ -55,9 -57,6 +57,9 @@@ CHANNEL_COLOR_SPECS = 
        (0.0, 0.8, 0.0),
        (1.0, 0.0, 0.0),
        (0.8, 0.0, 0.8),
 +        (0.7, 0.7, 0.0),
 +        (0.15, 0.90, 0.98),
 +
  )
  TRIGGER_COLOR_SPEC = (1.0, 0.4, 0.0)
  AUTORANGE_UPDATE_RATE = 0.5 #sec
@@@ -85,9 -84,38 +87,40 @@@ class control_panel(wx.Panel)
                WIDTH = 90
                self.parent = parent
                wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
 +              parent[SHOW_CONTROL_PANEL_KEY] = True
 +              parent.subscribe(SHOW_CONTROL_PANEL_KEY, self.Show)
                control_box = wx.BoxSizer(wx.VERTICAL)
+               ##################################################
+               # Emulate Analog
+               ##################################################
+               forms.check_box(
+                       sizer=control_box, parent=self, label='Emulate Analog',
+                       ps=parent, key=EMULATE_ANALOG_KEY,
+               )
+               #static text and slider for analog alpha
+               analog_alpha_text = forms.static_text(
+                       sizer=control_box, parent=self, label='Analog Alpha',
+                       converter=forms.float_converter(lambda x: '%.4f'%x),
+                       ps=parent, key=ANALOG_ALPHA_KEY, width=50,
+               )
+               analog_alpha_slider = forms.log_slider(
+                       sizer=control_box, parent=self,
+                       min_exp=ANALOG_ALPHA_MIN_EXP,
+                       max_exp=ANALOG_ALPHA_MAX_EXP,
+                       num_steps=SLIDER_STEPS,
+                       ps=parent, key=ANALOG_ALPHA_KEY,
+               )
+               for widget in (analog_alpha_text, analog_alpha_slider):
+                       parent.subscribe(EMULATE_ANALOG_KEY, widget.Enable)
+                       widget.Enable(parent[EMULATE_ANALOG_KEY])
+                       parent.subscribe(EMULATE_ANALOG_KEY, widget.ShowItems)
+                         #allways show initially, so room is reserved for them
+                       widget.ShowItems(True) # (parent[EMULATE_ANALOG_KEY])
+               
+                 parent.subscribe(EMULATE_ANALOG_KEY, self._update_layout)
                ##################################################
                # Axes Options
                ##################################################
        def _on_decr_y_off(self, event):
                self.parent[Y_OFF_KEY] = self.parent[Y_OFF_KEY] - self.parent[Y_PER_DIV_KEY]
  
+       ##################################################
+       # subscriber handlers
+       ##################################################
+         def _update_layout(self,key):
+           # Just ignore the key value we get
+           # we only need to now that the visability or size of something has changed
+           self.parent.Layout()
+           #self.parent.Fit()  
  ##################################################
  # Scope window with plotter and control panel
  ##################################################
@@@ -379,7 -416,6 +421,7 @@@ class scope_window(wx.Panel, pubsub.pub
                sample_rate_key,
                t_scale,
                v_scale,
 +              v_offset,
                xy_mode,
                ac_couple_key,
                trigger_level_key,
                trigger_channel_key,
                decimation_key,
                msg_key,
+                 emulate_analog,
+                 analog_alpha,
        ):
                pubsub.pubsub.__init__(self)
                #check num inputs
                self[X_PER_DIV_KEY] = v_scale
                self[Y_PER_DIV_KEY] = v_scale
                self[T_OFF_KEY] = 0
 -              self[X_OFF_KEY] = 0
 -              self[Y_OFF_KEY] = 0
 +              self[X_OFF_KEY] = v_offset
 +              self[Y_OFF_KEY] = v_offset
                self[T_DIVS_KEY] = 8
                self[X_DIVS_KEY] = 8
                self[Y_DIVS_KEY] = 8
                self[TRIGGER_MODE_KEY] = gr.gr_TRIG_MODE_AUTO
                self[TRIGGER_SLOPE_KEY] = gr.gr_TRIG_SLOPE_POS
                self[T_FRAC_OFF_KEY] = 0.5
+               self[EMULATE_ANALOG_KEY] = emulate_analog
+               self[ANALOG_ALPHA_KEY] = analog_alpha
                for i in range(num_inputs):
                        self.proxy(common.index_key(AC_COUPLE_KEY, i), controller, common.index_key(ac_couple_key, i))
                #init panel and plot
                self.plotter.enable_legend(True)
                self.plotter.enable_point_label(True)
                self.plotter.enable_grid_lines(True)
+                 self.plotter.set_emulate_analog(emulate_analog)
+                 self.plotter.set_analog_alpha(analog_alpha)
                #setup the box with plot and controls
                self.control_panel = control_panel(self)
                main_box = wx.BoxSizer(wx.HORIZONTAL)
                        XY_MODE_KEY, AUTORANGE_KEY, T_FRAC_OFF_KEY,
                        TRIGGER_SHOW_KEY, XY_MARKER_KEY, X_CHANNEL_KEY, Y_CHANNEL_KEY,
                ]: self.subscribe(key, self.update_grid)
+                 #register events for plotter settings
+               self.subscribe(EMULATE_ANALOG_KEY, self.plotter.set_emulate_analog)
+               self.subscribe(ANALOG_ALPHA_KEY, self.plotter.set_analog_alpha)
                #initial update
                self.update_grid()
  
                        self.plotter.set_y_grid(self.get_y_min(), self.get_y_max(), self[Y_PER_DIV_KEY])
                #redraw current sample
                self.handle_samples()
index 358361de62d6953ee6f969ee1db7dd5e64a17a20,204434ce6ede19505fb917fe3fc0bea1da3657e1..a12517883cfe4f4a3f77042c336ed981cb70200d
@@@ -27,6 -27,7 +27,7 @@@ import commo
  from gnuradio import gr
  from pubsub import pubsub
  from constants import *
+ import math
  
  class ac_couple_block(gr.hier_block2):
        """
@@@ -71,13 -72,21 +72,22 @@@ class _scope_sink_base(gr.hier_block2, 
                size=scope_window.DEFAULT_WIN_SIZE,
                v_scale=0,
                t_scale=0,
 +              v_offset=0,
                xy_mode=False,
                ac_couple=False,
                num_inputs=1,
                frame_rate=scope_window.DEFAULT_FRAME_RATE,
+                 emulate_analog=False,
+                 analog_alpha=None,
                **kwargs #do not end with a comma
        ):
+                 #ensure analog alpha
+                 if analog_alpha is None: 
+                   actual_frame_rate=float(frame_rate)
+                   analog_cutoff_freq=0.5 # Hertz
+                   #calculate alpha from wanted cutoff freq
+                   analog_alpha = 1.0 - math.exp(-2.0*math.pi*analog_cutoff_freq/actual_frame_rate)
                if not t_scale: t_scale = 10.0/sample_rate
                #init
                gr.hier_block2.__init__(
                        sample_rate_key=SAMPLE_RATE_KEY,
                        t_scale=t_scale,
                        v_scale=v_scale,
 +                      v_offset=v_offset,
                        xy_mode=xy_mode,
                        ac_couple_key=AC_COUPLE_KEY,
                        trigger_level_key=TRIGGER_LEVEL_KEY,
                        trigger_channel_key=TRIGGER_CHANNEL_KEY,
                        decimation_key=DECIMATION_KEY,
                        msg_key=MSG_KEY,
+                         emulate_analog=emulate_analog,
+                         analog_alpha=analog_alpha,
                )
                common.register_access_methods(self, self.win)
                #connect
@@@ -169,10 -179,11 +181,11 @@@ class test_top_block (stdgui2.std_top_b
      def __init__(self, frame, panel, vbox, argv):
          stdgui2.std_top_block.__init__ (self, frame, panel, vbox, argv)
  
+         default_input_rate = 1e6
          if len(argv) > 1:
-             frame_decim = int(argv[1]) 
+             input_rate = int(argv[1]) 
          else:
-             frame_decim = 1
+             input_rate = default_input_rate
  
          if len(argv) > 2:
              v_scale = float(argv[2])  # start up at this v_scale value
          if len(argv) > 3:
              t_scale = float(argv[3])  # start up at this t_scale value
          else:
-             t_scale = .00003  # old behavior
+             t_scale = .00003*default_input_rate/input_rate # old behavior
  
-         print "frame decim %s  v_scale %s  t_scale %s" % (frame_decim,v_scale,t_scale)
+         print "input rate %s  v_scale %s  t_scale %s" % (input_rate,v_scale,t_scale)
              
-         input_rate = 1e6
  
          # Generate a complex sinusoid
-         self.src0 = gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 25.1e3, 1e3)
+         ampl=1.0e3
+         self.src0 = gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 25.1e3*input_rate/default_input_rate, ampl)
+         self.noise =gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 11.1*25.1e3*input_rate/default_input_rate, ampl/10) 
+         #self.noise =gr.noise_source_c(gr.GR_GAUSSIAN, ampl/10)
+         self.combine=gr.add_cc()
  
          # We add this throttle block so that this demo doesn't suck down
          # all the CPU available.  You normally wouldn't use it...
  
          # Ultimately this will be
          # self.connect("src0 throttle scope")
-       self.connect(self.src0, self.thr, scope) 
+       self.connect(self.src0,(self.combine,0))
+         self.connect(self.noise,(self.combine,1))
+         self.connect(self.combine, self.thr, scope) 
  
  def main ():
      app = stdgui2.stdapp (test_top_block, "O'Scope Test App")