diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ConfigParser.cpp | 5 | ||||
-rw-r--r-- | src/ConfigParser.h | 2 | ||||
-rw-r--r-- | src/DabModulator.cpp | 9 | ||||
-rw-r--r-- | src/MemlessPoly.cpp | 133 | ||||
-rw-r--r-- | src/MemlessPoly.h | 11 |
5 files changed, 105 insertions, 55 deletions
diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 459811f..9ac1280 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -171,7 +171,10 @@ static void parse_configfile( // Poly coefficients: if (pt.get("poly.enabled", 0) == 1) { mod_settings.polyCoefFilename = - pt.get<std::string>("poly.polycoeffile", "default"); + pt.get<std::string>("poly.polycoeffile", "dpd/poly.coef"); + + mod_settings.polyNumThreads = + pt.get<int>("poly.num_threads", 0); } // Output options diff --git a/src/ConfigParser.h b/src/ConfigParser.h index 22a4fc5..89f0fb7 100644 --- a/src/ConfigParser.h +++ b/src/ConfigParser.h @@ -75,7 +75,7 @@ struct mod_settings_t { std::string filterTapsFilename = ""; std::string polyCoefFilename = ""; - + unsigned polyNumThreads = 0; #if defined(HAVE_OUTPUT_UHD) OutputUHDConfig outputuhd_conf; diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index 34d8e66..cc2642a 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -205,13 +205,8 @@ int DabModulator::process(Buffer* dataOut) shared_ptr<MemlessPoly> cifPoly; if (not m_settings.polyCoefFilename.empty()) { - cifPoly = make_shared<MemlessPoly>(m_settings.polyCoefFilename); - etiLog.level(debug) << m_settings.polyCoefFilename << "\n"; - etiLog.level(debug) << cifPoly->m_coefs[0] << " " << - cifPoly->m_coefs[1] << " "<< cifPoly->m_coefs[2] << " "<< - cifPoly->m_coefs[3] << " "<< cifPoly->m_coefs[4] << " "<< - cifPoly->m_coefs[5] << " "<< cifPoly->m_coefs[6] << " "<< - cifPoly->m_coefs[7] << "\n"; + cifPoly = make_shared<MemlessPoly>(m_settings.polyCoefFilename, + m_settings.polyNumThreads); rcs.enrol(cifPoly.get()); } diff --git a/src/MemlessPoly.cpp b/src/MemlessPoly.cpp index 7e074eb..b0d950c 100644 --- a/src/MemlessPoly.cpp +++ b/src/MemlessPoly.cpp @@ -36,6 +36,7 @@ #include <stdio.h> #include <stdexcept> +#include <future> #include <array> #include <iostream> #include <fstream> @@ -43,22 +44,36 @@ using namespace std; +#define NUM_COEFS 5 // By default the signal is unchanged -static const std::array<float, 8> default_coefficients({ +static const std::array<complexf, 8> default_coefficients({{ 1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 - }); + }}); -MemlessPoly::MemlessPoly(const std::string& coefs_file) : +MemlessPoly::MemlessPoly(const std::string& coefs_file, unsigned int num_threads) : PipelinedModCodec(), RemoteControllable("memlesspoly"), - m_coefs_file(coefs_file) + m_num_threads(num_threads), + m_coefs(), + m_coefs_file(coefs_file), + m_coefs_mutex() { PDEBUG("MemlessPoly::MemlessPoly(%s) @ %p\n", coefs_file.c_str(), this); + if (m_num_threads == 0) { + const unsigned int hw_concurrency = std::thread::hardware_concurrency(); + etiLog.level(info) << "Polynomial Predistorter will use " << + hw_concurrency << " threads (auto detected)"; + } + else { + etiLog.level(info) << "Polynomial Predistorter will use " << + 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."); @@ -69,41 +84,42 @@ MemlessPoly::MemlessPoly(const std::string& coefs_file) : void MemlessPoly::load_coefficients(const std::string &coefFile) { - std::vector<float> coefs; + std::vector<complexf> coefs; if (coefFile == "default") { std::copy(default_coefficients.begin(), default_coefficients.end(), std::back_inserter(coefs)); } else { 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! "); + if (!coef_fstream) { + throw std::runtime_error("MemlessPoly: Could not open file with coefs!"); } int n_coefs; coef_fstream >> n_coefs; 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_coefs != 8) { - throw std::runtime_error( "MemlessPoly: error: coefs file does not have 8 coefs\n"); + else if (n_coefs != NUM_COEFS) { + throw std::runtime_error("MemlessPoly: invalid number of coefs: " + + std::to_string(coefs.size())); } - fprintf(stderr, "MemlessPoly: Reading %d coefs...\n", n_coefs); + etiLog.log(debug, "MemlessPoly: Reading %d coefs...", n_coefs); coefs.resize(n_coefs); - int n; - for (n = 0; n < n_coefs; n++) { - coef_fstream >> coefs[n]; - PDEBUG("MemlessPoly: coef: %f\n", coefs[n] ); + for (int n = 0; n < n_coefs; n++) { + float a, b; + coef_fstream >> a; + coef_fstream >> b; + coefs[n] = complexf(a, b); + 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 ! "); + 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 !"); } } } @@ -115,30 +131,69 @@ void MemlessPoly::load_coefficients(const std::string &coefFile) } } +static void apply_coeff( + const vector<complexf> &coefs, + const complexf* in, size_t start, size_t stop, + complexf* out) +{ + for (size_t i = start; i < stop; i++) { + + /* Implement + a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4 + a5*x^5; + with less multiplications: + a0 + x*(a1 + x*(a2 + x*(a3 + x*(a3 + x*(a4 + a5*x))))); + */ + + /* Make sure to adapt NUM_COEFS when you change this */ + out[i] = + coefs[0] + in[i] * + ( coefs[1] + in[i] * + ( coefs[2] + in[i] * + ( coefs[3] + in[i] * + ( coefs[4] + in[i] * + ( coefs[5] + in[i] ))))); + } +} int MemlessPoly::internal_process(Buffer* const dataIn, Buffer* dataOut) { - 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_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_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 - ); + dataOut->setLength(dataIn->getLength()); + + const complexf* in = reinterpret_cast<const complexf*>(dataIn->getData()); + complexf* out = reinterpret_cast<complexf*>(dataOut->getData()); + size_t sizeOut = dataOut->getLength() / sizeof(complexf); + + { + std::lock_guard<std::mutex> lock(m_coefs_mutex); + const unsigned int hw_concurrency = std::thread::hardware_concurrency(); + + const unsigned int num_threads = + (m_num_threads > 0) ? m_num_threads : hw_concurrency; + + if (num_threads) { + const size_t step = sizeOut / num_threads; + vector<future<void> > flags; + + 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)); + + start += step; + } + + // Do the last in this thread + apply_coeff(m_coefs, in, start, sizeOut, out); + + // Wait for completion of the tasks + for (auto& f : flags) { + f.get(); } } + else { + apply_coeff(m_coefs, in, 0, sizeOut, out); + } + } return dataOut->getLength(); } diff --git a/src/MemlessPoly.h b/src/MemlessPoly.h index 210b4b4..b7fd81e 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); + MemlessPoly(const std::string& coefs_file, unsigned int num_threads); virtual const char* name() { return "MemlessPoly"; } @@ -63,16 +63,13 @@ public: virtual const std::string get_parameter( const std::string& parameter) const; -//TODO to protected - std::vector<float> m_coefs; - - -protected: +private: int internal_process(Buffer* const dataIn, Buffer* dataOut); void load_coefficients(const std::string &coefFile); + unsigned int m_num_threads; + std::vector<complexf> m_coefs; std::string m_coefs_file; - mutable std::mutex m_coefs_mutex; }; |