summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gnuradio-core/src/lib/general/Makefile.am3
-rw-r--r--gnuradio-core/src/lib/general/general.i2
-rw-r--r--gnuradio-core/src/lib/general/gr_bin_statistics_f.cc173
-rw-r--r--gnuradio-core/src/lib/general/gr_bin_statistics_f.h99
-rw-r--r--gnuradio-core/src/lib/general/gr_bin_statistics_f.i42
-rw-r--r--gnuradio-core/src/lib/general/gr_feval.cc38
-rw-r--r--gnuradio-core/src/lib/general/gr_feval.h60
-rw-r--r--gnuradio-core/src/lib/general/gr_feval.i140
-rw-r--r--gnuradio-core/src/python/gnuradio/gr/Makefile.am1
-rwxr-xr-xgnuradio-core/src/python/gnuradio/gr/qa_bin_statistics.py226
-rwxr-xr-xgnuradio-examples/python/usrp/usrp_spectrum_sense.py241
-rw-r--r--gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc4
12 files changed, 995 insertions, 34 deletions
diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am
index ace399ab3..aa5ec604f 100644
--- a/gnuradio-core/src/lib/general/Makefile.am
+++ b/gnuradio-core/src/lib/general/Makefile.am
@@ -98,6 +98,7 @@ libgeneral_la_SOURCES = \
gr_agc2_cc.cc \
gr_agc2_ff.cc \
gr_align_on_samplenumbers_ss.cc \
+ gr_bin_statistics_f.cc \
gr_binary_slicer_fb.cc \
gr_bytes_to_syms.cc \
gr_char_to_float.cc \
@@ -219,6 +220,7 @@ grinclude_HEADERS = \
gr_agc2_cc.h \
gr_agc2_ff.h \
gr_align_on_samplenumbers_ss.h \
+ gr_bin_statistics_f.h \
gr_binary_slicer_fb.h \
gr_bytes_to_syms.h \
gr_char_to_float.h \
@@ -359,6 +361,7 @@ swiginclude_HEADERS = \
gr_agc2_cc.i \
gr_agc2_ff.i \
gr_align_on_samplenumbers_ss.i \
+ gr_bin_statistics_f.i \
gr_binary_slicer_fb.i \
gr_bytes_to_syms.i \
gr_char_to_float.i \
diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i
index 691cd8332..01cadcc0d 100644
--- a/gnuradio-core/src/lib/general/general.i
+++ b/gnuradio-core/src/lib/general/general.i
@@ -112,6 +112,7 @@
#include <gr_pwr_squelch_ff.h>
#include <gr_ctcss_squelch_ff.h>
#include <gr_feedforward_agc_cc.h>
+#include <gr_bin_statistics_f.h>
%}
%include "gr_sync_block.i"
@@ -205,5 +206,6 @@
%include "gr_pwr_squelch_ff.i"
%include "gr_ctcss_squelch_ff.i"
%include "gr_feedforward_agc_cc.i"
+%include "gr_bin_statistics_f.i"
%include "general_generated.i"
diff --git a/gnuradio-core/src/lib/general/gr_bin_statistics_f.cc b/gnuradio-core/src/lib/general/gr_bin_statistics_f.cc
new file mode 100644
index 000000000..c6153e8ec
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_bin_statistics_f.cc
@@ -0,0 +1,173 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 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 2, 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_bin_statistics_f.h>
+#include <gr_io_signature.h>
+
+gr_bin_statistics_f_sptr
+gr_make_bin_statistics_f(unsigned int vlen,
+ gr_msg_queue_sptr msgq,
+ gr_feval_dd *tune,
+ size_t tune_delay,
+ size_t dwell_delay)
+{
+ return gr_bin_statistics_f_sptr(new gr_bin_statistics_f(vlen,
+ msgq,
+ tune,
+ tune_delay,
+ dwell_delay));
+}
+
+gr_bin_statistics_f::gr_bin_statistics_f(unsigned int vlen,
+ gr_msg_queue_sptr msgq,
+ gr_feval_dd *tune,
+ size_t tune_delay,
+ size_t dwell_delay)
+ : gr_sync_block("bin_statistics_f",
+ gr_make_io_signature(1, 1, sizeof(float) * vlen),
+ gr_make_io_signature(0, 0, 0)),
+ d_vlen(vlen), d_msgq(msgq), d_tune(tune),
+ d_tune_delay(tune_delay), d_dwell_delay(dwell_delay),
+ d_center_freq(0), d_delay(0),
+ d_max(vlen)
+{
+ enter_init();
+}
+
+gr_bin_statistics_f::~gr_bin_statistics_f()
+{
+ // NOP
+}
+
+void
+gr_bin_statistics_f::enter_init()
+{
+ d_state = ST_INIT;
+ d_delay = 0;
+}
+
+void
+gr_bin_statistics_f::enter_tune_delay()
+{
+ d_state = ST_TUNE_DELAY;
+ d_delay = d_tune_delay;
+ d_center_freq = d_tune->calleval(0);
+}
+
+void
+gr_bin_statistics_f::enter_dwell_delay()
+{
+ d_state = ST_DWELL_DELAY;
+ d_delay = d_dwell_delay;
+ reset_stats();
+}
+
+void
+gr_bin_statistics_f::leave_dwell_delay()
+{
+ send_stats();
+}
+
+int
+gr_bin_statistics_f::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const float *input = (const float *) input_items[0];
+ size_t vlen = d_max.size();
+
+ int n = 0;
+ int t;
+
+ while (n < noutput_items){
+ switch (d_state){
+
+ case ST_INIT:
+ enter_tune_delay();
+ break;
+
+ case ST_TUNE_DELAY:
+ t = std::min(noutput_items - n, int(d_delay));
+ n += t;
+ d_delay -= t;
+ assert(d_delay >= 0);
+ if (d_delay == 0)
+ enter_dwell_delay();
+ break;
+
+ case ST_DWELL_DELAY:
+ t = std::min(noutput_items - n, int(d_delay));
+ for (int i = 0; i < t; i++){
+ accrue_stats(&input[n * vlen]);
+ n++;
+ }
+ d_delay -= t;
+ assert(d_delay >= 0);
+ if (d_delay == 0){
+ leave_dwell_delay();
+ enter_tune_delay();
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+
+ return noutput_items;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// virtual methods for gathering stats
+//////////////////////////////////////////////////////////////////////////
+
+void
+gr_bin_statistics_f::reset_stats()
+{
+ for (size_t i = 0; i < vlen(); i++){
+ d_max[i] = 0;
+ }
+}
+
+void
+gr_bin_statistics_f::accrue_stats(const float *input)
+{
+ for (size_t i = 0; i < vlen(); i++){
+ d_max[i] = std::max(d_max[i], input[i]); // compute per bin maxima
+ }
+}
+
+void
+gr_bin_statistics_f::send_stats()
+{
+ if (msgq()->full_p()) // if the queue is full, don't block, drop the data...
+ return;
+
+ // build & send a message
+ gr_message_sptr msg = gr_make_message(0, center_freq(), vlen(), vlen() * sizeof(float));
+ memcpy(msg->msg(), &d_max[0], vlen() * sizeof(float));
+ msgq()->insert_tail(msg);
+}
diff --git a/gnuradio-core/src/lib/general/gr_bin_statistics_f.h b/gnuradio-core/src/lib/general/gr_bin_statistics_f.h
new file mode 100644
index 000000000..48741f598
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_bin_statistics_f.h
@@ -0,0 +1,99 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 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 2, 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_BIN_STATISTICS_F_H
+#define INCLUDED_GR_BIN_STATISTICS_F_H
+
+
+#include <gr_sync_block.h>
+#include <gr_feval.h>
+#include <gr_message.h>
+#include <gr_msg_queue.h>
+
+class gr_bin_statistics_f;
+typedef boost::shared_ptr<gr_bin_statistics_f> gr_bin_statistics_f_sptr;
+
+
+gr_bin_statistics_f_sptr
+gr_make_bin_statistics_f(unsigned int vlen, // vector length
+ gr_msg_queue_sptr msgq,
+ gr_feval_dd *tune, // callback
+ size_t tune_delay, // samples
+ size_t dwell_delay); // samples
+
+/*!
+ * \brief control scanning and record frequency domain statistics
+ * \ingroup sink
+ */
+class gr_bin_statistics_f : public gr_sync_block
+{
+ friend gr_bin_statistics_f_sptr
+ gr_make_bin_statistics_f(unsigned int vlen, // vector length
+ gr_msg_queue_sptr msgq,
+ gr_feval_dd *tune, // callback
+ size_t tune_delay, // samples
+ size_t dwell_delay); // samples
+
+ enum state_t { ST_INIT, ST_TUNE_DELAY, ST_DWELL_DELAY };
+
+ size_t d_vlen;
+ gr_msg_queue_sptr d_msgq;
+ gr_feval_dd *d_tune;
+ size_t d_tune_delay;
+ size_t d_dwell_delay;
+ double d_center_freq;
+
+ state_t d_state;
+ size_t d_delay; // nsamples remaining to state transition
+
+ gr_bin_statistics_f(unsigned int vlen,
+ gr_msg_queue_sptr msgq,
+ gr_feval_dd *tune,
+ size_t tune_delay,
+ size_t dwell_delay);
+
+ void enter_init();
+ void enter_tune_delay();
+ void enter_dwell_delay();
+ void leave_dwell_delay();
+
+protected:
+ std::vector<float> d_max; // per bin maxima
+
+ size_t vlen() const { return d_vlen; }
+ double center_freq() const { return d_center_freq; }
+ gr_msg_queue_sptr msgq() const { return d_msgq; }
+
+ virtual void reset_stats();
+ virtual void accrue_stats(const float *input);
+ virtual void send_stats();
+
+public:
+ ~gr_bin_statistics_f();
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+};
+
+#endif
diff --git a/gnuradio-core/src/lib/general/gr_bin_statistics_f.i b/gnuradio-core/src/lib/general/gr_bin_statistics_f.i
new file mode 100644
index 000000000..a0fbb9873
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_bin_statistics_f.i
@@ -0,0 +1,42 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 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 2, 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,bin_statistics_f);
+
+gr_bin_statistics_f_sptr
+gr_make_bin_statistics_f(unsigned int vlen, // vector length
+ gr_msg_queue_sptr msgq,
+ gr_feval_dd *tune, // callback
+ size_t tune_delay, // samples
+ size_t dwell_delay); // samples
+
+
+class gr_bin_statistics_f : public gr_sync_block
+{
+private:
+ gr_bin_statistics_f(unsigned int vlen,
+ gr_msg_queue_sptr msgq,
+ gr_feval_dd *tune,
+ size_t tune_delay,
+ size_t dwell_delay);
+public:
+ ~gr_bin_statistics_f();
+};
diff --git a/gnuradio-core/src/lib/general/gr_feval.cc b/gnuradio-core/src/lib/general/gr_feval.cc
index 3617620b5..9ac5b1579 100644
--- a/gnuradio-core/src/lib/general/gr_feval.cc
+++ b/gnuradio-core/src/lib/general/gr_feval.cc
@@ -34,6 +34,14 @@ gr_feval_dd::eval(double x)
return 0;
}
+double
+gr_feval_dd::calleval(double x)
+{
+ return eval(x);
+}
+
+// ----------------------------------------------------------------
+
gr_feval_cc::~gr_feval_cc(){}
gr_complex
@@ -42,6 +50,14 @@ gr_feval_cc::eval(gr_complex x)
return 0;
}
+gr_complex
+gr_feval_cc::calleval(gr_complex x)
+{
+ return eval(x);
+}
+
+// ----------------------------------------------------------------
+
gr_feval_ll::~gr_feval_ll(){}
long
@@ -50,6 +66,14 @@ gr_feval_ll::eval(long x)
return 0;
}
+long
+gr_feval_ll::calleval(long x)
+{
+ return eval(x);
+}
+
+// ----------------------------------------------------------------
+
gr_feval::~gr_feval(){}
void
@@ -58,29 +82,35 @@ gr_feval::eval(void)
// nop
}
+void
+gr_feval::calleval(void)
+{
+ eval();
+}
+
/*
* Trivial examples showing C++ (transparently) calling Python
*/
double
gr_feval_dd_example(gr_feval_dd *f, double x)
{
- return f->eval(x);
+ return f->calleval(x);
}
gr_complex
gr_feval_cc_example(gr_feval_cc *f, gr_complex x)
{
- return f->eval(x);
+ return f->calleval(x);
}
long
gr_feval_ll_example(gr_feval_ll *f, long x)
{
- return f->eval(x);
+ return f->calleval(x);
}
void
gr_feval_example(gr_feval *f)
{
- f->eval();
+ f->calleval();
}
diff --git a/gnuradio-core/src/lib/general/gr_feval.h b/gnuradio-core/src/lib/general/gr_feval.h
index a2f7020a4..b8a5eec25 100644
--- a/gnuradio-core/src/lib/general/gr_feval.h
+++ b/gnuradio-core/src/lib/general/gr_feval.h
@@ -31,17 +31,24 @@
* and is callable from both places. It uses SWIG's
* "director" feature to implement the magic.
* It's slow. Don't use it in a performance critical path.
+ *
+ * Override eval to define the behavior.
+ * Use calleval to invoke eval (this kludge is required to allow a
+ * python specific "shim" to be inserted.
*/
class gr_feval_dd
{
-public:
- gr_feval_dd() {}
- virtual ~gr_feval_dd();
-
+protected:
/*!
* \brief override this to define the function
*/
virtual double eval(double x);
+
+public:
+ gr_feval_dd() {}
+ virtual ~gr_feval_dd();
+
+ virtual double calleval(double x); // invoke "eval"
};
/*!
@@ -51,17 +58,24 @@ public:
* and is callable from both places. It uses SWIG's
* "director" feature to implement the magic.
* It's slow. Don't use it in a performance critical path.
+ *
+ * Override eval to define the behavior.
+ * Use calleval to invoke eval (this kludge is required to allow a
+ * python specific "shim" to be inserted.
*/
class gr_feval_cc
{
-public:
- gr_feval_cc() {}
- virtual ~gr_feval_cc();
-
+protected:
/*!
* \brief override this to define the function
*/
virtual gr_complex eval(gr_complex x);
+
+public:
+ gr_feval_cc() {}
+ virtual ~gr_feval_cc();
+
+ virtual gr_complex calleval(gr_complex x); // invoke "eval"
};
/*!
@@ -71,17 +85,24 @@ public:
* and is callable from both places. It uses SWIG's
* "director" feature to implement the magic.
* It's slow. Don't use it in a performance critical path.
+ *
+ * Override eval to define the behavior.
+ * Use calleval to invoke eval (this kludge is required to allow a
+ * python specific "shim" to be inserted.
*/
class gr_feval_ll
{
-public:
- gr_feval_ll() {}
- virtual ~gr_feval_ll();
-
+protected:
/*!
* \brief override this to define the function
*/
virtual long eval(long x);
+
+public:
+ gr_feval_ll() {}
+ virtual ~gr_feval_ll();
+
+ virtual long calleval(long x); // invoke "eval"
};
/*!
@@ -91,17 +112,24 @@ public:
* and is callable from both places. It uses SWIG's
* "director" feature to implement the magic.
* It's slow. Don't use it in a performance critical path.
+ *
+ * Override eval to define the behavior.
+ * Use calleval to invoke eval (this kludge is required to allow a
+ * python specific "shim" to be inserted.
*/
class gr_feval
{
-public:
- gr_feval() {}
- virtual ~gr_feval();
-
+protected:
/*!
* \brief override this to define the function
*/
virtual void eval();
+
+public:
+ gr_feval() {}
+ virtual ~gr_feval();
+
+ virtual void calleval(); // invoke "eval"
};
/*!
diff --git a/gnuradio-core/src/lib/general/gr_feval.i b/gnuradio-core/src/lib/general/gr_feval.i
index 09d98b648..9df276f66 100644
--- a/gnuradio-core/src/lib/general/gr_feval.i
+++ b/gnuradio-core/src/lib/general/gr_feval.i
@@ -20,53 +20,169 @@
* Boston, MA 02110-1301, USA.
*/
+
+/*
+ * N.B., this is a _very_ non-standard SWIG .i file
+ *
+ * It contains a bunch of magic that is required to ensure that when
+ * these classes are used as base classes for python code,
+ * everything works when calling back from C++ into Python.
+ *
+ * The gist of the problem is that our C++ code is usually not holding
+ * the Python Global Interpreter Lock (GIL). Thus if we invoke a
+ * "director" method from C++, we'll end up in Python not holding the
+ * GIL. Disaster (SIGSEGV) will result. To avoid this we insert a
+ * "shim" that grabs and releases the GIL.
+ *
+ * If you don't understand SWIG "directors" or the Python GIL,
+ * don't bother trying to understand what's going on in here.
+ *
+ * [We could eliminate a bunch of this hair by requiring SWIG 1.3.29
+ * or later and some additional magic declarations, but many systems
+ * aren't shipping that version yet. Thus we kludge...]
+ */
+
+
// Enable SWIG directors for these classes
-%feature("director") gr_feval_dd;
-%feature("director") gr_feval_cc;
-%feature("director") gr_feval_ll;
-%feature("director") gr_feval;
+%feature("director") gr_py_feval_dd;
+%feature("director") gr_py_feval_cc;
+%feature("director") gr_py_feval_ll;
+%feature("director") gr_py_feval;
+
+%feature("nodirector") gr_py_feval_dd::calleval;
+%feature("nodirector") gr_py_feval_cc::calleval;
+%feature("nodirector") gr_py_feval_ll::calleval;
+%feature("nodirector") gr_py_feval::calleval;
+
+
+%rename(feval_dd) gr_py_feval_dd;
+%rename(feval_cc) gr_py_feval_cc;
+%rename(feval_ll) gr_py_feval_ll;
+%rename(feval) gr_py_feval;
+
+//%exception {
+// try { $action }
+// catch (Swig::DirectorException &e) { std::cerr << e.getMessage(); SWIG_fail; }
+//}
+
+%{
+
+// class that ensures we acquire and release the Python GIL
+class ensure_py_gil_state {
+ PyGILState_STATE d_gstate;
+public:
+ ensure_py_gil_state() { d_gstate = PyGILState_Ensure(); }
+ ~ensure_py_gil_state() { PyGILState_Release(d_gstate); }
+};
+
+%}
-%rename(feval_dd) gr_feval_dd;
+/*
+ * These are the real C++ base classes, however we don't want these exposed.
+ */
+%ignore gr_feval_dd;
class gr_feval_dd
{
+protected:
+ virtual double eval(double x);
+
public:
gr_feval_dd() {}
virtual ~gr_feval_dd();
- virtual double eval(double x);
+ virtual double calleval(double x);
};
-%rename(feval_cc) gr_feval_cc;
+%ignore gr_feval_cc;
class gr_feval_cc
{
+protected:
+ virtual gr_complex eval(gr_complex x);
+
public:
gr_feval_cc() {}
virtual ~gr_feval_cc();
- virtual gr_complex eval(gr_complex x);
+ virtual gr_complex calleval(gr_complex x);
};
-%rename(feval_ll) gr_feval_ll;
+%ignore gr_feval_ll;
class gr_feval_ll
{
+protected:
+ virtual long eval(long x);
+
public:
gr_feval_ll() {}
virtual ~gr_feval_ll();
- virtual long eval(long x);
+ virtual long calleval(long x);
};
-%rename(feval) gr_feval;
+%ignore gr_feval;
class gr_feval
{
+protected:
+ virtual void eval();
+
public:
gr_feval() {}
virtual ~gr_feval();
- virtual void eval();
+ virtual void calleval();
+};
+
+/*
+ * These are the ones to derive from in Python. They have the magic shim
+ * that ensures that we're holding the Python GIL when we enter Python land...
+ */
+
+%inline %{
+
+class gr_py_feval_dd : public gr_feval_dd
+{
+ public:
+ double calleval(double x)
+ {
+ ensure_py_gil_state _lock;
+ return eval(x);
+ }
};
+class gr_py_feval_cc : public gr_feval_cc
+{
+ public:
+ gr_complex calleval(gr_complex x)
+ {
+ ensure_py_gil_state _lock;
+ return eval(x);
+ }
+};
+
+class gr_py_feval_ll : public gr_feval_ll
+{
+ public:
+ long calleval(long x)
+ {
+ ensure_py_gil_state _lock;
+ return eval(x);
+ }
+};
+
+class gr_py_feval : public gr_feval
+{
+ public:
+ void calleval()
+ {
+ ensure_py_gil_state _lock;
+ eval();
+ }
+};
+
+%}
+
+
// examples / test cases
diff --git a/gnuradio-core/src/python/gnuradio/gr/Makefile.am b/gnuradio-core/src/python/gnuradio/gr/Makefile.am
index ec91917b2..fcf026146 100644
--- a/gnuradio-core/src/python/gnuradio/gr/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/gr/Makefile.am
@@ -48,6 +48,7 @@ noinst_PYTHON = \
qa_add_v_and_friends.py \
qa_agc.py \
qa_basic_flow_graph.py \
+ qa_bin_statistics.py \
qa_cma_equalizer.py \
qa_complex_to_xxx.py \
qa_constellation_decoder_cb.py \
diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_bin_statistics.py b/gnuradio-core/src/python/gnuradio/gr/qa_bin_statistics.py
new file mode 100755
index 000000000..75cfc8308
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_bin_statistics.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python
+#
+# Copyright 2006 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 2, 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.
+#
+
+from gnuradio import gr, gr_unittest
+import random
+import struct
+
+#import os
+#print "pid =", os.getpid()
+#raw_input("Attach gdb and press return...")
+
+
+class counter(gr.feval_dd):
+ def __init__(self, step_size=1):
+ gr.feval_dd.__init__(self)
+ self.step_size = step_size
+ self.count = 0
+
+ def eval(self, input):
+ #print "eval: self.count =", self.count
+ t = self.count
+ self.count = self.count + self.step_size
+ return t
+
+
+class counter3(gr.feval_dd):
+ def __init__(self, f, step_size):
+ gr.feval_dd.__init__(self)
+ self.f = f
+ self.step_size = step_size
+ self.count = 0
+
+ def eval(self, input):
+ try:
+ #print "eval: self.count =", self.count
+ t = self.count
+ self.count = self.count + self.step_size
+ self.f(self.count)
+ except Exception, e:
+ print "Exception: ", e
+ return t
+
+def foobar3(new_t):
+ #print "foobar3: new_t =", new_t
+ pass
+
+
+class counter4(gr.feval_dd):
+ def __init__(self, obj_instance, step_size):
+ gr.feval_dd.__init__(self)
+ self.obj_instance = obj_instance
+ self.step_size = step_size
+ self.count = 0
+
+ def eval(self, input):
+ try:
+ #print "eval: self.count =", self.count
+ t = self.count
+ self.count = self.count + self.step_size
+ self.obj_instance.foobar4(self.count)
+ except Exception, e:
+ print "Exception: ", e
+ return t
+
+
+class parse_msg(object):
+ def __init__(self, msg):
+ self.center_freq = msg.arg1()
+ self.vlen = int(msg.arg2())
+ assert(msg.length() == self.vlen * gr.sizeof_float)
+ self.data = struct.unpack('%df' % (self.vlen,), msg.to_string())
+
+
+class test_bin_statistics(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.fg = gr.flow_graph ()
+
+ def tearDown(self):
+ self.fg = None
+
+ def test_001(self):
+ vlen = 4
+ tune = counter(1)
+ tune_delay = 0
+ dwell_delay = 1
+ msgq = gr.msg_queue()
+
+ src_data = tuple([float(x) for x in
+ ( 1, 2, 3, 4,
+ 5, 6, 7, 8,
+ 9, 10, 11, 12,
+ 13, 14, 15, 16
+ )])
+
+ expected_results = tuple([float(x) for x in
+ ( 1, 2, 3, 4,
+ 5, 6, 7, 8,
+ 9, 10, 11, 12,
+ 13, 14, 15, 16
+ )])
+
+ src = gr.vector_source_f(src_data, False)
+ s2v = gr.stream_to_vector(gr.sizeof_float, vlen)
+ stats = gr.bin_statistics_f(vlen, msgq, tune, tune_delay, dwell_delay)
+ self.fg.connect(src, s2v, stats)
+ self.fg.run()
+ self.assertEqual(4, msgq.count())
+ for i in range(4):
+ m = parse_msg(msgq.delete_head())
+ #print "m =", m.center_freq, m.data
+ self.assertEqual(expected_results[vlen*i:vlen*i + vlen], m.data)
+
+ def test_002(self):
+ vlen = 4
+ tune = counter(1)
+ tune_delay = 1
+ dwell_delay = 2
+ msgq = gr.msg_queue()
+
+ src_data = tuple([float(x) for x in
+ ( 1, 2, 3, 4,
+ 9, 6, 11, 8,
+ 5, 10, 7, 12,
+ 13, 14, 15, 16
+ )])
+
+ expected_results = tuple([float(x) for x in
+ ( 9, 10, 11, 12)])
+
+ src = gr.vector_source_f(src_data, False)
+ s2v = gr.stream_to_vector(gr.sizeof_float, vlen)
+ stats = gr.bin_statistics_f(vlen, msgq, tune, tune_delay, dwell_delay)
+ self.fg.connect(src, s2v, stats)
+ self.fg.run()
+ self.assertEqual(1, msgq.count())
+ for i in range(1):
+ m = parse_msg(msgq.delete_head())
+ #print "m =", m.center_freq, m.data
+ self.assertEqual(expected_results[vlen*i:vlen*i + vlen], m.data)
+
+
+
+ def test_003(self):
+ vlen = 4
+ tune = counter3(foobar3, 1)
+ tune_delay = 1
+ dwell_delay = 2
+ msgq = gr.msg_queue()
+
+ src_data = tuple([float(x) for x in
+ ( 1, 2, 3, 4,
+ 9, 6, 11, 8,
+ 5, 10, 7, 12,
+ 13, 14, 15, 16
+ )])
+
+ expected_results = tuple([float(x) for x in
+ ( 9, 10, 11, 12)])
+
+ src = gr.vector_source_f(src_data, False)
+ s2v = gr.stream_to_vector(gr.sizeof_float, vlen)
+ stats = gr.bin_statistics_f(vlen, msgq, tune, tune_delay, dwell_delay)
+ self.fg.connect(src, s2v, stats)
+ self.fg.run()
+ self.assertEqual(1, msgq.count())
+ for i in range(1):
+ m = parse_msg(msgq.delete_head())
+ #print "m =", m.center_freq, m.data
+ self.assertEqual(expected_results[vlen*i:vlen*i + vlen], m.data)
+
+
+ def foobar4(self, new_t):
+ #print "foobar4: new_t =", new_t
+ pass
+
+ def test_004(self):
+ vlen = 4
+ tune = counter4(self, 1)
+ tune_delay = 1
+ dwell_delay = 2
+ msgq = gr.msg_queue()
+
+ src_data = tuple([float(x) for x in
+ ( 1, 2, 3, 4,
+ 9, 6, 11, 8,
+ 5, 10, 7, 12,
+ 13, 14, 15, 16
+ )])
+
+ expected_results = tuple([float(x) for x in
+ ( 9, 10, 11, 12)])
+
+ src = gr.vector_source_f(src_data, False)
+ s2v = gr.stream_to_vector(gr.sizeof_float, vlen)
+ stats = gr.bin_statistics_f(vlen, msgq, tune, tune_delay, dwell_delay)
+ self.fg.connect(src, s2v, stats)
+ self.fg.run()
+ self.assertEqual(1, msgq.count())
+ for i in range(1):
+ m = parse_msg(msgq.delete_head())
+ #print "m =", m.center_freq, m.data
+ self.assertEqual(expected_results[vlen*i:vlen*i + vlen], m.data)
+
+
+if __name__ == '__main__':
+ gr_unittest.main ()
diff --git a/gnuradio-examples/python/usrp/usrp_spectrum_sense.py b/gnuradio-examples/python/usrp/usrp_spectrum_sense.py
new file mode 100755
index 000000000..87768649c
--- /dev/null
+++ b/gnuradio-examples/python/usrp/usrp_spectrum_sense.py
@@ -0,0 +1,241 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, gru, eng_notation, optfir, window
+from gnuradio import audio
+from gnuradio import usrp
+from gnuradio import blks
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import usrp_dbid
+import sys
+import math
+import struct
+
+
+class tune(gr.feval_dd):
+ """
+ This class allows C++ code to callback into python.
+ """
+ def __init__(self, fg):
+ gr.feval_dd.__init__(self)
+ self.fg = fg
+
+ def eval(self, ignore):
+ """
+ This method is called from gr.bin_statistics_f when it wants to change
+ the center frequency. This method tunes the front end to the new center
+ frequency, and returns the new frequency as its result.
+ """
+ try:
+ # We use this try block so that if something goes wrong from here
+ # down, at least we'll have a prayer of knowing what went wrong.
+ # Without this, you get a very mysterious:
+ #
+ # terminate called after throwing an instance of 'Swig::DirectorMethodException'
+ # Aborted
+ #
+ # message on stderr. Not exactly helpful ;)
+
+ new_freq = self.fg.set_next_freq()
+ return new_freq
+
+ except Exception, e:
+ print "tune: Exception: ", e
+
+
+class parse_msg(object):
+ def __init__(self, msg):
+ self.center_freq = msg.arg1()
+ self.vlen = int(msg.arg2())
+ assert(msg.length() == self.vlen * gr.sizeof_float)
+
+ # FIXME consider using Numarray or NumPy vector
+ t = msg.to_string()
+ self.raw_data = t
+ self.data = struct.unpack('%df' % (self.vlen,), t)
+
+
+class my_graph(gr.flow_graph):
+
+ def __init__(self):
+ gr.flow_graph.__init__(self)
+
+ usage = "usage: %prog [options] min_freq max_freq"
+ parser = OptionParser(option_class=eng_option, usage=usage)
+ parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=(0,0),
+ help="select USRP Rx side A or B (default=A)")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("", "--tune-delay", type="eng_float", default=1e-3, metavar="SECS",
+ help="time to delay (in seconds) after changing frequency [default=%default]")
+ parser.add_option("", "--dwell-delay", type="eng_float", default=10e-3, metavar="SECS",
+ help="time to dwell (in seconds) at a given frequncy [default=%default]")
+ parser.add_option("-F", "--fft-size", type="int", default=256,
+ help="specify number of FFT bins [default=%default]")
+ parser.add_option("-d", "--decim", type="intx", default=16,
+ help="set decimation to DECIM [default=%default]")
+ parser.add_option("", "--real-time", action="store_true", default=False,
+ help="Attempt to enable real-time scheduling")
+ parser.add_option("-B", "--fusb-block-size", type="int", default=0,
+ help="specify fast usb block size [default=%default]")
+ parser.add_option("-N", "--fusb-nblocks", type="int", default=0,
+ help="specify number of fast usb blocks [default=%default]")
+
+ (options, args) = parser.parse_args()
+ if len(args) != 2:
+ parser.print_help()
+ sys.exit(1)
+
+ self.min_freq = eng_notation.str_to_num(args[0])
+ self.max_freq = eng_notation.str_to_num(args[1])
+
+ if self.min_freq > self.max_freq:
+ self.min_freq, self.max_freq = self.max_freq, self.min_freq # swap them
+
+ self.fft_size = options.fft_size
+
+
+ if not options.real_time:
+ realtime = False
+ else:
+ # Attempt to enable realtime scheduling
+ r = gr.enable_realtime_scheduling()
+ if r == gr.RT_OK:
+ realtime = True
+ else:
+ realtime = False
+ print "Note: failed to enable realtime scheduling"
+
+ # If the user hasn't set the fusb_* parameters on the command line,
+ # pick some values that will reduce latency.
+
+ if 1:
+ if options.fusb_block_size == 0 and options.fusb_nblocks == 0:
+ if realtime: # be more aggressive
+ options.fusb_block_size = gr.prefs().get_long('fusb', 'rt_block_size', 1024)
+ options.fusb_nblocks = gr.prefs().get_long('fusb', 'rt_nblocks', 16)
+ else:
+ options.fusb_block_size = gr.prefs().get_long('fusb', 'block_size', 4096)
+ options.fusb_nblocks = gr.prefs().get_long('fusb', 'nblocks', 16)
+
+ #print "fusb_block_size =", options.fusb_block_size
+ #print "fusb_nblocks =", options.fusb_nblocks
+
+ # build graph
+
+ self.u = usrp.source_c(fusb_block_size=options.fusb_block_size,
+ fusb_nblocks=options.fusb_nblocks)
+
+
+ adc_rate = self.u.adc_rate() # 64 MS/s
+ usrp_decim = options.decim
+ self.u.set_decim_rate(usrp_decim)
+ usrp_rate = adc_rate / usrp_decim
+
+ self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec))
+ self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
+ print "Using RX d'board %s" % (self.subdev.side_and_name(),)
+
+
+ s2v = gr.stream_to_vector(gr.sizeof_gr_complex, self.fft_size)
+
+ mywindow = window.blackmanharris(self.fft_size)
+ fft = gr.fft_vcc(self.fft_size, True, mywindow)
+ power = 0
+ for tap in mywindow:
+ power += tap*tap
+
+ c2mag = gr.complex_to_mag_squared(self.fft_size)
+
+ # FIXME the log10 primitive is dog slow
+ log = gr.nlog10_ff(10, self.fft_size,
+ -20*math.log10(self.fft_size)-10*math.log10(power/self.fft_size))
+
+ # Set the freq_step to 75% of the actual data throughput.
+ # This allows us to discard the bins on both ends of the spectrum.
+
+ self.freq_step = 0.75 * usrp_rate
+ self.min_center_freq = self.min_freq + self.freq_step/2
+ self.max_center_freq = self.max_freq - self.freq_step/2
+
+ self.next_freq = self.min_center_freq
+
+ tune_delay = max(0, int(round(options.tune_delay * usrp_rate / self.fft_size))) # in fft_frames
+ dwell_delay = max(1, int(round(options.dwell_delay * usrp_rate / self.fft_size))) # in fft_frames
+
+ self.msgq = gr.msg_queue(16)
+ self._tune_callback = tune(self) # hang on to this to keep it from being GC'd
+ stats = gr.bin_statistics_f(self.fft_size, self.msgq,
+ self._tune_callback, tune_delay, dwell_delay)
+
+ # FIXME leave out the log10 until we speed it up
+ #self.connect(self.u, s2v, fft, c2mag, log, stats)
+ self.connect(self.u, s2v, fft, c2mag, stats)
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.subdev.gain_range()
+ options.gain = float(g[0]+g[1])/2
+
+ self.set_gain(options.gain)
+ print "gain =", options.gain
+
+
+ def set_next_freq(self):
+ target_freq = self.next_freq
+ self.next_freq = self.next_freq + self.freq_step
+ if self.next_freq > self.max_center_freq:
+ self.next_freq = self.min_center_freq
+
+ if not self.set_freq(target_freq):
+ print "Failed to set frequency to", target_freq
+
+ return target_freq
+
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+
+ Tuning is a two step process. First we ask the front-end to
+ tune as close to the desired frequency as it can. Then we use
+ the result of that operation and our target_frequency to
+ determine the value for the digital down converter.
+ """
+ return self.u.tune(0, self.subdev, target_freq)
+
+
+ def set_gain(self, gain):
+ self.subdev.set_gain(gain)
+
+
+def main_loop(fg):
+ while 1:
+
+ # Get the next message sent from the C++ code (blocking call).
+ # It contains the center frequency and the mag squared of the fft
+ m = parse_msg(fg.msgq.delete_head())
+
+ # Print center freq so we know that something is happening...
+ print m.center_freq
+
+ # FIXME do something useful with the data...
+
+ # m.data are the mag_squared of the fft output (they are in the
+ # standard order. I.e., bin 0 == DC.)
+ # You'll probably want to do the equivalent of "fftshift" on them
+ # m.raw_data is a string that contains the binary floats.
+ # You could write this as binary to a file.
+
+
+if __name__ == '__main__':
+ fg = my_graph()
+ try:
+ fg.start() # start executing flow graph in another thread...
+ main_loop(fg)
+
+ except KeyboardInterrupt:
+ pass
diff --git a/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc b/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc
index bfe44f17a..78be73533 100644
--- a/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc
+++ b/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc
@@ -55,12 +55,12 @@ static gr_feval_dd* l_pdf_fcn_1_bit;
static double pdf_fcn_0 (double x)
{
- return (l_pdf_fcn_0_bit->eval (x));
+ return (l_pdf_fcn_0_bit->calleval (x));
}
static double pdf_fcn_1 (double x)
{
- return (l_pdf_fcn_1_bit->eval (x));
+ return (l_pdf_fcn_1_bit->calleval (x));
}
ecc_syms_to_metrics::ecc_syms_to_metrics