From b49d5c3898f4a6f03d7cb033508ba1416e30c6f0 Mon Sep 17 00:00:00 2001 From: andreas128 Date: Sun, 26 Mar 2017 13:28:02 +0200 Subject: Working pipeline --- src/MemlessPoly.h | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/MemlessPoly.h (limited to 'src/MemlessPoly.h') diff --git a/src/MemlessPoly.h b/src/MemlessPoly.h new file mode 100644 index 0000000..fe372d8 --- /dev/null +++ b/src/MemlessPoly.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2007, 2008, 2009, 2010, 2011 Her Majesty the Queen in + Right of Canada (Communications Research Center Canada) + + Copyright (C) 2017 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org + */ +/* + This file is part of ODR-DabMod. + + ODR-DabMod is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + ODR-DabMod is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ODR-DabMod. If not, see . + */ + +#pragma once + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "RemoteControl.h" +#include "ModPlugin.h" +#include "PcDebug.h" +#include "ThreadsafeQueue.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MEMLESSPOLY_PIPELINE_DELAY 1 + +typedef std::complex complexf; + +class MemlessPoly : public PipelinedModCodec, public RemoteControllable +{ +public: + MemlessPoly(const std::string& taps_file); + + virtual const char* name() { return "MemlessPoly"; } + + /******* REMOTE CONTROL ********/ + virtual void set_parameter(const std::string& parameter, + const std::string& value); + + virtual const std::string get_parameter( + const std::string& parameter) const; + + +protected: + int internal_process(Buffer* const dataIn, Buffer* dataOut); + void load_filter_taps(const std::string &tapsFile); + + std::string m_taps_file; + + mutable std::mutex m_taps_mutex; + std::vector m_taps; +}; + -- cgit v1.2.3 From 89ac4f53d0a10d1c07980fae5ddeb8818e7b9733 Mon Sep 17 00:00:00 2001 From: andreas128 Date: Sat, 1 Apr 2017 12:13:01 +0100 Subject: Fix file reading --- src/ConfigParser.cpp | 6 ++++++ src/ConfigParser.h | 2 ++ src/DabMod.cpp | 6 ++++-- src/DabModulator.cpp | 26 +++++++++++++++++++------- src/DabModulator.h | 4 +++- src/MemlessPoly.cpp | 1 + src/MemlessPoly.h | 4 +++- 7 files changed, 38 insertions(+), 11 deletions(-) (limited to 'src/MemlessPoly.h') diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 393f58a..b7649df 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -168,6 +168,12 @@ static void parse_configfile( pt.get("firfilter.filtertapsfile", "default"); } + // Poly coefficients: + if (pt.get("poly.enabled", 0) == 1) { + mod_settings.polyCoefFilename = + pt.get("poly.polycoeffile", "default"); + } + // Output options std::string output_selected; try { diff --git a/src/ConfigParser.h b/src/ConfigParser.h index 02b798a..fede801 100644 --- a/src/ConfigParser.h +++ b/src/ConfigParser.h @@ -74,6 +74,8 @@ struct mod_settings_t { std::string filterTapsFilename = ""; + std::string polyCoefFilename = ""; + #if defined(HAVE_OUTPUT_UHD) OutputUHDConfig outputuhd_conf; diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 4e4cdab..adc4cf2 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -322,7 +322,8 @@ int launch_modulator(int argc, char* argv[]) mod_settings.digitalgain, mod_settings.normalise, mod_settings.gainmodeVariance, - mod_settings.filterTapsFilename); + mod_settings.filterTapsFilename, + mod_settings.polyCoefFilename); if (format_converter) { flowgraph.connect(modulator, format_converter); @@ -426,7 +427,8 @@ int launch_modulator(int argc, char* argv[]) mod_settings.digitalgain, mod_settings.normalise, mod_settings.gainmodeVariance, - mod_settings.filterTapsFilename); + mod_settings.filterTapsFilename, + mod_settings.polyCoefFilename); if (format_converter) { flowgraph.connect(modulator, format_converter); diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index bd14396..81257f4 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -62,7 +62,8 @@ DabModulator::DabModulator( unsigned dabMode, GainMode gainMode, float& digGain, float normalise, float gainmodeVariance, - const std::string& filterTapsFilename + const std::string& filterTapsFilename, + const std::string& polyCoefFilename ) : ModInput(), myOutputRate(outputRate), @@ -75,6 +76,7 @@ DabModulator::DabModulator( myEtiSource(etiSource), myFlowgraph(NULL), myFilterTapsFilename(filterTapsFilename), + myPolyCoefFilename(polyCoefFilename), myTiiConfig(tiiConfig) { PDEBUG("DabModulator::DabModulator(%u, %u, %u, %zu) @ %p\n", @@ -218,8 +220,12 @@ int DabModulator::process(Buffer* dataOut) } shared_ptr cifPoly; - cifPoly = make_shared("default"); - rcs.enrol(cifPoly.get()); + if (not myPolyCoefFilename.empty()) { + cifPoly = make_shared(myPolyCoefFilename); + std::cout << myPolyCoefFilename << "\n"; + std::cout << cifPoly->m_taps[0] << " " << cifPoly->m_taps[1] << " "<< cifPoly->m_taps[2] << " "<< cifPoly->m_taps[3] << " "<< cifPoly->m_taps[4] << " "<< cifPoly->m_taps[5] << " "<< cifPoly->m_taps[6] << " "<< cifPoly->m_taps[7] << "\n"; + rcs.enrol(cifPoly.get()); + } auto myOutput = make_shared(dataOut); @@ -371,13 +377,19 @@ int DabModulator::process(Buffer* dataOut) // myFlowgraph->connect(cifGuard, myOutput); // } //} + //if (cifRes) { + // myFlowgraph->connect(cifGuard, cifRes); + // myFlowgraph->connect(cifRes, cifPoly); + // myFlowgraph->connect(cifPoly, myOutput); + //} else { + // myFlowgraph->connect(cifGuard, cifPoly); + // myFlowgraph->connect(cifPoly, myOutput); + //} if (cifRes) { myFlowgraph->connect(cifGuard, cifRes); - myFlowgraph->connect(cifRes, cifPoly); - myFlowgraph->connect(cifPoly, myOutput); + myFlowgraph->connect(cifRes, myOutput); } else { - myFlowgraph->connect(cifGuard, cifPoly); - myFlowgraph->connect(cifPoly, myOutput); + myFlowgraph->connect(cifGuard, myOutput); } } diff --git a/src/DabModulator.h b/src/DabModulator.h index c9bdbe1..0c691dd 100644 --- a/src/DabModulator.h +++ b/src/DabModulator.h @@ -55,7 +55,8 @@ public: unsigned dabMode, GainMode gainMode, float& digGain, float normalise, float gainmodeVariance, - const std::string& filterTapsFilename); + const std::string& filterTapsFilename, + const std::string& polyCoefFilename); DabModulator(const DabModulator& other) = delete; DabModulator& operator=(const DabModulator& other) = delete; virtual ~DabModulator(); @@ -80,6 +81,7 @@ protected: Flowgraph* myFlowgraph; OutputMemory* myOutput; std::string myFilterTapsFilename; + std::string myPolyCoefFilename; tii_config_t& myTiiConfig; size_t myNbSymbols; diff --git a/src/MemlessPoly.cpp b/src/MemlessPoly.cpp index b4bd5d0..1faf338 100644 --- a/src/MemlessPoly.cpp +++ b/src/MemlessPoly.cpp @@ -84,6 +84,7 @@ void MemlessPoly::load_filter_taps(const std::string &tapsFile) { std::vector filter_taps; if (tapsFile == "default") { + std::cout << "MemlessPoly default\n"; std::copy(default_coefficients.begin(), default_coefficients.end(), std::back_inserter(filter_taps)); } diff --git a/src/MemlessPoly.h b/src/MemlessPoly.h index fe372d8..33ae202 100644 --- a/src/MemlessPoly.h +++ b/src/MemlessPoly.h @@ -63,6 +63,9 @@ public: virtual const std::string get_parameter( const std::string& parameter) const; +//TODO to protected + std::vector m_taps; + protected: int internal_process(Buffer* const dataIn, Buffer* dataOut); @@ -71,6 +74,5 @@ protected: std::string m_taps_file; mutable std::mutex m_taps_mutex; - std::vector m_taps; }; -- cgit v1.2.3 From ebf4bac7c87ec4b7a25fb626a53b8c407d3f446b Mon Sep 17 00:00:00 2001 From: andreas128 Date: Thu, 6 Apr 2017 21:57:07 +0100 Subject: Refactor MemlessPoly to have more meaningful names --- src/MemlessPoly.cpp | 126 +++++++++++++++++++++++----------------------------- src/MemlessPoly.h | 10 ++--- 2 files changed, 60 insertions(+), 76 deletions(-) (limited to 'src/MemlessPoly.h') 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 #include -#ifdef __SSE__ -# include -#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 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 filter_taps; - if (tapsFile == "default") { - std::cout << "MemlessPoly default\n"; + std::vector 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 lock(m_taps_mutex); + std::lock_guard 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(dataIn->getData()); float* out = reinterpret_cast(dataOut->getData()); size_t sizeIn = dataIn->getLength() / sizeof(float); { - std::lock_guard lock(m_taps_mutex); - for (i = 0; i < sizeIn; i += 1) { + std::lock_guard 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 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 m_taps; + std::vector 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; }; -- cgit v1.2.3