From e435dc9ecdd7d32927ccf96d924cf23a4bae657c Mon Sep 17 00:00:00 2001 From: Casper Date: Fri, 27 Jan 2023 14:56:46 +0100 Subject: [PATCH] Add: ClipHandler --- src/lasp/dsp/CMakeLists.txt | 1 + src/lasp/dsp/lasp_clip.cpp | 94 ++++++++++++++++++++++ src/lasp/dsp/lasp_clip.h | 77 ++++++++++++++++++ src/lasp/pybind11/lasp_pyindatahandler.cpp | 12 +++ 4 files changed, 184 insertions(+) create mode 100644 src/lasp/dsp/lasp_clip.cpp create mode 100644 src/lasp/dsp/lasp_clip.h diff --git a/src/lasp/dsp/CMakeLists.txt b/src/lasp/dsp/CMakeLists.txt index 61a8f59..6dcc5b7 100644 --- a/src/lasp/dsp/CMakeLists.txt +++ b/src/lasp/dsp/CMakeLists.txt @@ -14,6 +14,7 @@ set(lasp_dsp_files lasp_slm.cpp lasp_threadedindatahandler.cpp lasp_ppm.cpp + lasp_clip.cpp ) diff --git a/src/lasp/dsp/lasp_clip.cpp b/src/lasp/dsp/lasp_clip.cpp new file mode 100644 index 0000000..a3b8c8f --- /dev/null +++ b/src/lasp/dsp/lasp_clip.cpp @@ -0,0 +1,94 @@ +/* #define DEBUGTRACE_ENABLED */ +#include "debugtrace.hpp" +#include "lasp_clip.h" +#include + +using std::cerr; +using std::endl; + +using Lck = std::scoped_lock; +using rte = std::runtime_error; + +ClipHandler::ClipHandler(StreamMgr &mgr) + : ThreadedInDataHandler(mgr){ + + DEBUGTRACE_ENTER; + } + +bool ClipHandler::inCallback_threaded(const DaqData &d) { + + DEBUGTRACE_ENTER; + Lck lck(_mtx); + + dmat data = d.toFloat(); + + const us nchannels = d.nchannels; + assert(data.n_cols == nchannels); + + if (nchannels != _clip_time.size()) { + DEBUGTRACE_PRINT("Resizing clip indication"); + _clip_time = vd(nchannels, arma::fill::value(-1)); + } + + /// Obtain max abs values for each column, convert this row-vec to a column + /// vector, and scale with the max-range for each channel + vd maxabs = arma::max(arma::abs(data), 0).as_col() / _max_range; + + /// Find indices for channels that have a clip + arma::uvec clips = maxabs > clip_point; + + for (us i = 0; i < nchannels; i++) { + if (clips(i)) { + /// Reset clip counter + _clip_time(i) = 0; + } else if (_clip_time(i) > clip_indication_time) { + /// Reset to 'unclipped' + _clip_time(i) = -1; + } else if (_clip_time(i) >= 0) { + /// Add a bit of clip time + _clip_time(i) += _dt; + } + } + return true; +} + +arma::uvec ClipHandler::getCurrentValue() const { + + DEBUGTRACE_ENTER; + Lck lck(_mtx); + + arma::uvec clips(_clip_time.size(), arma::fill::zeros); + clips.elem(arma::find(_clip_time >= 0)).fill(1); + + return {clips}; +} + +void ClipHandler::reset(const Daq *daq) { + + DEBUGTRACE_ENTER; + Lck lck(_mtx); + + if (daq) { + + const us nchannels = daq->neninchannels(); + _max_range.resize(nchannels); + + dvec ranges = daq->inputRangeForEnabledChannels(); + assert(ranges.size() == nchannels); + for(us i=0;ineninchannels();i++) { + _max_range[i] = ranges[i]; + } + + _clip_time.fill(-1); + + const d fs = daq->samplerate(); + /* DEBUGTRACE_PRINT(fs); */ + _dt = daq->framesPerBlock() / fs; + } +} + +ClipHandler::~ClipHandler() { + DEBUGTRACE_ENTER; + Lck lck(_mtx); + stop(); +} diff --git a/src/lasp/dsp/lasp_clip.h b/src/lasp/dsp/lasp_clip.h new file mode 100644 index 0000000..fde6985 --- /dev/null +++ b/src/lasp/dsp/lasp_clip.h @@ -0,0 +1,77 @@ +// lasp_clip.h +// +// Author: J.A. de Jong - ASCEE +// +// Description: Peak Programme Meter +#pragma once +#include +#include "lasp_filter.h" +#include "lasp_mathtypes.h" +#include "lasp_threadedindatahandler.h" + +/** + * \addtogroup dsp + * @{ + * + * \addtogroup rt + * @{ + */ + + +/** + * @brief Clipping detector (Clip). Detects when a signal overdrives the input + * */ +class ClipHandler: public ThreadedInDataHandler { + + /** + * @brief Assuming full scale of a signal is +/- 1.0. If a value is found + */ + static inline const d clip_point = 0.98; + + /** + * @brief How long it takes in [s] after a clip event has happened, that we + * are actually still in 'clip' mode. + */ + static inline const d clip_indication_time = 2.0; + + /** + * @brief Inverse of block sampling frequency [s]: (framesPerBlock/fs) + */ + d _dt; + + + mutable std::mutex _mtx; + /** + * @brief How long ago the last clip has happened. Negative in case no clip + * has happened. + */ + vd _clip_time; + + /** + * @brief Storage for maximum values + */ + vd _max_range; + + public: + /** + * @brief Constructs Clipping indicator + * + * @param mgr Stream Mgr to operate on + */ + ClipHandler(StreamMgr& mgr); + ~ClipHandler(); + + /** + * @brief Get the current values of the clip handler. Returns a vector of of True's. + * + * @return clipping indication + */ + arma::uvec getCurrentValue() const; + + bool inCallback_threaded(const DaqData& ) override final; + void reset(const Daq*) override final; + +}; + +/** @} */ +/** @} */ diff --git a/src/lasp/pybind11/lasp_pyindatahandler.cpp b/src/lasp/pybind11/lasp_pyindatahandler.cpp index aa3fb02..a0882f0 100644 --- a/src/lasp/pybind11/lasp_pyindatahandler.cpp +++ b/src/lasp/pybind11/lasp_pyindatahandler.cpp @@ -3,6 +3,7 @@ #include "arma_npy.h" #include "debugtrace.hpp" #include "lasp_ppm.h" +#include "lasp_clip.h" #include "lasp_rtaps.h" #include "lasp_streammgr.h" #include "lasp_threadedindatahandler.h" @@ -192,6 +193,17 @@ void init_datahandler(py::module &m) { ColToNpy(std::get<1>(tp))); }); + /// Clip Detector + py::class_ clip(m, "ClipHandler"); + clip.def(py::init()); + + clip.def("getCurrentValue", [](const ClipHandler &clip) { + + arma::uvec cval = clip.getCurrentValue(); + + return ColToNpy(cval); // something goes wrong here + }); + /// Real time Aps /// py::class_ rtaps(m, "RtAps");