Statistics
| Branch: | Tag: | Revision:

root / gr-wxgui / src / python / number_window.py @ 36649d4e

History | View | Annotate | Download (6.4 kB)

1
#
2
# Copyright 2008 Free Software Foundation, Inc.
3
#
4
# This file is part of GNU Radio
5
#
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)
9
# any later version.
10
#
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.
15
#
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.
20
#
21
22
##################################################
23
# Imports
24
##################################################
25
import common
26
import numpy
27
import wx
28
import pubsub
29
from constants import *
30
31
##################################################
32
# Constants
33
##################################################
34
NEG_INF = float('-inf')
35
SLIDER_STEPS = 100
36
AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP = -3, 0
37
DEFAULT_NUMBER_RATE = 5
38
DEFAULT_WIN_SIZE = (300, 300)
39
DEFAULT_GAUGE_RANGE = 1000
40
41
##################################################
42
# Number window control panel
43
##################################################
44
class control_panel(wx.Panel):
45
        """!
46
        A control panel with wx widgits to control the averaging.
47
        """
48
49
        def __init__(self, parent):
50
                """!
51
                Create a new control panel.
52
                @param parent the wx parent window
53
                """
54
                self.parent = parent
55
                wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
56
                control_box = wx.BoxSizer(wx.VERTICAL)
57
                #checkboxes for average and peak hold
58
                control_box.AddStretchSpacer()
59
                control_box.Add(common.LabelText(self, 'Options'), 0, wx.ALIGN_CENTER)
60
                self.average_check_box = common.CheckBoxController(self, 'Average', parent.ext_controller, parent.average_key)
61
                control_box.Add(self.average_check_box, 0, wx.EXPAND)
62
                self.peak_hold_check_box = common.CheckBoxController(self, 'Peak Hold', parent, PEAK_HOLD_KEY)
63
                control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND)
64
                control_box.AddSpacer(2)
65
                self.avg_alpha_slider = common.LogSliderController(
66
                        self, 'Avg Alpha',
67
                        AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP, SLIDER_STEPS,
68
                        parent.ext_controller, parent.avg_alpha_key,
69
                        formatter=lambda x: ': %.4f'%x,
70
                )
71
                parent.ext_controller.subscribe(parent.average_key, self.avg_alpha_slider.Enable)
72
                control_box.Add(self.avg_alpha_slider, 0, wx.EXPAND)
73
                #run/stop
74
                control_box.AddStretchSpacer()
75
                self.run_button = common.ToggleButtonController(self, parent, RUNNING_KEY, 'Stop', 'Run')
76
                control_box.Add(self.run_button, 0, wx.EXPAND)
77
                #set sizer
78
                self.SetSizerAndFit(control_box)
79
80
##################################################
81
# Numbersink window with label and gauges
82
##################################################
83
class number_window(wx.Panel, pubsub.pubsub, common.prop_setter):
84
        def __init__(
85
                self,
86
                parent,
87
                controller,
88
                size,
89
                title,
90
                units,
91
                show_gauge,
92
                real,
93
                minval,
94
                maxval,
95
                decimal_places,
96
                average_key,
97
                avg_alpha_key,
98
                peak_hold,
99
                msg_key,
100
        ):
101
                pubsub.pubsub.__init__(self)
102
                wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
103
                #setup
104
                self.peak_val_real = NEG_INF
105
                self.peak_val_imag = NEG_INF
106
                self.ext_controller = controller
107
                self.real = real
108
                self.units = units
109
                self.minval = minval
110
                self.maxval = maxval
111
                self.decimal_places = decimal_places
112
                self.average_key = average_key
113
                self.avg_alpha_key = avg_alpha_key
114
                #setup the box with display and controls
115
                self.control_panel = control_panel(self)
116
                main_box = wx.BoxSizer(wx.HORIZONTAL)
117
                sizer = wx.BoxSizer(wx.VERTICAL)
