diff --git a/plugins/samplesource/airspyhff/airspyhffinput.cpp b/plugins/samplesource/airspyhff/airspyhffinput.cpp index 0fde45a7b..e525c17dc 100644 --- a/plugins/samplesource/airspyhff/airspyhffinput.cpp +++ b/plugins/samplesource/airspyhff/airspyhffinput.cpp @@ -135,7 +135,7 @@ bool AirspyHFFInput::openDevice() delete[] sampleRates; - airspyhf_set_sample_type(m_dev, AIRSPYHF_SAMPLE_INT16_IQ); + airspyhf_set_sample_type(m_dev, AIRSPYHF_SAMPLE_FLOAT32_IQ); return true; } diff --git a/plugins/samplesource/airspyhff/airspyhffthread.cpp b/plugins/samplesource/airspyhff/airspyhffthread.cpp index ebafee037..aa8be13d8 100644 --- a/plugins/samplesource/airspyhff/airspyhffthread.cpp +++ b/plugins/samplesource/airspyhff/airspyhffthread.cpp @@ -99,7 +99,7 @@ void AirspyHFFThread::run() } // Decimate according to specified log2 (ex: log2=4 => decim=16) -void AirspyHFFThread::callback(const qint16* buf, qint32 len) +void AirspyHFFThread::callback(const float* buf, qint32 len) { SampleVector::iterator it = m_convertBuffer.begin(); @@ -136,7 +136,7 @@ void AirspyHFFThread::callback(const qint16* buf, qint32 len) int AirspyHFFThread::rx_callback(airspyhf_transfer_t* transfer) { - qint32 bytes_to_write = transfer->sample_count * sizeof(qint16); - m_this->callback((qint16 *) transfer->samples, bytes_to_write); + qint32 nbIAndQ = transfer->sample_count * 2; + m_this->callback((float *) transfer->samples, nbIAndQ); return 0; } diff --git a/plugins/samplesource/airspyhff/airspyhffthread.h b/plugins/samplesource/airspyhff/airspyhffthread.h index 998dc6470..f26d8c3c6 100644 --- a/plugins/samplesource/airspyhff/airspyhffthread.h +++ b/plugins/samplesource/airspyhff/airspyhffthread.h @@ -23,7 +23,7 @@ #include #include "dsp/samplesinkfifo.h" -#include "dsp/decimators.h" +#include "dsp/decimatorsf.h" #define AIRSPYHFF_BLOCKSIZE (1<<17) @@ -53,14 +53,10 @@ private: unsigned int m_log2Decim; static AirspyHFFThread *m_this; -#ifdef SDR_RX_SAMPLE_24BIT - Decimators m_decimators; -#else - Decimators m_decimators; -#endif + DecimatorsF m_decimators; void run(); - void callback(const qint16* buf, qint32 len); + void callback(const float* buf, qint32 len); static int rx_callback(airspyhf_transfer_t* transfer); }; diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index 44bcefa3a..438101ce1 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -21,6 +21,7 @@ set(sdrbase_SOURCES dsp/ctcssdetector.cpp dsp/cwkeyer.cpp dsp/cwkeyersettings.cpp + dsp/decimatorsf.cpp dsp/dspcommands.cpp dsp/dspengine.cpp dsp/dspdevicesourceengine.cpp @@ -100,6 +101,7 @@ set(sdrbase_HEADERS dsp/cwkeyer.h dsp/cwkeyersettings.h dsp/decimators.h + dsp/decimatorsf.h dsp/decimatorsu.h dsp/interpolators.h dsp/dspcommands.h @@ -120,6 +122,7 @@ set(sdrbase_HEADERS dsp/hbfiltertraits.h dsp/inthalfbandfilter.h dsp/inthalfbandfilterdb.h + dsp/inthalfbandfilterdbf.h dsp/inthalfbandfiltereo1.h dsp/inthalfbandfiltereo1i.h dsp/inthalfbandfilterst.h diff --git a/sdrbase/dsp/decimatorsf.cpp b/sdrbase/dsp/decimatorsf.cpp new file mode 100644 index 000000000..dd637ce70 --- /dev/null +++ b/sdrbase/dsp/decimatorsf.cpp @@ -0,0 +1,1173 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "decimatorsf.h" + +void DecimatorsF::decimate1(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + float xreal, yimag; + + for (int pos = 0; pos < nbIAndQ - 1; pos += 2) + { + xreal = buf[pos+0]; + yimag = buf[pos+1]; + (**it).setReal(xreal * SDR_RX_SCALEF); + (**it).setImag(yimag * SDR_RX_SCALEF); + ++(*it); // Valgrind optim (comment not repeated) + } +} + +void DecimatorsF::decimate2_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double intbuf[2]; + + for (int pos = 0; pos < nbIAndQ - 3; pos += 4) + { + intbuf[0] = buf[pos+2]; + intbuf[1] = buf[pos+3]; + + m_decimator2.myDecimate( + buf[pos+0], + buf[pos+1], + &intbuf[0], + &intbuf[1]); + + (**it).setReal(intbuf[0] * SDR_RX_SCALED); + (**it).setImag(intbuf[1] * SDR_RX_SCALED); + + ++(*it); + } +} + +void DecimatorsF::decimate2_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double xreal, yimag; + + for (int pos = 0; pos < nbIAndQ - 7; pos += 8) + { + xreal = (buf[pos+0] - buf[pos+3]); + yimag = (buf[pos+1] + buf[pos+2]); + (**it).setReal(xreal * SDR_RX_SCALED); + (**it).setImag(yimag * SDR_RX_SCALED); + ++(*it); + + xreal = (buf[pos+7] - buf[pos+4]); + yimag = (- buf[pos+5] - buf[pos+6]); + (**it).setReal(xreal * SDR_RX_SCALED); + (**it).setImag(yimag * SDR_RX_SCALED); + ++(*it); + } +} + +void DecimatorsF::decimate2_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double xreal, yimag; + + for (int pos = 0; pos < nbIAndQ - 7; pos += 8) + { + xreal = (buf[pos+1] - buf[pos+2]); + yimag = (- buf[pos+0] - buf[pos+3]); + (**it).setReal(xreal * SDR_RX_SCALED); + (**it).setImag(yimag * SDR_RX_SCALED); + ++(*it); + + xreal = (buf[pos+6] - buf[pos+5]); + yimag = (buf[pos+4] + buf[pos+7]); + (**it).setReal(xreal * SDR_RX_SCALED); + (**it).setImag(yimag * SDR_RX_SCALED); + ++(*it); + } +} + +void DecimatorsF::decimate4_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double xreal, yimag; + + for (int pos = 0; pos < nbIAndQ - 7; pos += 8) + { + xreal = (buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4]); + yimag = (buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6]); + + (**it).setReal(xreal * SDR_RX_SCALED); + (**it).setImag(yimag * SDR_RX_SCALED); + + ++(*it); + } +} + +void DecimatorsF::decimate4_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + // Sup (USB): + // x y x y x y x y / x -> 1,-2,-5,6 / y -> -0,-3,4,7 + // [ rotate: 1, 0, -2, 3, -5, -4, 6, -7] + // Inf (LSB): + // x y x y x y x y / x -> 0,-3,-4,7 / y -> 1,2,-5,-6 + // [ rotate: 0, 1, -3, 2, -4, -5, 7, -6] + double xreal, yimag; + + for (int pos = 0; pos < nbIAndQ - 7; pos += 8) + { + xreal = (buf[pos+1] - buf[pos+2] - buf[pos+5] + buf[pos+6]); + yimag = (- buf[pos+0] - buf[pos+3] + buf[pos+4] + buf[pos+7]); + + (**it).setReal(xreal * SDR_RX_SCALED); + (**it).setImag(yimag * SDR_RX_SCALED); + + ++(*it); + } +} + +void DecimatorsF::decimate8_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double xreal[2], yimag[2]; + + for (int pos = 0; pos < nbIAndQ - 15; pos += 8) + { + xreal[0] = (buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4]); + yimag[0] = (buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6]); + pos += 8; + + xreal[1] = (buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4]); + yimag[1] = (buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6]); + + m_decimator2.myDecimate(xreal[0], yimag[0], &xreal[1], &yimag[1]); + + (**it).setReal(xreal[1] * SDR_RX_SCALED); + (**it).setImag(yimag[1] * SDR_RX_SCALED); + + ++(*it); + } +} + +void DecimatorsF::decimate8_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double xreal[2], yimag[2]; + + for (int pos = 0; pos < nbIAndQ - 15; pos += 8) + { + xreal[0] = (buf[pos+1] - buf[pos+2] - buf[pos+5] + buf[pos+6]); + yimag[0] = (- buf[pos+0] - buf[pos+3] + buf[pos+4] + buf[pos+7]); + pos += 8; + + xreal[1] = (buf[pos+1] - buf[pos+2] - buf[pos+5] + buf[pos+6]); + yimag[1] = (- buf[pos+0] - buf[pos+3] + buf[pos+4] + buf[pos+7]); + + m_decimator2.myDecimate(xreal[0], yimag[0], &xreal[1], &yimag[1]); + + (**it).setReal(xreal[1] * SDR_RX_SCALED); + (**it).setImag(yimag[1] * SDR_RX_SCALED); + + ++(*it); + } +} + +void DecimatorsF::decimate16_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + // Offset tuning: 4x downsample and rotate, then + // downsample 4x more. [ rotate: 0, 1, -3, 2, -4, -5, 7, -6] + double xreal[4], yimag[4]; + + for (int pos = 0; pos < nbIAndQ - 31; ) + { + for (int i = 0; i < 4; i++) + { + xreal[i] = (buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4]); + yimag[i] = (buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6]); + pos += 8; + } + + m_decimator2.myDecimate(xreal[0], yimag[0], &xreal[1], &yimag[1]); + m_decimator2.myDecimate(xreal[2], yimag[2], &xreal[3], &yimag[3]); + + m_decimator4.myDecimate(xreal[1], yimag[1], &xreal[3], &yimag[3]); + + (**it).setReal(xreal[3] * SDR_RX_SCALED); + (**it).setImag(yimag[3] * SDR_RX_SCALED); + + ++(*it); + } +} + +void DecimatorsF::decimate16_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + // Offset tuning: 4x downsample and rotate, then + // downsample 4x more. [ rotate: 1, 0, -2, 3, -5, -4, 6, -7] + double xreal[4], yimag[4]; + + for (int pos = 0; pos < nbIAndQ - 31; ) + { + for (int i = 0; i < 4; i++) + { + xreal[i] = (buf[pos+1] - buf[pos+2] - buf[pos+5] + buf[pos+6]); + yimag[i] = (buf[pos+4] + buf[pos+7] - buf[pos+0] - buf[pos+3]); + pos += 8; + } + + m_decimator2.myDecimate(xreal[0], yimag[0], &xreal[1], &yimag[1]); + m_decimator2.myDecimate(xreal[2], yimag[2], &xreal[3], &yimag[3]); + + m_decimator4.myDecimate(xreal[1], yimag[1], &xreal[3], &yimag[3]); + + (**it).setReal(xreal[3] * SDR_RX_SCALED); + (**it).setImag(yimag[3] * SDR_RX_SCALED); + + ++(*it); + } +} + +void DecimatorsF::decimate32_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double xreal[8], yimag[8]; + + for (int pos = 0; pos < nbIAndQ - 63; ) + { + for (int i = 0; i < 8; i++) + { + xreal[i] = (buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4]); + yimag[i] = (buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6]); + pos += 8; + } + + m_decimator2.myDecimate(xreal[0], yimag[0], &xreal[1], &yimag[1]); + m_decimator2.myDecimate(xreal[2], yimag[2], &xreal[3], &yimag[3]); + m_decimator2.myDecimate(xreal[4], yimag[4], &xreal[5], &yimag[5]); + m_decimator2.myDecimate(xreal[6], yimag[6], &xreal[7], &yimag[7]); + + m_decimator4.myDecimate(xreal[1], yimag[1], &xreal[3], &yimag[3]); + m_decimator4.myDecimate(xreal[5], yimag[5], &xreal[7], &yimag[7]); + + m_decimator8.myDecimate(xreal[3], yimag[3], &xreal[7], &yimag[7]); + + (**it).setReal(xreal[7] * SDR_RX_SCALED); + (**it).setImag(yimag[7] * SDR_RX_SCALED); + + ++(*it); + } +} + +void DecimatorsF::decimate32_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double xreal[8], yimag[8]; + + for (int pos = 0; pos < nbIAndQ - 63; ) + { + for (int i = 0; i < 8; i++) + { + xreal[i] = (buf[pos+1] - buf[pos+2] - buf[pos+5] + buf[pos+6]); + yimag[i] = (buf[pos+4] + buf[pos+7] - buf[pos+0] - buf[pos+3]); + pos += 8; + } + + m_decimator2.myDecimate(xreal[0], yimag[0], &xreal[1], &yimag[1]); + m_decimator2.myDecimate(xreal[2], yimag[2], &xreal[3], &yimag[3]); + m_decimator2.myDecimate(xreal[4], yimag[4], &xreal[5], &yimag[5]); + m_decimator2.myDecimate(xreal[6], yimag[6], &xreal[7], &yimag[7]); + + m_decimator4.myDecimate(xreal[1], yimag[1], &xreal[3], &yimag[3]); + m_decimator4.myDecimate(xreal[5], yimag[5], &xreal[7], &yimag[7]); + + m_decimator8.myDecimate(xreal[3], yimag[3], &xreal[7], &yimag[7]); + + (**it).setReal(xreal[7] * SDR_RX_SCALED); + (**it).setImag(yimag[7] * SDR_RX_SCALED); + + ++(*it); + } +} + +void DecimatorsF::decimate64_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double xreal[16], yimag[16]; + + for (int pos = 0; pos < nbIAndQ - 127; ) + { + for (int i = 0; i < 16; i++) + { + xreal[i] = (buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4]); + yimag[i] = (buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6]); + pos += 8; + } + + m_decimator2.myDecimate(xreal[0], yimag[0], &xreal[1], &yimag[1]); + m_decimator2.myDecimate(xreal[2], yimag[2], &xreal[3], &yimag[3]); + m_decimator2.myDecimate(xreal[4], yimag[4], &xreal[5], &yimag[5]); + m_decimator2.myDecimate(xreal[6], yimag[6], &xreal[7], &yimag[7]); + m_decimator2.myDecimate(xreal[8], yimag[8], &xreal[9], &yimag[9]); + m_decimator2.myDecimate(xreal[10], yimag[10], &xreal[11], &yimag[11]); + m_decimator2.myDecimate(xreal[12], yimag[12], &xreal[13], &yimag[13]); + m_decimator2.myDecimate(xreal[14], yimag[14], &xreal[15], &yimag[15]); + + m_decimator4.myDecimate(xreal[1], yimag[1], &xreal[3], &yimag[3]); + m_decimator4.myDecimate(xreal[5], yimag[5], &xreal[7], &yimag[7]); + m_decimator4.myDecimate(xreal[9], yimag[9], &xreal[11], &yimag[11]); + m_decimator4.myDecimate(xreal[13], yimag[13], &xreal[15], &yimag[15]); + + m_decimator8.myDecimate(xreal[3], yimag[3], &xreal[7], &yimag[7]); + m_decimator8.myDecimate(xreal[11], yimag[11], &xreal[15], &yimag[15]); + + m_decimator16.myDecimate(xreal[7], yimag[7], &xreal[15], &yimag[15]); + + (**it).setReal(xreal[15] * SDR_RX_SCALED); + (**it).setImag(yimag[15] * SDR_RX_SCALED); + + ++(*it); + } +} + +void DecimatorsF::decimate64_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double xreal[16], yimag[16]; + + for (int pos = 0; pos < nbIAndQ - 127; ) + { + for (int i = 0; i < 16; i++) + { + xreal[i] = (buf[pos+1] - buf[pos+2] - buf[pos+5] + buf[pos+6]); + yimag[i] = (buf[pos+4] + buf[pos+7] - buf[pos+0] - buf[pos+3]); + pos += 8; + } + + m_decimator2.myDecimate(xreal[0], yimag[0], &xreal[1], &yimag[1]); + m_decimator2.myDecimate(xreal[2], yimag[2], &xreal[3], &yimag[3]); + m_decimator2.myDecimate(xreal[4], yimag[4], &xreal[5], &yimag[5]); + m_decimator2.myDecimate(xreal[6], yimag[6], &xreal[7], &yimag[7]); + m_decimator2.myDecimate(xreal[8], yimag[8], &xreal[9], &yimag[9]); + m_decimator2.myDecimate(xreal[10], yimag[10], &xreal[11], &yimag[11]); + m_decimator2.myDecimate(xreal[12], yimag[12], &xreal[13], &yimag[13]); + m_decimator2.myDecimate(xreal[14], yimag[14], &xreal[15], &yimag[15]); + + m_decimator4.myDecimate(xreal[1], yimag[1], &xreal[3], &yimag[3]); + m_decimator4.myDecimate(xreal[5], yimag[5], &xreal[7], &yimag[7]); + m_decimator4.myDecimate(xreal[9], yimag[9], &xreal[11], &yimag[11]); + m_decimator4.myDecimate(xreal[13], yimag[13], &xreal[15], &yimag[15]); + + m_decimator8.myDecimate(xreal[3], yimag[3], &xreal[7], &yimag[7]); + m_decimator8.myDecimate(xreal[11], yimag[11], &xreal[15], &yimag[15]); + + m_decimator16.myDecimate(xreal[7], yimag[7], &xreal[15], &yimag[15]); + + (**it).setReal(xreal[15] * SDR_RX_SCALED); + (**it).setImag(yimag[15] * SDR_RX_SCALED); + + ++(*it); + } +} + +void DecimatorsF::decimate4_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double intbuf[4]; + + for (int pos = 0; pos < nbIAndQ - 7; pos += 8) + { + intbuf[0] = buf[pos+2]; + intbuf[1] = buf[pos+3]; + intbuf[2] = buf[pos+6]; + intbuf[3] = buf[pos+7]; + + m_decimator2.myDecimate( + buf[pos+0], + buf[pos+1], + &intbuf[0], + &intbuf[1]); + m_decimator2.myDecimate( + buf[pos+4], + buf[pos+5], + &intbuf[2], + &intbuf[3]); + + m_decimator4.myDecimate( + intbuf[0], + intbuf[1], + &intbuf[2], + &intbuf[3]); + + (**it).setReal(intbuf[2] * SDR_RX_SCALED); + (**it).setImag(intbuf[3] * SDR_RX_SCALED); + ++(*it); + } +} + +void DecimatorsF::decimate8_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double intbuf[8]; + + for (int pos = 0; pos < nbIAndQ - 15; pos += 16) + { + intbuf[0] = buf[pos+2]; + intbuf[1] = buf[pos+3]; + intbuf[2] = buf[pos+6]; + intbuf[3] = buf[pos+7]; + intbuf[4] = buf[pos+10]; + intbuf[5] = buf[pos+11]; + intbuf[6] = buf[pos+14]; + intbuf[7] = buf[pos+15]; + + m_decimator2.myDecimate( + buf[pos+0], + buf[pos+1], + &intbuf[0], + &intbuf[1]); + m_decimator2.myDecimate( + buf[pos+4], + buf[pos+5], + &intbuf[2], + &intbuf[3]); + m_decimator2.myDecimate( + buf[pos+8], + buf[pos+9], + &intbuf[4], + &intbuf[5]); + m_decimator2.myDecimate( + buf[pos+12], + buf[pos+13], + &intbuf[6], + &intbuf[7]); + + m_decimator4.myDecimate( + intbuf[0], + intbuf[1], + &intbuf[2], + &intbuf[3]); + m_decimator4.myDecimate( + intbuf[4], + intbuf[5], + &intbuf[6], + &intbuf[7]); + + m_decimator8.myDecimate( + intbuf[2], + intbuf[3], + &intbuf[6], + &intbuf[7]); + + (**it).setReal(intbuf[6] * SDR_RX_SCALED); + (**it).setImag(intbuf[7] * SDR_RX_SCALED); + ++(*it); + } +} + +void DecimatorsF::decimate16_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double intbuf[16]; + + for (int pos = 0; pos < nbIAndQ - 31; pos += 32) + { + intbuf[0] = buf[pos+2]; + intbuf[1] = buf[pos+3]; + intbuf[2] = buf[pos+6]; + intbuf[3] = buf[pos+7]; + intbuf[4] = buf[pos+10]; + intbuf[5] = buf[pos+11]; + intbuf[6] = buf[pos+14]; + intbuf[7] = buf[pos+15]; + intbuf[8] = buf[pos+18]; + intbuf[9] = buf[pos+19]; + intbuf[10] = buf[pos+22]; + intbuf[11] = buf[pos+23]; + intbuf[12] = buf[pos+26]; + intbuf[13] = buf[pos+27]; + intbuf[14] = buf[pos+30]; + intbuf[15] = buf[pos+31]; + + m_decimator2.myDecimate( + buf[pos+0], + buf[pos+1], + &intbuf[0], + &intbuf[1]); + m_decimator2.myDecimate( + buf[pos+4], + buf[pos+5], + &intbuf[2], + &intbuf[3]); + m_decimator2.myDecimate( + buf[pos+8], + buf[pos+9], + &intbuf[4], + &intbuf[5]); + m_decimator2.myDecimate( + buf[pos+12], + buf[pos+13], + &intbuf[6], + &intbuf[7]); + m_decimator2.myDecimate( + buf[pos+16], + buf[pos+17], + &intbuf[8], + &intbuf[9]); + m_decimator2.myDecimate( + buf[pos+20], + buf[pos+21], + &intbuf[10], + &intbuf[11]); + m_decimator2.myDecimate( + buf[pos+24], + buf[pos+25], + &intbuf[12], + &intbuf[13]); + m_decimator2.myDecimate( + buf[pos+28], + buf[pos+29], + &intbuf[14], + &intbuf[15]); + + m_decimator4.myDecimate( + intbuf[0], + intbuf[1], + &intbuf[2], + &intbuf[3]); + m_decimator4.myDecimate( + intbuf[4], + intbuf[5], + &intbuf[6], + &intbuf[7]); + m_decimator4.myDecimate( + intbuf[8], + intbuf[9], + &intbuf[10], + &intbuf[11]); + m_decimator4.myDecimate( + intbuf[12], + intbuf[13], + &intbuf[14], + &intbuf[15]); + + m_decimator8.myDecimate( + intbuf[2], + intbuf[3], + &intbuf[6], + &intbuf[7]); + m_decimator8.myDecimate( + intbuf[10], + intbuf[11], + &intbuf[14], + &intbuf[15]); + + m_decimator16.myDecimate( + intbuf[6], + intbuf[7], + &intbuf[14], + &intbuf[15]); + + (**it).setReal(intbuf[14] * SDR_RX_SCALED); + (**it).setImag(intbuf[15] * SDR_RX_SCALED); + ++(*it); + } +} + +void DecimatorsF::decimate32_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double intbuf[32]; + + for (int pos = 0; pos < nbIAndQ - 63; pos += 64) + { + intbuf[0] = buf[pos+2]; + intbuf[1] = buf[pos+3]; + intbuf[2] = buf[pos+6]; + intbuf[3] = buf[pos+7]; + intbuf[4] = buf[pos+10]; + intbuf[5] = buf[pos+11]; + intbuf[6] = buf[pos+14]; + intbuf[7] = buf[pos+15]; + intbuf[8] = buf[pos+18]; + intbuf[9] = buf[pos+19]; + intbuf[10] = buf[pos+22]; + intbuf[11] = buf[pos+23]; + intbuf[12] = buf[pos+26]; + intbuf[13] = buf[pos+27]; + intbuf[14] = buf[pos+30]; + intbuf[15] = buf[pos+31]; + intbuf[16] = buf[pos+34]; + intbuf[17] = buf[pos+35]; + intbuf[18] = buf[pos+38]; + intbuf[19] = buf[pos+39]; + intbuf[20] = buf[pos+42]; + intbuf[21] = buf[pos+43]; + intbuf[22] = buf[pos+46]; + intbuf[23] = buf[pos+47]; + intbuf[24] = buf[pos+50]; + intbuf[25] = buf[pos+51]; + intbuf[26] = buf[pos+54]; + intbuf[27] = buf[pos+55]; + intbuf[28] = buf[pos+58]; + intbuf[29] = buf[pos+59]; + intbuf[30] = buf[pos+62]; + intbuf[31] = buf[pos+63]; + + m_decimator2.myDecimate( + buf[pos+0], + buf[pos+1], + &intbuf[0], + &intbuf[1]); + m_decimator2.myDecimate( + buf[pos+4], + buf[pos+5], + &intbuf[2], + &intbuf[3]); + m_decimator2.myDecimate( + buf[pos+8], + buf[pos+9], + &intbuf[4], + &intbuf[5]); + m_decimator2.myDecimate( + buf[pos+12], + buf[pos+13], + &intbuf[6], + &intbuf[7]); + m_decimator2.myDecimate( + buf[pos+16], + buf[pos+17], + &intbuf[8], + &intbuf[9]); + m_decimator2.myDecimate( + buf[pos+20], + buf[pos+21], + &intbuf[10], + &intbuf[11]); + m_decimator2.myDecimate( + buf[pos+24], + buf[pos+25], + &intbuf[12], + &intbuf[13]); + m_decimator2.myDecimate( + buf[pos+28], + buf[pos+29], + &intbuf[14], + &intbuf[15]); + m_decimator2.myDecimate( + buf[pos+32], + buf[pos+33], + &intbuf[16], + &intbuf[17]); + m_decimator2.myDecimate( + buf[pos+36], + buf[pos+37], + &intbuf[18], + &intbuf[19]); + m_decimator2.myDecimate( + buf[pos+40], + buf[pos+41], + &intbuf[20], + &intbuf[21]); + m_decimator2.myDecimate( + buf[pos+44], + buf[pos+45], + &intbuf[22], + &intbuf[23]); + m_decimator2.myDecimate( + buf[pos+48], + buf[pos+49], + &intbuf[24], + &intbuf[25]); + m_decimator2.myDecimate( + buf[pos+52], + buf[pos+53], + &intbuf[26], + &intbuf[27]); + m_decimator2.myDecimate( + buf[pos+56], + buf[pos+57], + &intbuf[28], + &intbuf[29]); + m_decimator2.myDecimate( + buf[pos+60], + buf[pos+61], + &intbuf[30], + &intbuf[31]); + + m_decimator4.myDecimate( + intbuf[0], + intbuf[1], + &intbuf[2], + &intbuf[3]); + m_decimator4.myDecimate( + intbuf[4], + intbuf[5], + &intbuf[6], + &intbuf[7]); + m_decimator4.myDecimate( + intbuf[8], + intbuf[9], + &intbuf[10], + &intbuf[11]); + m_decimator4.myDecimate( + intbuf[12], + intbuf[13], + &intbuf[14], + &intbuf[15]); + m_decimator4.myDecimate( + intbuf[16], + intbuf[17], + &intbuf[18], + &intbuf[19]); + m_decimator4.myDecimate( + intbuf[20], + intbuf[21], + &intbuf[22], + &intbuf[23]); + m_decimator4.myDecimate( + intbuf[24], + intbuf[25], + &intbuf[26], + &intbuf[27]); + m_decimator4.myDecimate( + intbuf[28], + intbuf[29], + &intbuf[30], + &intbuf[31]); + + m_decimator8.myDecimate( + intbuf[2], + intbuf[3], + &intbuf[6], + &intbuf[7]); + m_decimator8.myDecimate( + intbuf[10], + intbuf[11], + &intbuf[14], + &intbuf[15]); + m_decimator8.myDecimate( + intbuf[18], + intbuf[19], + &intbuf[22], + &intbuf[23]); + m_decimator8.myDecimate( + intbuf[26], + intbuf[27], + &intbuf[30], + &intbuf[31]); + + m_decimator16.myDecimate( + intbuf[6], + intbuf[7], + &intbuf[14], + &intbuf[15]); + m_decimator16.myDecimate( + intbuf[22], + intbuf[23], + &intbuf[30], + &intbuf[31]); + + m_decimator32.myDecimate( + intbuf[14], + intbuf[15], + &intbuf[30], + &intbuf[31]); + + (**it).setReal(intbuf[30] * SDR_RX_SCALED); + (**it).setImag(intbuf[31] * SDR_RX_SCALED); + ++(*it); + } +} + +void DecimatorsF::decimate64_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ) +{ + double intbuf[64]; + + for (int pos = 0; pos < nbIAndQ - 127; pos += 128) + { + intbuf[0] = buf[pos+2]; + intbuf[1] = buf[pos+3]; + intbuf[2] = buf[pos+6]; + intbuf[3] = buf[pos+7]; + intbuf[4] = buf[pos+10]; + intbuf[5] = buf[pos+11]; + intbuf[6] = buf[pos+14]; + intbuf[7] = buf[pos+15]; + intbuf[8] = buf[pos+18]; + intbuf[9] = buf[pos+19]; + intbuf[10] = buf[pos+22]; + intbuf[11] = buf[pos+23]; + intbuf[12] = buf[pos+26]; + intbuf[13] = buf[pos+27]; + intbuf[14] = buf[pos+30]; + intbuf[15] = buf[pos+31]; + intbuf[16] = buf[pos+34]; + intbuf[17] = buf[pos+35]; + intbuf[18] = buf[pos+38]; + intbuf[19] = buf[pos+39]; + intbuf[20] = buf[pos+42]; + intbuf[21] = buf[pos+43]; + intbuf[22] = buf[pos+46]; + intbuf[23] = buf[pos+47]; + intbuf[24] = buf[pos+50]; + intbuf[25] = buf[pos+51]; + intbuf[26] = buf[pos+54]; + intbuf[27] = buf[pos+55]; + intbuf[28] = buf[pos+58]; + intbuf[29] = buf[pos+59]; + intbuf[30] = buf[pos+62]; + intbuf[31] = buf[pos+63]; + + intbuf[32] = buf[pos+66]; + intbuf[33] = buf[pos+67]; + intbuf[34] = buf[pos+70]; + intbuf[35] = buf[pos+71]; + intbuf[36] = buf[pos+74]; + intbuf[37] = buf[pos+75]; + intbuf[38] = buf[pos+78]; + intbuf[39] = buf[pos+79]; + intbuf[40] = buf[pos+82]; + intbuf[41] = buf[pos+83]; + intbuf[42] = buf[pos+86]; + intbuf[43] = buf[pos+87]; + intbuf[44] = buf[pos+90]; + intbuf[45] = buf[pos+91]; + intbuf[46] = buf[pos+94]; + intbuf[47] = buf[pos+95]; + intbuf[48] = buf[pos+98]; + intbuf[49] = buf[pos+99]; + intbuf[50] = buf[pos+102]; + intbuf[51] = buf[pos+103]; + intbuf[52] = buf[pos+106]; + intbuf[53] = buf[pos+107]; + intbuf[54] = buf[pos+110]; + intbuf[55] = buf[pos+111]; + intbuf[56] = buf[pos+114]; + intbuf[57] = buf[pos+115]; + intbuf[58] = buf[pos+118]; + intbuf[59] = buf[pos+119]; + intbuf[60] = buf[pos+122]; + intbuf[61] = buf[pos+123]; + intbuf[62] = buf[pos+126]; + intbuf[63] = buf[pos+127]; + + m_decimator2.myDecimate( + buf[pos+0], + buf[pos+1], + &intbuf[0], + &intbuf[1]); + m_decimator2.myDecimate( + buf[pos+4], + buf[pos+5], + &intbuf[2], + &intbuf[3]); + m_decimator2.myDecimate( + buf[pos+8], + buf[pos+9], + &intbuf[4], + &intbuf[5]); + m_decimator2.myDecimate( + buf[pos+12], + buf[pos+13], + &intbuf[6], + &intbuf[7]); + m_decimator2.myDecimate( + buf[pos+16], + buf[pos+17], + &intbuf[8], + &intbuf[9]); + m_decimator2.myDecimate( + buf[pos+20], + buf[pos+21], + &intbuf[10], + &intbuf[11]); + m_decimator2.myDecimate( + buf[pos+24], + buf[pos+25], + &intbuf[12], + &intbuf[13]); + m_decimator2.myDecimate( + buf[pos+28], + buf[pos+29], + &intbuf[14], + &intbuf[15]); + m_decimator2.myDecimate( + buf[pos+32], + buf[pos+33], + &intbuf[16], + &intbuf[17]); + m_decimator2.myDecimate( + buf[pos+36], + buf[pos+37], + &intbuf[18], + &intbuf[19]); + m_decimator2.myDecimate( + buf[pos+40], + buf[pos+41], + &intbuf[20], + &intbuf[21]); + m_decimator2.myDecimate( + buf[pos+44], + buf[pos+45], + &intbuf[22], + &intbuf[23]); + m_decimator2.myDecimate( + buf[pos+48], + buf[pos+49], + &intbuf[24], + &intbuf[25]); + m_decimator2.myDecimate( + buf[pos+52], + buf[pos+53], + &intbuf[26], + &intbuf[27]); + m_decimator2.myDecimate( + buf[pos+56], + buf[pos+57], + &intbuf[28], + &intbuf[29]); + m_decimator2.myDecimate( + buf[pos+60], + buf[pos+61], + &intbuf[30], + &intbuf[31]); + m_decimator2.myDecimate( + buf[pos+64], + buf[pos+65], + &intbuf[32], + &intbuf[33]); + m_decimator2.myDecimate( + buf[pos+68], + buf[pos+69], + &intbuf[34], + &intbuf[35]); + m_decimator2.myDecimate( + buf[pos+72], + buf[pos+73], + &intbuf[36], + &intbuf[37]); + m_decimator2.myDecimate( + buf[pos+76], + buf[pos+77], + &intbuf[38], + &intbuf[39]); + m_decimator2.myDecimate( + buf[pos+80], + buf[pos+81], + &intbuf[40], + &intbuf[41]); + m_decimator2.myDecimate( + buf[pos+84], + buf[pos+85], + &intbuf[42], + &intbuf[43]); + m_decimator2.myDecimate( + buf[pos+88], + buf[pos+89], + &intbuf[44], + &intbuf[45]); + m_decimator2.myDecimate( + buf[pos+92], + buf[pos+93], + &intbuf[46], + &intbuf[47]); + m_decimator2.myDecimate( + buf[pos+96], + buf[pos+97], + &intbuf[48], + &intbuf[49]); + m_decimator2.myDecimate( + buf[pos+100], + buf[pos+101], + &intbuf[50], + &intbuf[51]); + m_decimator2.myDecimate( + buf[pos+104], + buf[pos+105], + &intbuf[52], + &intbuf[53]); + m_decimator2.myDecimate( + buf[pos+108], + buf[pos+109], + &intbuf[54], + &intbuf[55]); + m_decimator2.myDecimate( + buf[pos+112], + buf[pos+113], + &intbuf[56], + &intbuf[57]); + m_decimator2.myDecimate( + buf[pos+116], + buf[pos+117], + &intbuf[58], + &intbuf[59]); + m_decimator2.myDecimate( + buf[pos+120], + buf[pos+121], + &intbuf[60], + &intbuf[61]); + m_decimator2.myDecimate( + buf[pos+124], + buf[pos+125], + &intbuf[62], + &intbuf[63]); + + m_decimator4.myDecimate( + intbuf[0], + intbuf[1], + &intbuf[2], + &intbuf[3]); + m_decimator4.myDecimate( + intbuf[4], + intbuf[5], + &intbuf[6], + &intbuf[7]); + m_decimator4.myDecimate( + intbuf[8], + intbuf[9], + &intbuf[10], + &intbuf[11]); + m_decimator4.myDecimate( + intbuf[12], + intbuf[13], + &intbuf[14], + &intbuf[15]); + m_decimator4.myDecimate( + intbuf[16], + intbuf[17], + &intbuf[18], + &intbuf[19]); + m_decimator4.myDecimate( + intbuf[20], + intbuf[21], + &intbuf[22], + &intbuf[23]); + m_decimator4.myDecimate( + intbuf[24], + intbuf[25], + &intbuf[26], + &intbuf[27]); + m_decimator4.myDecimate( + intbuf[28], + intbuf[29], + &intbuf[30], + &intbuf[31]); + m_decimator4.myDecimate( + intbuf[32], + intbuf[33], + &intbuf[34], + &intbuf[35]); + m_decimator4.myDecimate( + intbuf[36], + intbuf[37], + &intbuf[38], + &intbuf[39]); + m_decimator4.myDecimate( + intbuf[40], + intbuf[41], + &intbuf[42], + &intbuf[43]); + m_decimator4.myDecimate( + intbuf[44], + intbuf[45], + &intbuf[46], + &intbuf[47]); + m_decimator4.myDecimate( + intbuf[48], + intbuf[49], + &intbuf[50], + &intbuf[51]); + m_decimator4.myDecimate( + intbuf[52], + intbuf[53], + &intbuf[54], + &intbuf[55]); + m_decimator4.myDecimate( + intbuf[56], + intbuf[57], + &intbuf[58], + &intbuf[59]); + m_decimator4.myDecimate( + intbuf[60], + intbuf[61], + &intbuf[62], + &intbuf[63]); + + m_decimator8.myDecimate( + intbuf[2], + intbuf[3], + &intbuf[6], + &intbuf[7]); + m_decimator8.myDecimate( + intbuf[10], + intbuf[11], + &intbuf[14], + &intbuf[15]); + m_decimator8.myDecimate( + intbuf[18], + intbuf[19], + &intbuf[22], + &intbuf[23]); + m_decimator8.myDecimate( + intbuf[26], + intbuf[27], + &intbuf[30], + &intbuf[31]); + m_decimator8.myDecimate( + intbuf[34], + intbuf[35], + &intbuf[38], + &intbuf[39]); + m_decimator8.myDecimate( + intbuf[42], + intbuf[43], + &intbuf[46], + &intbuf[47]); + m_decimator8.myDecimate( + intbuf[50], + intbuf[51], + &intbuf[54], + &intbuf[55]); + m_decimator8.myDecimate( + intbuf[58], + intbuf[59], + &intbuf[62], + &intbuf[63]); + + m_decimator16.myDecimate( + intbuf[6], + intbuf[7], + &intbuf[14], + &intbuf[15]); + m_decimator16.myDecimate( + intbuf[22], + intbuf[23], + &intbuf[30], + &intbuf[31]); + m_decimator16.myDecimate( + intbuf[38], + intbuf[39], + &intbuf[46], + &intbuf[47]); + m_decimator16.myDecimate( + intbuf[54], + intbuf[55], + &intbuf[62], + &intbuf[63]); + + m_decimator32.myDecimate( + intbuf[14], + intbuf[15], + &intbuf[30], + &intbuf[31]); + m_decimator32.myDecimate( + intbuf[46], + intbuf[47], + &intbuf[62], + &intbuf[63]); + + m_decimator64.myDecimate( + intbuf[30], + intbuf[31], + &intbuf[62], + &intbuf[63]); + + (**it).setReal(intbuf[62] * SDR_RX_SCALED); + (**it).setImag(intbuf[63] * SDR_RX_SCALED); + ++(*it); + } +} + diff --git a/sdrbase/dsp/decimatorsf.h b/sdrbase/dsp/decimatorsf.h new file mode 100644 index 000000000..3c631ee1e --- /dev/null +++ b/sdrbase/dsp/decimatorsf.h @@ -0,0 +1,57 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// 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 SDRBASE_DSP_DECIMATORSF_H_ +#define SDRBASE_DSP_DECIMATORSF_H_ + +#include "dsp/inthalfbandfilterdbf.h" + +#define DECIMATORSF_HB_FILTER_ORDER 64 + +class DecimatorsF +{ +public: + void decimate1(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate2_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate2_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate2_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate4_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate4_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate4_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate8_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate8_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate8_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate16_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate16_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate16_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate32_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate32_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate32_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate64_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate64_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate64_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + + IntHalfbandFilterDBF m_decimator2; // 1st stages + IntHalfbandFilterDBF m_decimator4; // 2nd stages + IntHalfbandFilterDBF m_decimator8; // 3rd stages + IntHalfbandFilterDBF m_decimator16; // 4th stages + IntHalfbandFilterDBF m_decimator32; // 5th stages + IntHalfbandFilterDBF m_decimator64; // 6th stages +}; + + + +#endif /* SDRBASE_DSP_DECIMATORSF_H_ */ diff --git a/sdrbase/dsp/hbfiltertraits.cpp b/sdrbase/dsp/hbfiltertraits.cpp index ba6008a32..8f82c1e36 100644 --- a/sdrbase/dsp/hbfiltertraits.cpp +++ b/sdrbase/dsp/hbfiltertraits.cpp @@ -30,6 +30,13 @@ const int32_t HBFIRFilterTraits<16>::hbCoeffs[4] = { (int32_t)(0.3076987787367443383246268240327481180429 * (1 << hbShift)), }; +const double HBFIRFilterTraits<16>::hbCoeffsF[4] = { + -0.0052391810630145274965685509016566356877, + 0.0232111017863650750947535073009930783883, + -0.0761058457486735451258397233686991967261, + 0.3076987787367443383246268240327481180429, +}; + const int16_t HBFIRFilterTraits<32>::hbMod[32+6] = { 31,32,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19, 20,21,22, 23,24,25,26,27,28,29,30,31,32,0,1,2 @@ -57,6 +64,17 @@ const int32_t HBFIRFilterTraits<32>::hbCoeffs[8] = { // (qint32)( 0.317237706405931241260276465254719369113 * (1 << hbShift)) }; +const double HBFIRFilterTraits<32>::hbCoeffsF[8] = { + -0.0018878783958199373254477348993418672762, + 0.0038624783041994003966734805288751886110, + -0.0082424665965482504098593707908548822161, + 0.0159471139705940345709933581019868142903, + -0.0286765592339759019246958615667608682998, + 0.0507185615622293764492845014046906726435, + -0.0980159074728618323613105189906491432339, + 0.3159417644358786247948955860920250415802, +}; + const int16_t HBFIRFilterTraits<48>::hbMod[48+6] = { 47,48,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23, 24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46, @@ -93,6 +111,21 @@ const int32_t HBFIRFilterTraits<48>::hbCoeffs[12] = { // (qint32)( 0.317491986549921390015072120149852707982 * (1 << hbShift)) }; +const double HBFIRFilterTraits<48>::hbCoeffsF[12] = { + -0.0011627994808655962074434020436797254661, + 0.0017451165792459334517860991553561689216, + -0.0029357205890606303047563052643909031758, + 0.0048726090910227891003780875678330630763, + -0.0077313759655872928144848543752232217230, + 0.0117637971494846688830238079503942572046, + -0.0173810771817523163074170611253066454083, + 0.0253500636065296450216699497559602605179, + -0.0373266939135983855102551842719549313188, + 0.0576685041500848358242414803953579394147, + -0.1024912545928038654086122960507054813206, + 0.3173768238826674692454332671331940218806, +}; + const int16_t HBFIRFilterTraits<64>::hbMod[64+6] = { 63,64,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23, 24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46, @@ -137,6 +170,25 @@ const int32_t HBFIRFilterTraits<64>::hbCoeffs[16] = { // (qint32)( 0.317657589850154464805598308885237202048 * (1 << hbShift)), }; +const double HBFIRFilterTraits<64>::hbCoeffsF[16] = { + -0.0004653050334792540416659067936677729449, + 0.0007120490624526883919470643391491648799, + -0.0012303473710125558716887983479182366864, + 0.0019716520179919017584369012041634050547, + -0.0029947484165425580261710170049127555103, + 0.0043703902150498061263128590780979720876, + -0.0061858352927315653213558022116558277048, + 0.0085554408639278121950777489246320328675, + -0.0116397924445187355563247066925214312505, + 0.0156852221106748394852115069397768820636, + -0.0211070832238078286147153761476147337817, + 0.0286850846890029896607554604770484729670, + -0.0400956173930921908055147184768429724500, + 0.0597215923200692666572564348825835622847, + -0.1036982054813635201195864965484361164272, + 0.3175014394028848885298543791577685624361, +}; + const int16_t HBFIRFilterTraits<80>::hbMod[80+6] = { 79,80,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23, 24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46, @@ -169,6 +221,29 @@ const int32_t HBFIRFilterTraits<80>::hbCoeffs[20] = { (int32_t)( 0.3176437752925042046214798574510496109724 * (1 << hbShift)), }; +const double HBFIRFilterTraits<80>::hbCoeffsF[20] = { + -0.0001054430663706784843331246137587697831, // ~1/9483 => hbShift = 14 + 0.0001895717826405601933066613629108587702, + -0.0003519516996893227891822497621632237497, + 0.0005975111594421821190753485453228677216, + -0.0009524124279789792160699768430731637636, + 0.0014474605824692796454677967687985074008, + -0.0021186428821101787461911314380813564640, + 0.0030082068742630901220236339099756150972, + -0.0041664004891296358909502650647027621744, + 0.0056547140936428538088298623165428580251, + -0.0075518323360079901707120342280177283101, + 0.0099644038858163180155669280679830990266, + -0.0130470841719700410971105597468522319105, + 0.0170422818715445859028001507340377429500, + -0.0223637819225956900603957677731159492396, + 0.0297925991327811050257690084208661573939, + -0.0410092859102263174175817539435229264200, + 0.0604034694948822267757115866970707429573, + -0.1041194584045879306666293473426776472479, + 0.3176437752925042046214798574510496109724, +}; + const int16_t HBFIRFilterTraits<96>::hbMod[96+6] = { 95,96,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23, 24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46, @@ -206,6 +281,33 @@ const int32_t HBFIRFilterTraits<96>::hbCoeffs[24] = { (int32_t)( 0.3177437550265513332981015537370694801211 * (1 << hbShift)), }; +const double HBFIRFilterTraits<96>::hbCoeffsF[24] = { + -0.0000243052463317893968695708462046667364, + 0.0000503567741519847557611806732058568059, + -0.0001002354600628052128195172310043403741, + 0.0001801275832684542921834081052878673290, + -0.0003014864432246496970743687704441526876, + 0.0004783148860127731604417744559754055445, + -0.0007274200147704492930983422027679807798, + 0.0010686503612886001472748187524075547117, + -0.0015251456116906108098629779590282851132, + 0.0021238131085570461677181075543785482296, + -0.0028960654265650425873146467381502588978, + 0.0038789688077727475616629515542399531114, + -0.0051173875903961539915454359572777320864, + 0.0066675444490017317031305132957186287967, + -0.0086031967328669932404405784609480178915, + 0.0110268456349653827530676863943881471641, + -0.0140900919878225727721599014330422505736, + 0.0180336055419063577553995258995200856589, + -0.0232708957455770061584221508610426099040, + 0.0305843805330435619671547442521841730922, + -0.0416576245224431485070226699463091790676, + 0.0608846679850302968661779345893592108041, + -0.1044156487571061137087369274922821205109, + 0.3177437550265513332981015537370694801211, +}; + const int16_t HBFIRFilterTraits<112>::hbMod[112+6] = { 111,112,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23, 24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46, @@ -248,6 +350,36 @@ const int32_t HBFIRFilterTraits<112>::hbCoeffs[28] = { (int32_t)( 0.3178181645034457436516106554336147382855 * (1 << hbShift)), }; +const double HBFIRFilterTraits<112>::hbCoeffsF[28] = { + -0.0000057182612173497993884982611156875265, + 0.0000134089330475142792093150995169636985, + -0.0000285019056923813186876261183133607346, + 0.0000540489980941085909355720007241075109, + -0.0000947833751586818473982426480617391462, + 0.0001567867952902222809536542103003853299, + -0.0002476681450895876299839182266282477940, + 0.0003767405865262860096935593201550318554, + -0.0005551920408570068304551781146471967077, + 0.0007962529081739059839267769191906154447, + -0.0011153731476064448775026294313761354715, + 0.0015304714714705458088878087252737714152, + -0.0020622467141092528514212389723070373293, + 0.0027347048425079849461039049884902851772, + -0.0035759786171320282616159502708796935622, + 0.0046196952795832949348331375460929848487, + -0.0059072308383088713984454543037827534135, + 0.0074914857942512255370437479484735376900, + -0.0094433233524672671732602680094714742154, + 0.0118628557280401076418074879370578855742, + -0.0149000865720731560937206694461565348320, + 0.0187949228094094408780811988890491193160, + -0.0239611153097040799342387629167205886915, + 0.0311823240686547251132587632582726655528, + -0.0421443341867254184229807378869736567140, + 0.0612443342926724393349147135268140118569, + -0.1046363792986205604185201423206308390945, + 0.3178181645034457436516106554336147382855, +}; const int16_t HBFIRFilterTraits<128>::hbMod[128+6] = { 127,128,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23, @@ -295,5 +427,40 @@ const int32_t HBFIRFilterTraits<128>::hbCoeffs[32] = { (int32_t)( 0.3178751792920155860855402352171950042248 * (1 << hbShift)), }; +const double HBFIRFilterTraits<128>::hbCoeffsF[32] = { + //* Remez as in https://www.dsprelated.com/showcode/270.php */ + -0.0000013530084481063586964138655693856705, // ~1/739098 => hbShift = 20 + 0.0000035468835939308468221931557040615957, + -0.0000080263259193852748679242486984364291, + 0.0000160249362715262112246382419922241525, + -0.0000293930772937943995460653712203935584, + 0.0000506245785103059592661099708177374623, + -0.0000829848508757281692112955928664064231, + 0.0001306421953216197048494584542766006052, + -0.0001988007175677746298826653603697423023, + 0.0002938302746977689504891129157471141298, + -0.0004233934809845499216279796073081342911, + 0.0005965709177428588560684885599982862914, + -0.0008239883872841064762701512869114139903, + 0.0011179618447797630680778935285957231827, + -0.0014926744261021872121897313689942166093, + 0.0019644262679035678388628216595179765136, + -0.0025520032927806384458191413244776413194, + 0.0032772538071471992750238744207536001340, + -0.0041660018952565701713663948169141804101, + 0.0052495120038521464814196271220225753495, + -0.0065668614662222155736737150277804175857, + 0.0081688408784787811672822854802689107601, + -0.0101245136956070701239607245724982931279, + 0.0125326183062810583845880785247572930530, + -0.0155423066893098579810406079104723175988, + 0.0193932322698959942741669948418348212726, + -0.0244995384963461564076236953724219347350, + 0.0316459368298866380864176051090908003971, + -0.0425198999626832385700936356442980468273, + 0.0615208850123762293615747864805598510429, + -0.1048057030317238041972061068918264936656, + 0.3178751792920155860855402352171950042248, +}; diff --git a/sdrbase/dsp/hbfiltertraits.h b/sdrbase/dsp/hbfiltertraits.h index b896ce2ae..f72e46765 100644 --- a/sdrbase/dsp/hbfiltertraits.h +++ b/sdrbase/dsp/hbfiltertraits.h @@ -38,6 +38,7 @@ struct HBFIRFilterTraits<16> static const int32_t hbShift = 12; static const int16_t hbMod[16+6]; static const int32_t hbCoeffs[4] __attribute__ ((aligned (16))); + static const double hbCoeffsF[4]; }; template<> @@ -47,6 +48,7 @@ struct HBFIRFilterTraits<32> static const int32_t hbShift = 12; static const int16_t hbMod[32+6]; static const int32_t hbCoeffs[8] __attribute__ ((aligned (32))); + static const double hbCoeffsF[8]; }; template<> @@ -56,6 +58,7 @@ struct HBFIRFilterTraits<48> static const int32_t hbShift = 12; static const int16_t hbMod[48+6]; static const int32_t hbCoeffs[12] __attribute__ ((aligned (16))); + static const double hbCoeffsF[12]; }; template<> @@ -65,6 +68,7 @@ struct HBFIRFilterTraits<64> static const int32_t hbShift = 12; static const int16_t hbMod[64+6]; static const int32_t hbCoeffs[16] __attribute__ ((aligned (32))); + static const double hbCoeffsF[16]; }; template<> @@ -74,6 +78,7 @@ struct HBFIRFilterTraits<80> static const int32_t hbShift = 14; static const int16_t hbMod[80+6]; static const int32_t hbCoeffs[20] __attribute__ ((aligned (16))); + static const double hbCoeffsF[20]; }; template<> @@ -83,6 +88,7 @@ struct HBFIRFilterTraits<96> static const int32_t hbShift = 16; static const int16_t hbMod[96+6]; static const int32_t hbCoeffs[24] __attribute__ ((aligned (32))); + static const double hbCoeffsF[24]; }; template<> @@ -92,6 +98,7 @@ struct HBFIRFilterTraits<112> static const int32_t hbShift = 18; static const int16_t hbMod[112+6]; static const int32_t hbCoeffs[28] __attribute__ ((aligned (16))); + static const double hbCoeffsF[28]; }; template<> @@ -101,6 +108,7 @@ struct HBFIRFilterTraits<128> static const int32_t hbShift = 20; static const int16_t hbMod[128+6]; static const int32_t hbCoeffs[32] __attribute__ ((aligned (16))); + static const double hbCoeffsF[32]; }; #endif /* SDRBASE_DSP_HBFILTERTRAITS_H_ */ diff --git a/sdrbase/dsp/inthalfbandfilterdbf.h b/sdrbase/dsp/inthalfbandfilterdbf.h new file mode 100644 index 000000000..01b281f50 --- /dev/null +++ b/sdrbase/dsp/inthalfbandfilterdbf.h @@ -0,0 +1,711 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 F4EXB // +// written by Edouard Griffiths // +// // +// Float 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_DBF_H +#define INCLUDE_INTHALFBANDFILTER_DBF_H + +#include +#include "dsp/dsptypes.h" +#include "dsp/hbfiltertraits.h" +#include "util/export.h" + +template +class SDRANGEL_API IntHalfbandFilterDBF { +public: + IntHalfbandFilterDBF(); + + // downsample by 2, return center part of original spectrum + bool workDecimateCenter(Sample* sample) + { + // insert sample into ring-buffer + storeSampleFixReal((FixReal) sample->real(), (FixReal) sample->imag()); + + switch(m_state) + { + case 0: + // advance write-pointer + advancePointer(); + // next state + m_state = 1; + // tell caller we don't have a new sample + return false; + + default: + // save result + doFIR(sample); + // advance write-pointer + advancePointer(); + // 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 workInterpolateCenterZeroStuffing(Sample* sampleIn, Sample *SampleOut) + { + switch(m_state) + { + case 0: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) 0, (FixReal) 0); + // save result + doFIR(SampleOut); + // advance write-pointer + advancePointer(); + // next state + m_state = 1; + // tell caller we didn't consume the sample + return false; + + default: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) sampleIn->real(), (FixReal) sampleIn->imag()); + // save result + doFIR(SampleOut); + // advance write-pointer + advancePointer(); + // next state + m_state = 0; + // tell caller we consumed the sample + return true; + } + } + + /** Optimized upsampler by 2 not calculating FIR with inserted null samples */ + bool workInterpolateCenter(Sample* sampleIn, Sample *SampleOut) + { + switch(m_state) + { + case 0: + // return the middle peak + SampleOut->setReal(m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][0]); + SampleOut->setImag(m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][1]); + m_state = 1; // next state + return false; // tell caller we didn't consume the sample + + default: + // calculate with non null samples + doInterpolateFIR(SampleOut); + + // insert sample into ring double buffer + m_samplesDB[m_ptr][0] = sampleIn->real(); + m_samplesDB[m_ptr][1] = sampleIn->imag(); + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][0] = sampleIn->real(); + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][1] = sampleIn->imag(); + + // advance pointer + if (m_ptr < (HBFIRFilterTraits::hbOrder/2) - 1) { + m_ptr++; + } else { + m_ptr = 0; + } + + m_state = 0; // next state + return true; // tell caller we consumed the sample + } + } + + // downsample by 2, return lower half of original spectrum + bool workDecimateLowerHalf(Sample* sample) + { + switch(m_state) + { + case 0: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) -sample->imag(), (FixReal) sample->real()); + // advance write-pointer + advancePointer(); + // next state + m_state = 1; + // tell caller we don't have a new sample + return false; + + case 1: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) -sample->real(), (FixReal) -sample->imag()); + // save result + doFIR(sample); + // advance write-pointer + advancePointer(); + // next state + m_state = 2; + // tell caller we have a new sample + return true; + + case 2: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) sample->imag(), (FixReal) -sample->real()); + // advance write-pointer + advancePointer(); + // next state + m_state = 3; + // tell caller we don't have a new sample + return false; + + default: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) sample->real(), (FixReal) sample->imag()); + // save result + doFIR(sample); + // advance write-pointer + advancePointer(); + // next state + m_state = 0; + // tell caller we have a new sample + return true; + } + } + + /** Optimized upsampler by 2 not calculating FIR with inserted null samples */ + bool workInterpolateLowerHalf(Sample* sampleIn, Sample *sampleOut) + { + Sample s; + + switch(m_state) + { + case 0: + // return the middle peak + sampleOut->setReal(m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][1]); // imag + sampleOut->setImag(-m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][0]); // - real + m_state = 1; // next state + return false; // tell caller we didn't consume the sample + + case 1: + // calculate with non null samples + doInterpolateFIR(&s); + sampleOut->setReal(-s.real()); + sampleOut->setImag(-s.imag()); + + // insert sample into ring double buffer + m_samplesDB[m_ptr][0] = sampleIn->real(); + m_samplesDB[m_ptr][1] = sampleIn->imag(); + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][0] = sampleIn->real(); + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][1] = sampleIn->imag(); + + // advance pointer + if (m_ptr < (HBFIRFilterTraits::hbOrder/2) - 1) { + m_ptr++; + } else { + m_ptr = 0; + } + + m_state = 2; // next state + return true; // tell caller we consumed the sample + + case 2: + // return the middle peak + sampleOut->setReal(-m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][1]); // - imag + sampleOut->setImag(m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][0]); // real + m_state = 3; // next state + return false; // tell caller we didn't consume the sample + + default: + // calculate with non null samples + doInterpolateFIR(&s); + sampleOut->setReal(s.real()); + sampleOut->setImag(s.imag()); + + // insert sample into ring double buffer + m_samplesDB[m_ptr][0] = sampleIn->real(); + m_samplesDB[m_ptr][1] = sampleIn->imag(); + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][0] = sampleIn->real(); + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][1] = sampleIn->imag(); + + // advance pointer + if (m_ptr < (HBFIRFilterTraits::hbOrder/2) - 1) { + m_ptr++; + } else { + m_ptr = 0; + } + + m_state = 0; // next state + return true; // tell caller we consumed the sample + } + } + + // upsample by 2, from lower half of original spectrum - double buffer variant + bool workInterpolateLowerHalfZeroStuffing(Sample* sampleIn, Sample *sampleOut) + { + Sample s; + + switch(m_state) + { + case 0: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) 0, (FixReal) 0); + + // save result + doFIR(&s); + sampleOut->setReal(s.imag()); + sampleOut->setImag(-s.real()); + + // advance write-pointer + advancePointer(); + + // next state + m_state = 1; + + // tell caller we didn't consume the sample + return false; + + case 1: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) sampleIn->real(), (FixReal) sampleIn->imag()); + + // save result + doFIR(&s); + sampleOut->setReal(-s.real()); + sampleOut->setImag(-s.imag()); + + // advance write-pointer + advancePointer(); + + // next state + m_state = 2; + + // tell caller we consumed the sample + return true; + + case 2: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) 0, (FixReal) 0); + + // save result + doFIR(&s); + sampleOut->setReal(-s.imag()); + sampleOut->setImag(s.real()); + + // advance write-pointer + advancePointer(); + + // next state + m_state = 3; + + // tell caller we didn't consume the sample + return false; + + default: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) sampleIn->real(), (FixReal) sampleIn->imag()); + + // save result + doFIR(&s); + sampleOut->setReal(s.real()); + sampleOut->setImag(s.imag()); + + // advance write-pointer + advancePointer(); + + // 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 + storeSampleFixReal((FixReal) sample->imag(), (FixReal) -sample->real()); + // advance write-pointer + advancePointer(); + // next state + m_state = 1; + // tell caller we don't have a new sample + return false; + + case 1: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) -sample->real(), (FixReal) -sample->imag()); + // save result + doFIR(sample); + // advance write-pointer + advancePointer(); + // next state + m_state = 2; + // tell caller we have a new sample + return true; + + case 2: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) -sample->imag(), (FixReal) sample->real()); + // advance write-pointer + advancePointer(); + // next state + m_state = 3; + // tell caller we don't have a new sample + return false; + + default: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) sample->real(), (FixReal) sample->imag()); + // save result + doFIR(sample); + // advance write-pointer + advancePointer(); + // next state + m_state = 0; + // tell caller we have a new sample + return true; + } + } + + /** Optimized upsampler by 2 not calculating FIR with inserted null samples */ + bool workInterpolateUpperHalf(Sample* sampleIn, Sample *sampleOut) + { + Sample s; + + switch(m_state) + { + case 0: + // return the middle peak + sampleOut->setReal(-m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][1]); // - imag + sampleOut->setImag(m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][0]); // + real + m_state = 1; // next state + return false; // tell caller we didn't consume the sample + + case 1: + // calculate with non null samples + doInterpolateFIR(&s); + sampleOut->setReal(-s.real()); + sampleOut->setImag(-s.imag()); + + // insert sample into ring double buffer + m_samplesDB[m_ptr][0] = sampleIn->real(); + m_samplesDB[m_ptr][1] = sampleIn->imag(); + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][0] = sampleIn->real(); + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][1] = sampleIn->imag(); + + // advance pointer + if (m_ptr < (HBFIRFilterTraits::hbOrder/2) - 1) { + m_ptr++; + } else { + m_ptr = 0; + } + + m_state = 2; // next state + return true; // tell caller we consumed the sample + + case 2: + // return the middle peak + sampleOut->setReal(m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][1]); // + imag + sampleOut->setImag(-m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][0]); // - real + m_state = 3; // next state + return false; // tell caller we didn't consume the sample + + default: + // calculate with non null samples + doInterpolateFIR(&s); + sampleOut->setReal(s.real()); + sampleOut->setImag(s.imag()); + + // insert sample into ring double buffer + m_samplesDB[m_ptr][0] = sampleIn->real(); + m_samplesDB[m_ptr][1] = sampleIn->imag(); + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][0] = sampleIn->real(); + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][1] = sampleIn->imag(); + + // advance pointer + if (m_ptr < (HBFIRFilterTraits::hbOrder/2) - 1) { + m_ptr++; + } else { + m_ptr = 0; + } + + m_state = 0; // next state + return true; // tell caller we consumed the sample + } + } + + // upsample by 2, move original spectrum to upper half - double buffer variant + bool workInterpolateUpperHalfZeroStuffing(Sample* sampleIn, Sample *sampleOut) + { + Sample s; + + switch(m_state) + { + case 0: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) 0, (FixReal) 0); + + // save result + doFIR(&s); + sampleOut->setReal(-s.imag()); + sampleOut->setImag(s.real()); + + // advance write-pointer + advancePointer(); + + // next state + m_state = 1; + + // tell caller we didn't consume the sample + return false; + + case 1: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) sampleIn->real(), (FixReal) sampleIn->imag()); + + // save result + doFIR(&s); + sampleOut->setReal(-s.real()); + sampleOut->setImag(-s.imag()); + + // advance write-pointer + advancePointer(); + + // next state + m_state = 2; + + // tell caller we consumed the sample + return true; + + case 2: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) 0, (FixReal) 0); + + // save result + doFIR(&s); + sampleOut->setReal(s.imag()); + sampleOut->setImag(-s.real()); + + // advance write-pointer + advancePointer(); + + // next state + m_state = 3; + + // tell caller we didn't consume the sample + return false; + + default: + // insert sample into ring-buffer + storeSampleFixReal((FixReal) sampleIn->real(), (FixReal) sampleIn->imag()); + + // save result + doFIR(&s); + sampleOut->setReal(s.real()); + sampleOut->setImag(s.imag()); + + // advance write-pointer + advancePointer(); + + // next state + m_state = 0; + + // tell caller we consumed the sample + return true; + } + } + + void myDecimate(const Sample* sample1, Sample* sample2) + { + storeSampleFixReal((FixReal) sample1->real(), (FixReal) sample1->imag()); + advancePointer(); + + storeSampleFixReal((FixReal) sample2->real(), (FixReal) sample2->imag()); + doFIR(sample2); + advancePointer(); + } + + void myDecimate(AccuType x1, AccuType y1, AccuType *x2, AccuType *y2) + { + storeSampleAccu(x1, y1); + advancePointer(); + + storeSampleAccu(*x2, *y2); + doFIRAccu(x2, y2); + advancePointer(); + } + + /** Simple zero stuffing and filter */ + void myInterpolateZeroStuffing(Sample* sample1, Sample* sample2) + { + storeSampleFixReal((FixReal) sample1->real(), (FixReal) sample1->imag()); + doFIR(sample1); + advancePointer(); + + storeSampleFixReal((FixReal) 0, (FixReal) 0); + doFIR(sample2); + advancePointer(); + } + + /** Optimized upsampler by 2 not calculating FIR with inserted null samples */ + void myInterpolate(qint32 *x1, qint32 *y1, qint32 *x2, qint32 *y2) + { + // insert sample into ring double buffer + m_samplesDB[m_ptr][0] = *x1; + m_samplesDB[m_ptr][1] = *y1; + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][0] = *x1; + m_samplesDB[m_ptr + HBFIRFilterTraits::hbOrder/2][1] = *y1; + + // advance pointer + if (m_ptr < (HBFIRFilterTraits::hbOrder/2) - 1) { + m_ptr++; + } else { + m_ptr = 0; + } + + // first output sample calculated with the middle peak + *x1 = m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][0]; + *y1 = m_samplesDB[m_ptr + (HBFIRFilterTraits::hbOrder/4) - 1][1]; + + // second sample calculated with the filter + doInterpolateFIR(x2, y2); + } + +protected: + SampleType m_samplesDB[2*(HBFIRFilterTraits::hbOrder - 1)][2]; // double buffer technique + int m_ptr; + int m_size; + int m_state; + + void storeSampleFixReal(const FixReal& sampleI, const FixReal& sampleQ) + { + m_samplesDB[m_ptr][0] = sampleI / SDR_RX_SCALED; + m_samplesDB[m_ptr][1] = sampleQ / SDR_RX_SCALED; + m_samplesDB[m_ptr + m_size][0] = sampleI / SDR_RX_SCALED; + m_samplesDB[m_ptr + m_size][1] = sampleQ / SDR_RX_SCALED; + } + + void storeSampleAccu(AccuType x, AccuType y) + { + m_samplesDB[m_ptr][0] = x; + m_samplesDB[m_ptr][1] = y; + m_samplesDB[m_ptr + m_size][0] = x; + m_samplesDB[m_ptr + m_size][1] = y; + } + + void advancePointer() + { + m_ptr = m_ptr + 1 < m_size ? m_ptr + 1: 0; + } + + void doFIR(Sample* sample) + { + int a = m_ptr + m_size; // tip pointer + int b = m_ptr + 1; // tail pointer + AccuType iAcc = 0; + AccuType qAcc = 0; + + for (int i = 0; i < HBFIRFilterTraits::hbOrder / 4; i++) + { + iAcc += (m_samplesDB[a][0] + m_samplesDB[b][0]) * HBFIRFilterTraits::hbCoeffsF[i]; + qAcc += (m_samplesDB[a][1] + m_samplesDB[b][1]) * HBFIRFilterTraits::hbCoeffsF[i]; + a -= 2; + b += 2; + } + + iAcc += m_samplesDB[b-1][0] << (HBFIRFilterTraits::hbShift - 1); + qAcc += m_samplesDB[b-1][1] << (HBFIRFilterTraits::hbShift - 1); + + sample->setReal(iAcc*SDR_RX_SCALED); + sample->setImag(qAcc*SDR_RX_SCALED); + } + + void doFIRAccu(AccuType *x, AccuType *y) + { + int a = m_ptr + m_size; // tip pointer + int b = m_ptr + 1; // tail pointer + AccuType iAcc = 0; + AccuType qAcc = 0; + + for (int i = 0; i < HBFIRFilterTraits::hbOrder / 4; i++) + { + iAcc += (m_samplesDB[a][0] + m_samplesDB[b][0]) * HBFIRFilterTraits::hbCoeffsF[i]; + qAcc += (m_samplesDB[a][1] + m_samplesDB[b][1]) * HBFIRFilterTraits::hbCoeffsF[i]; + a -= 2; + b += 2; + } + + iAcc += m_samplesDB[b-1][0] / 2.0; + qAcc += m_samplesDB[b-1][1] / 2.0; + + *x = iAcc; // HB_SHIFT incorrect do not loose the gained bit + *y = qAcc; + } + + void doInterpolateFIR(Sample* sample) + { + qint16 a = m_ptr; + qint16 b = m_ptr + (HBFIRFilterTraits::hbOrder / 2) - 1; + + // go through samples in buffer + AccuType iAcc = 0; + AccuType qAcc = 0; + + for (int i = 0; i < HBFIRFilterTraits::hbOrder / 4; i++) + { + iAcc += (m_samplesDB[a][0] + m_samplesDB[b][0]) * HBFIRFilterTraits::hbCoeffsF[i]; + qAcc += (m_samplesDB[a][1] + m_samplesDB[b][1]) * HBFIRFilterTraits::hbCoeffsF[i]; + a++; + b--; + } + + sample->setReal(iAcc * SDR_RX_SCALED); + sample->setImag(qAcc * SDR_RX_SCALED); + } + + void doInterpolateFIR(qint32 *x, qint32 *y) + { + qint16 a = m_ptr; + qint16 b = m_ptr + (HBFIRFilterTraits::hbOrder / 2) - 1; + + // go through samples in buffer + AccuType iAcc = 0; + AccuType qAcc = 0; + + for (int i = 0; i < HBFIRFilterTraits::hbOrder / 4; i++) + { + iAcc += (m_samplesDB[a][0] + m_samplesDB[b][0]) * HBFIRFilterTraits::hbCoeffsF[i]; + qAcc += (m_samplesDB[a][1] + m_samplesDB[b][1]) * HBFIRFilterTraits::hbCoeffsF[i]; + a++; + b--; + } + + *x = iAcc * SDR_RX_SCALED; + *y = qAcc * SDR_RX_SCALED; + } +}; + +template +IntHalfbandFilterDBF::IntHalfbandFilterDBF() +{ + m_size = HBFIRFilterTraits::hbOrder - 1; + + for (int i = 0; i < m_size; i++) + { + m_samplesDB[i][0] = 0; + m_samplesDB[i][1] = 0; + } + + m_ptr = 0; + m_state = 0; +} + +#endif // INCLUDE_INTHALFBANDFILTER_DBF_H