diff --git a/CMakeLists.txt b/CMakeLists.txt index 2acfbbd9b..36d90c533 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,6 +212,7 @@ set(sdrbase_HEADERS sdrbase/dsp/interpolator.h sdrbase/dsp/hbfiltertraits.h sdrbase/dsp/inthalfbandfilter.h + sdrbase/dsp/inthalfbandfilterdb.h sdrbase/dsp/kissfft.h sdrbase/dsp/kissengine.h sdrbase/dsp/lowpass.h diff --git a/sdrbase/dsp/inthalfbandfilter.h b/sdrbase/dsp/inthalfbandfilter.h index 3a45ba65f..b362bd6a9 100644 --- a/sdrbase/dsp/inthalfbandfilter.h +++ b/sdrbase/dsp/inthalfbandfilter.h @@ -1,3 +1,20 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 F4EXB // +// written by Edouard Griffiths // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + #ifndef INCLUDE_INTHALFBANDFILTER_H #define INCLUDE_INTHALFBANDFILTER_H @@ -86,51 +103,6 @@ public: } } - // upsample by 2, return center part of original spectrum - double buffer variant - bool workInterpolateCenterDB(Sample* sampleIn, Sample *SampleOut) - { - switch(m_state) - { - case 0: - // insert sample into ring-buffer - m_samplesDB[m_ptrDB][0] = 0; - m_samplesDB[m_ptrDB][1] = 0; - m_samplesDB[m_ptrDB + m_sizeDB][0] = 0; - m_samplesDB[m_ptrDB + m_sizeDB][1] = 0; - - // save result - doFIRDB(SampleOut); - - // advance write-pointer - m_ptrDB = (m_ptrDB + 1) % m_sizeDB; - - // next state - m_state = 1; - - // tell caller we didn't consume the sample - return false; - - default: - // insert sample into ring-buffer - m_samplesDB[m_ptrDB][0] = sampleIn->real(); - m_samplesDB[m_ptrDB][1] = sampleIn->imag(); - m_samplesDB[m_ptrDB + m_sizeDB][0] = sampleIn->real(); - m_samplesDB[m_ptrDB + m_sizeDB][1] = sampleIn->imag(); - - // save result - doFIRDB(SampleOut); - - // advance write-pointer - m_ptrDB = (m_ptrDB + 1) % m_sizeDB; - - // next state - m_state = 0; - - // tell caller we consumed the sample - return true; - } - } - bool workDecimateCenter(qint32 *x, qint32 *y) { // insert sample into ring-buffer @@ -356,99 +328,6 @@ public: } } - // upsample by 2, from lower half of original spectrum - double buffer variant - bool workInterpolateLowerHalfDB(Sample* sampleIn, Sample *sampleOut) - { - Sample s; - - switch(m_state) - { - case 0: - // insert sample into ring-buffer - m_samplesDB[m_ptrDB][0] = 0; - m_samplesDB[m_ptrDB][1] = 0; - m_samplesDB[m_ptrDB + m_sizeDB][0] = 0; - m_samplesDB[m_ptrDB + m_sizeDB][1] = 0; - - // save result - doFIRDB(&s); - sampleOut->setReal(s.imag()); - sampleOut->setImag(-s.real()); - - // advance write-pointer - m_ptrDB = (m_ptrDB + 1) % m_sizeDB; - - // next state - m_state = 1; - - // tell caller we didn't consume the sample - return false; - - case 1: - // insert sample into ring-buffer - m_samplesDB[m_ptrDB][0] = sampleIn->real(); - m_samplesDB[m_ptrDB][1] = sampleIn->imag(); - m_samplesDB[m_ptrDB + m_sizeDB][0] = sampleIn->real(); - m_samplesDB[m_ptrDB + m_sizeDB][1] = sampleIn->imag(); - - // save result - doFIRDB(&s); - sampleOut->setReal(-s.real()); - sampleOut->setImag(-s.imag()); - - // advance write-pointer - m_ptrDB = (m_ptrDB + 1) % m_sizeDB; - - // next state - m_state = 2; - - // tell caller we consumed the sample - return true; - - case 2: - // insert sample into ring-buffer - m_samplesDB[m_ptrDB][0] = 0; - m_samplesDB[m_ptrDB][1] = 0; - m_samplesDB[m_ptrDB + m_sizeDB][0] = 0; - m_samplesDB[m_ptrDB + m_sizeDB][1] = 0; - - // save result - doFIRDB(&s); - sampleOut->setReal(-s.imag()); - sampleOut->setImag(s.real()); - - // advance write-pointer - m_ptrDB = (m_ptrDB + 1) % m_sizeDB; - - // next state - m_state = 3; - - // tell caller we didn't consume the sample - return false; - - default: - // insert sample into ring-buffer - m_samplesDB[m_ptrDB][0] = sampleIn->real(); - m_samplesDB[m_ptrDB][1] = sampleIn->imag(); - m_samplesDB[m_ptrDB + m_sizeDB][0] = sampleIn->real(); - m_samplesDB[m_ptrDB + m_sizeDB][1] = sampleIn->imag(); - - // save result - doFIRDB(&s); - sampleOut->setReal(s.real()); - sampleOut->setImag(s.imag()); - - // advance write-pointer - m_ptrDB = (m_ptrDB + 1) % m_sizeDB; - - // next state - m_state = 0; - - // tell caller we consumed the sample - return true; - } - } - // downsample by 2, return upper half of original spectrum bool workDecimateUpperHalf(Sample* sample) { @@ -603,99 +482,6 @@ public: } } - // upsample by 2, move original spectrum to upper half - double buffer variant - bool workInterpolateUpperHalfDB(Sample* sampleIn, Sample *sampleOut) - { - Sample s; - - switch(m_state) - { - case 0: - // insert sample into ring-buffer - m_samplesDB[m_ptrDB][0] = 0; - m_samplesDB[m_ptrDB][1] = 0; - m_samplesDB[m_ptrDB + m_sizeDB][0] = 0; - m_samplesDB[m_ptrDB + m_sizeDB][1] = 0; - - // save result - doFIRDB(&s); - sampleOut->setReal(-s.imag()); - sampleOut->setImag(s.real()); - - // advance write-pointer - m_ptrDB = (m_ptrDB + 1) % m_sizeDB; - - // next state - m_state = 1; - - // tell caller we didn't consume the sample - return false; - - case 1: - // insert sample into ring-buffer - m_samplesDB[m_ptrDB][0] = sampleIn->real(); - m_samplesDB[m_ptrDB][1] = sampleIn->imag(); - m_samplesDB[m_ptrDB + m_sizeDB][0] = sampleIn->real(); - m_samplesDB[m_ptrDB + m_sizeDB][1] = sampleIn->imag(); - - // save result - doFIRDB(&s); - sampleOut->setReal(-s.real()); - sampleOut->setImag(-s.imag()); - - // advance write-pointer - m_ptrDB = (m_ptrDB + 1) % m_sizeDB; - - // next state - m_state = 2; - - // tell caller we consumed the sample - return true; - - case 2: - // insert sample into ring-buffer - m_samplesDB[m_ptrDB][0] = 0; - m_samplesDB[m_ptrDB][1] = 0; - m_samplesDB[m_ptrDB + m_sizeDB][0] = 0; - m_samplesDB[m_ptrDB + m_sizeDB][1] = 0; - - // save result - doFIRDB(&s); - sampleOut->setReal(s.imag()); - sampleOut->setImag(-s.real()); - - // advance write-pointer - m_ptrDB = (m_ptrDB + 1) % m_sizeDB; - - // next state - m_state = 3; - - // tell caller we didn't consume the sample - return false; - - default: - // insert sample into ring-buffer - m_samplesDB[m_ptrDB][0] = sampleIn->real(); - m_samplesDB[m_ptrDB][1] = sampleIn->imag(); - m_samplesDB[m_ptrDB + m_sizeDB][0] = sampleIn->real(); - m_samplesDB[m_ptrDB + m_sizeDB][1] = sampleIn->imag(); - - // save result - doFIRDB(&s); - sampleOut->setReal(s.real()); - sampleOut->setImag(s.imag()); - - // advance write-pointer - m_ptrDB = (m_ptrDB + 1) % m_sizeDB; - - // next state - m_state = 0; - - // tell caller we consumed the sample - return true; - } - } - void myDecimate(const Sample* sample1, Sample* sample2) { m_samples[m_ptr][0] = sample1->real(); @@ -726,42 +512,14 @@ public: protected: qint32 m_samples[HBFIRFilterTraits::hbOrder + 1][2]; // Valgrind optim (from qint16) - qint32 m_samplesDB[2*(HBFIRFilterTraits::hbOrder - 1)][2]; // double buffer technique qint16 m_ptr; - int m_ptrDB; - int m_sizeDB; int m_state; - void doFIRDB(Sample* sample) - { - int a = m_ptrDB + m_sizeDB; // tip pointer - int b = m_ptrDB + 1; // tail pointer - qint32 iAcc = 0; - qint32 qAcc = 0; - - for (int i = 0; i < HBFIRFilterTraits::hbOrder / 4; i++) - { - iAcc += (m_samplesDB[a][0] + m_samplesDB[b][0]) * HBFIRFilterTraits::hbCoeffs[i]; - qAcc += (m_samplesDB[a][1] + m_samplesDB[b][1]) * HBFIRFilterTraits::hbCoeffs[i]; - a -= 2; - b += 2; - } - - iAcc += ((qint32)m_samplesDB[b-1][0]) << (HBFIRFilterTraits::hbShift - 1); - qAcc += ((qint32)m_samplesDB[b-1][1]) << (HBFIRFilterTraits::hbShift - 1); - - sample->setReal(iAcc >> HBFIRFilterTraits::hbShift -1); - sample->setImag(qAcc >> HBFIRFilterTraits::hbShift -1); - } - void doFIR(Sample* sample) { // init read-pointer -// int a = HBFIRFilterTraits::hbMod[m_ptr + 2 + 1]; // 0 + 1 -// int b = HBFIRFilterTraits::hbMod[m_ptr + 2 - 2]; //-1 - 1 - // ancient way: - int a = (m_ptr + 1) % (HBFIRFilterTraits::hbOrder + 1); - int b = (m_ptr + (HBFIRFilterTraits::hbOrder - 1)) % (HBFIRFilterTraits::hbOrder + 1); + int a = HBFIRFilterTraits::hbMod[m_ptr + 2 + 1]; // 0 + 1 + int b = HBFIRFilterTraits::hbMod[m_ptr + 2 - 2]; //-1 - 1 // go through samples in buffer qint32 iAcc = 0; @@ -776,16 +534,11 @@ protected: qAcc += (m_samples[a][1] + m_samples[b][1]) * HBFIRFilterTraits::hbCoeffs[i]; // update read-pointer -// a = HBFIRFilterTraits::hbMod[a + 2 + 2]; -// b = HBFIRFilterTraits::hbMod[b + 2 - 2]; - // ancient way: - a = (a + 2) % (HBFIRFilterTraits::hbOrder + 1); - b = (b + (HBFIRFilterTraits::hbOrder - 1)) % (HBFIRFilterTraits::hbOrder + 1); + a = HBFIRFilterTraits::hbMod[a + 2 + 2]; + b = HBFIRFilterTraits::hbMod[b + 2 - 2]; } -// a = HBFIRFilterTraits::hbMod[a + 2 - 1]; - // ancient way: - a = (a + HBFIRFilterTraits::hbOrder) % (HBFIRFilterTraits::hbOrder + 1); + a = HBFIRFilterTraits::hbMod[a + 2 - 1]; iAcc += ((qint32)m_samples[a][0] + 1) << (HBFIRFilterTraits::hbShift - 1); qAcc += ((qint32)m_samples[a][1] + 1) << (HBFIRFilterTraits::hbShift - 1); @@ -837,22 +590,13 @@ protected: template IntHalfbandFilter::IntHalfbandFilter() { - m_sizeDB = HBFIRFilterTraits::hbOrder - 1; - for (int i = 0; i < HBFIRFilterTraits::hbOrder + 1; i++) { m_samples[i][0] = 0; m_samples[i][1] = 0; - - if (i < m_sizeDB) - { - m_samplesDB[i][0] = 0; - m_samplesDB[i][1] = 0; - } } m_ptr = 0; - m_ptrDB = 0; m_state = 0; } diff --git a/sdrbase/dsp/inthalfbandfilterdb.h b/sdrbase/dsp/inthalfbandfilterdb.h new file mode 100644 index 000000000..751d7eca5 --- /dev/null +++ b/sdrbase/dsp/inthalfbandfilterdb.h @@ -0,0 +1,594 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 F4EXB // +// written by Edouard Griffiths // +// // +// Integer half-band FIR based interpolator and decimator // +// This is the double buffer variant // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_INTHALFBANDFILTER_DB_H +#define INCLUDE_INTHALFBANDFILTER_DB_H + +#include +#include "dsp/dsptypes.h" +#include "dsp/hbfiltertraits.h" +#include "util/export.h" + +template +class SDRANGEL_API IntHalfbandFilterDB { +public: + IntHalfbandFilterDB(); + + // downsample by 2, return center part of original spectrum + bool workDecimateCenter(Sample* sample) + { + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = sample->real(); + m_samplesDB[m_ptrDB][1] = sample->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sample->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sample->imag(); + + switch(m_state) + { + case 0: + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 1; + + // tell caller we don't have a new sample + return false; + + default: + // save result + doFIR(sample); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 0; + + // tell caller we have a new sample + return true; + } + } + + // upsample by 2, return center part of original spectrum - double buffer variant + bool workInterpolateCenter(Sample* sampleIn, Sample *SampleOut) + { + switch(m_state) + { + case 0: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = 0; + m_samplesDB[m_ptrDB][1] = 0; + m_samplesDB[m_ptrDB + m_sizeDB][0] = 0; + m_samplesDB[m_ptrDB + m_sizeDB][1] = 0; + + // save result + doFIR(SampleOut); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 1; + + // tell caller we didn't consume the sample + return false; + + default: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = sampleIn->real(); + m_samplesDB[m_ptrDB][1] = sampleIn->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sampleIn->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sampleIn->imag(); + + // save result + doFIR(SampleOut); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 0; + + // tell caller we consumed the sample + return true; + } + } + + bool workDecimateCenter(qint32 *x, qint32 *y) + { + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = *x; + m_samplesDB[m_ptrDB][1] = *y; + m_samplesDB[m_ptrDB + m_sizeDB][0] = *x; + m_samplesDB[m_ptrDB + m_sizeDB][1] = *y; + + switch(m_state) + { + case 0: + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 1; + + // tell caller we don't have a new sample + return false; + + default: + // save result + doFIR(x, y); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 0; + + // tell caller we have a new sample + return true; + } + } + + // downsample by 2, return lower half of original spectrum + bool workDecimateLowerHalf(Sample* sample) + { + switch(m_state) + { + case 0: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = -sample->imag(); + m_samplesDB[m_ptrDB][1] = sample->real(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = -sample->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sample->real(); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 1; + + // tell caller we don't have a new sample + return false; + + case 1: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = -sample->real(); + m_samplesDB[m_ptrDB][1] = -sample->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = -sample->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = -sample->imag(); + + // save result + doFIR(sample); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 2; + + // tell caller we have a new sample + return true; + + case 2: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = sample->imag(); + m_samplesDB[m_ptrDB][1] = -sample->real(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sample->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = -sample->real(); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 3; + + // tell caller we don't have a new sample + return false; + + default: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = sample->real(); + m_samplesDB[m_ptrDB][1] = sample->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sample->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sample->imag(); + + // save result + doFIR(sample); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 0; + + // tell caller we have a new sample + return true; + } + } + + // upsample by 2, from lower half of original spectrum - double buffer variant + bool workInterpolateLowerHalf(Sample* sampleIn, Sample *sampleOut) + { + Sample s; + + switch(m_state) + { + case 0: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = 0; + m_samplesDB[m_ptrDB][1] = 0; + m_samplesDB[m_ptrDB + m_sizeDB][0] = 0; + m_samplesDB[m_ptrDB + m_sizeDB][1] = 0; + + // save result + doFIR(&s); + sampleOut->setReal(s.imag()); + sampleOut->setImag(-s.real()); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 1; + + // tell caller we didn't consume the sample + return false; + + case 1: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = sampleIn->real(); + m_samplesDB[m_ptrDB][1] = sampleIn->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sampleIn->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sampleIn->imag(); + + // save result + doFIR(&s); + sampleOut->setReal(-s.real()); + sampleOut->setImag(-s.imag()); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 2; + + // tell caller we consumed the sample + return true; + + case 2: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = 0; + m_samplesDB[m_ptrDB][1] = 0; + m_samplesDB[m_ptrDB + m_sizeDB][0] = 0; + m_samplesDB[m_ptrDB + m_sizeDB][1] = 0; + + // save result + doFIR(&s); + sampleOut->setReal(-s.imag()); + sampleOut->setImag(s.real()); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 3; + + // tell caller we didn't consume the sample + return false; + + default: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = sampleIn->real(); + m_samplesDB[m_ptrDB][1] = sampleIn->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sampleIn->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sampleIn->imag(); + + // save result + doFIR(&s); + sampleOut->setReal(s.real()); + sampleOut->setImag(s.imag()); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 0; + + // tell caller we consumed the sample + return true; + } + } + + // downsample by 2, return upper half of original spectrum + bool workDecimateUpperHalf(Sample* sample) + { + switch(m_state) + { + case 0: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = sample->imag(); + m_samplesDB[m_ptrDB][1] = -sample->real(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sample->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = -sample->real(); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 1; + + // tell caller we don't have a new sample + return false; + + case 1: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = -sample->real(); + m_samplesDB[m_ptrDB][1] = -sample->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = -sample->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = -sample->imag(); + + // save result + doFIR(sample); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 2; + + // tell caller we have a new sample + return true; + + case 2: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = -sample->imag(); + m_samplesDB[m_ptrDB][1] = sample->real(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = -sample->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sample->real(); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 3; + + // tell caller we don't have a new sample + return false; + + default: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = sample->real(); + m_samplesDB[m_ptrDB][1] = sample->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sample->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sample->imag(); + + // save result + doFIR(sample); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 0; + + // tell caller we have a new sample + return true; + } + } + + // upsample by 2, move original spectrum to upper half - double buffer variant + bool workInterpolateUpperHalf(Sample* sampleIn, Sample *sampleOut) + { + Sample s; + + switch(m_state) + { + case 0: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = 0; + m_samplesDB[m_ptrDB][1] = 0; + m_samplesDB[m_ptrDB + m_sizeDB][0] = 0; + m_samplesDB[m_ptrDB + m_sizeDB][1] = 0; + + // save result + doFIR(&s); + sampleOut->setReal(-s.imag()); + sampleOut->setImag(s.real()); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 1; + + // tell caller we didn't consume the sample + return false; + + case 1: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = sampleIn->real(); + m_samplesDB[m_ptrDB][1] = sampleIn->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sampleIn->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sampleIn->imag(); + + // save result + doFIR(&s); + sampleOut->setReal(-s.real()); + sampleOut->setImag(-s.imag()); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 2; + + // tell caller we consumed the sample + return true; + + case 2: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = 0; + m_samplesDB[m_ptrDB][1] = 0; + m_samplesDB[m_ptrDB + m_sizeDB][0] = 0; + m_samplesDB[m_ptrDB + m_sizeDB][1] = 0; + + // save result + doFIR(&s); + sampleOut->setReal(s.imag()); + sampleOut->setImag(-s.real()); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 3; + + // tell caller we didn't consume the sample + return false; + + default: + // insert sample into ring-buffer + m_samplesDB[m_ptrDB][0] = sampleIn->real(); + m_samplesDB[m_ptrDB][1] = sampleIn->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sampleIn->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sampleIn->imag(); + + // save result + doFIR(&s); + sampleOut->setReal(s.real()); + sampleOut->setImag(s.imag()); + + // advance write-pointer + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + // next state + m_state = 0; + + // tell caller we consumed the sample + return true; + } + } + + void myDecimate(const Sample* sample1, Sample* sample2) + { + m_samplesDB[m_ptrDB][0] = sample1->real(); + m_samplesDB[m_ptrDB][1] = sample1->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sample1->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sample1->imag(); + + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + m_samplesDB[m_ptrDB][0] = sample2->real(); + m_samplesDB[m_ptrDB][1] = sample2->imag(); + m_samplesDB[m_ptrDB + m_sizeDB][0] = sample2->real(); + m_samplesDB[m_ptrDB + m_sizeDB][1] = sample2->imag(); + + doFIR(sample2); + + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + } + + void myDecimate(qint32 x1, qint32 y1, qint32 *x2, qint32 *y2) + { + m_samplesDB[m_ptrDB][0] = x1; + m_samplesDB[m_ptrDB][1] = y1; + m_samplesDB[m_ptrDB + m_sizeDB][0] = x1; + m_samplesDB[m_ptrDB + m_sizeDB][1] = y1; + + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + + m_samplesDB[m_ptrDB][0] = *x2; + m_samplesDB[m_ptrDB][1] = *y2; + m_samplesDB[m_ptrDB + m_sizeDB][0] = *x2; + m_samplesDB[m_ptrDB + m_sizeDB][1] = *y2; + + doFIR(x2, y2); + + m_ptrDB = (m_ptrDB + 1) % m_sizeDB; + } + +protected: + qint32 m_samplesDB[2*(HBFIRFilterTraits::hbOrder - 1)][2]; // double buffer technique + int m_ptrDB; + int m_sizeDB; + int m_state; + + void doFIR(Sample* sample) + { + int a = m_ptrDB + m_sizeDB; // tip pointer + int b = m_ptrDB + 1; // tail pointer + qint32 iAcc = 0; + qint32 qAcc = 0; + + for (int i = 0; i < HBFIRFilterTraits::hbOrder / 4; i++) + { + iAcc += (m_samplesDB[a][0] + m_samplesDB[b][0]) * HBFIRFilterTraits::hbCoeffs[i]; + qAcc += (m_samplesDB[a][1] + m_samplesDB[b][1]) * HBFIRFilterTraits::hbCoeffs[i]; + a -= 2; + b += 2; + } + + iAcc += ((qint32)m_samplesDB[b-1][0]) << (HBFIRFilterTraits::hbShift - 1); + qAcc += ((qint32)m_samplesDB[b-1][1]) << (HBFIRFilterTraits::hbShift - 1); + + sample->setReal(iAcc >> HBFIRFilterTraits::hbShift -1); + sample->setImag(qAcc >> HBFIRFilterTraits::hbShift -1); + } + + void doFIR(qint32 *x, qint32 *y) + { + int a = m_ptrDB + m_sizeDB; // tip pointer + int b = m_ptrDB + 1; // tail pointer + qint32 iAcc = 0; + qint32 qAcc = 0; + + for (int i = 0; i < HBFIRFilterTraits::hbOrder / 4; i++) + { + iAcc += (m_samplesDB[a][0] + m_samplesDB[b][0]) * HBFIRFilterTraits::hbCoeffs[i]; + qAcc += (m_samplesDB[a][1] + m_samplesDB[b][1]) * HBFIRFilterTraits::hbCoeffs[i]; + a -= 2; + b += 2; + } + + iAcc += ((qint32)m_samplesDB[b-1][0]) << (HBFIRFilterTraits::hbShift - 1); + qAcc += ((qint32)m_samplesDB[b-1][1]) << (HBFIRFilterTraits::hbShift - 1); + + *x = iAcc >> (HBFIRFilterTraits::hbShift -1); // HB_SHIFT incorrect do not loose the gained bit + *y = qAcc >> (HBFIRFilterTraits::hbShift -1); + } +}; + +template +IntHalfbandFilterDB::IntHalfbandFilterDB() +{ + m_sizeDB = HBFIRFilterTraits::hbOrder - 1; + + for (int i = 0; i < m_sizeDB; i++) + { + m_samplesDB[i][0] = 0; + m_samplesDB[i][1] = 0; + } + + m_ptrDB = 0; + m_state = 0; +} + +#endif // INCLUDE_INTHALFBANDFILTER_DB_H diff --git a/sdrbase/dsp/upchannelizer.cpp b/sdrbase/dsp/upchannelizer.cpp index 1d463185c..709ba7d37 100644 --- a/sdrbase/dsp/upchannelizer.cpp +++ b/sdrbase/dsp/upchannelizer.cpp @@ -202,20 +202,20 @@ void UpChannelizer::applyConfiguration() } UpChannelizer::FilterStage::FilterStage(Mode mode) : - m_filter(new IntHalfbandFilter), + m_filter(new IntHalfbandFilterDB), m_workFunction(0) { switch(mode) { case ModeCenter: - m_workFunction = &IntHalfbandFilter::workInterpolateCenterDB; + m_workFunction = &IntHalfbandFilterDB::workInterpolateCenter; break; case ModeLowerHalf: - m_workFunction = &IntHalfbandFilter::workInterpolateLowerHalfDB; + m_workFunction = &IntHalfbandFilterDB::workInterpolateLowerHalf; break; case ModeUpperHalf: - m_workFunction = &IntHalfbandFilter::workInterpolateUpperHalfDB; + m_workFunction = &IntHalfbandFilterDB::workInterpolateUpperHalf; break; } } diff --git a/sdrbase/dsp/upchannelizer.h b/sdrbase/dsp/upchannelizer.h index d773ecab3..a4a6410cb 100644 --- a/sdrbase/dsp/upchannelizer.h +++ b/sdrbase/dsp/upchannelizer.h @@ -23,7 +23,7 @@ #include #include "util/export.h" #include "util/message.h" -#include "dsp/inthalfbandfilter.h" +#include "dsp/inthalfbandfilterdb.h" #define UPCHANNELIZER_HB_FILTER_ORDER 96 @@ -69,8 +69,8 @@ protected: ModeUpperHalf }; - typedef bool (IntHalfbandFilter::*WorkFunction)(Sample* sIn, Sample *sOut); - IntHalfbandFilter* m_filter; + typedef bool (IntHalfbandFilterDB::*WorkFunction)(Sample* sIn, Sample *sOut); + IntHalfbandFilterDB* m_filter; WorkFunction m_workFunction; FilterStage(Mode mode);