118
                main_box.Add(sizer, 1, wx.EXPAND)
119
                main_box.Add(self.control_panel, 0, wx.EXPAND)
120
                sizer.Add(common.LabelText(self, title), 1, wx.ALIGN_CENTER)
121
                self.text = wx.StaticText(self, size=(size[0], -1))
122
                sizer.Add(self.text, 1, wx.EXPAND)
123
                self.gauge_real = wx.Gauge(self, range=DEFAULT_GAUGE_RANGE, style=wx.GA_HORIZONTAL)
124
                self.gauge_imag = wx.Gauge(self, range=DEFAULT_GAUGE_RANGE, style=wx.GA_HORIZONTAL)
125
                #hide/show gauges
126
                self.show_gauges(show_gauge)
127
                sizer.Add(self.gauge_real, 1, wx.EXPAND)
128
                sizer.Add(self.gauge_imag, 1, wx.EXPAND)
129
                self.SetSizerAndFit(main_box)
130
                #initial setup
131
                self.ext_controller[self.average_key] = self.ext_controller[self.average_key]
132
                self.ext_controller[self.avg_alpha_key] = self.ext_controller[self.avg_alpha_key]
133
                self._register_set_prop(self, PEAK_HOLD_KEY, peak_hold)
134
                self._register_set_prop(self, RUNNING_KEY, True)
135
                #register events
136
                self.ext_controller.subscribe(msg_key, self.handle_msg)
137
138
        def show_gauges(self, show_gauge):
139
                """!
140
                Show or hide the gauges.
141
                If this is real, never show the imaginary gauge.
142
                @param show_gauge true to show
143
                """
144
                if show_gauge: self.gauge_real.Show()
145
                else: self.gauge_real.Hide()
146
                if show_gauge and not self.real: self.gauge_imag.Show()
147
                else: self.gauge_imag.Hide()
148
149
        def handle_msg(self, msg):
150
                """!
151
                Handle a message from the message queue.
152
                Convert the string based message into a float or complex.
153
                If more than one number was read, only take the last number.
154
                Perform peak hold operations, set the gauges and display.
155
                @param msg the number sample as a character array
156
                """
157
                if not self[RUNNING_KEY]: return
158
                #set gauge
159
                def set_gauge_value(gauge, value):
160
                        gauge_val = DEFAULT_GAUGE_RANGE*(value-self.minval)/(self.maxval-self.minval)
161
                        gauge_val = max(0, gauge_val) #clip
162
                        gauge_val = min(DEFAULT_GAUGE_RANGE, gauge_val) #clip
163
                        gauge.SetValue(gauge_val)
164
                format_string = "%%.%df"%self.decimal_places
165
                if self.real:
166
                        sample = numpy.fromstring(msg, numpy.float32)[-1]
167
                        if self[PEAK_HOLD_KEY]: sample = self.peak_val_real = max(self.peak_val_real, sample)
168
                        label_text = "%s %s"%(format_string%sample, self.units)
169
                        set_gauge_value(self.gauge_real, sample)
170
                else:
171
                        sample = numpy.fromstring(msg, numpy.complex64)[-1]
172
                        if self[PEAK_HOLD_KEY]:
173
                                self.peak_val_real = max(self.peak_val_real, sample.real)
174
                                self.peak_val_imag = max(self.peak_val_imag, sample.imag)
175
                                sample = self.peak_val_real + self.peak_val_imag*1j
176
                        label_text = "%s + %sj %s"%(format_string%sample.real, format_string%sample.imag, self.units)
177
                        set_gauge_value(self.gauge_real, sample.real)
178
                        set_gauge_value(self.gauge_imag, sample.imag)
179
                #set label text
180
                self.text.SetLabel(label_text)
181
                #clear peak hold
182
                if not self[PEAK_HOLD_KEY]:
183
                        self.peak_val_real = NEG_INF
184
                        self.peak_val_imag = NEG_INF