Merge branch 'master' into develop

This commit is contained in:
Anne de Jong 2022-10-16 18:39:55 +02:00
commit e2aa149030
10 changed files with 91 additions and 42 deletions

View File

@ -81,6 +81,7 @@ AvPowerSpectra::AvPowerSpectra(const us nfft, const Window::WindowType w,
void AvPowerSpectra::reset() { void AvPowerSpectra::reset() {
_timeBuf.reset(); _timeBuf.reset();
_est.reset(); _est.reset();
n_averages=0;
} }

View File

@ -2,23 +2,25 @@
#include "lasp_biquadbank.h" #include "lasp_biquadbank.h"
#include "debugtrace.hpp" #include "debugtrace.hpp"
#include "lasp_thread.h" #include "lasp_thread.h"
#include <cassert>
#include <vector> #include <vector>
using std::cerr; using std::cerr;
using std::endl; using std::endl;
using rte = std::runtime_error; using rte = std::runtime_error;
using lock = std::scoped_lock<std::mutex>;
SeriesBiquad::SeriesBiquad(const vd &filter_coefs) { SeriesBiquad::SeriesBiquad(const vd &filter_coefs) {
DEBUGTRACE_ENTER; DEBUGTRACE_ENTER;
if (filter_coefs.n_cols != 1) { if (filter_coefs.n_cols != 1) {
throw rte("Expected filter coefficients for a single SeriesBiquad as a " throw rte("Expected filter coefficients for a single SeriesBiquad as a "
"single column with length 6 x n_filters"); "single column with length 6 x n_filters");
} }
if (filter_coefs.n_rows % 6 != 0) { if (filter_coefs.n_rows % 6 != 0) {
cerr << "Number of rows given: " << filter_coefs.n_rows << endl; cerr << "Number of rows given: " << filter_coefs.n_rows << endl;
throw rte("filter_coefs should be multiple of 6, given: " + throw rte("filter_coefs should be multiple of 6, given: " +
std::to_string(filter_coefs.n_rows)); std::to_string(filter_coefs.n_rows));
} }
us nfilters = filter_coefs.n_rows / 6; us nfilters = filter_coefs.n_rows / 6;
@ -32,7 +34,7 @@ SeriesBiquad::SeriesBiquad(const vd &filter_coefs) {
/// Check if third row in this matrix equals unity. /// Check if third row in this matrix equals unity.
if (!arma::approx_equal(sos.row(3), arma::rowvec(nfilters, arma::fill::ones), if (!arma::approx_equal(sos.row(3), arma::rowvec(nfilters, arma::fill::ones),
"absdiff", 1e-9)) { "absdiff", 1e-9)) {
std::cerr << "Read row: " << sos.row(3) << endl; std::cerr << "Read row: " << sos.row(3) << endl;
throw rte( throw rte(
@ -82,6 +84,7 @@ BiquadBank::BiquadBank(const dmat &filters, const vd *gains) {
* @brief Make sure the pool is created once, such that all threads are ready * @brief Make sure the pool is created once, such that all threads are ready
* for use. * for use.
*/ */
lock lck(_mtx);
getPool(); getPool();
for (us i = 0; i < filters.n_cols; i++) { for (us i = 0; i < filters.n_cols; i++) {
@ -96,6 +99,8 @@ BiquadBank::BiquadBank(const dmat &filters, const vd *gains) {
} }
void BiquadBank::setGains(const vd &gains) { void BiquadBank::setGains(const vd &gains) {
DEBUGTRACE_ENTER; DEBUGTRACE_ENTER;
lock lck(_mtx);
const us nfilters = _filters.size(); const us nfilters = _filters.size();
if (gains.size() != nfilters) { if (gains.size() != nfilters) {
throw rte("Invalid number of gain values given."); throw rte("Invalid number of gain values given.");
@ -105,34 +110,46 @@ void BiquadBank::setGains(const vd &gains) {
void BiquadBank::filter(vd &inout) { void BiquadBank::filter(vd &inout) {
dmat res(inout.n_rows, _filters.size()); lock lck(_mtx);
std::vector<std::future<vd>> futs; std::vector<std::future<vd>> futs;
#if 1
auto &pool = getPool(); auto &pool = getPool();
for (us i = 0; i < res.n_cols; i++) { vd inout_cpy = inout;
for (us i = 0; i < _filters.size(); i++) {
futs.emplace_back(pool.submit( futs.emplace_back(pool.submit(
[&](us i) { [&](vd inout, us i) {
// Copy column _filters[i].filter(inout);
vd col = inout; return inout;
_filters[i].filter(col);
return col;
}, // Launch a task to filter. }, // Launch a task to filter.
i // Column i as argument to the lambda function above. inout_cpy, i // Column i as argument to the lambda function above.
)); ));
} }
// Zero-out in-out and sum-up the filtered values // Zero-out in-out and sum-up the filtered values
inout.zeros(); inout.zeros();
for (us i = 0; i < res.n_cols; i++) { for (us i = 0; i < _filters.size(); i++) {
inout += futs[i].get() * _gains[i]; inout += futs[i].get() * _gains[i];
} }
#else
/// Testing, unthreaded version
vd inout_cpy = inout;
inout.zeros();
for (us i = 0; i < _filters.size(); i++) {
vd cpy_again = inout_cpy;
_filters[i].filter(cpy_again);
inout += cpy_again * _gains(i);
}
#endif
} }
void BiquadBank::reset() { void BiquadBank::reset() {
DEBUGTRACE_ENTER; DEBUGTRACE_ENTER;
lock lck(_mtx);
for (auto &f : _filters) { for (auto &f : _filters) {
f.reset(); f.reset();
} }
} }
std::unique_ptr<Filter> BiquadBank::clone() const { std::unique_ptr<Filter> BiquadBank::clone() const {
lock lck(_mtx);
return std::make_unique<BiquadBank>(_filters, _gains); return std::make_unique<BiquadBank>(_filters, _gains);
} }

View File

@ -49,7 +49,7 @@ public:
class BiquadBank : public Filter { class BiquadBank : public Filter {
std::vector<SeriesBiquad> _filters; std::vector<SeriesBiquad> _filters;
vd _gains; vd _gains;
mutable std::mutex _mtx;
public: public:
/** /**

View File

@ -34,21 +34,21 @@ bool RtAps::inCallback_threaded(const DaqData &data) {
if (_filterPrototype) { if (_filterPrototype) {
// Adjust number of filters, if necessary // Adjust number of filters, if necessary
if (nchannels > _freqWeightingFilter.size()) { if (nchannels > _freqWeightingFilters.size()) {
while (nchannels > _freqWeightingFilter.size()) { while (nchannels > _freqWeightingFilters.size()) {
_freqWeightingFilter.emplace_back(_filterPrototype->clone()); _freqWeightingFilters.emplace_back(_filterPrototype->clone());
} }
for (auto &filter : _freqWeightingFilter) { for (auto &filter : _freqWeightingFilters) {
filter->reset(); filter->reset();
} }
} }
// Apply filtering // Apply filtering
#pragma omp parallel for /* #pragma omp parallel for */
for (us i = 0; i < nchannels; i++) { for (us i = 0; i < nchannels; i++) {
vd col = fltdata.col(i); vd col = fltdata.col(i);
_freqWeightingFilter.at(i)->filter(col); _freqWeightingFilters.at(i)->filter(col);
fltdata.col(i) = col; fltdata.col(i) = col;
} }
} // End of if(_filterPrototype) } // End of if(_filterPrototype)

View File

@ -23,7 +23,7 @@ class RtAps : public ThreadedInDataHandler {
std::mutex _mtx; std::mutex _mtx;
std::unique_ptr<Filter> _filterPrototype; std::unique_ptr<Filter> _filterPrototype;
std::vector<std::unique_ptr<Filter>> _freqWeightingFilter; std::vector<std::unique_ptr<Filter>> _freqWeightingFilters;
AvPowerSpectra _ps; AvPowerSpectra _ps;

View File

@ -1,11 +1,12 @@
/* #define DEBUGTRACE_ENABLED */ /* #define DEBUGTRACE_ENABLED */
#include "debugtrace.hpp"
#include "lasp_siggen.h" #include "lasp_siggen.h"
#include "debugtrace.hpp"
#include "lasp_mathtypes.h" #include "lasp_mathtypes.h"
#include <cassert> #include <cassert>
#include <type_traits> #include <type_traits>
using std::cerr; using std::cerr;
using std::endl; using std::endl;
using rte = std::runtime_error;
inline d level_amp(d level_dB) { return pow(10, level_dB / 20); } inline d level_amp(d level_dB) { return pow(10, level_dB / 20); }
@ -21,18 +22,24 @@ vd Siggen::genSignal(const us nframes) {
if (!_muted) { if (!_muted) {
vd signal_dynamic = _level_linear * genSignalUnscaled(nframes); vd signal_dynamic = _level_linear * genSignalUnscaled(nframes);
if (_filter) { for (auto f : _filters) {
_filter->filter(signal_dynamic); assert(f.second);
f.second->filter(signal_dynamic);
} }
signal += signal_dynamic; signal += signal_dynamic;
} }
return signal; return signal;
} }
void Siggen::setFilter(std::shared_ptr<Filter> filter) { void Siggen::setFilter(const std::string &name,
std::shared_ptr<Filter> filter) {
DEBUGTRACE_ENTER; DEBUGTRACE_ENTER;
mutexlock lck(_mtx); mutexlock lck(_mtx);
_filter = filter; if (filter) {
_filters[name] = filter;
} else if (_filters.find(name) != _filters.end()) {
_filters.extract(name);
}
} }
void Siggen::setDCOffset(const d offset) { void Siggen::setDCOffset(const d offset) {
DEBUGTRACE_ENTER; DEBUGTRACE_ENTER;
@ -48,5 +55,9 @@ void Siggen::reset(const d newFs) {
DEBUGTRACE_ENTER; DEBUGTRACE_ENTER;
mutexlock lck(_mtx); mutexlock lck(_mtx);
_fs = newFs; _fs = newFs;
for (auto &f : _filters) {
assert(f.second);
f.second->reset();
}
resetImpl(); resetImpl();
} }

View File

@ -22,7 +22,7 @@ class DaqData;
*/ */
class Siggen { class Siggen {
private: private:
std::shared_ptr<Filter> _filter; std::map<std::string, std::shared_ptr<Filter>> _filters;
d _dc_offset = 0, _level_linear = 1; d _dc_offset = 0, _level_linear = 1;
bool _muted = false; bool _muted = false;
@ -37,12 +37,14 @@ public:
virtual ~Siggen() = default; virtual ~Siggen() = default;
/** /**
* @brief Set a post-filter on the signal. For example to EQ the signal, or * @brief Set a filter on the signal. For example to EQ the signal, or
* otherwise to shape the spectrum. * otherwise to shape the spectrum. Filters are stored in a map, and
* setFilter can be used to overwrite them, if a null pointer is given.
* *
* @param name The name of the filter (i.e. "noiseshaper", or "eq"
* @param f The filter to install. * @param f The filter to install.
*/ */
void setFilter(std::shared_ptr<Filter> f); void setFilter(const std::string& name, std::shared_ptr<Filter> f);
/** /**
* @brief Set a linear DC offset value to the signal * @brief Set a linear DC offset value to the signal

View File

@ -12,6 +12,7 @@ __all__ = ['FirOctaveFilterBank', 'FirThirdOctaveFilterBank',
from .filter.filterbank_design import (OctaveBankDesigner, from .filter.filterbank_design import (OctaveBankDesigner,
ThirdOctaveBankDesigner) ThirdOctaveBankDesigner)
from .lasp_cpp import BiquadBank
import numpy as np import numpy as np
@ -33,12 +34,11 @@ class OverallFilterBank:
""" """
Filter input data Filter input data
""" """
if data.ndim == 1: if data.ndim == 2 and data.shape[1] != 1:
data = data[:, None] raise RuntimeError("invalid number of channels, should be 1")
elif data.ndim == 2:
assert data.shape[1] == 1, "invalid number of channels, should be 1"
if data.shape[0] == 0: if data.shape[0] == 0:
# No new time samples
return {} return {}
# Output given as a dictionary with x as the key # Output given as a dictionary with x as the key
@ -235,12 +235,20 @@ class SosFilterBank:
self.fs = fs self.fs = fs
self.xs = list(range(xmin, xmax + 1)) self.xs = list(range(xmin, xmax + 1))
# The number of parallel filters
nfilt = len(self.xs) nfilt = len(self.xs)
self.nfilt = nfilt self.nfilt = nfilt
self._fb = pyxSosFilterBank(nfilt, 5)
sos = None
for i, x in enumerate(self.xs): for i, x in enumerate(self.xs):
sos = self.designer.createSOSFilter(x) channel = self.designer.createSOSFilter(x)
self._fb.setFilter(i, sos) if sos is None:
sos = np.empty((channel.size, len(self.xs)))
sos[:, i] = channel.flatten()
self._fb = BiquadBank(sos)
self.xmin = xmin self.xmin = xmin
self.xmax = xmax self.xmax = xmax
@ -250,13 +258,14 @@ class SosFilterBank:
""" """
Filter input data Filter input data
""" """
assert data.ndim == 2
assert data.shape[1] == 1, "invalid number of channels, should be 1" if data.ndim > 1 and data.shape[1] != 1:
raise RuntimeError("invalid number of channels, should be 1")
if data.shape[0] == 0: if data.shape[0] == 0:
return {} return {}
filtered_data = self._fb.filter_(data) filtered_data = self._fb.filter(data)
# Output given as a dictionary with nom_txt as the key # Output given as a dictionary with nom_txt as the key
output = {} output = {}

View File

@ -79,11 +79,20 @@ void init_dsp(py::module &m) {
}); });
/// BiquadBank /// BiquadBank
py::class_<BiquadBank, std::shared_ptr<BiquadBank>> bqb(m, "BiquadBank"); py::class_<BiquadBank, Filter, std::shared_ptr<BiquadBank>> bqb(m,
bqb.def(py::init<const dmat &, const vd *>()); "BiquadBank");
bqb.def(py::init([](dpyarray coefs) {
return std::make_shared<BiquadBank>(NpyToMat<d, false>(coefs));
}));
bqb.def(py::init([](dpyarray coefs, dpyarray gains) {
vd gains_arma = NpyToMat<d, false>(gains);
return std::make_shared<BiquadBank>(NpyToMat<d, false>(coefs), &gains_arma);
}));
bqb.def("setGains", bqb.def("setGains",
[](BiquadBank &b, dpyarray gains) { b.setGains(NpyToCol(gains)); }); [](BiquadBank &b, dpyarray gains) { b.setGains(NpyToCol(gains)); });
bqb.def("filter", [](BiquadBank &b, dpyarray input) { bqb.def("filter", [](BiquadBank &b, dpyarray input) {
// Yes, a copy here
vd inout = NpyToCol<d, true>(input); vd inout = NpyToCol<d, true>(input);
b.filter(inout); b.filter(inout);
return ColToNpy(inout); return ColToNpy(inout);

View File

@ -32,7 +32,7 @@ void init_siggen(py::module &m) {
siggen.def("setMute", &Siggen::setMute); siggen.def("setMute", &Siggen::setMute);
siggen.def("setLevel", &Siggen::setLevel); siggen.def("setLevel", &Siggen::setLevel);
siggen.def("setLevel", &Siggen::setLevel, py::arg("newLevel"), py::arg("dB") = true); siggen.def("setLevel", &Siggen::setLevel, py::arg("newLevel"), py::arg("dB") = true);
/* siggen.def("genSignal", &Siggen::genSignal); */
siggen.def("setFilter", &Siggen::setFilter); siggen.def("setFilter", &Siggen::setFilter);
py::class_<Noise,std::shared_ptr<Noise>> noise(m, "Noise", siggen); py::class_<Noise,std::shared_ptr<Noise>> noise(m, "Noise", siggen);