summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/MemlessPoly.cpp126
-rw-r--r--src/MemlessPoly.h10
2 files changed, 60 insertions, 76 deletions
diff --git a/src/MemlessPoly.cpp b/src/MemlessPoly.cpp
index 1faf338..7e074eb 100644
--- a/src/MemlessPoly.cpp
+++ b/src/MemlessPoly.cpp
@@ -4,12 +4,12 @@
Copyright (C) 2017
Matthias P. Braendli, matthias.braendli@mpb.li
+ Andreas Steger, andreas.steger@digris.ch
http://opendigitalradio.org
- This block implements a FIR filter. The real filter taps are given
- as floats, and the block can take advantage of SSE.
- For better performance, filtering is done in another thread, leading
+ This block implements a memoryless polynom for digital predistortion.
+ For better performance, multiplying is done in another thread, leading
to a pipeline delay of two calls to MemlessPoly::process
*/
/*
@@ -41,117 +41,101 @@
#include <fstream>
#include <memory>
-#ifdef __SSE__
-# include <xmmintrin.h>
-#endif
-
using namespace std;
-/* This is the FIR Filter calculated with the doc/fir-filter/generate-filter.py script
- * with settings
- * gain = 1
- * sampling_freq = 2.048e6
- * cutoff = 810e3
- * transition_width = 250e3
- *
- * It is a good default filter for the common scenarios.
- */
- //0.8, -0.2, 0.2, 0.25,
+// By default the signal is unchanged
static const std::array<float, 8> default_coefficients({
- 0.1, 0.0, 0.0, 0.0,
+ 1, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0
});
-MemlessPoly::MemlessPoly(const std::string& taps_file) :
+MemlessPoly::MemlessPoly(const std::string& coefs_file) :
PipelinedModCodec(),
RemoteControllable("memlesspoly"),
- m_taps_file(taps_file)
+ m_coefs_file(coefs_file)
{
PDEBUG("MemlessPoly::MemlessPoly(%s) @ %p\n",
- taps_file.c_str(), this);
+ coefs_file.c_str(), this);
- RC_ADD_PARAMETER(ntaps, "(Read-only) number of filter taps.");
- RC_ADD_PARAMETER(coeffile, "Filename containing filter taps. When written to, the new file gets automatically loaded.");
+ 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.");
- load_filter_taps(m_taps_file);
+ load_coefficients(m_coefs_file);
start_pipeline_thread();
}
-void MemlessPoly::load_filter_taps(const std::string &tapsFile)
+void MemlessPoly::load_coefficients(const std::string &coefFile)
{
- std::vector<float> filter_taps;
- if (tapsFile == "default") {
- std::cout << "MemlessPoly default\n";
+ std::vector<float> coefs;
+ if (coefFile == "default") {
std::copy(default_coefficients.begin(), default_coefficients.end(),
- std::back_inserter(filter_taps));
+ std::back_inserter(coefs));
}
else {
- std::ifstream taps_fstream(tapsFile.c_str());
- if(!taps_fstream) {
- fprintf(stderr, "MemlessPoly: file %s could not be opened !\n", tapsFile.c_str());
- throw std::runtime_error("MemlessPoly: Could not open file with taps! ");
+ std::ifstream coef_fstream(coefFile.c_str());
+ if(!coef_fstream) {
+ fprintf(stderr, "MemlessPoly: file %s could not be opened !\n", coefFile.c_str());
+ throw std::runtime_error("MemlessPoly: Could not open file with coefs! ");
}
- int n_taps;
- taps_fstream >> n_taps;
+ int n_coefs;
+ coef_fstream >> n_coefs;
- if (n_taps <= 0) {
- fprintf(stderr, "MemlessPoly: warning: taps file has invalid format\n");
- throw std::runtime_error("MemlessPoly: taps file has invalid format.");
+ if (n_coefs <= 0) {
+ fprintf(stderr, "MemlessPoly: warning: coefs file has invalid format\n");
+ throw std::runtime_error("MemlessPoly: coefs file has invalid format.");
}
- if (n_taps > 100) {
- fprintf(stderr, "MemlessPoly: warning: taps file has more than 100 taps\n");
+ if (n_coefs != 8) {
+ throw std::runtime_error( "MemlessPoly: error: coefs file does not have 8 coefs\n");
}
- fprintf(stderr, "MemlessPoly: Reading %d taps...\n", n_taps);
+ fprintf(stderr, "MemlessPoly: Reading %d coefs...\n", n_coefs);
- filter_taps.resize(n_taps);
+ coefs.resize(n_coefs);
int n;
- for (n = 0; n < n_taps; n++) {
- taps_fstream >> filter_taps[n];
- PDEBUG("MemlessPoly: tap: %f\n", filter_taps[n] );
- if (taps_fstream.eof()) {
- fprintf(stderr, "MemlessPoly: file %s should contains %d taps, but EOF reached "\
- "after %d taps !\n", tapsFile.c_str(), n_taps, n);
- throw std::runtime_error("MemlessPoly: filtertaps file invalid ! ");
+ for (n = 0; n < n_coefs; n++) {
+ coef_fstream >> coefs[n];
+ PDEBUG("MemlessPoly: coef: %f\n", coefs[n] );
+ if (coef_fstream.eof()) {
+ fprintf(stderr, "MemlessPoly: file %s should contains %d coefs, but EOF reached "\
+ "after %d coefs !\n", coefFile.c_str(), n_coefs, n);
+ throw std::runtime_error("MemlessPoly: coefs file invalid ! ");
}
}
}
{
- std::lock_guard<std::mutex> lock(m_taps_mutex);
+ std::lock_guard<std::mutex> lock(m_coefs_mutex);
- m_taps = filter_taps;
+ m_coefs = coefs;
}
}
int MemlessPoly::internal_process(Buffer* const dataIn, Buffer* dataOut)
{
- size_t i;
-
const float* in = reinterpret_cast<const float*>(dataIn->getData());
float* out = reinterpret_cast<float*>(dataOut->getData());
size_t sizeIn = dataIn->getLength() / sizeof(float);
{
- std::lock_guard<std::mutex> lock(m_taps_mutex);
- for (i = 0; i < sizeIn; i += 1) {
+ std::lock_guard<std::mutex> lock(m_coefs_mutex);
+ for (size_t i = 0; i < sizeIn; i += 1) {
float mag = std::abs(in[i]);
//out[i] = in[i];
out[i] = in[i] * (
- m_taps[0] +
- m_taps[1] * mag +
- m_taps[2] * mag*mag +
- m_taps[3] * mag*mag*mag +
- m_taps[4] * mag*mag*mag*mag +
- m_taps[5] * mag*mag*mag*mag*mag +
- m_taps[6] * mag*mag*mag*mag*mag*mag +
- m_taps[7] * mag*mag*mag*mag*mag*mag*mag
+ m_coefs[0] +
+ m_coefs[1] * mag +
+ m_coefs[2] * mag*mag +
+ m_coefs[3] * mag*mag*mag +
+ m_coefs[4] * mag*mag*mag*mag +
+ m_coefs[5] * mag*mag*mag*mag*mag +
+ m_coefs[6] * mag*mag*mag*mag*mag*mag +
+ m_coefs[7] * mag*mag*mag*mag*mag*mag*mag
);
}
}
@@ -164,13 +148,13 @@ void MemlessPoly::set_parameter(const string& parameter, const string& value)
stringstream ss(value);
ss.exceptions ( stringstream::failbit | stringstream::badbit );
- if (parameter == "ntaps") {
- throw ParameterError("Parameter 'ntaps' is read-only");
+ if (parameter == "ncoefs") {
+ throw ParameterError("Parameter 'ncoefs' is read-only");
}
else if (parameter == "coeffile") {
try {
- load_filter_taps(value);
- m_taps_file = value;
+ load_coefficients(value);
+ m_coefs_file = value;
}
catch (std::runtime_error &e) {
throw ParameterError(e.what());
@@ -187,11 +171,11 @@ void MemlessPoly::set_parameter(const string& parameter, const string& value)
const string MemlessPoly::get_parameter(const string& parameter) const
{
stringstream ss;
- if (parameter == "ntaps") {
- ss << m_taps.size();
+ if (parameter == "ncoefs") {
+ ss << m_coefs.size();
}
- else if (parameter == "tapsfile") {
- ss << m_taps_file;
+ else if (parameter == "coefFile") {
+ ss << m_coefs_file;
}
else {
ss << "Parameter '" << parameter <<
diff --git a/src/MemlessPoly.h b/src/MemlessPoly.h
index 33ae202..210b4b4 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& taps_file);
+ MemlessPoly(const std::string& coefs_file);
virtual const char* name() { return "MemlessPoly"; }
@@ -64,15 +64,15 @@ public:
const std::string& parameter) const;
//TODO to protected
- std::vector<float> m_taps;
+ std::vector<float> m_coefs;
protected:
int internal_process(Buffer* const dataIn, Buffer* dataOut);
- void load_filter_taps(const std::string &tapsFile);
+ void load_coefficients(const std::string &coefFile);
- std::string m_taps_file;
+ std::string m_coefs_file;
- mutable std::mutex m_taps_mutex;
+ mutable std::mutex m_coefs_mutex;
};