Improved code for cubes. RtAps is not working. Don't know why. TimeBuffer code has better readability. Bugfix in output from Column to Numpy. GIL release for AvPowerSpectra::compute via Pybind.
This commit is contained in:
parent
6aa1262c73
commit
4764a52de8
@ -53,11 +53,11 @@ Daq::Daq(const DeviceInfo &devinfo, const DaqConfiguration &config)
|
|||||||
if (!config.match(devinfo)) {
|
if (!config.match(devinfo)) {
|
||||||
throw rte("DaqConfiguration does not match device info");
|
throw rte("DaqConfiguration does not match device info");
|
||||||
}
|
}
|
||||||
if (neninchannels(false) > ninchannels) {
|
if (neninchannels(false) > devinfo.ninchannels) {
|
||||||
throw rte(
|
throw rte(
|
||||||
"Number of enabled input channels is higher than device capability");
|
"Number of enabled input channels is higher than device capability");
|
||||||
}
|
}
|
||||||
if (nenoutchannels() > noutchannels) {
|
if (nenoutchannels() > devinfo.noutchannels) {
|
||||||
throw rte(
|
throw rte(
|
||||||
"Number of enabled output channels is higher than device capability");
|
"Number of enabled output channels is higher than device capability");
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ DaqData::DaqData(const us nframes, const us nchannels,
|
|||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
DEBUGTRACE_PRINT(sw);
|
DEBUGTRACE_PRINT(sw);
|
||||||
|
|
||||||
|
assert(sw > 0 && sw <= 8);
|
||||||
_data = new (std::align_val_t{8}) byte_t[sw * nchannels * nframes];
|
_data = new (std::align_val_t{8}) byte_t[sw * nchannels * nframes];
|
||||||
if (!_data) {
|
if (!_data) {
|
||||||
throw rte("Could not allocate memory for DaqData!");
|
throw rte("Could not allocate memory for DaqData!");
|
||||||
@ -180,15 +181,18 @@ dmat DaqData::toFloat() const {
|
|||||||
return toFloat<int8_t>();
|
return toFloat<int8_t>();
|
||||||
break;
|
break;
|
||||||
case (DataType::dtype_int16):
|
case (DataType::dtype_int16):
|
||||||
|
DEBUGTRACE_PRINT("Dtype = int16");
|
||||||
return toFloat<int16_t>();
|
return toFloat<int16_t>();
|
||||||
break;
|
break;
|
||||||
case (DataType::dtype_int32):
|
case (DataType::dtype_int32):
|
||||||
return toFloat<int32_t>();
|
return toFloat<int32_t>();
|
||||||
break;
|
break;
|
||||||
case (DataType::dtype_fl32):
|
case (DataType::dtype_fl32):
|
||||||
|
DEBUGTRACE_PRINT("Dtype = float32");
|
||||||
return toFloat<float>();
|
return toFloat<float>();
|
||||||
break;
|
break;
|
||||||
case (DataType::dtype_fl64):
|
case (DataType::dtype_fl64):
|
||||||
|
DEBUGTRACE_PRINT("Dtype = float64");
|
||||||
return toFloat<double>();
|
return toFloat<double>();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -206,5 +210,10 @@ void DaqData::print() const {
|
|||||||
cout << "First sample of first channel (as float)" << toFloat(0,0) << endl;
|
cout << "First sample of first channel (as float)" << toFloat(0,0) << endl;
|
||||||
cout << "Last sample of first channel (as float)" << toFloat(nframes-1,0) << endl;
|
cout << "Last sample of first channel (as float)" << toFloat(nframes-1,0) << endl;
|
||||||
cout << "Last sample of last channel (as float)" << toFloat(nframes-1,nchannels-1) << endl;
|
cout << "Last sample of last channel (as float)" << toFloat(nframes-1,nchannels-1) << endl;
|
||||||
|
dmat data = toFloat();
|
||||||
|
vrd max = arma::max(data, 0);
|
||||||
|
vrd min = arma::min(data, 0);
|
||||||
|
cout << "Maximum value in buf: " << max << endl;
|
||||||
|
cout << "Minumum value in buf: " << min << endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -260,9 +260,9 @@ public:
|
|||||||
us monitorOffset = monitorOutput ? 1 : 0;
|
us monitorOffset = monitorOutput ? 1 : 0;
|
||||||
/* /// Put the output monitor in front */
|
/* /// Put the output monitor in front */
|
||||||
if (monitorOutput) {
|
if (monitorOutput) {
|
||||||
for (us sample = 0; sample < nFramesPerBlock; sample++) {
|
for (us frame = 0; frame < nFramesPerBlock; frame++) {
|
||||||
data.value<double>(sample, 0) =
|
data.value<double>(frame, 0) =
|
||||||
buf[totalOffset + sample * nchannels + (nchannels - 1)];
|
buf[totalOffset + (frame * nchannels) + (nchannels - 1)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ PowerSpectra::PowerSpectra(const vd &window)
|
|||||||
DEBUGTRACE_PRINT(win_pow);
|
DEBUGTRACE_PRINT(win_pow);
|
||||||
}
|
}
|
||||||
|
|
||||||
arma::Cube<c> PowerSpectra::compute(const dmat &input) {
|
ccube PowerSpectra::compute(const dmat &input) {
|
||||||
|
|
||||||
/// Run very often. Silence this one.
|
/// Run very often. Silence this one.
|
||||||
/* DEBUGTRACE_ENTER; */
|
/* DEBUGTRACE_ENTER; */
|
||||||
@ -36,7 +36,7 @@ arma::Cube<c> PowerSpectra::compute(const dmat &input) {
|
|||||||
|
|
||||||
cmat rfft = _fft.fft(input_tmp);
|
cmat rfft = _fft.fft(input_tmp);
|
||||||
|
|
||||||
arma::cx_cube output(rfft.n_rows, input.n_cols, input.n_cols);
|
ccube output(rfft.n_rows, input.n_cols, input.n_cols);
|
||||||
for (us i = 0; i < input.n_cols; i++) {
|
for (us i = 0; i < input.n_cols; i++) {
|
||||||
/// This one can be run in parallel without any problem. Note that it is
|
/// This one can be run in parallel without any problem. Note that it is
|
||||||
/// the inner loop that is run in parallel.
|
/// the inner loop that is run in parallel.
|
||||||
@ -63,6 +63,7 @@ AvPowerSpectra::AvPowerSpectra(const us nfft, const Window::WindowType w,
|
|||||||
}
|
}
|
||||||
|
|
||||||
_overlap_keep = (nfft * overlap_percentage) / 100;
|
_overlap_keep = (nfft * overlap_percentage) / 100;
|
||||||
|
DEBUGTRACE_PRINT(_overlap_keep);
|
||||||
if (_overlap_keep >= nfft) {
|
if (_overlap_keep >= nfft) {
|
||||||
throw rte("Overlap is too high. Results in no jump. Please "
|
throw rte("Overlap is too high. Results in no jump. Please "
|
||||||
"choose a smaller overlap percentage or a higher nfft");
|
"choose a smaller overlap percentage or a higher nfft");
|
||||||
@ -77,39 +78,40 @@ AvPowerSpectra::AvPowerSpectra(const us nfft, const Window::WindowType w,
|
|||||||
DEBUGTRACE_PRINT(_alpha);
|
DEBUGTRACE_PRINT(_alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void AvPowerSpectra::reset() {
|
||||||
|
_timeBuf.reset();
|
||||||
|
_est.reset();
|
||||||
|
|
||||||
std::optional<arma::cx_cube> AvPowerSpectra::compute(const dmat &timedata) {
|
|
||||||
|
|
||||||
/* DEBUGTRACE_ENTER; */
|
|
||||||
/* DEBUGTRACE_PRINT(timedata.n_rows); */
|
|
||||||
/* DEBUGTRACE_PRINT(_ps.nfft); */
|
|
||||||
|
|
||||||
_timeBuf.push(timedata);
|
|
||||||
if (_est.n_cols == 0) {
|
|
||||||
_est = arma::cx_cube(_ps.nfft / 2 + 1, timedata.n_cols, timedata.n_cols,
|
|
||||||
arma::fill::zeros);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<arma::cx_cube> res;
|
std::optional<ccube> AvPowerSpectra::compute(const dmat &timedata) {
|
||||||
|
|
||||||
|
DEBUGTRACE_ENTER;
|
||||||
|
DEBUGTRACE_PRINT(timedata.n_rows);
|
||||||
|
DEBUGTRACE_PRINT(_ps.nfft);
|
||||||
|
|
||||||
|
_timeBuf.push(timedata);
|
||||||
|
|
||||||
us i = 0;
|
us i = 0;
|
||||||
while (auto samples = _timeBuf.pop(_ps.nfft, _overlap_keep)) {
|
while (auto samples = _timeBuf.pop(_ps.nfft, _overlap_keep)) {
|
||||||
/* DEBUGTRACE_PRINT((int)_mode); */
|
DEBUGTRACE_PRINT((int)_mode);
|
||||||
switch (_mode) {
|
switch (_mode) {
|
||||||
case (Mode::Spectrogram): {
|
case (Mode::Spectrogram): {
|
||||||
|
DEBUGTRACE_PRINT("Spectrogram mode");
|
||||||
_est = _ps.compute(samples.value());
|
_est = _ps.compute(samples.value());
|
||||||
} break;
|
} break;
|
||||||
case (Mode::Averaging): {
|
case (Mode::Averaging): {
|
||||||
|
DEBUGTRACE_PRINT("Averaging mode");
|
||||||
n_averages++;
|
n_averages++;
|
||||||
if (n_averages == 1) {
|
if (n_averages == 1) {
|
||||||
_est = _ps.compute(samples.value());
|
_est = _ps.compute(samples.value());
|
||||||
} else {
|
} else {
|
||||||
_est = _est * (static_cast<d>(n_averages - 1) / n_averages) +
|
_est = (static_cast<d>(n_averages - 1) / n_averages) * _est +
|
||||||
_ps.compute(samples.value()) / n_averages;
|
_ps.compute(samples.value()) / n_averages;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case (Mode::Leaking): {
|
case (Mode::Leaking): {
|
||||||
/* DEBUGTRACE_PRINT("Leaking mode"); */
|
DEBUGTRACE_PRINT("Leaking mode");
|
||||||
if (arma::size(_est) == arma::size(0, 0, 0)) {
|
if (arma::size(_est) == arma::size(0, 0, 0)) {
|
||||||
_est = _ps.compute(samples.value());
|
_est = _ps.compute(samples.value());
|
||||||
} else {
|
} else {
|
||||||
@ -124,7 +126,7 @@ std::optional<arma::cx_cube> AvPowerSpectra::compute(const dmat &timedata) {
|
|||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
std::optional<arma::cx_cube> AvPowerSpectra::get_est() {
|
std::optional<ccube> AvPowerSpectra::get_est() const {
|
||||||
if (_est.n_cols > 0)
|
if (_est.n_cols > 0)
|
||||||
return _est;
|
return _est;
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
@ -65,7 +65,7 @@ public:
|
|||||||
* can be accessed by: C(f, i, j). Storage is such that frequency components
|
* can be accessed by: C(f, i, j). Storage is such that frequency components
|
||||||
* are contiguous.
|
* are contiguous.
|
||||||
*/
|
*/
|
||||||
arma::Cube<c> compute(const dmat &input);
|
ccube compute(const dmat &input);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,7 +89,7 @@ class AvPowerSpectra {
|
|||||||
/**
|
/**
|
||||||
* @brief Current estimate of cross-spectral density
|
* @brief Current estimate of cross-spectral density
|
||||||
*/
|
*/
|
||||||
arma::cx_cube _est;
|
ccube _est;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Buffer of storage of time data.
|
* @brief Buffer of storage of time data.
|
||||||
@ -128,7 +128,11 @@ public:
|
|||||||
AvPowerSpectra(const AvPowerSpectra &) = delete;
|
AvPowerSpectra(const AvPowerSpectra &) = delete;
|
||||||
AvPowerSpectra &operator=(const AvPowerSpectra &) = delete;
|
AvPowerSpectra &operator=(const AvPowerSpectra &) = delete;
|
||||||
|
|
||||||
void reset() { _est.reset(); }
|
/**
|
||||||
|
* @brief Reset to empty state. Clears the time buffer and sets estimator to
|
||||||
|
* empty.
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Compute an update of the power spectra based on given time data.
|
* @brief Compute an update of the power spectra based on given time data.
|
||||||
@ -143,7 +147,7 @@ public:
|
|||||||
* new estimate. It can be checked by operator bool().
|
* new estimate. It can be checked by operator bool().
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
std::optional<arma::cx_cube> compute(const dmat &timedata);
|
std::optional<ccube> compute(const dmat &timedata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the latest estimate of cps (cross-power spectra.
|
* @brief Returns the latest estimate of cps (cross-power spectra.
|
||||||
@ -151,7 +155,7 @@ public:
|
|||||||
* @return Pointer (reference, not owning!) to spectral estimate date, or
|
* @return Pointer (reference, not owning!) to spectral estimate date, or
|
||||||
* nullptr, in case nothing could yet be computed.
|
* nullptr, in case nothing could yet be computed.
|
||||||
*/
|
*/
|
||||||
std::optional<arma::cx_cube> get_est();
|
std::optional<ccube> get_est() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The overlap is rounded to a certain amount of time samples. This
|
* @brief The overlap is rounded to a certain amount of time samples. This
|
||||||
|
@ -47,6 +47,7 @@ using vc = arma::Col<c>;
|
|||||||
using vrc = arma::Row<c>;
|
using vrc = arma::Row<c>;
|
||||||
using dmat = arma::Mat<d>;
|
using dmat = arma::Mat<d>;
|
||||||
using cmat = arma::Mat<c>;
|
using cmat = arma::Mat<c>;
|
||||||
using cube = arma::Cube<c>;
|
using ccube = arma::Cube<c>;
|
||||||
|
using dcube = arma::Cube<d>;
|
||||||
|
|
||||||
const d number_pi = arma::datum::pi;
|
const d number_pi = arma::datum::pi;
|
||||||
|
@ -6,42 +6,55 @@
|
|||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
RtAps::RtAps(StreamMgr &mgr, const Filter *freqWeightingFilter,
|
||||||
|
const us nfft,
|
||||||
|
const Window::WindowType w,
|
||||||
|
const d overlap_percentage, const d time_constant)
|
||||||
|
: ThreadedInDataHandler(mgr),
|
||||||
|
_ps(nfft, w, overlap_percentage, time_constant) {
|
||||||
|
|
||||||
|
/* if (freqWeightingFilter != nullptr) { */
|
||||||
|
/* _filterPrototype = freqWeightingFilter->clone(); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
RtAps::~RtAps() {
|
||||||
|
std::scoped_lock<std::mutex> lck(_mtx);
|
||||||
|
stop();
|
||||||
|
}
|
||||||
bool RtAps::inCallback_threaded(const DaqData &data) {
|
bool RtAps::inCallback_threaded(const DaqData &data) {
|
||||||
|
|
||||||
/* DEBUGTRACE_ENTER; */
|
DEBUGTRACE_ENTER;
|
||||||
|
|
||||||
std::scoped_lock<std::mutex> lck(_mtx);
|
std::scoped_lock<std::mutex> lck(_mtx);
|
||||||
dmat fltdata = data.toFloat();
|
dmat fltdata = data.toFloat();
|
||||||
const us nchannels = fltdata.n_cols;
|
data.print();
|
||||||
|
/* const us nchannels = fltdata.n_cols; */
|
||||||
|
|
||||||
if (_filterPrototype) {
|
/* if (_filterPrototype) { */
|
||||||
|
|
||||||
// Adjust number of filters, if necessary
|
/* // Adjust number of filters, if necessary */
|
||||||
if (nchannels > _freqWeightingFilter.size()) {
|
/* if (nchannels > _freqWeightingFilter.size()) { */
|
||||||
while (nchannels > _freqWeightingFilter.size()) {
|
/* while (nchannels > _freqWeightingFilter.size()) { */
|
||||||
_freqWeightingFilter.emplace_back(_filterPrototype->clone());
|
/* _freqWeightingFilter.emplace_back(_filterPrototype->clone()); */
|
||||||
}
|
/* } */
|
||||||
|
|
||||||
for (auto &filter : _freqWeightingFilter) {
|
/* for (auto &filter : _freqWeightingFilter) { */
|
||||||
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);
|
/* _freqWeightingFilter.at(i)->filter(col); */
|
||||||
fltdata.col(i) = col;
|
/* fltdata.col(i) = col; */
|
||||||
}
|
/* } */
|
||||||
} // End of if(_filterPrototype)
|
/* } // End of if(_filterPrototype) */
|
||||||
|
|
||||||
std::optional<arma::cx_cube> res = _ps.compute(fltdata);
|
_ps.compute(fltdata);
|
||||||
|
|
||||||
if (res.has_value()) {
|
|
||||||
/* DEBUGTRACE_PRINT("Data ready!"); */
|
|
||||||
_latest_est = std::make_unique<cube>(std::move(res.value()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -53,13 +66,18 @@ void RtAps::reset(const Daq *daq) { // Explicitly say
|
|||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
std::scoped_lock<std::mutex> lck(_mtx);
|
std::scoped_lock<std::mutex> lck(_mtx);
|
||||||
_ps.reset();
|
_ps.reset();
|
||||||
_latest_est.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<cube> RtAps::getCurrentValue() {
|
std::unique_ptr<ccube> RtAps::getCurrentValue() {
|
||||||
|
|
||||||
/* DEBUGTRACE_ENTER; */
|
/* DEBUGTRACE_ENTER; */
|
||||||
std::scoped_lock<std::mutex> lck(_mtx);
|
std::scoped_lock<std::mutex> lck(_mtx);
|
||||||
|
auto est = _ps.get_est();
|
||||||
|
return std::make_unique<ccube>(est.value_or(ccube()));
|
||||||
|
|
||||||
return std::move(_latest_est);
|
/* return std::move(_latest_est); */
|
||||||
|
/* if (_latest_est) { */
|
||||||
|
/* return std::make_unique<cube>(cube(*_latest_est)); */
|
||||||
|
/* } else */
|
||||||
|
/* return nullptr; */
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,6 @@ 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>> _freqWeightingFilter;
|
||||||
bool _data_ready = false;
|
|
||||||
std::unique_ptr<cube> _latest_est;
|
|
||||||
|
|
||||||
AvPowerSpectra _ps;
|
AvPowerSpectra _ps;
|
||||||
|
|
||||||
@ -40,29 +38,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
RtAps(StreamMgr &mgr, const Filter *freqWeightingFilter, const us nfft = 2048,
|
RtAps(StreamMgr &mgr, const Filter *freqWeightingFilter, const us nfft = 2048,
|
||||||
const Window::WindowType w = Window::WindowType::Hann,
|
const Window::WindowType w = Window::WindowType::Hann,
|
||||||
const d overlap_percentage = 50., const d time_constant = -1)
|
const d overlap_percentage = 50., const d time_constant = -1);
|
||||||
: ThreadedInDataHandler(mgr),
|
~RtAps();
|
||||||
_ps(nfft, w, overlap_percentage, time_constant) {
|
|
||||||
|
|
||||||
{
|
|
||||||
std::scoped_lock<std::mutex> lck(_mtx);
|
|
||||||
if (freqWeightingFilter != nullptr) {
|
|
||||||
_filterPrototype = freqWeightingFilter->clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
~RtAps() {
|
|
||||||
std::scoped_lock<std::mutex> lck(_mtx);
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the latest estimate of the power spectra
|
* @brief Get the latest estimate of the power spectra
|
||||||
*
|
*
|
||||||
* @return Optionally, if available, the latest values
|
* @return Optionally, if available, the latest values
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<cube> getCurrentValue();
|
std::unique_ptr<ccube> getCurrentValue();
|
||||||
|
|
||||||
bool inCallback_threaded(const DaqData &) override final;
|
bool inCallback_threaded(const DaqData &) override final;
|
||||||
void reset(const Daq *) override final;
|
void reset(const Daq *) override final;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* #define DEBUGTRACE_ENABLED */
|
/* #define DEBUGTRACE_ENABLED */
|
||||||
#include "debugtrace.hpp"
|
|
||||||
#include "lasp_timebuffer.h"
|
#include "lasp_timebuffer.h"
|
||||||
|
#include "debugtrace.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
@ -35,32 +35,36 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<dmat> pop(const us nsamples, us keep) {
|
std::optional<dmat> pop(const us nframes, const us keep) {
|
||||||
|
|
||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
|
|
||||||
if (keep > nsamples)
|
if (keep >= nframes) {
|
||||||
throw rte("keep should be <= nsamples");
|
throw rte("keep should be < nframes");
|
||||||
|
}
|
||||||
|
|
||||||
if (nsamples <= n_frames()) {
|
if (nframes <= n_frames()) {
|
||||||
|
|
||||||
assert(!_storage.empty());
|
assert(!_storage.empty());
|
||||||
|
|
||||||
dmat res(nsamples, _storage.front().n_cols);
|
dmat res(nframes, _storage.front().n_cols);
|
||||||
|
|
||||||
for (us i = 0; i < nsamples; i++) {
|
us j = 0;
|
||||||
|
for (us i = 0; i < nframes; i++) {
|
||||||
|
|
||||||
|
if (i + keep < nframes) {
|
||||||
|
// Just pop elements and copy over
|
||||||
|
res.row(i) = _storage.front();
|
||||||
|
_storage.pop_front();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
if (i + keep >= nsamples) {
|
|
||||||
// Suppose keep == 0, then we never arrive here
|
// Suppose keep == 0, then we never arrive here
|
||||||
// Suppose keep == 1, then storage[0] is copyied over.
|
// Suppose keep == 1, then storage[0] is copyied over.
|
||||||
// Suppose keep == 2, then storage[0[ and storage[1] is copyied over.
|
// Suppose keep == 2, then storage[0[ and storage[1] is copyied over.
|
||||||
// Etc.
|
// Etc.
|
||||||
res.row(i) = _storage[i + keep - nsamples];
|
res.row(i) = _storage[j];
|
||||||
} else {
|
j++;
|
||||||
|
|
||||||
// Just pop elements and copy over
|
|
||||||
res.row(i) = _storage.front();
|
|
||||||
_storage.pop_front();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
@ -83,7 +87,5 @@ std::optional<dmat> TimeBuffer::pop(const us n_rows,const us keep) {
|
|||||||
return _imp->pop(n_rows, keep);
|
return _imp->pop(n_rows, keep);
|
||||||
}
|
}
|
||||||
TimeBuffer::~TimeBuffer() {}
|
TimeBuffer::~TimeBuffer() {}
|
||||||
void TimeBuffer::reset() {
|
void TimeBuffer::reset() { _imp->reset(); }
|
||||||
_imp->reset();
|
|
||||||
}
|
|
||||||
void TimeBuffer::push(const dmat &dat) { _imp->push(dat); }
|
void TimeBuffer::push(const dmat &dat) { _imp->push(dat); }
|
||||||
|
@ -9,6 +9,7 @@ namespace py = pybind11;
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
using pyarray = py::array_t<T, py::array::f_style | py::array::forcecast>;
|
using pyarray = py::array_t<T, py::array::f_style | py::array::forcecast>;
|
||||||
using dpyarray = pyarray<d>;
|
using dpyarray = pyarray<d>;
|
||||||
|
using cpyarray = pyarray<c>;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,6 +128,6 @@ arma::Mat<T> NpyToCol(pyarray<T> data) {
|
|||||||
if (data.ndim() != 1) {
|
if (data.ndim() != 1) {
|
||||||
throw std::runtime_error("Expects a 1D array");
|
throw std::runtime_error("Expects a 1D array");
|
||||||
}
|
}
|
||||||
return arma::Col<d>(data.mutable_data(0), data.size(), copy);
|
return arma::Col<T>(data.mutable_data(0), data.size(), copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
namespace py = pybind11;
|
namespace py = pybind11;
|
||||||
|
using rte = std::runtime_error;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \ingroup pybind
|
* \ingroup pybind
|
||||||
@ -29,11 +30,25 @@ void init_dsp(py::module &m) {
|
|||||||
|
|
||||||
py::class_<Fft> fft(m, "Fft");
|
py::class_<Fft> fft(m, "Fft");
|
||||||
fft.def(py::init<us>());
|
fft.def(py::init<us>());
|
||||||
fft.def("fft", py::overload_cast<const vd &>(&Fft::fft));
|
fft.def("fft", [](Fft &f, dpyarray dat) {
|
||||||
fft.def("fft", py::overload_cast<const dmat &>(&Fft::fft));
|
if (dat.ndim() == 1) {
|
||||||
|
return ColToNpy<c>(f.fft(NpyToCol<d, false>(dat)));
|
||||||
|
} else if (dat.ndim() == 2) {
|
||||||
|
return MatToNpy<c>(f.fft(NpyToMat<d, false>(dat)));
|
||||||
|
} else {
|
||||||
|
throw rte("Invalid dimensions of array");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fft.def("ifft", [](Fft &f, cpyarray dat) {
|
||||||
|
if (dat.ndim() == 1) {
|
||||||
|
return ColToNpy<d>(f.ifft(NpyToCol<c, false>(dat)));
|
||||||
|
} else if (dat.ndim() == 2) {
|
||||||
|
return MatToNpy<d>(f.ifft(NpyToMat<c, false>(dat)));
|
||||||
|
} else {
|
||||||
|
throw rte("Invalid dimensions of array");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
fft.def("ifft", py::overload_cast<const vc &>(&Fft::ifft));
|
|
||||||
fft.def("ifft", py::overload_cast<const cmat &>(&Fft::ifft));
|
|
||||||
fft.def_static("load_fft_wisdom", &Fft::load_fft_wisdom);
|
fft.def_static("load_fft_wisdom", &Fft::load_fft_wisdom);
|
||||||
fft.def_static("store_fft_wisdom", &Fft::store_fft_wisdom);
|
fft.def_static("store_fft_wisdom", &Fft::store_fft_wisdom);
|
||||||
|
|
||||||
@ -89,10 +104,17 @@ void init_dsp(py::module &m) {
|
|||||||
py::arg("overlap_percentage") = 50.0, py::arg("time_constant") = -1);
|
py::arg("overlap_percentage") = 50.0, py::arg("time_constant") = -1);
|
||||||
|
|
||||||
aps.def("compute", [](AvPowerSpectra &aps, dpyarray timedata) {
|
aps.def("compute", [](AvPowerSpectra &aps, dpyarray timedata) {
|
||||||
std::optional<arma::cx_cube> res =
|
std::optional<ccube> res;
|
||||||
aps.compute(NpyToMat<d, false>(timedata));
|
{
|
||||||
|
py::gil_scoped_release release;
|
||||||
|
res = aps.compute(NpyToMat<d, false>(timedata));
|
||||||
|
}
|
||||||
|
|
||||||
return CubeToNpy<c>(res.value_or(cube(0, 0, 0)));
|
return CubeToNpy<c>(res.value_or(ccube(0, 0, 0)));
|
||||||
|
});
|
||||||
|
aps.def("get_est", [](const AvPowerSpectra &ps) {
|
||||||
|
auto est = ps.get_est();
|
||||||
|
return CubeToNpy<c>(est.value_or(ccube(0, 0, 0)));
|
||||||
});
|
});
|
||||||
|
|
||||||
py::class_<SLM> slm(m, "cppSLM");
|
py::class_<SLM> slm(m, "cppSLM");
|
||||||
|
@ -215,10 +215,10 @@ void init_datahandler(py::module &m) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
rtaps.def("getCurrentValue", [](RtAps &rt) {
|
rtaps.def("getCurrentValue", [](RtAps &rt) {
|
||||||
std::unique_ptr<cube> val = rt.getCurrentValue();
|
std::unique_ptr<ccube> val = rt.getCurrentValue();
|
||||||
if (val) {
|
if (val) {
|
||||||
return CubeToNpy<c> (*val);
|
return CubeToNpy<c> (*val);
|
||||||
}
|
}
|
||||||
return CubeToNpy<c>(cube(1,0,0));
|
return CubeToNpy<c>(ccube(1,0,0));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ def test_aps1():
|
|||||||
|
|
||||||
sig = np.random.randn(int(fs*tend))
|
sig = np.random.randn(int(fs*tend))
|
||||||
|
|
||||||
cps = aps.compute(sig)
|
cps = aps.compute(sig[:,None])
|
||||||
|
|
||||||
pow1 = np.sum(sig**2)/sig.size
|
pow1 = np.sum(sig**2)/sig.size
|
||||||
pow2 = np.sum((cps[:,0,0]).real)
|
pow2 = np.sum((cps[:,0,0]).real)
|
||||||
|
@ -27,7 +27,7 @@ out = bq.filter(in_)
|
|||||||
|
|
||||||
from scipy.signal import welch
|
from scipy.signal import welch
|
||||||
nfft = 48000
|
nfft = 48000
|
||||||
freq, H1 = welch(out[:,0],
|
freq, H1 = welch(out,
|
||||||
# scaling
|
# scaling
|
||||||
fs=fs,nfft=nfft)
|
fs=fs,nfft=nfft)
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ def test_forward_fft():
|
|||||||
sig = np.random.randn(nfft)
|
sig = np.random.randn(nfft)
|
||||||
fft_lasp = Fft(nfft)
|
fft_lasp = Fft(nfft)
|
||||||
|
|
||||||
res_lasp = fft_lasp.fft(sig)[:,0]
|
res_lasp = fft_lasp.fft(sig)
|
||||||
res_npy = np.fft.rfft(sig)
|
res_npy = np.fft.rfft(sig)
|
||||||
assert(np.isclose(np.linalg.norm(res_lasp- res_npy), 0))
|
assert(np.isclose(np.linalg.norm(res_lasp- res_npy), 0))
|
||||||
|
|
||||||
@ -38,11 +38,11 @@ def test_backward_fft():
|
|||||||
Sig = Sigr + 1j*Sigi
|
Sig = Sigr + 1j*Sigi
|
||||||
|
|
||||||
fft_lasp = Fft(nfft)
|
fft_lasp = Fft(nfft)
|
||||||
sig_lasp = fft_lasp.ifft(Sig)[:,0]
|
sig_lasp = fft_lasp.ifft(Sig)
|
||||||
sig_py = np.fft.irfft(Sig)
|
sig_py = np.fft.irfft(Sig)
|
||||||
|
|
||||||
assert(np.isclose(np.linalg.norm(sig_py- sig_lasp), 0))
|
assert(np.isclose(np.linalg.norm(sig_py- sig_lasp), 0))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_forward_fft()
|
test_forward_fft()
|
||||||
# test_backward_fft()()
|
test_backward_fft()
|
||||||
|
@ -23,7 +23,7 @@ def test_ps():
|
|||||||
# sig = 8*np.cos(omg*t)
|
# sig = 8*np.cos(omg*t)
|
||||||
|
|
||||||
|
|
||||||
cps = ps.compute(sig)
|
cps = ps.compute(sig[:,None])
|
||||||
|
|
||||||
pow1 = np.sum(sig**2)/sig.size
|
pow1 = np.sum(sig**2)/sig.size
|
||||||
pow2 = np.sum((cps[:,0,0]).real)
|
pow2 = np.sum((cps[:,0,0]).real)
|
||||||
|
Loading…
Reference in New Issue
Block a user