diff options
85 files changed, 2498 insertions, 1339 deletions
diff --git a/Makefile.common b/Makefile.common index 20b8a78cf..2a5addd65 100644 --- a/Makefile.common +++ b/Makefile.common @@ -110,6 +110,10 @@ GCELL_SPU_LA = @gcell_spu_LA@ # libtool aware wrapper for ppu-embedspu GCELL_EMBEDSPU_LIBTOOL = @abs_top_srcdir@/gcell/lib/runtime/gcell-embedspu-libtool +# GR-DIGITAL includes and libraries +GR_DIGITAL_INCLUDES = @gr_digital_INCLUDES@ +GR_DIGITAL_LA = @gr_digital_LA@ + # Fix for BSD make not defining $(RM). We define it now in configure.ac # using AM_PATH_PROG, but now here have to add a -f to be like GNU make RM=$(RM_PROG) -f diff --git a/config/grc_gr_digital.m4 b/config/grc_gr_digital.m4 index 83c3f03a4..d7c1d605f 100644 --- a/config/grc_gr_digital.m4 +++ b/config/grc_gr_digital.m4 @@ -23,12 +23,29 @@ AC_DEFUN([GRC_GR_DIGITAL],[ dnl Don't do gr-digital if gnuradio-core skipped GRC_CHECK_DEPENDENCY(gr-digital, gnuradio-core) + if test $passed != with; then + dnl how and where to find INCLUDES and LA and such + gr_digital_INCLUDES="\ +-I\${abs_top_srcdir}/gr-digital/lib \ +-I\${abs_top_srcdir}/gr-digital/hier \ +-I\${abs_top_srcdir}/gr-digital/swig" + gr_digital_LA="\${abs_top_builddir}/gr-digital/lib/libgnuradio-core.la" + gr_digital_LIBDIRPATH="\${abs_top_builddir}/gr-digital/lib:\${abs_top_builddir}/gr-digital/lib/.libs" + gr_digital_SWIGDIRPATH="\${abs_top_builddir}/gr-digtial/lib/swig:\${abs_top_builddir}/gr-digital/swig/.libs:\${abs_top_srcdir}/gr-digital/swig" + gr_digital_PYDIRPATH="\${abs_top_srcdir}/gr-digital/python" + fi + + AC_SUBST(gr_digital_I) + AC_SUBST(gr_digital_SWIGDIRPATH) + AC_SUBST(gr_digital_PYDIRPATH) + AC_CONFIG_FILES([\ gr-digital/Makefile \ gr-digital/gnuradio-digital.pc \ gr-digital/apps/Makefile \ gr-digital/grc/Makefile \ gr-digital/lib/Makefile \ + gr-digital/hier/Makefile \ gr-digital/python/Makefile \ gr-digital/python/run_tests \ gr-digital/python/utils/Makefile \ diff --git a/gnuradio-core/src/guile/tests/general_ctors.test b/gnuradio-core/src/guile/tests/general_ctors.test index 813574bca..a0e39855c 100644 --- a/gnuradio-core/src/guile/tests/general_ctors.test +++ b/gnuradio-core/src/guile/tests/general_ctors.test @@ -244,13 +244,13 @@ (pass-if (true? (gr:phase-modulator-fc 0))) ;;; ./general/gr_pll_carriertracking_cc.h -(pass-if (true? (gr:pll-carriertracking-cc 0 0 0 0))) +(pass-if (true? (gr:pll-carriertracking-cc 0 0 0))) ;;; ./general/gr_pll_freqdet_cf.h -(pass-if (true? (gr:pll-freqdet-cf 0 0 0 0))) +(pass-if (true? (gr:pll-freqdet-cf 0 0 0))) ;;; ./general/gr_pll_refout_cc.h -(pass-if (true? (gr:pll-refout-cc 0 0 0 0))) +(pass-if (true? (gr:pll-refout-cc 0 0 0))) ;;; ./general/gr_pn_correlator_cc.h (pass-if (true? (gr:pn-correlator-cc 1 1 1))) diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc index b5a5aed7d..a939609f3 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc @@ -60,7 +60,7 @@ gr_pfb_clock_sync_ccf::gr_pfb_clock_sync_ccf (double sps, float loop_bw, gr_make_io_signaturev (1, 4, iosig)), d_updated (false), d_nfilters(filter_size), d_max_dev(max_rate_deviation), - d_osps(osps) + d_osps(osps), d_error(0) { d_nfilters = filter_size; d_sps = floor(sps); @@ -367,51 +367,51 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items, int nrequired = ninput_items[0] - d_taps_per_filter - d_osps; int i = 0, count = 0; - float error, error_r, error_i; + float error_r, error_i; // produce output as long as we can and there are enough input samples while((i < noutput_items-d_osps) && (count < nrequired)) { - d_filtnum = (int)floor(d_k); - - // Keep the current filter number in [0, d_nfilters] - // If we've run beyond the last filter, wrap around and go to next sample - // If we've go below 0, wrap around and go to previous sample - while(d_filtnum >= d_nfilters) { - d_k -= d_nfilters; - d_filtnum -= d_nfilters; - count += 1; - } - while(d_filtnum < 0) { - d_k += d_nfilters; - d_filtnum += d_nfilters; - count -= 1; - } - for(int k = 0; k < d_osps; k++) { + d_filtnum = (int)floor(d_k); + + // Keep the current filter number in [0, d_nfilters] + // If we've run beyond the last filter, wrap around and go to next sample + // If we've go below 0, wrap around and go to previous sample + while(d_filtnum >= d_nfilters) { + d_k -= d_nfilters; + d_filtnum -= d_nfilters; + count += 1; + } + while(d_filtnum < 0) { + d_k += d_nfilters; + d_filtnum += d_nfilters; + count -= 1; + } + out[i+k] = d_filters[d_filtnum]->filter(&in[count+k]); + d_k = d_k + d_rate_i + d_rate_f; // update phase + + if(output_items.size() == 4) { + err[i] = d_error; + outrate[i] = d_rate_f; + outk[i] = d_k; + } } + // Update the phase and rate estimates for this symbol gr_complex diff = d_diff_filters[d_filtnum]->filter(&in[count]); error_r = out[i].real() * diff.real(); error_i = out[i].imag() * diff.imag(); - error = (error_i + error_r) / 2.0; // average error from I&Q channel - - // Run the control loop to update the current phase (k) and tracking rate - d_rate_f = d_rate_f + d_beta*error; - d_k = d_k + d_alpha*error + d_rate_i + d_rate_f; + d_error = (error_i + error_r) / 2.0; // average error from I&Q channel + + // Run the control loop to update the current phase (k) and + // tracking rate estimates based on the error value + d_rate_f = d_rate_f + d_beta*d_error; + d_k = d_k + d_alpha*d_error; // Keep our rate within a good range d_rate_f = gr_branchless_clip(d_rate_f, d_max_dev); - if(output_items.size() == 4) { - // FIXME: don't really know what to do about d_osps>1 - for(int k = 0; k < d_osps; k++) { - err[i] = diff.real(); - outrate[i] = d_rate_f; - outk[i] = d_k; - } - } - i+=d_osps; count += (int)floor(d_sps); } diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h index 1f96b9000..2eae11807 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h @@ -155,6 +155,7 @@ class GR_CORE_API gr_pfb_clock_sync_ccf : public gr_block float d_max_dev; int d_filtnum; int d_osps; + float d_error; /*! * Build the polyphase filterbank timing synchronizer. diff --git a/gnuradio-core/src/lib/general/CMakeLists.txt b/gnuradio-core/src/lib/general/CMakeLists.txt index 1cd9c6bd1..cb3f0da4b 100644 --- a/gnuradio-core/src/lib/general/CMakeLists.txt +++ b/gnuradio-core/src/lib/general/CMakeLists.txt @@ -96,6 +96,7 @@ LIST(APPEND gnuradio_core_sources LIST(APPEND test_gnuradio_core_sources ${CMAKE_CURRENT_SOURCE_DIR}/qa_general.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_gr_circular_file.cc + ${CMAKE_CURRENT_SOURCE_DIR}/qa_gr_cpm.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_gr_firdes.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_gr_fxpt.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_gr_fxpt_nco.cc @@ -189,6 +190,7 @@ SET(gr_core_general_triple_threats gr_conjugate_cc gr_copy gr_cpfsk_bc + gr_cpm gr_ctcss_squelch_ff gr_decode_ccsds_27_fb gr_diff_decoder_bb diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am index f210cee39..fe545f98c 100644 --- a/gnuradio-core/src/lib/general/Makefile.am +++ b/gnuradio-core/src/lib/general/Makefile.am @@ -55,6 +55,7 @@ libgeneral_la_SOURCES = \ gr_copy.cc \ gr_count_bits.cc \ gr_cpfsk_bc.cc \ + gr_cpm.cc \ gr_ctcss_squelch_ff.cc \ gr_decode_ccsds_27_fb.cc \ gr_deinterleave.cc \ @@ -176,6 +177,7 @@ libgeneral_la_SOURCES = \ libgeneral_qa_la_SOURCES = \ qa_general.cc \ qa_gr_circular_file.cc \ + qa_gr_cpm.cc \ qa_gr_firdes.cc \ qa_gr_fxpt.cc \ qa_gr_fxpt_nco.cc \ @@ -203,6 +205,7 @@ grinclude_HEADERS = \ gr_copy.h \ gr_count_bits.h \ gr_cpfsk_bc.h \ + gr_cpm.h \ gr_ctcss_squelch_ff.h \ gr_decode_ccsds_27_fb.h \ gr_diff_decoder_bb.h \ @@ -340,6 +343,7 @@ grinclude_HEADERS = \ noinst_HEADERS = \ qa_general.h \ qa_gr_circular_file.h \ + qa_gr_cpm.h \ qa_gr_firdes.h \ qa_gr_fxpt.h \ qa_gr_fxpt_nco.h \ @@ -367,6 +371,7 @@ swiginclude_HEADERS = \ gr_conjugate_cc.i \ gr_copy.i \ gr_cpfsk_bc.i \ + gr_cpm.i \ gr_ctcss_squelch_ff.i \ gr_decode_ccsds_27_fb.i \ gr_diff_decoder_bb.i \ diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i index f9adff3fa..e965eea64 100644 --- a/gnuradio-core/src/lib/general/general.i +++ b/gnuradio-core/src/lib/general/general.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright 2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -137,6 +137,7 @@ #include <gr_annotator_alltoall.h> #include <gr_annotator_1to1.h> #include <gr_burst_tagger.h> +#include <gr_cpm.h> %} %include "gri_control_loop.i" @@ -254,3 +255,4 @@ %include "gr_annotator_alltoall.i" %include "gr_annotator_1to1.i" %include "gr_burst_tagger.i" +%include "gr_cpm.i" diff --git a/gnuradio-core/src/lib/general/gr_cpm.cc b/gnuradio-core/src/lib/general/gr_cpm.cc new file mode 100644 index 000000000..a00526b52 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_cpm.cc @@ -0,0 +1,214 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Free Software Foundation, Inc. + * + * 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. + */ + +// Calculate the taps for the CPM phase responses + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <cmath> +#include <cfloat> +#include <gr_cpm.h> + +#ifndef M_TWOPI +# define M_TWOPI (2*M_PI) +#endif + +//! Normalised sinc function, sinc(x)=sin(pi*x)/pi*x +inline double +sinc(double x) +{ + if (x == 0) { + return 1.0; + } + + return sin(M_PI * x) / (M_PI * x); +} + + +//! Taps for L-RC CPM (Raised cosine of length L symbols) +std::vector<float> +generate_cpm_lrc_taps(unsigned samples_per_sym, unsigned L) +{ + std::vector<float> taps(samples_per_sym * L, 1.0/L/samples_per_sym); + for (unsigned i = 0; i < samples_per_sym * L; i++) { + taps[i] *= 1 - cos(M_TWOPI * i / L / samples_per_sym); + } + + return taps; +} + + +/*! Taps for L-SRC CPM (Spectral raised cosine of length L symbols). + * + * L-SRC has a time-continuous phase response function of + * + * g(t) = 1/LT * sinc(2t/LT) * cos(beta * 2pi t / LT) / (1 - (4beta / LT * t)^2) + * + * which is the Fourier transform of a cos-rolloff function with rolloff + * beta, and looks like a sinc-function, multiplied with a rolloff term. + * We return the main lobe of the sinc, i.e., everything between the + * zero crossings. + * The time-discrete IR is thus + * + * g(k) = 1/Ls * sinc(2k/Ls) * cos(beta * pi k / Ls) / (1 - (4beta / Ls * k)^2) + * where k = 0...Ls-1 + * and s = samples per symbol. + */ +std::vector<float> +generate_cpm_lsrc_taps(unsigned samples_per_sym, unsigned L, double beta) +{ + double Ls = (double) L * samples_per_sym; + std::vector<double> taps_d(L * samples_per_sym, 0.0); + std::vector<float> taps(L * samples_per_sym, 0.0); + + double sum = 0; + for (unsigned i = 0; i < samples_per_sym * L; i++) { + double k = i - Ls/2; // Causal to acausal + + taps_d[i] = 1.0 / Ls * sinc(2.0 * k / Ls); + + // For k = +/-Ls/4*beta, the rolloff term's cos-function becomes zero + // and the whole thing converges to PI/4 (to prove this, use de + // l'hopital's rule). + if (fabs(fabs(k) - Ls/4/beta) < 2*DBL_EPSILON) { + taps_d[i] *= M_PI_4; + } else { + double tmp = 4.0 * beta * k / Ls; + taps_d[i] *= cos(beta * M_TWOPI * k / Ls) / (1 - tmp * tmp); + } + sum += taps_d[i]; + } + for (unsigned i = 0; i < samples_per_sym * L; i++) { + taps[i] = (float) taps_d[i] / sum; + } + + return taps; +} + + +//! Taps for L-REC CPM (Rectangular pulse shape of length L symbols) +std::vector<float> +generate_cpm_lrec_taps(unsigned samples_per_sym, unsigned L) +{ + return std::vector<float>(samples_per_sym * L, 1.0/L/samples_per_sym); +} + + +//! Helper function for TFM +double tfm_g0(double k, double sps) +{ + if (fabs(k) < 2 * DBL_EPSILON) { + return 1.145393004159143; // 1 + pi^2/48 / sqrt(2) + } + + const double pi2_24 = 0.411233516712057; // pi^2/24 + double f = M_PI * k / sps; + return sinc(k/sps) - pi2_24 * (2 * sin(f) - 2*f*cos(f) - f*f*sin(f)) / (f*f*f); +} + + +//! Taps for TFM CPM (Tamed frequency modulation) +// +// See [2, Chapter 2.7.2]. +// +// [2]: Anderson, Aulin and Sundberg; Digital Phase Modulation +std::vector<float> +generate_cpm_tfm_taps(unsigned sps, unsigned L) +{ + unsigned causal_shift = sps * L / 2; + std::vector<double> taps_d(sps * L, 0.0); + std::vector<float> taps(sps * L, 0.0); + + double sum = 0; + for (unsigned i = 0; i < sps * L; i++) { + double k = (double)(((int)i) - ((int)causal_shift)); // Causal to acausal + + taps_d[i] = tfm_g0(k - sps, sps) + + 2 * tfm_g0(k, sps) + + tfm_g0(k + sps, sps); + sum += taps_d[i]; + } + for (unsigned i = 0; i < sps * L; i++) { + taps[i] = (float) taps_d[i] / sum; + } + + return taps; +} + + +//! Taps for Gaussian CPM. Phase response is truncated after \p L symbols. +// \p bt sets the 3dB-time-bandwidth product. +// +// Note: for h = 0.5, this is the phase response for GMSK. +// +// This C99-compatible formula for the taps is taken straight +// from [1, Chapter 9.2.3]. +// A version in Q-notation can be found in [2, Chapter 2.7.2]. +// +// [1]: Karl-Dirk Kammeyer; Nachrichtenübertragung, 4th Edition. +// [2]: Anderson, Aulin and Sundberg; Digital Phase Modulation +// +std::vector<float> +generate_cpm_gaussian_taps(unsigned samples_per_sym, unsigned L, double bt) +{ + double Ls = (double) L * samples_per_sym; + std::vector<double> taps_d(L * samples_per_sym, 0.0); + std::vector<float> taps(L * samples_per_sym, 0.0); + + // alpha = sqrt(2/ln(2)) * pi * BT + double alpha = 5.336446256636997 * bt; + for (unsigned i = 0; i < samples_per_sym * L; i++) { + double k = i - Ls/2; // Causal to acausal + taps_d[i] = (erf(alpha * (k / samples_per_sym + 0.5)) - + erf(alpha * (k / samples_per_sym - 0.5))) + * 0.5 / samples_per_sym; + taps[i] = (float) taps_d[i]; + } + + return taps; +} + + +std::vector<float> +gr_cpm::phase_response(cpm_type type, unsigned samples_per_sym, unsigned L, double beta) +{ + switch (type) { + case LRC: + return generate_cpm_lrc_taps(samples_per_sym, L); + + case LSRC: + return generate_cpm_lsrc_taps(samples_per_sym, L, beta); + + case LREC: + return generate_cpm_lrec_taps(samples_per_sym, L); + + case TFM: + return generate_cpm_tfm_taps(samples_per_sym, L); + + case GAUSSIAN: + return generate_cpm_gaussian_taps(samples_per_sym, L, beta); + + default: + return generate_cpm_lrec_taps(samples_per_sym, 1); + } +} + diff --git a/gnuradio-core/src/lib/general/gr_cpm.h b/gnuradio-core/src/lib/general/gr_cpm.h new file mode 100644 index 000000000..ef2ff8414 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_cpm.h @@ -0,0 +1,81 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Free Software Foundation, Inc. + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_GR_CPM_H +#define INCLUDED_GR_CPM_H + +#include <gr_core_api.h> +#include <vector> + +class GR_CORE_API gr_cpm +{ + public: + enum cpm_type { + LRC, + LSRC, + LREC, + TFM, + GAUSSIAN, + GENERIC = 999 + }; + + /*! \brief Return the taps for an interpolating FIR filter (gr_interp_fir_filter_fff). + * + * These taps represent the phase response \f$g(k)\f$ for use in a CPM modulator, + * see also gr_cpmmod_bc. + * + * \param type The CPM type (Rectangular, Raised Cosine, Spectral Raised Cosine, + * Tamed FM or Gaussian). + * \param samples_per_sym Samples per symbol. + * \param L The length of the phase response in symbols. + * \param beta For Spectral Raised Cosine, this is the rolloff factor. For Gaussian + * phase responses, this the 3dB-time-bandwidth product. For all other + * cases, it is ignored. + * + * Output: returns a vector of length \a K = \p samples_per_sym x \p L. + * This can be used directly in an interpolating FIR filter such as + * gr_interp_fir_filter_fff with interpolation factor \p samples_per_sym. + * + * All phase responses are normalised s.t. \f$ \sum_{k=0}^{K-1} g(k) = 1\f$; this will cause + * a maximum phase change of \f$ h \cdot \pi\f$ between two symbols, where \a h is the + * modulation index. + * + * The following phase responses can be generated: + * - LREC: Rectangular phase response. + * - LRC: Raised cosine phase response, looks like 1 - cos(x). + * - LSRC: Spectral raised cosine. This requires a rolloff factor beta. + * The phase response is the Fourier transform of raised cosine + * function. + * - TFM: Tamed frequency modulation. This scheme minimizes phase change for + * rapidly varying input symbols. + * - GAUSSIAN: A Gaussian phase response. For a modulation index h = 1/2, this + * results in GMSK. + * + * A short description of all these phase responses can be found in [1]. + * + * [1]: Anderson, Aulin and Sundberg; Digital Phase Modulation + */ + static std::vector<float> + phase_response(cpm_type type, unsigned samples_per_sym, unsigned L, double beta=0.3); +}; + +#endif /* INCLUDED_GR_CPM_H */ + diff --git a/gnuradio-core/src/lib/general/gr_cpm.i b/gnuradio-core/src/lib/general/gr_cpm.i new file mode 100644 index 000000000..f01aba34e --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_cpm.i @@ -0,0 +1,40 @@ +/* -*- C++ -*- */ +/* + * Copyright 2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +%rename(cpm) gr_cpm; + +class gr_cpm +{ + public: + enum cpm_type { + LRC, + LSRC, + LREC, + TFM, + GAUSSIAN, + GENERIC = 999 + }; + + static std::vector<float> + phase_response(cpm_type type, unsigned samples_per_sym, unsigned L, double beta=0.3); +}; + diff --git a/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.cc b/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.cc index 19ab316a1..583e0eb70 100644 --- a/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.cc +++ b/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2010 Free Software Foundation, Inc. + * Copyright 2006,2010,2011 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -30,22 +30,24 @@ #include <math.h> #include <gr_math.h> -#define M_TWOPI (2*M_PI) +#ifndef M_TWOPI +#define M_TWOPI (2.0f*M_PI) +#endif gr_pll_carriertracking_cc_sptr -gr_make_pll_carriertracking_cc (float alpha, float beta, float max_freq, float min_freq) +gr_make_pll_carriertracking_cc (float loop_bw, float max_freq, float min_freq) { - return gnuradio::get_initial_sptr(new gr_pll_carriertracking_cc (alpha, beta, max_freq, min_freq)); + return gnuradio::get_initial_sptr(new gr_pll_carriertracking_cc (loop_bw, max_freq, min_freq)); } -gr_pll_carriertracking_cc::gr_pll_carriertracking_cc (float alpha, float beta, float max_freq, float min_freq) +gr_pll_carriertracking_cc::gr_pll_carriertracking_cc (float loop_bw, + float max_freq, + float min_freq) : gr_sync_block ("pll_carriertracking_cc", gr_make_io_signature (1, 1, sizeof (gr_complex)), gr_make_io_signature (1, 1, sizeof (gr_complex))), - d_alpha(alpha), d_beta(beta), - d_max_freq(max_freq), d_min_freq(min_freq), - d_phase(0), d_freq((max_freq+min_freq)/2), - d_locksig(0),d_lock_threshold(0),d_squelch_enable(false) + gri_control_loop(loop_bw, max_freq, min_freq), + d_locksig(0), d_lock_threshold(0), d_squelch_enable(false) { } @@ -72,7 +74,7 @@ gr_pll_carriertracking_cc::phase_detector(gr_complex sample,float ref_phase) bool gr_pll_carriertracking_cc::lock_detector(void) { - return (fabs(d_locksig) > d_lock_threshold); + return (fabsf(d_locksig) > d_lock_threshold); } bool @@ -100,17 +102,16 @@ gr_pll_carriertracking_cc::work (int noutput_items, for (int i = 0; i < noutput_items; i++){ error = phase_detector(iptr[i],d_phase); - - d_freq = d_freq + d_beta * error; - d_phase = mod_2pi(d_phase + d_freq + d_alpha * error); - - if (d_freq > d_max_freq) - d_freq = d_max_freq; - else if (d_freq < d_min_freq) - d_freq = d_min_freq; - gr_sincosf(d_phase,&t_imag,&t_real); - optr[i] = iptr[i] * gr_complex(t_real,-t_imag); - d_locksig = d_locksig * (1.0 - d_alpha) + d_alpha*(iptr[i].real() * t_real + iptr[i].imag() * t_imag); + + advance_loop(error); + phase_wrap(); + frequency_limit(); + + gr_sincosf(d_phase, &t_imag, &t_real); + optr[i] = iptr[i] * gr_complex(t_real, -t_imag); + + d_locksig = d_locksig * (1.0 - d_alpha) + \ + d_alpha*(iptr[i].real() * t_real + iptr[i].imag() * t_imag); if ((d_squelch_enable) && !lock_detector()) optr[i] = 0; diff --git a/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.h b/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.h index 27e74f111..db74bb101 100644 --- a/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.h +++ b/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,206 Free Software Foundation, Inc. + * Copyright 2004,2006,2011 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -25,12 +25,14 @@ #include <gr_core_api.h> #include <gr_sync_block.h> +#include <gri_control_loop.h> class gr_pll_carriertracking_cc; typedef boost::shared_ptr<gr_pll_carriertracking_cc> gr_pll_carriertracking_cc_sptr; -GR_CORE_API gr_pll_carriertracking_cc_sptr gr_make_pll_carriertracking_cc (float alpha, float beta, - float max_freq, float min_freq); +GR_CORE_API gr_pll_carriertracking_cc_sptr gr_make_pll_carriertracking_cc (float loop_bw, + float max_freq, + float min_freq); /*! * \brief Implements a PLL which locks to the input frequency and outputs the * input signal mixed with that carrier. @@ -42,19 +44,20 @@ GR_CORE_API gr_pll_carriertracking_cc_sptr gr_make_pll_carriertracking_cc (float * the input and outputs that signal, downconverted to DC * * All settings max_freq and min_freq are in terms of radians per sample, - * NOT HERTZ. Alpha is the phase gain (first order, units of radians per radian) - * and beta is the frequency gain (second order, units of radians per sample per radian) + * NOT HERTZ. The loop bandwidth determins the lock range and should be set + * around pi/200 -- 2pi/100. * \sa gr_pll_freqdet_cf, gr_pll_carriertracking_cc */ -class GR_CORE_API gr_pll_carriertracking_cc : public gr_sync_block +class GR_CORE_API gr_pll_carriertracking_cc : public gr_sync_block, public gri_control_loop { - friend GR_CORE_API gr_pll_carriertracking_cc_sptr gr_make_pll_carriertracking_cc (float alpha, float beta, - float max_freq, float min_freq); + friend GR_CORE_API gr_pll_carriertracking_cc_sptr gr_make_pll_carriertracking_cc (float loop_bw, + float max_freq, + float min_freq); - float d_alpha,d_beta,d_max_freq,d_min_freq,d_phase,d_freq,d_locksig,d_lock_threshold; + float d_locksig,d_lock_threshold; bool d_squelch_enable; - gr_pll_carriertracking_cc (float alpha, float beta, float max_freq, float min_freq); + gr_pll_carriertracking_cc (float loop_bw, float max_freq, float min_freq); int work (int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.i b/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.i index 3e84fccbe..d309111b2 100644 --- a/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.i +++ b/gnuradio-core/src/lib/general/gr_pll_carriertracking_cc.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2005 Free Software Foundation, Inc. + * Copyright 2005,2011 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,13 +23,14 @@ GR_SWIG_BLOCK_MAGIC(gr,pll_carriertracking_cc); gr_pll_carriertracking_cc_sptr -gr_make_pll_carriertracking_cc (float alpha, float beta, - float max_freq, float min_freq); +gr_make_pll_carriertracking_cc (float loop_bw, + float max_freq, + float min_freq); -class gr_pll_carriertracking_cc : public gr_sync_block +class gr_pll_carriertracking_cc : public gr_sync_block, public gri_control_loop { private: - gr_pll_carriertracking_cc (float alpha, float beta, float max_freq, float min_freq); + gr_pll_carriertracking_cc (float loop_bw, float max_freq, float min_freq); public: bool lock_detector(void); bool squelch_enable(bool); diff --git a/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.cc b/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.cc index 1f17f2afc..0ae773e6e 100644 --- a/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.cc +++ b/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2010 Free Software Foundation, Inc. + * Copyright 2004,2010,2011 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -20,8 +20,6 @@ * Boston, MA 02110-1301, USA. */ -// WARNING: this file is machine generated. Edits will be over written - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -31,21 +29,21 @@ #include <math.h> #include <gr_math.h> -#define M_TWOPI (2*M_PI) +#ifndef M_TWOPI +#define M_TWOPI (2.0f*M_PI) +#endif gr_pll_freqdet_cf_sptr -gr_make_pll_freqdet_cf (float alpha, float beta, float max_freq, float min_freq) +gr_make_pll_freqdet_cf (float loop_bw, float max_freq, float min_freq) { - return gnuradio::get_initial_sptr(new gr_pll_freqdet_cf (alpha, beta, max_freq, min_freq)); + return gnuradio::get_initial_sptr(new gr_pll_freqdet_cf (loop_bw, max_freq, min_freq)); } -gr_pll_freqdet_cf::gr_pll_freqdet_cf (float alpha, float beta, float max_freq, float min_freq) +gr_pll_freqdet_cf::gr_pll_freqdet_cf (float loop_bw, float max_freq, float min_freq) : gr_sync_block ("pll_freqdet_cf", gr_make_io_signature (1, 1, sizeof (gr_complex)), gr_make_io_signature (1, 1, sizeof (float))), - d_alpha(alpha), d_beta(beta), - d_max_freq(max_freq), d_min_freq(min_freq), - d_phase(0), d_freq((max_freq+min_freq)/2) + gri_control_loop(loop_bw, max_freq, min_freq) { } @@ -70,8 +68,8 @@ gr_pll_freqdet_cf::phase_detector(gr_complex sample,float ref_phase) int gr_pll_freqdet_cf::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { const gr_complex *iptr = (gr_complex *) input_items[0]; float *optr = (float *) output_items[0]; @@ -82,13 +80,10 @@ gr_pll_freqdet_cf::work (int noutput_items, while (size-- > 0) { error = phase_detector(*iptr++,d_phase); - d_freq = d_freq + d_beta * error; - d_phase = mod_2pi(d_phase + d_freq + d_alpha * error); - - if (d_freq > d_max_freq) - d_freq = d_max_freq; - else if (d_freq < d_min_freq) - d_freq = d_min_freq; + advance_loop(error); + phase_wrap(); + frequency_limit(); + *optr++ = d_freq; } return noutput_items; diff --git a/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.h b/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.h index 6ed1f99c2..336f3fd31 100644 --- a/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.h +++ b/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2011 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -25,12 +25,14 @@ #include <gr_core_api.h> #include <gr_sync_block.h> +#include <gri_control_loop.h> class gr_pll_freqdet_cf; typedef boost::shared_ptr<gr_pll_freqdet_cf> gr_pll_freqdet_cf_sptr; -GR_CORE_API gr_pll_freqdet_cf_sptr gr_make_pll_freqdet_cf (float alpha, float beta, - float max_freq, float min_freq); +GR_CORE_API gr_pll_freqdet_cf_sptr gr_make_pll_freqdet_cf (float loop_bw, + float max_freq, + float min_freq); /*! * \brief Implements a PLL which locks to the input frequency and outputs * an estimate of that frequency. Useful for FM Demod. @@ -41,24 +43,24 @@ GR_CORE_API gr_pll_freqdet_cf_sptr gr_make_pll_freqdet_cf (float alpha, float be * This PLL locks onto a [possibly noisy] reference carrier on * the input and outputs an estimate of that frequency in radians per sample. * All settings max_freq and min_freq are in terms of radians per sample, - * NOT HERTZ. Alpha is the phase gain (first order, units of radians per radian) - * and beta is the frequency gain (second order, units of radians per sample per radian) + * NOT HERTZ. The loop bandwidth determins the lock range and should be set + * around pi/200 -- 2pi/100. * \sa gr_pll_refout_cc, gr_pll_carriertracking_cc */ -class GR_CORE_API gr_pll_freqdet_cf : public gr_sync_block +class GR_CORE_API gr_pll_freqdet_cf : public gr_sync_block, public gri_control_loop { - friend GR_CORE_API gr_pll_freqdet_cf_sptr gr_make_pll_freqdet_cf (float alpha, float beta, - float max_freq, float min_freq); + friend GR_CORE_API gr_pll_freqdet_cf_sptr gr_make_pll_freqdet_cf (float loop_bw, + float max_freq, + float min_freq); - float d_alpha,d_beta,d_max_freq,d_min_freq,d_phase,d_freq; - gr_pll_freqdet_cf (float alpha, float beta, float max_freq, float min_freq); + float mod_2pi (float in); + gr_pll_freqdet_cf (float loop_bw, float max_freq, float min_freq); int work (int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); private: - float mod_2pi (float in); float phase_detector(gr_complex sample,float ref_phase); }; diff --git a/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.i b/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.i index b730f037a..f93e6e37e 100644 --- a/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.i +++ b/gnuradio-core/src/lib/general/gr_pll_freqdet_cf.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2005 Free Software Foundation, Inc. + * Copyright 2005,2011 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -22,11 +22,12 @@ GR_SWIG_BLOCK_MAGIC(gr,pll_freqdet_cf) - gr_pll_freqdet_cf_sptr gr_make_pll_freqdet_cf (float alpha, float beta, - float max_freq, float min_freq); + gr_pll_freqdet_cf_sptr gr_make_pll_freqdet_cf (float loop_bw, + float max_freq, + float min_freq); -class gr_pll_freqdet_cf : public gr_sync_block +class gr_pll_freqdet_cf : public gr_sync_block, public gri_control_loop { private: - gr_pll_freqdet_cf (float alpha, float beta, float max_freq, float min_freq); + gr_pll_freqdet_cf (float loop_bw, float max_freq, float min_freq); }; diff --git a/gnuradio-core/src/lib/general/gr_pll_refout_cc.cc b/gnuradio-core/src/lib/general/gr_pll_refout_cc.cc index 8968cd3f1..2b480fcf1 100644 --- a/gnuradio-core/src/lib/general/gr_pll_refout_cc.cc +++ b/gnuradio-core/src/lib/general/gr_pll_refout_cc.cc @@ -30,7 +30,9 @@ #include <math.h> #include <gr_math.h> -#define M_TWOPI (2*M_PI) +#ifndef M_TWOPI +#define M_TWOPI (2.0f*M_PI) +#endif gr_pll_refout_cc_sptr gr_make_pll_refout_cc (float loop_bw, float max_freq, float min_freq) diff --git a/gnuradio-core/src/lib/general/gr_pll_refout_cc.h b/gnuradio-core/src/lib/general/gr_pll_refout_cc.h index 11bce5046..dcbeb1efa 100644 --- a/gnuradio-core/src/lib/general/gr_pll_refout_cc.h +++ b/gnuradio-core/src/lib/general/gr_pll_refout_cc.h @@ -43,8 +43,8 @@ GR_CORE_API gr_pll_refout_cc_sptr gr_make_pll_refout_cc (float loop_bw, * aligned to it. * * All settings max_freq and min_freq are in terms of radians per sample, - * NOT HERTZ. Alpha is the phase gain (first order, units of radians per radian) - * and beta is the frequency gain (second order, units of radians per sample per radian) + * NOT HERTZ. The loop bandwidth determins the lock range and should be set + * around pi/200 -- 2pi/100. * \sa gr_pll_freqdet_cf, gr_pll_carriertracking_cc */ class GR_CORE_API gr_pll_refout_cc : public gr_sync_block, public gri_control_loop diff --git a/gnuradio-core/src/lib/general/gri_control_loop.cc b/gnuradio-core/src/lib/general/gri_control_loop.cc index caad1f5f9..4c64bb922 100644 --- a/gnuradio-core/src/lib/general/gri_control_loop.cc +++ b/gnuradio-core/src/lib/general/gri_control_loop.cc @@ -74,9 +74,9 @@ void gri_control_loop::frequency_limit() { if (d_freq > d_max_freq) - d_freq = d_min_freq; + d_freq = d_max_freq; else if (d_freq < d_min_freq) - d_freq = d_max_freq; + d_freq = d_min_freq; } /******************************************************************* diff --git a/gnuradio-core/src/lib/general/qa_general.cc b/gnuradio-core/src/lib/general/qa_general.cc index 6984d798c..b9080f362 100644 --- a/gnuradio-core/src/lib/general/qa_general.cc +++ b/gnuradio-core/src/lib/general/qa_general.cc @@ -28,6 +28,7 @@ #include <qa_general.h> #include <qa_gr_firdes.h> #include <qa_gr_circular_file.h> +#include <qa_gr_cpm.h> #include <qa_gr_fxpt.h> #include <qa_gr_fxpt_nco.h> #include <qa_gr_fxpt_vco.h> @@ -41,6 +42,7 @@ qa_general::suite () s->addTest (qa_gr_firdes::suite ()); s->addTest (qa_gr_circular_file::suite ()); + s->addTest (qa_gr_cpm::suite ()); s->addTest (qa_gr_fxpt::suite ()); s->addTest (qa_gr_fxpt_nco::suite ()); s->addTest (qa_gr_fxpt_vco::suite ()); diff --git a/gnuradio-core/src/lib/general/qa_gr_cpm.cc b/gnuradio-core/src/lib/general/qa_gr_cpm.cc new file mode 100644 index 000000000..cc32d1117 --- /dev/null +++ b/gnuradio-core/src/lib/general/qa_gr_cpm.cc @@ -0,0 +1,140 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include <qa_gr_cpm.h> +#include <gr_cpm.h> +#include <cppunit/TestAssert.h> + +const double DELTA = 1e-5; +const int L = 5; +const int samples_per_sym = 4; +const float taps_lrc[20] = { + 0, 0.002447174185242, 0.009549150281253, 0.020610737385376, + 0.034549150281253, 0.050000000000000, 0.065450849718747, 0.079389262614624, + 0.090450849718747, 0.097552825814758, 0.100000000000000, 0.097552825814758, + 0.090450849718747, 0.079389262614624, 0.065450849718747, 0.050000000000000, + 0.034549150281253, 0.020610737385376, 0.009549150281253, 0.002447174185242 +}; + + +const float taps_lsrc[20] = { // beta = 0.2 + 0.000000000000000, 0.009062686687436, 0.019517618142920, 0.030875041875917, + 0.042552315421249, 0.053912556756416, 0.064308860403517, 0.073130584159352, + 0.079847961304114, 0.084051371489937, 0.085482007518284, 0.084051371489937, + 0.079847961304114, 0.073130584159352, 0.064308860403517, 0.053912556756416, + 0.042552315421249, 0.030875041875917, 0.019517618142920, 0.009062686687436 +}; + + +const float taps_tfm[20] = { + -0.003946522220317, -0.005147757690530, -0.003171631690177, 0.003959659609805, + 0.017498721302356, 0.037346982678383, 0.062251889790391, 0.087364237065604, + 0.110049050955117, 0.125677762224511, 0.132288693729399, 0.125677762224511, + 0.110049050955117, 0.087364237065604, 0.062251889790391, 0.037346982678383, + 0.017498721302356, 0.003959659609805, -0.003171631690177, -0.005147757690530 +}; + + +const float taps_gaussian[20] = { // BT = 0.3 + 0.000000743866524, 0.000009286258371, 0.000085441834550, 0.000581664421923, + 0.002945540765422, 0.011178079812344, 0.032117220937421, 0.070841188736816, + 0.122053715366673, 0.167389736919915, 0.185594670675172, 0.167389736919915, + 0.122053715366673, 0.070841188736816, 0.032117220937421, 0.011178079812344, + 0.002945540765422, 0.000581664421923, 0.000085441834550, 0.000009286258371 +}; + + +// Check LREC phase response +void +qa_gr_cpm::t1 () +{ + std::vector<float> taps(gr_cpm::phase_response(gr_cpm::LREC, samples_per_sym, L)); + + for (int i = 0; i < L * samples_per_sym; i++) { + CPPUNIT_ASSERT_DOUBLES_EQUAL(taps[i], 0.05, DELTA); + } +} + + +// Check LRC phase response +void +qa_gr_cpm::t2 () +{ + std::vector<float> taps(gr_cpm::phase_response(gr_cpm::LRC, samples_per_sym, L)); + float sum = 0; + + for (int i = 0; i < L * samples_per_sym; i++) { + CPPUNIT_ASSERT_DOUBLES_EQUAL(taps[i], taps_lrc[i], DELTA); + sum += taps[i]; + } + + CPPUNIT_ASSERT_DOUBLES_EQUAL(sum, 1.0, DELTA); +} + + +// Check LSRC phase response +void +qa_gr_cpm::t3 () +{ + std::vector<float> taps(gr_cpm::phase_response(gr_cpm::LSRC, samples_per_sym, L, 0.2)); + float sum = 0; + + for (int i = 0; i < L * samples_per_sym; i++) { + CPPUNIT_ASSERT_DOUBLES_EQUAL(taps[i], taps_lsrc[i], DELTA); + sum += taps[i]; + } + + CPPUNIT_ASSERT_DOUBLES_EQUAL(sum, 1.0, DELTA); +} + + +// Check the TFM phase response +void +qa_gr_cpm::t4 () +{ + std::vector<float> taps(gr_cpm::phase_response(gr_cpm::TFM, samples_per_sym, L)); + float sum = 0; + + for (int i = 0; i < L * samples_per_sym; i++) { + CPPUNIT_ASSERT_DOUBLES_EQUAL(taps[i], taps_tfm[i], DELTA); + sum += taps[i]; + } + + CPPUNIT_ASSERT_DOUBLES_EQUAL(sum, 1.0, DELTA); +} + + +// Check the Gaussian phase response +void +qa_gr_cpm::t5 () +{ + std::vector<float> taps(gr_cpm::phase_response(gr_cpm::GAUSSIAN, samples_per_sym, L, 0.3)); + float sum = 0; + + for (int i = 0; i < L * samples_per_sym; i++) { + CPPUNIT_ASSERT_DOUBLES_EQUAL(taps[i], taps_gaussian[i], DELTA); + sum += taps[i]; + } + + CPPUNIT_ASSERT_DOUBLES_EQUAL(sum, 1.0, DELTA); +} + diff --git a/gnuradio-core/src/lib/general/qa_gr_cpm.h b/gnuradio-core/src/lib/general/qa_gr_cpm.h new file mode 100644 index 000000000..741cb2860 --- /dev/null +++ b/gnuradio-core/src/lib/general/qa_gr_cpm.h @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef _QA_GR_CPM_H +#define _QA_GR_CPM_H + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gr_cpm : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gr_cpm); + CPPUNIT_TEST (t1); + CPPUNIT_TEST (t2); + CPPUNIT_TEST (t3); + CPPUNIT_TEST (t4); + CPPUNIT_TEST (t5); + CPPUNIT_TEST_SUITE_END (); + + private: + void t1 (); + void t2 (); + void t3 (); + void t4 (); + void t5 (); + +}; + + +#endif /* _QA_GR_CPM_H */ + diff --git a/gnuradio-core/src/lib/hier/Makefile.am b/gnuradio-core/src/lib/hier/Makefile.am index b525d19b4..369feef75 100644 --- a/gnuradio-core/src/lib/hier/Makefile.am +++ b/gnuradio-core/src/lib/hier/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2009 Free Software Foundation, Inc. +# Copyright 2009,2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # diff --git a/gnuradio-core/src/lib/hier/hier.i b/gnuradio-core/src/lib/hier/hier.i index dbcc8e915..bec3de7ed 100644 --- a/gnuradio-core/src/lib/hier/hier.i +++ b/gnuradio-core/src/lib/hier/hier.i @@ -29,3 +29,4 @@ %} %include "gr_channel_model.i" + diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_pll_carriertracking.py b/gnuradio-core/src/python/gnuradio/gr/qa_pll_carriertracking.py index 8e4a0eefa..4c12924ec 100755 --- a/gnuradio-core/src/python/gnuradio/gr/qa_pll_carriertracking.py +++ b/gnuradio-core/src/python/gnuradio/gr/qa_pll_carriertracking.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2007,2010 Free Software Foundation, Inc. +# Copyright 2004,2007,2010,2011 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -32,117 +32,116 @@ class test_pll_carriertracking (gr_unittest.TestCase): self.tb = None def test_pll_carriertracking (self): - expected_result = ((1.00000238419+6.47922693275e-09j), - (0.998399555683+0.0565364062786j), - (0.994261980057+0.10695001483j), - (0.98843306303+0.151648163795j), - (0.981579363346+0.191063538194j), - (0.974212288857+0.225630432367j), - (0.966734290123+0.255773901939j), - (0.959442555904+0.281897842884j), - (0.952551782131+0.304379671812j), - (0.946205317974+0.323566257954j), - (0.940503358841+0.339778244495j), - (0.935505151749+0.353307723999j), - (0.931235432625+0.364419162273j), - (0.927616357803+0.373535633087j), - (0.924710214138+0.380666583776j), - (0.922494113445+0.386005342007j), - (0.92093116045+0.389725029469j), - (0.919974088669+0.391981720924j), - (0.919572234154+0.392916500568j), - (0.919680893421+0.392660915852j), - (0.920248389244+0.39133310318j), - (0.921222627163+0.389039844275j), - (0.922548472881+0.385877460241j), - (0.924184799194+0.381939411163j), - (0.926086127758+0.377309292555j), - (0.928135097027+0.37224984169j), - (0.930293083191+0.366814315319j), - (0.932614028454+0.360868781805j), - (0.935064375401+0.354473829269j), - (0.937613248825+0.347684770823j), - (0.940225422382+0.340550601482j), - (0.942881464958+0.33312189579j), - (0.945559620857+0.325443327427j), - (0.948240220547+0.31755694747j), - (0.950899422169+0.309499144554j), - (0.953524827957+0.301307469606j), - (0.956105649471+0.293015599251j), - (0.958630502224+0.284654557705j), - (0.96103054285+0.276443749666j), - (0.963361799717+0.26819768548j), - (0.965623259544+0.259936869144j), - (0.967810571194+0.251679092646j), - (0.969916880131+0.243440493941j), - (0.971936583519+0.235235646367j), - (0.97387367487+0.227080151439j), - (0.975726902485+0.218987599015j), - (0.977494239807+0.210969462991j), - (0.979169845581+0.203035995364j), - (0.980761289597+0.195199295878j), - (0.982269346714+0.187469303608j), - (0.983659446239+0.180052131414j), - (0.984931468964+0.1729388237j), - (0.986136198044+0.165923252702j), - (0.987275123596+0.159012272954j), - (0.988349795341+0.15221118927j), - (0.989354014397+0.145524248481j), - (0.990296065807+0.138957872987j), - (0.991178870201+0.132516458631j), - (0.992005050182+0.126204773784j), - (0.992770493031+0.120025672019j), - (0.993480443954+0.113984130323j), - (0.994139909744+0.108083210886j), - (0.994751393795+0.102326385677j), - (0.995293080807+0.0969148278236j), - (0.995791256428+0.091630294919j), - (0.996252119541+0.0864710733294j), - (0.996678769588+0.0814334899187j), - (0.997069239616+0.0765165910125j), - (0.997423350811+0.071716658771j), - (0.997748315334+0.0670333206654j), - (0.998046517372+0.0624645166099j), - (0.998317599297+0.058009263128j), - (0.998557567596+0.053665690124j), - (0.998775064945+0.0494344644248j), - (0.998971700668+0.0453144386411j), - (0.999140620232+0.0415064357221j), - (0.99927687645+0.0379924885929j), - (0.999400436878+0.0345549099147j), - (0.999511957169+0.0311931278557j), - (0.99961233139+0.0279070306569j), - (0.999694347382+0.0246965941042j), - (0.999765276909+0.0215622838587j), - (0.999826848507+0.0185046810657j), - (0.999880313873+0.0155246723443j), - (0.999920129776+0.0126227736473j), - (0.999949812889+0.00980060640723j), - (0.99997317791+0.00705910893157j), - (0.999990820885+0.00439921114594j), - (0.999998450279+0.00202245195396j), - (0.999998092651-0.00029227725463j), - (0.999994516373-0.00254815118387j), - (0.999988794327-0.00474932929501j), - (0.999977111816-0.00689708162099j), - (0.999957799911-0.00899503659457j), - (0.999936699867-0.0110441967845j), - (0.999914228916-0.0130464555696j), - (0.999889075756-0.0150024276227j), - (0.999855577946-0.0169130507857j), - (0.999821305275-0.0187777336687j), - (0.999786794186-0.0205969288945j)) + expected_result = ((1.00000238419+6.57831922268e-09j), + (0.998351693153+0.0573740489781j), + (0.994012773037+0.109242096543j), + (0.987789511681+0.155784770846j), + (0.980356454849+0.197242289782j), + (0.972262203693+0.233890414238j), + (0.963963091373+0.266027569771j), + (0.955816328526+0.293958544731j), + (0.948096513748+0.31798568368j), + (0.941002130508+0.338400006294j), + (0.934680581093+0.355482578278j), + (0.929229319096+0.369498342276j), + (0.924701035023+0.380694836378j), + (0.921043872833+0.389459967613j), + (0.918319702148+0.395834594965j), + (0.91650646925+0.400014132261j), + (0.915561556816+0.40217769146j), + (0.915425121784+0.402490824461j), + (0.916029334068+0.401106894016j), + (0.917308092117+0.39817237854j), + (0.919185698032+0.393822491169j), + (0.921583771706+0.388183712959j), + (0.924419641495+0.381372988224j), + (0.927624821663+0.373506993055j), + (0.93112629652+0.364693939686j), + (0.934793651104+0.355197936296j), + (0.938562095165+0.345107495785j), + (0.942447602749+0.33434677124j), + (0.946396291256+0.323003143072j), + (0.950359642506+0.311159342527j), + (0.954286515713+0.298890888691j), + (0.958144724369+0.286276459694j), + (0.961902141571+0.273387700319j), + (0.96553081274+0.260292351246j), + (0.969001471996+0.247053653002j), + (0.972298383713+0.233733415604j), + (0.975410103798+0.220389455557j), + (0.978325486183+0.207074314356j), + (0.981000483036+0.194007188082j), + (0.983471632004+0.181051760912j), + (0.985742926598+0.168245732784j), + (0.987816333771+0.155622571707j), + (0.989693164825+0.143212914467j), + (0.991374969482+0.131043404341j), + (0.992875099182+0.119139909744j), + (0.994201719761+0.107524067163j), + (0.995362222195+0.0962148010731j), + (0.996359944344+0.0852287560701j), + (0.997212648392+0.0745811164379j), + (0.997930467129+0.0642844736576j), + (0.998514950275+0.0545224510133j), + (0.998972594738+0.0452938191593j), + (0.999334216118+0.0364210158587j), + (0.99960911274+0.0279066264629j), + (0.999806642532+0.0197515785694j), + (0.99992787838+0.0119558870792j), + (0.999987542629+0.00451827049255j), + (0.999994814396-0.00256353616714j), + (0.999957740307-0.00929233431816j), + (0.999877095222-0.0156717002392j), + (0.999762177467-0.0217055380344j), + (0.999622702599-0.0273993015289j), + (0.999463677406-0.0327589809895j), + (0.999292552471-0.0376165211201j), + (0.999108791351-0.0421659946442j), + (0.998919844627-0.0464186370373j), + (0.998729586601-0.0503882467747j), + (0.998537421227-0.0540841519833j), + (0.998342692852-0.0575186908245j), + (0.9981533885-0.0607041418552j), + (0.997971534729-0.063651651144j), + (0.997796595097-0.0663715749979j), + (0.997623920441-0.0688742175698j), + (0.997461974621-0.0711689144373j), + (0.997311413288-0.0732654929161j), + (0.997185945511-0.0749996080995j), + (0.997077047825-0.0763883292675j), + (0.996980309486-0.0776248201728j), + (0.996895432472-0.0787187665701j), + (0.996822297573-0.0796797126532j), + (0.996752738953-0.0805156230927j), + (0.996692657471-0.0812350511551j), + (0.996642947197-0.0818456709385j), + (0.996603965759-0.0823540389538j), + (0.996568918228-0.0827651321888j), + (0.996540248394-0.0830852389336j), + (0.996520996094-0.0833202600479j), + (0.996510386467-0.0834743082523j), + (0.996518313885-0.0833787024021j), + (0.996529102325-0.083223849535j), + (0.996545791626-0.0830176770687j), + (0.99656867981-0.0827698707581j), + (0.996593296528-0.0824855566025j), + (0.99661642313-0.0821713805199j), + (0.996643543243-0.081834435463j), + (0.996674180031-0.0814796686172j), + (0.996706545353-0.0811114609241j), + (0.996734440327-0.0807323306799j), + (0.996764600277-0.0803465023637j), + (0.996797323227-0.0799564495683j)) sampling_freq = 10e3 freq = sampling_freq / 100 - alpha = 0.1 - beta = alpha * alpha / 4.0 + loop_bw = math.pi/100.0 maxf = 1 minf = -1 src = gr.sig_source_c (sampling_freq, gr.GR_COS_WAVE, freq, 1.0) - pll = gr.pll_carriertracking_cc(alpha, beta, maxf, minf) + pll = gr.pll_carriertracking_cc(loop_bw, maxf, minf) head = gr.head (gr.sizeof_gr_complex, int (freq)) dst = gr.vector_sink_c () diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_pll_freqdet.py b/gnuradio-core/src/python/gnuradio/gr/qa_pll_freqdet.py index 5225a9a3b..b84299a94 100755 --- a/gnuradio-core/src/python/gnuradio/gr/qa_pll_freqdet.py +++ b/gnuradio-core/src/python/gnuradio/gr/qa_pll_freqdet.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2007,2010 Free Software Foundation, Inc. +# Copyright 2004,2007,2010,2011 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -32,117 +32,116 @@ class test_pll_freqdet (gr_unittest.TestCase): self.tb = None def test_pll_refout (self): - expected_result = (1.1489677586e-07, - 0.972821060568, - 2.74556447638, - 5.14063078448, - 8.00965819311, - 11.2291393027, - 14.6967068752, - 18.3279143967, - 22.0534772463, - 25.8170093072, - 29.5729107661, - 33.284774699, - 36.923857393, - 40.4367950308, - 43.8452195091, - 47.1363835133, - 50.3011949468, - 53.3336447847, - 56.2301489564, - 58.9891659262, - 61.6107668417, - 64.0962975824, - 66.4481356707, - 68.6694531128, - 70.7640326003, - 72.7048735417, - 74.5033180826, - 76.2012544926, - 77.8019199967, - 79.3088126954, - 80.7255907715, - 82.0560369166, - 83.3039516093, - 84.47312347, - 85.5673411194, - 86.5902864563, - 87.5456117346, - 88.4368565575, - 89.2363918613, - 89.9860999864, - 90.688880206, - 91.3474598523, - 91.9644654653, - 92.5423042123, - 93.0832706099, - 93.5894872344, - 94.0629225081, - 94.5054203452, - 94.9186882929, - 95.3043331057, - 95.6326268597, - 95.9117515522, - 96.1801447842, - 96.437391527, - 96.6831953314, - 96.9173605408, - 97.1397982206, - 97.3504727968, - 97.5493842694, - 97.7366275022, - 97.9123092169, - 98.0766013539, - 98.2297054988, - 98.3408087235, - 98.448722155, - 98.5534457933, - 98.6549322065, - 98.7531932527, - 98.8481459259, - 98.9397487233, - 99.0279067813, - 99.1125074491, - 99.193438076, - 99.2705800823, - 99.3438030304, - 99.3817663128, - 99.3911400359, - 99.4089388448, - 99.4334136894, - 99.4630408207, - 99.4964684305, - 99.5325166512, - 99.5701538394, - 99.6084432158, - 99.6466021546, - 99.6839073198, - 99.7197895289, - 99.7537270313, - 99.7542606398, - 99.7595848672, - 99.7691186729, - 99.7822928746, - 99.7986331535, - 99.8175940432, - 99.838713083, - 99.8614922382, - 99.8854571901, - 99.9101454781, - 99.9351302152, - 99.9599845147) + expected_result = (4.33888922882e-08, + 0.367369994515, + 1.08135249597, + 2.10983253908, + 3.42221529438, + 4.98940390402, + 6.78379190842, + 8.77923286024, + 10.9510106794, + 13.2758363182, + 15.7317829127, + 18.2982902299, + 20.9561068599, + 23.6755271122, + 26.452952094, + 29.2731265301, + 32.1219053479, + 34.9862418188, + 37.8540971414, + 40.7144315483, + 43.5571390869, + 46.3730179743, + 49.1537231663, + 51.8917218889, + 54.58026103, + 57.2015358514, + 59.7513664199, + 62.2380533124, + 64.657612252, + 67.006640002, + 69.2822432184, + 71.4820384499, + 73.6041047056, + 75.6469478817, + 77.6094829742, + 79.4909866472, + 81.2911031615, + 83.0097850853, + 84.6355598352, + 86.1820937186, + 87.6504420946, + 89.0418441206, + 90.3577286819, + 91.5996432431, + 92.7692775646, + 93.8684162704, + 94.8989269904, + 95.8627662892, + 96.7619381633, + 97.598505899, + 98.362769679, + 99.0579904444, + 99.6992633875, + 100.288805948, + 100.828805921, + 101.321421457, + 101.76878699, + 102.17300138, + 102.536116055, + 102.860158727, + 103.147085962, + 103.398830608, + 103.617254366, + 103.792467691, + 103.939387906, + 104.060030865, + 104.15631756, + 104.230085975, + 104.283067372, + 104.316933727, + 104.333238432, + 104.333440018, + 104.318914008, + 104.290941063, + 104.250742554, + 104.187634452, + 104.103822339, + 104.013227468, + 103.916810336, + 103.815448432, + 103.709936239, + 103.600997093, + 103.489283183, + 103.375351833, + 103.259712936, + 103.142828952, + 103.025091195, + 102.90686726, + 102.776726069, + 102.648078982, + 102.521459607, + 102.397294831, + 102.275999684, + 102.157882471, + 102.043215927, + 101.93218978, + 101.824958181, + 101.72159228, + 101.622151366, + 101.526623582) sampling_freq = 10e3 freq = sampling_freq / 100 - alpha = 0.2 - beta = alpha * alpha / 4.0 + loop_bw = math.pi/100.0 maxf = 1 minf = -1 src = gr.sig_source_c (sampling_freq, gr.GR_COS_WAVE, freq, 1.0) - pll = gr.pll_freqdet_cf(alpha, beta, maxf, minf) + pll = gr.pll_freqdet_cf(loop_bw, maxf, minf) head = gr.head (gr.sizeof_float, int (freq)) dst = gr.vector_sink_f () diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_pll_refout.py b/gnuradio-core/src/python/gnuradio/gr/qa_pll_refout.py index c40a885a8..14f9ab877 100755 --- a/gnuradio-core/src/python/gnuradio/gr/qa_pll_refout.py +++ b/gnuradio-core/src/python/gnuradio/gr/qa_pll_refout.py @@ -32,117 +32,116 @@ class test_pll_refout (gr_unittest.TestCase): self.tb = None def test_pll_refout (self): - expected_result = ((1+7.39965699825e-10j), - (0.999980390072+0.00626518437639j), - (0.999828696251+0.0185074284673j), - (0.999342679977+0.0362518876791j), - (0.998255133629+0.0590478181839j), - (0.996255218983+0.0864609107375j), - (0.993005692959+0.118066303432j), - (0.988157629967+0.153442293406j), - (0.981362581253+0.192165210843j), - (0.972283244133+0.233806177974j), - (0.960601866245+0.277928203344j), - (0.946027755737+0.324085712433j), - (0.928303182125+0.371824204922j), - (0.907292485237+0.420500129461j), - (0.882742881775+0.469856351614j), - (0.854515135288+0.519426465034j), - (0.822515428066+0.568742752075j), - (0.786696314812+0.617340147495j), - (0.747057616711+0.664759278297j), - (0.703645646572+0.710551083088j), - (0.656552672386+0.754280209541j), - (0.605915129185+0.795529305935j), - (0.551911592484+0.833902597427j), - (0.494760006666+0.869029641151j), - (0.43471455574+0.900568306446j), - (0.37224894762+0.928132891655j), - (0.30767711997+0.951490819454j), - (0.241136431694+0.970491230488j), - (0.172981828451+0.984925031662j), - (0.103586450219+0.99462044239j), - (0.0333373323083+0.999444127083j), - (-0.0373690575361+0.999301552773j), - (-0.108130030334+0.994136750698j), - (-0.178540825844+0.983932495117j), - (-0.248198583722+0.968709170818j), - (-0.316705673933+0.948523879051j), - (-0.383672952652+0.923469007015j), - (-0.448723316193+0.893670737743j), - (-0.51132196188+0.85938924551j), - (-0.571328520775+0.820721447468j), - (-0.628420114517+0.777874112129j), - (-0.682293117046+0.73107868433j), - (-0.732665538788+0.680588841438j), - (-0.779277384281+0.626679122448j), - (-0.821892917156+0.569642007351j), - (-0.860301196575+0.509786069393j), - (-0.894317150116+0.447433561087j), - (-0.923782229424+0.382918298244j), - (-0.948564887047+0.316582858562j), - (-0.968560874462+0.248776733875j), - (-0.983657121658+0.180051699281j), - (-0.993847966194+0.110753215849j), - (-0.999158322811+0.0410195216537j), - (-0.999585151672-0.0288011860102j), - (-0.995150566101-0.0983632653952j), - (-0.985901713371-0.16732545197j), - (-0.971909940243-0.235353127122j), - (-0.953270018101-0.302119642496j), - (-0.9300994277-0.367307811975j), - (-0.902537107468-0.430612027645j), - (-0.870742559433-0.49173912406j), - (-0.834894418716-0.550410091877j), - (-0.795189499855-0.606360971928j), - (-0.751972675323-0.659194231033j), - (-0.705345034599-0.708864152431j), - (-0.65554022789-0.755160272121j), - (-0.602804005146-0.79788929224j), - (-0.547393083572-0.836875617504j), - (-0.489574223757-0.871961653233j), - (-0.429622590542-0.903008520603j), - (-0.367820799351-0.929896712303j), - (-0.30445766449-0.952525854111j), - (-0.239826664329-0.970815718174j), - (-0.174224823713-0.984705924988j), - (-0.107951194048-0.994156181812j), - (-0.0415063276887-0.999138236046j), - (0.0248276274651-0.999691724777j), - (0.0909758731723-0.995853126049j), - (0.156649470329-0.987654268742j), - (0.221562758088-0.975146114826j), - (0.285434871912-0.958398103714j), - (0.347990810871-0.937497973442j), - (0.408962905407-0.912550985813j), - (0.468091338873-0.883680105209j), - (0.525126338005-0.851024270058j), - (0.57982814312-0.814738810062j), - (0.631968915462-0.77499371767j), - (0.681333422661-0.731973171234j), - (0.727582573891-0.68602013588j), - (0.770699381828-0.637198925018j), - (0.810512244701-0.585721731186j), - (0.846863090992-0.531810998917j), - (0.879608631134-0.475698113441j), - (0.908620357513-0.417623132467j), - (0.933785498142-0.357833325863j), - (0.955007195473-0.296582698822j), - (0.972205162048-0.234130680561j), - (0.985315918922-0.170741200447j), - (0.994293272495-0.106681488454j), - (0.999108314514-0.0422209985554j)) + expected_result = ((1+6.4087357643e-10j), + (0.999985277653+0.00542619498447j), + (0.999868750572+0.0162021834403j), + (0.99948567152+0.0320679470897j), + (0.99860727787+0.0527590736747j), + (0.996953129768+0.0780025869608j), + (0.994203746319+0.107512556016j), + (0.990011692047+0.140985429287j), + (0.984013140202+0.178095817566j), + (0.975838363171+0.218493551016j), + (0.965121984482+0.261800557375j), + (0.95151245594+0.307610183954j), + (0.934681296349+0.355486690998j), + (0.914401650429+0.404808044434j), + (0.890356600285+0.455263823271j), + (0.862329125404+0.506348133087j), + (0.830152392387+0.557536482811j), + (0.793714106083+0.608290970325j), + (0.752960026264+0.658066213131j), + (0.707896590233+0.706316053867j), + (0.658591926098+0.752500295639j), + (0.605175673962+0.796091973782j), + (0.547837555408+0.836584687233j), + (0.48682525754+0.873499393463j), + (0.42244040966+0.906390726566j), + (0.355197101831+0.934791445732j), + (0.285494059324+0.958380460739j), + (0.213591173291+0.976923108101j), + (0.139945343137+0.990159213543j), + (0.065038472414+0.997882783413j), + (-0.0106285437942+0.999943494797j), + (-0.0865436866879+0.996248066425j), + (-0.162189796567+0.986759603024j), + (-0.23705175519+0.971496999264j), + (-0.310622543097+0.950533330441j), + (-0.38240903616+0.923993110657j), + (-0.451937526464+0.89204955101j), + (-0.518758952618+0.854920566082j), + (-0.582311093807+0.812966048717j), + (-0.642372369766+0.76639264822j), + (-0.698591887951+0.715520322323j), + (-0.750654160976+0.660695314407j), + (-0.798280358315+0.602286040783j), + (-0.841228663921+0.540679454803j), + (-0.87929558754+0.476276367903j), + (-0.912315964699+0.409486919641j), + (-0.940161883831+0.340728074312j), + (-0.962742805481+0.270418733358j), + (-0.980004072189+0.198977485299j), + (-0.991925954819+0.126818284392j), + (-0.99851256609+0.0545223206282j), + (-0.999846458435-0.0175215266645j), + (-0.996021270752-0.0891158208251j), + (-0.987133920193-0.159895718098j), + (-0.973306238651-0.2295101583j), + (-0.954683184624-0.297624111176j), + (-0.931430280209-0.363919824362j), + (-0.903732538223-0.428097635508j), + (-0.871792256832-0.489875763655j), + (-0.835827112198-0.548992812634j), + (-0.796068251133-0.605206847191j), + (-0.752758979797-0.658296227455j), + (-0.706152498722-0.70805978775j), + (-0.656641483307-0.754202902317j), + (-0.604367733002-0.79670548439j), + (-0.549597978592-0.835429251194j), + (-0.492602348328-0.870254516602j), + (-0.433654457331-0.901079237461j), + (-0.373029649258-0.927819430828j), + (-0.31100410223-0.950408577919j), + (-0.247853919864-0.968797445297j), + (-0.183855071664-0.982953369617j), + (-0.119282215834-0.992860376835j), + (-0.0544078871608-0.998518764973j), + (0.0104992967099-0.999944865704j), + (0.0749994292855-0.997183561325j), + (0.138844624162-0.990314185619j), + (0.201967850327-0.979392170906j), + (0.264124274254-0.964488625526j), + (0.325075358152-0.945688128471j), + (0.3845885396-0.92308807373j), + (0.442438393831-0.89679890871j), + (0.498407125473-0.866943061352j), + (0.552284479141-0.833655714989j), + (0.603869199753-0.797083437443j), + (0.652970373631-0.757383465767j), + (0.69940674305-0.714723825455j), + (0.743007957935-0.66928255558j), + (0.78350687027-0.62138313055j), + (0.820889055729-0.571087777615j), + (0.855021059513-0.51859331131j), + (0.885780930519-0.46410369873j), + (0.913058102131-0.407829582691j), + (0.936754107475-0.349988251925j), + (0.956783294678-0.290801793337j), + (0.973072886467-0.230497643352j), + (0.985563337803-0.169307261705j), + (0.9942086339-0.1074674353j), + (0.9989772439-0.0452152714133j), + (0.999851942062+0.0172088555992j)) sampling_freq = 10e3 freq = sampling_freq / 100 - alpha = 0.1 - beta = alpha * alpha / 4.0 + loop_bw = math.pi/100.0 maxf = 1 minf = -1 src = gr.sig_source_c (sampling_freq, gr.GR_COS_WAVE, freq, 1.0) - pll = gr.pll_refout_cc(alpha, beta, maxf, minf) + pll = gr.pll_refout_cc(loop_bw, maxf, minf) head = gr.head (gr.sizeof_gr_complex, int (freq)) dst = gr.vector_sink_c () @@ -151,8 +150,7 @@ class test_pll_refout (gr_unittest.TestCase): self.tb.run () dst_data = dst.data () - - self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 5) + self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 4) if __name__ == '__main__': gr_unittest.run(test_pll_refout, "test_pll_refout.xml") diff --git a/gr-digital/CMakeLists.txt b/gr-digital/CMakeLists.txt index cc00da69a..bd11be4d3 100644 --- a/gr-digital/CMakeLists.txt +++ b/gr-digital/CMakeLists.txt @@ -33,6 +33,7 @@ GR_REGISTER_COMPONENT("gr-digital" ENABLE_GR_DIGITAL GR_SET_GLOBAL(GR_DIGITAL_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/lib + ${CMAKE_CURRENT_SOURCE_DIR}/hier ) GR_SET_GLOBAL(GR_DIGITAL_SWIG_INCLUDE_DIRS @@ -81,11 +82,13 @@ CPACK_COMPONENT("digital_swig" ######################################################################## # Add subdirectories ######################################################################## +GR_INCLUDE_SUBDIRECTORY(hier) #appends to lib sources ADD_SUBDIRECTORY(lib) IF(ENABLE_PYTHON) ADD_SUBDIRECTORY(swig) ADD_SUBDIRECTORY(python) ADD_SUBDIRECTORY(grc) + ADD_SUBDIRECTORY(examples) ENDIF(ENABLE_PYTHON) ######################################################################## diff --git a/gr-digital/Makefile.am b/gr-digital/Makefile.am index f1409793f..346db120f 100644 --- a/gr-digital/Makefile.am +++ b/gr-digital/Makefile.am @@ -21,7 +21,7 @@ include $(top_srcdir)/Makefile.common -SUBDIRS = lib +SUBDIRS = hier lib if PYTHON SUBDIRS += swig python apps grc examples diff --git a/gr-digital/examples/CMakeLists.txt b/gr-digital/examples/CMakeLists.txt new file mode 100644 index 000000000..55a8379d9 --- /dev/null +++ b/gr-digital/examples/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright 2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +INCLUDE(GrPython) + +GR_PYTHON_INSTALL(PROGRAMS + transmit_path.py + receive_path.py + DESTINATION ${GR_PKG_DATA_DIR}/examples/digital + COMPONENT "digital_python" +) diff --git a/gr-digital/examples/benchmark_add_channel.py b/gr-digital/examples/benchmark_add_channel.py new file mode 100755 index 000000000..def1f8267 --- /dev/null +++ b/gr-digital/examples/benchmark_add_channel.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python +# +# Copyright 2010,2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +import random, math, sys + +class my_top_block(gr.top_block): + def __init__(self, ifile, ofile, options): + gr.top_block.__init__(self) + + SNR = 10.0**(options.snr/10.0) + frequency_offset = options.frequency_offset + time_offset = options.time_offset + phase_offset = options.phase_offset*(math.pi/180.0) + + # calculate noise voltage from SNR + # FIXME: normalize to signal amplitude + power_in_signal = abs(1.0)**2 + noise_power = power_in_signal/SNR + noise_voltage = math.sqrt(noise_power) + print noise_voltage + + self.src = gr.file_source(gr.sizeof_gr_complex, ifile) + #self.throttle = gr.throttle(gr.sizeof_gr_complex, options.sample_rate) + self.channel = gr.channel_model(noise_voltage, frequency_offset, + time_offset, noise_seed=random.randint(0,100000)) + self.phase = gr.multiply_const_cc(complex(math.cos(phase_offset), + math.sin(phase_offset))) + self.snk = gr.file_sink(gr.sizeof_gr_complex, ofile) + + self.connect(self.src, self.channel, self.phase, self.snk) + + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +def main(): + # Create Options Parser: + usage = "benchmack_add_channel.py [options] <input file> <output file>" + parser = OptionParser (usage=usage, option_class=eng_option, conflict_handler="resolve") + parser.add_option("-n", "--snr", type="eng_float", default=30, + help="set the SNR of the channel in dB [default=%default]") + parser.add_option("", "--seed", action="store_true", default=False, + help="use a random seed for AWGN noise [default=%default]") + parser.add_option("-f", "--frequency-offset", type="eng_float", default=0, + help="set frequency offset introduced by channel [default=%default]") + parser.add_option("-t", "--time-offset", type="eng_float", default=1.0, + help="set timing offset between Tx and Rx [default=%default]") + parser.add_option("-p", "--phase-offset", type="eng_float", default=0, + help="set phase offset (in degrees) between Tx and Rx [default=%default]") + parser.add_option("-m", "--use-multipath", action="store_true", default=False, + help="Use a multipath channel [default=%default]") + + (options, args) = parser.parse_args () + + if len(args) != 2: + parser.print_help(sys.stderr) + sys.exit(1) + + ifile = args[0] + ofile = args[1] + + # build the graph + tb = my_top_block(ifile, ofile, options) + + r = gr.enable_realtime_scheduling() + if r != gr.RT_OK: + print "Warning: Failed to enable realtime scheduling." + + tb.start() # start flow graph + tb.wait() # wait for it to finish + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gr-digital/grc/Makefile.am b/gr-digital/grc/Makefile.am index d271ca06a..963939f12 100644 --- a/gr-digital/grc/Makefile.am +++ b/gr-digital/grc/Makefile.am @@ -34,4 +34,6 @@ dist_grcblocks_DATA = \ digital_psk_mod.xml \ digital_psk_demod.xml \ digital_qam_mod.xml \ - digital_qam_demod.xml + digital_qam_demod.xml \ + digital_fll_band_edge_cc.xml \ + digital_mpsk_receiver_cc.xml diff --git a/gr-digital/grc/digital_block_tree.xml b/gr-digital/grc/digital_block_tree.xml index 1be4110e1..3432d876c 100644 --- a/gr-digital/grc/digital_block_tree.xml +++ b/gr-digital/grc/digital_block_tree.xml @@ -34,6 +34,8 @@ <block>digital_cma_equalizer_cc</block> <block>digital_lms_dd_equalizer_cc</block> <block>digital_kurtotic_equalizer_cc</block> + <block>digital_fll_band_edge_cc</block> + <block>digital_mpsk_receiver_cc</block> </cat> <cat> <name>Digital Modulators</name> diff --git a/gr-digital/grc/digital_costas_loop_cc.xml b/gr-digital/grc/digital_costas_loop_cc.xml index 087535b87..668c43dec 100644 --- a/gr-digital/grc/digital_costas_loop_cc.xml +++ b/gr-digital/grc/digital_costas_loop_cc.xml @@ -8,16 +8,10 @@ <name>Costas Loop</name> <key>digital_costas_loop_cc</key> <import>from gnuradio import digital</import> - <make>digital.costas_loop_cc($eta, $w, $order)</make> - <callback>set_damping_factor($eta)</callback> - <callback>set_natural_freq($w)</callback> + <make>digital.costas_loop_cc($w, $order)</make> + <callback>set_loop_bandwidth($w)</callback> <param> - <name>Damping Factor</name> - <key>eta</key> - <type>real</type> - </param> - <param> - <name>Natural Frequency</name> + <name>Loop Bandwidth</name> <key>w</key> <type>real</type> </param> diff --git a/grc/blocks/gr_fll_band_edge_cc.xml b/gr-digital/grc/digital_fll_band_edge_cc.xml index 5a13ac49b..1c5a34e54 100644 --- a/grc/blocks/gr_fll_band_edge_cc.xml +++ b/gr-digital/grc/digital_fll_band_edge_cc.xml @@ -8,10 +8,8 @@ <name>FLL Band-Edge</name> <key>gr_fll_band_edge_cc</key> <import>from gnuradio import gr</import> - <make>gr.fll_band_edge_cc($samps_per_sym, $rolloff, $filter_size, $alpha, $beta)</make> - <callback>set_alpha($alpha)</callback> - <callback>set_beta($beta)</callback> - + <make>gr.fll_band_edge_cc($samps_per_sym, $rolloff, $filter_size, $w)</make> + <callback>set_loop_bandwidth($w)</callback> <param> <name>Type</name> <key>type</key> @@ -41,15 +39,11 @@ </param> <param> - <name>Alpha</name> - <key>alpha</key> - <type>real</type> - </param> - <param> - <name>Beta</name> - <key>beta</key> + <name>Loop Bandwidth</name> + <key>w</key> <type>real</type> </param> + <sink> <name>in</name> <type>$type.input</type> diff --git a/grc/blocks/gr_mpsk_receiver_cc.xml b/gr-digital/grc/digital_mpsk_receiver_cc.xml index 843c3a4c1..948f18b6e 100644 --- a/grc/blocks/gr_mpsk_receiver_cc.xml +++ b/gr-digital/grc/digital_mpsk_receiver_cc.xml @@ -8,9 +8,8 @@ <name>MPSK Receiver</name> <key>gr_mpsk_receiver_cc</key> <import>from gnuradio import gr</import> - <make>gr.mpsk_receiver_cc($M, $theta, $alpha, $beta, $fmin, $fmax, $mu, $gain_mu, $omega, $gain_omega, $omega_relative_limit)</make> - <callback>set_alpha($alpha)</callback> - <callback>set_beta($beta)</callback> + <make>gr.mpsk_receiver_cc($M, $theta, $w, $fmin, $fmax, $mu, $gain_mu, $omega, $gain_omega, $omega_relative_limit)</make> + <callback>set_loop_bandwidth($w)</callback> <callback>set_mu($mu)</callback> <callback>set_gain_mu($gain_mu)</callback> <callback>set_omega($omega)</callback> @@ -26,13 +25,8 @@ <type>real</type> </param> <param> - <name>Alpha</name> - <key>alpha</key> - <type>real</type> - </param> - <param> - <name>Beta</name> - <key>beta</key> + <name>Loop Bandwidth</name> + <key>w</key> <type>real</type> </param> <param> diff --git a/gr-digital/hier/.gitignore b/gr-digital/hier/.gitignore new file mode 100644 index 000000000..b336cc7ce --- /dev/null +++ b/gr-digital/hier/.gitignore @@ -0,0 +1,2 @@ +/Makefile +/Makefile.in diff --git a/gr-digital/hier/CMakeLists.txt b/gr-digital/hier/CMakeLists.txt new file mode 100644 index 000000000..f46acc81e --- /dev/null +++ b/gr-digital/hier/CMakeLists.txt @@ -0,0 +1,43 @@ +# 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. + +######################################################################## +# This file included, use CMake directory variables +######################################################################## + +LIST(APPEND gr_digital_sources + ${CMAKE_CURRENT_SOURCE_DIR}/digital_gmskmod_bc.cc + ${CMAKE_CURRENT_SOURCE_DIR}/digital_cpmmod_bc.cc +) + +INSTALL(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/digital_gmskmod_bc.h + ${CMAKE_CURRENT_SOURCE_DIR}/digital_cpmmod_bc.h + DESTINATION ${GR_INCLUDE_DIR}/gnuradio + COMPONENT "digital_devel" +) + +INSTALL( + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/_digital_hier.i + ${CMAKE_CURRENT_SOURCE_DIR}/digital_gmskmod_bc.i + ${CMAKE_CURRENT_SOURCE_DIR}/digital_cpmmod_bc.i + DESTINATION ${GR_INCLUDE_DIR}/gnuradio/swig + COMPONENT "digital_swig" +) diff --git a/gr-digital/hier/Makefile.am b/gr-digital/hier/Makefile.am new file mode 100644 index 000000000..b11b85f77 --- /dev/null +++ b/gr-digital/hier/Makefile.am @@ -0,0 +1,40 @@ +# +# Copyright 2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +include $(top_srcdir)/Makefile.common + +AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(WITH_INCLUDES) + +noinst_LTLIBRARIES = libdigital_hier.la + +libdigital_hier_la_SOURCES = \ + digital_gmskmod_bc.cc \ + digital_cpmmod_bc.cc + +grinclude_HEADERS = \ + digital_gmskmod_bc.h \ + digital_cpmmod_bc.h + + +swiginclude_HEADERS = \ + _digital_hier.i \ + digital_gmskmod_bc.i \ + digital_cpmmod_bc.i diff --git a/gr-digital/hier/_digital_hier.i b/gr-digital/hier/_digital_hier.i new file mode 100644 index 000000000..022e38644 --- /dev/null +++ b/gr-digital/hier/_digital_hier.i @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +%{ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <digital_cpmmod_bc.h> +#include <digital_gmskmod_bc.h> +%} + +%include "digital_cpmmod_bc.i" +%include "digital_gmskmod_bc.i" diff --git a/gr-digital/hier/digital_cpmmod_bc.cc b/gr-digital/hier/digital_cpmmod_bc.cc new file mode 100644 index 000000000..a95b604d1 --- /dev/null +++ b/gr-digital/hier/digital_cpmmod_bc.cc @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Free Software Foundation, Inc. + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <digital_cpmmod_bc.h> +#include <gr_io_signature.h> + + +// Shared pointer constructor +digital_cpmmod_bc_sptr +digital_make_cpmmod_bc(int type, float h, + unsigned samples_per_sym, + unsigned L, double beta) +{ + return gnuradio::get_initial_sptr(new digital_cpmmod_bc((gr_cpm::cpm_type)type, + h, samples_per_sym, + L, beta)); +} + + +digital_cpmmod_bc::digital_cpmmod_bc(gr_cpm::cpm_type type, float h, + unsigned samples_per_sym, + unsigned L, double beta) + : gr_hier_block2("digital_cpmmod_bc", + gr_make_io_signature(1, 1, sizeof(char)), + gr_make_io_signature2(1, 1, sizeof(gr_complex), sizeof(float))), + d_taps(gr_cpm::phase_response(type, samples_per_sym, L, beta)), + d_char_to_float(gr_make_char_to_float()), + d_pulse_shaper(gr_make_interp_fir_filter_fff(samples_per_sym, d_taps)), + d_fm(gr_make_frequency_modulator_fc(M_PI * h)) +{ + switch (type) { + case gr_cpm::LRC: + case gr_cpm::LSRC: + case gr_cpm::LREC: + case gr_cpm::TFM: + case gr_cpm::GAUSSIAN: + break; + + default: + throw std::invalid_argument("invalid CPM type"); + } + + connect(self(), 0, d_char_to_float, 0); + connect(d_char_to_float, 0, d_pulse_shaper, 0); + connect(d_pulse_shaper, 0, d_fm, 0); + connect(d_fm, 0, self(), 0); +} + diff --git a/gr-digital/hier/digital_cpmmod_bc.h b/gr-digital/hier/digital_cpmmod_bc.h new file mode 100644 index 000000000..4e9547cd6 --- /dev/null +++ b/gr-digital/hier/digital_cpmmod_bc.h @@ -0,0 +1,96 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_CPMMOD_BC_H +#define INCLUDED_DIGITAL_CPMMOD_BC_H + +#include <digital_api.h> +#include <gr_hier_block2.h> +#include <gr_char_to_float.h> +#include <gr_interp_fir_filter_fff.h> +#include <gr_frequency_modulator_fc.h> +#include <gr_cpm.h> + + +class digital_cpmmod_bc; +typedef boost::shared_ptr<digital_cpmmod_bc> digital_cpmmod_bc_sptr; + + +DIGITAL_API digital_cpmmod_bc_sptr +digital_make_cpmmod_bc(int type, float h, + unsigned samples_per_sym, + unsigned L, double beta=0.3); + +/*! + * \brief Generic CPM modulator + * + * \ingroup modulation_blk + * + * \param type The modulation type. Can be one of LREC, LRC, LSRC, TFM + * or GAUSSIAN. See gr_cpm::phase_response() for a + * detailed description. + * \param h The modulation index. \f$ h \cdot \pi\f$ is the maximum + * phase change that can occur between two symbols, i.e., if + * you only send ones, the phase will increase by \f$ h \cdot + * \pi\f$ every \p samples_per_sym samples. Set this to 0.5 + * for Minimum Shift Keying variants. + * \param samples_per_sym Samples per symbol. + * \param L The length of the phase duration in symbols. For L=1, this + * yields full- response CPM symbols, for L > 1, + * partial-response. + * \param beta For LSRC, this is the rolloff factor. For Gaussian + * pulses, this is the 3 dB time-bandwidth product. + * + * Examples: + * - Setting h = 0.5, L = 1, type = LREC yields MSK. + * - Setting h = 0.5, type = GAUSSIAN and beta = 0.3 yields GMSK + * as used in GSM. + * + * The input of this block are symbols from an M-ary alphabet + * +/-1, +/-3, ..., +/-(M-1). Usually, M = 2 and therefore, the + * valid inputs are +/-1. + * The modulator will silently accept any other inputs, though. + * The output is the phase-modulated signal. + */ +class DIGITAL_API digital_cpmmod_bc : public gr_hier_block2 +{ + friend DIGITAL_API digital_cpmmod_bc_sptr digital_make_cpmmod_bc(int type, float h, + unsigned samples_per_sym, + unsigned L, double beta); + + std::vector<float> d_taps; + gr_char_to_float_sptr d_char_to_float; + gr_interp_fir_filter_fff_sptr d_pulse_shaper; + gr_frequency_modulator_fc_sptr d_fm; + +protected: + digital_cpmmod_bc(gr_cpm::cpm_type type, float h, + unsigned samples_per_sym, + unsigned L, double beta); + +public: + //! Return the phase response FIR taps + std::vector<float> get_taps() { return d_taps; }; +}; + +#endif /* INCLUDED_DIGITAL_CPMMOD_BC_H */ + diff --git a/gr-digital/hier/digital_cpmmod_bc.i b/gr-digital/hier/digital_cpmmod_bc.i new file mode 100644 index 000000000..fa7c50da7 --- /dev/null +++ b/gr-digital/hier/digital_cpmmod_bc.i @@ -0,0 +1,40 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +GR_SWIG_BLOCK_MAGIC(digital, cpmmod_bc) + +digital_cpmmod_bc_sptr +digital_make_cpmmod_bc(int type, float h, + unsigned samples_per_sym, + unsigned L, double beta=0.3); + +class digital_cpmmod_bc : public gr_hier_block2 +{ + private: + digital_cpmmod_bc(int type, float h, + unsigned samples_per_sym, + unsigned L, double beta); + + public: + std::vector<float> get_taps(); +}; + diff --git a/gr-digital/hier/digital_gmskmod_bc.cc b/gr-digital/hier/digital_gmskmod_bc.cc new file mode 100644 index 000000000..e53e90037 --- /dev/null +++ b/gr-digital/hier/digital_gmskmod_bc.cc @@ -0,0 +1,44 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <digital_gmskmod_bc.h> +#include <gr_io_signature.h> + +// Shared pointer constructor +digital_gmskmod_bc_sptr +digital_make_gmskmod_bc(unsigned samples_per_sym, + double bt, unsigned L) +{ + return gnuradio::get_initial_sptr(new digital_gmskmod_bc(samples_per_sym, bt, L)); +} + + +digital_gmskmod_bc::digital_gmskmod_bc(unsigned samples_per_sym, + double bt, unsigned L) + : digital_cpmmod_bc(gr_cpm::GAUSSIAN, 0.5, samples_per_sym, L, bt) +{ +} + diff --git a/gr-digital/hier/digital_gmskmod_bc.h b/gr-digital/hier/digital_gmskmod_bc.h new file mode 100644 index 000000000..33fcc6c12 --- /dev/null +++ b/gr-digital/hier/digital_gmskmod_bc.h @@ -0,0 +1,62 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_GMSKMOD_BC_H +#define INCLUDED_DIGITAL_GMSKMOD_BC_H + +#include <digital_api.h> +#include <digital_cpmmod_bc.h> + +class digital_gmskmod_bc; +typedef boost::shared_ptr<digital_gmskmod_bc> digital_gmskmod_bc_sptr; + + +DIGITAL_API digital_gmskmod_bc_sptr +digital_make_gmskmod_bc(unsigned samples_per_sym=2, + double bt=0.3, unsigned L=4); + +/*! + * \brief GMSK modulator + * + * \ingroup modulation_blk + * + * \param samples_per_sym Samples per symbol. + * \param bt The 3 dB time-bandwidth product. + * \param L The length of the phase duration in symbols. The Gaussian + * pulse is truncated after L symbols. + * + * The input of this block are symbols from an M-ary alphabet + * +/-1, +/-3, ..., +/-(M-1). Usually, M = 2 and therefore, the + * valid inputs are +/-1. + * The modulator will silently accept any other inputs, though. + * The output is the phase-modulated signal. + */ +class DIGITAL_API digital_gmskmod_bc : public digital_cpmmod_bc +{ + friend DIGITAL_API digital_gmskmod_bc_sptr digital_make_gmskmod_bc(unsigned samples_per_sym, + double bt, unsigned L); + digital_gmskmod_bc(unsigned samples_per_sym, + double bt, unsigned L); +}; + +#endif /* INCLUDED_DIGITAL_GMSKMOD_BC_H */ + diff --git a/gr-digital/hier/digital_gmskmod_bc.i b/gr-digital/hier/digital_gmskmod_bc.i new file mode 100644 index 000000000..ad7b82237 --- /dev/null +++ b/gr-digital/hier/digital_gmskmod_bc.i @@ -0,0 +1,39 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +GR_SWIG_BLOCK_MAGIC(digital, gmskmod_bc) + +digital_gmskmod_bc_sptr +digital_make_gmskmod_bc(unsigned samples_per_sym=2, + double bt=0.3, unsigned L=4); + +class digital_gmskmod_bc : public gr_hier_block2 +{ + private: + digital_cpmmod_bc(int type, float h, + unsigned samples_per_sym, + double beta, unsigned L); + + public: + std::vector<float> get_taps(); +}; + diff --git a/gr-digital/lib/Makefile.am b/gr-digital/lib/Makefile.am index 4a9359fce..ce961ef2e 100644 --- a/gr-digital/lib/Makefile.am +++ b/gr-digital/lib/Makefile.am @@ -61,6 +61,7 @@ libgnuradio_digital_la_SOURCES = \ digital_mpsk_receiver_cc.cc libgnuradio_digital_la_LIBADD = \ - $(GNURADIO_CORE_LA) + $(GNURADIO_CORE_LA) \ + $(abs_top_builddir)/gr-digital/hier/libdigital_hier.la libgnuradio_digital_la_LDFLAGS = $(NO_UNDEFINED) $(LTVERSIONFLAGS) diff --git a/gr-digital/lib/digital_constellation.cc b/gr-digital/lib/digital_constellation.cc index d1f218439..0c100f38e 100644 --- a/gr-digital/lib/digital_constellation.cc +++ b/gr-digital/lib/digital_constellation.cc @@ -411,6 +411,20 @@ digital_constellation_qpsk::digital_constellation_qpsk () d_constellation[1] = gr_complex(SQRT_TWO, -SQRT_TWO); d_constellation[2] = gr_complex(-SQRT_TWO, SQRT_TWO); d_constellation[3] = gr_complex(SQRT_TWO, SQRT_TWO); + + /* + d_constellation[0] = gr_complex(SQRT_TWO, SQRT_TWO); + d_constellation[1] = gr_complex(-SQRT_TWO, SQRT_TWO); + d_constellation[2] = gr_complex(SQRT_TWO, -SQRT_TWO); + d_constellation[3] = gr_complex(SQRT_TWO, -SQRT_TWO); + */ + + d_pre_diff_code.resize(4); + d_pre_diff_code[0] = 0x0; + d_pre_diff_code[1] = 0x2; + d_pre_diff_code[2] = 0x3; + d_pre_diff_code[3] = 0x1; + d_rotational_symmetry = 4; d_dimensionality = 1; calc_arity(); @@ -422,8 +436,80 @@ digital_constellation_qpsk::decision_maker(const gr_complex *sample) // Real component determines small bit. // Imag component determines big bit. return 2*(imag(*sample)>0) + (real(*sample)>0); + + /* + bool a = real(*sample) > 0; + bool b = imag(*sample) > 0; + if(a) { + if(b) + return 0x0; + else + return 0x1; + } + else { + if(b) + return 0x2; + else + return 0x3; + } + */ +} + + +/********************************************************************/ + + +digital_constellation_dqpsk_sptr +digital_make_constellation_dqpsk() +{ + return digital_constellation_dqpsk_sptr(new digital_constellation_dqpsk ()); } +digital_constellation_dqpsk::digital_constellation_dqpsk () +{ + // This constellation is not gray coded, which allows + // us to use differential encodings (through gr_diff_encode and + // gr_diff_decode) on the symbols. + d_constellation.resize(4); + d_constellation[0] = gr_complex(+SQRT_TWO, +SQRT_TWO); + d_constellation[1] = gr_complex(-SQRT_TWO, +SQRT_TWO); + d_constellation[2] = gr_complex(-SQRT_TWO, -SQRT_TWO); + d_constellation[3] = gr_complex(+SQRT_TWO, -SQRT_TWO); + + // Use this mapping to convert to gray code before diff enc. + d_pre_diff_code.resize(4); + d_pre_diff_code[0] = 0x0; + d_pre_diff_code[1] = 0x1; + d_pre_diff_code[2] = 0x3; + d_pre_diff_code[3] = 0x2; + d_apply_pre_diff_code = true; + + d_rotational_symmetry = 4; + d_dimensionality = 1; + calc_arity(); +} + +unsigned int +digital_constellation_dqpsk::decision_maker(const gr_complex *sample) +{ + // Slower deicison maker as we can't slice along one axis. + // Maybe there's a better way to do this, still. + + bool a = real(*sample) > 0; + bool b = imag(*sample) > 0; + if(a) { + if(b) + return 0x0; + else + return 0x3; + } + else { + if(b) + return 0x1; + else + return 0x2; + } +} digital_constellation_8psk_sptr digital_make_constellation_8psk() diff --git a/gr-digital/lib/digital_constellation.h b/gr-digital/lib/digital_constellation.h index df00f3898..9b2a58588 100644 --- a/gr-digital/lib/digital_constellation.h +++ b/gr-digital/lib/digital_constellation.h @@ -42,8 +42,10 @@ typedef boost::shared_ptr<digital_constellation> digital_constellation_sptr; class DIGITAL_API digital_constellation : public boost::enable_shared_from_this<digital_constellation> { public: - digital_constellation (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, unsigned int dimensionality); + digital_constellation (std::vector<gr_complex> constellation, + std::vector<unsigned int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int dimensionality); digital_constellation (); //! Returns the constellation points for a symbol value @@ -74,6 +76,8 @@ public: std::vector<std::vector<gr_complex> > v_points(); //! Whether to apply an encoding before doing differential encoding. (e.g. gray coding) bool apply_pre_diff_code() { return d_apply_pre_diff_code;} + //! Whether to apply an encoding before doing differential encoding. (e.g. gray coding) + void set_pre_diff_code(bool a) { d_apply_pre_diff_code = a;} //! Returns the encoding to apply before differential encoding. std::vector<unsigned int> pre_diff_code() { return d_pre_diff_code;} //! Returns the order of rotational symmetry. @@ -82,7 +86,7 @@ public: unsigned int dimensionality() {return d_dimensionality;} unsigned int bits_per_symbol () { - return floor(log(double(d_constellation.size()))/d_dimensionality/log(2.0)); + return floor(log(d_constellation.size())/d_dimensionality/log(2)); } unsigned int arity () { @@ -120,17 +124,19 @@ typedef boost::shared_ptr<digital_constellation_calcdist> digital_constellation_ // public constructor DIGITAL_API digital_constellation_calcdist_sptr -digital_make_constellation_calcdist (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, unsigned int dimensionality); +digital_make_constellation_calcdist (std::vector<gr_complex> constellation, + std::vector<unsigned int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int dimensionality); class DIGITAL_API digital_constellation_calcdist : public digital_constellation { public: digital_constellation_calcdist (std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int dimensionality); + std::vector<unsigned int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int dimensionality); unsigned int decision_maker (const gr_complex *sample); // void calc_metric(gr_complex *sample, float *metric, trellis_metric_type_t type); // void calc_euclidean_metric(gr_complex *sample, float *metric); @@ -155,10 +161,10 @@ class DIGITAL_API digital_constellation_sector : public digital_constellation public: digital_constellation_sector (std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int dimensionality, - unsigned int n_sectors); + std::vector<unsigned int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int dimensionality, + unsigned int n_sectors); unsigned int decision_maker (const gr_complex *sample); @@ -194,19 +200,25 @@ typedef boost::shared_ptr<digital_constellation_rect> digital_constellation_rect // public constructor DIGITAL_API digital_constellation_rect_sptr -digital_make_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int real_sectors, unsigned int imag_sectors, - float width_real_sectors, float width_imag_sectors); +digital_make_constellation_rect (std::vector<gr_complex> constellation, + std::vector<unsigned int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int real_sectors, + unsigned int imag_sectors, + float width_real_sectors, + float width_imag_sectors); class DIGITAL_API digital_constellation_rect : public digital_constellation_sector { public: - digital_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int real_sectors, unsigned int imag_sectors, - float width_real_sectors, float width_imag_sectors); + digital_constellation_rect (std::vector<gr_complex> constellation, + std::vector<unsigned int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int real_sectors, + unsigned int imag_sectors, + float width_real_sectors, + float width_imag_sectors); protected: @@ -222,10 +234,13 @@ class DIGITAL_API digital_constellation_rect : public digital_constellation_sect float d_width_imag_sectors; friend DIGITAL_API digital_constellation_rect_sptr - digital_make_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int real_sectors, unsigned int imag_sectors, - float width_real_sectors, float width_imag_sectors); + digital_make_constellation_rect (std::vector<gr_complex> constellation, + std::vector<unsigned int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int real_sectors, + unsigned int imag_sectors, + float width_real_sectors, + float width_imag_sectors); }; @@ -323,6 +338,33 @@ class DIGITAL_API digital_constellation_qpsk : public digital_constellation }; +/************************************************************/ +/* digital_constellation_dqpsk */ +/* */ +/* Works with differential encoding; slower decisions. */ +/* */ +/************************************************************/ + +//! \brief DQPSK-specific constellation and decision maker +class digital_constellation_dqpsk; +typedef boost::shared_ptr<digital_constellation_dqpsk> digital_constellation_dqpsk_sptr; + +// public constructor +DIGITAL_API digital_constellation_dqpsk_sptr +digital_make_constellation_dqpsk (); + +class DIGITAL_API digital_constellation_dqpsk : public digital_constellation +{ + public: + + digital_constellation_dqpsk (); + unsigned int decision_maker (const gr_complex *sample); + + friend DIGITAL_API digital_constellation_dqpsk_sptr + digital_make_constellation_dqpsk (); + +}; + /************************************************************/ /* digital_constellation_8psk */ diff --git a/gr-digital/lib/digital_constellation_receiver_cb.cc b/gr-digital/lib/digital_constellation_receiver_cb.cc index e2b6bf1d8..b9239962a 100644 --- a/gr-digital/lib/digital_constellation_receiver_cb.cc +++ b/gr-digital/lib/digital_constellation_receiver_cb.cc @@ -54,153 +54,20 @@ digital_constellation_receiver_cb::digital_constellation_receiver_cb (digital_co : gr_block ("constellation_receiver_cb", gr_make_io_signature (1, 1, sizeof (gr_complex)), gr_make_io_signaturev (1, 4, iosig)), - d_freq(0), d_max_freq(fmax), d_min_freq(fmin), d_phase(0), + gri_control_loop(loop_bw, fmax, fmin), d_constellation(constellation), d_current_const_point(0) { if (d_constellation->dimensionality() != 1) throw std::runtime_error ("This receiver only works with constellations of dimension 1."); - - // Set the damping factor for a critically damped system - d_damping = sqrtf(2.0f)/2.0f; - - // Set the bandwidth, which will then call update_gains() - set_loop_bandwidth(loop_bw); -} - - -/******************************************************************* - SET FUNCTIONS -*******************************************************************/ - -void -digital_constellation_receiver_cb::set_loop_bandwidth(float bw) -{ - if(bw < 0) { - throw std::out_of_range ("digital_constellation_receiver_cb: invalid bandwidth. Must be >= 0."); - } - - d_loop_bw = bw; - update_gains(); -} - -void -digital_constellation_receiver_cb::set_damping_factor(float df) -{ - if(df < 0 || df > 1.0) { - throw std::out_of_range ("digital_constellation_receiver_cb: invalid damping factor. Must be in [0,1]."); - } - - d_damping = df; - update_gains(); -} - -void -digital_constellation_receiver_cb::set_alpha(float alpha) -{ - if(alpha < 0 || alpha > 1.0) { - throw std::out_of_range ("digital_constellation_receiver_cb: invalid alpha. Must be in [0,1]."); - } - d_alpha = alpha; -} - -void -digital_constellation_receiver_cb::set_beta(float beta) -{ - if(beta < 0 || beta > 1.0) { - throw std::out_of_range ("digital_constellation_receiver_cb: invalid beta. Must be in [0,1]."); - } - d_beta = beta; -} - -void -digital_constellation_receiver_cb::set_frequency(float freq) -{ - if(freq > d_max_freq) - d_freq = d_min_freq; - else if(freq < d_min_freq) - d_freq = d_max_freq; - else - d_freq = freq; -} - -void -digital_constellation_receiver_cb::set_phase(float phase) -{ - d_phase = phase; - while(d_phase>M_TWOPI) - d_phase -= M_TWOPI; - while(d_phase<-M_TWOPI) - d_phase += M_TWOPI; -} - - -/******************************************************************* - GET FUNCTIONS -*******************************************************************/ - - -float -digital_constellation_receiver_cb::get_loop_bandwidth() const -{ - return d_loop_bw; -} - -float -digital_constellation_receiver_cb::get_damping_factor() const -{ - return d_damping; -} - -float -digital_constellation_receiver_cb::get_alpha() const -{ - return d_alpha; -} - -float -digital_constellation_receiver_cb::get_beta() const -{ - return d_beta; -} - -float -digital_constellation_receiver_cb::get_frequency() const -{ - return d_freq; -} - -float -digital_constellation_receiver_cb::get_phase() const -{ - return d_phase; -} - -/******************************************************************* -*******************************************************************/ - -void -digital_constellation_receiver_cb::update_gains() -{ - float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw); - d_alpha = (4*d_damping*d_loop_bw) / denom; - d_beta = (4*d_loop_bw*d_loop_bw) / denom; } void digital_constellation_receiver_cb::phase_error_tracking(float phase_error) { - d_freq += d_beta*phase_error; // adjust frequency based on error - d_phase += d_freq + d_alpha*phase_error; // adjust phase based on error - - // Make sure we stay within +-2pi - while(d_phase > M_TWOPI) - d_phase -= M_TWOPI; - while(d_phase < -M_TWOPI) - d_phase += M_TWOPI; - - // Limit the frequency range - d_freq = gr_branchless_clip(d_freq, d_max_freq); + advance_loop(phase_error); + phase_wrap(); + frequency_limit(); #if VERBOSE_COSTAS printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n", @@ -236,10 +103,12 @@ digital_constellation_receiver_cb::general_work (int noutput_items, sample = in[i]; nco = gr_expj(d_phase); // get the NCO value for derotating the current sample sample = nco*sample; // get the downconverted symbol + sym_value = d_constellation->decision_maker_pe(&sample, &phase_error); - // phase_error = -arg(sample*conj(d_constellation->points()[sym_value])); phase_error_tracking(phase_error); // corrects phase and frequency offsets + out[i] = sym_value; + if(output_items.size() == 4) { out_err[i] = phase_error; out_phase[i] = d_phase; diff --git a/gr-digital/lib/digital_constellation_receiver_cb.h b/gr-digital/lib/digital_constellation_receiver_cb.h index 5e414dfed..d33be8958 100644 --- a/gr-digital/lib/digital_constellation_receiver_cb.h +++ b/gr-digital/lib/digital_constellation_receiver_cb.h @@ -26,6 +26,7 @@ #include <digital_api.h> #include <gr_block.h> #include <digital_constellation.h> +#include <gri_control_loop.h> #include <gr_complex.h> #include <math.h> #include <fstream> @@ -64,134 +65,14 @@ digital_make_constellation_receiver_cb (digital_constellation_sptr constellation * */ -class DIGITAL_API digital_constellation_receiver_cb : public gr_block +class DIGITAL_API digital_constellation_receiver_cb : public gr_block, public gri_control_loop { - public: +public: int general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - - /******************************************************************* - SET FUNCTIONS - *******************************************************************/ - - /*! - * \brief Set the loop bandwidth - * - * Set the loop filter's bandwidth to \p bw. This should be between - * 2*pi/200 and 2*pi/100 (in rads/samp). It must also be a positive - * number. - * - * When a new damping factor is set, the gains, alpha and beta, of the loop - * are recalculated by a call to update_gains(). - * - * \param bw (float) new bandwidth - * - */ - void set_loop_bandwidth(float bw); - - /*! - * \brief Set the loop damping factor - * - * Set the loop filter's damping factor to \p df. The damping factor - * should be sqrt(2)/2.0 for critically damped systems. - * Set it to anything else only if you know what you are doing. It must - * be a number between 0 and 1. - * - * When a new damping factor is set, the gains, alpha and beta, of the loop - * are recalculated by a call to update_gains(). - * - * \param df (float) new damping factor - * - */ - void set_damping_factor(float df); - - /*! - * \brief Set the loop gain alpha - * - * Set's the loop filter's alpha gain parameter. - * - * This value should really only be set by adjusting the loop bandwidth - * and damping factor. - * - * \param alpha (float) new alpha gain - * - */ - void set_alpha(float alpha); - - /*! - * \brief Set the loop gain beta - * - * Set's the loop filter's beta gain parameter. - * - * This value should really only be set by adjusting the loop bandwidth - * and damping factor. - * - * \param beta (float) new beta gain - * - */ - void set_beta(float beta); - - /*! - * \brief Set the phase/freq recovery loop's frequency. - * - * Set's the phase/freq recovery loop's frequency. While this is normally - * updated by the inner loop of the algorithm, it could be useful to - * manually initialize, set, or reset this under certain circumstances. - * - * \param freq (float) new frequency - * - */ - void set_frequency(float freq); - - /*! - * \brief Set the phase/freq recovery loop's phase. - * - * Set's the phase/freq recovery loop's phase. While this is normally - * updated by the inner loop of the algorithm, it could be useful to - * manually initialize, set, or reset this under certain circumstances. - * - * \param phase (float) new phase - * - */ - void set_phase(float phase); - - /******************************************************************* - GET FUNCTIONS - *******************************************************************/ - - /*! - * \brief Returns the loop bandwidth - */ - float get_loop_bandwidth() const; - - /*! - * \brief Returns the loop damping factor - */ - float get_damping_factor() const; - - /*! - * \brief Returns the loop gain alpha - */ - float get_alpha() const; - - /*! - * \brief Returns the loop gain beta - */ - float get_beta() const; - - /*! - * \brief Get the phase/freq recovery loop's frequency estimate - */ - float get_frequency() const; - - /*! - * \brief Get the phase/freq loop's phase estimate - */ - float get_phase() const; - protected: /*! @@ -211,18 +92,9 @@ protected: void phase_error_tracking(float phase_error); - private: +private: unsigned int d_M; - // Members related to carrier and phase tracking - float d_freq, d_max_freq, d_min_freq; - float d_phase; - - float d_loop_bw; - float d_damping; - float d_alpha; - float d_beta; - digital_constellation_sptr d_constellation; unsigned int d_current_const_point; @@ -230,20 +102,11 @@ protected: static const unsigned int DLLEN = 8; //! delay line plus some length for overflow protection - __GR_ATTR_ALIGNED(8) gr_complex d_dl[2*DLLEN]; + gr_complex d_dl[2*DLLEN] __attribute__ ((aligned(8))); //! index to delay line unsigned int d_dl_idx; - /*! \brief update the system gains from the loop bandwidth and damping factor - * - * This function updates the system gains based on the loop - * bandwidth and damping factor of the system. - * These two factors can be set separately through their own - * set functions. - */ - void update_gains(); - friend DIGITAL_API digital_constellation_receiver_cb_sptr digital_make_constellation_receiver_cb (digital_constellation_sptr constell, float loop_bw, float fmin, float fmax); diff --git a/gr-digital/lib/digital_fll_band_edge_cc.cc b/gr-digital/lib/digital_fll_band_edge_cc.cc index 70cb54351..05c092622 100644 --- a/gr-digital/lib/digital_fll_band_edge_cc.cc +++ b/gr-digital/lib/digital_fll_band_edge_cc.cc @@ -55,6 +55,7 @@ digital_fll_band_edge_cc::digital_fll_band_edge_cc (float samps_per_sym, float r : gr_sync_block ("fll_band_edge_cc", gr_make_io_signature (1, 1, sizeof(gr_complex)), gr_make_io_signaturev (1, 4, iosig)), + gri_control_loop(bandwidth, M_TWOPI*(2.0/samps_per_sym), -M_TWOPI*(2.0/samps_per_sym)), d_updated (false) { // Initialize samples per symbol @@ -75,22 +76,8 @@ digital_fll_band_edge_cc::digital_fll_band_edge_cc (float samps_per_sym, float r } d_filter_size = filter_size; - // base this on the number of samples per symbol - d_max_freq = M_TWOPI * (2.0/samps_per_sym); - d_min_freq = -M_TWOPI * (2.0/samps_per_sym); - - // Set the damping factor for a critically damped system - d_damping = sqrtf(2.0f)/2.0f; - - // Set the bandwidth, which will then call update_gains() - set_loop_bandwidth(bandwidth); - // Build the band edge filters design_filter(d_sps, d_rolloff, d_filter_size); - - // Initialize loop values - d_freq = 0; - d_phase = 0; } digital_fll_band_edge_cc::~digital_fll_band_edge_cc () @@ -102,47 +89,6 @@ digital_fll_band_edge_cc::~digital_fll_band_edge_cc () SET FUNCTIONS *******************************************************************/ - -void -digital_fll_band_edge_cc::set_loop_bandwidth(float bw) -{ - if(bw < 0) { - throw std::out_of_range ("digital_fll_band_edge_cc: invalid bandwidth. Must be >= 0."); - } - - d_loop_bw = bw; - update_gains(); -} - -void -digital_fll_band_edge_cc::set_damping_factor(float df) -{ - if(df < 0 || df > 1.0) { - throw std::out_of_range ("digital_fll_band_edge_cc: invalid damping factor. Must be in [0,1]."); - } - - d_damping = df; - update_gains(); -} - -void -digital_fll_band_edge_cc::set_alpha(float alpha) -{ - if(alpha < 0 || alpha > 1.0) { - throw std::out_of_range ("digital_fll_band_edge_cc: invalid alpha. Must be in [0,1]."); - } - d_alpha = alpha; -} - -void -digital_fll_band_edge_cc::set_beta(float beta) -{ - if(beta < 0 || beta > 1.0) { - throw std::out_of_range ("digital_fll_band_edge_cc: invalid beta. Must be in [0,1]."); - } - d_beta = beta; -} - void digital_fll_band_edge_cc::set_samples_per_symbol(float sps) { @@ -173,57 +119,10 @@ digital_fll_band_edge_cc::set_filter_size(int filter_size) design_filter(d_sps, d_rolloff, d_filter_size); } -void -digital_fll_band_edge_cc::set_frequency(float freq) -{ - if(freq > d_max_freq) - d_freq = d_min_freq; - else if(freq < d_min_freq) - d_freq = d_max_freq; - else - d_freq = freq; -} - -void -digital_fll_band_edge_cc::set_phase(float phase) -{ - d_phase = phase; - while(d_phase>M_TWOPI) - d_phase -= M_TWOPI; - while(d_phase<-M_TWOPI) - d_phase += M_TWOPI; -} - - /******************************************************************* GET FUNCTIONS *******************************************************************/ - -float -digital_fll_band_edge_cc::get_loop_bandwidth() const -{ - return d_loop_bw; -} - -float -digital_fll_band_edge_cc::get_damping_factor() const -{ - return d_damping; -} - -float -digital_fll_band_edge_cc::get_alpha() const -{ - return d_alpha; -} - -float -digital_fll_band_edge_cc::get_beta() const -{ - return d_beta; -} - float digital_fll_band_edge_cc::get_samples_per_symbol() const { @@ -242,31 +141,10 @@ digital_fll_band_edge_cc:: get_filter_size() const return d_filter_size; } -float -digital_fll_band_edge_cc::get_frequency() const -{ - return d_freq; -} - -float -digital_fll_band_edge_cc::get_phase() const -{ - return d_phase; -} - /******************************************************************* *******************************************************************/ - -void -digital_fll_band_edge_cc::update_gains() -{ - float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw); - d_alpha = (4*d_damping*d_loop_bw) / denom; - d_beta = (4*d_loop_bw*d_loop_bw) / denom; -} - void digital_fll_band_edge_cc::design_filter(float samps_per_sym, float rolloff, int filter_size) @@ -366,18 +244,9 @@ digital_fll_band_edge_cc::work (int noutput_items, } error = norm(out_lower) - norm(out_upper); - d_freq = d_freq + d_beta * error; - d_phase = d_phase + d_freq + d_alpha * error; - - if(d_phase > M_PI) - d_phase -= M_TWOPI; - else if(d_phase < -M_PI) - d_phase += M_TWOPI; - - if (d_freq > d_max_freq) - d_freq = d_max_freq; - else if (d_freq < d_min_freq) - d_freq = d_min_freq; + advance_loop(error); + phase_wrap(); + frequency_limit(); if(output_items.size() == 4) { frq[i] = d_freq; diff --git a/gr-digital/lib/digital_fll_band_edge_cc.h b/gr-digital/lib/digital_fll_band_edge_cc.h index c7a56a7c9..6ef8376ac 100644 --- a/gr-digital/lib/digital_fll_band_edge_cc.h +++ b/gr-digital/lib/digital_fll_band_edge_cc.h @@ -26,6 +26,7 @@ #include <digital_api.h> #include <gr_sync_block.h> +#include <gri_control_loop.h> class digital_fll_band_edge_cc; typedef boost::shared_ptr<digital_fll_band_edge_cc> digital_fll_band_edge_cc_sptr; @@ -40,39 +41,51 @@ DIGITAL_API digital_fll_band_edge_cc_sptr digital_make_fll_band_edge_cc (float s * * \ingroup general * - * The frequency lock loop derives a band-edge filter that covers the upper and lower bandwidths - * of a digitally-modulated signal. The bandwidth range is determined by the excess bandwidth - * (e.g., rolloff factor) of the modulated signal. The placement in frequency of the band-edges - * is determined by the oversampling ratio (number of samples per symbol) and the excess bandwidth. - * The size of the filters should be fairly large so as to average over a number of symbols. + * The frequency lock loop derives a band-edge filter that covers the + * upper and lower bandwidths of a digitally-modulated signal. The + * bandwidth range is determined by the excess bandwidth (e.g., + * rolloff factor) of the modulated signal. The placement in frequency + * of the band-edges is determined by the oversampling ratio (number + * of samples per symbol) and the excess bandwidth. The size of the + * filters should be fairly large so as to average over a number of + * symbols. * - * The FLL works by filtering the upper and lower band edges into x_u(t) and x_l(t), respectively. - * These are combined to form cc(t) = x_u(t) + x_l(t) and ss(t) = x_u(t) - x_l(t). Combining - * these to form the signal e(t) = Re{cc(t) \\times ss(t)^*} (where ^* is the complex conjugate) - * provides an error signal at the DC term that is directly proportional to the carrier frequency. - * We then make a second-order loop using the error signal that is the running average of e(t). + * The FLL works by filtering the upper and lower band edges into + * x_u(t) and x_l(t), respectively. These are combined to form cc(t) + * = x_u(t) + x_l(t) and ss(t) = x_u(t) - x_l(t). Combining these to + * form the signal e(t) = Re{cc(t) \\times ss(t)^*} (where ^* is the + * complex conjugate) provides an error signal at the DC term that is + * directly proportional to the carrier frequency. We then make a + * second-order loop using the error signal that is the running + * average of e(t). * - * In practice, the above equation can be simplified by just comparing the absolute value squared - * of the output of both filters: abs(x_l(t))^2 - abs(x_u(t))^2 = norm(x_l(t)) - norm(x_u(t)). + * In practice, the above equation can be simplified by just comparing + * the absolute value squared of the output of both filters: + * abs(x_l(t))^2 - abs(x_u(t))^2 = norm(x_l(t)) - norm(x_u(t)). * - * In theory, the band-edge filter is the derivative of the matched filter in frequency, - * (H_be(f) = \\frac{H(f)}{df}. In practice, this comes down to a quarter sine wave at the point - * of the matched filter's rolloff (if it's a raised-cosine, the derivative of a cosine is a sine). - * Extend this sine by another quarter wave to make a half wave around the band-edges is equivalent - * in time to the sum of two sinc functions. The baseband filter fot the band edges is therefore - * derived from this sum of sincs. The band edge filters are then just the baseband signal - * modulated to the correct place in frequency. All of these calculations are done in the + * In theory, the band-edge filter is the derivative of the matched + * filter in frequency, (H_be(f) = \\frac{H(f)}{df}. In practice, this + * comes down to a quarter sine wave at the point of the matched + * filter's rolloff (if it's a raised-cosine, the derivative of a + * cosine is a sine). Extend this sine by another quarter wave to + * make a half wave around the band-edges is equivalent in time to the + * sum of two sinc functions. The baseband filter fot the band edges + * is therefore derived from this sum of sincs. The band edge filters + * are then just the baseband signal modulated to the correct place in + * frequency. All of these calculations are done in the * 'design_filter' function. * - * Note: We use FIR filters here because the filters have to have a flat phase response over the - * entire frequency range to allow their comparisons to be valid. + * Note: We use FIR filters here because the filters have to have a + * flat phase response over the entire frequency range to allow their + * comparisons to be valid. * - * It is very important that the band edge filters be the derivatives of the pulse shaping filter, - * and that they be linear phase. Otherwise, the variance of the error will be very large. + * It is very important that the band edge filters be the derivatives + * of the pulse shaping filter, and that they be linear + * phase. Otherwise, the variance of the error will be very large. * */ -class DIGITAL_API digital_fll_band_edge_cc : public gr_sync_block +class DIGITAL_API digital_fll_band_edge_cc : public gr_sync_block, public gri_control_loop { private: /*! @@ -90,21 +103,11 @@ class DIGITAL_API digital_fll_band_edge_cc : public gr_sync_block float d_sps; float d_rolloff; int d_filter_size; - float d_max_freq; - float d_min_freq; - - float d_loop_bw; - float d_damping; - float d_alpha; - float d_beta; std::vector<gr_complex> d_taps_lower; std::vector<gr_complex> d_taps_upper; bool d_updated; - float d_freq; - float d_phase; - /*! * Build the FLL * \param samps_per_sym (float) number of samples per symbol @@ -116,11 +119,6 @@ class DIGITAL_API digital_fll_band_edge_cc : public gr_sync_block int filter_size, float bandwidth); /*! - * \brief Update the gains, alpha and beta, of the loop filter. - */ - void update_gains(); - - /*! * Design the band-edge filter based on the number of samples per symbol, * filter rolloff factor, and the filter size * @@ -138,67 +136,11 @@ public: *******************************************************************/ /*! - * \brief Set the loop bandwidth - * - * Set the loop filter's bandwidth to \p bw. This should be between - * 2*pi/200 and 2*pi/100 (in rads/samp). It must also be a positive - * number. - * - * When a new damping factor is set, the gains, alpha and beta, of the loop - * are recalculated by a call to update_gains(). - * - * \param bw (float) new bandwidth - * - */ - void set_loop_bandwidth(float bw); - - /*! - * \brief Set the loop damping factor - * - * Set the loop filter's damping factor to \p df. The damping factor - * should be sqrt(2)/2.0 for critically damped systems. - * Set it to anything else only if you know what you are doing. It must - * be a number between 0 and 1. - * - * When a new damping factor is set, the gains, alpha and beta, of the loop - * are recalculated by a call to update_gains(). - * - * \param df (float) new damping factor - * - */ - void set_damping_factor(float df); - - /*! - * \brief Set the loop gain alpha - * - * Set's the loop filter's alpha gain parameter. - * - * This value should really only be set by adjusting the loop bandwidth - * and damping factor. - * - * \param alpha (float) new alpha gain - * - */ - void set_alpha(float alpha); - - /*! - * \brief Set the loop gain beta - * - * Set's the loop filter's beta gain parameter. - * - * This value should really only be set by adjusting the loop bandwidth - * and damping factor. - * - * \param beta (float) new beta gain - * - */ - void set_beta(float beta); - - /*! * \brief Set the number of samples per symbol * - * Set's the number of samples per symbol the system should use. This value - * is uesd to calculate the filter taps and will force a recalculation. + * Set's the number of samples per symbol the system should + * use. This value is uesd to calculate the filter taps and will + * force a recalculation. * * \param sps (float) new samples per symbol * @@ -208,13 +150,14 @@ public: /*! * \brief Set the rolloff factor of the shaping filter * - * This sets the rolloff factor that is used in the pulse shaping filter - * and is used to calculate the filter taps. Changing this will force a - * recalculation of the filter taps. + * This sets the rolloff factor that is used in the pulse shaping + * filter and is used to calculate the filter taps. Changing this + * will force a recalculation of the filter taps. * - * This should be the same value that is used in the transmitter's pulse - * shaping filter. It must be between 0 and 1 and is usually between - * 0.2 and 0.5 (where 0.22 and 0.35 are commonly used values). + * This should be the same value that is used in the transmitter's + * pulse shaping filter. It must be between 0 and 1 and is usually + * between 0.2 and 0.5 (where 0.22 and 0.35 are commonly used + * values). * * \param rolloff (float) new shaping filter rolloff factor [0,1] * @@ -224,68 +167,25 @@ public: /*! * \brief Set the number of taps in the filter * - * This sets the number of taps in the band-edge filters. Setting this will - * force a recalculation of the filter taps. + * This sets the number of taps in the band-edge filters. Setting + * this will force a recalculation of the filter taps. * - * This should be about the same number of taps used in the transmitter's - * shaping filter and also not very large. A large number of taps will - * result in a large delay between input and frequency estimation, and - * so will not be as accurate. Between 30 and 70 taps is usual. + * This should be about the same number of taps used in the + * transmitter's shaping filter and also not very large. A large + * number of taps will result in a large delay between input and + * frequency estimation, and so will not be as accurate. Between 30 + * and 70 taps is usual. * * \param filter_size (float) number of taps in the filters * */ void set_filter_size(int filter_size); - /*! - * \brief Set the FLL's frequency. - * - * Set's the FLL's frequency. While this is normally updated by the - * inner loop of the algorithm, it could be useful to manually initialize, - * set, or reset this under certain circumstances. - * - * \param freq (float) new frequency - * - */ - void set_frequency(float freq); - - /*! - * \brief Set the FLL's phase. - * - * Set's the FLL's phase. While this is normally updated by the - * inner loop of the algorithm, it could be useful to manually initialize, - * set, or reset this under certain circumstances. - * - * \param phase (float) new phase - * - */ - void set_phase(float phase); - /******************************************************************* GET FUNCTIONS *******************************************************************/ /*! - * \brief Returns the loop bandwidth - */ - float get_loop_bandwidth() const; - - /*! - * \brief Returns the loop damping factor - */ - float get_damping_factor() const; - - /*! - * \brief Returns the loop gain alpha - */ - float get_alpha() const; - - /*! - * \brief Returns the loop gain beta - */ - float get_beta() const; - - /*! * \brief Returns the number of sampler per symbol used for the filter */ float get_samples_per_symbol() const; @@ -301,16 +201,6 @@ public: int get_filter_size() const; /*! - * \brief Get the FLL's frequency estimate - */ - float get_frequency() const; - - /*! - * \brief Get the FLL's phase estimate - */ - float get_phase() const; - - /*! * Print the taps to screen. */ void print_taps(); diff --git a/gr-digital/lib/digital_mpsk_receiver_cc.cc b/gr-digital/lib/digital_mpsk_receiver_cc.cc index 3b2ea9840..363b86c9f 100644 --- a/gr-digital/lib/digital_mpsk_receiver_cc.cc +++ b/gr-digital/lib/digital_mpsk_receiver_cc.cc @@ -41,28 +41,30 @@ digital_mpsk_receiver_cc_sptr digital_make_mpsk_receiver_cc(unsigned int M, float theta, - float alpha, float beta, + float loop_bw, float fmin, float fmax, float mu, float gain_mu, float omega, float gain_omega, float omega_rel) { return gnuradio::get_initial_sptr(new digital_mpsk_receiver_cc (M, theta, - alpha, beta, - fmin, fmax, - mu, gain_mu, - omega, gain_omega, omega_rel)); + loop_bw, + fmin, fmax, + mu, gain_mu, + omega, gain_omega, + omega_rel)); } digital_mpsk_receiver_cc::digital_mpsk_receiver_cc (unsigned int M, float theta, - float alpha, float beta, - float fmin, float fmax, - float mu, float gain_mu, - float omega, float gain_omega, float omega_rel) + float loop_bw, + float fmin, float fmax, + float mu, float gain_mu, + float omega, float gain_omega, + float omega_rel) : gr_block ("mpsk_receiver_cc", gr_make_io_signature (1, 1, sizeof (gr_complex)), gr_make_io_signature (1, 1, sizeof (gr_complex))), + gri_control_loop(loop_bw, fmax, fmin), d_M(M), d_theta(theta), - d_alpha(alpha), d_beta(beta), d_freq(0), d_max_freq(fmax), d_min_freq(fmin), d_phase(0), d_current_const_point(0), d_mu(mu), d_gain_mu(gain_mu), d_gain_omega(gain_omega), d_omega_rel(omega_rel), d_max_omega(0), d_min_omega(0), @@ -265,18 +267,10 @@ digital_mpsk_receiver_cc::phase_error_tracking(gr_complex sample) // Make phase and frequency corrections based on sampled value phase_error = (*this.*d_phase_error_detector)(sample); - - d_freq += d_beta*phase_error; // adjust frequency based on error - d_phase += d_freq + d_alpha*phase_error; // adjust phase based on error - - // Make sure we stay within +-2pi - while(d_phase > M_TWOPI) - d_phase -= M_TWOPI; - while(d_phase < -M_TWOPI) - d_phase += M_TWOPI; - // Limit the frequency range - d_freq = gr_branchless_clip(d_freq, d_max_freq); + advance_loop(phase_error); + phase_wrap(); + frequency_limit(); #if VERBOSE_COSTAS printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n", diff --git a/gr-digital/lib/digital_mpsk_receiver_cc.h b/gr-digital/lib/digital_mpsk_receiver_cc.h index 8a6352ec7..85cd81e99 100644 --- a/gr-digital/lib/digital_mpsk_receiver_cc.h +++ b/gr-digital/lib/digital_mpsk_receiver_cc.h @@ -25,6 +25,7 @@ #include <digital_api.h> #include <gruel/attributes.h> +#include <gri_control_loop.h> #include <gr_block.h> #include <gr_complex.h> #include <fstream> @@ -37,41 +38,48 @@ typedef boost::shared_ptr<digital_mpsk_receiver_cc> digital_mpsk_receiver_cc_spt // public constructor DIGITAL_API digital_mpsk_receiver_cc_sptr digital_make_mpsk_receiver_cc (unsigned int M, float theta, - float alpha, float beta, + float loop_bw, float fmin, float fmax, float mu, float gain_mu, float omega, float gain_omega, float omega_rel); /*! - * \brief This block takes care of receiving M-PSK modulated signals through phase, frequency, and symbol - * synchronization. + * \brief This block takes care of receiving M-PSK modulated signals + * through phase, frequency, and symbol synchronization. * \ingroup sync_blk * \ingroup demod_blk * - * This block takes care of receiving M-PSK modulated signals through phase, frequency, and symbol - * synchronization. It performs carrier frequency and phase locking as well as symbol timing recovery. - * It works with (D)BPSK, (D)QPSK, and (D)8PSK as tested currently. It should also work for OQPSK and - * PI/4 DQPSK. + * This block takes care of receiving M-PSK modulated signals through + * phase, frequency, and symbol synchronization. It performs carrier + * frequency and phase locking as well as symbol timing recovery. It + * works with (D)BPSK, (D)QPSK, and (D)8PSK as tested currently. It + * should also work for OQPSK and PI/4 DQPSK. * - * The phase and frequency synchronization are based on a Costas loop that finds the error of the incoming - * signal point compared to its nearest constellation point. The frequency and phase of the NCO are - * updated according to this error. There are optimized phase error detectors for BPSK and QPSK, but 8PSK - * is done using a brute-force computation of the constellation points to find the minimum. + * The phase and frequency synchronization are based on a Costas loop + * that finds the error of the incoming signal point compared to its + * nearest constellation point. The frequency and phase of the NCO are + * updated according to this error. There are optimized phase error + * detectors for BPSK and QPSK, but 8PSK is done using a brute-force + * computation of the constellation points to find the minimum. * - * The symbol synchronization is done using a modified Mueller and Muller circuit from the paper: + * The symbol synchronization is done using a modified Mueller and + * Muller circuit from the paper: * - * G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller and Muller - * algorithm," Electronics Letters, Vol. 31, no. 13, 22 June 1995, pp. 1032 - 1033. + * G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller + * and Muller algorithm," Electronics Letters, Vol. 31, no. 13, 22 + * June 1995, pp. 1032 - 1033. * - * This circuit interpolates the downconverted sample (using the NCO developed by the Costas loop) - * every mu samples, then it finds the sampling error based on this and the past symbols and the decision - * made on the samples. Like the phase error detector, there are optimized decision algorithms for BPSK - * and QPKS, but 8PSK uses another brute force computation against all possible symbols. The modifications - * to the M&M used here reduce self-noise. + * This circuit interpolates the downconverted sample (using the NCO + * developed by the Costas loop) every mu samples, then it finds the + * sampling error based on this and the past symbols and the decision + * made on the samples. Like the phase error detector, there are + * optimized decision algorithms for BPSK and QPKS, but 8PSK uses + * another brute force computation against all possible symbols. The + * modifications to the M&M used here reduce self-noise. * */ -class DIGITAL_API digital_mpsk_receiver_cc : public gr_block +class DIGITAL_API digital_mpsk_receiver_cc : public gr_block, public gri_control_loop { public: ~digital_mpsk_receiver_cc (); @@ -112,43 +120,14 @@ class DIGITAL_API digital_mpsk_receiver_cc : public gr_block //! (M&M) Sets value for omega gain factor void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; } - - - // Member function related to the phase/frequency tracking portion of the receiver - //! (CL) Returns the value for alpha (the phase gain term) - float alpha() const { return d_alpha; } - - //! (CL) Returns the value of beta (the frequency gain term) - float beta() const { return d_beta; } - - //! (CL) Returns the current value of the frequency of the NCO in the Costas loop - float freq() const { return d_freq; } - - //! (CL) Returns the current value of the phase of the NCO in the Costal loop - float phase() const { return d_phase; } - - //! (CL) Sets the value for alpha (the phase gain term) - void set_alpha(float alpha) { d_alpha = alpha; } - - //! (CL) Setss the value of beta (the frequency gain term) - void set_beta(float beta) { d_beta = beta; } - - //! (CL) Sets the current value of the frequency of the NCO in the Costas loop - void set_freq(float freq) { d_freq = freq; } - - //! (CL) Setss the current value of the phase of the NCO in the Costal loop - void set_phase(float phase) { d_phase = phase; } - - protected: - - /*! + + /*! * \brief Constructor to synchronize incoming M-PSK symbols * * \param M modulation order of the M-PSK modulation * \param theta any constant phase rotation from the real axis of the constellation - * \param alpha gain parameter to adjust the phase in the Costas loop (~0.01) - * \param beta gain parameter to adjust the frequency in the Costas loop (~alpha^2/4) + * \param loop_bw Loop bandwidth to set gains of phase/freq tracking loop * \param fmin minimum normalized frequency value the loop can achieve * \param fmax maximum normalized frequency value the loop can achieve * \param mu initial parameter for the interpolator [0,1] @@ -161,7 +140,7 @@ protected: * value of M. */ digital_mpsk_receiver_cc (unsigned int M, float theta, - float alpha, float beta, + float loop_bw, float fmin, float fmax, float mu, float gain_mu, float omega, float gain_omega, float omega_rel); @@ -172,54 +151,61 @@ protected: void phase_error_tracking(gr_complex sample); -/*! + /*! * \brief Phase error detector for MPSK modulations. * * \param sample the I&Q sample from which to determine the phase error * - * This function determines the phase error for any MPSK signal by creating a set of PSK constellation points - * and doing a brute-force search to see which point minimizes the Euclidean distance. This point is then used - * to derotate the sample to the real-axis and a atan (using the fast approximation function) to determine the - * phase difference between the incoming sample and the real constellation point + * This function determines the phase error for any MPSK signal by + * creating a set of PSK constellation points and doing a + * brute-force search to see which point minimizes the Euclidean + * distance. This point is then used to derotate the sample to the + * real-axis and a atan (using the fast approximation function) to + * determine the phase difference between the incoming sample and + * the real constellation point * * This should be cleaned up and made more efficient. * * \returns the approximated phase error. - */ + */ float phase_error_detector_generic(gr_complex sample) const; // generic for M but more costly - /*! + /*! * \brief Phase error detector for BPSK modulation. * * \param sample the I&Q sample from which to determine the phase error * - * This function determines the phase error using a simple BPSK phase error detector by multiplying the real - * and imaginary (the error signal) components together. As the imaginary part goes to 0, so does this error. + * This function determines the phase error using a simple BPSK + * phase error detector by multiplying the real and imaginary (the + * error signal) components together. As the imaginary part goes to + * 0, so does this error. * * \returns the approximated phase error. - */ + */ float phase_error_detector_bpsk(gr_complex sample) const; // optimized for BPSK - /*! + /*! * \brief Phase error detector for QPSK modulation. * * \param sample the I&Q sample from which to determine the phase error * - * This function determines the phase error using the limiter approach in a standard 4th order Costas loop + * This function determines the phase error using the limiter + * approach in a standard 4th order Costas loop * * \returns the approximated phase error. - */ + */ float phase_error_detector_qpsk(gr_complex sample) const; - /*! + /*! * \brief Decision maker for a generic MPSK constellation. * * \param sample the baseband I&Q sample from which to make the decision * - * This decision maker is a generic implementation that does a brute-force search - * for the constellation point that minimizes the error between it and the incoming signal. + * This decision maker is a generic implementation that does a + * brute-force search for the constellation point that minimizes the + * error between it and the incoming signal. * * \returns the index to d_constellation that minimizes the error/ */ @@ -231,46 +217,44 @@ protected: * * \param sample the baseband I&Q sample from which to make the decision * - * This decision maker is a simple slicer function that makes a decision on the symbol based on its - * placement on the real axis of greater than 0 or less than 0; the quadrature component is always 0. + * This decision maker is a simple slicer function that makes a + * decision on the symbol based on its placement on the real axis of + * greater than 0 or less than 0; the quadrature component is always + * 0. * * \returns the index to d_constellation that minimizes the error/ - */ + */ unsigned int decision_bpsk(gr_complex sample) const; - /*! + /*! * \brief Decision maker for QPSK constellation. * * \param sample the baseband I&Q sample from which to make the decision * - * This decision maker is a simple slicer function that makes a decision on the symbol based on its - * placement versus both axes and returns which quadrant the symbol is in. + * This decision maker is a simple slicer function that makes a + * decision on the symbol based on its placement versus both axes + * and returns which quadrant the symbol is in. * * \returns the index to d_constellation that minimizes the error/ - */ + */ unsigned int decision_qpsk(gr_complex sample) const; - private: +private: unsigned int d_M; float d_theta; - // Members related to carrier and phase tracking - float d_alpha; - float d_beta; - float d_freq, d_max_freq, d_min_freq; - float d_phase; - -/*! + /*! * \brief Decision maker function pointer * * \param sample the baseband I&Q sample from which to make the decision * - * This is a function pointer that is set in the constructor to point to the proper decision function - * for the specified constellation order. + * This is a function pointer that is set in the constructor to + * point to the proper decision function for the specified + * constellation order. * * \return index into d_constellation point that is the closest to the recieved sample - */ + */ unsigned int (digital_mpsk_receiver_cc::*d_decision)(gr_complex sample) const; // pointer to decision function @@ -283,14 +267,15 @@ protected: gr_complex d_p_2T, d_p_1T, d_p_0T; gr_complex d_c_2T, d_c_1T, d_c_0T; - /*! + /*! * \brief Phase error detector function pointer * * \param sample the I&Q sample from which to determine the phase error * - * This is a function pointer that is set in the constructor to point to the proper phase error detector - * function for the specified constellation order. - */ + * This is a function pointer that is set in the constructor to + * point to the proper phase error detector function for the + * specified constellation order. + */ float (digital_mpsk_receiver_cc::*d_phase_error_detector)(gr_complex sample) const; @@ -308,7 +293,7 @@ protected: friend DIGITAL_API digital_mpsk_receiver_cc_sptr digital_make_mpsk_receiver_cc (unsigned int M, float theta, - float alpha, float beta, + float loop_bw, float fmin, float fmax, float mu, float gain_mu, float omega, float gain_omega, float omega_rel); diff --git a/gr-digital/python/Makefile.am b/gr-digital/python/Makefile.am index 6c61002f1..a33e4963d 100644 --- a/gr-digital/python/Makefile.am +++ b/gr-digital/python/Makefile.am @@ -35,6 +35,7 @@ noinst_PYTHON = \ qa_binary_slicer_fb.py \ qa_clock_recovery_mm.py \ qa_cma_equalizer.py \ + qa_cpm.py \ qa_constellation.py \ qa_constellation_receiver.py \ qa_constellation_decoder_cb.py \ diff --git a/gr-digital/python/__init__.py b/gr-digital/python/__init__.py index 4046f7faf..7173fa09d 100644 --- a/gr-digital/python/__init__.py +++ b/gr-digital/python/__init__.py @@ -26,6 +26,7 @@ from psk2 import * from bpsk import * from qpsk import * from qam import * +from gmsk import * from pkt import * from packet_utils import * from crc import * diff --git a/gr-digital/python/generic_mod_demod.py b/gr-digital/python/generic_mod_demod.py index da8e2cfd9..b1986512f 100644 --- a/gr-digital/python/generic_mod_demod.py +++ b/gr-digital/python/generic_mod_demod.py @@ -54,7 +54,7 @@ def add_common_options(parser): Sets options common to both modulator and demodulator. """ parser.add_option("-p", "--constellation-points", type="int", default=_def_constellation_points, - help="set the number of constellation points (must be a power of 2 (power of 4 for QAM) [default=%default]") + help="set the number of constellation points (must be a power of 2 for psk, power of 4 for QAM) [default=%default]") parser.add_option("", "--non-differential", action="store_true", dest="differential", default=False, help="do not use differential encoding [default=%default]") @@ -120,7 +120,7 @@ class generic_mod(gr.hier_block2): self.bytes2chunks = \ gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST) - if self._constellation.apply_pre_diff_code(): + if gray_coded == True: self.symbol_mapper = gr.map_bb(self._constellation.pre_diff_code()) if differential: @@ -142,7 +142,7 @@ class generic_mod(gr.hier_block2): # Connect blocks = [self, self.bytes2chunks] - if self._constellation.apply_pre_diff_code(): + if gray_coded == True: blocks.append(self.symbol_mapper) if differential: blocks.append(self.diffenc) @@ -211,6 +211,7 @@ class generic_demod(gr.hier_block2): samples_per_symbol=_def_samples_per_symbol, differential=_def_differential, excess_bw=_def_excess_bw, + gray_coded=True, freq_bw=_def_freq_bw, timing_bw=_def_timing_bw, phase_bw=_def_phase_bw, @@ -228,9 +229,11 @@ class generic_demod(gr.hier_block2): @type samples_per_symbol: float @param excess_bw: Root-raised cosine filter excess bandwidth @type excess_bw: float + @param gray_coded: turn gray coding on/off + @type gray_coded: bool @param freq_bw: loop filter lock-in bandwidth @type freq_bw: float - @param timing_bw: timing recoery loop lock-in bandwidth + @param timing_bw: timing recovery loop lock-in bandwidth @type timing_bw: float @param phase_bw: phase recovery loop bandwidth @type phase_bw: float @@ -265,8 +268,9 @@ class generic_demod(gr.hier_block2): self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100) # Frequency correction + fll_ntaps = 55 self.freq_recov = digital_swig.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw, - ntaps, self._freq_bw) + fll_ntaps, self._freq_bw) # symbol timing recovery with RRC data filter taps = gr.firdes.root_raised_cosine(nfilts, nfilts*self._samples_per_symbol, @@ -280,12 +284,12 @@ class generic_demod(gr.hier_block2): self.receiver = digital_swig.constellation_receiver_cb( self._constellation, self._phase_bw, fmin, fmax) - + # Do differential decoding based on phase change of symbols if differential: self.diffdec = gr.diff_decoder_bb(arity) - if self._constellation.apply_pre_diff_code(): + if gray_coded: self.symbol_mapper = gr.map_bb( mod_codes.invert_code(self._constellation.pre_diff_code())) @@ -297,9 +301,10 @@ class generic_demod(gr.hier_block2): if log: self._setup_logging() - + # Connect and Initialize base class - blocks = [self, self.agc, self.freq_recov, self.time_recov, self.receiver] + blocks = [self, self.agc, self.freq_recov, + self.time_recov, self.receiver] if differential: blocks.append(self.diffdec) if self._constellation.apply_pre_diff_code(): diff --git a/gr-digital/python/gmsk.py b/gr-digital/python/gmsk.py index 3b6c016a0..ba122821e 100644 --- a/gr-digital/python/gmsk.py +++ b/gr-digital/python/gmsk.py @@ -25,7 +25,9 @@ # See gnuradio-examples/python/digital for examples from gnuradio import gr -from gnuradio import modulation_utils +import digital_swig +import modulation_utils2 + from math import pi import numpy from pprint import pprint @@ -37,11 +39,9 @@ _def_bt = 0.35 _def_verbose = False _def_log = False -_def_gain_mu = None -_def_mu = 0.5 -_def_freq_error = 0.0 -_def_omega_relative_limit = 0.005 - +# Symbol timing recovery +_def_timing_bw = 2*pi/100.0 +_def_timing_max_dev = 1.5 # ///////////////////////////////////////////////////////////////////////////// # GMSK modulator @@ -79,7 +79,8 @@ class gmsk_mod(gr.hier_block2): self._bt = bt if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2: - raise TypeError, ("samples_per_symbol must be an integer >= 2, is %r" % (samples_per_symbol,)) + raise TypeError, ("samples_per_symbol must be an integer >= 2, is %r" % \ + (samples_per_symbol,)) ntaps = 4 * samples_per_symbol # up to 3 bits in filter at once sensitivity = (pi / 2) / samples_per_symbol # phase change per bit = pi / 2 @@ -128,11 +129,11 @@ class gmsk_mod(gr.hier_block2): def _setup_logging(self): print "Modulation logging turned on." self.connect(self.nrz, - gr.file_sink(gr.sizeof_float, "nrz.dat")) + gr.file_sink(gr.sizeof_float, "tx_gmsk_nrz.32f")) self.connect(self.gaussian_filter, - gr.file_sink(gr.sizeof_float, "gaussian_filter.dat")) + gr.file_sink(gr.sizeof_float, "tx_gmsk_gaussian_filter.32f")) self.connect(self.fmmod, - gr.file_sink(gr.sizeof_gr_complex, "fmmod.dat")) + gr.file_sink(gr.sizeof_gr_complex, "tx_gmsk_fmmod.32fc")) def add_options(parser): @@ -148,7 +149,7 @@ class gmsk_mod(gr.hier_block2): """ Given command line options, create dictionary suitable for passing to __init__ """ - return modulation_utils.extract_kwargs_from_options(gmsk_mod.__init__, + return modulation_utils2.extract_kwargs_from_options(gmsk_mod.__init__, ('self',), options) extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) @@ -162,10 +163,8 @@ class gmsk_demod(gr.hier_block2): def __init__(self, samples_per_symbol=_def_samples_per_symbol, - gain_mu=_def_gain_mu, - mu=_def_mu, - omega_relative_limit=_def_omega_relative_limit, - freq_error=_def_freq_error, + bt=_def_bt, + timing_bw=_def_timing_bw, verbose=_def_verbose, log=_def_log): """ @@ -177,21 +176,12 @@ class gmsk_demod(gr.hier_block2): @param samples_per_symbol: samples per baud @type samples_per_symbol: integer + @param timing_bw: timing recovery loop lock-in bandwidth + @type timing_bw: float @param verbose: Print information about modulator? @type verbose: bool @param log: Print modualtion data to files? @type log: bool - - Clock recovery parameters. These all have reasonble defaults. - - @param gain_mu: controls rate of mu adjustment - @type gain_mu: float - @param mu: fractional delay [0.0, 1.0] - @type mu: float - @param omega_relative_limit: sets max variation in omega - @type omega_relative_limit: float, typically 0.000200 (200 ppm) - @param freq_error: bit rate error as a fraction - @param float """ gr.hier_block2.__init__(self, "gmsk_demod", @@ -199,33 +189,31 @@ class gmsk_demod(gr.hier_block2): gr.io_signature(1, 1, gr.sizeof_char)) # Output signature self._samples_per_symbol = samples_per_symbol - self._gain_mu = gain_mu - self._mu = mu - self._omega_relative_limit = omega_relative_limit - self._freq_error = freq_error + self._bt = bt + self._timing_bw = timing_bw + self._timing_max_dev= _def_timing_max_dev if samples_per_symbol < 2: raise TypeError, "samples_per_symbol >= 2, is %f" % samples_per_symbol - self._omega = samples_per_symbol*(1+self._freq_error) - - if not self._gain_mu: - self._gain_mu = 0.175 - - self._gain_omega = .25 * self._gain_mu * self._gain_mu # critically damped - # Demodulate FM sensitivity = (pi / 2) / samples_per_symbol self.fmdemod = gr.quadrature_demod_cf(1.0 / sensitivity) # the clock recovery block tracks the symbol clock and resamples as needed. # the output of the block is a stream of soft symbols (float) - self.clock_recovery = gr.clock_recovery_mm_ff(self._omega, self._gain_omega, - self._mu, self._gain_mu, - self._omega_relative_limit) - + nfilts = 32 + ntaps = 11 * int(self._samples_per_symbol*nfilts) + taps = gr.firdes.gaussian(nfilts, + nfilts*self._samples_per_symbol, + self._bt, ntaps) + self.clock_recovery = \ + gr.pfb_clock_sync_fff(self._samples_per_symbol, + self._timing_bw, taps, + nfilts, nfilts//2, self._timing_max_dev) + # slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample - self.slicer = gr.binary_slicer_fb() + self.slicer = digital_swig.binary_slicer_fb() if verbose: self._print_verbage() @@ -245,48 +233,38 @@ class gmsk_demod(gr.hier_block2): def _print_verbage(self): - print "bits per symbol = %d" % self.bits_per_symbol() - print "M&M clock recovery omega = %f" % self._omega - print "M&M clock recovery gain mu = %f" % self._gain_mu - print "M&M clock recovery mu = %f" % self._mu - print "M&M clock recovery omega rel. limit = %f" % self._omega_relative_limit - print "frequency error = %f" % self._freq_error + print "bits per symbol: %d" % self.bits_per_symbol() + print "Bandwidth-Time Prod: %f" % self._bw + print "Timing bandwidth: %.2e" % self._timing_bw def _setup_logging(self): print "Demodulation logging turned on." self.connect(self.fmdemod, - gr.file_sink(gr.sizeof_float, "fmdemod.dat")) + gr.file_sink(gr.sizeof_float, "rx_gmsk_fmdemod.32f")) self.connect(self.clock_recovery, - gr.file_sink(gr.sizeof_float, "clock_recovery.dat")) + gr.file_sink(gr.sizeof_float, "rx_gmsk_clock_recovery.32f")) self.connect(self.slicer, - gr.file_sink(gr.sizeof_char, "slicer.dat")) + gr.file_sink(gr.sizeof_char, "rx_gmsk_slicer.8b")) def add_options(parser): """ Adds GMSK demodulation-specific options to the standard parser """ - parser.add_option("", "--gain-mu", type="float", default=_def_gain_mu, - help="M&M clock recovery gain mu [default=%default] (GMSK/PSK)") - parser.add_option("", "--mu", type="float", default=_def_mu, - help="M&M clock recovery mu [default=%default] (GMSK/PSK)") - parser.add_option("", "--omega-relative-limit", type="float", default=_def_omega_relative_limit, - help="M&M clock recovery omega relative limit [default=%default] (GMSK/PSK)") - parser.add_option("", "--freq-error", type="float", default=_def_freq_error, - help="M&M clock recovery frequency error [default=%default] (GMSK)") + parser.add_option("", "--timing-bw", type="float", default=_def_timing_bw, + help="set timing symbol sync loop gain lock-in bandwidth [default=%default]") add_options=staticmethod(add_options) def extract_kwargs_from_options(options): """ Given command line options, create dictionary suitable for passing to __init__ """ - return modulation_utils.extract_kwargs_from_options(gmsk_demod.__init__, - ('self',), options) + return modulation_utils2.extract_kwargs_from_options(gmsk_demod.__init__, + ('self',), options) extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) - # # Add these to the mod/demod registry # -modulation_utils.add_type_1_mod('gmsk', gmsk_mod) -modulation_utils.add_type_1_demod('gmsk', gmsk_demod) +modulation_utils2.add_type_1_mod('gmsk', gmsk_mod) +modulation_utils2.add_type_1_demod('gmsk', gmsk_demod) diff --git a/gr-digital/python/qa_constellation.py b/gr-digital/python/qa_constellation.py index 02afb8d2d..264ff7de6 100755 --- a/gr-digital/python/qa_constellation.py +++ b/gr-digital/python/qa_constellation.py @@ -70,10 +70,8 @@ tested_constellation_info = ( 'mod_code': tested_mod_codes, }, True, None), (digital_swig.constellation_bpsk, {}, True, None), - # No differential testing for qpsk because it is gray-coded. - # This is because soft decision making is simpler if we can assume - # gray coding. (digital_swig.constellation_qpsk, {}, False, None), + (digital_swig.constellation_dqpsk, {}, True, None), (digital_swig.constellation_8psk, {}, False, None), (twod_constell, {}, True, None), (threed_constell, {}, True, None), @@ -143,8 +141,8 @@ class test_constellation (gr_unittest.TestCase): class mod_demod(gr.hier_block2): def __init__(self, constellation, differential, rotation): if constellation.arity() > 256: - # If this becomes limiting some of the blocks should be generalised so that they can work - # with shorts and ints as well as chars. + # If this becomes limiting some of the blocks should be generalised so + # that they can work with shorts and ints as well as chars. raise ValueError("Constellation cannot contain more than 256 points.") gr.hier_block2.__init__(self, "mod_demod", @@ -174,7 +172,8 @@ class mod_demod(gr.hier_block2): if self.differential: self.blocks.append(gr.diff_encoder_bb(arity)) # Convert to constellation symbols. - self.blocks.append(gr.chunks_to_symbols_bc(self.constellation.points(), self.constellation.dimensionality())) + self.blocks.append(gr.chunks_to_symbols_bc(self.constellation.points(), + self.constellation.dimensionality())) # CHANNEL # Channel just consists of a rotation to check differential coding. if rotation is not None: diff --git a/gr-digital/python/qa_constellation_receiver.py b/gr-digital/python/qa_constellation_receiver.py index 79dded8ba..25107e4a7 100755 --- a/gr-digital/python/qa_constellation_receiver.py +++ b/gr-digital/python/qa_constellation_receiver.py @@ -29,6 +29,7 @@ from generic_mod_demod import generic_mod, generic_demod from qa_constellation import tested_constellations, twod_constell +import math # Set a seed so that if errors turn up they are reproducible. # 1234 fails @@ -47,11 +48,8 @@ FREQUENCY_OFFSET = 0.01 TIMING_OFFSET = 1.0 # RECEIVER PARAMETERS -# Increased from normal default of 0.01 to speed things up. -FREQ_ALPHA = 0.02 -# Decreased from normal default of 0.1 is required for the constellations -# with smaller point separations. -PHASE_ALPHA = 0.02 +FREQ_BW = 2*math.pi/100.0 +PHASE_BW = 2*math.pi/100.0 class test_constellation_receiver (gr_unittest.TestCase): @@ -127,8 +125,8 @@ class rec_test_tb (gr.top_block): channel = gr.channel_model(NOISE_VOLTAGE, FREQUENCY_OFFSET, TIMING_OFFSET) # Receiver Blocks demod = generic_demod(constellation, differential=differential, - freq_alpha=FREQ_ALPHA, - phase_alpha=PHASE_ALPHA) + freq_bw=FREQ_BW, + phase_bw=PHASE_BW) self.dst = gr.vector_sink_b() self.connect(src, packer, mod, channel, demod, self.dst) diff --git a/gr-digital/python/qa_cpm.py b/gr-digital/python/qa_cpm.py new file mode 100755 index 000000000..12a84c76c --- /dev/null +++ b/gr-digital/python/qa_cpm.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# +# Copyright 2010 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, gr_unittest +import digital_swig +import numpy + +class test_cpm(gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def do_check_phase_shift(self, type, name): + sps = 2 + L = 1 + in_bits = (1,) * 20 + src = gr.vector_source_b(in_bits, False) + cpm = digital_swig.cpmmod_bc(type, 0.5, sps, L) + arg = gr.complex_to_arg() + sink = gr.vector_sink_f() + + self.tb.connect(src, cpm, arg, sink) + self.tb.run() + + symbol_phases = numpy.array(sink.data()[sps*L-1::sps]) + phase_diff = numpy.mod(numpy.subtract(symbol_phases[1:], symbol_phases[:-1]), + (2*numpy.pi,) * (len(symbol_phases)-1)) + self.assertFloatTuplesAlmostEqual(tuple(phase_diff), (0.5 * numpy.pi,) * len(phase_diff), 5, + msg="Phase shift was not correct for CPM method " + name) + + def test_001_lrec(self): + self.do_check_phase_shift(gr.cpm.LRC, 'LREC') + + def test_001_lrc(self): + self.do_check_phase_shift(gr.cpm.LRC, 'LRC') + + def test_001_lsrc(self): + self.do_check_phase_shift(gr.cpm.LSRC, 'LSRC') + + def test_001_ltfm(self): + self.do_check_phase_shift(gr.cpm.TFM, 'TFM') + + def test_001_lgmsk(self): + sps = 2 + L = 5 + bt = 0.3 + in_bits = (1,) * 20 + src = gr.vector_source_b(in_bits, False) + gmsk = digital_swig.gmskmod_bc(sps, bt, L) + arg = gr.complex_to_arg() + sink = gr.vector_sink_f() + + self.tb.connect(src, gmsk, arg, sink) + self.tb.run() + + symbol_phases = numpy.array(sink.data()[sps*L-1::sps]) + phase_diff = numpy.mod(numpy.subtract(symbol_phases[1:], symbol_phases[:-1]), + (2*numpy.pi,) * (len(symbol_phases)-1)) + self.assertFloatTuplesAlmostEqual(tuple(phase_diff), (0.5 * numpy.pi,) * len(phase_diff), 5, + msg="Phase shift was not correct for GMSK") + + def test_phase_response(self): + phase_response = gr.cpm.phase_response(gr.cpm.LREC, 2, 4) + self.assertAlmostEqual(numpy.sum(phase_response), 1) + + +if __name__ == '__main__': + gr_unittest.run(test_cpm, "test_cpm.xml") + diff --git a/gr-digital/python/qa_crc32.py b/gr-digital/python/qa_crc32.py index f86813f3f..f86813f3f 100644..100755 --- a/gr-digital/python/qa_crc32.py +++ b/gr-digital/python/qa_crc32.py diff --git a/gr-digital/python/qa_fll_band_edge.py b/gr-digital/python/qa_fll_band_edge.py index 088eb2b68..088eb2b68 100644..100755 --- a/gr-digital/python/qa_fll_band_edge.py +++ b/gr-digital/python/qa_fll_band_edge.py diff --git a/gr-digital/python/qa_lms_equalizer.py b/gr-digital/python/qa_lms_equalizer.py index 025c785aa..025c785aa 100644..100755 --- a/gr-digital/python/qa_lms_equalizer.py +++ b/gr-digital/python/qa_lms_equalizer.py diff --git a/gr-digital/python/qa_mpsk_receiver.py b/gr-digital/python/qa_mpsk_receiver.py index 7e9a76e1f..6531e59f7 100644..100755 --- a/gr-digital/python/qa_mpsk_receiver.py +++ b/gr-digital/python/qa_mpsk_receiver.py @@ -36,8 +36,7 @@ class test_mpsk_receiver(gr_unittest.TestCase): # Test BPSK sync M = 2 theta = 0 - alpha = 0.1 - beta = 0.25*alpha*alpha + loop_bw = cmath.pi/100.0 fmin = -0.5 fmax = 0.5 mu = 0.25 @@ -46,7 +45,7 @@ class test_mpsk_receiver(gr_unittest.TestCase): gain_omega = 0.001 omega_rel = 0.001 - self.test = digital_swig.mpsk_receiver_cc(M, theta, alpha, beta, + self.test = digital_swig.mpsk_receiver_cc(M, theta, loop_bw, fmin, fmax, mu, gain_mu, omega, gain_omega, omega_rel) @@ -68,8 +67,8 @@ class test_mpsk_receiver(gr_unittest.TestCase): expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] - #print expected_result - #print dst_data + #for e,d in zip(expected_result, dst_data): + # print e, d self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 1) @@ -78,8 +77,7 @@ class test_mpsk_receiver(gr_unittest.TestCase): # Test QPSK sync M = 4 theta = 0 - alpha = 0.1 - beta = 0.25*alpha*alpha + loop_bw = 2*cmath.pi/100.0 fmin = -0.5 fmax = 0.5 mu = 0.25 @@ -88,11 +86,11 @@ class test_mpsk_receiver(gr_unittest.TestCase): gain_omega = 0.001 omega_rel = 0.001 - self.test = digital_swig.mpsk_receiver_cc(M, theta, alpha, beta, + self.test = digital_swig.mpsk_receiver_cc(M, theta, loop_bw, fmin, fmax, mu, gain_mu, omega, gain_omega, omega_rel) - + data = 1000*[complex( 0.707, 0.707), complex( 0.707, 0.707), complex(-0.707, 0.707), complex(-0.707, 0.707), complex(-0.707, -0.707), complex(-0.707, -0.707), @@ -103,8 +101,8 @@ class test_mpsk_receiver(gr_unittest.TestCase): self.tb.connect(self.src, self.test, self.snk) self.tb.run() - expected_result = 1000*[complex(1.2, 0), complex(0, 1.2), - complex(-1.2, 0), complex(0, -1.2)] + expected_result = 1000*[complex(0, -1.0), complex(1.0, 0), + complex(0, 1.0), complex(-1.0, 0)] dst_data = self.snk.data() # Only compare last Ncmp samples @@ -114,9 +112,9 @@ class test_mpsk_receiver(gr_unittest.TestCase): expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] - #print expected_result - #print dst_data - + #for e,d in zip(expected_result, dst_data): + # print e, d + self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 1) if __name__ == '__main__': diff --git a/gr-digital/python/qpsk.py b/gr-digital/python/qpsk.py index 76e5df270..481b7cb5b 100644 --- a/gr-digital/python/qpsk.py +++ b/gr-digital/python/qpsk.py @@ -100,10 +100,77 @@ class qpsk_demod(generic_demod): super(qpsk_demod, self).__init__(constellation=constellation, *args, **kwargs) + + +# ///////////////////////////////////////////////////////////////////////////// +# DQPSK constellation +# ///////////////////////////////////////////////////////////////////////////// + +def dqpsk_constellation(m=_def_constellation_points): + if m != _def_constellation_points: + raise ValueError("DQPSK can only have 4 constellation points.") + return digital_swig.constellation_dqpsk() + +# ///////////////////////////////////////////////////////////////////////////// +# DQPSK modulator +# ///////////////////////////////////////////////////////////////////////////// + +class dqpsk_mod(generic_mod): + + def __init__(self, constellation_points=_def_constellation_points, + gray_coded=_def_gray_coded, + differential=True, *args, **kwargs): + """ + Hierarchical block for RRC-filtered DQPSK modulation. + + The input is a byte stream (unsigned char) and the + output is the complex modulated signal at baseband. + + See generic_mod block for list of parameters. + """ + + constellation_points = _def_constellation_points + constellation = digital_swig.constellation_dqpsk() + if constellation_points != 4: + raise ValueError('Number of constellation points must be 4 for DQPSK.') + super(dqpsk_mod, self).__init__(constellation=constellation, + gray_coded=gray_coded, + differential=True, + *args, **kwargs) + +# ///////////////////////////////////////////////////////////////////////////// +# DQPSK demodulator +# +# ///////////////////////////////////////////////////////////////////////////// + +class dqpsk_demod(generic_demod): + + def __init__(self, constellation_points=_def_constellation_points, + differential=True, *args, **kwargs): + + """ + Hierarchical block for RRC-filtered DQPSK modulation. + + The input is a byte stream (unsigned char) and the + output is the complex modulated signal at baseband. + + See generic_demod block for list of parameters. + """ + constellation_points = _def_constellation_points + constellation = digital_swig.constellation_dqpsk() + if constellation_points != 4: + raise ValueError('Number of constellation points must be 4 for DQPSK.') + super(dqpsk_demod, self).__init__(constellation=constellation, + differential=True, + *args, **kwargs) + # # Add these to the mod/demod registry # modulation_utils2.add_type_1_mod('qpsk', qpsk_mod) modulation_utils2.add_type_1_demod('qpsk', qpsk_demod) modulation_utils2.add_type_1_constellation('qpsk', qpsk_constellation) +modulation_utils2.add_type_1_mod('dqpsk', dqpsk_mod) +modulation_utils2.add_type_1_demod('dqpsk', dqpsk_demod) +modulation_utils2.add_type_1_constellation('dqpsk', dqpsk_constellation) diff --git a/gr-digital/swig/CMakeLists.txt b/gr-digital/swig/CMakeLists.txt index b62c024e0..5c6477aa1 100644 --- a/gr-digital/swig/CMakeLists.txt +++ b/gr-digital/swig/CMakeLists.txt @@ -30,10 +30,11 @@ SET(GR_SWIG_INCLUDE_DIRS SET(GR_SWIG_LIBRARIES gnuradio-digital) +GR_SWIG_MAKE(digital_hier digital_hier.i) GR_SWIG_MAKE(digital_swig digital_swig.i) GR_SWIG_INSTALL( - TARGETS digital_swig + TARGETS digital_hier digital_swig DESTINATION ${GR_PYTHON_DIR}/gnuradio/digital COMPONENT "digital_python" ) diff --git a/gr-digital/swig/Makefile.am b/gr-digital/swig/Makefile.am index c0d28c24c..6604665b0 100644 --- a/gr-digital/swig/Makefile.am +++ b/gr-digital/swig/Makefile.am @@ -26,8 +26,7 @@ TESTS = EXTRA_DIST += $(nobase_guile_DATA) AM_CPPFLAGS = \ - -I$(abs_top_srcdir)/gr-digital/lib \ - -I$(abs_top_builddir)/gr-digital/lib \ + $(GR_DIGITAL_INCLUDES) \ $(STD_DEFINES_AND_INCLUDES) \ $(PYTHON_CPPFLAGS) \ $(WITH_INCLUDES) @@ -43,6 +42,7 @@ noinst_GUILE = digital.test ############################## # SWIG interface and library TOP_SWIG_IFILES = \ + digital_hier.i \ digital_swig.i # Install so that they end up available as: @@ -73,9 +73,11 @@ digital_swig_swiginclude_headers = \ digital_kurtotic_equalizer_cc.i \ digital_mpsk_receiver_cc.i +digital_hier_swig_args = \ + $(GR_DIGITAL_INCLUDES) + digital_swig_swig_args = \ - -I$(abs_top_srcdir)/gr-digital/lib \ - -I$(abs_top_builddir)/gr-digital/lib + $(GR_DIGITAL_INCLUDES) if GUILE TESTS += run_guile_tests diff --git a/gr-digital/swig/Makefile.swig.gen b/gr-digital/swig/Makefile.swig.gen index bd9aabcea..95d6aea89 100644 --- a/gr-digital/swig/Makefile.swig.gen +++ b/gr-digital/swig/Makefile.swig.gen @@ -101,8 +101,7 @@ _digital_swig_la_LDFLAGS = \ _digital_swig_la_CXXFLAGS = \ $(STD_SWIG_CXX_FLAGS) \ - -I$(top_builddir) \ - $(digital_swig_la_swig_cxxflags) + -I$(top_builddir) python/digital_swig.cc: digital_swig.py digital_swig.py: digital_swig.i @@ -143,3 +142,148 @@ gnuradio/digital_swig-primitive.scm: gnuradio/digital_swig.scm endif # end of GUILE +# -*- Makefile -*- +# +# Copyright 2009,2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +# Makefile.swig.gen for digital_hier.i + +## Default install locations for these files: +## +## Default location for the Python directory is: +## ${prefix}/lib/python${python_version}/site-packages/[category]/digital_hier +## Default location for the Python exec directory is: +## ${exec_prefix}/lib/python${python_version}/site-packages/[category]/digital_hier +## +## The following can be overloaded to change the install location, but +## this has to be done in the including Makefile.am -before- +## Makefile.swig is included. + +digital_hier_pythondir_category ?= gnuradio/digital_hier +digital_hier_pylibdir_category ?= $(digital_hier_pythondir_category) +digital_hier_pythondir = $(pythondir)/$(digital_hier_pythondir_category) +digital_hier_pylibdir = $(pyexecdir)/$(digital_hier_pylibdir_category) + +# The .so libraries for the guile modules get installed whereever guile +# is installed, usually /usr/lib/guile/gnuradio/ +# FIXME: determince whether these should be installed with gnuradio. +digital_hier_scmlibdir = $(libdir) + +# The scm files for the guile modules get installed where ever guile +# is installed, usually /usr/share/guile/site/digital_hier +# FIXME: determince whether these should be installed with gnuradio. +digital_hier_scmdir = $(guiledir) + +## SWIG headers are always installed into the same directory. + +digital_hier_swigincludedir = $(swigincludedir) + +## This is a template file for a "generated" Makefile addition (in +## this case, "Makefile.swig.gen"). By including the top-level +## Makefile.swig, this file will be used to generate the SWIG +## dependencies. Assign the variable TOP_SWIG_FILES to be the list of +## SWIG .i files to generated wrappings for; there can be more than 1 +## so long as the names are unique (no sorting is done on the +## TOP_SWIG_FILES list). This file explicitly assumes that a SWIG .i +## file will generate .cc, .py, and possibly .h files -- meaning that +## all of these files will have the same base name (that provided for +## the SWIG .i file). +## +## This code is setup to ensure parallel MAKE ("-j" or "-jN") does the +## right thing. For more info, see < +## http://sources.redhat.com/automake/automake.html#Multiple-Outputs > + +## Other cleaned files: dependency files generated by SWIG or this Makefile + +MOSTLYCLEANFILES += $(DEPDIR)/*.S* + +## Various SWIG variables. These can be overloaded in the including +## Makefile.am by setting the variable value there, then including +## Makefile.swig . + +digital_hier_swiginclude_HEADERS = \ + digital_hier.i \ + $(digital_hier_swiginclude_headers) + +if PYTHON +digital_hier_pylib_LTLIBRARIES = \ + _digital_hier.la + +_digital_hier_la_SOURCES = \ + python/digital_hier.cc \ + $(digital_hier_la_swig_sources) + +digital_hier_python_PYTHON = \ + digital_hier.py \ + $(digital_hier_python) + +_digital_hier_la_LIBADD = \ + $(STD_SWIG_LA_LIB_ADD) \ + $(digital_hier_la_swig_libadd) + +_digital_hier_la_LDFLAGS = \ + $(STD_SWIG_LA_LD_FLAGS) \ + $(digital_hier_la_swig_ldflags) + +_digital_hier_la_CXXFLAGS = \ + $(STD_SWIG_CXX_FLAGS) \ + -I$(top_builddir) \ + $(digital_hier_la_swig_cxxflags) + +python/digital_hier.cc: digital_hier.py +digital_hier.py: digital_hier.i + +# Include the python dependencies for this file +-include python/digital_hier.d + +endif # end of if python + +if GUILE + +digital_hier_scmlib_LTLIBRARIES = \ + libguile-gnuradio-digital_hier.la +libguile_gnuradio_digital_hier_la_SOURCES = \ + guile/digital_hier.cc \ + $(digital_hier_la_swig_sources) +nobase_digital_hier_scm_DATA = \ + gnuradio/digital_hier.scm \ + gnuradio/digital_hier-primitive.scm +libguile_gnuradio_digital_hier_la_LIBADD = \ + $(STD_SWIG_LA_LIB_ADD) \ + $(digital_hier_la_swig_libadd) +libguile_gnuradio_digital_hier_la_LDFLAGS = \ + $(STD_SWIG_LA_LD_FLAGS) \ + $(digital_hier_la_swig_ldflags) +libguile_gnuradio_digital_hier_la_CXXFLAGS = \ + $(STD_SWIG_CXX_FLAGS) \ + -I$(top_builddir) \ + $(digital_hier_la_swig_cxxflags) + +guile/digital_hier.cc: gnuradio/digital_hier.scm +gnuradio/digital_hier.scm: digital_hier.i +gnuradio/digital_hier-primitive.scm: gnuradio/digital_hier.scm + +# Include the guile dependencies for this file +-include guile/digital_hier.d + +endif # end of GUILE + + diff --git a/gr-digital/swig/digital_constellation.i b/gr-digital/swig/digital_constellation.i index ae31d443e..7e0ad6afe 100644 --- a/gr-digital/swig/digital_constellation.i +++ b/gr-digital/swig/digital_constellation.i @@ -50,6 +50,7 @@ public: unsigned int arity (); digital_constellation_sptr base (); bool apply_pre_diff_code(); + void set_pre_diff_code(bool a); std::vector<unsigned int> pre_diff_code(); unsigned int rotational_symmetry(); unsigned int dimensionality(); @@ -152,6 +153,23 @@ public: digital_constellation_qpsk (); }; +/* + DQPSK Constellation +*/ + +class digital_constellation_dqpsk; +typedef boost::shared_ptr<digital_constellation_dqpsk> digital_constellation_dqpsk_sptr; +%template(digital_constellation_dqpsk_sptr) boost::shared_ptr<digital_constellation_dqpsk>; +%rename(constellation_dqpsk) digital_make_constellation_dqpsk; +digital_constellation_dqpsk_sptr digital_make_constellation_dqpsk(); +%ignore digital_constellation_dqpsk; + +class digital_constellation_dqpsk : public digital_constellation +{ +public: + digital_constellation_dqpsk (); +}; + /* 8PSK Constellation diff --git a/gr-digital/swig/digital_constellation_receiver_cb.i b/gr-digital/swig/digital_constellation_receiver_cb.i index e4be5f39f..9c4ba645e 100644 --- a/gr-digital/swig/digital_constellation_receiver_cb.i +++ b/gr-digital/swig/digital_constellation_receiver_cb.i @@ -28,23 +28,9 @@ digital_constellation_receiver_cb_sptr digital_make_constellation_receiver_cb (digital_constellation_sptr constellation, float loop_bw, float fmin, float fmax); -class digital_constellation_receiver_cb : public gr_block +class digital_constellation_receiver_cb : public gr_block, public gri_control_loop { private: digital_constellation_receiver_cb (digital_contellation_sptr constellation, float loop_bw, float fmin, float fmax); -public: - void set_loop_bandwidth(float bw); - void set_damping_factor(float df); - void set_alpha(float alpha); - void set_beta(float beta); - void set_frequency(float freq); - void set_phase(float phase); - - float get_loop_bandwidth() const; - float get_damping_factor() const; - float get_alpha() const; - float get_beta() const; - float get_frequency() const; - float get_phase() const; }; diff --git a/gr-digital/swig/digital_fll_band_edge_cc.i b/gr-digital/swig/digital_fll_band_edge_cc.i index f022bc7e1..3efcb89ed 100644 --- a/gr-digital/swig/digital_fll_band_edge_cc.i +++ b/gr-digital/swig/digital_fll_band_edge_cc.i @@ -27,7 +27,7 @@ digital_fll_band_edge_cc_sptr digital_make_fll_band_edge_cc (float samps_per_sym int filter_size, float bandwidth); -class digital_fll_band_edge_cc : public gr_sync_block +class digital_fll_band_edge_cc : public gr_sync_block, public gri_control_loop { private: digital_fll_band_edge_cc (float samps_per_sym, float rolloff, diff --git a/gr-digital/swig/digital_hier.i b/gr-digital/swig/digital_hier.i new file mode 100644 index 000000000..e004461d2 --- /dev/null +++ b/gr-digital/swig/digital_hier.i @@ -0,0 +1,40 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef SWIGIMPORTED +%module(directors="1") digital_hier +#endif + + //%feature("autodoc", "1"); // generate python docstrings + +%include "gnuradio.i" // the common stuff + +%include "_digital_hier.i" + +#if SWIGGUILE +%scheme %{ +(load-extension-global "libguile-gnuradio-digital_hier" "scm_init_gnuradio_digital_hier_module") +%} + +%goops %{ + (use-modules (gnuradio gnuradio_core_runtime)) +%} +#endif diff --git a/gr-digital/swig/digital_mpsk_receiver_cc.i b/gr-digital/swig/digital_mpsk_receiver_cc.i index cdc9f661b..b51411f6f 100644 --- a/gr-digital/swig/digital_mpsk_receiver_cc.i +++ b/gr-digital/swig/digital_mpsk_receiver_cc.i @@ -23,16 +23,16 @@ GR_SWIG_BLOCK_MAGIC(digital,mpsk_receiver_cc); digital_mpsk_receiver_cc_sptr digital_make_mpsk_receiver_cc (unsigned int M, float theta, - float alpha, float beta, + float loop_bw, float fmin, float fmax, float mu, float gain_mu, float omega, float gain_omega, float omega_rel); -class digital_mpsk_receiver_cc : public gr_block +class digital_mpsk_receiver_cc : public gr_block, public gri_control_loop { private: digital_mpsk_receiver_cc (unsigned int M,float theta, - float alpha, float beta, + float loop_bw, float fmin, float fmax, float mu, float gain_mu, float omega, float gain_omega, float omega_rel); @@ -49,12 +49,4 @@ public: } void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; } void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; } - float alpha() const { return d_alpha; } - float beta() const { return d_beta; } - float freq() const { return d_freq; } - float phase() const { return d_phase; } - void set_alpha(float alpha) { d_alpha = alpha; } - void set_beta(float beta) { d_beta = beta; } - void set_freq(float freq) { d_freq = freq; } - void set_phase(float phase) { d_phase = phase; } }; diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i index 0328ca2fc..ca50f9c50 100644 --- a/gr-digital/swig/digital_swig.i +++ b/gr-digital/swig/digital_swig.i @@ -40,6 +40,7 @@ #include "digital_mpsk_receiver_cc.h" %} +%include "digital_hier.i" %include "digital_binary_slicer_fb.i" %include "digital_clock_recovery_mm_cc.i" %include "digital_clock_recovery_mm_ff.i" diff --git a/gr-utils/src/python/gr_plot_const.py b/gr-utils/src/python/gr_plot_const.py index 0c52899b2..8873e5b7e 100755 --- a/gr-utils/src/python/gr_plot_const.py +++ b/gr-utils/src/python/gr_plot_const.py @@ -92,7 +92,7 @@ class draw_constellation: self.imags = scipy.array([i.imag for i in iq]) self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) - return Tr + return True else: print "End of File" return False diff --git a/grc/blocks/Makefile.am b/grc/blocks/Makefile.am index 14ffe8358..6f72fe399 100644 --- a/grc/blocks/Makefile.am +++ b/grc/blocks/Makefile.am @@ -91,6 +91,7 @@ dist_ourdata_DATA = \ gr_costas_loop_cc.xml \ gr_cpfsk_bc.xml \ gr_dc_blocker.xml \ + gr_cpmmod_bc.xml \ gr_decode_ccsds_27_fb.xml \ gr_deinterleave.xml \ gr_delay.xml \ @@ -108,7 +109,6 @@ dist_ourdata_DATA = \ gr_file_source.xml \ gr_filter_delay_fc.xml \ gr_fir_filter_xxx.xml \ - gr_fll_band_edge_cc.xml \ gr_float_to_char.xml \ gr_float_to_complex.xml \ gr_float_to_short.xml \ @@ -117,6 +117,7 @@ dist_ourdata_DATA = \ gr_freq_xlating_fir_filter_xxx.xml \ gr_frequency_modulator_fc.xml \ gr_glfsr_source_x.xml \ + gr_gmskmod_bc.xml \ gr_goertzel_fc.xml \ gr_head.xml \ gr_hilbert_fc.xml \ @@ -134,7 +135,6 @@ dist_ourdata_DATA = \ gr_message_sink.xml \ gr_message_source.xml \ gr_moving_average_xx.xml \ - gr_mpsk_receiver_cc.xml \ gr_mpsk_sync_cc.xml \ gr_multiply_const_vxx.xml \ gr_multiply_xx.xml \ diff --git a/grc/blocks/block_tree.xml b/grc/blocks/block_tree.xml index 0b641d79c..f5365dcb5 100644 --- a/grc/blocks/block_tree.xml +++ b/grc/blocks/block_tree.xml @@ -121,14 +121,11 @@ <block>gr_costas_loop_cc</block> <block>gr_mpsk_sync_cc</block> - <block>gr_mpsk_receiver_cc</block> <block>gr_pll_carriertracking_cc</block> <block>gr_pll_freqdet_cf</block> <block>gr_pll_refout_cc</block> - <block>gr_fll_band_edge_cc</block> - <block>gr_correlate_access_code_bb</block> <block>gr_pn_correlator_cc</block> <block>gr_simple_correlator</block> @@ -197,6 +194,8 @@ <block>gr_phase_modulator_fc</block> <block>gr_quadrature_demod_cf</block> <block>gr_cpfsk_bc</block> + <block>gr_cpmmod_bc</block> + <block>gr_gmskmod_bc</block> <block>gr_diff_phasor_cc</block> <block>gr_constellation_decoder_cb</block> diff --git a/grc/blocks/gr_cpmmod_bc.xml b/grc/blocks/gr_cpmmod_bc.xml new file mode 100644 index 000000000..da405534e --- /dev/null +++ b/grc/blocks/gr_cpmmod_bc.xml @@ -0,0 +1,69 @@ +<?xml version="1.0"?> +<!-- +################################################### +## Continuous Phase Modulation +################################################### + --> +<block> + <name>Continuous Phase Modulation</name> + <key>gr_cpmmod_bc</key> + <import>from gnuradio import gr</import> + <make>gr.cpmmod_bc($type, $mod_index, $samples_per_symbol, $L, $beta)</make> + <param> + <name>CPM Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>L-REC (Rectangular phase response)</name> + <key>gr.cpm.LREC</key> + </option> + <option> + <name>L-RC (Raised Cosine)</name> + <key>gr.cpm.LRC</key> + </option> + <option> + <name>L-SRC (Spectral raised cosine)</name> + <key>gr.cpm.LSRC</key> + </option> + <option> + <name>TFM (Tamed frequency modulation)</name> + <key>gr.cpm.TFM</key> + </option> + <option> + <name>Gaussian</name> + <key>gr.cpm.GAUSSIAN</key> + </option> + </param> + <param> + <name>Modulation Index</name> + <key>mod_index</key> + <value>0.5</value> + <type>real</type> + </param> + <param> + <name>Samples/Symbol</name> + <key>samples_per_symbol</key> + <value>4</value> + <type>int</type> + </param> + <param> + <name>Pulse Duration (Symbols)</name> + <key>L</key> + <value>4</value> + <type>int</type> + </param> + <param> + <name>Phase Response Parameter (BT or Beta)</name> + <key>beta</key> + <value>0.3</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_gmskmod_bc.xml b/grc/blocks/gr_gmskmod_bc.xml new file mode 100644 index 000000000..82e47452b --- /dev/null +++ b/grc/blocks/gr_gmskmod_bc.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<!-- +################################################### +## GMSK +################################################### + --> +<block> + <name>GMSK Modulator</name> + <key>gr_gmskmod_bc</key> + <import>from gnuradio import gr</import> + <make>gr.gmskmod_bc($samples_per_symbol, $bt, $L)</make> + <param> + <name>Samples/Symbol</name> + <key>samples_per_symbol</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>3 dB Time-Bandwith Product</name> + <key>bt</key> + <value>0.3</value> + <type>real</type> + </param> + <param> + <name>Pulse Duration (Symbols)</name> + <key>L</key> + <value>4</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/blocks/gr_pll_carriertracking_cc.xml b/grc/blocks/gr_pll_carriertracking_cc.xml index 5b876b259..27e673248 100644 --- a/grc/blocks/gr_pll_carriertracking_cc.xml +++ b/grc/blocks/gr_pll_carriertracking_cc.xml @@ -8,15 +8,11 @@ <name>PLL Carrier Tracking</name> <key>gr_pll_carriertracking_cc</key> <import>from gnuradio import gr</import> - <make>gr.pll_carriertracking_cc($alpha, $beta, $max_freq, $min_freq)</make> + <make>gr.pll_carriertracking_cc($w, $max_freq, $min_freq)</make> + <callback>set_loop_bandwidth($w)</callback> <param> - <name>Alpha</name> - <key>alpha</key> - <type>real</type> - </param> - <param> - <name>Beta</name> - <key>beta</key> + <name>Loop Bandwidth</name> + <key>w</key> <type>real</type> </param> <param> diff --git a/grc/blocks/gr_pll_freqdet_cf.xml b/grc/blocks/gr_pll_freqdet_cf.xml index 8ec1fb3bb..d6e4694f0 100644 --- a/grc/blocks/gr_pll_freqdet_cf.xml +++ b/grc/blocks/gr_pll_freqdet_cf.xml @@ -8,15 +8,11 @@ <name>PLL Freq Det</name> <key>gr_pll_freqdet_cf</key> <import>from gnuradio import gr</import> - <make>gr.pll_freqdet_cf($alpha, $beta, $max_freq, $min_freq)</make> + <make>gr.pll_freqdet_cf($w, $max_freq, $min_freq)</make> + <callback>set_loop_bandwidth($w)</callback> <param> - <name>Alpha</name> - <key>alpha</key> - <type>real</type> - </param> - <param> - <name>Beta</name> - <key>beta</key> + <name>Loop Bandwidth</name> + <key>w</key> <type>real</type> </param> <param> diff --git a/grc/blocks/gr_pll_refout_cc.xml b/grc/blocks/gr_pll_refout_cc.xml index 64cf2bfb6..b231ddd19 100644 --- a/grc/blocks/gr_pll_refout_cc.xml +++ b/grc/blocks/gr_pll_refout_cc.xml @@ -8,15 +8,11 @@ <name>PLL Ref Out</name> <key>gr_pll_refout_cc</key> <import>from gnuradio import gr</import> - <make>gr.pll_refout_cc($alpha, $beta, $max_freq, $min_freq)</make> + <make>gr.pll_refout_cc($w, $max_freq, $min_freq)</make> + <callback>set_loop_bandwidth($w)</callback> <param> - <name>Alpha</name> - <key>alpha</key> - <type>real</type> - </param> - <param> - <name>Beta</name> - <key>beta</key> + <name>Loop Bandwidth</name> + <key>w</key> <type>real</type> </param> <param> |