aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dpd/dpd.ini3
-rw-r--r--dpd/poly.coef6
-rw-r--r--dpd/poly_am.coef6
-rw-r--r--dpd/poly_pm.coef6
-rw-r--r--src/ConfigParser.cpp9
-rw-r--r--src/ConfigParser.h3
-rw-r--r--src/DabModulator.cpp6
-rw-r--r--src/MemlessPoly.cpp210
-rw-r--r--src/MemlessPoly.h15
9 files changed, 189 insertions, 75 deletions
diff --git a/dpd/dpd.ini b/dpd/dpd.ini
index 1bc51de..54af9ce 100644
--- a/dpd/dpd.ini
+++ b/dpd/dpd.ini
@@ -22,7 +22,8 @@ enabled=1
[poly]
enabled=1
-polycoeffile=dpd/poly.coef
+polycoeffileam=dpd/poly_am.coef
+polycoeffilepm=dpd/poly_pm.coef
# How many threads to use for the predistorter.
# If not set, detect automatically.
diff --git a/dpd/poly.coef b/dpd/poly.coef
deleted file mode 100644
index de5ec68..0000000
--- a/dpd/poly.coef
+++ /dev/null
@@ -1,6 +0,0 @@
-5
-0.8
-0
-0
-0
-0
diff --git a/dpd/poly_am.coef b/dpd/poly_am.coef
new file mode 100644
index 0000000..ff09e5a
--- /dev/null
+++ b/dpd/poly_am.coef
@@ -0,0 +1,6 @@
+5
+2.2
+1.16110192544
+-13.7895532562
+55.107515965
+-53.8583673922
diff --git a/dpd/poly_pm.coef b/dpd/poly_pm.coef
new file mode 100644
index 0000000..ae91b12
--- /dev/null
+++ b/dpd/poly_pm.coef
@@ -0,0 +1,6 @@
+5
+0.141477421551
+-0.654864288614
+1.00568534673
+-0.588530075442
+0.0935391293974
diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp
index 9ac1280..062660b 100644
--- a/src/ConfigParser.cpp
+++ b/src/ConfigParser.cpp
@@ -168,10 +168,13 @@ static void parse_configfile(
pt.get<std::string>("firfilter.filtertapsfile", "default");
}
- // Poly coefficients:
+ // Poly coefficients amplitude:
if (pt.get("poly.enabled", 0) == 1) {
- mod_settings.polyCoefFilename =
- pt.get<std::string>("poly.polycoeffile", "dpd/poly.coef");
+ mod_settings.polyCoefFilenameAm =
+ pt.get<std::string>("poly.polycoeffileam", "dpd/poly_am.coef");
+
+ mod_settings.polyCoefFilenamePm =
+ pt.get<std::string>("poly.polycoeffilepm", "dpd/poly_pm.coef");
mod_settings.polyNumThreads =
pt.get<int>("poly.num_threads", 0);
diff --git a/src/ConfigParser.h b/src/ConfigParser.h
index 89f0fb7..d99fa08 100644
--- a/src/ConfigParser.h
+++ b/src/ConfigParser.h
@@ -74,7 +74,8 @@ struct mod_settings_t {
std::string filterTapsFilename = "";
- std::string polyCoefFilename = "";
+ std::string polyCoefFilenameAm = "";
+ std::string polyCoefFilenamePm = "";
unsigned polyNumThreads = 0;
#if defined(HAVE_OUTPUT_UHD)
diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp
index cc2642a..f7f583a 100644
--- a/src/DabModulator.cpp
+++ b/src/DabModulator.cpp
@@ -204,8 +204,10 @@ int DabModulator::process(Buffer* dataOut)
}
shared_ptr<MemlessPoly> cifPoly;
- if (not m_settings.polyCoefFilename.empty()) {
- cifPoly = make_shared<MemlessPoly>(m_settings.polyCoefFilename,
+ if (not m_settings.polyCoefFilenameAm.empty() and
+ not m_settings.polyCoefFilenamePm.empty() ) {
+ cifPoly = make_shared<MemlessPoly>(m_settings.polyCoefFilenameAm,
+ m_settings.polyCoefFilenamePm,
m_settings.polyNumThreads);
rcs.enrol(cifPoly.get());
}
diff --git a/src/MemlessPoly.cpp b/src/MemlessPoly.cpp
index 7da868e..e103b73 100644
--- a/src/MemlessPoly.cpp
+++ b/src/MemlessPoly.cpp
@@ -47,18 +47,24 @@
using namespace std;
-#define NUM_COEFS 5
+#define NUM_COEFS_AM 5
+#define NUM_COEFS_PM 5
-MemlessPoly::MemlessPoly(const std::string& coefs_file, unsigned int num_threads) :
+MemlessPoly::MemlessPoly(const std::string& coefs_am_file, const std::string& coefs_pm_file, unsigned int num_threads) :
PipelinedModCodec(),
RemoteControllable("memlesspoly"),
m_num_threads(num_threads),
- m_coefs(),
- m_coefs_file(coefs_file),
- m_coefs_mutex()
+ m_coefs_am(),
+ m_coefs_am_file(coefs_am_file),
+ m_coefs_am_mutex(),
+ m_coefs_pm(),
+ m_coefs_pm_file(coefs_pm_file),
+ m_coefs_pm_mutex()
{
PDEBUG("MemlessPoly::MemlessPoly(%s) @ %p\n",
- coefs_file.c_str(), this);
+ coefs_am_file.c_str(), this);
+ PDEBUG("MemlessPoly::MemlessPoly(%s) @ %p\n",
+ coefs_pm_file.c_str(), this);
if (m_num_threads == 0) {
const unsigned int hw_concurrency = std::thread::hardware_concurrency();
@@ -70,53 +76,99 @@ MemlessPoly::MemlessPoly(const std::string& coefs_file, unsigned int num_threads
m_num_threads << " threads (set in config file)";
}
- RC_ADD_PARAMETER(ncoefs, "(Read-only) number of coefficients.");
- RC_ADD_PARAMETER(coeffile, "Filename containing coefficients. When written to, the new file gets automatically loaded.");
+ RC_ADD_PARAMETER(ncoefs_am, "(Read-only) number of coefficients for amplitude.");
+ RC_ADD_PARAMETER(coeffile_am, "Filename containing coefficients for amplitude. When written to, the new file gets automatically loaded.");
+
+ RC_ADD_PARAMETER(ncoefs_pm, "(Read-only) number of coefficients for phase.");
+ RC_ADD_PARAMETER(coeffile_pm, "Filename containing coefficients for amplitude. When written to, the new file gets automatically loaded.");
- load_coefficients(m_coefs_file);
+ load_coefficients_am(m_coefs_am_file);
+ load_coefficients_pm(m_coefs_pm_file);
start_pipeline_thread();
}
-void MemlessPoly::load_coefficients(const std::string &coefFile)
+void MemlessPoly::load_coefficients_am(const std::string &coefFile_am)
+{
+ std::vector<float> coefs_am;
+ std::ifstream coef_fstream_am(coefFile_am.c_str());
+ if (!coef_fstream_am) {
+ throw std::runtime_error("MemlessPoly: Could not open file with coefs_am!");
+ }
+ int n_coefs_am;
+ coef_fstream_am >> n_coefs_am;
+
+ if (n_coefs_am <= 0) {
+ throw std::runtime_error("MemlessPoly: coefs_am file has invalid format.");
+ }
+ else if (n_coefs_am != NUM_COEFS_AM) {
+ throw std::runtime_error("MemlessPoly: invalid number of coefs_am: " +
+ std::to_string(n_coefs_am) + " expected " + std::to_string(NUM_COEFS_AM));
+ }
+
+ etiLog.log(debug, "MemlessPoly: Reading %d coefs_am...", n_coefs_am);
+
+ coefs_am.resize(n_coefs_am);
+
+ for (int n = 0; n < n_coefs_am; n++) {
+ float a;
+ coef_fstream_am >> a;
+ coefs_am[n] = a;
+
+ if (coef_fstream_am.eof()) {
+ etiLog.log(error, "MemlessPoly: file %s should contains %d coefs_am, "
+ "but EOF reached after %d coefs_am !",
+ coefFile_am.c_str(), n_coefs_am, n);
+ throw std::runtime_error("MemlessPoly: coefs_am file invalid !");
+ }
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(m_coefs_am_mutex);
+
+ m_coefs_am = coefs_am;
+ }
+}
+
+void MemlessPoly::load_coefficients_pm(const std::string &coefFile_pm)
{
- std::vector<float> coefs;
- std::ifstream coef_fstream(coefFile.c_str());
- if (!coef_fstream) {
- throw std::runtime_error("MemlessPoly: Could not open file with coefs!");
+ std::vector<float> coefs_pm;
+ std::ifstream coef_fstream_pm(coefFile_pm.c_str());
+ if (!coef_fstream_pm) {
+ throw std::runtime_error("MemlessPoly: Could not open file with coefs_pm!");
}
- int n_coefs;
- coef_fstream >> n_coefs;
+ int n_coefs_pm;
+ coef_fstream_pm >> n_coefs_pm;
- if (n_coefs <= 0) {
- throw std::runtime_error("MemlessPoly: coefs file has invalid format.");
+ if (n_coefs_pm <= 0) {
+ throw std::runtime_error("MemlessPoly: coefs_pm file has invalid format.");
}
- else if (n_coefs != NUM_COEFS) {
- throw std::runtime_error("MemlessPoly: invalid number of coefs: " +
- std::to_string(n_coefs) + " expected " + std::to_string(NUM_COEFS));
+ else if (n_coefs_pm != NUM_COEFS_PM) {
+ throw std::runtime_error("MemlessPoly: invalid number of coefs_pm: " +
+ std::to_string(n_coefs_pm) + " expected " + std::to_string(NUM_COEFS_PM));
}
- etiLog.log(debug, "MemlessPoly: Reading %d coefs...", n_coefs);
+ etiLog.log(debug, "MemlessPoly: Reading %d coefs_pm...", n_coefs_pm);
- coefs.resize(n_coefs);
+ coefs_pm.resize(n_coefs_pm);
- for (int n = 0; n < n_coefs; n++) {
+ for (int n = 0; n < n_coefs_pm; n++) {
float a;
- coef_fstream >> a;
- coefs[n] = a;
-
- if (coef_fstream.eof()) {
- etiLog.log(error, "MemlessPoly: file %s should contains %d coefs, "
- "but EOF reached after %d coefs !",
- coefFile.c_str(), n_coefs, n);
- throw std::runtime_error("MemlessPoly: coefs file invalid !");
+ coef_fstream_pm >> a;
+ coefs_pm[n] = a;
+
+ if (coef_fstream_pm.eof()) {
+ etiLog.log(error, "MemlessPoly: file %s should contains %d coefs_pm, "
+ "but EOF reached after %d coefs_pm !",
+ coefFile_pm.c_str(), n_coefs_pm, n);
+ throw std::runtime_error("MemlessPoly: coefs_pm file invalid !");
}
}
{
- std::lock_guard<std::mutex> lock(m_coefs_mutex);
+ std::lock_guard<std::mutex> lock(m_coefs_pm_mutex);
- m_coefs = coefs;
+ m_coefs_pm = coefs_pm;
}
}
@@ -124,19 +176,44 @@ void MemlessPoly::load_coefficients(const std::string &coefFile)
* instead, and this allows the compiler to auto-vectorize the loop.
*/
static void apply_coeff(
- const vector<float> &coefs,
+ const vector<float> &coefs_am,
+ const vector<float> &coefs_pm,
const complexf *__restrict in, size_t start, size_t stop,
complexf *__restrict out)
{
- for (size_t i = start; i < stop; i++) {
- const float in_mag_sq = std::norm(in[i]);
- out[i] =
- in[i] *
- ( coefs[0] + in_mag_sq *
- ( coefs[1] + in_mag_sq *
- ( coefs[2] + in_mag_sq *
- ( coefs[3] + in_mag_sq *
- ( coefs[4] + in_mag_sq )))));
+ for (size_t i = start; i < stop; i+=1) {
+
+ float in_mag_sq = in[i].real() * in[i].real() + in[i].imag() * in[i].imag();
+
+ float amplitude_correction =
+ ( coefs_am[0] + in_mag_sq *
+ ( coefs_am[1] + in_mag_sq *
+ ( coefs_am[2] + in_mag_sq *
+ ( coefs_am[3] + in_mag_sq *
+ coefs_am[4]))));
+
+ float phase_correction = -1 *
+ ( coefs_pm[0] + in_mag_sq *
+ ( coefs_pm[1] + in_mag_sq *
+ ( coefs_pm[2] + in_mag_sq *
+ ( coefs_pm[3] + in_mag_sq *
+ coefs_pm[4]))));
+
+ float phase_correction_sq = phase_correction * phase_correction;
+
+ // Approximation for Cosinus 1 - 1/2 x^2 + 1/24 x^4 - 1/720 x^6
+ float re = (1.0f - phase_correction_sq *
+ ( -0.5f + phase_correction_sq *
+ ( 0.486666f + phase_correction_sq *
+ ( -0.00138888f))));
+
+ // Approximation for Sinus x + 1/6 x^3 + 1/120 x^5
+ float im = phase_correction *
+ (1.0f + phase_correction_sq *
+ (0.166666f + phase_correction_sq *
+ (0.00833333f)));
+
+ out[i] = in[i] * amplitude_correction * complex<float>(re, im);
}
}
@@ -149,7 +226,8 @@ int MemlessPoly::internal_process(Buffer* const dataIn, Buffer* dataOut)
size_t sizeOut = dataOut->getLength() / sizeof(complexf);
{
- std::lock_guard<std::mutex> lock(m_coefs_mutex);
+ std::lock_guard<std::mutex> lock_am(m_coefs_am_mutex);
+ std::lock_guard<std::mutex> lock_pm(m_coefs_pm_mutex);
const unsigned int hw_concurrency = std::thread::hardware_concurrency();
const unsigned int num_threads =
@@ -162,13 +240,13 @@ int MemlessPoly::internal_process(Buffer* const dataIn, Buffer* dataOut)
size_t start = 0;
for (size_t i = 0; i < num_threads - 1; i++) {
flags.push_back(async(launch::async, apply_coeff,
- m_coefs, in, start, start + step, out));
+ m_coefs_am, m_coefs_pm, in, start, start + step, out));
start += step;
}
// Do the last in this thread
- apply_coeff(m_coefs, in, start, sizeOut, out);
+ apply_coeff(m_coefs_am, m_coefs_pm, in, start, sizeOut, out);
// Wait for completion of the tasks
for (auto& f : flags) {
@@ -176,7 +254,7 @@ int MemlessPoly::internal_process(Buffer* const dataIn, Buffer* dataOut)
}
}
else {
- apply_coeff(m_coefs, in, 0, sizeOut, out);
+ apply_coeff(m_coefs_am, m_coefs_pm, in, 0, sizeOut, out);
}
}
@@ -188,13 +266,25 @@ void MemlessPoly::set_parameter(const string& parameter, const string& value)
stringstream ss(value);
ss.exceptions ( stringstream::failbit | stringstream::badbit );
- if (parameter == "ncoefs") {
- throw ParameterError("Parameter 'ncoefs' is read-only");
+ if (parameter == "ncoefs_am") {
+ throw ParameterError("Parameter 'ncoefs_am' is read-only");
+ }
+ else if (parameter == "ncoefs_pm") {
+ throw ParameterError("Parameter 'ncoefs_pm' is read-only");
+ }
+ else if (parameter == "coeffile_am") {
+ try {
+ load_coefficients_am(value);
+ m_coefs_am_file = value;
+ }
+ catch (std::runtime_error &e) {
+ throw ParameterError(e.what());
+ }
}
- else if (parameter == "coeffile") {
+ else if (parameter == "coeffile_pm") {
try {
- load_coefficients(value);
- m_coefs_file = value;
+ load_coefficients_pm(value);
+ m_coefs_pm_file = value;
}
catch (std::runtime_error &e) {
throw ParameterError(e.what());
@@ -211,11 +301,17 @@ void MemlessPoly::set_parameter(const string& parameter, const string& value)
const string MemlessPoly::get_parameter(const string& parameter) const
{
stringstream ss;
- if (parameter == "ncoefs") {
- ss << m_coefs.size();
+ if (parameter == "ncoefs_am") {
+ ss << m_coefs_am.size();
+ }
+ else if (parameter == "ncoefs_pm") {
+ ss << m_coefs_pm.size();
+ }
+ else if (parameter == "coefFile_am") {
+ ss << m_coefs_am_file;
}
- else if (parameter == "coefFile") {
- ss << m_coefs_file;
+ else if (parameter == "coefFile_pm") {
+ ss << m_coefs_pm_file;
}
else {
ss << "Parameter '" << parameter <<
diff --git a/src/MemlessPoly.h b/src/MemlessPoly.h
index 49b97e1..536b054 100644
--- a/src/MemlessPoly.h
+++ b/src/MemlessPoly.h
@@ -52,7 +52,7 @@ typedef std::complex<float> complexf;
class MemlessPoly : public PipelinedModCodec, public RemoteControllable
{
public:
- MemlessPoly(const std::string& coefs_file, unsigned int num_threads);
+ MemlessPoly(const std::string& coefs_am_file, const std::string& coefs_pm_file, unsigned int num_threads);
virtual const char* name() { return "MemlessPoly"; }
@@ -65,11 +65,16 @@ public:
private:
int internal_process(Buffer* const dataIn, Buffer* dataOut);
- void load_coefficients(const std::string &coefFile);
+ void load_coefficients_am(const std::string &coefFile_am);
+ void load_coefficients_pm(const std::string &coefFile_pm);
unsigned int m_num_threads;
- std::vector<float> m_coefs;
- std::string m_coefs_file;
- mutable std::mutex m_coefs_mutex;
+ std::vector<float> m_coefs_am;
+ std::string m_coefs_am_file;
+ mutable std::mutex m_coefs_am_mutex;
+
+ std::vector<float> m_coefs_pm;
+ std::string m_coefs_pm_file;
+ mutable std::mutex m_coefs_pm_mutex;
};