/*
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty
the Queen in Right of Canada (Communications Research Center Canada)
Copyright (C) 2018
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
*/
/*
This file is part of ODR-DabMod.
ODR-DabMod 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.
ODR-DabMod 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 ODR-DabMod. If not, see .
*/
#include "PhaseReference.h"
#include "PcDebug.h"
#include
/* ETSI EN 300 401 Table 43 (Clause 14.3.2)
* Contains h_{i,k} values
*/
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,
0, 3, 2, 3, 0, 1, 3, 0, 2, 1, 2, 3, 2, 3, 3, 0 },
/* h2 */ { 0, 0, 0, 2, 0, 2, 1, 3, 2, 2, 0, 2, 2, 0, 1, 3,
0, 0, 0, 2, 0, 2, 1, 3, 2, 2, 0, 2, 2, 0, 1, 3 },
/* h3 */ { 0, 1, 2, 1, 0, 3, 3, 2, 2, 3, 2, 1, 2, 1, 3, 2,
0, 1, 2, 1, 0, 3, 3, 2, 2, 3, 2, 1, 2, 1, 3, 2 }
};
/* EN 300 401, Clause 14.3.2:
* \phi_k = (\pi / 2) * (h_{i,k-k'} + n
*
* where "The indices i, k' and the parameter n are specified as functions of
* the carrier index k for the four transmission modes in tables 44 to 47."
*
* Tables 44 to 47 describe the frequency interleaving done in
* FrequencyInterleaver.
*/
PhaseReference::PhaseReference(unsigned int dabmode, bool fixedPoint) :
ModInput(),
d_dabmode(dabmode),
d_fixedPoint(fixedPoint)
{
PDEBUG("PhaseReference::PhaseReference(%u) @ %p\n", dabmode, this);
switch (d_dabmode) {
case 1:
d_carriers = 1536;
break;
case 2:
d_carriers = 384;
break;
case 3:
d_carriers = 192;
break;
case 4:
d_dabmode = 0;
case 0:
d_carriers = 768;
break;
default:
throw std::runtime_error(
"PhaseReference::PhaseReference DAB mode not valid!");
}
if (d_fixedPoint) {
d_phaseRefFixed.fillData(d_dabmode, d_carriers);
}
else {
d_phaseRefCF32.fillData(d_dabmode, d_carriers);
}
}
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::convert(uint8_t data) {
const complexf value[] = {
complexf(1, 0),
complexf(0, 1),
complexf(-1, 0),
complexf(0, -1),
};
return value[data % 4];
}
template <>
complexfix PhaseRefGen::convert(uint8_t data) {
constexpr auto one = fixed_16{1};
constexpr auto zero = fixed_16{0};
const complexfix value[] = {
complexfix(one, zero),
complexfix(zero, one),
complexfix(-one, zero),
complexfix(zero, -one),
};
return value[data % 4];
}
template
void PhaseRefGen::fillData(unsigned int dabmode, size_t carriers)
{
dataIn.resize(carriers);
if (dataIn.size() != carriers) {
throw std::runtime_error(
"PhaseReference::fillData dataIn has incorrect size!");
}
for (size_t index = 0,
offset = 0;
index < dataIn.size();
++offset) {
for (size_t k = 0; k < 32; ++k) {
dataIn[index++] = convert(
d_h[ table[dabmode][offset][0] ][k] +
table[dabmode][offset][1] );
}
}
}
int PhaseReference::process(Buffer* dataOut)
{
PDEBUG("PhaseReference::process(dataOut: %p)\n", dataOut);
if (d_fixedPoint) {
dataOut->setData(d_phaseRefFixed.dataIn.data(), d_carriers * sizeof(complexfix));
}
else {
dataOut->setData(d_phaseRefCF32.dataIn.data(), d_carriers * sizeof(complexf));
}
return 1;
}