diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2024-10-06 19:47:19 +0200 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2024-10-06 19:47:19 +0200 |
commit | 8736f6160aeafe7a177cb6143fea80157e174e52 (patch) | |
tree | c73d39eda0db5341875b0fac34cdc89c0961c94a /src | |
parent | b563b465e8b3df367da7799e789d29e0009cb96a (diff) | |
download | dabmod-8736f6160aeafe7a177cb6143fea80157e174e52.tar.gz dabmod-8736f6160aeafe7a177cb6143fea80157e174e52.tar.bz2 dabmod-8736f6160aeafe7a177cb6143fea80157e174e52.zip |
Implement fixed-point symbols, FFT and file output
Diffstat (limited to 'src')
-rw-r--r-- | src/Buffer.h | 3 | ||||
-rw-r--r-- | src/ConfigParser.cpp | 2 | ||||
-rw-r--r-- | src/ConfigParser.h | 2 | ||||
-rw-r--r-- | src/DabMod.cpp | 12 | ||||
-rw-r--r-- | src/DabModulator.cpp | 74 | ||||
-rw-r--r-- | src/DifferentialModulator.cpp | 69 | ||||
-rw-r--r-- | src/DifferentialModulator.h | 5 | ||||
-rw-r--r-- | src/FrequencyInterleaver.cpp | 77 | ||||
-rw-r--r-- | src/FrequencyInterleaver.h | 9 | ||||
-rw-r--r-- | src/GuardIntervalInserter.cpp | 207 | ||||
-rw-r--r-- | src/GuardIntervalInserter.h | 31 | ||||
-rw-r--r-- | src/NullSymbol.cpp | 9 | ||||
-rw-r--r-- | src/NullSymbol.h | 6 | ||||
-rw-r--r-- | src/OfdmGenerator.cpp | 172 | ||||
-rw-r--r-- | src/OfdmGenerator.h | 50 | ||||
-rw-r--r-- | src/OutputMemory.cpp | 8 | ||||
-rw-r--r-- | src/OutputMemory.h | 2 | ||||
-rw-r--r-- | src/PhaseReference.cpp | 135 | ||||
-rw-r--r-- | src/PhaseReference.h | 22 | ||||
-rw-r--r-- | src/QpskSymbolMapper.cpp | 263 | ||||
-rw-r--r-- | src/QpskSymbolMapper.h | 5 | ||||
-rw-r--r-- | src/SignalMultiplexer.cpp | 5 | ||||
-rw-r--r-- | src/SignalMultiplexer.h | 5 | ||||
-rw-r--r-- | src/Utils.cpp | 2 |
24 files changed, 754 insertions, 421 deletions
diff --git a/src/Buffer.h b/src/Buffer.h index 077d654..711b804 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -34,7 +34,10 @@ #include <vector> #include <memory> #include <complex> +#include "fpm/fixed.hpp" + typedef std::complex<float> complexf; +typedef std::complex<fpm::fixed_16_16> complexfix; /* Buffer is a container for a byte array, which is memory-aligned * to 32 bytes for SSE performance. diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 4a1e362..a48f7e7 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -154,6 +154,8 @@ static void parse_configfile( mod_settings.showProcessTime); // modulator parameters: + mod_settings.fixedPoint = pt.GetInteger("modulator.fixed_point", mod_settings.fixedPoint); + const string gainMode_setting = pt.Get("modulator.gainmode", "var"); mod_settings.gainMode = parse_gainmode(gainMode_setting); mod_settings.gainmodeVariance = pt.GetReal("modulator.normalise_variance", diff --git a/src/ConfigParser.h b/src/ConfigParser.h index ae76dee..f3a2af9 100644 --- a/src/ConfigParser.h +++ b/src/ConfigParser.h @@ -51,6 +51,8 @@ struct mod_settings_t { bool useLimeOutput = false; bool useBladeRFOutput = false; + bool fixedPoint = false; + size_t outputRate = 2048000; size_t clockRate = 0; unsigned dabMode = 1; diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 4e338f9..5f8412b 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -249,7 +249,15 @@ static shared_ptr<ModOutput> prepare_output(mod_settings_t& s) { shared_ptr<ModOutput> output; - if (s.useFileOutput) { + if (s.fixedPoint) { + if (s.useFileOutput) { + output = make_shared<OutputFile>(s.outputName, s.fileOutputShowMetadata); + } + else { + throw runtime_error("Fixed point only works with file output"); + } + } + else if (s.useFileOutput) { if (s.fileOutputFormat == "complexf") { output = make_shared<OutputFile>(s.outputName, s.fileOutputShowMetadata); } @@ -413,7 +421,7 @@ int launch_modulator(int argc, char* argv[]) ModulatorData m; rcs.enrol(&m); - { + if (not mod_settings.fixedPoint) { // This is mostly useful on ARM systems where FFTW planning takes some time. If we do it here // it will be done before the modulator starts up etiLog.level(debug) << "Running FFTW planning..."; diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index 4a29132..d48f1a2 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -142,14 +142,14 @@ int DabModulator::process(Buffer* dataOut) auto cifMux = make_shared<FrameMultiplexer>(m_etiSource); auto cifPart = make_shared<BlockPartitioner>(mode); - auto cifMap = make_shared<QpskSymbolMapper>(m_nbCarriers); - auto cifRef = make_shared<PhaseReference>(mode); - auto cifFreq = make_shared<FrequencyInterleaver>(mode); - auto cifDiff = make_shared<DifferentialModulator>(m_nbCarriers); + auto cifMap = make_shared<QpskSymbolMapper>(m_nbCarriers, m_settings.fixedPoint); + auto cifRef = make_shared<PhaseReference>(mode, m_settings.fixedPoint); + auto cifFreq = make_shared<FrequencyInterleaver>(mode, m_settings.fixedPoint); + auto cifDiff = make_shared<DifferentialModulator>(m_nbCarriers, m_settings.fixedPoint); - auto cifNull = make_shared<NullSymbol>(m_nbCarriers); - auto cifSig = make_shared<SignalMultiplexer>( - (1 + m_nbSymbols) * m_nbCarriers * sizeof(complexf)); + auto cifNull = make_shared<NullSymbol>(m_nbCarriers, + m_settings.fixedPoint ? sizeof(complexfix) : sizeof(complexf)); + auto cifSig = make_shared<SignalMultiplexer>(); // TODO this needs a review bool useCicEq = false; @@ -182,44 +182,66 @@ int DabModulator::process(Buffer* dataOut) m_settings.dabMode, m_settings.tiiConfig); rcs.enrol(tii.get()); - tiiRef = make_shared<PhaseReference>(mode); + tiiRef = make_shared<PhaseReference>(mode, m_settings.fixedPoint); } catch (const TIIError& e) { etiLog.level(error) << "Could not initialise TII: " << e.what(); } - auto cifOfdm = make_shared<OfdmGenerator>( - (1 + m_nbSymbols), - m_nbCarriers, - m_spacing, - m_settings.enableCfr, - m_settings.cfrClip, - m_settings.cfrErrorClip); + shared_ptr<ModPlugin> cifOfdm; + + if (m_settings.fixedPoint) { + cifOfdm = make_shared<OfdmGeneratorFixed>( + (1 + m_nbSymbols), + m_nbCarriers, + m_spacing, + m_settings.enableCfr, + m_settings.cfrClip, + m_settings.cfrErrorClip); + } + else { + auto ofdm = make_shared<OfdmGeneratorCF32>( + (1 + m_nbSymbols), + m_nbCarriers, + m_spacing, + m_settings.enableCfr, + m_settings.cfrClip, + m_settings.cfrErrorClip); + + rcs.enrol(ofdm.get()); + cifOfdm = ofdm; + } - rcs.enrol(cifOfdm.get()); + shared_ptr<GainControl> cifGain; - auto cifGain = make_shared<GainControl>( - m_spacing, - m_settings.gainMode, - m_settings.digitalgain, - m_settings.normalise, - m_settings.gainmodeVariance); + if (not m_settings.fixedPoint) { + cifGain = make_shared<GainControl>( + m_spacing, + m_settings.gainMode, + m_settings.digitalgain, + m_settings.normalise, + m_settings.gainmodeVariance); - rcs.enrol(cifGain.get()); + rcs.enrol(cifGain.get()); + } auto cifGuard = make_shared<GuardIntervalInserter>( m_nbSymbols, m_spacing, m_nullSize, m_symSize, - m_settings.ofdmWindowOverlap); + m_settings.ofdmWindowOverlap, m_settings.fixedPoint); rcs.enrol(cifGuard.get()); shared_ptr<FIRFilter> cifFilter; if (not m_settings.filterTapsFilename.empty()) { + if (m_settings.fixedPoint) throw std::runtime_error("fixed point doesn't support fir filter"); + cifFilter = make_shared<FIRFilter>(m_settings.filterTapsFilename); rcs.enrol(cifFilter.get()); } shared_ptr<MemlessPoly> cifPoly; if (not m_settings.polyCoefFilename.empty()) { + if (m_settings.fixedPoint) throw std::runtime_error("fixed point doesn't support predistortion"); + cifPoly = make_shared<MemlessPoly>(m_settings.polyCoefFilename, m_settings.polyNumThreads); rcs.enrol(cifPoly.get()); @@ -227,6 +249,8 @@ int DabModulator::process(Buffer* dataOut) shared_ptr<Resampler> cifRes; if (m_settings.outputRate != 2048000) { + if (m_settings.fixedPoint) throw std::runtime_error("fixed point doesn't support resampler"); + cifRes = make_shared<Resampler>( 2048000, m_settings.outputRate, @@ -234,6 +258,8 @@ int DabModulator::process(Buffer* dataOut) } if (not m_format.empty()) { + if (m_settings.fixedPoint) throw std::runtime_error("fixed point doesn't support format converter"); + m_formatConverter = make_shared<FormatConverter>(m_format); } diff --git a/src/DifferentialModulator.cpp b/src/DifferentialModulator.cpp index 54e97e2..cfebf65 100644 --- a/src/DifferentialModulator.cpp +++ b/src/DifferentialModulator.cpp @@ -26,9 +26,10 @@ #include <stdexcept> #include <cstring> -DifferentialModulator::DifferentialModulator(size_t carriers) : +DifferentialModulator::DifferentialModulator(size_t carriers, bool fixedPoint) : ModMux(), - d_carriers(carriers) + m_carriers(carriers), + m_fixedPoint(fixedPoint) { PDEBUG("DifferentialModulator::DifferentialModulator(%zu)\n", carriers); @@ -38,10 +39,42 @@ DifferentialModulator::DifferentialModulator(size_t carriers) : DifferentialModulator::~DifferentialModulator() { PDEBUG("DifferentialModulator::~DifferentialModulator()\n"); - } +template<typename T> +void do_process(size_t carriers, std::vector<Buffer*> dataIn, Buffer* dataOut) +{ + size_t phaseSize = dataIn[0]->getLength() / sizeof(T); + size_t dataSize = dataIn[1]->getLength() / sizeof(T); + dataOut->setLength((phaseSize + dataSize) * sizeof(T)); + + const T* phase = reinterpret_cast<const T*>(dataIn[0]->getData()); + const T* in = reinterpret_cast<const T*>(dataIn[1]->getData()); + T* out = reinterpret_cast<T*>(dataOut->getData()); + + if (phaseSize != carriers) { + throw std::runtime_error( + "DifferentialModulator::process input phase size not valid!"); + } + if (dataSize % carriers != 0) { + throw std::runtime_error( + "DifferentialModulator::process input data size not valid!"); + } + + memcpy(dataOut->getData(), phase, phaseSize * sizeof(T)); + for (size_t i = 0; i < dataSize; i += carriers) { + for (size_t j = 0; j < carriers; j += 4) { + out[carriers + j] = out[j] * in[j]; + out[carriers + j + 1] = out[j + 1] * in[j + 1]; + out[carriers + j + 2] = out[j + 2] * in[j + 2]; + out[carriers + j + 3] = out[j + 3] * in[j + 3]; + } + in += carriers; + out += carriers; + } +} + // dataIn[0] -> phase reference // dataIn[1] -> data symbols int DifferentialModulator::process(std::vector<Buffer*> dataIn, Buffer* dataOut) @@ -63,33 +96,11 @@ int DifferentialModulator::process(std::vector<Buffer*> dataIn, Buffer* dataOut) "DifferentialModulator::process nb of input streams not 2!"); } - size_t phaseSize = dataIn[0]->getLength() / sizeof(complexf); - size_t dataSize = dataIn[1]->getLength() / sizeof(complexf); - dataOut->setLength((phaseSize + dataSize) * sizeof(complexf)); - - const complexf* phase = reinterpret_cast<const complexf*>(dataIn[0]->getData()); - const complexf* in = reinterpret_cast<const complexf*>(dataIn[1]->getData()); - complexf* out = reinterpret_cast<complexf*>(dataOut->getData()); - - if (phaseSize != d_carriers) { - throw std::runtime_error( - "DifferentialModulator::process input phase size not valid!"); - } - if (dataSize % d_carriers != 0) { - throw std::runtime_error( - "DifferentialModulator::process input data size not valid!"); + if (m_fixedPoint) { + do_process<complexfix>(m_carriers, dataIn, dataOut); } - - memcpy(dataOut->getData(), phase, phaseSize * sizeof(complexf)); - for (size_t i = 0; i < dataSize; i += d_carriers) { - for (size_t j = 0; j < d_carriers; j += 4) { - out[d_carriers + j] = out[j] * in[j]; - out[d_carriers + j + 1] = out[j + 1] * in[j + 1]; - out[d_carriers + j + 2] = out[j + 2] * in[j + 2]; - out[d_carriers + j + 3] = out[j + 3] * in[j + 3]; - } - in += d_carriers; - out += d_carriers; + else { + do_process<complexf>(m_carriers, dataIn, dataOut); } return dataOut->getLength(); diff --git a/src/DifferentialModulator.h b/src/DifferentialModulator.h index b26ea8b..9cc5081 100644 --- a/src/DifferentialModulator.h +++ b/src/DifferentialModulator.h @@ -35,7 +35,7 @@ class DifferentialModulator : public ModMux { public: - DifferentialModulator(size_t carriers); + DifferentialModulator(size_t carriers, bool fixedPoint); virtual ~DifferentialModulator(); DifferentialModulator(const DifferentialModulator&); DifferentialModulator& operator=(const DifferentialModulator&); @@ -45,6 +45,7 @@ public: const char* name() { return "DifferentialModulator"; } protected: - size_t d_carriers; + size_t m_carriers; + size_t m_fixedPoint; }; diff --git a/src/FrequencyInterleaver.cpp b/src/FrequencyInterleaver.cpp index a62e9f4..856e8d0 100644 --- a/src/FrequencyInterleaver.cpp +++ b/src/FrequencyInterleaver.cpp @@ -28,8 +28,9 @@ #include <cstdlib> -FrequencyInterleaver::FrequencyInterleaver(size_t mode) : - ModCodec() +FrequencyInterleaver::FrequencyInterleaver(size_t mode, bool fixedPoint) : + ModCodec(), + m_fixedPoint(fixedPoint) { PDEBUG("FrequencyInterleaver::FrequencyInterleaver(%zu) @ %p\n", mode, this); @@ -39,45 +40,43 @@ FrequencyInterleaver::FrequencyInterleaver(size_t mode) : size_t beta; switch (mode) { case 1: - d_carriers = 1536; + m_carriers = 1536; num = 2048; beta = 511; break; case 2: - d_carriers = 384; + m_carriers = 384; num = 512; beta = 127; break; case 3: - d_carriers = 192; + m_carriers = 192; num = 256; beta = 63; break; case 0: case 4: - d_carriers = 768; + m_carriers = 768; num = 1024; beta = 255; break; default: PDEBUG("Carriers: %zu\n", (d_carriers >> 1) << 1); - throw std::runtime_error("FrequencyInterleaver::FrequencyInterleaver " - "nb of carriers invalid!"); - break; + throw std::runtime_error("FrequencyInterleaver: invalid dab mode"); } - const int ret = posix_memalign((void**)(&d_indexes), 16, d_carriers * sizeof(size_t)); + const int ret = posix_memalign((void**)(&m_indices), 16, m_carriers * sizeof(size_t)); if (ret != 0) { throw std::runtime_error("memory allocation failed: " + std::to_string(ret)); } - size_t* index = d_indexes; + size_t *index = m_indices; size_t perm = 0; PDEBUG("i: %4u, R: %4u\n", 0, 0); for (size_t j = 1; j < num; ++j) { perm = (alpha * perm + beta) & (num - 1); - if (perm >= ((num - d_carriers) / 2) - && perm <= (num - (num - d_carriers) / 2) + if (perm >= ((num - m_carriers) / 2) + && perm <= (num - (num - m_carriers) / 2) && perm != (num / 2)) { PDEBUG("i: %4zu, R: %4zu, d: %4zu, n: %4zu, k: %5zi, index: %zu\n", j, perm, perm, index - d_indexes, perm - num / 2, @@ -85,8 +84,9 @@ FrequencyInterleaver::FrequencyInterleaver(size_t mode) : ? perm - (1 + (num / 2)) : perm + (d_carriers - (num / 2))); *(index++) = perm > num / 2 ? - perm - (1 + (num / 2)) : perm + (d_carriers - (num / 2)); - } else { + perm - (1 + (num / 2)) : perm + (m_carriers - (num / 2)); + } + else { PDEBUG("i: %4zu, R: %4zu\n", j, perm); } } @@ -97,9 +97,33 @@ FrequencyInterleaver::~FrequencyInterleaver() { PDEBUG("FrequencyInterleaver::~FrequencyInterleaver() @ %p\n", this); - free(d_indexes); + free(m_indices); } +template<typename T> +void do_process(Buffer* const dataIn, Buffer* dataOut, + size_t carriers, const size_t * const indices) +{ + const T* in = reinterpret_cast<const T*>(dataIn->getData()); + T* out = reinterpret_cast<T*>(dataOut->getData()); + size_t sizeIn = dataIn->getLength() / sizeof(T); + + if (sizeIn % carriers != 0) { + throw std::runtime_error( + "FrequencyInterleaver::process input size not valid!"); + } + + for (size_t i = 0; i < sizeIn;) { +// memset(out, 0, d_carriers * sizeof(T)); + for (size_t j = 0; j < carriers; i += 4, j += 4) { + out[indices[j]] = in[i]; + out[indices[j + 1]] = in[i + 1]; + out[indices[j + 2]] = in[i + 2]; + out[indices[j + 3]] = in[i + 3]; + } + out += carriers; + } +} int FrequencyInterleaver::process(Buffer* const dataIn, Buffer* dataOut) { @@ -109,24 +133,11 @@ int FrequencyInterleaver::process(Buffer* const dataIn, Buffer* dataOut) dataOut->setLength(dataIn->getLength()); - const complexf* in = reinterpret_cast<const complexf*>(dataIn->getData()); - complexf* out = reinterpret_cast<complexf*>(dataOut->getData()); - size_t sizeIn = dataIn->getLength() / sizeof(complexf); - - if (sizeIn % d_carriers != 0) { - throw std::runtime_error( - "FrequencyInterleaver::process input size not valid!"); + if (m_fixedPoint) { + do_process<complexfix>(dataIn, dataOut, m_carriers, m_indices); } - - for (size_t i = 0; i < sizeIn;) { -// memset(out, 0, d_carriers * sizeof(complexf)); - for (size_t j = 0; j < d_carriers; i += 4, j += 4) { - out[d_indexes[j]] = in[i]; - out[d_indexes[j + 1]] = in[i + 1]; - out[d_indexes[j + 2]] = in[i + 2]; - out[d_indexes[j + 3]] = in[i + 3]; - } - out += d_carriers; + else { + do_process<complexf>(dataIn, dataOut, m_carriers, m_indices); } return 1; diff --git a/src/FrequencyInterleaver.h b/src/FrequencyInterleaver.h index 43ca21a..b31b968 100644 --- a/src/FrequencyInterleaver.h +++ b/src/FrequencyInterleaver.h @@ -25,16 +25,14 @@ # include <config.h> #endif - #include "ModPlugin.h" #include <sys/types.h> - class FrequencyInterleaver : public ModCodec { public: - FrequencyInterleaver(size_t mode); + FrequencyInterleaver(size_t mode, bool fixedPoint); virtual ~FrequencyInterleaver(); FrequencyInterleaver(const FrequencyInterleaver&) = delete; FrequencyInterleaver& operator=(const FrequencyInterleaver&) = delete; @@ -43,7 +41,8 @@ public: const char* name() override { return "FrequencyInterleaver"; } protected: - size_t d_carriers; - size_t* d_indexes; + bool m_fixedPoint; + size_t m_carriers; + size_t *m_indices; }; diff --git a/src/GuardIntervalInserter.cpp b/src/GuardIntervalInserter.cpp index e200b84..0b39de8 100644 --- a/src/GuardIntervalInserter.cpp +++ b/src/GuardIntervalInserter.cpp @@ -31,35 +31,45 @@ #include <stdexcept> #include <mutex> +GuardIntervalInserter::Params::Params( + size_t nbSymbols, + size_t spacing, + size_t nullSize, + size_t symSize, + size_t& windowOverlap) : + nbSymbols(nbSymbols), + spacing(spacing), + nullSize(nullSize), + symSize(symSize), + windowOverlap(windowOverlap) {} GuardIntervalInserter::GuardIntervalInserter( size_t nbSymbols, size_t spacing, size_t nullSize, size_t symSize, - size_t& windowOverlap) : + size_t& windowOverlap, + bool fixedPoint) : ModCodec(), RemoteControllable("guardinterval"), - d_nbSymbols(nbSymbols), - d_spacing(spacing), - d_nullSize(nullSize), - d_symSize(symSize), - d_windowOverlap(windowOverlap) + m_fixedPoint(fixedPoint), + m_params(nbSymbols, spacing, nullSize, symSize, windowOverlap) { - if (d_nullSize == 0) { + if (nullSize == 0) { throw std::logic_error("NULL symbol must be present"); } + RC_ADD_PARAMETER(windowlen, "Window length for OFDM windowng [0 to disable]"); /* We use a raised-cosine window for the OFDM windowing. - * Each symbol is extended on both sides by d_windowOverlap samples. + * Each symbol is extended on both sides by windowOverlap samples. * * * Sym n |####################| * Sym n+1 |####################| * - * We now extend the symbols by d_windowOverlap (one dash) + * We now extend the symbols by windowOverlap (one dash) * * Sym n extended -|####################|- * Sym n+1 extended -|####################|- @@ -73,7 +83,7 @@ GuardIntervalInserter::GuardIntervalInserter( * / \ * ... ________________/ \__ ... * - * The window length is 2*d_windowOverlap. + * The window length is 2*windowOverlap. */ update_window(windowOverlap); @@ -85,44 +95,45 @@ GuardIntervalInserter::GuardIntervalInserter( void GuardIntervalInserter::update_window(size_t new_window_overlap) { - std::lock_guard<std::mutex> lock(d_windowMutex); + std::lock_guard<std::mutex> lock(m_params.windowMutex); - d_windowOverlap = new_window_overlap; + m_params.windowOverlap = new_window_overlap; - // d_window only contains the rising window edge. - d_window.resize(2*d_windowOverlap); - for (size_t i = 0; i < 2*d_windowOverlap; i++) { - d_window[i] = (float)(0.5 * (1.0 - cos(M_PI * i / (2*d_windowOverlap - 1)))); + // m_params.window only contains the rising window edge. + m_params.window.resize(2*m_params.windowOverlap); + for (size_t i = 0; i < 2*m_params.windowOverlap; i++) { + m_params.window[i] = (float)(0.5 * (1.0 - cos(M_PI * i / (2*m_params.windowOverlap - 1)))); } } -int GuardIntervalInserter::process(Buffer* const dataIn, Buffer* dataOut) +template<typename T> +int do_process(const GuardIntervalInserter::Params& p, Buffer* const dataIn, Buffer* dataOut) { - PDEBUG("GuardIntervalInserter::process(dataIn: %p, dataOut: %p)\n", + PDEBUG("GuardIntervalInserter do_process(dataIn: %p, dataOut: %p)\n", dataIn, dataOut); - std::lock_guard<std::mutex> lock(d_windowMutex); + std::lock_guard<std::mutex> lock(p.windowMutex); - // Every symbol overlaps over a length of d_windowOverlap with + // Every symbol overlaps over a length of windowOverlap with // the previous symbol, and with the next symbol. First symbol // receives no prefix window, because we don't remember the // last symbol from the previous TF (yet). Last symbol also // receives no suffix window, for the same reason. // Overall output buffer length must stay independent of the windowing. - dataOut->setLength((d_nullSize + (d_nbSymbols * d_symSize)) * sizeof(complexf)); + dataOut->setLength((p.nullSize + (p.nbSymbols * p.symSize)) * sizeof(T)); - const complexf* in = reinterpret_cast<const complexf*>(dataIn->getData()); - complexf* out = reinterpret_cast<complexf*>(dataOut->getData()); - size_t sizeIn = dataIn->getLength() / sizeof(complexf); + const T* in = reinterpret_cast<const T*>(dataIn->getData()); + T* out = reinterpret_cast<T*>(dataOut->getData()); + size_t sizeIn = dataIn->getLength() / sizeof(T); - const size_t num_symbols = d_nbSymbols + 1; - if (sizeIn != num_symbols * d_spacing) + const size_t num_symbols = p.nbSymbols + 1; + if (sizeIn != num_symbols * p.spacing) { - PDEBUG("Nb symbols: %zu\n", d_nbSymbols); - PDEBUG("Spacing: %zu\n", d_spacing); - PDEBUG("Null size: %zu\n", d_nullSize); - PDEBUG("Sym size: %zu\n", d_symSize); - PDEBUG("\n%zu != %zu\n", sizeIn, (d_nbSymbols + 1) * d_spacing); + PDEBUG("Nb symbols: %zu\n", p.nbSymbols); + PDEBUG("Spacing: %zu\n", p.spacing); + PDEBUG("Null size: %zu\n", p.nullSize); + PDEBUG("Sym size: %zu\n", p.symSize); + PDEBUG("\n%zu != %zu\n", sizeIn, (p.nbSymbols + 1) * p.spacing); throw std::runtime_error( "GuardIntervalInserter::process input size not valid!"); } @@ -130,65 +141,66 @@ int GuardIntervalInserter::process(Buffer* const dataIn, Buffer* dataOut) // TODO remember the end of the last TF so that we can do some // windowing too. - if (d_windowOverlap) { + + if (p.windowOverlap) { if constexpr (std::is_same_v<complexf, T>) { { // Handle Null symbol separately because it is longer - const size_t prefixlength = d_nullSize - d_spacing; + const size_t prefixlength = p.nullSize - p.spacing; // end = spacing - memcpy(out, &in[d_spacing - prefixlength], - prefixlength * sizeof(complexf)); + memcpy(out, &in[p.spacing - prefixlength], + prefixlength * sizeof(T)); - memcpy(&out[prefixlength], in, (d_spacing - d_windowOverlap) * sizeof(complexf)); + memcpy(&out[prefixlength], in, (p.spacing - p.windowOverlap) * sizeof(T)); // The remaining part of the symbol must have half of the window applied, // sloping down from 1 to 0.5 - for (size_t i = 0; i < d_windowOverlap; i++) { - const size_t out_ix = prefixlength + d_spacing - d_windowOverlap + i; - const size_t in_ix = d_spacing - d_windowOverlap + i; - out[out_ix] = in[in_ix] * d_window[2*d_windowOverlap - (i+1)]; + for (size_t i = 0; i < p.windowOverlap; i++) { + const size_t out_ix = prefixlength + p.spacing - p.windowOverlap + i; + const size_t in_ix = p.spacing - p.windowOverlap + i; + out[out_ix] = in[in_ix] * p.window[2*p.windowOverlap - (i+1)]; } // Suffix is taken from the beginning of the symbol, and sees the other // half of the window applied. - for (size_t i = 0; i < d_windowOverlap; i++) { - const size_t out_ix = prefixlength + d_spacing + i; - out[out_ix] = in[i] * d_window[d_windowOverlap - (i+1)]; + for (size_t i = 0; i < p.windowOverlap; i++) { + const size_t out_ix = prefixlength + p.spacing + i; + out[out_ix] = in[i] * p.window[p.windowOverlap - (i+1)]; } - in += d_spacing; - out += d_nullSize; + in += p.spacing; + out += p.nullSize; // out is now pointing to the proper end of symbol. There are - // d_windowOverlap samples ahead that were already written. + // windowOverlap samples ahead that were already written. } // Data symbols - for (size_t sym_ix = 0; sym_ix < d_nbSymbols; sym_ix++) { + for (size_t sym_ix = 0; sym_ix < p.nbSymbols; sym_ix++) { /* _ix variables are indices into in[], _ox variables are * indices for out[] */ - const ssize_t start_rise_ox = -d_windowOverlap; - const size_t start_rise_ix = 2 * d_spacing - d_symSize - d_windowOverlap; + const ssize_t start_rise_ox = -p.windowOverlap; + const size_t start_rise_ix = 2 * p.spacing - p.symSize - p.windowOverlap; /* const size_t start_real_symbol_ox = 0; - const size_t start_real_symbol_ix = 2 * d_spacing - d_symSize; + const size_t start_real_symbol_ix = 2 * p.spacing - p.symSize; */ - const ssize_t end_rise_ox = d_windowOverlap; - const size_t end_rise_ix = 2 * d_spacing - d_symSize + d_windowOverlap; - const ssize_t end_cyclic_prefix_ox = d_symSize - d_spacing; + const ssize_t end_rise_ox = p.windowOverlap; + const size_t end_rise_ix = 2 * p.spacing - p.symSize + p.windowOverlap; + const ssize_t end_cyclic_prefix_ox = p.symSize - p.spacing; /* end_cyclic_prefix_ix = end of symbol - const size_t begin_fall_ox = d_symSize - d_windowOverlap; - const size_t begin_fall_ix = d_spacing - d_windowOverlap; - const size_t end_real_symbol_ox = d_symSize; + const size_t begin_fall_ox = p.symSize - p.windowOverlap; + const size_t begin_fall_ix = p.spacing - p.windowOverlap; + const size_t end_real_symbol_ox = p.symSize; end_real_symbol_ix = end of symbol - const size_t end_fall_ox = d_symSize + d_windowOverlap; - const size_t end_fall_ix = d_spacing + d_windowOverlap; + const size_t end_fall_ox = p.symSize + p.windowOverlap; + const size_t end_fall_ix = p.spacing + p.windowOverlap; */ ssize_t ox = start_rise_ox; size_t ix = start_rise_ix; for (size_t i = 0; ix < end_rise_ix; i++) { - out[ox] += in[ix] * d_window.at(i); + out[ox] += in[ix] * p.window.at(i); ix++; ox++; } @@ -196,75 +208,88 @@ int GuardIntervalInserter::process(Buffer* const dataIn, Buffer* dataOut) const size_t remaining_prefix_length = end_cyclic_prefix_ox - end_rise_ox; memcpy( &out[ox], &in[ix], - remaining_prefix_length * sizeof(complexf)); + remaining_prefix_length * sizeof(T)); ox += remaining_prefix_length; assert(ox == end_cyclic_prefix_ox); ix = 0; - const bool last_symbol = (sym_ix + 1 >= d_nbSymbols); + const bool last_symbol = (sym_ix + 1 >= p.nbSymbols); if (last_symbol) { // No windowing at all at end - memcpy(&out[ox], &in[ix], d_spacing * sizeof(complexf)); - ox += d_spacing; + memcpy(&out[ox], &in[ix], p.spacing * sizeof(T)); + ox += p.spacing; } else { - // Copy the middle part of the symbol, d_windowOverlap samples + // Copy the middle part of the symbol, p.windowOverlap samples // short of the end. memcpy( &out[ox], &in[ix], - (d_spacing - d_windowOverlap) * sizeof(complexf)); - ox += d_spacing - d_windowOverlap; - ix += d_spacing - d_windowOverlap; - assert(ox == (ssize_t)(d_symSize - d_windowOverlap)); + (p.spacing - p.windowOverlap) * sizeof(T)); + ox += p.spacing - p.windowOverlap; + ix += p.spacing - p.windowOverlap; + assert(ox == (ssize_t)(p.symSize - p.windowOverlap)); // Apply window from 1 to 0.5 for the end of the symbol - for (size_t i = 0; ox < (ssize_t)d_symSize; i++) { - out[ox] = in[ix] * d_window[2*d_windowOverlap - (i+1)]; + for (size_t i = 0; ox < (ssize_t)p.symSize; i++) { + out[ox] = in[ix] * p.window[2*p.windowOverlap - (i+1)]; ox++; ix++; } - assert(ix == d_spacing); + assert(ix == p.spacing); ix = 0; // Cyclic suffix, with window from 0.5 to 0 - for (size_t i = 0; ox < (ssize_t)(d_symSize + d_windowOverlap); i++) { - out[ox] = in[ix] * d_window[d_windowOverlap - (i+1)]; + for (size_t i = 0; ox < (ssize_t)(p.symSize + p.windowOverlap); i++) { + out[ox] = in[ix] * p.window[p.windowOverlap - (i+1)]; ox++; ix++; } - assert(ix == d_windowOverlap); + assert(ix == p.windowOverlap); } - out += d_symSize; - in += d_spacing; + out += p.symSize; + in += p.spacing; // out is now pointing to the proper end of symbol. There are - // d_windowOverlap samples ahead that were already written. + // windowOverlap samples ahead that were already written. } - } + } } else { // Handle Null symbol separately because it is longer // end - (nullSize - spacing) = 2 * spacing - nullSize - memcpy(out, &in[2 * d_spacing - d_nullSize], - (d_nullSize - d_spacing) * sizeof(complexf)); - memcpy(&out[d_nullSize - d_spacing], in, d_spacing * sizeof(complexf)); - in += d_spacing; - out += d_nullSize; + memcpy(out, &in[2 * p.spacing - p.nullSize], + (p.nullSize - p.spacing) * sizeof(T)); + memcpy(&out[p.nullSize - p.spacing], in, p.spacing * sizeof(T)); + in += p.spacing; + out += p.nullSize; // Data symbols - for (size_t i = 0; i < d_nbSymbols; ++i) { + for (size_t i = 0; i < p.nbSymbols; ++i) { // end - (symSize - spacing) = 2 * spacing - symSize - memcpy(out, &in[2 * d_spacing - d_symSize], - (d_symSize - d_spacing) * sizeof(complexf)); - memcpy(&out[d_symSize - d_spacing], in, d_spacing * sizeof(complexf)); - in += d_spacing; - out += d_symSize; + memcpy(out, &in[2 * p.spacing - p.symSize], + (p.symSize - p.spacing) * sizeof(T)); + memcpy(&out[p.symSize - p.spacing], in, p.spacing * sizeof(T)); + in += p.spacing; + out += p.symSize; } } return sizeIn; } +int GuardIntervalInserter::process(Buffer* const dataIn, Buffer* dataOut) +{ + if (m_fixedPoint) { + if (m_params.windowOverlap) { + throw std::runtime_error("fixed point and ofdm windowing not supported"); + } + return do_process<complexfix>(m_params, dataIn, dataOut); + } + else { + return do_process<complexf>(m_params, dataIn, dataOut); + } +} + void GuardIntervalInserter::set_parameter( const std::string& parameter, const std::string& value) @@ -291,7 +316,7 @@ const std::string GuardIntervalInserter::get_parameter(const std::string& parame using namespace std; stringstream ss; if (parameter == "windowlen") { - ss << d_windowOverlap; + ss << m_params.windowOverlap; } else { ss << "Parameter '" << parameter << @@ -304,6 +329,6 @@ const std::string GuardIntervalInserter::get_parameter(const std::string& parame const json::map_t GuardIntervalInserter::get_all_values() const { json::map_t map; - map["windowlen"].v = d_windowOverlap; + map["windowlen"].v = m_params.windowOverlap; return map; } diff --git a/src/GuardIntervalInserter.h b/src/GuardIntervalInserter.h index f78ac91..380142e 100644 --- a/src/GuardIntervalInserter.h +++ b/src/GuardIntervalInserter.h @@ -50,7 +50,8 @@ class GuardIntervalInserter : public ModCodec, public RemoteControllable size_t spacing, size_t nullSize, size_t symSize, - size_t& windowOverlap); + size_t& windowOverlap, + bool fixedPoint); virtual ~GuardIntervalInserter() {} @@ -62,16 +63,30 @@ class GuardIntervalInserter : public ModCodec, public RemoteControllable virtual const std::string get_parameter(const std::string& parameter) const override; virtual const json::map_t get_all_values() const override; + struct Params { + Params( + size_t nbSymbols, + size_t spacing, + size_t nullSize, + size_t symSize, + size_t& windowOverlap); + + size_t nbSymbols; + size_t spacing; + size_t nullSize; + size_t symSize; + size_t& windowOverlap; + + mutable std::mutex windowMutex; + std::vector<float> window; + }; + protected: void update_window(size_t new_window_overlap); - size_t d_nbSymbols; - size_t d_spacing; - size_t d_nullSize; - size_t d_symSize; + bool m_fixedPoint; + + Params m_params; - mutable std::mutex d_windowMutex; - size_t& d_windowOverlap; - std::vector<float> d_window; }; diff --git a/src/NullSymbol.cpp b/src/NullSymbol.cpp index 023ae42..526e662 100644 --- a/src/NullSymbol.cpp +++ b/src/NullSymbol.cpp @@ -31,11 +31,12 @@ #include <cstdlib> #include <cstring> -NullSymbol::NullSymbol(size_t nbCarriers) : +NullSymbol::NullSymbol(size_t numCarriers, size_t typeSize) : ModInput(), - myNbCarriers(nbCarriers) + m_numCarriers(numCarriers), + m_typeSize(typeSize) { - PDEBUG("NullSymbol::NullSymbol(%zu) @ %p\n", nbCarriers, this); + PDEBUG("NullSymbol::NullSymbol(%zu) @ %p\n", numCarriers, this); } @@ -49,7 +50,7 @@ int NullSymbol::process(Buffer* dataOut) { PDEBUG("NullSymbol::process(dataOut: %p)\n", dataOut); - dataOut->setLength(myNbCarriers * 2 * sizeof(float)); + dataOut->setLength(m_numCarriers * m_typeSize); memset(dataOut->getData(), 0, dataOut->getLength()); return dataOut->getLength(); diff --git a/src/NullSymbol.h b/src/NullSymbol.h index 814e434..6ba9e63 100644 --- a/src/NullSymbol.h +++ b/src/NullSymbol.h @@ -39,14 +39,14 @@ class NullSymbol : public ModInput { public: - NullSymbol(size_t nbCarriers); + NullSymbol(size_t nunCarriers, size_t typeSize); virtual ~NullSymbol(); int process(Buffer* dataOut); const char* name() { return "NullSymbol"; } private: - size_t myNbCarriers; - + size_t m_numCarriers; + size_t m_typeSize; }; diff --git a/src/OfdmGenerator.cpp b/src/OfdmGenerator.cpp index cb799d3..e679694 100644 --- a/src/OfdmGenerator.cpp +++ b/src/OfdmGenerator.cpp @@ -27,17 +27,19 @@ #include "OfdmGenerator.h" #include "PcDebug.h" -#define FFT_TYPE fftwf_complex - -#include <string.h> #include <stdexcept> #include <assert.h> #include <string> #include <numeric> +#include <vector> +#include <cstring> +#include <complex> static const size_t MAX_CLIP_STATS = 10; -OfdmGenerator::OfdmGenerator(size_t nbSymbols, +using FFTW_TYPE = fftwf_complex; + +OfdmGeneratorCF32::OfdmGeneratorCF32(size_t nbSymbols, size_t nbCarriers, size_t spacing, bool& enableCfr, @@ -102,29 +104,29 @@ OfdmGenerator::OfdmGenerator(size_t nbSymbols, PDEBUG(" myZeroSize: %u\n", myZeroSize); const int N = mySpacing; // The size of the FFT - myFftIn = (FFT_TYPE*)fftwf_malloc(sizeof(FFT_TYPE) * N); - myFftOut = (FFT_TYPE*)fftwf_malloc(sizeof(FFT_TYPE) * N); + myFftIn = (FFTW_TYPE*)fftwf_malloc(sizeof(FFTW_TYPE) * N); + myFftOut = (FFTW_TYPE*)fftwf_malloc(sizeof(FFTW_TYPE) * N); fftwf_set_timelimit(2); myFftPlan = fftwf_plan_dft_1d(N, myFftIn, myFftOut, FFTW_BACKWARD, FFTW_MEASURE); - myCfrPostClip = (FFT_TYPE*)fftwf_malloc(sizeof(FFT_TYPE) * N); - myCfrPostFft = (FFT_TYPE*)fftwf_malloc(sizeof(FFT_TYPE) * N); + myCfrPostClip = (FFTW_TYPE*)fftwf_malloc(sizeof(FFTW_TYPE) * N); + myCfrPostFft = (FFTW_TYPE*)fftwf_malloc(sizeof(FFTW_TYPE) * N); myCfrFft = fftwf_plan_dft_1d(N, myCfrPostClip, myCfrPostFft, FFTW_FORWARD, FFTW_MEASURE); - if (sizeof(complexf) != sizeof(FFT_TYPE)) { + if (sizeof(complexf) != sizeof(FFTW_TYPE)) { printf("sizeof(complexf) %zu\n", sizeof(complexf)); - printf("sizeof(FFT_TYPE) %zu\n", sizeof(FFT_TYPE)); + printf("sizeof(FFT_TYPE) %zu\n", sizeof(FFTW_TYPE)); throw std::runtime_error( "OfdmGenerator::process complexf size is not FFT_TYPE size!"); } } -OfdmGenerator::~OfdmGenerator() +OfdmGeneratorCF32::~OfdmGeneratorCF32() { PDEBUG("OfdmGenerator::~OfdmGenerator() @ %p\n", this); @@ -153,15 +155,15 @@ OfdmGenerator::~OfdmGenerator() } } -int OfdmGenerator::process(Buffer* const dataIn, Buffer* dataOut) +int OfdmGeneratorCF32::process(Buffer* const dataIn, Buffer* dataOut) { PDEBUG("OfdmGenerator::process(dataIn: %p, dataOut: %p)\n", dataIn, dataOut); dataOut->setLength(myNbSymbols * mySpacing * sizeof(complexf)); - FFT_TYPE* in = reinterpret_cast<FFT_TYPE*>(dataIn->getData()); - FFT_TYPE* out = reinterpret_cast<FFT_TYPE*>(dataOut->getData()); + FFTW_TYPE* in = reinterpret_cast<FFTW_TYPE*>(dataIn->getData()); + FFTW_TYPE* out = reinterpret_cast<FFTW_TYPE*>(dataOut->getData()); size_t sizeIn = dataIn->getLength() / sizeof(complexf); size_t sizeOut = dataOut->getLength() / sizeof(complexf); @@ -212,17 +214,17 @@ int OfdmGenerator::process(Buffer* const dataIn, Buffer* dataOut) * PosSrc=0 PosDst=1 PosSize=768 * NegSrc=768 NegDst=1280 NegSize=768 */ - memset(&myFftIn[myZeroDst], 0, myZeroSize * sizeof(FFT_TYPE)); + memset(&myFftIn[myZeroDst], 0, myZeroSize * sizeof(FFTW_TYPE)); memcpy(&myFftIn[myPosDst], &in[myPosSrc], - myPosSize * sizeof(FFT_TYPE)); + myPosSize * sizeof(FFTW_TYPE)); memcpy(&myFftIn[myNegDst], &in[myNegSrc], - myNegSize * sizeof(FFT_TYPE)); + myNegSize * sizeof(FFTW_TYPE)); if (myCfr) { reference.resize(mySpacing); memcpy(reinterpret_cast<fftwf_complex*>(reference.data()), - myFftIn, mySpacing * sizeof(FFT_TYPE)); + myFftIn, mySpacing * sizeof(FFTW_TYPE)); } fftwf_execute(myFftPlan); // IFFT from myFftIn to myFftOut @@ -235,7 +237,7 @@ int OfdmGenerator::process(Buffer* const dataIn, Buffer* dataOut) if (myMERCalcIndex == i) { before_cfr.resize(mySpacing); memcpy(reinterpret_cast<fftwf_complex*>(before_cfr.data()), - myFftOut, mySpacing * sizeof(FFT_TYPE)); + myFftOut, mySpacing * sizeof(FFTW_TYPE)); } /* cfr_one_iteration runs the myFftPlan again at the end, and @@ -277,7 +279,7 @@ int OfdmGenerator::process(Buffer* const dataIn, Buffer* dataOut) num_error_clip += stat.errclip_count; } - memcpy(out, myFftOut, mySpacing * sizeof(FFT_TYPE)); + memcpy(out, myFftOut, mySpacing * sizeof(FFTW_TYPE)); in += myNbCarriers; out += mySpacing; @@ -308,14 +310,14 @@ int OfdmGenerator::process(Buffer* const dataIn, Buffer* dataOut) return sizeOut; } -OfdmGenerator::cfr_iter_stat_t OfdmGenerator::cfr_one_iteration( +OfdmGeneratorCF32::cfr_iter_stat_t OfdmGeneratorCF32::cfr_one_iteration( complexf *symbol, const complexf *reference) { // use std::norm instead of std::abs to avoid calculating the // square roots const float clip_squared = myCfrClip * myCfrClip; - OfdmGenerator::cfr_iter_stat_t ret; + OfdmGeneratorCF32::cfr_iter_stat_t ret; // Clip for (size_t i = 0; i < mySpacing; i++) { @@ -331,7 +333,7 @@ OfdmGenerator::cfr_iter_stat_t OfdmGenerator::cfr_one_iteration( } // Take FFT of our clipped signal - memcpy(myCfrPostClip, symbol, mySpacing * sizeof(FFT_TYPE)); + memcpy(myCfrPostClip, symbol, mySpacing * sizeof(FFTW_TYPE)); fftwf_execute(myCfrFft); // FFT from myCfrPostClip to myCfrPostFft // Calculate the error in frequency domain by subtracting our reference @@ -374,7 +376,7 @@ OfdmGenerator::cfr_iter_stat_t OfdmGenerator::cfr_one_iteration( } -void OfdmGenerator::set_parameter(const std::string& parameter, +void OfdmGeneratorCF32::set_parameter(const std::string& parameter, const std::string& value) { using namespace std; @@ -404,7 +406,7 @@ void OfdmGenerator::set_parameter(const std::string& parameter, } } -const std::string OfdmGenerator::get_parameter(const std::string& parameter) const +const std::string OfdmGeneratorCF32::get_parameter(const std::string& parameter) const { using namespace std; stringstream ss; @@ -458,9 +460,127 @@ const std::string OfdmGenerator::get_parameter(const std::string& parameter) con return ss.str(); } -const json::map_t OfdmGenerator::get_all_values() const +const json::map_t OfdmGeneratorCF32::get_all_values() const { json::map_t map; // TODO needs rework of the values return map; } + +OfdmGeneratorFixed::OfdmGeneratorFixed(size_t nbSymbols, + size_t nbCarriers, + size_t spacing, + bool& enableCfr, + float& cfrClip, + float& cfrErrorClip, + bool inverse) : + ModCodec(), + myNbSymbols(nbSymbols), + myNbCarriers(nbCarriers), + mySpacing(spacing) +{ + PDEBUG("OfdmGenerator::OfdmGenerator(%zu, %zu, %zu, %s) @ %p\n", + nbSymbols, nbCarriers, spacing, inverse ? "true" : "false", this); + + etiLog.level(info) << "Using KISS FFT by Mark Borgerding for fixed-point transform"; + + if (nbCarriers > spacing) { + throw std::runtime_error( + "OfdmGenerator::OfdmGenerator nbCarriers > spacing!"); + } + + if (inverse) { + myPosDst = (nbCarriers & 1 ? 0 : 1); + myPosSrc = 0; + myPosSize = (nbCarriers + 1) / 2; + myNegDst = spacing - (nbCarriers / 2); + myNegSrc = (nbCarriers + 1) / 2; + myNegSize = nbCarriers / 2; + } + else { + myPosDst = (nbCarriers & 1 ? 0 : 1); + myPosSrc = nbCarriers / 2; + myPosSize = (nbCarriers + 1) / 2; + myNegDst = spacing - (nbCarriers / 2); + myNegSrc = 0; + myNegSize = nbCarriers / 2; + } + myZeroDst = myPosDst + myPosSize; + myZeroSize = myNegDst - myZeroDst; + + PDEBUG(" myPosDst: %u\n", myPosDst); + PDEBUG(" myPosSrc: %u\n", myPosSrc); + PDEBUG(" myPosSize: %u\n", myPosSize); + PDEBUG(" myNegDst: %u\n", myNegDst); + PDEBUG(" myNegSrc: %u\n", myNegSrc); + PDEBUG(" myNegSize: %u\n", myNegSize); + PDEBUG(" myZeroDst: %u\n", myZeroDst); + PDEBUG(" myZeroSize: %u\n", myZeroSize); + + const int N = mySpacing; // The size of the FFT + + const size_t nbytes = N * sizeof(kiss_fft_cpx); + myFftIn = (kiss_fft_cpx*)KISS_FFT_MALLOC(nbytes); + myFftOut = (kiss_fft_cpx*)KISS_FFT_MALLOC(nbytes); + memset(myFftIn, 0, nbytes); + + myKissCfg = kiss_fft_alloc(N, inverse, nullptr, nullptr); +} + +OfdmGeneratorFixed::~OfdmGeneratorFixed() +{ + if (myKissCfg) KISS_FFT_FREE(myKissCfg); + if (myFftIn) KISS_FFT_FREE(myFftIn); + if (myFftOut) KISS_FFT_FREE(myFftOut); +} + +int OfdmGeneratorFixed::process(Buffer* const dataIn, Buffer* dataOut) +{ + dataOut->setLength(myNbSymbols * mySpacing * sizeof(kiss_fft_cpx)); + + kiss_fft_cpx* in = reinterpret_cast<kiss_fft_cpx*>(dataIn->getData()); + kiss_fft_cpx* out = reinterpret_cast<kiss_fft_cpx*>(dataOut->getData()); + + size_t sizeIn = dataIn->getLength() / sizeof(kiss_fft_cpx); + size_t sizeOut = dataOut->getLength() / sizeof(kiss_fft_cpx); + + if (sizeIn != myNbSymbols * myNbCarriers) { + PDEBUG("Nb symbols: %zu\n", myNbSymbols); + PDEBUG("Nb carriers: %zu\n", myNbCarriers); + PDEBUG("Spacing: %zu\n", mySpacing); + PDEBUG("\n%zu != %zu\n", sizeIn, myNbSymbols * myNbCarriers); + throw std::runtime_error( + "OfdmGenerator::process input size not valid!"); + } + if (sizeOut != myNbSymbols * mySpacing) { + PDEBUG("Nb symbols: %zu\n", myNbSymbols); + PDEBUG("Nb carriers: %zu\n", myNbCarriers); + PDEBUG("Spacing: %zu\n", mySpacing); + PDEBUG("\n%zu != %zu\n", sizeIn, myNbSymbols * mySpacing); + throw std::runtime_error( + "OfdmGenerator::process output size not valid!"); + } + + for (size_t i = 0; i < myNbSymbols; ++i) { + myFftIn[0].r = 0; + myFftIn[0].i = 0; + + /* For TM I this is: + * ZeroDst=769 ZeroSize=511 + * PosSrc=0 PosDst=1 PosSize=768 + * NegSrc=768 NegDst=1280 NegSize=768 + */ + memset(&myFftIn[myZeroDst], 0, myZeroSize * sizeof(kiss_fft_cpx)); + memcpy(&myFftIn[myPosDst], &in[myPosSrc], myPosSize * sizeof(kiss_fft_cpx)); + memcpy(&myFftIn[myNegDst], &in[myNegSrc], myNegSize * sizeof(kiss_fft_cpx)); + + kiss_fft(myKissCfg, myFftIn, myFftOut); + + memcpy(out, myFftOut, mySpacing * sizeof(kiss_fft_cpx)); + + in += myNbCarriers; + out += mySpacing; + } + + return sizeOut; +} diff --git a/src/OfdmGenerator.h b/src/OfdmGenerator.h index cab936e..2e1aa63 100644 --- a/src/OfdmGenerator.h +++ b/src/OfdmGenerator.h @@ -33,25 +33,26 @@ #include "ModPlugin.h" #include "RemoteControl.h" #include "PAPRStats.h" -#include "fftw3.h" +#include "kiss_fft.h" + +#include <fftw3.h> #include <cstddef> -#include <vector> -#include <complex> #include <atomic> -class OfdmGenerator : public ModCodec, public RemoteControllable +// Complex Float uses FFTW +class OfdmGeneratorCF32 : public ModCodec, public RemoteControllable { public: - OfdmGenerator(size_t nbSymbols, + OfdmGeneratorCF32(size_t nbSymbols, size_t nbCarriers, size_t spacing, bool& enableCfr, float& cfrClip, float& cfrErrorClip, bool inverse = true); - virtual ~OfdmGenerator(); - OfdmGenerator(const OfdmGenerator&) = delete; - OfdmGenerator& operator=(const OfdmGenerator&) = delete; + virtual ~OfdmGeneratorCF32(); + OfdmGeneratorCF32(const OfdmGeneratorCF32&) = delete; + OfdmGeneratorCF32& operator=(const OfdmGeneratorCF32&) = delete; int process(Buffer* const dataIn, Buffer* dataOut) override; const char* name() override { return "OfdmGenerator"; } @@ -105,4 +106,37 @@ class OfdmGenerator : public ModCodec, public RemoteControllable std::deque<double> myMERs; }; +// Fixed point implementation uses KISS FFT with -DFIXED_POINT=32 +class OfdmGeneratorFixed : public ModCodec +{ + public: + OfdmGeneratorFixed(size_t nbSymbols, + size_t nbCarriers, + size_t spacing, + bool& enableCfr, + float& cfrClip, + float& cfrErrorClip, + bool inverse = true); + virtual ~OfdmGeneratorFixed(); + OfdmGeneratorFixed(const OfdmGeneratorFixed&) = delete; + OfdmGeneratorFixed& operator=(const OfdmGeneratorFixed&) = delete; + + int process(Buffer* const dataIn, Buffer* dataOut) override; + const char* name() override { return "OfdmGenerator"; } + + private: + kiss_fft_cfg myKissCfg = nullptr; + kiss_fft_cpx *myFftIn, *myFftOut; + const size_t myNbSymbols; + const size_t myNbCarriers; + const size_t mySpacing; + unsigned myPosSrc; + unsigned myPosDst; + unsigned myPosSize; + unsigned myNegSrc; + unsigned myNegDst; + unsigned myNegSize; + unsigned myZeroDst; + unsigned myZeroSize; +}; diff --git a/src/OutputMemory.cpp b/src/OutputMemory.cpp index d6ef917..ac8a67b 100644 --- a/src/OutputMemory.cpp +++ b/src/OutputMemory.cpp @@ -39,7 +39,7 @@ OutputMemory::OutputMemory(Buffer* dataOut) { PDEBUG("OutputMemory::OutputMemory(%p) @ %p\n", dataOut, this); - setOutput(dataOut); + myDataOut = dataOut; #if OUTPUT_MEM_HISTOGRAM myMax = 0.0f; @@ -67,12 +67,6 @@ OutputMemory::~OutputMemory() } -void OutputMemory::setOutput(Buffer* dataOut) -{ - myDataOut = dataOut; -} - - int OutputMemory::process(Buffer* dataIn) { PDEBUG("OutputMemory::process(dataIn: %p)\n", diff --git a/src/OutputMemory.h b/src/OutputMemory.h index f0a5fbb..e7252d3 100644 --- a/src/OutputMemory.h +++ b/src/OutputMemory.h @@ -61,8 +61,6 @@ public: meta_vec_t get_latest_metadata(void); - void setOutput(Buffer* dataOut); - protected: Buffer* myDataOut; meta_vec_t myMetadata; diff --git a/src/PhaseReference.cpp b/src/PhaseReference.cpp index 568e15e..d7b89bf 100644 --- a/src/PhaseReference.cpp +++ b/src/PhaseReference.cpp @@ -29,12 +29,10 @@ #include <stdexcept> -using complexf = std::complex<float>; - /* ETSI EN 300 401 Table 43 (Clause 14.3.2) * Contains h_{i,k} values */ -const uint8_t PhaseReference::d_h[4][32] = { +static const uint8_t d_h[4][32] = { /* h0 */ { 0, 2, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 2, 2, 1, 1, 0, 2, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 2, 2, 1, 1 }, /* h1 */ { 0, 3, 2, 3, 0, 1, 3, 0, 2, 1, 2, 3, 2, 3, 3, 0, @@ -54,41 +52,80 @@ const uint8_t PhaseReference::d_h[4][32] = { * Tables 44 to 47 describe the frequency interleaving done in * FrequencyInterleaver. */ -PhaseReference::PhaseReference(unsigned int dabmode) : +PhaseReference::PhaseReference(unsigned int dabmode, bool fixedPoint) : ModInput(), - d_dabmode(dabmode) + d_dabmode(dabmode), + d_fixedPoint(fixedPoint) { PDEBUG("PhaseReference::PhaseReference(%u) @ %p\n", dabmode, this); switch (d_dabmode) { case 1: d_carriers = 1536; - d_num = 2048; break; case 2: d_carriers = 384; - d_num = 512; break; case 3: d_carriers = 192; - d_num = 256; break; case 4: d_dabmode = 0; case 0: d_carriers = 768; - d_num = 1024; break; default: throw std::runtime_error( "PhaseReference::PhaseReference DAB mode not valid!"); } - d_dataIn.resize(d_carriers); - fillData(); + + if (d_fixedPoint) { + d_phaseRefFixed.fillData(d_dabmode, d_carriers); + } + else { + d_phaseRefCF32.fillData(d_dabmode, d_carriers); + } } -complexf convert(uint8_t data) { +static const int table[][48][2] = { + { // Mode 0/4 + // Positive part + { 0, 0 }, { 3, 1 }, { 2, 0 }, { 1, 2 }, { 0, 0 }, { 3, 1 }, + { 2, 2 }, { 1, 2 }, { 0, 2 }, { 3, 1 }, { 2, 3 }, { 1, 0 }, + // Negative part + { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 0, 2 }, { 1, 2 }, + { 2, 0 }, { 3, 3 }, { 0, 3 }, { 1, 1 }, { 2, 3 }, { 3, 2 }, + }, + { // Mode 1 + // Positive part + { 0, 3 }, { 3, 1 }, { 2, 1 }, { 1, 1 }, { 0, 2 }, { 3, 2 }, + { 2, 1 }, { 1, 0 }, { 0, 2 }, { 3, 2 }, { 2, 3 }, { 1, 3 }, + { 0, 0 }, { 3, 2 }, { 2, 1 }, { 1, 3 }, { 0, 3 }, { 3, 3 }, + { 2, 3 }, { 1, 0 }, { 0, 3 }, { 3, 0 }, { 2, 1 }, { 1, 1 }, + // Negative part + { 0, 1 }, { 1, 2 }, { 2, 0 }, { 3, 1 }, { 0, 3 }, { 1, 2 }, + { 2, 2 }, { 3, 3 }, { 0, 2 }, { 1, 1 }, { 2, 2 }, { 3, 3 }, + { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 3 }, { 0, 2 }, { 1, 2 }, + { 2, 2 }, { 3, 1 }, { 0, 1 }, { 1, 3 }, { 2, 1 }, { 3, 2 }, + }, + { // Mode 2 + // Positive part + { 2, 0 }, { 1, 2 }, { 0, 2 }, { 3, 1 }, { 2, 0 }, { 1, 3 }, + // Negative part + { 0, 2 }, { 1, 3 }, { 2, 2 }, { 3, 2 }, { 0, 1 }, { 1, 2 }, + }, + { // Mode 3 + // Positive part + { 3, 2 }, { 2, 2 }, { 1, 2 }, + // Negative part + { 0, 2 }, { 1, 3 }, { 2, 0 }, + }, +}; + + +template <> +complexf PhaseRefGen<complexf>::convert(uint8_t data) { const complexf value[] = { complexf(1, 0), complexf(0, 1), @@ -98,62 +135,37 @@ complexf convert(uint8_t data) { return value[data % 4]; } +template <> +complexfix PhaseRefGen<complexfix>::convert(uint8_t data) { + constexpr auto one = fpm::fixed_16_16{1}; + constexpr auto zero = fpm::fixed_16_16{0}; -void PhaseReference::fillData() -{ - const int table[][48][2] = { - { // Mode 0/4 - // Positive part - { 0, 0 }, { 3, 1 }, { 2, 0 }, { 1, 2 }, { 0, 0 }, { 3, 1 }, - { 2, 2 }, { 1, 2 }, { 0, 2 }, { 3, 1 }, { 2, 3 }, { 1, 0 }, - // Negative part - { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 0, 2 }, { 1, 2 }, - { 2, 0 }, { 3, 3 }, { 0, 3 }, { 1, 1 }, { 2, 3 }, { 3, 2 }, - }, - { // Mode 1 - // Positive part - { 0, 3 }, { 3, 1 }, { 2, 1 }, { 1, 1 }, { 0, 2 }, { 3, 2 }, - { 2, 1 }, { 1, 0 }, { 0, 2 }, { 3, 2 }, { 2, 3 }, { 1, 3 }, - { 0, 0 }, { 3, 2 }, { 2, 1 }, { 1, 3 }, { 0, 3 }, { 3, 3 }, - { 2, 3 }, { 1, 0 }, { 0, 3 }, { 3, 0 }, { 2, 1 }, { 1, 1 }, - // Negative part - { 0, 1 }, { 1, 2 }, { 2, 0 }, { 3, 1 }, { 0, 3 }, { 1, 2 }, - { 2, 2 }, { 3, 3 }, { 0, 2 }, { 1, 1 }, { 2, 2 }, { 3, 3 }, - { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 3 }, { 0, 2 }, { 1, 2 }, - { 2, 2 }, { 3, 1 }, { 0, 1 }, { 1, 3 }, { 2, 1 }, { 3, 2 }, - }, - { // Mode 2 - // Positive part - { 2, 0 }, { 1, 2 }, { 0, 2 }, { 3, 1 }, { 2, 0 }, { 1, 3 }, - // Negative part - { 0, 2 }, { 1, 3 }, { 2, 2 }, { 3, 2 }, { 0, 1 }, { 1, 2 }, - }, - { // Mode 3 - // Positive part - { 3, 2 }, { 2, 2 }, { 1, 2 }, - // Negative part - { 0, 2 }, { 1, 3 }, { 2, 0 }, - }, + const complexfix value[] = { + complexfix(one, zero), + complexfix(zero, one), + complexfix(-one, zero), + complexfix(zero, -one), }; + return value[data % 4]; +} - if (d_dabmode > 3) { - throw std::runtime_error( - "PhaseReference::fillData invalid DAB mode!"); - } - - if (d_dataIn.size() != d_carriers) { +template <typename T> +void PhaseRefGen<T>::fillData(unsigned int dabmode, size_t carriers) +{ + dataIn.resize(carriers); + if (dataIn.size() != carriers) { throw std::runtime_error( - "PhaseReference::fillData d_dataIn has incorrect size!"); + "PhaseReference::fillData dataIn has incorrect size!"); } for (size_t index = 0, offset = 0; - index < d_dataIn.size(); + index < dataIn.size(); ++offset) { for (size_t k = 0; k < 32; ++k) { - d_dataIn[index++] = convert( - d_h[ table[d_dabmode][offset][0] ][k] + - table[d_dabmode][offset][1] ); + dataIn[index++] = convert( + d_h[ table[dabmode][offset][0] ][k] + + table[dabmode][offset][1] ); } } } @@ -163,7 +175,12 @@ int PhaseReference::process(Buffer* dataOut) { PDEBUG("PhaseReference::process(dataOut: %p)\n", dataOut); - dataOut->setData(&d_dataIn[0], d_carriers * sizeof(complexf)); + if (d_fixedPoint) { + dataOut->setData(&d_phaseRefFixed.dataIn[0], d_carriers * sizeof(complexfix)); + } + else { + dataOut->setData(&d_phaseRefCF32.dataIn[0], d_carriers * sizeof(complexf)); + } return 1; } diff --git a/src/PhaseReference.h b/src/PhaseReference.h index 6ecdc4e..735009c 100644 --- a/src/PhaseReference.h +++ b/src/PhaseReference.h @@ -32,25 +32,33 @@ #include "ModPlugin.h" -#include <cstddef> -#include <complex> #include <vector> +#include <cstddef> + +template <typename T> +struct PhaseRefGen { + std::vector<T> dataIn; + void fillData(unsigned int dabmode, size_t carriers); + + private: + T convert(uint8_t data); +}; + class PhaseReference : public ModInput { public: - PhaseReference(unsigned int dabmode); + PhaseReference(unsigned int dabmode, bool fixedPoint); int process(Buffer* dataOut) override; const char* name() override { return "PhaseReference"; } protected: unsigned int d_dabmode; + bool d_fixedPoint; size_t d_carriers; - size_t d_num; - const static uint8_t d_h[4][32]; - std::vector<std::complex<float> > d_dataIn; - void fillData(); + PhaseRefGen<complexf> d_phaseRefCF32; + PhaseRefGen<complexfix> d_phaseRefFixed; }; diff --git a/src/QpskSymbolMapper.cpp b/src/QpskSymbolMapper.cpp index c9b01fb..c12ad80 100644 --- a/src/QpskSymbolMapper.cpp +++ b/src/QpskSymbolMapper.cpp @@ -31,9 +31,10 @@ #include "QpskSymbolMapper.h" #include "PcDebug.h" -QpskSymbolMapper::QpskSymbolMapper(size_t carriers) : +QpskSymbolMapper::QpskSymbolMapper(size_t carriers, bool fixedPoint) : ModCodec(), - d_carriers(carriers) { } + m_fixedPoint(fixedPoint), + m_carriers(carriers) { } int QpskSymbolMapper::process(Buffer* const dataIn, Buffer* dataOut) { @@ -41,112 +42,172 @@ int QpskSymbolMapper::process(Buffer* const dataIn, Buffer* dataOut) "(dataIn: %p, dataOut: %p)\n", dataIn, dataOut); - dataOut->setLength(dataIn->getLength() * 4 * 2 * sizeof(float)); // 4 output complex symbols per input byte -#ifdef __SSE__ - const uint8_t* in = reinterpret_cast<const uint8_t*>(dataIn->getData()); - __m128* out = reinterpret_cast<__m128*>(dataOut->getData()); - - if (dataIn->getLength() % (d_carriers / 4) != 0) { - throw std::runtime_error( - "QpskSymbolMapper::process input size not valid: " + - std::to_string(dataIn->getLength()) + - "(input size) % (" + std::to_string(d_carriers) + - " (carriers) / 4) != 0"); - } + // 4 output complex symbols per input byte + + if (m_fixedPoint) { + dataOut->setLength(dataIn->getLength() * 4 * sizeof(complexfix)); + + using fixed_t = complexfix::value_type; + + const uint8_t* in = reinterpret_cast<const uint8_t*>(dataIn->getData()); + fixed_t* out = reinterpret_cast<fixed_t*>(dataOut->getData()); - const static __m128 symbols[16] = { - _mm_setr_ps( M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2), - _mm_setr_ps( M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2), - _mm_setr_ps( M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2), - _mm_setr_ps( M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2), - _mm_setr_ps( M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2), - _mm_setr_ps( M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2), - _mm_setr_ps( M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2), - _mm_setr_ps( M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2), - _mm_setr_ps(-M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2), - _mm_setr_ps(-M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2), - _mm_setr_ps(-M_SQRT1_2,- M_SQRT1_2, M_SQRT1_2, M_SQRT1_2), - _mm_setr_ps(-M_SQRT1_2,- M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2), - _mm_setr_ps(-M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2), - _mm_setr_ps(-M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2), - _mm_setr_ps(-M_SQRT1_2,- M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2), - _mm_setr_ps(-M_SQRT1_2,- M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2) - }; - size_t inOffset = 0; - size_t outOffset = 0; - uint8_t tmp = 0; - for (size_t i = 0; i < dataIn->getLength(); i += d_carriers / 4) { - for (size_t j = 0; j < d_carriers / 8; ++j) { - tmp = (in[inOffset] & 0xc0) >> 4; - tmp |= (in[inOffset + (d_carriers / 8)] & 0xc0) >> 6; - out[outOffset] = symbols[tmp]; - tmp = (in[inOffset] & 0x30) >> 2; - tmp |= (in[inOffset + (d_carriers / 8)] & 0x30) >> 4; - out[outOffset + 1] = symbols[tmp]; - tmp = (in[inOffset] & 0x0c); - tmp |= (in[inOffset + (d_carriers / 8)] & 0x0c) >> 2; - out[outOffset + 2] = symbols[tmp]; - tmp = (in[inOffset] & 0x03) << 2; - tmp |= (in[inOffset + (d_carriers / 8)] & 0x03); - out[outOffset + 3] = symbols[tmp]; - ++inOffset; - outOffset += 4; + if (dataIn->getLength() % (m_carriers / 4) != 0) { + throw std::runtime_error( + "QpskSymbolMapper::process input size not valid!"); + } + + constexpr fixed_t v = static_cast<fixed_t>(M_SQRT1_2); + + const static fixed_t symbols[16][4] = { + { v, v, v, v}, + { v, v, v, -v}, + { v, -v, v, v}, + { v, -v, v, -v}, + { v, v, -v, v}, + { v, v, -v, -v}, + { v, -v, -v, v}, + { v, -v, -v, -v}, + {-v, v, v, v}, + {-v, v, v, -v}, + {-v, -v, v, v}, + {-v, -v, v, -v}, + {-v, v, -v, v}, + {-v, v, -v, -v}, + {-v, -v, -v, v}, + {-v, -v, -v, -v} + }; + size_t inOffset = 0; + size_t outOffset = 0; + uint8_t tmp; + for (size_t i = 0; i < dataIn->getLength(); i += m_carriers / 4) { + for (size_t j = 0; j < m_carriers / 8; ++j) { + tmp = (in[inOffset] & 0xc0) >> 4; + tmp |= (in[inOffset + (m_carriers / 8)] & 0xc0) >> 6; + memcpy(&out[outOffset], symbols[tmp], sizeof(fixed_t) * 4); + tmp = (in[inOffset] & 0x30) >> 2; + tmp |= (in[inOffset + (m_carriers / 8)] & 0x30) >> 4; + memcpy(&out[outOffset + 4], symbols[tmp], sizeof(fixed_t) * 4); + tmp = (in[inOffset] & 0x0c); + tmp |= (in[inOffset + (m_carriers / 8)] & 0x0c) >> 2; + memcpy(&out[outOffset + 8], symbols[tmp], sizeof(fixed_t) * 4); + tmp = (in[inOffset] & 0x03) << 2; + tmp |= (in[inOffset + (m_carriers / 8)] & 0x03); + memcpy(&out[outOffset + 12], symbols[tmp], sizeof(fixed_t) * 4); + ++inOffset; + outOffset += 4*4; + } + inOffset += m_carriers / 8; } - inOffset += d_carriers / 8; } + else { + dataOut->setLength(dataIn->getLength() * 4 * sizeof(complexf)); +#ifdef __SSE__ + const uint8_t* in = reinterpret_cast<const uint8_t*>(dataIn->getData()); + __m128* out = reinterpret_cast<__m128*>(dataOut->getData()); + + if (dataIn->getLength() % (m_carriers / 4) != 0) { + throw std::runtime_error( + "QpskSymbolMapper::process input size not valid: " + + std::to_string(dataIn->getLength()) + + "(input size) % (" + std::to_string(m_carriers) + + " (carriers) / 4) != 0"); + } + + const static __m128 symbols[16] = { + _mm_setr_ps( M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2), + _mm_setr_ps( M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2), + _mm_setr_ps( M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2), + _mm_setr_ps( M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2), + _mm_setr_ps( M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2), + _mm_setr_ps( M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2), + _mm_setr_ps( M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2), + _mm_setr_ps( M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2), + _mm_setr_ps(-M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2), + _mm_setr_ps(-M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2), + _mm_setr_ps(-M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2), + _mm_setr_ps(-M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2), + _mm_setr_ps(-M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2), + _mm_setr_ps(-M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2), + _mm_setr_ps(-M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2), + _mm_setr_ps(-M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2) + }; + size_t inOffset = 0; + size_t outOffset = 0; + uint8_t tmp = 0; + for (size_t i = 0; i < dataIn->getLength(); i += m_carriers / 4) { + for (size_t j = 0; j < m_carriers / 8; ++j) { + tmp = (in[inOffset] & 0xc0) >> 4; + tmp |= (in[inOffset + (m_carriers / 8)] & 0xc0) >> 6; + out[outOffset] = symbols[tmp]; + tmp = (in[inOffset] & 0x30) >> 2; + tmp |= (in[inOffset + (m_carriers / 8)] & 0x30) >> 4; + out[outOffset + 1] = symbols[tmp]; + tmp = (in[inOffset] & 0x0c); + tmp |= (in[inOffset + (m_carriers / 8)] & 0x0c) >> 2; + out[outOffset + 2] = symbols[tmp]; + tmp = (in[inOffset] & 0x03) << 2; + tmp |= (in[inOffset + (m_carriers / 8)] & 0x03); + out[outOffset + 3] = symbols[tmp]; + ++inOffset; + outOffset += 4; + } + inOffset += m_carriers / 8; + } #else // !__SSE__ - const uint8_t* in = reinterpret_cast<const uint8_t*>(dataIn->getData()); - float* out = reinterpret_cast<float*>(dataOut->getData()); - if (dataIn->getLength() % (d_carriers / 4) != 0) { - throw std::runtime_error( - "QpskSymbolMapper::process input size not valid!"); - } - if (dataOut->getLength() / sizeof(float) != dataIn->getLength() * 4 * 2) { // 4 output complex symbols per input byte - throw std::runtime_error( - "QpskSymbolMapper::process output size not valid!"); - } + const uint8_t* in = reinterpret_cast<const uint8_t*>(dataIn->getData()); + float* out = reinterpret_cast<float*>(dataOut->getData()); + if (dataIn->getLength() % (m_carriers / 4) != 0) { + throw std::runtime_error( + "QpskSymbolMapper::process input size not valid!"); + } + if (dataOut->getLength() / sizeof(float) != dataIn->getLength() * 4 * 2) { // 4 output complex symbols per input byte + throw std::runtime_error( + "QpskSymbolMapper::process output size not valid!"); + } - const static float symbols[16][4] = { - { M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2}, - { M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2}, - { M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2}, - { M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2}, - { M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2}, - { M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2}, - { M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2}, - { M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2}, - {-M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2}, - {-M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2}, - {-M_SQRT1_2,- M_SQRT1_2, M_SQRT1_2, M_SQRT1_2}, - {-M_SQRT1_2,- M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2}, - {-M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2}, - {-M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2}, - {-M_SQRT1_2,- M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2}, - {-M_SQRT1_2,- M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2} - }; - size_t inOffset = 0; - size_t outOffset = 0; - uint8_t tmp; - for (size_t i = 0; i < dataIn->getLength(); i += d_carriers / 4) { - for (size_t j = 0; j < d_carriers / 8; ++j) { - tmp = (in[inOffset] & 0xc0) >> 4; - tmp |= (in[inOffset + (d_carriers / 8)] & 0xc0) >> 6; - memcpy(&out[outOffset], symbols[tmp], sizeof(float) * 4); - tmp = (in[inOffset] & 0x30) >> 2; - tmp |= (in[inOffset + (d_carriers / 8)] & 0x30) >> 4; - memcpy(&out[outOffset + 4], symbols[tmp], sizeof(float) * 4); - tmp = (in[inOffset] & 0x0c); - tmp |= (in[inOffset + (d_carriers / 8)] & 0x0c) >> 2; - memcpy(&out[outOffset + 8], symbols[tmp], sizeof(float) * 4); - tmp = (in[inOffset] & 0x03) << 2; - tmp |= (in[inOffset + (d_carriers / 8)] & 0x03); - memcpy(&out[outOffset + 12], symbols[tmp], sizeof(float) * 4); - ++inOffset; - outOffset += 4*4; + const static float symbols[16][4] = { + { M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2}, + { M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2}, + { M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2}, + { M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2}, + { M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2}, + { M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2}, + { M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2}, + { M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2}, + {-M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2}, + {-M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2}, + {-M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2}, + {-M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2}, + {-M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2}, + {-M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2}, + {-M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2}, + {-M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2} + }; + size_t inOffset = 0; + size_t outOffset = 0; + uint8_t tmp; + for (size_t i = 0; i < dataIn->getLength(); i += m_carriers / 4) { + for (size_t j = 0; j < m_carriers / 8; ++j) { + tmp = (in[inOffset] & 0xc0) >> 4; + tmp |= (in[inOffset + (m_carriers / 8)] & 0xc0) >> 6; + memcpy(&out[outOffset], symbols[tmp], sizeof(float) * 4); + tmp = (in[inOffset] & 0x30) >> 2; + tmp |= (in[inOffset + (m_carriers / 8)] & 0x30) >> 4; + memcpy(&out[outOffset + 4], symbols[tmp], sizeof(float) * 4); + tmp = (in[inOffset] & 0x0c); + tmp |= (in[inOffset + (m_carriers / 8)] & 0x0c) >> 2; + memcpy(&out[outOffset + 8], symbols[tmp], sizeof(float) * 4); + tmp = (in[inOffset] & 0x03) << 2; + tmp |= (in[inOffset + (m_carriers / 8)] & 0x03); + memcpy(&out[outOffset + 12], symbols[tmp], sizeof(float) * 4); + ++inOffset; + outOffset += 4*4; + } + inOffset += m_carriers / 8; } - inOffset += d_carriers / 8; - } #endif // __SSE__ + } return 1; } diff --git a/src/QpskSymbolMapper.h b/src/QpskSymbolMapper.h index dbcf4dd..6cf7a2e 100644 --- a/src/QpskSymbolMapper.h +++ b/src/QpskSymbolMapper.h @@ -31,12 +31,13 @@ class QpskSymbolMapper : public ModCodec { public: - QpskSymbolMapper(size_t carriers); + QpskSymbolMapper(size_t carriers, bool fixedPoint); int process(Buffer* const dataIn, Buffer* dataOut); const char* name() { return "QpskSymbolMapper"; } protected: - size_t d_carriers; + bool m_fixedPoint; + size_t m_carriers; }; diff --git a/src/SignalMultiplexer.cpp b/src/SignalMultiplexer.cpp index 1d95bdd..8ecbe78 100644 --- a/src/SignalMultiplexer.cpp +++ b/src/SignalMultiplexer.cpp @@ -28,9 +28,8 @@ #include <string.h> -SignalMultiplexer::SignalMultiplexer(size_t framesize) : - ModMux(), - d_frameSize(framesize) +SignalMultiplexer::SignalMultiplexer() : + ModMux() { PDEBUG("SignalMultiplexer::SignalMultiplexer(%zu) @ %p\n", framesize, this); diff --git a/src/SignalMultiplexer.h b/src/SignalMultiplexer.h index 5186a8d..1f6bc12 100644 --- a/src/SignalMultiplexer.h +++ b/src/SignalMultiplexer.h @@ -36,7 +36,7 @@ class SignalMultiplexer : public ModMux { public: - SignalMultiplexer(size_t frameSize); + SignalMultiplexer(); virtual ~SignalMultiplexer(); SignalMultiplexer(const SignalMultiplexer&); SignalMultiplexer& operator=(const SignalMultiplexer&); @@ -44,8 +44,5 @@ public: int process(std::vector<Buffer*> dataIn, Buffer* dataOut); const char* name() { return "SignalMultiplexer"; } - -protected: - size_t d_frameSize; }; diff --git a/src/Utils.cpp b/src/Utils.cpp index 788d125..0065bc1 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -26,9 +26,9 @@ */ #include <ctime> +#include <cstring> #include <sstream> #include "Utils.h" -#include "GainControl.h" #if defined(HAVE_PRCTL) # include <sys/prctl.h> #endif |