diff options
-rw-r--r-- | gnuradio-core/src/lib/general/Makefile.am | 3 | ||||
-rw-r--r-- | gnuradio-core/src/lib/general/general.i | 2 | ||||
-rw-r--r-- | gnuradio-core/src/lib/general/gr_bin_statistics_f.cc | 173 | ||||
-rw-r--r-- | gnuradio-core/src/lib/general/gr_bin_statistics_f.h | 99 | ||||
-rw-r--r-- | gnuradio-core/src/lib/general/gr_bin_statistics_f.i | 42 | ||||
-rw-r--r-- | gnuradio-core/src/lib/general/gr_feval.cc | 38 | ||||
-rw-r--r-- | gnuradio-core/src/lib/general/gr_feval.h | 60 | ||||
-rw-r--r-- | gnuradio-core/src/lib/general/gr_feval.i | 140 | ||||
-rw-r--r-- | gnuradio-core/src/python/gnuradio/gr/Makefile.am | 1 | ||||
-rwxr-xr-x | gnuradio-core/src/python/gnuradio/gr/qa_bin_statistics.py | 226 | ||||
-rwxr-xr-x | gnuradio-examples/python/usrp/usrp_spectrum_sense.py | 241 | ||||
-rw-r--r-- | gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc | 4 |
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 |