diff options
author | Christian Daniel <cd@maintech.de> | 2013-08-07 23:23:25 +0200 |
---|---|---|
committer | Christian Daniel <cd@maintech.de> | 2013-08-07 23:23:25 +0200 |
commit | fb090cdfa91ae3ead3d23969d4fad3aab7caa8b1 (patch) | |
tree | 64a72c907d1da9e89674578249989be1d240f140 | |
parent | 37e6f6ff29f34d7dda7450ed41ef677d7a083eb5 (diff) |
improve interpolator
-rw-r--r-- | include-gpl/dsp/interpolator.h | 8 | ||||
-rw-r--r-- | include-gpl/dsp/inthalfbandfilter.h | 2 | ||||
-rw-r--r-- | plugins/demod/nfm/nfmdemod.cpp | 6 | ||||
-rw-r--r-- | plugins/demod/tetra/tetrademod.cpp | 4 | ||||
-rw-r--r-- | sdrbase/dsp/interpolator.cpp | 92 |
5 files changed, 68 insertions, 44 deletions
diff --git a/include-gpl/dsp/interpolator.h b/include-gpl/dsp/interpolator.h index 9aa86a0..bdf538e 100644 --- a/include-gpl/dsp/interpolator.h +++ b/include-gpl/dsp/interpolator.h @@ -8,7 +8,7 @@ class SDRANGELOVE_API Interpolator { public: Interpolator(); - void create(int nTaps, int phaseSteps, double sampleRate, double cutoff); + void create(int phaseSteps, double sampleRate, double cutoff); bool interpolate(Real* distance, const Complex& next, bool* consumed, Complex* result) { @@ -39,7 +39,7 @@ private: { m_ptr--; if(m_ptr < 0) - m_ptr = m_nTaps; + m_ptr = m_nTaps - 1; m_samples[m_ptr] = next; } @@ -53,9 +53,7 @@ private: for(int i = 0; i < m_nTaps; i++) { rAcc += *coeff * m_samples[sample].real(); iAcc += *coeff * m_samples[sample].imag(); - sample++; - if(sample >= m_nTaps) - sample = 0; + sample = (sample + 1) % m_nTaps; coeff++; } *result = Complex(rAcc, iAcc); diff --git a/include-gpl/dsp/inthalfbandfilter.h b/include-gpl/dsp/inthalfbandfilter.h index 37c4519..ccc1bfa 100644 --- a/include-gpl/dsp/inthalfbandfilter.h +++ b/include-gpl/dsp/inthalfbandfilter.h @@ -10,7 +10,7 @@ /* * supported filter orders: 64, 48, 32 */ -#define HB_FILTERORDER 48 +#define HB_FILTERORDER 32 #define HB_SHIFT 14 class SDRANGELOVE_API IntHalfbandFilter { diff --git a/plugins/demod/nfm/nfmdemod.cpp b/plugins/demod/nfm/nfmdemod.cpp index c6179ab..6330a16 100644 --- a/plugins/demod/nfm/nfmdemod.cpp +++ b/plugins/demod/nfm/nfmdemod.cpp @@ -35,7 +35,7 @@ NFMDemod::NFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) : m_squelchLevel *= m_squelchLevel; m_nco.setFreq(m_frequency, m_sampleRate); - m_interpolator.create(1, 32, 32 * m_sampleRate, 12500); + m_interpolator.create(16, m_sampleRate, 12500); m_sampleDistanceRemain = (Real)m_sampleRate / 44100.0; m_lowpass.create(21, 44100, 3000); @@ -123,7 +123,7 @@ bool NFMDemod::handleMessage(Message* cmd) qDebug("%d samples/sec, %lld Hz offset", signal->getSampleRate(), signal->getFrequencyOffset()); m_sampleRate = signal->getSampleRate(); m_nco.setFreq(-signal->getFrequencyOffset(), m_sampleRate); - m_interpolator.create(25, 32, 32 * m_sampleRate, m_rfBandwidth / 2.0); + m_interpolator.create(16, m_sampleRate, m_rfBandwidth / 2.1); m_sampleDistanceRemain = m_sampleRate / 44100.0; m_squelchState = 0; cmd->completed(); @@ -131,7 +131,7 @@ bool NFMDemod::handleMessage(Message* cmd) } else if(cmd->id() == MsgConfigureNFMDemod::ID()) { MsgConfigureNFMDemod* cfg = (MsgConfigureNFMDemod*)cmd; m_rfBandwidth = cfg->getRFBandwidth(); - m_interpolator.create(25, 32, 32 * m_sampleRate, m_rfBandwidth / 2.0); + m_interpolator.create(16, m_sampleRate, m_rfBandwidth / 2.1); m_lowpass.create(21, 44100, cfg->getAFBandwidth()); m_squelchLevel = pow(10.0, cfg->getSquelch() / 20.0); m_squelchLevel *= m_squelchLevel; diff --git a/plugins/demod/tetra/tetrademod.cpp b/plugins/demod/tetra/tetrademod.cpp index 4cf8ea1..f26810a 100644 --- a/plugins/demod/tetra/tetrademod.cpp +++ b/plugins/demod/tetra/tetrademod.cpp @@ -30,7 +30,7 @@ TetraDemod::TetraDemod(SampleSink* sampleSink) : m_frequency = 0; m_nco.setFreq(m_frequency, m_sampleRate); - m_interpolator.create(1, 32, 32 * m_sampleRate, 36000); + m_interpolator.create(32, 32 * m_sampleRate, 36000); m_sampleDistanceRemain = (Real)m_sampleRate / 36000.0; } @@ -87,7 +87,7 @@ bool TetraDemod::handleMessage(Message* cmd) qDebug("%d samples/sec, %lld Hz offset", signal->getSampleRate(), signal->getFrequencyOffset()); m_sampleRate = signal->getSampleRate(); m_nco.setFreq(-signal->getFrequencyOffset(), m_sampleRate); - m_interpolator.create(51, 32, 32 * m_sampleRate, 25000 / 2); + m_interpolator.create(32, m_sampleRate, 25000 / 2); m_sampleDistanceRemain = m_sampleRate / 36000.0; cmd->completed(); return true; diff --git a/sdrbase/dsp/interpolator.cpp b/sdrbase/dsp/interpolator.cpp index 629240c..ee441c4 100644 --- a/sdrbase/dsp/interpolator.cpp +++ b/sdrbase/dsp/interpolator.cpp @@ -1,56 +1,82 @@ #define _USE_MATH_DEFINES +#include <stdio.h> #include <math.h> #include <vector> #include "dsp/interpolator.h" +static std::vector<Real> createPolyphaseLowPass( + int phaseSteps, + double gain, + double sampleRateHz, + double cutoffFreqHz, + double transitionWidthHz, + double oobAttenuationdB) +{ + int ntaps = (int)(oobAttenuationdB * sampleRateHz / (22.0 * transitionWidthHz)); + if((ntaps % 2) == 0) + ntaps++; + ntaps *= phaseSteps; + + std::vector<float> taps(ntaps); + std::vector<float> window(ntaps); + + for(int n = 0; n < ntaps; n++) + window[n] = 0.54 - 0.46 * cos ((2 * M_PI * n) / (ntaps - 1)); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * cutoffFreqHz / sampleRateHz; + for(int n = -M; n <= M; n++) { + if(n == 0) taps[n + M] = fwT0 / M_PI * window[n + M]; + else taps[n + M] = sin (n * fwT0) / (n * M_PI) * window[n + M]; + } + + double max = taps[0 + M]; + for(int n = 1; n <= M; n++) + max += 2.0 * taps[n + M]; + + gain /= max; + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; +} + Interpolator::Interpolator() { } -void Interpolator::create(int nTaps, int phaseSteps, double sampleRate, double cutoff) +void Interpolator::create(int phaseSteps, double sampleRate, double cutoff) { - double wc = 2.0 * M_PI * cutoff; - double Wc = wc / sampleRate; - int numTaps = nTaps * phaseSteps; - int i; - Real sum; - - // make room - m_samples.resize(nTaps * 2); - for(int i = 0; i < nTaps; i++) - m_samples[i] = 0; + std::vector<Real> taps = createPolyphaseLowPass( + phaseSteps, // number of polyphases + 1.0, // gain + phaseSteps * sampleRate, // sampling frequency + cutoff, // hz beginning of transition band + sampleRate / 5.0, // hz width of transition band + 20.0); // out of band attenuation + + // init state m_ptr = 0; - m_nTaps = nTaps; + m_nTaps = taps.size() / phaseSteps; m_phaseSteps = phaseSteps; - m_taps.resize(numTaps); - - std::vector<Real> taps; - taps.resize(numTaps); - - // generate Sinc filter core - for(i = 0; i < numTaps; i++) { - if(i == (numTaps - 1) / 2) - taps[i] = Wc / M_PI; - else - taps[i] = sin(((double)i - ((double)numTaps - 1.0) / 2.0) * Wc) / (((double)i - ((double)numTaps - 1.0) / 2.0) * M_PI); - } - - // apply Hamming window - for(i = 0; i < numTaps; i++) - taps[i] *= 0.54 + 0.46 * cos((2.0 * M_PI * ((double)i - ((double)numTaps - 1.0) / 2.0)) / (double)numTaps); + m_taps.resize(taps.size()); + m_samples.resize(m_nTaps); + for(int i = 0; i < m_nTaps; i++) + m_samples[i] = 0; // copy to filter taps for(int phase = 0; phase < phaseSteps; phase++) { - for(int i = 0; i < nTaps; i++) - m_taps[phase * nTaps + i] = taps[i* phaseSteps + phase]; + for(int i = 0; i < m_nTaps; i++) + m_taps[phase * m_nTaps + i] = taps[i * phaseSteps + phase]; } // normalize phase filters for(int phase = 0; phase < phaseSteps; phase++) { - sum = 0; - for(i = phase * nTaps; i < phase * nTaps + nTaps; i++) + Real sum = 0; + for(int i = phase * m_nTaps; i < phase * m_nTaps + m_nTaps; i++) sum += m_taps[i]; - for(i = phase * nTaps; i < phase * nTaps + nTaps; i++) + for(int i = phase * m_nTaps; i < phase * m_nTaps + m_nTaps; i++) m_taps[i] /= sum; } } |