summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include-gpl/dsp/interpolator.h8
-rw-r--r--include-gpl/dsp/inthalfbandfilter.h2
-rw-r--r--plugins/demod/nfm/nfmdemod.cpp6
-rw-r--r--plugins/demod/tetra/tetrademod.cpp4
-rw-r--r--sdrbase/dsp/interpolator.cpp92
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;
}
}