summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/example.ini7
-rw-r--r--src/DabMod.cpp7
-rw-r--r--src/DabModulator.cpp5
-rw-r--r--src/TII.cpp75
-rw-r--r--src/TII.h49
5 files changed, 100 insertions, 43 deletions
diff --git a/doc/example.ini b/doc/example.ini
index 6887972..bdb3f00 100644
--- a/doc/example.ini
+++ b/doc/example.ini
@@ -270,4 +270,9 @@ offset=0.002
enable=0
comb=16
pattern=3
-
+; There are two variants of TII being used. The old variant that uses the wrong
+; phase on the second carrier in each carrier pairs and is therefore not
+; conforming to the specification. Modern analysers can decode both variants,
+; while others, like the Philips DAB752 and the VAD v2 monitor are known to
+; decode only the old non-conforming variant.
+old_variant=0
diff --git a/src/DabMod.cpp b/src/DabMod.cpp
index 526670d..37db71a 100644
--- a/src/DabMod.cpp
+++ b/src/DabMod.cpp
@@ -588,9 +588,10 @@ int launch_modulator(int argc, char* argv[])
#endif
/* Read TII parameters from config file */
- tiiConfig.enable = pt.get("tii.enable", 0);
- tiiConfig.comb = pt.get("tii.comb", 0);
- tiiConfig.pattern = pt.get("tii.pattern", 0);
+ tiiConfig.enable = pt.get("tii.enable", 0);
+ tiiConfig.comb = pt.get("tii.comb", 0);
+ tiiConfig.pattern = pt.get("tii.pattern", 0);
+ tiiConfig.old_variant = pt.get("tii.old_variant", 0);
}
etiLog.level(info) << "Starting up version " <<
diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp
index 827b73f..678d175 100644
--- a/src/DabModulator.cpp
+++ b/src/DabModulator.cpp
@@ -187,9 +187,11 @@ int DabModulator::process(Buffer* dataOut)
(float)mySpacing * (float)myOutputRate / 2048000.0f, cic_ratio);
shared_ptr<TII> tii;
+ shared_ptr<PhaseReference> tiiRef;
try {
- tii = make_shared<TII>(myDabMode, myTiiConfig);
+ tii = make_shared<TII>(myDabMode, myTiiConfig, myEtiSource.getFp());
rcs.enrol(tii.get());
+ tiiRef = make_shared<PhaseReference>(mode);
}
catch (TIIError& e) {
etiLog.level(error) << "Could not initialise TII: " << e.what();
@@ -331,6 +333,7 @@ int DabModulator::process(Buffer* dataOut)
myFlowgraph->connect(cifNull, cifSig);
myFlowgraph->connect(cifDiff, cifSig);
if (tii) {
+ myFlowgraph->connect(tiiRef, tii);
myFlowgraph->connect(tii, cifSig);
}
diff --git a/src/TII.cpp b/src/TII.cpp
index 15543d0..6bc3f0d 100644
--- a/src/TII.cpp
+++ b/src/TII.cpp
@@ -2,7 +2,7 @@
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty
the Queen in Right of Canada (Communications Research Center Canada)
- Copyright (C) 2015
+ Copyright (C) 2017
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -106,22 +106,23 @@ const int pattern_tm1_2_4[][8] = { // {{{
{1,1,1,0,1,0,0,0},
{1,1,1,1,0,0,0,0} }; // }}}
-TII::TII(unsigned int dabmode, tii_config_t& tii_config) :
- ModInput(),
+TII::TII(unsigned int dabmode, tii_config_t& tii_config, unsigned phase) :
+ ModCodec(),
RemoteControllable("tii"),
m_dabmode(dabmode),
- m_conf(tii_config),
- m_insert(true)
+ m_conf(tii_config)
{
PDEBUG("TII::TII(%u) @ %p\n", dabmode, this);
RC_ADD_PARAMETER(enable, "enable TII [0-1]");
RC_ADD_PARAMETER(comb, "TII comb number [0-23]");
RC_ADD_PARAMETER(pattern, "TII pattern number [0-69]");
+ RC_ADD_PARAMETER(old_variant, "select old TII variant for old (buggy) receivers [0-1]");
switch (m_dabmode) {
case 1:
m_carriers = 1536;
+ m_insert = (phase & 0x40) ? false : true;
if (not(0 <= m_conf.pattern and m_conf.pattern <= 69) ) {
throw TIIError("TII::TII pattern not valid!");
@@ -129,6 +130,7 @@ TII::TII(unsigned int dabmode, tii_config_t& tii_config) :
break;
case 2:
m_carriers = 384;
+ m_insert = (phase & 0x01) ? false : true;
if (not(0 <= m_conf.pattern and m_conf.pattern <= 69) ) {
throw TIIError("TII::TII pattern not valid!");
@@ -153,8 +155,8 @@ TII::TII(unsigned int dabmode, tii_config_t& tii_config) :
throw TIIError("TII::TII comb not valid!");
}
- m_dataIn.clear();
- m_dataIn.resize(m_carriers);
+ m_enabled_carriers.clear();
+ m_enabled_carriers.resize(m_carriers);
prepare_pattern();
}
@@ -169,28 +171,47 @@ const char* TII::name()
// Calculate name on demand because comb and pattern are
// modifiable through RC
std::stringstream ss;
- ss << "TII(comb:" << m_conf.comb << ", pattern:" << m_conf.pattern << ")";
+ ss << "TII(comb:" << m_conf.comb <<
+ ", pattern:" << m_conf.pattern <<
+ ", variant:" << (m_conf.old_variant ? "old" : "new") << ")";
m_name = ss.str();
return m_name.c_str();
}
-int TII::process(Buffer* dataOut)
+int TII::process(Buffer* dataIn, Buffer* dataOut)
{
PDEBUG("TII::process(dataOut: %p)\n",
dataOut);
+ if ( (dataIn == NULL) or
+ (dataIn->getLength() != m_carriers * sizeof(complexf))) {
+ throw TIIError("TII::process input size not valid!");
+ }
+
+ dataOut->setLength(m_carriers * sizeof(complexf));
+ bzero(dataOut->getData(), dataOut->getLength());
if (m_conf.enable and m_insert) {
- boost::mutex::scoped_lock lock(m_dataIn_mutex);
- dataOut->setData(&m_dataIn[0], m_carriers * sizeof(complexf));
- }
- else {
- dataOut->setLength(m_carriers * sizeof(complexf));
- bzero(dataOut->getData(), dataOut->getLength());
+ boost::mutex::scoped_lock lock(m_enabled_carriers_mutex);
+ complexf* in = reinterpret_cast<complexf*>(dataIn->getData());
+ complexf* out = reinterpret_cast<complexf*>(dataOut->getData());
+
+ for (size_t i = 0; i < m_enabled_carriers.size(); i+=2) {
+ //BAD implementation:
+ // setting exactly the same phase of the signal for lower adjacent
+ // frequency
+ if (m_enabled_carriers[i]) {
+ out[i] = m_conf.old_variant ? in[i+1] : in[i];
+ }
+
+ if (m_enabled_carriers[i+1]) {
+ out[i+1] = in[i+1];
+ }
+ }
}
- // TODO wrong! Must align with frames containing the right data
+ // Align with frames containing the right data (when FC.fp is first quarter)
m_insert = not m_insert;
return 1;
@@ -199,23 +220,25 @@ int TII::process(Buffer* dataOut)
void TII::enable_carrier(int k) {
int ix = m_carriers/2 + k;
- if (ix < 0 or ix+1 >= (ssize_t)m_dataIn.size()) {
+ if (ix < 0 or ix+1 >= (ssize_t)m_enabled_carriers.size()) {
throw TIIError("TII::enable_carrier invalid k!");
}
- // TODO power of the carrier ?
- m_dataIn.at(ix) = 1.0;
- m_dataIn.at(ix+1) = 1.0; // TODO verify if +1 is really correct
+ m_enabled_carriers[ix] = true;
+ // NULL frequency is never enabled.
+ if (ix > 1 and (ix-1 != 768)) {
+ m_enabled_carriers[ix-1] = true;
+ }
}
void TII::prepare_pattern() {
int comb = m_conf.comb; // Convert from unsigned to signed
- boost::mutex::scoped_lock lock(m_dataIn_mutex);
+ boost::mutex::scoped_lock lock(m_enabled_carriers_mutex);
// Clear previous pattern
- for (size_t i = 0; i < m_dataIn.size(); i++) {
- m_dataIn[i] = 0.0;
+ for (size_t i = 0; i < m_enabled_carriers.size(); i++) {
+ m_enabled_carriers[i] = false;
}
// This could be written more efficiently, but since it is
@@ -309,6 +332,9 @@ void TII::set_parameter(const std::string& parameter, const std::string& value)
m_conf.comb = new_comb;
prepare_pattern();
}
+ else if (parameter == "old_variant") {
+ ss >> m_conf.old_variant;
+ }
else {
stringstream ss;
ss << "Parameter '" << parameter <<
@@ -330,6 +356,9 @@ const std::string TII::get_parameter(const std::string& parameter) const
else if (parameter == "comb") {
ss << m_conf.comb;
}
+ else if (parameter == "old_variant") {
+ ss << (m_conf.old_variant ? 1 : 0);
+ }
else {
ss << "Parameter '" << parameter <<
"' is not exported by controllable " << get_rc_name();
diff --git a/src/TII.h b/src/TII.h
index d491c43..2bd2040 100644
--- a/src/TII.h
+++ b/src/TII.h
@@ -2,7 +2,7 @@
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty
the Queen in Right of Canada (Communications Research Center Canada)
- Copyright (C) 2015
+ Copyright (C) 2017
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -43,11 +43,33 @@
struct tii_config_t
{
- tii_config_t() : enable(false), comb(0), pattern(0) {}
+ tii_config_t() : enable(false), comb(0), pattern(0), old_variant(false) {}
bool enable;
int comb;
int pattern;
+
+ /* EN 300 401 clause 14.8 describes how to generate the TII signal, and
+ * defines z_{m,0,k}:
+ *
+ * z_{m,0,k} = A_{c,p}(k) e^{j \psi_k} + A_{c,p}(k-1) e^{j \psi{k-1}}
+ *
+ * What was implemented in the old variant was
+ *
+ * z_{m,0,k} = A_{c,p}(k) e^{j \psi_k} + A_{c,p}(k-1) e^{j \psi{k}}
+ * ^
+ * |
+ * Wrong phase on the second
+ * carrier of the pair.
+ *
+ * Correctly implemented decoders ought to be able to decode such a TII,
+ * but will not be able to correctly estimate the delay of different
+ * transmitters.
+ *
+ * The option 'old_variant' allows the user to choose between this
+ * old incorrect implementation and the new conforming one.
+ */
+ bool old_variant;
};
class TIIError : public std::runtime_error {
@@ -58,13 +80,15 @@ class TIIError : public std::runtime_error {
std::runtime_error(msg) {}
};
-class TII : public ModInput, public RemoteControllable
+class TII : public ModCodec, public RemoteControllable
{
public:
- TII(unsigned int dabmode, tii_config_t& tii_config);
+ TII(unsigned int dabmode, tii_config_t& tii_config, unsigned phase);
virtual ~TII();
+ TII(const TII&) = delete;
+ TII& operator=(const TII&) = delete;
- int process(Buffer* dataOut);
+ int process(Buffer* dataIn, Buffer* dataOut);
const char* name();
/******* REMOTE CONTROL ********/
@@ -74,13 +98,12 @@ class TII : public ModInput, public RemoteControllable
virtual const std::string get_parameter(
const std::string& parameter) const;
-
protected:
- // Fill m_dataIn with the correct carriers for the pattern/comb
+ // Fill m_enabled_carriers with the correct carriers for the pattern/comb
// combination
void prepare_pattern(void);
- // prerequisites: calling thread must hold m_dataIn mutex
+ // prerequisites: calling thread must hold m_enabled_carriers mutex
void enable_carrier(int k);
// Configuration settings
@@ -96,14 +119,10 @@ class TII : public ModInput, public RemoteControllable
std::string m_name;
- // m_dataIn is read by modulator thread, and written
+ // m_enabled_carriers is read by modulator thread, and written
// to by RC thread.
- mutable boost::mutex m_dataIn_mutex;
- std::vector<std::complex<float> > m_dataIn;
-
- private:
- TII(const TII&);
- TII& operator=(const TII&);
+ mutable boost::mutex m_enabled_carriers_mutex;
+ std::vector<bool> m_enabled_carriers;
};