diff --git a/CMakeLists.txt b/CMakeLists.txt index b39c72ef7..047c3caa1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -315,6 +315,7 @@ target_link_libraries(sdrangelbench ${QT_LIBRARIES} ) +target_compile_features(sdrangelbench PRIVATE cxx_generalized_initializers) # cmake >= 3.1.0 qt5_use_modules(sdrangelbench Multimedia) ############################################################################## diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index c69bced99..1ae66fa84 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/decimatorsff.cpp dsp/decimatorsfi.cpp dsp/dspcommands.cpp dsp/dspengine.cpp @@ -104,6 +105,7 @@ set(sdrbase_HEADERS dsp/cwkeyer.h dsp/cwkeyersettings.h dsp/decimators.h + dsp/decimatorsff.h dsp/decimatorsfi.h dsp/decimatorsu.h dsp/interpolators.h @@ -125,7 +127,8 @@ set(sdrbase_HEADERS dsp/hbfiltertraits.h dsp/inthalfbandfilter.h dsp/inthalfbandfilterdb.h - dsp/inthalfbandfilterdbf.h + dsp/inthalfbandfilterdbff.h + dsp/inthalfbandfilterdbfi.h dsp/inthalfbandfiltereo1.h dsp/inthalfbandfiltereo1i.h dsp/inthalfbandfilterst.h diff --git a/sdrbase/dsp/decimatorsff.cpp b/sdrbase/dsp/decimatorsff.cpp new file mode 100644 index 000000000..0134865e8 --- /dev/null +++ b/sdrbase/dsp/decimatorsff.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 "decimatorsff.h" + +void DecimatorsFF::decimate1(FSampleVector::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); + (**it).setImag(yimag); + ++(*it); // Valgrind optim (comment not repeated) + } +} + +void DecimatorsFF::decimate2_cen(FSampleVector::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]); + (**it).setImag(intbuf[1]); + + ++(*it); + } +} + +void DecimatorsFF::decimate2_inf(FSampleVector::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); + (**it).setImag(yimag); + ++(*it); + + xreal = (buf[pos+7] - buf[pos+4]); + yimag = (- buf[pos+5] - buf[pos+6]); + (**it).setReal(xreal); + (**it).setImag(yimag); + ++(*it); + } +} + +void DecimatorsFF::decimate2_sup(FSampleVector::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); + (**it).setImag(yimag); + ++(*it); + + xreal = (buf[pos+6] - buf[pos+5]); + yimag = (buf[pos+4] + buf[pos+7]); + (**it).setReal(xreal); + (**it).setImag(yimag); + ++(*it); + } +} + +void DecimatorsFF::decimate4_inf(FSampleVector::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); + (**it).setImag(yimag); + + ++(*it); + } +} + +void DecimatorsFF::decimate4_sup(FSampleVector::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); + (**it).setImag(yimag); + + ++(*it); + } +} + +void DecimatorsFF::decimate8_inf(FSampleVector::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]); + (**it).setImag(yimag[1]); + + ++(*it); + } +} + +void DecimatorsFF::decimate8_sup(FSampleVector::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]); + (**it).setImag(yimag[1]); + + ++(*it); + } +} + +void DecimatorsFF::decimate16_inf(FSampleVector::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]); + (**it).setImag(yimag[3]); + + ++(*it); + } +} + +void DecimatorsFF::decimate16_sup(FSampleVector::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]); + (**it).setImag(yimag[3]); + + ++(*it); + } +} + +void DecimatorsFF::decimate32_inf(FSampleVector::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]); + (**it).setImag(yimag[7]); + + ++(*it); + } +} + +void DecimatorsFF::decimate32_sup(FSampleVector::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]); + (**it).setImag(yimag[7]); + + ++(*it); + } +} + +void DecimatorsFF::decimate64_inf(FSampleVector::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]); + (**it).setImag(yimag[15]); + + ++(*it); + } +} + +void DecimatorsFF::decimate64_sup(FSampleVector::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]); + (**it).setImag(yimag[15]); + + ++(*it); + } +} + +void DecimatorsFF::decimate4_cen(FSampleVector::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]); + (**it).setImag(intbuf[3]); + ++(*it); + } +} + +void DecimatorsFF::decimate8_cen(FSampleVector::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]); + (**it).setImag(intbuf[7]); + ++(*it); + } +} + +void DecimatorsFF::decimate16_cen(FSampleVector::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]); + (**it).setImag(intbuf[15]); + ++(*it); + } +} + +void DecimatorsFF::decimate32_cen(FSampleVector::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]); + (**it).setImag(intbuf[31]); + ++(*it); + } +} + +void DecimatorsFF::decimate64_cen(FSampleVector::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]); + (**it).setImag(intbuf[63]); + ++(*it); + } +} + diff --git a/sdrbase/dsp/decimatorsff.h b/sdrbase/dsp/decimatorsff.h new file mode 100644 index 000000000..649a0fc6c --- /dev/null +++ b/sdrbase/dsp/decimatorsff.h @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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_DECIMATORSFF_H_ +#define SDRBASE_DSP_DECIMATORSFF_H_ + +#include "dsp/inthalfbandfilterdbff.h" +#include "export.h" + +#define DECIMATORSFF_HB_FILTER_ORDER 64 + +/** Decimators with float input and float output */ +class SDRBASE_API DecimatorsFF +{ +public: + void decimate1(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate2_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate2_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate2_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate4_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate4_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate4_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate8_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate8_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate8_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate16_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate16_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate16_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate32_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate32_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate32_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate64_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate64_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + void decimate64_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); + + IntHalfbandFilterDBFF m_decimator2; // 1st stages + IntHalfbandFilterDBFF m_decimator4; // 2nd stages + IntHalfbandFilterDBFF m_decimator8; // 3rd stages + IntHalfbandFilterDBFF m_decimator16; // 4th stages + IntHalfbandFilterDBFF m_decimator32; // 5th stages + IntHalfbandFilterDBFF m_decimator64; // 6th stages +}; + + + +#endif /* SDRBASE_DSP_DECIMATORSFF_H_ */ diff --git a/sdrbase/dsp/decimatorsfi.h b/sdrbase/dsp/decimatorsfi.h index 31f8fe50e..283cb6e0a 100644 --- a/sdrbase/dsp/decimatorsfi.h +++ b/sdrbase/dsp/decimatorsfi.h @@ -17,10 +17,10 @@ #ifndef SDRBASE_DSP_DECIMATORSFI_H_ #define SDRBASE_DSP_DECIMATORSFI_H_ -#include "dsp/inthalfbandfilterdbf.h" +#include "dsp/inthalfbandfilterdbfi.h" #include "export.h" -#define DECIMATORSF_HB_FILTER_ORDER 64 +#define DECIMATORSFI_HB_FILTER_ORDER 64 /** Decimators with float input and integer output */ class SDRBASE_API DecimatorsFI @@ -46,12 +46,12 @@ public: 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 + IntHalfbandFilterDBFI m_decimator2; // 1st stages + IntHalfbandFilterDBFI m_decimator4; // 2nd stages + IntHalfbandFilterDBFI m_decimator8; // 3rd stages + IntHalfbandFilterDBFI m_decimator16; // 4th stages + IntHalfbandFilterDBFI m_decimator32; // 5th stages + IntHalfbandFilterDBFI m_decimator64; // 6th stages }; diff --git a/sdrbase/dsp/dsptypes.h b/sdrbase/dsp/dsptypes.h index e3913a785..f39f9deb7 100644 --- a/sdrbase/dsp/dsptypes.h +++ b/sdrbase/dsp/dsptypes.h @@ -64,6 +64,28 @@ struct Sample FixReal m_imag; }; +struct FSample +{ + FSample() : m_real(0), m_imag(0) {} + FSample(Real real) : m_real(real), m_imag(0) {} + FSample(Real real, Real imag) : m_real(real), m_imag(imag) {} + FSample(const FSample& other) : m_real(other.m_real), m_imag(other.m_imag) {} + inline FSample& operator=(const FSample& other) { m_real = other.m_real; m_imag = other.m_imag; return *this; } + + inline FSample& operator+=(const FSample& other) { m_real += other.m_real; m_imag += other.m_imag; return *this; } + inline FSample& operator-=(const FSample& other) { m_real -= other.m_real; m_imag -= other.m_imag; return *this; } + inline FSample& operator/=(const Real& divisor) { m_real /= divisor; m_imag /= divisor; return *this; } + + inline void setReal(Real v) { m_real = v; } + inline void setImag(Real v) { m_imag = v; } + + inline Real real() const { return m_real; } + inline Real imag() const { return m_imag; } + + Real m_real; + Real m_imag; +}; + struct AudioSample { qint16 l; qint16 r; @@ -71,6 +93,7 @@ struct AudioSample { #pragma pack(pop) typedef std::vector SampleVector; +typedef std::vector FSampleVector; typedef std::vector AudioVector; #endif // INCLUDE_DSPTYPES_H diff --git a/sdrbase/dsp/inthalfbandfilterdbff.h b/sdrbase/dsp/inthalfbandfilterdbff.h new file mode 100644 index 000000000..2816f2696 --- /dev/null +++ b/sdrbase/dsp/inthalfbandfilterdbff.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_DBFF_H +#define INCLUDE_INTHALFBANDFILTER_DBFF_H + +#include +#include "dsp/dsptypes.h" +#include "dsp/hbfiltertraits.h" +#include "export.h" + +template +class SDRBASE_API IntHalfbandFilterDBFF { +public: + IntHalfbandFilterDBFF(); + + // downsample by 2, return center part of original spectrum + bool workDecimateCenter(FSample* sample) + { + // insert sample into ring-buffer + storeSampleReal((Real) sample->real(), (Real) 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(FSample* sampleIn, FSample *SampleOut) + { + switch(m_state) + { + case 0: + // insert sample into ring-buffer + storeSampleReal((Real) 0, (Real) 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 + storeSampleReal((Real) sampleIn->real(), (Real) 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(FSample* sampleIn, FSample *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(FSample* sample) + { + switch(m_state) + { + case 0: + // insert sample into ring-buffer + storeSampleReal((Real) -sample->imag(), (Real) 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 + storeSampleReal((Real) -sample->real(), (Real) -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 + storeSampleReal((Real) sample->imag(), (Real) -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 + storeSampleReal((Real) sample->real(), (Real) 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(FSample* sampleIn, FSample *sampleOut) + { + FSample 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(FSample* sampleIn, FSample *sampleOut) + { + FSample s; + + switch(m_state) + { + case 0: + // insert sample into ring-buffer + storeSampleReal((Real) 0, (Real) 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 + storeSampleReal((Real) sampleIn->real(), (Real) 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 + storeSampleReal((Real) 0, (Real) 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 + storeSampleReal((Real) sampleIn->real(), (Real) 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(FSample* sample) + { + switch(m_state) + { + case 0: + // insert sample into ring-buffer + storeSampleReal((Real) sample->imag(), (Real) -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 + storeSampleReal((Real) -sample->real(), (Real) -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 + storeSampleReal((Real) -sample->imag(), (Real) 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 + storeSampleReal((Real) sample->real(), (Real) 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(FSample* sampleIn, FSample *sampleOut) + { + FSample 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(FSample* sampleIn, FSample *sampleOut) + { + FSample s; + + switch(m_state) + { + case 0: + // insert sample into ring-buffer + storeSampleReal((Real) 0, (Real) 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 + storeSampleReal((Real) sampleIn->real(), (Real) 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 + storeSampleReal((Real) 0, (Real) 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 + storeSampleReal((Real) sampleIn->real(), (Real) 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 FSample* sample1, FSample* sample2) + { + storeSampleReal((Real) sample1->real(), (Real) sample1->imag()); + advancePointer(); + + storeSampleReal((Real) sample2->real(), (Real) 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(FSample* sample1, FSample* sample2) + { + storeSampleReal((Real) sample1->real(), (Real) sample1->imag()); + doFIR(sample1); + advancePointer(); + + storeSampleReal((Real) 0, (Real) 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 storeSampleReal(const Real& sampleI, const Real& sampleQ) + { + m_samplesDB[m_ptr][0] = sampleI; + m_samplesDB[m_ptr][1] = sampleQ; + m_samplesDB[m_ptr + m_size][0] = sampleI; + m_samplesDB[m_ptr + m_size][1] = sampleQ; + } + + 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(FSample* 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); + sample->setImag(qAcc); + } + + 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(FSample* 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); + sample->setImag(qAcc); + } + + void doInterpolateFIR(Real *x, Real *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; + *y = qAcc; + } +}; + +template +IntHalfbandFilterDBFF::IntHalfbandFilterDBFF() +{ + 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_DBFF_H diff --git a/sdrbase/dsp/inthalfbandfilterdbf.h b/sdrbase/dsp/inthalfbandfilterdbfi.h similarity index 98% rename from sdrbase/dsp/inthalfbandfilterdbf.h rename to sdrbase/dsp/inthalfbandfilterdbfi.h index 5dc7bad7a..f83c4fd33 100644 --- a/sdrbase/dsp/inthalfbandfilterdbf.h +++ b/sdrbase/dsp/inthalfbandfilterdbfi.h @@ -18,8 +18,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_INTHALFBANDFILTER_DBF_H -#define INCLUDE_INTHALFBANDFILTER_DBF_H +#ifndef INCLUDE_INTHALFBANDFILTER_DBFI_H +#define INCLUDE_INTHALFBANDFILTER_DBFI_H #include #include "dsp/dsptypes.h" @@ -27,9 +27,9 @@ #include "export.h" template -class SDRBASE_API IntHalfbandFilterDBF { +class SDRBASE_API IntHalfbandFilterDBFI { public: - IntHalfbandFilterDBF(); + IntHalfbandFilterDBFI(); // downsample by 2, return center part of original spectrum bool workDecimateCenter(Sample* sample) @@ -694,7 +694,7 @@ protected: }; template -IntHalfbandFilterDBF::IntHalfbandFilterDBF() +IntHalfbandFilterDBFI::IntHalfbandFilterDBFI() { m_size = HBFIRFilterTraits::hbOrder - 1; diff --git a/sdrbench/mainbench.cpp b/sdrbench/mainbench.cpp index ea3ef4b7e..5477d1246 100644 --- a/sdrbench/mainbench.cpp +++ b/sdrbench/mainbench.cpp @@ -26,7 +26,8 @@ MainBench *MainBench::m_instance = 0; MainBench::MainBench(qtwebapp::LoggerWithFile *logger, const ParserBench& parser, QObject *parent) : QObject(parent), m_logger(logger), - m_parser(parser) + m_parser(parser), + m_uniform_distribution(-1.0, 1.0) { qDebug() << "MainBench::MainBench: start"; m_instance = this; @@ -49,6 +50,10 @@ void MainBench::run() testDecimateII(); } else if (m_parser.getTestType() == ParserBench::TestDecimatorsFI) { testDecimateFI(); + } else if (m_parser.getTestType() == ParserBench::TestDecimatorsFF) { + testDecimateFF(); + } else { + qDebug() << "MainBench::run: unknown test type: " << m_parser.getTestType(); } emit finished(); @@ -73,13 +78,9 @@ void MainBench::testDecimateII() } nsecs = timer.nsecsElapsed(); - QDebug debug = qDebug(); - debug.noquote(); - debug << tr("MainBench::testDecimateII: ran test in %L1 ns").arg(nsecs); - + printResults("MainBench::testDecimateII", nsecs); qDebug() << "MainBench::testDecimateII: cleanup test data"; - delete[] buf; } @@ -92,6 +93,8 @@ void MainBench::testDecimateFI() float *buf = new float[m_parser.getNbSamples()*2]; m_convertBuffer.resize(m_parser.getNbSamples()/(1< +#include +#include #include "dsp/decimators.h" #include "dsp/decimatorsfi.h" +#include "dsp/decimatorsff.h" #include "parserbench.h" namespace qtwebapp { @@ -45,12 +48,17 @@ signals: private: void testDecimateII(); void testDecimateFI(); + void testDecimateFF(); void decimateII(const qint16 *buf, int len); void decimateFI(const float *buf, int len); + void decimateFF(const float *buf, int len); + void printResults(const QString& prefix, qint64 nsecs); static MainBench *m_instance; qtwebapp::LoggerWithFile *m_logger; const ParserBench& m_parser; + std::mt19937 m_generator; + std::uniform_real_distribution m_uniform_distribution; #ifdef SDR_RX_SAMPLE_24BIT Decimators m_decimatorsII; @@ -58,8 +66,10 @@ private: Decimators m_decimatorsII; #endif DecimatorsFI m_decimatorsFI; + DecimatorsFF m_decimatorsFF; SampleVector m_convertBuffer; + FSampleVector m_convertBufferF; }; #endif // SDRBENCH_MAINBENCH_H_ diff --git a/sdrbench/parserbench.cpp b/sdrbench/parserbench.cpp index b1d7f741f..cd0a2fe0d 100644 --- a/sdrbench/parserbench.cpp +++ b/sdrbench/parserbench.cpp @@ -116,6 +116,8 @@ ParserBench::TestType ParserBench::getTestType() const { if (m_testStr == "decimatefi") { return TestDecimatorsFI; + } else if (m_testStr == "decimateff") { + return TestDecimatorsFF; } else { return TestDecimatorsII; } diff --git a/sdrbench/parserbench.h b/sdrbench/parserbench.h index 2b67f23e1..10a930a3a 100644 --- a/sdrbench/parserbench.h +++ b/sdrbench/parserbench.h @@ -27,7 +27,8 @@ public: typedef enum { TestDecimatorsII, - TestDecimatorsFI + TestDecimatorsFI, + TestDecimatorsFF } TestType; ParserBench();