#ifndef _INTERPOLATION_FARROW_HPP_ #define _INTERPOLATION_FARROW_HPP_ #pragma once #include #include #include #include #include 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 Processor::Block { typedef struct _ml_farrow_coef_hdr_t { uint32_t M; uint32_t N; } ml_farrow_coef_hdr_t; public: Farrow(TimingGenerator &timingGenerator, uint32_t M=0, uint32_t N=0) : Processor::Block(1, 1) , m_timingGenerator(timingGenerator) , m_fir(N) , m_M(M) , m_N(N) , m_w(0) , m_r(0) , m_coeff(N, M) , m_b(M) , m_h(M) { init(M, N); } ~Farrow() { } void init(uint32_t M, uint32_t N) { m_fir.setNumTaps(N); m_M = M; m_N = N; m_coeff.resize(N, M); m_b.resize(M); m_h.resize(M); } void process() { // Get buffers auto buf_in = buffer_in(); auto buf_out = buffer_out(); // Process input while(buf_out->free()) { size_t adv = m_timingGenerator.getAdv(); radio_float_t mu = m_timingGenerator.getMu(); if (buf_in->len() < adv) { break; } if (adv != 0) { m_fir.feed(*buf_in, adv); // Partial filter responses for (int i=0; i < m_M; i++) { m_h[i] = m_fir.processReal(column(m_coeff, i)); } } // Combine ComplexScalar yout = horner(mu); // Process timing generator bool is_sample = m_timingGenerator.process(yout); if (is_sample) { buf_out->write(&yout, 1); } } } void load(const char *pFilename) { int i, j; FILE *pFile; ml_farrow_coef_hdr_t hdr; RealScalar *pCoeff; pFile = fopen(pFilename, "rb"); if (!pFile) { printf("Can't open %s\n", pFilename); return; } if (EOF == fread(&hdr, sizeof(hdr), 1, pFile)) { printf("Can't read %s\n", pFilename); return; } init(hdr.M, hdr.N); pCoeff = new RealScalar[hdr.M*hdr.N]; for (i=0; i < (int)hdr.M; i++) { if (EOF == fread(pCoeff, sizeof(RealScalar), hdr.N, pFile)) { printf("Can't read %s\n", pFilename); return; } for (j=0; j < hdr.N; j++) { m_coeff(j,i) = pCoeff[j]; } } printf("Farrow filter coefficients loaded (M=%d, N=%d)\n", m_M, m_N); delete [] pCoeff; fclose(pFile); } private: TimingGenerator &m_timingGenerator; FirComplex m_fir; uint32_t m_M; uint32_t m_N; uint32_t m_r; uint32_t m_w; RMat m_coeff; CVec m_b; CVec m_h; ComplexScalar horner(RealScalar mu) { uint32_t i; m_b[0] = m_h[0]; for (i=1; i < m_M; i++) { m_b[i] = ComplexScalar(m_h[i].real() + m_b[i-1].real() * mu, m_h[i].imag() + m_b[i-1].imag() * mu); } return m_b[m_M-1]; } }; } // Radio::Interpolation } // ::Radio #endif // _INTERPOLATION_FARROW_HPP_