Imported Upstream version 3.2.2
[debian/gnuradio] / gr-wxgui / src / python / histo_window.py
1 #
2 # Copyright 2009 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 plotter
26 import common
27 import wx
28 import numpy
29 import math
30 import pubsub
31 from constants import *
32 from gnuradio import gr #for gr.prefs
33 import forms
34
35 ##################################################
36 # Constants
37 ##################################################
38 DEFAULT_WIN_SIZE = (600, 300)
39
40 ##################################################
41 # histo window control panel
42 ##################################################
43 class control_panel(wx.Panel):
44         """
45         A control panel with wx widgits to control the plotter and histo sink.
46         """
47
48         def __init__(self, parent):
49                 """
50                 Create a new control panel.
51                 @param parent the wx parent window
52                 """
53                 self.parent = parent
54                 wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
55                 control_box = wx.BoxSizer(wx.VERTICAL)
56                 SIZE = (100, -1)
57                 control_box = forms.static_box_sizer(
58                         parent=self, label='Options',
59                         bold=True, orient=wx.VERTICAL,
60                 )
61                 #num bins
62                 control_box.AddStretchSpacer()
63                 forms.text_box(
64                         sizer=control_box, parent=self, label='Num Bins',
65                         converter=forms.int_converter(),
66                         ps=parent, key=NUM_BINS_KEY,
67                 )
68                 #frame size
69                 control_box.AddStretchSpacer()
70                 forms.text_box(
71                         sizer=control_box, parent=self, label='Frame Size',
72                         converter=forms.int_converter(),
73                         ps=parent, key=FRAME_SIZE_KEY,
74                 )
75                 #run/stop
76                 control_box.AddStretchSpacer()
77                 forms.toggle_button(
78                         sizer=control_box, parent=self,
79                         true_label='Stop', false_label='Run',
80                         ps=parent, key=RUNNING_KEY,
81                 )
82                 #set sizer
83                 self.SetSizerAndFit(control_box)
84
85 ##################################################
86 # histo window with plotter and control panel
87 ##################################################
88 class histo_window(wx.Panel, pubsub.pubsub):
89         def __init__(
90                 self,
91                 parent,
92                 controller,
93                 size,
94                 title,
95                 maximum_key,
96                 minimum_key,
97                 num_bins_key,
98                 frame_size_key,
99                 msg_key,
100         ):
101                 pubsub.pubsub.__init__(self)
102                 #setup
103                 self.samples = list()
104                 #proxy the keys
105                 self.proxy(MAXIMUM_KEY, controller, maximum_key)
106                 self.proxy(MINIMUM_KEY, controller, minimum_key)
107                 self.proxy(NUM_BINS_KEY, controller, num_bins_key)
108                 self.proxy(FRAME_SIZE_KEY, controller, frame_size_key)
109                 self.proxy(MSG_KEY, controller, msg_key)
110                 #initialize values
111                 self[RUNNING_KEY] = True
112                 self[X_DIVS_KEY] = 8
113                 self[Y_DIVS_KEY] = 4
114                 #init panel and plot
115                 wx.Panel.__init__(self, parent, style=wx.SIMPLE_BORDER)
116                 self.plotter = plotter.bar_plotter(self)
117                 self.plotter.SetSize(wx.Size(*size))
118                 self.plotter.set_title(title)
119                 self.plotter.enable_point_label(True)
120                 self.plotter.enable_grid_lines(False)
121                 #setup the box with plot and controls
122                 self.control_panel = control_panel(self)
123                 main_box = wx.BoxSizer(wx.HORIZONTAL)
124                 main_box.Add(self.plotter, 1, wx.EXPAND)
125                 main_box.Add(self.control_panel, 0, wx.EXPAND)
126                 self.SetSizerAndFit(main_box)
127                 #register events
128                 self.subscribe(MSG_KEY, self.handle_msg)
129                 self.subscribe(X_DIVS_KEY, self.update_grid)
130                 self.subscribe(Y_DIVS_KEY, self.update_grid)
131
132         def handle_msg(self, msg):
133                 """
134                 Handle the message from the fft sink message queue.
135                 @param msg the frame as a character array
136                 """
137                 if not self[RUNNING_KEY]: return
138                 #convert to floating point numbers
139                 self.samples = 100*numpy.fromstring(msg, numpy.float32)[:self[NUM_BINS_KEY]] #only take first frame
140                 self.plotter.set_bars(
141                         bars=self.samples,
142                         bar_width=0.6,
143                         color_spec=(0, 0, 1),
144                 )
145                 self.update_grid()
146
147         def update_grid(self):
148                 if not len(self.samples): return
149                 #calculate the maximum y value
150                 y_off = math.ceil(numpy.max(self.samples))
151                 y_off = min(max(y_off, 1.0), 100.0) #between 1% and 100%
152                 #update the x grid
153                 self.plotter.set_x_grid(
154                         self[MINIMUM_KEY], self[MAXIMUM_KEY],
155                         common.get_clean_num((self[MAXIMUM_KEY] - self[MINIMUM_KEY])/self[X_DIVS_KEY]),
156                 )
157                 self.plotter.set_x_label('Counts')
158                 #update the y grid
159                 self.plotter.set_y_grid(0, y_off, y_off/self[Y_DIVS_KEY])
160                 self.plotter.set_y_label('Frequency', '%')
161                 self.plotter.update()