lasp/src/lasp/dsp/lasp_slm.h

173 lines
5.4 KiB
C++

#pragma once
#include "lasp_biquadbank.h"
#include "lasp_filter.h"
#include "lasp_thread.h"
#include <memory>
#include <optional>
/**
* \ingroup dsp
* @{
*/
/**
* @brief Sound Level Meter implementation that gives a result for each
* channel. A channel is the result of a filtered signal
*/
class SLM {
GlobalThreadPool _pool;
/**
* @brief A, C or Z weighting, depending on the pre-filter installed.
*/
std::unique_ptr<Filter> _pre_filter;
/**
* @brief Bandpass filters for each channel
*/
std::vector<std::unique_ptr<Filter>> _bandpass;
/**
* @brief Storage for the single-pole low-pass filter coefficient based on
* the Fast / Slow time constant. < 0 means the filter is disabled.
*/
d _alpha = -1;
vd _sp_storage;
d Lrefsq; /// Square of reference value for computing decibels
us downsampling_fac; /// Every x'th sample is returned.
us cur_offset = 0; /// Storage for offset point in input arrays
///
public:
/**
* @brief Public storage for the mean of the square of the signal.
*/
vd Pm;
/**
* @brief Public storage for the maximum signal power, after single pole
* low-pass filter.
*/
vd Pmax; /// Storage for maximum computed signal power so far.
/**
* @brief Public storage for the peak signal power, before single pole
* low-pass filter.
*/
vd Ppeak;
us N = 0; /// Counter for the number of time samples counted that came
/// in;
/**
* @brief Initialize a Sound Level Meter
*
* @param fs Sampling frequency [Hz]
* @param Lref Level reference, used to scale to proper decibel units (dB
* SPL / dBV, etc)
* @param downsampling_fac Every 1/downsampling_fac value is returned from
* compute()
* @param tau Time consant of level meter
* @param pre_filter The pre-filter (Typically an A/C frequency weighting
* filter)
* @param bandpass The parallel set of bandpass filters.
*/
SLM(const d fs, const d Lref, const us downsampling_fac, const d tau,
std::unique_ptr<Filter> pre_filter,
std::vector<std::unique_ptr<Filter>> bandpass);
/**
* @brief Convenience function to create a Sound Level meter from Biquad
* filters only.
*
* @param fs Sampling frequency [Hz]
* @param Lref Level reference, used to scale to proper decibel units (dB
* SPL / dBV, etc)
* @param downsampling_fac Every 1/downsampling_fac value is returned from
* compute()
* @param tau Time consant of level meter
* @param pre_filter_coefs Biquad filter coefficients for pre-filter
* @param bandpass_coefs Biquad filter coeffiecients for bandpass filter
*
* @return Sound Level Meter object
*/
static SLM fromBiquads(const d fs, const d Lref, const us downsampling_fac,
const d tau, const vd &pre_filter_coefs,
const dmat &bandpass_coefs);
/**
* @brief Convenience function to create a Sound Level meter from Biquad
* filters only. No pre-filter, only bandpass.
*
* @param fs Sampling frequency [Hz]
* @param Lref Level reference, used to scale to proper decibel units (dB
* SPL / dBV, etc)
* @param downsampling_fac Every 1/downsampling_fac value is returned from
* compute()
* @param tau Time consant of level meter
* @param bandpass_coefs Biquad filter coefficients for bandpass filter. First axis isis the coefficient index, second axis is the filter index.
*
* @return Sound Level Meter object
*/
static SLM fromBiquads(const d fs, const d Lref, const us downsampling_fac,
const d tau, const dmat &bandpass_coefs);
~SLM();
/**
* @brief Reset state related to samples acquired. All filters reset to zero.
* Start again from no history.
*/
void reset();
SLM(const SLM &o) = delete;
SLM &operator=(const SLM &o) = delete;
SLM(SLM &&o) = default;
/**
* @brief Run the sound level meter on given input data. Return downsampled
* level data for each filterbank channel.
*
* @param input Raw input data
*
* @return Filtered level data for each filtered channel.
*/
dmat run(const vd &input);
/**
* @brief Calculates peak levels measured for each filter channel. The peak
* level is just the highest instantaneous measured power value.
*
* @return vector of peak level values
*/
vd Lpeak() const { return 10 * arma::log10(Ppeak / Lrefsq); };
/**
* @brief Calculates equivalent (time-averaged) levels measured for each
* filter channel
*
* @return vector of equivalent level values
*/
vd Leq() const { return 10 * arma::log10(Pm / Lrefsq); };
/**
* @brief Calculates max levels measured for each filter channel. The max
* value is the maximum time-filtered (Fast / Slow) power level.
*
* @return vector of max level values
*/
vd Lmax() const { return 10 * arma::log10(Pmax / Lrefsq); };
/**
* @brief Comput a 'suggested' downsampling factor, i.e. a lower frame rate
* at which sound level meter values are returned from the computation. This
* is possible since the signal power is low-pas filtered with a single pole
* low pass filter. It can remove computational burden, especially for
* plotting, to have a value > 10.
*
* @param fs Sampling frequency of signal [Hz]
* @param tw Time weighting of SLM low pass filter
*
* @return Suggested downsampling factor, no unit. [-]
*/
static us suggestedDownSamplingFac(const d fs,const d tw);
private:
vd run_single(vd input, const us filter_no);
};
/** @} */