diff --git a/radio/Interpolation.hpp b/radio/Interpolation.hpp index e9d830e..a234d87 100644 --- a/radio/Interpolation.hpp +++ b/radio/Interpolation.hpp @@ -17,6 +17,13 @@ namespace Radio namespace Interpolation { +// -------------------------------------------------------------- +// Complex FIR-based polyphase interpolation filter (Farrow structure) +// From: +// "PERFORMANCE AND DESIGN OF FARROW FILTER USED FOR ARBITRARY RESAMPLING" +// [unknown date], Fred Harris, Signal Processing ChairCommunication Systems and Signal Processing Institute +// College of Engineering, San Diego State University, San Diego, CA 92182-0190 USA +// -------------------------------------------------------------- class Farrow : public FirComplex { typedef struct _ml_farrow_coef_hdr_t @@ -63,7 +70,7 @@ public: m_fifo[m_w] = x; } - ComplexScalar process(radio_float_t mu, uint32_t pop) + ComplexScalar process(RealScalar mu, uint32_t pop) { uint32_t i, r; int32_t j; @@ -131,8 +138,9 @@ public: } } printf("Farrow filter coefficients loaded (M=%d, N=%d)", m_M, m_N); - + delete [] pCoeff; + fclose(pFile); } @@ -146,7 +154,7 @@ private: CVec m_h; CVec m_fifo; - ComplexScalar horner(radio_float_t mu) + ComplexScalar horner(RealScalar mu) { uint32_t i; @@ -161,6 +169,179 @@ private: }; +// -------------------------------------------------------------- +// Complex FIR-based discrete step polyphase interpolation filter +// -------------------------------------------------------------- +class PolyPhase : public FirComplex +{ +public: + PolyPhase() + { + + } + + ~PolyPhase() + { + + } + + void init(RealScalar fa, RealScalar tsym, RealScalar alpha, uint32_t N, uint32_t M) + { + uint32_t i, j; + fir_float_t *pCoeff; + RealScalar k; + + FirComplex::setNumTaps(N); + m_M = M; + m_N = N; + m_coeff.resize(N, M); + m_fifo.resize(N); + m_fifo.setZero(); + + pCoeff = (fir_float_t*)malloc((N+1)*M*sizeof(fir_float_t)); + memset(pCoeff, 0, (N+1)*M*sizeof(fir_float_t)); + + k = CalcFirSRRC(pCoeff, M*fa, tsym, alpha, N*M); + + m_coeff.resize(N, M); + for(i=0; i < M; i++) + { + for(j=0; j < N; j++) + { + m_coeff(j,i) = M*pCoeff[M*j+M/2+i]; + } + } + free(pCoeff); + } + + void feed(ComplexScalar const &x, uint32_t push) + { + m_w = (m_w + push) % m_N; + m_fifo[m_w] = x; + } + + ComplexScalar process(RealScalar mu, uint32_t pop) + { + uint32_t i, r, index; + int32_t j; + + index = (uint32_t)dmod(dmax(0, mu*m_M), (RealScalar)m_M); + + m_r = (m_r + pop) % m_N; + + if (pop) + { + r = m_r; + j = m_N-1; + while(r < m_N) + { + m_x[j--] = m_fifo[r++]; + } + r = 0; + while(j >= 0) + { + m_x[j--] = m_fifo[r++]; + } + } + + return FirComplex::processReal(m_coeff.col(index)); + } + +private: + uint32_t m_M; + uint32_t m_N; + uint32_t m_r; + uint32_t m_w; + RMat m_coeff; + CVec m_fifo; +}; + +class DownSampler : public FirComplex +{ +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) + { + 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; + ComplexScalar res(0,0); + + j = 0; + for (i=0; i < len; i++) + { + m_pFir[m_currStage].feed(src(i)); + res += m_pFir[m_currStage].processReal(m_pCoeff[m_currStage]); + m_currStage--; + if (m_currStage >= m_M) + { + dst(j++) = res; + res = ComplexScalar(0,0); + m_currStage = m_M-1; + } + + } + return j; + } + +private: + FirComplex *m_pFir; + RVec *m_pCoeff; + uint32_t m_M; + uint32_t m_currStage; + +}; } // Radio::Interpolation } // ::Radio