lasp/cpp_src/dsp/lasp_avpowerspectra.h
Thijs Hekman a986a6b9cd
All checks were successful
Building, testing and releasing LASP if it has a tag / Build-Test-Ubuntu (push) Successful in -4m53s
Building, testing and releasing LASP if it has a tag / Release-Ubuntu (push) Has been skipped
Added the aps calculator where blocks are neglectd below a certain threshold. Warning, this is sweep specific and is currently the method implemented in lasp_measurement. Fine for muZ, not necessarily for other stuff
2024-11-01 16:16:06 +01:00

272 lines
8.8 KiB
C++

#pragma once
#include "lasp_fft.h"
#include "lasp_mathtypes.h"
#include "lasp_timebuffer.h"
#include "lasp_window.h"
/** \defgroup dsp Digital Signal Processing utilities
* These are classes and functions used for processing raw signal data, to
* obtain statistics.
*
*
* @{
*/
/**
* @brief Computes single-sided cross-power spectra for a group of channels.
* Only a single block of length fft, no averaging. This class should normally
* not be used. Please refer to AvPowerSpectra instead.
*/
class PowerSpectra {
public:
/**
* @brief The FFT length
*/
us nfft;
private:
/**
* @brief Instance to compute actual FFT's
*/
Fft _fft;
vd _window;
d _scale_fac;
public:
/**
* @brief Initalize power spectra computer
*
* @param nfft The fft length
* @param w The window type
*/
PowerSpectra(const us nfft, const Window::WindowType w);
/**
* @brief Initalize power spectra computer
*
* @param window Uses the window length to compute fft length, and uses the
* window shape as the actual window.
*/
PowerSpectra(const vd &window);
/**
* @brief Computes the spectra. Data is normalized by the (spectral) power of
* the window, to compensate for the effect of the window.
*
* @param input Input data, first axis is assumed the sample, second axis the
* channel. Input first dimension should be equal to nfft, otherwise a
* runtime error is thrown.
*
* @return Cross-power-spectra. Cubic array with size indices C_fij, where
* f is the frequency index, i is the row and j is the column. An element
* can be accessed by: C(f, i, j). Storage is such that frequency components
* are contiguous.
*/
ccube compute(const dmat &input);
};
/**
* @brief Estimate cross-power spectra using Welch' method of spectral
* estimation. The exact amount of overlap in Welch' method is rounded up to a
* certain amount of samples.
*/
class AvPowerSpectra {
enum class Mode {
Averaging = 0, // Averaging all time date
Leaking = 1, // Exponential weighting of an "instantaneous cps"
Spectrogram = 2 // Instantenous spectrum, no averaging
};
Mode _mode;
d _alpha; // Only valid in case of 'Leaking'
us _n_averages = 0; // Only valid in case of 'Averaging'
PowerSpectra _ps;
/**
* @brief Current estimate of cross-spectral density
*/
ccube _est;
/**
* @brief Buffer of storage of time data.
*/
TimeBuffer _timeBuf;
/**
* @brief The amount of samples to keep in the overlap
*/
us _overlap_keep;
public:
/**
* @brief Initalize averaged power spectra computer. If a time constant is
* given > 0, it is used in a kind of exponential weighting.
*
* @param nfft The fft length
* @param w The window type.
* @param overlap_percentage A number 0 < overlap_percentage <= 100. It
* determines the amount of overlap used in Welch' method. A typical value is
* 50 %, i.e. 50.
* @param fs_tau Value should either be < 0, indicating that the
* estimate is averages over all time data.
* For a value = 0 the instantaneous power spectrum is returned, which can be
* interpreted as the spectrogram. For a value > 0 a exponential forgetting is
* used, where the value is used as the time constant such that the decay
* follows approximately the trend exp(-n/fs_tau), where n is the
* sample number in the power spectra. To choose 'fast' time weighting, set
* time_constant to the value of fs*0.125, where fs denotes the sampling
* frequency.
**/
AvPowerSpectra(const us nfft = 2048,
const Window::WindowType w = Window::WindowType::Hann,
const d overlap_percentage = 50.,
const d fs_tau = -1);
AvPowerSpectra(const AvPowerSpectra &) = delete;
AvPowerSpectra &operator=(const AvPowerSpectra &) = delete;
/**
* @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.
* Note that the number of channels is determined from the first time this
* function is called. If a later call has an incompatible number of
* channels, a runtime error is thrown.
*
* @param timedata
*
* @return a copy of the latest estimate of the power spectra. an
* update is only given if the amount of new time data is enough to compute a
* new estimate. if no new estimate is available, it returns an empty ccube.
* Note that the latest available estimate can be obtained using get_est().
* */
ccube compute(const dmat &timedata);
/**
* @brief Returns the latest estimate of cps (cross-power spectra.
*
* @return a copy of the latest estimate of the power spectra. an
* update is only given if the amount of new time data is enough to compute a
* new estimate. If no estimate is available, it returns an empty ccube.
* */
ccube get_est() const;
/**
* @brief The overlap is rounded to a certain amount of time samples. This
* function returns that value.
*
* @return The amount of samples in overlapping.
*/
us exactOverlapSamples() const { return _ps.nfft - _overlap_keep; }
};
/** @} */
/**
* @brief Estimate cross-power spectra using Welch' method of spectral
* estimation. The exact amount of overlap in Welch' method is rounded up to a
* certain amount of samples. This class is specifically for sweeps and will ignore
* fft blocks where the auto-power of the "reference" signal is below the average
* when in averaging mode.
*/
class AvSweepPowerSpectra {
enum class Mode {
Averaging = 0, // Averaging all time date
Leaking = 1, // Exponential weighting of an "instantaneous cps"
Spectrogram = 2 // Instantenous spectrum, no averaging
};
Mode _mode;
d _alpha; // Only valid in case of 'Leaking'
us _nfft;
vd _n_averages { 1, arma::fill::zeros}; // Only valid in case of 'Averaging'
PowerSpectra _ps;
/**
* @brief Current estimate of cross-spectral density
*/
ccube _est;
/**
* @brief Buffer of storage of time data.
*/
TimeBuffer _timeBuf;
/**
* @brief The amount of samples to keep in the overlap
*/
us _overlap_keep;
public:
/**
* @brief Initalize averaged power spectra computer. If a time constant is
* given > 0, it is used in a kind of exponential weighting.
*
* @param nfft The fft length
* @param w The window type.
* @param overlap_percentage A number 0 < overlap_percentage <= 100. It
* determines the amount of overlap used in Welch' method. A typical value is
* 50 %, i.e. 50.
* @param fs_tau Value should either be < 0, indicating that the
* estimate is averages over all time data.
* For a value = 0 the instantaneous power spectrum is returned, which can be
* interpreted as the spectrogram. For a value > 0 a exponential forgetting is
* used, where the value is used as the time constant such that the decay
* follows approximately the trend exp(-n/fs_tau), where n is the
* sample number in the power spectra. To choose 'fast' time weighting, set
* time_constant to the value of fs*0.125, where fs denotes the sampling
* frequency.
**/
AvSweepPowerSpectra(const us nfft = 2048,
const Window::WindowType w = Window::WindowType::Hann,
const d overlap_percentage = 50.,
const d fs_tau = -1);
AvSweepPowerSpectra(const AvSweepPowerSpectra &) = delete;
AvSweepPowerSpectra &operator=(const AvSweepPowerSpectra &) = delete;
/**
* @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.
* Note that the number of channels is determined from the first time this
* function is called. If a later call has an incompatible number of
* channels, a runtime error is thrown.
*
* @param timedata
*
* @return a copy of the latest estimate of the power spectra. an
* update is only given if the amount of new time data is enough to compute a
* new estimate. if no new estimate is available, it returns an empty ccube.
* Note that the latest available estimate can be obtained using get_est().
* */
ccube compute(const dmat &timedata);
/**
* @brief Returns the latest estimate of cps (cross-power spectra.
*
* @return a copy of the latest estimate of the power spectra. an
* update is only given if the amount of new time data is enough to compute a
* new estimate. If no estimate is available, it returns an empty ccube.
* */
ccube get_est() const;
/**
* @brief The overlap is rounded to a certain amount of time samples. This
* function returns that value.
*
* @return The amount of samples in overlapping.
*/
us exactOverlapSamples() const { return _ps.nfft - _overlap_keep; }
};
/** @} */