diff options
Diffstat (limited to 'gr-digital/include')
21 files changed, 2251 insertions, 0 deletions
diff --git a/gr-digital/include/.gitignore b/gr-digital/include/.gitignore new file mode 100644 index 000000000..b336cc7ce --- /dev/null +++ b/gr-digital/include/.gitignore @@ -0,0 +1,2 @@ +/Makefile +/Makefile.in diff --git a/gr-digital/include/CMakeLists.txt b/gr-digital/include/CMakeLists.txt new file mode 100644 index 000000000..7b38e645b --- /dev/null +++ b/gr-digital/include/CMakeLists.txt @@ -0,0 +1,44 @@ +# 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. + +######################################################################## +# Install header files +######################################################################## +INSTALL(FILES + digital_api.h + digital_binary_slicer_fb.h + digital_clock_recovery_mm_cc.h + digital_clock_recovery_mm_ff.h + digital_constellation.h + digital_constellation_receiver_cb.h + digital_constellation_decoder_cb.h + digital_correlate_access_code_bb.h + digital_costas_loop_cc.h + digital_cma_equalizer_cc.h + digital_crc32.h + digital_fll_band_edge_cc.h + digital_lms_dd_equalizer_cc.h + digital_kurtotic_equalizer_cc.h + digital_metric_type.h + digital_mpsk_receiver_cc.h + digital_gmskmod_bc.h + digital_cpmmod_bc.h + DESTINATION ${GR_INCLUDE_DIR}/gnuradio + COMPONENT "digital_devel" +) diff --git a/gr-digital/include/Makefile.am b/gr-digital/include/Makefile.am new file mode 100644 index 000000000..346d036ce --- /dev/null +++ b/gr-digital/include/Makefile.am @@ -0,0 +1,45 @@ +# +# 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 + +# These headers get installed in ${prefix}/include/gnuradio +grinclude_HEADERS = \ + digital_api.h \ + digital_binary_slicer_fb.h \ + digital_clock_recovery_mm_cc.h \ + digital_clock_recovery_mm_ff.h \ + digital_constellation.h \ + digital_constellation_receiver_cb.h \ + digital_constellation_decoder_cb.h \ + digital_correlate_access_code_bb.h \ + digital_costas_loop_cc.h \ + digital_cma_equalizer_cc.h \ + digital_crc32.h \ + digital_fll_band_edge_cc.h \ + digital_lms_dd_equalizer_cc.h \ + digital_kurtotic_equalizer_cc.h \ + digital_metric_type.h \ + digital_mpsk_receiver_cc.h \ + digital_gmskmod_bc.h \ + digital_cpmmod_bc.h + +libgnuradio_digital_la_LDFLAGS = $(NO_UNDEFINED) $(LTVERSIONFLAGS) diff --git a/gr-digital/include/digital_api.h b/gr-digital/include/digital_api.h new file mode 100644 index 000000000..d45ace13f --- /dev/null +++ b/gr-digital/include/digital_api.h @@ -0,0 +1,33 @@ +/* + * Copyright 2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_API_H +#define INCLUDED_DIGITAL_API_H + +#include <gruel/attributes.h> + +#ifdef gnuradio_digital_EXPORTS +# define DIGITAL_API __GR_ATTR_EXPORT +#else +# define DIGITAL_API __GR_ATTR_IMPORT +#endif + +#endif /* INCLUDED_DIGITAL_API_H */ diff --git a/gr-digital/include/digital_binary_slicer_fb.h b/gr-digital/include/digital_binary_slicer_fb.h new file mode 100644 index 000000000..9da776012 --- /dev/null +++ b/gr-digital/include/digital_binary_slicer_fb.h @@ -0,0 +1,52 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_BINARY_SLICER_FB_H +#define INCLUDED_DIGITAL_BINARY_SLICER_FB_H + +#include <digital_api.h> +#include <gr_sync_block.h> + +class digital_binary_slicer_fb; +typedef boost::shared_ptr<digital_binary_slicer_fb> digital_binary_slicer_fb_sptr; + +DIGITAL_API digital_binary_slicer_fb_sptr digital_make_binary_slicer_fb (); + +/*! + * \brief slice float binary symbol outputting 1 bit output + * \ingroup converter_blk + * + * x < 0 --> 0 + * x >= 0 --> 1 + */ +class DIGITAL_API digital_binary_slicer_fb : public gr_sync_block +{ + friend DIGITAL_API digital_binary_slicer_fb_sptr digital_make_binary_slicer_fb (); + digital_binary_slicer_fb (); + + public: + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/gr-digital/include/digital_clock_recovery_mm_cc.h b/gr-digital/include/digital_clock_recovery_mm_cc.h new file mode 100644 index 000000000..e45b79229 --- /dev/null +++ b/gr-digital/include/digital_clock_recovery_mm_cc.h @@ -0,0 +1,113 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_CLOCK_RECOVERY_MM_CC_H +#define INCLUDED_DIGITAL_CLOCK_RECOVERY_MM_CC_H + +#include <digital_api.h> +#include <gr_block.h> +#include <gr_complex.h> +#include <gr_math.h> + +class gri_mmse_fir_interpolator_cc; + +class digital_clock_recovery_mm_cc; +typedef boost::shared_ptr<digital_clock_recovery_mm_cc> digital_clock_recovery_mm_cc_sptr; + +// public constructor +DIGITAL_API digital_clock_recovery_mm_cc_sptr +digital_make_clock_recovery_mm_cc (float omega, float gain_omega, + float mu, float gain_mu, + float omega_relative_limit=0.001); + +/*! + * \brief Mueller and Müller (M&M) based clock recovery block with complex input, complex output. + * \ingroup sync_blk + * + * This implements the Mueller and Müller (M&M) discrete-time error-tracking synchronizer. + * The complex version here is based on: + * Modified Mueller and Muller clock recovery circuit + * Based: + * 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. + */ +class DIGITAL_API digital_clock_recovery_mm_cc : public gr_block +{ + public: + ~digital_clock_recovery_mm_cc (); + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + float mu() const { return d_mu;} + float omega() const { return d_omega;} + float gain_mu() const { return d_gain_mu;} + float gain_omega() const { return d_gain_omega;} + void set_verbose (bool verbose) { d_verbose = verbose; } + + void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; } + void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; } + void set_mu (float mu) { d_mu = mu; } + void set_omega (float omega) { + d_omega = omega; + d_min_omega = omega*(1.0 - d_omega_relative_limit); + d_max_omega = omega*(1.0 + d_omega_relative_limit); + d_omega_mid = 0.5*(d_min_omega+d_max_omega); + } + +protected: + digital_clock_recovery_mm_cc (float omega, float gain_omega, + float mu, float gain_mu, + float omega_relative_limi); + + private: + float d_mu; + float d_omega; + float d_gain_omega; + float d_min_omega; // minimum allowed omega + float d_max_omega; // maximum allowed omeg + float d_omega_relative_limit; // used to compute min and max omega + float d_omega_mid; + float d_gain_mu; + gr_complex d_last_sample; + gri_mmse_fir_interpolator_cc *d_interp; + bool d_verbose; + + gr_complex d_p_2T; + gr_complex d_p_1T; + gr_complex d_p_0T; + + gr_complex d_c_2T; + gr_complex d_c_1T; + gr_complex d_c_0T; + + gr_complex slicer_0deg (gr_complex sample); + gr_complex slicer_45deg (gr_complex sample); + + friend DIGITAL_API digital_clock_recovery_mm_cc_sptr + digital_make_clock_recovery_mm_cc (float omega, float gain_omega, + float mu, float gain_mu, + float omega_relative_limit); +}; + +#endif diff --git a/gr-digital/include/digital_clock_recovery_mm_ff.h b/gr-digital/include/digital_clock_recovery_mm_ff.h new file mode 100644 index 000000000..6f88a4dcd --- /dev/null +++ b/gr-digital/include/digital_clock_recovery_mm_ff.h @@ -0,0 +1,99 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_CLOCK_RECOVERY_MM_FF_H +#define INCLUDED_DIGITAL_CLOCK_RECOVERY_MM_FF_H + +#include <digital_api.h> +#include <gr_block.h> +#include <gr_math.h> +#include <stdio.h> + +class gri_mmse_fir_interpolator; + +class digital_clock_recovery_mm_ff; +typedef boost::shared_ptr<digital_clock_recovery_mm_ff> digital_clock_recovery_mm_ff_sptr; + +// public constructor +DIGITAL_API digital_clock_recovery_mm_ff_sptr +digital_make_clock_recovery_mm_ff (float omega, float gain_omega, + float mu, float gain_mu, + float omega_relative_limit=0.001); + +/*! + * \brief Mueller and Müller (M&M) based clock recovery block with float input, float output. + * \ingroup sync_blk + * + * This implements the Mueller and Müller (M&M) discrete-time error-tracking synchronizer. + * + * See "Digital Communication Receivers: Synchronization, Channel + * Estimation and Signal Processing" by Heinrich Meyr, Marc Moeneclaey, & Stefan Fechtel. + * ISBN 0-471-50275-8. + */ +class DIGITAL_API digital_clock_recovery_mm_ff : public gr_block +{ + public: + ~digital_clock_recovery_mm_ff (); + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + float mu() const { return d_mu;} + float omega() const { return d_omega;} + float gain_mu() const { return d_gain_mu;} + float gain_omega() const { return d_gain_omega;} + + void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; } + void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; } + void set_mu (float mu) { d_mu = mu; } + void set_omega (float omega){ + d_omega = omega; + d_min_omega = omega*(1.0 - d_omega_relative_limit); + d_max_omega = omega*(1.0 + d_omega_relative_limit); + d_omega_mid = 0.5*(d_min_omega+d_max_omega); + } + +protected: + digital_clock_recovery_mm_ff (float omega, float gain_omega, float mu, float gain_mu, + float omega_relative_limit); + + private: + float d_mu; // fractional sample position [0.0, 1.0] + float d_omega; // nominal frequency + float d_min_omega; // minimum allowed omega + float d_omega_mid; // average omega + float d_max_omega; // maximum allowed omega + float d_gain_omega; // gain for adjusting omega + float d_gain_mu; // gain for adjusting mu + float d_last_sample; + gri_mmse_fir_interpolator *d_interp; + FILE *d_logfile; + float d_omega_relative_limit; // used to compute min and max omega + + friend DIGITAL_API digital_clock_recovery_mm_ff_sptr + digital_make_clock_recovery_mm_ff (float omega, float gain_omega, + float mu, float gain_mu, + float omega_relative_limit); +}; + +#endif diff --git a/gr-digital/include/digital_cma_equalizer_cc.h b/gr-digital/include/digital_cma_equalizer_cc.h new file mode 100644 index 000000000..69e2f657a --- /dev/null +++ b/gr-digital/include/digital_cma_equalizer_cc.h @@ -0,0 +1,102 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_CMA_EQUALIZER_CC_H +#define INCLUDED_DIGITAL_CMA_EQUALIZER_CC_H + +#include <digital_api.h> +#include <gr_adaptive_fir_ccc.h> +#include <gr_math.h> +#include <iostream> + +class digital_cma_equalizer_cc; +typedef boost::shared_ptr<digital_cma_equalizer_cc> digital_cma_equalizer_cc_sptr; + +DIGITAL_API digital_cma_equalizer_cc_sptr +digital_make_cma_equalizer_cc(int num_taps, float modulus, float mu, int sps); + +/*! + * \brief Implements constant modulus adaptive filter on complex stream + * \ingroup eq_blk + * + * The error value and tap update equations (for p=2) can be found in: + * + * D. Godard, "Self-Recovering Equalization and Carrier Tracking in + * Two-Dimensional Data Communication Systems," IEEE Transactions on + * Communications, Vol. 28, No. 11, pp. 1867 - 1875, 1980, + */ +class DIGITAL_API digital_cma_equalizer_cc : public gr_adaptive_fir_ccc +{ +private: + float d_modulus; + float d_mu; + + friend DIGITAL_API digital_cma_equalizer_cc_sptr digital_make_cma_equalizer_cc(int num_taps, + float modulus, + float mu, + int sps); + digital_cma_equalizer_cc(int num_taps, float modulus, float mu, int sps); + +protected: + + virtual gr_complex error(const gr_complex &out) + { + gr_complex error = out*(norm(out) - d_modulus); + float re = gr_clip(error.real(), 1.0); + float im = gr_clip(error.imag(), 1.0); + return gr_complex(re, im); + } + + virtual void update_tap(gr_complex &tap, const gr_complex &in) + { + // Hn+1 = Hn - mu*conj(Xn)*zn*(|zn|^2 - 1) + tap -= d_mu*conj(in)*d_error; + } + +public: + float get_gain() + { + return d_mu; + } + + void set_gain(float mu) + { + if(mu < 0.0f || mu > 1.0f) { + throw std::out_of_range("digital_cma_equalizer::set_gain: Gain value must be in [0,1]"); + } + d_mu = mu; + } + + float get_modulus() + { + return d_modulus; + } + + void set_modulus(float mod) + { + if(mod < 0) + throw std::out_of_range("digital_cma_equalizer::set_modulus: Modulus value must be >= 0"); + d_modulus = mod; + } +}; + +#endif diff --git a/gr-digital/include/digital_constellation.h b/gr-digital/include/digital_constellation.h new file mode 100644 index 000000000..9b2a58588 --- /dev/null +++ b/gr-digital/include/digital_constellation.h @@ -0,0 +1,395 @@ +/* -*- c++ -*- */ +/* + * 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. + */ + +#ifndef INCLUDED_DIGITAL_CONSTELLATION_H +#define INCLUDED_DIGITAL_CONSTELLATION_H + +#include <digital_api.h> +#include <vector> +#include <math.h> +#include <gr_complex.h> +#include <boost/enable_shared_from_this.hpp> +#include <digital_metric_type.h> + +/************************************************************/ +/* digital_constellation */ +/* */ +/* Base class defining interface. */ +/************************************************************/ + +class digital_constellation; +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 (); + + //! Returns the constellation points for a symbol value + void map_to_points(unsigned int value, gr_complex *points); + std::vector<gr_complex> map_to_points_v(unsigned int value); + + //! Returns the constellation point that matches best. + virtual unsigned int decision_maker (const gr_complex *sample) = 0; + //! Takes a vector rather than a pointer. Better for SWIG wrapping. + unsigned int decision_maker_v (std::vector<gr_complex> sample); + //! Also calculates the phase error. + unsigned int decision_maker_pe (const gr_complex *sample, float *phase_error); + //! Calculates distance. + unsigned int decision_maker_e (const gr_complex *sample, float *error); + + //! Calculates metrics for all points in the constellation. + //! For use with the viterbi algorithm. + virtual void calc_metric(const gr_complex *sample, float *metric, trellis_metric_type_t type); + virtual void calc_euclidean_metric(const gr_complex *sample, float *metric); + virtual void calc_hard_symbol_metric(const gr_complex *sample, float *metric); + + //! Returns the set of points in this constellation. + std::vector<gr_complex> points() { return d_constellation;} + //! Returns the vector of points in this constellation. + //! Raise error if dimensionality is not one. + std::vector<gr_complex> s_points(); + //! Returns a vector of vectors of points. + 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. + unsigned int rotational_symmetry() { return d_rotational_symmetry;} + //! Returns the number of complex numbers in a single symbol. + unsigned int dimensionality() {return d_dimensionality;} + + unsigned int bits_per_symbol () { + return floor(log(d_constellation.size())/d_dimensionality/log(2)); + } + + unsigned int arity () { + return d_arity; + } + + digital_constellation_sptr base() { + return shared_from_this(); + } + + protected: + + std::vector<gr_complex> d_constellation; + std::vector<unsigned int> d_pre_diff_code; + bool d_apply_pre_diff_code; + unsigned int d_rotational_symmetry; + unsigned int d_dimensionality; + unsigned int d_arity; + + float get_distance(unsigned int index, const gr_complex *sample); + unsigned int get_closest_point(const gr_complex *sample); + void calc_arity (); +}; + +/************************************************************/ +/* digital_constellation_calcdist */ +/* */ +/* Constellation which calculates the distance to each */ +/* point in the constellation for decision making. */ +/* Inefficient for large constellations. */ +/************************************************************/ + +class digital_constellation_calcdist; +typedef boost::shared_ptr<digital_constellation_calcdist> digital_constellation_calcdist_sptr; + +// 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); + + +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); + 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); + // void calc_hard_symbol_metric(gr_complex *sample, float *metric); + + private: + friend DIGITAL_API digital_constellation_calcdist_sptr + digital_make_constellation_calcdist (std::vector<gr_complex> constellation); +}; + +/************************************************************/ +/* digital_constellation_sector */ +/* */ +/* An abstract class. */ +/* Constellation space is divided into sectors. */ +/* Each sector is associated with the nearest constellation */ +/* point. */ +/************************************************************/ + +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); + + unsigned int decision_maker (const gr_complex *sample); + + protected: + + virtual unsigned int get_sector (const gr_complex *sample) = 0; + virtual unsigned int calc_sector_value (unsigned int sector) = 0; + void find_sector_values (); + + unsigned int n_sectors; + + private: + + std::vector<unsigned int> sector_values; + +}; + +/************************************************************/ +/* digital_constellation_rect */ +/* */ +/* Only implemented for 1-(complex)dimensional */ +/* constellation. */ +/* Constellation space is divided into rectangular sectors. */ +/* Each sector is associated with the nearest constellation */ +/* point. */ +/* Works well for square QAM. */ +/* Works for any generic constellation provided sectors are */ +/* not too large. */ +/************************************************************/ + +class digital_constellation_rect; +typedef boost::shared_ptr<digital_constellation_rect> digital_constellation_rect_sptr; + +// 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); + +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); + + protected: + + unsigned int get_sector (const gr_complex *sample); + + unsigned int calc_sector_value (unsigned int sector); + + private: + + unsigned int n_real_sectors; + unsigned int n_imag_sectors; + float d_width_real_sectors; + 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_constellation_psk */ +/* */ +/* Constellation space is divided into pie slices sectors. */ +/* Each slice is associated with the nearest constellation */ +/* point. */ +/* Works well for PSK but nothing else. */ +/* Assumes that there is a constellation point at 1. */ +/************************************************************/ + +class digital_constellation_psk; +typedef boost::shared_ptr<digital_constellation_psk> digital_constellation_psk_sptr; + +// public constructor +DIGITAL_API digital_constellation_psk_sptr +digital_make_constellation_psk (std::vector<gr_complex> constellation, + std::vector<unsigned int> pre_diff_code, + unsigned int n_sectors); + +class DIGITAL_API digital_constellation_psk : public digital_constellation_sector +{ + public: + + digital_constellation_psk (std::vector<gr_complex> constellation, + std::vector<unsigned int> pre_diff_code, + unsigned int n_sectors); + + protected: + + unsigned int get_sector (const gr_complex *sample); + + unsigned int calc_sector_value (unsigned int sector); + + private: + + friend DIGITAL_API digital_constellation_psk_sptr + digital_make_constellation_psk (std::vector<gr_complex> constellation, + std::vector<unsigned int> pre_diff_code, + unsigned int n_sectors); + +}; + +/************************************************************/ +/* digital_constellation_bpsk */ +/* */ +/* Only works for BPSK. */ +/* */ +/************************************************************/ + +class digital_constellation_bpsk; +typedef boost::shared_ptr<digital_constellation_bpsk> digital_constellation_bpsk_sptr; + +// public constructor +DIGITAL_API digital_constellation_bpsk_sptr +digital_make_constellation_bpsk (); + +class DIGITAL_API digital_constellation_bpsk : public digital_constellation +{ + public: + + digital_constellation_bpsk (); + unsigned int decision_maker (const gr_complex *sample); + + friend DIGITAL_API digital_constellation_bpsk_sptr + digital_make_constellation_bpsk (); + +}; + +/************************************************************/ +/* digital_constellation_qpsk */ +/* */ +/* Only works for QPSK. */ +/* */ +/************************************************************/ + +class digital_constellation_qpsk; +typedef boost::shared_ptr<digital_constellation_qpsk> digital_constellation_qpsk_sptr; + +// public constructor +DIGITAL_API digital_constellation_qpsk_sptr +digital_make_constellation_qpsk (); + +class DIGITAL_API digital_constellation_qpsk : public digital_constellation +{ + public: + + digital_constellation_qpsk (); + unsigned int decision_maker (const gr_complex *sample); + + friend DIGITAL_API digital_constellation_qpsk_sptr + digital_make_constellation_qpsk (); + +}; + +/************************************************************/ +/* 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 */ +/* */ +/* Only works for 8PSK. */ +/* */ +/************************************************************/ + +class digital_constellation_8psk; +typedef boost::shared_ptr<digital_constellation_8psk> digital_constellation_8psk_sptr; + +// public constructor +DIGITAL_API digital_constellation_8psk_sptr +digital_make_constellation_8psk (); + +class DIGITAL_API digital_constellation_8psk : public digital_constellation +{ + public: + + digital_constellation_8psk (); + unsigned int decision_maker (const gr_complex *sample); + + friend DIGITAL_API digital_constellation_8psk_sptr + digital_make_constellation_8psk (); + +}; + +#endif diff --git a/gr-digital/include/digital_constellation_decoder_cb.h b/gr-digital/include/digital_constellation_decoder_cb.h new file mode 100644 index 000000000..1ce01fe12 --- /dev/null +++ b/gr-digital/include/digital_constellation_decoder_cb.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_CONSTELLATION_DECODER_CB_H +#define INCLUDED_DIGITAL_CONSTELLATION_DECODER_CB_H + +#include <digital_api.h> +#include <gr_block.h> +#include <digital_constellation.h> +#include <vector> + +class digital_constellation_decoder_cb; +typedef boost::shared_ptr<digital_constellation_decoder_cb>digital_constellation_decoder_cb_sptr; + +DIGITAL_API digital_constellation_decoder_cb_sptr +digital_make_constellation_decoder_cb (digital_constellation_sptr constellation); + +/*! + * \brief Constellation Decoder + * \ingroup coding_blk + * + */ +class DIGITAL_API digital_constellation_decoder_cb : public gr_block +{ + + private: + digital_constellation_sptr d_constellation; + unsigned int d_dim; + + friend DIGITAL_API digital_constellation_decoder_cb_sptr + digital_make_constellation_decoder_cb (digital_constellation_sptr constellation); + + digital_constellation_decoder_cb (digital_constellation_sptr constellation); + + public: + + void forecast (int noutput_items, + gr_vector_int &ninput_items_required); + + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/gr-digital/include/digital_constellation_receiver_cb.h b/gr-digital/include/digital_constellation_receiver_cb.h new file mode 100644 index 000000000..d33be8958 --- /dev/null +++ b/gr-digital/include/digital_constellation_receiver_cb.h @@ -0,0 +1,115 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_CONSTELLATION_RECEIVER_CB_H +#define INCLUDED_DIGITAL_CONSTELLATION_RECEIVER_CB_H + +#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> + +class digital_constellation_receiver_cb; +typedef boost::shared_ptr<digital_constellation_receiver_cb> digital_constellation_receiver_cb_sptr; + +// public constructor +DIGITAL_API digital_constellation_receiver_cb_sptr +digital_make_constellation_receiver_cb (digital_constellation_sptr constellation, + float loop_bw, float fmin, float fmax); + +/*! + * \brief This block takes care of receiving generic modulated signals through phase, frequency, and symbol + * synchronization. + * \ingroup sync_blk + * \ingroup demod_blk + * + * This block takes care of receiving generic modulated signals through phase, frequency, and symbol + * synchronization. It performs carrier frequency and phase locking as well as symbol timing recovery. + * + * 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. + * + * 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. + * + * 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_constellation_receiver_cb : public gr_block, public gri_control_loop +{ +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); + +protected: + + /*! + * \brief Constructor to synchronize incoming M-PSK symbols + * + * \param constellation constellation of points for generic modulation + * \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 fmin minimum normalized frequency value the loop can achieve + * \param fmax maximum normalized frequency value the loop can achieve + * + * The constructor also chooses which phase detector and decision maker to use in the + * work loop based on the value of M. + */ + digital_constellation_receiver_cb (digital_constellation_sptr constellation, + float loop_bw, float fmin, float fmax); + + void phase_error_tracking(float phase_error); + +private: + unsigned int d_M; + + digital_constellation_sptr d_constellation; + unsigned int d_current_const_point; + + //! delay line length. + static const unsigned int DLLEN = 8; + + //! delay line plus some length for overflow protection + gr_complex d_dl[2*DLLEN] __attribute__ ((aligned(8))); + + //! index to delay line + unsigned int d_dl_idx; + + friend DIGITAL_API digital_constellation_receiver_cb_sptr + digital_make_constellation_receiver_cb (digital_constellation_sptr constell, + float loop_bw, float fmin, float fmax); +}; + +#endif diff --git a/gr-digital/include/digital_correlate_access_code_bb.h b/gr-digital/include/digital_correlate_access_code_bb.h new file mode 100644 index 000000000..c4cb60428 --- /dev/null +++ b/gr-digital/include/digital_correlate_access_code_bb.h @@ -0,0 +1,84 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2006,2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_CORRELATE_ACCESS_CODE_BB_H +#define INCLUDED_DIGITAL_CORRELATE_ACCESS_CODE_BB_H + +#include <digital_api.h> +#include <gr_sync_block.h> +#include <string> + +class digital_correlate_access_code_bb; +typedef boost::shared_ptr<digital_correlate_access_code_bb> digital_correlate_access_code_bb_sptr; + +/*! + * \param access_code is represented with 1 byte per bit, e.g., "010101010111000100" + * \param threshold maximum number of bits that may be wrong + */ +DIGITAL_API digital_correlate_access_code_bb_sptr +digital_make_correlate_access_code_bb (const std::string &access_code, int threshold); + +/*! + * \brief Examine input for specified access code, one bit at a time. + * \ingroup sync_blk + * + * input: stream of bits, 1 bit per input byte (data in LSB) + * output: stream of bits, 2 bits per output byte (data in LSB, flag in next higher bit) + * + * Each output byte contains two valid bits, the data bit, and the + * flag bit. The LSB (bit 0) is the data bit, and is the original + * input data, delayed 64 bits. Bit 1 is the + * flag bit and is 1 if the corresponding data bit is the first data + * bit following the access code. Otherwise the flag bit is 0. + */ +class DIGITAL_API digital_correlate_access_code_bb : public gr_sync_block +{ + friend DIGITAL_API digital_correlate_access_code_bb_sptr + digital_make_correlate_access_code_bb (const std::string &access_code, int threshold); + private: + unsigned long long d_access_code; // access code to locate start of packet + // access code is left justified in the word + unsigned long long d_data_reg; // used to look for access_code + unsigned long long d_flag_reg; // keep track of decisions + unsigned long long d_flag_bit; // mask containing 1 bit which is location of new flag + unsigned long long d_mask; // masks access_code bits (top N bits are set where + // N is the number of bits in the access code) + unsigned int d_threshold; // how many bits may be wrong in sync vector + + protected: + digital_correlate_access_code_bb(const std::string &access_code, int threshold); + + public: + ~digital_correlate_access_code_bb(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + + /*! + * \param access_code is represented with 1 byte per bit, e.g., "010101010111000100" + */ + bool set_access_code (const std::string &access_code); +}; + +#endif /* INCLUDED_DIGITAL_CORRELATE_ACCESS_CODE_BB_H */ diff --git a/gr-digital/include/digital_costas_loop_cc.h b/gr-digital/include/digital_costas_loop_cc.h new file mode 100644 index 000000000..c78726341 --- /dev/null +++ b/gr-digital/include/digital_costas_loop_cc.h @@ -0,0 +1,118 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_DIGITAL_COSTAS_LOOP_CC_H +#define INCLUDED_DIGITAL_COSTAS_LOOP_CC_H + +#include <gr_sync_block.h> +#include <gri_control_loop.h> +#include <stdexcept> +#include <fstream> + + +/*! \brief A Costas loop carrier recovery module. + * \ingroup sync_blk + * + * The Costas loop locks to the center frequency of a signal and + * downconverts it to baseband. The second (order=2) order loop is + * used for BPSK where the real part of the output signal is the + * baseband BPSK signal and the imaginary part is the error + * signal. When order=4, it can be used for quadrature modulations + * where both I and Q (real and imaginary) are outputted. + * + * More details can be found online: + * + * J. Feigin, "Practical Costas loop design: Designing a simple and inexpensive + * BPSK Costas loop carrier recovery circuit," RF signal processing, pp. 20-36, + * 2002. + * + * http://rfdesign.com/images/archive/0102Feigin20.pdf + * + * \param alpha the loop gain used for phase adjustment + * \param beta the loop gain for frequency adjustments + * \param max_freq the maximum frequency deviation (radians/sample) the loop can handle + * \param min_freq the minimum frequency deviation (radians/sample) the loop can handle + * \param order the loop order, either 2 or 4 + */ + +#include <digital_api.h> + +class digital_costas_loop_cc; +typedef boost::shared_ptr<digital_costas_loop_cc> digital_costas_loop_cc_sptr; + + +DIGITAL_API digital_costas_loop_cc_sptr +digital_make_costas_loop_cc (float loop_bw, int order + ) throw (std::invalid_argument); + + +/*! + * \brief Carrier tracking PLL for QPSK + * \ingroup sync_blk + * input: complex; output: complex + * <br>The Costas loop can have two output streams: + * stream 1 is the baseband I and Q; + * stream 2 is the normalized frequency of the loop + * + * \p order must be 2 or 4. + */ +class DIGITAL_API digital_costas_loop_cc : public gr_sync_block, public gri_control_loop +{ + friend DIGITAL_API digital_costas_loop_cc_sptr + digital_make_costas_loop_cc (float loop_bw, int order + ) throw (std::invalid_argument); + + int d_order; + + digital_costas_loop_cc (float loop_bw, int order + ) throw (std::invalid_argument); + + /*! \brief the phase detector circuit for 8th-order PSK loops + * \param sample complex sample + * \return the phase error + */ + float phase_detector_8(gr_complex sample) const; // for 8PSK + + /*! \brief the phase detector circuit for fourth-order loops + * \param sample complex sample + * \return the phase error + */ + float phase_detector_4(gr_complex sample) const; // for QPSK + + /*! \brief the phase detector circuit for second-order loops + * \param sample a complex sample + * \return the phase error + */ + float phase_detector_2(gr_complex sample) const; // for BPSK + + + float (digital_costas_loop_cc::*d_phase_detector)(gr_complex sample) const; + +public: + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/gr-digital/include/digital_cpmmod_bc.h b/gr-digital/include/digital_cpmmod_bc.h new file mode 100644 index 000000000..4e9547cd6 --- /dev/null +++ b/gr-digital/include/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/include/digital_crc32.h b/gr-digital/include/digital_crc32.h new file mode 100644 index 000000000..852d06f49 --- /dev/null +++ b/gr-digital/include/digital_crc32.h @@ -0,0 +1,51 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_CRC32_H +#define INCLUDED_DIGITAL_CRC32_H + +#include <digital_api.h> +#include <string> +#include <gr_types.h> + +/*! + * \brief update running CRC-32 + * \ingroup misc + * + * Update a running CRC with the bytes buf[0..len-1] The CRC should be + * initialized to all 1's, and the transmitted value is the 1's + * complement of the final running CRC. The resulting CRC should be + * transmitted in big endian order. + */ +DIGITAL_API unsigned int +digital_update_crc32(unsigned int crc, const unsigned char *buf, size_t len); + +DIGITAL_API unsigned int +digital_update_crc32(unsigned int crc, const std::string buf); + +DIGITAL_API unsigned int +digital_crc32(const unsigned char *buf, size_t len); + +DIGITAL_API unsigned int +digital_crc32(const std::string buf); + +#endif /* INCLUDED_CRC32_H */ diff --git a/gr-digital/include/digital_fll_band_edge_cc.h b/gr-digital/include/digital_fll_band_edge_cc.h new file mode 100644 index 000000000..6ef8376ac --- /dev/null +++ b/gr-digital/include/digital_fll_band_edge_cc.h @@ -0,0 +1,213 @@ +/* -*- c++ -*- */ +/* + * 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. + */ + + +#ifndef INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_H +#define INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_H + +#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; +DIGITAL_API digital_fll_band_edge_cc_sptr digital_make_fll_band_edge_cc (float samps_per_sym, + float rolloff, + int filter_size, + float bandwidth); + +/*! + * \class digital_fll_band_edge_cc + * \brief Frequency Lock Loop using band-edge filters + * + * \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 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 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. + * + * 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, public gri_control_loop +{ + private: + /*! + * Build the FLL + * \param samps_per_sym (float) Number of samples per symbol of signal + * \param rolloff (float) Rolloff factor of signal + * \param filter_size (int) Size (in taps) of the filter + * \param bandwidth (float) Loop bandwidth + */ + friend DIGITAL_API digital_fll_band_edge_cc_sptr digital_make_fll_band_edge_cc (float samps_per_sym, + float rolloff, + int filter_size, + float bandwidth); + + float d_sps; + float d_rolloff; + int d_filter_size; + + std::vector<gr_complex> d_taps_lower; + std::vector<gr_complex> d_taps_upper; + bool d_updated; + + /*! + * Build the FLL + * \param samps_per_sym (float) number of samples per symbol + * \param rolloff (float) Rolloff (excess bandwidth) of signal filter + * \param filter_size (int) number of filter taps to generate + * \param bandwidth (float) Loop bandwidth + */ + digital_fll_band_edge_cc(float samps_per_sym, float rolloff, + int filter_size, float bandwidth); + + /*! + * Design the band-edge filter based on the number of samples per symbol, + * filter rolloff factor, and the filter size + * + * \param samps_per_sym (float) Number of samples per symbol of signal + * \param rolloff (float) Rolloff factor of signal + * \param filter_size (int) Size (in taps) of the filter + */ + void design_filter(float samps_per_sym, float rolloff, int filter_size); + +public: + ~digital_fll_band_edge_cc (); + + /******************************************************************* + SET FUNCTIONS + *******************************************************************/ + + /*! + * \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. + * + * \param sps (float) new samples per symbol + * + */ + void set_samples_per_symbol(float sps); + + /*! + * \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 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] + * + */ + void set_rolloff(float rolloff); + + /*! + * \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 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); + + /******************************************************************* + GET FUNCTIONS + *******************************************************************/ + + /*! + * \brief Returns the number of sampler per symbol used for the filter + */ + float get_samples_per_symbol() const; + + /*! + * \brief Returns the rolloff factor used for the filter + */ + float get_rolloff() const; + + /*! + * \brief Returns the number of taps of the filter + */ + int get_filter_size() const; + + /*! + * Print the taps to screen. + */ + void print_taps(); + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/gr-digital/include/digital_gmskmod_bc.h b/gr-digital/include/digital_gmskmod_bc.h new file mode 100644 index 000000000..33fcc6c12 --- /dev/null +++ b/gr-digital/include/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/include/digital_kurtotic_equalizer_cc.h b/gr-digital/include/digital_kurtotic_equalizer_cc.h new file mode 100644 index 000000000..c07862e11 --- /dev/null +++ b/gr-digital/include/digital_kurtotic_equalizer_cc.h @@ -0,0 +1,112 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_KURTOTIC_EQUALIZER_CC_H +#define INCLUDED_DIGITAL_KURTOTIC_EQUALIZER_CC_H + +#include <digital_api.h> +#include <gr_adaptive_fir_ccc.h> +#include <gr_math.h> +#include <iostream> + +class digital_kurtotic_equalizer_cc; +typedef boost::shared_ptr<digital_kurtotic_equalizer_cc> digital_kurtotic_equalizer_cc_sptr; + +DIGITAL_API digital_kurtotic_equalizer_cc_sptr +digital_make_kurtotic_equalizer_cc(int num_taps, float mu); + +/*! + * \brief Implements a kurtosis-based adaptive equalizer on complex stream + * \ingroup eq_blk + * + * Y. Guo, J. Zhao, Y. Sun, "Sign kurtosis maximization based blind + * equalization algorithm," IEEE Conf. on Control, Automation, + * Robotics and Vision, Vol. 3, Dec. 2004, pp. 2052 - 2057. + */ +class DIGITAL_API digital_kurtotic_equalizer_cc : public gr_adaptive_fir_ccc +{ +private: + float d_mu; + float d_p, d_m; + gr_complex d_q, d_u; + float d_alpha_p, d_alpha_q, d_alpha_m; + + friend DIGITAL_API digital_kurtotic_equalizer_cc_sptr digital_make_kurtotic_equalizer_cc(int num_taps, + float mu); + digital_kurtotic_equalizer_cc(int num_taps, float mu); + + gr_complex sign(gr_complex x) + { + float re = (float)(x.real() >= 0.0f); + float im = (float)(x.imag() >= 0.0f); + return gr_complex(re, im); + } + +protected: + + virtual gr_complex error(const gr_complex &out) + { + + // p = E[|z|^2] + // q = E[z^2] + // m = E[|z|^4] + // u = E[kurtosis(z)] + + float nrm = norm(out); + gr_complex cnj = conj(out); + float epsilon_f = 1e-12; + gr_complex epsilon_c = gr_complex(1e-12, 1e-12); + + + d_p = (1-d_alpha_p)*d_p + (d_alpha_p)*nrm + epsilon_f; + d_q = (1-d_alpha_q)*d_q + (d_alpha_q)*out*out + epsilon_c; + d_m = (1-d_alpha_m)*d_m + (d_alpha_m)*nrm*nrm + epsilon_f; + d_u = d_m - 2.0f*(d_p*d_p) - d_q*d_q; + + gr_complex F = (1.0f / (d_p*d_p*d_p)) * + (sign(d_u) * (nrm*cnj - 2.0f*d_p*cnj - conj(d_q)*out) - + abs(d_u)*cnj); + + //std::cout << "out: " << out << " p: " << d_p << " q: " << d_q; + //std::cout << " m: " << d_m << " u: " << d_u << std::endl; + //std::cout << "error: " << F << std::endl; + + float re = gr_clip(F.real(), 1.0); + float im = gr_clip(F.imag(), 1.0); + return gr_complex(re, im); + } + + virtual void update_tap(gr_complex &tap, const gr_complex &in) + { + tap += d_mu*in*d_error; + } + +public: + void set_gain(float mu) + { + if(mu < 0) + throw std::out_of_range("digital_kurtotic_equalizer::set_gain: Gain value must be >= 0"); + d_mu = mu; + } +}; + +#endif diff --git a/gr-digital/include/digital_lms_dd_equalizer_cc.h b/gr-digital/include/digital_lms_dd_equalizer_cc.h new file mode 100644 index 000000000..edfa18e23 --- /dev/null +++ b/gr-digital/include/digital_lms_dd_equalizer_cc.h @@ -0,0 +1,117 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_LMS_DD_EQUALIZER_CC_H +#define INCLUDED_DIGITAL_LMS_DD_EQUALIZER_CC_H + +#include <digital_api.h> +#include <gr_adaptive_fir_ccc.h> +#include <digital_constellation.h> + +class digital_lms_dd_equalizer_cc; +typedef boost::shared_ptr<digital_lms_dd_equalizer_cc> digital_lms_dd_equalizer_cc_sptr; + +DIGITAL_API digital_lms_dd_equalizer_cc_sptr digital_make_lms_dd_equalizer_cc (int num_taps, + float mu, int sps, + digital_constellation_sptr cnst); + +/*! + * \brief Least-Mean-Square Decision Directed Equalizer (complex in/out) + * \ingroup eq_blk + * + * This block implements an LMS-based decision-directed equalizer. + * It uses a set of weights, w, to correlate against the inputs, u, + * and a decisions is then made from this output. The error + * in the decision is used to update teh weight vector. + * + * y[n] = conj(w[n]) u[n] + * d[n] = decision(y[n]) + * e[n] = d[n] - y[n] + * w[n+1] = w[n] + mu u[n] conj(e[n]) + * + * Where mu is a gain value (between 0 and 1 and usualy small, + * around 0.001 - 0.01. + * + * This block uses the digital_constellation object for making + * the decision from y[n]. Create the constellation object for + * whatever constellation is to be used and pass in the object. + * In Python, you can use something like: + * self.constellation = digital.constellation_qpsk() + * To create a QPSK constellation (see the digital_constellation + * block for more details as to what constellations are available + * or how to create your own). You then pass the object to this + * block as an sptr, or using "self.constellation.base()". + * + * The theory for this algorithm can be found in Chapter 9 of: + * S. Haykin, Adaptive Filter Theory, Upper Saddle River, NJ: + * Prentice Hall, 1996. + * + */ +class DIGITAL_API digital_lms_dd_equalizer_cc : public gr_adaptive_fir_ccc +{ +private: + friend DIGITAL_API digital_lms_dd_equalizer_cc_sptr digital_make_lms_dd_equalizer_cc (int num_taps, + float mu, int sps, + digital_constellation_sptr cnst); + + float d_mu; + std::vector<gr_complex> d_taps; + digital_constellation_sptr d_cnst; + + digital_lms_dd_equalizer_cc (int num_taps, + float mu, int sps, + digital_constellation_sptr cnst); + +protected: + + virtual gr_complex error(const gr_complex &out) + { + gr_complex decision, error; + d_cnst->map_to_points(d_cnst->decision_maker(&out), &decision); + error = decision - out; + return error; + } + + virtual void update_tap(gr_complex &tap, const gr_complex &in) + { + tap += d_mu*conj(in)*d_error; + } + +public: + float get_gain() + { + return d_mu; + } + + void set_gain(float mu) + { + if(mu < 0.0f || mu > 1.0f) { + throw std::out_of_range("digital_lms_dd_equalizer::set_mu: Gain value must in [0, 1]"); + } + else { + d_mu = mu; + } + } + +}; + +#endif diff --git a/gr-digital/include/digital_metric_type.h b/gr-digital/include/digital_metric_type.h new file mode 100644 index 000000000..83de166f0 --- /dev/null +++ b/gr-digital/include/digital_metric_type.h @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_METRIC_TYPE_H +#define INCLUDED_DIGITAL_METRIC_TYPE_H + +typedef enum { + TRELLIS_EUCLIDEAN = 200, TRELLIS_HARD_SYMBOL, TRELLIS_HARD_BIT +} trellis_metric_type_t; + +#endif + diff --git a/gr-digital/include/digital_mpsk_receiver_cc.h b/gr-digital/include/digital_mpsk_receiver_cc.h new file mode 100644 index 000000000..85cd81e99 --- /dev/null +++ b/gr-digital/include/digital_mpsk_receiver_cc.h @@ -0,0 +1,302 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2011 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_MPSK_RECEIVER_CC_H +#define INCLUDED_DIGITAL_MPSK_RECEIVER_CC_H + +#include <digital_api.h> +#include <gruel/attributes.h> +#include <gri_control_loop.h> +#include <gr_block.h> +#include <gr_complex.h> +#include <fstream> + +class gri_mmse_fir_interpolator_cc; + +class digital_mpsk_receiver_cc; +typedef boost::shared_ptr<digital_mpsk_receiver_cc> digital_mpsk_receiver_cc_sptr; + +// public constructor +DIGITAL_API digital_mpsk_receiver_cc_sptr +digital_make_mpsk_receiver_cc (unsigned int M, float theta, + 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. + * \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. + * + * 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: + * + * 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. + * + */ + +class DIGITAL_API digital_mpsk_receiver_cc : public gr_block, public gri_control_loop +{ + public: + ~digital_mpsk_receiver_cc (); + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + + // Member functions related to the symbol tracking portion of the receiver + //! (M&M) Returns current value of mu + float mu() const { return d_mu;} + + //! (M&M) Returns current value of omega + float omega() const { return d_omega;} + + //! (M&M) Returns mu gain factor + float gain_mu() const { return d_gain_mu;} + + //! (M&M) Returns omega gain factor + float gain_omega() const { return d_gain_omega;} + + //! (M&M) Sets value of mu + void set_mu (float mu) { d_mu = mu; } + + //! (M&M) Sets value of omega and its min and max values + void set_omega (float omega) { + d_omega = omega; + d_min_omega = omega*(1.0 - d_omega_rel); + d_max_omega = omega*(1.0 + d_omega_rel); + d_omega_mid = 0.5*(d_min_omega+d_max_omega); + } + + //! (M&M) Sets value for mu gain factor + void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; } + + //! (M&M) Sets value for omega gain factor + void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; } + +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 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] + * \param gain_mu gain parameter of the M&M error signal to adjust mu (~0.05) + * \param omega initial value for the number of symbols between samples (~number of samples/symbol) + * \param gain_omega gain parameter to adjust omega based on the error (~omega^2/4) + * \param omega_rel sets the maximum (omega*(1+omega_rel)) and minimum (omega*(1+omega_rel)) omega (~0.005) + * + * The constructor also chooses which phase detector and decision maker to use in the work loop based on the + * value of M. + */ + digital_mpsk_receiver_cc (unsigned int M, float theta, + float loop_bw, + float fmin, float fmax, + float mu, float gain_mu, + float omega, float gain_omega, float omega_rel); + + void make_constellation(); + void mm_sampler(const gr_complex symbol); + void mm_error_tracking(gr_complex sample); + 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 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. + * + * \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 + * + * \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. + * + * \returns the index to d_constellation that minimizes the error/ + */ + unsigned int decision_generic(gr_complex sample) const; + + + /*! + * \brief Decision maker for BPSK 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 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. + * + * \returns the index to d_constellation that minimizes the error/ + */ + unsigned int decision_qpsk(gr_complex sample) const; + +private: + unsigned int d_M; + float d_theta; + + /*! + * \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. + * + * \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 + + + std::vector<gr_complex> d_constellation; + unsigned int d_current_const_point; + + // Members related to symbol timing + float d_mu, d_gain_mu; + float d_omega, d_gain_omega, d_omega_rel, d_max_omega, d_min_omega, d_omega_mid; + 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. + */ + float (digital_mpsk_receiver_cc::*d_phase_error_detector)(gr_complex sample) const; + + + //! get interpolated value + gri_mmse_fir_interpolator_cc *d_interp; + + //! delay line length. + static const unsigned int DLLEN = 8; + + //! delay line plus some length for overflow protection + __GR_ATTR_ALIGNED(8) gr_complex d_dl[2*DLLEN]; + + //! index to delay line + unsigned int d_dl_idx; + + friend DIGITAL_API digital_mpsk_receiver_cc_sptr + digital_make_mpsk_receiver_cc (unsigned int M, float theta, + float loop_bw, + float fmin, float fmax, + float mu, float gain_mu, + float omega, float gain_omega, float omega_rel); +}; + +#endif |