diff options
94 files changed, 2006 insertions, 188 deletions
diff --git a/cmake/Modules/FindQwt.cmake b/cmake/Modules/FindQwt.cmake index bc8683f7d..857020796 100644 --- a/cmake/Modules/FindQwt.cmake +++ b/cmake/Modules/FindQwt.cmake @@ -3,11 +3,22 @@ # QWT_LIBRARIES libraries to link against # QWT_FOUND If false, do not try to use Qwt -find_path ( QWT_INCLUDE_DIRS qwt_plot.h /usr/include/qwt-qt4 /usr/include/qwt /opt/local/include/qwt ) - -find_library ( QWT_LIBRARIES NAMES qwt-qt4 qwt) +find_path (QWT_INCLUDE_DIRS + NAMES qwt_plot.h + PATHS + /usr/local/include/qwt-qt4 + /usr/local/include/qwt + /usr/include/qwt-qt4 + /usr/include/qwt +) + +find_library (QWT_LIBRARIES + NAMES qwt-qt4 qwt + PATHS /usr/local/lib /usr/lib +) # handle the QUIETLY and REQUIRED arguments and set QWT_FOUND to TRUE if # all listed variables are TRUE include ( FindPackageHandleStandardArgs ) find_package_handle_standard_args( Qwt DEFAULT_MSG QWT_LIBRARIES QWT_INCLUDE_DIRS ) +MARK_AS_ADVANCED(QWT_LIBRARIES QWT_INCLUDE_DIRS) diff --git a/cmake/Modules/GrMiscUtils.cmake b/cmake/Modules/GrMiscUtils.cmake index 0e1f40027..27003cf59 100644 --- a/cmake/Modules/GrMiscUtils.cmake +++ b/cmake/Modules/GrMiscUtils.cmake @@ -155,7 +155,7 @@ function(GR_LIBRARY_FOO target) GR_LIBTOOL(TARGET ${target} DESTINATION ${GR_LIBRARY_DIR}) #give the library a special name with ultra-zero soversion - set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_NAME ${target}-${LIBVER} SOVERSION "0.0.0") + set_target_properties(${target} PROPERTIES OUTPUT_NAME ${target}-${LIBVER} SOVERSION "0.0.0") set(target_name lib${target}-${LIBVER}.so.0.0.0) #custom command to generate symlinks diff --git a/config.guess b/config.guess index 8152efd67..49ba16f15 100644 --- a/config.guess +++ b/config.guess @@ -2,9 +2,9 @@ # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011 Free Software Foundation, Inc. +# 2011, 2012 Free Software Foundation, Inc. -timestamp='2011-11-11' +timestamp='2012-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -57,8 +57,8 @@ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free -Software Foundation, Inc. +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -145,7 +145,7 @@ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward @@ -897,16 +897,16 @@ EOF echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) - echo cris-axis-linux-gnu + echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; crisv32:Linux:*:*) - echo crisv32-axis-linux-gnu + echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; frv:Linux:*:*) - echo frv-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; hexagon:Linux:*:*) - echo hexagon-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu @@ -948,7 +948,7 @@ EOF test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) - echo or32-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu @@ -989,7 +989,7 @@ EOF echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) - echo x86_64-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu diff --git a/config.sub b/config.sub index e76eaf472..d6b6b3c76 100644 --- a/config.sub +++ b/config.sub @@ -2,9 +2,9 @@ # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011 Free Software Foundation, Inc. +# 2011, 2012 Free Software Foundation, Inc. -timestamp='2011-11-11' +timestamp='2012-01-01' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software @@ -76,8 +76,8 @@ version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free -Software Foundation, Inc. +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -320,7 +320,6 @@ case $basic_machine in basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | picochip) - # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; @@ -719,7 +718,6 @@ case $basic_machine in i370-ibm* | ibm*) basic_machine=i370-ibm ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 @@ -1559,9 +1557,6 @@ case $basic_machine in ;; m68000-sun) os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 ;; m68*-cisco) os=-aout diff --git a/docs/doxygen/other/group_defs.dox b/docs/doxygen/other/group_defs.dox index 6288d1f0a..facdc2338 100644 --- a/docs/doxygen/other/group_defs.dox +++ b/docs/doxygen/other/group_defs.dox @@ -32,6 +32,7 @@ /*! \defgroup uhd_blk UHD Interface */ /*! \defgroup audio_blk Audio Interface */ /*! \defgroup pfb_blk Polyphase Filterbank */ +/*! \defgroup snr_blk SNR estimators */ /*! * \defgroup base_blk Base classes for GR Blocks diff --git a/gnuradio-core/src/lib/filter/CMakeLists.txt b/gnuradio-core/src/lib/filter/CMakeLists.txt index ce7e387c2..d26e55fb8 100644 --- a/gnuradio-core/src/lib/filter/CMakeLists.txt +++ b/gnuradio-core/src/lib/filter/CMakeLists.txt @@ -28,7 +28,7 @@ foreach(gr_core_filter_asm ${gr_core_filter_asms}) endforeach(gr_core_filter_asm) #detect 32 or 64 bit compiler -if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86|x86_64)$") +if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86|x86_64|amd64)$") include(CheckTypeSize) check_type_size("void*" SIZEOF_VOID_P BUILTIN_TYPES_ONLY) if (${SIZEOF_VOID_P} EQUAL 8) diff --git a/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.cc b/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.cc index 02bfaf105..9fa98cc69 100644 --- a/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.cc +++ b/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.cc @@ -62,6 +62,7 @@ gr_fft_filter_ccc::gr_fft_filter_ccc (int decimation, const std::vector<gr_compl #else d_filter = new gri_fft_filter_ccc_sse(decimation, taps); #endif + d_new_taps = taps; d_nsamples = d_filter->set_taps(taps); set_output_multiple(d_nsamples); } @@ -78,6 +79,12 @@ gr_fft_filter_ccc::set_taps (const std::vector<gr_complex> &taps) d_updated = true; } +std::vector<gr_complex> +gr_fft_filter_ccc::taps () const +{ + return d_new_taps; +} + int gr_fft_filter_ccc::work (int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.h b/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.h index 721a44a83..1b72a1c00 100644 --- a/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.h +++ b/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.h @@ -62,6 +62,7 @@ class GR_CORE_API gr_fft_filter_ccc : public gr_sync_decimator ~gr_fft_filter_ccc (); void set_taps (const std::vector<gr_complex> &taps); + std::vector<gr_complex> taps () const; int work (int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.i b/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.i index aa7564f54..812920d8b 100644 --- a/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.i +++ b/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.i @@ -36,4 +36,5 @@ class gr_fft_filter_ccc : public gr_sync_decimator ~gr_fft_filter_ccc (); void set_taps (const std::vector<gr_complex> &taps); + std::vector<gr_complex> taps () const; }; diff --git a/gnuradio-core/src/lib/filter/gr_fft_filter_fff.cc b/gnuradio-core/src/lib/filter/gr_fft_filter_fff.cc index e5b218f20..c0a9b3483 100644 --- a/gnuradio-core/src/lib/filter/gr_fft_filter_fff.cc +++ b/gnuradio-core/src/lib/filter/gr_fft_filter_fff.cc @@ -55,7 +55,7 @@ gr_fft_filter_fff::gr_fft_filter_fff (int decimation, const std::vector<float> & #else d_filter = new gri_fft_filter_fff_sse(decimation, taps); #endif - + d_new_taps = taps; d_nsamples = d_filter->set_taps(taps); set_output_multiple(d_nsamples); } @@ -72,6 +72,12 @@ gr_fft_filter_fff::set_taps (const std::vector<float> &taps) d_updated = true; } +std::vector<float> +gr_fft_filter_fff::taps () const +{ + return d_new_taps; +} + int gr_fft_filter_fff::work (int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gnuradio-core/src/lib/filter/gr_fft_filter_fff.h b/gnuradio-core/src/lib/filter/gr_fft_filter_fff.h index b0dc74883..ddd8dcac2 100644 --- a/gnuradio-core/src/lib/filter/gr_fft_filter_fff.h +++ b/gnuradio-core/src/lib/filter/gr_fft_filter_fff.h @@ -62,6 +62,7 @@ class GR_CORE_API gr_fft_filter_fff : public gr_sync_decimator ~gr_fft_filter_fff (); void set_taps (const std::vector<float> &taps); + std::vector<float> taps () const; int work (int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gnuradio-core/src/lib/filter/gr_fft_filter_fff.i b/gnuradio-core/src/lib/filter/gr_fft_filter_fff.i index bbe84f99f..7e2cde977 100644 --- a/gnuradio-core/src/lib/filter/gr_fft_filter_fff.i +++ b/gnuradio-core/src/lib/filter/gr_fft_filter_fff.i @@ -36,4 +36,5 @@ class gr_fft_filter_fff : public gr_sync_decimator ~gr_fft_filter_fff (); void set_taps (const std::vector<float> &taps); + std::vector<float> taps () const; }; diff --git a/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.cc.t b/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.cc.t index 29e351925..f7458e743 100644 --- a/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.cc.t +++ b/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.cc.t @@ -63,6 +63,12 @@ void d_updated = true; } +std::vector<@TAP_TYPE@> +@NAME@::taps () const +{ + return d_new_taps; +} + int @NAME@::work (int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.h.t b/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.h.t index db0625504..f638e7bb5 100644 --- a/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.h.t +++ b/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.h.t @@ -59,6 +59,7 @@ class GR_CORE_API @NAME@ : public gr_sync_decimator ~@NAME@ (); void set_taps (const std::vector<@TAP_TYPE@> &taps); + std::vector<@TAP_TYPE@> taps () const; int work (int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.i.t b/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.i.t index 0cbe8cbcc..fb4ff95af 100644 --- a/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.i.t +++ b/gnuradio-core/src/lib/filter/gr_fir_filter_XXX.i.t @@ -38,4 +38,5 @@ class @NAME@ : public gr_sync_decimator ~@NAME@ (); void set_taps (const std::vector<@TAP_TYPE@> &taps); + std::vector<@TAP_TYPE@> taps () const; }; diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc index 398956ddd..9297b6587 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc @@ -60,7 +60,7 @@ gr_pfb_clock_sync_ccf::gr_pfb_clock_sync_ccf (double sps, float loop_bw, gr_make_io_signaturev (1, 4, iosig)), d_updated (false), d_nfilters(filter_size), d_max_dev(max_rate_deviation), - d_osps(osps), d_error(0) + d_osps(osps), d_error(0), d_out_idx(0) { d_nfilters = filter_size; d_sps = floor(sps); @@ -380,7 +380,7 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items, // produce output as long as we can and there are enough input samples while((i < noutput_items) && (count < nrequired)) { - for(int k = 0; k < d_osps; k++) { + while(d_out_idx < d_osps) { d_filtnum = (int)floor(d_k); // Keep the current filter number in [0, d_nfilters] @@ -397,16 +397,27 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items, count -= 1; } - out[i+k] = d_filters[d_filtnum]->filter(&in[count+k]); + out[i+d_out_idx] = d_filters[d_filtnum]->filter(&in[count+d_out_idx]); d_k = d_k + d_rate_i + d_rate_f; // update phase - + d_out_idx++; + if(output_items.size() == 4) { err[i] = d_error; outrate[i] = d_rate_f; outk[i] = d_k; } + + // We've run out of output items we can create; return now. + if(i+d_out_idx >= noutput_items) { + consume_each(count); + return i; + } } + // reset here; if we didn't complete a full osps samples last time, + // the early return would take care of it. + d_out_idx = 0; + // Update the phase and rate estimates for this symbol gr_complex diff = d_diff_filters[d_filtnum]->filter(&in[count]); error_r = out[i].real() * diff.real(); @@ -424,7 +435,7 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items, i+=d_osps; count += (int)floor(d_sps); } - consume_each(count); + consume_each(count); return i; } diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h index f4f589cd9..1e1bbca10 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h @@ -197,7 +197,8 @@ class GR_CORE_API gr_pfb_clock_sync_ccf : public gr_block int d_filtnum; int d_osps; float d_error; - + int d_out_idx; + /*! * Build the polyphase filterbank timing synchronizer. */ diff --git a/gnuradio-core/src/lib/filter/qa_gri_mmse_fir_interpolator_cc.cc b/gnuradio-core/src/lib/filter/qa_gri_mmse_fir_interpolator_cc.cc index 2fc97a78a..d0ed04238 100644 --- a/gnuradio-core/src/lib/filter/qa_gri_mmse_fir_interpolator_cc.cc +++ b/gnuradio-core/src/lib/filter/qa_gri_mmse_fir_interpolator_cc.cc @@ -31,6 +31,7 @@ #include <stdio.h> #include <cmath> #include <stdexcept> +#include <unistd.h> #define NELEM(x) (sizeof (x) / sizeof (x[0])) diff --git a/gnuradio-core/src/lib/general/gr_fft_vcc_fftw.cc b/gnuradio-core/src/lib/general/gr_fft_vcc_fftw.cc index 3293e3ab8..c66015c11 100644 --- a/gnuradio-core/src/lib/general/gr_fft_vcc_fftw.cc +++ b/gnuradio-core/src/lib/general/gr_fft_vcc_fftw.cc @@ -67,8 +67,17 @@ gr_fft_vcc_fftw::work (int noutput_items, if (d_window.size()){ gr_complex *dst = d_fft->get_inbuf(); - for (unsigned int i = 0; i < d_fft_size; i++) // apply window - dst[i] = in[i] * d_window[i]; + if(!d_forward && d_shift){ + int offset = (!d_forward && d_shift)?floor(d_fft_size/2):0; + int fft_m_offset = d_fft_size - offset; + for (unsigned int i = 0; i < offset; i++) // apply window + dst[i+fft_m_offset] = in[i] * d_window[i]; + for (unsigned int i = offset; i < d_fft_size; i++) // apply window + dst[i-offset] = in[i] * d_window[i]; + } else { + for (unsigned int i = 0; i < d_fft_size; i++) // apply window + dst[i] = in[i] * d_window[i]; + } } else { if(!d_forward && d_shift) { // apply an ifft shift on the data diff --git a/gnuradio-core/src/lib/gengen/gr_noise_source_X.h.t b/gnuradio-core/src/lib/gengen/gr_noise_source_X.h.t index 9dd92c8f5..ab5992257 100644 --- a/gnuradio-core/src/lib/gengen/gr_noise_source_X.h.t +++ b/gnuradio-core/src/lib/gengen/gr_noise_source_X.h.t @@ -55,6 +55,9 @@ class GR_CORE_API @NAME@ : public gr_sync_block { void set_type (gr_noise_type_t type) { d_type = type; } void set_amplitude (float ampl) { d_ampl = ampl; } + gr_noise_type_t type () const { return d_type; } + float amplitude () const { return d_ampl; } + virtual 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/gengen/gr_noise_source_X.i.t b/gnuradio-core/src/lib/gengen/gr_noise_source_X.i.t index 27261502d..179dc0343 100644 --- a/gnuradio-core/src/lib/gengen/gr_noise_source_X.i.t +++ b/gnuradio-core/src/lib/gengen/gr_noise_source_X.i.t @@ -34,4 +34,7 @@ class @NAME@ : public gr_block { public: void set_type (gr_noise_type_t type) { d_type = type; } void set_amplitude (float ampl) { d_ampl = ampl; } + + gr_noise_type_t type () const { return d_type; } + float amplitude () const { return d_ampl; } }; diff --git a/gnuradio-core/src/lib/hier/gr_channel_model.cc b/gnuradio-core/src/lib/hier/gr_channel_model.cc index fb57e808a..5f190e972 100644 --- a/gnuradio-core/src/lib/hier/gr_channel_model.cc +++ b/gnuradio-core/src/lib/hier/gr_channel_model.cc @@ -99,3 +99,28 @@ gr_channel_model::set_timing_offset(double epsilon) { d_timing_offset->set_interp_ratio(epsilon); } + + +double +gr_channel_model::noise_voltage() const +{ + return d_noise->amplitude(); +} + +double +gr_channel_model::frequency_offset() const +{ + return d_freq_offset->frequency(); +} + +std::vector<gr_complex> +gr_channel_model::taps() const +{ + return d_multipath->taps(); +} + +double +gr_channel_model::timing_offset() const +{ + return d_timing_offset->interp_ratio(); +} diff --git a/gnuradio-core/src/lib/hier/gr_channel_model.h b/gnuradio-core/src/lib/hier/gr_channel_model.h index 07c0c76b6..c5d06ce11 100644 --- a/gnuradio-core/src/lib/hier/gr_channel_model.h +++ b/gnuradio-core/src/lib/hier/gr_channel_model.h @@ -71,4 +71,9 @@ class GR_CORE_API gr_channel_model : public gr_hier_block2 void set_frequency_offset(double frequency_offset); void set_taps(const std::vector<gr_complex> &taps); void set_timing_offset(double epsilon); + + double noise_voltage() const; + double frequency_offset() const; + std::vector<gr_complex> taps() const; + double timing_offset() const; }; diff --git a/gnuradio-core/src/lib/hier/gr_channel_model.i b/gnuradio-core/src/lib/hier/gr_channel_model.i index ff9ab466d..2e0cb7bdf 100644 --- a/gnuradio-core/src/lib/hier/gr_channel_model.i +++ b/gnuradio-core/src/lib/hier/gr_channel_model.i @@ -42,4 +42,9 @@ class gr_channel_model : public gr_hier_block2 void set_frequency_offset(double frequency_offset); void set_taps(const std::vector<gr_complex> &taps); void set_timing_offset(double epsilon); + + double noise_voltage() const; + double frequency_offset() const; + std::vector<gr_complex> taps() const; + double timing_offset() const; }; diff --git a/gnuradio-core/src/lib/io/gr_oscope_guts.cc b/gnuradio-core/src/lib/io/gr_oscope_guts.cc index ce7feca13..f1bdeb9c1 100644 --- a/gnuradio-core/src/lib/io/gr_oscope_guts.cc +++ b/gnuradio-core/src/lib/io/gr_oscope_guts.cc @@ -31,8 +31,7 @@ #include <math.h> #include <assert.h> -static const int OUTPUT_RECORD_SIZE = 2048; // must be power of 2 - +static const int OUTPUT_RECORD_SIZE = 16384; // Must be power of 2 static inline int wrap_bi (int buffer_index) // wrap buffer index { @@ -139,7 +138,7 @@ gr_oscope_guts::process_sample (const float *channel_data) { for (int i = 0; i < d_nchannels; i++) { - for (int j = OUTPUT_RECORD_SIZE-1; j >= 0; j--) + for (int j = OUTPUT_RECORD_SIZE-1; j > 0; j--) { d_buffer[i][j] = d_buffer[i][j-1]; } diff --git a/gnuradio-core/src/lib/io/gr_udp_sink.cc b/gnuradio-core/src/lib/io/gr_udp_sink.cc index 36b4cbe36..9fc4da0ae 100644 --- a/gnuradio-core/src/lib/io/gr_udp_sink.cc +++ b/gnuradio-core/src/lib/io/gr_udp_sink.cc @@ -20,6 +20,8 @@ * Boston, MA 02110-1301, USA. */ +#include <boost/asio.hpp> + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/gnuradio-core/src/lib/runtime/gr_block_executor.cc b/gnuradio-core/src/lib/runtime/gr_block_executor.cc index 737b26f67..ef53baf78 100644 --- a/gnuradio-core/src/lib/runtime/gr_block_executor.cc +++ b/gnuradio-core/src/lib/runtime/gr_block_executor.cc @@ -155,8 +155,8 @@ propagate_tags(gr_block::tag_propagation_policy_t policy, gr_block_detail *d, return true; } -gr_block_executor::gr_block_executor (gr_block_sptr block) - : d_block(block), d_log(0) +gr_block_executor::gr_block_executor (gr_block_sptr block, int max_noutput_items) + : d_block(block), d_log(0), d_max_noutput_items(max_noutput_items) { if (ENABLE_LOGGING){ std::string name = str(boost::format("sst-%03d.log") % which_scheduler++); @@ -182,6 +182,7 @@ gr_block_executor::run_one_iteration() { int noutput_items; int max_items_avail; + int max_noutput_items = d_max_noutput_items; gr_block *m = d_block.get(); gr_block_detail *d = m->detail().get(); @@ -203,6 +204,7 @@ gr_block_executor::run_one_iteration() // determine the minimum available output space noutput_items = min_available_space (d, m->output_multiple ()); + noutput_items = std::min(noutput_items, d_max_noutput_items); LOG(*d_log << " source\n noutput_items = " << noutput_items << std::endl); if (noutput_items == -1) // we're done goto were_done; @@ -247,6 +249,7 @@ gr_block_executor::run_one_iteration() // take a swag at how much output we can sink noutput_items = (int) (max_items_avail * m->relative_rate ()); noutput_items = round_down (noutput_items, m->output_multiple ()); + noutput_items = std::min(noutput_items, d_max_noutput_items); LOG(*d_log << " max_items_avail = " << max_items_avail << std::endl); LOG(*d_log << " noutput_items = " << noutput_items << std::endl); @@ -307,7 +310,11 @@ gr_block_executor::run_one_iteration() reqd_noutput_items = round_up(reqd_noutput_items, m->output_multiple()); if (reqd_noutput_items > 0 && reqd_noutput_items <= noutput_items) noutput_items = reqd_noutput_items; + + // if we need this many outputs, overrule the max_noutput_items setting + max_noutput_items = std::max(m->output_multiple(), max_noutput_items); } + noutput_items = std::min(noutput_items, max_noutput_items); // ask the block how much input they need to produce noutput_items m->forecast (noutput_items, d_ninput_items_required); diff --git a/gnuradio-core/src/lib/runtime/gr_block_executor.h b/gnuradio-core/src/lib/runtime/gr_block_executor.h index 15279f273..e022d8273 100644 --- a/gnuradio-core/src/lib/runtime/gr_block_executor.h +++ b/gnuradio-core/src/lib/runtime/gr_block_executor.h @@ -51,9 +51,10 @@ protected: gr_vector_void_star d_output_items; std::vector<uint64_t> d_start_nitems_read; //stores where tag counts are before work std::vector<gr_tag_t> d_returned_tags; + int d_max_noutput_items; public: - gr_block_executor(gr_block_sptr block); + gr_block_executor(gr_block_sptr block, int max_noutput_items=100000); ~gr_block_executor (); enum state { diff --git a/gnuradio-core/src/lib/runtime/gr_scheduler.cc b/gnuradio-core/src/lib/runtime/gr_scheduler.cc index e4d8b3dd9..3ae08a7a3 100644 --- a/gnuradio-core/src/lib/runtime/gr_scheduler.cc +++ b/gnuradio-core/src/lib/runtime/gr_scheduler.cc @@ -24,7 +24,7 @@ #endif #include <gr_scheduler.h> -gr_scheduler::gr_scheduler(gr_flat_flowgraph_sptr ffg) +gr_scheduler::gr_scheduler(gr_flat_flowgraph_sptr ffg, int max_noutput_items) { } diff --git a/gnuradio-core/src/lib/runtime/gr_scheduler.h b/gnuradio-core/src/lib/runtime/gr_scheduler.h index 4e97b5881..92af8d1cb 100644 --- a/gnuradio-core/src/lib/runtime/gr_scheduler.h +++ b/gnuradio-core/src/lib/runtime/gr_scheduler.h @@ -47,7 +47,7 @@ public: * The scheduler will continue running until all blocks until they * report that they are done or the stop method is called. */ - gr_scheduler(gr_flat_flowgraph_sptr ffg); + gr_scheduler(gr_flat_flowgraph_sptr ffg, int max_noutput_items); virtual ~gr_scheduler(); diff --git a/gnuradio-core/src/lib/runtime/gr_scheduler_sts.cc b/gnuradio-core/src/lib/runtime/gr_scheduler_sts.cc index fefc0dc70..3cc1d4d45 100644 --- a/gnuradio-core/src/lib/runtime/gr_scheduler_sts.cc +++ b/gnuradio-core/src/lib/runtime/gr_scheduler_sts.cc @@ -43,13 +43,13 @@ public: gr_scheduler_sptr -gr_scheduler_sts::make(gr_flat_flowgraph_sptr ffg) +gr_scheduler_sts::make(gr_flat_flowgraph_sptr ffg, int max_noutput_items) { - return gr_scheduler_sptr(new gr_scheduler_sts(ffg)); + return gr_scheduler_sptr(new gr_scheduler_sts(ffg, max_noutput_items)); } -gr_scheduler_sts::gr_scheduler_sts(gr_flat_flowgraph_sptr ffg) - : gr_scheduler(ffg) +gr_scheduler_sts::gr_scheduler_sts(gr_flat_flowgraph_sptr ffg, int max_noutput_items) + : gr_scheduler(ffg, max_noutput_items) { // Split the flattened flow graph into discrete partitions, each // of which is topologically sorted. diff --git a/gnuradio-core/src/lib/runtime/gr_scheduler_sts.h b/gnuradio-core/src/lib/runtime/gr_scheduler_sts.h index 9b73b68c1..08c68d88a 100644 --- a/gnuradio-core/src/lib/runtime/gr_scheduler_sts.h +++ b/gnuradio-core/src/lib/runtime/gr_scheduler_sts.h @@ -39,10 +39,10 @@ protected: * The scheduler will continue running until all blocks until they * report that they are done or the stop method is called. */ - gr_scheduler_sts(gr_flat_flowgraph_sptr ffg); + gr_scheduler_sts(gr_flat_flowgraph_sptr ffg, int max_noutput_items); public: - static gr_scheduler_sptr make(gr_flat_flowgraph_sptr ffg); + static gr_scheduler_sptr make(gr_flat_flowgraph_sptr ffg, int max_noutput_items); ~gr_scheduler_sts(); diff --git a/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.cc b/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.cc index af0338570..0a7ff4556 100644 --- a/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.cc +++ b/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.cc @@ -33,25 +33,27 @@ class tpb_container { gr_block_sptr d_block; + int d_max_noutput_items; public: - tpb_container(gr_block_sptr block) : d_block(block) {} + tpb_container(gr_block_sptr block, int max_noutput_items) + : d_block(block), d_max_noutput_items(max_noutput_items) {} void operator()() { - gr_tpb_thread_body body(d_block); + gr_tpb_thread_body body(d_block, d_max_noutput_items); } }; gr_scheduler_sptr -gr_scheduler_tpb::make(gr_flat_flowgraph_sptr ffg) +gr_scheduler_tpb::make(gr_flat_flowgraph_sptr ffg, int max_noutput_items) { - return gr_scheduler_sptr(new gr_scheduler_tpb(ffg)); + return gr_scheduler_sptr(new gr_scheduler_tpb(ffg, max_noutput_items)); } -gr_scheduler_tpb::gr_scheduler_tpb(gr_flat_flowgraph_sptr ffg) - : gr_scheduler(ffg) +gr_scheduler_tpb::gr_scheduler_tpb(gr_flat_flowgraph_sptr ffg, int max_noutput_items) + : gr_scheduler(ffg, max_noutput_items) { // Get a topologically sorted vector of all the blocks in use. // Being topologically sorted probably isn't going to matter, but @@ -73,7 +75,8 @@ gr_scheduler_tpb::gr_scheduler_tpb(gr_flat_flowgraph_sptr ffg) std::stringstream name; name << "thread-per-block[" << i << "]: " << blocks[i]; d_threads.create_thread( - gruel::thread_body_wrapper<tpb_container>(tpb_container(blocks[i]), name.str())); + gruel::thread_body_wrapper<tpb_container>(tpb_container(blocks[i], max_noutput_items), + name.str())); } } diff --git a/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.h b/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.h index f97ab2e7f..ab74fa84d 100644 --- a/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.h +++ b/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.h @@ -39,10 +39,10 @@ protected: * The scheduler will continue running until all blocks until they * report that they are done or the stop method is called. */ - gr_scheduler_tpb(gr_flat_flowgraph_sptr ffg); + gr_scheduler_tpb(gr_flat_flowgraph_sptr ffg, int max_noutput_items); public: - static gr_scheduler_sptr make(gr_flat_flowgraph_sptr ffg); + static gr_scheduler_sptr make(gr_flat_flowgraph_sptr ffg, int max_noutput_items=100000); ~gr_scheduler_tpb(); diff --git a/gnuradio-core/src/lib/runtime/gr_top_block.cc b/gnuradio-core/src/lib/runtime/gr_top_block.cc index f341525c0..56d1352cd 100644 --- a/gnuradio-core/src/lib/runtime/gr_top_block.cc +++ b/gnuradio-core/src/lib/runtime/gr_top_block.cc @@ -54,9 +54,9 @@ gr_top_block::~gr_top_block() } void -gr_top_block::start() +gr_top_block::start(int max_noutput_items) { - d_impl->start(); + d_impl->start(max_noutput_items); } void @@ -72,9 +72,9 @@ gr_top_block::wait() } void -gr_top_block::run() +gr_top_block::run(int max_noutput_items) { - start(); + start(max_noutput_items); wait(); } @@ -96,6 +96,18 @@ gr_top_block::dump() d_impl->dump(); } +int +gr_top_block::max_noutput_items() +{ + return d_impl->max_noutput_items(); +} + +void +gr_top_block::set_max_noutput_items(int nmax) +{ + d_impl->set_max_noutput_items(nmax); +} + gr_top_block_sptr gr_top_block::to_top_block() { diff --git a/gnuradio-core/src/lib/runtime/gr_top_block.h b/gnuradio-core/src/lib/runtime/gr_top_block.h index fca68ae71..9d01ba3ef 100644 --- a/gnuradio-core/src/lib/runtime/gr_top_block.h +++ b/gnuradio-core/src/lib/runtime/gr_top_block.h @@ -53,16 +53,25 @@ public: * * Calls start() then wait(). Used to run a flowgraph that will stop * on its own, or when another thread will call stop(). + * + * \param max_noutput_items the maximum number of output items + * allowed for any block in the flowgraph. This passes through to + * the start function; see that function for more details. */ - void run(); + void run(int max_noutput_items=100000); /*! * Start the contained flowgraph. Creates one or more threads to * execute the flow graph. Returns to the caller once the threads * are created. Calling start() on a top_block that is already * started IS an error. + * + * \param max_noutput_items the maximum number of output items + * allowed for any block in the flowgraph; the noutput_items can + * always be less than this, but this will cap it as a maximum. Use + * this to adjust the maximum latency a flowgraph can exhibit. */ - void start(); + void start(int max_noutput_items=100000); /*! * Stop the running flowgraph. Notifies each thread created by the @@ -107,6 +116,12 @@ public: */ void dump(); + //! Get the number of max noutput_items in the flowgraph + int max_noutput_items(); + + //! Set the maximum number of noutput_items in the flowgraph + void set_max_noutput_items(int nmax); + gr_top_block_sptr to_top_block(); // Needed for Python/Guile type coercion }; diff --git a/gnuradio-core/src/lib/runtime/gr_top_block.i b/gnuradio-core/src/lib/runtime/gr_top_block.i index 90fa18b94..70c627ffd 100644 --- a/gnuradio-core/src/lib/runtime/gr_top_block.i +++ b/gnuradio-core/src/lib/runtime/gr_top_block.i @@ -40,7 +40,7 @@ private: public: ~gr_top_block(); - void start() throw (std::runtime_error); + void start(int max_noutput_items=100000) throw (std::runtime_error); void stop(); //void wait(); //void run() throw (std::runtime_error); @@ -48,6 +48,9 @@ public: void unlock() throw (std::runtime_error); void dump(); + int max_noutput_items(); + void set_max_noutput_items(int nmax); + gr_top_block_sptr to_top_block(); // Needed for Python/Guile type coercion }; diff --git a/gnuradio-core/src/lib/runtime/gr_top_block_impl.cc b/gnuradio-core/src/lib/runtime/gr_top_block_impl.cc index 9cad687fb..0227d789c 100644 --- a/gnuradio-core/src/lib/runtime/gr_top_block_impl.cc +++ b/gnuradio-core/src/lib/runtime/gr_top_block_impl.cc @@ -39,7 +39,8 @@ #define GR_TOP_BLOCK_IMPL_DEBUG 0 -typedef gr_scheduler_sptr (*scheduler_maker)(gr_flat_flowgraph_sptr ffg); +typedef gr_scheduler_sptr (*scheduler_maker)(gr_flat_flowgraph_sptr ffg, + int max_noutput_items); static struct scheduler_table { const char *name; @@ -50,7 +51,7 @@ static struct scheduler_table { }; static gr_scheduler_sptr -make_scheduler(gr_flat_flowgraph_sptr ffg) +make_scheduler(gr_flat_flowgraph_sptr ffg, int max_noutput_items) { static scheduler_maker factory = 0; @@ -72,7 +73,7 @@ make_scheduler(gr_flat_flowgraph_sptr ffg) } } } - return factory(ffg); + return factory(ffg, max_noutput_items); } @@ -88,10 +89,12 @@ gr_top_block_impl::~gr_top_block_impl() } void -gr_top_block_impl::start() +gr_top_block_impl::start(int max_noutput_items) { gruel::scoped_lock l(d_mutex); + d_max_noutput_items = max_noutput_items; + if (d_state != IDLE) throw std::runtime_error("top_block::start: top block already running or wait() not called after previous stop()"); @@ -105,7 +108,7 @@ gr_top_block_impl::start() d_ffg->validate(); d_ffg->setup_connections(); - d_scheduler = make_scheduler(d_ffg); + d_scheduler = make_scheduler(d_ffg, d_max_noutput_items); d_state = RUNNING; } @@ -168,7 +171,7 @@ gr_top_block_impl::restart() d_ffg = new_ffg; // Create a new scheduler to execute it - d_scheduler = make_scheduler(d_ffg); + d_scheduler = make_scheduler(d_ffg, d_max_noutput_items); d_state = RUNNING; } @@ -178,3 +181,15 @@ gr_top_block_impl::dump() if (d_ffg) d_ffg->dump(); } + +int +gr_top_block_impl::max_noutput_items() +{ + return d_max_noutput_items; +} + +void +gr_top_block_impl::set_max_noutput_items(int nmax) +{ + d_max_noutput_items = nmax; +} diff --git a/gnuradio-core/src/lib/runtime/gr_top_block_impl.h b/gnuradio-core/src/lib/runtime/gr_top_block_impl.h index 904443be5..d804e3f30 100644 --- a/gnuradio-core/src/lib/runtime/gr_top_block_impl.h +++ b/gnuradio-core/src/lib/runtime/gr_top_block_impl.h @@ -42,7 +42,7 @@ public: ~gr_top_block_impl(); // Create and start scheduler threads - void start(); + void start(int max_noutput_items=100000); // Signal scheduler threads to stop void stop(); @@ -58,6 +58,12 @@ public: // Dump the flowgraph to stdout void dump(); + + // Get the number of max noutput_items in the flowgraph + int max_noutput_items(); + + // Set the maximum number of noutput_items in the flowgraph + void set_max_noutput_items(int nmax); protected: @@ -70,6 +76,7 @@ protected: gruel::mutex d_mutex; // protects d_state and d_lock_count tb_state d_state; int d_lock_count; + int d_max_noutput_items; private: void restart(); diff --git a/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc b/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc index faa888697..d44c09aa6 100644 --- a/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc +++ b/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc @@ -28,8 +28,8 @@ using namespace pmt; -gr_tpb_thread_body::gr_tpb_thread_body(gr_block_sptr block) - : d_exec(block) +gr_tpb_thread_body::gr_tpb_thread_body(gr_block_sptr block, int max_noutput_items) + : d_exec(block, max_noutput_items) { // std::cerr << "gr_tpb_thread_body: " << block << std::endl; diff --git a/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.h b/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.h index 548cfedfb..3170b402e 100644 --- a/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.h +++ b/gnuradio-core/src/lib/runtime/gr_tpb_thread_body.h @@ -38,7 +38,7 @@ class GR_CORE_API gr_tpb_thread_body { gr_block_executor d_exec; public: - gr_tpb_thread_body(gr_block_sptr block); + gr_tpb_thread_body(gr_block_sptr block, int max_noutput_items=100000); ~gr_tpb_thread_body(); }; diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_fft_filter.py b/gnuradio-core/src/python/gnuradio/gr/qa_fft_filter.py index b3124ad29..325495c1d 100755 --- a/gnuradio-core/src/python/gnuradio/gr/qa_fft_filter.py +++ b/gnuradio-core/src/python/gnuradio/gr/qa_fft_filter.py @@ -273,6 +273,30 @@ class test_fft_filter(gr_unittest.TestCase): self.assert_fft_float_ok2(expected_result, result_data) + def test_fff_get0(self): + random.seed(0) + for i in xrange(25): + ntaps = int(random.uniform(2, 100)) + taps = make_random_float_tuple(ntaps) + + op = gr.fft_filter_fff(1, taps) + result_data = op.taps() + #print result_data + + self.assertEqual(taps, result_data) + + def test_ccc_get0(self): + random.seed(0) + for i in xrange(25): + ntaps = int(random.uniform(2, 100)) + taps = make_random_complex_tuple(ntaps) + + op = gr.fft_filter_ccc(1, taps) + result_data = op.taps() + #print result_data + + self.assertComplexTuplesAlmostEqual(taps, result_data, 4) + if __name__ == '__main__': gr_unittest.run(test_fft_filter, "test_fft_filter.xml") diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_noise.py b/gnuradio-core/src/python/gnuradio/gr/qa_noise.py index 4a575f5d6..d7750cfe2 100755 --- a/gnuradio-core/src/python/gnuradio/gr/qa_noise.py +++ b/gnuradio-core/src/python/gnuradio/gr/qa_noise.py @@ -34,6 +34,18 @@ class test_noise_source(gr_unittest.TestCase): # Just confirm that we can instantiate a noise source op = gr.noise_source_f(gr.GR_GAUSSIAN, 10, 10) + def test_002(self): + # Test get methods + set_type = gr.GR_GAUSSIAN + set_ampl = 10 + op = gr.noise_source_f(set_type, set_ampl, 10) + get_type = op.type() + get_ampl = op.amplitude() + + self.assertEqual(get_type, set_type) + self.assertEqual(get_ampl, set_ampl) + + if __name__ == '__main__': gr_unittest.run(test_noise_source, "test_noise_source.xml") diff --git a/gnuradio-core/src/python/gnuradio/gr/top_block.py b/gnuradio-core/src/python/gnuradio/gr/top_block.py index 1e36d3b48..f2d83893c 100644 --- a/gnuradio-core/src/python/gnuradio/gr/top_block.py +++ b/gnuradio-core/src/python/gnuradio/gr/top_block.py @@ -93,14 +93,14 @@ class top_block(object): raise RuntimeError("top_block: invalid state--did you forget to call gr.top_block.__init__ in a derived class?") return getattr(self._tb, name) - def start(self): - self._tb.start() + def start(self, max_noutput_items=100000): + self._tb.start(max_noutput_items) def stop(self): self._tb.stop() - def run(self): - self.start() + def run(self, max_noutput_items=100000): + self.start(max_noutput_items) self.wait() def wait(self): diff --git a/gr-atsc/src/lib/qa_atsci_single_viterbi.cc b/gr-atsc/src/lib/qa_atsci_single_viterbi.cc index dac1e94c3..95e595026 100644 --- a/gr-atsc/src/lib/qa_atsci_single_viterbi.cc +++ b/gr-atsc/src/lib/qa_atsci_single_viterbi.cc @@ -238,7 +238,7 @@ qa_atsci_single_viterbi::t1 () if (differs) { const int ERRTOL = 12; /* Or relate to delay? */ int shouldfix = 1; - int lasti = -ERRTOL; + //int lasti = -ERRTOL; printf ( " Inserted errors: "); for (int erri = 0; erri < NN; erri++) { @@ -246,7 +246,7 @@ qa_atsci_single_viterbi::t1 () printf (" %d", erri); // if (erri < lasti+ERRTOL) // shouldfix = 0; - lasti = erri; + //lasti = erri; } } printf ("\n Erroneous result dibits:"); diff --git a/gr-audio/lib/alsa/audio_alsa_source.cc b/gr-audio/lib/alsa/audio_alsa_source.cc index 08d4996a8..a90552ff5 100644 --- a/gr-audio/lib/alsa/audio_alsa_source.cc +++ b/gr-audio/lib/alsa/audio_alsa_source.cc @@ -348,12 +348,11 @@ audio_alsa_source::work_s16_2x1 (int noutput_items, typedef gr_int16 sample_t; // the type of samples we're creating static const float scale_factor = 1.0 / std::pow(2.0f, 16-1); - unsigned int nchan = output_items.size (); float **out = (float **) &output_items[0]; sample_t *buf = (sample_t *) d_buffer; int bi; - assert (nchan == 1); + assert (output_items.size () == 1); unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t); assert (d_buffer_size_bytes == d_period_size * sizeof_frame); @@ -425,12 +424,11 @@ audio_alsa_source::work_s32_2x1 (int noutput_items, typedef gr_int32 sample_t; // the type of samples we're creating static const float scale_factor = 1.0 / std::pow(2.0f, 32-1); - unsigned int nchan = output_items.size (); float **out = (float **) &output_items[0]; sample_t *buf = (sample_t *) d_buffer; int bi; - assert (nchan == 1); + assert (output_items.size () == 1); unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t); assert (d_buffer_size_bytes == d_period_size * sizeof_frame); diff --git a/gr-digital/examples/CMakeLists.txt b/gr-digital/examples/CMakeLists.txt index 2645557cc..7b94f745c 100644 --- a/gr-digital/examples/CMakeLists.txt +++ b/gr-digital/examples/CMakeLists.txt @@ -25,6 +25,7 @@ GR_PYTHON_INSTALL(PROGRAMS example_timing.py run_length.py gen_whitener.py + snr_estimators.py DESTINATION ${GR_PKG_DATA_DIR}/examples/digital COMPONENT "digital_python" ) diff --git a/gr-digital/examples/Makefile.am b/gr-digital/examples/Makefile.am index 3841bbd0e..3e6b32e85 100644 --- a/gr-digital/examples/Makefile.am +++ b/gr-digital/examples/Makefile.am @@ -29,7 +29,8 @@ dist_basicdata_SCRIPTS = \ example_fll.py \ example_timing.py \ run_length.py \ - gen_whitener.py + gen_whitener.py \ + snr_estimators.py nbdatadir = $(dig_examples_prefix)/narrowband dist_nbdata_SCRIPTS = \ diff --git a/gr-digital/examples/narrowband/digital_bert_rx.py b/gr-digital/examples/narrowband/digital_bert_rx.py index 28331310d..dfed0eee7 100755 --- a/gr-digital/examples/narrowband/digital_bert_rx.py +++ b/gr-digital/examples/narrowband/digital_bert_rx.py @@ -113,9 +113,11 @@ class rx_psk_block(gr.top_block): self._demodulator = self._demodulator_class(**demod_kwargs) if(options.rx_freq is not None): + symbol_rate = options.bitrate / self._demodulator.bits_per_symbol() self._source = uhd_receiver(options.args, options.bitrate, options.samples_per_symbol, options.rx_freq, options.rx_gain, + options.spec, options.antenna, options.verbose) options.samples_per_symbol = self._source._sps diff --git a/gr-digital/examples/narrowband/digital_bert_tx.py b/gr-digital/examples/narrowband/digital_bert_tx.py index 46f4f9097..f29e997af 100755 --- a/gr-digital/examples/narrowband/digital_bert_tx.py +++ b/gr-digital/examples/narrowband/digital_bert_tx.py @@ -67,9 +67,11 @@ class tx_psk_block(gr.top_block): self._modulator = self._modulator_class(**mod_kwargs) if(options.tx_freq is not None): - self._sink = uhd_transmitter(options.args, options.bitrate, + symbol_rate = options.bitrate / self._modulator.bits_per_symbol() + self._sink = uhd_transmitter(options.args, symbol_rate, options.samples_per_symbol, options.tx_freq, options.tx_gain, + options.spec, options.antenna, options.verbose) options.samples_per_symbol = self._sink._sps @@ -87,7 +89,8 @@ class tx_psk_block(gr.top_block): verbose=options.verbose, log=options.log) - self.connect(self._transmitter, self._sink) + self.amp = gr.multiply_const_cc(options.amplitude) + self.connect(self._transmitter, self.amp, self._sink) def get_options(mods): diff --git a/gr-digital/examples/snr_estimators.py b/gr-digital/examples/snr_estimators.py new file mode 100755 index 000000000..432abd455 --- /dev/null +++ b/gr-digital/examples/snr_estimators.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python + +import sys + +try: + import scipy + from scipy import stats +except ImportError: + print "Error: Program requires scipy (www.scipy.org)." + sys.exit(1) + +try: + import pylab +except ImportError: + print "Error: Program requires Matplotlib (matplotlib.sourceforge.net)." + sys.exit(1) + +from gnuradio import gr, digital +from optparse import OptionParser +from gnuradio.eng_option import eng_option + +''' +This example program uses Python and GNU Radio to calculate SNR of a +noise BPSK signal to compare them. + +For an explination of the online algorithms, see: +http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Higher-order_statistics +''' + +def online_skewness(data, alpha): + n = 0 + mean = 0 + M2 = 0 + M3 = 0 + d_M3 = 0 + + for n in xrange(len(data)): + delta = data[n] - mean + delta_n = delta / (n+1) + term1 = delta * delta_n * (n) + mean = mean + delta_n + M3 = term1 * delta_n * (n - 1) - 3 * delta_n * M2 + M2 = M2 + term1 + d_M3 = (0.001)*M3 + (1-0.001)*d_M3; + + return d_M3 + +def snr_est_simple(signal): + y1 = scipy.mean(abs(signal)) + y2 = scipy.real(scipy.mean(signal**2)) + y3 = (y1*y1 - y2) + snr_rat = y1*y1/y3 + return 10.0*scipy.log10(snr_rat), snr_rat + +def snr_est_skew(signal): + y1 = scipy.mean(abs(signal)) + y2 = scipy.mean(scipy.real(signal**2)) + y3 = (y1*y1 - y2) + y4 = online_skewness(abs(signal.real), 0.001) + + skw = y4*y4 / (y2*y2*y2); + snr_rat = y1*y1 / (y3 + skw*y1*y1) + return 10.0*scipy.log10(snr_rat), snr_rat + +def snr_est_m2m4(signal): + M2 = scipy.mean(abs(signal)**2) + M4 = scipy.mean(abs(signal)**4) + snr_rat = 2*scipy.sqrt(2*M2*M2 - M4) / (M2 - scipy.sqrt(2*M2*M2 - M4)) + return 10.0*scipy.log10(snr_rat), snr_rat + +def snr_est_svr(signal): + N = len(signal) + ssum = 0 + msum = 0 + for i in xrange(1, N): + ssum += (abs(signal[i])**2)*(abs(signal[i-1])**2) + msum += (abs(signal[i])**4) + savg = (1.0/(float(N)-1.0))*ssum + mavg = (1.0/(float(N)-1.0))*msum + beta = savg / (mavg - savg) + + snr_rat = 2*((beta - 1) + scipy.sqrt(beta*(beta-1))) + return 10.0*scipy.log10(snr_rat), snr_rat + + +def main(): + gr_estimators = {"simple": digital.SNR_EST_SIMPLE, + "skew": digital.SNR_EST_SKEW, + "m2m4": digital.SNR_EST_M2M4, + "svr": digital.SNR_EST_SVR} + py_estimators = {"simple": snr_est_simple, + "skew": snr_est_skew, + "m2m4": snr_est_m2m4, + "svr": snr_est_svr} + + + parser = OptionParser(option_class=eng_option, conflict_handler="resolve") + parser.add_option("-N", "--nsamples", type="int", default=10000, + help="Set the number of samples to process [default=%default]") + parser.add_option("", "--snr-min", type="float", default=-5, + help="Minimum SNR [default=%default]") + parser.add_option("", "--snr-max", type="float", default=20, + help="Maximum SNR [default=%default]") + parser.add_option("", "--snr-step", type="float", default=0.5, + help="SNR step amount [default=%default]") + parser.add_option("-t", "--type", type="choice", + choices=gr_estimators.keys(), default="simple", + help="Estimator type {0} [default=%default]".format( + gr_estimators.keys())) + (options, args) = parser.parse_args () + + N = options.nsamples + xx = scipy.random.randn(N) + xy = scipy.random.randn(N) + bits = 2*scipy.complex64(scipy.random.randint(0, 2, N)) - 1 + + snr_known = list() + snr_python = list() + snr_gr = list() + + # when to issue an SNR tag; can be ignored in this example. + ntag = 10000 + + n_cpx = xx + 1j*xy + + py_est = py_estimators[options.type] + gr_est = gr_estimators[options.type] + + SNR_min = options.snr_min + SNR_max = options.snr_max + SNR_step = options.snr_step + SNR_dB = scipy.arange(SNR_min, SNR_max+SNR_step, SNR_step) + for snr in SNR_dB: + SNR = 10.0**(snr/10.0) + scale = scipy.sqrt(SNR) + yy = bits + n_cpx/scale + print "SNR: ", snr + + Sknown = scipy.mean(yy**2) + Nknown = scipy.var(n_cpx/scale)/2 + snr0 = Sknown/Nknown + snr0dB = 10.0*scipy.log10(snr0) + snr_known.append(snr0dB) + + snrdB, snr = py_est(yy) + snr_python.append(snrdB) + + gr_src = gr.vector_source_c(bits.tolist(), False) + gr_snr = digital.mpsk_snr_est_cc(gr_est, ntag, 0.001) + gr_chn = gr.channel_model(1.0/scale) + gr_snk = gr.null_sink(gr.sizeof_gr_complex) + tb = gr.top_block() + tb.connect(gr_src, gr_chn, gr_snr, gr_snk) + tb.run() + + snr_gr.append(gr_snr.snr()) + + f1 = pylab.figure(1) + s1 = f1.add_subplot(1,1,1) + s1.plot(SNR_dB, snr_known, "k-o", linewidth=2, label="Known") + s1.plot(SNR_dB, snr_python, "b-o", linewidth=2, label="Python") + s1.plot(SNR_dB, snr_gr, "g-o", linewidth=2, label="GNU Radio") + s1.grid(True) + s1.set_title('SNR Estimators') + s1.set_xlabel('SNR (dB)') + s1.set_ylabel('Estimated SNR') + s1.legend() + + pylab.show() + + +if __name__ == "__main__": + main() + diff --git a/gr-digital/grc/digital_dxpsk_demod.xml b/gr-digital/grc/digital_dxpsk_demod.xml index d5e742097..cfd474f68 100644 --- a/gr-digital/grc/digital_dxpsk_demod.xml +++ b/gr-digital/grc/digital_dxpsk_demod.xml @@ -33,6 +33,7 @@ <make>digital.$(type)_demod( samples_per_symbol=$samples_per_symbol, excess_bw=$excess_bw, + freq_bw=$freq_bw, phase_bw=$phase_bw, timing_bw=$timing_bw, gray_coded=$gray_coded, @@ -67,6 +68,12 @@ <type>real</type> </param> <param> + <name>FLL Bandwidth</name> + <key>freq_bw</key> + <value>6.28/100.0</value> + <type>real</type> + </param> + <param> <name>Phase Loop Bandwidth</name> <key>phase_bw</key> <value>6.28/100.0</value> diff --git a/gr-digital/include/CMakeLists.txt b/gr-digital/include/CMakeLists.txt index cf20bd1e7..81ed8d368 100644 --- a/gr-digital/include/CMakeLists.txt +++ b/gr-digital/include/CMakeLists.txt @@ -22,6 +22,7 @@ ######################################################################## install(FILES digital_api.h + digital_impl_mpsk_snr_est.h digital_binary_slicer_fb.h digital_clock_recovery_mm_cc.h digital_clock_recovery_mm_ff.h @@ -37,12 +38,14 @@ install(FILES digital_kurtotic_equalizer_cc.h digital_metric_type.h digital_mpsk_receiver_cc.h + digital_mpsk_snr_est_cc.h digital_ofdm_cyclic_prefixer.h digital_ofdm_frame_acquisition.h digital_ofdm_frame_sink.h digital_ofdm_insert_preamble.h digital_ofdm_mapper_bcv.h digital_ofdm_sampler.h + digital_probe_mpsk_snr_est_c.h digital_gmskmod_bc.h digital_cpmmod_bc.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio diff --git a/gr-digital/include/Makefile.am b/gr-digital/include/Makefile.am index 8ce3a94e8..3cf186d3d 100644 --- a/gr-digital/include/Makefile.am +++ b/gr-digital/include/Makefile.am @@ -24,6 +24,7 @@ include $(top_srcdir)/Makefile.common # These headers get installed in ${prefix}/include/gnuradio grinclude_HEADERS = \ digital_api.h \ + digital_impl_mpsk_snr_est.h \ digital_binary_slicer_fb.h \ digital_clock_recovery_mm_cc.h \ digital_clock_recovery_mm_ff.h \ @@ -39,12 +40,14 @@ grinclude_HEADERS = \ digital_kurtotic_equalizer_cc.h \ digital_metric_type.h \ digital_mpsk_receiver_cc.h \ + digital_mpsk_snr_est_cc.h \ digital_ofdm_cyclic_prefixer.h \ digital_ofdm_frame_acquisition.h \ digital_ofdm_frame_sink.h \ digital_ofdm_insert_preamble.h \ digital_ofdm_mapper_bcv.h \ digital_ofdm_sampler.h \ + digital_probe_mpsk_snr_est_c.h \ digital_gmskmod_bc.h \ digital_cpmmod_bc.h diff --git a/gr-digital/include/digital_impl_mpsk_snr_est.h b/gr-digital/include/digital_impl_mpsk_snr_est.h new file mode 100644 index 000000000..df7dbadec --- /dev/null +++ b/gr-digital/include/digital_impl_mpsk_snr_est.h @@ -0,0 +1,279 @@ +/* -*- 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_DIGITAL_IMPL_MPSK_SNR_EST_H +#define INCLUDED_DIGITAL_IMPL_MPSK_SNR_EST_H + +#include <digital_api.h> +#include <gr_sync_block.h> + +//! Enum for the type of SNR estimator to select +/*! \ingroup snr_blk + * \anchor ref_snr_est_types + * + * Below are some ROUGH estimates of what values of SNR each of these + * types of estimators is good for. In general, these offer a + * trade-off between accuracy and performance. + * + * \li SNR_EST_SIMPLE: Simple estimator (>= 7 dB) + * \li SNR_EST_SKEW: Skewness-base est (>= 5 dB) + * \li SNR_EST_M2M4: 2nd & 4th moment est (>= 1 dB) + * \li SNR_EST_SVR: SVR-based est (>= 0dB) +*/ +enum snr_est_type_t { + SNR_EST_SIMPLE = 0, // Simple estimator (>= 7 dB) + SNR_EST_SKEW, // Skewness-base est (>= 5 dB) + SNR_EST_M2M4, // 2nd & 4th moment est (>= 1 dB) + SNR_EST_SVR // SVR-based est (>= 0dB) +}; + +/*! \brief A parent class for SNR estimators, specifically for M-PSK + * signals in AWGN channels. + * \ingroup snr_blk + */ +class DIGITAL_API digital_impl_mpsk_snr_est +{ + protected: + double d_alpha, d_beta; + + public: + /*! Constructor + * + * Parameters: + * \param alpha: the update rate of internal running average + * calculations. + */ + digital_impl_mpsk_snr_est(double alpha); + virtual ~digital_impl_mpsk_snr_est(); + + //! Get the running-average coefficient + double alpha() const; + + //! Set the running-average coefficient + void set_alpha(double alpha); + + //! Update the current registers + virtual int update(int noutput_items, + const gr_complex *in); + + //! Use the register values to compute a new estimate + virtual double snr(); +}; + + +//! \brief SNR Estimator using simple mean/variance estimates. +/*! \ingroup snr_blk + * + * A very simple SNR estimator that just uses mean and variance + * estimates of an M-PSK constellation. This esimator is quick and + * cheap and accurate for high SNR (above 7 dB or so) but quickly + * starts to overestimate the SNR at low SNR. + */ +class DIGITAL_API digital_impl_mpsk_snr_est_simple : + public digital_impl_mpsk_snr_est +{ + private: + double d_y1, d_y2; + + public: + /*! Constructor + * + * Parameters: + * \param alpha: the update rate of internal running average + * calculations. + */ + digital_impl_mpsk_snr_est_simple(double alpha); + ~digital_impl_mpsk_snr_est_simple() {} + + int update(int noutput_items, + const gr_complex *in); + double snr(); +}; + + +//! \brief SNR Estimator using skewness correction. +/*! \ingroup snr_blk + * + * This is an estimator that came from a discussion between Tom + * Rondeau and fred harris with no known paper reference. The idea is + * that at low SNR, the variance estimations will be affected because + * of fold-over around the decision boundaries, which results in a + * skewness to the samples. We estimate the skewness and use this as + * a correcting term. + */ +class DIGITAL_API digital_impl_mpsk_snr_est_skew : + public digital_impl_mpsk_snr_est +{ + private: + double d_y1, d_y2, d_y3; + + public: + /*! Constructor + * + * Parameters: + * \param alpha: the update rate of internal running average + * calculations. + */ + digital_impl_mpsk_snr_est_skew(double alpha); + ~digital_impl_mpsk_snr_est_skew() {} + + int update(int noutput_items, + const gr_complex *in); + double snr(); +}; + + +//! \brief SNR Estimator using 2nd and 4th-order moments. +/*! \ingroup snr_blk + * + * An SNR estimator for M-PSK signals that uses 2nd (M2) and 4th (M4) + * order moments. This estimator uses knowledge of the kurtosis of + * the signal (k_a) and noise (k_w) to make its estimation. We use + * Beaulieu's approximations here to M-PSK signals and AWGN channels + * such that k_a=1 and k_w=2. These approximations significantly + * reduce the complexity of the calculations (and computations) + * required. + * + * Reference: + * D. R. Pauluzzi and N. C. Beaulieu, "A comparison of SNR + * estimation techniques for the AWGN channel," IEEE + * Trans. Communications, Vol. 48, No. 10, pp. 1681-1691, 2000. + */ +class DIGITAL_API digital_impl_mpsk_snr_est_m2m4 : + public digital_impl_mpsk_snr_est +{ + private: + double d_y1, d_y2; + + public: + /*! Constructor + * + * Parameters: + * \param alpha: the update rate of internal running average + * calculations. + */ + digital_impl_mpsk_snr_est_m2m4(double alpha); + ~digital_impl_mpsk_snr_est_m2m4() {} + + int update(int noutput_items, + const gr_complex *in); + double snr(); +}; + + +//! \brief SNR Estimator using 2nd and 4th-order moments. +/*! \ingroup snr_blk + * + * An SNR estimator for M-PSK signals that uses 2nd (M2) and 4th (M4) + * order moments. This estimator uses knowledge of the kurtosis of + * the signal (k_a) and noise (k_w) to make its estimation. In this + * case, you can set your own estimations for k_a and k_w, the + * kurtosis of the signal and noise, to fit this estimation better to + * your signal and channel conditions. + * + * A word of warning: this estimator has not been fully tested or + * proved with any amount of rigor. The estimation for M4 in + * particular might be ignoring effectf of when k_a and k_w are + * different. Use this estimator with caution and a copy of the + * reference on hand. + * + * The digital_mpsk_snr_est_m2m4 assumes k_a and k_w to simplify the + * computations for M-PSK and AWGN channels. Use that estimator + * unless you have a way to guess or estimate these values here. + * + * Original paper: + * R. Matzner, "An SNR estimation algorithm for complex baseband + * signal using higher order statistics," Facta Universitatis + * (Nis), no. 6, pp. 41-52, 1993. + * + * Reference used in derivation: + * D. R. Pauluzzi and N. C. Beaulieu, "A comparison of SNR + * estimation techniques for the AWGN channel," IEEE + * Trans. Communications, Vol. 48, No. 10, pp. 1681-1691, 2000. + */ +class DIGITAL_API digital_impl_snr_est_m2m4 : + public digital_impl_mpsk_snr_est +{ + private: + double d_y1, d_y2; + double d_ka, d_kw; + + public: + /*! Constructor + * + * Parameters: + * \param alpha: the update rate of internal running average + * calculations. + * \param ka: estimate of the signal kurtosis (1 for PSK) + * \param kw: estimate of the channel noise kurtosis (2 for AWGN) + */ + digital_impl_snr_est_m2m4(double alpha, double ka, double kw); + ~digital_impl_snr_est_m2m4() {} + + int update(int noutput_items, + const gr_complex *in); + double snr(); +}; + + +//! \brief Signal-to-Variation Ratio SNR Estimator. +/*! \ingroup snr_blk + * + * This estimator actually comes from an SNR estimator for M-PSK + * signals in fading channels, but this implementation is + * specifically for AWGN channels. The math was simplified to assume + * a signal and noise kurtosis (k_a and k_w) for M-PSK signals in + * AWGN. These approximations significantly reduce the complexity of + * the calculations (and computations) required. + * + * Original paper: + * A. L. Brandao, L. B. Lopes, and D. C. McLernon, "In-service + * monitoring of multipath delay and cochannel interference for + * indoor mobile communication systems," Proc. IEEE + * Int. Conf. Communications, vol. 3, pp. 1458-1462, May 1994. + * + * Reference: + * D. R. Pauluzzi and N. C. Beaulieu, "A comparison of SNR + * estimation techniques for the AWGN channel," IEEE + * Trans. Communications, Vol. 48, No. 10, pp. 1681-1691, 2000. + */ +class DIGITAL_API digital_impl_mpsk_snr_est_svr : + public digital_impl_mpsk_snr_est +{ + private: + double d_y1, d_y2; + + public: + /*! Constructor + * + * Parameters: + * \param alpha: the update rate of internal running average + * calculations. + */ + digital_impl_mpsk_snr_est_svr(double alpha); + ~digital_impl_mpsk_snr_est_svr() {} + + int update(int noutput_items, + const gr_complex *in); + double snr(); +}; + +#endif /* INCLUDED_DIGITAL_IMPL_MPSK_SNR_EST_H */ diff --git a/gr-digital/include/digital_mpsk_snr_est_cc.h b/gr-digital/include/digital_mpsk_snr_est_cc.h new file mode 100644 index 000000000..2cbd98bab --- /dev/null +++ b/gr-digital/include/digital_mpsk_snr_est_cc.h @@ -0,0 +1,115 @@ +/* -*- 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_DIGITAL_MPSK_SNR_EST_CC_H +#define INCLUDED_DIGITAL_MPSK_SNR_EST_CC_H + +#include <digital_api.h> +#include <gr_sync_block.h> +#include <digital_impl_mpsk_snr_est.h> + +class digital_mpsk_snr_est_cc; +typedef boost::shared_ptr<digital_mpsk_snr_est_cc> digital_mpsk_snr_est_cc_sptr; + +DIGITAL_API digital_mpsk_snr_est_cc_sptr +digital_make_mpsk_snr_est_cc(snr_est_type_t type, + int tag_nsamples=10000, + double alpha=0.001); + +//! \brief A block for computing SNR of a signal. +/*! \ingroup snr_blk + * + * This block can be used to monitor and retrieve estimations of the + * signal SNR. It is designed to work in a flowgraph and passes all + * incoming data along to its output. + * + * The block is designed for use with M-PSK signals especially. The + * type of estimator is specified as the \p type parameter in the + * constructor. The estimators tend to trade off performance for + * accuracy, although experimentation should be done to figure out + * the right approach for a given implementation. Further, the + * current set of estimators are designed and proven theoretically + * under AWGN conditions; some amount of error should be assumed + * and/or estimated for real channel conditions. + */ +class DIGITAL_API digital_mpsk_snr_est_cc : public gr_sync_block +{ + private: + snr_est_type_t d_type; + int d_nsamples, d_count; + double d_alpha; + digital_impl_mpsk_snr_est *d_snr_est; + + //d_key is the tag name, 'snr', d_me is the block name + unique ID + pmt::pmt_t d_key, d_me; + + /*! Factory function returning shared pointer of this class + * + * Parameters: + * + * \param type: the type of estimator to use \ref ref_snr_est_types + * "snr_est_type_t" for details about the available types. + * \param tag_nsamples: after this many samples, a tag containing + * the SNR (key='snr') will be sent + * \param alpha: the update rate of internal running average + * calculations. + */ + friend DIGITAL_API digital_mpsk_snr_est_cc_sptr + digital_make_mpsk_snr_est_cc(snr_est_type_t type, + int tag_nsamples, + double alpha); + + // Private constructor + digital_mpsk_snr_est_cc(snr_est_type_t type, + int tag_nsamples, + double alpha); + +public: + + ~digital_mpsk_snr_est_cc(); + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + //! Return the estimated signal-to-noise ratio in decibels + double snr(); + + //! Return the type of estimator in use + snr_est_type_t type() const; + + //! Return how many samples between SNR tags + int tag_nsample() const; + + //! Get the running-average coefficient + double alpha() const; + + //! Set type of estimator to use + void set_type(snr_est_type_t t); + + //! Set the number of samples between SNR tags + void set_tag_nsample(int n); + + //! Set the running-average coefficient + void set_alpha(double alpha); +}; + +#endif /* INCLUDED_DIGITAL_MPSK_SNR_EST_CC_H */ diff --git a/gr-digital/include/digital_probe_mpsk_snr_est_c.h b/gr-digital/include/digital_probe_mpsk_snr_est_c.h new file mode 100644 index 000000000..a78e90412 --- /dev/null +++ b/gr-digital/include/digital_probe_mpsk_snr_est_c.h @@ -0,0 +1,113 @@ +/* -*- 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_DIGITAL_PROBE_MPSK_SNR_EST_C_H +#define INCLUDED_DIGITAL_PROBE_MPSK_SNR_EST_C_H + +#include <digital_api.h> +#include <gr_sync_block.h> +#include <digital_impl_mpsk_snr_est.h> + +class digital_probe_mpsk_snr_est_c; +typedef boost::shared_ptr<digital_probe_mpsk_snr_est_c> digital_probe_mpsk_snr_est_c_sptr; + +DIGITAL_API digital_probe_mpsk_snr_est_c_sptr +digital_make_probe_mpsk_snr_est_c(snr_est_type_t type, + int msg_nsamples=10000, + double alpha=0.001); + +//! \brief A probe for computing SNR of a signal. +/*! \ingroup snr_blk + * + * This is a probe block (a sink) that can be used to monitor and + * retrieve estimations of the signal SNR. This probe is designed for + * use with M-PSK signals especially. The type of estimator is + * specified as the \p type parameter in the constructor. The + * estimators tend to trade off performance for accuracy, although + * experimentation should be done to figure out the right approach + * for a given implementation. Further, the current set of estimators + * are designed and proven theoretically under AWGN conditions; some + * amount of error should be assumed and/or estimated for real + * channel conditions. + */ +class DIGITAL_API digital_probe_mpsk_snr_est_c : public gr_sync_block +{ + private: + snr_est_type_t d_type; + int d_nsamples, d_count; + double d_alpha; + digital_impl_mpsk_snr_est *d_snr_est; + + //d_key is the message name, 'snr' + pmt::pmt_t d_key; + + /*! Factory function returning shared pointer of this class + * + * Parameters: + * + * \param type: the type of estimator to use \ref ref_snr_est_types + * "snr_est_type_t" for details about the available types. + * \param msg_nsamples: [not implemented yet] after this many + * samples, a message containing the SNR (key='snr') will be sent + * \param alpha: the update rate of internal running average + * calculations. + */ + friend DIGITAL_API digital_probe_mpsk_snr_est_c_sptr + digital_make_probe_mpsk_snr_est_c(snr_est_type_t type, + int msg_nsamples, + double alpha); + + //! Private constructor + digital_probe_mpsk_snr_est_c(snr_est_type_t type, + int msg_nsamples, + double alpha); + +public: + + ~digital_probe_mpsk_snr_est_c(); + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + //! Return the estimated signal-to-noise ratio in decibels + double snr(); + + //! Return the type of estimator in use + snr_est_type_t type() const; + + //! Return how many samples between SNR messages + int msg_nsample() const; + + //! Get the running-average coefficient + double alpha() const; + + //! Set type of estimator to use + void set_type(snr_est_type_t t); + + //! Set the number of samples between SNR messages + void set_msg_nsample(int n); + + //! Set the running-average coefficient + void set_alpha(double alpha); +}; + +#endif /* INCLUDED_DIGITAL_PROBE_MPSK_SNR_EST_C_H */ diff --git a/gr-digital/lib/CMakeLists.txt b/gr-digital/lib/CMakeLists.txt index b90757111..779972ff3 100644 --- a/gr-digital/lib/CMakeLists.txt +++ b/gr-digital/lib/CMakeLists.txt @@ -32,6 +32,7 @@ link_directories(${Boost_LIBRARY_DIRS}) # Setup library ######################################################################## list(APPEND gr_digital_sources + digital_impl_mpsk_snr_est.cc digital_binary_slicer_fb.cc digital_clock_recovery_mm_cc.cc digital_clock_recovery_mm_ff.cc @@ -46,12 +47,14 @@ list(APPEND gr_digital_sources digital_lms_dd_equalizer_cc.cc digital_kurtotic_equalizer_cc.cc digital_mpsk_receiver_cc.cc + digital_mpsk_snr_est_cc.cc digital_ofdm_cyclic_prefixer.cc digital_ofdm_frame_acquisition.cc digital_ofdm_frame_sink.cc digital_ofdm_insert_preamble.cc digital_ofdm_mapper_bcv.cc digital_ofdm_sampler.cc + digital_probe_mpsk_snr_est_c.cc digital_gmskmod_bc.cc digital_cpmmod_bc.cc ) diff --git a/gr-digital/lib/Makefile.am b/gr-digital/lib/Makefile.am index 2860974ca..d5ad199e3 100644 --- a/gr-digital/lib/Makefile.am +++ b/gr-digital/lib/Makefile.am @@ -27,6 +27,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) \ lib_LTLIBRARIES = libgnuradio-digital.la libgnuradio_digital_la_SOURCES = \ + digital_impl_mpsk_snr_est.cc \ digital_binary_slicer_fb.cc \ digital_clock_recovery_mm_cc.cc \ digital_clock_recovery_mm_ff.cc \ @@ -41,12 +42,14 @@ libgnuradio_digital_la_SOURCES = \ digital_lms_dd_equalizer_cc.cc \ digital_kurtotic_equalizer_cc.cc \ digital_mpsk_receiver_cc.cc \ + digital_mpsk_snr_est_cc.cc \ digital_ofdm_cyclic_prefixer.cc \ digital_ofdm_frame_acquisition.cc \ digital_ofdm_frame_sink.cc \ digital_ofdm_insert_preamble.cc \ digital_ofdm_mapper_bcv.cc \ digital_ofdm_sampler.cc \ + digital_probe_mpsk_snr_est_c.cc \ digital_gmskmod_bc.cc \ digital_cpmmod_bc.cc diff --git a/gr-digital/lib/digital_constellation.cc b/gr-digital/lib/digital_constellation.cc index 0c100f38e..d9a53c493 100644 --- a/gr-digital/lib/digital_constellation.cc +++ b/gr-digital/lib/digital_constellation.cc @@ -357,10 +357,8 @@ digital_constellation_psk::get_sector (const gr_complex *sample) float phase = arg(*sample); float width = M_TWOPI / n_sectors; int sector = floor(phase/width + 0.5); - unsigned int u_sector; if (sector < 0) sector += n_sectors; - u_sector = sector; return sector; } diff --git a/gr-digital/lib/digital_impl_mpsk_snr_est.cc b/gr-digital/lib/digital_impl_mpsk_snr_est.cc new file mode 100644 index 000000000..38177083f --- /dev/null +++ b/gr-digital/lib/digital_impl_mpsk_snr_est.cc @@ -0,0 +1,256 @@ +/* -*- 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 <digital_impl_mpsk_snr_est.h> +#include <cstdio> + +digital_impl_mpsk_snr_est::digital_impl_mpsk_snr_est(double alpha) +{ + set_alpha(alpha); +} + +digital_impl_mpsk_snr_est::~digital_impl_mpsk_snr_est() +{} + +void +digital_impl_mpsk_snr_est::set_alpha(double alpha) +{ + d_alpha = alpha; + d_beta = 1.0-alpha; +} + +double +digital_impl_mpsk_snr_est::alpha() const +{ + return d_alpha; +} + +int +digital_impl_mpsk_snr_est::update(int noutput_items, + const gr_complex *in) +{ + throw std::runtime_error("digital_impl_mpsk_snr_est: Unimplemented"); +} + +double +digital_impl_mpsk_snr_est::snr() +{ + throw std::runtime_error("digital_impl_mpsk_snr_est: Unimplemented"); +} + + +/********************************************************************/ + + +digital_impl_mpsk_snr_est_simple::digital_impl_mpsk_snr_est_simple( + double alpha) : + digital_impl_mpsk_snr_est(alpha) +{ + d_y1 = 0; + d_y2 = 0; +} + +int +digital_impl_mpsk_snr_est_simple::update( + int noutput_items, + const gr_complex *in) +{ + for (int i = 0; i < noutput_items; i++){ + double y1 = abs(in[i]); + d_y1 = d_alpha*y1 + d_beta*d_y1; + + double y2 = real(in[i]*in[i]); + d_y2 = d_alpha*y2 + d_beta*d_y2; + } + return noutput_items; +} + +double +digital_impl_mpsk_snr_est_simple::snr() +{ + double y1_2 = d_y1*d_y1; + double y3 = y1_2 - d_y2 + 1e-20; + return 10.0*log10(y1_2/y3); +} + + +/********************************************************************/ + + +digital_impl_mpsk_snr_est_skew::digital_impl_mpsk_snr_est_skew( + double alpha) : + digital_impl_mpsk_snr_est(alpha) +{ + d_y1 = 0; + d_y2 = 0; + d_y3 = 0; +} + + +int +digital_impl_mpsk_snr_est_skew::update( + int noutput_items, + const gr_complex *in) +{ + for (int i = 0; i < noutput_items; i++){ + double y1 = abs(in[i]); + d_y1 = d_alpha*y1 + d_beta*d_y1; + + double y2 = real(in[i]*in[i]); + d_y2 = d_alpha*y2 + d_beta*d_y2; + + // online algorithm for calculating skewness + // See: + // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Higher-order_statistics + double d = abs(in[i]) - d_y1; + double d_i = d / (i+1); + double y3 = (d*d_i*i)*d_i*(i-1) - 3.0*d_i*d_y2; + d_y3 = d_alpha*y3 + d_beta*d_y3; + } + return noutput_items; +} + +double +digital_impl_mpsk_snr_est_skew::snr() +{ + double y3 = d_y3*d_y3 / (d_y2*d_y2*d_y2); + double y1_2 = d_y1*d_y1; + double x = y1_2 - d_y2; + return 10.0*log10(y1_2 / (x + y3*y1_2)); +} + + +/********************************************************************/ + + +digital_impl_mpsk_snr_est_m2m4::digital_impl_mpsk_snr_est_m2m4( + double alpha) : + digital_impl_mpsk_snr_est(alpha) +{ + d_y1 = 0; + d_y2 = 0; +} + +int +digital_impl_mpsk_snr_est_m2m4::update( + int noutput_items, + const gr_complex *in) +{ + for (int i = 0; i < noutput_items; i++){ + double y1 = abs(in[i])*abs(in[i]); + d_y1 = d_alpha*y1 + d_beta*d_y1; + + double y2 = abs(in[i])*abs(in[i])*abs(in[i])*abs(in[i]); + d_y2 = d_alpha*y2 + d_beta*d_y2; + } + return noutput_items; +} + +double +digital_impl_mpsk_snr_est_m2m4::snr() +{ + double y1_2 = d_y1*d_y1; + return 10.0*log10(2.0*sqrt(2*y1_2 - d_y2) / + (d_y1 - sqrt(2*y1_2 - d_y2))); +} + + +/********************************************************************/ + + +digital_impl_snr_est_m2m4::digital_impl_snr_est_m2m4( + double alpha, double ka, double kw) : + digital_impl_mpsk_snr_est(alpha) +{ + d_y1 = 0; + d_y2 = 0; + d_ka = ka; + d_kw = kw; +} + +int +digital_impl_snr_est_m2m4::update( + int noutput_items, + const gr_complex *in) +{ + for (int i = 0; i < noutput_items; i++) { + double y1 = abs(in[i])*abs(in[i]); + d_y1 = d_alpha*y1 + d_beta*d_y1; + + double y2 = abs(in[i])*abs(in[i])*abs(in[i])*abs(in[i]); + d_y2 = d_alpha*y2 + d_beta*d_y2; + } + return noutput_items; +} + +double +digital_impl_snr_est_m2m4::snr() +{ + double M2 = d_y1; + double M4 = d_y2; + double s = M2*(d_kw - 2) + + sqrt((4.0-d_ka*d_kw)*M2*M2 + M4*(d_ka+d_kw-4.0)) / + (d_ka + d_kw - 4.0); + double n = M2 - s; + + return 10.0*log10(s / n); +} + + +/********************************************************************/ + + +digital_impl_mpsk_snr_est_svr::digital_impl_mpsk_snr_est_svr( + double alpha) : + digital_impl_mpsk_snr_est(alpha) +{ + d_y1 = 0; + d_y2 = 0; +} + +int +digital_impl_mpsk_snr_est_svr::update( + int noutput_items, + const gr_complex *in) +{ + for (int i = 0; i < noutput_items; i++){ + double x = abs(in[i]); + double x1 = abs(in[i-1]); + double y1 = (x*x)*(x1*x1); + d_y1 = d_alpha*y1 + d_beta*d_y1; + + double y2 = x*x*x*x; + d_y2 = d_alpha*y2 + d_beta*d_y2; + } + return noutput_items; +} + +double +digital_impl_mpsk_snr_est_svr::snr() +{ + double x = d_y1 / (d_y2 - d_y1); + return 10.0*log10(2.*((x-1) + sqrt(x*(x-1)))); +} diff --git a/gr-digital/lib/digital_mpsk_snr_est_cc.cc b/gr-digital/lib/digital_mpsk_snr_est_cc.cc new file mode 100644 index 000000000..b5a60f0d3 --- /dev/null +++ b/gr-digital/lib/digital_mpsk_snr_est_cc.cc @@ -0,0 +1,186 @@ +/* -*- 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 <digital_mpsk_snr_est_cc.h> +#include <gr_io_signature.h> +#include <cstdio> + +digital_mpsk_snr_est_cc_sptr +digital_make_mpsk_snr_est_cc(snr_est_type_t type, + int tag_nsamples, + double alpha) +{ + return gnuradio::get_initial_sptr(new digital_mpsk_snr_est_cc( + type, tag_nsamples, alpha)); +} + +digital_mpsk_snr_est_cc::digital_mpsk_snr_est_cc(snr_est_type_t type, + int tag_nsamples, + double alpha) + : gr_sync_block ("mpsk_snr_est_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex))) +{ + d_snr_est = NULL; + + d_type = type; + d_nsamples = tag_nsamples; + d_count = 0; + set_alpha(alpha); + + set_type(type); + + // at least 1 estimator has to look back + set_history(2); + + std::stringstream str; + str << name() << unique_id(); + d_me = pmt::pmt_string_to_symbol(str.str()); + d_key = pmt::pmt_string_to_symbol("snr"); +} + +digital_mpsk_snr_est_cc::~digital_mpsk_snr_est_cc() +{ + if(d_snr_est) + delete d_snr_est; +} + +int +digital_mpsk_snr_est_cc::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + // This is a pass-through block; copy input to output + memcpy(output_items[0], input_items[0], + noutput_items * sizeof(gr_complex)); + + const gr_complex *in = (const gr_complex*)input_items[0]; + + // Update, calculate, and issue an SNR tag every d_nsamples + int index = 0, x = 0; + int64_t nwritten = nitems_written(0); + while(index + (d_nsamples-d_count) <= noutput_items) { + x = d_nsamples - d_count; + nwritten += x; + + // Update the SNR estimate registers from the current input + d_snr_est->update(x, &in[index]); + + // Issue a tag with the SNR data + pmt::pmt_t pmt_snr = pmt::pmt_from_double(d_snr_est->snr()); + add_item_tag(0, // stream ID + nwritten, // tag's sample number + d_key, // snr key + pmt_snr, // SNR + d_me); // block src id + + index += x; + d_count = 0; + } + + // Keep track of remaining items and update estimators + x = noutput_items - index; + d_count += x; + d_snr_est->update(x, &in[index]); + + return noutput_items; +} + +double +digital_mpsk_snr_est_cc::snr() +{ + if(d_snr_est) + return d_snr_est->snr(); + else + throw std::runtime_error("digital_mpsk_snr_est_cc:: No SNR estimator defined.\n"); +} + +snr_est_type_t +digital_mpsk_snr_est_cc::type() const +{ + return d_type; +} + +int +digital_mpsk_snr_est_cc::tag_nsample() const +{ + return d_nsamples; +} + +double +digital_mpsk_snr_est_cc::alpha() const +{ + return d_alpha; +} + +void +digital_mpsk_snr_est_cc::set_type(snr_est_type_t t) +{ + d_type = t; + + if(d_snr_est) + delete d_snr_est; + + switch (d_type) { + case(SNR_EST_SIMPLE): + d_snr_est = new digital_impl_mpsk_snr_est_simple(d_alpha); + break; + case(SNR_EST_SKEW): + d_snr_est = new digital_impl_mpsk_snr_est_skew(d_alpha); + break; + case(SNR_EST_M2M4): + d_snr_est = new digital_impl_mpsk_snr_est_m2m4(d_alpha); + break; + case(SNR_EST_SVR): + d_snr_est = new digital_impl_mpsk_snr_est_svr(d_alpha); + break; + default: + throw std::invalid_argument("digital_mpsk_snr_est_cc: unknown type specified.\n"); + } +} + +void +digital_mpsk_snr_est_cc::set_tag_nsample(int n) +{ + if(n > 0) { + d_nsamples = n; + d_count = 0; // reset state + } + else + throw std::invalid_argument("digital_mpsk_snr_est_cc: tag_nsamples can't be <= 0\n"); +} + +void +digital_mpsk_snr_est_cc::set_alpha(double alpha) +{ + if((alpha >= 0) && (alpha <= 1.0)) { + d_alpha = alpha; + if(d_snr_est) + d_snr_est->set_alpha(d_alpha); + } + else + throw std::invalid_argument("digital_mpsk_snr_est_cc: alpha must be in [0,1]\n"); +} diff --git a/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc b/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc new file mode 100644 index 000000000..5cdfea96d --- /dev/null +++ b/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc @@ -0,0 +1,152 @@ +/* -*- 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 <digital_probe_mpsk_snr_est_c.h> +#include <gr_io_signature.h> +#include <cstdio> + +digital_probe_mpsk_snr_est_c_sptr +digital_make_probe_mpsk_snr_est_c(snr_est_type_t type, + int msg_nsamples, + double alpha) +{ + return gnuradio::get_initial_sptr( + new digital_probe_mpsk_snr_est_c(type, msg_nsamples, alpha)); +} + +digital_probe_mpsk_snr_est_c::digital_probe_mpsk_snr_est_c( + snr_est_type_t type, + int msg_nsamples, + double alpha) + : gr_sync_block ("probe_mpsk_snr_est_c", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(0, 0, 0)) +{ + d_snr_est = NULL; + + d_type = type; + d_nsamples = msg_nsamples; + d_count = 0; + set_alpha(alpha); + + set_type(type); + + // at least 1 estimator has to look back + set_history(2); + + d_key = pmt::pmt_string_to_symbol("snr"); +} + +digital_probe_mpsk_snr_est_c::~digital_probe_mpsk_snr_est_c() +{ + if(d_snr_est) + delete d_snr_est; +} + +int +digital_probe_mpsk_snr_est_c::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]; + return d_snr_est->update(noutput_items, in); +} + +double +digital_probe_mpsk_snr_est_c::snr() +{ + if(d_snr_est) + return d_snr_est->snr(); + else + throw std::runtime_error("digital_probe_mpsk_snr_est_c:: No SNR estimator defined.\n"); +} + +snr_est_type_t +digital_probe_mpsk_snr_est_c::type() const +{ + return d_type; +} + +int +digital_probe_mpsk_snr_est_c::msg_nsample() const +{ + return d_nsamples; +} + +double +digital_probe_mpsk_snr_est_c::alpha() const +{ + return d_alpha; +} + +void +digital_probe_mpsk_snr_est_c::set_type(snr_est_type_t t) +{ + d_type = t; + + if(d_snr_est) + delete d_snr_est; + + switch (d_type) { + case(SNR_EST_SIMPLE): + d_snr_est = new digital_impl_mpsk_snr_est_simple(d_alpha); + break; + case(SNR_EST_SKEW): + d_snr_est = new digital_impl_mpsk_snr_est_skew(d_alpha); + break; + case(SNR_EST_M2M4): + d_snr_est = new digital_impl_mpsk_snr_est_m2m4(d_alpha); + break; + case(SNR_EST_SVR): + d_snr_est = new digital_impl_mpsk_snr_est_svr(d_alpha); + break; + default: + throw std::invalid_argument("digital_probe_mpsk_snr_est_c: unknown type specified.\n"); + } +} + +void +digital_probe_mpsk_snr_est_c::set_msg_nsample(int n) +{ + if(n > 0) { + d_nsamples = n; + d_count = 0; // reset state + } + else + throw std::invalid_argument("digital_probe_mpsk_snr_est_c: msg_nsamples can't be <= 0\n"); +} + +void +digital_probe_mpsk_snr_est_c::set_alpha(double alpha) +{ + if((alpha >= 0) && (alpha <= 1.0)) { + d_alpha = alpha; + if(d_snr_est) + d_snr_est->set_alpha(d_alpha); + } + else + throw std::invalid_argument("digital_probe_mpsk_snr_est_c: alpha must be in [0,1]\n"); +} diff --git a/gr-digital/python/Makefile.am b/gr-digital/python/Makefile.am index ead6f7dfd..42bcc4dd2 100644 --- a/gr-digital/python/Makefile.am +++ b/gr-digital/python/Makefile.am @@ -45,6 +45,7 @@ noinst_PYTHON = \ qa_fll_band_edge.py \ qa_lms_equalizer.py \ qa_mpsk_receiver.py \ + qa_mpsk_snr_est.py \ qa_ofdm_insert_preamble.py digital_PYTHON = \ diff --git a/gr-digital/python/qa_fll_band_edge.py b/gr-digital/python/qa_fll_band_edge.py index 088eb2b68..7d89bc9ea 100755 --- a/gr-digital/python/qa_fll_band_edge.py +++ b/gr-digital/python/qa_fll_band_edge.py @@ -46,6 +46,7 @@ class test_fll_band_edge_cc(gr_unittest.TestCase): foffset = 0.2 / (2.0*math.pi) # Create a set of 1's and -1's, pulse shape and interpolate to sps + random.seed(0) data = [2.0*random.randint(0, 2) - 1.0 for i in xrange(200)] self.src = gr.vector_source_c(data, False) self.rrc = gr.interp_fir_filter_ccf(sps, rrc_taps) diff --git a/gr-digital/python/qa_mpsk_snr_est.py b/gr-digital/python/qa_mpsk_snr_est.py new file mode 100755 index 000000000..d392567bf --- /dev/null +++ b/gr-digital/python/qa_mpsk_snr_est.py @@ -0,0 +1,126 @@ +#!/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 +import digital_swig as digital +import math, random + +def get_cplx(): + return complex(2*random.randint(0,1) - 1, 0) +def get_n_cplx(): + return complex(random.random()-0.5, random.random()-0.5) + +class test_mpsk_snr_est (gr_unittest.TestCase): + def setUp (self): + self.tb = gr.top_block () + + random.seed(0) # make repeatable + N = 10000 + self._noise = [get_n_cplx() for i in xrange(N)] + self._bits = [get_cplx() for i in xrange(N)] + + def tearDown (self): + self.tb = None + + def mpsk_snr_est_setup (self, op): + result = [] + for i in xrange(1,6): + src_data = [b+(i*n) for b,n in zip(self._bits, self._noise)] + + src = gr.vector_source_c (src_data) + dst = gr.null_sink (gr.sizeof_gr_complex) + + tb = gr.top_block () + tb.connect (src, op) + tb.connect (op, dst) + tb.run () # run the graph and wait for it to finish + + result.append(op.snr()) + return result + + def test_mpsk_snr_est_simple (self): + expected_result = [11.48, 5.91, 3.30, 2.08, 1.46] + + N = 10000 + alpha = 0.001 + op = digital.mpsk_snr_est_cc (digital.SNR_EST_SIMPLE, N, alpha) + + actual_result = self.mpsk_snr_est_setup(op) + self.assertFloatTuplesAlmostEqual (expected_result, actual_result, 2) + + def test_mpsk_snr_est_skew (self): + expected_result = [11.48, 5.91, 3.30, 2.08, 1.46] + + N = 10000 + alpha = 0.001 + op = digital.mpsk_snr_est_cc (digital.SNR_EST_SKEW, N, alpha) + + actual_result = self.mpsk_snr_est_setup(op) + self.assertFloatTuplesAlmostEqual (expected_result, actual_result, 2) + + def test_mpsk_snr_est_m2m4 (self): + expected_result = [11.02, 6.20, 4.98, 5.16, 5.66] + + N = 10000 + alpha = 0.001 + op = digital.mpsk_snr_est_cc (digital.SNR_EST_M2M4, N, alpha) + + actual_result = self.mpsk_snr_est_setup(op) + self.assertFloatTuplesAlmostEqual (expected_result, actual_result, 2) + + def test_mpsk_snr_est_svn (self): + expected_result = [10.90, 6.00, 4.76, 4.97, 5.49] + + N = 10000 + alpha = 0.001 + op = digital.mpsk_snr_est_cc (digital.SNR_EST_SVR, N, alpha) + + actual_result = self.mpsk_snr_est_setup(op) + self.assertFloatTuplesAlmostEqual (expected_result, actual_result, 2) + + def test_probe_mpsk_snr_est_m2m4 (self): + expected_result = [11.02, 6.20, 4.98, 5.16, 5.66] + + actual_result = [] + for i in xrange(1,6): + src_data = [b+(i*n) for b,n in zip(self._bits, self._noise)] + + src = gr.vector_source_c (src_data) + + N = 10000 + alpha = 0.001 + op = digital.probe_mpsk_snr_est_c (digital.SNR_EST_M2M4, N, alpha) + + tb = gr.top_block () + tb.connect (src, op) + tb.run () # run the graph and wait for it to finish + + actual_result.append(op.snr()) + self.assertFloatTuplesAlmostEqual (expected_result, actual_result, 2) + + +if __name__ == '__main__': + # Test various SNR estimators; we're not using a Gaussian + # noise source, so these estimates have no real meaning; + # just a sanity check. + gr_unittest.run(test_mpsk_snr_est, "test_mpsk_snr_est.xml") + diff --git a/gr-digital/swig/CMakeLists.txt b/gr-digital/swig/CMakeLists.txt index dd6097286..6f2c2251a 100644 --- a/gr-digital/swig/CMakeLists.txt +++ b/gr-digital/swig/CMakeLists.txt @@ -59,12 +59,14 @@ install( digital_lms_dd_equalizer_cc.i digital_kurtotic_equalizer_cc.i digital_mpsk_receiver_cc.i + digital_mpsk_snr_est_cc.i digital_ofdm_cyclic_prefixer.i digital_ofdm_frame_acquisition.i digital_ofdm_frame_sink.i digital_ofdm_insert_preamble.i digital_ofdm_mapper_bcv.i digital_ofdm_sampler.i + digital_probe_mpsk_snr_est_c.i digital_gmskmod_bc.i digital_cpmmod_bc.i DESTINATION ${GR_INCLUDE_DIR}/gnuradio/swig diff --git a/gr-digital/swig/Makefile.am b/gr-digital/swig/Makefile.am index 8591c8d74..97b47fafa 100644 --- a/gr-digital/swig/Makefile.am +++ b/gr-digital/swig/Makefile.am @@ -84,12 +84,14 @@ digital_swig_swiginclude_headers = \ digital_lms_dd_equalizer_cc.i \ digital_kurtotic_equalizer_cc.i \ digital_mpsk_receiver_cc.i \ + digital_mpsk_snr_est_cc.i \ digital_ofdm_cyclic_prefixer.i \ digital_ofdm_frame_acquisition.i \ digital_ofdm_frame_sink.i \ digital_ofdm_insert_preamble.i \ digital_ofdm_mapper_bcv.i \ digital_ofdm_sampler.i \ + digital_probe_mpsk_snr_est_c.i \ digital_gmskmod_bc.i \ digital_cpmmod_bc.i \ $(TOP_SWIG_DOC_IFILES) diff --git a/gr-digital/swig/digital_mpsk_snr_est_cc.i b/gr-digital/swig/digital_mpsk_snr_est_cc.i new file mode 100644 index 000000000..f0ca13f87 --- /dev/null +++ b/gr-digital/swig/digital_mpsk_snr_est_cc.i @@ -0,0 +1,45 @@ +/* -*- 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(digital,mpsk_snr_est_cc); + +digital_mpsk_snr_est_cc_sptr +digital_make_mpsk_snr_est_cc(snr_est_type_t type, + int tag_nsamples=10000, + double alpha=0.001); + +class digital_mpsk_snr_est_cc : public gr_sync_block +{ +private: + void digital_mpsk_snr_est_cc(snr_est_type_t type, + int tag_nsamples, + double alpha); + +public: + double snr(); + snr_est_type_t type() const; + int tag_nsample() const; + double alpha() const; + void set_type(snr_est_type_t t); + void set_tag_nsample(int n); + void set_alpha(double alpha); +}; diff --git a/gr-digital/swig/digital_probe_mpsk_snr_est_c.i b/gr-digital/swig/digital_probe_mpsk_snr_est_c.i new file mode 100644 index 000000000..93db4127a --- /dev/null +++ b/gr-digital/swig/digital_probe_mpsk_snr_est_c.i @@ -0,0 +1,45 @@ +/* -*- 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(digital,probe_mpsk_snr_est_c); + +digital_probe_mpsk_snr_est_c_sptr +digital_make_probe_mpsk_snr_est_c(snr_est_type_t type, + int msg_nsamples=10000, + double alpha=0.001); + +class digital_probe_mpsk_snr_est_c : public gr_sync_block +{ +private: + void digital_probe_mpsk_snr_est_c(snr_est_type_t type, + int msg_nsamples, + double alpha); + +public: + double snr(); + snr_est_type_t type() const; + int msg_nsample() const; + double alpha() const; + void set_type(snr_est_type_t t); + void set_msg_nsample(int n); + void set_alpha(double alpha); +}; diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i index 86b5cab13..a39ef9ab7 100644 --- a/gr-digital/swig/digital_swig.i +++ b/gr-digital/swig/digital_swig.i @@ -24,6 +24,15 @@ //load generated python docstrings %include "digital_swig_doc.i" +#if SWIGPYTHON +enum snr_est_type_t { + SNR_EST_SIMPLE = 0, // Simple estimator (>= 7 dB) + SNR_EST_SKEW, // Skewness-base est (>= 5 dB) + SNR_EST_M2M4, // 2nd & 4th moment est (>= 1 dB) + SNR_EST_SVR // SVR-based est (>= 0dB) +}; +#endif + %include <gri_control_loop.i> %{ @@ -41,12 +50,14 @@ #include "digital_kurtotic_equalizer_cc.h" #include "digital_lms_dd_equalizer_cc.h" #include "digital_mpsk_receiver_cc.h" +#include "digital_mpsk_snr_est_cc.h" #include "digital_ofdm_cyclic_prefixer.h" #include "digital_ofdm_frame_acquisition.h" #include "digital_ofdm_frame_sink.h" #include "digital_ofdm_insert_preamble.h" #include "digital_ofdm_mapper_bcv.h" #include "digital_ofdm_sampler.h" +#include "digital_probe_mpsk_snr_est_c.h" #include "digital_cpmmod_bc.h" #include "digital_gmskmod_bc.h" %} @@ -65,16 +76,26 @@ %include "digital_kurtotic_equalizer_cc.i" %include "digital_lms_dd_equalizer_cc.i" %include "digital_mpsk_receiver_cc.i" +%include "digital_mpsk_snr_est_cc.i" %include "digital_ofdm_cyclic_prefixer.i" %include "digital_ofdm_frame_acquisition.i" %include "digital_ofdm_frame_sink.i" %include "digital_ofdm_insert_preamble.i" %include "digital_ofdm_mapper_bcv.i" %include "digital_ofdm_sampler.i" +%include "digital_probe_mpsk_snr_est_c.i" %include "digital_cpmmod_bc.i" %include "digital_gmskmod_bc.i" #if SWIGGUILE + +enum snr_est_type_t { + SNR_EST_SIMPLE = 0, // Simple estimator (>= 7 dB) + SNR_EST_SKEW, // Skewness-base est (>= 5 dB) + SNR_EST_M2M4, // 2nd & 4th moment est (>= 1 dB) + SNR_EST_SVR // SVR-based est (>= 0dB) +}; + %scheme %{ (load-extension-global "libguile-gnuradio-digital_swig" "scm_init_gnuradio_digital_swig_module") %} diff --git a/gr-howto-write-a-block/config.guess b/gr-howto-write-a-block/config.guess index 8152efd67..49ba16f15 100755 --- a/gr-howto-write-a-block/config.guess +++ b/gr-howto-write-a-block/config.guess @@ -2,9 +2,9 @@ # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011 Free Software Foundation, Inc. +# 2011, 2012 Free Software Foundation, Inc. -timestamp='2011-11-11' +timestamp='2012-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -57,8 +57,8 @@ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free -Software Foundation, Inc. +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -145,7 +145,7 @@ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward @@ -897,16 +897,16 @@ EOF echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) - echo cris-axis-linux-gnu + echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; crisv32:Linux:*:*) - echo crisv32-axis-linux-gnu + echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; frv:Linux:*:*) - echo frv-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; hexagon:Linux:*:*) - echo hexagon-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu @@ -948,7 +948,7 @@ EOF test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) - echo or32-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu @@ -989,7 +989,7 @@ EOF echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) - echo x86_64-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu diff --git a/gr-howto-write-a-block/config.sub b/gr-howto-write-a-block/config.sub index e76eaf472..d6b6b3c76 100755 --- a/gr-howto-write-a-block/config.sub +++ b/gr-howto-write-a-block/config.sub @@ -2,9 +2,9 @@ # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011 Free Software Foundation, Inc. +# 2011, 2012 Free Software Foundation, Inc. -timestamp='2011-11-11' +timestamp='2012-01-01' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software @@ -76,8 +76,8 @@ version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free -Software Foundation, Inc. +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -320,7 +320,6 @@ case $basic_machine in basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | picochip) - # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; @@ -719,7 +718,6 @@ case $basic_machine in i370-ibm* | ibm*) basic_machine=i370-ibm ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 @@ -1559,9 +1557,6 @@ case $basic_machine in ;; m68000-sun) os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 ;; m68*-cisco) os=-aout diff --git a/gr-howto-write-a-block/version.sh b/gr-howto-write-a-block/version.sh index 4e4c7cc31..58ec712f6 100644 --- a/gr-howto-write-a-block/version.sh +++ b/gr-howto-write-a-block/version.sh @@ -1,4 +1,4 @@ MAJOR_VERSION=3 API_COMPAT=5 MINOR_VERSION=1 -MAINT_VERSION=git +MAINT_VERSION=0 diff --git a/gr-noaa/CMakeLists.txt b/gr-noaa/CMakeLists.txt index 621dd5d6e..a3a5d56db 100644 --- a/gr-noaa/CMakeLists.txt +++ b/gr-noaa/CMakeLists.txt @@ -84,4 +84,18 @@ if(ENABLE_PYTHON) add_subdirectory(apps) endif(ENABLE_PYTHON) +######################################################################## +# Create Pkg Config File +######################################################################## +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/gnuradio-noaa.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/gnuradio-noaa.pc +@ONLY) + +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/gnuradio-noaa.pc + DESTINATION ${GR_LIBRARY_DIR}/pkgconfig + COMPONENT "noaa_devel" +) + endif(ENABLE_GR_NOAA) diff --git a/gr-noaa/Makefile.am b/gr-noaa/Makefile.am index 854ce1476..ce5f66109 100644 --- a/gr-noaa/Makefile.am +++ b/gr-noaa/Makefile.am @@ -27,3 +27,5 @@ if PYTHON SUBDIRS += swig python apps endif +pkgconfigdir = $(libdir)/pkgconfig +dist_pkgconfig_DATA = gnuradio-noaa.pc diff --git a/gr-noaa/gnuradio-noaa.pc.in b/gr-noaa/gnuradio-noaa.pc.in new file mode 100644 index 000000000..cacfeecca --- /dev/null +++ b/gr-noaa/gnuradio-noaa.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: gnuradio-noaa +Description: GNU Radio blocks implementing a NOAA satellite protocols +Requires: gnuradio-core +Version: @LIBVER@ +Libs: -L${libdir} -lgnuradio-noaa +Cflags: -I${includedir} diff --git a/gr-uhd/apps/uhd_fft.py b/gr-uhd/apps/uhd_fft.py index a9bb1435e..f311a903b 100755 --- a/gr-uhd/apps/uhd_fft.py +++ b/gr-uhd/apps/uhd_fft.py @@ -48,7 +48,7 @@ class app_top_block(stdgui2.std_top_block): parser.add_option("-a", "--args", type="string", default="", help="UHD device address args , [default=%default]") parser.add_option("", "--spec", type="string", default=None, - help="Subdevice of UHD device where appropriate") + help="Subdevice of UHD device where appropriate") 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, @@ -61,25 +61,31 @@ class app_top_block(stdgui2.std_top_block): 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 ("", "--averaging", action="store_true", default=False, + parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, + help="Set fftsink averaging factor, default=[%default]") + parser.add_option ("", "--averaging", action="store_true", default=False, help="Enable fftsink averaging, 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, + 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]") - parser.add_option("--fft-rate", type="int", default=30, + parser.add_option("", "--fft-rate", type="int", default=30, help="Set FFT update rate, [default=%default]") + parser.add_option("", "--wire-format", type="string", default="sc16", + help="Set wire format from USRP [default=%default]") + parser.add_option("", "--scalar", type="int", default=1024, + help="Set scalar multiplier value sc8 wire format [default=%default]") (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() sys.exit(1) - self.options = options + self.options = options self.show_debug_info = True + scalar="scalar="+str(options.scalar) self.u = uhd.usrp_source(device_addr=options.args, - stream_args=uhd.stream_args('fc32')) + stream_args=uhd.stream_args(cpu_format='fc32', + otw_format=options.wire_format, args=scalar)) # Set the subdevice spec if(options.spec): @@ -104,20 +110,20 @@ class app_top_block(stdgui2.std_top_block): self.scope = fftsink2.fft_sink_c (panel, fft_size=options.fft_size, sample_rate=input_rate, - ref_scale=options.ref_scale, + ref_scale=options.ref_scale, ref_level=20.0, y_divs = 12, average=options.averaging, - avg_alpha=options.avg_alpha, + avg_alpha=options.avg_alpha, fft_rate=options.fft_rate) self.frame.SetMinSize((800, 420)) self.connect(self.u, self.scope) self._build_gui(vbox) - self._setup_events() + self._setup_events() - + # set initial values if options.gain is None: @@ -162,18 +168,18 @@ class app_top_block(stdgui2.std_top_block): 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) + # 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) + hbox.Add((5,0), 0, 0) + vbox.Add(hbox, 0, wx.EXPAND) - self._build_subpanel(vbox) + self._build_subpanel(vbox) def _build_subpanel(self, vbox_arg): # build a secondary information panel (sometimes hidden) @@ -223,15 +229,15 @@ class app_top_block(stdgui2.std_top_block): self.myform['freq'].set_value(self.u.get_center_freq()) self.myform['rffreq'].set_value(r.actual_rf_freq) self.myform['dspfreq'].set_value(r.actual_dsp_freq) - if not self.options.oscilloscope: - self.scope.set_baseband_freq(target_freq) - return True + 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 + 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): @@ -245,31 +251,32 @@ class app_top_block(stdgui2.std_top_block): 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) - + 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]) + (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 + 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) - - + 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() diff --git a/gr-uhd/apps/uhd_rx_cfile.py b/gr-uhd/apps/uhd_rx_cfile.py index ea2aad8fe..de44d4f56 100755 --- a/gr-uhd/apps/uhd_rx_cfile.py +++ b/gr-uhd/apps/uhd_rx_cfile.py @@ -39,12 +39,15 @@ class rx_cfile_block(gr.top_block): def __init__(self, options, filename): gr.top_block.__init__(self) + scalar="scalar="+str(options.scalar) # Create a UHD device source if options.output_shorts: - self._u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('sc16')) + self._u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('sc16', + options.wire_format, args=scalar)) self._sink = gr.file_sink(gr.sizeof_short*2, filename) else: - self._u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32')) + self._u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32', + options.wire_format, args=scalar)) self._sink = gr.file_sink(gr.sizeof_gr_complex, filename) # Set the subdevice spec @@ -127,6 +130,10 @@ def get_options(): help="verbose output") parser.add_option("", "--lo-offset", type="eng_float", default=None, help="set daughterboard LO offset to OFFSET [default=hw default]") + parser.add_option("", "--wire-format", type="string", default="sc16", + help="set wire format from USRP [default=%default") + parser.add_option("", "--scalar", type="int", default=1024, + help="set scalar multiplier value for sc8 wire format [default=%default]") (options, args) = parser.parse_args () if len(args) != 1: diff --git a/gr-uhd/include/gr_uhd_usrp_source.h b/gr-uhd/include/gr_uhd_usrp_source.h index e9fc41b93..8a799b397 100644 --- a/gr-uhd/include/gr_uhd_usrp_source.h +++ b/gr-uhd/include/gr_uhd_usrp_source.h @@ -455,6 +455,15 @@ public: * \return the multi usrp device object */ virtual uhd::usrp::multi_usrp::sptr get_device(void) = 0; + + /*! + * Convenience function for finite data acquisition. + * This is not to be used with the scheduler; rather, + * one can request samples from the USRP in python. + * //TODO multi-channel + * //TODO assumes fc32 + */ + virtual std::vector<std::complex<float> > finite_acquisition(const size_t nsamps) = 0; }; #endif /* INCLUDED_GR_UHD_USRP_SOURCE_H */ diff --git a/gr-uhd/lib/gr_uhd_usrp_source.cc b/gr-uhd/lib/gr_uhd_usrp_source.cc index 51a756908..2244238bd 100644 --- a/gr-uhd/lib/gr_uhd_usrp_source.cc +++ b/gr-uhd/lib/gr_uhd_usrp_source.cc @@ -409,6 +409,25 @@ public: return true; } + std::vector<std::complex<float> > finite_acquisition(const size_t nsamps){ + #ifdef GR_UHD_USE_STREAM_API + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); + cmd.num_samps = nsamps; + cmd.stream_now = true; + _dev->issue_stream_cmd(cmd); + + std::vector<std::complex<float> > samps(nsamps); + const size_t actual_num_samps = _rx_stream->recv( + &samps.front(), nsamps, _metadata, 0.1 + ); + samps.resize(actual_num_samps); + + return samps; + #else + throw std::runtime_error("not implemented in this version"); + #endif + } + private: uhd::usrp::multi_usrp::sptr _dev; const uhd::stream_args_t _stream_args; diff --git a/gr-wxgui/src/python/stdgui2.py b/gr-wxgui/src/python/stdgui2.py index e510f174c..f397fd01e 100644 --- a/gr-wxgui/src/python/stdgui2.py +++ b/gr-wxgui/src/python/stdgui2.py @@ -27,23 +27,27 @@ from gnuradio import gr class stdapp (wx.App): - def __init__ (self, top_block_maker, title="GNU Radio", nstatus=2): + def __init__ (self, top_block_maker, title="GNU Radio", nstatus=2, + max_noutput_items=None): self.top_block_maker = top_block_maker self.title = title self._nstatus = nstatus + self._max_noutput_items = max_noutput_items # All our initialization must come before calling wx.App.__init__. # OnInit is called from somewhere in the guts of __init__. wx.App.__init__ (self, redirect=False) def OnInit (self): - frame = stdframe (self.top_block_maker, self.title, self._nstatus) + frame = stdframe (self.top_block_maker, self.title, self._nstatus, + self._max_noutput_items) frame.Show (True) self.SetTopWindow (frame) return True class stdframe (wx.Frame): - def __init__ (self, top_block_maker, title="GNU Radio", nstatus=2): + def __init__ (self, top_block_maker, title="GNU Radio", nstatus=2, + max_nouts=None): # print "stdframe.__init__" wx.Frame.__init__(self, None, -1, title) @@ -57,7 +61,7 @@ class stdframe (wx.Frame): self.SetMenuBar (mainmenu) self.Bind (wx.EVT_CLOSE, self.OnCloseWindow) - self.panel = stdpanel (self, self, top_block_maker) + self.panel = stdpanel (self, self, top_block_maker, max_nouts) vbox = wx.BoxSizer(wx.VERTICAL) vbox.Add(self.panel, 1, wx.EXPAND) self.SetSizer(vbox) @@ -72,7 +76,8 @@ class stdframe (wx.Frame): return self.panel.top_block class stdpanel (wx.Panel): - def __init__ (self, parent, frame, top_block_maker): + def __init__ (self, parent, frame, top_block_maker, + max_nouts=None): # print "stdpanel.__init__" wx.Panel.__init__ (self, parent, -1) self.frame = frame @@ -83,7 +88,10 @@ class stdpanel (wx.Panel): self.SetAutoLayout (True) vbox.Fit (self) - self.top_block.start () + if(max_nouts is not None): + self.top_block.start (max_nouts) + else: + self.top_block.start () class std_top_block (gr.top_block): def __init__ (self, parent, panel, vbox, argv): diff --git a/gruel/src/include/gruel/high_res_timer.h b/gruel/src/include/gruel/high_res_timer.h index 9be524624..63841f612 100644 --- a/gruel/src/include/gruel/high_res_timer.h +++ b/gruel/src/include/gruel/high_res_timer.h @@ -46,7 +46,7 @@ namespace gruel { #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 + #define GRUEL_HRT_USE_CLOCK_GETTIME #else #define GRUEL_HRT_USE_MICROSEC_CLOCK #endif diff --git a/version.sh b/version.sh index 4e4c7cc31..58ec712f6 100644 --- a/version.sh +++ b/version.sh @@ -1,4 +1,4 @@ MAJOR_VERSION=3 API_COMPAT=5 MINOR_VERSION=1 -MAINT_VERSION=git +MAINT_VERSION=0 diff --git a/volk/include/volk/volk_16i_max_star_16i_a.h b/volk/include/volk/volk_16i_max_star_16i_a.h index 6a4f63708..28197ddef 100644 --- a/volk/include/volk/volk_16i_max_star_16i_a.h +++ b/volk/include/volk/volk_16i_max_star_16i_a.h @@ -18,7 +18,7 @@ static inline void volk_16i_max_star_16i_a_ssse3(short* target, short* src0, un short candidate = src0[0]; short cands[8]; - __m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6; + __m128i xmm0, xmm1, xmm3, xmm4, xmm5, xmm6; __m128i *p_src0; @@ -41,7 +41,7 @@ static inline void volk_16i_max_star_16i_a_ssse3(short* target, short* src0, un for(i = 0; i < bound; ++i) { xmm1 = _mm_load_si128(p_src0); p_src0 += 1; - xmm2 = _mm_sub_epi16(xmm1, xmm0); + //xmm2 = _mm_sub_epi16(xmm1, xmm0); diff --git a/volk/include/volk/volk_32f_s32f_stddev_32f_a.h b/volk/include/volk/volk_32f_s32f_stddev_32f_a.h index 881067bdc..75fe0cb2e 100644 --- a/volk/include/volk/volk_32f_s32f_stddev_32f_a.h +++ b/volk/include/volk/volk_32f_s32f_stddev_32f_a.h @@ -60,7 +60,7 @@ static inline void volk_32f_s32f_stddev_32f_a_sse4_1(float* stddev, const float* } returnValue /= num_points; returnValue -= (mean * mean); - returnValue = sqrt(returnValue); + returnValue = sqrtf(returnValue); } *stddev = returnValue; } @@ -106,7 +106,7 @@ static inline void volk_32f_s32f_stddev_32f_a_sse(float* stddev, const float* in } returnValue /= num_points; returnValue -= (mean * mean); - returnValue = sqrt(returnValue); + returnValue = sqrtf(returnValue); } *stddev = returnValue; } @@ -133,7 +133,7 @@ static inline void volk_32f_s32f_stddev_32f_a_generic(float* stddev, const float returnValue /= num_points; returnValue -= (mean * mean); - returnValue = sqrt(returnValue); + returnValue = sqrtf(returnValue); } *stddev = returnValue; } diff --git a/volk/include/volk/volk_32f_stddev_and_mean_32f_x2_a.h b/volk/include/volk/volk_32f_stddev_and_mean_32f_x2_a.h index 3a82e3d2f..20ff676d8 100644 --- a/volk/include/volk/volk_32f_stddev_and_mean_32f_x2_a.h +++ b/volk/include/volk/volk_32f_stddev_and_mean_32f_x2_a.h @@ -72,7 +72,7 @@ static inline void volk_32f_stddev_and_mean_32f_x2_a_sse4_1(float* stddev, float newMean /= num_points; returnValue /= num_points; returnValue -= (newMean * newMean); - returnValue = sqrt(returnValue); + returnValue = sqrtf(returnValue); } *stddev = returnValue; *mean = newMean; @@ -128,7 +128,7 @@ static inline void volk_32f_stddev_and_mean_32f_x2_a_sse(float* stddev, float* m newMean /= num_points; returnValue /= num_points; returnValue -= (newMean * newMean); - returnValue = sqrt(returnValue); + returnValue = sqrtf(returnValue); } *stddev = returnValue; *mean = newMean; @@ -157,7 +157,7 @@ static inline void volk_32f_stddev_and_mean_32f_x2_a_generic(float* stddev, floa newMean /= num_points; returnValue /= num_points; returnValue -= (newMean * newMean); - returnValue = sqrt(returnValue); + returnValue = sqrtf(returnValue); } *stddev = returnValue; *mean = newMean; diff --git a/volk/lib/CMakeLists.txt b/volk/lib/CMakeLists.txt index 092c3ba0d..00d8660ab 100644 --- a/volk/lib/CMakeLists.txt +++ b/volk/lib/CMakeLists.txt @@ -85,7 +85,17 @@ execute_process( #set the various overrule values (see archs.xml) #a lot of this is translating between automake and cmake if(NOT "${CROSSCOMPILE_MULTILIB}" STREQUAL "true") - set(MD_SUBCPU ${CMAKE_HOST_SYSTEM_PROCESSOR}) + set(MD_SUBCPU ${CMAKE_SYSTEM_PROCESSOR}) + #detect 32 or 64 bit compiler + if(MD_SUBCPU MATCHES "^(i.86|x86|x86_64|amd64)$") + include(CheckTypeSize) + check_type_size("void*" SIZEOF_VOID_P BUILTIN_TYPES_ONLY) + if (${SIZEOF_VOID_P} EQUAL 8) + set(MD_SUBCPU x86_64) + else() + set(MD_SUBCPU x86) + endif() + endif() endif() if(NOT "${ORC_FOUND}" STREQUAL "TRUE") set(LV_HAVE_ORC "no") @@ -267,7 +277,7 @@ if(ORC_FOUND) #create a rule to generate the source and add to the list of sources add_custom_command( - COMMAND ${ORCC_EXECUTABLE} --implementation -o ${orcc_gen} ${orc_file} + COMMAND ${ORCC_EXECUTABLE} --include math.h --implementation -o ${orcc_gen} ${orc_file} DEPENDS ${orc_file} OUTPUT ${orcc_gen} ) list(APPEND volk_sources ${orcc_gen}) diff --git a/volk/orc/volk_16ic_magnitude_16i_a_orc_impl.orc b/volk/orc/volk_16ic_magnitude_16i_a_orc_impl.orc index 3966526ed..fbaebc46d 100644 --- a/volk/orc/volk_16ic_magnitude_16i_a_orc_impl.orc +++ b/volk/orc/volk_16ic_magnitude_16i_a_orc_impl.orc @@ -17,7 +17,7 @@ x2 divf iqf, iqf, scalar x2 mulf prodiqf, iqf, iqf splitql qf, if, prodiqf addf sumf, if, qf -sqrt, sqrtf rootf, sumf +sqrtf rootf, sumf mulf rootf, rootf, scalar convfl rootl, rootf convlw dst, rootl diff --git a/volk/orc/volk_16sc_magnitude_32f_aligned16_orc_impl.orc b/volk/orc/volk_16sc_magnitude_32f_aligned16_orc_impl.orc index d5c8212c3..66fef7d2e 100644 --- a/volk/orc/volk_16sc_magnitude_32f_aligned16_orc_impl.orc +++ b/volk/orc/volk_16sc_magnitude_32f_aligned16_orc_impl.orc @@ -22,4 +22,4 @@ divf imagf, imagf, scalar mulf realf, realf, realf mulf imagf, imagf, imagf addf sumf, realf, imagf -sqrt, sqrtf dst, sumf +sqrtf dst, sumf diff --git a/volk/orc/volk_32f_sqrt_32f_a_orc_impl.orc b/volk/orc/volk_32f_sqrt_32f_a_orc_impl.orc index 719cca037..f339b1122 100644 --- a/volk/orc/volk_32f_sqrt_32f_a_orc_impl.orc +++ b/volk/orc/volk_32f_sqrt_32f_a_orc_impl.orc @@ -1,4 +1,4 @@ .function volk_32f_sqrt_32f_a_orc_impl .source 4 src .dest 4 dst -sqrt, sqrtf dst, src +sqrtf dst, src diff --git a/volk/orc/volk_32fc_magnitude_32f_a_orc_impl.orc b/volk/orc/volk_32fc_magnitude_32f_a_orc_impl.orc index 4fc0642fc..032ab2b1b 100644 --- a/volk/orc/volk_32fc_magnitude_32f_a_orc_impl.orc +++ b/volk/orc/volk_32fc_magnitude_32f_a_orc_impl.orc @@ -10,4 +10,4 @@ x2 mulf prodiqf, src, src splitql qf, if, prodiqf addf sumf, if, qf -sqrt, sqrtf dst, sumf +sqrtf dst, sumf diff --git a/volk/orc/volk_32fc_s32f_magnitude_16i_a_orc_impl.orc b/volk/orc/volk_32fc_s32f_magnitude_16i_a_orc_impl.orc index ed89c3d18..d3bf78935 100644 --- a/volk/orc/volk_32fc_s32f_magnitude_16i_a_orc_impl.orc +++ b/volk/orc/volk_32fc_s32f_magnitude_16i_a_orc_impl.orc @@ -14,7 +14,7 @@ x2 mulf prodiqf, src, src splitql qf, if, prodiqf addf sumf, if, qf -sqrt, sqrtf rootf, sumf +sqrtf rootf, sumf mulf rootf, rootf, scalar #cmpltf maskl, 32768.0, rootf #andl maskl, maskl, 0x80000000 diff --git a/volk/orc/volk_8i_convert_16i_a_orc_impl.orc b/volk/orc/volk_8i_convert_16i_a_orc_impl.orc index d813c6cfa..17198bf1e 100644 --- a/volk/orc/volk_8i_convert_16i_a_orc_impl.orc +++ b/volk/orc/volk_8i_convert_16i_a_orc_impl.orc @@ -1,5 +1,6 @@ .function volk_8i_convert_16i_a_orc_impl .source 1 src .dest 2 dst -convsbw dst, src -shlw dst, dst, 8 +.temp 2 tmp +convsbw tmp, src +shlw dst, tmp, 8 |