diff --git a/sdrbase/dsp/inthalfbandfilter.h b/sdrbase/dsp/inthalfbandfilter.h index bda5e9220..bbe82eb94 100644 --- a/sdrbase/dsp/inthalfbandfilter.h +++ b/sdrbase/dsp/inthalfbandfilter.h @@ -141,6 +141,51 @@ 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 @@ -304,7 +349,7 @@ public: // next state m_state = 1; - // tell caller we don't have a new sample + // tell caller we didn't consume the sample return false; case 1: @@ -323,7 +368,7 @@ public: // next state m_state = 2; - // tell caller we have a new sample + // tell caller we consumed the sample return true; case 2: @@ -342,7 +387,7 @@ public: // next state m_state = 3; - // tell caller we don't have a new sample + // tell caller we didn't consume the sample return false; default: @@ -361,7 +406,100 @@ public: // next state m_state = 0; - // tell caller we have a new sample + // tell caller we consumed the sample + return true; + } + } + + // 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; } } @@ -458,7 +596,7 @@ public: // next state m_state = 1; - // tell caller we don't have a new sample + // tell caller we didn't consume the sample return false; case 1: @@ -477,7 +615,7 @@ public: // next state m_state = 2; - // tell caller we have a new sample + // tell caller we consumed the sample return true; case 2: @@ -496,7 +634,7 @@ public: // next state m_state = 3; - // tell caller we don't have a new sample + // tell caller we didn't consume the sample return false; default: @@ -515,7 +653,100 @@ public: // next state m_state = 0; - // tell caller we have a new sample + // tell caller we consumed the sample + return true; + } + } + + // 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; } } @@ -549,15 +780,43 @@ public: } protected: - qint32 m_samples[HBFIRFilterTraits::hbOrder + 1][2]; // Valgrind optim (from qint16) + 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 +// 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); // go through samples in buffer qint32 iAcc = 0; @@ -572,11 +831,16 @@ 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]; +// 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 - 1]; +// a = HBFIRFilterTraits::hbMod[a + 2 - 1]; + // ancient way: + a = (a + HBFIRFilterTraits::hbOrder) % (HBFIRFilterTraits::hbOrder + 1); iAcc += ((qint32)m_samples[a][0] + 1) << (HBFIRFilterTraits::hbShift - 1); qAcc += ((qint32)m_samples[a][1] + 1) << (HBFIRFilterTraits::hbShift - 1); @@ -628,11 +892,23 @@ protected: template IntHalfbandFilter::IntHalfbandFilter() { - for(int i = 0; i < HBFIRFilterTraits::hbOrder + 1; i++) { + 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/upchannelizer.cpp b/sdrbase/dsp/upchannelizer.cpp index 9576d80a2..1d463185c 100644 --- a/sdrbase/dsp/upchannelizer.cpp +++ b/sdrbase/dsp/upchannelizer.cpp @@ -207,15 +207,15 @@ UpChannelizer::FilterStage::FilterStage(Mode mode) : { switch(mode) { case ModeCenter: - m_workFunction = &IntHalfbandFilter::workInterpolateCenter; + m_workFunction = &IntHalfbandFilter::workInterpolateCenterDB; break; case ModeLowerHalf: - m_workFunction = &IntHalfbandFilter::workInterpolateLowerHalf; + m_workFunction = &IntHalfbandFilter::workInterpolateLowerHalfDB; break; case ModeUpperHalf: - m_workFunction = &IntHalfbandFilter::workInterpolateUpperHalf; + m_workFunction = &IntHalfbandFilter::workInterpolateUpperHalfDB; break; } } diff --git a/sdrbase/dsp/upchannelizer.h b/sdrbase/dsp/upchannelizer.h index b890ab2e4..d773ecab3 100644 --- a/sdrbase/dsp/upchannelizer.h +++ b/sdrbase/dsp/upchannelizer.h @@ -25,7 +25,7 @@ #include "util/message.h" #include "dsp/inthalfbandfilter.h" -#define UPCHANNELIZER_HB_FILTER_ORDER 64 +#define UPCHANNELIZER_HB_FILTER_ORDER 96 class MessageQueue;