/*!\file * \brief Файл содержит модуль вычисления бегущего среднего. */ /* * RunningAverage.h * * Created on: 26 июн. 2019 г. * Author: titov */ #ifndef SOURCE_ALGORITHM_RUNNINGAVERAGE_H_ #define SOURCE_ALGORITHM_RUNNINGAVERAGE_H_ #include #include namespace algorithm { /*!\brief Вычисление бегущего среднего. * \detail Класс вычисляет бегущее среднее с большими диапозонами данных. Имеет динамически выделяемый кольцевой буфер памяти. * Каждый новый отсчет в буфер усредняеться за пероид измерения одного отсчета. Класс поддерживает полную сумму всех отсчетов в актуальном состоянии. * * y[n] = y[n-1] + ( x[n] - x[n - M] ) / M */ template 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 inline algorithm::RunningAverage::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::max() / size ), element_min( std::numeric_limits::min() / size ) { set(init_value); } template inline Float algorithm::RunningAverage::mean() const { return ( result ) * significant; } template inline void algorithm::RunningAverage::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 inline void algorithm::RunningAverage::resize( Size input_size ) { Float value = mean(); element_size = input_size; _1_num = Float(1) / (input_size); set( value ); } template inline Float algorithm::RunningAverage::setPrecision( Float precision ) { significant = precision; _1_sign = ( precision == 0.0f ? 0.0f : 1.0f / precision ) / size; return ( static_cast( std::numeric_limits::max() * precision ) / size ); } template inline Float algorithm::RunningAverage::calcPrecision( Float amplitude ) { return ( ( amplitude ) / static_cast( std::numeric_limits::max() - 1 ) ); } template inline void algorithm::RunningAverage::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 inline Integer algorithm::RunningAverage::convert( Float value ) { using namespace std; return roundf( value ); } template Integer algorithm::RunningAverage::subtraction(Integer a, Integer b) { if( b > 0 and a < ( std::numeric_limits::min() + b ) ) return std::numeric_limits::min(); else if( b < 0 and a > ( std::numeric_limits::max() + b ) ) return std::numeric_limits::max(); else return a - b; } template Integer algorithm::RunningAverage::addition(Integer a, Integer b) { if( b > 0 and a > ( std::numeric_limits::max() - b ) ) return std::numeric_limits::max(); else if( b < 0 and a < ( std::numeric_limits::min() - b ) ) return std::numeric_limits::min(); else return a + b; } template Integer algorithm::RunningAverage::limit(Integer in) { return in > element_max ? element_max : in < element_min ? element_min : in; } template Float algorithm::RunningAverage::sensitivity() const { return significant * size / 2; } template Float algorithm::RunningAverage::accuracy() const { return significant; } template Float algorithm::RunningAverage::quantization() const { return significant * size; } #endif /* SOURCE_ALGORITHM_RUNNINGAVERAGE_H_ */