264 lines
7.3 KiB
C++
264 lines
7.3 KiB
C++
/*!\file
|
||
* \brief Файл содержит модуль вычисления бегущего среднего.
|
||
*/
|
||
/*
|
||
* RunningAverage.h
|
||
*
|
||
* Created on: 26 июн. 2019 г.
|
||
* Author: titov
|
||
*/
|
||
|
||
#ifndef SOURCE_ALGORITHM_RUNNINGAVERAGE_H_
|
||
#define SOURCE_ALGORITHM_RUNNINGAVERAGE_H_
|
||
|
||
#include <limits>
|
||
#include <cmath>
|
||
|
||
namespace algorithm {
|
||
|
||
/*!\brief Вычисление бегущего среднего.
|
||
* \detail Класс вычисляет бегущее среднее с большими диапозонами данных. Имеет динамически выделяемый кольцевой буфер памяти.
|
||
* Каждый новый отсчет в буфер усредняеться за пероид измерения одного отсчета. Класс поддерживает полную сумму всех отсчетов в актуальном состоянии.
|
||
*
|
||
* y[n] = y[n-1] + ( x[n] - x[n - M] ) / M
|
||
*/
|
||
template<typename Integer, typename Float>
|
||
class RunningAverage {
|
||
public:
|
||
|
||
typedef unsigned short Size;
|
||
typedef Integer IntegerType;
|
||
typedef Float FloatType;
|
||
|
||
RunningAverage( Integer * buff, Size size, Size element_size,
|
||
Float precision = Float(0.0f), Float init_value = Float(0.0f) );
|
||
|
||
/*!\brief Функция вычисляет среднее из суммы всех отсчетов.
|
||
* \return Бегущее среднее.
|
||
*/
|
||
Float mean() const;
|
||
|
||
/*!\brief Функция устанавилвает выход фильтра в заданное значение.
|
||
*
|
||
*/
|
||
void set( Float value );
|
||
|
||
/*!\brief Установить количество усредняемых отсчетов.
|
||
* \detail Функция изменяет количество усредняемых отсчетов не изменяя размер.
|
||
* \param[in] input_size Количество отсчетов в одном элементе буфера.
|
||
*/
|
||
void resize( Size input_size );
|
||
|
||
/*!\brief Установить точность вычислений.
|
||
*
|
||
*/
|
||
Float setPrecision( Float precision );
|
||
|
||
/*!\brief Рассчитать точность вычислений.
|
||
* \detail Расчет ведеться исходя из размера буфера и максимального целочисленного значения.
|
||
*/
|
||
static Float calcPrecision( Float amplitude );
|
||
|
||
/*\brief Добавить отсчет в фильтр.
|
||
* \detail Функция добавляет отсчет и обновляет переменные.
|
||
*\param[in] value - текущее значение фильтруемой переменной.
|
||
*/
|
||
void add( Float value );
|
||
|
||
Float sensitivity() const;
|
||
Float accuracy() const;
|
||
Float quantization() const;
|
||
|
||
private:
|
||
Float input_value; //!<Накопление отсчета за период усреднения одного отсчета.
|
||
Size element_size; //!<Период усреднения одного отсчета.
|
||
Size input_index; //!<Количество уже усредненных отсчетов.
|
||
|
||
Integer * const buffer; //!<Массив для хранения предыдущих усредненых отсчетов.
|
||
const Size size; //!<Размер буфера.
|
||
|
||
Size index; //!<Положение последнего усредненного отсчета.
|
||
|
||
Float _1_num; //!<Коэффициент пересчета.
|
||
Float significant; //!<Вес одного разряда в целочисленном представлении.
|
||
Float _1_sign; //!<Коэффициент пересчета в целочисленное представление.
|
||
|
||
Integer sum_value; //!<
|
||
Integer result; //!<Результат работы фильтра
|
||
|
||
RunningAverage & operator=(const RunningAverage &) = delete;
|
||
RunningAverage(const RunningAverage &) = delete;
|
||
|
||
static Integer convert( Float );
|
||
|
||
protected:
|
||
static Integer subtraction( Integer a, Integer b );
|
||
static Integer addition( Integer a, Integer b );
|
||
|
||
const Integer element_max;
|
||
const Integer element_min;
|
||
Integer limit( Integer in );
|
||
};
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
inline algorithm::RunningAverage<Integer, Float>::RunningAverage(
|
||
Integer * buff, Size size, Size element_size, Float precision, Float init_value ) :
|
||
input_value(0), element_size(element_size), input_index(0),
|
||
buffer(buff), size(size), index(0),
|
||
_1_num( Float(1) / (element_size) ),
|
||
significant(precision), _1_sign(( precision == 0.0f ? 0.0f : 1.0f / precision ) / size),
|
||
sum_value(0), result(0),
|
||
element_max( std::numeric_limits<Integer>::max() / size ),
|
||
element_min( std::numeric_limits<Integer>::min() / size ) {
|
||
|
||
set(init_value);
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
inline Float algorithm::RunningAverage<Integer, Float>::mean() const {
|
||
|
||
return ( result ) * significant;
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
inline void algorithm::RunningAverage<Integer, Float>::set( Float value ) {
|
||
|
||
sum_value = 0;
|
||
for( Size i = 0; i < size; i++ )
|
||
sum_value += ( buffer[i] = limit( convert( ( value ) * _1_sign ) ) );
|
||
|
||
result = sum_value;
|
||
|
||
input_value = 0;
|
||
input_index = 0;
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
inline void algorithm::RunningAverage<Integer, Float>::resize( Size input_size ) {
|
||
|
||
Float value = mean();
|
||
|
||
element_size = input_size;
|
||
_1_num = Float(1) / (input_size);
|
||
|
||
set( value );
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
inline Float algorithm::RunningAverage<Integer, Float>::setPrecision(
|
||
Float precision ) {
|
||
|
||
significant = precision;
|
||
_1_sign = ( precision == 0.0f ? 0.0f : 1.0f / precision ) / size;
|
||
|
||
return ( static_cast<Float>( std::numeric_limits<Integer>::max() * precision ) / size );
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
inline Float algorithm::RunningAverage<Integer, Float>::calcPrecision(
|
||
Float amplitude ) {
|
||
|
||
return ( ( amplitude ) / static_cast<Float>( std::numeric_limits<Integer>::max() - 1 ) );
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
inline void algorithm::RunningAverage<Integer, Float>::add( Float value ) {
|
||
|
||
input_value += value;
|
||
input_index++;
|
||
|
||
if( input_index == element_size ) {
|
||
|
||
Integer temp = limit( convert( ( input_value * _1_num ) * _1_sign ) );
|
||
|
||
sum_value = subtraction( sum_value, buffer[index] );
|
||
buffer[index] = temp;
|
||
sum_value = addition( sum_value, temp );
|
||
|
||
result = sum_value;
|
||
|
||
input_value = 0.0f;
|
||
input_index = 0;
|
||
|
||
index++;
|
||
|
||
if( index == size)
|
||
index = 0;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
inline Integer algorithm::RunningAverage<Integer, Float>::convert( Float value ) {
|
||
|
||
using namespace std;
|
||
|
||
return roundf( value );
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
Integer algorithm::RunningAverage<Integer, Float>::subtraction(Integer a, Integer b) {
|
||
|
||
if( b > 0 and a < ( std::numeric_limits<Integer>::min() + b ) )
|
||
return std::numeric_limits<Integer>::min();
|
||
|
||
else if( b < 0 and a > ( std::numeric_limits<Integer>::max() + b ) )
|
||
return std::numeric_limits<Integer>::max();
|
||
|
||
else
|
||
return a - b;
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
Integer algorithm::RunningAverage<Integer, Float>::addition(Integer a, Integer b) {
|
||
|
||
if( b > 0 and a > ( std::numeric_limits<Integer>::max() - b ) )
|
||
return std::numeric_limits<Integer>::max();
|
||
|
||
else if( b < 0 and a < ( std::numeric_limits<Integer>::min() - b ) )
|
||
return std::numeric_limits<Integer>::min();
|
||
|
||
else
|
||
return a + b;
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
Integer algorithm::RunningAverage<Integer, Float>::limit(Integer in) {
|
||
return in > element_max ?
|
||
element_max : in < element_min ? element_min : in;
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
Float algorithm::RunningAverage<Integer, Float>::sensitivity() const {
|
||
|
||
return significant * size / 2;
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
Float algorithm::RunningAverage<Integer, Float>::accuracy() const {
|
||
|
||
return significant;
|
||
|
||
}
|
||
|
||
template<typename Integer, typename Float>
|
||
Float algorithm::RunningAverage<Integer, Float>::quantization() const {
|
||
|
||
return significant * size;
|
||
|
||
}
|
||
|
||
#endif /* SOURCE_ALGORITHM_RUNNINGAVERAGE_H_ */
|