#ifndef _INTERPOLATION_DOWNSAMPLER_HPP_ #define _INTERPOLATION_DOWNSAMPLER_HPP_ #pragma once #include #include namespace Radio { namespace Interpolation { // -------------------------------------------------------------- // Complex FIR-based DownSampler // -------------------------------------------------------------- class DownSampler { public: DownSampler() : m_pFir(nullptr) , m_pCoeff(nullptr) , m_M(0) , m_currStage(0) { } ~DownSampler() { if (m_pFir) delete [] m_pFir; if (m_pCoeff) delete [] m_pCoeff; } void init(uint32_t M, RealScalar const *coeff, uint32_t N) { uint32_t i, j; uint32_t stage_N; uint32_t stage; if (m_pFir) delete [] m_pFir; if (m_pCoeff) delete [] m_pCoeff; m_pFir = new FirComplex[M]; m_pCoeff = new RVec[M]; for (stage=0; stage < M; stage++) { stage_N = 0; for (i=stage; i < N; i += M) { stage_N++; } m_pFir[stage].setNumTaps(stage_N); m_pCoeff[stage].resize(stage_N); j=0; for (i=stage; i < N; i += M) { if (coeff) { m_pCoeff[stage][j++] = coeff[i]; } } } m_M = M; m_currStage = m_M-1; } uint32_t process(CVec &dst, CVec const &src, uint32_t len) { uint32_t i; uint32_t j; j = 0; for (i=0; i < len; i++) { m_pFir[m_currStage].feed(src[i]); if (m_currStage == (m_M-1)) { dst[j] = m_pFir[m_currStage].processReal(m_pCoeff[m_currStage]); } else { dst[j] += m_pFir[m_currStage].processReal(m_pCoeff[m_currStage]); } if (--m_currStage >= m_M) { m_currStage = m_M-1; j++; } } return j; } private: FirComplex *m_pFir; RVec *m_pCoeff; uint32_t m_M; uint32_t m_currStage; }; } // Radio::Interpolation } // ::Radio #endif // _INTERPOLATION_DOWNSAMPLER_HPP_