[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r10660 - in gnuradio/trunk: . gnuradio-core/src/lib/io
From: |
jcorgan |
Subject: |
[Commit-gnuradio] r10660 - in gnuradio/trunk: . gnuradio-core/src/lib/io gr-wxgui/src/python gr-wxgui/src/python/plotter grc/data/platforms/python grc/data/platforms/python/blocks grc/examples/simple grc/examples/trellis grc/src/grc_gnuradio/wxgui |
Date: |
Thu, 19 Mar 2009 20:16:20 -0600 (MDT) |
Author: jcorgan
Date: 2009-03-19 20:16:20 -0600 (Thu, 19 Mar 2009)
New Revision: 10660
Added:
gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink.i
gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink_f.cc
gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink_f.h
gnuradio/trunk/gr-wxgui/src/python/histo_window.py
gnuradio/trunk/gr-wxgui/src/python/histosink_gl.py
gnuradio/trunk/gr-wxgui/src/python/plotter/bar_plotter.py
gnuradio/trunk/gr-wxgui/src/python/plotter/common.py
gnuradio/trunk/gr-wxgui/src/python/plotter/grid_plotter_base.py
gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_histosink2.xml
Modified:
gnuradio/trunk/
gnuradio/trunk/gnuradio-core/src/lib/io/Makefile.am
gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_guts.cc
gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_guts.h
gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink.i
gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_f.cc
gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_f.h
gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_x.cc
gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_x.h
gnuradio/trunk/gnuradio-core/src/lib/io/gr_trigger_mode.h
gnuradio/trunk/gnuradio-core/src/lib/io/io.i
gnuradio/trunk/gr-wxgui/src/python/Makefile.am
gnuradio/trunk/gr-wxgui/src/python/common.py
gnuradio/trunk/gr-wxgui/src/python/const_window.py
gnuradio/trunk/gr-wxgui/src/python/constants.py
gnuradio/trunk/gr-wxgui/src/python/constsink_gl.py
gnuradio/trunk/gr-wxgui/src/python/fft_window.py
gnuradio/trunk/gr-wxgui/src/python/fftsink_gl.py
gnuradio/trunk/gr-wxgui/src/python/fftsink_nongl.py
gnuradio/trunk/gr-wxgui/src/python/number_window.py
gnuradio/trunk/gr-wxgui/src/python/numbersink2.py
gnuradio/trunk/gr-wxgui/src/python/plotter/Makefile.am
gnuradio/trunk/gr-wxgui/src/python/plotter/__init__.py
gnuradio/trunk/gr-wxgui/src/python/plotter/channel_plotter.py
gnuradio/trunk/gr-wxgui/src/python/plotter/plotter_base.py
gnuradio/trunk/gr-wxgui/src/python/plotter/waterfall_plotter.py
gnuradio/trunk/gr-wxgui/src/python/pubsub.py
gnuradio/trunk/gr-wxgui/src/python/scope_window.py
gnuradio/trunk/gr-wxgui/src/python/scopesink2.py
gnuradio/trunk/gr-wxgui/src/python/scopesink_gl.py
gnuradio/trunk/gr-wxgui/src/python/scopesink_nongl.py
gnuradio/trunk/gr-wxgui/src/python/waterfall_window.py
gnuradio/trunk/gr-wxgui/src/python/waterfallsink_gl.py
gnuradio/trunk/grc/data/platforms/python/block_tree.xml
gnuradio/trunk/grc/data/platforms/python/blocks/Makefile.am
gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_constellationsink2.xml
gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_fftsink2.xml
gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_numbersink2.xml
gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_scopesink2.xml
gnuradio/trunk/grc/examples/simple/ber_simulation.grc
gnuradio/trunk/grc/examples/trellis/interference_cancellation.grc
gnuradio/trunk/grc/src/grc_gnuradio/wxgui/callback_controls.py
Log:
Merged r10463:10658 from jblum/gui_guts into trunk. Trunk passes distcheck.
Property changes on: gnuradio/trunk
___________________________________________________________________
Modified: svn:mergeinfo
- /gnuradio/branches/developers/eb/t348:10638-10648
/gnuradio/branches/developers/michaelld/am_swig_4:10555-10595
/gnuradio/branches/developers/michaelld/two_mods:10540-10546
+ /gnuradio/branches/developers/eb/t348:10638-10648
/gnuradio/branches/developers/jblum/gui_guts:10464-10658
/gnuradio/branches/developers/michaelld/am_swig_4:10555-10595
/gnuradio/branches/developers/michaelld/two_mods:10540-10546
Modified: gnuradio/trunk/gnuradio-core/src/lib/io/Makefile.am
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/Makefile.am 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/Makefile.am 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -33,6 +33,7 @@
gr_file_source.cc \
gr_file_descriptor_sink.cc \
gr_file_descriptor_source.cc \
+ gr_histo_sink_f.cc \
gr_message_sink.cc \
gr_message_source.cc \
gr_oscope_guts.cc \
@@ -64,6 +65,7 @@
gr_file_source.h \
gr_file_descriptor_sink.h \
gr_file_descriptor_source.h \
+ gr_histo_sink_f.h \
gr_message_sink.h \
gr_message_source.h \
gr_oscope_guts.h \
@@ -101,6 +103,7 @@
gr_file_source.i \
gr_file_descriptor_sink.i \
gr_file_descriptor_source.i \
+ gr_histo_sink.i \
gr_message_sink.i \
gr_message_source.i \
gr_oscope_sink.i \
Copied: gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink.i (from rev
10658,
gnuradio/branches/developers/jblum/gui_guts/gnuradio-core/src/lib/io/gr_histo_sink.i)
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink.i
(rev 0)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink.i 2009-03-20
02:16:20 UTC (rev 10660)
@@ -0,0 +1,39 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+GR_SWIG_BLOCK_MAGIC(gr,histo_sink_f)
+
+gr_histo_sink_f_sptr gr_make_histo_sink_f (gr_msg_queue_sptr msgq);
+
+class gr_histo_sink_f : public gr_sync_block
+{
+public:
+ ~gr_histo_sink_f (void);
+
+ unsigned int get_frame_size(void);
+ unsigned int get_num_bins(void);
+
+ void set_frame_size(unsigned int frame_size);
+ void set_num_bins(unsigned int num_bins);
+
+};
Copied: gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink_f.cc (from rev
10658,
gnuradio/branches/developers/jblum/gui_guts/gnuradio-core/src/lib/io/gr_histo_sink_f.cc)
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink_f.cc
(rev 0)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink_f.cc 2009-03-20
02:16:20 UTC (rev 10660)
@@ -0,0 +1,169 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_histo_sink_f.h>
+#include <gr_io_signature.h>
+
+static float get_clean_num(float num){
+ if (num == 0) return 0;
+ /* extract sign and exponent from num */
+ int sign = (num < 0) ? -1 : 1; num = fabs(num);
+ float exponent = floor(log10(num));
+ /* search for closest number with base 1, 2, 5, 10 */
+ float closest_num = 10*pow(10, exponent);
+ if (fabs(num - 1*pow(10, exponent)) < fabs(num - closest_num))
+ closest_num = 1*pow(10, exponent);
+ if (fabs(num - 2*pow(10, exponent)) < fabs(num - closest_num))
+ closest_num = 2*pow(10, exponent);
+ if (fabs(num - 5*pow(10, exponent)) < fabs(num - closest_num))
+ closest_num = 5*pow(10, exponent);
+ return sign*closest_num;
+}
+
+gr_histo_sink_f_sptr
+gr_make_histo_sink_f (gr_msg_queue_sptr msgq)
+{
+ return gr_histo_sink_f_sptr (new gr_histo_sink_f (msgq));
+}
+
+gr_histo_sink_f::gr_histo_sink_f (gr_msg_queue_sptr msgq)
+ : gr_sync_block ("histo_sink_f", gr_make_io_signature (1, 1, sizeof
(float)), gr_make_io_signature (0, 0, 0)),
+ d_msgq (msgq), d_num_bins(11), d_frame_size(1000), d_sample_count(0),
d_bins(NULL), d_samps(NULL)
+{
+ pthread_mutex_init(&d_mutex, 0);
+ //allocate arrays and clear
+ set_num_bins(d_num_bins);
+ set_frame_size(d_frame_size);
+}
+
+gr_histo_sink_f::~gr_histo_sink_f (void)
+{
+ pthread_mutex_destroy(&d_mutex);
+ delete [] d_samps;
+ delete [] d_bins;
+}
+
+int
+gr_histo_sink_f::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const float *in = (const float *) input_items[0];
+ pthread_mutex_lock(&d_mutex);
+ for (unsigned int i = 0; i < (unsigned int)noutput_items; i++){
+ d_samps[d_sample_count] = in[i];
+ d_sample_count++;
+ /* processed a frame? */
+ if (d_sample_count == d_frame_size){
+ send_frame();
+ clear();
+ }
+ }
+ pthread_mutex_unlock(&d_mutex);
+ return noutput_items;
+}
+
+void
+gr_histo_sink_f::send_frame(void){
+ /* output queue full, drop the data */
+ if (d_msgq->full_p()) return;
+ /* find the minimum and maximum */
+ float minimum = d_samps[0];
+ float maximum = d_samps[0];
+ for (unsigned int i = 0; i < d_frame_size; i++){
+ if (d_samps[i] < minimum) minimum = d_samps[i];
+ if (d_samps[i] > maximum) maximum = d_samps[i];
+ }
+ minimum = get_clean_num(minimum);
+ maximum = get_clean_num(maximum);
+ if (minimum == maximum || minimum > maximum) return; //useless data or screw
up?
+ /* load the bins */
+ int index;
+ float bin_width = (maximum - minimum)/(d_num_bins-1);
+ for (unsigned int i = 0; i < d_sample_count; i++){
+ index = round((d_samps[i] - minimum)/bin_width);
+ /* ensure the index range in case a small floating point error is involed
*/
+ if (index < 0) index = 0;
+ if (index >= (int)d_num_bins) index = d_num_bins-1;
+ d_bins[index]++;
+ }
+ /* Build a message to hold the output records */
+ gr_message_sptr msg = gr_make_message(0, minimum, maximum,
d_num_bins*sizeof(float));
+ float *out = (float *)msg->msg(); // get pointer to raw message buffer
+ /* normalize the bins and put into message */
+ for (unsigned int i = 0; i < d_num_bins; i++){
+ out[i] = ((float)d_bins[i])/d_frame_size;
+ }
+ /* send the message */
+ d_msgq->handle(msg);
+}
+
+void
+gr_histo_sink_f::clear(void){
+ d_sample_count = 0;
+ /* zero the bins */
+ for (unsigned int i = 0; i < d_num_bins; i++){
+ d_bins[i] = 0;
+ }
+}
+
+/**************************************************
+ * Getters
+ **************************************************/
+unsigned int
+gr_histo_sink_f::get_frame_size(void){
+ return d_frame_size;
+}
+
+unsigned int
+gr_histo_sink_f::get_num_bins(void){
+ return d_num_bins;
+}
+
+/**************************************************
+ * Setters
+ **************************************************/
+void
+gr_histo_sink_f::set_frame_size(unsigned int frame_size){
+ pthread_mutex_lock(&d_mutex);
+ d_frame_size = frame_size;
+ /* allocate a new sample array */
+ delete [] d_samps;
+ d_samps = new float[d_frame_size];
+ clear();
+ pthread_mutex_unlock(&d_mutex);
+}
+
+void
+gr_histo_sink_f::set_num_bins(unsigned int num_bins){
+ pthread_mutex_lock(&d_mutex);
+ d_num_bins = num_bins;
+ /* allocate a new bin array */
+ delete [] d_bins;
+ d_bins = new unsigned int[d_num_bins];
+ clear();
+ pthread_mutex_unlock(&d_mutex);
+}
Copied: gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink_f.h (from rev
10658,
gnuradio/branches/developers/jblum/gui_guts/gnuradio-core/src/lib/io/gr_histo_sink_f.h)
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink_f.h
(rev 0)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/gr_histo_sink_f.h 2009-03-20
02:16:20 UTC (rev 10660)
@@ -0,0 +1,70 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GR_HISTO_SINK_F_H
+#define INCLUDED_GR_HISTO_SINK_F_H
+
+#include <gr_sync_block.h>
+#include <gr_msg_queue.h>
+#include <pthread.h>
+
+class gr_histo_sink_f;
+typedef boost::shared_ptr<gr_histo_sink_f> gr_histo_sink_f_sptr;
+
+gr_histo_sink_f_sptr gr_make_histo_sink_f (gr_msg_queue_sptr msgq);
+
+/*!
+ * \brief Histogram module.
+ * \ingroup sink
+ */
+class gr_histo_sink_f : public gr_sync_block
+{
+private:
+ gr_msg_queue_sptr d_msgq;
+ unsigned int d_num_bins;
+ unsigned int d_frame_size;
+ unsigned int d_sample_count;
+ unsigned int *d_bins;
+ float *d_samps;
+ pthread_mutex_t d_mutex;
+
+ friend gr_histo_sink_f_sptr gr_make_histo_sink_f (gr_msg_queue_sptr msgq);
+ gr_histo_sink_f (gr_msg_queue_sptr msgq);
+ void send_frame(void);
+ void clear(void);
+
+public:
+ ~gr_histo_sink_f (void);
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+ unsigned int get_frame_size(void);
+ unsigned int get_num_bins(void);
+
+ void set_frame_size(unsigned int frame_size);
+ void set_num_bins(unsigned int num_bins);
+
+};
+
+#endif /* INCLUDED_GR_HISTO_SINK_F_H */
Modified: gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_guts.cc
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_guts.cc 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_guts.cc 2009-03-20
02:16:20 UTC (rev 10660)
@@ -31,30 +31,31 @@
#include <math.h>
#include <assert.h>
-static const int OUTPUT_RECORD_SIZE = 2048; // must be power of 2
+static const int OUTPUT_RECORD_SIZE = 2048; // must be power of 2
static inline int
-wrap_bi (int buffer_index) // wrap buffer index
+wrap_bi (int buffer_index) // wrap buffer index
{
return buffer_index & (OUTPUT_RECORD_SIZE - 1);
}
static inline int
-incr_bi (int buffer_index) // increment buffer index
+incr_bi (int buffer_index) // increment buffer index
{
return wrap_bi (buffer_index + 1);
}
static inline int
-decr_bi (int buffer_index) // decrement buffer index
+decr_bi (int buffer_index) // decrement buffer index
{
return wrap_bi (buffer_index - 1);
}
-gr_oscope_guts::gr_oscope_guts (int nchannels, double sample_rate,
gr_msg_queue_sptr msgq)
- : d_nchannels (nchannels),
+gr_oscope_guts::gr_oscope_guts (double sample_rate, gr_msg_queue_sptr msgq)
+ : d_nchannels (1),
d_msgq (msgq),
- d_trigger_mode (gr_TRIG_AUTO),
+ d_trigger_mode (gr_TRIG_MODE_AUTO),
+ d_trigger_slope (gr_TRIG_SLOPE_POS),
d_trigger_channel (0),
d_sample_rate (sample_rate),
d_update_rate (20),
@@ -65,19 +66,14 @@
d_decimator_count_init (1),
d_hold_off_count (0),
d_hold_off_count_init (OUTPUT_RECORD_SIZE/2-1),
+ d_pre_trigger_count (0),
d_post_trigger_count (0),
- d_post_trigger_count_init (OUTPUT_RECORD_SIZE/2),
- d_prev_sample (0)
+ d_post_trigger_count_init (OUTPUT_RECORD_SIZE/2)
{
- if (d_nchannels > MAX_CHANNELS){
- fprintf (stderr, "gr_oscope_guts: too many channels. MAX_CHANNELS =
%d\n", MAX_CHANNELS);
- throw std::runtime_error ("too many channels");
- }
-
for (int i = 0; i < MAX_CHANNELS; i++)
d_buffer[i] = 0;
- for (int i = 0; i < d_nchannels; i++){
+ for (int i = 0; i < MAX_CHANNELS; i++){
d_buffer[i] = new float [OUTPUT_RECORD_SIZE];
for (int j = 0; j < OUTPUT_RECORD_SIZE; j++)
d_buffer[i][j] = 0.0;
@@ -109,10 +105,8 @@
d_decimator_count = d_decimator_count_init;
for (int i = 0; i < d_nchannels; i++)
- d_buffer[i][d_obi] = channel_data[i]; // copy data into buffer
+ d_buffer[i][d_obi] = channel_data[i]; // copy data into
buffer
- int trigger = 0;
-
switch (d_state){
case HOLD_OFF:
d_hold_off_count--;
@@ -121,12 +115,8 @@
break;
case LOOK_FOR_TRIGGER:
- trigger = found_trigger (d_buffer[d_trigger_channel][d_obi]);
- if (trigger != 0){
+ if (found_trigger ())
enter_post_trigger ();
- if (trigger < 0) // previous sample was closer
- d_post_trigger_count--;
- }
break;
case POST_TRIGGER:
@@ -158,8 +148,8 @@
void
gr_oscope_guts::enter_look_for_trigger ()
{
+ d_pre_trigger_count = 0;
d_state = LOOK_FOR_TRIGGER;
- d_prev_sample = d_buffer[d_trigger_channel][d_obi];
}
void
@@ -167,48 +157,49 @@
{
d_state = POST_TRIGGER;
d_post_trigger_count = d_post_trigger_count_init;
+ //ensure that the trigger offset is no more than than half a sample
+ if (d_trigger_off > .5) d_trigger_off -= 1;
+ else d_post_trigger_count--;
}
// ----------------------------------------------------------------
-// returns 0 if no trigger found.
-// returns +1 if this sample is the trigger point
-// returns -1 if the previous sample is the trigger point
+// returns true if trigger found
-int
-gr_oscope_guts::found_trigger (float new_sample)
+bool
+gr_oscope_guts::found_trigger ()
{
- float prev_sample = d_prev_sample;
- d_prev_sample = new_sample;
- bool trig;
+ float prev_sample = d_buffer[d_trigger_channel][decr_bi(d_obi)];
+ float new_sample = d_buffer[d_trigger_channel][d_obi];
switch (d_trigger_mode){
- case gr_TRIG_AUTO: // always trigger
- return +1;
-
- case gr_TRIG_POS_SLOPE:
- trig = prev_sample < d_trigger_level && new_sample >= d_trigger_level;
- if (trig){
- if (fabs (prev_sample - d_trigger_level) < fabs (new_sample -
d_trigger_level))
- return -1;
- else
- return +1;
- }
- return 0;
+ case gr_TRIG_MODE_AUTO: //too many samples without a trigger
+ d_pre_trigger_count++;
+ if (d_pre_trigger_count > OUTPUT_RECORD_SIZE/2) return true;
- case gr_TRIG_NEG_SLOPE:
- trig = prev_sample > d_trigger_level && new_sample <= d_trigger_level;
- if (trig){
- if (fabs (prev_sample - d_trigger_level) < fabs (new_sample -
d_trigger_level))
- return -1;
- else
- return +1;
+ case gr_TRIG_MODE_NORM: //look for trigger
+ switch (d_trigger_slope){
+
+ case gr_TRIG_SLOPE_POS: //trigger point in pos slope?
+ if (new_sample < d_trigger_level || prev_sample >= d_trigger_level)
return false;
+ break;
+
+ case gr_TRIG_SLOPE_NEG: //trigger point in neg slope?
+ if (new_sample > d_trigger_level || prev_sample <= d_trigger_level)
return false;
+ break;
}
- return 0;
+ //calculate the trigger offset in % sample
+ d_trigger_off = (d_trigger_level - prev_sample)/(new_sample - prev_sample);
+ return true;
+
+ case gr_TRIG_MODE_FREE: //free run mode, always trigger
+ d_trigger_off = 0;
+ return true;
+
default:
assert (0);
- return 0;
+ return false;
}
}
@@ -218,28 +209,30 @@
void
gr_oscope_guts::write_output_records ()
{
- // if the output queue if full, drop the data on the ground.
+ // if the output queue if full, drop the data like its hot.
if (d_msgq->full_p())
return;
-
- // Build a message to hold the output records
+ // Build a message to hold the output records
gr_message_sptr msg =
- gr_make_message(0, // msg
type
- d_nchannels, // arg1
for other side
- OUTPUT_RECORD_SIZE, // arg2
for other side
- d_nchannels * OUTPUT_RECORD_SIZE * sizeof(float)); //
sizeof payload
+ gr_make_message(0, // msg type
+ d_nchannels, // arg1 for
other side
+ OUTPUT_RECORD_SIZE, // arg2 for
other side
+ ((d_nchannels * OUTPUT_RECORD_SIZE) + 1) * sizeof(float)); //
sizeof payload
- float *out = (float *)msg->msg(); // get pointer to raw message buffer
+ float *out = (float *)msg->msg(); // get pointer to raw message buffer
for (int ch = 0; ch < d_nchannels; ch++){
// note that d_obi + 1 points at the oldest sample in the buffer
- for (int i = 0; i < OUTPUT_RECORD_SIZE; i++)
+ for (int i = 0; i < OUTPUT_RECORD_SIZE; i++){
out[i] = d_buffer[ch][wrap_bi(d_obi + 1 + i)];
-
+ }
out += OUTPUT_RECORD_SIZE;
}
-
- d_msgq->handle(msg); // send the msg
+ //Set the last sample as the trigger offset:
+ // The non gl scope sink will not look at this last sample.
+ // The gl scope sink will use this last sample as an offset.
+ out[0] = d_trigger_off;
+ d_msgq->handle(msg); // send the msg
}
// ----------------------------------------------------------------
@@ -291,18 +284,20 @@
bool
gr_oscope_guts::set_trigger_mode (gr_trigger_mode mode)
{
- switch (mode){
- case gr_TRIG_POS_SLOPE:
- case gr_TRIG_NEG_SLOPE:
- case gr_TRIG_AUTO:
- d_trigger_mode = mode;
- trigger_changed ();
- return true;
- }
- return false;
+ d_trigger_mode = mode;
+ trigger_changed ();
+ return true;
}
bool
+gr_oscope_guts::set_trigger_slope (gr_trigger_slope slope)
+{
+ d_trigger_slope = slope;
+ trigger_changed ();
+ return true;
+}
+
+bool
gr_oscope_guts::set_trigger_level (double trigger_level)
{
d_trigger_level = trigger_level;
@@ -315,23 +310,30 @@
{
// find the level 1/2 way between the min and the max
- float min_v = d_buffer[d_trigger_channel][0];
- float max_v = d_buffer[d_trigger_channel][0];
+ float min_v = d_buffer[d_trigger_channel][0];
+ float max_v = d_buffer[d_trigger_channel][0];
for (int i = 1; i < OUTPUT_RECORD_SIZE; i++){
min_v = std::min (min_v, d_buffer[d_trigger_channel][i]);
max_v = std::max (max_v, d_buffer[d_trigger_channel][i]);
}
+ return set_trigger_level((min_v + max_v) * 0.5);
+}
- d_trigger_level = (min_v + max_v) * 0.5;
- trigger_changed ();
- return true;
+bool
+gr_oscope_guts::set_num_channels(int nchannels)
+{
+ if (nchannels > 0 && nchannels <= MAX_CHANNELS){
+ d_nchannels = nchannels;
+ return true;
+ }
+ return false;
}
+
void
gr_oscope_guts::trigger_changed ()
{
- // d_prev_sample = d_buffer[d_trigger_channel][decr_bi(d_obi)];
enter_look_for_trigger ();
}
@@ -373,6 +375,12 @@
return d_trigger_mode;
}
+gr_trigger_slope
+gr_oscope_guts::get_trigger_slope () const
+{
+ return d_trigger_slope;
+}
+
double
gr_oscope_guts::get_trigger_level () const
{
Modified: gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_guts.h
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_guts.h 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_guts.h 2009-03-20
02:16:20 UTC (rev 10660)
@@ -41,13 +41,15 @@
*/
class gr_oscope_guts {
+public:
+ static const int MAX_CHANNELS = 8;
private:
- static const int MAX_CHANNELS = 16;
enum scope_state { HOLD_OFF, LOOK_FOR_TRIGGER, POST_TRIGGER };
int d_nchannels; // how many channels
gr_msg_queue_sptr d_msgq; // message queue we stuff
output records into
- gr_trigger_mode d_trigger_mode;
+ gr_trigger_mode d_trigger_mode;
+ gr_trigger_slope d_trigger_slope;
int d_trigger_channel; // which channel to watch for
trigger condition
double d_sample_rate; // input sample rate in Hz
double d_update_rate; // approx freq to produce an
output record (Hz)
@@ -61,9 +63,10 @@
int d_decimator_count_init;
int d_hold_off_count;
int d_hold_off_count_init;
+ int d_pre_trigger_count;
int d_post_trigger_count;
int d_post_trigger_count_init;
- float d_prev_sample; // used for
trigger checking
+ float d_trigger_off; //%sample
trigger is off
// NOT IMPLEMENTED
gr_oscope_guts (const gr_oscope_guts &rhs); // no copy
constructor
@@ -71,7 +74,7 @@
void trigger_changed ();
void update_rate_or_decimation_changed ();
- int found_trigger (float sample); // returns -1, 0, +1
+ bool found_trigger (); // returns true if found
void write_output_records ();
void enter_hold_off (); // called on state entry
@@ -80,7 +83,7 @@
public:
// CREATORS
- gr_oscope_guts (int nchannels, double sample_rate, gr_msg_queue_sptr msgq);
+ gr_oscope_guts (double sample_rate, gr_msg_queue_sptr msgq);
~gr_oscope_guts ();
// MANIPULATORS
@@ -95,9 +98,11 @@
bool set_decimation_count (int decimation_count);
bool set_trigger_channel (int channel);
bool set_trigger_mode (gr_trigger_mode mode);
+ bool set_trigger_slope (gr_trigger_slope slope);
bool set_trigger_level (double trigger_level);
bool set_trigger_level_auto (); // set to 50%
level
bool set_sample_rate(double sample_rate);
+ bool set_num_channels(int nchannels);
// ACCESSORS
@@ -107,6 +112,7 @@
int get_decimation_count () const;
int get_trigger_channel () const;
gr_trigger_mode get_trigger_mode () const;
+ gr_trigger_slope get_trigger_slope () const;
double get_trigger_level () const;
// # of samples written to each output record.
Modified: gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink.i
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink.i 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink.i 2009-03-20
02:16:20 UTC (rev 10660)
@@ -20,11 +20,7 @@
* Boston, MA 02110-1301, USA.
*/
-enum gr_trigger_mode {
- gr_TRIG_AUTO, // auto trigger (on anything)
- gr_TRIG_POS_SLOPE, // trigger on positive slope across trigger
level
- gr_TRIG_NEG_SLOPE // trigger on negative slope across trigger
level
-};
+%include gr_trigger_mode.h
// GR_SWIG_BLOCK_MAGIC(gr,oscope_sink_x)
@@ -43,6 +39,7 @@
bool set_decimation_count (int decimation_count);
bool set_trigger_channel (int channel);
bool set_trigger_mode (gr_trigger_mode mode);
+ bool set_trigger_slope (gr_trigger_slope slope);
bool set_trigger_level (double trigger_level);
bool set_trigger_level_auto (); // set to 50%
level
bool set_sample_rate(double sample_rate);
@@ -54,6 +51,7 @@
int get_decimation_count () const;
int get_trigger_channel () const;
gr_trigger_mode get_trigger_mode () const;
+ gr_trigger_slope get_trigger_slope () const;
double get_trigger_level () const;
// # of samples written to each output record.
Modified: gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_f.cc
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_f.cc 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_f.cc 2009-03-20
02:16:20 UTC (rev 10660)
@@ -38,20 +38,18 @@
gr_oscope_sink_f::gr_oscope_sink_f (double sampling_rate, gr_msg_queue_sptr
msgq)
: gr_oscope_sink_x ("oscope_sink_f",
- gr_make_io_signature (1, MAX_CHANNELS, sizeof (float)),
+ gr_make_io_signature (1, gr_oscope_guts::MAX_CHANNELS,
sizeof (float)),
sampling_rate),
d_msgq(msgq)
{
+ d_guts = new gr_oscope_guts (d_sampling_rate, d_msgq);
}
bool
gr_oscope_sink_f::check_topology (int ninputs, int noutputs)
{
- delete d_guts;
- d_guts = 0;
- d_guts = new gr_oscope_guts (ninputs, d_sampling_rate, d_msgq);
- return true;
+ return d_guts->set_num_channels(ninputs);
}
@@ -65,7 +63,7 @@
gr_vector_void_star &output_items)
{
int ni = input_items.size ();
- float tmp[MAX_CHANNELS];
+ float tmp[gr_oscope_guts::MAX_CHANNELS];
for (int i = 0; i < noutput_items; i++){
Modified: gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_f.h
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_f.h 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_f.h 2009-03-20
02:16:20 UTC (rev 10660)
@@ -36,13 +36,10 @@
* \brief Building block for python oscilloscope module.
* \ingroup sink
*
- * Accepts 1 to 16 float streams.
+ * Accepts multiple float streams.
*/
class gr_oscope_sink_f : public gr_oscope_sink_x
{
-public:
- static const int MAX_CHANNELS = 16;
-
private:
friend gr_oscope_sink_f_sptr
gr_make_oscope_sink_f (double sampling_rate, gr_msg_queue_sptr msgq);
Modified: gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_x.cc
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_x.cc 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_x.cc 2009-03-20
02:16:20 UTC (rev 10660)
@@ -69,6 +69,12 @@
}
bool
+gr_oscope_sink_x::set_trigger_slope (gr_trigger_slope slope)
+{
+ return d_guts->set_trigger_slope (slope);
+}
+
+bool
gr_oscope_sink_x::set_trigger_level (double trigger_level)
{
return d_guts->set_trigger_level (trigger_level);
@@ -87,6 +93,12 @@
return d_guts->set_sample_rate (sample_rate);
}
+bool
+gr_oscope_sink_x::set_num_channels (int nchannels)
+{
+ return d_guts->set_num_channels (nchannels);
+}
+
// ACCESSORS
int
@@ -125,6 +137,12 @@
return d_guts->get_trigger_mode ();
}
+gr_trigger_slope
+gr_oscope_sink_x::get_trigger_slope () const
+{
+ return d_guts->get_trigger_slope ();
+}
+
double
gr_oscope_sink_x::get_trigger_level () const
{
Modified: gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_x.h
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_x.h 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/gr_oscope_sink_x.h 2009-03-20
02:16:20 UTC (rev 10660)
@@ -51,9 +51,11 @@
bool set_decimation_count (int decimation_count);
bool set_trigger_channel (int channel);
bool set_trigger_mode (gr_trigger_mode mode);
+ bool set_trigger_slope (gr_trigger_slope slope);
bool set_trigger_level (double trigger_level);
bool set_trigger_level_auto (); // set to 50%
level
bool set_sample_rate(double sample_rate);
+ bool set_num_channels (int nchannels);
// ACCESSORS
@@ -63,6 +65,7 @@
int get_decimation_count () const;
int get_trigger_channel () const;
gr_trigger_mode get_trigger_mode () const;
+ gr_trigger_slope get_trigger_slope () const;
double get_trigger_level () const;
// # of samples written to each output record.
Modified: gnuradio/trunk/gnuradio-core/src/lib/io/gr_trigger_mode.h
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/gr_trigger_mode.h 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/gr_trigger_mode.h 2009-03-20
02:16:20 UTC (rev 10660)
@@ -24,9 +24,14 @@
#define INCLUDED_GR_TRIGGER_MODE_H
enum gr_trigger_mode {
- gr_TRIG_AUTO, // auto trigger (on anything)
- gr_TRIG_POS_SLOPE, // trigger on positive slope across trigger
level
- gr_TRIG_NEG_SLOPE // trigger on negative slope across trigger
level
+ gr_TRIG_MODE_FREE,
+ gr_TRIG_MODE_AUTO,
+ gr_TRIG_MODE_NORM,
};
+enum gr_trigger_slope {
+ gr_TRIG_SLOPE_POS,
+ gr_TRIG_SLOPE_NEG,
+};
+
#endif /* INCLUDED_GR_TRIGGER_MODE_H */
Modified: gnuradio/trunk/gnuradio-core/src/lib/io/io.i
===================================================================
--- gnuradio/trunk/gnuradio-core/src/lib/io/io.i 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gnuradio-core/src/lib/io/io.i 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -30,6 +30,7 @@
#include <gr_file_source.h>
#include <gr_file_descriptor_sink.h>
#include <gr_file_descriptor_source.h>
+#include <gr_histo_sink_f.h>
#include <microtune_4702_eval_board.h>
#include <microtune_4937_eval_board.h>
#include <sdr_1000.h>
@@ -50,6 +51,7 @@
%include "gr_file_source.i"
%include "gr_file_descriptor_sink.i"
%include "gr_file_descriptor_source.i"
+%include "gr_histo_sink.i"
%include "microtune_xxxx_eval_board.i"
%include "microtune_4702_eval_board.i"
%include "microtune_4937_eval_board.i"
Modified: gnuradio/trunk/gr-wxgui/src/python/Makefile.am
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/Makefile.am 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/Makefile.am 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -42,6 +42,8 @@
fftsink_gl.py \
fft_window.py \
gui.py \
+ histosink_gl.py \
+ histo_window.py \
numbersink2.py \
number_window.py \
plot.py \
Modified: gnuradio/trunk/gr-wxgui/src/python/common.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/common.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/common.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -19,60 +19,86 @@
# Boston, MA 02110-1301, USA.
#
-import threading
-import numpy
-import math
-import wx
+#A macro to apply an index to a key
+index_key = lambda key, i: "%s_%d"%(key, i+1)
-class prop_setter(object):
- def _register_set_prop(self, controller, control_key, *args):
- def set_method(value): controller[control_key] = value
- if args: set_method(args[0])
- setattr(self, 'set_%s'%control_key, set_method)
+def _register_access_method(destination, controller, key):
+ """
+ Helper function for register access methods.
+ This helper creates distinct set and get methods for each key
+ and adds them to the destination object.
+ """
+ def set(value): controller[key] = value
+ setattr(destination, 'set_'+key, set)
+ def get(): return controller[key]
+ setattr(destination, 'get_'+key, get)
-##################################################
-# Custom Data Event
-##################################################
-EVT_DATA = wx.PyEventBinder(wx.NewEventType())
-class DataEvent(wx.PyEvent):
- def __init__(self, data):
- wx.PyEvent.__init__(self, wx.NewId(), EVT_DATA.typeId)
- self.data = data
+def register_access_methods(destination, controller):
+ """
+ Register setter and getter functions in the destination object for all
keys in the controller.
+ @param destination the object to get new setter and getter methods
+ @param controller the pubsub controller
+ """
+ for key in controller.keys(): _register_access_method(destination,
controller, key)
##################################################
# Input Watcher Thread
##################################################
+import threading
+
class input_watcher(threading.Thread):
"""
Input watcher thread runs forever.
Read messages from the message queue.
Forward messages to the message handler.
"""
- def __init__ (self, msgq, handle_msg):
+ def __init__ (self, msgq, controller, msg_key, arg1_key='',
arg2_key=''):
threading.Thread.__init__(self)
self.setDaemon(1)
self.msgq = msgq
- self._handle_msg = handle_msg
+ self._controller = controller
+ self._msg_key = msg_key
+ self._arg1_key = arg1_key
+ self._arg2_key = arg2_key
self.keep_running = True
self.start()
def run(self):
- while self.keep_running:
self._handle_msg(self.msgq.delete_head().to_string())
+ while self.keep_running:
+ msg = self.msgq.delete_head()
+ if self._arg1_key: self._controller[self._arg1_key] =
msg.arg1()
+ if self._arg2_key: self._controller[self._arg2_key] =
msg.arg2()
+ self._controller[self._msg_key] = msg.to_string()
##################################################
# WX Shared Classes
##################################################
+import math
+import wx
+
+EVT_DATA = wx.PyEventBinder(wx.NewEventType())
+class DataEvent(wx.PyEvent):
+ def __init__(self, data):
+ wx.PyEvent.__init__(self, wx.NewId(), EVT_DATA.typeId)
+ self.data = data
+
class LabelText(wx.StaticText):
"""
Label text to give the wx plots a uniform look.
Get the default label text and set the font bold.
"""
def __init__(self, parent, label):
- wx.StaticText.__init__(self, parent, -1, label)
+ wx.StaticText.__init__(self, parent, label=label)
font = self.GetFont()
font.SetWeight(wx.FONTWEIGHT_BOLD)
self.SetFont(font)
+class LabelBox(wx.BoxSizer):
+ def __init__(self, parent, label, widget):
+ wx.BoxSizer.__init__(self, wx.HORIZONTAL)
+ self.Add(wx.StaticText(parent, label=' %s '%label), 1,
wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+ self.Add(widget, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+
class IncrDecrButtons(wx.BoxSizer):
"""
A horizontal box sizer with a increment and a decrement button.
@@ -84,14 +110,14 @@
@param on_decr the event handler for decrement
"""
wx.BoxSizer.__init__(self, wx.HORIZONTAL)
- self._incr_button = wx.Button(parent, -1, '+',
style=wx.BU_EXACTFIT)
+ self._incr_button = wx.Button(parent, label='+',
style=wx.BU_EXACTFIT)
self._incr_button.Bind(wx.EVT_BUTTON, on_incr)
self.Add(self._incr_button, 0, wx.ALIGN_CENTER_VERTICAL)
- self._decr_button = wx.Button(parent, -1, ' - ',
style=wx.BU_EXACTFIT)
+ self._decr_button = wx.Button(parent, label=' - ',
style=wx.BU_EXACTFIT)
self._decr_button.Bind(wx.EVT_BUTTON, on_decr)
self.Add(self._decr_button, 0, wx.ALIGN_CENTER_VERTICAL)
- def Disable(self, disable=True): self.Enable(not disable)
+ def Disable(self): self.Enable(False)
def Enable(self, enable=True):
if enable:
self._incr_button.Enable()
@@ -104,7 +130,7 @@
def __init__(self, parent, controller, control_key, true_label,
false_label):
self._controller = controller
self._control_key = control_key
- wx.Button.__init__(self, parent, -1, '', style=wx.BU_EXACTFIT)
+ wx.Button.__init__(self, parent, style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self._evt_button)
controller.subscribe(control_key, lambda x: self.SetLabel(x and
true_label or false_label))
@@ -122,30 +148,55 @@
def _evt_checkbox(self, e):
self._controller[self._control_key] = bool(e.IsChecked())
+from gnuradio import eng_notation
+
+class TextBoxController(wx.TextCtrl):
+ def __init__(self, parent, controller, control_key, cast=float):
+ self._controller = controller
+ self._control_key = control_key
+ self._cast = cast
+ wx.TextCtrl.__init__(self, parent, style=wx.TE_PROCESS_ENTER)
+ self.Bind(wx.EVT_TEXT_ENTER, self._evt_enter)
+ controller.subscribe(control_key, lambda x:
self.SetValue(eng_notation.num_to_str(x)))
+
+ def _evt_enter(self, e):
+ try: self._controller[self._control_key] =
self._cast(eng_notation.str_to_num(self.GetValue()))
+ except: self._controller[self._control_key] =
self._controller[self._control_key]
+
class LogSliderController(wx.BoxSizer):
"""
Log slider controller with display label and slider.
Gives logarithmic scaling to slider operation.
"""
- def __init__(self, parent, label, min_exp, max_exp, slider_steps,
controller, control_key, formatter=lambda x: ': %.6f'%x):
+ def __init__(self, parent, prefix, min_exp, max_exp, slider_steps,
controller, control_key, formatter=lambda x: ': %.6f'%x):
+ self._prefix = prefix
+ self._min_exp = min_exp
+ self._max_exp = max_exp
+ self._controller = controller
+ self._control_key = control_key
+ self._formatter = formatter
wx.BoxSizer.__init__(self, wx.VERTICAL)
- self._label = wx.StaticText(parent, -1, label +
formatter(1/3.0))
+ self._label = wx.StaticText(parent, label=prefix +
formatter(1/3.0))
self.Add(self._label, 0, wx.EXPAND)
- self._slider = wx.Slider(parent, -1, 0, 0, slider_steps,
style=wx.SL_HORIZONTAL)
+ self._slider = wx.Slider(parent, minValue=0,
maxValue=slider_steps, style=wx.SL_HORIZONTAL)
self.Add(self._slider, 0, wx.EXPAND)
- def _on_slider_event(event):
- controller[control_key] = \
-
10**(float(max_exp-min_exp)*self._slider.GetValue()/slider_steps + min_exp)
- self._slider.Bind(wx.EVT_SLIDER, _on_slider_event)
- def _on_controller_set(value):
- self._label.SetLabel(label + formatter(value))
- slider_value =
slider_steps*(math.log10(value)-min_exp)/(max_exp-min_exp)
- slider_value = min(max(0, slider_value), slider_steps)
- if abs(slider_value - self._slider.GetValue()) > 1:
- self._slider.SetValue(slider_value)
- controller.subscribe(control_key, _on_controller_set)
+ self._slider.Bind(wx.EVT_SLIDER, self._on_slider_event)
+ controller.subscribe(control_key, self._on_controller_set)
- def Disable(self, disable=True): self.Enable(not disable)
+ def _get_slope(self):
+ return float(self._max_exp-self._min_exp)/self._slider.GetMax()
+
+ def _on_slider_event(self, e):
+ self._controller[self._control_key] =
10**(self._get_slope()*self._slider.GetValue() + self._min_exp)
+
+ def _on_controller_set(self, value):
+ self._label.SetLabel(self._prefix + self._formatter(value))
+ slider_value =
(math.log10(value)-self._min_exp)/self._get_slope()
+ slider_value = min(max(self._slider.GetMin(), slider_value),
self._slider.GetMax())
+ if abs(slider_value - self._slider.GetValue()) > 1:
+ self._slider.SetValue(slider_value)
+
+ def Disable(self): self.Enable(False)
def Enable(self, enable=True):
if enable:
self._slider.Enable()
@@ -154,45 +205,39 @@
self._slider.Disable()
self._label.Disable()
-class DropDownController(wx.BoxSizer):
+class DropDownController(wx.Choice):
"""
Drop down controller with label and chooser.
Srop down selection from a set of choices.
"""
- def __init__(self, parent, label, choices, controller, control_key,
size=(-1, -1)):
+ def __init__(self, parent, choices, controller, control_key, size=(-1,
-1)):
"""
@param parent the parent window
- @param label the label for the drop down
@param choices a list of tuples -> (label, value)
@param controller the prop val controller
@param control_key the prop key for this control
"""
- wx.BoxSizer.__init__(self, wx.HORIZONTAL)
- self._label = wx.StaticText(parent, -1, ' %s '%label)
- self.Add(self._label, 1, wx.ALIGN_CENTER_VERTICAL)
- self._chooser = wx.Choice(parent, -1, choices=[c[0] for c in
choices], size=size)
- def _on_chooser_event(event):
- controller[control_key] =
choices[self._chooser.GetSelection()][1]
- self._chooser.Bind(wx.EVT_CHOICE, _on_chooser_event)
- self.Add(self._chooser, 0, wx.ALIGN_CENTER_VERTICAL)
- def _on_controller_set(value):
- #only set the chooser if the value is a possible choice
- for i, choice in enumerate(choices):
- if value == choice[1]:
self._chooser.SetSelection(i)
- controller.subscribe(control_key, _on_controller_set)
+ self._controller = controller
+ self._control_key = control_key
+ self._choices = choices
+ wx.Choice.__init__(self, parent, choices=[c[0] for c in
choices], size=size)
+ self.Bind(wx.EVT_CHOICE, self._on_chooser_event)
+ controller.subscribe(control_key, self._on_controller_set)
- def Disable(self, disable=True): self.Enable(not disable)
- def Enable(self, enable=True):
- if enable:
- self._chooser.Enable()
- self._label.Enable()
- else:
- self._chooser.Disable()
- self._label.Disable()
+ def _on_chooser_event(self, e):
+ self._controller[self._control_key] =
self._choices[self.GetSelection()][1]
+ def _on_controller_set(self, value):
+ #only set the chooser if the value is a possible choice
+ for i, choice in enumerate(self._choices):
+ if value == choice[1]: self.SetSelection(i)
+
##################################################
# Shared Functions
##################################################
+import numpy
+import math
+
def get_exp(num):
"""
Get the exponent of the number in base 10.
@@ -209,8 +254,7 @@
@return the closest number
"""
if num == 0: return 0
- if num > 0: sign = 1
- else: sign = -1
+ sign = num > 0 and 1 or -1
exp = get_exp(num)
nums = numpy.array((1, 2, 5, 10))*(10**exp)
return sign*nums[numpy.argmin(numpy.abs(nums - abs(num)))]
@@ -263,49 +307,3 @@
min = mean - rms
max = mean + rms
return min, max
-
-def get_si_components(num):
- """
- Get the SI units for the number.
- Extract the coeff and exponent of the number.
- The exponent will be a multiple of 3.
- @param num the floating point number
- @return the tuple coeff, exp, prefix
- """
- exp = get_exp(num)
- exp -= exp%3
- exp = min(max(exp, -24), 24) #bounds on SI table below
- prefix = {
- 24: 'Y', 21: 'Z',
- 18: 'E', 15: 'P',
- 12: 'T', 9: 'G',
- 6: 'M', 3: 'K',
- 0: '',
- -3: 'm', -6: 'u',
- -9: 'n', -12: 'p',
- -15: 'f', -18: 'a',
- -21: 'z', -24: 'y',
- }[exp]
- coeff = num/10**exp
- return coeff, exp, prefix
-
-def label_format(num):
- """
- Format a floating point number into a presentable string.
- If the number has an small enough exponent, use regular decimal.
- Otherwise, format the number with floating point notation.
- Exponents are normalized to multiples of 3.
- In the case where the exponent was found to be -3,
- it is best to display this as a regular decimal, with a 0 to the left.
- @param num the number to format
- @return a label string
- """
- coeff, exp, prefix = get_si_components(num)
- if -3 <= exp < 3: return '%g'%num
- return '%se%d'%('%.3g'%coeff, exp)
-
-if __name__ == '__main__':
- import random
- for i in range(-25, 25):
- num = random.random()*10**i
- print num, ':', get_si_components(num)
Modified: gnuradio/trunk/gr-wxgui/src/python/const_window.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/const_window.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/const_window.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -62,32 +62,31 @@
@param parent the wx parent window
"""
self.parent = parent
- wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
+ wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
control_box = wx.BoxSizer(wx.VERTICAL)
self.marker_index = 2
#begin control box
- control_box.AddStretchSpacer()
control_box.Add(common.LabelText(self, 'Options'), 0,
wx.ALIGN_CENTER)
- #marker
- control_box.AddStretchSpacer()
- self.marker_chooser = common.DropDownController(self, 'Marker',
MARKER_TYPES, parent, MARKER_KEY)
- control_box.Add(self.marker_chooser, 0, wx.EXPAND)
#alpha
control_box.AddStretchSpacer()
- self.alpha_slider = common.LogSliderController(
+ alpha_slider = common.LogSliderController(
self, 'Alpha',
ALPHA_MIN_EXP, ALPHA_MAX_EXP, SLIDER_STEPS,
- parent.ext_controller, parent.alpha_key,
+ parent, ALPHA_KEY,
)
- control_box.Add(self.alpha_slider, 0, wx.EXPAND)
+ control_box.Add(alpha_slider, 0, wx.EXPAND)
#gain_mu
control_box.AddStretchSpacer()
- self.gain_mu_slider = common.LogSliderController(
+ gain_mu_slider = common.LogSliderController(
self, 'Gain Mu',
GAIN_MU_MIN_EXP, GAIN_MU_MAX_EXP, SLIDER_STEPS,
- parent.ext_controller, parent.gain_mu_key,
+ parent, GAIN_MU_KEY,
)
- control_box.Add(self.gain_mu_slider, 0, wx.EXPAND)
+ control_box.Add(gain_mu_slider, 0, wx.EXPAND)
+ #marker
+ control_box.AddStretchSpacer()
+ marker_chooser = common.DropDownController(self, MARKER_TYPES,
parent, MARKER_KEY)
+ control_box.Add(common.LabelBox(self, 'Marker',
marker_chooser), 0, wx.EXPAND)
#run/stop
control_box.AddStretchSpacer()
self.run_button = common.ToggleButtonController(self, parent,
RUNNING_KEY, 'Stop', 'Run')
@@ -98,7 +97,7 @@
##################################################
# Constellation window with plotter and control panel
##################################################
-class const_window(wx.Panel, pubsub.pubsub, common.prop_setter):
+class const_window(wx.Panel, pubsub.pubsub):
def __init__(
self,
parent,
@@ -110,22 +109,27 @@
beta_key,
gain_mu_key,
gain_omega_key,
+ omega_key,
+ sample_rate_key,
):
pubsub.pubsub.__init__(self)
- #setup
- self.ext_controller = controller
- self.alpha_key = alpha_key
- self.beta_key = beta_key
- self.gain_mu_key = gain_mu_key
- self.gain_omega_key = gain_omega_key
+ #proxy the keys
+ self.proxy(MSG_KEY, controller, msg_key)
+ self.proxy(ALPHA_KEY, controller, alpha_key)
+ self.proxy(BETA_KEY, controller, beta_key)
+ self.proxy(GAIN_MU_KEY, controller, gain_mu_key)
+ self.proxy(GAIN_OMEGA_KEY, controller, gain_omega_key)
+ self.proxy(OMEGA_KEY, controller, omega_key)
+ self.proxy(SAMPLE_RATE_KEY, controller, sample_rate_key)
#init panel and plot
- wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
+ wx.Panel.__init__(self, parent, style=wx.SIMPLE_BORDER)
self.plotter = plotter.channel_plotter(self)
self.plotter.SetSize(wx.Size(*size))
self.plotter.set_title(title)
self.plotter.set_x_label('Inphase')
self.plotter.set_y_label('Quadrature')
self.plotter.enable_point_label(True)
+ self.plotter.enable_grid_lines(True)
#setup the box with plot and controls
self.control_panel = control_panel(self)
main_box = wx.BoxSizer(wx.HORIZONTAL)
@@ -133,22 +137,21 @@
main_box.Add(self.control_panel, 0, wx.EXPAND)
self.SetSizerAndFit(main_box)
#alpha and gain mu 2nd orders
- def set_beta(alpha): self.ext_controller[self.beta_key] =
.25*alpha**2
- self.ext_controller.subscribe(self.alpha_key, set_beta)
- def set_gain_omega(gain_mu):
self.ext_controller[self.gain_omega_key] = .25*gain_mu**2
- self.ext_controller.subscribe(self.gain_mu_key, set_gain_omega)
- #initial setup
- self.ext_controller[self.alpha_key] =
self.ext_controller[self.alpha_key]
- self.ext_controller[self.gain_mu_key] =
self.ext_controller[self.gain_mu_key]
- self._register_set_prop(self, RUNNING_KEY, True)
- self._register_set_prop(self, X_DIVS_KEY, 8)
- self._register_set_prop(self, Y_DIVS_KEY, 8)
- self._register_set_prop(self, MARKER_KEY, DEFAULT_MARKER_TYPE)
+ def set_beta(alpha): self[BETA_KEY] = .25*alpha**2
+ self.subscribe(ALPHA_KEY, set_beta)
+ def set_gain_omega(gain_mu): self[GAIN_OMEGA_KEY] =
.25*gain_mu**2
+ self.subscribe(GAIN_MU_KEY, set_gain_omega)
+ #initialize values
+ self[ALPHA_KEY] = self[ALPHA_KEY]
+ self[GAIN_MU_KEY] = self[GAIN_MU_KEY]
+ self[RUNNING_KEY] = True
+ self[X_DIVS_KEY] = 8
+ self[Y_DIVS_KEY] = 8
+ self[MARKER_KEY] = DEFAULT_MARKER_TYPE
#register events
- self.ext_controller.subscribe(msg_key, self.handle_msg)
- for key in (
- X_DIVS_KEY, Y_DIVS_KEY,
- ): self.subscribe(key, self.update_grid)
+ self.subscribe(MSG_KEY, self.handle_msg)
+ self.subscribe(X_DIVS_KEY, self.update_grid)
+ self.subscribe(Y_DIVS_KEY, self.update_grid)
#initial update
self.update_grid()
@@ -173,15 +176,12 @@
self.plotter.update()
def update_grid(self):
- #grid parameters
- x_divs = self[X_DIVS_KEY]
- y_divs = self[Y_DIVS_KEY]
#update the x axis
x_max = 2.0
- self.plotter.set_x_grid(-x_max, x_max,
common.get_clean_num(2.0*x_max/x_divs))
+ self.plotter.set_x_grid(-x_max, x_max,
common.get_clean_num(2.0*x_max/self[X_DIVS_KEY]))
#update the y axis
y_max = 2.0
- self.plotter.set_y_grid(-y_max, y_max,
common.get_clean_num(2.0*y_max/y_divs))
+ self.plotter.set_y_grid(-y_max, y_max,
common.get_clean_num(2.0*y_max/self[Y_DIVS_KEY]))
#update plotter
self.plotter.update()
Modified: gnuradio/trunk/gr-wxgui/src/python/constants.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/constants.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/constants.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -36,6 +36,7 @@
GAIN_MU_KEY = 'gain_mu'
GAIN_OMEGA_KEY = 'gain_omega'
MARKER_KEY = 'marker'
+XY_MARKER_KEY = 'xy_marker'
MSG_KEY = 'msg'
NUM_LINES_KEY = 'num_lines'
OMEGA_KEY = 'omega'
@@ -43,15 +44,15 @@
REF_LEVEL_KEY = 'ref_level'
RUNNING_KEY = 'running'
SAMPLE_RATE_KEY = 'sample_rate'
-SCOPE_TRIGGER_CHANNEL_KEY = 'scope_trigger_channel'
-SCOPE_TRIGGER_LEVEL_KEY = 'scope_trigger_level'
-SCOPE_TRIGGER_MODE_KEY = 'scope_trigger_mode'
-SCOPE_X_CHANNEL_KEY = 'scope_x_channel'
-SCOPE_Y_CHANNEL_KEY = 'scope_y_channel'
-SCOPE_XY_MODE_KEY = 'scope_xy_mode'
TRIGGER_CHANNEL_KEY = 'trigger_channel'
TRIGGER_LEVEL_KEY = 'trigger_level'
TRIGGER_MODE_KEY = 'trigger_mode'
+TRIGGER_SLOPE_KEY = 'trigger_slope'
+TRIGGER_SHOW_KEY = 'trigger_show'
+XY_MODE_KEY = 'xy_mode'
+X_CHANNEL_KEY = 'x_channel'
+Y_CHANNEL_KEY = 'y_channel'
+T_FRAC_OFF_KEY = 't_frac_off'
T_DIVS_KEY = 't_divs'
T_OFF_KEY = 't_off'
T_PER_DIV_KEY = 't_per_div'
@@ -61,4 +62,7 @@
Y_DIVS_KEY = 'y_divs'
Y_OFF_KEY = 'y_off'
Y_PER_DIV_KEY = 'y_per_div'
-
+MAXIMUM_KEY = 'maximum'
+MINIMUM_KEY = 'minimum'
+NUM_BINS_KEY = 'num_bins'
+FRAME_SIZE_KEY = 'frame_size'
Modified: gnuradio/trunk/gr-wxgui/src/python/constsink_gl.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/constsink_gl.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/constsink_gl.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -31,7 +31,7 @@
##################################################
# Constellation sink block (wrapper for old wxgui)
##################################################
-class const_sink_c(gr.hier_block2, common.prop_setter):
+class const_sink_c(gr.hier_block2):
"""
A constellation block with a gui window.
"""
@@ -97,8 +97,7 @@
#connect
self.connect(self, self._costas, self._retime, agc, sd, sink)
#controller
- def setter(p, k, x): # lambdas can't have assignments :(
- p[k] = x
+ def setter(p, k, x): p[k] = x
self.controller = pubsub()
self.controller.subscribe(ALPHA_KEY, self._costas.set_alpha)
self.controller.publish(ALPHA_KEY, self._costas.alpha)
@@ -116,7 +115,7 @@
#initial update
self.controller[SAMPLE_RATE_KEY] = sample_rate
#start input watcher
- common.input_watcher(msgq, lambda x: setter(self.controller,
MSG_KEY, x))
+ common.input_watcher(msgq, self.controller, MSG_KEY)
#create window
self.win = const_window.const_window(
parent=parent,
@@ -128,15 +127,9 @@
beta_key=BETA_KEY,
gain_mu_key=GAIN_MU_KEY,
gain_omega_key=GAIN_OMEGA_KEY,
+ omega_key=OMEGA_KEY,
+ sample_rate_key=SAMPLE_RATE_KEY,
)
- #register callbacks from window for external use
- for attr in filter(lambda a: a.startswith('set_'),
dir(self.win)):
- setattr(self, attr, getattr(self.win, attr))
- self._register_set_prop(self.controller, ALPHA_KEY)
- self._register_set_prop(self.controller, BETA_KEY)
- self._register_set_prop(self.controller, GAIN_MU_KEY)
- self._register_set_prop(self.controller, OMEGA_KEY)
- self._register_set_prop(self.controller, GAIN_OMEGA_KEY)
- self._register_set_prop(self.controller, SAMPLE_RATE_KEY)
+ common.register_access_methods(self, self.win)
Modified: gnuradio/trunk/gr-wxgui/src/python/fft_window.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/fft_window.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/fft_window.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -39,8 +39,8 @@
DEFAULT_WIN_SIZE = (600, 300)
DEFAULT_FRAME_RATE = gr.prefs().get_long('wxgui', 'fft_rate', 30)
DIV_LEVELS = (1, 2, 5, 10, 20)
-FFT_PLOT_COLOR_SPEC = (0, 0, 1)
-PEAK_VALS_COLOR_SPEC = (0, 1, 0)
+FFT_PLOT_COLOR_SPEC = (0.3, 0.3, 1.0)
+PEAK_VALS_COLOR_SPEC = (0.0, 0.8, 0.0)
NO_PEAK_VALS = list()
##################################################
@@ -57,31 +57,31 @@
@param parent the wx parent window
"""
self.parent = parent
- wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
+ wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
control_box = wx.BoxSizer(wx.VERTICAL)
#checkboxes for average and peak hold
control_box.AddStretchSpacer()
control_box.Add(common.LabelText(self, 'Options'), 0,
wx.ALIGN_CENTER)
- self.average_check_box = common.CheckBoxController(self,
'Average', parent.ext_controller, parent.average_key)
- control_box.Add(self.average_check_box, 0, wx.EXPAND)
- self.peak_hold_check_box = common.CheckBoxController(self,
'Peak Hold', parent, PEAK_HOLD_KEY)
- control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND)
+ peak_hold_check_box = common.CheckBoxController(self, 'Peak
Hold', parent, PEAK_HOLD_KEY)
+ control_box.Add(peak_hold_check_box, 0, wx.EXPAND)
+ average_check_box = common.CheckBoxController(self, 'Average',
parent, AVERAGE_KEY)
+ control_box.Add(average_check_box, 0, wx.EXPAND)
control_box.AddSpacer(2)
- self.avg_alpha_slider = common.LogSliderController(
+ avg_alpha_slider = common.LogSliderController(
self, 'Avg Alpha',
AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP, SLIDER_STEPS,
- parent.ext_controller, parent.avg_alpha_key,
+ parent, AVG_ALPHA_KEY,
formatter=lambda x: ': %.4f'%x,
)
- parent.ext_controller.subscribe(parent.average_key,
self.avg_alpha_slider.Enable)
- control_box.Add(self.avg_alpha_slider, 0, wx.EXPAND)
+ parent.subscribe(AVERAGE_KEY, avg_alpha_slider.Enable)
+ control_box.Add(avg_alpha_slider, 0, wx.EXPAND)
#radio buttons for div size
control_box.AddStretchSpacer()
control_box.Add(common.LabelText(self, 'Set dB/div'), 0,
wx.ALIGN_CENTER)
radio_box = wx.BoxSizer(wx.VERTICAL)
self.radio_buttons = list()
for y_per_div in DIV_LEVELS:
- radio_button = wx.RadioButton(self, -1, "%d
dB/div"%y_per_div)
+ radio_button = wx.RadioButton(self, label="%d
dB/div"%y_per_div)
radio_button.Bind(wx.EVT_RADIOBUTTON,
self._on_y_per_div)
self.radio_buttons.append(radio_button)
radio_box.Add(radio_button, 0, wx.ALIGN_LEFT)
@@ -91,18 +91,23 @@
control_box.AddStretchSpacer()
control_box.Add(common.LabelText(self, 'Set Ref Level'), 0,
wx.ALIGN_CENTER)
control_box.AddSpacer(2)
- self._ref_lvl_buttons = common.IncrDecrButtons(self,
self._on_incr_ref_level, self._on_decr_ref_level)
- control_box.Add(self._ref_lvl_buttons, 0, wx.ALIGN_CENTER)
+ _ref_lvl_buttons = common.IncrDecrButtons(self,
self._on_incr_ref_level, self._on_decr_ref_level)
+ control_box.Add(_ref_lvl_buttons, 0, wx.ALIGN_CENTER)
#autoscale
control_box.AddStretchSpacer()
- self.autoscale_button = wx.Button(self, label='Autoscale',
style=wx.BU_EXACTFIT)
- self.autoscale_button.Bind(wx.EVT_BUTTON, self.parent.autoscale)
- control_box.Add(self.autoscale_button, 0, wx.EXPAND)
+ autoscale_button = wx.Button(self, label='Autoscale',
style=wx.BU_EXACTFIT)
+ autoscale_button.Bind(wx.EVT_BUTTON, self.parent.autoscale)
+ control_box.Add(autoscale_button, 0, wx.EXPAND)
#run/stop
- self.run_button = common.ToggleButtonController(self, parent,
RUNNING_KEY, 'Stop', 'Run')
- control_box.Add(self.run_button, 0, wx.EXPAND)
+ run_button = common.ToggleButtonController(self, parent,
RUNNING_KEY, 'Stop', 'Run')
+ control_box.Add(run_button, 0, wx.EXPAND)
#set sizer
self.SetSizerAndFit(control_box)
+ #mouse wheel event
+ def on_mouse_wheel(event):
+ if event.GetWheelRotation() < 0:
self._on_incr_ref_level(event)
+ else: self._on_decr_ref_level(event)
+ parent.plotter.Bind(wx.EVT_MOUSEWHEEL, on_mouse_wheel)
##################################################
# Event handlers
@@ -117,16 +122,14 @@
index = self.radio_buttons.index(selected_radio_button)
self.parent[Y_PER_DIV_KEY] = DIV_LEVELS[index]
def _on_incr_ref_level(self, event):
- self.parent.set_ref_level(
- self.parent[REF_LEVEL_KEY] + self.parent[Y_PER_DIV_KEY])
+ self.parent[REF_LEVEL_KEY] = self.parent[REF_LEVEL_KEY] +
self.parent[Y_PER_DIV_KEY]
def _on_decr_ref_level(self, event):
- self.parent.set_ref_level(
- self.parent[REF_LEVEL_KEY] - self.parent[Y_PER_DIV_KEY])
+ self.parent[REF_LEVEL_KEY] = self.parent[REF_LEVEL_KEY] -
self.parent[Y_PER_DIV_KEY]
##################################################
# FFT window with plotter and control panel
##################################################
-class fft_window(wx.Panel, pubsub.pubsub, common.prop_setter):
+class fft_window(wx.Panel, pubsub.pubsub):
def __init__(
self,
parent,
@@ -150,47 +153,48 @@
if y_per_div not in DIV_LEVELS: y_per_div = DIV_LEVELS[0]
#setup
self.samples = list()
- self.ext_controller = controller
self.real = real
self.fft_size = fft_size
- self.sample_rate_key = sample_rate_key
- self.average_key = average_key
- self.avg_alpha_key = avg_alpha_key
self._reset_peak_vals()
+ #proxy the keys
+ self.proxy(MSG_KEY, controller, msg_key)
+ self.proxy(AVERAGE_KEY, controller, average_key)
+ self.proxy(AVG_ALPHA_KEY, controller, avg_alpha_key)
+ self.proxy(SAMPLE_RATE_KEY, controller, sample_rate_key)
#init panel and plot
- wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
+ wx.Panel.__init__(self, parent, style=wx.SIMPLE_BORDER)
self.plotter = plotter.channel_plotter(self)
self.plotter.SetSize(wx.Size(*size))
self.plotter.set_title(title)
+ self.plotter.enable_legend(True)
self.plotter.enable_point_label(True)
+ self.plotter.enable_grid_lines(True)
#setup the box with plot and controls
self.control_panel = control_panel(self)
main_box = wx.BoxSizer(wx.HORIZONTAL)
main_box.Add(self.plotter, 1, wx.EXPAND)
main_box.Add(self.control_panel, 0, wx.EXPAND)
self.SetSizerAndFit(main_box)
- #initial setup
- self.ext_controller[self.average_key] =
self.ext_controller[self.average_key]
- self.ext_controller[self.avg_alpha_key] =
self.ext_controller[self.avg_alpha_key]
- self._register_set_prop(self, PEAK_HOLD_KEY, peak_hold)
- self._register_set_prop(self, Y_PER_DIV_KEY, y_per_div)
- self._register_set_prop(self, Y_DIVS_KEY, y_divs)
- self._register_set_prop(self, X_DIVS_KEY, 8) #approximate
- self._register_set_prop(self, REF_LEVEL_KEY, ref_level)
- self._register_set_prop(self, BASEBAND_FREQ_KEY, baseband_freq)
- self._register_set_prop(self, RUNNING_KEY, True)
+ #initialize values
+ self[AVERAGE_KEY] = self[AVERAGE_KEY]
+ self[AVG_ALPHA_KEY] = self[AVG_ALPHA_KEY]
+ self[PEAK_HOLD_KEY] = peak_hold
+ self[Y_PER_DIV_KEY] = y_per_div
+ self[Y_DIVS_KEY] = y_divs
+ self[X_DIVS_KEY] = 8 #approximate
+ self[REF_LEVEL_KEY] = ref_level
+ self[BASEBAND_FREQ_KEY] = baseband_freq
+ self[RUNNING_KEY] = True
#register events
- self.subscribe(PEAK_HOLD_KEY, self.plotter.enable_legend)
- self.ext_controller.subscribe(AVERAGE_KEY, lambda x:
self._reset_peak_vals())
- self.ext_controller.subscribe(msg_key, self.handle_msg)
- self.ext_controller.subscribe(self.sample_rate_key,
self.update_grid)
+ self.subscribe(AVERAGE_KEY, lambda x: self._reset_peak_vals())
+ self.subscribe(MSG_KEY, self.handle_msg)
+ self.subscribe(SAMPLE_RATE_KEY, self.update_grid)
for key in (
BASEBAND_FREQ_KEY,
Y_PER_DIV_KEY, X_DIVS_KEY,
Y_DIVS_KEY, REF_LEVEL_KEY,
): self.subscribe(key, self.update_grid)
#initial update
- self.plotter.enable_legend(self[PEAK_HOLD_KEY])
self.update_grid()
def autoscale(self, *args):
@@ -207,9 +211,9 @@
noise_floor -= abs(noise_floor)*.5
peak_level += abs(peak_level)*.1
#set the reference level to a multiple of y divs
-
self.set_ref_level(self[Y_DIVS_KEY]*math.ceil(peak_level/self[Y_DIVS_KEY]))
+ self[REF_LEVEL_KEY] =
self[Y_DIVS_KEY]*math.ceil(peak_level/self[Y_DIVS_KEY])
#set the range to a clean number of the dynamic range
- self.set_y_per_div(common.get_clean_num((peak_level -
noise_floor)/self[Y_DIVS_KEY]))
+ self[Y_PER_DIV_KEY] = common.get_clean_num((peak_level -
noise_floor)/self[Y_DIVS_KEY])
def _reset_peak_vals(self): self.peak_vals = NO_PEAK_VALS
@@ -234,19 +238,21 @@
if self[PEAK_HOLD_KEY]:
if len(self.peak_vals) != len(samples): self.peak_vals
= samples
self.peak_vals = numpy.maximum(samples, self.peak_vals)
- else: self._reset_peak_vals()
+ #plot the peak hold
+ self.plotter.set_waveform(
+ channel='Peak',
+ samples=self.peak_vals,
+ color_spec=PEAK_VALS_COLOR_SPEC,
+ )
+ else:
+ self._reset_peak_vals()
+ self.plotter.clear_waveform(channel='Peak')
#plot the fft
self.plotter.set_waveform(
channel='FFT',
samples=samples,
color_spec=FFT_PLOT_COLOR_SPEC,
)
- #plot the peak hold
- self.plotter.set_waveform(
- channel='Peak',
- samples=self.peak_vals,
- color_spec=PEAK_VALS_COLOR_SPEC,
- )
#update the plotter
self.plotter.update()
@@ -259,7 +265,7 @@
The y axis depends on y per div, y divs, and ref level.
"""
#grid parameters
- sample_rate = self.ext_controller[self.sample_rate_key]
+ sample_rate = self[SAMPLE_RATE_KEY]
baseband_freq = self[BASEBAND_FREQ_KEY]
y_per_div = self[Y_PER_DIV_KEY]
y_divs = self[Y_DIVS_KEY]
@@ -269,24 +275,21 @@
if self.real: x_width = sample_rate/2.0
else: x_width = sample_rate/1.0
x_per_div = common.get_clean_num(x_width/x_divs)
- coeff, exp, prefix =
common.get_si_components(abs(baseband_freq) + abs(sample_rate/2.0))
#update the x grid
if self.real:
self.plotter.set_x_grid(
baseband_freq,
baseband_freq + sample_rate/2.0,
- x_per_div,
- 10**(-exp),
+ x_per_div, True,
)
else:
self.plotter.set_x_grid(
baseband_freq - sample_rate/2.0,
baseband_freq + sample_rate/2.0,
- x_per_div,
- 10**(-exp),
+ x_per_div, True,
)
#update x units
- self.plotter.set_x_label('Frequency', prefix+'Hz')
+ self.plotter.set_x_label('Frequency', 'Hz')
#update y grid
self.plotter.set_y_grid(ref_level-y_per_div*y_divs, ref_level,
y_per_div)
#update y units
Modified: gnuradio/trunk/gr-wxgui/src/python/fftsink_gl.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/fftsink_gl.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/fftsink_gl.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -31,7 +31,7 @@
##################################################
# FFT sink block (wrapper for old wxgui)
##################################################
-class _fft_sink_base(gr.hier_block2, common.prop_setter):
+class _fft_sink_base(gr.hier_block2):
"""
An fft block with real/complex inputs and a gui window.
"""
@@ -85,9 +85,7 @@
self.controller.subscribe(SAMPLE_RATE_KEY, fft.set_sample_rate)
self.controller.publish(SAMPLE_RATE_KEY, fft.sample_rate)
#start input watcher
- def setter(p, k, x): # lambdas can't have assignments :(
- p[k] = x
- common.input_watcher(msgq, lambda x: setter(self.controller,
MSG_KEY, x))
+ common.input_watcher(msgq, self.controller, MSG_KEY)
#create window
self.win = fft_window.fft_window(
parent=parent,
@@ -106,12 +104,9 @@
peak_hold=peak_hold,
msg_key=MSG_KEY,
)
- #register callbacks from window for external use
- for attr in filter(lambda a: a.startswith('set_'),
dir(self.win)):
- setattr(self, attr, getattr(self.win, attr))
- self._register_set_prop(self.controller, SAMPLE_RATE_KEY)
- self._register_set_prop(self.controller, AVERAGE_KEY)
- self._register_set_prop(self.controller, AVG_ALPHA_KEY)
+ common.register_access_methods(self, self.win)
+ setattr(self.win, 'set_baseband_freq', getattr(self,
'set_baseband_freq')) #BACKWARDS
+ setattr(self.win, 'set_peak_hold', getattr(self,
'set_peak_hold')) #BACKWARDS
class fft_sink_f(_fft_sink_base):
_fft_chain = blks2.logpwrfft_f
Modified: gnuradio/trunk/gr-wxgui/src/python/fftsink_nongl.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/fftsink_nongl.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/fftsink_nongl.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -319,7 +319,7 @@
# self.SetBackgroundColour ('black')
self.build_popup_menu()
- self.set_baseband_freq(0.0)
+ self.set_baseband_freq(self.fftsink.baseband_freq)
EVT_DATA_EVENT (self, self.set_data)
wx.EVT_CLOSE (self, self.on_close_window)
Copied: gnuradio/trunk/gr-wxgui/src/python/histo_window.py (from rev 10658,
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/histo_window.py)
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/histo_window.py
(rev 0)
+++ gnuradio/trunk/gr-wxgui/src/python/histo_window.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -0,0 +1,154 @@
+#
+# Copyright 2009 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+##################################################
+# Imports
+##################################################
+import plotter
+import common
+import wx
+import numpy
+import math
+import pubsub
+from constants import *
+from gnuradio import gr #for gr.prefs
+
+##################################################
+# Constants
+##################################################
+DEFAULT_WIN_SIZE = (600, 300)
+
+##################################################
+# histo window control panel
+##################################################
+class control_panel(wx.Panel):
+ """
+ A control panel with wx widgits to control the plotter and histo sink.
+ """
+
+ def __init__(self, parent):
+ """
+ Create a new control panel.
+ @param parent the wx parent window
+ """
+ self.parent = parent
+ wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
+ control_box = wx.BoxSizer(wx.VERTICAL)
+ SIZE = (100, -1)
+ control_box.Add(common.LabelText(self, 'Options'), 0,
wx.ALIGN_CENTER)
+ control_box.AddStretchSpacer()
+ #num bins
+ def num_bins_cast(num):
+ num = int(num)
+ assert num > 1
+ return num
+ num_bins_ctrl = common.TextBoxController(self, parent,
NUM_BINS_KEY, cast=num_bins_cast)
+ control_box.Add(common.LabelBox(self, ' Num Bins ',
num_bins_ctrl), 0, wx.EXPAND)
+ control_box.AddStretchSpacer()
+ #frame size
+ frame_size_ctrl = common.TextBoxController(self, parent,
FRAME_SIZE_KEY, cast=num_bins_cast)
+ control_box.Add(common.LabelBox(self, ' Frame Size ',
frame_size_ctrl), 0, wx.EXPAND)
+ control_box.AddStretchSpacer()
+ #run/stop
+ self.run_button = common.ToggleButtonController(self, parent,
RUNNING_KEY, 'Stop', 'Run')
+ control_box.Add(self.run_button, 0, wx.EXPAND)
+ #set sizer
+ self.SetSizerAndFit(control_box)
+
+##################################################
+# histo window with plotter and control panel
+##################################################
+class histo_window(wx.Panel, pubsub.pubsub):
+ def __init__(
+ self,
+ parent,
+ controller,
+ size,
+ title,
+ maximum_key,
+ minimum_key,
+ num_bins_key,
+ frame_size_key,
+ msg_key,
+ ):
+ pubsub.pubsub.__init__(self)
+ #setup
+ self.samples = list()
+ #proxy the keys
+ self.proxy(MAXIMUM_KEY, controller, maximum_key)
+ self.proxy(MINIMUM_KEY, controller, minimum_key)
+ self.proxy(NUM_BINS_KEY, controller, num_bins_key)
+ self.proxy(FRAME_SIZE_KEY, controller, frame_size_key)
+ self.proxy(MSG_KEY, controller, msg_key)
+ #init panel and plot
+ wx.Panel.__init__(self, parent, style=wx.SIMPLE_BORDER)
+ self.plotter = plotter.bar_plotter(self)
+ self.plotter.SetSize(wx.Size(*size))
+ self.plotter.set_title(title)
+ self.plotter.enable_point_label(True)
+ self.plotter.enable_grid_lines(False)
+ #setup the box with plot and controls
+ self.control_panel = control_panel(self)
+ main_box = wx.BoxSizer(wx.HORIZONTAL)
+ main_box.Add(self.plotter, 1, wx.EXPAND)
+ main_box.Add(self.control_panel, 0, wx.EXPAND)
+ self.SetSizerAndFit(main_box)
+ #initialize values
+ self[NUM_BINS_KEY] = self[NUM_BINS_KEY]
+ self[FRAME_SIZE_KEY] = self[FRAME_SIZE_KEY]
+ self[RUNNING_KEY] = True
+ self[X_DIVS_KEY] = 8
+ self[Y_DIVS_KEY] = 4
+ #register events
+ self.subscribe(MSG_KEY, self.handle_msg)
+ self.subscribe(X_DIVS_KEY, self.update_grid)
+ self.subscribe(Y_DIVS_KEY, self.update_grid)
+
+ def handle_msg(self, msg):
+ """
+ Handle the message from the fft sink message queue.
+ @param msg the frame as a character array
+ """
+ if not self[RUNNING_KEY]: return
+ #convert to floating point numbers
+ self.samples = 100*numpy.fromstring(msg,
numpy.float32)[:self[NUM_BINS_KEY]] #only take first frame
+ self.plotter.set_bars(
+ bars=self.samples,
+ bar_width=0.6,
+ color_spec=(0, 0, 1),
+ )
+ self.update_grid()
+
+ def update_grid(self):
+ if not len(self.samples): return
+ #calculate the maximum y value
+ y_off = math.ceil(numpy.max(self.samples))
+ y_off = min(max(y_off, 1.0), 100.0) #between 1% and 100%
+ #update the x grid
+ self.plotter.set_x_grid(
+ self[MINIMUM_KEY], self[MAXIMUM_KEY],
+ common.get_clean_num((self[MAXIMUM_KEY] -
self[MINIMUM_KEY])/self[X_DIVS_KEY]),
+ )
+ self.plotter.set_x_label('Counts')
+ #update the y grid
+ self.plotter.set_y_grid(0, y_off, y_off/self[Y_DIVS_KEY])
+ self.plotter.set_y_label('Frequency', '%')
+ self.plotter.update()
Copied: gnuradio/trunk/gr-wxgui/src/python/histosink_gl.py (from rev 10658,
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/histosink_gl.py)
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/histosink_gl.py
(rev 0)
+++ gnuradio/trunk/gr-wxgui/src/python/histosink_gl.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -0,0 +1,110 @@
+#
+# Copyright 2009 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+##################################################
+# Imports
+##################################################
+import histo_window
+import common
+from gnuradio import gr, blks2
+from pubsub import pubsub
+from constants import *
+
+##################################################
+# histo sink block (wrapper for old wxgui)
+##################################################
+class histo_sink_f(gr.hier_block2):
+ """
+ A histogram block and a gui window.
+ """
+
+ def __init__(
+ self,
+ parent,
+ size=histo_window.DEFAULT_WIN_SIZE,
+ title='',
+ num_bins=11,
+ frame_size=1000,
+ ):
+ #init
+ gr.hier_block2.__init__(
+ self,
+ "histo_sink",
+ gr.io_signature(1, 1, gr.sizeof_float),
+ gr.io_signature(0, 0, 0),
+ )
+ #blocks
+ msgq = gr.msg_queue(2)
+ histo = gr.histo_sink_f(msgq)
+ histo.set_num_bins(num_bins)
+ histo.set_frame_size(frame_size)
+ #connect
+ self.connect(self, histo)
+ #controller
+ self.controller = pubsub()
+ self.controller.subscribe(NUM_BINS_KEY, histo.set_num_bins)
+ self.controller.publish(NUM_BINS_KEY, histo.get_num_bins)
+ self.controller.subscribe(FRAME_SIZE_KEY, histo.set_frame_size)
+ self.controller.publish(FRAME_SIZE_KEY, histo.get_frame_size)
+ #start input watcher
+ common.input_watcher(msgq, self.controller, MSG_KEY,
arg1_key=MINIMUM_KEY, arg2_key=MAXIMUM_KEY)
+ #create window
+ self.win = histo_window.histo_window(
+ parent=parent,
+ controller=self.controller,
+ size=size,
+ title=title,
+ maximum_key=MAXIMUM_KEY,
+ minimum_key=MINIMUM_KEY,
+ num_bins_key=NUM_BINS_KEY,
+ frame_size_key=FRAME_SIZE_KEY,
+ msg_key=MSG_KEY,
+ )
+ common.register_access_methods(self, self.win)
+
+# ----------------------------------------------------------------
+# Standalone test app
+# ----------------------------------------------------------------
+
+import wx
+from gnuradio.wxgui import stdgui2
+
+class test_app_block (stdgui2.std_top_block):
+ def __init__(self, frame, panel, vbox, argv):
+ stdgui2.std_top_block.__init__ (self, frame, panel, vbox, argv)
+
+ # build our flow graph
+ input_rate = 20.48e3
+
+ 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)
+ thr2 = gr.throttle(gr.sizeof_float, input_rate)
+ sink2 = histo_sink_f (panel, title="Data", num_bins=31,
frame_size=1000)
+ vbox.Add (sink2.win, 1, wx.EXPAND)
+
+ self.connect(src2, thr2, sink2)
+
+def main ():
+ app = stdgui2.stdapp (test_app_block, "Histo Sink Test App")
+ app.MainLoop ()
+
+if __name__ == '__main__':
+ main ()
Modified: gnuradio/trunk/gr-wxgui/src/python/number_window.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/number_window.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/number_window.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -53,23 +53,23 @@
@param parent the wx parent window
"""
self.parent = parent
- wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
+ wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
control_box = wx.BoxSizer(wx.VERTICAL)
#checkboxes for average and peak hold
control_box.AddStretchSpacer()
control_box.Add(common.LabelText(self, 'Options'), 0,
wx.ALIGN_CENTER)
- self.average_check_box = common.CheckBoxController(self,
'Average', parent.ext_controller, parent.average_key)
- control_box.Add(self.average_check_box, 0, wx.EXPAND)
self.peak_hold_check_box = common.CheckBoxController(self,
'Peak Hold', parent, PEAK_HOLD_KEY)
control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND)
+ self.average_check_box = common.CheckBoxController(self,
'Average', parent, AVERAGE_KEY)
+ control_box.Add(self.average_check_box, 0, wx.EXPAND)
control_box.AddSpacer(2)
self.avg_alpha_slider = common.LogSliderController(
self, 'Avg Alpha',
AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP, SLIDER_STEPS,
- parent.ext_controller, parent.avg_alpha_key,
+ parent, AVG_ALPHA_KEY,
formatter=lambda x: ': %.4f'%x,
)
- parent.ext_controller.subscribe(parent.average_key,
self.avg_alpha_slider.Enable)
+ parent.subscribe(AVERAGE_KEY, self.avg_alpha_slider.Enable)
control_box.Add(self.avg_alpha_slider, 0, wx.EXPAND)
#run/stop
control_box.AddStretchSpacer()
@@ -81,7 +81,7 @@
##################################################
# Numbersink window with label and gauges
##################################################
-class number_window(wx.Panel, pubsub.pubsub, common.prop_setter):
+class number_window(wx.Panel, pubsub.pubsub):
def __init__(
self,
parent,
@@ -98,20 +98,23 @@
avg_alpha_key,
peak_hold,
msg_key,
+ sample_rate_key,
):
pubsub.pubsub.__init__(self)
- wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
+ wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
#setup
self.peak_val_real = NEG_INF
self.peak_val_imag = NEG_INF
- self.ext_controller = controller
self.real = real
self.units = units
self.minval = minval
self.maxval = maxval
self.decimal_places = decimal_places
- self.average_key = average_key
- self.avg_alpha_key = avg_alpha_key
+ #proxy the keys
+ self.proxy(MSG_KEY, controller, msg_key)
+ self.proxy(AVERAGE_KEY, controller, average_key)
+ self.proxy(AVG_ALPHA_KEY, controller, avg_alpha_key)
+ self.proxy(SAMPLE_RATE_KEY, controller, sample_rate_key)
#setup the box with display and controls
self.control_panel = control_panel(self)
main_box = wx.BoxSizer(wx.HORIZONTAL)
@@ -128,13 +131,13 @@
sizer.Add(self.gauge_real, 1, wx.EXPAND)
sizer.Add(self.gauge_imag, 1, wx.EXPAND)
self.SetSizerAndFit(main_box)
- #initial setup
- self.ext_controller[self.average_key] =
self.ext_controller[self.average_key]
- self.ext_controller[self.avg_alpha_key] =
self.ext_controller[self.avg_alpha_key]
- self._register_set_prop(self, PEAK_HOLD_KEY, peak_hold)
- self._register_set_prop(self, RUNNING_KEY, True)
+ #initialize values
+ self[PEAK_HOLD_KEY] = peak_hold
+ self[RUNNING_KEY] = True
+ self[AVERAGE_KEY] = self[AVERAGE_KEY]
+ self[AVG_ALPHA_KEY] = self[AVG_ALPHA_KEY]
#register events
- self.ext_controller.subscribe(msg_key, self.handle_msg)
+ self.subscribe(MSG_KEY, self.handle_msg)
self.Bind(common.EVT_DATA, self.update)
def show_gauges(self, show_gauge):
Modified: gnuradio/trunk/gr-wxgui/src/python/numbersink2.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/numbersink2.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/numbersink2.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -31,7 +31,7 @@
##################################################
# Number sink block (wrapper for old wxgui)
##################################################
-class _number_sink_base(gr.hier_block2, common.prop_setter):
+class _number_sink_base(gr.hier_block2):
"""
An decimator block with a number window display
"""
@@ -74,29 +74,28 @@
if self._real:
mult = gr.multiply_const_ff(factor)
add = gr.add_const_ff(ref_level)
- self._avg = gr.single_pole_iir_filter_ff(1.0)
+ avg = gr.single_pole_iir_filter_ff(1.0)
else:
mult = gr.multiply_const_cc(factor)
add = gr.add_const_cc(ref_level)
- self._avg = gr.single_pole_iir_filter_cc(1.0)
+ avg = gr.single_pole_iir_filter_cc(1.0)
msgq = gr.msg_queue(2)
sink = gr.message_sink(self._item_size, msgq, True)
#connect
- self.connect(self, sd, mult, add, self._avg, sink)
- #setup averaging
- self._avg_alpha = avg_alpha
- self.set_average(average)
- self.set_avg_alpha(avg_alpha)
+ self.connect(self, sd, mult, add, avg, sink)
#controller
self.controller = pubsub()
self.controller.subscribe(SAMPLE_RATE_KEY, sd.set_sample_rate)
- self.controller.subscribe(AVERAGE_KEY, self.set_average)
- self.controller.publish(AVERAGE_KEY, self.get_average)
- self.controller.subscribe(AVG_ALPHA_KEY, self.set_avg_alpha)
- self.controller.publish(AVG_ALPHA_KEY, self.get_avg_alpha)
+ self.controller.publish(SAMPLE_RATE_KEY, sd.sample_rate)
+ def update_avg(*args):
+ if self.controller[AVERAGE_KEY]:
avg.set_taps(self.controller[AVG_ALPHA_KEY])
+ else: avg.set_taps(1.0)
+ self.controller.subscribe(AVERAGE_KEY, update_avg)
+ self.controller.subscribe(AVG_ALPHA_KEY, update_avg)
+ self.controller[AVERAGE_KEY] = average
+ self.controller[AVG_ALPHA_KEY] = avg_alpha
#start input watcher
- def set_msg(msg): self.controller[MSG_KEY] = msg
- common.input_watcher(msgq, set_msg)
+ common.input_watcher(msgq, self.controller, MSG_KEY)
#create window
self.win = number_window.number_window(
parent=parent,
@@ -113,25 +112,12 @@
avg_alpha_key=AVG_ALPHA_KEY,
peak_hold=peak_hold,
msg_key=MSG_KEY,
+ sample_rate_key=SAMPLE_RATE_KEY,
)
- #register callbacks from window for external use
- for attr in filter(lambda a: a.startswith('set_'),
dir(self.win)):
- setattr(self, attr, getattr(self.win, attr))
- self._register_set_prop(self.controller, SAMPLE_RATE_KEY)
+ common.register_access_methods(self, self.controller)
#backwards compadibility
self.set_show_gauge = self.win.show_gauges
- def get_average(self): return self._average
- def set_average(self, average):
- self._average = average
- if self.get_average(): self._avg.set_taps(self.get_avg_alpha())
- else: self._avg.set_taps(1.0)
-
- def get_avg_alpha(self): return self._avg_alpha
- def set_avg_alpha(self, avg_alpha):
- self._avg_alpha = avg_alpha
- self.set_average(self.get_average())
-
class number_sink_f(_number_sink_base):
_item_size = gr.sizeof_float
_real = True
Modified: gnuradio/trunk/gr-wxgui/src/python/plotter/Makefile.am
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/plotter/Makefile.am 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/plotter/Makefile.am 2009-03-20
02:16:20 UTC (rev 10660)
@@ -1,5 +1,5 @@
#
-# Copyright 2004,2005,2008 Free Software Foundation, Inc.
+# Copyright 2004,2005,2008,2009 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -30,8 +30,11 @@
ourpython_PYTHON = \
__init__.py \
+ bar_plotter.py \
channel_plotter.py \
+ common.py \
gltext.py \
+ grid_plotter_base.py \
plotter_base.py \
waterfall_plotter.py
Modified: gnuradio/trunk/gr-wxgui/src/python/plotter/__init__.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/plotter/__init__.py 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/plotter/__init__.py 2009-03-20
02:16:20 UTC (rev 10660)
@@ -21,3 +21,4 @@
from channel_plotter import channel_plotter
from waterfall_plotter import waterfall_plotter
+from bar_plotter import bar_plotter
Copied: gnuradio/trunk/gr-wxgui/src/python/plotter/bar_plotter.py (from rev
10658,
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/bar_plotter.py)
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/plotter/bar_plotter.py
(rev 0)
+++ gnuradio/trunk/gr-wxgui/src/python/plotter/bar_plotter.py 2009-03-20
02:16:20 UTC (rev 10660)
@@ -0,0 +1,144 @@
+#
+# Copyright 2009 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import wx
+from grid_plotter_base import grid_plotter_base
+from OpenGL import GL
+import common
+import numpy
+
+LEGEND_TEXT_FONT_SIZE = 8
+LEGEND_BOX_PADDING = 3
+MIN_PADDING = 0, 0, 0, 70 #top, right, bottom, left
+#constants for the waveform storage
+SAMPLES_KEY = 'samples'
+COLOR_SPEC_KEY = 'color_spec'
+MARKERY_KEY = 'marker'
+TRIG_OFF_KEY = 'trig_off'
+
+##################################################
+# Bar Plotter for histogram waveforms
+##################################################
+class bar_plotter(grid_plotter_base):
+
+ def __init__(self, parent):
+ """
+ Create a new bar plotter.
+ """
+ #init
+ grid_plotter_base.__init__(self, parent, MIN_PADDING)
+ self._bars = list()
+ self._bar_width = .5
+ self._color_spec = (0, 0, 0)
+ #setup bar cache
+ self._bar_cache = self.new_gl_cache(self._draw_bars)
+ #setup bar plotter
+ self.register_init(self._init_bar_plotter)
+
+ def _init_bar_plotter(self):
+ """
+ Run gl initialization tasks.
+ """
+ GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
+
+ def _draw_bars(self):
+ """
+ Draw the vertical bars.
+ """
+ bars = self._bars
+ num_bars = len(bars)
+ if num_bars == 0: return
+ #use scissor to prevent drawing outside grid
+ GL.glEnable(GL.GL_SCISSOR_TEST)
+ GL.glScissor(
+ self.padding_left,
+ self.padding_bottom+1,
+ self.width-self.padding_left-self.padding_right-1,
+ self.height-self.padding_top-self.padding_bottom-1,
+ )
+ #load the points
+ points = list()
+ width = self._bar_width/2
+ for i, bar in enumerate(bars):
+ points.extend([
+ (i-width, 0),
+ (i+width, 0),
+ (i+width, bar),
+ (i-width, bar),
+ ]
+ )
+ GL.glColor3f(*self._color_spec)
+ #matrix transforms
+ GL.glPushMatrix()
+ GL.glTranslatef(self.padding_left, self.padding_top, 0)
+ GL.glScalef(
+ (self.width-self.padding_left-self.padding_right),
+ (self.height-self.padding_top-self.padding_bottom),
+ 1,
+ )
+ GL.glTranslatef(0, 1, 0)
+ GL.glScalef(1.0/(num_bars-1), -1.0/(self.y_max-self.y_min), 1)
+ GL.glTranslatef(0, -self.y_min, 0)
+ #draw the bars
+ GL.glVertexPointerf(points)
+ GL.glDrawArrays(GL.GL_QUADS, 0, len(points))
+ GL.glPopMatrix()
+ GL.glDisable(GL.GL_SCISSOR_TEST)
+
+ def _populate_point_label(self, x_val, y_val):
+ """
+ Get the text the will populate the point label.
+ Give X and Y values for the current point.
+ Give values for the channel at the X coordinate.
+ @param x_val the current x value
+ @param y_val the current y value
+ @return a string with newlines
+ """
+ if len(self._bars) == 0: return ''
+ scalar = float(len(self._bars)-1)/(self.x_max - self.x_min)
+ #convert x val to bar #
+ bar_index = scalar*(x_val - self.x_min)
+ #if abs(bar_index - round(bar_index)) > self._bar_width/2:
return ''
+ bar_index = int(round(bar_index))
+ bar_start = (bar_index - self._bar_width/2)/scalar + self.x_min
+ bar_end = (bar_index + self._bar_width/2)/scalar + self.x_min
+ bar_value = self._bars[bar_index]
+ return '%s to %s\n%s: %s'%(
+ common.eng_format(bar_start, self.x_units),
+ common.eng_format(bar_end, self.x_units),
+ self.y_label, common.eng_format(bar_value,
self.y_units),
+ )
+
+ def set_bars(self, bars, bar_width, color_spec):
+ """
+ Set the bars.
+ @param bars a list of bars
+ @param bar_width the fractional width of the bar, between 0 and
1
+ @param color_spec the color tuple
+ """
+ self.lock()
+ self._bars = bars
+ self._bar_width = float(bar_width)
+ self._color_spec = color_spec
+ self._bar_cache.changed(True)
+ self.unlock()
+
+
Modified: gnuradio/trunk/gr-wxgui/src/python/plotter/channel_plotter.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/plotter/channel_plotter.py
2009-03-20 01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/plotter/channel_plotter.py
2009-03-20 02:16:20 UTC (rev 10660)
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -20,20 +20,21 @@
#
import wx
-from plotter_base import grid_plotter_base
-from OpenGL.GL import *
-from gnuradio.wxgui import common
+from grid_plotter_base import grid_plotter_base
+from OpenGL import GL
+import common
import numpy
import gltext
import math
LEGEND_TEXT_FONT_SIZE = 8
LEGEND_BOX_PADDING = 3
-PADDING = 35, 15, 40, 60 #top, right, bottom, left
+MIN_PADDING = 35, 10, 0, 0 #top, right, bottom, left
#constants for the waveform storage
SAMPLES_KEY = 'samples'
COLOR_SPEC_KEY = 'color_spec'
MARKERY_KEY = 'marker'
+TRIG_OFF_KEY = 'trig_off'
##################################################
# Channel Plotter for X Y Waveforms
@@ -45,16 +46,21 @@
Create a new channel plotter.
"""
#init
- grid_plotter_base.__init__(self, parent, PADDING)
+ grid_plotter_base.__init__(self, parent, MIN_PADDING)
+ #setup legend cache
+ self._legend_cache = self.new_gl_cache(self._draw_legend, 50)
+ self.enable_legend(False)
+ #setup waveform cache
+ self._waveform_cache = self.new_gl_cache(self._draw_waveforms,
50)
self._channels = dict()
- self.enable_legend(False)
+ #init channel plotter
+ self.register_init(self._init_channel_plotter)
- def _gl_init(self):
+ def _init_channel_plotter(self):
"""
Run gl initialization tasks.
"""
- glEnableClientState(GL_VERTEX_ARRAY)
- self._grid_compiled_list_id = glGenLists(1)
+ GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
def enable_legend(self, enable=None):
"""
@@ -65,73 +71,55 @@
if enable is None: return self._enable_legend
self.lock()
self._enable_legend = enable
- self.changed(True)
+ self._legend_cache.changed(True)
self.unlock()
- def draw(self):
+ def _draw_waveforms(self):
"""
- Draw the grid and waveforms.
+ Draw the waveforms for each channel.
+ Scale the waveform data to the grid using gl matrix operations.
"""
- self.lock()
- self.clear()
- #store the grid drawing operations
- if self.changed():
- glNewList(self._grid_compiled_list_id, GL_COMPILE)
- self._draw_grid()
- self._draw_legend()
- glEndList()
- self.changed(False)
- #draw the grid
- glCallList(self._grid_compiled_list_id)
#use scissor to prevent drawing outside grid
- glEnable(GL_SCISSOR_TEST)
- glScissor(
+ GL.glEnable(GL.GL_SCISSOR_TEST)
+ GL.glScissor(
self.padding_left+1,
self.padding_bottom+1,
self.width-self.padding_left-self.padding_right-1,
self.height-self.padding_top-self.padding_bottom-1,
)
- #draw the waveforms
- self._draw_waveforms()
- glDisable(GL_SCISSOR_TEST)
- self._draw_point_label()
- #swap buffer into display
- self.SwapBuffers()
- self.unlock()
-
- def _draw_waveforms(self):
- """
- Draw the waveforms for each channel.
- Scale the waveform data to the grid using gl matrix operations.
- """
for channel in reversed(sorted(self._channels.keys())):
samples = self._channels[channel][SAMPLES_KEY]
num_samps = len(samples)
if not num_samps: continue
#use opengl to scale the waveform
- glPushMatrix()
- glTranslatef(self.padding_left, self.padding_top, 0)
- glScalef(
+ GL.glPushMatrix()
+ GL.glTranslatef(self.padding_left, self.padding_top, 0)
+ GL.glScalef(
(self.width-self.padding_left-self.padding_right),
(self.height-self.padding_top-self.padding_bottom),
1,
)
- glTranslatef(0, 1, 0)
+ GL.glTranslatef(0, 1, 0)
if isinstance(samples, tuple):
x_scale, x_trans = 1.0/(self.x_max-self.x_min),
-self.x_min
points = zip(*samples)
else:
- x_scale, x_trans = 1.0/(num_samps-1), 0
+ x_scale, x_trans = 1.0/(num_samps-1),
-self._channels[channel][TRIG_OFF_KEY]
points = zip(numpy.arange(0, num_samps),
samples)
- glScalef(x_scale, -1.0/(self.y_max-self.y_min), 1)
- glTranslatef(x_trans, -self.y_min, 0)
+ GL.glScalef(x_scale, -1.0/(self.y_max-self.y_min), 1)
+ GL.glTranslatef(x_trans, -self.y_min, 0)
#draw the points/lines
- glColor3f(*self._channels[channel][COLOR_SPEC_KEY])
+ GL.glColor3f(*self._channels[channel][COLOR_SPEC_KEY])
marker = self._channels[channel][MARKERY_KEY]
- if marker: glPointSize(marker)
- glVertexPointerf(points)
- glDrawArrays(marker is None and GL_LINE_STRIP or
GL_POINTS, 0, len(points))
- glPopMatrix()
+ if marker is None:
+ GL.glVertexPointerf(points)
+ GL.glDrawArrays(GL.GL_LINE_STRIP, 0,
len(points))
+ elif isinstance(marker, (int, float)) and marker > 0:
+ GL.glPointSize(marker)
+ GL.glVertexPointerf(points)
+ GL.glDrawArrays(GL.GL_POINTS, 0, len(points))
+ GL.glPopMatrix()
+ GL.glDisable(GL.GL_SCISSOR_TEST)
def _populate_point_label(self, x_val, y_val):
"""
@@ -143,12 +131,9 @@
@return a string with newlines
"""
#create text
- label_str = '%s: %s %s\n%s: %s %s'%(
- self.x_label,
- common.label_format(x_val),
- self.x_units, self.y_label,
- common.label_format(y_val),
- self.y_units,
+ label_str = '%s: %s\n%s: %s'%(
+ self.x_label, common.eng_format(x_val, self.x_units),
+ self.y_label, common.eng_format(y_val, self.y_units),
)
for channel in sorted(self._channels.keys()):
samples = self._channels[channel][SAMPLES_KEY]
@@ -156,11 +141,12 @@
if not num_samps: continue
if isinstance(samples, tuple): continue
#linear interpolation
- x_index =
(num_samps-1)*(x_val/self.x_scalar-self.x_min)/(self.x_max-self.x_min)
+ x_index =
(num_samps-1)*(x_val-self.x_min)/(self.x_max-self.x_min)
x_index_low = int(math.floor(x_index))
x_index_high = int(math.ceil(x_index))
- y_value = (samples[x_index_high] -
samples[x_index_low])*(x_index - x_index_low) + samples[x_index_low]
- label_str += '\n%s: %s %s'%(channel,
common.label_format(y_value), self.y_units)
+ scale = x_index - x_index_low +
self._channels[channel][TRIG_OFF_KEY]
+ y_value = (samples[x_index_high] -
samples[x_index_low])*scale + samples[x_index_low]
+ label_str += '\n%s: %s'%(channel,
common.eng_format(y_value, self.y_units))
return label_str
def _draw_legend(self):
@@ -178,7 +164,7 @@
txt = gltext.Text(channel,
font_size=LEGEND_TEXT_FONT_SIZE)
w, h = txt.get_size()
#draw rect + text
- glColor3f(*color_spec)
+ GL.glColor3f(*color_spec)
self._draw_rect(
x_off - w - LEGEND_BOX_PADDING,
self.padding_top/2 - h/2 - LEGEND_BOX_PADDING,
@@ -188,21 +174,36 @@
txt.draw_text(wx.Point(x_off - w, self.padding_top/2 -
h/2))
x_off -= w + 4*LEGEND_BOX_PADDING
- def set_waveform(self, channel, samples, color_spec, marker=None):
+ def clear_waveform(self, channel):
"""
+ Remove a waveform from the list of waveforms.
+ @param channel the channel key
+ """
+ self.lock()
+ if channel in self._channels.keys():
+ self._channels.pop(channel)
+ self._legend_cache.changed(True)
+ self._waveform_cache.changed(True)
+ self.unlock()
+
+ def set_waveform(self, channel, samples=[], color_spec=(0, 0, 0),
marker=None, trig_off=0):
+ """
Set the waveform for a given channel.
@param channel the channel key
@param samples the waveform samples
@param color_spec the 3-tuple for line color
@param marker None for line
+ @param trig_off fraction of sample for trigger offset
"""
self.lock()
- if channel not in self._channels.keys(): self.changed(True)
+ if channel not in self._channels.keys():
self._legend_cache.changed(True)
self._channels[channel] = {
SAMPLES_KEY: samples,
COLOR_SPEC_KEY: color_spec,
MARKERY_KEY: marker,
+ TRIG_OFF_KEY: trig_off,
}
+ self._waveform_cache.changed(True)
self.unlock()
if __name__ == '__main__':
Copied: gnuradio/trunk/gr-wxgui/src/python/plotter/common.py (from rev 10658,
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/common.py)
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/plotter/common.py
(rev 0)
+++ gnuradio/trunk/gr-wxgui/src/python/plotter/common.py 2009-03-20
02:16:20 UTC (rev 10660)
@@ -0,0 +1,131 @@
+#
+# Copyright 2009 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import threading
+import time
+import math
+import wx
+
+##################################################
+# Number formatting
+##################################################
+def get_exp(num):
+ """
+ Get the exponent of the number in base 10.
+ @param num the floating point number
+ @return the exponent as an integer
+ """
+ if num == 0: return 0
+ return int(math.floor(math.log10(abs(num))))
+
+def get_si_components(num):
+ """
+ Get the SI units for the number.
+ Extract the coeff and exponent of the number.
+ The exponent will be a multiple of 3.
+ @param num the floating point number
+ @return the tuple coeff, exp, prefix
+ """
+ num = float(num)
+ exp = get_exp(num)
+ exp -= exp%3
+ exp = min(max(exp, -24), 24) #bounds on SI table below
+ prefix = {
+ 24: 'Y', 21: 'Z',
+ 18: 'E', 15: 'P',
+ 12: 'T', 9: 'G',
+ 6: 'M', 3: 'k',
+ 0: '',
+ -3: 'm', -6: 'u',
+ -9: 'n', -12: 'p',
+ -15: 'f', -18: 'a',
+ -21: 'z', -24: 'y',
+ }[exp]
+ coeff = num/10**exp
+ return coeff, exp, prefix
+
+def sci_format(num):
+ """
+ Format a floating point number into scientific notation.
+ @param num the number to format
+ @return a label string
+ """
+ coeff, exp, prefix = get_si_components(num)
+ if -3 <= exp < 3: return '%g'%num
+ return '%.3ge%d'%(coeff, exp)
+
+def eng_format(num, units=''):
+ """
+ Format a floating point number into engineering notation.
+ @param num the number to format
+ @param units the units to append
+ @return a label string
+ """
+ coeff, exp, prefix = get_si_components(num)
+ if -3 <= exp < 3: return '%g'%num
+ return '%g%s%s%s'%(coeff, units and ' ' or '', prefix, units)
+
+##################################################
+# Interface with thread safe lock/unlock
+##################################################
+class mutex(object):
+ _lock = threading.Lock()
+ def lock(self): self._lock.acquire()
+ def unlock(self): self._lock.release()
+
+##################################################
+# Periodic update thread for point label
+##################################################
+class point_label_thread(threading.Thread, mutex):
+
+ def __init__(self, plotter):
+ self._plotter = plotter
+ self._coor_queue = list()
+ #bind plotter mouse events
+ self._plotter.Bind(wx.EVT_MOTION, lambda evt:
self.enqueue(evt.GetPosition()))
+ self._plotter.Bind(wx.EVT_LEAVE_WINDOW, lambda evt:
self.enqueue(None))
+ #start the thread
+ threading.Thread.__init__(self)
+ self.start()
+
+ def enqueue(self, coor):
+ self.lock()
+ self._coor_queue.append(coor)
+ self.unlock()
+
+ def run(self):
+ last_ts = time.time()
+ last_coor = coor = None
+ try:
+ while True:
+ time.sleep(1.0/30.0)
+ self.lock()
+ #get most recent coor change
+ if self._coor_queue:
+ coor = self._coor_queue[-1]
+ self._coor_queue = list()
+ self.unlock()
+ #update if coor change, or enough time expired
+ if last_coor != coor or (time.time() - last_ts)
> (1.0/2.0):
+
self._plotter.set_point_label_coordinate(coor)
+ last_coor = coor
+ last_ts = time.time()
+ except wx.PyDeadObjectError: pass
Copied: gnuradio/trunk/gr-wxgui/src/python/plotter/grid_plotter_base.py (from
rev 10658,
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/grid_plotter_base.py)
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/plotter/grid_plotter_base.py
(rev 0)
+++ gnuradio/trunk/gr-wxgui/src/python/plotter/grid_plotter_base.py
2009-03-20 02:16:20 UTC (rev 10660)
@@ -0,0 +1,370 @@
+#
+# Copyright 2009 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import wx
+import wx.glcanvas
+from OpenGL import GL
+import common
+from plotter_base import plotter_base
+import gltext
+import math
+
+GRID_LINE_COLOR_SPEC = (.7, .7, .7) #gray
+GRID_BORDER_COLOR_SPEC = (0, 0, 0) #black
+TICK_TEXT_FONT_SIZE = 9
+TITLE_TEXT_FONT_SIZE = 13
+UNITS_TEXT_FONT_SIZE = 9
+AXIS_LABEL_PADDING = 5
+TICK_LABEL_PADDING = 5
+TITLE_LABEL_PADDING = 7
+POINT_LABEL_FONT_SIZE = 8
+POINT_LABEL_COLOR_SPEC = (1, 1, .5)
+POINT_LABEL_PADDING = 3
+GRID_LINE_DASH_LEN = 4
+
+##################################################
+# Grid Plotter Base Class
+##################################################
+class grid_plotter_base(plotter_base):
+
+ def __init__(self, parent, min_padding=(0, 0, 0, 0)):
+ plotter_base.__init__(self, parent)
+ #setup grid cache
+ self._grid_cache = self.new_gl_cache(self._draw_grid, 25)
+ self.enable_grid_lines(True)
+ #setup padding
+ self.padding_top_min, self.padding_right_min,
self.padding_bottom_min, self.padding_left_min = min_padding
+ #store title and unit strings
+ self.set_title('Title')
+ self.set_x_label('X Label')
+ self.set_y_label('Y Label')
+ #init the grid to some value
+ self.set_x_grid(-1, 1, 1)
+ self.set_y_grid(-1, 1, 1)
+ #setup point label cache
+ self._point_label_cache =
self.new_gl_cache(self._draw_point_label, 75)
+ self.enable_point_label(False)
+ self.set_point_label_coordinate(None)
+ common.point_label_thread(self)
+ #init grid plotter
+ self.register_init(self._init_grid_plotter)
+
+ def _init_grid_plotter(self):
+ """
+ Run gl initialization tasks.
+ """
+ GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
+
+ def set_point_label_coordinate(self, coor):
+ """
+ Set the point label coordinate.
+ @param coor the coordinate x, y tuple or None
+ """
+ self.lock()
+ self._point_label_coordinate = coor
+ self._point_label_cache.changed(True)
+ self.update()
+ self.unlock()
+
+ def enable_point_label(self, enable=None):
+ """
+ Enable/disable the point label.
+ @param enable true to enable
+ @return the enable state when None
+ """
+ if enable is None: return self._enable_point_label
+ self.lock()
+ self._enable_point_label = enable
+ self._point_label_cache.changed(True)
+ self.unlock()
+
+ def set_title(self, title):
+ """
+ Set the title.
+ @param title the title string
+ """
+ self.lock()
+ self.title = title
+ self._grid_cache.changed(True)
+ self.unlock()
+
+ def set_x_label(self, x_label, x_units=''):
+ """
+ Set the x label and units.
+ @param x_label the x label string
+ @param x_units the x units string
+ """
+ self.lock()
+ self.x_label = x_label
+ self.x_units = x_units
+ self._grid_cache.changed(True)
+ self.unlock()
+
+ def set_y_label(self, y_label, y_units=''):
+ """
+ Set the y label and units.
+ @param y_label the y label string
+ @param y_units the y units string
+ """
+ self.lock()
+ self.y_label = y_label
+ self.y_units = y_units
+ self._grid_cache.changed(True)
+ self.unlock()
+
+ def set_x_grid(self, minimum, maximum, step, scale=False):
+ """
+ Set the x grid parameters.
+ @param minimum the left-most value
+ @param maximum the right-most value
+ @param step the grid spacing
+ @param scale true to scale the x grid
+ """
+ self.lock()
+ self.x_min = float(minimum)
+ self.x_max = float(maximum)
+ self.x_step = float(step)
+ if scale:
+ coeff, exp, prefix =
common.get_si_components(max(abs(self.x_min), abs(self.x_max)))
+ self.x_scalar = 10**(-exp)
+ self.x_prefix = prefix
+ else:
+ self.x_scalar = 1.0
+ self.x_prefix = ''
+ for cache in self._gl_caches: cache.changed(True)
+ self.unlock()
+
+ def set_y_grid(self, minimum, maximum, step, scale=False):
+ """
+ Set the y grid parameters.
+ @param minimum the bottom-most value
+ @param maximum the top-most value
+ @param step the grid spacing
+ @param scale true to scale the y grid
+ """
+ self.lock()
+ self.y_min = float(minimum)
+ self.y_max = float(maximum)
+ self.y_step = float(step)
+ if scale:
+ coeff, exp, prefix =
common.get_si_components(max(abs(self.y_min), abs(self.y_max)))
+ self.y_scalar = 10**(-exp)
+ self.y_prefix = prefix
+ else:
+ self.y_scalar = 1.0
+ self.y_prefix = ''
+ for cache in self._gl_caches: cache.changed(True)
+ self.unlock()
+
+ def _draw_grid(self):
+ """
+ Create the x, y, tick, and title labels.
+ Resize the padding for the labels.
+ Draw the border, grid, title, and labels.
+ """
+ ##################################################
+ # Create GL text labels
+ ##################################################
+ #create x tick labels
+ x_tick_labels = [(tick, self._get_tick_label(tick,
self.x_units))
+ for tick in self._get_ticks(self.x_min, self.x_max,
self.x_step, self.x_scalar)]
+ #create x tick labels
+ y_tick_labels = [(tick, self._get_tick_label(tick,
self.y_units))
+ for tick in self._get_ticks(self.y_min, self.y_max,
self.y_step, self.y_scalar)]
+ #create x label
+ x_label_str = self.x_units and "%s (%s%s)"%(self.x_label,
self.x_prefix, self.x_units) or self.x_label
+ x_label = gltext.Text(x_label_str, bold=True,
font_size=UNITS_TEXT_FONT_SIZE, centered=True)
+ #create y label
+ y_label_str = self.y_units and "%s (%s%s)"%(self.y_label,
self.y_prefix, self.y_units) or self.y_label
+ y_label = gltext.Text(y_label_str, bold=True,
font_size=UNITS_TEXT_FONT_SIZE, centered=True)
+ #create title
+ title_label = gltext.Text(self.title, bold=True,
font_size=TITLE_TEXT_FONT_SIZE, centered=True)
+ ##################################################
+ # Resize the padding
+ ##################################################
+ self.padding_top = max(2*TITLE_LABEL_PADDING +
title_label.get_size()[1], self.padding_top_min)
+ self.padding_right = max(2*TICK_LABEL_PADDING,
self.padding_right_min)
+ self.padding_bottom = max(2*AXIS_LABEL_PADDING +
TICK_LABEL_PADDING + x_label.get_size()[1] + max([label.get_size()[1] for tick,
label in x_tick_labels]), self.padding_bottom_min)
+ self.padding_left = max(2*AXIS_LABEL_PADDING +
TICK_LABEL_PADDING + y_label.get_size()[1] + max([label.get_size()[0] for tick,
label in y_tick_labels]), self.padding_left_min)
+ ##################################################
+ # Draw Grid X
+ ##################################################
+ for tick, label in x_tick_labels:
+ scaled_tick =
(self.width-self.padding_left-self.padding_right)*\
+
(tick/self.x_scalar-self.x_min)/(self.x_max-self.x_min) + self.padding_left
+ self._draw_grid_line(
+ (scaled_tick, self.padding_top),
+ (scaled_tick, self.height-self.padding_bottom),
+ )
+ w, h = label.get_size()
+ label.draw_text(wx.Point(scaled_tick-w/2,
self.height-self.padding_bottom+TICK_LABEL_PADDING))
+ ##################################################
+ # Draw Grid Y
+ ##################################################
+ for tick, label in y_tick_labels:
+ scaled_tick =
(self.height-self.padding_top-self.padding_bottom)*\
+ (1 -
(tick/self.y_scalar-self.y_min)/(self.y_max-self.y_min)) + self.padding_top
+ self._draw_grid_line(
+ (self.padding_left, scaled_tick),
+ (self.width-self.padding_right, scaled_tick),
+ )
+ w, h = label.get_size()
+
label.draw_text(wx.Point(self.padding_left-w-TICK_LABEL_PADDING,
scaled_tick-h/2))
+ ##################################################
+ # Draw Border
+ ##################################################
+ GL.glColor3f(*GRID_BORDER_COLOR_SPEC)
+ self._draw_rect(
+ self.padding_left,
+ self.padding_top,
+ self.width - self.padding_right - self.padding_left,
+ self.height - self.padding_top - self.padding_bottom,
+ fill=False,
+ )
+ ##################################################
+ # Draw Labels
+ ##################################################
+ #draw title label
+ title_label.draw_text(wx.Point(self.width/2.0,
TITLE_LABEL_PADDING + title_label.get_size()[1]/2))
+ #draw x labels
+ x_label.draw_text(wx.Point(
+
(self.width-self.padding_left-self.padding_right)/2.0 + self.padding_left,
+ self.height-(AXIS_LABEL_PADDING +
x_label.get_size()[1]/2),
+ )
+ )
+ #draw y labels
+ y_label.draw_text(wx.Point(
+ AXIS_LABEL_PADDING + y_label.get_size()[1]/2,
+
(self.height-self.padding_top-self.padding_bottom)/2.0 + self.padding_top,
+ ), rotation=90,
+ )
+
+ def _get_tick_label(self, tick, unit):
+ """
+ Format the tick value and create a gl text.
+ @param tick the floating point tick value
+ @param unit the axis unit
+ @return the tick label text
+ """
+ if unit: tick_str = common.sci_format(tick)
+ else: tick_str = common.eng_format(tick)
+ return gltext.Text(tick_str, font_size=TICK_TEXT_FONT_SIZE)
+
+ def _get_ticks(self, min, max, step, scalar):
+ """
+ Determine the positions for the ticks.
+ @param min the lower bound
+ @param max the upper bound
+ @param step the grid spacing
+ @param scalar the grid scaling
+ @return a list of tick positions between min and max
+ """
+ #cast to float
+ min = float(min)
+ max = float(max)
+ step = float(step)
+ #check for valid numbers
+ try:
+ assert step > 0
+ assert max > min
+ assert max - min > step
+ except AssertionError: return [-1, 1]
+ #determine the start and stop value
+ start = int(math.ceil(min/step))
+ stop = int(math.floor(max/step))
+ return [i*step*scalar for i in range(start, stop+1)]
+
+ def enable_grid_lines(self, enable=None):
+ """
+ Enable/disable the grid lines.
+ @param enable true to enable
+ @return the enable state when None
+ """
+ if enable is None: return self._enable_grid_lines
+ self.lock()
+ self._enable_grid_lines = enable
+ self._grid_cache.changed(True)
+ self.unlock()
+
+ def _draw_grid_line(self, coor1, coor2):
+ """
+ Draw a dashed line from coor1 to coor2.
+ @param corr1 a tuple of x, y
+ @param corr2 a tuple of x, y
+ """
+ if not self.enable_grid_lines(): return
+ length = math.sqrt((coor1[0] - coor2[0])**2 + (coor1[1] -
coor2[1])**2)
+ num_points = int(length/GRID_LINE_DASH_LEN)
+ #calculate points array
+ points = [(
+ coor1[0] + i*(coor2[0]-coor1[0])/(num_points - 1),
+ coor1[1] + i*(coor2[1]-coor1[1])/(num_points - 1)
+ ) for i in range(num_points)]
+ #set color and draw
+ GL.glColor3f(*GRID_LINE_COLOR_SPEC)
+ GL.glVertexPointerf(points)
+ GL.glDrawArrays(GL.GL_LINES, 0, len(points))
+
+ def _draw_rect(self, x, y, width, height, fill=True):
+ """
+ Draw a rectangle on the x, y plane.
+ X and Y are the top-left corner.
+ @param x the left position of the rectangle
+ @param y the top position of the rectangle
+ @param width the width of the rectangle
+ @param height the height of the rectangle
+ @param fill true to color inside of rectangle
+ """
+ GL.glBegin(fill and GL.GL_QUADS or GL.GL_LINE_LOOP)
+ GL.glVertex2f(x, y)
+ GL.glVertex2f(x+width, y)
+ GL.glVertex2f(x+width, y+height)
+ GL.glVertex2f(x, y+height)
+ GL.glEnd()
+
+ def _draw_point_label(self):
+ """
+ Draw the point label for the last mouse motion coordinate.
+ The mouse coordinate must be an X, Y tuple.
+ The label will be drawn at the X, Y coordinate.
+ The values of the X, Y coordinate will be scaled to the current
X, Y bounds.
+ """
+ if not self.enable_point_label(): return
+ if not self._point_label_coordinate: return
+ x, y = self._point_label_coordinate
+ if x < self.padding_left or x > self.width-self.padding_right:
return
+ if y < self.padding_top or y > self.height-self.padding_bottom:
return
+ #scale to window bounds
+ x_win_scalar = float(x -
self.padding_left)/(self.width-self.padding_left-self.padding_right)
+ y_win_scalar = float((self.height - y) -
self.padding_bottom)/(self.height-self.padding_top-self.padding_bottom)
+ #scale to grid bounds
+ x_val = x_win_scalar*(self.x_max-self.x_min) + self.x_min
+ y_val = y_win_scalar*(self.y_max-self.y_min) + self.y_min
+ #create text
+ label_str = self._populate_point_label(x_val, y_val)
+ if not label_str: return
+ txt = gltext.Text(label_str, font_size=POINT_LABEL_FONT_SIZE)
+ w, h = txt.get_size()
+ #draw rect + text
+ GL.glColor3f(*POINT_LABEL_COLOR_SPEC)
+ if x > self.width/2: x -= w+2*POINT_LABEL_PADDING
+ self._draw_rect(x, y-h-2*POINT_LABEL_PADDING,
w+2*POINT_LABEL_PADDING, h+2*POINT_LABEL_PADDING)
+ txt.draw_text(wx.Point(x+POINT_LABEL_PADDING,
y-h-POINT_LABEL_PADDING))
Modified: gnuradio/trunk/gr-wxgui/src/python/plotter/plotter_base.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/plotter/plotter_base.py 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/plotter/plotter_base.py 2009-03-20
02:16:20 UTC (rev 10660)
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -21,27 +21,59 @@
import wx
import wx.glcanvas
-from OpenGL.GL import *
-from gnuradio.wxgui import common
-import threading
-import gltext
-import math
-import time
+from OpenGL import GL
+import common
BACKGROUND_COLOR_SPEC = (1, 0.976, 1, 1) #creamy white
-GRID_LINE_COLOR_SPEC = (0, 0, 0) #black
-TICK_TEXT_FONT_SIZE = 9
-TITLE_TEXT_FONT_SIZE = 13
-UNITS_TEXT_FONT_SIZE = 9
-TICK_LABEL_PADDING = 5
-POINT_LABEL_FONT_SIZE = 8
-POINT_LABEL_COLOR_SPEC = (1, 1, .5)
-POINT_LABEL_PADDING = 3
##################################################
+# GL caching interface
+##################################################
+class gl_cache(object):
+ """
+ Cache a set of gl drawing routines in a compiled list.
+ """
+
+ def __init__(self, draw):
+ """
+ Create a new cache.
+ @param draw a function to draw gl stuff
+ """
+ self.changed(True)
+ self._draw = draw
+
+ def init(self):
+ """
+ To be called when gl initializes.
+ Create a new compiled list.
+ """
+ self._grid_compiled_list_id = GL.glGenLists(1)
+
+ def draw(self):
+ """
+ Draw the gl stuff using a compiled list.
+ If changed, reload the compiled list.
+ """
+ if self.changed():
+ GL.glNewList(self._grid_compiled_list_id, GL.GL_COMPILE)
+ self._draw()
+ GL.glEndList()
+ self.changed(False)
+ #draw the grid
+ GL.glCallList(self._grid_compiled_list_id)
+
+ def changed(self, state=None):
+ """
+ Set the changed flag if state is not None.
+ Otherwise return the changed flag.
+ """
+ if state is None: return self._changed
+ self._changed = state
+
+##################################################
# OpenGL WX Plotter Canvas
##################################################
-class _plotter_base(wx.glcanvas.GLCanvas):
+class plotter_base(wx.glcanvas.GLCanvas, common.mutex):
"""
Plotter base class for all plot types.
"""
@@ -54,340 +86,86 @@
Bind the paint and size events.
@param parent the parent widgit
"""
- self._global_lock = threading.Lock()
attribList = (wx.glcanvas.WX_GL_DOUBLEBUFFER,
wx.glcanvas.WX_GL_RGBA)
wx.glcanvas.GLCanvas.__init__(self, parent,
attribList=attribList)
- self.changed(False)
self._gl_init_flag = False
self._resized_flag = True
- self._update_ts = 0
+ self._init_fcns = list()
+ self._draw_fcns = list()
+ self._gl_caches = list()
self.Bind(wx.EVT_PAINT, self._on_paint)
self.Bind(wx.EVT_SIZE, self._on_size)
+ self.Bind(wx.EVT_ERASE_BACKGROUND, lambda e: None)
- def lock(self): self._global_lock.acquire()
- def unlock(self): self._global_lock.release()
+ def new_gl_cache(self, draw_fcn, draw_pri=50):
+ """
+ Create a new gl cache.
+ Register its draw and init function.
+ @return the new cache object
+ """
+ cache = gl_cache(draw_fcn)
+ self.register_init(cache.init)
+ self.register_draw(cache.draw, draw_pri)
+ self._gl_caches.append(cache)
+ return cache
+ def register_init(self, init_fcn):
+ self._init_fcns.append(init_fcn)
+
+ def register_draw(self, draw_fcn, draw_pri=50):
+ """
+ Register a draw function with a layer priority.
+ Large pri values are drawn last.
+ Small pri values are drawn first.
+ """
+ for i in range(len(self._draw_fcns)):
+ if draw_pri < self._draw_fcns[i][0]:
+ self._draw_fcns.insert(i, (draw_pri, draw_fcn))
+ return
+ self._draw_fcns.append((draw_pri, draw_fcn))
+
def _on_size(self, event):
"""
Flag the resize event.
The paint event will handle the actual resizing.
"""
+ self.lock()
self._resized_flag = True
+ self.unlock()
def _on_paint(self, event):
"""
- Respond to paint events, call update.
+ Respond to paint events.
Initialize GL if this is the first paint event.
+ Resize the view port if the width or height changed.
+ Redraw the screen, calling the draw functions.
"""
+ self.lock()
self.SetCurrent()
#check if gl was initialized
if not self._gl_init_flag:
- glClearColor(*BACKGROUND_COLOR_SPEC)
- self._gl_init()
+ GL.glClearColor(*BACKGROUND_COLOR_SPEC)
+ for fcn in self._init_fcns: fcn()
self._gl_init_flag = True
#check for a change in window size
if self._resized_flag:
- self.lock()
self.width, self.height = self.GetSize()
- glMatrixMode(GL_PROJECTION)
- glLoadIdentity()
- glOrtho(0, self.width, self.height, 0, 1, 0)
- glMatrixMode(GL_MODELVIEW)
- glLoadIdentity()
- glViewport(0, 0, self.width, self.height)
+ GL.glMatrixMode(GL.GL_PROJECTION)
+ GL.glLoadIdentity()
+ GL.glOrtho(0, self.width, self.height, 0, 1, 0)
+ GL.glMatrixMode(GL.GL_MODELVIEW)
+ GL.glLoadIdentity()
+ GL.glViewport(0, 0, self.width, self.height)
+ for cache in self._gl_caches: cache.changed(True)
self._resized_flag = False
- self.changed(True)
- self.unlock()
- self.draw()
+ #clear, draw functions, swap
+ GL.glClear(GL.GL_COLOR_BUFFER_BIT)
+ for fcn in self._draw_fcns: fcn[1]()
+ self.SwapBuffers()
+ self.unlock()
def update(self):
"""
Force a paint event.
- Record the timestamp.
"""
wx.PostEvent(self, wx.PaintEvent())
- self._update_ts = time.time()
-
- def clear(self): glClear(GL_COLOR_BUFFER_BIT)
-
- def changed(self, state=None):
- """
- Set the changed flag if state is not None.
- Otherwise return the changed flag.
- """
- if state is not None: self._changed = state
- else: return self._changed
-
-##################################################
-# Grid Plotter Base Class
-##################################################
-class grid_plotter_base(_plotter_base):
-
- def __init__(self, parent, padding):
- _plotter_base.__init__(self, parent)
- self.padding_top, self.padding_right, self.padding_bottom,
self.padding_left = padding
- #store title and unit strings
- self.set_title('Title')
- self.set_x_label('X Label')
- self.set_y_label('Y Label')
- #init the grid to some value
- self.set_x_grid(-1, 1, 1)
- self.set_y_grid(-1, 1, 1)
- #setup point label
- self.enable_point_label(False)
- self._mouse_coordinate = None
- self.Bind(wx.EVT_MOTION, self._on_motion)
- self.Bind(wx.EVT_LEAVE_WINDOW, self._on_leave_window)
-
- def _on_motion(self, event):
- """
- Mouse motion, record the position X, Y.
- """
- self.lock()
- self._mouse_coordinate = event.GetPosition()
- #update based on last known update time
- if time.time() - self._update_ts > 0.03: self.update()
- self.unlock()
-
- def _on_leave_window(self, event):
- """
- Mouse leave window, set the position to None.
- """
- self.lock()
- self._mouse_coordinate = None
- self.update()
- self.unlock()
-
- def enable_point_label(self, enable=None):
- """
- Enable/disable the point label.
- @param enable true to enable
- @return the enable state when None
- """
- if enable is None: return self._enable_point_label
- self.lock()
- self._enable_point_label = enable
- self.changed(True)
- self.unlock()
-
- def set_title(self, title):
- """
- Set the title.
- @param title the title string
- """
- self.lock()
- self.title = title
- self.changed(True)
- self.unlock()
-
- def set_x_label(self, x_label, x_units=''):
- """
- Set the x label and units.
- @param x_label the x label string
- @param x_units the x units string
- """
- self.lock()
- self.x_label = x_label
- self.x_units = x_units
- self.changed(True)
- self.unlock()
-
- def set_y_label(self, y_label, y_units=''):
- """
- Set the y label and units.
- @param y_label the y label string
- @param y_units the y units string
- """
- self.lock()
- self.y_label = y_label
- self.y_units = y_units
- self.changed(True)
- self.unlock()
-
- def set_x_grid(self, x_min, x_max, x_step, x_scalar=1.0):
- """
- Set the x grid parameters.
- @param x_min the left-most value
- @param x_max the right-most value
- @param x_step the grid spacing
- @param x_scalar the scalar factor
- """
- self.lock()
- self.x_min = float(x_min)
- self.x_max = float(x_max)
- self.x_step = float(x_step)
- self.x_scalar = float(x_scalar)
- self.changed(True)
- self.unlock()
-
- def set_y_grid(self, y_min, y_max, y_step, y_scalar=1.0):
- """
- Set the y grid parameters.
- @param y_min the bottom-most value
- @param y_max the top-most value
- @param y_step the grid spacing
- @param y_scalar the scalar factor
- """
- self.lock()
- self.y_min = float(y_min)
- self.y_max = float(y_max)
- self.y_step = float(y_step)
- self.y_scalar = float(y_scalar)
- self.changed(True)
- self.unlock()
-
- def _draw_grid(self):
- """
- Draw the border, grid, title, and units.
- """
- ##################################################
- # Draw Border
- ##################################################
- glColor3f(*GRID_LINE_COLOR_SPEC)
- self._draw_rect(
- self.padding_left,
- self.padding_top,
- self.width - self.padding_right - self.padding_left,
- self.height - self.padding_top - self.padding_bottom,
- fill=False,
- )
- ##################################################
- # Draw Grid X
- ##################################################
- for tick in self._get_ticks(self.x_min, self.x_max,
self.x_step, self.x_scalar):
- scaled_tick =
(self.width-self.padding_left-self.padding_right)*\
-
(tick/self.x_scalar-self.x_min)/(self.x_max-self.x_min) + self.padding_left
- glColor3f(*GRID_LINE_COLOR_SPEC)
- self._draw_line(
- (scaled_tick, self.padding_top, 0),
- (scaled_tick, self.height-self.padding_bottom,
0),
- )
- txt = self._get_tick_label(tick)
- w, h = txt.get_size()
- txt.draw_text(wx.Point(scaled_tick-w/2,
self.height-self.padding_bottom+TICK_LABEL_PADDING))
- ##################################################
- # Draw Grid Y
- ##################################################
- for tick in self._get_ticks(self.y_min, self.y_max,
self.y_step, self.y_scalar):
- scaled_tick =
(self.height-self.padding_top-self.padding_bottom)*\
- (1 -
(tick/self.y_scalar-self.y_min)/(self.y_max-self.y_min)) + self.padding_top
- glColor3f(*GRID_LINE_COLOR_SPEC)
- self._draw_line(
- (self.padding_left, scaled_tick, 0),
- (self.width-self.padding_right, scaled_tick, 0),
- )
- txt = self._get_tick_label(tick)
- w, h = txt.get_size()
-
txt.draw_text(wx.Point(self.padding_left-w-TICK_LABEL_PADDING, scaled_tick-h/2))
- ##################################################
- # Draw Title
- ##################################################
- #draw x units
- txt = gltext.Text(self.title, bold=True,
font_size=TITLE_TEXT_FONT_SIZE, centered=True)
- txt.draw_text(wx.Point(self.width/2.0, .5*self.padding_top))
- ##################################################
- # Draw Labels
- ##################################################
- #draw x labels
- x_label_str = self.x_units and "%s (%s)"%(self.x_label,
self.x_units) or self.x_label
- txt = gltext.Text(x_label_str, bold=True,
font_size=UNITS_TEXT_FONT_SIZE, centered=True)
- txt.draw_text(wx.Point(
-
(self.width-self.padding_left-self.padding_right)/2.0 + self.padding_left,
- self.height-.25*self.padding_bottom,
- )
- )
- #draw y labels
- y_label_str = self.y_units and "%s (%s)"%(self.y_label,
self.y_units) or self.y_label
- txt = gltext.Text(y_label_str, bold=True,
font_size=UNITS_TEXT_FONT_SIZE, centered=True)
- txt.draw_text(wx.Point(
- .25*self.padding_left,
-
(self.height-self.padding_top-self.padding_bottom)/2.0 + self.padding_top,
- ), rotation=90,
- )
-
- def _get_tick_label(self, tick):
- """
- Format the tick value and create a gl text.
- @param tick the floating point tick value
- @return the tick label text
- """
- tick_str = common.label_format(tick)
- return gltext.Text(tick_str, font_size=TICK_TEXT_FONT_SIZE)
-
- def _get_ticks(self, min, max, step, scalar):
- """
- Determine the positions for the ticks.
- @param min the lower bound
- @param max the upper bound
- @param step the grid spacing
- @param scalar the grid scaling
- @return a list of tick positions between min and max
- """
- #cast to float
- min = float(min)
- max = float(max)
- step = float(step)
- #check for valid numbers
- assert step > 0
- assert max > min
- assert max - min > step
- #determine the start and stop value
- start = int(math.ceil(min/step))
- stop = int(math.floor(max/step))
- return [i*step*scalar for i in range(start, stop+1)]
-
- def _draw_line(self, coor1, coor2):
- """
- Draw a line from coor1 to coor2.
- @param corr1 a tuple of x, y, z
- @param corr2 a tuple of x, y, z
- """
- glBegin(GL_LINES)
- glVertex3f(*coor1)
- glVertex3f(*coor2)
- glEnd()
-
- def _draw_rect(self, x, y, width, height, fill=True):
- """
- Draw a rectangle on the x, y plane.
- X and Y are the top-left corner.
- @param x the left position of the rectangle
- @param y the top position of the rectangle
- @param width the width of the rectangle
- @param height the height of the rectangle
- @param fill true to color inside of rectangle
- """
- glBegin(fill and GL_QUADS or GL_LINE_LOOP)
- glVertex2f(x, y)
- glVertex2f(x+width, y)
- glVertex2f(x+width, y+height)
- glVertex2f(x, y+height)
- glEnd()
-
- def _draw_point_label(self):
- """
- Draw the point label for the last mouse motion coordinate.
- The mouse coordinate must be an X, Y tuple.
- The label will be drawn at the X, Y coordinate.
- The values of the X, Y coordinate will be scaled to the current
X, Y bounds.
- """
- if not self.enable_point_label(): return
- if not self._mouse_coordinate: return
- x, y = self._mouse_coordinate
- if x < self.padding_left or x > self.width-self.padding_right:
return
- if y < self.padding_top or y > self.height-self.padding_bottom:
return
- #scale to window bounds
- x_win_scalar = float(x -
self.padding_left)/(self.width-self.padding_left-self.padding_right)
- y_win_scalar = float((self.height - y) -
self.padding_bottom)/(self.height-self.padding_top-self.padding_bottom)
- #scale to grid bounds
- x_val = self.x_scalar*(x_win_scalar*(self.x_max-self.x_min) +
self.x_min)
- y_val = self.y_scalar*(y_win_scalar*(self.y_max-self.y_min) +
self.y_min)
- #create text
- label_str = self._populate_point_label(x_val, y_val)
- txt = gltext.Text(label_str, font_size=POINT_LABEL_FONT_SIZE)
- w, h = txt.get_size()
- #draw rect + text
- glColor3f(*POINT_LABEL_COLOR_SPEC)
- if x > self.width/2: x -= w+2*POINT_LABEL_PADDING
- self._draw_rect(x, y-h-2*POINT_LABEL_PADDING,
w+2*POINT_LABEL_PADDING, h+2*POINT_LABEL_PADDING)
- txt.draw_text(wx.Point(x+POINT_LABEL_PADDING,
y-h-POINT_LABEL_PADDING))
Modified: gnuradio/trunk/gr-wxgui/src/python/plotter/waterfall_plotter.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/plotter/waterfall_plotter.py
2009-03-20 01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/plotter/waterfall_plotter.py
2009-03-20 02:16:20 UTC (rev 10660)
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -20,9 +20,9 @@
#
import wx
-from plotter_base import grid_plotter_base
-from OpenGL.GL import *
-from gnuradio.wxgui import common
+from grid_plotter_base import grid_plotter_base
+from OpenGL import GL
+import common
import numpy
import gltext
import math
@@ -33,7 +33,7 @@
LEGEND_WIDTH = 8
LEGEND_FONT_SIZE = 8
LEGEND_BORDER_COLOR_SPEC = (0, 0, 0) #black
-PADDING = 35, 60, 40, 60 #top, right, bottom, left
+MIN_PADDING = 0, 60, 0, 0 #top, right, bottom, left
ceil_log2 = lambda x: 2**int(math.ceil(math.log(x)/math.log(2)))
@@ -91,7 +91,13 @@
Create a new channel plotter.
"""
#init
- grid_plotter_base.__init__(self, parent, PADDING)
+ grid_plotter_base.__init__(self, parent, MIN_PADDING)
+ #setup legend cache
+ self._legend_cache = self.new_gl_cache(self._draw_legend)
+ #setup waterfall cache
+ self._waterfall_cache = self.new_gl_cache(self._draw_waterfall,
50)
+ #setup waterfall plotter
+ self.register_init(self._init_waterfall)
self._resize_texture(False)
self._minimum = 0
self._maximum = 0
@@ -102,78 +108,56 @@
self.set_num_lines(0)
self.set_color_mode(COLORS.keys()[0])
- def _gl_init(self):
+ def _init_waterfall(self):
"""
Run gl initialization tasks.
"""
- self._grid_compiled_list_id = glGenLists(1)
- self._waterfall_texture = glGenTextures(1)
+ self._waterfall_texture = GL.glGenTextures(1)
- def draw(self):
- """
- Draw the grid and waveforms.
- """
- self.lock()
- #resize texture
- self._resize_texture()
- #store the grid drawing operations
- if self.changed():
- glNewList(self._grid_compiled_list_id, GL_COMPILE)
- self._draw_grid()
- self._draw_legend()
- glEndList()
- self.changed(False)
- self.clear()
- #draw the grid
- glCallList(self._grid_compiled_list_id)
- self._draw_waterfall()
- self._draw_point_label()
- #swap buffer into display
- self.SwapBuffers()
- self.unlock()
-
def _draw_waterfall(self):
"""
Draw the waterfall from the texture.
The texture is circularly filled and will wrap around.
Use matrix modeling to shift and scale the texture onto the
coordinate plane.
"""
+ #resize texture
+ self._resize_texture()
#setup texture
- glBindTexture(GL_TEXTURE_2D, self._waterfall_texture)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
+ GL.glBindTexture(GL.GL_TEXTURE_2D, self._waterfall_texture)
+ GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER,
GL.GL_LINEAR)
+ GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER,
GL.GL_LINEAR)
+ GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T,
GL.GL_REPEAT)
+ GL.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE,
GL.GL_REPLACE)
#write the buffer to the texture
while self._buffer:
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, self._pointer,
self._fft_size, 1, GL_RGBA, GL_UNSIGNED_BYTE, self._buffer.pop(0))
+ GL.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0,
self._pointer, self._fft_size, 1, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE,
self._buffer.pop(0))
self._pointer = (self._pointer + 1)%self._num_lines
#begin drawing
- glEnable(GL_TEXTURE_2D)
- glPushMatrix()
+ GL.glEnable(GL.GL_TEXTURE_2D)
+ GL.glPushMatrix()
#matrix scaling
- glTranslatef(self.padding_left, self.padding_top, 0)
- glScalef(
+ GL.glTranslatef(self.padding_left, self.padding_top, 0)
+ GL.glScalef(
float(self.width-self.padding_left-self.padding_right),
float(self.height-self.padding_top-self.padding_bottom),
1.0,
)
#draw texture with wrapping
- glBegin(GL_QUADS)
+ GL.glBegin(GL.GL_QUADS)
prop_y = float(self._pointer)/(self._num_lines-1)
prop_x = float(self._fft_size)/ceil_log2(self._fft_size)
off = 1.0/(self._num_lines-1)
- glTexCoord2f(0, prop_y+1-off)
- glVertex2f(0, 1)
- glTexCoord2f(prop_x, prop_y+1-off)
- glVertex2f(1, 1)
- glTexCoord2f(prop_x, prop_y)
- glVertex2f(1, 0)
- glTexCoord2f(0, prop_y)
- glVertex2f(0, 0)
- glEnd()
- glPopMatrix()
- glDisable(GL_TEXTURE_2D)
+ GL.glTexCoord2f(0, prop_y+1-off)
+ GL.glVertex2f(0, 1)
+ GL.glTexCoord2f(prop_x, prop_y+1-off)
+ GL.glVertex2f(1, 1)
+ GL.glTexCoord2f(prop_x, prop_y)
+ GL.glVertex2f(1, 0)
+ GL.glTexCoord2f(0, prop_y)
+ GL.glVertex2f(0, 0)
+ GL.glEnd()
+ GL.glPopMatrix()
+ GL.glDisable(GL.GL_TEXTURE_2D)
def _populate_point_label(self, x_val, y_val):
"""
@@ -183,7 +167,7 @@
@param y_val the current y value
@return a value string with units
"""
- return '%s: %s %s'%(self.x_label, common.label_format(x_val),
self.x_units)
+ return '%s: %s'%(self.x_label, common.eng_format(x_val,
self.x_units))
def _draw_legend(self):
"""
@@ -196,11 +180,11 @@
x = self.width - self.padding_right + LEGEND_LEFT_PAD
for i in range(LEGEND_NUM_BLOCKS):
color =
COLORS[self._color_mode][int(255*i/float(LEGEND_NUM_BLOCKS-1))]
- glColor4f(*map(lambda c: ord(c)/255.0, color))
+ GL.glColor4f(*map(lambda c: ord(c)/255.0, color))
y = self.height - (i+1)*block_height -
self.padding_bottom
self._draw_rect(x, y, LEGEND_WIDTH, block_height)
#draw rectangle around color scale border
- glColor3f(*LEGEND_BORDER_COLOR_SPEC)
+ GL.glColor3f(*LEGEND_BORDER_COLOR_SPEC)
self._draw_rect(x, self.padding_top, LEGEND_WIDTH,
legend_height, fill=False)
#draw each legend label
label_spacing = float(legend_height)/(LEGEND_NUM_LABELS-1)
@@ -224,9 +208,9 @@
self._buffer = list()
self._pointer = 0
if self._num_lines and self._fft_size:
- glBindTexture(GL_TEXTURE_2D, self._waterfall_texture)
+ GL.glBindTexture(GL.GL_TEXTURE_2D,
self._waterfall_texture)
data = numpy.zeros(self._num_lines*self._fft_size*4,
numpy.uint8).tostring()
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
ceil_log2(self._fft_size), self._num_lines, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
+ GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA,
ceil_log2(self._fft_size), self._num_lines, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE,
data)
self._resize_texture_flag = False
def set_color_mode(self, color_mode):
@@ -239,7 +223,7 @@
self.lock()
if color_mode in COLORS.keys():
self._color_mode = color_mode
- self.changed(True)
+ self._legend_cache.changed(True)
self.update()
self.unlock()
@@ -268,7 +252,7 @@
if self._minimum != minimum or self._maximum != maximum:
self._minimum = minimum
self._maximum = maximum
- self.changed(True)
+ self._legend_cache.changed(True)
if self._fft_size != len(samples):
self._fft_size = len(samples)
self._resize_texture(True)
@@ -279,4 +263,5 @@
#convert the samples to RGBA data
data = numpy.choose(samples,
COLORS[self._color_mode]).tostring()
self._buffer.append(data)
+ self._waterfall_cache.changed(True)
self.unlock()
Modified: gnuradio/trunk/gr-wxgui/src/python/pubsub.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/pubsub.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/pubsub.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -28,73 +28,73 @@
class pubsub(dict):
def __init__(self):
- self._publishers = { }
- self._subscribers = { }
- self._proxies = { }
-
+ self._publishers = { }
+ self._subscribers = { }
+ self._proxies = { }
+
def __missing__(self, key, value=None):
- dict.__setitem__(self, key, value)
- self._publishers[key] = None
- self._subscribers[key] = []
- self._proxies[key] = None
-
+ dict.__setitem__(self, key, value)
+ self._publishers[key] = None
+ self._subscribers[key] = []
+ self._proxies[key] = None
+
def __setitem__(self, key, val):
- if not self.has_key(key):
- self.__missing__(key, val)
- elif self._proxies[key] is not None:
- (p, newkey) = self._proxies[key]
- p[newkey] = val
- else:
- dict.__setitem__(self, key, val)
- for sub in self._subscribers[key]:
- # Note this means subscribers will get called in the thread
- # context of the 'set' caller.
- sub(val)
+ if not self.has_key(key):
+ self.__missing__(key, val)
+ elif self._proxies[key] is not None:
+ (p, pkey) = self._proxies[key]
+ p[pkey] = val
+ else:
+ dict.__setitem__(self, key, val)
+ for sub in self._subscribers[key]:
+ # Note this means subscribers will get called in the thread
+ # context of the 'set' caller.
+ sub(val)
def __getitem__(self, key):
- if not self.has_key(key): self.__missing__(key)
- if self._proxies[key] is not None:
- (p, newkey) = self._proxies[key]
- return p[newkey]
- elif self._publishers[key] is not None:
- return self._publishers[key]()
- else:
- return dict.__getitem__(self, key)
+ if not self.has_key(key): self.__missing__(key)
+ if self._proxies[key] is not None:
+ (p, pkey) = self._proxies[key]
+ return p[pkey]
+ elif self._publishers[key] is not None:
+ return self._publishers[key]()
+ else:
+ return dict.__getitem__(self, key)
def publish(self, key, publisher):
- if not self.has_key(key): self.__missing__(key)
+ if not self.has_key(key): self.__missing__(key)
if self._proxies[key] is not None:
- (p, newkey) = self._proxies[key]
- p.publish(newkey, publisher)
+ (p, pkey) = self._proxies[key]
+ p.publish(pkey, publisher)
else:
self._publishers[key] = publisher
-
+
def subscribe(self, key, subscriber):
- if not self.has_key(key): self.__missing__(key)
+ if not self.has_key(key): self.__missing__(key)
if self._proxies[key] is not None:
- (p, newkey) = self._proxies[key]
- p.subscribe(newkey, subscriber)
+ (p, pkey) = self._proxies[key]
+ p.subscribe(pkey, subscriber)
else:
self._subscribers[key].append(subscriber)
-
+
def unpublish(self, key):
if self._proxies[key] is not None:
- (p, newkey) = self._proxies[key]
- p.unpublish(newkey)
+ (p, pkey) = self._proxies[key]
+ p.unpublish(pkey)
else:
self._publishers[key] = None
-
+
def unsubscribe(self, key, subscriber):
if self._proxies[key] is not None:
- (p, newkey) = self._proxies[key]
- p.unsubscribe(newkey, subscriber)
+ (p, pkey) = self._proxies[key]
+ p.unsubscribe(pkey, subscriber)
else:
self._subscribers[key].remove(subscriber)
- def proxy(self, key, p, newkey=None):
- if not self.has_key(key): self.__missing__(key)
- if newkey is None: newkey = key
- self._proxies[key] = (p, newkey)
+ def proxy(self, key, p, pkey=None):
+ if not self.has_key(key): self.__missing__(key)
+ if pkey is None: pkey = key
+ self._proxies[key] = (p, pkey)
def unproxy(self, key):
self._proxies[key] = None
@@ -110,22 +110,22 @@
# Add some subscribers
# First is a bare function
def print_len(x):
- print "len=%i" % (len(x), )
+ print "len=%i" % (len(x), )
o.subscribe('foo', print_len)
# The second is a class member function
class subber(object):
- def __init__(self, param):
- self._param = param
- def printer(self, x):
- print self._param, `x`
+ def __init__(self, param):
+ self._param = param
+ def printer(self, x):
+ print self._param, `x`
s = subber('param')
o.subscribe('foo', s.printer)
# The third is a lambda function
o.subscribe('foo', lambda x: sys.stdout.write('val='+`x`+'\n'))
- # Update key 'foo', will notify subscribers
+ # Update key 'foo', will notify subscribers
print "Updating 'foo' with three subscribers:"
o['foo'] = 'bar';
@@ -135,7 +135,7 @@
# Update now will only trigger second and third subscriber
print "Updating 'foo' after removing a subscriber:"
o['foo'] = 'bar2';
-
+
# Publish a key as a function, in this case, a lambda function
o.publish('baz', lambda : 42)
print "Published value of 'baz':", o['baz']
@@ -145,7 +145,7 @@
# This will return None, as there is no publisher
print "Value of 'baz' with no publisher:", o['baz']
-
+
# Set 'baz' key, it gets cached
o['baz'] = 'bazzz'
Modified: gnuradio/trunk/gr-wxgui/src/python/scope_window.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/scope_window.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/scope_window.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -29,41 +29,40 @@
import time
import pubsub
from constants import *
-from gnuradio import gr #for gr.prefs
+from gnuradio import gr #for gr.prefs, trigger modes
##################################################
# Constants
##################################################
DEFAULT_FRAME_RATE = gr.prefs().get_long('wxgui', 'scope_rate', 30)
DEFAULT_WIN_SIZE = (600, 300)
-DEFAULT_V_SCALE = 1000
+COUPLING_MODES = (
+ ('DC', False),
+ ('AC', True),
+)
TRIGGER_MODES = (
- ('Off', 0),
- ('Neg', -1),
- ('Pos', +1),
+ ('Freerun', gr.gr_TRIG_MODE_FREE),
+ ('Automatic', gr.gr_TRIG_MODE_AUTO),
+ ('Normal', gr.gr_TRIG_MODE_NORM),
)
-TRIGGER_LEVELS = (
- ('Auto', None),
- ('+High', 0.75),
- ('+Med', 0.5),
- ('+Low', 0.25),
- ('Zero', 0.0),
- ('-Low', -0.25),
- ('-Med', -0.5),
- ('-High', -0.75),
+TRIGGER_SLOPES = (
+ ('Positive +', gr.gr_TRIG_SLOPE_POS),
+ ('Negative -', gr.gr_TRIG_SLOPE_NEG),
)
CHANNEL_COLOR_SPECS = (
- (0, 0, 1),
- (0, 1, 0),
- (1, 0, 0),
- (1, 0, 1),
+ (0.3, 0.3, 1.0),
+ (0.0, 0.8, 0.0),
+ (1.0, 0.0, 0.0),
+ (0.8, 0.0, 0.8),
)
+TRIGGER_COLOR_SPEC = (1.0, 0.4, 0.0)
AUTORANGE_UPDATE_RATE = 0.5 #sec
MARKER_TYPES = (
+ ('Line Link', None),
+ ('Dot Large', 3.0),
+ ('Dot Med', 2.0),
('Dot Small', 1.0),
- ('Dot Medium', 2.0),
- ('Dot Large', 3.0),
- ('Line Link', None),
+ ('None', 0.0),
)
DEFAULT_MARKER_TYPE = None
@@ -79,175 +78,213 @@
Create a new control panel.
@param parent the wx parent window
"""
+ SIZE = (100, -1)
self.parent = parent
wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
- self.control_box = control_box = wx.BoxSizer(wx.VERTICAL)
- #trigger options
+ control_box = wx.BoxSizer(wx.VERTICAL)
+ ##################################################
+ # Axes Options
+ ##################################################
control_box.AddStretchSpacer()
- control_box.Add(common.LabelText(self, 'Trigger Options'), 0,
wx.ALIGN_CENTER)
- control_box.AddSpacer(2)
- #trigger mode
- self.trigger_mode_chooser = common.DropDownController(self,
'Mode', TRIGGER_MODES, parent, TRIGGER_MODE_KEY)
- control_box.Add(self.trigger_mode_chooser, 0, wx.EXPAND)
- #trigger level
- self.trigger_level_chooser = common.DropDownController(self,
'Level', TRIGGER_LEVELS, parent, TRIGGER_LEVEL_KEY)
- parent.subscribe(TRIGGER_MODE_KEY, lambda x:
self.trigger_level_chooser.Disable(x==0))
- control_box.Add(self.trigger_level_chooser, 0, wx.EXPAND)
- #trigger channel
- choices = [('Ch%d'%(i+1), i) for i in range(parent.num_inputs)]
- self.trigger_channel_chooser = common.DropDownController(self,
'Channel', choices, parent, TRIGGER_CHANNEL_KEY)
- parent.subscribe(TRIGGER_MODE_KEY, lambda x:
self.trigger_channel_chooser.Disable(x==0))
- control_box.Add(self.trigger_channel_chooser, 0, wx.EXPAND)
- #axes options
- SPACING = 15
- control_box.AddStretchSpacer()
control_box.Add(common.LabelText(self, 'Axes Options'), 0,
wx.ALIGN_CENTER)
control_box.AddSpacer(2)
##################################################
# Scope Mode Box
##################################################
- self.scope_mode_box = wx.BoxSizer(wx.VERTICAL)
- control_box.Add(self.scope_mode_box, 0, wx.EXPAND)
+ scope_mode_box = wx.BoxSizer(wx.VERTICAL)
+ control_box.Add(scope_mode_box, 0, wx.EXPAND)
#x axis divs
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- self.scope_mode_box.Add(hbox, 0, wx.EXPAND)
- hbox.Add(wx.StaticText(self, -1, ' Secs/Div '), 1,
wx.ALIGN_CENTER_VERTICAL)
- x_buttons = common.IncrDecrButtons(self, self._on_incr_t_divs,
self._on_decr_t_divs)
- hbox.Add(x_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
- hbox.AddSpacer(SPACING)
+ x_buttons_scope = common.IncrDecrButtons(self,
self._on_incr_t_divs, self._on_decr_t_divs)
+ scope_mode_box.Add(common.LabelBox(self, 'Secs/Div',
x_buttons_scope), 0, wx.EXPAND)
#y axis divs
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- self.scope_mode_box.Add(hbox, 0, wx.EXPAND)
- hbox.Add(wx.StaticText(self, -1, ' Units/Div '), 1,
wx.ALIGN_CENTER_VERTICAL)
- y_buttons = common.IncrDecrButtons(self, self._on_incr_y_divs,
self._on_decr_y_divs)
- parent.subscribe(AUTORANGE_KEY, y_buttons.Disable)
- hbox.Add(y_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
- hbox.AddSpacer(SPACING)
+ y_buttons_scope = common.IncrDecrButtons(self,
self._on_incr_y_divs, self._on_decr_y_divs)
+ parent.subscribe(AUTORANGE_KEY, lambda x:
y_buttons_scope.Enable(not x))
+ scope_mode_box.Add(common.LabelBox(self, 'Counts/Div',
y_buttons_scope), 0, wx.EXPAND)
#y axis ref lvl
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- self.scope_mode_box.Add(hbox, 0, wx.EXPAND)
- hbox.Add(wx.StaticText(self, -1, ' Y Offset '), 1,
wx.ALIGN_CENTER_VERTICAL)
- y_off_buttons = common.IncrDecrButtons(self,
self._on_incr_y_off, self._on_decr_y_off)
- parent.subscribe(AUTORANGE_KEY, y_off_buttons.Disable)
- hbox.Add(y_off_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
- hbox.AddSpacer(SPACING)
+ y_off_buttons_scope = common.IncrDecrButtons(self,
self._on_incr_y_off, self._on_decr_y_off)
+ parent.subscribe(AUTORANGE_KEY, lambda x:
y_off_buttons_scope.Enable(not x))
+ scope_mode_box.Add(common.LabelBox(self, 'Y Offset',
y_off_buttons_scope), 0, wx.EXPAND)
+ #t axis ref lvl
+ scope_mode_box.AddSpacer(5)
+ t_off_slider = wx.Slider(self, size=SIZE,
style=wx.SL_HORIZONTAL)
+ t_off_slider.SetRange(0, 1000)
+ def t_off_slider_changed(evt): parent[T_FRAC_OFF_KEY] =
float(t_off_slider.GetValue())/t_off_slider.GetMax()
+ t_off_slider.Bind(wx.EVT_SLIDER, t_off_slider_changed)
+ parent.subscribe(T_FRAC_OFF_KEY, lambda x:
t_off_slider.SetValue(int(round(x*t_off_slider.GetMax()))))
+ scope_mode_box.Add(common.LabelBox(self, 'T Offset',
t_off_slider), 0, wx.EXPAND)
+ scope_mode_box.AddSpacer(5)
##################################################
# XY Mode Box
##################################################
- self.xy_mode_box = wx.BoxSizer(wx.VERTICAL)
- control_box.Add(self.xy_mode_box, 0, wx.EXPAND)
- #x and y channel
- CHOOSER_WIDTH = 60
- CENTER_SPACING = 10
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- self.xy_mode_box.Add(hbox, 0, wx.EXPAND)
- choices = [('Ch%d'%(i+1), i) for i in range(parent.num_inputs)]
- self.channel_x_chooser = common.DropDownController(self, 'X
Ch', choices, parent, SCOPE_X_CHANNEL_KEY, (CHOOSER_WIDTH, -1))
- hbox.Add(self.channel_x_chooser, 0, wx.EXPAND)
- hbox.AddSpacer(CENTER_SPACING)
- self.channel_y_chooser = common.DropDownController(self, 'Y
Ch', choices, parent, SCOPE_Y_CHANNEL_KEY, (CHOOSER_WIDTH, -1))
- hbox.Add(self.channel_y_chooser, 0, wx.EXPAND)
- #div controls
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- self.xy_mode_box.Add(hbox, 0, wx.EXPAND)
- hbox.Add(wx.StaticText(self, -1, ' X/Div '), 1,
wx.ALIGN_CENTER_VERTICAL)
+ xy_mode_box = wx.BoxSizer(wx.VERTICAL)
+ control_box.Add(xy_mode_box, 0, wx.EXPAND)
+ #x div controls
x_buttons = common.IncrDecrButtons(self, self._on_incr_x_divs,
self._on_decr_x_divs)
- parent.subscribe(AUTORANGE_KEY, x_buttons.Disable)
- hbox.Add(x_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
- hbox.AddSpacer(CENTER_SPACING)
- hbox.Add(wx.StaticText(self, -1, ' Y/Div '), 1,
wx.ALIGN_CENTER_VERTICAL)
+ parent.subscribe(AUTORANGE_KEY, lambda x: x_buttons.Enable(not
x))
+ xy_mode_box.Add(common.LabelBox(self, 'X/Div', x_buttons), 0,
wx.EXPAND)
+ #y div controls
y_buttons = common.IncrDecrButtons(self, self._on_incr_y_divs,
self._on_decr_y_divs)
- parent.subscribe(AUTORANGE_KEY, y_buttons.Disable)
- hbox.Add(y_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
- #offset controls
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- self.xy_mode_box.Add(hbox, 0, wx.EXPAND)
- hbox.Add(wx.StaticText(self, -1, ' X Off '), 1,
wx.ALIGN_CENTER_VERTICAL)
+ parent.subscribe(AUTORANGE_KEY, lambda x: y_buttons.Enable(not
x))
+ xy_mode_box.Add(common.LabelBox(self, 'Y/Div', y_buttons), 0,
wx.EXPAND)
+ #x offset controls
x_off_buttons = common.IncrDecrButtons(self,
self._on_incr_x_off, self._on_decr_x_off)
- parent.subscribe(AUTORANGE_KEY, x_off_buttons.Disable)
- hbox.Add(x_off_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
- hbox.AddSpacer(CENTER_SPACING)
- hbox.Add(wx.StaticText(self, -1, ' Y Off '), 1,
wx.ALIGN_CENTER_VERTICAL)
+ parent.subscribe(AUTORANGE_KEY, lambda x:
x_off_buttons.Enable(not x))
+ xy_mode_box.Add(common.LabelBox(self, 'X Off', x_off_buttons),
0, wx.EXPAND)
+ #y offset controls
y_off_buttons = common.IncrDecrButtons(self,
self._on_incr_y_off, self._on_decr_y_off)
- parent.subscribe(AUTORANGE_KEY, y_off_buttons.Disable)
- hbox.Add(y_off_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
- ##################################################
- # End Special Boxes
- ##################################################
- #misc options
- control_box.AddStretchSpacer()
- control_box.Add(common.LabelText(self, 'Range Options'), 0,
wx.ALIGN_CENTER)
- #ac couple check box
- self.ac_couple_check_box = common.CheckBoxController(self, 'AC
Couple', parent, AC_COUPLE_KEY)
- control_box.Add(self.ac_couple_check_box, 0, wx.ALIGN_LEFT)
+ parent.subscribe(AUTORANGE_KEY, lambda x:
y_off_buttons.Enable(not x))
+ xy_mode_box.Add(common.LabelBox(self, 'Y Off', y_off_buttons),
0, wx.EXPAND)
+ xy_mode_box.ShowItems(False)
#autorange check box
self.autorange_check_box = common.CheckBoxController(self,
'Autorange', parent, AUTORANGE_KEY)
control_box.Add(self.autorange_check_box, 0, wx.ALIGN_LEFT)
- #marker
control_box.AddStretchSpacer()
- self.marker_chooser = common.DropDownController(self, 'Marker',
MARKER_TYPES, parent, MARKER_KEY)
- control_box.Add(self.marker_chooser, 0, wx.EXPAND)
- #xy mode
- control_box.AddStretchSpacer()
- self.scope_xy_mode_button = common.ToggleButtonController(self,
parent, SCOPE_XY_MODE_KEY, 'Scope Mode', 'X:Y Mode')
- parent.subscribe(SCOPE_XY_MODE_KEY, self._on_scope_xy_mode)
- control_box.Add(self.scope_xy_mode_button, 0, wx.EXPAND)
+ ##################################################
+ # Channel Options
+ ##################################################
+ TRIGGER_PAGE_INDEX = parent.num_inputs
+ XY_PAGE_INDEX = parent.num_inputs+1
+ control_box.Add(common.LabelText(self, 'Channel Options'), 0,
wx.ALIGN_CENTER)
+ control_box.AddSpacer(2)
+ options_notebook = wx.Notebook(self)
+ control_box.Add(options_notebook, 0, wx.EXPAND)
+ def options_notebook_changed(evt):
+ try:
+ parent[TRIGGER_SHOW_KEY] =
options_notebook.GetSelection() == TRIGGER_PAGE_INDEX
+ parent[XY_MODE_KEY] =
options_notebook.GetSelection() == XY_PAGE_INDEX
+ except wx.PyDeadObjectError: pass
+ options_notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED,
options_notebook_changed)
+ def xy_mode_changed(mode):
+ #ensure xy tab is selected
+ if mode and options_notebook.GetSelection() !=
XY_PAGE_INDEX:
+ options_notebook.SetSelection(XY_PAGE_INDEX)
+ #ensure xy tab is not selected
+ elif not mode and options_notebook.GetSelection() ==
XY_PAGE_INDEX:
+ options_notebook.SetSelection(0)
+ #show/hide control buttons
+ scope_mode_box.ShowItems(not mode)
+ xy_mode_box.ShowItems(mode)
+ control_box.Layout()
+ parent.subscribe(XY_MODE_KEY, xy_mode_changed)
+ ##################################################
+ # Channel Menu Boxes
+ ##################################################
+ for i in range(parent.num_inputs):
+ channel_menu_panel = wx.Panel(options_notebook)
+ options_notebook.AddPage(channel_menu_panel,
'Ch%d'%(i+1))
+ channel_menu_box = wx.BoxSizer(wx.VERTICAL)
+ channel_menu_panel.SetSizer(channel_menu_box)
+ #ac couple check box
+ channel_menu_box.AddStretchSpacer()
+ coupling_chooser =
common.DropDownController(channel_menu_panel, COUPLING_MODES, parent,
common.index_key(AC_COUPLE_KEY, i), SIZE)
+
channel_menu_box.Add(common.LabelBox(channel_menu_panel, 'Coupling',
coupling_chooser), 0, wx.EXPAND)
+ #marker
+ channel_menu_box.AddStretchSpacer()
+ marker_chooser =
common.DropDownController(channel_menu_panel, MARKER_TYPES, parent,
common.index_key(MARKER_KEY, i), SIZE)
+
channel_menu_box.Add(common.LabelBox(channel_menu_panel, 'Marker',
marker_chooser), 0, wx.EXPAND)
+ channel_menu_box.AddStretchSpacer()
+ ##################################################
+ # Trigger Menu Box
+ ##################################################
+ trigger_menu_panel = wx.Panel(options_notebook)
+ options_notebook.AddPage(trigger_menu_panel, 'Trig')
+ trigger_menu_box = wx.BoxSizer(wx.VERTICAL)
+ trigger_menu_panel.SetSizer(trigger_menu_box)
+ #trigger mode
+ trigger_mode_chooser =
common.DropDownController(trigger_menu_panel, TRIGGER_MODES, parent,
TRIGGER_MODE_KEY, SIZE)
+ trigger_menu_box.Add(common.LabelBox(trigger_menu_panel,
'Mode', trigger_mode_chooser), 0, wx.EXPAND)
+ #trigger slope
+ trigger_slope_chooser =
common.DropDownController(trigger_menu_panel, TRIGGER_SLOPES, parent,
TRIGGER_SLOPE_KEY, SIZE)
+ parent.subscribe(TRIGGER_MODE_KEY, lambda x:
trigger_slope_chooser.Enable(x!=gr.gr_TRIG_MODE_FREE))
+ trigger_menu_box.Add(common.LabelBox(trigger_menu_panel,
'Slope', trigger_slope_chooser), 0, wx.EXPAND)
+ #trigger channel
+ choices = [('Channel %d'%(i+1), i) for i in
range(parent.num_inputs)]
+ trigger_channel_chooser =
common.DropDownController(trigger_menu_panel, choices, parent,
TRIGGER_CHANNEL_KEY, SIZE)
+ parent.subscribe(TRIGGER_MODE_KEY, lambda x:
trigger_channel_chooser.Enable(x!=gr.gr_TRIG_MODE_FREE))
+ trigger_menu_box.Add(common.LabelBox(trigger_menu_panel,
'Channel', trigger_channel_chooser), 0, wx.EXPAND)
+ #trigger level
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ trigger_menu_box.Add(hbox, 0, wx.EXPAND)
+ hbox.Add(wx.StaticText(trigger_menu_panel, label=' Level '), 1,
wx.ALIGN_CENTER_VERTICAL)
+ trigger_level_button = wx.Button(trigger_menu_panel,
label='50%', style=wx.BU_EXACTFIT)
+ parent.subscribe(TRIGGER_MODE_KEY, lambda x:
trigger_level_button.Enable(x!=gr.gr_TRIG_MODE_FREE))
+ trigger_level_button.Bind(wx.EVT_BUTTON,
self.parent.set_auto_trigger_level)
+ hbox.Add(trigger_level_button, 0, wx.ALIGN_CENTER_VERTICAL)
+ hbox.AddSpacer(10)
+ trigger_level_buttons =
common.IncrDecrButtons(trigger_menu_panel, self._on_incr_trigger_level,
self._on_decr_trigger_level)
+ parent.subscribe(TRIGGER_MODE_KEY, lambda x:
trigger_level_buttons.Enable(x!=gr.gr_TRIG_MODE_FREE))
+ hbox.Add(trigger_level_buttons, 0, wx.ALIGN_CENTER_VERTICAL)
+ ##################################################
+ # XY Menu Box
+ ##################################################
+ if parent.num_inputs > 1:
+ xy_menu_panel = wx.Panel(options_notebook)
+ options_notebook.AddPage(xy_menu_panel, 'XY')
+ xy_menu_box = wx.BoxSizer(wx.VERTICAL)
+ xy_menu_panel.SetSizer(xy_menu_box)
+ #x and y channel choosers
+ xy_menu_box.AddStretchSpacer()
+ choices = [('Ch%d'%(i+1), i) for i in
range(parent.num_inputs)]
+ x_channel_chooser =
common.DropDownController(xy_menu_panel, choices, parent, X_CHANNEL_KEY, SIZE)
+ xy_menu_box.Add(common.LabelBox(xy_menu_panel, 'Ch X',
x_channel_chooser), 0, wx.EXPAND)
+ xy_menu_box.AddStretchSpacer()
+ y_channel_chooser =
common.DropDownController(xy_menu_panel, choices, parent, Y_CHANNEL_KEY, SIZE)
+ xy_menu_box.Add(common.LabelBox(xy_menu_panel, 'Ch Y',
y_channel_chooser), 0, wx.EXPAND)
+ #marker
+ xy_menu_box.AddStretchSpacer()
+ marker_chooser =
common.DropDownController(xy_menu_panel, MARKER_TYPES, parent, XY_MARKER_KEY,
SIZE)
+ xy_menu_box.Add(common.LabelBox(xy_menu_panel,
'Marker', marker_chooser), 0, wx.EXPAND)
+ xy_menu_box.AddStretchSpacer()
+ ##################################################
+ # Run/Stop Button
+ ##################################################
#run/stop
self.run_button = common.ToggleButtonController(self, parent,
RUNNING_KEY, 'Stop', 'Run')
control_box.Add(self.run_button, 0, wx.EXPAND)
#set sizer
self.SetSizerAndFit(control_box)
+ #mouse wheel event
+ def on_mouse_wheel(event):
+ if not parent[XY_MODE_KEY]:
+ if event.GetWheelRotation() < 0:
self._on_incr_t_divs(event)
+ else: self._on_decr_t_divs(event)
+ parent.plotter.Bind(wx.EVT_MOUSEWHEEL, on_mouse_wheel)
##################################################
# Event handlers
##################################################
- def _on_scope_xy_mode(self, mode):
- self.scope_mode_box.ShowItems(not mode)
- self.xy_mode_box.ShowItems(mode)
- self.control_box.Layout()
+ #trigger level
+ def _on_incr_trigger_level(self, event):
+ self.parent[TRIGGER_LEVEL_KEY] += self.parent[Y_PER_DIV_KEY]/3.
+ def _on_decr_trigger_level(self, event):
+ self.parent[TRIGGER_LEVEL_KEY] -= self.parent[Y_PER_DIV_KEY]/3.
#incr/decr divs
def _on_incr_t_divs(self, event):
- self.parent.set_t_per_div(
- common.get_clean_incr(self.parent[T_PER_DIV_KEY]))
+ self.parent[T_PER_DIV_KEY] =
common.get_clean_incr(self.parent[T_PER_DIV_KEY])
def _on_decr_t_divs(self, event):
- self.parent.set_t_per_div(
- common.get_clean_decr(self.parent[T_PER_DIV_KEY]))
+ self.parent[T_PER_DIV_KEY] =
common.get_clean_decr(self.parent[T_PER_DIV_KEY])
def _on_incr_x_divs(self, event):
- self.parent.set_x_per_div(
- common.get_clean_incr(self.parent[X_PER_DIV_KEY]))
+ self.parent[X_PER_DIV_KEY] =
common.get_clean_incr(self.parent[X_PER_DIV_KEY])
def _on_decr_x_divs(self, event):
- self.parent.set_x_per_div(
- common.get_clean_decr(self.parent[X_PER_DIV_KEY]))
+ self.parent[X_PER_DIV_KEY] =
common.get_clean_decr(self.parent[X_PER_DIV_KEY])
def _on_incr_y_divs(self, event):
- self.parent.set_y_per_div(
- common.get_clean_incr(self.parent[Y_PER_DIV_KEY]))
+ self.parent[Y_PER_DIV_KEY] =
common.get_clean_incr(self.parent[Y_PER_DIV_KEY])
def _on_decr_y_divs(self, event):
- self.parent.set_y_per_div(
- common.get_clean_decr(self.parent[Y_PER_DIV_KEY]))
+ self.parent[Y_PER_DIV_KEY] =
common.get_clean_decr(self.parent[Y_PER_DIV_KEY])
#incr/decr offset
- def _on_incr_t_off(self, event):
- self.parent.set_t_off(
- self.parent[T_OFF_KEY] + self.parent[T_PER_DIV_KEY])
- def _on_decr_t_off(self, event):
- self.parent.set_t_off(
- self.parent[T_OFF_KEY] - self.parent[T_PER_DIV_KEY])
def _on_incr_x_off(self, event):
- self.parent.set_x_off(
- self.parent[X_OFF_KEY] + self.parent[X_PER_DIV_KEY])
+ self.parent[X_OFF_KEY] = self.parent[X_OFF_KEY] +
self.parent[X_PER_DIV_KEY]
def _on_decr_x_off(self, event):
- self.parent.set_x_off(
- self.parent[X_OFF_KEY] - self.parent[X_PER_DIV_KEY])
+ self.parent[X_OFF_KEY] = self.parent[X_OFF_KEY] -
self.parent[X_PER_DIV_KEY]
def _on_incr_y_off(self, event):
- self.parent.set_y_off(
- self.parent[Y_OFF_KEY] + self.parent[Y_PER_DIV_KEY])
+ self.parent[Y_OFF_KEY] = self.parent[Y_OFF_KEY] +
self.parent[Y_PER_DIV_KEY]
def _on_decr_y_off(self, event):
- self.parent.set_y_off(
- self.parent[Y_OFF_KEY] - self.parent[Y_PER_DIV_KEY])
+ self.parent[Y_OFF_KEY] = self.parent[Y_OFF_KEY] -
self.parent[Y_PER_DIV_KEY]
##################################################
# Scope window with plotter and control panel
##################################################
-class scope_window(wx.Panel, pubsub.pubsub, common.prop_setter):
+class scope_window(wx.Panel, pubsub.pubsub):
def __init__(
self,
parent,
@@ -259,11 +296,13 @@
sample_rate_key,
t_scale,
v_scale,
- ac_couple,
xy_mode,
- scope_trigger_level_key,
- scope_trigger_mode_key,
- scope_trigger_channel_key,
+ ac_couple_key,
+ trigger_level_key,
+ trigger_mode_key,
+ trigger_slope_key,
+ trigger_channel_key,
+ decimation_key,
msg_key,
):
pubsub.pubsub.__init__(self)
@@ -271,67 +310,73 @@
assert num_inputs <= len(CHANNEL_COLOR_SPECS)
#setup
self.sampleses = None
- self.ext_controller = controller
self.num_inputs = num_inputs
- self.sample_rate_key = sample_rate_key
- autorange = v_scale is None
+ autorange = not v_scale
self.autorange_ts = 0
- if v_scale is None: v_scale = 1
+ v_scale = v_scale or 1
self.frame_rate_ts = 0
- self._init = False #HACK
- #scope keys
- self.scope_trigger_level_key = scope_trigger_level_key
- self.scope_trigger_mode_key = scope_trigger_mode_key
- self.scope_trigger_channel_key = scope_trigger_channel_key
+ #proxy the keys
+ self.proxy(MSG_KEY, controller, msg_key)
+ self.proxy(SAMPLE_RATE_KEY, controller, sample_rate_key)
+ self.proxy(TRIGGER_LEVEL_KEY, controller, trigger_level_key)
+ self.proxy(TRIGGER_MODE_KEY, controller, trigger_mode_key)
+ self.proxy(TRIGGER_SLOPE_KEY, controller, trigger_slope_key)
+ self.proxy(TRIGGER_CHANNEL_KEY, controller, trigger_channel_key)
+ self.proxy(DECIMATION_KEY, controller, decimation_key)
+ 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
- wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
+ wx.Panel.__init__(self, parent, style=wx.SIMPLE_BORDER)
self.plotter = plotter.channel_plotter(self)
self.plotter.SetSize(wx.Size(*size))
self.plotter.set_title(title)
self.plotter.enable_legend(True)
self.plotter.enable_point_label(True)
+ self.plotter.enable_grid_lines(True)
#setup the box with plot and controls
self.control_panel = control_panel(self)
main_box = wx.BoxSizer(wx.HORIZONTAL)
main_box.Add(self.plotter, 1, wx.EXPAND)
main_box.Add(self.control_panel, 0, wx.EXPAND)
self.SetSizerAndFit(main_box)
- #initial setup
- self._register_set_prop(self, RUNNING_KEY, True)
- self._register_set_prop(self, AC_COUPLE_KEY, ac_couple)
- self._register_set_prop(self, SCOPE_XY_MODE_KEY, xy_mode)
- self._register_set_prop(self, AUTORANGE_KEY, autorange)
- self._register_set_prop(self, T_PER_DIV_KEY, t_scale)
- self._register_set_prop(self, X_PER_DIV_KEY, v_scale)
- self._register_set_prop(self, Y_PER_DIV_KEY, v_scale)
- self._register_set_prop(self, T_OFF_KEY, 0)
- self._register_set_prop(self, X_OFF_KEY, 0)
- self._register_set_prop(self, Y_OFF_KEY, 0)
- self._register_set_prop(self, T_DIVS_KEY, 8)
- self._register_set_prop(self, X_DIVS_KEY, 8)
- self._register_set_prop(self, Y_DIVS_KEY, 8)
- self._register_set_prop(self, SCOPE_X_CHANNEL_KEY, 0)
- self._register_set_prop(self, SCOPE_Y_CHANNEL_KEY, num_inputs-1)
- self._register_set_prop(self, FRAME_RATE_KEY, frame_rate)
- self._register_set_prop(self, TRIGGER_CHANNEL_KEY, 0)
- self._register_set_prop(self, TRIGGER_MODE_KEY, 1)
- self._register_set_prop(self, TRIGGER_LEVEL_KEY, None)
- self._register_set_prop(self, MARKER_KEY, DEFAULT_MARKER_TYPE)
- #register events
- self.ext_controller.subscribe(msg_key, self.handle_msg)
- for key in (
+ #initialize values
+ self[RUNNING_KEY] = True
+ for i in range(self.num_inputs):
+ self[common.index_key(AC_COUPLE_KEY, i)] =
self[common.index_key(AC_COUPLE_KEY, i)]
+ self[common.index_key(MARKER_KEY, i)] =
DEFAULT_MARKER_TYPE
+ self[XY_MARKER_KEY] = 2.0
+ self[XY_MODE_KEY] = xy_mode
+ self[X_CHANNEL_KEY] = 0
+ self[Y_CHANNEL_KEY] = self.num_inputs-1
+ self[AUTORANGE_KEY] = autorange
+ self[T_PER_DIV_KEY] = t_scale
+ 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[T_DIVS_KEY] = 8
+ self[X_DIVS_KEY] = 8
+ self[Y_DIVS_KEY] = 8
+ self[FRAME_RATE_KEY] = frame_rate
+ self[TRIGGER_LEVEL_KEY] = 0
+ self[TRIGGER_CHANNEL_KEY] = 0
+ 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
+ #register events for message
+ self.subscribe(MSG_KEY, self.handle_msg)
+ #register events for grid
+ for key in [common.index_key(MARKER_KEY, i) for i in
range(self.num_inputs)] + [
+ TRIGGER_LEVEL_KEY, TRIGGER_MODE_KEY,
T_PER_DIV_KEY, X_PER_DIV_KEY, Y_PER_DIV_KEY,
T_OFF_KEY, X_OFF_KEY, Y_OFF_KEY,
T_DIVS_KEY, X_DIVS_KEY, Y_DIVS_KEY,
- SCOPE_XY_MODE_KEY,
- SCOPE_X_CHANNEL_KEY,
- SCOPE_Y_CHANNEL_KEY,
- AUTORANGE_KEY,
- AC_COUPLE_KEY,
- MARKER_KEY,
- ): self.subscribe(key, self.update_grid)
- #initial update, dont do this here, wait for handle_msg #HACK
- #self.update_grid()
+ 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)
+ #initial update
+ self.update_grid()
def handle_msg(self, msg):
"""
@@ -345,15 +390,23 @@
if time.time() - self.frame_rate_ts < 1.0/self[FRAME_RATE_KEY]:
return
#convert to floating point numbers
samples = numpy.fromstring(msg, numpy.float32)
+ #extract the trigger offset
+ self.trigger_offset = samples[-1]
+ samples = samples[:-1]
samps_per_ch = len(samples)/self.num_inputs
self.sampleses = [samples[samps_per_ch*i:samps_per_ch*(i+1)]
for i in range(self.num_inputs)]
- if not self._init: #HACK
- self._init = True
- self.update_grid()
#handle samples
self.handle_samples()
self.frame_rate_ts = time.time()
+ def set_auto_trigger_level(self, *args):
+ """
+ Use the current trigger channel and samples to calculate the
50% level.
+ """
+ if not self.sampleses: return
+ samples = self.sampleses[self[TRIGGER_CHANNEL_KEY]]
+ self[TRIGGER_LEVEL_KEY] =
(numpy.max(samples)+numpy.min(samples))/2
+
def handle_samples(self):
"""
Handle the cached samples from the scope input.
@@ -361,52 +414,37 @@
"""
if not self.sampleses: return
sampleses = self.sampleses
- #trigger level (must do before ac coupling)
- self.ext_controller[self.scope_trigger_channel_key] =
self[TRIGGER_CHANNEL_KEY]
- self.ext_controller[self.scope_trigger_mode_key] =
self[TRIGGER_MODE_KEY]
- trigger_level = self[TRIGGER_LEVEL_KEY]
- if trigger_level is None:
self.ext_controller[self.scope_trigger_level_key] = ''
- else:
- samples = sampleses[self[TRIGGER_CHANNEL_KEY]]
- self.ext_controller[self.scope_trigger_level_key] = \
- trigger_level*(numpy.max(samples)-numpy.min(samples))/2
+ numpy.average(samples)
- #ac coupling
- if self[AC_COUPLE_KEY]:
- sampleses = [samples - numpy.average(samples) for
samples in sampleses]
- if self[SCOPE_XY_MODE_KEY]:
- x_samples = sampleses[self[SCOPE_X_CHANNEL_KEY]]
- y_samples = sampleses[self[SCOPE_Y_CHANNEL_KEY]]
+ if self[XY_MODE_KEY]:
+ self[DECIMATION_KEY] = 1
+ x_samples = sampleses[self[X_CHANNEL_KEY]]
+ y_samples = sampleses[self[Y_CHANNEL_KEY]]
#autorange
if self[AUTORANGE_KEY] and time.time() -
self.autorange_ts > AUTORANGE_UPDATE_RATE:
x_min, x_max = common.get_min_max(x_samples)
y_min, y_max = common.get_min_max(y_samples)
#adjust the x per div
x_per_div =
common.get_clean_num((x_max-x_min)/self[X_DIVS_KEY])
- if x_per_div != self[X_PER_DIV_KEY]:
self.set_x_per_div(x_per_div)
+ if x_per_div != self[X_PER_DIV_KEY]:
self[X_PER_DIV_KEY] = x_per_div; return
#adjust the x offset
x_off =
x_per_div*round((x_max+x_min)/2/x_per_div)
- if x_off != self[X_OFF_KEY]:
self.set_x_off(x_off)
+ if x_off != self[X_OFF_KEY]: self[X_OFF_KEY] =
x_off; return
#adjust the y per div
y_per_div =
common.get_clean_num((y_max-y_min)/self[Y_DIVS_KEY])
- if y_per_div != self[Y_PER_DIV_KEY]:
self.set_y_per_div(y_per_div)
+ if y_per_div != self[Y_PER_DIV_KEY]:
self[Y_PER_DIV_KEY] = y_per_div; return
#adjust the y offset
y_off =
y_per_div*round((y_max+y_min)/2/y_per_div)
- if y_off != self[Y_OFF_KEY]:
self.set_y_off(y_off)
+ if y_off != self[Y_OFF_KEY]: self[Y_OFF_KEY] =
y_off; return
self.autorange_ts = time.time()
#plot xy channel
self.plotter.set_waveform(
channel='XY',
samples=(x_samples, y_samples),
color_spec=CHANNEL_COLOR_SPECS[0],
- marker=self[MARKER_KEY],
+ marker=self[XY_MARKER_KEY],
)
#turn off each waveform
for i, samples in enumerate(sampleses):
- self.plotter.set_waveform(
- channel='Ch%d'%(i+1),
- samples=[],
- color_spec=CHANNEL_COLOR_SPECS[i],
- )
+
self.plotter.clear_waveform(channel='Ch%d'%(i+1))
else:
#autorange
if self[AUTORANGE_KEY] and time.time() -
self.autorange_ts > AUTORANGE_UPDATE_RATE:
@@ -415,86 +453,89 @@
y_max = numpy.max([bound[1] for bound in
bounds])
#adjust the y per div
y_per_div =
common.get_clean_num((y_max-y_min)/self[Y_DIVS_KEY])
- if y_per_div != self[Y_PER_DIV_KEY]:
self.set_y_per_div(y_per_div)
+ if y_per_div != self[Y_PER_DIV_KEY]:
self[Y_PER_DIV_KEY] = y_per_div; return
#adjust the y offset
y_off =
y_per_div*round((y_max+y_min)/2/y_per_div)
- if y_off != self[Y_OFF_KEY]:
self.set_y_off(y_off)
+ if y_off != self[Y_OFF_KEY]: self[Y_OFF_KEY] =
y_off; return
self.autorange_ts = time.time()
- #plot each waveform
- for i, samples in enumerate(sampleses):
- #number of samples to scale to the screen
- num_samps =
int(self[T_PER_DIV_KEY]*self[T_DIVS_KEY]*self.ext_controller[self.sample_rate_key])
- #handle num samps out of bounds
- if num_samps > len(samples):
- self.set_t_per_div(
-
common.get_clean_decr(self[T_PER_DIV_KEY]))
- elif num_samps < 2:
- self.set_t_per_div(
-
common.get_clean_incr(self[T_PER_DIV_KEY]))
- num_samps = 0
- else:
+ #number of samples to scale to the screen
+ actual_rate = self.get_actual_rate()
+ time_span = self[T_PER_DIV_KEY]*self[T_DIVS_KEY]
+ num_samps = int(round(time_span*actual_rate))
+ #handle the time offset
+ t_off =
self[T_FRAC_OFF_KEY]*(len(sampleses[0])/actual_rate - time_span)
+ if t_off != self[T_OFF_KEY]: self[T_OFF_KEY] = t_off;
return
+ samps_off = int(round(actual_rate*self[T_OFF_KEY]))
+ #adjust the decim so that we use about half the samps
+ self[DECIMATION_KEY] = int(round(
+
time_span*self[SAMPLE_RATE_KEY]/(0.5*len(sampleses[0]))
+ )
+ )
+ #num samps too small, auto increment the time
+ if num_samps < 2: self[T_PER_DIV_KEY] =
common.get_clean_incr(self[T_PER_DIV_KEY])
+ #num samps in bounds, plot each waveform
+ elif num_samps <= len(sampleses[0]):
+ for i, samples in enumerate(sampleses):
#plot samples
self.plotter.set_waveform(
channel='Ch%d'%(i+1),
- samples=samples[:num_samps],
+
samples=samples[samps_off:num_samps+samps_off],
color_spec=CHANNEL_COLOR_SPECS[i],
- marker=self[MARKER_KEY],
+
marker=self[common.index_key(MARKER_KEY, i)],
+ trig_off=self.trigger_offset,
)
#turn XY channel off
+ self.plotter.clear_waveform(channel='XY')
+ #keep trigger level within range
+ if self[TRIGGER_LEVEL_KEY] > self.get_y_max():
+ self[TRIGGER_LEVEL_KEY] = self.get_y_max(); return
+ if self[TRIGGER_LEVEL_KEY] < self.get_y_min():
+ self[TRIGGER_LEVEL_KEY] = self.get_y_min(); return
+ #disable the trigger channel
+ if not self[TRIGGER_SHOW_KEY] or self[XY_MODE_KEY] or
self[TRIGGER_MODE_KEY] == gr.gr_TRIG_MODE_FREE:
+ self.plotter.clear_waveform(channel='Trig')
+ else: #show trigger channel
+ trigger_level = self[TRIGGER_LEVEL_KEY]
+ trigger_point =
(len(self.sampleses[0])-1)/self.get_actual_rate()/2.0
self.plotter.set_waveform(
- channel='XY',
- samples=[],
- color_spec=CHANNEL_COLOR_SPECS[0],
+ channel='Trig',
+ samples=(
+ [self.get_t_min(), trigger_point,
trigger_point, trigger_point, trigger_point, self.get_t_max()],
+ [trigger_level, trigger_level,
self.get_y_max(), self.get_y_min(), trigger_level, trigger_level]
+ ),
+ color_spec=TRIGGER_COLOR_SPEC,
)
#update the plotter
self.plotter.update()
+ def get_actual_rate(self): return
1.0*self[SAMPLE_RATE_KEY]/self[DECIMATION_KEY]
+ def get_t_min(self): return self[T_OFF_KEY]
+ def get_t_max(self): return self[T_PER_DIV_KEY]*self[T_DIVS_KEY] +
self[T_OFF_KEY]
+ def get_x_min(self): return -1*self[X_PER_DIV_KEY]*self[X_DIVS_KEY]/2.0
+ self[X_OFF_KEY]
+ def get_x_max(self): return self[X_PER_DIV_KEY]*self[X_DIVS_KEY]/2.0 +
self[X_OFF_KEY]
+ def get_y_min(self): return -1*self[Y_PER_DIV_KEY]*self[Y_DIVS_KEY]/2.0
+ self[Y_OFF_KEY]
+ def get_y_max(self): return self[Y_PER_DIV_KEY]*self[Y_DIVS_KEY]/2.0 +
self[Y_OFF_KEY]
+
def update_grid(self, *args):
"""
Update the grid to reflect the current settings:
xy divisions, xy offset, xy mode setting
"""
- #grid parameters
- t_per_div = self[T_PER_DIV_KEY]
- x_per_div = self[X_PER_DIV_KEY]
- y_per_div = self[Y_PER_DIV_KEY]
- t_off = self[T_OFF_KEY]
- x_off = self[X_OFF_KEY]
- y_off = self[Y_OFF_KEY]
- t_divs = self[T_DIVS_KEY]
- x_divs = self[X_DIVS_KEY]
- y_divs = self[Y_DIVS_KEY]
- if self[SCOPE_XY_MODE_KEY]:
+ if self[T_FRAC_OFF_KEY] < 0: self[T_FRAC_OFF_KEY] = 0; return
+ if self[T_FRAC_OFF_KEY] > 1: self[T_FRAC_OFF_KEY] = 1; return
+ if self[XY_MODE_KEY]:
#update the x axis
-
self.plotter.set_x_label('Ch%d'%(self[SCOPE_X_CHANNEL_KEY]+1))
- self.plotter.set_x_grid(
- -1*x_per_div*x_divs/2.0 + x_off,
- x_per_div*x_divs/2.0 + x_off,
- x_per_div,
- )
+ self.plotter.set_x_label('Ch%d'%(self[X_CHANNEL_KEY]+1))
+ self.plotter.set_x_grid(self.get_x_min(),
self.get_x_max(), self[X_PER_DIV_KEY])
#update the y axis
-
self.plotter.set_y_label('Ch%d'%(self[SCOPE_Y_CHANNEL_KEY]+1))
- self.plotter.set_y_grid(
- -1*y_per_div*y_divs/2.0 + y_off,
- y_per_div*y_divs/2.0 + y_off,
- y_per_div,
- )
+ self.plotter.set_y_label('Ch%d'%(self[Y_CHANNEL_KEY]+1))
+ self.plotter.set_y_grid(self.get_y_min(),
self.get_y_max(), self[Y_PER_DIV_KEY])
else:
#update the t axis
- coeff, exp, prefix =
common.get_si_components(t_per_div*t_divs + t_off)
- self.plotter.set_x_label('Time', prefix+'s')
- self.plotter.set_x_grid(
- t_off,
- t_per_div*t_divs + t_off,
- t_per_div,
- 10**(-exp),
- )
+ self.plotter.set_x_label('Time', 's')
+ self.plotter.set_x_grid(self.get_t_min(),
self.get_t_max(), self[T_PER_DIV_KEY], True)
#update the y axis
self.plotter.set_y_label('Counts')
- self.plotter.set_y_grid(
- -1*y_per_div*y_divs/2.0 + y_off,
- y_per_div*y_divs/2.0 + y_off,
- y_per_div,
- )
+ self.plotter.set_y_grid(self.get_y_min(),
self.get_y_max(), self[Y_PER_DIV_KEY])
#redraw current sample
self.handle_samples()
Modified: gnuradio/trunk/gr-wxgui/src/python/scopesink2.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/scopesink2.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/scopesink2.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -38,7 +38,7 @@
except ImportError:
raise RuntimeError("Unable to import OpenGL. Are Python wrappers for
OpenGL installed?")
- from scopesink_gl import scope_sink_f, scope_sink_c, constellation_sink
+ from scopesink_gl import scope_sink_f, scope_sink_c
else:
- from scopesink_nongl import scope_sink_f, scope_sink_c, constellation_sink
+ from scopesink_nongl import scope_sink_f, scope_sink_c
Modified: gnuradio/trunk/gr-wxgui/src/python/scopesink_gl.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/scopesink_gl.py 2009-03-20 01:48:45 UTC
(rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/scopesink_gl.py 2009-03-20 02:16:20 UTC
(rev 10660)
@@ -28,10 +28,38 @@
from pubsub import pubsub
from constants import *
+class ac_couple_block(gr.hier_block2):
+ """
+ AC couple the incoming stream by subtracting out the low pass signal.
+ Mute the low pass filter to disable ac coupling.
+ """
+
+ def __init__(self, controller, ac_couple_key, ac_couple,
sample_rate_key):
+ gr.hier_block2.__init__(
+ self,
+ "ac_couple",
+ gr.io_signature(1, 1, gr.sizeof_float),
+ gr.io_signature(1, 1, gr.sizeof_float),
+ )
+ #blocks
+ copy = gr.kludge_copy(gr.sizeof_float)
+ lpf = gr.single_pole_iir_filter_ff(0.0)
+ sub = gr.sub_ff()
+ mute = gr.mute_ff()
+ #connect
+ self.connect(self, copy, sub, self)
+ self.connect(copy, lpf, mute, (sub, 1))
+ #subscribe
+ controller.subscribe(ac_couple_key, lambda x: mute.set_mute(not
x))
+ controller.subscribe(sample_rate_key, lambda x:
lpf.set_taps(2.0/x))
+ #initialize
+ controller[ac_couple_key] = ac_couple
+ controller[sample_rate_key] = controller[sample_rate_key]
+
##################################################
# Scope sink block (wrapper for old wxgui)
##################################################
-class _scope_sink_base(gr.hier_block2, common.prop_setter):
+class _scope_sink_base(gr.hier_block2):
"""
A scope block with a gui window.
"""
@@ -42,15 +70,14 @@
title='',
sample_rate=1,
size=scope_window.DEFAULT_WIN_SIZE,
- frame_decim=None, #ignore (old wrapper)
- v_scale=scope_window.DEFAULT_V_SCALE,
- t_scale=None,
+ v_scale=0,
+ t_scale=0,
+ xy_mode=False,
+ ac_couple=False,
num_inputs=1,
- ac_couple=False,
- xy_mode=False,
frame_rate=scope_window.DEFAULT_FRAME_RATE,
):
- if t_scale is None: t_scale = 0.001
+ if not t_scale: t_scale = 10.0/sample_rate
#init
gr.hier_block2.__init__(
self,
@@ -61,37 +88,41 @@
#scope
msgq = gr.msg_queue(2)
scope = gr.oscope_sink_f(sample_rate, msgq)
+ #controller
+ self.controller = pubsub()
+ self.controller.subscribe(SAMPLE_RATE_KEY,
scope.set_sample_rate)
+ self.controller.publish(SAMPLE_RATE_KEY, scope.sample_rate)
+ self.controller.subscribe(DECIMATION_KEY,
scope.set_decimation_count)
+ self.controller.publish(DECIMATION_KEY,
scope.get_decimation_count)
+ self.controller.subscribe(TRIGGER_LEVEL_KEY,
scope.set_trigger_level)
+ self.controller.publish(TRIGGER_LEVEL_KEY,
scope.get_trigger_level)
+ self.controller.subscribe(TRIGGER_MODE_KEY,
scope.set_trigger_mode)
+ self.controller.publish(TRIGGER_MODE_KEY,
scope.get_trigger_mode)
+ self.controller.subscribe(TRIGGER_SLOPE_KEY,
scope.set_trigger_slope)
+ self.controller.publish(TRIGGER_SLOPE_KEY,
scope.get_trigger_slope)
+ self.controller.subscribe(TRIGGER_CHANNEL_KEY,
scope.set_trigger_channel)
+ self.controller.publish(TRIGGER_CHANNEL_KEY,
scope.get_trigger_channel)
#connect
if self._real:
for i in range(num_inputs):
- self.connect((self, i), (scope, i))
+ self.connect(
+ (self, i),
+ ac_couple_block(self.controller,
common.index_key(AC_COUPLE_KEY, i), ac_couple, SAMPLE_RATE_KEY),
+ (scope, i),
+ )
else:
for i in range(num_inputs):
c2f = gr.complex_to_float()
self.connect((self, i), c2f)
- self.connect((c2f, 0), (scope, 2*i+0))
- self.connect((c2f, 1), (scope, 2*i+1))
+ for j in range(2):
+ self.connect(
+ (c2f, j),
+
ac_couple_block(self.controller, common.index_key(AC_COUPLE_KEY, 2*i+j),
ac_couple, SAMPLE_RATE_KEY),
+ (scope, 2*i+j),
+ )
num_inputs *= 2
- #controller
- self.controller = pubsub()
- self.controller.subscribe(SAMPLE_RATE_KEY,
scope.set_sample_rate)
- self.controller.publish(SAMPLE_RATE_KEY, scope.sample_rate)
- def set_trigger_level(level):
- if level == '': scope.set_trigger_level_auto()
- else: scope.set_trigger_level(level)
- self.controller.subscribe(SCOPE_TRIGGER_LEVEL_KEY,
set_trigger_level)
- def set_trigger_mode(mode):
- if mode == 0: mode = gr.gr_TRIG_AUTO
- elif mode < 0: mode = gr.gr_TRIG_NEG_SLOPE
- elif mode > 0: mode = gr.gr_TRIG_POS_SLOPE
- else: return
- scope.set_trigger_mode(mode)
- self.controller.subscribe(SCOPE_TRIGGER_MODE_KEY,
set_trigger_mode)
- self.controller.subscribe(SCOPE_TRIGGER_CHANNEL_KEY,
scope.set_trigger_channel)
#start input watcher
- def setter(p, k, x): # lambdas can't have assignments :(
- p[k] = x
- common.input_watcher(msgq, lambda x: setter(self.controller,
MSG_KEY, x))
+ common.input_watcher(msgq, self.controller, MSG_KEY)
#create window
self.win = scope_window.scope_window(
parent=parent,
@@ -103,21 +134,16 @@
sample_rate_key=SAMPLE_RATE_KEY,
t_scale=t_scale,
v_scale=v_scale,
- ac_couple=ac_couple,
xy_mode=xy_mode,
- scope_trigger_level_key=SCOPE_TRIGGER_LEVEL_KEY,
- scope_trigger_mode_key=SCOPE_TRIGGER_MODE_KEY,
- scope_trigger_channel_key=SCOPE_TRIGGER_CHANNEL_KEY,
+ ac_couple_key=AC_COUPLE_KEY,
+ trigger_level_key=TRIGGER_LEVEL_KEY,
+ trigger_mode_key=TRIGGER_MODE_KEY,
+ trigger_slope_key=TRIGGER_SLOPE_KEY,
+ trigger_channel_key=TRIGGER_CHANNEL_KEY,
+ decimation_key=DECIMATION_KEY,
msg_key=MSG_KEY,
)
- #register callbacks from window for external use
- for attr in filter(lambda a: a.startswith('set_'),
dir(self.win)):
- setattr(self, attr, getattr(self.win, attr))
- self._register_set_prop(self.controller, SAMPLE_RATE_KEY)
- #backwards compadibility
- self.win.set_format_line = lambda: setter(self.win, MARKER_KEY,
None)
- self.win.set_format_dot = lambda: setter(self.win, MARKER_KEY,
2.0)
- self.win.set_format_plus = lambda: setter(self.win,
MARKER_KEY, 3.0)
+ common.register_access_methods(self, self.win)
class scope_sink_f(_scope_sink_base):
_item_size = gr.sizeof_float
@@ -127,12 +153,6 @@
_item_size = gr.sizeof_gr_complex
_real = False
-#backwards compadible wrapper (maybe only grc uses this)
-class constellation_sink(scope_sink_c):
- def __init__(self, *args, **kwargs):
- scope_sink_c.__init__(self, *args, **kwargs)
- self.set_scope_xy_mode(True)
-
# ----------------------------------------------------------------
# Stand-alone test application
# ----------------------------------------------------------------
@@ -171,7 +191,6 @@
self.thr = gr.throttle(gr.sizeof_gr_complex, input_rate)
scope = scope_sink_c (panel,"Secret Data",sample_rate=input_rate,
- frame_decim=frame_decim,
v_scale=v_scale, t_scale=t_scale)
vbox.Add (scope.win, 1, wx.EXPAND)
Modified: gnuradio/trunk/gr-wxgui/src/python/scopesink_nongl.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/scopesink_nongl.py 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/scopesink_nongl.py 2009-03-20
02:16:20 UTC (rev 10660)
@@ -35,7 +35,7 @@
class scope_sink_f(gr.hier_block2):
def __init__(self, parent, title='', sample_rate=1,
size=default_scopesink_size, frame_decim=default_frame_decim,
- v_scale=default_v_scale, t_scale=None, num_inputs=1):
+ v_scale=default_v_scale, t_scale=None, num_inputs=1,
**kwargs):
gr.hier_block2.__init__(self, "scope_sink_f",
gr.io_signature(num_inputs, num_inputs,
gr.sizeof_float),
@@ -56,7 +56,7 @@
class scope_sink_c(gr.hier_block2):
def __init__(self, parent, title='', sample_rate=1,
size=default_scopesink_size, frame_decim=default_frame_decim,
- v_scale=default_v_scale, t_scale=None, num_inputs=1):
+ v_scale=default_v_scale, t_scale=None, num_inputs=1,
**kwargs):
gr.hier_block2.__init__(self, "scope_sink_c",
gr.io_signature(num_inputs, num_inputs,
gr.sizeof_gr_complex),
@@ -167,10 +167,7 @@
self.marker = 'line'
self.xy = xy
- if v_scale == None: # 0 and None are both False, but 0 != None
- self.autorange = True
- else:
- self.autorange = False # 0 is a valid v_scale
+ self.autorange = not v_scale
self.running = True
def get_time_per_div (self):
@@ -320,7 +317,8 @@
ctrlbox.Add (self.trig_chan_choice, 0, wx.ALIGN_CENTER)
self.trig_mode_choice = wx.Choice (self, 1005,
- choices = ['Auto', 'Pos', 'Neg'])
+ choices = ['Free', 'Auto', 'Norm'])
+ self.trig_mode_choice.SetSelection(1)
self.trig_mode_choice.SetToolTipString ("Select trigger slope or Auto
(untriggered roll)")
wx.EVT_CHOICE (self, 1005, self.trig_mode_choice_event)
ctrlbox.Add (self.trig_mode_choice, 0, wx.ALIGN_CENTER)
@@ -432,12 +430,12 @@
def trig_mode_choice_event (self, evt):
sink = self.info.scopesink
s = evt.GetString ()
- if s == 'Pos':
- sink.set_trigger_mode (gr.gr_TRIG_POS_SLOPE)
- elif s == 'Neg':
- sink.set_trigger_mode (gr.gr_TRIG_NEG_SLOPE)
+ if s == 'Norm':
+ sink.set_trigger_mode (gr.gr_TRIG_MODE_NORM)
elif s == 'Auto':
- sink.set_trigger_mode (gr.gr_TRIG_AUTO)
+ sink.set_trigger_mode (gr.gr_TRIG_MODE_AUTO)
+ elif s == 'Free':
+ sink.set_trigger_mode (gr.gr_TRIG_MODE_FREE)
else:
assert 0, "Bad trig_mode_choice string"
Modified: gnuradio/trunk/gr-wxgui/src/python/waterfall_window.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/waterfall_window.py 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/waterfall_window.py 2009-03-20
02:16:20 UTC (rev 10660)
@@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
+# Boston, MA 02110-1`301, USA.
#
##################################################
@@ -61,57 +61,57 @@
@param parent the wx parent window
"""
self.parent = parent
- wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
+ wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
control_box = wx.BoxSizer(wx.VERTICAL)
control_box.AddStretchSpacer()
control_box.Add(common.LabelText(self, 'Options'), 0,
wx.ALIGN_CENTER)
#color mode
control_box.AddStretchSpacer()
- self.color_mode_chooser = common.DropDownController(self,
'Color', COLOR_MODES, parent, COLOR_MODE_KEY)
- control_box.Add(self.color_mode_chooser, 0, wx.EXPAND)
+ color_mode_chooser = common.DropDownController(self,
COLOR_MODES, parent, COLOR_MODE_KEY)
+ control_box.Add(common.LabelBox(self, 'Color',
color_mode_chooser), 0, wx.EXPAND)
#average
control_box.AddStretchSpacer()
- self.average_check_box = common.CheckBoxController(self,
'Average', parent.ext_controller, parent.average_key)
- control_box.Add(self.average_check_box, 0, wx.EXPAND)
+ average_check_box = common.CheckBoxController(self, 'Average',
parent, AVERAGE_KEY)
+ control_box.Add(average_check_box, 0, wx.EXPAND)
control_box.AddSpacer(2)
- self.avg_alpha_slider = common.LogSliderController(
+ avg_alpha_slider = common.LogSliderController(
self, 'Avg Alpha',
AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP, SLIDER_STEPS,
- parent.ext_controller, parent.avg_alpha_key,
+ parent, AVG_ALPHA_KEY,
formatter=lambda x: ': %.4f'%x,
)
- parent.ext_controller.subscribe(parent.average_key,
self.avg_alpha_slider.Enable)
- control_box.Add(self.avg_alpha_slider, 0, wx.EXPAND)
+ parent.subscribe(AVERAGE_KEY, avg_alpha_slider.Enable)
+ control_box.Add(avg_alpha_slider, 0, wx.EXPAND)
#dyanmic range buttons
control_box.AddStretchSpacer()
control_box.Add(common.LabelText(self, 'Dynamic Range'), 0,
wx.ALIGN_CENTER)
control_box.AddSpacer(2)
- self._dynamic_range_buttons = common.IncrDecrButtons(self,
self._on_incr_dynamic_range, self._on_decr_dynamic_range)
- control_box.Add(self._dynamic_range_buttons, 0, wx.ALIGN_CENTER)
+ dynamic_range_buttons = common.IncrDecrButtons(self,
self._on_incr_dynamic_range, self._on_decr_dynamic_range)
+ control_box.Add(dynamic_range_buttons, 0, wx.ALIGN_CENTER)
#ref lvl buttons
control_box.AddStretchSpacer()
control_box.Add(common.LabelText(self, 'Set Ref Level'), 0,
wx.ALIGN_CENTER)
control_box.AddSpacer(2)
- self._ref_lvl_buttons = common.IncrDecrButtons(self,
self._on_incr_ref_level, self._on_decr_ref_level)
- control_box.Add(self._ref_lvl_buttons, 0, wx.ALIGN_CENTER)
+ ref_lvl_buttons = common.IncrDecrButtons(self,
self._on_incr_ref_level, self._on_decr_ref_level)
+ control_box.Add(ref_lvl_buttons, 0, wx.ALIGN_CENTER)
#num lines buttons
control_box.AddStretchSpacer()
control_box.Add(common.LabelText(self, 'Set Time Scale'), 0,
wx.ALIGN_CENTER)
control_box.AddSpacer(2)
- self._time_scale_buttons = common.IncrDecrButtons(self,
self._on_incr_time_scale, self._on_decr_time_scale)
- control_box.Add(self._time_scale_buttons, 0, wx.ALIGN_CENTER)
+ time_scale_buttons = common.IncrDecrButtons(self,
self._on_incr_time_scale, self._on_decr_time_scale)
+ control_box.Add(time_scale_buttons, 0, wx.ALIGN_CENTER)
#autoscale
control_box.AddStretchSpacer()
- self.autoscale_button = wx.Button(self, label='Autoscale',
style=wx.BU_EXACTFIT)
- self.autoscale_button.Bind(wx.EVT_BUTTON, self.parent.autoscale)
- control_box.Add(self.autoscale_button, 0, wx.EXPAND)
+ autoscale_button = wx.Button(self, label='Autoscale',
style=wx.BU_EXACTFIT)
+ autoscale_button.Bind(wx.EVT_BUTTON, self.parent.autoscale)
+ control_box.Add(autoscale_button, 0, wx.EXPAND)
#clear
- self.clear_button = wx.Button(self, label='Clear',
style=wx.BU_EXACTFIT)
- self.clear_button.Bind(wx.EVT_BUTTON, self._on_clear_button)
- control_box.Add(self.clear_button, 0, wx.EXPAND)
+ clear_button = wx.Button(self, label='Clear',
style=wx.BU_EXACTFIT)
+ clear_button.Bind(wx.EVT_BUTTON, self._on_clear_button)
+ control_box.Add(clear_button, 0, wx.EXPAND)
#run/stop
- self.run_button = common.ToggleButtonController(self, parent,
RUNNING_KEY, 'Stop', 'Run')
- control_box.Add(self.run_button, 0, wx.EXPAND)
+ run_button = common.ToggleButtonController(self, parent,
RUNNING_KEY, 'Stop', 'Run')
+ control_box.Add(run_button, 0, wx.EXPAND)
#set sizer
self.SetSizerAndFit(control_box)
@@ -119,34 +119,30 @@
# Event handlers
##################################################
def _on_clear_button(self, event):
- self.parent.set_num_lines(self.parent[NUM_LINES_KEY])
+ self.parent[NUM_LINES_KEY] = self.parent[NUM_LINES_KEY]
def _on_incr_dynamic_range(self, event):
- self.parent.set_dynamic_range(
- min(self.parent[DYNAMIC_RANGE_KEY] + 10,
MAX_DYNAMIC_RANGE))
+ self.parent[DYNAMIC_RANGE_KEY] =
min(self.parent[DYNAMIC_RANGE_KEY] + 10, MAX_DYNAMIC_RANGE)
def _on_decr_dynamic_range(self, event):
- self.parent.set_dynamic_range(
- max(self.parent[DYNAMIC_RANGE_KEY] - 10,
MIN_DYNAMIC_RANGE))
+ self.parent[DYNAMIC_RANGE_KEY] =
max(self.parent[DYNAMIC_RANGE_KEY] - 10, MIN_DYNAMIC_RANGE)
def _on_incr_ref_level(self, event):
- self.parent.set_ref_level(
- self.parent[REF_LEVEL_KEY] +
self.parent[DYNAMIC_RANGE_KEY]*.1)
+ self.parent[REF_LEVEL_KEY] = self.parent[REF_LEVEL_KEY] +
self.parent[DYNAMIC_RANGE_KEY]*.1
def _on_decr_ref_level(self, event):
- self.parent.set_ref_level(
- self.parent[REF_LEVEL_KEY] -
self.parent[DYNAMIC_RANGE_KEY]*.1)
+ self.parent[REF_LEVEL_KEY] = self.parent[REF_LEVEL_KEY] -
self.parent[DYNAMIC_RANGE_KEY]*.1
def _on_incr_time_scale(self, event):
- old_rate =
self.parent.ext_controller[self.parent.frame_rate_key]
- self.parent.ext_controller[self.parent.frame_rate_key] *= 0.75
- if self.parent.ext_controller[self.parent.frame_rate_key] ==
old_rate:
- self.parent.ext_controller[self.parent.decimation_key]
+= 1
+ old_rate = self.parent[FRAME_RATE_KEY]
+ self.parent[FRAME_RATE_KEY] *= 0.75
+ if self.parent[FRAME_RATE_KEY] == old_rate:
+ self.parent[DECIMATION_KEY] += 1
def _on_decr_time_scale(self, event):
- old_rate =
self.parent.ext_controller[self.parent.frame_rate_key]
- self.parent.ext_controller[self.parent.frame_rate_key] *= 1.25
- if self.parent.ext_controller[self.parent.frame_rate_key] ==
old_rate:
- self.parent.ext_controller[self.parent.decimation_key]
-= 1
+ old_rate = self.parent[FRAME_RATE_KEY]
+ self.parent[FRAME_RATE_KEY] *= 1.25
+ if self.parent[FRAME_RATE_KEY] == old_rate:
+ self.parent[DECIMATION_KEY] -= 1
##################################################
# Waterfall window with plotter and control panel
##################################################
-class waterfall_window(wx.Panel, pubsub.pubsub, common.prop_setter):
+class waterfall_window(wx.Panel, pubsub.pubsub):
def __init__(
self,
parent,
@@ -169,20 +165,22 @@
pubsub.pubsub.__init__(self)
#setup
self.samples = list()
- self.ext_controller = controller
self.real = real
self.fft_size = fft_size
- self.decimation_key = decimation_key
- self.sample_rate_key = sample_rate_key
- self.frame_rate_key = frame_rate_key
- self.average_key = average_key
- self.avg_alpha_key = avg_alpha_key
+ #proxy the keys
+ self.proxy(MSG_KEY, controller, msg_key)
+ self.proxy(DECIMATION_KEY, controller, decimation_key)
+ self.proxy(FRAME_RATE_KEY, controller, frame_rate_key)
+ self.proxy(AVERAGE_KEY, controller, average_key)
+ self.proxy(AVG_ALPHA_KEY, controller, avg_alpha_key)
+ self.proxy(SAMPLE_RATE_KEY, controller, sample_rate_key)
#init panel and plot
- wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
+ wx.Panel.__init__(self, parent, style=wx.SIMPLE_BORDER)
self.plotter = plotter.waterfall_plotter(self)
self.plotter.SetSize(wx.Size(*size))
self.plotter.set_title(title)
self.plotter.enable_point_label(True)
+ self.plotter.enable_grid_lines(False)
#setup the box with plot and controls
self.control_panel = control_panel(self)
main_box = wx.BoxSizer(wx.HORIZONTAL)
@@ -192,26 +190,23 @@
#plotter listeners
self.subscribe(COLOR_MODE_KEY, self.plotter.set_color_mode)
self.subscribe(NUM_LINES_KEY, self.plotter.set_num_lines)
- #initial setup
- self.ext_controller[self.average_key] =
self.ext_controller[self.average_key]
- self.ext_controller[self.avg_alpha_key] =
self.ext_controller[self.avg_alpha_key]
- self._register_set_prop(self, DYNAMIC_RANGE_KEY, dynamic_range)
- self._register_set_prop(self, NUM_LINES_KEY, num_lines)
- self._register_set_prop(self, Y_DIVS_KEY, 8)
- self._register_set_prop(self, X_DIVS_KEY, 8) #approximate
- self._register_set_prop(self, REF_LEVEL_KEY, ref_level)
- self._register_set_prop(self, BASEBAND_FREQ_KEY, baseband_freq)
- self._register_set_prop(self, COLOR_MODE_KEY, COLOR_MODES[0][1])
- self._register_set_prop(self, RUNNING_KEY, True)
+ #initialize values
+ self[AVERAGE_KEY] = self[AVERAGE_KEY]
+ self[AVG_ALPHA_KEY] = self[AVG_ALPHA_KEY]
+ self[DYNAMIC_RANGE_KEY] = dynamic_range
+ self[NUM_LINES_KEY] = num_lines
+ self[Y_DIVS_KEY] = 8
+ self[X_DIVS_KEY] = 8 #approximate
+ self[REF_LEVEL_KEY] = ref_level
+ self[BASEBAND_FREQ_KEY] = baseband_freq
+ self[COLOR_MODE_KEY] = COLOR_MODES[0][1]
+ self[RUNNING_KEY] = True
#register events
- self.ext_controller.subscribe(msg_key, self.handle_msg)
- self.ext_controller.subscribe(self.decimation_key,
self.update_grid)
- self.ext_controller.subscribe(self.sample_rate_key,
self.update_grid)
- self.ext_controller.subscribe(self.frame_rate_key,
self.update_grid)
- self.subscribe(BASEBAND_FREQ_KEY, self.update_grid)
- self.subscribe(NUM_LINES_KEY, self.update_grid)
- self.subscribe(Y_DIVS_KEY, self.update_grid)
- self.subscribe(X_DIVS_KEY, self.update_grid)
+ self.subscribe(MSG_KEY, self.handle_msg)
+ for key in (
+ DECIMATION_KEY, SAMPLE_RATE_KEY, FRAME_RATE_KEY,
+ BASEBAND_FREQ_KEY, X_DIVS_KEY, Y_DIVS_KEY,
NUM_LINES_KEY,
+ ): self.subscribe(key, self.update_grid)
#initial update
self.update_grid()
@@ -230,8 +225,8 @@
noise_floor -= abs(noise_floor)*.5
peak_level += abs(peak_level)*.1
#set the range and level
- self.set_ref_level(peak_level)
- self.set_dynamic_range(peak_level - noise_floor)
+ self[REF_LEVEL_KEY] = peak_level
+ self[DYNAMIC_RANGE_KEY] = peak_level - noise_floor
def handle_msg(self, msg):
"""
@@ -266,8 +261,8 @@
The y axis depends on y per div, y divs, and ref level.
"""
#grid parameters
- sample_rate = self.ext_controller[self.sample_rate_key]
- frame_rate = self.ext_controller[self.frame_rate_key]
+ sample_rate = self[SAMPLE_RATE_KEY]
+ frame_rate = self[FRAME_RATE_KEY]
baseband_freq = self[BASEBAND_FREQ_KEY]
num_lines = self[NUM_LINES_KEY]
y_divs = self[Y_DIVS_KEY]
@@ -276,28 +271,25 @@
if self.real: x_width = sample_rate/2.0
else: x_width = sample_rate/1.0
x_per_div = common.get_clean_num(x_width/x_divs)
- coeff, exp, prefix =
common.get_si_components(abs(baseband_freq) + abs(sample_rate/2.0))
#update the x grid
if self.real:
self.plotter.set_x_grid(
baseband_freq,
baseband_freq + sample_rate/2.0,
- x_per_div,
- 10**(-exp),
+ x_per_div, True,
)
else:
self.plotter.set_x_grid(
baseband_freq - sample_rate/2.0,
baseband_freq + sample_rate/2.0,
- x_per_div,
- 10**(-exp),
+ x_per_div, True,
)
#update x units
- self.plotter.set_x_label('Frequency', prefix+'Hz')
+ self.plotter.set_x_label('Frequency', 'Hz')
#update y grid
duration = float(num_lines)/frame_rate
y_per_div = common.get_clean_num(duration/y_divs)
- self.plotter.set_y_grid(0, duration, y_per_div)
+ self.plotter.set_y_grid(0, duration, y_per_div, True)
#update y units
self.plotter.set_y_label('Time', 's')
#update plotter
Modified: gnuradio/trunk/gr-wxgui/src/python/waterfallsink_gl.py
===================================================================
--- gnuradio/trunk/gr-wxgui/src/python/waterfallsink_gl.py 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/gr-wxgui/src/python/waterfallsink_gl.py 2009-03-20
02:16:20 UTC (rev 10660)
@@ -31,7 +31,7 @@
##################################################
# Waterfall sink block (wrapper for old wxgui)
##################################################
-class _waterfall_sink_base(gr.hier_block2, common.prop_setter):
+class _waterfall_sink_base(gr.hier_block2):
"""
An fft block with real/complex inputs and a gui window.
"""
@@ -89,9 +89,7 @@
self.controller.subscribe(FRAME_RATE_KEY, fft.set_vec_rate)
self.controller.publish(FRAME_RATE_KEY, fft.frame_rate)
#start input watcher
- def setter(p, k, x): # lambdas can't have assignments :(
- p[k] = x
- common.input_watcher(msgq, lambda x: setter(self.controller,
MSG_KEY, x))
+ common.input_watcher(msgq, self.controller, MSG_KEY)
#create window
self.win = waterfall_window.waterfall_window(
parent=parent,
@@ -111,12 +109,8 @@
avg_alpha_key=AVG_ALPHA_KEY,
msg_key=MSG_KEY,
)
- #register callbacks from window for external use
- for attr in filter(lambda a: a.startswith('set_'),
dir(self.win)):
- setattr(self, attr, getattr(self.win, attr))
- self._register_set_prop(self.controller, SAMPLE_RATE_KEY)
- self._register_set_prop(self.controller, AVERAGE_KEY)
- self._register_set_prop(self.controller, AVG_ALPHA_KEY)
+ common.register_access_methods(self, self.win)
+ setattr(self.win, 'set_baseband_freq', getattr(self,
'set_baseband_freq')) #BACKWARDS
class waterfall_sink_f(_waterfall_sink_base):
_fft_chain = blks2.logpwrfft_f
Modified: gnuradio/trunk/grc/data/platforms/python/block_tree.xml
===================================================================
--- gnuradio/trunk/grc/data/platforms/python/block_tree.xml 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/grc/data/platforms/python/block_tree.xml 2009-03-20
02:16:20 UTC (rev 10660)
@@ -38,6 +38,7 @@
<block>wxgui_fftsink2</block>
<block>wxgui_constellationsink2</block>
<block>wxgui_waterfallsink2</block>
+ <block>wxgui_histosink2</block>
</cat>
<cat>
<name>Operators</name>
Modified: gnuradio/trunk/grc/data/platforms/python/blocks/Makefile.am
===================================================================
--- gnuradio/trunk/grc/data/platforms/python/blocks/Makefile.am 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/grc/data/platforms/python/blocks/Makefile.am 2009-03-20
02:16:20 UTC (rev 10660)
@@ -210,6 +210,7 @@
variable_text_box.xml \
wxgui_constellationsink2.xml \
wxgui_fftsink2.xml \
+ wxgui_histosink2.xml \
wxgui_numbersink2.xml \
wxgui_scopesink2.xml \
wxgui_waterfallsink2.xml \
Modified:
gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_constellationsink2.xml
===================================================================
---
gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_constellationsink2.xml
2009-03-20 01:48:45 UTC (rev 10659)
+++
gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_constellationsink2.xml
2009-03-20 02:16:20 UTC (rev 10660)
@@ -7,14 +7,22 @@
<block>
<name>Constellation Sink</name>
<key>wxgui_constellationsink2</key>
- <import>from gnuradio.wxgui import scopesink2</import>
- <make>scopesink2.constellation_sink(
+ <import>from gnuradio.wxgui import constsink_gl</import>
+ <make>constsink_gl.const_sink_c(
self.GetWin(),
title=$title,
sample_rate=$samp_rate,
- frame_decim=$frame_decim,
+ frame_rate=$frame_rate,
+ const_size=$const_size,
+ M=$M,
+ theta=$theta,
+ alpha=$alpha,
+ fmax=$fmax,
+ mu=$mu,
+ gain_mu=$gain_mu,
+ symbol_rate=$symbol_rate,
+ omega_limit=$omega_limit,
)
-self.$(id).win.$(marker)()
#set $grid_pos = $grid_pos.eval
#if not grid_pos
self.Add(self.$(id).win)
@@ -35,30 +43,66 @@
<type>real</type>
</param>
<param>
- <name>Frame Decimation</name>
- <key>frame_decim</key>
- <value>15</value>
+ <name>Frame Rate</name>
+ <key>frame_rate</key>
+ <value>5</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Constellation Size</name>
+ <key>const_size</key>
+ <value>2048</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>M</name>
+ <key>M</key>
+ <value>4</value>
<type>int</type>
</param>
<param>
- <name>Marker</name>
- <key>marker</key>
- <value>set_format_plus</value>
- <type>enum</type>
- <option>
- <name>Line</name>
- <key>set_format_line</key>
- </option>
- <option>
- <name>Dot</name>
- <key>set_format_dot</key>
- </option>
- <option>
- <name>Plus</name>
- <key>set_format_plus</key>
- </option>
+ <name>Theta</name>
+ <key>theta</key>
+ <value>0</value>
+ <type>real</type>
</param>
<param>
+ <name>Alpha</name>
+ <key>alpha</key>
+ <value>0.005</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Max Freq</name>
+ <key>fmax</key>
+ <value>0.06</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Mu</name>
+ <key>mu</key>
+ <value>0.5</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Gain Mu</name>
+ <key>gain_mu</key>
+ <value>0.005</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Symbol Rate</name>
+ <key>symbol_rate</key>
+ <value>samp_rate/4.</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Omega Limit</name>
+ <key>omega_limit</key>
+ <value>0.005</value>
+ <type>real</type>
+ </param>
+ <param>
<name>Grid Position</name>
<key>grid_pos</key>
<value></value>
Modified: gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_fftsink2.xml
===================================================================
--- gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_fftsink2.xml
2009-03-20 01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_fftsink2.xml
2009-03-20 02:16:20 UTC (rev 10660)
@@ -12,7 +12,6 @@
self.GetWin(),
baseband_freq=$baseband_freq,
y_per_div=$y_per_div,
- y_divs=$y_divs,
ref_level=$ref_level,
sample_rate=$samp_rate,
fft_size=$fft_size,
@@ -68,16 +67,30 @@
<name>Y per Div</name>
<key>y_per_div</key>
<value>10</value>
- <type>real</type>
+ <type>enum</type>
+ <option>
+ <name>1 dB</name>
+ <key>1</key>
+ </option>
+ <option>
+ <name>2 dB</name>
+ <key>2</key>
+ </option>
+ <option>
+ <name>5 dB</name>
+ <key>5</key>
+ </option>
+ <option>
+ <name>10 dB</name>
+ <key>10</key>
+ </option>
+ <option>
+ <name>20 dB</name>
+ <key>20</key>
+ </option>
</param>
<param>
- <name>Y Divs</name>
- <key>y_divs</key>
- <value>8</value>
- <type>real</type>
- </param>
- <param>
- <name>Reference Level</name>
+ <name>Ref Level (dB)</name>
<key>ref_level</key>
<value>50</value>
<type>real</type>
@@ -95,40 +108,43 @@
<type>int</type>
</param>
<param>
- <name>Average Alpha</name>
- <key>avg_alpha</key>
- <value>0</value>
- <type>real</type>
- </param>
- <param>
- <name>Average</name>
- <key>average</key>
+ <name>Peak Hold</name>
+ <key>peak_hold</key>
<value>False</value>
<type>enum</type>
+ <hide>#if $peak_hold.eval == 'True' then 'none' else
'part'#</hide>
<option>
- <name>Yes</name>
+ <name>On</name>
<key>True</key>
</option>
<option>
- <name>No</name>
+ <name>Off</name>
<key>False</key>
</option>
</param>
<param>
- <name>Peak Hold</name>
- <key>peak_hold</key>
+ <name>Average</name>
+ <key>average</key>
<value>False</value>
<type>enum</type>
+ <hide>#if $average.eval == 'True' then 'none' else
'part'#</hide>
<option>
- <name>Yes</name>
+ <name>On</name>
<key>True</key>
</option>
<option>
- <name>No</name>
+ <name>Off</name>
<key>False</key>
</option>
</param>
<param>
+ <name>Average Alpha</name>
+ <key>avg_alpha</key>
+ <value>0</value>
+ <type>real</type>
+ <hide>#if $average.eval == 'True' then 'none' else 'all'#</hide>
+ </param>
+ <param>
<name>Grid Position</name>
<key>grid_pos</key>
<value></value>
Copied: gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_histosink2.xml
(from rev 10658,
gnuradio/branches/developers/jblum/gui_guts/grc/data/platforms/python/blocks/wxgui_histosink2.xml)
===================================================================
--- gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_histosink2.xml
(rev 0)
+++ gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_histosink2.xml
2009-03-20 02:16:20 UTC (rev 10660)
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Histogram Sink
+###################################################
+ -->
+<block>
+ <name>Histo Sink</name>
+ <key>wxgui_histosink2</key>
+ <import>from gnuradio.wxgui import histosink_gl</import>
+ <make>histosink_gl.histo_sink_f(
+ self.GetWin(),
+ title=$title,
+ num_bins=$num_bins,
+ frame_size=$frame_size,
+)
+#set $grid_pos = $grid_pos.eval
+#if not grid_pos
+self.Add(self.$(id).win)
+#else
+self.GridAdd(self.$(id).win, $grid_pos[0], $grid_pos[1], $grid_pos[2],
$grid_pos[3])
+#end if</make>
+ <callback>set_num_bins($num_bins)</callback>
+ <callback>set_frame_size($frame_size)</callback>
+ <param>
+ <name>Title</name>
+ <key>title</key>
+ <value>Histogram Plot</value>
+ <type>string</type>
+ </param>
+ <param>
+ <name>Num Bins</name>
+ <key>num_bins</key>
+ <value>27</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Frame Size</name>
+ <key>frame_size</key>
+ <value>1000</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Grid Position</name>
+ <key>grid_pos</key>
+ <value></value>
+ <type>grid_pos</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>float</type>
+ </sink>
+ <doc>
+Use the Grid Position (row, column, row span, column span) to position the
graphical element in the window.
+ </doc>
+</block>
Modified: gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_numbersink2.xml
===================================================================
--- gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_numbersink2.xml
2009-03-20 01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_numbersink2.xml
2009-03-20 02:16:20 UTC (rev 10660)
@@ -19,10 +19,10 @@
ref_level=$ref_level,
sample_rate=$samp_rate,
number_rate=$number_rate,
- average=$options.average,
+ average=$average,
avg_alpha=#if $avg_alpha.eval then $avg_alpha else 'None'#,
label=$title,
- peak_hold=$options.peak_hold,
+ peak_hold=$peak_hold,
show_gauge=$show_gauge,
)
#set $grid_pos = $grid_pos.eval
@@ -108,36 +108,43 @@
<type>int</type>
</param>
<param>
- <name>Average Alpha</name>
- <key>avg_alpha</key>
- <value>0</value>
- <type>real</type>
+ <name>Peak Hold</name>
+ <key>peak_hold</key>
+ <value>False</value>
+ <type>enum</type>
+ <hide>#if $peak_hold.eval == 'True' then 'none' else
'part'#</hide>
+ <option>
+ <name>On</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>False</key>
+ </option>
</param>
<param>
- <name>Options</name>
- <key>options</key>
- <value>none</value>
+ <name>Average</name>
+ <key>average</key>
+ <value>False</value>
<type>enum</type>
+ <hide>#if $average.eval == 'True' then 'none' else
'part'#</hide>
<option>
- <name>None</name>
- <key>none</key>
- <opt>peak_hold:False</opt>
- <opt>average:False</opt>
+ <name>On</name>
+ <key>True</key>
</option>
<option>
- <name>Average</name>
- <key>average</key>
- <opt>peak_hold:False</opt>
- <opt>average:True</opt>
+ <name>Off</name>
+ <key>False</key>
</option>
- <option>
- <name>Peak Hold</name>
- <key>peak_hold</key>
- <opt>peak_hold:True</opt>
- <opt>average:False</opt>
- </option>
</param>
<param>
+ <name>Average Alpha</name>
+ <key>avg_alpha</key>
+ <value>0</value>
+ <type>real</type>
+ <hide>#if $average.eval == 'True' then 'none' else 'all'#</hide>
+ </param>
+ <param>
<name>Show Gauge</name>
<key>show_gauge</key>
<value>True</value>
Modified: gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_scopesink2.xml
===================================================================
--- gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_scopesink2.xml
2009-03-20 01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/grc/data/platforms/python/blocks/wxgui_scopesink2.xml
2009-03-20 02:16:20 UTC (rev 10660)
@@ -13,21 +13,18 @@
self.GetWin(),
title=$title,
sample_rate=$samp_rate,
- frame_decim=$frame_decim,
- v_scale=#if $v_scale.eval then $v_scale else 'None'#,
+ v_scale=$v_scale,
t_scale=$t_scale,
+ ac_couple=$ac_couple,
+ xy_mode=$xy_mode,
num_inputs=$num_inputs,
)
-self.$(id).win.$(marker)()
#set $grid_pos = $grid_pos.eval
#if not grid_pos
self.Add(self.$(id).win)
#else
self.GridAdd(self.$(id).win, $grid_pos[0], $grid_pos[1], $grid_pos[2],
$grid_pos[3])
#end if</make>
-<!--
-$(id).win.info.scopesink.set_trigger_channel($(trigger_channel))
-$(id).win.info.scopesink.set_trigger_mode(gr.$(trigger_mode)) -->
<callback>set_sample_rate($samp_rate)</callback>
<param>
<name>Type</name>
@@ -58,12 +55,6 @@
<type>real</type>
</param>
<param>
- <name>Frame Decimation</name>
- <key>frame_decim</key>
- <value>15</value>
- <type>int</type>
- </param>
- <param>
<name>V Scale</name>
<key>v_scale</key>
<value>0</value>
@@ -72,51 +63,39 @@
<param>
<name>T Scale</name>
<key>t_scale</key>
- <value>.001</value>
+ <value>0</value>
<type>real</type>
</param>
<param>
- <name>Marker</name>
- <key>marker</key>
- <value>set_format_line</value>
+ <name>AC Couple</name>
+ <key>ac_couple</key>
+ <value>False</value>
<type>enum</type>
+ <hide>#if $ac_couple.eval == 'True' then 'none' else
'part'#</hide>
<option>
- <name>Line</name>
- <key>set_format_line</key>
+ <name>Off</name>
+ <key>False</key>
</option>
<option>
- <name>Dot</name>
- <key>set_format_dot</key>
+ <name>On</name>
+ <key>True</key>
</option>
- <option>
- <name>Plus</name>
- <key>set_format_plus</key>
- </option>
</param>
- <!-- <param>
- <name>Trigger Channel</name>
- <key>trigger_channel</key>
- <value>0</value>
- <type>int</type>
- </param>
<param>
- <name>Trigger Mode</name>
- <key>trigger_mode</key>
- <value>gr_TRIG_AUTO</value>
+ <name>XY Mode</name>
+ <key>xy_mode</key>
+ <value>False</value>
<type>enum</type>
+ <hide>#if $xy_mode.eval == 'True' then 'none' else
'part'#</hide>
<option>
- <name>Auto</name>
- <key>gr_TRIG_AUTO</key>
+ <name>Off</name>
+ <key>False</key>
</option>
<option>
- <name>Positive Slope</name>
- <key>gr_TRIG_POS_SLOPE</key>
+ <name>On</name>
+ <key>True</key>
</option>
- <option>
- <name>Negative Slope</name>
- <key>gr_TRIG_NEG_SLOPE</key>
- </option>
- </param> -->
+ </param>
<param>
<name>Num Inputs</name>
<key>num_inputs</key>
@@ -129,6 +108,7 @@
<value></value>
<type>grid_pos</type>
</param>
+ <check>not $xy_mode or '$type' == 'complex' or $num_inputs != 1</check>
<sink>
<name>in</name>
<type>$type</type>
@@ -137,6 +117,10 @@
<doc>
Set the V Scale to 0 for the scope to auto-scale.
+Set the T Scale to 0 for automatic setting.
+
+XY Mode allows the scope to initialize as an XY plotter.
+
Use the Grid Position (row, column, row span, column span) to position the
graphical element in the window.
</doc>
</block>
Modified: gnuradio/trunk/grc/examples/simple/ber_simulation.grc
===================================================================
--- gnuradio/trunk/grc/examples/simple/ber_simulation.grc 2009-03-20
01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/grc/examples/simple/ber_simulation.grc 2009-03-20
02:16:20 UTC (rev 10660)
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='ASCII'?>
<flow_graph>
- <timestamp>Thu Jul 24 14:28:06 2008</timestamp>
+ <timestamp>Thu Mar 19 11:08:59 2009</timestamp>
<block>
<key>options</key>
<param>
@@ -36,39 +36,12 @@
<value>Custom</value>
</param>
<param>
- <key>_coordinate</key>
- <value>(16, 10)</value>
+ <key>realtime_scheduling</key>
+ <value></value>
</param>
<param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>gr_add_vxx</key>
- <param>
- <key>id</key>
- <value>gr_add_vxx</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>type</key>
- <value>complex</value>
- </param>
- <param>
- <key>num_inputs</key>
- <value>2</value>
- </param>
- <param>
- <key>vlen</key>
- <value>1</value>
- </param>
- <param>
<key>_coordinate</key>
- <value>(652, 395)</value>
+ <value>(16, 10)</value>
</param>
<param>
<key>_rotation</key>
@@ -76,45 +49,6 @@
</param>
</block>
<block>
- <key>wxgui_constellationsink2</key>
- <param>
- <key>id</key>
- <value>wxgui_constellationsink2</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>title</key>
- <value>"Constellation: "+str(const)</value>
- </param>
- <param>
- <key>samp_rate</key>
- <value>samp_rate</value>
- </param>
- <param>
- <key>frame_decim</key>
- <value>15</value>
- </param>
- <param>
- <key>marker</key>
- <value>set_format_plus</value>
- </param>
- <param>
- <key>grid_pos</key>
- <value>2, 0, 1, 1</value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(907, 334)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
<key>gr_noise_source_x</key>
<param>
<key>id</key>
@@ -239,14 +173,18 @@
<value>15</value>
</param>
<param>
+ <key>peak_hold</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>average</key>
+ <value>False</value>
+ </param>
+ <param>
<key>avg_alpha</key>
<value>0</value>
</param>
<param>
- <key>options</key>
- <value>none</value>
- </param>
- <param>
<key>show_gauge</key>
<value>False</value>
</param>
@@ -306,7 +244,7 @@
</param>
<param>
<key>type</key>
- <value>"BER"</value>
+ <value>'BER'</value>
</param>
<param>
<key>win_size</key>
@@ -483,6 +421,92 @@
<value>0</value>
</param>
</block>
+ <block>
+ <key>gr_add_vxx</key>
+ <param>
+ <key>id</key>
+ <value>gr_add_vxx</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>num_inputs</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(652, 395)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_scopesink2</key>
+ <param>
+ <key>id</key>
+ <value>wxgui_scopesink2_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>"Constellation: "+str(const)</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>v_scale</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>t_scale</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ac_couple</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>xy_mode</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>num_inputs</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value>2, 0, 1, 1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(828, 368)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
<connection>
<source_block_id>blks2_error_rate</source_block_id>
<sink_block_id>wxgui_numbersink2</sink_block_id>
@@ -520,21 +544,21 @@
<sink_key>1</sink_key>
</connection>
<connection>
- <source_block_id>gr_add_vxx</source_block_id>
- <sink_block_id>wxgui_constellationsink2</sink_block_id>
+ <source_block_id>random_source_x</source_block_id>
+ <sink_block_id>gr_throttle</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>random_source_x</source_block_id>
- <sink_block_id>gr_throttle</sink_block_id>
+ <sink_block_id>gr_chunks_to_symbols_xx</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
- <source_block_id>random_source_x</source_block_id>
- <sink_block_id>gr_chunks_to_symbols_xx</sink_block_id>
+ <source_block_id>gr_add_vxx</source_block_id>
+ <sink_block_id>wxgui_scopesink2_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
-</flow_graph>
\ No newline at end of file
+</flow_graph>
Modified: gnuradio/trunk/grc/examples/trellis/interference_cancellation.grc
===================================================================
--- gnuradio/trunk/grc/examples/trellis/interference_cancellation.grc
2009-03-20 01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/grc/examples/trellis/interference_cancellation.grc
2009-03-20 02:16:20 UTC (rev 10660)
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='ASCII'?>
<flow_graph>
- <timestamp>Tue Nov 18 00:48:20 2008</timestamp>
+ <timestamp>Thu Mar 19 11:22:40 2009</timestamp>
<block>
<key>options</key>
<param>
@@ -36,6 +36,10 @@
<value>Custom</value>
</param>
<param>
+ <key>realtime_scheduling</key>
+ <value></value>
+ </param>
+ <param>
<key>_coordinate</key>
<value>(10, 10)</value>
</param>
@@ -411,37 +415,6 @@
</param>
</block>
<block>
- <key>gr_add_vxx</key>
- <param>
- <key>id</key>
- <value>gr_add_vxx_1</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>type</key>
- <value>complex</value>
- </param>
- <param>
- <key>num_inputs</key>
- <value>2</value>
- </param>
- <param>
- <key>vlen</key>
- <value>1</value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(1400, 262)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
<key>gr_noise_source_x</key>
<param>
<key>id</key>
@@ -477,45 +450,6 @@
</param>
</block>
<block>
- <key>wxgui_constellationsink2</key>
- <param>
- <key>id</key>
- <value>wxgui_constellationsink2_0</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>title</key>
- <value>Constellation Plot</value>
- </param>
- <param>
- <key>samp_rate</key>
- <value>R</value>
- </param>
- <param>
- <key>frame_decim</key>
- <value>15</value>
- </param>
- <param>
- <key>marker</key>
- <value>set_format_plus</value>
- </param>
- <param>
- <key>grid_pos</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(1301, 74)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
<key>gr_sub_xx</key>
<param>
<key>id</key>
@@ -530,6 +464,10 @@
<value>short</value>
</param>
<param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
<key>num_inputs</key>
<value>2</value>
</param>
@@ -607,6 +545,10 @@
<value>short</value>
</param>
<param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
<key>num_inputs</key>
<value>2</value>
</param>
@@ -750,6 +692,10 @@
<value>complex</value>
</param>
<param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
<key>num_inputs</key>
<value>2</value>
</param>
@@ -777,6 +723,10 @@
<value>short</value>
</param>
<param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
<key>num_inputs</key>
<value>2</value>
</param>
@@ -920,6 +870,10 @@
<value>complex</value>
</param>
<param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
<key>num_inputs</key>
<value>2</value>
</param>
@@ -947,6 +901,10 @@
<value>short</value>
</param>
<param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
<key>num_inputs</key>
<value>2</value>
</param>
@@ -1064,14 +1022,18 @@
<value>15</value>
</param>
<param>
+ <key>peak_hold</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>average</key>
+ <value>False</value>
+ </param>
+ <param>
<key>avg_alpha</key>
<value>0.001</value>
</param>
<param>
- <key>options</key>
- <value>average</value>
- </param>
- <param>
<key>show_gauge</key>
<value>True</value>
</param>
@@ -1143,14 +1105,18 @@
<value>15</value>
</param>
<param>
+ <key>peak_hold</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>average</key>
+ <value>False</value>
+ </param>
+ <param>
<key>avg_alpha</key>
<value>0.001</value>
</param>
<param>
- <key>options</key>
- <value>average</value>
- </param>
- <param>
<key>show_gauge</key>
<value>True</value>
</param>
@@ -1222,103 +1188,28 @@
<value>15</value>
</param>
<param>
- <key>avg_alpha</key>
- <value>0.001</value>
+ <key>peak_hold</key>
+ <value>False</value>
</param>
<param>
- <key>options</key>
- <value>average</value>
+ <key>average</key>
+ <value>False</value>
</param>
<param>
- <key>show_gauge</key>
- <value>True</value>
- </param>
- <param>
- <key>grid_pos</key>
- <value>1,0,1,1</value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(1269, 1417)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>wxgui_numbersink2</key>
- <param>
- <key>id</key>
- <value>wxgui_numbersink2_0</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>type</key>
- <value>float</value>
- </param>
- <param>
- <key>title</key>
- <value>BER 1 (raw)</value>
- </param>
- <param>
- <key>units</key>
- <value>BER</value>
- </param>
- <param>
- <key>samp_rate</key>
- <value>R</value>
- </param>
- <param>
- <key>base_value</key>
- <value>0.0</value>
- </param>
- <param>
- <key>min_value</key>
- <value>0</value>
- </param>
- <param>
- <key>max_value</key>
- <value>1</value>
- </param>
- <param>
- <key>factor</key>
- <value>1.0</value>
- </param>
- <param>
- <key>decimal_places</key>
- <value>6</value>
- </param>
- <param>
- <key>ref_level</key>
- <value>0</value>
- </param>
- <param>
- <key>number_rate</key>
- <value>15</value>
- </param>
- <param>
<key>avg_alpha</key>
<value>0.001</value>
</param>
<param>
- <key>options</key>
- <value>average</value>
- </param>
- <param>
<key>show_gauge</key>
<value>True</value>
</param>
<param>
<key>grid_pos</key>
- <value>0,0,1,1</value>
+ <value>1,0,1,1</value>
</param>
<param>
<key>_coordinate</key>
- <value>(1267, 410)</value>
+ <value>(1269, 1417)</value>
</param>
<param>
<key>_rotation</key>
@@ -1715,6 +1606,175 @@
<value>0</value>
</param>
</block>
+ <block>
+ <key>gr_add_vxx</key>
+ <param>
+ <key>id</key>
+ <value>gr_add_vxx_1</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>num_inputs</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1400, 262)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_numbersink2</key>
+ <param>
+ <key>id</key>
+ <value>wxgui_numbersink2_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>BER 1 (raw)</value>
+ </param>
+ <param>
+ <key>units</key>
+ <value>BER</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>R</value>
+ </param>
+ <param>
+ <key>base_value</key>
+ <value>0.0</value>
+ </param>
+ <param>
+ <key>min_value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>max_value</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>factor</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>decimal_places</key>
+ <value>6</value>
+ </param>
+ <param>
+ <key>ref_level</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>number_rate</key>
+ <value>15</value>
+ </param>
+ <param>
+ <key>peak_hold</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>average</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>avg_alpha</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>show_gauge</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value>0,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1267, 410)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_scopesink2</key>
+ <param>
+ <key>id</key>
+ <value>wxgui_scopesink2_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>Scope Plot</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>R</value>
+ </param>
+ <param>
+ <key>v_scale</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>t_scale</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ac_couple</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>xy_mode</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>num_inputs</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1533, 149)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
<connection>
<source_block_id>random_source_x_1</source_block_id>
<sink_block_id>trellis_encoder_xx_1</sink_block_id>
@@ -1758,12 +1818,6 @@
<sink_key>1</sink_key>
</connection>
<connection>
- <source_block_id>gr_add_vxx_1</source_block_id>
- <sink_block_id>wxgui_constellationsink2_0</sink_block_id>
- <source_key>0</source_key>
- <sink_key>0</sink_key>
- </connection>
- <connection>
<source_block_id>gr_chunks_to_symbols_xx_1</source_block_id>
<sink_block_id>gr_multiply_const_vxx_1</sink_block_id>
<source_key>0</source_key>
@@ -2009,4 +2063,10 @@
<source_key>0</source_key>
<sink_key>1</sink_key>
</connection>
+ <connection>
+ <source_block_id>gr_add_vxx_1</source_block_id>
+ <sink_block_id>wxgui_scopesink2_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
</flow_graph>
Modified: gnuradio/trunk/grc/src/grc_gnuradio/wxgui/callback_controls.py
===================================================================
--- gnuradio/trunk/grc/src/grc_gnuradio/wxgui/callback_controls.py
2009-03-20 01:48:45 UTC (rev 10659)
+++ gnuradio/trunk/grc/src/grc_gnuradio/wxgui/callback_controls.py
2009-03-20 02:16:20 UTC (rev 10660)
@@ -26,7 +26,7 @@
"""Label text class for uniform labels among all controls."""
def __init__(self, window, label):
- wx.StaticText.__init__(self, window, -1, str(label))
+ wx.StaticText.__init__(self, window, label=str(label))
font = self.GetFont()
font.SetWeight(wx.FONTWEIGHT_BOLD)
self.SetFont(font)
@@ -92,7 +92,7 @@
"""House a button for variable control."""
def _init(self):
- self.button = wx.Button(self.get_window(), -1,
self.labels[self.index])
+ self.button = wx.Button(self.get_window(),
label=self.labels[self.index])
self.button.Bind(wx.EVT_BUTTON, self._handle_changed)
self.Add(self.button, 0, wx.ALIGN_CENTER)
@@ -107,7 +107,7 @@
"""House a drop down for variable control."""
def _init(self):
- self.drop_down = wx.Choice(self.get_window(), -1,
choices=self.labels)
+ self.drop_down = wx.Choice(self.get_window(),
choices=self.labels)
self.Add(self.drop_down, 0, wx.ALIGN_CENTER)
self.drop_down.Bind(wx.EVT_CHOICE, self._handle_changed)
self.drop_down.SetSelection(self.index)
@@ -124,13 +124,13 @@
def _init(self):
#create box for radio buttons
radio_box = wx.BoxSizer(self.radio_box_orientation)
- panel = wx.Panel(self.get_window(), -1)
+ panel = wx.Panel(self.get_window())
panel.SetSizer(radio_box)
self.Add(panel, 0, wx.ALIGN_CENTER)
#create radio buttons
self.radio_buttons = list()
for label in self.labels:
- radio_button = wx.RadioButton(panel, -1, label)
+ radio_button = wx.RadioButton(panel, label=label)
radio_button.SetValue(False)
self.radio_buttons.append(radio_button)
radio_box.Add(radio_button, 0, self.radio_button_align)
@@ -177,13 +177,13 @@
#create gui elements
label_text_sizer = wx.BoxSizer(self.label_text_orientation)
#label and text box container
label_text = LabelText(self.get_window(), '%s: '%str(label))
- self.text_box = text_box = wx.TextCtrl(self.get_window(), -1,
str(value), style=wx.TE_PROCESS_ENTER)
+ self.text_box = text_box = wx.TextCtrl(self.get_window(),
style=wx.TE_PROCESS_ENTER)
text_box.Bind(wx.EVT_TEXT_ENTER, self._handle_enter) #bind this
special enter hotkey event
for obj in (label_text, text_box): #fill the container with
label and text entry box
- label_text_sizer.Add(obj, 0,
wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
+ label_text_sizer.Add(obj, 0, wx.ALIGN_CENTER)
self.Add(label_text_sizer, 0, wx.ALIGN_CENTER)
#make the slider
- self.slider = slider = wx.Slider(self.get_window(), -1,
size=wx.Size(*self.get_slider_size()), style=self.slider_style)
+ self.slider = slider = wx.Slider(self.get_window(),
size=wx.Size(*self.get_slider_size()), style=self.slider_style)
try: slider.SetRange(0, num_steps)
except Exception, e:
print >> sys.stderr, 'Error in set slider range:
"%s".'%e
@@ -245,11 +245,11 @@
class slider_horizontal_control(_slider_control_base):
label_text_orientation = wx.HORIZONTAL
slider_style = wx.SL_HORIZONTAL
- def get_slider_size(self): return self.slider_length, 20
+ def get_slider_size(self): return self.slider_length, -1
class slider_vertical_control(_slider_control_base):
label_text_orientation = wx.VERTICAL
slider_style = wx.SL_VERTICAL
- def get_slider_size(self): return 20, self.slider_length
+ def get_slider_size(self): return -1, self.slider_length
##############################################################################################
# Text Box Control
@@ -271,10 +271,10 @@
#create gui elements
label_text_sizer = wx.BoxSizer(wx.HORIZONTAL) #label and text
box container
label_text = LabelText(self.get_window(), '%s: '%str(label))
- self.text_box = text_box = wx.TextCtrl(self.get_window(), -1,
str(value), style=wx.TE_PROCESS_ENTER)
+ self.text_box = text_box = wx.TextCtrl(self.get_window(),
value=str(value), style=wx.TE_PROCESS_ENTER)
text_box.Bind(wx.EVT_TEXT_ENTER, self._handle_enter) #bind this
special enter hotkey event
for obj in (label_text, text_box): #fill the container with
label and text entry box
- label_text_sizer.Add(obj, 0,
wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
+ label_text_sizer.Add(obj, 0, wx.ALIGN_CENTER)
self.Add(label_text_sizer, 0, wx.ALIGN_CENTER)
#detect string mode
self._string_mode = isinstance(value, str)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r10660 - in gnuradio/trunk: . gnuradio-core/src/lib/io gr-wxgui/src/python gr-wxgui/src/python/plotter grc/data/platforms/python grc/data/platforms/python/blocks grc/examples/simple grc/examples/trellis grc/src/grc_gnuradio/wxgui,
jcorgan <=