Changeset 8707
- Timestamp:
- 06/25/08 14:12:06
- Files:
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
gnuradio/branches/releases/3.1/gr-wxgui/src/python/fftsink2.py
r8339 r8707 24 24 from gnuradio.wxgui import stdgui2 25 25 import wx 26 import gnuradio.wxgui.plot asplot26 import plot 27 27 import numpy 28 28 import threading 29 29 import math 30 31 DIV_LEVELS = (1, 2, 5, 10, 20) 30 32 31 33 default_fftsink_size = (640,240) … … 69 71 else: 70 72 self.avg.set_taps(1.0) 71 self.win.peak_vals = None72 73 self.win.peak_vals = None 74 73 75 def set_peak_hold(self, enable): 74 76 self.peak_hold = enable … … 121 123 # FIXME We need to add 3dB to all bins but the DC bin 122 124 self.log = gr.nlog10_ff(20, self.fft_size, 123 -10*math.log10(self.fft_size) # Adjust for number of bins124 -10*math.log10(power/self.fft_size)# Adjust for windowing loss125 -20*math.log10(ref_scale/2))# Adjust for reference scale126 125 -10*math.log10(self.fft_size) # Adjust for number of bins 126 -10*math.log10(power/self.fft_size) # Adjust for windowing loss 127 -20*math.log10(ref_scale/2)) # Adjust for reference scale 128 127 129 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)130 self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink) 129 131 130 132 self.win = fft_window(self, parent, size=size) 131 133 self.set_average(self.average) 132 134 self.set_peak_hold(self.peak_hold) 133 135 134 136 class fft_sink_c(gr.hier_block2, fft_sink_base): … … 164 166 # FIXME We need to add 3dB to all bins but the DC bin 165 167 self.log = gr.nlog10_ff(20, self.fft_size, 166 -10*math.log10(self.fft_size) # Adjust for number of bins167 -10*math.log10(power/self.fft_size)# Adjust for windowing loss168 -20*math.log10(ref_scale/2))# Adjust for reference scale169 168 -10*math.log10(self.fft_size) # Adjust for number of bins 169 -10*math.log10(power/self.fft_size) # Adjust for windowing loss 170 -20*math.log10(ref_scale/2)) # Adjust for reference scale 171 170 172 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)173 self.connect(self, self.s2p, self.one_in_n, self.fft, self.c2mag, self.avg, self.log, self.sink) 172 174 173 175 self.win = fft_window(self, parent, size=size) 174 176 self.set_average(self.average) 177 self.set_peak_hold(self.peak_hold) 175 178 176 179 … … 219 222 wx.PostEvent (self.event_receiver, de) 220 223 del de 224 225 class control_panel(wx.Panel): 221 226 222 223 class fft_window (plot.PlotCanvas): 227 class LabelText(wx.StaticText): 228 def __init__(self, window, label): 229 wx.StaticText.__init__(self, window, -1, label) 230 font = self.GetFont() 231 font.SetWeight(wx.FONTWEIGHT_BOLD) 232 font.SetUnderlined(True) 233 self.SetFont(font) 234 235 def __init__(self, parent): 236 self.parent = parent 237 wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER) 238 control_box = wx.BoxSizer(wx.VERTICAL) 239 240 #checkboxes for average and peak hold 241 control_box.AddStretchSpacer() 242 control_box.Add(self.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.Bind(wx.EVT_CHECKBOX, parent.on_average) 245 control_box.Add(self.average_check_box, 0, wx.EXPAND) 246 self.peak_hold_check_box = wx.CheckBox(parent=self, style=wx.CHK_2STATE, label="Peak Hold") 247 self.peak_hold_check_box.Bind(wx.EVT_CHECKBOX, parent.on_peak_hold) 248 control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND) 249 250 #radio buttons for div size 251 control_box.AddStretchSpacer() 252 control_box.Add(self.LabelText(self, 'Set dB/div'), 0, wx.ALIGN_CENTER) 253 radio_box = wx.BoxSizer(wx.VERTICAL) 254 self.radio_buttons = list() 255 for y_per_div in DIV_LEVELS: 256 radio_button = wx.RadioButton(self, -1, "%d dB/div"%y_per_div) 257 radio_button.Bind(wx.EVT_RADIOBUTTON, self.on_radio_button_change) 258 self.radio_buttons.append(radio_button) 259 radio_box.Add(radio_button, 0, wx.ALIGN_LEFT) 260 control_box.Add(radio_box, 0, wx.EXPAND) 261 262 #ref lvl buttons 263 control_box.AddStretchSpacer() 264 control_box.Add(self.LabelText(self, 'Adj Ref Lvl'), 0, wx.ALIGN_CENTER) 265 control_box.AddSpacer(2) 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 control_box.AddStretchSpacer() 275 #set sizer 276 self.SetSizerAndFit(control_box) 277 #update 278 self.update() 279 280 def update(self): 281 """! 282 Read the state of the fft plot settings and update the control panel. 283 """ 284 #update checkboxes 285 self.average_check_box.SetValue(self.parent.fftsink.average) 286 self.peak_hold_check_box.SetValue(self.parent.fftsink.peak_hold) 287 #update radio buttons 288 try: 289 index = list(DIV_LEVELS).index(self.parent.fftsink.y_per_div) 290 self.radio_buttons[index].SetValue(True) 291 except: pass 292 293 def on_radio_button_change(self, evt): 294 selected_radio_button = filter(lambda rb: rb.GetValue(), self.radio_buttons)[0] 295 index = self.radio_buttons.index(selected_radio_button) 296 self.parent.fftsink.set_y_per_div(DIV_LEVELS[index]) 297 298 class fft_window (wx.Panel): 224 299 def __init__ (self, fftsink, parent, id = -1, 225 300 pos = wx.DefaultPosition, size = wx.DefaultSize, 226 301 style = wx.DEFAULT_FRAME_STYLE, name = ""): 227 plot.PlotCanvas.__init__ (self, parent, id, pos, size, style, name) 228 229 self.y_range = None 302 230 303 self.fftsink = fftsink 304 #init panel and plot 305 wx.Panel.__init__(self, parent, -1) 306 self.plot = plot.PlotCanvas(self, id, pos, size, style, name) 307 #setup the box with plot and controls 308 self.control_panel = control_panel(self) 309 main_box = wx.BoxSizer (wx.HORIZONTAL) 310 main_box.Add (self.plot, 1, wx.EXPAND) 311 main_box.Add (self.control_panel, 0, wx.EXPAND) 312 self.SetSizerAndFit(main_box) 313 231 314 self.peak_hold = False 232 315 self.peak_vals = None 233 316 234 self. SetEnableGrid (True)317 self.plot.SetEnableGrid (True) 235 318 # self.SetEnableZoom (True) 236 319 # self.SetBackgroundColour ('black') 237 320 238 321 self.build_popup_menu() 239 self.set_baseband_freq(0.0)240 322 self.set_baseband_freq(0.0) 323 241 324 EVT_DATA_EVENT (self, self.set_data) 242 325 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 326 self.plot.Bind(wx.EVT_RIGHT_UP, self.on_right_click) 327 self.plot.Bind(wx.EVT_MOTION, self.evt_motion) 328 246 329 self.input_watcher = input_watcher(fftsink.msgq, fftsink.fft_size, self) 247 330 248 331 def set_scale(self, freq): 249 x = max(abs(self.fftsink.sample_rate), abs(self.fftsink.baseband_freq)) 332 x = max(abs(self.fftsink.sample_rate), abs(self.fftsink.baseband_freq)) 250 333 if x >= 1e9: 251 334 self._scale_factor = 1e-9 252 335 self._units = "GHz" 253 self._format = "%3.6f"336 self._format = "%3.6f" 254 337 elif x >= 1e6: 255 338 self._scale_factor = 1e-6 256 339 self._units = "MHz" 257 self._format = "%3.3f"340 self._format = "%3.3f" 258 341 else: 259 342 self._scale_factor = 1e-3 260 343 self._units = "kHz" 261 self._format = "%3.3f"344 self._format = "%3.3f" 262 345 263 346 def set_baseband_freq(self, baseband_freq): 264 if self.peak_hold:265 self.peak_vals = None266 self.set_scale(baseband_freq)267 self.fftsink.set_baseband_freq(baseband_freq)268 347 if self.peak_hold: 348 self.peak_vals = None 349 self.set_scale(baseband_freq) 350 self.fftsink.set_baseband_freq(baseband_freq) 351 269 352 def on_close_window (self, event): 270 353 print "fft_window:on_close_window" … … 284 367 if self.fftsink.input_is_real: # only plot 1/2 the points 285 368 x_vals = ((numpy.arange (L/2) * (self.fftsink.sample_rate 286 * self._scale_factor / L))369 * self._scale_factor / L)) 287 370 + self.fftsink.baseband_freq * self._scale_factor) 288 371 self._points = numpy.zeros((len(x_vals), 2), numpy.float64) 289 372 self._points[:,0] = x_vals 290 373 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_vals294 self._peak_points[:,1] = self.peak_vals[0:L/2]374 if self.peak_hold: 375 self._peak_points = numpy.zeros((len(x_vals), 2), numpy.float64) 376 self._peak_points[:,0] = x_vals 377 self._peak_points[:,1] = self.peak_vals[0:L/2] 295 378 else: 296 379 # the "negative freqs" are in the second half of the array … … 301 384 self._points[:,0] = x_vals 302 385 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_vals306 self._peak_points[:,1] = numpy.concatenate ((self.peak_vals[L/2:], self.peak_vals[0:L/2]))386 if self.peak_hold: 387 self._peak_points = numpy.zeros((len(x_vals), 2), numpy.float64) 388 self._peak_points[:,0] = x_vals 389 self._peak_points[:,1] = numpy.concatenate ((self.peak_vals[L/2:], self.peak_vals[0:L/2])) 307 390 308 391 lines = [plot.PolyLine (self._points, colour='BLUE'),] 309 if self.peak_hold:310 lines.append(plot.PolyLine (self._peak_points, colour='GREEN'))392 if self.peak_hold: 393 lines.append(plot.PolyLine (self._peak_points, colour='GREEN')) 311 394 312 395 graphics = plot.PlotGraphics (lines, 313 396 title=self.fftsink.title, 314 397 xLabel = self._units, yLabel = "dB") 315 316 self.Draw (graphics, xAxis=None, yAxis=self.y_range) 317 self.update_y_range () 318 398 x_range = x_vals[0], x_vals[-1] 399 ymax = self.fftsink.ref_level 400 ymin = self.fftsink.ref_level - self.fftsink.y_per_div * self.fftsink.y_divs 401 y_range = ymin, ymax 402 self.plot.Draw (graphics, xAxis=x_range, yAxis=y_range, step=self.fftsink.y_per_div) 319 403 320 404 def set_peak_hold(self, enable): … … 322 406 self.peak_vals = None 323 407 324 def update_y_range (self):325 ymax = self.fftsink.ref_level326 ymin = self.fftsink.ref_level - self.fftsink.y_per_div * self.fftsink.y_divs327 self.y_range = self._axisInterval ('min', ymin, ymax)328 329 408 def on_average(self, evt): 330 409 # print "on_average" 331 410 self.fftsink.set_average(evt.IsChecked()) 411 self.control_panel.update() 332 412 333 413 def on_peak_hold(self, evt): 334 414 # print "on_peak_hold" 335 415 self.fftsink.set_peak_hold(evt.IsChecked()) 416 self.control_panel.update() 336 417 337 418 def on_incr_ref_level(self, evt): … … 347 428 def on_incr_y_per_div(self, evt): 348 429 # print "on_incr_y_per_div" 349 self.fftsink.set_y_per_div(next_up(self.fftsink.y_per_div, (1,2,5,10,20))) 430 self.fftsink.set_y_per_div(next_up(self.fftsink.y_per_div, DIV_LEVELS)) 431 self.control_panel.update() 350 432 351 433 def on_decr_y_per_div(self, evt): 352 434 # print "on_decr_y_per_div" 353 self.fftsink.set_y_per_div(next_down(self.fftsink.y_per_div, (1,2,5,10,20))) 435 self.fftsink.set_y_per_div(next_down(self.fftsink.y_per_div, DIV_LEVELS)) 436 self.control_panel.update() 354 437 355 438 def on_y_per_div(self, evt): … … 366 449 elif Id == self.id_y_per_div_20: 367 450 self.fftsink.set_y_per_div(20) 451 self.control_panel.update() 368 452 369 453 def on_right_click(self, event): … … 372 456 item = menu.FindItemById(id) 373 457 item.Check(pred()) 374 self. PopupMenu(menu, event.GetPosition())458 self.plot.PopupMenu(menu, event.GetPosition()) 375 459 376 460 def evt_motion(self, event): 377 461 if not hasattr(self, "_points"): 378 return # Got here before first window data update379 380 # Clip to plotted values381 (ux, uy) = self. GetXY(event) # Scaled position462 return # Got here before first window data update 463 464 # Clip to plotted values 465 (ux, uy) = self.plot.GetXY(event) # Scaled position 382 466 x_vals = numpy.array(self._points[:,0]) 383 467 if ux < x_vals[0] or ux > x_vals[-1]: … … 411 495 self.id_average = wx.NewId() 412 496 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)497 498 self.plot.Bind(wx.EVT_MENU, self.on_average, id=self.id_average) 499 self.plot.Bind(wx.EVT_MENU, self.on_peak_hold, id=self.id_peak_hold) 500 self.plot.Bind(wx.EVT_MENU, self.on_incr_ref_level, id=self.id_incr_ref_level) 501 self.plot.Bind(wx.EVT_MENU, self.on_decr_ref_level, id=self.id_decr_ref_level) 502 self.plot.Bind(wx.EVT_MENU, self.on_incr_y_per_div, id=self.id_incr_y_per_div) 503 self.plot.Bind(wx.EVT_MENU, self.on_decr_y_per_div, id=self.id_decr_y_per_div) 504 self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_1) 505 self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_2) 506 self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_5) 507 self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_10) 508 self.plot.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_20) 425 509 426 510 # make a menu … … 497 581 sink1 = fft_sink_c (panel, title="Complex Data", fft_size=fft_size, 498 582 sample_rate=input_rate, baseband_freq=100e3, 499 ref_level=0, y_per_div=20 )583 ref_level=0, y_per_div=20, y_divs=10) 500 584 vbox.Add (sink1.win, 1, wx.EXPAND) 501 585 502 self.connect(src1, thr1, sink1)586 self.connect(src1, thr1, sink1) 503 587 504 588 #src2 = gr.sig_source_f (input_rate, gr.GR_SIN_WAVE, 2e3, 1) … … 507 591 sink2 = fft_sink_f (panel, title="Real Data", fft_size=fft_size*2, 508 592 sample_rate=input_rate, baseband_freq=100e3, 509 ref_level=0, y_per_div=20 )593 ref_level=0, y_per_div=20, y_divs=10) 510 594 vbox.Add (sink2.win, 1, wx.EXPAND) 511 595 512 self.connect(src2, thr2, sink2)596 self.connect(src2, thr2, sink2) 513 597 514 598 def main (): gnuradio/branches/releases/3.1/gr-wxgui/src/python/plot.py
r5553 r8707 768 768 return self._xUseScopeTicks 769 769 770 def Draw(self, graphics, xAxis = None, yAxis = None, dc = None ):770 def Draw(self, graphics, xAxis = None, yAxis = None, dc = None, step=None): 771 771 """Draw objects in graphics with specified x and y axis. 772 772 graphics- instance of PlotGraphics with list of PolyXXX objects … … 830 830 xTextExtent= (0,0) # No text for ticks 831 831 if self._ySpec is not 'none': 832 yticks = self._ticks(yAxis[0], yAxis[1] )832 yticks = self._ticks(yAxis[0], yAxis[1], step) 833 833 yTextExtentBottom= dc.GetTextExtent(yticks[0][1]) 834 834 yTextExtentTop = dc.GetTextExtent(yticks[-1][1]) … … 1278 1278 text = 0 # axis values not drawn on right side 1279 1279 1280 def _ticks(self, lower, upper ):1280 def _ticks(self, lower, upper, step=None): 1281 1281 ideal = (upper-lower)/7. 1282 1282 log = _numpy.log10(ideal) … … 1299 1299 digits = -int(power) 1300 1300 format = '%'+`digits+2`+'.'+`digits`+'f' 1301 #force grid when step is not None 1302 if step is not None: grid = step 1301 1303 ticks = [] 1302 1304 t = -grid*_numpy.floor(-lower/grid) 1303 1305 while t <= upper: 1306 if t == -0: t = 0 #remove neg zero condition 1304 1307 ticks.append( (t, format % (t,)) ) 1305 1308 t = t + grid
