MotorControlModuleSDFM_TMS3.../Projects/EFC_Application/UMLibrary/algorithm/RunningAverage.hh

264 lines
7.3 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!\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_ */