aboutsummaryrefslogtreecommitdiffstats
path: root/src/DabModulator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/DabModulator.cpp')
-rw-r--r--src/DabModulator.cpp229
1 files changed, 127 insertions, 102 deletions
diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp
index aa4f2a8..4a29132 100644
--- a/src/DabModulator.cpp
+++ b/src/DabModulator.cpp
@@ -3,7 +3,7 @@
Her Majesty the Queen in Right of Canada (Communications Research
Center Canada)
- Copyright (C) 2019
+ Copyright (C) 2023
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -27,53 +27,54 @@
#include <string>
#include <memory>
+#include <vector>
#include "DabModulator.h"
#include "PcDebug.h"
-#if !defined(BUILD_FOR_EASYDABV3)
-# include "QpskSymbolMapper.h"
-# include "FrequencyInterleaver.h"
-# include "PhaseReference.h"
-# include "DifferentialModulator.h"
-# include "NullSymbol.h"
-# include "CicEqualizer.h"
-# include "OfdmGenerator.h"
-# include "GainControl.h"
-# include "GuardIntervalInserter.h"
-# include "Resampler.h"
-# include "FIRFilter.h"
-# include "MemlessPoly.h"
-# include "TII.h"
-#endif
-
-#include "FrameMultiplexer.h"
-#include "PrbsGenerator.h"
#include "BlockPartitioner.h"
-#include "SignalMultiplexer.h"
+#include "CicEqualizer.h"
#include "ConvEncoder.h"
+#include "DifferentialModulator.h"
+#include "FIRFilter.h"
+#include "FrameMultiplexer.h"
+#include "FrequencyInterleaver.h"
+#include "GainControl.h"
+#include "GuardIntervalInserter.h"
+#include "Log.h"
+#include "MemlessPoly.h"
+#include "NullSymbol.h"
+#include "OfdmGenerator.h"
+#include "PhaseReference.h"
+#include "PrbsGenerator.h"
#include "PuncturingEncoder.h"
+#include "QpskSymbolMapper.h"
+#include "RemoteControl.h"
+#include "Resampler.h"
+#include "SignalMultiplexer.h"
+#include "TII.h"
#include "TimeInterleaver.h"
#include "TimestampDecoder.h"
-#include "RemoteControl.h"
-#include "Log.h"
using namespace std;
DabModulator::DabModulator(EtiSource& etiSource,
- mod_settings_t& settings) :
+ mod_settings_t& settings,
+ const std::string& format) :
ModInput(),
RemoteControllable("modulator"),
m_settings(settings),
- myEtiSource(etiSource),
- myFlowgraph()
+ m_format(format),
+ m_etiSource(etiSource),
+ m_flowgraph()
{
PDEBUG("DabModulator::DabModulator() @ %p\n", this);
RC_ADD_PARAMETER(rate, "(Read-only) IQ output samplerate");
+ RC_ADD_PARAMETER(num_clipped_samples, "(Read-only) Number of samples clipped in last frame during format conversion");
if (m_settings.dabMode == 0) {
- setMode(2);
+ setMode(1);
}
else {
setMode(m_settings.dabMode);
@@ -85,36 +86,36 @@ void DabModulator::setMode(unsigned mode)
{
switch (mode) {
case 1:
- myNbSymbols = 76;
- myNbCarriers = 1536;
- mySpacing = 2048;
- myNullSize = 2656;
- mySymSize = 2552;
- myFicSizeOut = 288;
+ m_nbSymbols = 76;
+ m_nbCarriers = 1536;
+ m_spacing = 2048;
+ m_nullSize = 2656;
+ m_symSize = 2552;
+ m_ficSizeOut = 288;
break;
case 2:
- myNbSymbols = 76;
- myNbCarriers = 384;
- mySpacing = 512;
- myNullSize = 664;
- mySymSize = 638;
- myFicSizeOut = 288;
+ m_nbSymbols = 76;
+ m_nbCarriers = 384;
+ m_spacing = 512;
+ m_nullSize = 664;
+ m_symSize = 638;
+ m_ficSizeOut = 288;
break;
case 3:
- myNbSymbols = 153;
- myNbCarriers = 192;
- mySpacing = 256;
- myNullSize = 345;
- mySymSize = 319;
- myFicSizeOut = 384;
+ m_nbSymbols = 153;
+ m_nbCarriers = 192;
+ m_spacing = 256;
+ m_nullSize = 345;
+ m_symSize = 319;
+ m_ficSizeOut = 384;
break;
case 4:
- myNbSymbols = 76;
- myNbCarriers = 768;
- mySpacing = 1024;
- myNullSize = 1328;
- mySymSize = 1276;
- myFicSizeOut = 288;
+ m_nbSymbols = 76;
+ m_nbCarriers = 768;
+ m_spacing = 1024;
+ m_nullSize = 1328;
+ m_symSize = 1276;
+ m_ficSizeOut = 288;
break;
default:
throw std::runtime_error("DabModulator::setMode invalid mode size");
@@ -128,27 +129,27 @@ int DabModulator::process(Buffer* dataOut)
PDEBUG("DabModulator::process(dataOut: %p)\n", dataOut);
- if (not myFlowgraph) {
+ if (not m_flowgraph) {
+ etiLog.level(debug) << "Setting up DabModulator...";
const unsigned mode = m_settings.dabMode;
setMode(mode);
- myFlowgraph = make_shared<Flowgraph>(m_settings.showProcessTime);
+ m_flowgraph = make_shared<Flowgraph>(m_settings.showProcessTime);
////////////////////////////////////////////////////////////////
// CIF data initialisation
////////////////////////////////////////////////////////////////
auto cifPrbs = make_shared<PrbsGenerator>(864 * 8, 0x110);
- auto cifMux = make_shared<FrameMultiplexer>(myEtiSource);
+ auto cifMux = make_shared<FrameMultiplexer>(m_etiSource);
auto cifPart = make_shared<BlockPartitioner>(mode);
-#if !defined(BUILD_FOR_EASYDABV3)
- auto cifMap = make_shared<QpskSymbolMapper>(myNbCarriers);
+ auto cifMap = make_shared<QpskSymbolMapper>(m_nbCarriers);
auto cifRef = make_shared<PhaseReference>(mode);
auto cifFreq = make_shared<FrequencyInterleaver>(mode);
- auto cifDiff = make_shared<DifferentialModulator>(myNbCarriers);
+ auto cifDiff = make_shared<DifferentialModulator>(m_nbCarriers);
- auto cifNull = make_shared<NullSymbol>(myNbCarriers);
+ auto cifNull = make_shared<NullSymbol>(m_nbCarriers);
auto cifSig = make_shared<SignalMultiplexer>(
- (1 + myNbSymbols) * myNbCarriers * sizeof(complexf));
+ (1 + m_nbSymbols) * m_nbCarriers * sizeof(complexf));
// TODO this needs a review
bool useCicEq = false;
@@ -169,8 +170,8 @@ int DabModulator::process(Buffer* dataOut)
shared_ptr<CicEqualizer> cifCicEq;
if (useCicEq) {
cifCicEq = make_shared<CicEqualizer>(
- myNbCarriers,
- (float)mySpacing * (float)m_settings.outputRate / 2048000.0f,
+ m_nbCarriers,
+ (float)m_spacing * (float)m_settings.outputRate / 2048000.0f,
cic_ratio);
}
@@ -188,9 +189,9 @@ int DabModulator::process(Buffer* dataOut)
}
auto cifOfdm = make_shared<OfdmGenerator>(
- (1 + myNbSymbols),
- myNbCarriers,
- mySpacing,
+ (1 + m_nbSymbols),
+ m_nbCarriers,
+ m_spacing,
m_settings.enableCfr,
m_settings.cfrClip,
m_settings.cfrErrorClip);
@@ -198,7 +199,7 @@ int DabModulator::process(Buffer* dataOut)
rcs.enrol(cifOfdm.get());
auto cifGain = make_shared<GainControl>(
- mySpacing,
+ m_spacing,
m_settings.gainMode,
m_settings.digitalgain,
m_settings.normalise,
@@ -207,7 +208,7 @@ int DabModulator::process(Buffer* dataOut)
rcs.enrol(cifGain.get());
auto cifGuard = make_shared<GuardIntervalInserter>(
- myNbSymbols, mySpacing, myNullSize, mySymSize,
+ m_nbSymbols, m_spacing, m_nullSize, m_symSize,
m_settings.ofdmWindowOverlap);
rcs.enrol(cifGuard.get());
@@ -229,18 +230,21 @@ int DabModulator::process(Buffer* dataOut)
cifRes = make_shared<Resampler>(
2048000,
m_settings.outputRate,
- mySpacing);
+ m_spacing);
+ }
+
+ if (not m_format.empty()) {
+ m_formatConverter = make_shared<FormatConverter>(m_format);
}
-#endif
- myOutput = make_shared<OutputMemory>(dataOut);
+ m_output = make_shared<OutputMemory>(dataOut);
- myFlowgraph->connect(cifPrbs, cifMux);
+ m_flowgraph->connect(cifPrbs, cifMux);
////////////////////////////////////////////////////////////////
// Processing FIC
////////////////////////////////////////////////////////////////
- shared_ptr<FicSource> fic(myEtiSource.getFic());
+ shared_ptr<FicSource> fic(m_etiSource.getFic());
////////////////////////////////////////////////////////////////
// Data initialisation
////////////////////////////////////////////////////////////////
@@ -272,15 +276,15 @@ int DabModulator::process(Buffer* dataOut)
PDEBUG(" Adding tail\n");
ficPunc->append_tail_rule(PuncturingRule(3, 0xcccccc));
- myFlowgraph->connect(fic, ficPrbs);
- myFlowgraph->connect(ficPrbs, ficConv);
- myFlowgraph->connect(ficConv, ficPunc);
- myFlowgraph->connect(ficPunc, cifPart);
+ m_flowgraph->connect(fic, ficPrbs);
+ m_flowgraph->connect(ficPrbs, ficConv);
+ m_flowgraph->connect(ficConv, ficPunc);
+ m_flowgraph->connect(ficPunc, cifPart);
////////////////////////////////////////////////////////////////
// Configuring subchannels
////////////////////////////////////////////////////////////////
- for (const auto& subchannel : myEtiSource.getSubchannels()) {
+ for (const auto& subchannel : m_etiSource.getSubchannels()) {
////////////////////////////////////////////////////////////
// Data initialisation
@@ -332,59 +336,59 @@ int DabModulator::process(Buffer* dataOut)
// Configuring time interleaver
auto subchInterleaver = make_shared<TimeInterleaver>(subchSizeOut);
- myFlowgraph->connect(subchannel, subchPrbs);
- myFlowgraph->connect(subchPrbs, subchConv);
- myFlowgraph->connect(subchConv, subchPunc);
- myFlowgraph->connect(subchPunc, subchInterleaver);
- myFlowgraph->connect(subchInterleaver, cifMux);
+ m_flowgraph->connect(subchannel, subchPrbs);
+ m_flowgraph->connect(subchPrbs, subchConv);
+ m_flowgraph->connect(subchConv, subchPunc);
+ m_flowgraph->connect(subchPunc, subchInterleaver);
+ m_flowgraph->connect(subchInterleaver, cifMux);
}
- myFlowgraph->connect(cifMux, cifPart);
-#if defined(BUILD_FOR_EASYDABV3)
- myFlowgraph->connect(cifPart, myOutput);
-#else
- myFlowgraph->connect(cifPart, cifMap);
- myFlowgraph->connect(cifMap, cifFreq);
- myFlowgraph->connect(cifRef, cifDiff);
- myFlowgraph->connect(cifFreq, cifDiff);
- myFlowgraph->connect(cifNull, cifSig);
- myFlowgraph->connect(cifDiff, cifSig);
+ m_flowgraph->connect(cifMux, cifPart);
+ m_flowgraph->connect(cifPart, cifMap);
+ m_flowgraph->connect(cifMap, cifFreq);
+ m_flowgraph->connect(cifRef, cifDiff);
+ m_flowgraph->connect(cifFreq, cifDiff);
+ m_flowgraph->connect(cifNull, cifSig);
+ m_flowgraph->connect(cifDiff, cifSig);
if (tii) {
- myFlowgraph->connect(tiiRef, tii);
- myFlowgraph->connect(tii, cifSig);
+ m_flowgraph->connect(tiiRef, tii);
+ m_flowgraph->connect(tii, cifSig);
}
shared_ptr<ModPlugin> prev_plugin = static_pointer_cast<ModPlugin>(cifSig);
- const std::list<shared_ptr<ModPlugin> > plugins({
+ const std::vector<shared_ptr<ModPlugin> > plugins({
static_pointer_cast<ModPlugin>(cifCicEq),
static_pointer_cast<ModPlugin>(cifOfdm),
static_pointer_cast<ModPlugin>(cifGain),
static_pointer_cast<ModPlugin>(cifGuard),
- static_pointer_cast<ModPlugin>(cifFilter), // optional block
- static_pointer_cast<ModPlugin>(cifRes), // optional block
- static_pointer_cast<ModPlugin>(cifPoly), // optional block
- static_pointer_cast<ModPlugin>(myOutput),
+ // optional blocks
+ static_pointer_cast<ModPlugin>(cifFilter),
+ static_pointer_cast<ModPlugin>(cifRes),
+ static_pointer_cast<ModPlugin>(cifPoly),
+ static_pointer_cast<ModPlugin>(m_formatConverter),
+ // mandatory block
+ static_pointer_cast<ModPlugin>(m_output),
});
for (auto& p : plugins) {
if (p) {
- myFlowgraph->connect(prev_plugin, p);
+ m_flowgraph->connect(prev_plugin, p);
prev_plugin = p;
}
}
-#endif
+ etiLog.level(debug) << "DabModulator set up.";
}
////////////////////////////////////////////////////////////////////
// Processing data
////////////////////////////////////////////////////////////////////
- return myFlowgraph->run();
+ return m_flowgraph->run();
}
meta_vec_t DabModulator::process_metadata(const meta_vec_t& metadataIn)
{
- if (myOutput) {
- return myOutput->get_latest_metadata();
+ if (m_output) {
+ return m_output->get_latest_metadata();
}
return {};
@@ -396,6 +400,9 @@ void DabModulator::set_parameter(const string& parameter, const string& value)
if (parameter == "rate") {
throw ParameterError("Parameter 'rate' is read-only");
}
+ else if (parameter == "num_clipped_samples") {
+ throw ParameterError("Parameter 'num_clipped_samples' is read-only");
+ }
else {
stringstream ss;
ss << "Parameter '" << parameter <<
@@ -410,6 +417,16 @@ const string DabModulator::get_parameter(const string& parameter) const
if (parameter == "rate") {
ss << m_settings.outputRate;
}
+ else if (parameter == "num_clipped_samples") {
+ if (m_formatConverter) {
+ ss << m_formatConverter->get_num_clipped_samples();
+ }
+ else {
+ ss << "Parameter '" << parameter <<
+ "' is not available when no format conversion is done.";
+ throw ParameterError(ss.str());
+ }
+ }
else {
ss << "Parameter '" << parameter <<
"' is not exported by controllable " << get_rc_name();
@@ -417,3 +434,11 @@ const string DabModulator::get_parameter(const string& parameter) const
}
return ss.str();
}
+
+const json::map_t DabModulator::get_all_values() const
+{
+ json::map_t map;
+ map["rate"].v = m_settings.outputRate;
+ map["num_clipped_samples"].v = m_formatConverter ? m_formatConverter->get_num_clipped_samples() : 0;
+ return map;
+}