Added real time signal viewer
This commit is contained in:
parent
24b9a24b04
commit
c7045a81e9
@ -7,6 +7,7 @@ set(lasp_dsp_files
|
|||||||
lasp_window.cpp
|
lasp_window.cpp
|
||||||
lasp_fft.cpp
|
lasp_fft.cpp
|
||||||
lasp_rtaps.cpp
|
lasp_rtaps.cpp
|
||||||
|
lasp_rtsignalviewer.cpp
|
||||||
lasp_avpowerspectra.cpp
|
lasp_avpowerspectra.cpp
|
||||||
lasp_biquadbank.cpp
|
lasp_biquadbank.cpp
|
||||||
lasp_thread.cpp
|
lasp_thread.cpp
|
||||||
|
@ -19,6 +19,10 @@
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Real time spectral estimator using Welch method of spectral
|
||||||
|
* estimation.
|
||||||
|
*/
|
||||||
class RtAps : public ThreadedInDataHandler {
|
class RtAps : public ThreadedInDataHandler {
|
||||||
|
|
||||||
std::unique_ptr<Filter> _filterPrototype;
|
std::unique_ptr<Filter> _filterPrototype;
|
||||||
|
104
src/lasp/dsp/lasp_rtsignalviewer.cpp
Normal file
104
src/lasp/dsp/lasp_rtsignalviewer.cpp
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/* #define DEBUGTRACE_ENABLED */
|
||||||
|
#include "debugtrace.hpp"
|
||||||
|
#include "lasp_rtsignalviewer.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
using std::cerr;
|
||||||
|
using std::endl;
|
||||||
|
using Lck = std::scoped_lock<std::mutex>;
|
||||||
|
using rte = std::runtime_error;
|
||||||
|
|
||||||
|
RtSignalViewer::RtSignalViewer(StreamMgr &mgr, const d approx_time_hist,
|
||||||
|
const us resolution, const us channel)
|
||||||
|
: ThreadedInDataHandler(mgr), _approx_time_hist(approx_time_hist),
|
||||||
|
_resolution(resolution), _channel(channel) {
|
||||||
|
|
||||||
|
DEBUGTRACE_ENTER;
|
||||||
|
|
||||||
|
if (approx_time_hist <= 0) {
|
||||||
|
throw rte("Invalid time history. Should be > 0");
|
||||||
|
}
|
||||||
|
if (resolution <= 1) {
|
||||||
|
throw rte("Invalid resolution. Should be > 1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtSignalViewer::inCallback_threaded(const DaqData &data) {
|
||||||
|
|
||||||
|
DEBUGTRACE_ENTER;
|
||||||
|
|
||||||
|
Lck lck(_sv_mtx);
|
||||||
|
|
||||||
|
/// Push new data in time buffer, scaled by sensitivity
|
||||||
|
_tb.push(data.toFloat(_channel) / _sens(_channel));
|
||||||
|
|
||||||
|
_dat.col(0) += _nsamples_per_point / _fs;
|
||||||
|
/// Required number of samples for a new 'point'
|
||||||
|
while (_tb.size() > _nsamples_per_point) {
|
||||||
|
// Roll forward time column
|
||||||
|
_dat.col(0) += _nsamples_per_point / _fs;
|
||||||
|
vd newvals = _tb.pop(_nsamples_per_point);
|
||||||
|
d newmax = newvals.max();
|
||||||
|
d newmin = newvals.min();
|
||||||
|
|
||||||
|
vd mincol = _dat.col(1);
|
||||||
|
vd maxcol = _dat.col(2);
|
||||||
|
_dat(arma::span(0, _resolution-2),1) = mincol(arma::span(1, _resolution-1));
|
||||||
|
_dat(arma::span(0, _resolution-2),2) = maxcol(arma::span(1, _resolution-1));
|
||||||
|
_dat(_resolution-1, 1) = newmin;
|
||||||
|
_dat(_resolution-1, 2) = newmax;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtSignalViewer::~RtSignalViewer() {
|
||||||
|
Lck lck(_sv_mtx);
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
void RtSignalViewer::reset(const Daq *daq) {
|
||||||
|
|
||||||
|
DEBUGTRACE_ENTER;
|
||||||
|
Lck lck(_sv_mtx);
|
||||||
|
|
||||||
|
// Reset time buffer
|
||||||
|
_tb.reset();
|
||||||
|
|
||||||
|
if (daq) {
|
||||||
|
_fs = daq->samplerate();
|
||||||
|
|
||||||
|
/// Update sensitivity values
|
||||||
|
_sens.resize(daq->neninchannels());
|
||||||
|
us i = 0;
|
||||||
|
for (const auto &ch : daq->enabledInChannels()) {
|
||||||
|
_sens[i] = ch.sensitivity;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The number of samples per point, based on which minmax are computed
|
||||||
|
_nsamples_per_point =
|
||||||
|
std::max<us>(static_cast<us>(_approx_time_hist / _resolution * _fs), 1);
|
||||||
|
|
||||||
|
const d dt_points = _nsamples_per_point / _fs;
|
||||||
|
const d tend = dt_points * _resolution;
|
||||||
|
|
||||||
|
// Initialize data array
|
||||||
|
_dat.resize(_resolution, 3);
|
||||||
|
_dat.col(0) = arma::linspace(0, tend, _resolution);
|
||||||
|
_dat.col(1).zeros();
|
||||||
|
_dat.col(2).zeros();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_sens.zeros();
|
||||||
|
_fs = 0;
|
||||||
|
_dat.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dmat RtSignalViewer::getCurrentValue() const {
|
||||||
|
|
||||||
|
DEBUGTRACE_ENTER;
|
||||||
|
Lck lck(_sv_mtx);
|
||||||
|
return _dat;
|
||||||
|
}
|
93
src/lasp/dsp/lasp_rtsignalviewer.h
Normal file
93
src/lasp/dsp/lasp_rtsignalviewer.h
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// lasp_threadedaps.h
|
||||||
|
//
|
||||||
|
// Author: J.A. de Jong - ASCEE
|
||||||
|
//
|
||||||
|
// Description: Real Time Signal Viewer.
|
||||||
|
#pragma once
|
||||||
|
#include "lasp_avpowerspectra.h"
|
||||||
|
#include "lasp_filter.h"
|
||||||
|
#include "lasp_mathtypes.h"
|
||||||
|
#include "lasp_threadedindatahandler.h"
|
||||||
|
#include "lasp_timebuffer.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \addtogroup dsp
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* \addtogroup rt
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Real time signal viewer. Shows envelope of the signal based on amount
|
||||||
|
* of history shown.
|
||||||
|
*/
|
||||||
|
class RtSignalViewer : public ThreadedInDataHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Storage for sensitivity values
|
||||||
|
*/
|
||||||
|
vd _sens;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Storage for time samples
|
||||||
|
*/
|
||||||
|
TimeBuffer _tb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The amount of time history to show
|
||||||
|
*/
|
||||||
|
const d _approx_time_hist;
|
||||||
|
/**
|
||||||
|
* @brief The number of points to show
|
||||||
|
*/
|
||||||
|
const us _resolution;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The channel to show
|
||||||
|
*/
|
||||||
|
const us _channel;
|
||||||
|
|
||||||
|
us _nsamples_per_point;
|
||||||
|
d _fs;
|
||||||
|
|
||||||
|
dmat _dat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mutex only for _signalviewer.
|
||||||
|
*/
|
||||||
|
mutable std::mutex _sv_mtx;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @param mgr Stream manager
|
||||||
|
* @param approx_time_hist The *approximate* time history to show. The exact
|
||||||
|
* time history will be calculated such that there fits an integer number of
|
||||||
|
* samples in a single 'point'.
|
||||||
|
* @param resolution Number of time points
|
||||||
|
* @param channel The channel number
|
||||||
|
*/
|
||||||
|
RtSignalViewer(StreamMgr &mgr, const d approx_time_hist, const us resolution,
|
||||||
|
const us channel);
|
||||||
|
|
||||||
|
~RtSignalViewer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a 2D array, with:
|
||||||
|
* - first column: time instances.
|
||||||
|
* - second column: minimum value of signal
|
||||||
|
* - third column: maximum value of signal
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
dmat getCurrentValue() const;
|
||||||
|
|
||||||
|
bool inCallback_threaded(const DaqData &) override final;
|
||||||
|
void reset(const Daq *) override final;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
/** @} */
|
@ -1,11 +1,12 @@
|
|||||||
/* #define DEBUGTRACE_ENABLED */
|
/* #define DEBUGTRACE_ENABLED */
|
||||||
#include <armadillo>
|
|
||||||
#include "arma_npy.h"
|
#include "arma_npy.h"
|
||||||
#include "debugtrace.hpp"
|
#include "debugtrace.hpp"
|
||||||
#include "lasp_ppm.h"
|
#include "lasp_ppm.h"
|
||||||
#include "lasp_rtaps.h"
|
#include "lasp_rtaps.h"
|
||||||
|
#include "lasp_rtsignalviewer.h"
|
||||||
#include "lasp_streammgr.h"
|
#include "lasp_streammgr.h"
|
||||||
#include "lasp_threadedindatahandler.h"
|
#include "lasp_threadedindatahandler.h"
|
||||||
|
#include <armadillo>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
@ -185,11 +186,10 @@ void init_datahandler(py::module &m) {
|
|||||||
ppm.def(py::init<StreamMgr &>());
|
ppm.def(py::init<StreamMgr &>());
|
||||||
|
|
||||||
ppm.def("getCurrentValue", [](const PPMHandler &ppm) {
|
ppm.def("getCurrentValue", [](const PPMHandler &ppm) {
|
||||||
|
|
||||||
std::tuple<vd, arma::uvec> tp = ppm.getCurrentValue();
|
std::tuple<vd, arma::uvec> tp = ppm.getCurrentValue();
|
||||||
|
|
||||||
return py::make_tuple(ColToNpy<d>(std::get<0>(tp)),
|
return py::make_tuple(ColToNpy<d>(std::get<0>(tp)),
|
||||||
ColToNpy<arma::uword>(std::get<1>(tp)));
|
ColToNpy<arma::uword>(std::get<1>(tp)));
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Real time Aps
|
/// Real time Aps
|
||||||
@ -216,6 +216,20 @@ void init_datahandler(py::module &m) {
|
|||||||
|
|
||||||
rtaps.def("getCurrentValue", [](RtAps &rt) {
|
rtaps.def("getCurrentValue", [](RtAps &rt) {
|
||||||
ccube val = rt.getCurrentValue();
|
ccube val = rt.getCurrentValue();
|
||||||
return CubeToNpy<c>(val);
|
return CubeToNpy<c>(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Real time Signal Viewer
|
||||||
|
///
|
||||||
|
py::class_<RtSignalViewer, ThreadedInDataHandler> rtsv(m, "RtSignalViewer");
|
||||||
|
rtsv.def(py::init<StreamMgr &, // StreamMgr
|
||||||
|
const d, // Time history
|
||||||
|
const us, // Resolution
|
||||||
|
const us // Channel number
|
||||||
|
>());
|
||||||
|
|
||||||
|
rtsv.def("getCurrentValue", [](RtSignalViewer &rt) {
|
||||||
|
dmat val = rt.getCurrentValue();
|
||||||
|
return MatToNpy<d>(val);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user