mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-04-05 02:58:37 -04:00
Corrected Highpass and Bandpass filters normalization. Implements #642
This commit is contained in:
parent
71f96aded6
commit
ae60808de8
@ -189,7 +189,6 @@ void AMDemodSink::processOneSample(Complex &ci)
|
||||
if (m_settings.m_bandpassEnable)
|
||||
{
|
||||
demod = m_bandpass.filter(demod);
|
||||
demod /= 301.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -121,7 +121,7 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
|
||||
if (m_settings.m_deltaSquelch)
|
||||
{
|
||||
if (m_afSquelch.analyze(demod * m_discriCompensation))
|
||||
if (m_afSquelch.analyze(demod))
|
||||
{
|
||||
m_afSquelchOpen = m_afSquelch.evaluate(); // ? m_squelchGate + m_squelchDecay : 0;
|
||||
|
||||
@ -132,7 +132,7 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
|
||||
if (m_afSquelchOpen)
|
||||
{
|
||||
m_squelchDelayLine.write(demod * m_discriCompensation);
|
||||
m_squelchDelayLine.write(demod);
|
||||
|
||||
if (m_squelchCount < 2*m_squelchGate) {
|
||||
m_squelchCount++;
|
||||
@ -159,7 +159,7 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_squelchDelayLine.write(demod * m_discriCompensation);
|
||||
m_squelchDelayLine.write(demod);
|
||||
|
||||
if (m_squelchCount < 2*m_squelchGate) {
|
||||
m_squelchCount++;
|
||||
@ -179,7 +179,7 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
{
|
||||
if (m_settings.m_ctcssOn)
|
||||
{
|
||||
Real ctcss_sample = m_ctcssLowpass.filter(demod * m_discriCompensation);
|
||||
Real ctcss_sample = m_ctcssLowpass.filter(demod);
|
||||
|
||||
if ((m_sampleCount & 7) == 7) // decimate 48k -> 6k
|
||||
{
|
||||
@ -224,7 +224,7 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
else
|
||||
{
|
||||
if (m_settings.m_highPass) {
|
||||
sample = m_bandpass.filter(m_squelchDelayLine.readBack(m_squelchGate)) * m_settings.m_volume;
|
||||
sample = m_bandpass.filter(m_squelchDelayLine.readBack(m_squelchGate)) * m_settings.m_volume * 301.0f;
|
||||
} else {
|
||||
sample = m_lowpass.filter(m_squelchDelayLine.readBack(m_squelchGate)) * m_settings.m_volume * 301.0f;
|
||||
}
|
||||
@ -375,17 +375,13 @@ void NFMDemodSink::applyAudioSampleRate(unsigned int sampleRate)
|
||||
|
||||
if (sampleRate < 16000) {
|
||||
m_afSquelch.setCoefficients(sampleRate/2000, 600, sampleRate, 200, 0, afSqTones_lowrate); // 0.5ms test period, 300ms average span, audio SR, 100ms attack, no decay
|
||||
|
||||
} else {
|
||||
m_afSquelch.setCoefficients(sampleRate/2000, 600, sampleRate, 200, 0, afSqTones); // 0.5ms test period, 300ms average span, audio SR, 100ms attack, no decay
|
||||
}
|
||||
|
||||
m_discriCompensation = (sampleRate/48000.0f);
|
||||
m_discriCompensation *= sqrt(m_discriCompensation);
|
||||
|
||||
m_phaseDiscri.setFMScaling((8.0f*sampleRate) / static_cast<float>(m_settings.m_fmDeviation)); // integrate 4x factor
|
||||
m_audioFifo.setSize(sampleRate);
|
||||
m_squelchDelayLine.resize(sampleRate/2);
|
||||
|
||||
m_audioSampleRate = sampleRate;
|
||||
}
|
||||
}
|
||||
|
@ -104,8 +104,6 @@ private:
|
||||
uint m_audioBufferFill;
|
||||
AudioFifo m_audioFifo;
|
||||
|
||||
float m_discriCompensation; //!< compensation factor that depends on audio rate (1 for 48 kS/s)
|
||||
|
||||
NCO m_nco;
|
||||
Interpolator m_interpolator;
|
||||
Real m_interpolatorDistance;
|
||||
|
@ -256,7 +256,6 @@ void UDPSinkSink::feed(const SampleVector::const_iterator& begin, const SampleVe
|
||||
{
|
||||
double demodf = sqrt(inMagSq);
|
||||
demodf = m_bandpass.filter(demodf);
|
||||
demodf /= 301.0;
|
||||
Real amplitude = demodf * agcFactor * m_settings.m_gain;
|
||||
FixReal demod = (FixReal) amplitude;
|
||||
udpWriteMono(demod);
|
||||
|
@ -134,14 +134,11 @@ void NFMModSource::modulateSample()
|
||||
calculateLevel(t);
|
||||
m_audioBufferFill++;
|
||||
|
||||
if (m_settings.m_ctcssOn)
|
||||
{
|
||||
m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * (0.85f * m_bandpass.filter(t) + 0.15f * 189.0f * m_ctcssNco.next()) * (M_PI / 189.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 378 = 302 * 1.25; 302 = number of filter taps (established experimentally) and 189 = 378/2 for 2*PI
|
||||
m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * m_bandpass.filter(t) * (M_PI / 189.0f);
|
||||
// 0.625 = 1/1.25 (heuristic)
|
||||
if (m_settings.m_ctcssOn) {
|
||||
m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * (0.85f * m_bandpass.filter(t) + 0.15f * 0.625f * m_ctcssNco.next()) * (M_PI / 0.625f);
|
||||
} else {
|
||||
m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * m_bandpass.filter(t) * (M_PI / 0.625f);
|
||||
}
|
||||
|
||||
// limit phasor range to ]-pi,pi]
|
||||
@ -368,4 +365,4 @@ void NFMModSource::applyChannelSettings(int channelSampleRate, int channelFreque
|
||||
|
||||
m_channelSampleRate = channelSampleRate;
|
||||
m_channelFrequencyOffset = channelFrequencyOffset;
|
||||
}
|
||||
}
|
||||
|
@ -23,27 +23,34 @@ public:
|
||||
int i;
|
||||
|
||||
// check constraints
|
||||
if(!(nTaps & 1)) {
|
||||
if (!(nTaps & 1))
|
||||
{
|
||||
qDebug("Bandpass filter has to have an odd number of taps");
|
||||
nTaps++;
|
||||
}
|
||||
|
||||
// make room
|
||||
m_samples.resize(nTaps);
|
||||
for(int i = 0; i < nTaps; i++)
|
||||
|
||||
for (int i = 0; i < nTaps; i++) {
|
||||
m_samples[i] = 0;
|
||||
}
|
||||
|
||||
m_ptr = 0;
|
||||
m_taps.resize(nTaps / 2 + 1);
|
||||
taps_lp.resize(nTaps / 2 + 1);
|
||||
taps_hp.resize(nTaps / 2 + 1);
|
||||
|
||||
// generate Sinc filter core
|
||||
for(i = 0; i < nTaps / 2 + 1; i++) {
|
||||
if(i == (nTaps - 1) / 2) {
|
||||
for (i = 0; i < nTaps / 2 + 1; i++)
|
||||
{
|
||||
if (i == (nTaps - 1) / 2)
|
||||
{
|
||||
taps_lp[i] = Wch / M_PI;
|
||||
taps_hp[i] = -(Wcl / M_PI);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
taps_lp[i] = sin(((double)i - ((double)nTaps - 1.0) / 2.0) * Wch) / (((double)i - ((double)nTaps - 1.0) / 2.0) * M_PI);
|
||||
taps_hp[i] = -sin(((double)i - ((double)nTaps - 1.0) / 2.0) * Wcl) / (((double)i - ((double)nTaps - 1.0) / 2.0) * M_PI);
|
||||
}
|
||||
@ -52,7 +59,8 @@ public:
|
||||
taps_hp[(nTaps - 1) / 2] += 1;
|
||||
|
||||
// apply Hamming window and combine lowpass and highpass
|
||||
for(i = 0; i < nTaps / 2 + 1; i++) {
|
||||
for (i = 0; i < nTaps / 2 + 1; i++)
|
||||
{
|
||||
taps_lp[i] *= 0.54 + 0.46 * cos((2.0 * M_PI * ((double)i - ((double)nTaps - 1.0) / 2.0)) / (double)nTaps);
|
||||
taps_hp[i] *= 0.54 + 0.46 * cos((2.0 * M_PI * ((double)i - ((double)nTaps - 1.0) / 2.0)) / (double)nTaps);
|
||||
m_taps[i] = -(taps_lp[i]+taps_hp[i]);
|
||||
@ -63,13 +71,13 @@ public:
|
||||
// normalize
|
||||
Real sum = 0;
|
||||
|
||||
for(i = 0; i < (int)m_taps.size() - 1; i++) {
|
||||
for (i = 0; i < (int)m_taps.size() - 1; i++) {
|
||||
sum += m_taps[i] * 2;
|
||||
}
|
||||
|
||||
sum += m_taps[i];
|
||||
sum += m_taps[i] - 1;
|
||||
|
||||
for(i = 0; i < (int)m_taps.size(); i++) {
|
||||
for (i = 0; i < (int)m_taps.size(); i++) {
|
||||
m_taps[i] /= sum;
|
||||
}
|
||||
}
|
||||
@ -84,8 +92,7 @@ public:
|
||||
m_samples[m_ptr] = sample;
|
||||
size = m_samples.size(); // Valgrind optim (2)
|
||||
|
||||
while(b < 0)
|
||||
{
|
||||
while (b < 0) {
|
||||
b += size;
|
||||
}
|
||||
|
||||
@ -96,15 +103,13 @@ public:
|
||||
acc += (m_samples[a] + m_samples[b]) * m_taps[i];
|
||||
a++;
|
||||
|
||||
while (a >= size)
|
||||
{
|
||||
while (a >= size) {
|
||||
a -= size;
|
||||
}
|
||||
|
||||
b--;
|
||||
|
||||
while(b < 0)
|
||||
{
|
||||
while(b < 0) {
|
||||
b += size;
|
||||
}
|
||||
}
|
||||
@ -113,8 +118,7 @@ public:
|
||||
|
||||
m_ptr++;
|
||||
|
||||
while (m_ptr >= size)
|
||||
{
|
||||
while (m_ptr >= size) {
|
||||
m_ptr -= size;
|
||||
}
|
||||
|
||||
|
@ -16,39 +16,51 @@ public:
|
||||
int i;
|
||||
|
||||
// check constraints
|
||||
if(!(nTaps & 1)) {
|
||||
if (!(nTaps & 1))
|
||||
{
|
||||
qDebug("Highpass filter has to have an odd number of taps");
|
||||
nTaps++;
|
||||
}
|
||||
|
||||
// make room
|
||||
m_samples.resize(nTaps);
|
||||
for(int i = 0; i < nTaps; i++)
|
||||
|
||||
for (int i = 0; i < nTaps; i++) {
|
||||
m_samples[i] = 0;
|
||||
}
|
||||
|
||||
m_ptr = 0;
|
||||
m_taps.resize(nTaps / 2 + 1);
|
||||
|
||||
// generate Sinc filter core for lowpass but inverting every other tap for highpass keeping center tap
|
||||
for(i = 0; i < nTaps / 2 + 1; i++) {
|
||||
if(i == (nTaps - 1) / 2)
|
||||
for (i = 0; i < nTaps / 2 + 1; i++)
|
||||
{
|
||||
if (i == (nTaps - 1) / 2) {
|
||||
m_taps[i] = -(Wc / M_PI);
|
||||
else
|
||||
} else {
|
||||
m_taps[i] = -sin(((double)i - ((double)nTaps - 1.0) / 2.0) * Wc) / (((double)i - ((double)nTaps - 1.0) / 2.0) * M_PI);
|
||||
}
|
||||
}
|
||||
|
||||
m_taps[(nTaps - 1) / 2] += 1;
|
||||
|
||||
// apply Hamming window
|
||||
for(i = 0; i < nTaps / 2 + 1; i++)
|
||||
for (i = 0; i < nTaps / 2 + 1; i++) {
|
||||
m_taps[i] *= 0.54 + 0.46 * cos((2.0 * M_PI * ((double)i - ((double)nTaps - 1.0) / 2.0)) / (double)nTaps);
|
||||
}
|
||||
|
||||
// normalize
|
||||
Real sum = 0;
|
||||
for(i = 0; i < (int)m_taps.size() - 1; i++)
|
||||
|
||||
for (i = 0; i < (int)m_taps.size() - 1; i++) {
|
||||
sum += m_taps[i] * 2;
|
||||
sum += m_taps[i];
|
||||
for(i = 0; i < (int)m_taps.size(); i++)
|
||||
}
|
||||
|
||||
sum += m_taps[i] - 1;
|
||||
|
||||
for (i = 0; i < (int)m_taps.size(); i++) {
|
||||
m_taps[i] /= sum;
|
||||
}
|
||||
}
|
||||
|
||||
Type filter(Type sample)
|
||||
@ -61,8 +73,7 @@ public:
|
||||
m_samples[m_ptr] = sample;
|
||||
size = m_samples.size(); // Valgrind optim (2)
|
||||
|
||||
while(b < 0)
|
||||
{
|
||||
while (b < 0) {
|
||||
b += size;
|
||||
}
|
||||
|
||||
@ -73,15 +84,13 @@ public:
|
||||
acc += (m_samples[a] + m_samples[b]) * m_taps[i];
|
||||
a++;
|
||||
|
||||
while (a >= size)
|
||||
{
|
||||
while (a >= size) {
|
||||
a -= size;
|
||||
}
|
||||
|
||||
b--;
|
||||
|
||||
while (b < 0)
|
||||
{
|
||||
while (b < 0) {
|
||||
b += size;
|
||||
}
|
||||
}
|
||||
@ -89,8 +98,7 @@ public:
|
||||
acc += m_samples[a] * m_taps[i];
|
||||
m_ptr++;
|
||||
|
||||
while (m_ptr >= size)
|
||||
{
|
||||
while (m_ptr >= size) {
|
||||
m_ptr -= size;
|
||||
}
|
||||
|
||||
|
@ -16,37 +16,49 @@ public:
|
||||
int i;
|
||||
|
||||
// check constraints
|
||||
if(!(nTaps & 1)) {
|
||||
if (!(nTaps & 1))
|
||||
{
|
||||
qDebug("Lowpass filter has to have an odd number of taps");
|
||||
nTaps++;
|
||||
}
|
||||
|
||||
// make room
|
||||
m_samples.resize(nTaps);
|
||||
for(int i = 0; i < nTaps; i++)
|
||||
|
||||
for (int i = 0; i < nTaps; i++) {
|
||||
m_samples[i] = 0;
|
||||
}
|
||||
|
||||
m_ptr = 0;
|
||||
m_taps.resize(nTaps / 2 + 1);
|
||||
|
||||
// generate Sinc filter core
|
||||
for(i = 0; i < nTaps / 2 + 1; i++) {
|
||||
if(i == (nTaps - 1) / 2)
|
||||
for (i = 0; i < nTaps / 2 + 1; i++)
|
||||
{
|
||||
if(i == (nTaps - 1) / 2) {
|
||||
m_taps[i] = Wc / M_PI;
|
||||
else
|
||||
} else {
|
||||
m_taps[i] = sin(((double)i - ((double)nTaps - 1.0) / 2.0) * Wc) / (((double)i - ((double)nTaps - 1.0) / 2.0) * M_PI);
|
||||
}
|
||||
}
|
||||
|
||||
// apply Hamming window
|
||||
for(i = 0; i < nTaps / 2 + 1; i++)
|
||||
for (i = 0; i < nTaps / 2 + 1; i++) {
|
||||
m_taps[i] *= 0.54 + 0.46 * cos((2.0 * M_PI * ((double)i - ((double)nTaps - 1.0) / 2.0)) / (double)nTaps);
|
||||
}
|
||||
|
||||
// normalize
|
||||
Real sum = 0;
|
||||
for(i = 0; i < (int)m_taps.size() - 1; i++)
|
||||
|
||||
for (i = 0; i < (int)m_taps.size() - 1; i++) {
|
||||
sum += m_taps[i] * 2;
|
||||
}
|
||||
|
||||
sum += m_taps[i];
|
||||
for(i = 0; i < (int)m_taps.size(); i++)
|
||||
|
||||
for (i = 0; i < (int)m_taps.size(); i++) {
|
||||
m_taps[i] /= sum;
|
||||
}
|
||||
}
|
||||
|
||||
Type filter(Type sample)
|
||||
@ -59,8 +71,7 @@ public:
|
||||
m_samples[m_ptr] = sample;
|
||||
size = m_samples.size(); // Valgrind optim (2)
|
||||
|
||||
while (b < 0)
|
||||
{
|
||||
while (b < 0) {
|
||||
b += size;
|
||||
}
|
||||
|
||||
@ -71,15 +82,13 @@ public:
|
||||
acc += (m_samples[a] + m_samples[b]) * m_taps[i];
|
||||
a++;
|
||||
|
||||
while (a >= size)
|
||||
{
|
||||
while (a >= size) {
|
||||
a -= size;
|
||||
}
|
||||
|
||||
b--;
|
||||
|
||||
while(b < 0)
|
||||
{
|
||||
while(b < 0) {
|
||||
b += size;
|
||||
}
|
||||
}
|
||||
@ -87,8 +96,7 @@ public:
|
||||
acc += m_samples[a] * m_taps[i];
|
||||
m_ptr++;
|
||||
|
||||
while(m_ptr >= size)
|
||||
{
|
||||
while(m_ptr >= size) {
|
||||
m_ptr -= size;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user