From cb3289d1494339cb0ac20bed080a0d37b99ab4fb Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 22 Dec 2011 18:00:47 -0500 Subject: digital: exposed setting FLL loop bandwidth factor in GRC; must have been overlooked initially. --- gr-digital/grc/digital_dxpsk_demod.xml | 7 +++++++ 1 file changed, 7 insertions(+) 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 @@ 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, @@ -66,6 +67,12 @@ 0.35 real + + FLL Bandwidth + freq_bw + 6.28/100.0 + real + Phase Loop Bandwidth phase_bw -- cgit From 5faab4fbcf423cc614d53f0f3c557c2f055b7ed0 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 22 Dec 2011 18:19:28 -0500 Subject: filters: added accessor functions to FFT and FIR filter classes to return vector of taps. --- gnuradio-core/src/lib/filter/gr_fft_filter_ccc.cc | 7 +++++++ gnuradio-core/src/lib/filter/gr_fft_filter_ccc.h | 1 + gnuradio-core/src/lib/filter/gr_fft_filter_ccc.i | 1 + gnuradio-core/src/lib/filter/gr_fft_filter_fff.cc | 8 +++++++- gnuradio-core/src/lib/filter/gr_fft_filter_fff.h | 1 + gnuradio-core/src/lib/filter/gr_fft_filter_fff.i | 1 + .../src/lib/filter/gr_fir_filter_XXX.cc.t | 6 ++++++ gnuradio-core/src/lib/filter/gr_fir_filter_XXX.h.t | 1 + gnuradio-core/src/lib/filter/gr_fir_filter_XXX.i.t | 1 + .../src/python/gnuradio/gr/qa_fft_filter.py | 24 ++++++++++++++++++++++ 10 files changed, 50 insertions(+), 1 deletion(-) 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::vectorset_taps(taps); set_output_multiple(d_nsamples); } @@ -78,6 +79,12 @@ gr_fft_filter_ccc::set_taps (const std::vector &taps) d_updated = true; } +std::vector +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 &taps); + std::vector 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 &taps); + std::vector 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 & #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 &taps) d_updated = true; } +std::vector +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 &taps); + std::vector 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 &taps); + std::vector 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/python/gnuradio/gr/qa_fft_filter.py b/gnuradio-core/src/python/gnuradio/gr/qa_fft_filter.py index b3124ad29..f02f700a6 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") -- cgit From 5cd411a7e260b0721fecbac6c53b0717b2adf7e6 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 22 Dec 2011 18:20:06 -0500 Subject: core: added accessors to noise_source to get type and amplitude of object. --- gnuradio-core/src/lib/gengen/gr_noise_source_X.h.t | 3 +++ gnuradio-core/src/lib/gengen/gr_noise_source_X.i.t | 3 +++ gnuradio-core/src/python/gnuradio/gr/qa_noise.py | 12 ++++++++++++ 3 files changed, 18 insertions(+) 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/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") -- cgit From c1c68974a6677f6dd81b1fb6e3c129e8d08c1fd0 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 22 Dec 2011 18:20:33 -0500 Subject: core: added accessors to get all settable values of the channel_model objects. --- gnuradio-core/src/lib/hier/gr_channel_model.cc | 25 +++++++++++++++++++++++++ gnuradio-core/src/lib/hier/gr_channel_model.h | 5 +++++ gnuradio-core/src/lib/hier/gr_channel_model.i | 5 +++++ 3 files changed, 35 insertions(+) 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_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 &taps); void set_timing_offset(double epsilon); + + double noise_voltage() const; + double frequency_offset() const; + std::vector 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 &taps); void set_timing_offset(double epsilon); + + double noise_voltage() const; + double frequency_offset() const; + std::vector taps() const; + double timing_offset() const; }; -- cgit From 6a78e0a8ae6dc17a12ab5e397f1452a1a363e7d1 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 23 Dec 2011 13:28:06 -0500 Subject: digital: added a class, digital_mpsk_snr_est_cc, that estimates the SNR of an M-ary PSK signal. This block can calculate the SNR using 1 of 4 different methods specified in the block's constructor. They (tend to) trade off accuracy for computational performnace. --- gr-digital/include/CMakeLists.txt | 1 + gr-digital/include/digital_mpsk_snr_est_cc.h | 108 +++++++++++++ gr-digital/lib/CMakeLists.txt | 1 + gr-digital/lib/digital_mpsk_snr_est_cc.cc | 226 +++++++++++++++++++++++++++ gr-digital/swig/CMakeLists.txt | 1 + gr-digital/swig/digital_mpsk_snr_est_cc.i | 46 ++++++ gr-digital/swig/digital_swig.i | 2 + 7 files changed, 385 insertions(+) create mode 100644 gr-digital/include/digital_mpsk_snr_est_cc.h create mode 100644 gr-digital/lib/digital_mpsk_snr_est_cc.cc create mode 100644 gr-digital/swig/digital_mpsk_snr_est_cc.i diff --git a/gr-digital/include/CMakeLists.txt b/gr-digital/include/CMakeLists.txt index cf20bd1e7..ceb4fdfe1 100644 --- a/gr-digital/include/CMakeLists.txt +++ b/gr-digital/include/CMakeLists.txt @@ -37,6 +37,7 @@ 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 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..9c2d636c4 --- /dev/null +++ b/gr-digital/include/digital_mpsk_snr_est_cc.h @@ -0,0 +1,108 @@ +/* -*- 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 +#include + +class digital_mpsk_snr_est_cc; +typedef boost::shared_ptr digital_mpsk_snr_est_cc_sptr; + +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 (>= 3 dB) + SNR_EST_SVN // SVN-based est (>= 0dB) +}; + +DIGITAL_API digital_mpsk_snr_est_cc_sptr +digital_make_mpsk_snr_est_cc(snr_est_type_t type, double alpha); + +/*! + * Provides various methods to compute SNR. + */ +class DIGITAL_API digital_mpsk_snr_est_cc : public gr_sync_block +{ + private: + snr_est_type_t d_type; + double d_y1, d_y2, d_y3, d_y4; + double d_alpha, d_beta; + + // Function pointers to the type of estimator used. + int (digital_mpsk_snr_est_cc::*d_estimator)(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + double (digital_mpsk_snr_est_cc::*d_calculator)(); + + // Factory function returning shared pointer of this class + friend DIGITAL_API digital_mpsk_snr_est_cc_sptr + digital_make_mpsk_snr_est_cc(snr_est_type_t type, double alpha); + + // Private constructor + digital_mpsk_snr_est_cc(snr_est_type_t type, double alpha); + + int est_simple(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + double est_simple_snr(); + + int est_skew(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + double est_skew_snr(); + + int est_m2m4(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + double est_m2m4_snr(); + + int est_svn(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + double est_svn_snr(); + +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; + + //! Get the running-average coefficient + double alpha() const; + + //! Set type of estimator to use + void set_type(snr_est_type_t t); + + //! Set the running-average coefficient + void set_alpha(double alpha); +}; + +#endif /* INCLUDED_DIGITAL_MPSK_SNR_EST_CC_H */ diff --git a/gr-digital/lib/CMakeLists.txt b/gr-digital/lib/CMakeLists.txt index b90757111..73ac5692f 100644 --- a/gr-digital/lib/CMakeLists.txt +++ b/gr-digital/lib/CMakeLists.txt @@ -46,6 +46,7 @@ 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 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..7793eed1d --- /dev/null +++ b/gr-digital/lib/digital_mpsk_snr_est_cc.cc @@ -0,0 +1,226 @@ +/* -*- 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 +#endif + +#include +#include +#include + +digital_mpsk_snr_est_cc_sptr +digital_make_mpsk_snr_est_cc(snr_est_type_t type, + double alpha) +{ + return gnuradio::get_initial_sptr(new digital_mpsk_snr_est_cc(type, alpha)); +} + +digital_mpsk_snr_est_cc::digital_mpsk_snr_est_cc(snr_est_type_t type, + 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_type(type), d_y1(0), d_y2(0), d_y3(0), d_y4(0) +{ + set_type(type); + set_alpha(alpha); + set_history(2); +} + +digital_mpsk_snr_est_cc::~digital_mpsk_snr_est_cc() +{ +} + +int +digital_mpsk_snr_est_cc::est_simple(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]; + + 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_mpsk_snr_est_cc::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); +} + +int +digital_mpsk_snr_est_cc::est_skew(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]; + + 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_mpsk_snr_est_cc::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)); +} + +int +digital_mpsk_snr_est_cc::est_m2m4(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]; + + 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_mpsk_snr_est_cc::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))); +} + + +int +digital_mpsk_snr_est_cc::est_svn(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]; + + 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_mpsk_snr_est_cc::est_svn_snr() +{ + double x = d_y1 / (d_y2 - d_y1); + return 10.0*log10(2.*((x-1) + sqrt(x*(x-1)))); +} + +int +digital_mpsk_snr_est_cc::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + return (*this.*d_estimator)(noutput_items, input_items, output_items); +} + +double +digital_mpsk_snr_est_cc::snr() +{ + return (*this.*d_calculator)(); +} + +snr_est_type_t +digital_mpsk_snr_est_cc::type() const +{ + return d_type; +} + +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; + d_y1 = 0; + d_y2 = 0; + d_y3 = 0; + d_y4 = 0; + + switch (d_type) { + case(SNR_EST_SIMPLE): + d_estimator = &digital_mpsk_snr_est_cc::est_simple; + d_calculator = &digital_mpsk_snr_est_cc::est_simple_snr; + break; + case(SNR_EST_SKEW): + d_estimator = &digital_mpsk_snr_est_cc::est_skew; + d_calculator = &digital_mpsk_snr_est_cc::est_skew_snr; + break; + case(SNR_EST_M2M4): + d_estimator = &digital_mpsk_snr_est_cc::est_m2m4; + d_calculator = &digital_mpsk_snr_est_cc::est_m2m4_snr; + break; + case(SNR_EST_SVN): + d_estimator = &digital_mpsk_snr_est_cc::est_svn; + d_calculator = &digital_mpsk_snr_est_cc::est_svn_snr; + break; + default: + throw std::invalid_argument("digital_mpsk_snr_est_cc: unknown type specified.\n"); + } +} + +void +digital_mpsk_snr_est_cc::set_alpha(double alpha) +{ + d_alpha = alpha; + d_beta = 1.0-alpha; +} diff --git a/gr-digital/swig/CMakeLists.txt b/gr-digital/swig/CMakeLists.txt index dd6097286..136f9e43f 100644 --- a/gr-digital/swig/CMakeLists.txt +++ b/gr-digital/swig/CMakeLists.txt @@ -59,6 +59,7 @@ 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 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..cb61e9482 --- /dev/null +++ b/gr-digital/swig/digital_mpsk_snr_est_cc.i @@ -0,0 +1,46 @@ +/* -*- 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); + +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 (>= 3 dB) + SNR_EST_SVN // SVN-based est (>= 0dB) +}; + +digital_mpsk_snr_est_cc_sptr +digital_make_mpsk_snr_est_cc(snr_est_type_t type, double alpha); + +class digital_mpsk_snr_est_cc : public gr_sync_block +{ +private: + void digital_mpsk_snr_est_cc(snr_est_type_t type, double alpha); + +public: + double snr(); + snr_est_type_t type() const; + double alpha() const; + void set_type(snr_est_type_t t); + void set_alpha(double alpha); +}; diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i index 86b5cab13..9182b2b09 100644 --- a/gr-digital/swig/digital_swig.i +++ b/gr-digital/swig/digital_swig.i @@ -41,6 +41,7 @@ #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" @@ -65,6 +66,7 @@ %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" -- cgit From 858e3582a108cfea8040f59628698e9394558092 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 29 Dec 2011 10:54:03 -0500 Subject: digital: made separate implementation classes for the different SNR estimators. --- gr-digital/include/CMakeLists.txt | 1 + gr-digital/include/Makefile.am | 1 + gr-digital/include/digital_impl_mpsk_snr_est.h | 123 ++++++++++++++ gr-digital/lib/CMakeLists.txt | 1 + gr-digital/lib/Makefile.am | 1 + gr-digital/lib/digital_impl_mpsk_snr_est.cc | 227 +++++++++++++++++++++++++ 6 files changed, 354 insertions(+) create mode 100644 gr-digital/include/digital_impl_mpsk_snr_est.h create mode 100644 gr-digital/lib/digital_impl_mpsk_snr_est.cc diff --git a/gr-digital/include/CMakeLists.txt b/gr-digital/include/CMakeLists.txt index ceb4fdfe1..8bac4c991 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 diff --git a/gr-digital/include/Makefile.am b/gr-digital/include/Makefile.am index 8ce3a94e8..9fa619015 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 \ 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..67cf83ec9 --- /dev/null +++ b/gr-digital/include/digital_impl_mpsk_snr_est.h @@ -0,0 +1,123 @@ +/* -*- 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 +#include + +/*! + * Parent class for SNR Estimators + */ +class DIGITAL_API digital_impl_mpsk_snr_est +{ + protected: + double d_alpha, d_beta; + + public: + 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, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + //! Use the register values to compute a new estimate + virtual double snr(); +}; + + +class DIGITAL_API digital_impl_mpsk_snr_est_simple : + public digital_impl_mpsk_snr_est +{ + private: + double d_y1, d_y2; + + public: + digital_impl_mpsk_snr_est_simple(double alpha); + ~digital_impl_mpsk_snr_est_simple() {} + + int update(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + double snr(); +}; + + +class DIGITAL_API digital_impl_mpsk_snr_est_skew : + public digital_impl_mpsk_snr_est +{ + private: + double d_y1, d_y2, d_y3; + + public: + digital_impl_mpsk_snr_est_skew(double alpha); + ~digital_impl_mpsk_snr_est_skew() {} + + int update(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + double snr(); +}; + + +class DIGITAL_API digital_impl_mpsk_snr_est_m2m4 : + public digital_impl_mpsk_snr_est +{ + private: + double d_y1, d_y2; + + public: + digital_impl_mpsk_snr_est_m2m4(double alpha); + ~digital_impl_mpsk_snr_est_m2m4() {} + + int update(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + double snr(); +}; + + +class DIGITAL_API digital_impl_mpsk_snr_est_svn : + public digital_impl_mpsk_snr_est +{ + private: + double d_y1, d_y2; + + public: + digital_impl_mpsk_snr_est_svn(double alpha); + ~digital_impl_mpsk_snr_est_svn() {} + + int update(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + double snr(); +}; + +#endif /* INCLUDED_DIGITAL_IMPL_MPSK_SNR_EST_H */ diff --git a/gr-digital/lib/CMakeLists.txt b/gr-digital/lib/CMakeLists.txt index 73ac5692f..94ef2b64d 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 diff --git a/gr-digital/lib/Makefile.am b/gr-digital/lib/Makefile.am index 2860974ca..b6fea599f 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 \ 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..aa0d4ffb9 --- /dev/null +++ b/gr-digital/lib/digital_impl_mpsk_snr_est.cc @@ -0,0 +1,227 @@ +/* -*- 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 +#endif + +#include +#include + +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, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + 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, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + + 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, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + + 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, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + + 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_mpsk_snr_est_svn::digital_impl_mpsk_snr_est_svn( + double alpha) : + digital_impl_mpsk_snr_est(alpha) +{ + d_y1 = 0; + d_y2 = 0; +} + +int +digital_impl_mpsk_snr_est_svn::update( + 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]; + + 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_svn::snr() +{ + double x = d_y1 / (d_y2 - d_y1); + return 10.0*log10(2.*((x-1) + sqrt(x*(x-1)))); +} -- cgit From ceb18ce1c1342477d0704edfaa3e775830a999e4 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 29 Dec 2011 10:54:52 -0500 Subject: digital: using impl SNR estimator classes instead of function pointers. --- gr-digital/include/digital_mpsk_snr_est_cc.h | 31 +----- gr-digital/lib/digital_mpsk_snr_est_cc.cc | 152 +++++---------------------- 2 files changed, 27 insertions(+), 156 deletions(-) diff --git a/gr-digital/include/digital_mpsk_snr_est_cc.h b/gr-digital/include/digital_mpsk_snr_est_cc.h index 9c2d636c4..84d6380a9 100644 --- a/gr-digital/include/digital_mpsk_snr_est_cc.h +++ b/gr-digital/include/digital_mpsk_snr_est_cc.h @@ -24,6 +24,7 @@ #include #include +#include class digital_mpsk_snr_est_cc; typedef boost::shared_ptr digital_mpsk_snr_est_cc_sptr; @@ -45,14 +46,8 @@ class DIGITAL_API digital_mpsk_snr_est_cc : public gr_sync_block { private: snr_est_type_t d_type; - double d_y1, d_y2, d_y3, d_y4; - double d_alpha, d_beta; - - // Function pointers to the type of estimator used. - int (digital_mpsk_snr_est_cc::*d_estimator)(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - double (digital_mpsk_snr_est_cc::*d_calculator)(); + double d_alpha; + digital_impl_mpsk_snr_est *d_snr_est; // Factory function returning shared pointer of this class friend DIGITAL_API digital_mpsk_snr_est_cc_sptr @@ -61,26 +56,6 @@ class DIGITAL_API digital_mpsk_snr_est_cc : public gr_sync_block // Private constructor digital_mpsk_snr_est_cc(snr_est_type_t type, double alpha); - int est_simple(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - double est_simple_snr(); - - int est_skew(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - double est_skew_snr(); - - int est_m2m4(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - double est_m2m4_snr(); - - int est_svn(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - double est_svn_snr(); - public: ~digital_mpsk_snr_est_cc(); diff --git a/gr-digital/lib/digital_mpsk_snr_est_cc.cc b/gr-digital/lib/digital_mpsk_snr_est_cc.cc index 7793eed1d..0830b4a4d 100644 --- a/gr-digital/lib/digital_mpsk_snr_est_cc.cc +++ b/gr-digital/lib/digital_mpsk_snr_est_cc.cc @@ -39,126 +39,23 @@ digital_mpsk_snr_est_cc::digital_mpsk_snr_est_cc(snr_est_type_t type, 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_type(type), d_y1(0), d_y2(0), d_y3(0), d_y4(0) + gr_make_io_signature(1, 1, sizeof(gr_complex))) { - set_type(type); - set_alpha(alpha); - set_history(2); -} - -digital_mpsk_snr_est_cc::~digital_mpsk_snr_est_cc() -{ -} - -int -digital_mpsk_snr_est_cc::est_simple(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]; - - 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_mpsk_snr_est_cc::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); -} - -int -digital_mpsk_snr_est_cc::est_skew(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]; - - 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; -} + d_snr_est = NULL; -double -digital_mpsk_snr_est_cc::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)); -} - -int -digital_mpsk_snr_est_cc::est_m2m4(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]; - - 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_mpsk_snr_est_cc::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))); -} + d_type = type; + set_alpha(alpha); + set_type(type); -int -digital_mpsk_snr_est_cc::est_svn(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]; - - 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; + // at least 1 estimator has to look back + set_history(2); } -double -digital_mpsk_snr_est_cc::est_svn_snr() +digital_mpsk_snr_est_cc::~digital_mpsk_snr_est_cc() { - double x = d_y1 / (d_y2 - d_y1); - return 10.0*log10(2.*((x-1) + sqrt(x*(x-1)))); + if(d_snr_est) + delete d_snr_est; } int @@ -166,13 +63,16 @@ digital_mpsk_snr_est_cc::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { - return (*this.*d_estimator)(noutput_items, input_items, output_items); + return d_snr_est->update(noutput_items, input_items, output_items); } double digital_mpsk_snr_est_cc::snr() { - return (*this.*d_calculator)(); + 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 @@ -191,27 +91,22 @@ void digital_mpsk_snr_est_cc::set_type(snr_est_type_t t) { d_type = t; - d_y1 = 0; - d_y2 = 0; - d_y3 = 0; - d_y4 = 0; + + if(d_snr_est) + delete d_snr_est; switch (d_type) { case(SNR_EST_SIMPLE): - d_estimator = &digital_mpsk_snr_est_cc::est_simple; - d_calculator = &digital_mpsk_snr_est_cc::est_simple_snr; + d_snr_est = new digital_impl_mpsk_snr_est_simple(d_alpha); break; case(SNR_EST_SKEW): - d_estimator = &digital_mpsk_snr_est_cc::est_skew; - d_calculator = &digital_mpsk_snr_est_cc::est_skew_snr; + d_snr_est = new digital_impl_mpsk_snr_est_skew(d_alpha); break; case(SNR_EST_M2M4): - d_estimator = &digital_mpsk_snr_est_cc::est_m2m4; - d_calculator = &digital_mpsk_snr_est_cc::est_m2m4_snr; + d_snr_est = new digital_impl_mpsk_snr_est_m2m4(d_alpha); break; case(SNR_EST_SVN): - d_estimator = &digital_mpsk_snr_est_cc::est_svn; - d_calculator = &digital_mpsk_snr_est_cc::est_svn_snr; + d_snr_est = new digital_impl_mpsk_snr_est_svn(d_alpha); break; default: throw std::invalid_argument("digital_mpsk_snr_est_cc: unknown type specified.\n"); @@ -222,5 +117,6 @@ void digital_mpsk_snr_est_cc::set_alpha(double alpha) { d_alpha = alpha; - d_beta = 1.0-alpha; + if(d_snr_est) + d_snr_est->set_alpha(d_alpha); } -- cgit From 74c53aa4c5b9aeac590b803b12601bcc9c8b9b60 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 29 Dec 2011 11:27:00 -0500 Subject: digital: added a probe (sink) for the new SNR estimators; also fixes up Makefiles and Swig files for SNR est blocks. --- gr-digital/include/CMakeLists.txt | 1 + gr-digital/include/Makefile.am | 2 + gr-digital/include/digital_probe_mpsk_snr_est_c.h | 76 +++++++++++++ gr-digital/lib/CMakeLists.txt | 1 + gr-digital/lib/Makefile.am | 2 + gr-digital/lib/digital_probe_mpsk_snr_est_c.cc | 123 ++++++++++++++++++++++ gr-digital/swig/CMakeLists.txt | 1 + gr-digital/swig/Makefile.am | 2 + gr-digital/swig/digital_probe_mpsk_snr_est_c.i | 41 ++++++++ gr-digital/swig/digital_swig.i | 9 ++ 10 files changed, 258 insertions(+) create mode 100644 gr-digital/include/digital_probe_mpsk_snr_est_c.h create mode 100644 gr-digital/lib/digital_probe_mpsk_snr_est_c.cc create mode 100644 gr-digital/swig/digital_probe_mpsk_snr_est_c.i diff --git a/gr-digital/include/CMakeLists.txt b/gr-digital/include/CMakeLists.txt index 8bac4c991..81ed8d368 100644 --- a/gr-digital/include/CMakeLists.txt +++ b/gr-digital/include/CMakeLists.txt @@ -45,6 +45,7 @@ install(FILES 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 9fa619015..3cf186d3d 100644 --- a/gr-digital/include/Makefile.am +++ b/gr-digital/include/Makefile.am @@ -40,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_probe_mpsk_snr_est_c.h b/gr-digital/include/digital_probe_mpsk_snr_est_c.h new file mode 100644 index 000000000..4920a0ae3 --- /dev/null +++ b/gr-digital/include/digital_probe_mpsk_snr_est_c.h @@ -0,0 +1,76 @@ +/* -*- 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 +#include +#include + +class digital_probe_mpsk_snr_est_c; +typedef boost::shared_ptr 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, double alpha); + +/*! + * Provides various methods to compute SNR. + */ +class DIGITAL_API digital_probe_mpsk_snr_est_c : public gr_sync_block +{ + private: + snr_est_type_t d_type; + double d_alpha; + digital_impl_mpsk_snr_est *d_snr_est; + + // Factory function returning shared pointer of this class + friend DIGITAL_API digital_probe_mpsk_snr_est_c_sptr + digital_make_probe_mpsk_snr_est_c(snr_est_type_t type, double alpha); + + // Private constructor + digital_probe_mpsk_snr_est_c(snr_est_type_t type, 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; + + //! Get the running-average coefficient + double alpha() const; + + //! Set type of estimator to use + void set_type(snr_est_type_t t); + + //! 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 94ef2b64d..779972ff3 100644 --- a/gr-digital/lib/CMakeLists.txt +++ b/gr-digital/lib/CMakeLists.txt @@ -54,6 +54,7 @@ list(APPEND gr_digital_sources 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 b6fea599f..d5ad199e3 100644 --- a/gr-digital/lib/Makefile.am +++ b/gr-digital/lib/Makefile.am @@ -42,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_probe_mpsk_snr_est_c.cc b/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc new file mode 100644 index 000000000..259074e13 --- /dev/null +++ b/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc @@ -0,0 +1,123 @@ +/* -*- 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 +#endif + +#include +#include +#include + +digital_probe_mpsk_snr_est_c_sptr +digital_make_probe_mpsk_snr_est_c(snr_est_type_t type, + double alpha) +{ + return gnuradio::get_initial_sptr( + new digital_probe_mpsk_snr_est_c(type, alpha)); +} + +digital_probe_mpsk_snr_est_c::digital_probe_mpsk_snr_est_c( + snr_est_type_t type, 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; + set_alpha(alpha); + + set_type(type); + + // at least 1 estimator has to look back + set_history(2); +} + +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) +{ + return d_snr_est->update(noutput_items, input_items); +} + +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; +} + +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_SVN): + d_snr_est = new digital_impl_mpsk_snr_est_svn(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_alpha(double alpha) +{ + d_alpha = alpha; + if(d_snr_est) + d_snr_est->set_alpha(d_alpha); +} diff --git a/gr-digital/swig/CMakeLists.txt b/gr-digital/swig/CMakeLists.txt index 136f9e43f..6f2c2251a 100644 --- a/gr-digital/swig/CMakeLists.txt +++ b/gr-digital/swig/CMakeLists.txt @@ -66,6 +66,7 @@ install( 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_probe_mpsk_snr_est_c.i b/gr-digital/swig/digital_probe_mpsk_snr_est_c.i new file mode 100644 index 000000000..fe3684a81 --- /dev/null +++ b/gr-digital/swig/digital_probe_mpsk_snr_est_c.i @@ -0,0 +1,41 @@ +/* -*- 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, + double alpha); + +class digital_probe_mpsk_snr_est_c : public gr_sync_block +{ +private: + void digital_probe_mpsk_snr_est_c(snr_est_type_t type, + double alpha); + +public: + double snr(); + snr_est_type_t type() const; + double alpha() const; + void set_type(snr_est_type_t t); + void set_alpha(double alpha); +}; diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i index 9182b2b09..bc50fc727 100644 --- a/gr-digital/swig/digital_swig.i +++ b/gr-digital/swig/digital_swig.i @@ -24,6 +24,13 @@ //load generated python docstrings %include "digital_swig_doc.i" +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_SVN // SVN-based est (>= 0dB) +}; + %include %{ @@ -48,6 +55,7 @@ #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" %} @@ -73,6 +81,7 @@ %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" -- cgit From 55ff1160c9e0d49028c52296fa920428d30fd7c3 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 29 Dec 2011 11:27:56 -0500 Subject: digital: fixing up blocks to use SNR est classes more appropriately. --- gr-digital/include/digital_impl_mpsk_snr_est.h | 22 ++++++++++++---------- gr-digital/include/digital_mpsk_snr_est_cc.h | 7 ------- gr-digital/lib/digital_impl_mpsk_snr_est.cc | 15 +++++---------- gr-digital/lib/digital_mpsk_snr_est_cc.cc | 7 ++++++- gr-digital/swig/digital_mpsk_snr_est_cc.i | 7 ------- 5 files changed, 23 insertions(+), 35 deletions(-) diff --git a/gr-digital/include/digital_impl_mpsk_snr_est.h b/gr-digital/include/digital_impl_mpsk_snr_est.h index 67cf83ec9..a96f3e9c1 100644 --- a/gr-digital/include/digital_impl_mpsk_snr_est.h +++ b/gr-digital/include/digital_impl_mpsk_snr_est.h @@ -25,6 +25,13 @@ #include #include +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_SVN // SVN-based est (>= 0dB) +}; + /*! * Parent class for SNR Estimators */ @@ -45,8 +52,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est //! Update the current registers virtual int update(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items); //! Use the register values to compute a new estimate virtual double snr(); @@ -64,8 +70,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_simple : ~digital_impl_mpsk_snr_est_simple() {} int update(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items); double snr(); }; @@ -81,8 +86,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_skew : ~digital_impl_mpsk_snr_est_skew() {} int update(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items); double snr(); }; @@ -98,8 +102,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_m2m4 : ~digital_impl_mpsk_snr_est_m2m4() {} int update(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items); double snr(); }; @@ -115,8 +118,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_svn : ~digital_impl_mpsk_snr_est_svn() {} int update(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + gr_vector_const_void_star &input_items); double snr(); }; diff --git a/gr-digital/include/digital_mpsk_snr_est_cc.h b/gr-digital/include/digital_mpsk_snr_est_cc.h index 84d6380a9..126b5f8c9 100644 --- a/gr-digital/include/digital_mpsk_snr_est_cc.h +++ b/gr-digital/include/digital_mpsk_snr_est_cc.h @@ -29,13 +29,6 @@ class digital_mpsk_snr_est_cc; typedef boost::shared_ptr digital_mpsk_snr_est_cc_sptr; -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 (>= 3 dB) - SNR_EST_SVN // SVN-based est (>= 0dB) -}; - DIGITAL_API digital_mpsk_snr_est_cc_sptr digital_make_mpsk_snr_est_cc(snr_est_type_t type, double alpha); diff --git a/gr-digital/lib/digital_impl_mpsk_snr_est.cc b/gr-digital/lib/digital_impl_mpsk_snr_est.cc index aa0d4ffb9..8adc6ffed 100644 --- a/gr-digital/lib/digital_impl_mpsk_snr_est.cc +++ b/gr-digital/lib/digital_impl_mpsk_snr_est.cc @@ -50,8 +50,7 @@ digital_impl_mpsk_snr_est::alpha() const int digital_impl_mpsk_snr_est::update(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items) { throw std::runtime_error("digital_impl_mpsk_snr_est: Unimplemented"); } @@ -77,8 +76,7 @@ digital_impl_mpsk_snr_est_simple::digital_impl_mpsk_snr_est_simple( int digital_impl_mpsk_snr_est_simple::update( int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items) { const gr_complex *in = (const gr_complex *) input_items[0]; @@ -117,8 +115,7 @@ digital_impl_mpsk_snr_est_skew::digital_impl_mpsk_snr_est_skew( int digital_impl_mpsk_snr_est_skew::update( int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items) { const gr_complex *in = (const gr_complex *) input_items[0]; @@ -164,8 +161,7 @@ digital_impl_mpsk_snr_est_m2m4::digital_impl_mpsk_snr_est_m2m4( int digital_impl_mpsk_snr_est_m2m4::update( int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items) { const gr_complex *in = (const gr_complex *) input_items[0]; @@ -202,8 +198,7 @@ digital_impl_mpsk_snr_est_svn::digital_impl_mpsk_snr_est_svn( int digital_impl_mpsk_snr_est_svn::update( int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items) { const gr_complex *in = (const gr_complex *) input_items[0]; diff --git a/gr-digital/lib/digital_mpsk_snr_est_cc.cc b/gr-digital/lib/digital_mpsk_snr_est_cc.cc index 0830b4a4d..7d75dbb8b 100644 --- a/gr-digital/lib/digital_mpsk_snr_est_cc.cc +++ b/gr-digital/lib/digital_mpsk_snr_est_cc.cc @@ -63,7 +63,12 @@ digital_mpsk_snr_est_cc::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { - return d_snr_est->update(noutput_items, input_items, output_items); + // This is a pass-through block; copy input to output + memcpy(output_items[0], input_items[0], + noutput_items * sizeof(gr_complex)); + + // Update the SNR estimate registers from the current inputs + return d_snr_est->update(noutput_items, input_items); } double diff --git a/gr-digital/swig/digital_mpsk_snr_est_cc.i b/gr-digital/swig/digital_mpsk_snr_est_cc.i index cb61e9482..42114f372 100644 --- a/gr-digital/swig/digital_mpsk_snr_est_cc.i +++ b/gr-digital/swig/digital_mpsk_snr_est_cc.i @@ -22,13 +22,6 @@ GR_SWIG_BLOCK_MAGIC(digital,mpsk_snr_est_cc); -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 (>= 3 dB) - SNR_EST_SVN // SVN-based est (>= 0dB) -}; - digital_mpsk_snr_est_cc_sptr digital_make_mpsk_snr_est_cc(snr_est_type_t type, double alpha); -- cgit From 91e29b5819955818671dae779203ffa8f49b66c4 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 29 Dec 2011 12:37:14 -0500 Subject: digital: QA code for SNR estimators. --- gr-digital/python/Makefile.am | 1 + gr-digital/python/qa_mpsk_snr_est.py | 113 +++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100755 gr-digital/python/qa_mpsk_snr_est.py 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_mpsk_snr_est.py b/gr-digital/python/qa_mpsk_snr_est.py new file mode 100755 index 000000000..b7f6a5280 --- /dev/null +++ b/gr-digital/python/qa_mpsk_snr_est.py @@ -0,0 +1,113 @@ +#!/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] + + op = digital.mpsk_snr_est_cc (digital.SNR_EST_SIMPLE, 0.001) + + 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] + + op = digital.mpsk_snr_est_cc (digital.SNR_EST_SKEW, 0.001) + 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] + + op = digital.mpsk_snr_est_cc (digital.SNR_EST_M2M4, 0.001) + 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] + + op = digital.mpsk_snr_est_cc (digital.SNR_EST_SVN, 0.001) + + 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) + op = digital.probe_mpsk_snr_est_c (digital.SNR_EST_M2M4, 0.001) + + 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") + -- cgit From 2db40bb40eda996bf47417a04ec001acb422d3d9 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 29 Dec 2011 12:38:27 -0500 Subject: digital: adding an example program for the SNR estimators with Python code to compare. --- gr-digital/examples/CMakeLists.txt | 1 + gr-digital/examples/Makefile.am | 3 +- gr-digital/examples/snr_estimators.py | 174 ++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 1 deletion(-) create mode 100755 gr-digital/examples/snr_estimators.py 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/snr_estimators.py b/gr-digital/examples/snr_estimators.py new file mode 100755 index 000000000..0f9fbca2b --- /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_svn(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, + "svn": digital.SNR_EST_SVN} + py_estimators = {"simple": snr_est_simple, + "skew": snr_est_skew, + "m2m4": snr_est_m2m4, + "svn": snr_est_svn} + + + 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() + + gain =0.5 + alpha = 0.004 + + 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 = gain*(bits + n_cpx/scale) + print "SNR: ", snr + + Sknown = scipy.mean((yy/gain)**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, 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() + -- cgit From 886e3c258ff40b4d10e7e8fc28912f14565a4fd1 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 29 Dec 2011 15:38:49 -0500 Subject: digital: adding documentation for SNR estimators; added an estimator for M2M4 type that allows the user to set the kurtosis of the signal and noise, if known, to work with non-MPSK and non-AWGN channels (untested). Also, the technique is signal to variation ratio (SVR), not SVN. Couldn't read my own writing. --- gr-digital/examples/snr_estimators.py | 6 +- gr-digital/include/digital_impl_mpsk_snr_est.h | 88 ++++++++++++++++++++++++-- gr-digital/lib/digital_impl_mpsk_snr_est.cc | 50 ++++++++++++++- gr-digital/lib/digital_mpsk_snr_est_cc.cc | 6 +- gr-digital/lib/digital_probe_mpsk_snr_est_c.cc | 4 +- gr-digital/swig/digital_swig.i | 2 +- 6 files changed, 140 insertions(+), 16 deletions(-) diff --git a/gr-digital/examples/snr_estimators.py b/gr-digital/examples/snr_estimators.py index 0f9fbca2b..6bd9257fa 100755 --- a/gr-digital/examples/snr_estimators.py +++ b/gr-digital/examples/snr_estimators.py @@ -68,7 +68,7 @@ def snr_est_m2m4(signal): 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_svn(signal): +def snr_est_svr(signal): N = len(signal) ssum = 0 msum = 0 @@ -87,11 +87,11 @@ def main(): gr_estimators = {"simple": digital.SNR_EST_SIMPLE, "skew": digital.SNR_EST_SKEW, "m2m4": digital.SNR_EST_M2M4, - "svn": digital.SNR_EST_SVN} + "svr": digital.SNR_EST_SVR} py_estimators = {"simple": snr_est_simple, "skew": snr_est_skew, "m2m4": snr_est_m2m4, - "svn": snr_est_svn} + "svr": snr_est_svr} parser = OptionParser(option_class=eng_option, conflict_handler="resolve") diff --git a/gr-digital/include/digital_impl_mpsk_snr_est.h b/gr-digital/include/digital_impl_mpsk_snr_est.h index a96f3e9c1..e530782bc 100644 --- a/gr-digital/include/digital_impl_mpsk_snr_est.h +++ b/gr-digital/include/digital_impl_mpsk_snr_est.h @@ -29,7 +29,7 @@ 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_SVN // SVN-based est (>= 0dB) + SNR_EST_SVR // SVR-based est (>= 0dB) }; /*! @@ -98,6 +98,21 @@ class DIGITAL_API digital_impl_mpsk_snr_est_m2m4 : double d_y1, d_y2; public: + /*! \brief SNR Estimator using 2nd and 4th-order moments. + * + * 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. + */ digital_impl_mpsk_snr_est_m2m4(double alpha); ~digital_impl_mpsk_snr_est_m2m4() {} @@ -106,16 +121,81 @@ class DIGITAL_API digital_impl_mpsk_snr_est_m2m4 : double snr(); }; +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: + /*! \brief SNR Estimator using 2nd and 4th-order moments. + * + * 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. + */ + digital_impl_snr_est_m2m4(double alpha, double ka, double kw); + ~digital_impl_snr_est_m2m4() {} + + int update(int noutput_items, + gr_vector_const_void_star &input_items); + double snr(); +}; + -class DIGITAL_API digital_impl_mpsk_snr_est_svn : +class DIGITAL_API digital_impl_mpsk_snr_est_svr : public digital_impl_mpsk_snr_est { private: double d_y1, d_y2; public: - digital_impl_mpsk_snr_est_svn(double alpha); - ~digital_impl_mpsk_snr_est_svn() {} + /*! \brief Signal-to-Variation Ratio SNR Estimator. + * + * 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. + */ + digital_impl_mpsk_snr_est_svr(double alpha); + ~digital_impl_mpsk_snr_est_svr() {} int update(int noutput_items, gr_vector_const_void_star &input_items); diff --git a/gr-digital/lib/digital_impl_mpsk_snr_est.cc b/gr-digital/lib/digital_impl_mpsk_snr_est.cc index 8adc6ffed..87ac84e04 100644 --- a/gr-digital/lib/digital_impl_mpsk_snr_est.cc +++ b/gr-digital/lib/digital_impl_mpsk_snr_est.cc @@ -187,7 +187,51 @@ digital_impl_mpsk_snr_est_m2m4::snr() /********************************************************************/ -digital_impl_mpsk_snr_est_svn::digital_impl_mpsk_snr_est_svn( +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, + gr_vector_const_void_star &input_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + + 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) { @@ -196,7 +240,7 @@ digital_impl_mpsk_snr_est_svn::digital_impl_mpsk_snr_est_svn( } int -digital_impl_mpsk_snr_est_svn::update( +digital_impl_mpsk_snr_est_svr::update( int noutput_items, gr_vector_const_void_star &input_items) { @@ -215,7 +259,7 @@ digital_impl_mpsk_snr_est_svn::update( } double -digital_impl_mpsk_snr_est_svn::snr() +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 index 7d75dbb8b..b71ac0022 100644 --- a/gr-digital/lib/digital_mpsk_snr_est_cc.cc +++ b/gr-digital/lib/digital_mpsk_snr_est_cc.cc @@ -67,7 +67,7 @@ digital_mpsk_snr_est_cc::work(int noutput_items, memcpy(output_items[0], input_items[0], noutput_items * sizeof(gr_complex)); - // Update the SNR estimate registers from the current inputs + // Update the SNR estimate registers from the current return d_snr_est->update(noutput_items, input_items); } @@ -110,8 +110,8 @@ digital_mpsk_snr_est_cc::set_type(snr_est_type_t t) case(SNR_EST_M2M4): d_snr_est = new digital_impl_mpsk_snr_est_m2m4(d_alpha); break; - case(SNR_EST_SVN): - d_snr_est = new digital_impl_mpsk_snr_est_svn(d_alpha); + 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"); diff --git a/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc b/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc index 259074e13..07f4e93de 100644 --- a/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc +++ b/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc @@ -106,8 +106,8 @@ digital_probe_mpsk_snr_est_c::set_type(snr_est_type_t t) case(SNR_EST_M2M4): d_snr_est = new digital_impl_mpsk_snr_est_m2m4(d_alpha); break; - case(SNR_EST_SVN): - d_snr_est = new digital_impl_mpsk_snr_est_svn(d_alpha); + 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"); diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i index bc50fc727..962cb5d28 100644 --- a/gr-digital/swig/digital_swig.i +++ b/gr-digital/swig/digital_swig.i @@ -28,7 +28,7 @@ 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_SVN // SVN-based est (>= 0dB) + SNR_EST_SVR // SVR-based est (>= 0dB) }; %include -- cgit From 062f4f37c8dd543cbd29ab4a4745534497c920a8 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 29 Dec 2011 18:28:52 -0500 Subject: digital: fixed QA code for SNR estimator SVR name change. --- gr-digital/python/qa_mpsk_snr_est.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gr-digital/python/qa_mpsk_snr_est.py b/gr-digital/python/qa_mpsk_snr_est.py index b7f6a5280..d62b8b84f 100755 --- a/gr-digital/python/qa_mpsk_snr_est.py +++ b/gr-digital/python/qa_mpsk_snr_est.py @@ -82,7 +82,7 @@ class test_mpsk_snr_est (gr_unittest.TestCase): def test_mpsk_snr_est_svn (self): expected_result = [10.90, 6.00, 4.76, 4.97, 5.49] - op = digital.mpsk_snr_est_cc (digital.SNR_EST_SVN, 0.001) + op = digital.mpsk_snr_est_cc (digital.SNR_EST_SVR, 0.001) actual_result = self.mpsk_snr_est_setup(op) self.assertFloatTuplesAlmostEqual (expected_result, actual_result, 2) -- cgit From 36dda1f11620c6c9db63036d76a67b3be3f711bc Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 29 Dec 2011 18:30:27 -0500 Subject: digital: added documentation for SNR estimators; made a Doxygen group for them. Also set the alpha value to a default of 0.001; most won't need to change this. --- docs/doxygen/other/group_defs.dox | 1 + gr-digital/include/digital_impl_mpsk_snr_est.h | 194 +++++++++++++++------- gr-digital/include/digital_mpsk_snr_est_cc.h | 30 +++- gr-digital/include/digital_probe_mpsk_snr_est_c.h | 27 ++- gr-digital/swig/digital_mpsk_snr_est_cc.i | 6 +- gr-digital/swig/digital_probe_mpsk_snr_est_c.i | 2 +- 6 files changed, 189 insertions(+), 71 deletions(-) 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/gr-digital/include/digital_impl_mpsk_snr_est.h b/gr-digital/include/digital_impl_mpsk_snr_est.h index e530782bc..5a85d100b 100644 --- a/gr-digital/include/digital_impl_mpsk_snr_est.h +++ b/gr-digital/include/digital_impl_mpsk_snr_est.h @@ -25,6 +25,19 @@ #include #include +//! 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) @@ -32,8 +45,9 @@ enum snr_est_type_t { SNR_EST_SVR // SVR-based est (>= 0dB) }; -/*! - * Parent class for SNR Estimators +/*! \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 { @@ -41,6 +55,12 @@ class DIGITAL_API digital_impl_mpsk_snr_est double d_alpha, d_beta; public: + /*! Constructor + * + * Parameters: + * \li \p alpha: the update rate of internal running average + * calculations. + */ digital_impl_mpsk_snr_est(double alpha); virtual ~digital_impl_mpsk_snr_est(); @@ -59,6 +79,14 @@ class DIGITAL_API digital_impl_mpsk_snr_est }; +//! \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 { @@ -66,6 +94,12 @@ class DIGITAL_API digital_impl_mpsk_snr_est_simple : double d_y1, d_y2; public: + /*! Constructor + * + * Parameters: + * \li \p alpha: the update rate of internal running average + * calculations. + */ digital_impl_mpsk_snr_est_simple(double alpha); ~digital_impl_mpsk_snr_est_simple() {} @@ -75,6 +109,16 @@ class DIGITAL_API digital_impl_mpsk_snr_est_simple : }; +//! \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 { @@ -82,6 +126,12 @@ class DIGITAL_API digital_impl_mpsk_snr_est_skew : double d_y1, d_y2, d_y3; public: + /*! Constructor + * + * Parameters: + * \li \p alpha: the update rate of internal running average + * calculations. + */ digital_impl_mpsk_snr_est_skew(double alpha); ~digital_impl_mpsk_snr_est_skew() {} @@ -91,6 +141,22 @@ class DIGITAL_API digital_impl_mpsk_snr_est_skew : }; +//! \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 { @@ -98,20 +164,11 @@ class DIGITAL_API digital_impl_mpsk_snr_est_m2m4 : double d_y1, d_y2; public: - /*! \brief SNR Estimator using 2nd and 4th-order moments. - * - * 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. + /*! Constructor * - * 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. + * Parameters: + * \li \p alpha: the update rate of internal running average + * calculations. */ digital_impl_mpsk_snr_est_m2m4(double alpha); ~digital_impl_mpsk_snr_est_m2m4() {} @@ -121,6 +178,37 @@ class DIGITAL_API digital_impl_mpsk_snr_est_m2m4 : 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 { @@ -129,34 +217,13 @@ class DIGITAL_API digital_impl_snr_est_m2m4 : double d_ka, d_kw; public: - /*! \brief SNR Estimator using 2nd and 4th-order moments. - * - * 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. + /*! Constructor * - * 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. + * Parameters: + * \li \p alpha: the update rate of internal running average + * calculations. + * \li \p ka: estimate of the signal kurtosis (1 for PSK) + * \li \p 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() {} @@ -167,6 +234,27 @@ class DIGITAL_API digital_impl_snr_est_m2m4 : }; +//! \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 { @@ -174,25 +262,11 @@ class DIGITAL_API digital_impl_mpsk_snr_est_svr : double d_y1, d_y2; public: - /*! \brief Signal-to-Variation Ratio SNR Estimator. - * - * 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. + /*! Constructor * - * 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. + * Parameters: + * \li \p alpha: the update rate of internal running average + * calculations. */ digital_impl_mpsk_snr_est_svr(double alpha); ~digital_impl_mpsk_snr_est_svr() {} diff --git a/gr-digital/include/digital_mpsk_snr_est_cc.h b/gr-digital/include/digital_mpsk_snr_est_cc.h index 126b5f8c9..295c1648b 100644 --- a/gr-digital/include/digital_mpsk_snr_est_cc.h +++ b/gr-digital/include/digital_mpsk_snr_est_cc.h @@ -30,10 +30,24 @@ class digital_mpsk_snr_est_cc; typedef boost::shared_ptr 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, double alpha); +digital_make_mpsk_snr_est_cc(snr_est_type_t type, + double alpha=0.001); -/*! - * Provides various methods to compute SNR. +//! \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 { @@ -42,7 +56,15 @@ class DIGITAL_API digital_mpsk_snr_est_cc : public gr_sync_block double d_alpha; digital_impl_mpsk_snr_est *d_snr_est; - // Factory function returning shared pointer of this class + /*! Factory function returning shared pointer of this class + * + * Parameters: + * + * \li \p type: the type of estimator to use \ref ref_snr_est_types + * "snr_est_type_t" for details about the available types. + * \li \p 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, double alpha); diff --git a/gr-digital/include/digital_probe_mpsk_snr_est_c.h b/gr-digital/include/digital_probe_mpsk_snr_est_c.h index 4920a0ae3..2b03765db 100644 --- a/gr-digital/include/digital_probe_mpsk_snr_est_c.h +++ b/gr-digital/include/digital_probe_mpsk_snr_est_c.h @@ -32,8 +32,19 @@ typedef boost::shared_ptr digital_probe_mpsk_snr_e DIGITAL_API digital_probe_mpsk_snr_est_c_sptr digital_make_probe_mpsk_snr_est_c(snr_est_type_t type, double alpha); -/*! - * Provides various methods to compute SNR. +//! \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 { @@ -42,11 +53,19 @@ class DIGITAL_API digital_probe_mpsk_snr_est_c : public gr_sync_block double d_alpha; digital_impl_mpsk_snr_est *d_snr_est; - // Factory function returning shared pointer of this class + /*! Factory function returning shared pointer of this class + * + * Parameters: + * + * \li \p type: the type of estimator to use \ref ref_snr_est_types + * "snr_est_type_t" for details about the available types. + * \li \p 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, double alpha); - // Private constructor + //! Private constructor digital_probe_mpsk_snr_est_c(snr_est_type_t type, double alpha); public: diff --git a/gr-digital/swig/digital_mpsk_snr_est_cc.i b/gr-digital/swig/digital_mpsk_snr_est_cc.i index 42114f372..947c5ab86 100644 --- a/gr-digital/swig/digital_mpsk_snr_est_cc.i +++ b/gr-digital/swig/digital_mpsk_snr_est_cc.i @@ -23,12 +23,14 @@ 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, double alpha); +digital_make_mpsk_snr_est_cc(snr_est_type_t type, + 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, double alpha); + void digital_mpsk_snr_est_cc(snr_est_type_t type, + double alpha); public: double snr(); diff --git a/gr-digital/swig/digital_probe_mpsk_snr_est_c.i b/gr-digital/swig/digital_probe_mpsk_snr_est_c.i index fe3684a81..fbe04cec2 100644 --- a/gr-digital/swig/digital_probe_mpsk_snr_est_c.i +++ b/gr-digital/swig/digital_probe_mpsk_snr_est_c.i @@ -24,7 +24,7 @@ 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, - double alpha); + double alpha=0.001); class digital_probe_mpsk_snr_est_c : public gr_sync_block { -- cgit From 3d92c79e311f40cb2f3839b5ac68eab76c476408 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 30 Dec 2011 10:58:04 -0500 Subject: digital: SNR estimators just take a complex vector; not full vector of complex vectors. --- gr-digital/include/digital_impl_mpsk_snr_est.h | 12 ++++++------ gr-digital/lib/digital_impl_mpsk_snr_est.cc | 22 ++++++---------------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/gr-digital/include/digital_impl_mpsk_snr_est.h b/gr-digital/include/digital_impl_mpsk_snr_est.h index 5a85d100b..cae95da09 100644 --- a/gr-digital/include/digital_impl_mpsk_snr_est.h +++ b/gr-digital/include/digital_impl_mpsk_snr_est.h @@ -72,7 +72,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est //! Update the current registers virtual int update(int noutput_items, - gr_vector_const_void_star &input_items); + const gr_complex *in); //! Use the register values to compute a new estimate virtual double snr(); @@ -104,7 +104,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_simple : ~digital_impl_mpsk_snr_est_simple() {} int update(int noutput_items, - gr_vector_const_void_star &input_items); + const gr_complex *in); double snr(); }; @@ -136,7 +136,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_skew : ~digital_impl_mpsk_snr_est_skew() {} int update(int noutput_items, - gr_vector_const_void_star &input_items); + const gr_complex *in); double snr(); }; @@ -174,7 +174,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_m2m4 : ~digital_impl_mpsk_snr_est_m2m4() {} int update(int noutput_items, - gr_vector_const_void_star &input_items); + const gr_complex *in); double snr(); }; @@ -229,7 +229,7 @@ class DIGITAL_API digital_impl_snr_est_m2m4 : ~digital_impl_snr_est_m2m4() {} int update(int noutput_items, - gr_vector_const_void_star &input_items); + const gr_complex *in); double snr(); }; @@ -272,7 +272,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_svr : ~digital_impl_mpsk_snr_est_svr() {} int update(int noutput_items, - gr_vector_const_void_star &input_items); + const gr_complex *in); double snr(); }; diff --git a/gr-digital/lib/digital_impl_mpsk_snr_est.cc b/gr-digital/lib/digital_impl_mpsk_snr_est.cc index 87ac84e04..38177083f 100644 --- a/gr-digital/lib/digital_impl_mpsk_snr_est.cc +++ b/gr-digital/lib/digital_impl_mpsk_snr_est.cc @@ -50,7 +50,7 @@ digital_impl_mpsk_snr_est::alpha() const int digital_impl_mpsk_snr_est::update(int noutput_items, - gr_vector_const_void_star &input_items) + const gr_complex *in) { throw std::runtime_error("digital_impl_mpsk_snr_est: Unimplemented"); } @@ -76,10 +76,8 @@ digital_impl_mpsk_snr_est_simple::digital_impl_mpsk_snr_est_simple( int digital_impl_mpsk_snr_est_simple::update( int noutput_items, - gr_vector_const_void_star &input_items) + const gr_complex *in) { - const gr_complex *in = (const gr_complex *) input_items[0]; - for (int i = 0; i < noutput_items; i++){ double y1 = abs(in[i]); d_y1 = d_alpha*y1 + d_beta*d_y1; @@ -115,10 +113,8 @@ digital_impl_mpsk_snr_est_skew::digital_impl_mpsk_snr_est_skew( int digital_impl_mpsk_snr_est_skew::update( int noutput_items, - gr_vector_const_void_star &input_items) + const gr_complex *in) { - const gr_complex *in = (const gr_complex *) input_items[0]; - for (int i = 0; i < noutput_items; i++){ double y1 = abs(in[i]); d_y1 = d_alpha*y1 + d_beta*d_y1; @@ -161,10 +157,8 @@ digital_impl_mpsk_snr_est_m2m4::digital_impl_mpsk_snr_est_m2m4( int digital_impl_mpsk_snr_est_m2m4::update( int noutput_items, - gr_vector_const_void_star &input_items) + const gr_complex *in) { - const gr_complex *in = (const gr_complex *) input_items[0]; - 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; @@ -200,10 +194,8 @@ digital_impl_snr_est_m2m4::digital_impl_snr_est_m2m4( int digital_impl_snr_est_m2m4::update( int noutput_items, - gr_vector_const_void_star &input_items) + const gr_complex *in) { - const gr_complex *in = (const gr_complex *) input_items[0]; - 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; @@ -242,10 +234,8 @@ digital_impl_mpsk_snr_est_svr::digital_impl_mpsk_snr_est_svr( int digital_impl_mpsk_snr_est_svr::update( int noutput_items, - gr_vector_const_void_star &input_items) + const gr_complex *in) { - const gr_complex *in = (const gr_complex *) input_items[0]; - for (int i = 0; i < noutput_items; i++){ double x = abs(in[i]); double x1 = abs(in[i-1]); -- cgit From 0bf8934a7f1bf41916a5f7562b250c18a87034c7 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 30 Dec 2011 10:58:58 -0500 Subject: digital: snr probe passing just the 0th input stream to SNR estimator. --- gr-digital/lib/digital_probe_mpsk_snr_est_c.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc b/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc index 07f4e93de..3d97ff899 100644 --- a/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc +++ b/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc @@ -64,7 +64,8 @@ digital_probe_mpsk_snr_est_c::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { - return d_snr_est->update(noutput_items, input_items); + const gr_complex *in = (const gr_complex*)input_items[0]; + return d_snr_est->update(noutput_items, in); } double -- cgit From a4d62472975aaeb50fa96c360c4b24d3ad84cf6e Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 30 Dec 2011 11:04:48 -0500 Subject: digital: the SNR estimator block now issues a tag with the SNR (key = 'snr'). The number of samples between when the tag is sent is set in the constructor (default = 10000) and can be changed. --- gr-digital/include/digital_mpsk_snr_est_cc.h | 21 +++++++- gr-digital/lib/digital_mpsk_snr_est_cc.cc | 71 +++++++++++++++++++++++++--- gr-digital/swig/digital_mpsk_snr_est_cc.i | 2 + 3 files changed, 86 insertions(+), 8 deletions(-) diff --git a/gr-digital/include/digital_mpsk_snr_est_cc.h b/gr-digital/include/digital_mpsk_snr_est_cc.h index 295c1648b..40c790222 100644 --- a/gr-digital/include/digital_mpsk_snr_est_cc.h +++ b/gr-digital/include/digital_mpsk_snr_est_cc.h @@ -31,6 +31,7 @@ typedef boost::shared_ptr 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. @@ -53,23 +54,33 @@ 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: * * \li \p type: the type of estimator to use \ref ref_snr_est_types * "snr_est_type_t" for details about the available types. + * \li \p tag_nsamples: after this many samples, a tag containing + * the SNR (key='snr') will be sent * \li \p 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, double alpha); + 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, double alpha); + digital_mpsk_snr_est_cc(snr_est_type_t type, + int tag_nsamples, + double alpha); public: @@ -85,12 +96,18 @@ public: //! 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); }; diff --git a/gr-digital/lib/digital_mpsk_snr_est_cc.cc b/gr-digital/lib/digital_mpsk_snr_est_cc.cc index b71ac0022..b5a60f0d3 100644 --- a/gr-digital/lib/digital_mpsk_snr_est_cc.cc +++ b/gr-digital/lib/digital_mpsk_snr_est_cc.cc @@ -30,12 +30,15 @@ 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, 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)), @@ -44,12 +47,19 @@ digital_mpsk_snr_est_cc::digital_mpsk_snr_est_cc(snr_est_type_t type, 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() @@ -67,8 +77,36 @@ digital_mpsk_snr_est_cc::work(int noutput_items, memcpy(output_items[0], input_items[0], noutput_items * sizeof(gr_complex)); - // Update the SNR estimate registers from the current - return d_snr_est->update(noutput_items, input_items); + 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 @@ -86,6 +124,12 @@ 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 { @@ -118,10 +162,25 @@ digital_mpsk_snr_est_cc::set_type(snr_est_type_t t) } } +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) { - d_alpha = alpha; - if(d_snr_est) - d_snr_est->set_alpha(d_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/swig/digital_mpsk_snr_est_cc.i b/gr-digital/swig/digital_mpsk_snr_est_cc.i index 947c5ab86..b0fc6bccf 100644 --- a/gr-digital/swig/digital_mpsk_snr_est_cc.i +++ b/gr-digital/swig/digital_mpsk_snr_est_cc.i @@ -24,12 +24,14 @@ 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: -- cgit From ef4d48de26b64d89851a93fc5402b33fcc1a809f Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 30 Dec 2011 11:10:23 -0500 Subject: digital: update to qa and example code for new constructor with tag_nsamples arg. --- gr-digital/examples/snr_estimators.py | 10 +++++----- gr-digital/python/qa_mpsk_snr_est.py | 22 +++++++++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/gr-digital/examples/snr_estimators.py b/gr-digital/examples/snr_estimators.py index 6bd9257fa..432abd455 100755 --- a/gr-digital/examples/snr_estimators.py +++ b/gr-digital/examples/snr_estimators.py @@ -118,8 +118,8 @@ def main(): snr_python = list() snr_gr = list() - gain =0.5 - alpha = 0.004 + # when to issue an SNR tag; can be ignored in this example. + ntag = 10000 n_cpx = xx + 1j*xy @@ -133,10 +133,10 @@ def main(): for snr in SNR_dB: SNR = 10.0**(snr/10.0) scale = scipy.sqrt(SNR) - yy = gain*(bits + n_cpx/scale) + yy = bits + n_cpx/scale print "SNR: ", snr - Sknown = scipy.mean((yy/gain)**2) + Sknown = scipy.mean(yy**2) Nknown = scipy.var(n_cpx/scale)/2 snr0 = Sknown/Nknown snr0dB = 10.0*scipy.log10(snr0) @@ -146,7 +146,7 @@ def main(): snr_python.append(snrdB) gr_src = gr.vector_source_c(bits.tolist(), False) - gr_snr = digital.mpsk_snr_est_cc(gr_est, 0.001) + 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() diff --git a/gr-digital/python/qa_mpsk_snr_est.py b/gr-digital/python/qa_mpsk_snr_est.py index d62b8b84f..e3abff908 100755 --- a/gr-digital/python/qa_mpsk_snr_est.py +++ b/gr-digital/python/qa_mpsk_snr_est.py @@ -60,7 +60,9 @@ class test_mpsk_snr_est (gr_unittest.TestCase): def test_mpsk_snr_est_simple (self): expected_result = [11.48, 5.91, 3.30, 2.08, 1.46] - op = digital.mpsk_snr_est_cc (digital.SNR_EST_SIMPLE, 0.001) + 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) @@ -68,21 +70,29 @@ class test_mpsk_snr_est (gr_unittest.TestCase): def test_mpsk_snr_est_skew (self): expected_result = [11.48, 5.91, 3.30, 2.08, 1.46] - op = digital.mpsk_snr_est_cc (digital.SNR_EST_SKEW, 0.001) + 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] - op = digital.mpsk_snr_est_cc (digital.SNR_EST_M2M4, 0.001) + 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] - op = digital.mpsk_snr_est_cc (digital.SNR_EST_SVR, 0.001) + 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) @@ -95,7 +105,9 @@ class test_mpsk_snr_est (gr_unittest.TestCase): src_data = [b+(i*n) for b,n in zip(self._bits, self._noise)] src = gr.vector_source_c (src_data) - op = digital.probe_mpsk_snr_est_c (digital.SNR_EST_M2M4, 0.001) + + alpha = 0.001 + op = digital.probe_mpsk_snr_est_c (digital.SNR_EST_M2M4, alpha) tb = gr.top_block () tb.connect (src, op) -- cgit From 8e134f11639deeadd0ed242e0f12360ef628d495 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 30 Dec 2011 11:24:12 -0500 Subject: digital: fixed documentation of parameters. --- gr-digital/include/digital_impl_mpsk_snr_est.h | 16 ++++++++-------- gr-digital/include/digital_mpsk_snr_est_cc.h | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/gr-digital/include/digital_impl_mpsk_snr_est.h b/gr-digital/include/digital_impl_mpsk_snr_est.h index cae95da09..df7dbadec 100644 --- a/gr-digital/include/digital_impl_mpsk_snr_est.h +++ b/gr-digital/include/digital_impl_mpsk_snr_est.h @@ -58,7 +58,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est /*! Constructor * * Parameters: - * \li \p alpha: the update rate of internal running average + * \param alpha: the update rate of internal running average * calculations. */ digital_impl_mpsk_snr_est(double alpha); @@ -97,7 +97,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_simple : /*! Constructor * * Parameters: - * \li \p alpha: the update rate of internal running average + * \param alpha: the update rate of internal running average * calculations. */ digital_impl_mpsk_snr_est_simple(double alpha); @@ -129,7 +129,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_skew : /*! Constructor * * Parameters: - * \li \p alpha: the update rate of internal running average + * \param alpha: the update rate of internal running average * calculations. */ digital_impl_mpsk_snr_est_skew(double alpha); @@ -167,7 +167,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_m2m4 : /*! Constructor * * Parameters: - * \li \p alpha: the update rate of internal running average + * \param alpha: the update rate of internal running average * calculations. */ digital_impl_mpsk_snr_est_m2m4(double alpha); @@ -220,10 +220,10 @@ class DIGITAL_API digital_impl_snr_est_m2m4 : /*! Constructor * * Parameters: - * \li \p alpha: the update rate of internal running average + * \param alpha: the update rate of internal running average * calculations. - * \li \p ka: estimate of the signal kurtosis (1 for PSK) - * \li \p kw: estimate of the channel noise kurtosis (2 for AWGN) + * \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() {} @@ -265,7 +265,7 @@ class DIGITAL_API digital_impl_mpsk_snr_est_svr : /*! Constructor * * Parameters: - * \li \p alpha: the update rate of internal running average + * \param alpha: the update rate of internal running average * calculations. */ digital_impl_mpsk_snr_est_svr(double alpha); diff --git a/gr-digital/include/digital_mpsk_snr_est_cc.h b/gr-digital/include/digital_mpsk_snr_est_cc.h index 40c790222..2cbd98bab 100644 --- a/gr-digital/include/digital_mpsk_snr_est_cc.h +++ b/gr-digital/include/digital_mpsk_snr_est_cc.h @@ -65,11 +65,11 @@ class DIGITAL_API digital_mpsk_snr_est_cc : public gr_sync_block * * Parameters: * - * \li \p type: the type of estimator to use \ref ref_snr_est_types + * \param type: the type of estimator to use \ref ref_snr_est_types * "snr_est_type_t" for details about the available types. - * \li \p tag_nsamples: after this many samples, a tag containing + * \param tag_nsamples: after this many samples, a tag containing * the SNR (key='snr') will be sent - * \li \p alpha: the update rate of internal running average + * \param alpha: the update rate of internal running average * calculations. */ friend DIGITAL_API digital_mpsk_snr_est_cc_sptr -- cgit From 1091192d27aab20694e1597868df4962b39ad060 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 30 Dec 2011 11:33:36 -0500 Subject: digital: adding SNR nsamples set/get functions in swig i file. --- gr-digital/swig/digital_mpsk_snr_est_cc.i | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gr-digital/swig/digital_mpsk_snr_est_cc.i b/gr-digital/swig/digital_mpsk_snr_est_cc.i index b0fc6bccf..f0ca13f87 100644 --- a/gr-digital/swig/digital_mpsk_snr_est_cc.i +++ b/gr-digital/swig/digital_mpsk_snr_est_cc.i @@ -37,7 +37,9 @@ private: 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); }; -- cgit From 6e52e9f86b40ccc38ee21068983936113e6b53dc Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 30 Dec 2011 11:35:15 -0500 Subject: digital: added tag_nsamples placeholder into SNR probe block. The intent of this block is to be able to pass messages containing the SNR at a set number of samples. --- gr-digital/include/digital_probe_mpsk_snr_est_c.h | 28 ++++++++++++++--- gr-digital/lib/digital_probe_mpsk_snr_est_c.cc | 38 ++++++++++++++++++++--- gr-digital/python/qa_mpsk_snr_est.py | 3 +- gr-digital/swig/digital_probe_mpsk_snr_est_c.i | 4 +++ 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/gr-digital/include/digital_probe_mpsk_snr_est_c.h b/gr-digital/include/digital_probe_mpsk_snr_est_c.h index 2b03765db..a78e90412 100644 --- a/gr-digital/include/digital_probe_mpsk_snr_est_c.h +++ b/gr-digital/include/digital_probe_mpsk_snr_est_c.h @@ -30,7 +30,9 @@ class digital_probe_mpsk_snr_est_c; typedef boost::shared_ptr 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, double alpha); +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 @@ -50,23 +52,33 @@ 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: * - * \li \p type: the type of estimator to use \ref ref_snr_est_types + * \param type: the type of estimator to use \ref ref_snr_est_types * "snr_est_type_t" for details about the available types. - * \li \p alpha: the update rate of internal running average + * \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, double alpha); + 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, double alpha); + digital_probe_mpsk_snr_est_c(snr_est_type_t type, + int msg_nsamples, + double alpha); public: @@ -82,12 +94,18 @@ public: //! 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); }; diff --git a/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc b/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc index 3d97ff899..5cdfea96d 100644 --- a/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc +++ b/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc @@ -30,14 +30,17 @@ 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, alpha)); + 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, double alpha) + 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)) @@ -45,12 +48,16 @@ digital_probe_mpsk_snr_est_c::digital_probe_mpsk_snr_est_c( 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() @@ -83,6 +90,12 @@ 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 { @@ -115,10 +128,25 @@ digital_probe_mpsk_snr_est_c::set_type(snr_est_type_t t) } } +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) { - d_alpha = alpha; - if(d_snr_est) - d_snr_est->set_alpha(d_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/qa_mpsk_snr_est.py b/gr-digital/python/qa_mpsk_snr_est.py index e3abff908..d392567bf 100755 --- a/gr-digital/python/qa_mpsk_snr_est.py +++ b/gr-digital/python/qa_mpsk_snr_est.py @@ -106,8 +106,9 @@ class test_mpsk_snr_est (gr_unittest.TestCase): src = gr.vector_source_c (src_data) + N = 10000 alpha = 0.001 - op = digital.probe_mpsk_snr_est_c (digital.SNR_EST_M2M4, alpha) + op = digital.probe_mpsk_snr_est_c (digital.SNR_EST_M2M4, N, alpha) tb = gr.top_block () tb.connect (src, op) diff --git a/gr-digital/swig/digital_probe_mpsk_snr_est_c.i b/gr-digital/swig/digital_probe_mpsk_snr_est_c.i index fbe04cec2..93db4127a 100644 --- a/gr-digital/swig/digital_probe_mpsk_snr_est_c.i +++ b/gr-digital/swig/digital_probe_mpsk_snr_est_c.i @@ -24,18 +24,22 @@ 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); }; -- cgit From 59ae7f87cc52e28a39b04895f2977624552f6f1d Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 30 Dec 2011 13:42:16 -0500 Subject: digital: somewhat strange buy necessary fix for autotools build with guile. --- gr-digital/swig/digital_swig.i | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i index 962cb5d28..a39ef9ab7 100644 --- a/gr-digital/swig/digital_swig.i +++ b/gr-digital/swig/digital_swig.i @@ -24,12 +24,14 @@ //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 @@ -86,6 +88,14 @@ enum snr_est_type_t { %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") %} -- cgit From 529ffdd0d60241a96b6daa72a1f942d6a92a3535 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 30 Dec 2011 00:51:41 -0800 Subject: cmake: added swig version check --- CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62eae906b..b6b5eb496 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,10 +124,20 @@ add_custom_target(uninstall ######################################################################## find_package(PythonLibs) find_package(SWIG) + +if(SWIG_FOUND) + message(STATUS "Minimum SWIG version required is 1.3.31") + set(SWIG_VERSION_CHECK FALSE) + if("${SWIG_VERSION}" VERSION_GREATER "1.3.30") + set(SWIG_VERSION_CHECK TRUE) + endif() +endif(SWIG_FOUND) + include(GrComponent) GR_REGISTER_COMPONENT("python-support" ENABLE_PYTHON PYTHONLIBS_FOUND SWIG_FOUND + SWIG_VERSION_CHECK ) find_package(CppUnit) -- cgit From 6f0aee4f7a200f87c6fbe23c12fb01cbda872608 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 22 Dec 2011 19:45:50 -0800 Subject: gr: sync the filesystem before python can parse doxygen --- cmake/Modules/GrSwig.cmake | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmake/Modules/GrSwig.cmake b/cmake/Modules/GrSwig.cmake index f49fc731c..ced8b16c8 100644 --- a/cmake/Modules/GrSwig.cmake +++ b/cmake/Modules/GrSwig.cmake @@ -72,10 +72,18 @@ function(GR_SWIG_MAKE_DOCS output_file) COMMENT "Generating doxygen xml for ${name} docs" ) + #call sync if we can to flush the doxygen writes to file before python reads + find_program(SYNC_EXECUTABLE sync) + unset(sync_command) + if(SYNC_EXECUTABLE) + set(sync_command COMMAND ${SYNC_EXECUTABLE}) + endif() + #call the swig_doc script on the xml files add_custom_command( OUTPUT ${output_file} DEPENDS ${input_files} ${OUTPUT_DIRECTORY}/xml/index.xml + ${sync_command} COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} ${CMAKE_SOURCE_DIR}/docs/doxygen/swig_doc.py ${OUTPUT_DIRECTORY}/xml -- cgit