aboutsummaryrefslogtreecommitdiffstats
path: root/src/DabModulator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/DabModulator.cpp')
-rw-r--r--src/DabModulator.cpp328
1 files changed, 328 insertions, 0 deletions
diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp
new file mode 100644
index 0000000..6396a4d
--- /dev/null
+++ b/src/DabModulator.cpp
@@ -0,0 +1,328 @@
+/*
+ Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012
+ Her Majesty the Queen in Right of Canada (Communications Research
+ Center Canada)
+ */
+/*
+ This file is part of CRC-DADMOD.
+
+ CRC-DADMOD is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ CRC-DADMOD is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with CRC-DADMOD. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "DabModulator.h"
+#include "PcDebug.h"
+
+#include "FrameMultiplexer.h"
+#include "PrbsGenerator.h"
+#include "BlockPartitioner.h"
+#include "QpskSymbolMapper.h"
+#include "FrequencyInterleaver.h"
+#include "PhaseReference.h"
+#include "DifferentialModulator.h"
+#include "NullSymbol.h"
+#include "SignalMultiplexer.h"
+#include "CicEqualizer.h"
+#include "OfdmGenerator.h"
+#include "GainControl.h"
+#include "GuardIntervalInserter.h"
+#include "Resampler.h"
+#include "ConvEncoder.h"
+#include "PuncturingEncoder.h"
+#include "TimeInterleaver.h"
+
+
+DabModulator::DabModulator(unsigned outputRate, unsigned clockRate,
+ unsigned dabMode, GainMode gainMode, float factor) :
+ ModCodec(ModFormat(1), ModFormat(0)),
+ myOutputRate(outputRate),
+ myClockRate(clockRate),
+ myDabMode(dabMode),
+ myGainMode(gainMode),
+ myFactor(factor),
+ myFlowgraph(NULL)
+{
+ PDEBUG("DabModulator::DabModulator(%u, %u, %u, %u) @ %p\n",
+ outputRate, clockRate, dabMode, gainMode, this);
+
+ if (myDabMode == 0) {
+ setMode(2);
+ } else {
+ setMode(myDabMode);
+ }
+}
+
+
+DabModulator::~DabModulator()
+{
+ PDEBUG("DabModulator::~DabModulator() @ %p\n", this);
+
+ delete myFlowgraph;
+}
+
+
+void DabModulator::setMode(unsigned mode)
+{
+ switch (mode) {
+ case 1:
+ myNbSymbols = 76;
+ myNbCarriers = 1536;
+ mySpacing = 2048;
+ myNullSize = 2656;
+ mySymSize = 2552;
+ myFicSizeOut = 288;
+ break;
+ case 2:
+ myNbSymbols = 76;
+ myNbCarriers = 384;
+ mySpacing = 512;
+ myNullSize = 664;
+ mySymSize = 638;
+ myFicSizeOut = 288;
+ break;
+ case 3:
+ myNbSymbols = 153;
+ myNbCarriers = 192;
+ mySpacing = 256;
+ myNullSize = 345;
+ mySymSize = 319;
+ myFicSizeOut = 384;
+ break;
+ case 4:
+ myNbSymbols = 76;
+ myNbCarriers = 768;
+ mySpacing = 1024;
+ myNullSize = 1328;
+ mySymSize = 1276;
+ myFicSizeOut = 288;
+ break;
+ default:
+ throw std::runtime_error("DabModulator::setMode invalid mode size");
+ }
+
+ myOutputFormat.size((size_t)((myNullSize + (myNbSymbols * mySymSize))
+ * sizeof(complexf) / 2048000.0 * myOutputRate));
+}
+
+
+int DabModulator::process(Buffer* const dataIn, Buffer* dataOut)
+{
+ PDEBUG("DabModulator::process(dataIn: %p, dataOut: %p)\n",
+ dataIn, dataOut);
+
+ myEtiReader.process(dataIn);
+ if (myFlowgraph == NULL) {
+ unsigned mode = myEtiReader.getMode();
+ if (myDabMode != 0) {
+ mode = myDabMode;
+ } else if (mode == 0) {
+ mode = 4;
+ }
+ setMode(mode);
+
+ myFlowgraph = new Flowgraph();
+ ////////////////////////////////////////////////////////////////
+ // CIF data initialisation
+ ////////////////////////////////////////////////////////////////
+ FrameMultiplexer* cifMux = NULL;
+ PrbsGenerator* cifPrbs = NULL;
+ BlockPartitioner* cifPart = NULL;
+ QpskSymbolMapper* cifMap = NULL;
+ FrequencyInterleaver* cifFreq = NULL;
+ PhaseReference* cifRef = NULL;
+ DifferentialModulator* cifDiff = NULL;
+ NullSymbol* cifNull = NULL;
+ SignalMultiplexer* cifSig = NULL;
+ CicEqualizer* cifCicEq = NULL;
+ OfdmGenerator* cifOfdm = NULL;
+ GainControl* cifGain = NULL;
+ GuardIntervalInserter* cifGuard = NULL;
+ Resampler* cifRes = NULL;
+
+ cifPrbs = new PrbsGenerator(864 * 8, 0x110);
+ cifMux = new FrameMultiplexer(myFicSizeOut + 864 * 8,
+ &myEtiReader.getSubchannels());
+ cifPart = new BlockPartitioner(mode, myEtiReader.getFct());
+ cifMap = new QpskSymbolMapper(myNbCarriers);
+ cifRef = new PhaseReference(mode);
+ cifFreq = new FrequencyInterleaver(mode);
+ cifDiff = new DifferentialModulator(myNbCarriers);
+ cifNull = new NullSymbol(myNbCarriers);
+ cifSig = new SignalMultiplexer(
+ (1 + myNbSymbols) * myNbCarriers * sizeof(complexf));
+
+ if (myClockRate) {
+ cifCicEq = new CicEqualizer(myNbCarriers,
+ (float)mySpacing * (float)myOutputRate / 2048000.0f,
+ myClockRate / myOutputRate);
+ }
+
+ cifOfdm = new OfdmGenerator((1 + myNbSymbols), myNbCarriers, mySpacing);
+ cifGain = new GainControl(mySpacing, myGainMode, myFactor);
+ cifGuard = new GuardIntervalInserter(myNbSymbols, mySpacing,
+ myNullSize, mySymSize);
+ myOutput = new OutputMemory();
+
+ if (myOutputRate != 2048000) {
+ cifRes = new Resampler(2048000, myOutputRate, mySpacing);
+ } else {
+ fprintf(stderr, "No resampler\n");
+ }
+
+ myFlowgraph->connect(cifPrbs, cifMux);
+
+ ////////////////////////////////////////////////////////////////
+ // Processing FIC
+ ////////////////////////////////////////////////////////////////
+ FicSource* fic = myEtiReader.getFic();
+ PrbsGenerator* ficPrbs = NULL;
+ ConvEncoder* ficConv = NULL;
+ PuncturingEncoder* ficPunc = NULL;
+ ////////////////////////////////////////////////////////////////
+ // Data initialisation
+ ////////////////////////////////////////////////////////////////
+ myFicSizeIn = fic->getFramesize();
+
+ ////////////////////////////////////////////////////////////////
+ // Modules configuration
+ ////////////////////////////////////////////////////////////////
+
+ // Configuring FIC channel
+
+ PDEBUG("FIC:\n");
+ PDEBUG(" Framesize: %zu\n", fic->getFramesize());
+
+ // Configuring prbs generator
+ ficPrbs = new PrbsGenerator(myFicSizeIn, 0x110);
+
+ // Configuring convolutionnal encoder
+ ficConv = new ConvEncoder(myFicSizeIn);
+
+ // Configuring puncturing encoder
+ ficPunc = new PuncturingEncoder();
+ std::vector<PuncturingRule*> rules = fic->get_rules();
+ std::vector<PuncturingRule*>::const_iterator rule;
+ for (rule = rules.begin(); rule != rules.end(); ++rule) {
+ PDEBUG(" Adding rule:\n");
+ PDEBUG(" Length: %zu\n", (*rule)->length());
+ PDEBUG(" Pattern: 0x%x\n", (*rule)->pattern());
+ ficPunc->append_rule(*(*rule));
+ }
+ 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);
+
+ ////////////////////////////////////////////////////////////////
+ // Configuring subchannels
+ ////////////////////////////////////////////////////////////////
+ std::vector<SubchannelSource*> subchannels =
+ myEtiReader.getSubchannels();
+ std::vector<SubchannelSource*>::const_iterator subchannel;
+ for (subchannel = subchannels.begin();
+ subchannel != subchannels.end();
+ ++subchannel) {
+ PrbsGenerator* subchPrbs = NULL;
+ ConvEncoder* subchConv = NULL;
+ PuncturingEncoder* subchPunc = NULL;
+ TimeInterleaver* subchInterleaver = NULL;
+
+ ////////////////////////////////////////////////////////////
+ // Data initialisation
+ ////////////////////////////////////////////////////////////
+ size_t subchSizeIn = (*subchannel)->framesize();
+ size_t subchSizeOut = (*subchannel)->framesizeCu() * 8;
+
+ ////////////////////////////////////////////////////////////
+ // Modules configuration
+ ////////////////////////////////////////////////////////////
+
+ // Configuring subchannel
+ PDEBUG("Subchannel:\n");
+ PDEBUG(" Start address: %zu\n",
+ (*subchannel)->startAddress());
+ PDEBUG(" Framesize: %zu\n",
+ (*subchannel)->framesize());
+ PDEBUG(" Bitrate: %zu\n", (*subchannel)->bitrate());
+ PDEBUG(" Framesize CU: %zu\n",
+ (*subchannel)->framesizeCu());
+ PDEBUG(" Protection: %zu\n",
+ (*subchannel)->protection());
+ PDEBUG(" Form: %zu\n",
+ (*subchannel)->protectionForm());
+ PDEBUG(" Level: %zu\n",
+ (*subchannel)->protectionLevel());
+ PDEBUG(" Option: %zu\n",
+ (*subchannel)->protectionOption());
+
+ // Configuring prbs genrerator
+ subchPrbs = new PrbsGenerator(subchSizeIn, 0x110);
+
+ // Configuring convolutionnal encoder
+ subchConv = new ConvEncoder(subchSizeIn);
+
+ // Configuring puncturing encoder
+ subchPunc = new PuncturingEncoder();
+ std::vector<PuncturingRule*> rules = (*subchannel)->get_rules();
+ std::vector<PuncturingRule*>::const_iterator rule;
+ for (rule = rules.begin(); rule != rules.end(); ++rule) {
+ PDEBUG(" Adding rule:\n");
+ PDEBUG(" Length: %zu\n", (*rule)->length());
+ PDEBUG(" Pattern: 0x%x\n", (*rule)->pattern());
+ subchPunc->append_rule(*(*rule));
+ }
+ PDEBUG(" Adding tail\n");
+ subchPunc->append_tail_rule(PuncturingRule(3, 0xcccccc));
+
+ // Configuring time interleaver
+ subchInterleaver = new TimeInterleaver(subchSizeOut);
+
+ myFlowgraph->connect(*subchannel, subchPrbs);
+ myFlowgraph->connect(subchPrbs, subchConv);
+ myFlowgraph->connect(subchConv, subchPunc);
+ myFlowgraph->connect(subchPunc, subchInterleaver);
+ myFlowgraph->connect(subchInterleaver, cifMux);
+ }
+
+ myFlowgraph->connect(cifMux, cifPart);
+ myFlowgraph->connect(cifPart, cifMap);
+ myFlowgraph->connect(cifMap, cifFreq);
+ myFlowgraph->connect(cifRef, cifDiff);
+ myFlowgraph->connect(cifFreq, cifDiff);
+ myFlowgraph->connect(cifNull, cifSig);
+ myFlowgraph->connect(cifDiff, cifSig);
+ if (myClockRate) {
+ myFlowgraph->connect(cifSig, cifCicEq);
+ myFlowgraph->connect(cifCicEq, cifOfdm);
+ } else {
+ myFlowgraph->connect(cifSig, cifOfdm);
+ }
+ myFlowgraph->connect(cifOfdm, cifGain);
+ myFlowgraph->connect(cifGain, cifGuard);
+ if (cifRes != NULL) {
+ myFlowgraph->connect(cifGuard, cifRes);
+ myFlowgraph->connect(cifRes, myOutput);
+ } else {
+ myFlowgraph->connect(cifGuard, myOutput);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////
+ // Proccessing data
+ ////////////////////////////////////////////////////////////////////
+ myOutput->setOutput(dataOut);
+ return myFlowgraph->run();
+}