aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2024-10-06 19:47:19 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2024-10-06 19:47:19 +0200
commit8736f6160aeafe7a177cb6143fea80157e174e52 (patch)
treec73d39eda0db5341875b0fac34cdc89c0961c94a /src
parentb563b465e8b3df367da7799e789d29e0009cb96a (diff)
downloaddabmod-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.h3
-rw-r--r--src/ConfigParser.cpp2
-rw-r--r--src/ConfigParser.h2
-rw-r--r--src/DabMod.cpp12
-rw-r--r--src/DabModulator.cpp74
-rw-r--r--src/DifferentialModulator.cpp69
-rw-r--r--src/DifferentialModulator.h5
-rw-r--r--src/FrequencyInterleaver.cpp77
-rw-r--r--src/FrequencyInterleaver.h9
-rw-r--r--src/GuardIntervalInserter.cpp207
-rw-r--r--src/GuardIntervalInserter.h31
-rw-r--r--src/NullSymbol.cpp9
-rw-r--r--src/NullSymbol.h6
-rw-r--r--src/OfdmGenerator.cpp172
-rw-r--r--src/OfdmGenerator.h50
-rw-r--r--src/OutputMemory.cpp8
-rw-r--r--src/OutputMemory.h2
-rw-r--r--src/PhaseReference.cpp135
-rw-r--r--src/PhaseReference.h22
-rw-r--r--src/QpskSymbolMapper.cpp263
-rw-r--r--src/QpskSymbolMapper.h5
-rw-r--r--src/SignalMultiplexer.cpp5
-rw-r--r--src/SignalMultiplexer.h5
-rw-r--r--src/Utils.cpp2
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