/* -*- c++ -*- */ /* * Copyright (C) 2017 Free Software Foundation, Inc. * * This file is part of GNU Radio * * SPDX-License-Identifier: GPL-3.0-or-later * */ #ifndef INCLUDED_DIGITAL_INTERPOLATING_RESAMPLER_H #define INCLUDED_DIGITAL_INTERPOLATING_RESAMPLER_H #include <gnuradio/digital/interpolating_resampler_type.h> #include <gnuradio/filter/mmse_fir_interpolator_cc.h> #include <gnuradio/filter/mmse_fir_interpolator_ff.h> #include <gnuradio/filter/mmse_interp_differentiator_cc.h> #include <gnuradio/filter/mmse_interp_differentiator_ff.h> #include <gnuradio/gr_complex.h> #include <vector> namespace gr { namespace digital { /*! * \brief Base class for the composite interpolating resampler objects * used by the symbol_synchronizer_xx blocks. * \ingroup internal * * \details * This is the base class for the composite interpolating resampler * objects used by the symbol_synchronizer_xx blocks to provide a * user selectable interpolating resampler type. * * This base class provides the enumeration type for the available * types of interpolating resamplers. * * This base class also provides methods to to update, manage, and * store the sample phase state of the interpolating resampler. * The sample phase increments and phase state are assumed to be in * units of samples, and a complete sample phase cycle is one sample. */ class interpolating_resampler { public: virtual ~interpolating_resampler() {} /*! * \brief Return the number of taps used in any single FIR filtering * operation */ virtual unsigned int ntaps() const = 0; /*! * \brief Return the current unwrapped interpolator samples phase in * units of samples */ virtual float phase() { return d_phase; } /*! * \brief Return the integral part of the current unwrapped * interpolator sample phase in units of (whole) samples */ virtual int phase_n() { return d_phase_n; } /*! * \brief Returns the fractional part of the current wrapped * interpolator sample phase in units of samples from [0.0, 1.0). */ virtual float phase_wrapped() { return d_phase_wrapped; } /*! * \brief Return the fractional part of the previous wrapped * interpolator sample phase in units of samples from [0.0, 1.0). */ virtual float prev_phase_wrapped() { return d_prev_phase_wrapped; } /*! * \brief Compute the next interpolator sample phase. * \param increment The sample phase increment to the next interpolation * point, in units of samples. * \param phase The new interpolator sample phase, in units of * samples. * \param phase_n The integral part of the new interpolator sample * phase, in units of samples. * \param phase_wrapped The new wrapped interpolator sample phase, * in units of samples. */ virtual void next_phase(float increment, float& phase, int& phase_n, float& phase_wrapped); /*! * \brief Advance the phase state to the next interpolator sample phase. * \param increment The sample phase increment to the next interpolation * point, in units of samples. */ virtual void advance_phase(float increment); /*! * \brief Revert the phase state to the previous interpolator sample * phase. */ virtual void revert_phase(); /*! * \brief Reset the phase state to the specified interpolator sample * phase. * \param phase The interpolator sample phase to which to reset, * in units of samples. */ virtual void sync_reset(float phase); private: enum ir_type d_type; protected: interpolating_resampler(enum ir_type type, bool derivative = false); bool d_derivative; float d_phase; float d_phase_wrapped; int d_phase_n; float d_prev_phase; float d_prev_phase_wrapped; int d_prev_phase_n; }; /*************************************************************************/ /*! * \brief A complex input, complex output, composite interpolating resampler * object used by the symbol_synchronizer_cc block. * \ingroup internal * * \details * This is the complex input, complex output composite interpolating * resampler object used by the symbol_synchronizer_cc block to provide a * user selectable interpolating resampler type. * * This class abstracts away the underlying interpolating resampler * type implementation, so the the symbol_synchronizer_cc block need not * be bothered with the underlying implementation after the object is * instantiated. */ class interpolating_resampler_ccf : public interpolating_resampler { public: /*! * \brief Create a complex input, complex output interpolating * resampler object. * \param type The underlying type implementation of the interpolating * resampler. * \param derivative True if an interpolating differentitator is * requested to be initialized to obtain interpolated * derivative samples as well. * \param nfilts The number of polyphase filter bank arms. Only needed * for some types. * \param taps Prototype filter for the polyphase filter bank. Only * needed for some types. */ static interpolating_resampler_ccf* make(enum ir_type type, bool derivative = false, int nfilts = 32, const std::vector<float>& taps = std::vector<float>()); virtual ~interpolating_resampler_ccf(){}; /*! * \brief Return an interpolated sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ virtual gr_complex interpolate(const gr_complex input[], float mu) const = 0; /*! * \brief Return an interpolated derivative sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ virtual gr_complex differentiate(const gr_complex input[], float mu) const = 0; protected: interpolating_resampler_ccf(enum ir_type type, bool derivative = false) : interpolating_resampler(type, derivative) { } }; /*************************************************************************/ /*! * \brief A float input, float output, composite interpolating resampler * object used by the symbol_synchronizer_ff block. * \ingroup internal * * \details * This is the float input, float output composite interpolating * resampler object used by the symbol_synchronizer_ff block to provide a * user selectable interpolating resampler type. * * This class abstracts away the underlying interpolating resampler * type implementation, so the the symbol_synchronizer_ff block need not * be bothered with the underlying implementation after the object is * instantiated. */ class interpolating_resampler_fff : public interpolating_resampler { public: /*! * \brief Create a float input, float output interpolating * resampler object. * \param type The underlying type implementation of the interpolating * resampler. * \param derivative True if an interpolating differentitator is * requested to be initialized to obtain interpolated * derivative samples as well. * \param nfilts The number of polyphase filter bank arms. Only needed * for some types. * \param taps Prototype filter for the polyphase filter bank. Only * needed for some types. */ static interpolating_resampler_fff* make(enum ir_type type, bool derivative = false, int nfilts = 32, const std::vector<float>& taps = std::vector<float>()); virtual ~interpolating_resampler_fff(){}; /*! * \brief Return an interpolated sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ virtual float interpolate(const float input[], float mu) const = 0; /*! * \brief Return an interpolated derivative sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ virtual float differentiate(const float input[], float mu) const = 0; protected: interpolating_resampler_fff(enum ir_type type, bool derivative = false) : interpolating_resampler(type, derivative) { } }; /*************************************************************************/ /*! * \brief A complex input, complex output, interpolating resampler * object using the MMSE interpolator filter bank. * \ingroup internal * * \details * This is the complex input, complex output, interpolating resampler * object using the MMSE interpolator filter bank as its underlying * polyphase filterbank interpolator. */ class interp_resampler_mmse_8tap_cc : public interpolating_resampler_ccf { public: /*! * \brief Create a complex input, complex output, polyphase filter bank * using the MMSE filter bank, interpolating resampler object. * \param derivative True if an interpolating differentitator is * requested to be initialized to obtain interpolated * derivative samples as well. */ interp_resampler_mmse_8tap_cc(bool derivative = false); ~interp_resampler_mmse_8tap_cc(); /*! * \brief Return the number of taps used in any single FIR filtering * operation */ unsigned int ntaps() const; /*! * \brief Return an interpolated sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ gr_complex interpolate(const gr_complex input[], float mu) const; /*! * \brief Return an interpolated derivative sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ gr_complex differentiate(const gr_complex input[], float mu) const; private: filter::mmse_fir_interpolator_cc* d_interp; filter::mmse_interp_differentiator_cc* d_interp_diff; }; /*! * \brief A float input, float output, interpolating resampler * object using the MMSE interpolator filter bank. * \ingroup internal * * \details * This is the float input, float output, interpolating resampler * object using the MMSE interpolator filter bank as its underlying * polyphase filterbank interpolator. */ class interp_resampler_mmse_8tap_ff : public interpolating_resampler_fff { public: /*! * \brief Create a float input, float output, polyphase filter bank * using the MMSE filter bank, interpolating resampler object. * \param derivative True if an interpolating differentitator is * requested to be initialized to obtain interpolated * derivative samples as well. */ interp_resampler_mmse_8tap_ff(bool derivative = false); ~interp_resampler_mmse_8tap_ff(); /*! * \brief Return the number of taps used in any single FIR filtering * operation */ unsigned int ntaps() const; /*! * \brief Return an interpolated sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ float interpolate(const float input[], float mu) const; /*! * \brief Return an interpolated derivative sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ float differentiate(const float input[], float mu) const; private: filter::mmse_fir_interpolator_ff* d_interp; filter::mmse_interp_differentiator_ff* d_interp_diff; }; /*************************************************************************/ /*! * \brief A complex input, complex output, interpolating resampler * object with a polyphase filter bank which uses the MMSE interpolator * filter arms. * \ingroup internal * * \details * This is the complex input, complex output, interpolating resampler * object with a polyphase filter bank which uses the MMSE interpolator * filter arms. This class has the "advantage" that the number of arms * used can be reduced from 128 (default) to 64, 32, 16, 8, 4, or 2. */ class interp_resampler_pfb_no_mf_cc : public interpolating_resampler_ccf { public: /*! * \brief Create a complex input, complex output, polyphase filter bank * using the MMSE filter bank, interpolating resampler object. * \param nfilts The number of polyphase filter bank arms. Must be in * {2, 4, 8, 16, 32, 64, 128 (default)} * \param derivative True if an interpolating differentitator is * requested to be initialized to obtain interpolated * derivative samples as well. */ interp_resampler_pfb_no_mf_cc(bool derivative = false, int nfilts = 128); ~interp_resampler_pfb_no_mf_cc(); /*! * \brief Return the number of taps used in any single FIR filtering * operation */ unsigned int ntaps() const; /*! * \brief Return an interpolated sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ gr_complex interpolate(const gr_complex input[], float mu) const; /*! * \brief Return an interpolated derivative sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ gr_complex differentiate(const gr_complex input[], float mu) const; private: int d_nfilters; std::vector<filter::kernel::fir_filter_ccf*> d_filters; std::vector<filter::kernel::fir_filter_ccf*> d_diff_filters; }; /*! * \brief A float input, float output, interpolating resampler * object with a polyphase filter bank which uses the MMSE interpolator * filter arms. * \ingroup internal * * \details * This is the float input, float output, interpolating resampler * object with a polyphase filter bank which uses the MMSE interpolator * filter arms. This class has the "advantage" that the number of arms * used can be reduced from 128 (default) to 64, 32, 16, 8, 4, or 2. */ class interp_resampler_pfb_no_mf_ff : public interpolating_resampler_fff { public: /*! * \brief Create a float input, float output, polyphase filter bank * using the MMSE filter bank, interpolating resampler object. * \param nfilts The number of polyphase filter bank arms. Must be in * {2, 4, 8, 16, 32, 64, 128 (default)} * \param derivative True if an interpolating differentitator is * requested to be initialized to obtain interpolated * derivative samples as well. */ interp_resampler_pfb_no_mf_ff(bool derivative = false, int nfilts = 128); ~interp_resampler_pfb_no_mf_ff(); /*! * \brief Return the number of taps used in any single FIR filtering * operation */ unsigned int ntaps() const; /*! * \brief Return an interpolated sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ float interpolate(const float input[], float mu) const; /*! * \brief Return an interpolated derivative sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ float differentiate(const float input[], float mu) const; private: int d_nfilters; std::vector<filter::kernel::fir_filter_fff*> d_filters; std::vector<filter::kernel::fir_filter_fff*> d_diff_filters; }; /*************************************************************************/ /*! * \brief A complex input, complex output, interpolating resampler * object with a polyphase filter bank with a user provided prototype * matched filter. * \ingroup internal * * \details * This is the complex input, complex output, interpolating resampler * object with a polyphase filter bank with a user provided prototype * matched filter. The prototype matched filter must be designed at a * rate of nfilts times the output rate. */ class interp_resampler_pfb_mf_ccf : public interpolating_resampler_ccf { public: /*! * \brief Create a complex input, complex output, polyphase filter bank, * with matched filter, interpolating resampler object. * \param taps Prototype filter for the polyphase filter bank. * \param nfilts The number of polyphase filter bank arms. * \param derivative True if an interpolating differentitator is * requested to be initialized to obtain interpolated * derivative samples as well. */ interp_resampler_pfb_mf_ccf(const std::vector<float>& taps, int nfilts = 32, bool derivative = false); ~interp_resampler_pfb_mf_ccf(); /*! * \brief Return the number of taps used in any single FIR filtering * operation */ unsigned int ntaps() const; /*! * \brief Return an interpolated sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ gr_complex interpolate(const gr_complex input[], float mu) const; /*! * \brief Return an interpolated derivative sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ gr_complex differentiate(const gr_complex input[], float mu) const; private: int d_nfilters; const unsigned int d_taps_per_filter; std::vector<filter::kernel::fir_filter_ccf*> d_filters; std::vector<filter::kernel::fir_filter_ccf*> d_diff_filters; std::vector<std::vector<float>> d_taps; std::vector<std::vector<float>> d_diff_taps; }; /*! * \brief A float input, float output, interpolating resampler * object with a polyphase filter bank with a user provided prototype * matched filter. * \ingroup internal * * \details * This is the float input, float output, interpolating resampler * object with a polyphase filter bank with a user provided prototype * matched filter. The prototype matched filter must be designed at a * rate of nfilts times the output rate. */ class interp_resampler_pfb_mf_fff : public interpolating_resampler_fff { public: /*! * \brief Create a float input, float output, polyphase filter bank, * with matched filter, interpolating resampler object. * \param taps Prototype filter for the polyphase filter bank. * \param nfilts The number of polyphase filter bank arms. * \param derivative True if an interpolating differentitator is * requested to be initialized to obtain interpolated * derivative samples as well. */ interp_resampler_pfb_mf_fff(const std::vector<float>& taps, int nfilts = 32, bool derivative = false); ~interp_resampler_pfb_mf_fff(); /*! * \brief Return the number of taps used in any single FIR filtering * operation */ unsigned int ntaps() const; /*! * \brief Return an interpolated sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ float interpolate(const float input[], float mu) const; /*! * \brief Return an interpolated derivative sample. * \param input Array of input samples of length ntaps(). * \param mu Intersample phase in the range [0.0, 1.0] samples. */ float differentiate(const float input[], float mu) const; private: int d_nfilters; const unsigned int d_taps_per_filter; std::vector<filter::kernel::fir_filter_fff*> d_filters; std::vector<filter::kernel::fir_filter_fff*> d_diff_filters; std::vector<std::vector<float>> d_taps; std::vector<std::vector<float>> d_diff_taps; }; } /* namespace digital */ } /* namespace gr */ #endif /* INCLUDED_DIGITAL_INTERPOLATING_RESAMPLER_H */