2 # Copyright 2008 Free Software Foundation, Inc.
4 # This file is part of GNU Radio
6 # GNU Radio is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3, or (at your option)
11 # GNU Radio is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with GNU Radio; see the file COPYING. If not, write to
18 # the Free Software Foundation, Inc., 51 Franklin Street,
19 # Boston, MA 02110-1301, USA.
22 ##################################################
24 ##################################################
29 from constants import *
30 from gnuradio import gr #for gr.prefs
33 ##################################################
35 ##################################################
36 NEG_INF = float('-inf')
38 AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP = -3, 0
39 DEFAULT_NUMBER_RATE = gr.prefs().get_long('wxgui', 'number_rate', 5)
40 DEFAULT_WIN_SIZE = (300, 300)
41 DEFAULT_GAUGE_RANGE = 1000
42 VALUE_REPR_KEY = 'value_repr'
43 VALUE_REAL_KEY = 'value_real'
44 VALUE_IMAG_KEY = 'value_imag'
46 ##################################################
47 # Number window control panel
48 ##################################################
49 class control_panel(wx.Panel):
51 A control panel with wx widgits to control the averaging.
54 def __init__(self, parent):
56 Create a new control panel.
57 @param parent the wx parent window
60 wx.Panel.__init__(self, parent)
61 control_box = wx.BoxSizer(wx.VERTICAL)
62 #checkboxes for average and peak hold
63 control_box.AddStretchSpacer()
64 options_box = forms.static_box_sizer(
65 parent=self, sizer=control_box, label='Options',
66 bold=True, orient=wx.VERTICAL,
69 sizer=options_box, parent=self, label='Peak Hold',
70 ps=parent, key=PEAK_HOLD_KEY,
73 sizer=options_box, parent=self, label='Average',
74 ps=parent, key=AVERAGE_KEY,
76 #static text and slider for averaging
77 avg_alpha_text = forms.static_text(
78 sizer=options_box, parent=self, label='Avg Alpha',
79 converter=forms.float_converter(lambda x: '%.4f'%x),
80 ps=parent, key=AVG_ALPHA_KEY, width=50,
82 avg_alpha_slider = forms.log_slider(
83 sizer=options_box, parent=self,
84 min_exp=AVG_ALPHA_MIN_EXP,
85 max_exp=AVG_ALPHA_MAX_EXP,
86 num_steps=SLIDER_STEPS,
87 ps=parent, key=AVG_ALPHA_KEY,
89 for widget in (avg_alpha_text, avg_alpha_slider):
90 parent.subscribe(AVERAGE_KEY, widget.Enable)
91 widget.Enable(parent[AVERAGE_KEY])
93 control_box.AddStretchSpacer()
95 sizer=control_box, parent=self,
96 true_label='Stop', false_label='Run',
97 ps=parent, key=RUNNING_KEY,
100 self.SetSizerAndFit(control_box)
102 ##################################################
103 # Numbersink window with label and gauges
104 ##################################################
105 class number_window(wx.Panel, pubsub.pubsub):
124 pubsub.pubsub.__init__(self)
125 wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
127 self.peak_val_real = NEG_INF
128 self.peak_val_imag = NEG_INF
131 self.decimal_places = decimal_places
133 self.proxy(MSG_KEY, controller, msg_key)
134 self.proxy(AVERAGE_KEY, controller, average_key)
135 self.proxy(AVG_ALPHA_KEY, controller, avg_alpha_key)
136 self.proxy(SAMPLE_RATE_KEY, controller, sample_rate_key)
138 self[PEAK_HOLD_KEY] = peak_hold
139 self[RUNNING_KEY] = True
140 self[VALUE_REAL_KEY] = minval
141 self[VALUE_IMAG_KEY] = minval
142 #setup the box with display and controls
143 self.control_panel = control_panel(self)
144 main_box = wx.BoxSizer(wx.HORIZONTAL)
145 sizer = forms.static_box_sizer(
146 parent=self, sizer=main_box, label=title,
147 bold=True, orient=wx.VERTICAL, proportion=1,
149 main_box.Add(self.control_panel, 0, wx.EXPAND)
150 sizer.AddStretchSpacer()
152 parent=self, sizer=sizer,
153 ps=self, key=VALUE_REPR_KEY, width=size[0],
154 converter=forms.str_converter(),
156 sizer.AddStretchSpacer()
157 self.gauge_real = forms.gauge(
158 parent=self, sizer=sizer, style=wx.GA_HORIZONTAL,
159 ps=self, key=VALUE_REAL_KEY, length=size[0],
160 minimum=minval, maximum=maxval, num_steps=DEFAULT_GAUGE_RANGE,
162 self.gauge_imag = forms.gauge(
163 parent=self, sizer=sizer, style=wx.GA_HORIZONTAL,
164 ps=self, key=VALUE_IMAG_KEY, length=size[0],
165 minimum=minval, maximum=maxval, num_steps=DEFAULT_GAUGE_RANGE,
168 self.show_gauges(show_gauge)
169 self.SetSizerAndFit(main_box)
171 self.subscribe(MSG_KEY, self.handle_msg)
173 def show_gauges(self, show_gauge):
175 Show or hide the gauges.
176 If this is real, never show the imaginary gauge.
177 @param show_gauge true to show
179 self.gauge_real.ShowItems(show_gauge)
180 self.gauge_imag.ShowItems(show_gauge and not self.real)
182 def handle_msg(self, msg):
184 Handle a message from the message queue.
185 Convert the string based message into a float or complex.
186 If more than one number was read, only take the last number.
187 Perform peak hold operations, set the gauges and display.
188 @param event event.data is the number sample as a character array
190 if not self[RUNNING_KEY]: return
191 format_string = "%%.%df"%self.decimal_places
193 sample = numpy.fromstring(msg, numpy.float32)[-1]
194 if self[PEAK_HOLD_KEY]: sample = self.peak_val_real = max(self.peak_val_real, sample)
195 label_text = "%s %s"%(format_string%sample, self.units)
196 self[VALUE_REAL_KEY] = sample
198 sample = numpy.fromstring(msg, numpy.complex64)[-1]
199 if self[PEAK_HOLD_KEY]:
200 self.peak_val_real = max(self.peak_val_real, sample.real)
201 self.peak_val_imag = max(self.peak_val_imag, sample.imag)
202 sample = self.peak_val_real + self.peak_val_imag*1j
203 label_text = "%s + %sj %s"%(format_string%sample.real, format_string%sample.imag, self.units)
204 self[VALUE_REAL_KEY] = sample.real
205 self[VALUE_IMAG_KEY] = sample.imag
207 self[VALUE_REPR_KEY] = label_text
209 if not self[PEAK_HOLD_KEY]:
210 self.peak_val_real = NEG_INF
211 self.peak_val_imag = NEG_INF