Skip to content

Commit

Permalink
refactor filter::MovingAverage; added filter::MovingAverage::reset()
Browse files Browse the repository at this point in the history
  • Loading branch information
TomSaw committed Jun 8, 2022
1 parent 313e0b1 commit 7b5827f
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 181 deletions.
168 changes: 76 additions & 92 deletions src/modm/math/filter/moving_average.hpp
Expand Up @@ -7,6 +7,7 @@
* Copyright (c) 2015, Thorsten Lajewski
* Copyright (c) 2017, Daniel Krebs
* Copyright (c) 2018, Christopher Durand
* Copyright (c) 2022, Thomas Sommer
*
* This file is part of the modm project.
*
Expand All @@ -15,111 +16,94 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#ifndef MODM_MOVING_AVERAGE_HPP
#define MODM_MOVING_AVERAGE_HPP
#pragma once

#include <cstddef>
#include <cstdint>
#include <type_traits>

namespace modm
{
namespace filter{
/**
* \brief Moving average filter
*
* Calculates the average of N newest values, i.a. the sum of the last N
* values have been passed to update(...), divided by N. If less than N
* values have been passed to the filter, the division factor is still N,
* so missing values are assumed to be zero.
*
* For integer types this implementation stores the current sum of all values in the buffer
* and updates this value with every call of update() by subtracting
* the overwritten buffer index and adding the new one.
*
* Due to numerical instabillity for floating value types, inside the update function
* the sum has to be recalculated making it less efficient.
*
* The internal sum is always up to date and the getValue()
* method consists of only one division.
*
* \warning Input range is limited by the following equation
* \code N * input::maxValue < T::maxValue \endcode
* The sum off the last N input values must not be greater than
* the maximum value of T, otherwise an overflow will occur.
*
* \tparam T Input type
* \tparam N Number of samples (maximum is 65356 or 2**16)
*
* \ingroup modm_math_filter
*/
template<typename T, std::size_t N>
class MovingAverage
{
private:
using Index = std::conditional_t<
(N >= 256),
uint_fast16_t,
uint_fast8_t
>;

public:
MovingAverage(const T& initialValue = 0);

/// Append new value
void
update(const T& input);
#include <concepts>
#include <span>
#include <algorithm>
#include <numeric>

/// Get filtered value
const T
getValue() const;
#include <modm/math/utils/integer_traits.hpp>

private:
Index index;
T buffer[N];
T sum;
};
}
}

// ----------------------------------------------------------------------------
template<typename T, std::size_t N>
modm::filter::MovingAverage<T, N>::MovingAverage(const T& initialValue) :
index(0), sum(N * initialValue)
namespace modm::filter
{
for (Index i = 0; i < N; ++i) {
buffer[i] = initialValue;
}
}

// ----------------------------------------------------------------------------
// TODO implementierung für float anpassen
/**
* \brief Moving average filter
*
* Calculates the average of N newest values, i.a. the sum of the last N
* values have been passed to update(...), divided by N. If less than N
* values have been passed to the filter, the division factor is still N,
* so missing values are assumed to be zero.
*
* For integer types this implementation stores the current sum of all values in the buffer
* and updates this value with every call of update() by subtracting
* the overwritten buffer index and adding the new one.
*
* Due to numerical instabillity for floating value types, inside the update function
* the sum has to be recalculated making it less efficient.
*
* The internal sum is always up to date and the getValue()
* method consists of only one division.
*
* \warning Input range is limited by the following equation
* \code N * input::maxValue < T::maxValue \endcode
* The sum off the last N input values must not be greater than
* the maximum value of T, otherwise an overflow will occur.
*
* \tparam T Input type
* \tparam N Number of samples
*
* \ingroup modm_math_filter
*/
template<typename T, std::size_t N>
void
modm::filter::MovingAverage<T, N>::update(const T& input)
class MovingAverage
{
sum -= buffer[index];
sum += input;

buffer[index] = input;

index++;
if (index >= N) {
index = 0;
public:
constexpr MovingAverage(T initialValue = 0)
{
reset(initialValue);
}
}

// -----------------------------------------------------------------------------
/// Reset whole buffer to 'input'
/// Next call of getValue() returns 'input'
constexpr void reset(T input)
{
std::fill(std::begin(buffer), std::end(buffer), input);
sum = N * input;
}

/// Append new value
constexpr void
update(T input)
{
if constexpr(std::floating_point<T>) {
buffer[index] = input;
sum = std::accumulate(std::begin(buffer), std::end(buffer), 0);
} else {
sum -= buffer[index];
sum += input;
buffer[index] = input;
}

if (++index == N)
index = 0;
}

template<typename T, std::size_t N>
const T
modm::filter::MovingAverage<T, N>::getValue() const
{
return (sum / static_cast<T>(N));
}
/// Get filtered value
T
constexpr getValue() const
{
return (sum / static_cast<T>(N));
}

private:
least_uint<N> index{0};
T buffer[N];
T sum;
};

#include "moving_average_float_impl.hpp"
#endif // MODM_MOVING_AVERAGE_HPP
} // namespace modm::filter
89 changes: 0 additions & 89 deletions src/modm/math/filter/moving_average_float_impl.hpp

This file was deleted.

28 changes: 28 additions & 0 deletions test/modm/math/filter/moving_average_test.cpp
Expand Up @@ -107,6 +107,20 @@ MovingAverageTest::testAverage()
}
}

void
MovingAverageTest::testReset()
{
modm::filter::MovingAverage<TestData::Type, 4> filter;

for (uint_fast8_t i = 0; i < 4; ++i)
{
filter.update(data[i].input);
}

filter.reset(42);
TEST_ASSERT_EQUALS(filter.getValue(), 42);
}

void
MovingAverageTest::testFloatAverage()
{
Expand All @@ -117,3 +131,17 @@ MovingAverageTest::testFloatAverage()
TEST_ASSERT_EQUALS_DELTA(filter.getValue(), dataF[i].output, double(1e-4));
}
}

void
MovingAverageTest::testFloatReset()
{
modm::filter::MovingAverage<TestDataFloat::Type, 4> filter;

for (uint_fast8_t i = 0; i < 4; ++i)
{
filter.update(dataF[i].input);
}

filter.reset(42.23);
TEST_ASSERT_EQUALS_FLOAT(filter.getValue(), 42.23);
}
6 changes: 6 additions & 0 deletions test/modm/math/filter/moving_average_test.hpp
Expand Up @@ -27,6 +27,12 @@ class MovingAverageTest : public unittest::TestSuite
void
testAverage();

void
testReset();

void
testFloatAverage();

void
testFloatReset();
};

0 comments on commit 7b5827f

Please sign in to comment.