272 lines
8.8 KiB
C++
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; }
|
|
};
|
|
/** @} */
|