diff options
165 files changed, 7031 insertions, 1374 deletions
diff --git a/config/grc_gr_qtgui.m4 b/config/grc_gr_qtgui.m4 index a4592fa41..ddb7c7ca9 100644 --- a/config/grc_gr_qtgui.m4 +++ b/config/grc_gr_qtgui.m4 @@ -47,12 +47,12 @@ AC_DEFUN([GRC_GR_QTGUI],[ if test $passed = yes; then dnl Check for package qt or qt-mt, set QT_CFLAGS and QT_LIBS - PKG_CHECK_MODULES(QTCORE, QtCore >= 4.2, [], - [passed=no; AC_MSG_RESULT([gr-qtgui requires libQtCore >= 4.2.])]) - PKG_CHECK_MODULES(QTGUI, QtGui >= 4.2, [], - [passed=no; AC_MSG_RESULT([gr-qtgui requires libQtGui >= 4.2.])]) - PKG_CHECK_MODULES(QTOPENGL, QtOpenGL >= 4.2, [], - [passed=no; AC_MSG_RESULT([gr-qtgui requires libQtOpenGL >- 4.2.])]) + PKG_CHECK_MODULES(QTCORE, QtCore >= 4.4, [], + [passed=no; AC_MSG_RESULT([gr-qtgui requires libQtCore >= 4.4.])]) + PKG_CHECK_MODULES(QTGUI, QtGui >= 4.4, [], + [passed=no; AC_MSG_RESULT([gr-qtgui requires libQtGui >= 4..])]) + PKG_CHECK_MODULES(QTOPENGL, QtOpenGL >= 4.4, [], + [passed=no; AC_MSG_RESULT([gr-qtgui requires libQtOpenGL >- 4.4.])]) dnl Fetch QWT variables GR_QWT([], [passed=no]) diff --git a/config/grc_gr_uhd.m4 b/config/grc_gr_uhd.m4 index 3cc9691e5..111b0ae43 100644 --- a/config/grc_gr_uhd.m4 +++ b/config/grc_gr_uhd.m4 @@ -40,6 +40,7 @@ AC_DEFUN([GRC_GR_UHD],[ AM_CONDITIONAL([GR_DEFINE_HAVE_UHD],[test $passed = yes]) AC_CONFIG_FILES([ \ + gr-uhd/gnuradio-uhd.pc \ gr-uhd/Makefile \ gr-uhd/grc/Makefile \ gr-uhd/include/Makefile \ @@ -47,6 +48,7 @@ AC_DEFUN([GRC_GR_UHD],[ gr-uhd/swig/Makefile \ gr-uhd/swig/run_tests \ gr-uhd/swig/run_guile_tests \ + gr-uhd/apps/Makefile \ ]) GRC_BUILD_CONDITIONAL(gr-uhd,[ diff --git a/config/grc_grc.m4 b/config/grc_grc.m4 index c21acccff..0474c4e89 100644 --- a/config/grc_grc.m4 +++ b/config/grc_grc.m4 @@ -34,17 +34,6 @@ AC_DEFUN([GRC_GRC],[ PYTHON_CHECK_MODULE([numpy],[NumPy],[],[passed=no],[True]) fi - dnl ######################################## - dnl # platform dependency pythonw - dnl ######################################## - dnl FIXME: move this test to Python config m4 - if test `${PYTHON} -c "import sys; print sys.platform"` = 'darwin'; then - PYTHONW=pythonw - else - PYTHONW=python - fi - AC_SUBST(PYTHONW) - AC_CONFIG_FILES([ \ grc/Makefile \ grc/base/Makefile \ diff --git a/config/grc_volk.m4 b/config/grc_volk.m4 index 1b3c54dd7..f349d5e99 100644 --- a/config/grc_volk.m4 +++ b/config/grc_volk.m4 @@ -21,19 +21,23 @@ AC_DEFUN([GRC_VOLK],[ GRC_ENABLE(volk) GRC_WITH(volk) - dnl volk uses a subsidiary configure.ac - AC_CONFIG_SUBDIRS([volk]) - - dnl If execution gets to here, $passed will be: - dnl with : if the --with code didn't error out + dnl If execution gets to here, test if $passed is: + dnl with : if the --with code didn't error out, use these values + dnl Test if $enable_volk is: dnl yes : if the --enable code passed muster and all dependencies are met - dnl no : otherwise - if test $passed != with; then + dnl no : otherwise, then do not set variables + if test $passed != with && test x$enable_volk == xyes; then dnl how and where to find INCLUDES and LA volk_INCLUDES="-I\${abs_top_srcdir}/volk/include" volk_LA="\${abs_top_builddir}/volk/lib/libvolk.la \ \${abs_top_builddir}/volk/lib/libvolk_runtime.la" fi + dnl volk uses a subsidiary configure.ac + dnl only run if building Volk + if test $passed == yes && test x$enable_volk != xno; then + AC_CONFIG_SUBDIRS([volk]) + fi + GRC_BUILD_CONDITIONAL(volk, []) ]) diff --git a/config/usrp_sdcc.m4 b/config/usrp_sdcc.m4 index 86f6429e5..3aae0bfa6 100644 --- a/config/usrp_sdcc.m4 +++ b/config/usrp_sdcc.m4 @@ -24,7 +24,7 @@ AC_DEFUN([USRP_SDCC], AC_CHECK_PROG(XAS, asx8051, asx8051 -plosgff,no) if test "$XCC" = "no" -o "$XAS" = "no" ; then - AC_MSG_RESULT([USRP requires sdcc. sdcc not found. See http://sdcc.sf.net]) + AC_MSG_RESULT([USRP requires sdcc version 2. sdcc not found. See http://sdcc.sf.net]) sdccok=no else sdcc_version_min=$1 diff --git a/gnuradio-core/src/lib/filter/Makefile.am b/gnuradio-core/src/lib/filter/Makefile.am index dee13e239..0314079a2 100644 --- a/gnuradio-core/src/lib/filter/Makefile.am +++ b/gnuradio-core/src/lib/filter/Makefile.am @@ -216,7 +216,9 @@ libfilter_la_common_SOURCES = \ gr_pfb_interpolator_ccf.cc \ gr_pfb_arb_resampler_ccf.cc \ gr_pfb_clock_sync_ccf.cc \ - gr_pfb_clock_sync_fff.cc + gr_pfb_clock_sync_fff.cc \ + gr_dc_blocker_cc.cc \ + gr_dc_blocker_ff.cc libfilter_qa_la_common_SOURCES = \ qa_filter.cc \ @@ -306,7 +308,9 @@ grinclude_HEADERS = \ gr_pfb_interpolator_ccf.h \ gr_pfb_arb_resampler_ccf.h \ gr_pfb_clock_sync_ccf.h \ - gr_pfb_clock_sync_fff.h + gr_pfb_clock_sync_fff.h \ + gr_dc_blocker_cc.h \ + gr_dc_blocker_ff.h noinst_HEADERS = \ assembly.h \ @@ -372,6 +376,8 @@ swiginclude_HEADERS = \ gr_pfb_arb_resampler_ccf.i \ gr_pfb_clock_sync_ccf.i \ gr_pfb_clock_sync_fff.i \ + gr_dc_blocker_cc.i \ + gr_dc_blocker_ff.i \ $(GENERATED_I) diff --git a/gnuradio-core/src/lib/filter/filter.i b/gnuradio-core/src/lib/filter/filter.i index 645607cba..58bb4f0d5 100644 --- a/gnuradio-core/src/lib/filter/filter.i +++ b/gnuradio-core/src/lib/filter/filter.i @@ -39,6 +39,8 @@ #include <gr_pfb_arb_resampler_ccf.h> #include <gr_pfb_clock_sync_ccf.h> #include <gr_pfb_clock_sync_fff.h> +#include <gr_dc_blocker_cc.h> +#include <gr_dc_blocker_ff.h> %} %include "gr_iir_filter_ffd.i" @@ -62,5 +64,7 @@ %include "gr_pfb_arb_resampler_ccf.i" %include "gr_pfb_clock_sync_ccf.i" %include "gr_pfb_clock_sync_fff.i" +%include "gr_dc_blocker_cc.i" +%include "gr_dc_blocker_ff.i" %include "filter_generated.i" diff --git a/gnuradio-core/src/lib/filter/gr_dc_blocker_cc.cc b/gnuradio-core/src/lib/filter/gr_dc_blocker_cc.cc new file mode 100644 index 000000000..e7d5ced25 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_dc_blocker_cc.cc @@ -0,0 +1,138 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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_dc_blocker_cc.h> +#include <gr_io_signature.h> +#include <cstdio> + +moving_averager_c::moving_averager_c(int D) + : d_length(D), d_out(0), d_out_d1(0), d_out_d2(0) +{ + d_delay_line = std::deque<gr_complex>(d_length-1, gr_complex(0,0)); +} + +moving_averager_c::~moving_averager_c() +{ +} + +gr_complex +moving_averager_c::filter(gr_complex x) +{ + d_out_d1 = d_out; + d_delay_line.push_back(x); + d_out = d_delay_line[0]; + d_delay_line.pop_front(); + + gr_complex y = x - d_out_d1 + d_out_d2; + d_out_d2 = y; + + return (y / (float)(d_length)); +} + + + +gr_dc_blocker_cc_sptr gr_make_dc_blocker_cc (int D, bool long_form) +{ + return gnuradio::get_initial_sptr(new gr_dc_blocker_cc(D, long_form)); +} + + +gr_dc_blocker_cc::gr_dc_blocker_cc (int D, bool long_form) + : gr_sync_block ("dc_blocker_cc", + gr_make_io_signature (1, 1, sizeof(gr_complex)), + gr_make_io_signature (1, 1, sizeof(gr_complex))), + d_length(D), d_long_form(long_form) +{ + if(d_long_form) { + d_ma_0 = new moving_averager_c(D); + d_ma_1 = new moving_averager_c(D); + d_ma_2 = new moving_averager_c(D); + d_ma_3 = new moving_averager_c(D); + d_delay_line = std::deque<gr_complex>(d_length-1, gr_complex(0,0)); + } + else { + d_ma_0 = new moving_averager_c(D); + d_ma_1 = new moving_averager_c(D); + } +} + +gr_dc_blocker_cc::~gr_dc_blocker_cc() +{ + if(d_long_form) { + delete d_ma_0; + delete d_ma_1; + delete d_ma_2; + delete d_ma_3; + } + else { + delete d_ma_0; + delete d_ma_1; + } +} + +int +gr_dc_blocker_cc::get_group_delay() +{ + if(d_long_form) + return (2*d_length-2); + else + return d_length - 1; +} + +int +gr_dc_blocker_cc::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + + if(d_long_form) { + gr_complex y1, y2, y3, y4, d; + for(int i = 0; i < noutput_items; i++) { + y1 = d_ma_0->filter(in[i]); + y2 = d_ma_1->filter(y1); + y3 = d_ma_2->filter(y2); + y4 = d_ma_3->filter(y3); + + d_delay_line.push_back(d_ma_0->delayed_sig()); + d = d_delay_line[0]; + d_delay_line.pop_front(); + + out[i] = d - y4; + } + } + else { + gr_complex y1, y2; + for(int i = 0; i < noutput_items; i++) { + y1 = d_ma_0->filter(in[i]); + y2 = d_ma_1->filter(y1); + out[i] = d_ma_0->delayed_sig() - y2; + } + } + + return noutput_items; +} diff --git a/gnuradio-core/src/lib/filter/gr_dc_blocker_cc.h b/gnuradio-core/src/lib/filter/gr_dc_blocker_cc.h new file mode 100644 index 000000000..de9ccc0ea --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_dc_blocker_cc.h @@ -0,0 +1,111 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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_DC_BLOCKER_CC_H +#define INCLUDED_GR_DC_BLOCKER_CC_H + +#include <gr_sync_block.h> +#include <deque> + +class gr_dc_blocker_cc; +typedef boost::shared_ptr<gr_dc_blocker_cc> gr_dc_blocker_cc_sptr; +gr_dc_blocker_cc_sptr gr_make_dc_blocker_cc (int D=32, bool long_form=true); + +/*! + * \class gr_dc_blocker_cc + * \brief a computationally efficient controllabel DC blocker + * + * \ingroup filter_blk + * + * This block implements a computationally efficient DC blocker that produces + * a tigher notch filter around DC for a smaller group delay than an + * equivalent FIR filter or using a single pole IIR filter (though the IIR + * filter is computationally cheaper). + * + * The block defaults to using a delay line of length 32 and the long form + * of the filter. Optionally, the delay line length can be changed to alter + * the width of the DC notch (longer lines will decrease the width). + * + * The long form of the filter produces a nearly flat response outside of + * the notch but at the cost of a group delay of 2D-2. + * + * The short form of the filter does not have as flat a response in the + * passband but has a group delay of only D-1 and is cheaper to compute. + * + * The theory behind this block can be found in the paper: + * + * <B><EM>R. Yates, "DC Blocker Algorithms," IEEE Signal Processing Magazine, + * Mar. 2008, pp 132-134.</EM></B> + */ +class moving_averager_c +{ +public: + moving_averager_c(int D); + ~moving_averager_c(); + + gr_complex filter(gr_complex x); + gr_complex delayed_sig() { return d_out; } + +private: + int d_length; + gr_complex d_out, d_out_d1, d_out_d2; + std::deque<gr_complex> d_delay_line; +}; + +class gr_dc_blocker_cc : public gr_sync_block +{ + private: + /*! + * Build the DC blocker. + * \param D (int) the length of the delay line + * \param long_form (bool) whether to use long (true, default) or short form + * \param channel (unsigned integer) Selects the channel to return [default=0]. + */ + friend gr_dc_blocker_cc_sptr gr_make_dc_blocker_cc (int D, bool long_form); + + int d_length; + bool d_long_form; + moving_averager_c *d_ma_0; + moving_averager_c *d_ma_1; + moving_averager_c *d_ma_2; + moving_averager_c *d_ma_3; + std::deque<gr_complex> d_delay_line; + + gr_dc_blocker_cc (int D, bool long_form); + +public: + ~gr_dc_blocker_cc (); + + /*! + * Get the blocker's group delay that is based on length of delay lines + */ + int get_group_delay(); + + //int set_length(int D); + + 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/filter/gr_dc_blocker_cc.i b/gnuradio-core/src/lib/filter/gr_dc_blocker_cc.i new file mode 100644 index 000000000..b88fecbde --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_dc_blocker_cc.i @@ -0,0 +1,34 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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,dc_blocker_cc); + +gr_dc_blocker_cc_sptr gr_make_dc_blocker_cc (int D=32, bool long_form=true); + +class gr_dc_blocker_cc : public gr_sync_block +{ + private: + gr_dc_blocker_cc (int D, bool long_form); + + public: + ~gr_dc_blocker_cc (); +}; diff --git a/gnuradio-core/src/lib/filter/gr_dc_blocker_ff.cc b/gnuradio-core/src/lib/filter/gr_dc_blocker_ff.cc new file mode 100644 index 000000000..d684bc7e8 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_dc_blocker_ff.cc @@ -0,0 +1,138 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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_dc_blocker_ff.h> +#include <gr_io_signature.h> +#include <cstdio> + +moving_averager_f::moving_averager_f(int D) + : d_length(D), d_out(0), d_out_d1(0), d_out_d2(0) +{ + d_delay_line = std::deque<float>(d_length-1, 0); +} + +moving_averager_f::~moving_averager_f() +{ +} + +float +moving_averager_f::filter(float x) +{ + d_out_d1 = d_out; + d_delay_line.push_back(x); + d_out = d_delay_line[0]; + d_delay_line.pop_front(); + + float y = x - d_out_d1 + d_out_d2; + d_out_d2 = y; + + return (y / (float)(d_length)); +} + + + +gr_dc_blocker_ff_sptr gr_make_dc_blocker_ff (int D, bool long_form) +{ + return gnuradio::get_initial_sptr(new gr_dc_blocker_ff(D, long_form)); +} + + +gr_dc_blocker_ff::gr_dc_blocker_ff (int D, bool long_form) + : gr_sync_block ("dc_blocker_ff", + gr_make_io_signature (1, 1, sizeof(float)), + gr_make_io_signature (1, 1, sizeof(float))), + d_length(D), d_long_form(long_form) +{ + if(d_long_form) { + d_ma_0 = new moving_averager_f(D); + d_ma_1 = new moving_averager_f(D); + d_ma_2 = new moving_averager_f(D); + d_ma_3 = new moving_averager_f(D); + d_delay_line = std::deque<float>(d_length-1, 0); + } + else { + d_ma_0 = new moving_averager_f(D); + d_ma_1 = new moving_averager_f(D); + } +} + +gr_dc_blocker_ff::~gr_dc_blocker_ff() +{ + if(d_long_form) { + delete d_ma_0; + delete d_ma_1; + delete d_ma_2; + delete d_ma_3; + } + else { + delete d_ma_0; + delete d_ma_1; + } +} + +int +gr_dc_blocker_ff::get_group_delay() +{ + if(d_long_form) + return (2*d_length-2); + else + return d_length - 1; +} + +int +gr_dc_blocker_ff::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]; + float *out = (float*)output_items[0]; + + if(d_long_form) { + float y1, y2, y3, y4, d; + for(int i = 0; i < noutput_items; i++) { + y1 = d_ma_0->filter(in[i]); + y2 = d_ma_1->filter(y1); + y3 = d_ma_2->filter(y2); + y4 = d_ma_3->filter(y3); + + d_delay_line.push_back(d_ma_0->delayed_sig()); + d = d_delay_line[0]; + d_delay_line.pop_front(); + + out[i] = d - y4; + } + } + else { + float y1, y2; + for(int i = 0; i < noutput_items; i++) { + y1 = d_ma_0->filter(in[i]); + y2 = d_ma_1->filter(y1); + out[i] = d_ma_0->delayed_sig() - y2; + } + } + + return noutput_items; +} diff --git a/gnuradio-core/src/lib/filter/gr_dc_blocker_ff.h b/gnuradio-core/src/lib/filter/gr_dc_blocker_ff.h new file mode 100644 index 000000000..b632d81da --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_dc_blocker_ff.h @@ -0,0 +1,111 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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_DC_BLOCKER_FF_H +#define INCLUDED_GR_DC_BLOCKER_FF_H + +#include <gr_sync_block.h> +#include <deque> + +class gr_dc_blocker_ff; +typedef boost::shared_ptr<gr_dc_blocker_ff> gr_dc_blocker_ff_sptr; +gr_dc_blocker_ff_sptr gr_make_dc_blocker_ff (int D=32, bool long_form=true); + +/*! + * \class gr_dc_blocker_ff + * \brief a computationally efficient controllabel DC blocker + * + * \ingroup filter_blk + * + * This block implements a computationally efficient DC blocker that produces + * a tigher notch filter around DC for a smaller group delay than an + * equivalent FIR filter or using a single pole IIR filter (though the IIR + * filter is computationally cheaper). + * + * The block defaults to using a delay line of length 32 and the long form + * of the filter. Optionally, the delay line length can be changed to alter + * the width of the DC notch (longer lines will decrease the width). + * + * The long form of the filter produces a nearly flat response outside of + * the notch but at the cost of a group delay of 2D-2. + * + * The short form of the filter does not have as flat a response in the + * passband but has a group delay of only D-1 and is cheaper to compute. + * + * The theory behind this block can be found in the paper: + * + * <B><EM>R. Yates, "DC Blocker Algorithms," IEEE Signal Processing Magazine, + * Mar. 2008, pp 132-134.</EM></B> + */ +class moving_averager_f +{ +public: + moving_averager_f(int D); + ~moving_averager_f(); + + float filter(float x); + float delayed_sig() { return d_out; } + +private: + int d_length; + float d_out, d_out_d1, d_out_d2; + std::deque<float> d_delay_line; +}; + +class gr_dc_blocker_ff : public gr_sync_block +{ + private: + /*! + * Build the DC blocker. + * \param D (int) the length of the delay line + * \param long_form (bool) whether to use long (true, default) or short form + * \param channel (unsigned integer) Selects the channel to return [default=0]. + */ + friend gr_dc_blocker_ff_sptr gr_make_dc_blocker_ff (int D, bool long_form); + + int d_length; + bool d_long_form; + moving_averager_f *d_ma_0; + moving_averager_f *d_ma_1; + moving_averager_f *d_ma_2; + moving_averager_f *d_ma_3; + std::deque<float> d_delay_line; + + gr_dc_blocker_ff (int D, bool long_form); + +public: + ~gr_dc_blocker_ff (); + + /*! + * Get the blocker's group delay that is based on length of delay lines + */ + int get_group_delay(); + + //int set_length(int D); + + 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/filter/gr_dc_blocker_ff.i b/gnuradio-core/src/lib/filter/gr_dc_blocker_ff.i new file mode 100644 index 000000000..032145c9e --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_dc_blocker_ff.i @@ -0,0 +1,34 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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,dc_blocker_ff); + +gr_dc_blocker_ff_sptr gr_make_dc_blocker_ff (int D=32, bool long_form=true); + +class gr_dc_blocker_ff : public gr_sync_block +{ + private: + gr_dc_blocker_ff (int D, bool long_form); + + public: + ~gr_dc_blocker_ff (); +}; diff --git a/gnuradio-core/src/lib/general/gr_frequency_modulator_fc.h b/gnuradio-core/src/lib/general/gr_frequency_modulator_fc.h index 4ba05d709..55f8412ce 100644 --- a/gnuradio-core/src/lib/general/gr_frequency_modulator_fc.h +++ b/gnuradio-core/src/lib/general/gr_frequency_modulator_fc.h @@ -47,7 +47,9 @@ class gr_frequency_modulator_fc : public gr_sync_block gr_frequency_modulator_fc (double sensitivity); public: - + void set_sensitivity(float sens) { d_sensitivity = sens; } + float get_sensitivity() { return d_sensitivity; } + int work (int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); diff --git a/gnuradio-core/src/lib/general/gr_frequency_modulator_fc.i b/gnuradio-core/src/lib/general/gr_frequency_modulator_fc.i index 612b59026..04d9a41ba 100644 --- a/gnuradio-core/src/lib/general/gr_frequency_modulator_fc.i +++ b/gnuradio-core/src/lib/general/gr_frequency_modulator_fc.i @@ -28,4 +28,7 @@ class gr_frequency_modulator_fc : public gr_sync_block { private: gr_frequency_modulator_fc (double sensitivity); +public: + void set_sensitivity(float sens) { d_sensitivity = sens; } + float get_sensitivity() { return d_sensitivity; } }; diff --git a/gnuradio-core/src/python/gnuradio/gr/Makefile.am b/gnuradio-core/src/python/gnuradio/gr/Makefile.am index f1b4ba2b1..45c970227 100644 --- a/gnuradio-core/src/python/gnuradio/gr/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/gr/Makefile.am @@ -55,6 +55,7 @@ noinst_PYTHON = \ qa_copy.py \ qa_correlate_access_code.py \ qa_delay.py \ + qa_dc_blocker.py \ qa_diff_encoder.py \ qa_diff_phasor_cc.py \ qa_ecc_ccsds_27.py \ diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_dc_blocker.py b/gnuradio-core/src/python/gnuradio/gr/qa_dc_blocker.py new file mode 100755 index 000000000..8977b475a --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/gr/qa_dc_blocker.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# +# Copyright 2011 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. +# + +from gnuradio import gr, gr_unittest + +class test_dc_blocker(gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_001(self): + ''' Test impulse response - long form, cc ''' + src_data = [1,] + 100*[0,] + expected_result = ((-0.02072429656982422+0j), (-0.02081298828125+0j), + (0.979156494140625+0j), (-0.02081298828125+0j), + (-0.02072429656982422+0j)) + + src = gr.vector_source_c(src_data) + op = gr.dc_blocker_cc(32, True) + dst = gr.vector_sink_c() + + self.tb.connect (src, op, dst) + self.tb.run() + + # only test samples around 2D-2 + result_data = dst.data()[60:65] + self.assertFloatTuplesAlmostEqual (expected_result, result_data) + + def test_002(self): + ''' Test impulse response - short form, cc ''' + src_data = [1,] + 100*[0,] + expected_result = ((-0.029296875+0j), (-0.0302734375+0j), + (0.96875+0j), (-0.0302734375+0j), + (-0.029296875+0j)) + + src = gr.vector_source_c(src_data) + op = gr.dc_blocker_cc(32, False) + dst = gr.vector_sink_c() + + self.tb.connect (src, op, dst) + self.tb.run() + + # only test samples around D-1 + result_data = dst.data()[29:34] + self.assertFloatTuplesAlmostEqual (expected_result, result_data) + + + def test_003(self): + ''' Test impulse response - long form, ff ''' + src_data = [1,] + 100*[0,] + expected_result = ((-0.02072429656982422), (-0.02081298828125), + (0.979156494140625), (-0.02081298828125), + (-0.02072429656982422)) + + src = gr.vector_source_f(src_data) + op = gr.dc_blocker_ff(32, True) + dst = gr.vector_sink_f() + + self.tb.connect (src, op, dst) + self.tb.run() + + # only test samples around 2D-2 + result_data = dst.data()[60:65] + self.assertFloatTuplesAlmostEqual (expected_result, result_data) + + def test_004(self): + ''' Test impulse response - short form, ff ''' + src_data = [1,] + 100*[0,] + expected_result = ((-0.029296875), (-0.0302734375), + (0.96875), (-0.0302734375), + (-0.029296875)) + + src = gr.vector_source_f(src_data) + op = gr.dc_blocker_ff(32, False) + dst = gr.vector_sink_f() + + self.tb.connect (src, op, dst) + self.tb.run() + + # only test samples around D-1 + result_data = dst.data()[29:34] + self.assertFloatTuplesAlmostEqual (expected_result, result_data) + +if __name__ == '__main__': + gr_unittest.run(test_dc_blocker, "test_dc_blocker.xml") + diff --git a/gnuradio-examples/grc/Makefile.am b/gnuradio-examples/grc/Makefile.am index 118ecd593..d9a0d9c2c 100644 --- a/gnuradio-examples/grc/Makefile.am +++ b/gnuradio-examples/grc/Makefile.am @@ -39,8 +39,7 @@ simpledatadir = $(grc_examples_prefix)/simple dist_simpledata_DATA = \ simple/ber_simulation.grc \ simple/dpsk_loopback.grc \ - simple/variable_config.grc \ - simple/var_sink_taps.grc + simple/variable_config.grc trellisdatadir = $(grc_examples_prefix)/trellis dist_trellisdata_DATA = \ diff --git a/gnuradio-examples/grc/simple/var_sink_taps.grc b/gnuradio-examples/grc/simple/var_sink_taps.grc deleted file mode 100644 index 07207850e..000000000 --- a/gnuradio-examples/grc/simple/var_sink_taps.grc +++ /dev/null @@ -1,488 +0,0 @@ -<?xml version='1.0' encoding='ASCII'?> -<flow_graph> - <timestamp>Tue May 19 16:45:51 2009</timestamp> - <block> - <key>options</key> - <param> - <key>id</key> - <value>var_sink_taps</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>title</key> - <value>Variable Sink + Taps</value> - </param> - <param> - <key>author</key> - <value>Example</value> - </param> - <param> - <key>description</key> - <value>gnuradio flow graph</value> - </param> - <param> - <key>window_size</key> - <value>1280, 1024</value> - </param> - <param> - <key>generate_options</key> - <value>wx_gui</value> - </param> - <param> - <key>category</key> - <value>Custom</value> - </param> - <param> - <key>realtime_scheduling</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(10, 10)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>gr_noise_source_x</key> - <param> - <key>id</key> - <value>gr_noise_source_x_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>noise_type</key> - <value>gr.GR_GAUSSIAN</value> - </param> - <param> - <key>amp</key> - <value>1</value> - </param> - <param> - <key>seed</key> - <value>42</value> - </param> - <param> - <key>_coordinate</key> - <value>(619, 36)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>gr_fir_filter_xxx</key> - <param> - <key>id</key> - <value>gr_fir_filter_xxx_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>ccc</value> - </param> - <param> - <key>decim</key> - <value>1</value> - </param> - <param> - <key>taps</key> - <value>dest_taps</value> - </param> - <param> - <key>_coordinate</key> - <value>(831, 47)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>gr_throttle</key> - <param> - <key>id</key> - <value>gr_throttle_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>samples_per_second</key> - <value>samp_rate</value> - </param> - <param> - <key>vlen</key> - <value>1</value> - </param> - <param> - <key>_coordinate</key> - <value>(999, 198)</value> - </param> - <param> - <key>_rotation</key> - <value>270</value> - </param> - </block> - <block> - <key>wxgui_fftsink2</key> - <param> - <key>id</key> - <value>wxgui_fftsink2_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>title</key> - <value>FFT Plot</value> - </param> - <param> - <key>samp_rate</key> - <value>samp_rate</value> - </param> - <param> - <key>baseband_freq</key> - <value>0</value> - </param> - <param> - <key>y_per_div</key> - <value>10</value> - </param> - <param> - <key>y_divs</key> - <value>10</value> - </param> - <param> - <key>ref_level</key> - <value>50</value> - </param> - <param> - <key>fft_size</key> - <value>1024</value> - </param> - <param> - <key>fft_rate</key> - <value>30</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>grid_pos</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(629, 184)</value> - </param> - <param> - <key>_rotation</key> - <value>180</value> - </param> - </block> - <block> - <key>import</key> - <param> - <key>id</key> - <value>import_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>import</key> - <value>from gnuradio.gr import firdes</value> - </param> - <param> - <key>_coordinate</key> - <value>(330, 120)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable</key> - <param> - <key>id</key> - <value>dest_taps</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>value</key> - <value>[0]</value> - </param> - <param> - <key>_coordinate</key> - <value>(836, 223)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable</key> - <param> - <key>id</key> - <value>samp_rate</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>value</key> - <value>32000</value> - </param> - <param> - <key>_coordinate</key> - <value>(831, 130)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable</key> - <param> - <key>id</key> - <value>source_taps</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>value</key> - <value>firdes.low_pass(1, samp_rate, 4000, 2000)</value> - </param> - <param> - <key>_coordinate</key> - <value>(397, 191)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable</key> - <param> - <key>id</key> - <value>taps_rate</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>value</key> - <value>10</value> - </param> - <param> - <key>_coordinate</key> - <value>(268, 189)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>gr_vector_source_x</key> - <param> - <key>id</key> - <value>gr_vector_source_x_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>vector</key> - <value>source_taps</value> - </param> - <param> - <key>repeat</key> - <value>True</value> - </param> - <param> - <key>vlen</key> - <value>len(source_taps)</value> - </param> - <param> - <key>_coordinate</key> - <value>(205, 33)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>note</key> - <param> - <key>id</key> - <value>note_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>note</key> - <value>Pass the FIR taps via a variable sink.</value> - </param> - <param> - <key>_coordinate</key> - <value>(14, 141)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>gr_throttle</key> - <param> - <key>id</key> - <value>gr_throttle</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>samples_per_second</key> - <value>taps_rate</value> - </param> - <param> - <key>vlen</key> - <value>len(source_taps)</value> - </param> - <param> - <key>_coordinate</key> - <value>(440, 41)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>blks2_variable_sink_x</key> - <param> - <key>id</key> - <value>blks2_variable_sink_x_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>complex</value> - </param> - <param> - <key>variable</key> - <value>dest_taps</value> - </param> - <param> - <key>decim</key> - <value>1</value> - </param> - <param> - <key>vlen</key> - <value>len(source_taps)</value> - </param> - <param> - <key>_coordinate</key> - <value>(305, 283)</value> - </param> - <param> - <key>_rotation</key> - <value>180</value> - </param> - </block> - <connection> - <source_block_id>gr_noise_source_x_0</source_block_id> - <sink_block_id>gr_fir_filter_xxx_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> - <connection> - <source_block_id>gr_fir_filter_xxx_0</source_block_id> - <sink_block_id>gr_throttle_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> - <connection> - <source_block_id>gr_throttle_0</source_block_id> - <sink_block_id>wxgui_fftsink2_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> - <connection> - <source_block_id>gr_vector_source_x_0</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>gr_throttle</source_block_id> - <sink_block_id>blks2_variable_sink_x_0</sink_block_id> - <source_key>0</source_key> - <sink_key>0</sink_key> - </connection> -</flow_graph> diff --git a/gnuradio-examples/python/usrp2/usrp2_wfm_rcv.py b/gnuradio-examples/python/usrp2/usrp2_wfm_rcv.py index 1783660d6..2b94c458e 100755 --- a/gnuradio-examples/python/usrp2/usrp2_wfm_rcv.py +++ b/gnuradio-examples/python/usrp2/usrp2_wfm_rcv.py @@ -87,7 +87,8 @@ class wfm_rx_block (stdgui2.std_top_block): dbid == 0x0040 or #usrp_dbid.TV_RX_REV_3 dbid == 0x0043 or #usrp_dbid.TV_RX_MIMO dbid == 0x0044 or #usrp_dbid.TV_RX_REV_2_MIMO - dbid == 0x0045 ): #usrp_dbid.TV_RX_REV_3_MIMO + dbid == 0x0045 or #usrp_dbid.TV_RX_REV_3_MIMO + dbid == 0x0053 ): #usrp_dbid.WBX print "This daughterboard does not cover the required frequency range" print "for this application. Please use a BasicRX or TVRX daughterboard." raw_input("Press ENTER to continue anyway, or Ctrl-C to exit.") diff --git a/gr-audio/include/gr_audio_api.h b/gr-audio/include/gr_audio_api.h index b21819bab..65782d308 100644 --- a/gr-audio/include/gr_audio_api.h +++ b/gr-audio/include/gr_audio_api.h @@ -22,10 +22,12 @@ #ifndef INCLUDED_GR_AUDIO_API_H #define INCLUDED_GR_AUDIO_API_H +#include <gruel/attributes.h> + #ifdef gnuradio_audio_EXPORTS -# define GR_AUDIO_API //FIXME needs attributes defines +# define GR_AUDIO_API __GR_ATTR_EXPORT #else -# define GR_AUDIO_API //FIXME needs attributes defines +# define GR_AUDIO_API __GR_ATTR_IMPORT #endif #endif /* INCLUDED_GR_AUDIO_API_H */ diff --git a/gr-qtgui/apps/Makefile.am b/gr-qtgui/apps/Makefile.am index c8d967334..7b35d949e 100644 --- a/gr-qtgui/apps/Makefile.am +++ b/gr-qtgui/apps/Makefile.am @@ -30,6 +30,7 @@ nodist_bin_SCRIPTS = \ noinst_PYTHON = \ pyqt_example_f.py \ pyqt_example_c.py \ + pyqt_time_c.py \ qt_digital.py \ qt_digital_window.py \ usrp2_display.py \ diff --git a/gr-qtgui/apps/pyqt_example_c.py b/gr-qtgui/apps/pyqt_example_c.py index e1b58442f..607ab12ee 100755 --- a/gr-qtgui/apps/pyqt_example_c.py +++ b/gr-qtgui/apps/pyqt_example_c.py @@ -145,5 +145,6 @@ class my_top_block(gr.top_block): if __name__ == "__main__": tb = my_top_block(); tb.start() - sys.exit(tb.qapp.exec_()) + tb.qapp.exec_() + tb.stop() diff --git a/gr-qtgui/apps/pyqt_example_f.py b/gr-qtgui/apps/pyqt_example_f.py index 6b2131019..2d957c85a 100755 --- a/gr-qtgui/apps/pyqt_example_f.py +++ b/gr-qtgui/apps/pyqt_example_f.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from gnuradio import gr, blks2 +from gnuradio import gr from gnuradio import qtgui from PyQt4 import QtGui, QtCore import sys, sip @@ -117,6 +117,8 @@ class my_top_block(gr.top_block): src2 = gr.sig_source_f(Rs, gr.GR_SIN_WAVE, f2, 0.1, 0) src = gr.add_ff() thr = gr.throttle(gr.sizeof_float, 100*fftsize) + noise = gr.noise_source_f(gr.GR_GAUSSIAN, 0.001) + add = gr.add_ff() self.snk1 = qtgui.sink_f(fftsize, gr.firdes.WIN_BLACKMAN_hARRIS, 0, Rs, "Float Signal Example", @@ -124,7 +126,9 @@ class my_top_block(gr.top_block): self.connect(src1, (src,0)) self.connect(src2, (src,1)) - self.connect(src, thr, self.snk1) + self.connect(src, thr, (add,0)) + self.connect(noise, (add,1)) + self.connect(add, self.snk1) self.ctrl_win = control_box() self.ctrl_win.attach_signal1(src1) @@ -144,5 +148,5 @@ class my_top_block(gr.top_block): if __name__ == "__main__": tb = my_top_block(); tb.start() - sys.exit(tb.qapp.exec_()) - + tb.qapp.exec_() + tb.stop() diff --git a/gr-qtgui/apps/pyqt_time_c.py b/gr-qtgui/apps/pyqt_time_c.py new file mode 100755 index 000000000..fa7d60e81 --- /dev/null +++ b/gr-qtgui/apps/pyqt_time_c.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python + +from gnuradio import gr +from gnuradio import qtgui +from PyQt4 import QtGui, QtCore +import sys, sip + +class dialog_box(QtGui.QWidget): + def __init__(self, display, control): + QtGui.QWidget.__init__(self, None) + self.setWindowTitle('PyQt Test GUI') + + self.boxlayout = QtGui.QBoxLayout(QtGui.QBoxLayout.LeftToRight, self) + self.boxlayout.addWidget(display, 1) + self.boxlayout.addWidget(control) + + self.resize(800, 500) + +class control_box(QtGui.QWidget): + def __init__(self, parent=None): + QtGui.QWidget.__init__(self, parent) + self.setWindowTitle('Control Panel') + + self.setToolTip('Control the signals') + QtGui.QToolTip.setFont(QtGui.QFont('OldEnglish', 10)) + + self.layout = QtGui.QFormLayout(self) + + # Control the first signal + self.freq1Edit = QtGui.QLineEdit(self) + self.freq1Edit.setMinimumWidth(100) + self.layout.addRow("Signal 1 Frequency:", self.freq1Edit) + self.connect(self.freq1Edit, QtCore.SIGNAL("editingFinished()"), + self.freq1EditText) + + self.amp1Edit = QtGui.QLineEdit(self) + self.amp1Edit.setMinimumWidth(100) + self.layout.addRow("Signal 1 Amplitude:", self.amp1Edit) + self.connect(self.amp1Edit, QtCore.SIGNAL("editingFinished()"), + self.amp1EditText) + + + # Control the second signal + self.freq2Edit = QtGui.QLineEdit(self) + self.freq2Edit.setMinimumWidth(100) + self.layout.addRow("Signal 2 Frequency:", self.freq2Edit) + self.connect(self.freq2Edit, QtCore.SIGNAL("editingFinished()"), + self.freq2EditText) + + + self.amp2Edit = QtGui.QLineEdit(self) + self.amp2Edit.setMinimumWidth(100) + self.layout.addRow("Signal 2 Amplitude:", self.amp2Edit) + self.connect(self.amp2Edit, QtCore.SIGNAL("editingFinished()"), + self.amp2EditText) + + self.quit = QtGui.QPushButton('Close', self) + self.quit.setMinimumWidth(100) + self.layout.addWidget(self.quit) + + self.connect(self.quit, QtCore.SIGNAL('clicked()'), + QtGui.qApp, QtCore.SLOT('quit()')) + + def attach_signal1(self, signal): + self.signal1 = signal + self.freq1Edit.setText(QtCore.QString("%1").arg(self.signal1.frequency())) + self.amp1Edit.setText(QtCore.QString("%1").arg(self.signal1.amplitude())) + + def attach_signal2(self, signal): + self.signal2 = signal + self.freq2Edit.setText(QtCore.QString("%1").arg(self.signal2.frequency())) + self.amp2Edit.setText(QtCore.QString("%1").arg(self.signal2.amplitude())) + + def freq1EditText(self): + try: + newfreq = float(self.freq1Edit.text()) + self.signal1.set_frequency(newfreq) + except ValueError: + print "Bad frequency value entered" + + def amp1EditText(self): + try: + newamp = float(self.amp1Edit.text()) + self.signal1.set_amplitude(newamp) + except ValueError: + print "Bad amplitude value entered" + + + def freq2EditText(self): + try: + newfreq = float(self.freq2Edit.text()) + self.signal2.set_frequency(newfreq) + except ValueError: + print "Bad frequency value entered" + + def amp2EditText(self): + try: + newamp = float(self.amp2Edit.text()) + self.signal2.set_amplitude(newamp) + except ValueError: + print "Bad amplitude value entered" + + +class my_top_block(gr.top_block): + def __init__(self): + gr.top_block.__init__(self) + + Rs = 8000 + f1 = 100 + f2 = 200 + + npts = 2048 + + self.qapp = QtGui.QApplication(sys.argv) + + src1 = gr.sig_source_c(Rs, gr.GR_SIN_WAVE, f1, 0.1, 0) + src2 = gr.sig_source_c(Rs, gr.GR_SIN_WAVE, f2, 0.1, 0) + src = gr.add_cc() + channel = gr.channel_model(0.01) + thr = gr.throttle(gr.sizeof_gr_complex, 100*npts) + self.snk1 = qtgui.time_sink_c(npts, Rs, + "Complex Time Example", 3) + + self.connect(src1, (src,0)) + self.connect(src2, (src,1)) + self.connect(src, channel, thr, (self.snk1, 0)) + self.connect(src1, (self.snk1, 1)) + self.connect(src2, (self.snk1, 2)) + + self.ctrl_win = control_box() + self.ctrl_win.attach_signal1(src1) + self.ctrl_win.attach_signal2(src2) + + # Get the reference pointer to the SpectrumDisplayForm QWidget + pyQt = self.snk1.pyqwidget() + + # Wrap the pointer as a PyQt SIP object + # This can now be manipulated as a PyQt4.QtGui.QWidget + pyWin = sip.wrapinstance(pyQt, QtGui.QWidget) + + # Example of using signal/slot to set the title of a curve + pyWin.connect(pyWin, QtCore.SIGNAL("setTitle(int, QString)"), + pyWin, QtCore.SLOT("setTitle(int, QString)")) + pyWin.emit(QtCore.SIGNAL("setTitle(int, QString)"), 0, "Re{sum}") + self.snk1.set_title(1, "Im{Sum}") + self.snk1.set_title(2, "Re{src1}") + self.snk1.set_title(3, "Im{src1}") + self.snk1.set_title(4, "Re{src2}") + self.snk1.set_title(5, "Im{src2}") + + # Can also set the color of a curve + #self.snk1.set_color(5, "blue") + + #pyWin.show() + self.main_box = dialog_box(pyWin, self.ctrl_win) + self.main_box.show() + +if __name__ == "__main__": + tb = my_top_block(); + tb.start() + tb.qapp.exec_() + tb.stop() + diff --git a/gr-qtgui/apps/pyqt_time_f.py b/gr-qtgui/apps/pyqt_time_f.py new file mode 100755 index 000000000..1b9efa10d --- /dev/null +++ b/gr-qtgui/apps/pyqt_time_f.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python + +from gnuradio import gr +from gnuradio import qtgui +from PyQt4 import QtGui, QtCore +import sys, sip + +class dialog_box(QtGui.QWidget): + def __init__(self, display, control): + QtGui.QWidget.__init__(self, None) + self.setWindowTitle('PyQt Test GUI') + + self.boxlayout = QtGui.QBoxLayout(QtGui.QBoxLayout.LeftToRight, self) + self.boxlayout.addWidget(display, 1) + self.boxlayout.addWidget(control) + + self.resize(800, 500) + +class control_box(QtGui.QWidget): + def __init__(self, parent=None): + QtGui.QWidget.__init__(self, parent) + self.setWindowTitle('Control Panel') + + self.setToolTip('Control the signals') + QtGui.QToolTip.setFont(QtGui.QFont('OldEnglish', 10)) + + self.layout = QtGui.QFormLayout(self) + + # Control the first signal + self.freq1Edit = QtGui.QLineEdit(self) + self.freq1Edit.setMinimumWidth(100) + self.layout.addRow("Signal 1 Frequency:", self.freq1Edit) + self.connect(self.freq1Edit, QtCore.SIGNAL("editingFinished()"), + self.freq1EditText) + + self.amp1Edit = QtGui.QLineEdit(self) + self.amp1Edit.setMinimumWidth(100) + self.layout.addRow("Signal 1 Amplitude:", self.amp1Edit) + self.connect(self.amp1Edit, QtCore.SIGNAL("editingFinished()"), + self.amp1EditText) + + + # Control the second signal + self.freq2Edit = QtGui.QLineEdit(self) + self.freq2Edit.setMinimumWidth(100) + self.layout.addRow("Signal 2 Frequency:", self.freq2Edit) + self.connect(self.freq2Edit, QtCore.SIGNAL("editingFinished()"), + self.freq2EditText) + + + self.amp2Edit = QtGui.QLineEdit(self) + self.amp2Edit.setMinimumWidth(100) + self.layout.addRow("Signal 2 Amplitude:", self.amp2Edit) + self.connect(self.amp2Edit, QtCore.SIGNAL("editingFinished()"), + self.amp2EditText) + + self.quit = QtGui.QPushButton('Close', self) + self.quit.setMinimumWidth(100) + self.layout.addWidget(self.quit) + + self.connect(self.quit, QtCore.SIGNAL('clicked()'), + QtGui.qApp, QtCore.SLOT('quit()')) + + def attach_signal1(self, signal): + self.signal1 = signal + self.freq1Edit.setText(QtCore.QString("%1").arg(self.signal1.frequency())) + self.amp1Edit.setText(QtCore.QString("%1").arg(self.signal1.amplitude())) + + def attach_signal2(self, signal): + self.signal2 = signal + self.freq2Edit.setText(QtCore.QString("%1").arg(self.signal2.frequency())) + self.amp2Edit.setText(QtCore.QString("%1").arg(self.signal2.amplitude())) + + def freq1EditText(self): + try: + newfreq = float(self.freq1Edit.text()) + self.signal1.set_frequency(newfreq) + except ValueError: + print "Bad frequency value entered" + + def amp1EditText(self): + try: + newamp = float(self.amp1Edit.text()) + self.signal1.set_amplitude(newamp) + except ValueError: + print "Bad amplitude value entered" + + + def freq2EditText(self): + try: + newfreq = float(self.freq2Edit.text()) + self.signal2.set_frequency(newfreq) + except ValueError: + print "Bad frequency value entered" + + def amp2EditText(self): + try: + newamp = float(self.amp2Edit.text()) + self.signal2.set_amplitude(newamp) + except ValueError: + print "Bad amplitude value entered" + + +class my_top_block(gr.top_block): + def __init__(self): + gr.top_block.__init__(self) + + Rs = 8000 + f1 = 100 + f2 = 200 + + npts = 2048 + + self.qapp = QtGui.QApplication(sys.argv) + + src1 = gr.sig_source_f(Rs, gr.GR_SIN_WAVE, f1, 0.1, 0) + src2 = gr.sig_source_f(Rs, gr.GR_SIN_WAVE, f2, 0.1, 0) + src = gr.add_ff() + thr = gr.throttle(gr.sizeof_float, 100*npts) + noise = gr.noise_source_f(gr.GR_GAUSSIAN, 0.001) + add = gr.add_ff() + self.snk1 = qtgui.time_sink_f(npts, Rs, + "Complex Time Example", 3) + + self.connect(src1, (src,0)) + self.connect(src2, (src,1)) + self.connect(src, thr, (add,0)) + self.connect(noise, (add,1)) + self.connect(add, self.snk1) + self.connect(src1, (self.snk1, 1)) + self.connect(src2, (self.snk1, 2)) + + self.ctrl_win = control_box() + self.ctrl_win.attach_signal1(src1) + self.ctrl_win.attach_signal2(src2) + + # Get the reference pointer to the SpectrumDisplayForm QWidget + pyQt = self.snk1.pyqwidget() + + # Wrap the pointer as a PyQt SIP object + # This can now be manipulated as a PyQt4.QtGui.QWidget + pyWin = sip.wrapinstance(pyQt, QtGui.QWidget) + + # Example of using signal/slot to set the title of a curve + pyWin.connect(pyWin, QtCore.SIGNAL("setTitle(int, QString)"), + pyWin, QtCore.SLOT("setTitle(int, QString)")) + pyWin.emit(QtCore.SIGNAL("setTitle(int, QString)"), 0, "sum") + self.snk1.set_title(1, "src1") + self.snk1.set_title(2, "src2") + + # Can also set the color of a curve + #self.snk1.set_color(5, "blue") + + #pyWin.show() + self.main_box = dialog_box(pyWin, self.ctrl_win) + self.main_box.show() + +if __name__ == "__main__": + tb = my_top_block(); + tb.start() + tb.qapp.exec_() + tb.stop() + diff --git a/gr-qtgui/apps/qt_digital.py b/gr-qtgui/apps/qt_digital.py index c6920a05d..99c799f2a 100755 --- a/gr-qtgui/apps/qt_digital.py +++ b/gr-qtgui/apps/qt_digital.py @@ -274,3 +274,4 @@ if __name__ == "__main__": tb = my_top_block(); tb.start() tb.qapp.exec_() + tb.stop() diff --git a/gr-qtgui/grc/Makefile.am b/gr-qtgui/grc/Makefile.am index b3114268c..ccd459a13 100644 --- a/gr-qtgui/grc/Makefile.am +++ b/gr-qtgui/grc/Makefile.am @@ -29,5 +29,6 @@ dist_grcblocks_DATA = \ qtgui_label.xml \ qtgui_range.xml \ qtgui_sink_x.xml \ + qtgui_time_sink_x.xml \ qtgui_tab_widget.xml \ qtgui_chooser.xml diff --git a/gr-qtgui/grc/qtgui_time_sink_x.xml b/gr-qtgui/grc/qtgui_time_sink_x.xml new file mode 100644 index 000000000..9c8da6fbc --- /dev/null +++ b/gr-qtgui/grc/qtgui_time_sink_x.xml @@ -0,0 +1,78 @@ +<?xml version="1.0"?> +<!-- +################################################### +##QT GUI Sink +################################################### + --> +<block> + <name>QT GUI Time Sink</name> + <key>qtgui_time_sink_x</key> + <category>QT GUI Widgets</category> + <import>from PyQt4 import Qt</import> + <import>from gnuradio.qtgui import qtgui</import> + <import>from gnuradio.gr import firdes</import> + <import>import sip</import> + <make>#set $win = 'self._%s_win'%$id +qtgui.$(type.fcn)( + $size, \#size + $bw, \#bw + $name, \#name + $nconnections \#number of inputs +) +self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget) +$(gui_hint()($win))</make> + <callback>set_time_domain_axis($min, $max)</callback> + <callback>set_update_time($t)</callback> + <callback>set_title($which, $title)</callback> + <callback>set_color($which, $color)</callback> + <param> + <name>Type</name> + <key>type</key> + <value>complex</value> + <type>enum</type> + <option><name>Complex</name><key>complex</key><opt>fcn:time_sink_c</opt></option> + <option><name>Float</name><key>float</key><opt>fcn:time_sink_f</opt></option> + </param> + <param> + <name>Name</name> + <key>name</key> + <value>QT GUI Plot</value> + <type>string</type> + </param> + <param> + <name>Number of Points</name> + <key>size</key> + <value>1024</value> + <type>int</type> + </param> + <param> + <name>Bandwidth (Hz)</name> + <key>bw</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>Number of Inputs</name> + <key>nconnections</key> + <value>1</value> + <type>int</type> + <hide>part</hide> + </param> + <param> + <name>GUI Hint</name> + <key>gui_hint</key> + <value></value> + <type>gui_hint</type> + <hide>part</hide> + </param> + <sink> + <name>in</name> + <type>$type</type> + <nports>$nconnections</nports> + </sink> + <doc> +The GUI hint can be used to position the widget within the application. \ +The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. \ +Both the tab specification and the grid position are optional. + </doc> +</block> diff --git a/gr-qtgui/lib/ConstellationDisplayPlot.cc b/gr-qtgui/lib/ConstellationDisplayPlot.cc index 75dbe9c37..dda7cfea2 100644 --- a/gr-qtgui/lib/ConstellationDisplayPlot.cc +++ b/gr-qtgui/lib/ConstellationDisplayPlot.cc @@ -1,3 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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 CONSTELLATION_DISPLAY_PLOT_C #define CONSTELLATION_DISPLAY_PLOT_C @@ -36,7 +58,7 @@ protected: ConstellationDisplayPlot::ConstellationDisplayPlot(QWidget* parent) : QwtPlot(parent) { - timespec_reset(&_lastReplot); + _lastReplot = 0; resize(parent->width(), parent->height()); @@ -161,8 +183,8 @@ void ConstellationDisplayPlot::PlotNewData(const double* realDataPoints, const double timeInterval) { if((numDataPoints > 0) && - (diff_timespec(get_highres_clock(), _lastReplot) > timeInterval)) { - + (gruel::high_res_timer_now() - _lastReplot > timeInterval*gruel::high_res_timer_tps())) { + if(numDataPoints != _numPoints){ _numPoints = numDataPoints; @@ -177,7 +199,7 @@ void ConstellationDisplayPlot::PlotNewData(const double* realDataPoints, memcpy(_realDataPoints, realDataPoints, numDataPoints*sizeof(double)); memcpy(_imagDataPoints, imagDataPoints, numDataPoints*sizeof(double)); - _lastReplot = get_highres_clock(); + _lastReplot = gruel::high_res_timer_now(); } } diff --git a/gr-qtgui/lib/ConstellationDisplayPlot.h b/gr-qtgui/lib/ConstellationDisplayPlot.h index bf4531e0a..23004f86c 100644 --- a/gr-qtgui/lib/ConstellationDisplayPlot.h +++ b/gr-qtgui/lib/ConstellationDisplayPlot.h @@ -1,6 +1,29 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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 CONSTELLATION_DISPLAY_PLOT_HPP #define CONSTELLATION_DISPLAY_PLOT_HPP +#include <stdint.h> #include <cstdio> #include <qwt_plot.h> #include <qwt_painter.h> @@ -11,7 +34,7 @@ #include <qwt_plot_zoomer.h> #include <qwt_plot_panner.h> #include <qwt_plot_marker.h> -#include <highResTimeFunctions.h> +#include <gruel/high_res_timer.h> #include <qwt_symbol.h> #include <qtgui_util.h> @@ -60,7 +83,7 @@ private: double* _realDataPoints; double* _imagDataPoints; - timespec _lastReplot; + gruel::high_res_timer_type _lastReplot; int64_t _numPoints; int64_t _penSize; diff --git a/gr-qtgui/lib/FrequencyDisplayPlot.cc b/gr-qtgui/lib/FrequencyDisplayPlot.cc index 30b318184..f57edd8f6 100644 --- a/gr-qtgui/lib/FrequencyDisplayPlot.cc +++ b/gr-qtgui/lib/FrequencyDisplayPlot.cc @@ -1,3 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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 FREQUENCY_DISPLAY_PLOT_C #define FREQUENCY_DISPLAY_PLOT_C @@ -98,7 +120,7 @@ FrequencyDisplayPlot::FrequencyDisplayPlot(QWidget* parent) _startFrequency = 0; _stopFrequency = 4000; - timespec_reset(&_lastReplot); + _lastReplot = 0; resize(parent->width(), parent->height()); @@ -340,7 +362,7 @@ FrequencyDisplayPlot::PlotNewData(const double* dataPoints, const int64_t numDat { // Only update plot if there is data and if the time interval has elapsed if((numDataPoints > 0) && - (diff_timespec(get_highres_clock(), _lastReplot) > timeInterval)) { + (gruel::high_res_timer_now() - _lastReplot > timeInterval*gruel::high_res_timer_tps())) { if(numDataPoints != _numPoints) { _numPoints = numDataPoints; @@ -379,7 +401,7 @@ FrequencyDisplayPlot::PlotNewData(const double* dataPoints, const int64_t numDat SetUpperIntensityLevel(_peakAmplitude); - _lastReplot = get_highres_clock(); + _lastReplot = gruel::high_res_timer_now(); } } diff --git a/gr-qtgui/lib/FrequencyDisplayPlot.h b/gr-qtgui/lib/FrequencyDisplayPlot.h index 7a207ab8d..a263fec2f 100644 --- a/gr-qtgui/lib/FrequencyDisplayPlot.h +++ b/gr-qtgui/lib/FrequencyDisplayPlot.h @@ -1,3 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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 FREQUENCY_DISPLAY_PLOT_HPP #define FREQUENCY_DISPLAY_PLOT_HPP @@ -13,7 +35,7 @@ #include <qwt_plot_panner.h> #include <qwt_plot_marker.h> #include <qwt_plot_magnifier.h> -#include <highResTimeFunctions.h> +#include <gruel/high_res_timer.h> #include <qwt_symbol.h> #include <qtgui_util.h> @@ -100,7 +122,7 @@ private: double _noiseFloorAmplitude; - timespec _lastReplot; + gruel::high_res_timer_type _lastReplot; bool _useCenterFrequencyFlag; }; diff --git a/gr-qtgui/lib/Makefile.am b/gr-qtgui/lib/Makefile.am index 7dee39eb4..849ee8360 100644 --- a/gr-qtgui/lib/Makefile.am +++ b/gr-qtgui/lib/Makefile.am @@ -24,12 +24,14 @@ include $(top_srcdir)/Makefile.common EXTRA_DIST += spectrumdisplayform.ui AM_CPPFLAGS = -I. $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) \ - $(QT_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES) + $(QT_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES) \ + -Dlibgnuradio_qtgui_EXPORTS # Only include these files in the build if qtgui passes configure checks # This is mostly to help make distcheck pass QMAKE_SOURCES = \ spectrumdisplayform.moc.cc \ + timedisplayform.moc.cc \ FrequencyDisplayPlot.moc.cc \ TimeDomainDisplayPlot.moc.cc \ WaterfallDisplayPlot.moc.cc \ @@ -49,11 +51,14 @@ libgnuradio_qtgui_la_SOURCES = \ waterfallGlobalData.cc \ ConstellationDisplayPlot.cc \ spectrumdisplayform.cc \ + timedisplayform.cc \ SpectrumGUIClass.cc \ spectrumUpdateEvents.cc \ plot_waterfall.cc \ qtgui_sink_c.cc \ qtgui_sink_f.cc \ + qtgui_time_sink_c.cc \ + qtgui_time_sink_f.cc \ qtgui_util.cc nodist_libgnuradio_qtgui_la_SOURCES=$(QMAKE_SOURCES) @@ -65,13 +70,16 @@ grinclude_HEADERS = \ WaterfallDisplayPlot.h \ waterfallGlobalData.h \ ConstellationDisplayPlot.h \ - highResTimeFunctions.h \ plot_waterfall.h \ spectrumdisplayform.h \ + timedisplayform.h \ SpectrumGUIClass.h \ spectrumUpdateEvents.h \ + gr_qtgui_api.h \ qtgui_sink_c.h \ qtgui_sink_f.h \ + qtgui_time_sink_c.h \ + qtgui_time_sink_f.h \ qtgui_util.h #QT_MOC_FLAGS=-DQT_SHARED -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_GUI_LIB -DQT_CORE_LIB diff --git a/gr-qtgui/lib/SpectrumGUIClass.cc b/gr-qtgui/lib/SpectrumGUIClass.cc index 1a519591d..af95e2bb2 100644 --- a/gr-qtgui/lib/SpectrumGUIClass.cc +++ b/gr-qtgui/lib/SpectrumGUIClass.cc @@ -1,3 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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 SPECTRUM_GUI_CLASS_CPP #define SPECTRUM_GUI_CLASS_CPP @@ -32,7 +54,7 @@ SpectrumGUIClass::SpectrumGUIClass(const uint64_t maxDataSize, _windowType = 5; - timespec_reset(&_lastGUIUpdateTime); + _lastGUIUpdateTime = 0; _windowOpennedFlag = false; _fftBuffersCreatedFlag = false; @@ -101,10 +123,10 @@ SpectrumGUIClass::OpenSpectrumWindow(QWidget* parent, qApp->postEvent(_spectrumDisplayForm, new QEvent(QEvent::Type(QEvent::User+3))); - timespec_reset(&_lastGUIUpdateTime); + _lastGUIUpdateTime = 0; // Draw Blank Display - UpdateWindow(false, NULL, 0, NULL, 0, NULL, 0, get_highres_clock(), true); + UpdateWindow(false, NULL, 0, NULL, 0, NULL, 0, gruel::high_res_timer_now(), true); // Set up the initial frequency axis settings SetFrequencyRange(_centerFrequency, _startFrequency, _stopFrequency); @@ -207,7 +229,7 @@ SpectrumGUIClass::UpdateWindow(const bool updateDisplayFlag, const uint64_t realTimeDomainDataSize, const float* complexTimeDomainData, const uint64_t complexTimeDomainDataSize, - const timespec timestamp, + const gruel::high_res_timer_type timestamp, const bool lastOfMultipleFFTUpdateFlag) { //gruel::scoped_lock lock(d_mutex); @@ -261,11 +283,11 @@ SpectrumGUIClass::UpdateWindow(const bool updateDisplayFlag, _lastDataPointCount = bufferSize; } - const timespec currentTime = get_highres_clock(); - const timespec lastUpdateGUITime = GetLastGUIUpdateTime(); + const gruel::high_res_timer_type currentTime = gruel::high_res_timer_now(); + const gruel::high_res_timer_type lastUpdateGUITime = GetLastGUIUpdateTime(); - if((diff_timespec(currentTime, lastUpdateGUITime) > (4*_updateTime)) && - (GetPendingGUIUpdateEvents() > 0) && !timespec_empty(&lastUpdateGUITime)) { + if((currentTime - lastUpdateGUITime > (4*_updateTime)*gruel::high_res_timer_tps()) && + (GetPendingGUIUpdateEvents() > 0) && lastUpdateGUITime != 0) { // Do not update the display if too much data is pending to be displayed _droppedEntriesCount++; } @@ -354,17 +376,17 @@ SpectrumGUIClass::SetFFTSize(const int newSize) _fftSize = newSize; } -timespec +gruel::high_res_timer_type SpectrumGUIClass::GetLastGUIUpdateTime() { gruel::scoped_lock lock(d_mutex); - timespec returnValue; + gruel::high_res_timer_type returnValue; returnValue = _lastGUIUpdateTime; return returnValue; } void -SpectrumGUIClass::SetLastGUIUpdateTime(const timespec newTime) +SpectrumGUIClass::SetLastGUIUpdateTime(const gruel::high_res_timer_type newTime) { gruel::scoped_lock lock(d_mutex); _lastGUIUpdateTime = newTime; diff --git a/gr-qtgui/lib/SpectrumGUIClass.h b/gr-qtgui/lib/SpectrumGUIClass.h index 48f45a0f5..857c2515f 100644 --- a/gr-qtgui/lib/SpectrumGUIClass.h +++ b/gr-qtgui/lib/SpectrumGUIClass.h @@ -1,3 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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 SPECTRUM_GUI_CLASS_HPP #define SPECTRUM_GUI_CLASS_HPP @@ -44,7 +66,7 @@ public: const uint64_t, const float*, const uint64_t, const float*, const uint64_t, - const timespec, const bool); + const gruel::high_res_timer_type, const bool); float GetPowerValue(); void SetPowerValue(const float); @@ -56,8 +78,8 @@ public: int GetFFTSizeIndex(); void SetFFTSize(const int); - timespec GetLastGUIUpdateTime(); - void SetLastGUIUpdateTime(const timespec); + gruel::high_res_timer_type GetLastGUIUpdateTime(); + void SetLastGUIUpdateTime(const gruel::high_res_timer_type); unsigned int GetPendingGUIUpdateEvents(); void IncrementPendingGUIUpdateEvents(); @@ -92,7 +114,7 @@ private: int _windowType; int64_t _lastDataPointCount; int _fftSize; - timespec _lastGUIUpdateTime; + gruel::high_res_timer_type _lastGUIUpdateTime; unsigned int _pendingGUIUpdateEventsCount; int _droppedEntriesCount; bool _fftBuffersCreatedFlag; diff --git a/gr-qtgui/lib/TimeDomainDisplayPlot.cc b/gr-qtgui/lib/TimeDomainDisplayPlot.cc index be25a6cde..f635a2b0c 100644 --- a/gr-qtgui/lib/TimeDomainDisplayPlot.cc +++ b/gr-qtgui/lib/TimeDomainDisplayPlot.cc @@ -1,3 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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 TIME_DOMAIN_DISPLAY_PLOT_C #define TIME_DOMAIN_DISPLAY_PLOT_C @@ -5,7 +27,8 @@ #include <qwt_scale_draw.h> #include <qwt_legend.h> - +#include <QColor> +#include <iostream> class TimePrecisionClass { @@ -70,16 +93,14 @@ private: std::string _unitType; }; -TimeDomainDisplayPlot::TimeDomainDisplayPlot(QWidget* parent):QwtPlot(parent) +TimeDomainDisplayPlot::TimeDomainDisplayPlot(int nplots, QWidget* parent) + : QwtPlot(parent), _nplots(nplots) { - timespec_reset(&_lastReplot); - resize(parent->width(), parent->height()); _numPoints = 1024; - _realDataPoints = new double[_numPoints]; - _imagDataPoints = new double[_numPoints]; _xAxisPoints = new double[_numPoints]; + memset(_xAxisPoints, 0x0, _numPoints*sizeof(double)); _zoomer = new TimeDomainDisplayZoomer(canvas(), 0); _zoomer->setSelectionFlags(QwtPicker::RectSelection | QwtPicker::DragSelection); @@ -96,41 +117,40 @@ TimeDomainDisplayPlot::TimeDomainDisplayPlot(QWidget* parent):QwtPlot(parent) canvas()->setPalette(palette); setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine); - set_xaxis(0, _numPoints); + setXaxis(0, _numPoints); setAxisTitle(QwtPlot::xBottom, "Time (sec)"); setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); - set_yaxis(-2.0, 2.0); - setAxisTitle(QwtPlot::yLeft, "Normalized Voltage"); + setYaxis(-2.0, 2.0); + setAxisTitle(QwtPlot::yLeft, "Amplitude"); + QList<QColor> colors; + colors << QColor(Qt::blue) << QColor(Qt::red) << QColor(Qt::green) + << QColor(Qt::black) << QColor(Qt::cyan) << QColor(Qt::magenta) + << QColor(Qt::yellow) << QColor(Qt::gray) << QColor(Qt::darkRed) + << QColor(Qt::darkGreen) << QColor(Qt::darkBlue) << QColor(Qt::darkGray); + + int ncolors = colors.size(); + + // Setup dataPoints and plot vectors // Automatically deleted when parent is deleted - _real_plot_curve = new QwtPlotCurve("Real Data"); - _real_plot_curve->attach(this); - _real_plot_curve->setPen(QPen(Qt::blue)); - _real_plot_curve->setRawData(_xAxisPoints, _realDataPoints, _numPoints); - - _imag_plot_curve = new QwtPlotCurve("Imaginary Data"); - _imag_plot_curve->attach(this); - _imag_plot_curve->setPen(QPen(Qt::magenta)); - _imag_plot_curve->setRawData(_xAxisPoints, _imagDataPoints, _numPoints); - // _imag_plot_curve->setVisible(false); - - memset(_realDataPoints, 0x0, _numPoints*sizeof(double)); - memset(_imagDataPoints, 0x0, _numPoints*sizeof(double)); - memset(_xAxisPoints, 0x0, _numPoints*sizeof(double)); + for(int i = 0; i < _nplots; i++) { + _dataPoints.push_back(new double[_numPoints]); + memset(_dataPoints[i], 0x0, _numPoints*sizeof(double)); + + _plot_curve.push_back(new QwtPlotCurve(QString("Data %1").arg(i))); + _plot_curve[i]->attach(this); + _plot_curve[i]->setPen(QPen(colors[i])); + _plot_curve[i]->setRawData(_xAxisPoints, _dataPoints[i], _numPoints); + } _sampleRate = 1; _resetXAxisPoints(); -#if QT_VERSION < 0x040000 - _zoomer->setMousePattern(QwtEventPattern::MouseSelect2, - Qt::RightButton, Qt::ControlModifier); -#else _zoomer->setMousePattern(QwtEventPattern::MouseSelect2, - Qt::RightButton, Qt::ControlModifier); -#endif + Qt::RightButton, Qt::ControlModifier); _zoomer->setMousePattern(QwtEventPattern::MouseSelect3, - Qt::RightButton); + Qt::RightButton); _panner = new QwtPlotPanner(canvas()); _panner->setAxisEnabled(QwtPlot::yRight, false); @@ -164,29 +184,40 @@ TimeDomainDisplayPlot::TimeDomainDisplayPlot(QWidget* parent):QwtPlot(parent) this, SLOT( LegendEntryChecked(QwtPlotItem *, bool ) )); } -TimeDomainDisplayPlot::~TimeDomainDisplayPlot(){ - delete[] _realDataPoints; - delete[] _imagDataPoints; +TimeDomainDisplayPlot::~TimeDomainDisplayPlot() +{ + for(int i = 0; i < _nplots; i++) + delete [] _dataPoints[i]; delete[] _xAxisPoints; - // _fft_plot_curves deleted when parent deleted // _zoomer and _panner deleted when parent deleted } void -TimeDomainDisplayPlot::set_yaxis(double min, double max) +TimeDomainDisplayPlot::setYaxis(double min, double max) { setAxisScale(QwtPlot::yLeft, min, max); _zoomer->setZoomBase(); } void -TimeDomainDisplayPlot::set_xaxis(double min, double max) +TimeDomainDisplayPlot::setXaxis(double min, double max) { setAxisScale(QwtPlot::xBottom, min, max); _zoomer->setZoomBase(); } +void +TimeDomainDisplayPlot::setTitle(int which, QString title) +{ + _plot_curve[which]->setTitle(title); +} + +void +TimeDomainDisplayPlot::setColor(int which, QString color) +{ + _plot_curve[which]->setPen(QPen(color)); +} void TimeDomainDisplayPlot::replot() { @@ -196,47 +227,37 @@ void TimeDomainDisplayPlot::replot() void TimeDomainDisplayPlot::resizeSlot( QSize *s ) { - resize(s->width(), s->height()); + // -10 is to spare some room for the legend and x-axis label + resize(s->width()-10, s->height()-10); } -void TimeDomainDisplayPlot::PlotNewData(const double* realDataPoints, - const double* imagDataPoints, +void TimeDomainDisplayPlot::PlotNewData(const std::vector<double*> dataPoints, const int64_t numDataPoints, const double timeInterval) { - if((numDataPoints > 0) && - (diff_timespec(get_highres_clock(), _lastReplot) > timeInterval)) { - + if((numDataPoints > 0)) { if(numDataPoints != _numPoints){ _numPoints = numDataPoints; - delete[] _realDataPoints; - delete[] _imagDataPoints; delete[] _xAxisPoints; - _realDataPoints = new double[_numPoints]; - _imagDataPoints = new double[_numPoints]; _xAxisPoints = new double[_numPoints]; - - _real_plot_curve->setRawData(_xAxisPoints, _realDataPoints, _numPoints); - _imag_plot_curve->setRawData(_xAxisPoints, _imagDataPoints, _numPoints); - - set_xaxis(0, numDataPoints); + for(int i = 0; i < _nplots; i++) { + delete[] _dataPoints[i]; + _dataPoints[i] = new double[_numPoints]; + _plot_curve[i]->setRawData(_xAxisPoints, _dataPoints[i], _numPoints); + } + + setXaxis(0, numDataPoints); _resetXAxisPoints(); } - memcpy(_realDataPoints, realDataPoints, numDataPoints*sizeof(double)); - memcpy(_imagDataPoints, imagDataPoints, numDataPoints*sizeof(double)); - - _lastReplot = get_highres_clock(); + for(int i = 0; i < _nplots; i++) { + memcpy(_dataPoints[i], dataPoints[i], numDataPoints*sizeof(double)); + } } } -void TimeDomainDisplayPlot::SetImaginaryDataVisible(const bool visibleFlag) -{ - _imag_plot_curve->setVisible(visibleFlag); -} - void TimeDomainDisplayPlot::_resetXAxisPoints() { double delt = 1.0/_sampleRate; diff --git a/gr-qtgui/lib/TimeDomainDisplayPlot.h b/gr-qtgui/lib/TimeDomainDisplayPlot.h index 01338300c..af87e1b14 100644 --- a/gr-qtgui/lib/TimeDomainDisplayPlot.h +++ b/gr-qtgui/lib/TimeDomainDisplayPlot.h @@ -1,8 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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 TIME_DOMAIN_DISPLAY_PLOT_HPP #define TIME_DOMAIN_DISPLAY_PLOT_HPP #include <stdint.h> #include <cstdio> +#include <vector> #include <qwt_plot.h> #include <qwt_painter.h> #include <qwt_plot_canvas.h> @@ -13,7 +36,6 @@ #include <qwt_plot_panner.h> #include <qwt_plot_magnifier.h> #include <qwt_plot_marker.h> -#include <highResTimeFunctions.h> #include <qwt_symbol.h> #include <qtgui_util.h> @@ -21,20 +43,20 @@ class TimeDomainDisplayPlot:public QwtPlot{ Q_OBJECT public: - TimeDomainDisplayPlot(QWidget*); + TimeDomainDisplayPlot(int nplots, QWidget*); virtual ~TimeDomainDisplayPlot(); - void PlotNewData(const double* realDataPoints, const double* imagDataPoints, + void PlotNewData(const std::vector<double*> dataPoints, const int64_t numDataPoints, const double timeInterval); - void SetImaginaryDataVisible(const bool); - virtual void replot(); - void set_yaxis(double min, double max); - void set_xaxis(double min, double max); - public slots: + void setYaxis(double min, double max); + void setXaxis(double min, double max); + void setTitle(int which, QString title); + void setColor(int which, QString color); + void resizeSlot( QSize *s ); void SetSampleRate(double sr, double units, const std::string &strunits); @@ -52,8 +74,8 @@ protected: private: void _resetXAxisPoints(); - QwtPlotCurve* _real_plot_curve; - QwtPlotCurve* _imag_plot_curve; + int _nplots; + std::vector<QwtPlotCurve*> _plot_curve; QwtPlotPanner* _panner; QwtPlotZoomer* _zoomer; @@ -61,14 +83,11 @@ private: QwtDblClickPlotPicker *_picker; QwtPlotMagnifier *_magnifier; - double* _realDataPoints; - double* _imagDataPoints; + std::vector<double*> _dataPoints; double* _xAxisPoints; double _sampleRate; - timespec _lastReplot; - int64_t _numPoints; }; diff --git a/gr-qtgui/lib/WaterfallDisplayPlot.cc b/gr-qtgui/lib/WaterfallDisplayPlot.cc index 2234f4238..1476be2bd 100644 --- a/gr-qtgui/lib/WaterfallDisplayPlot.cc +++ b/gr-qtgui/lib/WaterfallDisplayPlot.cc @@ -1,3 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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 WATERFALL_DISPLAY_PLOT_C #define WATERFALL_DISPLAY_PLOT_C @@ -88,7 +110,7 @@ class TimeScaleData public: TimeScaleData() { - timespec_reset(&_zeroTime); + _zeroTime = 0; _secondsPerLine = 1.0; } @@ -96,14 +118,14 @@ public: { } - virtual timespec GetZeroTime() const + virtual gruel::high_res_timer_type GetZeroTime() const { return _zeroTime; } - virtual void SetZeroTime(const timespec newTime) + virtual void SetZeroTime(const gruel::high_res_timer_type newTime) { - _zeroTime = newTime; + _zeroTime = newTime - gruel::high_res_timer_epoch(); } virtual void SetSecondsPerLine(const double newTime) @@ -118,13 +140,26 @@ public: protected: - timespec _zeroTime; + gruel::high_res_timer_type _zeroTime; double _secondsPerLine; private: }; +static QString +make_time_label(double secs) +{ + std::string time_str = pt::to_simple_string(pt::from_time_t(time_t(secs))); + + // lops off the YYYY-mmm-DD part of the string + size_t ind = time_str.find(" "); + if(ind != std::string::npos) + time_str = time_str.substr(ind); + + return QString("").sprintf("%s.%03ld", time_str.c_str(), long(std::fmod(secs*1000, 1000))); +} + class QwtTimeScaleDraw: public QwtScaleDraw, public TimeScaleData { public: @@ -138,14 +173,8 @@ public: virtual QwtText label(double value) const { - timespec lineTime = timespec_add(GetZeroTime(), (-value) * GetSecondsPerLine()); - std::string time_str = pt::to_simple_string(pt::from_time_t(lineTime.tv_sec)); - - // lops off the YYYY-mmm-DD part of the string - size_t ind = time_str.find(" "); - if(ind != std::string::npos) - time_str = time_str.substr(ind); - return QwtText(QString("").sprintf("%s.%03ld", time_str.c_str(), lineTime.tv_nsec/1000000)); + double secs = GetZeroTime()/double(gruel::high_res_timer_tps()) - (value * GetSecondsPerLine()); + return QwtText(make_time_label(secs)); } virtual void initiateUpdate() @@ -190,18 +219,10 @@ protected: using QwtPlotZoomer::trackerText; virtual QwtText trackerText( const QwtDoublePoint& p ) const { - timespec lineTime = timespec_add(GetZeroTime(), (-p.y()) * GetSecondsPerLine()); - std::string time_str = pt::to_simple_string(pt::from_time_t(lineTime.tv_sec)); - - // lops off the YYYY-mmm-DD part of the string - size_t ind = time_str.find(" "); - if(ind != std::string::npos) - time_str = time_str.substr(ind); - QString yLabel(QString("").sprintf("%s.%03ld", time_str.c_str(), lineTime.tv_nsec/1000000)); - + double secs = GetZeroTime()/double(gruel::high_res_timer_tps()) - (p.y() * GetSecondsPerLine()); QwtText t(QString("%1 %2, %3"). - arg(p.x(), 0, 'f', GetFrequencyPrecision()). - arg(_unitType.c_str()).arg(yLabel)); + arg(p.x(), 0, 'f', GetFrequencyPrecision()). + arg(_unitType.c_str()).arg(make_time_label(secs))); return t; } @@ -232,7 +253,7 @@ WaterfallDisplayPlot::WaterfallDisplayPlot(QWidget* parent) setAxisTitle(QwtPlot::yLeft, "Time"); setAxisScaleDraw(QwtPlot::yLeft, new QwtTimeScaleDraw()); - timespec_reset(&_lastReplot); + _lastReplot = 0; d_spectrogram = new PlotWaterfall(_waterfallData, "Waterfall Display"); @@ -367,7 +388,7 @@ void WaterfallDisplayPlot::PlotNewData(const double* dataPoints, const int64_t numDataPoints, const double timePerFFT, - const timespec timestamp, + const gruel::high_res_timer_type timestamp, const int droppedFrames) { if(numDataPoints > 0){ @@ -383,10 +404,10 @@ WaterfallDisplayPlot::PlotNewData(const double* dataPoints, replot(); } - _lastReplot = get_highres_clock(); + _lastReplot = gruel::high_res_timer_now(); } - if(diff_timespec(get_highres_clock(), _lastReplot) > timePerFFT) { + if(gruel::high_res_timer_now() - _lastReplot > timePerFFT*gruel::high_res_timer_tps()) { //FIXME: We may want to average the data between these updates to smooth display _waterfallData->addFFTData(dataPoints, numDataPoints, droppedFrames); _waterfallData->IncrementNumLinesToUpdate(); @@ -403,7 +424,7 @@ WaterfallDisplayPlot::PlotNewData(const double* dataPoints, replot(); - _lastReplot = get_highres_clock(); + _lastReplot = gruel::high_res_timer_now(); } } } @@ -546,7 +567,7 @@ WaterfallDisplayPlot::_UpdateIntensityRangeDisplay() replot(); // Update the last replot timer - _lastReplot = get_highres_clock(); + _lastReplot = gruel::high_res_timer_now(); } void diff --git a/gr-qtgui/lib/WaterfallDisplayPlot.h b/gr-qtgui/lib/WaterfallDisplayPlot.h index faa48d6aa..0c6a521b1 100644 --- a/gr-qtgui/lib/WaterfallDisplayPlot.h +++ b/gr-qtgui/lib/WaterfallDisplayPlot.h @@ -1,3 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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 WATERFALL_DISPLAY_PLOT_HPP #define WATERFALL_DISPLAY_PLOT_HPP @@ -10,7 +32,7 @@ #include <qtgui_util.h> #include <plot_waterfall.h> -#include <highResTimeFunctions.h> +#include <gruel/high_res_timer.h> class WaterfallDisplayPlot:public QwtPlot{ Q_OBJECT @@ -29,7 +51,7 @@ public: double GetStopFrequency()const; void PlotNewData(const double* dataPoints, const int64_t numDataPoints, - const double timePerFFT, const timespec timestamp, + const double timePerFFT, const gruel::high_res_timer_type timestamp, const int droppedFrames); void SetIntensityRange(const double minIntensity, const double maxIntensity); @@ -76,7 +98,7 @@ private: WaterfallData* _waterfallData; - timespec _lastReplot; + gruel::high_res_timer_type _lastReplot; bool _useCenterFrequencyFlag; diff --git a/gr-qtgui/lib/gr_qtgui_api.h b/gr-qtgui/lib/gr_qtgui_api.h new file mode 100644 index 000000000..65033a093 --- /dev/null +++ b/gr-qtgui/lib/gr_qtgui_api.h @@ -0,0 +1,33 @@ +/* + * Copyright 2010 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_QTGUI_API_H +#define INCLUDED_GR_QTGUI_API_H + +#include <gruel/attributes.h> + +#ifdef libgnuradio_qtgui_EXPORTS +# define GR_QTGUI_API __GR_ATTR_EXPORT +#else +# define GR_QTGUI_API __GR_ATTR_IMPORT +#endif + +#endif /* INCLUDED_GR_QTGUI_API_H */ diff --git a/gr-qtgui/lib/highResTimeFunctions.h b/gr-qtgui/lib/highResTimeFunctions.h index 251bbad8b..6b3844901 100644 --- a/gr-qtgui/lib/highResTimeFunctions.h +++ b/gr-qtgui/lib/highResTimeFunctions.h @@ -1,299 +1,36 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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 HIGH_RES_TIME_FUNCTIONS_H #define HIGH_RES_TIME_FUNCTIONS_H -#include <ctime> -#include <sys/time.h> -#include <cmath> -/* Requires the librt and libm libraries */ - -static const long NSEC_PER_SEC = 1000000000L; - -static inline bool -timespec_greater(const struct timespec* t1, - const struct timespec* t0) -{ - return ((t1->tv_sec > t0->tv_sec) || - ((t1->tv_sec == t0->tv_sec) && - (t1->tv_nsec > t0->tv_nsec))); -} - -static inline bool -timespec_greater(const struct timespec t1, - const struct timespec t0) -{ - return ((t1.tv_sec > t0.tv_sec) || - ((t1.tv_sec == t0.tv_sec) && - (t1.tv_nsec > t0.tv_nsec))); -} - -static inline bool -timespec_less(const struct timespec* t1, - const struct timespec* t0) -{ - return ((t1->tv_sec < t0->tv_sec) || - ((t1->tv_sec == t0->tv_sec) && - (t1->tv_nsec < t0->tv_nsec))); -} - -static inline bool -timespec_less(const struct timespec t1, - const struct timespec t0) -{ - return ((t1.tv_sec < t0.tv_sec) || - ((t1.tv_sec == t0.tv_sec) && - (t1.tv_nsec < t0.tv_nsec))); -} - -static inline bool -timespec_equal(const struct timespec* t1, - const struct timespec* t0) -{ - return ((t1->tv_sec == t0->tv_sec) && - (t1->tv_nsec == t0->tv_nsec)); -} - -static inline bool -timespec_equal(const struct timespec t1, - const struct timespec t0) -{ - return ((t1.tv_sec == t0.tv_sec) && - (t1.tv_nsec == t0.tv_nsec)); -} - -static inline void -timespec_reset(struct timespec* ret) -{ - ret->tv_sec = 0; - ret->tv_nsec = 0; -} - -static inline void -set_normalized_timespec(struct timespec *ts, - time_t sec, long nsec) -{ - while (nsec > NSEC_PER_SEC) { - nsec -= NSEC_PER_SEC; - ++sec; - } - while(nsec < 0) { - nsec += NSEC_PER_SEC; - --sec; - } - ts->tv_sec = sec; - ts->tv_nsec = nsec; -} - -static inline struct timespec -convert_to_timespec(const double timeValue) -{ - struct timespec ret; - double seconds = 0; - long nsec = static_cast<long>(modf(timeValue, &seconds) * - static_cast<double>(NSEC_PER_SEC)); - time_t sec = static_cast<time_t>(seconds); - - set_normalized_timespec(&ret, sec, nsec); - - return ret; -} - -static inline double -convert_from_timespec(const timespec actual) -{ - return (static_cast<double>(actual.tv_sec) + - (static_cast<double>(actual.tv_nsec) / - static_cast<double>(NSEC_PER_SEC))); -} - -static inline void -timespec_add(struct timespec *ret, - const struct timespec* t1, - const struct timespec* t0) -{ - time_t sec = t1->tv_sec + t0->tv_sec; - long nsec = t1->tv_nsec + t0->tv_nsec; +#include <gruel/high_res_timer.h> - set_normalized_timespec(ret, sec, nsec); -} - -static inline void -timespec_add(struct timespec *ret, - const struct timespec t1, - const struct timespec t0) -{ - return timespec_add(ret, &t1, &t0); -} - -static inline struct timespec -timespec_add(const struct timespec t1, - const struct timespec t0) -{ - struct timespec ret; - timespec_add(&ret, &t1, &t0); - return ret; -} - -static inline struct timespec -timespec_add(const struct timespec t1, - const double time0) -{ - struct timespec ret; - struct timespec t0; - t0 = convert_to_timespec(time0); - - timespec_add(&ret, &t1, &t0); - - return ret; -} +typedef gruel::high_res_timer_type highres_timespec; -static inline void -timespec_subtract(struct timespec *ret, - const struct timespec* t1, - const struct timespec* t0) -{ - time_t sec = t1->tv_sec - t0->tv_sec; - long nsec = t1->tv_nsec - t0->tv_nsec; - - set_normalized_timespec(ret, sec, nsec); -} - -static inline void -timespec_subtract(struct timespec *ret, - const struct timespec t1, - const struct timespec t0) -{ - return timespec_subtract(ret, &t1, &t0); -} - -static inline struct timespec -timespec_subtract(const struct timespec t1, - const struct timespec t0) -{ - struct timespec ret; - timespec_subtract(&ret, &t1, &t0); - return ret; -} - -static inline struct timespec -timespec_subtract(const struct timespec t1, - const double time0) -{ - struct timespec ret; - struct timespec t0; - t0 = convert_to_timespec(time0); - - timespec_subtract(&ret, &t1, &t0); - - return ret; -} - -static inline double -diff_timespec(struct timespec* ret, - const struct timespec *t1, - const struct timespec* t0) -{ - struct timespec actual; - time_t sec = 0; - long nsec = 0; - - if(timespec_greater(t1, t0)){ - sec = t1->tv_sec - t0->tv_sec; - nsec = t1->tv_nsec - t0->tv_nsec; - - set_normalized_timespec(&actual, sec, nsec); - - if(ret != NULL){ - ret->tv_sec = actual.tv_sec; - ret->tv_nsec = actual.tv_nsec; - } - - return convert_from_timespec(actual); - } - else{ - sec = t0->tv_sec - t1->tv_sec; - nsec = t0->tv_nsec - t1->tv_nsec; - - // Do nothing with the ret value as the ret value - // would have to store a negative, which it can't. - - set_normalized_timespec(&actual, sec, nsec); - - return (-convert_from_timespec(actual)); - } -} - -static inline double -diff_timespec(struct timespec* ret, - const struct timespec t1, - const struct timespec t0) -{ - return diff_timespec(ret, &t1, &t0); -} - -static inline double -diff_timespec(const struct timespec t1, - const struct timespec t0) -{ - return diff_timespec(NULL, &t1, &t0); -} - - -static inline double -diff_timespec(const struct timespec* t1, - const struct timespec* t0) -{ - return diff_timespec(NULL, t1, t0); -} - - -#ifdef CLOCK_REALTIME -// If we can use clock_gettime, use it; -// otherwise, use gettimeofday -static inline void -get_highres_clock(struct timespec* ret) -{ - if(clock_gettime(CLOCK_REALTIME, ret) != 0){ - // Unable to get high resolution time - - // fail over to low resolution time - timeval lowResTime; - gettimeofday(&lowResTime, NULL); - ret->tv_sec = lowResTime.tv_sec; - ret->tv_nsec = lowResTime.tv_usec*1000; - } -} - -#else - -// Trick timer functions into thinking it has an nsec timer -// but only use the low resolution (usec) timer. -static inline void -get_highres_clock(struct timespec* ret) -{ - timeval lowResTime; - gettimeofday(&lowResTime, NULL); - ret->tv_sec = lowResTime.tv_sec; - ret->tv_nsec = lowResTime.tv_usec*1000; -} -#endif - -static inline struct timespec +static inline highres_timespec get_highres_clock() { - struct timespec ret; - get_highres_clock(&ret); - return ret; -} - -static inline bool -timespec_empty(const struct timespec* ret) -{ - return ( (ret->tv_sec == 0 ) && (ret->tv_nsec == 0) ); -} - -static inline bool -timespec_empty(const struct timespec ret) -{ - return timespec_empty(&ret); + return gruel::high_res_timer_now(); } #endif /* HIGH_RES_TIME_FUNCTIONS_H */ diff --git a/gr-qtgui/lib/qtgui_sink_c.cc b/gr-qtgui/lib/qtgui_sink_c.cc index 7b40dd01d..965be0773 100644 --- a/gr-qtgui/lib/qtgui_sink_c.cc +++ b/gr-qtgui/lib/qtgui_sink_c.cc @@ -272,7 +272,7 @@ qtgui_sink_c::general_work (int noutput_items, // If we have enough input for one full FFT, do it if(datasize >= resid) { - const timespec currentTime = get_highres_clock(); + const gruel::high_res_timer_type currentTime = gruel::high_res_timer_now(); // Fill up residbuf with d_fftsize number of items memcpy(d_residbuf+d_index, &in[j], sizeof(gr_complex)*resid); diff --git a/gr-qtgui/lib/qtgui_sink_c.h b/gr-qtgui/lib/qtgui_sink_c.h index fb0cb6c5f..b0946885c 100644 --- a/gr-qtgui/lib/qtgui_sink_c.h +++ b/gr-qtgui/lib/qtgui_sink_c.h @@ -24,6 +24,7 @@ #define INCLUDED_QTGUI_SINK_C_H #include <Python.h> +#include <gr_qtgui_api.h> #include <gr_block.h> #include <gr_firdes.h> #include <gri_fft.h> @@ -33,17 +34,17 @@ class qtgui_sink_c; typedef boost::shared_ptr<qtgui_sink_c> qtgui_sink_c_sptr; -qtgui_sink_c_sptr qtgui_make_sink_c (int fftsize, int wintype, +GR_QTGUI_API qtgui_sink_c_sptr qtgui_make_sink_c (int fftsize, int wintype, double fc=0, double bandwidth=1.0, const std::string &name="Spectrum Display", bool plotfreq=true, bool plotwaterfall=true, bool plottime=true, bool plotconst=true, QWidget *parent=NULL); -class qtgui_sink_c : public gr_block +class GR_QTGUI_API qtgui_sink_c : public gr_block { private: - friend qtgui_sink_c_sptr qtgui_make_sink_c (int fftsize, int wintype, + friend GR_QTGUI_API qtgui_sink_c_sptr qtgui_make_sink_c (int fftsize, int wintype, double fc, double bw, const std::string &name, bool plotfreq, bool plotwaterfall, diff --git a/gr-qtgui/lib/qtgui_sink_f.cc b/gr-qtgui/lib/qtgui_sink_f.cc index 3312b9006..a435064c0 100644 --- a/gr-qtgui/lib/qtgui_sink_f.cc +++ b/gr-qtgui/lib/qtgui_sink_f.cc @@ -268,7 +268,7 @@ qtgui_sink_f::general_work (int noutput_items, // If we have enough input for one full FFT, do it if(datasize >= resid) { - const timespec currentTime = get_highres_clock(); + const gruel::high_res_timer_type currentTime = gruel::high_res_timer_now(); // Fill up residbuf with d_fftsize number of items memcpy(d_residbuf+d_index, &in[j], sizeof(float)*resid); diff --git a/gr-qtgui/lib/qtgui_sink_f.h b/gr-qtgui/lib/qtgui_sink_f.h index 518aa3846..30db05eea 100644 --- a/gr-qtgui/lib/qtgui_sink_f.h +++ b/gr-qtgui/lib/qtgui_sink_f.h @@ -24,6 +24,7 @@ #define INCLUDED_QTGUI_SINK_F_H #include <Python.h> +#include <gr_qtgui_api.h> #include <gr_block.h> #include <gr_firdes.h> #include <gri_fft.h> @@ -34,17 +35,17 @@ class qtgui_sink_f; typedef boost::shared_ptr<qtgui_sink_f> qtgui_sink_f_sptr; -qtgui_sink_f_sptr qtgui_make_sink_f (int fftsize, int wintype, +GR_QTGUI_API qtgui_sink_f_sptr qtgui_make_sink_f (int fftsize, int wintype, double fc=0, double bw=1.0, const std::string &name="Spectrum Display", bool plotfreq=true, bool plotwaterfall=true, bool plottime=true, bool plotconst=true, QWidget *parent=NULL); -class qtgui_sink_f : public gr_block +class GR_QTGUI_API qtgui_sink_f : public gr_block { private: - friend qtgui_sink_f_sptr qtgui_make_sink_f (int fftsize, int wintype, + friend GR_QTGUI_API qtgui_sink_f_sptr qtgui_make_sink_f (int fftsize, int wintype, double fc, double bw, const std::string &name, bool plotfreq, bool plotwaterfall, diff --git a/gr-qtgui/lib/qtgui_time_sink_c.cc b/gr-qtgui/lib/qtgui_time_sink_c.cc new file mode 100644 index 000000000..3d38419b2 --- /dev/null +++ b/gr-qtgui/lib/qtgui_time_sink_c.cc @@ -0,0 +1,199 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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 <qtgui_time_sink_c.h> +#include <gr_io_signature.h> +#include <string.h> + +#include <QTimer> + +qtgui_time_sink_c_sptr +qtgui_make_time_sink_c (int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent) +{ + return gnuradio::get_initial_sptr(new qtgui_time_sink_c (size, bw, name, + nconnections, parent)); +} + +qtgui_time_sink_c::qtgui_time_sink_c (int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent) + : gr_block ("time_sink_c", + gr_make_io_signature (nconnections, nconnections, sizeof(gr_complex)), + gr_make_io_signature (0, 0, 0)), + d_size(size), d_bandwidth(bw), d_name(name), + d_nconnections(2*nconnections), d_parent(parent) +{ + d_main_gui = NULL; + + d_index = 0; + + for(int i = 0; i < d_nconnections; i++) { + d_residbufs.push_back(new double[d_size]); + } + + initialize(); +} + +qtgui_time_sink_c::~qtgui_time_sink_c() +{ + // d_main_gui is a qwidget destroyed with its parent + for(int i = 0; i < d_nconnections; i++) { + delete [] d_residbufs[i]; + } +} + +void +qtgui_time_sink_c::forecast(int noutput_items, gr_vector_int &ninput_items_required) +{ + unsigned int ninputs = ninput_items_required.size(); + for (unsigned int i = 0; i < ninputs; i++) { + ninput_items_required[i] = std::min(d_size, 8191); + } +} + +void +qtgui_time_sink_c::initialize() +{ + if(qApp != NULL) { + d_qApplication = qApp; + } + else { + int argc=0; + char **argv = NULL; + d_qApplication = new QApplication(argc, argv); + } + + d_main_gui = new TimeDisplayForm(d_nconnections, d_parent); + + // initialize update time to 10 times a second + set_update_time(0.1); + d_last_time = 0; +} + + +void +qtgui_time_sink_c::exec_() +{ + d_qApplication->exec(); +} + +QWidget* +qtgui_time_sink_c::qwidget() +{ + return d_main_gui; +} + +PyObject* +qtgui_time_sink_c::pyqwidget() +{ + PyObject *w = PyLong_FromVoidPtr((void*)d_main_gui); + PyObject *retarg = Py_BuildValue("N", w); + return retarg; +} + +void +qtgui_time_sink_c::set_time_domain_axis(double min, double max) +{ + d_main_gui->setTimeDomainAxis(min, max); +} + +void +qtgui_time_sink_c::set_update_time(double t) +{ + d_update_time = t; + d_main_gui->setUpdateTime(d_update_time); +} + +void +qtgui_time_sink_c::set_title(int which, const std::string &title) +{ + d_main_gui->setTitle(which, title.c_str()); +} + +void +qtgui_time_sink_c::set_color(int which, const std::string &color) +{ + d_main_gui->setColor(which, color.c_str()); +} + +int +qtgui_time_sink_c::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + int n=0, j=0, idx=0; + const gr_complex *in = (const gr_complex*)input_items[idx]; + + for(int i=0; i < noutput_items; i+=d_size) { + unsigned int datasize = noutput_items - i; + unsigned int resid = d_size-d_index; + idx = 0; + + // If we have enough input for one full plot, do it + if(datasize >= resid) { + d_current_time = gruel::high_res_timer_now(); + + // Fill up residbufs with d_size number of items + for(n = 0; n < d_nconnections; n+=2) { + in = (const gr_complex*)input_items[idx++]; + for(unsigned int k = 0; k < resid; k++) { + d_residbufs[n][d_index+k] = in[j+k].real(); + d_residbufs[n+1][d_index+k] = in[j+k].imag(); + } + } + + // Update the plot if its time + if(gruel::high_res_timer_now() - d_last_time > d_update_time) { + d_last_time = d_current_time; + d_qApplication->postEvent(d_main_gui, + new TimeUpdateEvent(d_residbufs, d_size)); + } + + d_index = 0; + j += resid; + } + // Otherwise, copy what we received into the residbufs for next time + else { + for(n = 0; n < d_nconnections; n+=2) { + in = (const gr_complex*)input_items[idx++]; + for(unsigned int k = 0; k < resid; k++) { + d_residbufs[n][d_index+k] = in[j+k].real(); + d_residbufs[n+1][d_index+k] = in[j+k].imag(); + } + } + d_index += datasize; + j += datasize; + } + } + + consume_each(j); + return j; +} diff --git a/gr-qtgui/lib/qtgui_time_sink_c.h b/gr-qtgui/lib/qtgui_time_sink_c.h new file mode 100644 index 000000000..459423c40 --- /dev/null +++ b/gr-qtgui/lib/qtgui_time_sink_c.h @@ -0,0 +1,93 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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_QTGUI_TIME_SINK_C_H +#define INCLUDED_QTGUI_TIME_SINK_C_H + +#include <Python.h> +#include <gr_qtgui_api.h> +#include <gr_block.h> +#include <gr_firdes.h> +#include <gri_fft.h> +#include <qapplication.h> +#include <timedisplayform.h> + +class qtgui_time_sink_c; +typedef boost::shared_ptr<qtgui_time_sink_c> qtgui_time_sink_c_sptr; + +GR_QTGUI_API qtgui_time_sink_c_sptr qtgui_make_time_sink_c(int size, double bw, + const std::string &name, + int nconnectons=1, + QWidget *parent=NULL); + +class GR_QTGUI_API qtgui_time_sink_c : public gr_block +{ +private: + friend GR_QTGUI_API qtgui_time_sink_c_sptr qtgui_make_time_sink_c(int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent); + qtgui_time_sink_c(int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent=NULL); + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + + void initialize(); + + int d_size; + double d_bandwidth; + std::string d_name; + int d_nconnections; + + int d_index; + std::vector<double*> d_residbufs; + + double d_update_time; + + QWidget *d_parent; + TimeDisplayForm *d_main_gui; + + gruel::high_res_timer_type d_current_time; + gruel::high_res_timer_type d_last_time; + +public: + ~qtgui_time_sink_c(); + void exec_(); + QWidget* qwidget(); + PyObject* pyqwidget(); + + void set_time_domain_axis(double min, double max); + void set_update_time(double t); + void set_title(int which, const std::string &title); + void set_color(int which, const std::string &color); + + QApplication *d_qApplication; + + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_QTGUI_TIME_SINK_C_H */ diff --git a/gr-qtgui/lib/qtgui_time_sink_f.cc b/gr-qtgui/lib/qtgui_time_sink_f.cc new file mode 100644 index 000000000..58cc7a38a --- /dev/null +++ b/gr-qtgui/lib/qtgui_time_sink_f.cc @@ -0,0 +1,197 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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 <qtgui_time_sink_f.h> +#include <gr_io_signature.h> +#include <string.h> + +#include <QTimer> + +qtgui_time_sink_f_sptr +qtgui_make_time_sink_f (int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent) +{ + return gnuradio::get_initial_sptr(new qtgui_time_sink_f (size, bw, name, + nconnections, parent)); +} + +qtgui_time_sink_f::qtgui_time_sink_f (int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent) + : gr_block ("time_sink_f", + gr_make_io_signature (nconnections, nconnections, sizeof(float)), + gr_make_io_signature (0, 0, 0)), + d_size(size), d_bandwidth(bw), d_name(name), + d_nconnections(nconnections), d_parent(parent) +{ + d_main_gui = NULL; + + d_index = 0; + + for(int i = 0; i < d_nconnections; i++) { + d_residbufs.push_back(new double[d_size]); + } + + initialize(); +} + +qtgui_time_sink_f::~qtgui_time_sink_f() +{ + // d_main_gui is a qwidget destroyed with its parent + for(int i = 0; i < d_nconnections; i++) { + delete [] d_residbufs[i]; + } +} + +void +qtgui_time_sink_f::forecast(int noutput_items, gr_vector_int &ninput_items_required) +{ + unsigned int ninputs = ninput_items_required.size(); + for (unsigned int i = 0; i < ninputs; i++) { + ninput_items_required[i] = std::min(d_size, 8191); + } +} + +void +qtgui_time_sink_f::initialize() +{ + if(qApp != NULL) { + d_qApplication = qApp; + } + else { + int argc=0; + char **argv = NULL; + d_qApplication = new QApplication(argc, argv); + } + + d_main_gui = new TimeDisplayForm(d_nconnections, d_parent); + + // initialize update time to 10 times a second + set_update_time(0.1); + d_last_time = 0; +} + + +void +qtgui_time_sink_f::exec_() +{ + d_qApplication->exec(); +} + +QWidget* +qtgui_time_sink_f::qwidget() +{ + return d_main_gui; +} + +PyObject* +qtgui_time_sink_f::pyqwidget() +{ + PyObject *w = PyLong_FromVoidPtr((void*)d_main_gui); + PyObject *retarg = Py_BuildValue("N", w); + return retarg; +} + +void +qtgui_time_sink_f::set_time_domain_axis(double min, double max) +{ + d_main_gui->setTimeDomainAxis(min, max); +} + +void +qtgui_time_sink_f::set_update_time(double t) +{ + d_update_time = t; + d_main_gui->setUpdateTime(d_update_time); +} + +void +qtgui_time_sink_f::set_title(int which, const std::string &title) +{ + d_main_gui->setTitle(which, title.c_str()); +} + +void +qtgui_time_sink_f::set_color(int which, const std::string &color) +{ + d_main_gui->setColor(which, color.c_str()); +} + +int +qtgui_time_sink_f::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + int n=0, j=0, idx=0; + const float *in = (const float*)input_items[idx]; + + for(int i=0; i < noutput_items; i+=d_size) { + unsigned int datasize = noutput_items - i; + unsigned int resid = d_size-d_index; + idx = 0; + + // If we have enough input for one full plot, do it + if(datasize >= resid) { + d_current_time = gruel::high_res_timer_now(); + + // Fill up residbufs with d_size number of items + for(n = 0; n < d_nconnections; n++) { + in = (const float*)input_items[idx++]; + for(unsigned int k = 0; k < resid; k++) { + d_residbufs[n][d_index+k] = in[j+k]; + } + } + + // Update the plot if its time + if(gruel::high_res_timer_now() - d_last_time > d_update_time) { + d_last_time = d_current_time; + d_qApplication->postEvent(d_main_gui, + new TimeUpdateEvent(d_residbufs, d_size)); + } + + d_index = 0; + j += resid; + } + // Otherwise, copy what we received into the residbufs for next time + else { + for(n = 0; n < d_nconnections; n++) { + in = (const float*)input_items[idx++]; + for(unsigned int k = 0; k < resid; k++) { + d_residbufs[n][d_index+k] = in[j+k]; + } + } + d_index += datasize; + j += datasize; + } + } + + consume_each(j); + return j; +} diff --git a/gr-qtgui/lib/qtgui_time_sink_f.h b/gr-qtgui/lib/qtgui_time_sink_f.h new file mode 100644 index 000000000..632246c6e --- /dev/null +++ b/gr-qtgui/lib/qtgui_time_sink_f.h @@ -0,0 +1,93 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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_QTGUI_TIME_SINK_F_H +#define INCLUDED_QTGUI_TIME_SINK_F_H + +#include <Python.h> +#include <gr_qtgui_api.h> +#include <gr_block.h> +#include <gr_firdes.h> +#include <gri_fft.h> +#include <qapplication.h> +#include <timedisplayform.h> + +class qtgui_time_sink_f; +typedef boost::shared_ptr<qtgui_time_sink_f> qtgui_time_sink_f_sptr; + +GR_QTGUI_API qtgui_time_sink_f_sptr qtgui_make_time_sink_f(int size, double bw, + const std::string &name, + int nconnectons=1, + QWidget *parent=NULL); + +class GR_QTGUI_API qtgui_time_sink_f : public gr_block +{ +private: + friend GR_QTGUI_API qtgui_time_sink_f_sptr qtgui_make_time_sink_f(int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent); + qtgui_time_sink_f(int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent=NULL); + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + + void initialize(); + + int d_size; + double d_bandwidth; + std::string d_name; + int d_nconnections; + + int d_index; + std::vector<double*> d_residbufs; + + double d_update_time; + + QWidget *d_parent; + TimeDisplayForm *d_main_gui; + + gruel::high_res_timer_type d_current_time; + gruel::high_res_timer_type d_last_time; + +public: + ~qtgui_time_sink_f(); + void exec_(); + QWidget* qwidget(); + PyObject* pyqwidget(); + + void set_time_domain_axis(double min, double max); + void set_update_time(double t); + void set_title(int which, const std::string &title); + void set_color(int which, const std::string &color); + + QApplication *d_qApplication; + + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_QTGUI_TIME_SINK_F_H */ diff --git a/gr-qtgui/lib/qtgui_util.h b/gr-qtgui/lib/qtgui_util.h index a519c66a2..5b129c7b5 100644 --- a/gr-qtgui/lib/qtgui_util.h +++ b/gr-qtgui/lib/qtgui_util.h @@ -24,12 +24,12 @@ #define INCLUDED_QTGUI_UTIL_H #include <qevent.h> - +#include <gr_qtgui_api.h> #include <qwt_plot_picker.h> #include <qwt_picker_machine.h> -class QwtDblClickPlotPicker: public QwtPlotPicker +class GR_QTGUI_API QwtDblClickPlotPicker: public QwtPlotPicker { public: QwtDblClickPlotPicker(QwtPlotCanvas *); @@ -38,7 +38,7 @@ public: virtual QwtPickerMachine * stateMachine(int) const; }; -class QwtPickerDblClickPointMachine: public QwtPickerMachine +class GR_QTGUI_API QwtPickerDblClickPointMachine: public QwtPickerMachine { public: QwtPickerDblClickPointMachine(); diff --git a/gr-qtgui/lib/spectrumUpdateEvents.cc b/gr-qtgui/lib/spectrumUpdateEvents.cc index 53a205fb7..9be2f5357 100644 --- a/gr-qtgui/lib/spectrumUpdateEvents.cc +++ b/gr-qtgui/lib/spectrumUpdateEvents.cc @@ -8,10 +8,10 @@ SpectrumUpdateEvent::SpectrumUpdateEvent(const std::complex<float>* fftPoints, const double* realTimeDomainPoints, const double* imagTimeDomainPoints, const uint64_t numTimeDomainDataPoints, - const timespec dataTimestamp, + const gruel::high_res_timer_type dataTimestamp, const bool repeatDataFlag, const bool lastOfMultipleUpdateFlag, - const timespec generatedTimestamp, + const gruel::high_res_timer_type generatedTimestamp, const int droppedFFTFrames) : QEvent(QEvent::Type(10005)) { @@ -90,7 +90,7 @@ SpectrumUpdateEvent::getNumTimeDomainDataPoints() const return _numTimeDomainDataPoints; } -timespec +gruel::high_res_timer_type SpectrumUpdateEvent::getDataTimestamp() const { return _dataTimestamp; @@ -108,7 +108,7 @@ SpectrumUpdateEvent::getLastOfMultipleUpdateFlag() const return _lastOfMultipleUpdateFlag; } -timespec +gruel::high_res_timer_type SpectrumUpdateEvent::getEventGeneratedTimestamp() const { return _eventGeneratedTimestamp; @@ -177,4 +177,47 @@ SpectrumFrequencyRangeEvent::GetStopFrequency() const return _stopFrequency; } + +/***************************************************************************/ +#include <iostream> +TimeUpdateEvent::TimeUpdateEvent(const std::vector<double*> timeDomainPoints, + const uint64_t numTimeDomainDataPoints) + : QEvent(QEvent::Type(10005)) +{ + if(numTimeDomainDataPoints < 1) { + _numTimeDomainDataPoints = 1; + } + else { + _numTimeDomainDataPoints = numTimeDomainDataPoints; + } + + _nplots = timeDomainPoints.size(); + for(size_t i = 0; i < _nplots; i++) { + _dataTimeDomainPoints.push_back(new double[_numTimeDomainDataPoints]); + if(numTimeDomainDataPoints > 0) { + memcpy(_dataTimeDomainPoints[i], timeDomainPoints[i], + _numTimeDomainDataPoints*sizeof(double)); + } + } +} + +TimeUpdateEvent::~TimeUpdateEvent() +{ + for(size_t i = 0; i < _nplots; i++) { + delete[] _dataTimeDomainPoints[i]; + } +} + +const std::vector<double*> +TimeUpdateEvent::getTimeDomainPoints() const +{ + return _dataTimeDomainPoints; +} + +uint64_t +TimeUpdateEvent::getNumTimeDomainDataPoints() const +{ + return _numTimeDomainDataPoints; +} + #endif /* SPECTRUM_UPDATE_EVENTS_C */ diff --git a/gr-qtgui/lib/spectrumUpdateEvents.h b/gr-qtgui/lib/spectrumUpdateEvents.h index ccc072c3e..5a17657b7 100644 --- a/gr-qtgui/lib/spectrumUpdateEvents.h +++ b/gr-qtgui/lib/spectrumUpdateEvents.h @@ -5,7 +5,8 @@ #include <QEvent> #include <QString> #include <complex> -#include <highResTimeFunctions.h> +#include <vector> +#include <gruel/high_res_timer.h> class SpectrumUpdateEvent:public QEvent{ @@ -15,10 +16,10 @@ public: const double* realTimeDomainPoints, const double* imagTimeDomainPoints, const uint64_t numTimeDomainDataPoints, - const timespec dataTimestamp, + const gruel::high_res_timer_type dataTimestamp, const bool repeatDataFlag, const bool lastOfMultipleUpdateFlag, - const timespec generatedTimestamp, + const gruel::high_res_timer_type generatedTimestamp, const int droppedFFTFrames); ~SpectrumUpdateEvent(); @@ -28,10 +29,10 @@ public: const double* getImagTimeDomainPoints() const; uint64_t getNumFFTDataPoints() const; uint64_t getNumTimeDomainDataPoints() const; - timespec getDataTimestamp() const; + gruel::high_res_timer_type getDataTimestamp() const; bool getRepeatDataFlag() const; bool getLastOfMultipleUpdateFlag() const; - timespec getEventGeneratedTimestamp() const; + gruel::high_res_timer_type getEventGeneratedTimestamp() const; int getDroppedFFTFrames() const; protected: @@ -42,10 +43,10 @@ private: double* _imagDataTimeDomainPoints; uint64_t _numFFTDataPoints; uint64_t _numTimeDomainDataPoints; - timespec _dataTimestamp; + gruel::high_res_timer_type _dataTimestamp; bool _repeatDataFlag; bool _lastOfMultipleUpdateFlag; - timespec _eventGeneratedTimestamp; + gruel::high_res_timer_type _eventGeneratedTimestamp; int _droppedFFTFrames; }; @@ -89,4 +90,27 @@ private: }; +class TimeUpdateEvent: public QEvent +{ +public: + TimeUpdateEvent(const std::vector<double*> timeDomainPoints, + const uint64_t numTimeDomainDataPoints); + + ~TimeUpdateEvent(); + + int which() const; + const std::vector<double*> getTimeDomainPoints() const; + uint64_t getNumTimeDomainDataPoints() const; + timespec getDataTimestamp() const; + bool getRepeatDataFlag() const; + +protected: + +private: + size_t _nplots; + std::vector<double*> _dataTimeDomainPoints; + uint64_t _numTimeDomainDataPoints; +}; + + #endif /* SPECTRUM_UPDATE_EVENTS_H */ diff --git a/gr-qtgui/lib/spectrumdisplayform.cc b/gr-qtgui/lib/spectrumdisplayform.cc index 238c9889f..0e8594029 100644 --- a/gr-qtgui/lib/spectrumdisplayform.cc +++ b/gr-qtgui/lib/spectrumdisplayform.cc @@ -1,3 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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. + */ + #include <cmath> #include <QColorDialog> #include <QMessageBox> @@ -14,13 +36,16 @@ SpectrumDisplayForm::SpectrumDisplayForm(QWidget* parent) _frequencyDisplayPlot = new FrequencyDisplayPlot(FrequencyPlotDisplayFrame); _waterfallDisplayPlot = new WaterfallDisplayPlot(WaterfallPlotDisplayFrame); - _timeDomainDisplayPlot = new TimeDomainDisplayPlot(TimeDomainDisplayFrame); + _timeDomainDisplayPlot = new TimeDomainDisplayPlot(2, TimeDomainDisplayFrame); _constellationDisplayPlot = new ConstellationDisplayPlot(ConstellationDisplayFrame); _numRealDataPoints = 1024; _realFFTDataPoints = new double[_numRealDataPoints]; _averagedValues = new double[_numRealDataPoints]; _historyVector = new std::vector<double*>; + _timeDomainDisplayPlot->setTitle(0, "real"); + _timeDomainDisplayPlot->setTitle(1, "imag"); + AvgLineEdit->setRange(0, 500); // Set range of Average box value from 0 to 500 MinHoldCheckBox_toggled( false ); MaxHoldCheckBox_toggled( false ); @@ -119,13 +144,17 @@ SpectrumDisplayForm::newFrequencyData( const SpectrumUpdateEvent* spectrumUpdate //_lastSpectrumEvent = (SpectrumUpdateEvent)(*spectrumUpdateEvent); const std::complex<float>* complexDataPoints = spectrumUpdateEvent->getFFTPoints(); const uint64_t numFFTDataPoints = spectrumUpdateEvent->getNumFFTDataPoints(); - const double* realTimeDomainDataPoints = spectrumUpdateEvent->getRealTimeDomainPoints(); - const double* imagTimeDomainDataPoints = spectrumUpdateEvent->getImagTimeDomainPoints(); const uint64_t numTimeDomainDataPoints = spectrumUpdateEvent->getNumTimeDomainDataPoints(); - const timespec dataTimestamp = spectrumUpdateEvent->getDataTimestamp(); + const gruel::high_res_timer_type dataTimestamp = spectrumUpdateEvent->getDataTimestamp(); const bool repeatDataFlag = spectrumUpdateEvent->getRepeatDataFlag(); const bool lastOfMultipleUpdatesFlag = spectrumUpdateEvent->getLastOfMultipleUpdateFlag(); - const timespec generatedTimestamp = spectrumUpdateEvent->getEventGeneratedTimestamp(); + const gruel::high_res_timer_type generatedTimestamp = spectrumUpdateEvent->getEventGeneratedTimestamp(); + double* realTimeDomainDataPoints = (double*)spectrumUpdateEvent->getRealTimeDomainPoints(); + double* imagTimeDomainDataPoints = (double*)spectrumUpdateEvent->getImagTimeDomainPoints(); + + std::vector<double*> timeDomainDataPoints; + timeDomainDataPoints.push_back(realTimeDomainDataPoints); + timeDomainDataPoints.push_back(imagTimeDomainDataPoints); // REMEMBER: The dataTimestamp is NOT valid when the repeat data flag is true... ResizeBuffers(numFFTDataPoints, numTimeDomainDataPoints); @@ -210,11 +239,10 @@ SpectrumDisplayForm::newFrequencyData( const SpectrumUpdateEvent* spectrumUpdate _peakAmplitude, d_update_time); } if(tabindex == d_plot_time) { - _timeDomainDisplayPlot->PlotNewData(realTimeDomainDataPoints, - imagTimeDomainDataPoints, + _timeDomainDisplayPlot->PlotNewData(timeDomainDataPoints, numTimeDomainDataPoints, d_update_time); - } + } if(tabindex == d_plot_constellation) { _constellationDisplayPlot->PlotNewData(realTimeDomainDataPoints, imagTimeDomainDataPoints, @@ -673,7 +701,7 @@ SpectrumDisplayForm::ToggleTabConstellation(const bool state) void SpectrumDisplayForm::SetTimeDomainAxis(double min, double max) { - _timeDomainDisplayPlot->set_yaxis(min, max); + _timeDomainDisplayPlot->setYaxis(min, max); } void diff --git a/gr-qtgui/lib/spectrumdisplayform.h b/gr-qtgui/lib/spectrumdisplayform.h index 860edf2d1..30303a36f 100644 --- a/gr-qtgui/lib/spectrumdisplayform.h +++ b/gr-qtgui/lib/spectrumdisplayform.h @@ -1,3 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2010,2011 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 SPECTRUM_DISPLAY_FORM_H #define SPECTRUM_DISPLAY_FORM_H diff --git a/gr-qtgui/lib/timedisplayform.cc b/gr-qtgui/lib/timedisplayform.cc new file mode 100644 index 000000000..cc4ac9951 --- /dev/null +++ b/gr-qtgui/lib/timedisplayform.cc @@ -0,0 +1,177 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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. + */ + +#include <cmath> +#include <QColorDialog> +#include <QMessageBox> +#include <timedisplayform.h> +#include <iostream> + +TimeDisplayForm::TimeDisplayForm(int nplots, QWidget* parent) + : QWidget(parent) +{ + _systemSpecifiedFlag = false; + _intValidator = new QIntValidator(this); + _intValidator->setBottom(0); + + _layout = new QGridLayout(this); + _timeDomainDisplayPlot = new TimeDomainDisplayPlot(nplots, this); + _layout->addWidget(_timeDomainDisplayPlot, 0, 0); + + _numRealDataPoints = 1024; + + setLayout(_layout); + + Reset(); + + // Create a timer to update plots at the specified rate + displayTimer = new QTimer(this); + connect(displayTimer, SIGNAL(timeout()), this, SLOT(updateGuiTimer())); + + connect(_timeDomainDisplayPlot, SIGNAL(plotPointSelected(const QPointF)), + this, SLOT(onTimePlotPointSelected(const QPointF))); +} + +TimeDisplayForm::~TimeDisplayForm() +{ + // Qt deletes children when parent is deleted + + // Don't worry about deleting Display Plots - they are deleted when parents are deleted + delete _intValidator; + + displayTimer->stop(); + delete displayTimer; +} + +void +TimeDisplayForm::newData( const TimeUpdateEvent* spectrumUpdateEvent) +{ + const std::vector<double*> timeDomainDataPoints = spectrumUpdateEvent->getTimeDomainPoints(); + const uint64_t numTimeDomainDataPoints = spectrumUpdateEvent->getNumTimeDomainDataPoints(); + + _timeDomainDisplayPlot->PlotNewData(timeDomainDataPoints, + numTimeDomainDataPoints, + d_update_time); +} + +void +TimeDisplayForm::resizeEvent( QResizeEvent *e ) +{ + QSize s = size(); + emit _timeDomainDisplayPlot->resizeSlot(&s); +} + +void +TimeDisplayForm::customEvent( QEvent * e) +{ + if(e->type() == 10005) { + TimeUpdateEvent* timeUpdateEvent = (TimeUpdateEvent*)e; + newData(timeUpdateEvent); + } + //else if(e->type() == 10008){ + //setWindowTitle(((SpectrumWindowCaptionEvent*)e)->getLabel()); + //} + //else if(e->type() == 10009){ + //Reset(); + //if(_systemSpecifiedFlag){ + // _system->ResetPendingGUIUpdateEvents(); + //} + //} +} + +void +TimeDisplayForm::updateGuiTimer() +{ + _timeDomainDisplayPlot->canvas()->update(); +} + +void +TimeDisplayForm::onTimePlotPointSelected(const QPointF p) +{ + emit plotPointSelected(p, 3); +} + +void +TimeDisplayForm::setFrequencyRange(const double newCenterFrequency, + const double newStartFrequency, + const double newStopFrequency) +{ + double fdiff = std::max(fabs(newStartFrequency), fabs(newStopFrequency)); + + if(fdiff > 0) { + std::string strtime[4] = {"sec", "ms", "us", "ns"}; + double units10 = floor(log10(fdiff)); + double units3 = std::max(floor(units10 / 3.0), 0.0); + double units = pow(10, (units10-fmod(units10, 3.0))); + int iunit = static_cast<int>(units3); + + _startFrequency = newStartFrequency; + _stopFrequency = newStopFrequency; + + _timeDomainDisplayPlot->SetSampleRate(_stopFrequency - _startFrequency, + units, strtime[iunit]); + } +} + +void +TimeDisplayForm::Reset() +{ +} + + +void +TimeDisplayForm::closeEvent( QCloseEvent *e ) +{ + //if(_systemSpecifiedFlag){ + // _system->SetWindowOpenFlag(false); + //} + + qApp->processEvents(); + + QWidget::closeEvent(e); +} + +void +TimeDisplayForm::setTimeDomainAxis(double min, double max) +{ + _timeDomainDisplayPlot->setYaxis(min, max); +} + +void +TimeDisplayForm::setUpdateTime(double t) +{ + d_update_time = t; + // QTimer class takes millisecond input + displayTimer->start(d_update_time*1000); +} + +void +TimeDisplayForm::setTitle(int which, QString title) +{ + _timeDomainDisplayPlot->setTitle(which, title); +} + +void +TimeDisplayForm::setColor(int which, QString color) +{ + _timeDomainDisplayPlot->setColor(which, color); +} diff --git a/gr-qtgui/lib/timedisplayform.h b/gr-qtgui/lib/timedisplayform.h new file mode 100644 index 000000000..1216a1ef5 --- /dev/null +++ b/gr-qtgui/lib/timedisplayform.h @@ -0,0 +1,85 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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 TIME_DISPLAY_FORM_H +#define TIME_DISPLAY_FORM_H + +#include <spectrumUpdateEvents.h> +#include <FrequencyDisplayPlot.h> +#include <WaterfallDisplayPlot.h> +#include <TimeDomainDisplayPlot.h> +#include <ConstellationDisplayPlot.h> +#include <QtGui/QApplication> +#include <QtGui/QGridLayout> +#include <QValidator> +#include <QTimer> +#include <vector> + +class TimeDisplayForm : public QWidget +{ + Q_OBJECT + + public: + TimeDisplayForm(int nplots=1, QWidget* parent = 0); + ~TimeDisplayForm(); + + void Reset(); + +public slots: + void resizeEvent( QResizeEvent * e ); + void customEvent( QEvent * e ); + void setFrequencyRange( const double newCenterFrequency, + const double newStartFrequency, + const double newStopFrequency ); + void closeEvent( QCloseEvent * e ); + + void setTimeDomainAxis(double min, double max); + + void setUpdateTime(double t); + + void setTitle(int which, QString title); + void setColor(int which, QString color); + +private slots: + void newData( const TimeUpdateEvent* ); + void updateGuiTimer(); + + void onTimePlotPointSelected(const QPointF p); + +signals: + void plotPointSelected(const QPointF p, int type); + +private: + uint64_t _numRealDataPoints; + QIntValidator* _intValidator; + + QGridLayout *_layout; + TimeDomainDisplayPlot* _timeDomainDisplayPlot; + bool _systemSpecifiedFlag; + double _startFrequency; + double _stopFrequency; + + QTimer *displayTimer; + double d_update_time; +}; + +#endif /* TIME_DISPLAY_FORM_H */ diff --git a/gr-qtgui/swig/Makefile.am b/gr-qtgui/swig/Makefile.am index 8c695ba5b..1d8319987 100644 --- a/gr-qtgui/swig/Makefile.am +++ b/gr-qtgui/swig/Makefile.am @@ -51,4 +51,7 @@ qtgui_swig_la_swig_libadd = \ # additional SWIG files to be installed qtgui_swig_swiginclude_headers = \ - qtgui.i + qtgui_sink_c.i \ + qtgui_sink_f.i \ + qtgui_time_sink_c.i \ + qtgui_time_sink_f.i diff --git a/gr-qtgui/swig/qtgui.i b/gr-qtgui/swig/qtgui_sink_c.i index 77c6ccdd7..ff6241482 100644 --- a/gr-qtgui/swig/qtgui.i +++ b/gr-qtgui/swig/qtgui_sink_c.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2008,2009 Free Software Foundation, Inc. + * Copyright 2008,2009,2011 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,7 +24,6 @@ %{ #include <qtgui_sink_c.h> -#include <qtgui_sink_f.h> %} GR_SWIG_BLOCK_MAGIC(qtgui,sink_c) @@ -65,47 +64,3 @@ public: void set_constellation_pen_size(int size); void set_update_time(double t); }; - - - -/*********************************************************************/ - - -GR_SWIG_BLOCK_MAGIC(qtgui,sink_f) - -qtgui_sink_f_sptr qtgui_make_sink_f (int fftsize, int wintype, - double fc=0, double bw=0.0, - const std::string &name="Display", - bool plotfreq=true, bool plotwaterfall=true, - bool plottime=true, bool plotconst=true, - QWidget *parent=NULL); - -class qtgui_sink_f : public gr_block -{ -private: - friend qtgui_sink_f_sptr qtgui_make_sink_f (int fftsize, int wintype, - double fc, double bw, - const std::string &name, - bool plotfreq, bool plotwaterfall, - bool plottime, bool plotconst, - QWidget *parent); - qtgui_sink_f (int fftsize, int wintype, - double fc, double bw, - const std::string &name, - bool plotfreq, bool plotwaterfall, - bool plottime, bool plotconst, - QWidget *parent); - -public: - void exec_(); - PyObject* pyqwidget(); - - void set_frequency_range(const double centerfreq, - const double bandwidth); - void set_time_domain_axis(double min, double max); - void set_constellation_axis(double xmin, double xmax, - double ymin, double ymax); - void set_frequency_axis(double min, double max); - void set_constellation_pen_size(int size); - void set_update_time(double t); -}; diff --git a/gr-qtgui/swig/qtgui_sink_f.i b/gr-qtgui/swig/qtgui_sink_f.i new file mode 100644 index 000000000..c5eb656b9 --- /dev/null +++ b/gr-qtgui/swig/qtgui_sink_f.i @@ -0,0 +1,66 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2011 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. + */ + +%include "gnuradio.i" + +%{ +#include <qtgui_sink_f.h> +%} + +GR_SWIG_BLOCK_MAGIC(qtgui,sink_f) + +qtgui_sink_f_sptr qtgui_make_sink_f (int fftsize, int wintype, + double fc=0, double bw=0.0, + const std::string &name="Display", + bool plotfreq=true, bool plotwaterfall=true, + bool plottime=true, bool plotconst=true, + QWidget *parent=NULL); + +class qtgui_sink_f : public gr_block +{ +private: + friend qtgui_sink_f_sptr qtgui_make_sink_f (int fftsize, int wintype, + double fc, double bw, + const std::string &name, + bool plotfreq, bool plotwaterfall, + bool plottime, bool plotconst, + QWidget *parent); + qtgui_sink_f (int fftsize, int wintype, + double fc, double bw, + const std::string &name, + bool plotfreq, bool plotwaterfall, + bool plottime, bool plotconst, + QWidget *parent); + +public: + void exec_(); + PyObject* pyqwidget(); + + void set_frequency_range(const double centerfreq, + const double bandwidth); + void set_time_domain_axis(double min, double max); + void set_constellation_axis(double xmin, double xmax, + double ymin, double ymax); + void set_frequency_axis(double min, double max); + void set_constellation_pen_size(int size); + void set_update_time(double t); +}; diff --git a/gr-qtgui/swig/qtgui_swig.i b/gr-qtgui/swig/qtgui_swig.i index c250cdd04..5a4ffd6fb 100644 --- a/gr-qtgui/swig/qtgui_swig.i +++ b/gr-qtgui/swig/qtgui_swig.i @@ -25,8 +25,11 @@ %{ #include <qtgui_sink_c.h> #include <qtgui_sink_f.h> +#include <qtgui_time_sink_c.h> +#include <qtgui_time_sink_f.h> %} -%include "qtgui.i" - - +%include "qtgui_sink_c.i" +%include "qtgui_sink_f.i" +%include "qtgui_time_sink_c.i" +%include "qtgui_time_sink_f.i" diff --git a/gr-qtgui/swig/qtgui_time_sink_c.i b/gr-qtgui/swig/qtgui_time_sink_c.i new file mode 100644 index 000000000..8f5c9f4f0 --- /dev/null +++ b/gr-qtgui/swig/qtgui_time_sink_c.i @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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. + */ + +%include "gnuradio.i" + +%{ +#include <qtgui_time_sink_c.h> +%} + +GR_SWIG_BLOCK_MAGIC(qtgui,time_sink_c) + +qtgui_time_sink_c_sptr qtgui_make_time_sink_c(int size, double bw, + const std::string &name, + int nconnections=1, + QWidget *parent=NULL); + +class qtgui_time_sink_c : public gr_block +{ +private: + friend qtgui_time_sink_c_sptr qtgui_make_time_sink_c(int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent); + qtgui_time_sink_c(int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent=NULL); + +public: + void exec_(); + PyObject* pyqwidget(); + + void set_time_domain_axis(double min, double max); + void set_update_time(double t); + void set_title(int which, const std::string &title); + void set_color(int which, const std::string &color); +}; diff --git a/gr-qtgui/swig/qtgui_time_sink_f.i b/gr-qtgui/swig/qtgui_time_sink_f.i new file mode 100644 index 000000000..b92efe7be --- /dev/null +++ b/gr-qtgui/swig/qtgui_time_sink_f.i @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 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. + */ + +%include "gnuradio.i" + +%{ +#include <qtgui_time_sink_f.h> +%} + +GR_SWIG_BLOCK_MAGIC(qtgui,time_sink_f) + +qtgui_time_sink_f_sptr qtgui_make_time_sink_f(int size, double bw, + const std::string &name, + int nconnections=1, + QWidget *parent=NULL); + +class qtgui_time_sink_f : public gr_block +{ +private: + friend qtgui_time_sink_f_sptr qtgui_make_time_sink_f(int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent); + qtgui_time_sink_f(int size, double bw, + const std::string &name, + int nconnections, + QWidget *parent=NULL); + +public: + void exec_(); + PyObject* pyqwidget(); + + void set_time_domain_axis(double min, double max); + void set_update_time(double t); + void set_title(int which, const std::string &title); + void set_color(int which, const std::string &color); +}; diff --git a/gr-trellis/doc/gr-trellis.xml b/gr-trellis/doc/gr-trellis.xml index ed53715a8..5f1921343 100644 --- a/gr-trellis/doc/gr-trellis.xml +++ b/gr-trellis/doc/gr-trellis.xml @@ -279,6 +279,15 @@ The fourth way is specific to FSMs resulting from shift registers, and the outpu </programlisting> </listitem> +<listitem> +<para> +I have added other constructors as well, eg, one that constructs an FSM appropriate for modeling an arbitrary CPM scheme; one that constructs the radix-n version of a given FSM; one that constructs the "concatenation" of two FSMs, etc. +</para> +</listitem> + + + + </itemizedlist> @@ -397,8 +406,8 @@ r<subscript>k</subscript>= evaluates </para> <para> -i<subscript>0</subscript>= argmax<subscript>i</subscript> ||r<subscript>k</subscript>-c<subscript>i</subscript>||<superscript>2</superscript> = -argmax<subscript>i</subscript> sum<subscript>j=1</subscript><superscript>D</superscript> |r<subscript>k,j</subscript>-c<subscript>i,j</subscript>|<superscript>2</superscript> +i<subscript>0</subscript>= argmin<subscript>i</subscript> ||r<subscript>k</subscript>-c<subscript>i</subscript>||<superscript>2</superscript> = +argmin<subscript>i</subscript> sum<subscript>j=1</subscript><superscript>D</superscript> |r<subscript>k,j</subscript>-c<subscript>i,j</subscript>|<superscript>2</superscript> </para> <para> and outputs a sequence of O floats of the form (0,...,0,1,0,...,0), where the @@ -413,8 +422,8 @@ r<subscript>k</subscript>= evaluates </para> <para> -i<subscript>0</subscript>= argmax<subscript>i</subscript> ||r<subscript>k</subscript>-c<subscript>i</subscript>||<superscript>2</superscript> = -argmax<subscript>i</subscript> sum<subscript>j=1</subscript><superscript>D</superscript> (r<subscript>k,j</subscript>-c<subscript>i,j</subscript>)<superscript>2</superscript> +i<subscript>0</subscript>= argmin<subscript>i</subscript> ||r<subscript>k</subscript>-c<subscript>i</subscript>||<superscript>2</superscript> = +argmin<subscript>i</subscript> sum<subscript>j=1</subscript><superscript>D</superscript> (r<subscript>k,j</subscript>-c<subscript>i,j</subscript>)<superscript>2</superscript> </para> <para> and outputs a sequence of O floats of the form (d<subscript>1</subscript>,d<subscript>2</subscript>,...,d<subscript>O</subscript>), where the @@ -813,7 +822,7 @@ The modulated symbols are filtered by the ISI channel and AWGN with appropriate <para> Since the output alphabet of the equivalent FSM is quite large (1024) we chose to utilize the combined metrics calculator and Viterbi algorithm block. -also note that the first L observations are irrelevant and tus can be skipped. +Also note that the first L observations are irrelevant and thus can be skipped. </para> <programlisting> 33 # RX @@ -863,7 +872,20 @@ The function returns the number of symbols and the number of symbols in error. O <sect1 id="turbo"><title>Support for Concatenated Coding and Turbo Decoding</title> <para> -To do... +Soft versions of the algorithms have been implemented. +Also examples of turbo equalization/decoding and of sccc can +be found in the examples directory. + +Recently we added gnuradio blocks for sccc and pccc encoders and +turbo decoders. +Although these can be generated by existing gr-trellis blocks (in particular, +the SISO blocks, as done in some of the python examples) there is an advantage +in having this functionality as a single block. To see why, think of a turbo decoder with 10 iterations. Previously we needed to concatenate 10 x 2 SISO blocks +(for a sccc decoder) to emulate the passing of soft information between SISOs over 10 iterartions. With the new block however, only a single such block is needed that internally loops through 10 iterations; this results in space savings +and possibly time saving as well (since queueing at the input/ouput of the gr-blocks is avoided). + + +Still need to document them... </para> diff --git a/gr-trellis/src/examples/Makefile.am b/gr-trellis/src/examples/Makefile.am index 8fb727acd..92aeadfad 100644 --- a/gr-trellis/src/examples/Makefile.am +++ b/gr-trellis/src/examples/Makefile.am @@ -31,8 +31,6 @@ dist_ourdata_DATA = \ dist_ourdata_SCRIPTS = \ fsm_utils.py \ test_tcm.py \ - test_tcm1.py \ - test_tcm2.py \ test_tcm_parallel.py \ test_tcm_combined.py \ test_sccc_hard.py \ diff --git a/gr-trellis/src/examples/README b/gr-trellis/src/examples/README index d5bad85f5..bd28e3d61 100644 --- a/gr-trellis/src/examples/README +++ b/gr-trellis/src/examples/README @@ -6,28 +6,10 @@ fsm_utils.py contains several useful functions. fsm_files is a directory with some FSM definitions -If you just want to see what these programs do, run each of the following: +If you just want to see what these programs do run them; +in your terminal you will see something like this: -./test_tcm.py fsm_files/awgn1o2_4.fsm 6.0 1000 -./test_tcm1.py fsm_files/awgn1o2_4.fsm 6.0 1000 -./test_tcm2.py 6.0 1000 -./test_tcm_combined.py fsm_files/awgn1o2_4.fsm 6.0 1000 -./test_tcm_parallel.py fsm_files/awgn1o2_4.fsm 6.0 1000 - -./test_sccc_hard.py fsm_files/awgn1o2_4.fsm fsm_files/awgn2o3_4_msb.fsm 10.0 100 -./test_sccc_soft.py fsm_files/awgn1o2_4.fsm fsm_files/awgn2o3_4_msb.fsm 8.0 100 -./test_sccc_turbo.py fsm_files/awgn1o2_4.fsm fsm_files/awgn2o3_4_msb.fsm 5.0 100 - -./test_viterbi_equalization.py 12.0 100 -./test_viterbi_equalization1.py 12.0 100 -./test_turbo_equalization1.py fsm_files/awgn1o2_4.fsm 8.0 100 -./test_turbo_equalization2.py fsm_files/awgn1o2_4.fsm 8.0 100 - - -In your terminal you will see something like this: - - -$ ./test_tcm.py fsm_files/awgn1o2_4.fsm 6.0 1000 +$ ./test_tcm.py --esn0 6.0 --repetitions 1000 100 98 9.80e-01 102400 9 8.79e-05 200 198 9.90e-01 204800 20 9.77e-05 300 298 9.93e-01 307200 40 1.30e-04 diff --git a/gr-trellis/src/examples/test_pccc_turbo1.py b/gr-trellis/src/examples/test_pccc_turbo1.py new file mode 100755 index 000000000..1173d0734 --- /dev/null +++ b/gr-trellis/src/examples/test_pccc_turbo1.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python + +from gnuradio import gr +from gnuradio import trellis +from gnuradio import eng_notation +import math +import sys +import random +import fsm_utils + + +def run_test (fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation,Es,N0,IT,seed): + tb = gr.top_block () + + + # TX + src = gr.lfsr_32k_source_s() + src_head = gr.head (gr.sizeof_short,Kb/16) # packet size in shorts + s2fsmi = gr.packed_to_unpacked_ss(bitspersymbol,gr.GR_MSB_FIRST) # unpack shorts to symbols compatible with the outer FSM input cardinality + #src = gr.vector_source_s([0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],False) + enc = trellis.pccc_encoder_ss(fo,0,fi,0,interleaver,K) + code = gr.vector_sink_s() + mod = gr.chunks_to_symbols_sf(constellation,dimensionality) + + # CHANNEL + add = gr.add_ff() + noise = gr.noise_source_f(gr.GR_GAUSSIAN,math.sqrt(N0/2),seed) + + # RX + metrics_in = trellis.metrics_f(fi.O()*fo.O(),dimensionality,constellation,trellis.TRELLIS_EUCLIDEAN) # data preprocessing to generate metrics for innner SISO + scale = gr.multiply_const_ff(1.0/N0) + dec = trellis.pccc_decoder_s(fo,0,-1,fi,0,-1,interleaver,K,IT,trellis.TRELLIS_MIN_SUM) + + fsmi2s = gr.unpacked_to_packed_ss(bitspersymbol,gr.GR_MSB_FIRST) # pack FSM input symbols to shorts + dst = gr.check_lfsr_32k_s() + + tb.connect (src,src_head,s2fsmi,enc,mod) + #tb.connect (src,enc,mod) + #tb.connect(enc,code) + tb.connect (mod,(add,0)) + tb.connect (noise,(add,1)) + tb.connect (add,metrics_in,scale,dec,fsmi2s,dst) + + tb.run() + + #print code.data() + + ntotal = dst.ntotal () + nright = dst.nright () + runlength = dst.runlength () + return (ntotal,ntotal-nright) + + +def main(args): + nargs = len (args) + if nargs == 5: + fname_out=args[0] + fname_in=args[1] + esn0_db=float(args[2]) # Es/No in dB + IT=int(args[3]) + rep=int(args[4]) # number of times the experiment is run to collect enough errors + else: + sys.stderr.write ('usage: test_pccc_turbo.py fsm_name_1 fsm_fname_2 Es/No_db iterations repetitions\n') + sys.exit (1) + + # system parameters + Kb=1024*16 # packet size in bits (make it multiple of 16 so it can be packed in a short) + fo=trellis.fsm(fname_out) # get the outer FSM specification from a file + fi=trellis.fsm(fname_in) # get the innner FSM specification from a file + bitspersymbol = int(round(math.log(fo.I())/math.log(2))) # bits per FSM input symbol + if fo.I() != fi.I(): + sys.stderr.write ('Incompatible input cardinality between two FSMs.\n') + sys.exit (1) + K=Kb/bitspersymbol # packet size in trellis steps + interleaver=trellis.interleaver(K,666) # construct a random interleaver + #modulation = fsm_utils.psk8 # see fsm_utlis.py for available predefined modulations + dimensionality = 4 + constellation = [ 1, 0, 1, 0,\ + 1, 0,-1, 0,\ + 1, 0, 0, 1,\ + 1, 0, 0,-1,\ + -1, 0, 1, 0,\ + -1, 0,-1, 0,\ + -1, 0, 0, 1,\ + -1, 0, 0,-1,\ + 0, 1, 1, 0,\ + 0, 1,-1, 0,\ + 0, 1, 0, 1,\ + 0, 1, 0,-1,\ + 0,-1, 1, 0,\ + 0,-1,-1, 0,\ + 0,-1, 0, 1,\ + 0,-1, 0,-1,] # equivalent to 2 QPSK symbols + if len(constellation)/dimensionality != fi.O()*fo.O(): + sys.stderr.write ('Incompatible FSM output cardinality and modulation size.\n') + sys.exit (1) + # calculate average symbol energy + Es = 0 + for i in range(len(constellation)): + Es = Es + constellation[i]**2 + Es = Es / (len(constellation)/dimensionality) + N0=Es/pow(10.0,esn0_db/10.0); # calculate noise variance + + tot_s=0 # total number of transmitted shorts + terr_s=0 # total number of shorts in error + terr_p=0 # total number of packets in error + for i in range(rep): + (s,e)=run_test(fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation,Es,N0,IT,-long(666+i)) # run experiment with different seed to get different noise realizations + tot_s=tot_s+s + terr_s=terr_s+e + terr_p=terr_p+(terr_s!=0) + if ((i+1)%10==0): # display progress + print i+1,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + # estimate of the (short or bit) error rate + print rep,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + + +if __name__ == '__main__': + main (sys.argv[1:]) diff --git a/gr-trellis/src/examples/test_sccc_hard.py b/gr-trellis/src/examples/test_sccc_hard.py index a7933a18e..1a81bc59b 100755 --- a/gr-trellis/src/examples/test_sccc_hard.py +++ b/gr-trellis/src/examples/test_sccc_hard.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math diff --git a/gr-trellis/src/examples/test_sccc_soft.py b/gr-trellis/src/examples/test_sccc_soft.py index d96d36e3f..ea296e1e9 100755 --- a/gr-trellis/src/examples/test_sccc_soft.py +++ b/gr-trellis/src/examples/test_sccc_soft.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math diff --git a/gr-trellis/src/examples/test_sccc_turbo.py b/gr-trellis/src/examples/test_sccc_turbo.py index f3a856de7..703ee410b 100755 --- a/gr-trellis/src/examples/test_sccc_turbo.py +++ b/gr-trellis/src/examples/test_sccc_turbo.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math @@ -92,13 +91,14 @@ def run_test (fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation, def main(args): nargs = len (args) - if nargs == 4: + if nargs == 5: fname_out=args[0] fname_in=args[1] esn0_db=float(args[2]) # Es/No in dB - rep=int(args[3]) # number of times the experiment is run to collect enough errors + IT=int(args[3]) + rep=int(args[4]) # number of times the experiment is run to collect enough errors else: - sys.stderr.write ('usage: test_tcm.py fsm_name_out fsm_fname_in Es/No_db repetitions\n') + sys.stderr.write ('usage: test_sccc_turbo.py fsm_name_out fsm_fname_in Es/No_db iterations repetitions\n') sys.exit (1) # system parameters @@ -123,7 +123,6 @@ def main(args): Es = Es + constellation[i]**2 Es = Es / (len(constellation)/dimensionality) N0=Es/pow(10.0,esn0_db/10.0); # calculate noise variance - IT = 3 # number of turbo iterations tot_s=0 # total number of transmitted shorts terr_s=0 # total number of shorts in error diff --git a/gr-trellis/src/examples/test_tcm2.py b/gr-trellis/src/examples/test_sccc_turbo1.py index e527fc5ed..8a630c0d4 100755 --- a/gr-trellis/src/examples/test_tcm2.py +++ b/gr-trellis/src/examples/test_sccc_turbo1.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math @@ -9,20 +8,15 @@ import sys import random import fsm_utils -def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed): - tb = gr.top_block () +def run_test (fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation,Es,N0,IT,seed): + tb = gr.top_block () # TX - #packet = [0]*Kb - #for i in range(Kb-1*16): # last 16 bits = 0 to drive the final state to 0 - #packet[i] = random.randint(0, 1) # random 0s and 1s - #src = gr.vector_source_s(packet,False) src = gr.lfsr_32k_source_s() src_head = gr.head (gr.sizeof_short,Kb/16) # packet size in shorts - #b2s = gr.unpacked_to_packed_ss(1,gr.GR_MSB_FIRST) # pack bits in shorts - s2fsmi = gr.packed_to_unpacked_ss(bitspersymbol,gr.GR_MSB_FIRST) # unpack shorts to symbols compatible with the FSM input cardinality - enc = trellis.encoder_ss(f,0) # initial state = 0 + s2fsmi = gr.packed_to_unpacked_ss(bitspersymbol,gr.GR_MSB_FIRST) # unpack shorts to symbols compatible with the outer FSM input cardinality + enc = trellis.sccc_encoder_ss(fo,0,fi,0,interleaver,K) mod = gr.chunks_to_symbols_sf(constellation,dimensionality) # CHANNEL @@ -30,65 +24,54 @@ def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed): noise = gr.noise_source_f(gr.GR_GAUSSIAN,math.sqrt(N0/2),seed) # RX - metrics = trellis.metrics_f(f.O(),dimensionality,constellation,trellis.TRELLIS_EUCLIDEAN) # data preprocessing to generate metrics for Viterbi - va = trellis.viterbi_s(f,K,0,-1) # Put -1 if the Initial/Final states are not set. + dec = trellis.sccc_decoder_combined_fs(fo,0,-1,fi,0,-1,interleaver,K,IT,trellis.TRELLIS_MIN_SUM,dimensionality,constellation,trellis.TRELLIS_EUCLIDEAN,1.0) fsmi2s = gr.unpacked_to_packed_ss(bitspersymbol,gr.GR_MSB_FIRST) # pack FSM input symbols to shorts - #s2b = gr.packed_to_unpacked_ss(1,gr.GR_MSB_FIRST) # unpack shorts to bits - #dst = gr.vector_sink_s(); dst = gr.check_lfsr_32k_s() - + #tb.connect (src,src_head,s2fsmi,enc_out,inter,enc_in,mod) tb.connect (src,src_head,s2fsmi,enc,mod) - #tb.connect (src,b2s,s2fsmi,enc,mod) tb.connect (mod,(add,0)) tb.connect (noise,(add,1)) - tb.connect (add,metrics) - tb.connect (metrics,va,fsmi2s,dst) - #tb.connect (metrics,va,fsmi2s,s2b,dst) - + #tb.connect (add,head) + #tb.connect (tail,fsmi2s,dst) + tb.connect (add,dec,fsmi2s,dst) tb.run() + + #print enc_out.ST(), enc_in.ST() - # A bit of cheating: run the program once and print the - # final encoder state.. - # Then put it as the last argument in the viterbi block - #print "final state = " , enc.ST() - ntotal = dst.ntotal () nright = dst.nright () runlength = dst.runlength () - #ntotal = len(packet) - #if len(dst.data()) != ntotal: - #print "Error: not enough data\n" - #nright = 0; - #for i in range(ntotal): - #if packet[i]==dst.data()[i]: - #nright=nright+1 - #else: - #print "Error in ", i return (ntotal,ntotal-nright) - - def main(args): nargs = len (args) - if nargs == 2: - esn0_db=float(args[0]) # Es/No in dB - rep=int(args[1]) # number of times the experiment is run to collect enough errors + if nargs == 5: + fname_out=args[0] + fname_in=args[1] + esn0_db=float(args[2]) # Es/No in dB + IT=int(args[3]) + rep=int(args[4]) # number of times the experiment is run to collect enough errors else: - sys.stderr.write ('usage: test_tcm2.py Es/No_db repetitions\n') + sys.stderr.write ('usage: test_tcm.py fsm_name_out fsm_fname_in Es/No_db iterations repetitions\n') sys.exit (1) # system parameters - f=trellis.fsm(1,2,[5,7]) # generate FSM specification from the generator matrix Kb=1024*16 # packet size in bits (make it multiple of 16 so it can be packed in a short) - bitspersymbol = int(round(math.log(f.I())/math.log(2))) # bits per FSM input symbol + fo=trellis.fsm(fname_out) # get the outer FSM specification from a file + fi=trellis.fsm(fname_in) # get the innner FSM specification from a file + bitspersymbol = int(round(math.log(fo.I())/math.log(2))) # bits per FSM input symbol + if fo.O() != fi.I(): + sys.stderr.write ('Incompatible cardinality between outer and inner FSM.\n') + sys.exit (1) K=Kb/bitspersymbol # packet size in trellis steps - modulation = fsm_utils.psk4 # see fsm_utlis.py for available predefined modulations + interleaver=trellis.interleaver(K,666) # construct a random interleaver + modulation = fsm_utils.psk8 # see fsm_utlis.py for available predefined modulations dimensionality = modulation[0] constellation = modulation[1] - if len(constellation)/dimensionality != f.O(): + if len(constellation)/dimensionality != fi.O(): sys.stderr.write ('Incompatible FSM output cardinality and modulation size.\n') sys.exit (1) # calculate average symbol energy @@ -102,11 +85,11 @@ def main(args): terr_s=0 # total number of shorts in error terr_p=0 # total number of packets in error for i in range(rep): - (s,e)=run_test(f,Kb,bitspersymbol,K,dimensionality,constellation,N0,-long(666+i)) # run experiment with different seed to get different noise realizations + (s,e)=run_test(fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation,Es,N0,IT,-long(666+i)) # run experiment with different seed to get different noise realizations tot_s=tot_s+s terr_s=terr_s+e terr_p=terr_p+(terr_s!=0) - if ((i+1)%100==0) : # display progress + if ((i+1)%10==0): # display progress print i+1,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) # estimate of the (short or bit) error rate print rep,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) diff --git a/gr-trellis/src/examples/test_sccc_turbo2.py b/gr-trellis/src/examples/test_sccc_turbo2.py new file mode 100755 index 000000000..a47f6400e --- /dev/null +++ b/gr-trellis/src/examples/test_sccc_turbo2.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python + +from gnuradio import gr +from gnuradio import trellis +from gnuradio import eng_notation +import math +import sys +import random +import fsm_utils + + +def run_test (fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation,Es,N0,IT,seed): + tb = gr.top_block () + + # TX + src = gr.lfsr_32k_source_s() + src_head = gr.head (gr.sizeof_short,Kb/16) # packet size in shorts + s2fsmi = gr.packed_to_unpacked_ss(bitspersymbol,gr.GR_MSB_FIRST) # unpack shorts to symbols compatible with the outer FSM input cardinality + enc = trellis.sccc_encoder_ss(fo,0,fi,0,interleaver,K) + mod = gr.chunks_to_symbols_sf(constellation,dimensionality) + + # CHANNEL + add = gr.add_ff() + noise = gr.noise_source_f(gr.GR_GAUSSIAN,math.sqrt(N0/2),seed) + + # RX + metrics_in = trellis.metrics_f(fi.O(),dimensionality,constellation,trellis.TRELLIS_EUCLIDEAN) # data preprocessing to generate metrics for innner SISO + scale = gr.multiply_const_ff(1.0/N0) + dec = trellis.sccc_decoder_s(fo,0,-1,fi,0,-1,interleaver,K,IT,trellis.TRELLIS_MIN_SUM) + fsmi2s = gr.unpacked_to_packed_ss(bitspersymbol,gr.GR_MSB_FIRST) # pack FSM input symbols to shorts + dst = gr.check_lfsr_32k_s() + + #tb.connect (src,src_head,s2fsmi,enc_out,inter,enc_in,mod) + tb.connect (src,src_head,s2fsmi,enc,mod) + tb.connect (mod,(add,0)) + tb.connect (noise,(add,1)) + #tb.connect (add,head) + #tb.connect (tail,fsmi2s,dst) + tb.connect (add,metrics_in,scale,dec,fsmi2s,dst) + + tb.run() + + #print enc_out.ST(), enc_in.ST() + + ntotal = dst.ntotal () + nright = dst.nright () + runlength = dst.runlength () + return (ntotal,ntotal-nright) + + +def main(args): + nargs = len (args) + if nargs == 5: + fname_out=args[0] + fname_in=args[1] + esn0_db=float(args[2]) # Es/No in dB + IT=int(args[3]) + rep=int(args[4]) # number of times the experiment is run to collect enough errors + else: + sys.stderr.write ('usage: test_tcm.py fsm_name_out fsm_fname_in Es/No_db iterations repetitions\n') + sys.exit (1) + + # system parameters + Kb=1024*16 # packet size in bits (make it multiple of 16 so it can be packed in a short) + fo=trellis.fsm(fname_out) # get the outer FSM specification from a file + fi=trellis.fsm(fname_in) # get the innner FSM specification from a file + bitspersymbol = int(round(math.log(fo.I())/math.log(2))) # bits per FSM input symbol + if fo.O() != fi.I(): + sys.stderr.write ('Incompatible cardinality between outer and inner FSM.\n') + sys.exit (1) + K=Kb/bitspersymbol # packet size in trellis steps + interleaver=trellis.interleaver(K,666) # construct a random interleaver + modulation = fsm_utils.psk8 # see fsm_utlis.py for available predefined modulations + dimensionality = modulation[0] + constellation = modulation[1] + if len(constellation)/dimensionality != fi.O(): + sys.stderr.write ('Incompatible FSM output cardinality and modulation size.\n') + sys.exit (1) + # calculate average symbol energy + Es = 0 + for i in range(len(constellation)): + Es = Es + constellation[i]**2 + Es = Es / (len(constellation)/dimensionality) + N0=Es/pow(10.0,esn0_db/10.0); # calculate noise variance + + tot_s=0 # total number of transmitted shorts + terr_s=0 # total number of shorts in error + terr_p=0 # total number of packets in error + for i in range(rep): + (s,e)=run_test(fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation,Es,N0,IT,-long(666+i)) # run experiment with different seed to get different noise realizations + tot_s=tot_s+s + terr_s=terr_s+e + terr_p=terr_p+(terr_s!=0) + if ((i+1)%10==0): # display progress + print i+1,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + # estimate of the (short or bit) error rate + print rep,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + + +if __name__ == '__main__': + main (sys.argv[1:]) diff --git a/gr-trellis/src/examples/test_tcm.py b/gr-trellis/src/examples/test_tcm.py index 62e0c413a..d2e3c6271 100755 --- a/gr-trellis/src/examples/test_tcm.py +++ b/gr-trellis/src/examples/test_tcm.py @@ -1,13 +1,14 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math import sys import random import fsm_utils +from gnuradio.eng_option import eng_option +from optparse import OptionParser def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed): tb = gr.top_block () @@ -71,18 +72,25 @@ def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed): -def main(args): - nargs = len (args) - if nargs == 3: - fname=args[0] - esn0_db=float(args[1]) # Es/No in dB - rep=int(args[2]) # number of times the experiment is run to collect enough errors - else: - sys.stderr.write ('usage: test_tcm.py fsm_fname Es/No_db repetitions\n') - sys.exit (1) +def main(): + parser = OptionParser(option_class=eng_option) + parser.add_option("-f", "--fsm_file", type="string", default="fsm_files/awgn1o2_4.fsm", help="Filename containing the fsm specification, e.g. -f fsm_files/awgn1o2_4.fsm (default=fsm_files/awgn1o2_4.fsm)") + parser.add_option("-e", "--esn0", type="eng_float", default=10.0, help="Symbol energy to noise PSD level ratio in dB, e.g., -e 10.0 (default=10.0)") + parser.add_option("-r", "--repetitions", type="int", default=100, help="Number of packets to be generated for the simulation, e.g., -r 100 (default=100)") + + (options, args) = parser.parse_args () + if len(args) != 0: + parser.print_help() + raise SystemExit, 1 + + fname=options.fsm_file + esn0_db=float(options.esn0) + rep=int(options.repetitions) # system parameters f=trellis.fsm(fname) # get the FSM specification from a file + # alternatively you can specify the fsm from its generator matrix + #f=trellis.fsm(1,2,[5,7]) Kb=1024*16 # packet size in bits (make it multiple of 16 so it can be packed in a short) bitspersymbol = int(round(math.log(f.I())/math.log(2))) # bits per FSM input symbol K=Kb/bitspersymbol # packet size in trellis steps @@ -115,4 +123,4 @@ def main(args): if __name__ == '__main__': - main (sys.argv[1:]) + main() diff --git a/gr-trellis/src/examples/test_tcm1.py b/gr-trellis/src/examples/test_tcm_bit.py index 746bd9336..008e1e6f0 100755 --- a/gr-trellis/src/examples/test_tcm1.py +++ b/gr-trellis/src/examples/test_tcm_bit.py @@ -1,13 +1,15 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math import sys import random import fsm_utils +from gnuradio.eng_option import eng_option +from optparse import OptionParser + def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed): tb = gr.top_block () @@ -74,15 +76,21 @@ def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed): -def main(args): - nargs = len (args) - if nargs == 3: - fname=args[0] - esn0_db=float(args[1]) # Es/No in dB - rep=int(args[2]) # number of times the experiment is run to collect enough errors - else: - sys.stderr.write ('usage: test_tcm.py fsm_fname Es/No_db repetitions\n') - sys.exit (1) +def main(): + parser = OptionParser(option_class=eng_option) + parser.add_option("-f", "--fsm_file", type="string", default="fsm_files/awgn1o2_4.fsm", help="Filename containing the fsm specification, e.g. -f fsm_files/awgn1o2_4.fsm (default=fsm_files/awgn1o2_4.fsm)") + parser.add_option("-e", "--esn0", type="eng_float", default=10.0, help="Symbol energy to noise PSD level ratio in dB, e.g., -e 10.0 (default=10.0)") + parser.add_option("-r", "--repetitions", type="int", default=100, help="Number of packets to be generated for the simulation, e.g., -r 100 (default=100)") + + (options, args) = parser.parse_args () + if len(args) != 0: + parser.print_help() + raise SystemExit, 1 + + fname=options.fsm_file + esn0_db=float(options.esn0) + rep=int(options.repetitions) + # system parameters f=trellis.fsm(fname) # get the FSM specification from a file @@ -100,7 +108,7 @@ def main(args): for i in range(len(constellation)): Es = Es + constellation[i]**2 Es = Es / (len(constellation)/dimensionality) - N0=Es/pow(10.0,esn0_db/10.0); # noise variance + N0=Es/pow(10.0,esn0_db/10.0); # calculate noise variance tot_s=0 # total number of transmitted shorts terr_s=0 # total number of shorts in error @@ -118,4 +126,4 @@ def main(args): if __name__ == '__main__': - main (sys.argv[1:]) + main() diff --git a/gr-trellis/src/examples/test_tcm_combined.py b/gr-trellis/src/examples/test_tcm_combined.py index d2d42b40b..f9b698ae9 100755 --- a/gr-trellis/src/examples/test_tcm_combined.py +++ b/gr-trellis/src/examples/test_tcm_combined.py @@ -1,12 +1,14 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math import sys import fsm_utils +from gnuradio.eng_option import eng_option +from optparse import OptionParser + def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed): tb = gr.top_block () @@ -52,15 +54,20 @@ def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed): -def main(args): - nargs = len (args) - if nargs == 3: - fname=args[0] - esn0_db=float(args[1]) # Es/No in dB - rep=int(args[2]) # number of times the experiment is run to collect enough errors - else: - sys.stderr.write ('usage: test_tcm_combined.py fsm_fname Es/No_db repetitions\n') - sys.exit (1) +def main(): + parser = OptionParser(option_class=eng_option) + parser.add_option("-f", "--fsm_file", type="string", default="fsm_files/awgn1o2_4.fsm", help="Filename containing the fsm specification, e.g. -f fsm_files/awgn1o2_4.fsm (default=fsm_files/awgn1o2_4.fsm)") + parser.add_option("-e", "--esn0", type="eng_float", default=10.0, help="Symbol energy to noise PSD level ratio in dB, e.g., -e 10.0 (default=10.0)") + parser.add_option("-r", "--repetitions", type="int", default=100, help="Number of packets to be generated for the simulation, e.g., -r 100 (default=100)") + + (options, args) = parser.parse_args () + if len(args) != 0: + parser.print_help() + raise SystemExit, 1 + + fname=options.fsm_file + esn0_db=float(options.esn0) + rep=int(options.repetitions) # system parameters f=trellis.fsm(fname) # get the FSM specification from a file (will hopefully be automated in the future...) @@ -96,5 +103,5 @@ def main(args): if __name__ == '__main__': - main (sys.argv[1:]) + main() diff --git a/gr-trellis/src/examples/test_tcm_parallel.py b/gr-trellis/src/examples/test_tcm_parallel.py index 8e2f5a230..94761fd01 100755 --- a/gr-trellis/src/examples/test_tcm_parallel.py +++ b/gr-trellis/src/examples/test_tcm_parallel.py @@ -1,12 +1,14 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math import sys import fsm_utils +from gnuradio.eng_option import eng_option +from optparse import OptionParser + def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed,P): tb = gr.top_block () @@ -58,15 +60,20 @@ def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed,P): -def main(args): - nargs = len (args) - if nargs == 3: - fname=args[0] - esn0_db=float(args[1]) # Es/No in dB - rep=int(args[2]) # number of times the experiment is run to collect enough errors - else: - sys.stderr.write ('usage: test_tcm.py fsm_fname Es/No_db repetitions\n') - sys.exit (1) +def main(): + parser = OptionParser(option_class=eng_option) + parser.add_option("-f", "--fsm_file", type="string", default="fsm_files/awgn1o2_4.fsm", help="Filename containing the fsm specification, e.g. -f fsm_files/awgn1o2_4.fsm (default=fsm_files/awgn1o2_4.fsm)") + parser.add_option("-e", "--esn0", type="eng_float", default=10.0, help="Symbol energy to noise PSD level ratio in dB, e.g., -e 10.0 (default=10.0)") + parser.add_option("-r", "--repetitions", type="int", default=100, help="Number of packets to be generated for the simulation, e.g., -r 100 (default=100)") + + (options, args) = parser.parse_args () + if len(args) != 0: + parser.print_help() + raise SystemExit, 1 + + fname=options.fsm_file + esn0_db=float(options.esn0) + rep=int(options.repetitions) # system parameters f=trellis.fsm(fname) # get the FSM specification from a file @@ -102,5 +109,5 @@ def main(args): if __name__ == '__main__': - main (sys.argv[1:]) + main() diff --git a/gr-trellis/src/examples/test_turbo_equalization.py b/gr-trellis/src/examples/test_turbo_equalization.py index 612f6951c..0bf691222 100755 --- a/gr-trellis/src/examples/test_turbo_equalization.py +++ b/gr-trellis/src/examples/test_turbo_equalization.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math diff --git a/gr-trellis/src/examples/test_turbo_equalization1.py b/gr-trellis/src/examples/test_turbo_equalization1.py index 8d2feec8a..feae4ce89 100755 --- a/gr-trellis/src/examples/test_turbo_equalization1.py +++ b/gr-trellis/src/examples/test_turbo_equalization1.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math diff --git a/gr-trellis/src/examples/test_turbo_equalization2.py b/gr-trellis/src/examples/test_turbo_equalization2.py index f1731016e..ff14299c6 100755 --- a/gr-trellis/src/examples/test_turbo_equalization2.py +++ b/gr-trellis/src/examples/test_turbo_equalization2.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math diff --git a/gr-trellis/src/examples/test_viterbi_equalization.py b/gr-trellis/src/examples/test_viterbi_equalization.py index 86fc00674..eda692024 100755 --- a/gr-trellis/src/examples/test_viterbi_equalization.py +++ b/gr-trellis/src/examples/test_viterbi_equalization.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math diff --git a/gr-trellis/src/examples/test_viterbi_equalization1.py b/gr-trellis/src/examples/test_viterbi_equalization1.py index d26f73bc0..3a65b9363 100755 --- a/gr-trellis/src/examples/test_viterbi_equalization1.py +++ b/gr-trellis/src/examples/test_viterbi_equalization1.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from gnuradio import gr -from gnuradio import audio from gnuradio import trellis from gnuradio import eng_notation import math diff --git a/gr-trellis/src/lib/.gitignore b/gr-trellis/src/lib/.gitignore index 5dcb1c2c7..816b0aab8 100644 --- a/gr-trellis/src/lib/.gitignore +++ b/gr-trellis/src/lib/.gitignore @@ -57,6 +57,24 @@ /trellis_viterbi_i.cc /trellis_encoder_bb.h /trellis_encoder_bb.i +/trellis_sccc_encoder_bb.cc +/trellis_sccc_encoder_bb.h +/trellis_sccc_encoder_bb.i +/trellis_sccc_encoder_bi.cc +/trellis_sccc_encoder_bi.h +/trellis_sccc_encoder_bi.i +/trellis_sccc_encoder_bs.cc +/trellis_sccc_encoder_bs.h +/trellis_sccc_encoder_bs.i +/trellis_sccc_encoder_ii.cc +/trellis_sccc_encoder_ii.h +/trellis_sccc_encoder_ii.i +/trellis_sccc_encoder_si.cc +/trellis_sccc_encoder_si.h +/trellis_sccc_encoder_si.i +/trellis_sccc_encoder_ss.cc +/trellis_sccc_encoder_ss.h +/trellis_sccc_encoder_ss.i /trellis_metrics_s.cc /trellis_viterbi_combined_fs.h /trellis_viterbi_combined_fs.i @@ -94,6 +112,60 @@ /trellis_viterbi_combined_ss.i /trellis_viterbi_combined_ib.cc /trellis_viterbi_combined_sb.cc +/trellis_sccc_decoder_combined_fb.h +/trellis_sccc_decoder_combined_fb.i +/trellis_sccc_decoder_combined_fb.cc +/trellis_sccc_decoder_combined_fs.h +/trellis_sccc_decoder_combined_fs.i +/trellis_sccc_decoder_combined_fs.cc +/trellis_sccc_decoder_combined_fi.h +/trellis_sccc_decoder_combined_fi.i +/trellis_sccc_decoder_combined_fi.cc +/trellis_sccc_decoder_combined_cb.h +/trellis_sccc_decoder_combined_cb.i +/trellis_sccc_decoder_combined_cb.cc +/trellis_sccc_decoder_combined_cs.h +/trellis_sccc_decoder_combined_cs.i +/trellis_sccc_decoder_combined_cs.cc +/trellis_sccc_decoder_combined_ci.h +/trellis_sccc_decoder_combined_ci.i +/trellis_sccc_decoder_combined_ci.cc +/trellis_sccc_decoder_b.h +/trellis_sccc_decoder_b.i +/trellis_sccc_decoder_b.cc +/trellis_sccc_decoder_s.h +/trellis_sccc_decoder_s.i +/trellis_sccc_decoder_s.cc +/trellis_sccc_decoder_i.h +/trellis_sccc_decoder_i.i +/trellis_sccc_decoder_i.cc +/trellis_pccc_decoder_b.h +/trellis_pccc_decoder_b.i +/trellis_pccc_decoder_b.cc +/trellis_pccc_decoder_s.h +/trellis_pccc_decoder_s.i +/trellis_pccc_decoder_s.cc +/trellis_pccc_decoder_i.h +/trellis_pccc_decoder_i.i +/trellis_pccc_decoder_i.cc +/trellis_pccc_encoder_bb.cc +/trellis_pccc_encoder_bb.h +/trellis_pccc_encoder_bb.i +/trellis_pccc_encoder_bi.cc +/trellis_pccc_encoder_bi.h +/trellis_pccc_encoder_bi.i +/trellis_pccc_encoder_bs.cc +/trellis_pccc_encoder_bs.h +/trellis_pccc_encoder_bs.i +/trellis_pccc_encoder_ii.cc +/trellis_pccc_encoder_ii.h +/trellis_pccc_encoder_ii.i +/trellis_pccc_encoder_si.cc +/trellis_pccc_encoder_si.h +/trellis_pccc_encoder_si.i +/trellis_pccc_encoder_ss.cc +/trellis_pccc_encoder_ss.h +/trellis_pccc_encoder_ss.i /trellis_generated.i /generate-stamp /stamp-* diff --git a/gr-trellis/src/lib/Makefile.am b/gr-trellis/src/lib/Makefile.am index 08e75291a..ae7f21f56 100644 --- a/gr-trellis/src/lib/Makefile.am +++ b/gr-trellis/src/lib/Makefile.am @@ -40,12 +40,27 @@ core_generator = \ trellis_encoder_XX.cc.t \ trellis_encoder_XX.h.t \ trellis_encoder_XX.i.t \ + trellis_sccc_encoder_XX.cc.t \ + trellis_sccc_encoder_XX.h.t \ + trellis_sccc_encoder_XX.i.t \ + trellis_pccc_encoder_XX.cc.t \ + trellis_pccc_encoder_XX.h.t \ + trellis_pccc_encoder_XX.i.t \ trellis_metrics_X.cc.t \ trellis_metrics_X.h.t \ trellis_metrics_X.i.t \ trellis_viterbi_combined_XX.cc.t \ trellis_viterbi_combined_XX.h.t \ trellis_viterbi_combined_XX.i.t \ + trellis_sccc_decoder_combined_XX.cc.t \ + trellis_sccc_decoder_combined_XX.h.t \ + trellis_sccc_decoder_combined_XX.i.t \ + trellis_sccc_decoder_X.cc.t \ + trellis_sccc_decoder_X.h.t \ + trellis_sccc_decoder_X.i.t \ + trellis_pccc_decoder_X.cc.t \ + trellis_pccc_decoder_X.h.t \ + trellis_pccc_decoder_X.i.t \ trellis_viterbi_X.cc.t \ trellis_viterbi_X.h.t \ trellis_viterbi_X.i.t @@ -66,10 +81,11 @@ grinclude_HEADERS = \ quicksort_index.h \ base.h \ interleaver.h \ - trellis_metric_type.h \ - trellis_calc_metric.h \ + metric_type.h \ + calc_metric.h \ + core_algorithms.h \ trellis_permutation.h \ - trellis_siso_type.h \ + siso_type.h \ trellis_siso_f.h \ trellis_siso_combined_f.h \ $(GENERATED_H) @@ -81,7 +97,8 @@ libgnuradio_trellis_la_SOURCES = \ quicksort_index.cc \ base.cc \ interleaver.cc \ - trellis_calc_metric.cc \ + calc_metric.cc \ + core_algorithms.cc \ trellis_permutation.cc \ trellis_siso_f.cc \ trellis_siso_combined_f.cc \ diff --git a/gr-trellis/src/lib/Makefile.gen b/gr-trellis/src/lib/Makefile.gen index 6a3f83387..534a7466e 100644 --- a/gr-trellis/src/lib/Makefile.gen +++ b/gr-trellis/src/lib/Makefile.gen @@ -12,6 +12,30 @@ GENERATED_H = \ trellis_metrics_f.h \ trellis_metrics_i.h \ trellis_metrics_s.h \ + trellis_pccc_decoder_b.h \ + trellis_pccc_decoder_i.h \ + trellis_pccc_decoder_s.h \ + trellis_pccc_encoder_bb.h \ + trellis_pccc_encoder_bi.h \ + trellis_pccc_encoder_bs.h \ + trellis_pccc_encoder_ii.h \ + trellis_pccc_encoder_si.h \ + trellis_pccc_encoder_ss.h \ + trellis_sccc_decoder_b.h \ + trellis_sccc_decoder_combined_cb.h \ + trellis_sccc_decoder_combined_ci.h \ + trellis_sccc_decoder_combined_cs.h \ + trellis_sccc_decoder_combined_fb.h \ + trellis_sccc_decoder_combined_fi.h \ + trellis_sccc_decoder_combined_fs.h \ + trellis_sccc_decoder_i.h \ + trellis_sccc_decoder_s.h \ + trellis_sccc_encoder_bb.h \ + trellis_sccc_encoder_bi.h \ + trellis_sccc_encoder_bs.h \ + trellis_sccc_encoder_ii.h \ + trellis_sccc_encoder_si.h \ + trellis_sccc_encoder_ss.h \ trellis_viterbi_b.h \ trellis_viterbi_combined_cb.h \ trellis_viterbi_combined_ci.h \ @@ -39,6 +63,30 @@ GENERATED_I = \ trellis_metrics_f.i \ trellis_metrics_i.i \ trellis_metrics_s.i \ + trellis_pccc_decoder_b.i \ + trellis_pccc_decoder_i.i \ + trellis_pccc_decoder_s.i \ + trellis_pccc_encoder_bb.i \ + trellis_pccc_encoder_bi.i \ + trellis_pccc_encoder_bs.i \ + trellis_pccc_encoder_ii.i \ + trellis_pccc_encoder_si.i \ + trellis_pccc_encoder_ss.i \ + trellis_sccc_decoder_b.i \ + trellis_sccc_decoder_combined_cb.i \ + trellis_sccc_decoder_combined_ci.i \ + trellis_sccc_decoder_combined_cs.i \ + trellis_sccc_decoder_combined_fb.i \ + trellis_sccc_decoder_combined_fi.i \ + trellis_sccc_decoder_combined_fs.i \ + trellis_sccc_decoder_i.i \ + trellis_sccc_decoder_s.i \ + trellis_sccc_encoder_bb.i \ + trellis_sccc_encoder_bi.i \ + trellis_sccc_encoder_bs.i \ + trellis_sccc_encoder_ii.i \ + trellis_sccc_encoder_si.i \ + trellis_sccc_encoder_ss.i \ trellis_viterbi_b.i \ trellis_viterbi_combined_cb.i \ trellis_viterbi_combined_ci.i \ @@ -66,6 +114,30 @@ GENERATED_CC = \ trellis_metrics_f.cc \ trellis_metrics_i.cc \ trellis_metrics_s.cc \ + trellis_pccc_decoder_b.cc \ + trellis_pccc_decoder_i.cc \ + trellis_pccc_decoder_s.cc \ + trellis_pccc_encoder_bb.cc \ + trellis_pccc_encoder_bi.cc \ + trellis_pccc_encoder_bs.cc \ + trellis_pccc_encoder_ii.cc \ + trellis_pccc_encoder_si.cc \ + trellis_pccc_encoder_ss.cc \ + trellis_sccc_decoder_b.cc \ + trellis_sccc_decoder_combined_cb.cc \ + trellis_sccc_decoder_combined_ci.cc \ + trellis_sccc_decoder_combined_cs.cc \ + trellis_sccc_decoder_combined_fb.cc \ + trellis_sccc_decoder_combined_fi.cc \ + trellis_sccc_decoder_combined_fs.cc \ + trellis_sccc_decoder_i.cc \ + trellis_sccc_decoder_s.cc \ + trellis_sccc_encoder_bb.cc \ + trellis_sccc_encoder_bi.cc \ + trellis_sccc_encoder_bs.cc \ + trellis_sccc_encoder_ii.cc \ + trellis_sccc_encoder_si.cc \ + trellis_sccc_encoder_ss.cc \ trellis_viterbi_b.cc \ trellis_viterbi_combined_cb.cc \ trellis_viterbi_combined_ci.cc \ diff --git a/gr-trellis/src/lib/trellis_calc_metric.cc b/gr-trellis/src/lib/calc_metric.cc index 0d03fd1a7..0e8f9c2d5 100644 --- a/gr-trellis/src/lib/trellis_calc_metric.cc +++ b/gr-trellis/src/lib/calc_metric.cc @@ -22,7 +22,7 @@ #include <float.h> #include <stdexcept> -#include "trellis_calc_metric.h" +#include "calc_metric.h" diff --git a/gr-trellis/src/lib/trellis_calc_metric.h b/gr-trellis/src/lib/calc_metric.h index fabf4e145..d628f44e0 100644 --- a/gr-trellis/src/lib/trellis_calc_metric.h +++ b/gr-trellis/src/lib/calc_metric.h @@ -20,12 +20,12 @@ * Boston, MA 02110-1301, USA. */ -#ifndef INCLUDED_TRELLIS_CALC_METRIC_H -#define INCLUDED_TRELLIS_CALC_METRIC_H +#ifndef INCLUDED_CALC_METRIC_H +#define INCLUDED_CALC_METRIC_H #include <vector> #include <gr_complex.h> -#include <trellis_metric_type.h> +#include <metric_type.h> template <class T> diff --git a/gr-trellis/src/lib/core_algorithms.cc b/gr-trellis/src/lib/core_algorithms.cc new file mode 100644 index 000000000..91ac8fbdf --- /dev/null +++ b/gr-trellis/src/lib/core_algorithms.cc @@ -0,0 +1,1239 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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. + */ + +#include <cstring> +#include <stdexcept> +//#include <cstdio> +#include <iostream> +#include "core_algorithms.h" +#include "calc_metric.h" + +static const float INF = 1.0e9; + +float min(float a, float b) +{ + return a <= b ? a : b; +} + +float min_star(float a, float b) +{ + return (a <= b ? a : b)-log(1+exp(a <= b ? a-b : b-a)); +} + + + + +template <class T> +void viterbi_algorithm(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + const float *in, T *out)//, + //std::vector<int> &trace) +{ + std::vector<int> trace(S*K); + std::vector<float> alpha(S*2); + int alphai; + float norm,mm,minm; + int minmi; + int st; + + + if(S0<0) { // initial state not specified + for(int i=0;i<S;i++) alpha[0*S+i]=0; + } + else { + for(int i=0;i<S;i++) alpha[0*S+i]=INF; + alpha[0*S+S0]=0.0; + } + + alphai=0; + for(int k=0;k<K;k++) { + norm=INF; + for(int j=0;j<S;j++) { // for each next state do ACS + minm=INF; + minmi=0; + for(unsigned int i=0;i<PS[j].size();i++) { + //int i0 = j*I+i; + if((mm=alpha[alphai*S+PS[j][i]]+in[k*O+OS[PS[j][i]*I+PI[j][i]]])<minm) + minm=mm,minmi=i; + } + trace[k*S+j]=minmi; + alpha[((alphai+1)%2)*S+j]=minm; + if(minm<norm) norm=minm; + } + for(int j=0;j<S;j++) + alpha[((alphai+1)%2)*S+j]-=norm; // normalize total metrics so they do not explode + alphai=(alphai+1)%2; + } + + if(SK<0) { // final state not specified + minm=INF; + minmi=0; + for(int i=0;i<S;i++) + if((mm=alpha[alphai*S+i])<minm) minm=mm,minmi=i; + st=minmi; + } + else { + st=SK; + } + + for(int k=K-1;k>=0;k--) { // traceback + int i0=trace[k*S+st]; + out[k]= (T) PI[st][i0]; + st=PS[st][i0]; + } + +} + + +template +void viterbi_algorithm<unsigned char>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + const float *in, unsigned char *out); + + +template +void viterbi_algorithm<short>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + const float *in, short *out); + +template +void viterbi_algorithm<int>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + const float *in, int *out); + + + +//============================================== + +template <class Ti, class To> +void viterbi_algorithm_combined(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<Ti> &TABLE, + trellis_metric_type_t TYPE, + const Ti *in, To *out +) +{ + std::vector<int> trace(S*K); + std::vector<float> alpha(S*2); + float *metric = new float[O]; + int alphai; + float norm,mm,minm; + int minmi; + int st; + + if(S0<0) { // initial state not specified + for(int i=0;i<S;i++) alpha[0*S+i]=0; + } + else { + for(int i=0;i<S;i++) alpha[0*S+i]=INF; + alpha[0*S+S0]=0.0; + } + + alphai=0; + for(int k=0;k<K;k++) { + calc_metric(O, D, TABLE, &(in[k*D]), metric,TYPE); // calc metrics + norm=INF; + for(int j=0;j<S;j++) { // for each next state do ACS + minm=INF; + minmi=0; + for(unsigned int i=0;i<PS[j].size();i++) { + //int i0 = j*I+i; + if((mm=alpha[alphai*S+PS[j][i]]+metric[OS[PS[j][i]*I+PI[j][i]]])<minm) + minm=mm,minmi=i; + } + trace[k*S+j]=minmi; + alpha[((alphai+1)%2)*S+j]=minm; + if(minm<norm) norm=minm; + } + for(int j=0;j<S;j++) + alpha[((alphai+1)%2)*S+j]-=norm; // normalize total metrics so they do not explode + alphai=(alphai+1)%2; + } + + if(SK<0) { // final state not specified + minm=INF; + minmi=0; + for(int i=0;i<S;i++) + if((mm=alpha[alphai*S+i])<minm) minm=mm,minmi=i; + st=minmi; + } + else { + st=SK; + } + + for(int k=K-1;k>=0;k--) { // traceback + int i0=trace[k*S+st]; + out[k]= (To) PI[st][i0]; + st=PS[st][i0]; + } + + delete [] metric; + +} + +// Ti = s i f c +// To = b s i + +//--------------- + +template +void viterbi_algorithm_combined<short,unsigned char>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<short> &TABLE, + trellis_metric_type_t TYPE, + const short *in, unsigned char *out +); + +template +void viterbi_algorithm_combined<int,unsigned char>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<int> &TABLE, + trellis_metric_type_t TYPE, + const int *in, unsigned char *out +); + +template +void viterbi_algorithm_combined<float,unsigned char>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<float> &TABLE, + trellis_metric_type_t TYPE, + const float *in, unsigned char *out +); + +template +void viterbi_algorithm_combined<gr_complex,unsigned char>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<gr_complex> &TABLE, + trellis_metric_type_t TYPE, + const gr_complex *in, unsigned char *out +); + +//--------------- + +template +void viterbi_algorithm_combined<short,short>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<short> &TABLE, + trellis_metric_type_t TYPE, + const short *in, short *out +); + +template +void viterbi_algorithm_combined<int,short>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<int> &TABLE, + trellis_metric_type_t TYPE, + const int *in, short *out +); + +template +void viterbi_algorithm_combined<float,short>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<float> &TABLE, + trellis_metric_type_t TYPE, + const float *in, short *out +); + +template +void viterbi_algorithm_combined<gr_complex,short>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<gr_complex> &TABLE, + trellis_metric_type_t TYPE, + const gr_complex *in, short *out +); + +//-------------- + +template +void viterbi_algorithm_combined<short,int>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<short> &TABLE, + trellis_metric_type_t TYPE, + const short *in, int *out +); + +template +void viterbi_algorithm_combined<int,int>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<int> &TABLE, + trellis_metric_type_t TYPE, + const int *in, int *out +); + +template +void viterbi_algorithm_combined<float,int>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<float> &TABLE, + trellis_metric_type_t TYPE, + const float *in, int *out +); + +template +void viterbi_algorithm_combined<gr_complex,int>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<gr_complex> &TABLE, + trellis_metric_type_t TYPE, + const gr_complex *in, int *out +); + + + + + + + + + + + + + + + + + + + + +//=============================================== + + +void siso_algorithm(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + bool POSTI, bool POSTO, + float (*p2mymin)(float,float), + const float *priori, const float *prioro, float *post//, + //std::vector<float> &alpha, + //std::vector<float> &beta + ) +{ + float norm,mm,minm; + std::vector<float> alpha(S*(K+1)); + std::vector<float> beta(S*(K+1)); + + + if(S0<0) { // initial state not specified + for(int i=0;i<S;i++) alpha[0*S+i]=0; + } + else { + for(int i=0;i<S;i++) alpha[0*S+i]=INF; + alpha[0*S+S0]=0.0; + } + + for(int k=0;k<K;k++) { // forward recursion + norm=INF; + for(int j=0;j<S;j++) { + minm=INF; + for(unsigned int i=0;i<PS[j].size();i++) { + //int i0 = j*I+i; + mm=alpha[k*S+PS[j][i]]+priori[k*I+PI[j][i]]+prioro[k*O+OS[PS[j][i]*I+PI[j][i]]]; + minm=(*p2mymin)(minm,mm); + } + alpha[(k+1)*S+j]=minm; + if(minm<norm) norm=minm; + } + for(int j=0;j<S;j++) + alpha[(k+1)*S+j]-=norm; // normalize total metrics so they do not explode + } + + if(SK<0) { // final state not specified + for(int i=0;i<S;i++) beta[K*S+i]=0; + } + else { + for(int i=0;i<S;i++) beta[K*S+i]=INF; + beta[K*S+SK]=0.0; + } + + for(int k=K-1;k>=0;k--) { // backward recursion + norm=INF; + for(int j=0;j<S;j++) { + minm=INF; + for(int i=0;i<I;i++) { + int i0 = j*I+i; + mm=beta[(k+1)*S+NS[i0]]+priori[k*I+i]+prioro[k*O+OS[i0]]; + minm=(*p2mymin)(minm,mm); + } + beta[k*S+j]=minm; + if(minm<norm) norm=minm; + } + for(int j=0;j<S;j++) + beta[k*S+j]-=norm; // normalize total metrics so they do not explode + } + + +if (POSTI && POSTO) +{ + for(int k=0;k<K;k++) { // input combining + norm=INF; + for(int i=0;i<I;i++) { + minm=INF; + for(int j=0;j<S;j++) { + mm=alpha[k*S+j]+prioro[k*O+OS[j*I+i]]+beta[(k+1)*S+NS[j*I+i]]; + minm=(*p2mymin)(minm,mm); + } + post[k*(I+O)+i]=minm; + if(minm<norm) norm=minm; + } + for(int i=0;i<I;i++) + post[k*(I+O)+i]-=norm; // normalize metrics + } + + + for(int k=0;k<K;k++) { // output combining + norm=INF; + for(int n=0;n<O;n++) { + minm=INF; + for(int j=0;j<S;j++) { + for(int i=0;i<I;i++) { + mm= (n==OS[j*I+i] ? alpha[k*S+j]+priori[k*I+i]+beta[(k+1)*S+NS[j*I+i]] : INF); + minm=(*p2mymin)(minm,mm); + } + } + post[k*(I+O)+I+n]=minm; + if(minm<norm) norm=minm; + } + for(int n=0;n<O;n++) + post[k*(I+O)+I+n]-=norm; // normalize metrics + } +} +else if(POSTI) +{ + for(int k=0;k<K;k++) { // input combining + norm=INF; + for(int i=0;i<I;i++) { + minm=INF; + for(int j=0;j<S;j++) { + mm=alpha[k*S+j]+prioro[k*O+OS[j*I+i]]+beta[(k+1)*S+NS[j*I+i]]; + minm=(*p2mymin)(minm,mm); + } + post[k*I+i]=minm; + if(minm<norm) norm=minm; + } + for(int i=0;i<I;i++) + post[k*I+i]-=norm; // normalize metrics + } +} +else if(POSTO) +{ + for(int k=0;k<K;k++) { // output combining + norm=INF; + for(int n=0;n<O;n++) { + minm=INF; + for(int j=0;j<S;j++) { + for(int i=0;i<I;i++) { + mm= (n==OS[j*I+i] ? alpha[k*S+j]+priori[k*I+i]+beta[(k+1)*S+NS[j*I+i]] : INF); + minm=(*p2mymin)(minm,mm); + } + } + post[k*O+n]=minm; + if(minm<norm) norm=minm; + } + for(int n=0;n<O;n++) + post[k*O+n]-=norm; // normalize metrics + } +} +else + throw std::runtime_error ("Not both POSTI and POSTO can be false."); + +} + + +//=========================================================== + +template <class T> +void siso_algorithm_combined(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + bool POSTI, bool POSTO, + float (*p2mymin)(float,float), + int D, + const std::vector<T> &TABLE, + trellis_metric_type_t TYPE, + const float *priori, const T *observations, float *post +) +{ + float norm,mm,minm; + std::vector<float> alpha(S*(K+1)); + std::vector<float> beta(S*(K+1)); + float *prioro = new float[O*K]; + + + if(S0<0) { // initial state not specified + for(int i=0;i<S;i++) alpha[0*S+i]=0; + } + else { + for(int i=0;i<S;i++) alpha[0*S+i]=INF; + alpha[0*S+S0]=0.0; + } + + for(int k=0;k<K;k++) { // forward recursion + calc_metric(O, D, TABLE, &(observations[k*D]), &(prioro[k*O]),TYPE); // calc metrics + norm=INF; + for(int j=0;j<S;j++) { + minm=INF; + for(unsigned int i=0;i<PS[j].size();i++) { + //int i0 = j*I+i; + mm=alpha[k*S+PS[j][i]]+priori[k*I+PI[j][i]]+prioro[k*O+OS[PS[j][i]*I+PI[j][i]]]; + minm=(*p2mymin)(minm,mm); + } + alpha[(k+1)*S+j]=minm; + if(minm<norm) norm=minm; + } + for(int j=0;j<S;j++) + alpha[(k+1)*S+j]-=norm; // normalize total metrics so they do not explode + } + + if(SK<0) { // final state not specified + for(int i=0;i<S;i++) beta[K*S+i]=0; + } + else { + for(int i=0;i<S;i++) beta[K*S+i]=INF; + beta[K*S+SK]=0.0; + } + + for(int k=K-1;k>=0;k--) { // backward recursion + norm=INF; + for(int j=0;j<S;j++) { + minm=INF; + for(int i=0;i<I;i++) { + int i0 = j*I+i; + mm=beta[(k+1)*S+NS[i0]]+priori[k*I+i]+prioro[k*O+OS[i0]]; + minm=(*p2mymin)(minm,mm); + } + beta[k*S+j]=minm; + if(minm<norm) norm=minm; + } + for(int j=0;j<S;j++) + beta[k*S+j]-=norm; // normalize total metrics so they do not explode + } + + + if (POSTI && POSTO) + { + for(int k=0;k<K;k++) { // input combining + norm=INF; + for(int i=0;i<I;i++) { + minm=INF; + for(int j=0;j<S;j++) { + mm=alpha[k*S+j]+prioro[k*O+OS[j*I+i]]+beta[(k+1)*S+NS[j*I+i]]; + minm=(*p2mymin)(minm,mm); + } + post[k*(I+O)+i]=minm; + if(minm<norm) norm=minm; + } + for(int i=0;i<I;i++) + post[k*(I+O)+i]-=norm; // normalize metrics + } + + + for(int k=0;k<K;k++) { // output combining + norm=INF; + for(int n=0;n<O;n++) { + minm=INF; + for(int j=0;j<S;j++) { + for(int i=0;i<I;i++) { + mm= (n==OS[j*I+i] ? alpha[k*S+j]+priori[k*I+i]+beta[(k+1)*S+NS[j*I+i]] : INF); + minm=(*p2mymin)(minm,mm); + } + } + post[k*(I+O)+I+n]=minm; + if(minm<norm) norm=minm; + } + for(int n=0;n<O;n++) + post[k*(I+O)+I+n]-=norm; // normalize metrics + } + } + else if(POSTI) + { + for(int k=0;k<K;k++) { // input combining + norm=INF; + for(int i=0;i<I;i++) { + minm=INF; + for(int j=0;j<S;j++) { + mm=alpha[k*S+j]+prioro[k*O+OS[j*I+i]]+beta[(k+1)*S+NS[j*I+i]]; + minm=(*p2mymin)(minm,mm); + } + post[k*I+i]=minm; + if(minm<norm) norm=minm; + } + for(int i=0;i<I;i++) + post[k*I+i]-=norm; // normalize metrics + } + } + else if(POSTO) + { + for(int k=0;k<K;k++) { // output combining + norm=INF; + for(int n=0;n<O;n++) { + minm=INF; + for(int j=0;j<S;j++) { + for(int i=0;i<I;i++) { + mm= (n==OS[j*I+i] ? alpha[k*S+j]+priori[k*I+i]+beta[(k+1)*S+NS[j*I+i]] : INF); + minm=(*p2mymin)(minm,mm); + } + } + post[k*O+n]=minm; + if(minm<norm) norm=minm; + } + for(int n=0;n<O;n++) + post[k*O+n]-=norm; // normalize metrics + } + } + else + throw std::runtime_error ("Not both POSTI and POSTO can be false."); + + delete [] prioro; + +} + +//--------- + +template +void siso_algorithm_combined<short>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + bool POSTI, bool POSTO, + float (*p2mymin)(float,float), + int D, + const std::vector<short> &TABLE, + trellis_metric_type_t TYPE, + const float *priori, const short *observations, float *post +); + +template +void siso_algorithm_combined<int>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + bool POSTI, bool POSTO, + float (*p2mymin)(float,float), + int D, + const std::vector<int> &TABLE, + trellis_metric_type_t TYPE, + const float *priori, const int *observations, float *post +); + +template +void siso_algorithm_combined<float>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + bool POSTI, bool POSTO, + float (*p2mymin)(float,float), + int D, + const std::vector<float> &TABLE, + trellis_metric_type_t TYPE, + const float *priori, const float *observations, float *post +); + +template +void siso_algorithm_combined<gr_complex>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + bool POSTI, bool POSTO, + float (*p2mymin)(float,float), + int D, + const std::vector<gr_complex> &TABLE, + trellis_metric_type_t TYPE, + const float *priori, const gr_complex *observations, float *post +); + +//========================================================= + +template<class Ti, class To> +void sccc_decoder_combined( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + int D, const std::vector<Ti> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling, + const Ti *observations, To *data +) +{ + +//allocate space for priori, prioro and posti of inner FSM +std::vector<float> ipriori(blocklength*FSMi.I(),0.0); +std::vector<float> iprioro(blocklength*FSMi.O()); +std::vector<float> iposti(blocklength*FSMi.I()); + +//allocate space for priori, prioro and posto of outer FSM +std::vector<float> opriori(blocklength*FSMo.I(),0.0); +std::vector<float> oprioro(blocklength*FSMo.O()); +std::vector<float> oposti(blocklength*FSMo.I()); +std::vector<float> oposto(blocklength*FSMo.O()); + +// turn observations to neg-log-priors +for(int k=0;k<blocklength;k++) { + calc_metric(FSMi.O(), D, TABLE, &(observations[k*D]), &(iprioro[k*FSMi.O()]),METRIC_TYPE); + iprioro[k*FSMi.O()] *= scaling; +} + +for(int rep=0;rep<repetitions;rep++) { + // run inner SISO + siso_algorithm(FSMi.I(),FSMi.S(),FSMi.O(), + FSMi.NS(), FSMi.OS(), FSMi.PS(), FSMi.PI(), + blocklength, + STi0,STiK, + true, false, + p2mymin, + &(ipriori[0]), &(iprioro[0]), &(iposti[0]) + ); + + //interleave soft info inner -> outer + for(int k=0;k<blocklength;k++) { + int ki = INTERLEAVER.DEINTER()[k]; + //for(int i=0;i<FSMi.I();i++) { + //oprioro[k*FSMi.I()+i]=iposti[ki*FSMi.I()+i]; + //} + memcpy(&(oprioro[k*FSMi.I()]),&(iposti[ki*FSMi.I()]),FSMi.I()*sizeof(float)); + } + + // run outer SISO + + if(rep<repetitions-1) { // do not produce posti + siso_algorithm(FSMo.I(),FSMo.S(),FSMo.O(), + FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), + blocklength, + STo0,SToK, + false, true, + p2mymin, + &(opriori[0]), &(oprioro[0]), &(oposto[0]) + ); + + //interleave soft info outer --> inner + for(int k=0;k<blocklength;k++) { + int ki = INTERLEAVER.DEINTER()[k]; + //for(int i=0;i<FSMi.I();i++) { + //ipriori[ki*FSMi.I()+i]=oposto[k*FSMi.I()+i]; + //} + memcpy(&(ipriori[ki*FSMi.I()]),&(oposto[k*FSMi.I()]),FSMi.I()*sizeof(float)); + } + } + else // produce posti but not posto + + siso_algorithm(FSMo.I(),FSMo.S(),FSMo.O(), + FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), + blocklength, + STo0,SToK, + true, false, + p2mymin, + &(opriori[0]), &(oprioro[0]), &(oposti[0]) + ); + + /* + viterbi_algorithm(FSMo.I(),FSMo.S(),FSMo.O(), + FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), + blocklength, + STo0,SToK, + &(oprioro[0]), data + ); + */ + +} + + +// generate hard decisions +for(int k=0;k<blocklength;k++) { + float min=INF; + int mini=0; + for(int i=0;i<FSMo.I();i++) { + if(oposti[k*FSMo.I()+i]<min) { + min=oposti[k*FSMo.I()+i]; + mini=i; + } + } + data[k]=(To)mini; +} + + + +} + +//------- + +template +void sccc_decoder_combined<float,unsigned char>( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + int D, const std::vector<float> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling, + const float *observations, unsigned char *data +); + +template +void sccc_decoder_combined<float,short>( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + int D, const std::vector<float> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling, + const float *observations, short *data +); + +template +void sccc_decoder_combined<float,int>( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + int D, const std::vector<float> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling, + const float *observations, int *data +); + +template +void sccc_decoder_combined<gr_complex,unsigned char>( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + int D, const std::vector<gr_complex> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling, + const gr_complex *observations, unsigned char *data +); + +template +void sccc_decoder_combined<gr_complex,short>( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + int D, const std::vector<gr_complex> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling, + const gr_complex *observations, short *data +); + +template +void sccc_decoder_combined<gr_complex,int>( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + int D, const std::vector<gr_complex> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling, + const gr_complex *observations, int *data +); + + + +//========================================================= + +template<class T> +void sccc_decoder( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + const float *iprioro, T *data +) +{ + //allocate space for priori, and posti of inner FSM + std::vector<float> ipriori(blocklength*FSMi.I(),0.0); + std::vector<float> iposti(blocklength*FSMi.I()); + + //allocate space for priori, prioro and posto of outer FSM + std::vector<float> opriori(blocklength*FSMo.I(),0.0); + std::vector<float> oprioro(blocklength*FSMo.O()); + std::vector<float> oposti(blocklength*FSMo.I()); + std::vector<float> oposto(blocklength*FSMo.O()); + + for(int rep=0;rep<repetitions;rep++) { + // run inner SISO + siso_algorithm(FSMi.I(),FSMi.S(),FSMi.O(), + FSMi.NS(), FSMi.OS(), FSMi.PS(), FSMi.PI(), + blocklength, + STi0,STiK, + true, false, + p2mymin, + &(ipriori[0]), &(iprioro[0]), &(iposti[0]) + ); + + //interleave soft info inner -> outer + for(int k=0;k<blocklength;k++) { + int ki = INTERLEAVER.DEINTER()[k]; + //for(int i=0;i<FSMi.I();i++) { + //oprioro[k*FSMi.I()+i]=iposti[ki*FSMi.I()+i]; + //} + memcpy(&(oprioro[k*FSMi.I()]),&(iposti[ki*FSMi.I()]),FSMi.I()*sizeof(float)); + } + + // run outer SISO + + if(rep<repetitions-1) { // do not produce posti + siso_algorithm(FSMo.I(),FSMo.S(),FSMo.O(), + FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), + blocklength, + STo0,SToK, + false, true, + p2mymin, + &(opriori[0]), &(oprioro[0]), &(oposto[0]) + ); + + //interleave soft info outer --> inner + for(int k=0;k<blocklength;k++) { + int ki = INTERLEAVER.DEINTER()[k]; + //for(int i=0;i<FSMi.I();i++) { + //ipriori[ki*FSMi.I()+i]=oposto[k*FSMi.I()+i]; + //} + memcpy(&(ipriori[ki*FSMi.I()]),&(oposto[k*FSMi.I()]),FSMi.I()*sizeof(float)); + } + } + else {// produce posti but not posto + + siso_algorithm(FSMo.I(),FSMo.S(),FSMo.O(), + FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), + blocklength, + STo0,SToK, + true, false, + p2mymin, + &(opriori[0]), &(oprioro[0]), &(oposti[0]) + ); + + /* + viterbi_algorithm(FSMo.I(),FSMo.S(),FSMo.O(), + FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), + blocklength, + STo0,SToK, + &(oprioro[0]), data + ); + */ + } + + } // end repetitions + + // generate hard decisions + for(int k=0;k<blocklength;k++) { + float min=INF; + int mini=0; + for(int i=0;i<FSMo.I();i++) { + if(oposti[k*FSMo.I()+i]<min) { + min=oposti[k*FSMo.I()+i]; + mini=i; + } + } + data[k]=(T)mini; + } + + + +} + +//------- + +template +void sccc_decoder<unsigned char>( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + const float *iprioro, unsigned char *data +); + +template +void sccc_decoder<short>( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + const float *iprioro, short *data +); + +template +void sccc_decoder<int>( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + const float *iprioro, int *data +); + + +//==================================================== + +template<class T> +void pccc_decoder( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + const float *cprioro, T *data +) +{ + + //allocate space for priori, prioro and posti of FSM1 + std::vector<float> priori1(blocklength*FSM1.I(),0.0); + std::vector<float> prioro1(blocklength*FSM1.O()); + std::vector<float> posti1(blocklength*FSM1.I()); + + //allocate space for priori, prioro and posti of FSM2 + std::vector<float> priori2(blocklength*FSM2.I(),0.0); + std::vector<float> prioro2(blocklength*FSM2.O()); + std::vector<float> posti2(blocklength*FSM2.I()); + + //generate prioro1,2 (metrics are not updated per iteration: this is not the best you can do...) + for (int k=0;k<blocklength;k++) { + //std::cout << k << std::endl; + for(int i=0;i<FSM1.O();i++) { + float x=cprioro[k*FSM1.O()*FSM2.O()+i*FSM1.O()+0]; + for(int j=1;j<FSM2.O();j++) + x = (*p2mymin)(x,cprioro[k*FSM1.O()*FSM2.O()+i*FSM1.O()+j]); + prioro1[k*FSM1.O()+i]=x; + //std::cout << prioro1[k*FSM1.O()+i] << ", "; + } + //std::cout << std::endl; + for(int i=0;i<FSM2.O();i++) { + float x=cprioro[k*FSM1.O()*FSM2.O()+0*FSM1.O()+i]; + for(int j=1;j<FSM1.O();j++) + x = (*p2mymin)(x,cprioro[k*FSM1.O()*FSM2.O()+j*FSM1.O()+i]); + prioro2[k*FSM2.O()+i]=x; + } + } + + for(int rep=0;rep<repetitions;rep++) { + // run SISO 1 + siso_algorithm(FSM1.I(),FSM1.S(),FSM1.O(), + FSM1.NS(), FSM1.OS(), FSM1.PS(), FSM1.PI(), + blocklength, + ST10,ST1K, + true, false, + p2mymin, + &(priori1[0]), &(prioro1[0]), &(posti1[0]) + ); + + //for(int k=0;k<blocklength;k++){ + //for(int i=0;i<FSM1.I();i++) + //std::cout << posti1[k*FSM1.I()+i] << ", "; + //std::cout << std::endl; + //} + + //interleave soft info 1 -> 2 + for(int k=0;k<blocklength;k++) { + int ki = INTERLEAVER.INTER()[k]; + //for(int i=0;i<FSMi.I();i++) { + //oprioro[k*FSMi.I()+i]=iposti[ki*FSMi.I()+i]; + //} + memcpy(&(priori2[k*FSM2.I()]),&(posti1[ki*FSM1.I()]),FSM1.I()*sizeof(float)); + } + + // run SISO 2 + siso_algorithm(FSM2.I(),FSM2.S(),FSM2.O(), + FSM2.NS(), FSM2.OS(), FSM2.PS(), FSM2.PI(), + blocklength, + ST20,ST2K, + true, false, + p2mymin, + &(priori2[0]), &(prioro2[0]), &(posti2[0]) + ); + + //interleave soft info 2 --> 1 + for(int k=0;k<blocklength;k++) { + int ki = INTERLEAVER.INTER()[k]; + //for(int i=0;i<FSMi.I();i++) { + //ipriori[ki*FSMi.I()+i]=oposto[k*FSMi.I()+i]; + //} + memcpy(&(priori1[ki*FSM1.I()]),&(posti2[k*FSM2.I()]),FSM1.I()*sizeof(float)); + } + + } // end repetitions + + // generate hard decisions + for(int k=0;k<blocklength;k++) { + for(int i=0;i<FSM1.I();i++) + posti1[k*FSM1.I()+i] = (*p2mymin)(priori1[k*FSM1.I()+i],posti1[k*FSM1.I()+i]); + float min=INF; + int mini=0; + for(int i=0;i<FSM1.I();i++) { + if(posti1[k*FSM1.I()+i]<min) { + min=posti1[k*FSM1.I()+i]; + mini=i; + } + } + data[k]=(T)mini; + //std::cout << data[k] << ", "<< std::endl; + } + //std::cout << std::endl; + + + +} + +//---------------- + +template +void pccc_decoder<unsigned char>( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + const float *cprioro, unsigned char *data +); + +template +void pccc_decoder<short>( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + const float *cprioro, short *data +); + +template +void pccc_decoder<int>( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + const float *cprioro, int *data +); + diff --git a/gr-trellis/src/lib/core_algorithms.h b/gr-trellis/src/lib/core_algorithms.h new file mode 100644 index 000000000..fdb5f398e --- /dev/null +++ b/gr-trellis/src/lib/core_algorithms.h @@ -0,0 +1,128 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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_CORE_ALGORITHMS_H +#define INCLUDED_CORE_ALGORITHMS_H + +#include <cmath> +#include <vector> +//#include <gr_complex.h> +#include "metric_type.h" +#include "fsm.h" +#include "interleaver.h" + + +float min(float a, float b); +float min_star(float a, float b); + +template <class T> +void viterbi_algorithm(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + const float *in, T *out +); + +template <class Ti, class To> +void viterbi_algorithm_combined(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + int D, + const std::vector<Ti> &TABLE, + trellis_metric_type_t TYPE, + const Ti *in, To *out +); + + + +void siso_algorithm(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + bool POSTI, bool POSTO, + float (*p2mymin)(float,float), + const float *priori, const float *prioro, float *post +); + + +template <class T> +void siso_algorithm_combined(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + bool POSTI, bool POSTO, + float (*p2mymin)(float,float), + int D, + const std::vector<T> &TABLE, + trellis_metric_type_t TYPE, + const float *priori, const T *observations, float *post +); + + +template<class Ti, class To> +void sccc_decoder_combined( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + int D, const std::vector<Ti> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling, + const Ti *observations, To *data +); + + +template<class T> +void sccc_decoder( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + const float *iprioro, T *data +); + + +template<class T> +void pccc_decoder( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, int blocklength, int repetitions, + float (*p2mymin)(float,float), + const float *cprioro, T *data +); + + + +#endif diff --git a/gr-trellis/src/lib/generate_trellis.py b/gr-trellis/src/lib/generate_trellis.py index a4206d268..9f845f74a 100644 --- a/gr-trellis/src/lib/generate_trellis.py +++ b/gr-trellis/src/lib/generate_trellis.py @@ -28,16 +28,26 @@ import re other_roots = [ 'trellis_encoder_XX', + 'trellis_sccc_encoder_XX', + 'trellis_pccc_encoder_XX', 'trellis_metrics_X', 'trellis_viterbi_X', 'trellis_viterbi_combined_XX', + 'trellis_sccc_decoder_combined_XX', + 'trellis_sccc_decoder_X', + 'trellis_pccc_decoder_X', ] other_signatures = ( ['bb','bs','bi','ss','si','ii'], + ['bb','bs','bi','ss','si','ii'], + ['bb','bs','bi','ss','si','ii'], ['s','i','f','c'], ['b','s','i'], ['sb','ss','si','ib','is','ii','fb','fs','fi','cb','cs','ci'], + ['fb','fs','fi','cb','cs','ci'], + ['b','s','i'], + ['b','s','i'], ) diff --git a/gr-trellis/src/lib/interleaver.cc b/gr-trellis/src/lib/interleaver.cc index ff15eeadc..131dcb07b 100644 --- a/gr-trellis/src/lib/interleaver.cc +++ b/gr-trellis/src/lib/interleaver.cc @@ -124,7 +124,7 @@ interleaver::interleaver(int K, int seed) //###################################################################### -//# Write an INTERLEAVER specification from a file. +//# Write an INTERLEAVER specification to a file. //# Format //# K //# blank line diff --git a/gr-trellis/src/lib/trellis_metric_type.h b/gr-trellis/src/lib/metric_type.h index a1040f108..a1040f108 100644 --- a/gr-trellis/src/lib/trellis_metric_type.h +++ b/gr-trellis/src/lib/metric_type.h diff --git a/gr-trellis/src/lib/trellis_siso_type.h b/gr-trellis/src/lib/siso_type.h index 3a7163d02..3a7163d02 100644 --- a/gr-trellis/src/lib/trellis_siso_type.h +++ b/gr-trellis/src/lib/siso_type.h diff --git a/gr-trellis/src/lib/trellis.i b/gr-trellis/src/lib/trellis.i index d035cea54..8d1118436 100644 --- a/gr-trellis/src/lib/trellis.i +++ b/gr-trellis/src/lib/trellis.i @@ -38,8 +38,8 @@ %include "trellis_siso_f.i" %include "trellis_siso_combined_f.i" -%include "trellis_metric_type.h" -%include "trellis_siso_type.h" +%include "metric_type.h" +%include "siso_type.h" %include "trellis_generated.i" diff --git a/gr-trellis/src/lib/trellis_metrics_X.cc.t b/gr-trellis/src/lib/trellis_metrics_X.cc.t index 4bdaabc22..cd66df6fb 100644 --- a/gr-trellis/src/lib/trellis_metrics_X.cc.t +++ b/gr-trellis/src/lib/trellis_metrics_X.cc.t @@ -22,7 +22,7 @@ // @WARNING@ -#ifndef HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/gr-trellis/src/lib/trellis_metrics_X.h.t b/gr-trellis/src/lib/trellis_metrics_X.h.t index f862a032d..45d4ace10 100644 --- a/gr-trellis/src/lib/trellis_metrics_X.h.t +++ b/gr-trellis/src/lib/trellis_metrics_X.h.t @@ -26,7 +26,7 @@ #define @GUARD_NAME@ #include <gr_block.h> -#include "trellis_calc_metric.h" +#include "calc_metric.h" class @NAME@; typedef boost::shared_ptr<@NAME@> @SPTR_NAME@; diff --git a/gr-trellis/src/lib/trellis_pccc_decoder_X.cc.t b/gr-trellis/src/lib/trellis_pccc_decoder_X.cc.t new file mode 100644 index 000000000..34dd2eb87 --- /dev/null +++ b/gr-trellis/src/lib/trellis_pccc_decoder_X.cc.t @@ -0,0 +1,124 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010 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. + */ + +// @WARNING@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <@NAME@.h> +#include <gr_io_signature.h> +#include <assert.h> +#include <iostream> +#include "core_algorithms.h" + + +static const float INF = 1.0e9; + +@SPTR_NAME@ +trellis_make_@BASE_NAME@ ( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE +) +{ + return gnuradio::get_initial_sptr (new @NAME@ ( + FSM1, ST10, ST1K, + FSM2, ST20, ST2K, + INTERLEAVER, + blocklength, + repetitions, + SISO_TYPE + )); +} + +@NAME@::@NAME@ ( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE +) + : gr_block ("@BASE_NAME@", + gr_make_io_signature (1, 1, sizeof (float)), + gr_make_io_signature (1, 1, sizeof (@O_TYPE@))), + d_FSM1 (FSM1), d_ST10 (ST10), d_ST1K (ST1K), + d_FSM2 (FSM2), d_ST20 (ST20), d_ST2K (ST2K), + d_INTERLEAVER (INTERLEAVER), + d_blocklength (blocklength), + d_repetitions (repetitions), + d_SISO_TYPE (SISO_TYPE) +{ + assert(d_FSM1.I() == d_FSM2.I()); + set_relative_rate (1.0 / ((double) d_FSM1.O() * d_FSM2.O())); + set_output_multiple (d_blocklength); +} + + +void +@NAME@::forecast (int noutput_items, gr_vector_int &ninput_items_required) +{ + assert (noutput_items % d_blocklength == 0); + int input_required = d_FSM1.O() * d_FSM2.O() * noutput_items ; + ninput_items_required[0] = input_required; +} + + + +//=========================================================== + +int +@NAME@::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + assert (noutput_items % d_blocklength == 0); + int nblocks = noutput_items / d_blocklength; + + float (*p2min)(float, float) = NULL; + if(d_SISO_TYPE == TRELLIS_MIN_SUM) + p2min = &min; + else if(d_SISO_TYPE == TRELLIS_SUM_PRODUCT) + p2min = &min_star; + + + const float *in = (const float *) input_items[0]; + @O_TYPE@ *out = (@O_TYPE@ *) output_items[0]; + for (int n=0;n<nblocks;n++) { + pccc_decoder( + d_FSM1, d_ST10, d_ST1K, + d_FSM2, d_ST20, d_ST2K, + d_INTERLEAVER, d_blocklength, d_repetitions, + p2min, + &(in[n*d_blocklength*d_FSM1.O()*d_FSM2.O()]),&(out[n*d_blocklength]) + ); + } + + consume_each (d_FSM1.O() * d_FSM2.O() * noutput_items ); + return noutput_items; +} diff --git a/gr-trellis/src/lib/trellis_pccc_decoder_X.h.t b/gr-trellis/src/lib/trellis_pccc_decoder_X.h.t new file mode 100644 index 000000000..ff4b7a1f8 --- /dev/null +++ b/gr-trellis/src/lib/trellis_pccc_decoder_X.h.t @@ -0,0 +1,102 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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. + */ + +// @WARNING@ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include "fsm.h" +#include "interleaver.h" +#include <gr_block.h> +#include <vector> +#include "siso_type.h" + +class @NAME@; +typedef boost::shared_ptr<@NAME@> @SPTR_NAME@; + +@SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE // perform "min-sum" or "sum-product" combining +); + + +/*! + * \ingroup coding_blk + */ +class @NAME@ : public gr_block +{ + fsm d_FSM1; + fsm d_FSM2; + int d_ST10; + int d_ST1K; + int d_ST20; + int d_ST2K; + interleaver d_INTERLEAVER; + int d_blocklength; + int d_repetitions; + trellis_siso_type_t d_SISO_TYPE; + std::vector<float> d_buffer; + + friend @SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE + ); + + @NAME@ ( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE + ); + +public: + fsm FSM1 () const { return d_FSM1; } + fsm FSM2 () const { return d_FSM2; } + int ST10 () const { return d_ST10; } + int ST1K () const { return d_ST1K; } + int ST20 () const { return d_ST20; } + int ST2K () const { return d_ST2K; } + interleaver INTERLEAVER () const { return d_INTERLEAVER; } + int blocklength () const { return d_blocklength; } + int repetitions () const { return d_repetitions; } + trellis_siso_type_t SISO_TYPE () const { return d_SISO_TYPE; } + + void forecast (int noutput_items, + gr_vector_int &ninput_items_required); + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/gr-trellis/src/lib/trellis_pccc_decoder_X.i.t b/gr-trellis/src/lib/trellis_pccc_decoder_X.i.t new file mode 100644 index 000000000..83d7fe969 --- /dev/null +++ b/gr-trellis/src/lib/trellis_pccc_decoder_X.i.t @@ -0,0 +1,60 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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. + */ + +// @WARNING@ + +GR_SWIG_BLOCK_MAGIC(trellis,@BASE_NAME@); + +@SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE +); + + +class @NAME@ : public gr_block +{ +private: + @NAME@ ( + const fsm &FSM1, int ST10, int ST1K, + const fsm &FSM2, int ST20, int ST2K, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE + ); + +public: + fsm FSM1 () const { return d_FSM1; } + fsm FSM2 () const { return d_FSM2; } + int ST10 () const { return d_ST10; } + int ST1K () const { return d_ST1K; } + int ST20 () const { return d_ST20; } + int ST2K () const { return d_ST2K; } + interleaver INTERLEAVER () const { return d_INTERLEAVER; } + int blocklength () const { return d_blocklength; } + int repetitions () const { return d_repetitions; } + trellis_siso_type_t SISO_TYPE () const { return d_SISO_TYPE; } +}; diff --git a/gr-trellis/src/lib/trellis_pccc_encoder_XX.cc.t b/gr-trellis/src/lib/trellis_pccc_encoder_XX.cc.t new file mode 100644 index 000000000..40dcd4105 --- /dev/null +++ b/gr-trellis/src/lib/trellis_pccc_encoder_XX.cc.t @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010 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. + */ + +// @WARNING@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <@NAME@.h> +#include <gr_io_signature.h> +#include <iostream> + +@SPTR_NAME@ +trellis_make_@BASE_NAME@ ( + const fsm &FSM1, int ST1, + const fsm &FSM2, int ST2, + const interleaver &INTERLEAVER, + int blocklength +) +{ + return gnuradio::get_initial_sptr (new @NAME@ (FSM1,ST1,FSM2,ST2,INTERLEAVER,blocklength)); +} + +@NAME@::@NAME@ ( + const fsm &FSM1, int ST1, + const fsm &FSM2, int ST2, + const interleaver &INTERLEAVER, + int blocklength +) + : gr_sync_block ("@BASE_NAME@", + gr_make_io_signature (1, 1, sizeof (@I_TYPE@)), + gr_make_io_signature (1, 1, sizeof (@O_TYPE@))), + d_FSM1 (FSM1), + d_ST1 (ST1), + d_FSM2 (FSM2), + d_ST2 (ST2), + d_INTERLEAVER (INTERLEAVER), + d_blocklength (blocklength) +{ + assert(d_FSM1.I() == d_FSM2.I()); + set_output_multiple(d_blocklength); + d_buffer.resize(d_blocklength); +} + + + +int +@NAME@::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + assert(noutput_items%d_blocklength ==0); + for (int b = 0 ; b<noutput_items/d_blocklength; b++) { + const @I_TYPE@ *in = (const @I_TYPE@ *) input_items[0]+b*d_blocklength; + @O_TYPE@ *out = (@O_TYPE@ *) output_items[0]+b*d_blocklength; + + int ST1_tmp = d_ST1; + int ST2_tmp = d_ST2; + for (int i = 0; i < d_blocklength; i++){ + int k = d_INTERLEAVER.INTER()[i]; + int o1 = d_FSM1.OS()[ST1_tmp*d_FSM1.I()+in[i]]; + ST1_tmp = (int) d_FSM1.NS()[ST1_tmp*d_FSM1.I()+in[i]]; + int o2 = d_FSM2.OS()[ST2_tmp*d_FSM2.I()+in[k]]; + ST2_tmp = (int) d_FSM2.NS()[ST2_tmp*d_FSM2.I()+in[k]]; + out[i] = (@O_TYPE@) (o1*d_FSM1.O() + o2); + } + } + return noutput_items; +} + diff --git a/gr-trellis/src/lib/trellis_pccc_encoder_XX.h.t b/gr-trellis/src/lib/trellis_pccc_encoder_XX.h.t new file mode 100644 index 000000000..68ccf75db --- /dev/null +++ b/gr-trellis/src/lib/trellis_pccc_encoder_XX.h.t @@ -0,0 +1,83 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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. + */ + +// @WARNING@ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include <vector> +#include "fsm.h" +#include "interleaver.h" +#include <gr_sync_block.h> + +class @NAME@; +typedef boost::shared_ptr<@NAME@> @SPTR_NAME@; + +@SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSM1, int ST1, + const fsm &FSM2, int ST2, + const interleaver &INTERLEAVER, + int blocklength +); + +/*! + * \brief SCCC encoder. + * \ingroup coding_blk + */ +class @NAME@ : public gr_sync_block +{ +private: + friend @SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSM1, int ST1, + const fsm &FSM2, int ST2, + const interleaver &INTERLEAVER, + int blocklength + ); + fsm d_FSM1; + int d_ST1; + fsm d_FSM2; + int d_ST2; + interleaver d_INTERLEAVER; + int d_blocklength; + std::vector<int> d_buffer; + @NAME@ ( + const fsm &FSM1, int ST1, + const fsm &FSM2, int ST2, + const interleaver &INTERLEAVER, + int blocklength + ); + +public: + fsm FSM1 () const { return d_FSM1; } + int ST1 () const { return d_ST1; } + fsm FSM2 () const { return d_FSM2; } + int ST2 () const { return d_ST2; } + interleaver INTERLEAVER () const { return d_INTERLEAVER; } + int blocklength () const { return d_blocklength; } + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/gr-trellis/src/lib/trellis_pccc_encoder_XX.i.t b/gr-trellis/src/lib/trellis_pccc_encoder_XX.i.t new file mode 100644 index 000000000..c02ee428a --- /dev/null +++ b/gr-trellis/src/lib/trellis_pccc_encoder_XX.i.t @@ -0,0 +1,50 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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. + */ + +// @WARNING@ + +GR_SWIG_BLOCK_MAGIC(trellis,@BASE_NAME@); + +@SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSM1, int ST1, + const fsm &FSM2, int ST2, + const interleaver &INTERLEAVER, + int blocklength +); + +class @NAME@ : public gr_sync_block +{ +private: + @NAME@ ( + const fsm &FSM1, int ST1, + const fsm &FSM2, int ST2, + const interleaver &INTERLEAVER, + int blocklength + ); +public: + fsm FSM1 () const { return d_FSM1; } + int ST1 () const { return d_ST1; } + fsm FSM2 () const { return d_FSM2; } + int ST2 () const { return d_ST2; } + interleaver INTERLEAVER () const { return d_INTERLEAVER; } + int blocklength () const { return d_blocklength; } +}; diff --git a/gr-trellis/src/lib/trellis_sccc_decoder_X.cc.t b/gr-trellis/src/lib/trellis_sccc_decoder_X.cc.t new file mode 100644 index 000000000..4a0f471fa --- /dev/null +++ b/gr-trellis/src/lib/trellis_sccc_decoder_X.cc.t @@ -0,0 +1,124 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010 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. + */ + +// @WARNING@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <@NAME@.h> +#include <gr_io_signature.h> +#include <assert.h> +#include <iostream> +#include "core_algorithms.h" + + +static const float INF = 1.0e9; + +@SPTR_NAME@ +trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE +) +{ + return gnuradio::get_initial_sptr (new @NAME@ ( + FSMo, STo0, SToK, + FSMi, STi0, STiK, + INTERLEAVER, + blocklength, + repetitions, + SISO_TYPE + )); +} + +@NAME@::@NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE +) + : gr_block ("@BASE_NAME@", + gr_make_io_signature (1, 1, sizeof (float)), + gr_make_io_signature (1, 1, sizeof (@O_TYPE@))), + d_FSMo (FSMo), d_STo0 (STo0), d_SToK (SToK), + d_FSMi (FSMi), d_STi0 (STi0), d_STiK (STiK), + d_INTERLEAVER (INTERLEAVER), + d_blocklength (blocklength), + d_repetitions (repetitions), + d_SISO_TYPE (SISO_TYPE) +{ + assert(d_FSMo.O() == d_FSMi.I()); + set_relative_rate (1.0 / ((double) d_FSMi.O())); + set_output_multiple (d_blocklength); +} + + +void +@NAME@::forecast (int noutput_items, gr_vector_int &ninput_items_required) +{ + assert (noutput_items % d_blocklength == 0); + int input_required = d_FSMi.O() * noutput_items ; + ninput_items_required[0] = input_required; +} + + + +//=========================================================== + +int +@NAME@::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + assert (noutput_items % d_blocklength == 0); + int nblocks = noutput_items / d_blocklength; + + float (*p2min)(float, float) = NULL; + if(d_SISO_TYPE == TRELLIS_MIN_SUM) + p2min = &min; + else if(d_SISO_TYPE == TRELLIS_SUM_PRODUCT) + p2min = &min_star; + + + const float *in = (const float *) input_items[0]; + @O_TYPE@ *out = (@O_TYPE@ *) output_items[0]; + for (int n=0;n<nblocks;n++) { + sccc_decoder( + d_FSMo, d_STo0, d_SToK, + d_FSMi, d_STi0, d_STiK, + d_INTERLEAVER, d_blocklength, d_repetitions, + p2min, + &(in[n*d_blocklength*d_FSMi.O()]),&(out[n*d_blocklength]) + ); + } + + consume_each (d_FSMi.O() * noutput_items ); + return noutput_items; +} diff --git a/gr-trellis/src/lib/trellis_sccc_decoder_X.h.t b/gr-trellis/src/lib/trellis_sccc_decoder_X.h.t new file mode 100644 index 000000000..3adb8a5b7 --- /dev/null +++ b/gr-trellis/src/lib/trellis_sccc_decoder_X.h.t @@ -0,0 +1,102 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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. + */ + +// @WARNING@ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include "fsm.h" +#include "interleaver.h" +#include <gr_block.h> +#include <vector> +#include "siso_type.h" + +class @NAME@; +typedef boost::shared_ptr<@NAME@> @SPTR_NAME@; + +@SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE // perform "min-sum" or "sum-product" combining +); + + +/*! + * \ingroup coding_blk + */ +class @NAME@ : public gr_block +{ + fsm d_FSMo; + fsm d_FSMi; + int d_STo0; + int d_SToK; + int d_STi0; + int d_STiK; + interleaver d_INTERLEAVER; + int d_blocklength; + int d_repetitions; + trellis_siso_type_t d_SISO_TYPE; + std::vector<float> d_buffer; + + friend @SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE + ); + + @NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE + ); + +public: + fsm FSMo () const { return d_FSMo; } + fsm FSMi () const { return d_FSMi; } + int STo0 () const { return d_STo0; } + int SToK () const { return d_SToK; } + int STi0 () const { return d_STi0; } + int STiK () const { return d_STiK; } + interleaver INTERLEAVER () const { return d_INTERLEAVER; } + int blocklength () const { return d_blocklength; } + int repetitions () const { return d_repetitions; } + trellis_siso_type_t SISO_TYPE () const { return d_SISO_TYPE; } + + void forecast (int noutput_items, + gr_vector_int &ninput_items_required); + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/gr-trellis/src/lib/trellis_sccc_decoder_X.i.t b/gr-trellis/src/lib/trellis_sccc_decoder_X.i.t new file mode 100644 index 000000000..a4392ee6f --- /dev/null +++ b/gr-trellis/src/lib/trellis_sccc_decoder_X.i.t @@ -0,0 +1,60 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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. + */ + +// @WARNING@ + +GR_SWIG_BLOCK_MAGIC(trellis,@BASE_NAME@); + +@SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE +); + + +class @NAME@ : public gr_block +{ +private: + @NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE + ); + +public: + fsm FSMo () const { return d_FSMo; } + fsm FSMi () const { return d_FSMi; } + int STo0 () const { return d_STo0; } + int SToK () const { return d_SToK; } + int STi0 () const { return d_STi0; } + int STiK () const { return d_STiK; } + interleaver INTERLEAVER () const { return d_INTERLEAVER; } + int blocklength () const { return d_blocklength; } + int repetitions () const { return d_repetitions; } + trellis_siso_type_t SISO_TYPE () const { return d_SISO_TYPE; } +}; diff --git a/gr-trellis/src/lib/trellis_sccc_decoder_combined_XX.cc.t b/gr-trellis/src/lib/trellis_sccc_decoder_combined_XX.cc.t new file mode 100644 index 000000000..2927e3fe3 --- /dev/null +++ b/gr-trellis/src/lib/trellis_sccc_decoder_combined_XX.cc.t @@ -0,0 +1,147 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010 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. + */ + +// @WARNING@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <@NAME@.h> +#include <gr_io_signature.h> +#include <assert.h> +#include <iostream> +#include "core_algorithms.h" + + +static const float INF = 1.0e9; + +@SPTR_NAME@ +trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE, + int D, + const std::vector<@I_TYPE@> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling +) +{ + return gnuradio::get_initial_sptr (new @NAME@ ( + FSMo, STo0, SToK, + FSMi, STi0, STiK, + INTERLEAVER, + blocklength, + repetitions, + SISO_TYPE, + D, + TABLE,METRIC_TYPE, + scaling + )); +} + +@NAME@::@NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE, + int D, + const std::vector<@I_TYPE@> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling +) + : gr_block ("@BASE_NAME@", + gr_make_io_signature (1, 1, sizeof (@I_TYPE@)), + gr_make_io_signature (1, 1, sizeof (@O_TYPE@))), + d_FSMo (FSMo), d_STo0 (STo0), d_SToK (SToK), + d_FSMi (FSMi), d_STi0 (STi0), d_STiK (STiK), + d_INTERLEAVER (INTERLEAVER), + d_blocklength (blocklength), + d_repetitions (repetitions), + d_SISO_TYPE (SISO_TYPE), + d_D (D), + d_TABLE (TABLE), + d_METRIC_TYPE (METRIC_TYPE), + d_scaling (scaling) +{ + assert(d_FSMo.O() == d_FSMi.I()); + set_relative_rate (1.0 / ((double) d_D)); + set_output_multiple (d_blocklength); +} + +void @NAME@::set_scaling(float scaling) +{ + d_scaling = scaling; +} + + +void +@NAME@::forecast (int noutput_items, gr_vector_int &ninput_items_required) +{ + assert (noutput_items % d_blocklength == 0); + int input_required = d_D * noutput_items ; + ninput_items_required[0] = input_required; +} + + + +//=========================================================== + +int +@NAME@::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + assert (noutput_items % d_blocklength == 0); + int nblocks = noutput_items / d_blocklength; + + float (*p2min)(float, float) = NULL; + if(d_SISO_TYPE == TRELLIS_MIN_SUM) + p2min = &min; + else if(d_SISO_TYPE == TRELLIS_SUM_PRODUCT) + p2min = &min_star; + + + const @I_TYPE@ *in = (const @I_TYPE@ *) input_items[0]; + @O_TYPE@ *out = (@O_TYPE@ *) output_items[0]; + for (int n=0;n<nblocks;n++) { + sccc_decoder_combined( + d_FSMo, d_STo0, d_SToK, + d_FSMi, d_STi0, d_STiK, + d_INTERLEAVER, d_blocklength, d_repetitions, + p2min, + d_D,d_TABLE, + d_METRIC_TYPE, + d_scaling, + &(in[n*d_blocklength*d_D]),&(out[n*d_blocklength]) + ); + } + + consume_each (d_D * noutput_items ); + return noutput_items; +} diff --git a/gr-trellis/src/lib/trellis_sccc_decoder_combined_XX.h.t b/gr-trellis/src/lib/trellis_sccc_decoder_combined_XX.h.t new file mode 100644 index 000000000..146c26516 --- /dev/null +++ b/gr-trellis/src/lib/trellis_sccc_decoder_combined_XX.h.t @@ -0,0 +1,124 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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. + */ + +// @WARNING@ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include "fsm.h" +#include "interleaver.h" +#include <gr_block.h> +#include <vector> +#include "calc_metric.h" +#include "siso_type.h" + +class @NAME@; +typedef boost::shared_ptr<@NAME@> @SPTR_NAME@; + +@SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE, // perform "min-sum" or "sum-product" combining + int D, + const std::vector<@I_TYPE@> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling +); + + +/*! + * \ingroup coding_blk + */ +class @NAME@ : public gr_block +{ + fsm d_FSMo; + fsm d_FSMi; + int d_STo0; + int d_SToK; + int d_STi0; + int d_STiK; + interleaver d_INTERLEAVER; + int d_blocklength; + int d_repetitions; + trellis_siso_type_t d_SISO_TYPE; + int d_D; + std::vector<@I_TYPE@> d_TABLE; + trellis_metric_type_t d_METRIC_TYPE; + float d_scaling; + std::vector<float> d_buffer; + + friend @SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE, + int D, + const std::vector<@I_TYPE@> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling + ); + + @NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE, + int D, + const std::vector<@I_TYPE@> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling + ); + +public: + fsm FSMo () const { return d_FSMo; } + fsm FSMi () const { return d_FSMi; } + int STo0 () const { return d_STo0; } + int SToK () const { return d_SToK; } + int STi0 () const { return d_STi0; } + int STiK () const { return d_STiK; } + interleaver INTERLEAVER () const { return d_INTERLEAVER; } + int blocklength () const { return d_blocklength; } + int repetitions () const { return d_repetitions; } + int D () const { return d_D; } + std::vector<@I_TYPE@> TABLE () const { return d_TABLE; } + trellis_metric_type_t METRIC_TYPE () const { return d_METRIC_TYPE; } + trellis_siso_type_t SISO_TYPE () const { return d_SISO_TYPE; } + float scaling () const { return d_scaling; } + void set_scaling (float scaling); + + void forecast (int noutput_items, + gr_vector_int &ninput_items_required); + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/gr-trellis/src/lib/trellis_sccc_decoder_combined_XX.i.t b/gr-trellis/src/lib/trellis_sccc_decoder_combined_XX.i.t new file mode 100644 index 000000000..84f2eb07d --- /dev/null +++ b/gr-trellis/src/lib/trellis_sccc_decoder_combined_XX.i.t @@ -0,0 +1,73 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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. + */ + +// @WARNING@ + +GR_SWIG_BLOCK_MAGIC(trellis,@BASE_NAME@); + +@SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE, + int D, + const std::vector<@I_TYPE@> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling +); + + +class @NAME@ : public gr_block +{ +private: + @NAME@ ( + const fsm &FSMo, int STo0, int SToK, + const fsm &FSMi, int STi0, int STiK, + const interleaver &INTERLEAVER, + int blocklength, + int repetitions, + trellis_siso_type_t SISO_TYPE, + int D, + const std::vector<@I_TYPE@> &TABLE, + trellis_metric_type_t METRIC_TYPE, + float scaling + ); + +public: + fsm FSMo () const { return d_FSMo; } + fsm FSMi () const { return d_FSMi; } + int STo0 () const { return d_STo0; } + int SToK () const { return d_SToK; } + int STi0 () const { return d_STi0; } + int STiK () const { return d_STiK; } + interleaver INTERLEAVER () const { return d_INTERLEAVER; } + int blocklength () const { return d_blocklength; } + int repetitions () const { return d_repetitions; } + int D () const { return d_D; } + std::vector<@I_TYPE@> TABLE () const { return d_TABLE; } + trellis_metric_type_t METRIC_TYPE () const { return d_METRIC_TYPE; } + trellis_siso_type_t SISO_TYPE () const { return d_SISO_TYPE; } + float scaling() const { return d_scaling; } + void set_scaling (float scaling); +}; diff --git a/gr-trellis/src/lib/trellis_sccc_encoder_XX.cc.t b/gr-trellis/src/lib/trellis_sccc_encoder_XX.cc.t new file mode 100644 index 000000000..b1a46ca60 --- /dev/null +++ b/gr-trellis/src/lib/trellis_sccc_encoder_XX.cc.t @@ -0,0 +1,91 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010 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. + */ + +// @WARNING@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <@NAME@.h> +#include <gr_io_signature.h> +#include <iostream> + +@SPTR_NAME@ +trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo, + const fsm &FSMi, int STi, + const interleaver &INTERLEAVER, + int blocklength +) +{ + return gnuradio::get_initial_sptr (new @NAME@ (FSMo,STo,FSMi,STi,INTERLEAVER,blocklength)); +} + +@NAME@::@NAME@ ( + const fsm &FSMo, int STo, + const fsm &FSMi, int STi, + const interleaver &INTERLEAVER, + int blocklength +) + : gr_sync_block ("@BASE_NAME@", + gr_make_io_signature (1, 1, sizeof (@I_TYPE@)), + gr_make_io_signature (1, 1, sizeof (@O_TYPE@))), + d_FSMo (FSMo), + d_STo (STo), + d_FSMi (FSMi), + d_STi (STi), + d_INTERLEAVER (INTERLEAVER), + d_blocklength (blocklength) +{ + assert(d_FSMo.O() == d_FSMi.I()); + set_output_multiple(d_blocklength); + d_buffer.resize(d_blocklength); +} + + + +int +@NAME@::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + assert(noutput_items%d_blocklength ==0); + for (int b = 0 ; b<noutput_items/d_blocklength; b++) { + const @I_TYPE@ *in = (const @I_TYPE@ *) input_items[0]+b*d_blocklength; + @O_TYPE@ *out = (@O_TYPE@ *) output_items[0]+b*d_blocklength; + + int STo_tmp = d_STo; + for (int i = 0; i < d_blocklength; i++){ + d_buffer[i] = d_FSMo.OS()[STo_tmp*d_FSMo.I()+in[i]]; + STo_tmp = (int) d_FSMo.NS()[STo_tmp*d_FSMo.I()+in[i]]; + } + int STi_tmp = d_STi; + for (int i = 0; i < d_blocklength; i++){ + int k = d_INTERLEAVER.INTER()[i]; + out[i] = (@O_TYPE@) d_FSMi.OS()[STi_tmp*d_FSMi.I()+d_buffer[k]]; + STi_tmp = (int) d_FSMi.NS()[STi_tmp*d_FSMi.I()+d_buffer[k]]; + } + } + return noutput_items; +} + diff --git a/gr-trellis/src/lib/trellis_sccc_encoder_XX.h.t b/gr-trellis/src/lib/trellis_sccc_encoder_XX.h.t new file mode 100644 index 000000000..a9e4dc454 --- /dev/null +++ b/gr-trellis/src/lib/trellis_sccc_encoder_XX.h.t @@ -0,0 +1,83 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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. + */ + +// @WARNING@ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include <vector> +#include "fsm.h" +#include "interleaver.h" +#include <gr_sync_block.h> + +class @NAME@; +typedef boost::shared_ptr<@NAME@> @SPTR_NAME@; + +@SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo, + const fsm &FSMi, int STi, + const interleaver &INTERLEAVER, + int blocklength +); + +/*! + * \brief SCCC encoder. + * \ingroup coding_blk + */ +class @NAME@ : public gr_sync_block +{ +private: + friend @SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo, + const fsm &FSMi, int STi, + const interleaver &INTERLEAVER, + int blocklength + ); + fsm d_FSMo; + int d_STo; + fsm d_FSMi; + int d_STi; + interleaver d_INTERLEAVER; + int d_blocklength; + std::vector<int> d_buffer; + @NAME@ ( + const fsm &FSMo, int STo, + const fsm &FSMi, int STi, + const interleaver &INTERLEAVER, + int blocklength + ); + +public: + fsm FSMo () const { return d_FSMo; } + int STo () const { return d_STo; } + fsm FSMi () const { return d_FSMi; } + int STi () const { return d_STi; } + interleaver INTERLEAVER () const { return d_INTERLEAVER; } + int blocklength () const { return d_blocklength; } + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/gr-trellis/src/lib/trellis_sccc_encoder_XX.i.t b/gr-trellis/src/lib/trellis_sccc_encoder_XX.i.t new file mode 100644 index 000000000..ca6b56199 --- /dev/null +++ b/gr-trellis/src/lib/trellis_sccc_encoder_XX.i.t @@ -0,0 +1,50 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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. + */ + +// @WARNING@ + +GR_SWIG_BLOCK_MAGIC(trellis,@BASE_NAME@); + +@SPTR_NAME@ trellis_make_@BASE_NAME@ ( + const fsm &FSMo, int STo, + const fsm &FSMi, int STi, + const interleaver &INTERLEAVER, + int blocklength +); + +class @NAME@ : public gr_sync_block +{ +private: + @NAME@ ( + const fsm &FSMo, int STo, + const fsm &FSMi, int STi, + const interleaver &INTERLEAVER, + int blocklength + ); +public: + fsm FSMo () const { return d_FSMo; } + int STo () const { return d_STo; } + fsm FSMi () const { return d_FSMi; } + int STi () const { return d_STi; } + interleaver INTERLEAVER () const { return d_INTERLEAVER; } + int blocklength () const { return d_blocklength; } +}; diff --git a/gr-trellis/src/lib/trellis_siso_combined_f.cc b/gr-trellis/src/lib/trellis_siso_combined_f.cc index 708608b16..2a4cfa123 100644 --- a/gr-trellis/src/lib/trellis_siso_combined_f.cc +++ b/gr-trellis/src/lib/trellis_siso_combined_f.cc @@ -125,6 +125,13 @@ trellis_siso_combined_f::forecast (int noutput_items, gr_vector_int &ninput_item } } + + + + +/* + + inline float min(float a, float b) { return a <= b ? a : b; @@ -286,7 +293,7 @@ void siso_algorithm_combined(int I, int S, int O, } - +*/ diff --git a/gr-trellis/src/lib/trellis_siso_combined_f.h b/gr-trellis/src/lib/trellis_siso_combined_f.h index 6432c2262..786e79386 100644 --- a/gr-trellis/src/lib/trellis_siso_combined_f.h +++ b/gr-trellis/src/lib/trellis_siso_combined_f.h @@ -24,8 +24,9 @@ #define INCLUDED_TRELLIS_SISO_COMBINED_F_H #include "fsm.h" -#include "trellis_siso_type.h" -#include "trellis_calc_metric.h" +#include "siso_type.h" +#include "calc_metric.h" +#include "core_algorithms.h" #include <gr_block.h> class trellis_siso_combined_f; diff --git a/gr-trellis/src/lib/trellis_siso_f.cc b/gr-trellis/src/lib/trellis_siso_f.cc index c8fa8231d..d478c13a3 100644 --- a/gr-trellis/src/lib/trellis_siso_f.cc +++ b/gr-trellis/src/lib/trellis_siso_f.cc @@ -116,6 +116,11 @@ trellis_siso_f::forecast (int noutput_items, gr_vector_int &ninput_items_require } } + + + +/* Moved it to "core_algorithms.cc" */ +/* inline float min(float a, float b) { return a <= b ? a : b; @@ -270,7 +275,7 @@ else } - +*/ diff --git a/gr-trellis/src/lib/trellis_siso_f.h b/gr-trellis/src/lib/trellis_siso_f.h index 3e2c2498b..0e2cba67a 100644 --- a/gr-trellis/src/lib/trellis_siso_f.h +++ b/gr-trellis/src/lib/trellis_siso_f.h @@ -24,7 +24,8 @@ #define INCLUDED_TRELLIS_SISO_F_H #include "fsm.h" -#include "trellis_siso_type.h" +#include "siso_type.h" +#include "core_algorithms.h" #include <gr_block.h> class trellis_siso_f; diff --git a/gr-trellis/src/lib/trellis_viterbi_X.cc.t b/gr-trellis/src/lib/trellis_viterbi_X.cc.t index 178215362..2254f6450 100644 --- a/gr-trellis/src/lib/trellis_viterbi_X.cc.t +++ b/gr-trellis/src/lib/trellis_viterbi_X.cc.t @@ -73,9 +73,22 @@ void } } +/* +template +void viterbi_algorithm<@O_TYPE@>(int I, int S, int O, + const std::vector<int> &NS, + const std::vector<int> &OS, + const std::vector< std::vector<int> > &PS, + const std::vector< std::vector<int> > &PI, + int K, + int S0,int SK, + const float *in, @O_TYPE@ *out); +*/ +/* Moved it to "core_algorithms.cc" */ +/* void viterbi_algorithm(int I, int S, int O, const std::vector<int> &NS, const std::vector<int> &OS, @@ -141,7 +154,7 @@ void viterbi_algorithm(int I, int S, int O, } - +*/ diff --git a/gr-trellis/src/lib/trellis_viterbi_X.h.t b/gr-trellis/src/lib/trellis_viterbi_X.h.t index 67b46a8ee..362d3f57e 100644 --- a/gr-trellis/src/lib/trellis_viterbi_X.h.t +++ b/gr-trellis/src/lib/trellis_viterbi_X.h.t @@ -27,6 +27,7 @@ #include "fsm.h" #include <gr_block.h> +#include "core_algorithms.h" class @NAME@; typedef boost::shared_ptr<@NAME@> @SPTR_NAME@; @@ -78,4 +79,12 @@ public: gr_vector_void_star &output_items); }; + + + + + + + + #endif diff --git a/gr-trellis/src/lib/trellis_viterbi_combined_XX.cc.t b/gr-trellis/src/lib/trellis_viterbi_combined_XX.cc.t index d365de75f..e883a0ba7 100644 --- a/gr-trellis/src/lib/trellis_viterbi_combined_XX.cc.t +++ b/gr-trellis/src/lib/trellis_viterbi_combined_XX.cc.t @@ -90,6 +90,7 @@ void +/* void viterbi_algorithm_combined(int I, int S, int O, const std::vector<int> &NS, const std::vector<int> &OS, @@ -162,7 +163,7 @@ void viterbi_algorithm_combined(int I, int S, int O, } - +*/ diff --git a/gr-trellis/src/lib/trellis_viterbi_combined_XX.h.t b/gr-trellis/src/lib/trellis_viterbi_combined_XX.h.t index 21307d0e3..35e6c4ce0 100644 --- a/gr-trellis/src/lib/trellis_viterbi_combined_XX.h.t +++ b/gr-trellis/src/lib/trellis_viterbi_combined_XX.h.t @@ -27,7 +27,8 @@ #include "fsm.h" #include <gr_block.h> -#include "trellis_calc_metric.h" +#include "calc_metric.h" +#include "core_algorithms.h" class @NAME@; typedef boost::shared_ptr<@NAME@> @SPTR_NAME@; diff --git a/gr-uhd/Makefile.am b/gr-uhd/Makefile.am index 2e2d0fbe9..ea16c863c 100644 --- a/gr-uhd/Makefile.am +++ b/gr-uhd/Makefile.am @@ -21,9 +21,11 @@ include $(top_srcdir)/Makefile.common -SUBDIRS = include lib +SUBDIRS = include lib apps if PYTHON SUBDIRS += swig grc endif +pkgconfigdir = $(libdir)/pkgconfig +dist_pkgconfig_DATA = gnuradio-uhd.pc diff --git a/gr-uhd/apps/.gitignore b/gr-uhd/apps/.gitignore new file mode 100644 index 000000000..22a4e7292 --- /dev/null +++ b/gr-uhd/apps/.gitignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in + diff --git a/gr-uhd/apps/Makefile.am b/gr-uhd/apps/Makefile.am new file mode 100644 index 000000000..9bb9b6cdd --- /dev/null +++ b/gr-uhd/apps/Makefile.am @@ -0,0 +1,32 @@ +# +# Copyright 2011 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. +# + +include $(top_srcdir)/Makefile.common + +EXTRA_DIST += \ + $(bin_SCRIPTS) + +ourpythondir = $(grpythondir) + +bin_SCRIPTS = \ + uhd_fft.py \ + uhd_rx_cfile.py + diff --git a/gr-uhd/apps/uhd_fft.py b/gr-uhd/apps/uhd_fft.py new file mode 100755 index 000000000..87952ef3a --- /dev/null +++ b/gr-uhd/apps/uhd_fft.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python +# +# Copyright 2011 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. +# + +from gnuradio import gr, gru +from gnuradio import uhd +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider +from optparse import OptionParser +import wx +import sys +import numpy + +class app_top_block(stdgui2.std_top_block): + def __init__(self, frame, panel, vbox, argv): + stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) + + self.frame = frame + self.panel = panel + + parser = OptionParser(option_class=eng_option) + parser.add_option("-a", "--address", type="string", default="addr=192.168.10.2", + help="Address of UHD device, [default=%default]") + parser.add_option("-A", "--antenna", type="string", default=None, + help="select Rx Antenna where appropriate") + parser.add_option("-s", "--samp-rate", type="eng_float", default=1e6, + help="set sample rate (bandwidth) [default=%default]") + parser.add_option("-f", "--freq", type="eng_float", default=None, + help="set frequency to FREQ", metavar="FREQ") + parser.add_option("-g", "--gain", type="eng_float", default=None, + help="set gain in dB (default is midpoint)") + parser.add_option("-W", "--waterfall", action="store_true", default=False, + help="Enable waterfall display") + parser.add_option("-S", "--oscilloscope", action="store_true", default=False, + help="Enable oscilloscope display") + parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, + help="Set fftsink averaging factor, default=[%default]") + parser.add_option("", "--ref-scale", type="eng_float", default=1.0, + help="Set dBFS=0dB input value, default=[%default]") + parser.add_option("--fft-size", type="int", default=1024, + help="Set number of FFT bins [default=%default]") + (options, args) = parser.parse_args() + if len(args) != 0: + parser.print_help() + sys.exit(1) + self.options = options + self.show_debug_info = True + + self.u = uhd.usrp_source(device_addr=options.address, + io_type=uhd.io_type.COMPLEX_FLOAT32, + num_channels=1) + + self.u.set_samp_rate(options.samp_rate) + input_rate = self.u.get_samp_rate() + + if options.waterfall: + self.scope = \ + waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) + self.frame.SetMinSize((800, 420)) + elif options.oscilloscope: + self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) + self.frame.SetMinSize((800, 600)) + else: + self.scope = fftsink2.fft_sink_c (panel, + fft_size=options.fft_size, + sample_rate=input_rate, + ref_scale=options.ref_scale, + ref_level=20.0, + y_divs = 12, + avg_alpha=options.avg_alpha) + self.frame.SetMinSize((800, 420)) + + self.connect(self.u, self.scope) + + self._build_gui(vbox) + self._setup_events() + + + # set initial values + + if options.gain is None: + # if no gain was specified, use the mid-point in dB + g = self.u.get_gain_range() + options.gain = float(g.start()+g.stop())/2 + + if options.freq is None: + # if no freq was specified, use the mid-point + r = self.u.get_freq_range() + options.freq = float(r.start()+r.stop())/2 + + self.set_gain(options.gain) + + if(options.antenna): + self.u.set_antenna(options.antenna, 0) + + if self.show_debug_info: + self.myform['samprate'].set_value(self.u.get_samp_rate()) + self.myform['fs@gbe'].set_value(input_rate) + self.myform['baseband'].set_value(0) + self.myform['ddc'].set_value(0) + + if not(self.set_freq(options.freq)): + self._set_status_msg("Failed to set initial frequency") + + def _set_status_msg(self, msg): + self.frame.GetStatusBar().SetStatusText(msg, 0) + + def _build_gui(self, vbox): + + def _form_set_freq(kv): + return self.set_freq(kv['freq']) + + vbox.Add(self.scope.win, 10, wx.EXPAND) + + # add control area at the bottom + self.myform = myform = form.form() + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((5,0), 0, 0) + myform['freq'] = form.float_field( + parent=self.panel, sizer=hbox, label="Center freq", weight=1, + callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg)) + + hbox.Add((5,0), 0, 0) + g = self.u.get_gain_range() + + # some configurations don't have gain control + if g.stop() > g.start(): + myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", + weight=3, + min=int(g.start()), max=int(g.stop()), + callback=self.set_gain) + + hbox.Add((5,0), 0, 0) + vbox.Add(hbox, 0, wx.EXPAND) + + self._build_subpanel(vbox) + + def _build_subpanel(self, vbox_arg): + # build a secondary information panel (sometimes hidden) + + # FIXME figure out how to have this be a subpanel that is always + # created, but has its visibility controlled by foo.Show(True/False) + + def _form_set_samp_rate(kv): + return self.set_samp_rate(kv['samprate']) + + if not(self.show_debug_info): + return + + panel = self.panel + vbox = vbox_arg + myform = self.myform + + hbox = wx.BoxSizer(wx.HORIZONTAL) + + hbox.Add((5,0), 0) + myform['samprate'] = form.float_field( + parent=panel, sizer=hbox, label="Sample Rate", + callback=myform.check_input_and_call(_form_set_samp_rate, self._set_status_msg)) + + hbox.Add((5,0), 1) + myform['fs@gbe'] = form.static_float_field( + parent=panel, sizer=hbox, label="Fs@GbE") + + hbox.Add((5,0), 1) + myform['baseband'] = form.static_float_field( + parent=panel, sizer=hbox, label="Analog BB") + + hbox.Add((5,0), 1) + myform['ddc'] = form.static_float_field( + parent=panel, sizer=hbox, label="DDC") + + hbox.Add((5,0), 0) + vbox.Add(hbox, 0, wx.EXPAND) + + 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. + """ + r = self.u.set_center_freq(target_freq, 0) + + if r: + self.myform['freq'].set_value(target_freq) # update displayed value + if self.show_debug_info: + self.myform['baseband'].set_value(r.actual_rf_freq) + self.myform['ddc'].set_value(r.actual_dsp_freq) + if not self.options.oscilloscope: + self.scope.set_baseband_freq(target_freq) + return True + + return False + + def set_gain(self, gain): + if self.myform.has_key('gain'): + self.myform['gain'].set_value(gain) # update displayed value + self.u.set_gain(gain, 0) + + def set_samp_rate(self, samp_rate): + ok = self.u.set_samp_rate(samp_rate) + input_rate = self.u.get_samp_rate() + self.scope.set_sample_rate(input_rate) + if self.show_debug_info: # update displayed values + self.myform['samprate'].set_value(self.u.get_samp_rate()) + self.myform['fs@gbe'].set_value(input_rate) + + # uhd set_samp_rate never fails; always falls back to closest requested. + return True + + def _setup_events(self): + if not self.options.waterfall and not self.options.oscilloscope: + self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick) + + def evt_left_dclick(self, event): + (ux, uy) = self.scope.win.GetXY(event) + if event.CmdDown(): + # Re-center on maximum power + points = self.scope.win._points + if self.scope.win.peak_hold: + if self.scope.win.peak_vals is not None: + ind = numpy.argmax(self.scope.win.peak_vals) + else: + ind = int(points.shape()[0]/2) + else: + ind = numpy.argmax(points[:,1]) + (freq, pwr) = points[ind] + target_freq = freq/self.scope.win._scale_factor + print ind, freq, pwr + self.set_freq(target_freq) + else: + # Re-center on clicked frequency + target_freq = ux/self.scope.win._scale_factor + self.set_freq(target_freq) + + +def main (): + app = stdgui2.stdapp(app_top_block, "UHD FFT", nstatus=1) + app.MainLoop() + +if __name__ == '__main__': + main () diff --git a/gr-uhd/apps/uhd_rx_cfile.py b/gr-uhd/apps/uhd_rx_cfile.py new file mode 100755 index 000000000..f49052d9c --- /dev/null +++ b/gr-uhd/apps/uhd_rx_cfile.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# +# Copyright 2011 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. +# + +""" +Read samples from a UHD device and write to file formatted as binary +outputs single precision complex float values or complex short values +(interleaved 16 bit signed short integers). +""" + +from gnuradio import gr, eng_notation +from gnuradio import uhd +from gnuradio.eng_option import eng_option +from optparse import OptionParser +import sys + +n2s = eng_notation.num_to_str + +class rx_cfile_block(gr.top_block): + + def __init__(self, options, filename): + gr.top_block.__init__(self) + + # Create a UHD device source + if options.output_shorts: + self._u = uhd.usrp_source(device_addr=options.address, + io_type=uhd.io_type.COMPLEX_INT16, + num_channels=1) + self._sink = gr.file_sink(gr.sizeof_short*2, filename) + else: + self._u = uhd.usrp_source(device_addr=options.address, + io_type=uhd.io_type.COMPLEX_FLOAT32, + num_channels=1) + self._sink = gr.file_sink(gr.sizeof_gr_complex, filename) + + # Set receiver sample rate + self._u.set_samp_rate(options.samp_rate) + + # Set receive daughterboard gain + if options.gain is None: + g = self._u.get_gain_range() + options.gain = float(g.start()+g.stop())/2 + print "Using mid-point gain of", options.gain, "(", g.start(), "-", g.stop(), ")" + self._u.set_gain(options.gain) + + # Set the antenna + if(options.antenna): + self._u.set_antenna(options.antenna, 0) + + # Set frequency (tune request takes lo_offset) + if(options.lo_offset is not None): + treq = uhd.tune_request(options.freq, options.lo_offset) + else: + treq = uhd.tune_request(options.freq) + tr = self._u.set_center_freq(treq) + if tr == None: + sys.stderr.write('Failed to set center frequency\n') + raise SystemExit, 1 + + # Create head block if needed and wire it up + if options.nsamples is None: + self.connect(self._u, self._sink) + else: + if options.output_shorts: + self._head = gr.head(gr.sizeof_short*2, int(options.nsamples)) + else: + self._head = gr.head(gr.sizeof_gr_complex, int(options.nsamples)) + + self.connect(self._u, self._head, self._sink) + + input_rate = self._u.get_samp_rate() + + if options.verbose: + print "Address:", options.address + print "Rx gain:", options.gain + print "Rx baseband frequency:", n2s(tr.actual_rf_freq) + print "Rx DDC frequency:", n2s(tr.actual_dsp_freq) + print "Rx Sample Rate:", n2s(input_rate) + if options.nsamples is None: + print "Receiving samples until Ctrl-C" + else: + print "Receving", n2s(options.nsamples), "samples" + if options.output_shorts: + print "Writing 16-bit complex shorts" + else: + print "Writing 32-bit complex floats" + print "Output filename:", filename + +def get_options(): + usage="%prog: [options] output_filename" + parser = OptionParser(option_class=eng_option, usage=usage) + parser.add_option("-a", "--address", type="string", default="addr=192.168.10.2", + help="Address of UHD device, [default=%default]") + parser.add_option("-A", "--antenna", type="string", default=None, + help="select Rx Antenna where appropriate") + parser.add_option("", "--samp-rate", type="eng_float", default=1e6, + help="set sample rate (bandwidth) [default=%default]") + parser.add_option("-f", "--freq", type="eng_float", default=None, + help="set frequency to FREQ", metavar="FREQ") + parser.add_option("-g", "--gain", type="eng_float", default=None, + help="set gain in dB (default is midpoint)") + parser.add_option( "-s","--output-shorts", action="store_true", default=False, + help="output interleaved shorts instead of complex floats") + parser.add_option("-N", "--nsamples", type="eng_float", default=None, + help="number of samples to collect [default=+inf]") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="verbose output") + parser.add_option("", "--lo-offset", type="eng_float", default=None, + help="set daughterboard LO offset to OFFSET [default=hw default]") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + + if options.freq is None: + parser.print_help() + sys.stderr.write('You must specify the frequency with -f FREQ\n'); + raise SystemExit, 1 + + return (options, args[0]) + + +if __name__ == '__main__': + (options, filename) = get_options() + tb = rx_cfile_block(options, filename) + + try: + tb.run() + except KeyboardInterrupt: + pass diff --git a/gr-uhd/gnuradio-uhd.pc.in b/gr-uhd/gnuradio-uhd.pc.in new file mode 100644 index 000000000..383ad6011 --- /dev/null +++ b/gr-uhd/gnuradio-uhd.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: gnuradio-qtgui +Description: GNU Radio blocks for UHD +Requires: gnuradio-core +Version: @LIBVER@ +Libs: -L${libdir} -lgnuradio-uhd +Cflags: -I${includedir} diff --git a/gr-uhd/grc/gen_uhd_usrp_blocks.py b/gr-uhd/grc/gen_uhd_usrp_blocks.py index 8596e14a6..82b6aa964 100644 --- a/gr-uhd/grc/gen_uhd_usrp_blocks.py +++ b/gr-uhd/grc/gen_uhd_usrp_blocks.py @@ -298,7 +298,7 @@ def parse_tmpl(_tmpl, **kwargs): from Cheetah import Template return str(Template.Template(_tmpl, kwargs)) -max_num_mboards = 4 +max_num_mboards = 8 max_num_channels = max_num_mboards*4 if __name__ == '__main__': diff --git a/gr-uhd/include/gr_uhd_usrp_sink.h b/gr-uhd/include/gr_uhd_usrp_sink.h index 0475957de..320d07d41 100644 --- a/gr-uhd/include/gr_uhd_usrp_sink.h +++ b/gr-uhd/include/gr_uhd_usrp_sink.h @@ -101,6 +101,14 @@ public: virtual void set_gain(double gain, size_t chan = 0) = 0; /*! + * Set the named gain on the dboard. + * \param gain the gain in dB + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + */ + virtual void set_gain(double gain, const std::string &name, size_t chan = 0) = 0; + + /*! * Get the actual dboard gain setting. * \param chan the channel index 0 to N-1 * \return the actual gain in dB @@ -108,6 +116,22 @@ public: virtual double get_gain(size_t chan = 0) = 0; /*! + * Get the actual dboard gain setting of named stage. + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double get_gain(const std::string &name, size_t chan = 0) = 0; + + /*! + * Get the actual dboard gain setting of named stage. + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual std::vector<std::string> get_gain_names(size_t chan = 0) = 0; + + /*! * Get the settable gain range. * \param chan the channel index 0 to N-1 * \return the gain range in dB @@ -115,6 +139,14 @@ public: virtual uhd::gain_range_t get_gain_range(size_t chan = 0) = 0; /*! + * Get the settable gain range. + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + * \return the gain range in dB + */ + virtual uhd::gain_range_t get_gain_range(const std::string &name, size_t chan = 0) = 0; + + /*! * Set the antenna to use. * \param ant the antenna string * \param chan the channel index 0 to N-1 diff --git a/gr-uhd/include/gr_uhd_usrp_source.h b/gr-uhd/include/gr_uhd_usrp_source.h index 038f9a91e..36331f782 100644 --- a/gr-uhd/include/gr_uhd_usrp_source.h +++ b/gr-uhd/include/gr_uhd_usrp_source.h @@ -101,6 +101,14 @@ public: virtual void set_gain(double gain, size_t chan = 0) = 0; /*! + * Set the named gain on the dboard. + * \param gain the gain in dB + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + */ + virtual void set_gain(double gain, const std::string &name, size_t chan = 0) = 0; + + /*! * Get the actual dboard gain setting. * \param chan the channel index 0 to N-1 * \return the actual gain in dB @@ -108,6 +116,22 @@ public: virtual double get_gain(size_t chan = 0) = 0; /*! + * Get the actual dboard gain setting of named stage. + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double get_gain(const std::string &name, size_t chan = 0) = 0; + + /*! + * Get the actual dboard gain setting of named stage. + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual std::vector<std::string> get_gain_names(size_t chan = 0) = 0; + + /*! * Get the settable gain range. * \param chan the channel index 0 to N-1 * \return the gain range in dB @@ -115,6 +139,14 @@ public: virtual uhd::gain_range_t get_gain_range(size_t chan = 0) = 0; /*! + * Get the settable gain range. + * \param name the name of the gain stage + * \param chan the channel index 0 to N-1 + * \return the gain range in dB + */ + virtual uhd::gain_range_t get_gain_range(const std::string &name, size_t chan = 0) = 0; + + /*! * Set the antenna to use. * \param ant the antenna string * \param chan the channel index 0 to N-1 diff --git a/gr-uhd/lib/gr_uhd_usrp_sink.cc b/gr-uhd/lib/gr_uhd_usrp_sink.cc index d44af25ab..ce9d89d8d 100644 --- a/gr-uhd/lib/gr_uhd_usrp_sink.cc +++ b/gr-uhd/lib/gr_uhd_usrp_sink.cc @@ -76,14 +76,30 @@ public: return _dev->set_tx_gain(gain, chan); } + void set_gain(double gain, const std::string &name, size_t chan){ + return _dev->set_tx_gain(gain, name, chan); + } + double get_gain(size_t chan){ return _dev->get_tx_gain(chan); } + double get_gain(const std::string &name, size_t chan){ + return _dev->get_tx_gain(name, chan); + } + + std::vector<std::string> get_gain_names(size_t chan){ + return _dev->get_tx_gain_names(chan); + } + uhd::gain_range_t get_gain_range(size_t chan){ return _dev->get_tx_gain_range(chan); } + uhd::gain_range_t get_gain_range(const std::string &name, size_t chan){ + return _dev->get_tx_gain_range(name, chan); + } + void set_antenna(const std::string &ant, size_t chan){ return _dev->set_tx_antenna(ant, chan); } diff --git a/gr-uhd/lib/gr_uhd_usrp_source.cc b/gr-uhd/lib/gr_uhd_usrp_source.cc index fed8e6624..9983489c3 100644 --- a/gr-uhd/lib/gr_uhd_usrp_source.cc +++ b/gr-uhd/lib/gr_uhd_usrp_source.cc @@ -78,14 +78,30 @@ public: return _dev->set_rx_gain(gain, chan); } + void set_gain(double gain, const std::string &name, size_t chan){ + return _dev->set_rx_gain(gain, name, chan); + } + double get_gain(size_t chan){ return _dev->get_rx_gain(chan); } + double get_gain(const std::string &name, size_t chan){ + return _dev->get_rx_gain(name, chan); + } + + std::vector<std::string> get_gain_names(size_t chan){ + return _dev->get_rx_gain_names(chan); + } + uhd::gain_range_t get_gain_range(size_t chan){ return _dev->get_rx_gain_range(chan); } + uhd::gain_range_t get_gain_range(const std::string &name, size_t chan){ + return _dev->get_rx_gain_range(name, chan); + } + void set_antenna(const std::string &ant, size_t chan){ return _dev->set_rx_antenna(ant, chan); } diff --git a/gr-uhd/swig/uhd_swig.i b/gr-uhd/swig/uhd_swig.i index 3ffcc7aea..9bdb962c9 100644 --- a/gr-uhd/swig/uhd_swig.i +++ b/gr-uhd/swig/uhd_swig.i @@ -100,6 +100,7 @@ //////////////////////////////////////////////////////////////////////// %include stdint.i %include <uhd/types/serial.hpp> +%template(byte_vector_t) std::vector<uint8_t>; %include <uhd/usrp/dboard_iface.hpp> %template(dboard_iface_sptr) boost::shared_ptr<uhd::usrp::dboard_iface>; @@ -129,6 +130,6 @@ static const size_t ALL_MBOARDS; %goops %{ (use-modules (gnuradio gnuradio_core_runtime)) %} -#endif /* SWIGGUILE */ +#endif /* SWIGGUILE */ #endif /* GR_HAVE_UHD */ diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py index 3f90a7104..3dab0535a 100755 --- a/gr-utils/src/python/gr_plot_psd.py +++ b/gr-utils/src/python/gr_plot_psd.py @@ -93,12 +93,20 @@ class gr_plot_psd: self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) except MemoryError: print "End of File" + return False else: - tstep = 1.0 / self.sample_rate - #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) - self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) - - self.iq_psd, self.freq = self.dopsd(self.iq) + # retesting length here as newer version of scipy does not throw a MemoryError, just + # returns a zero-length array + if(len(self.iq) > 0): + tstep = 1.0 / self.sample_rate + #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) + self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) + + self.iq_psd, self.freq = self.dopsd(self.iq) + return True + else: + print "End of File" + return False def dopsd(self, iq): ''' Need to do this here and plot later so we can do the fftshift ''' @@ -130,7 +138,7 @@ class gr_plot_psd: self.sp_psd.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") self.sp_psd.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold") - self.get_data() + r = self.get_data() self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags @@ -220,8 +228,9 @@ class gr_plot_psd: self.step_forward() def step_forward(self): - self.get_data() - self.update_plots() + r = self.get_data() + if(r): + self.update_plots() def step_backward(self): # Step back in file position @@ -229,8 +238,9 @@ class gr_plot_psd: self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) else: self.hfile.seek(-self.hfile.tell(),1) - self.get_data() - self.update_plots() + r = self.get_data() + if(r): + self.update_plots() def find(item_in, list_search): try: diff --git a/grc/Makefile.am b/grc/Makefile.am index c36786281..9d473b4d3 100644 --- a/grc/Makefile.am +++ b/grc/Makefile.am @@ -43,7 +43,6 @@ BUILT_SOURCES += grc.conf grc.conf: $(srcdir)/grc.conf.in Makefile sed \ - -e 's|@pythonw[@]|$(PYTHONW)|g' \ -e 's|@blocksdir[@]|$(grc_blocksdir)|g' \ -e 's|@docdir[@]|$(gr_docdir)|g' \ $< > $@ diff --git a/grc/base/Block.py b/grc/base/Block.py index 42eb6b3fb..fe7ad3c2f 100644 --- a/grc/base/Block.py +++ b/grc/base/Block.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -92,8 +92,8 @@ class Block(Element): for param in map(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params): key = param.get_key() #test against repeated keys - try: assert key not in self.get_param_keys() - except AssertionError: raise Exception, 'Key "%s" already exists in params'%key + if key in self.get_param_keys(): + raise Exception, 'Key "%s" already exists in params'%key #store the param self.get_params().append(param) #create the source objects @@ -101,8 +101,8 @@ class Block(Element): for source in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='source'), sources): key = source.get_key() #test against repeated keys - try: assert key not in self.get_source_keys() - except AssertionError: raise Exception, 'Key "%s" already exists in sources'%key + if key in self.get_source_keys(): + raise Exception, 'Key "%s" already exists in sources'%key #store the port self.get_sources().append(source) #create the sink objects @@ -110,8 +110,8 @@ class Block(Element): for sink in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='sink'), sinks): key = sink.get_key() #test against repeated keys - try: assert key not in self.get_sink_keys() - except AssertionError: raise Exception, 'Key "%s" already exists in sinks'%key + if key in self.get_sink_keys(): + raise Exception, 'Key "%s" already exists in sinks'%key #store the port self.get_sinks().append(sink) diff --git a/grc/base/Connection.py b/grc/base/Connection.py index 94d4751b2..3ce7fd07f 100644 --- a/grc/base/Connection.py +++ b/grc/base/Connection.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -37,10 +37,12 @@ class Connection(Element): for port in (porta, portb): if port.is_source(): source = port if port.is_sink(): sink = port - assert(source and sink) + if not source: raise ValueError('Connection could not isolate source') + if not sink: raise ValueError('Connection could not isolate sink') #ensure that this connection (source -> sink) is unique for connection in self.get_parent().get_connections(): - assert not (connection.get_source() is source and connection.get_sink() is sink) + if connection.get_source() is source and connection.get_sink() is sink: + raise Exception('This connection between source and sink is not unique.') self._source = source self._sink = sink @@ -62,8 +64,8 @@ class Connection(Element): Element.validate(self) source_type = self.get_source().get_type() sink_type = self.get_sink().get_type() - try: assert source_type == sink_type - except AssertionError: self.add_error_message('Source type "%s" does not match sink type "%s".'%(source_type, sink_type)) + if source_type != sink_type: + self.add_error_message('Source type "%s" does not match sink type "%s".'%(source_type, sink_type)) def get_enabled(self): """ diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py index b4ac8fc3a..0ba1f2389 100644 --- a/grc/base/FlowGraph.py +++ b/grc/base/FlowGraph.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -194,18 +194,26 @@ class FlowGraph(Element): sink_key = connection_n.find('sink_key') #verify the blocks block_ids = map(lambda b: b.get_id(), self.get_blocks()) - assert(source_block_id in block_ids) - assert(sink_block_id in block_ids) + if source_block_id not in block_ids: + raise LookupError('source block id "%s" not in block ids'%source_block_id) + if sink_block_id not in block_ids: + raise LookupError('sink block id "%s" not in block ids'%sink_block_id) #get the blocks source_block = self.get_block(source_block_id) sink_block = self.get_block(sink_block_id) #verify the ports - assert(source_key in source_block.get_source_keys()) - assert(sink_key in sink_block.get_sink_keys()) + if source_key not in source_block.get_source_keys(): + raise LookupError('source key "%s" not in source block keys'%source_key) + if sink_key not in sink_block.get_sink_keys(): + raise LookupError('sink key "%s" not in sink block keys'%sink_key) #get the ports source = source_block.get_source(source_key) sink = sink_block.get_sink(sink_key) #build the connection self.connect(source, sink) - except AssertionError: Messages.send_error_load('Connection between %s(%s) and %s(%s) could not be made.'%(source_block_id, source_key, sink_block_id, sink_key)) + except LookupError, e: Messages.send_error_load( + 'Connection between %s(%s) and %s(%s) could not be made.\n\t%s'%( + source_block_id, source_key, sink_block_id, sink_key, e + ) + ) self.rewrite() #global rewrite diff --git a/grc/base/Param.py b/grc/base/Param.py index 5cd0f9d6d..c2fa5461a 100644 --- a/grc/base/Param.py +++ b/grc/base/Param.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -34,16 +34,16 @@ class Option(Element): self._opts = dict() opts = n.findall('opt') #test against opts when non enum - try: assert self.get_parent().is_enum() or not opts - except AssertionError: raise Exception, 'Options for non-enum types cannot have sub-options' + if not self.get_parent().is_enum() and opts: + raise Exception, 'Options for non-enum types cannot have sub-options' #extract opts for opt in opts: #separate the key:value try: key, value = opt.split(':') except: raise Exception, 'Error separating "%s" into key:value'%opt #test against repeated keys - try: assert not self._opts.has_key(key) - except AssertionError: raise Exception, 'Key "%s" already exists in option'%key + if self._opts.has_key(key): + raise Exception, 'Key "%s" already exists in option'%key #store the option self._opts[key] = value @@ -79,24 +79,24 @@ class Param(Element): for option in map(lambda o: Option(param=self, n=o), n.findall('option')): key = option.get_key() #test against repeated keys - try: assert key not in self.get_option_keys() - except AssertionError: raise Exception, 'Key "%s" already exists in options'%key + if key in self.get_option_keys(): + raise Exception, 'Key "%s" already exists in options'%key #store the option self.get_options().append(option) #test the enum options if self.is_enum(): #test against options with identical keys - try: assert len(set(self.get_option_keys())) == len(self.get_options()) - except AssertionError: raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys() + if len(set(self.get_option_keys())) != len(self.get_options()): + raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys() #test against inconsistent keys in options opt_keys = self.get_options()[0].get_opt_keys() for option in self.get_options(): - try: assert set(opt_keys) == set(option.get_opt_keys()) - except AssertionError: raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys + if set(opt_keys) != set(option.get_opt_keys()): + raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys #if a value is specified, it must be in the options keys self._value = value if value or value in self.get_option_keys() else self.get_option_keys()[0] - try: assert self.get_value() in self.get_option_keys() - except AssertionError: raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys()) + if self.get_value() not in self.get_option_keys(): + raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys()) else: self._value = value or '' def validate(self): @@ -105,8 +105,8 @@ class Param(Element): The value must be evaluated and type must a possible type. """ Element.validate(self) - try: assert self.get_type() in self.get_types() - except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type()) + if self.get_type() not in self.get_types(): + self.add_error_message('Type "%s" is not a possible type.'%self.get_type()) def get_evaluated(self): raise NotImplementedError diff --git a/grc/base/Platform.py b/grc/base/Platform.py index 096fdec41..a66c28ab9 100644 --- a/grc/base/Platform.py +++ b/grc/base/Platform.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009, 2011 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,16 +17,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -#Perform python integrity checks: -# GRC will not work with interpreters that fail the checks below. -# This can fail on interpreters built with special optimizations. -try: - assert False - raise Exception, 'Failed python integrity check: assert not supported' -except AssertionError: pass -if __doc__ is None: - raise Exception, 'Failed python integrity check: __doc__ not supported' - import os import sys from .. base import ParseXML, odict @@ -91,13 +81,12 @@ class Platform(_Element): block = self.Block(self._flow_graph, n) key = block.get_key() #test against repeated keys - try: - assert key not in self.get_block_keys() - #store the block + if key in self.get_block_keys(): + print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s'%(key, xml_file) + #store the block + else: self._blocks[key] = block self._blocks_n[key] = n - except AssertionError: - print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s'%(key, xml_file) except ParseXML.XMLSyntaxError, e: try: #try to add the xml file as a block tree ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD) diff --git a/grc/base/Port.py b/grc/base/Port.py index 494ea894f..7a1b5d4e6 100644 --- a/grc/base/Port.py +++ b/grc/base/Port.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -42,8 +42,8 @@ class Port(Element): The port must be non-empty and type must a possible type. """ Element.validate(self) - try: assert self.get_type() in self.get_types() - except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type()) + if self.get_type() not in self.get_types(): + self.add_error_message('Type "%s" is not a possible type.'%self.get_type()) def __str__(self): if self.is_source(): diff --git a/grc/base/odict.py b/grc/base/odict.py index ac3cb2070..044d04ad7 100644 --- a/grc/base/odict.py +++ b/grc/base/odict.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -55,7 +55,7 @@ class odict(DictMixin): @param val the value for the new entry """ index = (pos_key is None) and len(self._keys) or self._keys.index(pos_key) - assert key not in self._keys + if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key)) self._keys.insert(index+1, key) self._data[key] = val @@ -67,8 +67,8 @@ class odict(DictMixin): @param key the key for the new entry @param val the value for the new entry """ - index = (pos_key is not None) and self._keys.index(pos_key) or 0 - assert key not in self._keys + index = (pos_key is not None) and self._keys.index(pos_key) or 0 + if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key)) self._keys.insert(index, key) self._data[key] = val diff --git a/grc/blocks/Makefile.am b/grc/blocks/Makefile.am index 81eb81182..14ffe8358 100644 --- a/grc/blocks/Makefile.am +++ b/grc/blocks/Makefile.am @@ -90,6 +90,7 @@ dist_ourdata_DATA = \ gr_correlate_access_code_bb.xml \ gr_costas_loop_cc.xml \ gr_cpfsk_bc.xml \ + gr_dc_blocker.xml \ gr_decode_ccsds_27_fb.xml \ gr_deinterleave.xml \ gr_delay.xml \ diff --git a/grc/blocks/block_tree.xml b/grc/blocks/block_tree.xml index 66094a80d..0b641d79c 100644 --- a/grc/blocks/block_tree.xml +++ b/grc/blocks/block_tree.xml @@ -188,6 +188,7 @@ <block>gr_keep_one_in_n</block> <block>gr_moving_average_xx</block> <block>gr_iqcomp_cc</block> + <block>gr_dc_blocker</block> </cat> <cat> <name>Modulators</name> diff --git a/grc/blocks/gr_dc_blocker.xml b/grc/blocks/gr_dc_blocker.xml new file mode 100644 index 000000000..e5aeeb031 --- /dev/null +++ b/grc/blocks/gr_dc_blocker.xml @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<!-- +################################################### +## DC Blocker +################################################### + --> +<block> + <name>DC Blocker</name> + <key>gr_dc_blocker</key> + <import>from gnuradio import gr</import> + <make>gr.dc_blocker_$(type)($length, $long_form)</make> + <!-- <callback>set_length($lenght)</callback> --> + <param> + <name>Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex->Complex</name> + <key>cc</key> + <opt>input:complex</opt> + <opt>output:complex</opt> + </option> + <option> + <name>Float->Float</name> + <key>ff</key> + <opt>input:float</opt> + <opt>output:float</opt> + </option> + </param> + <param> + <name>Length</name> + <key>length</key> + <value>32</value> + <type>int</type> + </param> + <param> + <name>Long Form</name> + <key>long_form</key> + <value>True</value> + <type>bool</type> + </param> + + <sink> + <name>in</name> + <type>$type.input</type> + </sink> + <source> + <name>out</name> + <type>$type.output</type> + </source> +</block> diff --git a/grc/blocks/gr_frequency_modulator_fc.xml b/grc/blocks/gr_frequency_modulator_fc.xml index f18d9f1e1..d5f8fcfe3 100644 --- a/grc/blocks/gr_frequency_modulator_fc.xml +++ b/grc/blocks/gr_frequency_modulator_fc.xml @@ -9,6 +9,7 @@ <key>gr_frequency_modulator_fc</key> <import>from gnuradio import gr</import> <make>gr.frequency_modulator_fc($sensitivity)</make> + <callback>set_sensitivity($sensitivity)</callback> <param> <name>Sensitivity</name> <key>sensitivity</key> diff --git a/grc/grc.conf.in b/grc/grc.conf.in index 37a049971..9363ca981 100644 --- a/grc/grc.conf.in +++ b/grc/grc.conf.in @@ -3,7 +3,6 @@ # ~/.gnuradio/config.conf [grc] -pythonw = @pythonw@ doc_dir = @docdir@ global_blocks_path = @blocksdir@ local_blocks_path = diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 350b297bb..15785f2ee 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008, 2009, 2011 Free Software Foundation, Inc. +Copyright 2007-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -78,8 +78,7 @@ class ActionHandler: When not in focus, gtk and the accelerators handle the the key press. @return false to let gtk handle the key action """ - try: assert self.get_focus_flag() - except AssertionError: return False + if not self.get_focus_flag(): return False return Actions.handle_key_press(event) def _quit(self, window, event): diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index f374efde1..4d196477e 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. +Copyright 2007-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -76,7 +76,8 @@ class Action(gtk.Action): for i in range(len(keypresses)/2): keyval, mod_mask = keypresses[i*2:(i+1)*2] #register this keypress - assert not _actions_keypress_dict.has_key((keyval, mod_mask)) + if _actions_keypress_dict.has_key((keyval, mod_mask)): + raise KeyError('keyval/mod_mask pair already registered "%s"'%str((keyval, mod_mask))) _actions_keypress_dict[(keyval, mod_mask)] = self #set the accelerator group, and accelerator path #register the key name and mod mask with the accelerator path diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index 897145a1d..9f3326ada 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc. +Copyright 2007-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -290,10 +290,10 @@ class FlowGraph(Element): for selected in selected_elements: if selected in elements: continue selected_elements.remove(selected) - try: assert self._old_selected_port.get_parent() in elements - except: self._old_selected_port = None - try: assert self._new_selected_port.get_parent() in elements - except: self._new_selected_port = None + if self._old_selected_port and self._old_selected_port.get_parent() not in elements: + self._old_selected_port = None + if self._new_selected_port and self._new_selected_port.get_parent() not in elements: + self._new_selected_port = None #update highlighting for element in elements: element.set_highlighted(element in selected_elements) diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py index b5489d56e..bb19ed3d9 100644 --- a/grc/gui/Utils.py +++ b/grc/gui/Utils.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -53,7 +53,8 @@ def get_rotated_coordinate(coor, rotation): """ #handles negative angles rotation = (rotation + 360)%360 - assert rotation in POSSIBLE_ROTATIONS + if rotation not in POSSIBLE_ROTATIONS: + raise ValueError('unusable rotation angle "%s"'%str(rotation)) #determine the number of degrees to rotate cos_r, sin_r = { 0: (1, 0), diff --git a/grc/python/Block.py b/grc/python/Block.py index bd03eb5cd..14a5859e4 100644 --- a/grc/python/Block.py +++ b/grc/python/Block.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -65,9 +65,8 @@ class Block(_Block, _GUIBlock): for check in self._checks: check_res = self.resolve_dependencies(check) try: - check_eval = self.get_parent().evaluate(check_res) - try: assert check_eval - except AssertionError: self.add_error_message('Check "%s" failed.'%check) + if not self.get_parent().evaluate(check_res): + self.add_error_message('Check "%s" failed.'%check) except: self.add_error_message('Check "%s" did not evaluate.'%check) def rewrite(self): @@ -134,9 +133,9 @@ class Block(_Block, _GUIBlock): try: value = param.get_evaluated() value = value + direction - assert 0 < value - param.set_value(value) - changed = True + if 0 < value: + param.set_value(value) + changed = True except: pass return changed diff --git a/grc/python/Connection.py b/grc/python/Connection.py index edc18841a..39f915740 100644 --- a/grc/python/Connection.py +++ b/grc/python/Connection.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -38,5 +38,5 @@ class Connection(_Connection, _GUIConnection): #check vector length source_vlen = self.get_source().get_vlen() sink_vlen = self.get_sink().get_vlen() - try: assert source_vlen == sink_vlen - except AssertionError: self.add_error_message('Source vector length "%s" does not match sink vector length "%s".'%(source_vlen, sink_vlen)) + if source_vlen != sink_vlen: + self.add_error_message('Source vector length "%s" does not match sink vector length "%s".'%(source_vlen, sink_vlen)) diff --git a/grc/python/Constants.py b/grc/python/Constants.py index e661c3927..868c822aa 100644 --- a/grc/python/Constants.py +++ b/grc/python/Constants.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -23,10 +23,8 @@ from gnuradio import gr _gr_prefs = gr.prefs() -PYEXEC = os.environ.get('PYTHONW', _gr_prefs.get_string('grc', 'pythonw', '')) - #setup paths -PATH_SEP = ':' +PATH_SEP = {'/':':', '\\':';'}[os.path.sep] DOCS_DIR = os.environ.get('GR_DOC_DIR', _gr_prefs.get_string('grc', 'doc_dir', '')) HIER_BLOCKS_LIB_DIR = os.path.join(os.path.expanduser('~'), '.grc_gnuradio') BLOCKS_DIRS = filter( #filter blank strings diff --git a/grc/python/FlowGraph.py b/grc/python/FlowGraph.py index b2d406bbd..89a169355 100644 --- a/grc/python/FlowGraph.py +++ b/grc/python/FlowGraph.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -48,15 +48,16 @@ class FlowGraph(_FlowGraph, _GUIFlowGraph): #return from cache return self._eval_cache[my_hash] - def _get_io_signaturev(self, pad_key): + def get_io_signaturev(self, direction): """ Get a list of io signatures for this flow graph. - The pad key determines the directionality of the io signature. - @param pad_key a string of pad_source or pad_sink + @param direction a string of 'in' or 'out' @return a list of dicts with: type, label, vlen, size """ - pads = filter(lambda b: b.get_key() == pad_key, self.get_enabled_blocks()) - sorted_pads = sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id())) + sorted_pads = { + 'in': self.get_pad_sources(), + 'out': self.get_pad_sinks(), + }[direction] #load io signature return [{ 'label': str(pad.get_param('label').get_evaluated()), @@ -65,19 +66,21 @@ class FlowGraph(_FlowGraph, _GUIFlowGraph): 'size': pad.get_param('type').get_opt('size'), } for pad in sorted_pads] - def get_input_signaturev(self): + def get_pad_sources(self): """ - Get the io signature for the input side of this flow graph. - @return a list of io signature structures + Get a list of pad source blocks sorted by id order. + @return a list of pad source blocks in this flow graph """ - return self._get_io_signaturev('pad_source') + pads = filter(lambda b: b.get_key() == 'pad_source', self.get_enabled_blocks()) + return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id())) - def get_output_signaturev(self): + def get_pad_sinks(self): """ - Get the io signature for the output side of this flow graph. - @return a list of io signature structures + Get a list of pad sink blocks sorted by id order. + @return a list of pad sink blocks in this flow graph """ - return self._get_io_signaturev('pad_sink') + pads = filter(lambda b: b.get_key() == 'pad_sink', self.get_enabled_blocks()) + return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id())) def get_imports(self): """ diff --git a/grc/python/Generator.py b/grc/python/Generator.py index b669fa65a..2a2dfdd49 100644 --- a/grc/python/Generator.py +++ b/grc/python/Generator.py @@ -18,14 +18,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ import os +import sys import subprocess import tempfile from Cheetah.Template import Template import expr_utils from Constants import \ TOP_BLOCK_FILE_MODE, HIER_BLOCK_FILE_MODE, \ - HIER_BLOCKS_LIB_DIR, PYEXEC, \ - FLOW_GRAPH_TEMPLATE + HIER_BLOCKS_LIB_DIR, FLOW_GRAPH_TEMPLATE import convert_hier from .. gui import Messages @@ -74,10 +74,21 @@ Add a Misc->Throttle block to your flow graph to avoid CPU congestion.''') Execute this python flow graph. @return a popen object """ - #execute - cmds = [PYEXEC, '-u', self.get_file_path()] #-u is unbuffered stdio - if self._generate_options == 'no_gui': + #extract the path to the python executable + python_exe = sys.executable + + #when using wx gui on mac os, execute with pythonw + #using pythonw is not necessary anymore, disabled below + #if self._generate_options == 'wx_gui' and 'darwin' in sys.platform.lower(): + # python_exe = 'pythonw' + + #setup the command args to run + cmds = [python_exe, '-u', self.get_file_path()] #-u is unbuffered stdio + + #when in no gui mode on linux, use an xterm (looks nice) + if self._generate_options == 'no_gui' and 'linux' in sys.platform.lower(): cmds = ['xterm', '-e'] + cmds + p = subprocess.Popen(args=cmds, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False, universal_newlines=True) return p diff --git a/grc/python/Param.py b/grc/python/Param.py index 303ab3ed8..5536138c1 100644 --- a/grc/python/Param.py +++ b/grc/python/Param.py @@ -213,8 +213,7 @@ class Param(_Param, _GUIParam): lambda p: p._vlen, self.get_parent().get_ports()) ): try: - assert int(self.get_evaluated()) == 1 - return 'part' + if int(self.get_evaluated()) == 1: return 'part' except: pass #hide empty grid positions if self.get_key() in ('grid_pos', 'notebook') and not self.get_value(): return 'part' @@ -244,8 +243,7 @@ class Param(_Param, _GUIParam): def eval_string(v): try: e = self.get_parent().get_parent().evaluate(v) - assert isinstance(e, str) - return e + if isinstance(e, str): return e except: self._stringify_flag = True return v @@ -265,21 +263,21 @@ class Param(_Param, _GUIParam): #raise an exception if the data is invalid if t == 'raw': return e elif t == 'complex': - try: assert isinstance(e, COMPLEX_TYPES) - except AssertionError: raise Exception, 'Expression "%s" is invalid for type complex.'%str(e) + if not isinstance(e, COMPLEX_TYPES): + raise Exception, 'Expression "%s" is invalid for type complex.'%str(e) return e elif t == 'real': - try: assert isinstance(e, REAL_TYPES) - except AssertionError: raise Exception, 'Expression "%s" is invalid for type real.'%str(e) + if not isinstance(e, REAL_TYPES): + raise Exception, 'Expression "%s" is invalid for type real.'%str(e) return e elif t == 'int': - try: assert isinstance(e, INT_TYPES) - except AssertionError: raise Exception, 'Expression "%s" is invalid for type integer.'%str(e) + if not isinstance(e, INT_TYPES): + raise Exception, 'Expression "%s" is invalid for type integer.'%str(e) return e elif t == 'hex': return hex(e) elif t == 'bool': - try: assert isinstance(e, bool) - except AssertionError: raise Exception, 'Expression "%s" is invalid for type bool.'%str(e) + if not isinstance(e, bool): + raise Exception, 'Expression "%s" is invalid for type bool.'%str(e) return e else: raise TypeError, 'Type "%s" not handled'%t ######################### @@ -295,25 +293,22 @@ class Param(_Param, _GUIParam): if not isinstance(e, VECTOR_TYPES): self._lisitify_flag = True e = [e] - try: - for ei in e: assert isinstance(ei, COMPLEX_TYPES) - except AssertionError: raise Exception, 'Expression "%s" is invalid for type complex vector.'%str(e) + if not all([isinstance(ei, COMPLEX_TYPES) for ei in e]): + raise Exception, 'Expression "%s" is invalid for type complex vector.'%str(e) return e elif t == 'real_vector': if not isinstance(e, VECTOR_TYPES): self._lisitify_flag = True e = [e] - try: - for ei in e: assert isinstance(ei, REAL_TYPES) - except AssertionError: raise Exception, 'Expression "%s" is invalid for type real vector.'%str(e) + if not all([isinstance(ei, REAL_TYPES) for ei in e]): + raise Exception, 'Expression "%s" is invalid for type real vector.'%str(e) return e elif t == 'int_vector': if not isinstance(e, VECTOR_TYPES): self._lisitify_flag = True e = [e] - try: - for ei in e: assert isinstance(ei, INT_TYPES) - except AssertionError: raise Exception, 'Expression "%s" is invalid for type integer vector.'%str(e) + if not all([isinstance(ei, INT_TYPES) for ei in e]): + raise Exception, 'Expression "%s" is invalid for type integer vector.'%str(e) return e ######################### # String Types @@ -327,13 +322,13 @@ class Param(_Param, _GUIParam): ######################### elif t == 'id': #can python use this as a variable? - try: assert _check_id_matcher.match(v) - except AssertionError: raise Exception, 'ID "%s" must begin with a letter and may contain letters, numbers, and underscores.'%v + if not _check_id_matcher.match(v): + raise Exception, 'ID "%s" must begin with a letter and may contain letters, numbers, and underscores.'%v ids = [param.get_value() for param in self.get_all_params(t)] - try: assert ids.count(v) <= 1 #id should only appear once, or zero times if block is disabled - except: raise Exception, 'ID "%s" is not unique.'%v - try: assert v not in ID_BLACKLIST - except: raise Exception, 'ID "%s" is blacklisted.'%v + if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled + raise Exception, 'ID "%s" is not unique.'%v + if v in ID_BLACKLIST: + raise Exception, 'ID "%s" is blacklisted.'%v return v ######################### # Stream ID Type @@ -346,12 +341,12 @@ class Param(_Param, _GUIParam): )] #check that the virtual sink's stream id is unique if self.get_parent().is_virtual_sink(): - try: assert ids.count(v) <= 1 #id should only appear once, or zero times if block is disabled - except: raise Exception, 'Stream ID "%s" is not unique.'%v + if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled + raise Exception, 'Stream ID "%s" is not unique.'%v #check that the virtual source's steam id is found if self.get_parent().is_virtual_source(): - try: assert v in ids - except: raise Exception, 'Stream ID "%s" is not found.'%v + if v not in ids: + raise Exception, 'Stream ID "%s" is not found.'%v return v ######################### # GUI Position/Hint @@ -382,17 +377,15 @@ class Param(_Param, _GUIParam): elif t == 'grid_pos': if not v: return '' #allow for empty grid pos e = self.get_parent().get_parent().evaluate(v) - try: - assert isinstance(e, (list, tuple)) and len(e) == 4 - for ei in e: assert isinstance(ei, int) - except AssertionError: raise Exception, 'A grid position must be a list of 4 integers.' + if not isinstance(e, (list, tuple)) or len(e) != 4 or not all([isinstance(ei, int) for ei in e]): + raise Exception, 'A grid position must be a list of 4 integers.' row, col, row_span, col_span = e #check row, col - try: assert row >= 0 and col >= 0 - except AssertionError: raise Exception, 'Row and column must be non-negative.' + if row < 0 or col < 0: + raise Exception, 'Row and column must be non-negative.' #check row span, col span - try: assert row_span > 0 and col_span > 0 - except AssertionError: raise Exception, 'Row and column span must be greater than zero.' + if row_span <= 0 or col_span <= 0: + raise Exception, 'Row and column span must be greater than zero.' #get hostage cell parent try: my_parent = self.get_parent().get_param('notebook').evaluate() except: my_parent = '' @@ -421,8 +414,8 @@ class Param(_Param, _GUIParam): try: notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0] except: raise Exception, 'Notebook id "%s" is not an existing notebook id.'%notebook_id #check that page index exists - try: assert int(page_index) in range(len(notebook_block.get_param('labels').evaluate())) - except: raise Exception, 'Page index "%s" is not a valid index number.'%page_index + if int(page_index) not in range(len(notebook_block.get_param('labels').evaluate())): + raise Exception, 'Page index "%s" is not a valid index number.'%page_index return notebook_id, page_index ######################### # Import Type diff --git a/grc/python/Platform.py b/grc/python/Platform.py index ec3f94096..a9c2b18ad 100644 --- a/grc/python/Platform.py +++ b/grc/python/Platform.py @@ -1,5 +1,5 @@ -""" -Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +__doc__ = """ +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or diff --git a/grc/python/Port.py b/grc/python/Port.py index 6e5a5c59f..3846b0f4e 100644 --- a/grc/python/Port.py +++ b/grc/python/Port.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -83,16 +83,16 @@ class Port(_Port, _GUIPort): def validate(self): _Port.validate(self) - try: assert self.get_enabled_connections() or self.get_optional() - except AssertionError: self.add_error_message('Port is not connected.') - try: assert self.is_source() or len(self.get_enabled_connections()) <= 1 - except AssertionError: self.add_error_message('Port has too many connections.') + if not self.get_enabled_connections() and not self.get_optional(): + self.add_error_message('Port is not connected.') + if not self.is_source() and len(self.get_enabled_connections()) > 1: + self.add_error_message('Port has too many connections.') #message port logic if self.get_type() == 'msg': - try: assert not self.get_nports() - except AssertionError: self.add_error_message('A port of type "msg" cannot have "nports" set.') - try: assert self.get_vlen() == 1 - except AssertionError: self.add_error_message('A port of type "msg" must have a "vlen" of 1.') + if self.get_nports(): + self.add_error_message('A port of type "msg" cannot have "nports" set.') + if self.get_vlen() != 1: + self.add_error_message('A port of type "msg" must have a "vlen" of 1.') def rewrite(self): """ @@ -134,8 +134,7 @@ class Port(_Port, _GUIPort): if not nports: return '' try: nports = int(self.get_parent().get_parent().evaluate(nports)) - assert 0 < nports - return nports + if 0 < nports: return nports except: return 1 def get_optional(self): return bool(self._optional) diff --git a/grc/python/convert_hier.py b/grc/python/convert_hier.py index befddccea..c6ca5b769 100644 --- a/grc/python/convert_hier.py +++ b/grc/python/convert_hier.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -23,11 +23,11 @@ from .. base import odict def convert_hier(flow_graph, python_file): #extract info from the flow graph - input_sigs = flow_graph.get_input_signaturev() - output_sigs = flow_graph.get_output_signaturev() + input_sigs = flow_graph.get_io_signaturev('in') + output_sigs = flow_graph.get_io_signaturev('out') parameters = flow_graph.get_parameters() block_key = flow_graph.get_option('id') - block_name = flow_graph.get_option('title') + block_name = flow_graph.get_option('title') or flow_graph.get_option('id').replace('_', ' ').title() block_category = flow_graph.get_option('category') block_desc = flow_graph.get_option('description') block_author = flow_graph.get_option('author') @@ -56,19 +56,21 @@ def convert_hier(flow_graph, python_file): params_n.append(param_n) block_n['param'] = params_n #sink data + block_n['sink'] = list() for input_sig in input_sigs: sink_n = odict() sink_n['name'] = input_sig['label'] sink_n['type'] = input_sig['type'] sink_n['vlen'] = input_sig['vlen'] - block_n['sink'] = sink_n + block_n['sink'].append(sink_n) #source data + block_n['source'] = list() for output_sig in output_sigs: source_n = odict() source_n['name'] = output_sig['label'] source_n['type'] = output_sig['type'] source_n['vlen'] = output_sig['vlen'] - block_n['source'] = source_n + block_n['source'].append(source_n) #doc data block_n['doc'] = "%s\n%s\n%s"%(block_author, block_desc, python_file) #write the block_n to file diff --git a/grc/python/expr_utils.py b/grc/python/expr_utils.py index 3c39f5d89..a2e56eedf 100644 --- a/grc/python/expr_utils.py +++ b/grc/python/expr_utils.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -118,7 +118,7 @@ def sort_variables(exprs): Get a list of variables in order of dependencies. @param exprs a mapping of variable name to expression @return a list of variable names - @throws AssertionError circular dependencies + @throws Exception circular dependencies """ var_graph = get_graph(exprs) sorted_vars = list() @@ -126,7 +126,7 @@ def sort_variables(exprs): while var_graph.get_nodes(): #get a list of nodes with no edges indep_vars = filter(lambda var: not var_graph.get_edges(var), var_graph.get_nodes()) - assert indep_vars + if not indep_vars: raise Exception('circular dependency caught in sort_variables') #add the indep vars to the end of the list sorted_vars.extend(sorted(indep_vars)) #remove each edge-less node from the graph diff --git a/grc/python/extract_docs.py b/grc/python/extract_docs.py index f41f415b2..aa85397f9 100644 --- a/grc/python/extract_docs.py +++ b/grc/python/extract_docs.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008-2011 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -81,8 +81,8 @@ def extract(key): @param key the block key @return a string with documentation """ - try: assert _docs_cache.has_key(key) - except: _docs_cache[key] = _extract(key) + if not _docs_cache.has_key(key): + _docs_cache[key] = _extract(key) return _docs_cache[key] if __name__ == '__main__': diff --git a/grc/python/flow_graph.tmpl b/grc/python/flow_graph.tmpl index 7a74cf84c..d5e53b52b 100644 --- a/grc/python/flow_graph.tmpl +++ b/grc/python/flow_graph.tmpl @@ -74,8 +74,8 @@ class $(class_name)(gr.top_block): def __init__($param_str): gr.top_block.__init__(self, "$title") #elif $generate_options == 'hb' - #set $in_sigs = $flow_graph.get_input_signaturev() - #set $out_sigs = $flow_graph.get_output_signaturev() + #set $in_sigs = $flow_graph.get_io_signaturev('in') + #set $out_sigs = $flow_graph.get_io_signaturev('out') class $(class_name)(gr.hier_block2): #def make_io_sig($io_sigs) #set $size_strs = ['%s*%s'%(io_sig['size'], io_sig['vlen']) for io_sig in $io_sigs] @@ -153,11 +153,13 @@ gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))]) ## The port name should be the id of the parent block. ## However, port names for IO pads should be self. ######################################################## -#def make_port_name($port) - #if $port.get_parent().get_key().startswith('pad_') -self#slurp +#def make_port_sig($port) + #if $port.get_parent().get_key() == 'pad_source' +(self, $flow_graph.get_pad_sources().index($port.get_parent()))#slurp + #elif $port.get_parent().get_key() == 'pad_sink' +(self, $flow_graph.get_pad_sinks().index($port.get_parent()))#slurp #else -self.$port.get_parent().get_id()#slurp +(self.$port.get_parent().get_id(), $port.get_key())#slurp #end if #end def #if $connections @@ -175,7 +177,7 @@ self.$port.get_parent().get_id()#slurp #end if ##do not generate connections with virtual sinks #if not $sink.get_parent().is_virtual_sink() - self.connect(($make_port_name($source), $source.get_key()), ($make_port_name($sink), $sink.get_key())) + self.connect($make_port_sig($source), $make_port_sig($sink)) #end if #end for diff --git a/gruel/src/include/gruel/Makefile.am b/gruel/src/include/gruel/Makefile.am index 89a9da7f0..96aed326e 100644 --- a/gruel/src/include/gruel/Makefile.am +++ b/gruel/src/include/gruel/Makefile.am @@ -27,6 +27,7 @@ gruelincludedir = $(prefix)/include/gruel gruelinclude_HEADERS = \ attributes.h \ + high_res_timer.h \ inet.h \ msg_accepter.h \ msg_accepter_msgq.h \ diff --git a/gruel/src/include/gruel/high_res_timer.h b/gruel/src/include/gruel/high_res_timer.h new file mode 100644 index 000000000..fe9ae763f --- /dev/null +++ b/gruel/src/include/gruel/high_res_timer.h @@ -0,0 +1,124 @@ +/* + * Copyright 2011 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_GRUEL_HIGH_RES_TIMER_H +#define INCLUDED_GRUEL_HIGH_RES_TIMER_H + +namespace gruel { + //! Typedef for the timer tick count + typedef signed long long high_res_timer_type; + + //! Get the current time in ticks + high_res_timer_type high_res_timer_now(void); + + //! Get the number of ticks per second + high_res_timer_type high_res_timer_tps(void); + + //! Get the tick count at the epoch + high_res_timer_type high_res_timer_epoch(void); + +} /* namespace gruel */ + +//////////////////////////////////////////////////////////////////////// +// Use architecture defines to determine the implementation +//////////////////////////////////////////////////////////////////////// +#if defined(linux) || defined(__linux) || defined(__linux__) + #define GRUEL_HRT_USE_CLOCK_GETTIME +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #define GRUEL_HRT_USE_QUERY_PERFORMANCE_COUNTER +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + #define GRUEL_HRT_USE_MACH_ABSOLUTE_TIME +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + #define GRUEL_HRT_USE_MACH_ABSOLUTE_TIME +#else + #define GRUEL_HRT_USE_MICROSEC_CLOCK +#endif + +//////////////////////////////////////////////////////////////////////// +#ifdef GRUEL_HRT_USE_CLOCK_GETTIME + #include <ctime> + + inline gruel::high_res_timer_type gruel::high_res_timer_now(void){ + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return high_res_timer_type(ts.tv_sec*1000000000UL) + ts.tv_nsec; + } + + inline gruel::high_res_timer_type gruel::high_res_timer_tps(void){ + return 1000000000UL; + } +#endif /* GRUEL_HRT_USE_CLOCK_GETTIME */ + +//////////////////////////////////////////////////////////////////////// +#ifdef GRUEL_HRT_USE_MACH_ABSOLUTE_TIME + #include <mach/mach_time.h> + + inline gruel::high_res_timer_type gruel::high_res_timer_now(void){ + return mach_absolute_time(); + } + + inline gruel::high_res_timer_type gruel::high_res_timer_tps(void){ + mach_timebase_info_data_t info; + mach_timebase_info(&info); + return gruel::high_res_timer_type(info.numer*1000000000UL)/info.denom; + } +#endif + +//////////////////////////////////////////////////////////////////////// +#ifdef GRUEL_HRT_USE_QUERY_PERFORMANCE_COUNTER + #include <Windows.h> + + inline gruel::high_res_timer_type gruel::high_res_timer_now(void){ + LARGE_INTEGER counts; + QueryPerformanceCounter(&counts); + return counts.QuadPart; + } + + inline gruel::high_res_timer_type gruel::high_res_timer_tps(void){ + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return freq.QuadPart; + } +#endif + +//////////////////////////////////////////////////////////////////////// +#ifdef GRUEL_HRT_USE_MICROSEC_CLOCK + #include <boost/date_time/posix_time/posix_time.hpp> + + inline gruel::high_res_timer_type gruel::high_res_timer_now(void){ + static const boost::posix_time::ptime epoch(boost::posix_time::from_time_t(0)); + return (boost::posix_time::microsec_clock::universal_time() - epoch).ticks(); + } + + inline gruel::high_res_timer_type gruel::high_res_timer_tps(void){ + return boost::posix_time::time_duration::ticks_per_second(); + } +#endif + +//////////////////////////////////////////////////////////////////////// +#include <boost/date_time/posix_time/posix_time.hpp> + +inline gruel::high_res_timer_type gruel::high_res_timer_epoch(void){ + static const double hrt_ticks_per_utc_ticks = gruel::high_res_timer_tps()/double(boost::posix_time::time_duration::ticks_per_second()); + boost::posix_time::time_duration utc = boost::posix_time::microsec_clock::universal_time() - boost::posix_time::from_time_t(0); + return gruel::high_res_timer_now() - utc.ticks()*hrt_ticks_per_utc_ticks; +} + +#endif /* INCLUDED_GRUEL_HIGH_RES_TIMER_H */ diff --git a/gruel/src/python/Makefile.am b/gruel/src/python/Makefile.am index 5a45510d5..80cb04b24 100644 --- a/gruel/src/python/Makefile.am +++ b/gruel/src/python/Makefile.am @@ -35,5 +35,9 @@ noinst_PYTHON = \ gruel_PYTHON = \ __init__.py +gruelpmtdir = $(pythondir)/gruel/pmt + +gruelpmt_PYTHON = pmt/__init__.py + endif diff --git a/gruel/src/python/__init__.py b/gruel/src/python/__init__.py index 421a9aaa8..14014cc5a 100644 --- a/gruel/src/python/__init__.py +++ b/gruel/src/python/__init__.py @@ -21,5 +21,5 @@ # The presence of this file turns this directory into a Python package -from pmt_swig import * +import pmt; diff --git a/gruel/src/python/pmt/__init__.py b/gruel/src/python/pmt/__init__.py new file mode 100644 index 000000000..421a9aaa8 --- /dev/null +++ b/gruel/src/python/pmt/__init__.py @@ -0,0 +1,25 @@ +# +# Copyright 2011 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. +# + +# The presence of this file turns this directory into a Python package + +from pmt_swig import * + |