diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/MemlessPoly.cpp | 126 | ||||
-rw-r--r-- | src/MemlessPoly.h | 10 |
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; }; |