diff --git a/include/etl/cumulative_moving_average.h b/include/etl/cumulative_moving_average.h index 40989603..95e476cb 100644 --- a/include/etl/cumulative_moving_average.h +++ b/include/etl/cumulative_moving_average.h @@ -112,6 +112,78 @@ namespace etl T average; ///< The current cumulative average. }; + //*************************************************************************** +/// Cumulative Moving Average +/// For integral types. +/// \tparam T The sample value type. +/// \tparam SCALING The scaling factor applied to samples. Default = 1. +//*************************************************************************** + template + class cumulative_moving_average + { + typedef typename etl::conditional::value, int32_t, uint32_t>::type scale_t; + typedef typename etl::conditional::value, int32_t, uint32_t>::type sample_t; + + static const scale_t SCALE = static_cast(SCALING_); + + public: + + static const size_t SCALING = SCALING_; ///< The sample scaling factor. + + //************************************************************************* + /// Constructor + /// \param initial_value The initial value for the average. + //************************************************************************* + cumulative_moving_average(const T initial_value, const size_t sample_size) + : average(initial_value * SCALE) + , samples(sample_size) + { + } + + //************************************************************************* + /// Clears the average. + /// \param initial_value The initial value for the average. + //************************************************************************* + void clear(const T initial_value) + { + average = (initial_value * SCALE); + } + + //************************************************************************* + /// Sets the sample size. + /// \param sample_size The new sample size. + //************************************************************************* + void set_sample_size(const size_t sample_size) + { + samples = sample_t(sample_size); + } + + //************************************************************************* + /// Adds a new sample to the average. + /// \param new_value The value to add. + //************************************************************************* + void add(T new_value) + { + average *= samples; + average += SCALE * new_value; + average /= samples + sample_t(1); + } + + //************************************************************************* + /// Gets the current cumulative average. + /// \return The current average. + //************************************************************************* + T value() const + { + return average; + } + + private: + + T average; ///< The current cumulative average. + sample_t samples; ///< The nuimber of samples to average over. + }; + //*************************************************************************** /// Cumulative Moving Average /// For floating point types. @@ -130,8 +202,8 @@ namespace etl /// \param initial_value The initial value for the average. //************************************************************************* cumulative_moving_average(const T initial_value) - : sample_size(T(SAMPLE_SIZE_)), - sample_size_plus_1(T(SAMPLE_SIZE_ + 1)), + : samples(T(SAMPLE_SIZE_)), + samples_plus_1(T(SAMPLE_SIZE_ + 1U)), average(initial_value) { } @@ -151,9 +223,9 @@ namespace etl //************************************************************************* void add(const T new_value) { - average *= sample_size; + average *= samples; average += new_value; - average /= sample_size_plus_1; + average /= samples_plus_1; } //************************************************************************* @@ -167,10 +239,78 @@ namespace etl private: - const T sample_size; ///< The sample size to average over. - const T sample_size_plus_1; ///< One greater than the sample size. + const T samples; ///< The sample size to average over. + const T samples_plus_1; ///< One greater than the sample size. T average; ///< The current cumulative average. }; + + //*************************************************************************** +/// Cumulative Moving Average +/// For floating point types. +/// \tparam T The sample value type. +/// \tparam SAMPLE_SIZE The number of samples to average over. +//*************************************************************************** + template + class cumulative_moving_average + { + public: + + //************************************************************************* + /// Constructor + /// \param initial_value The initial value for the average. + //************************************************************************* + cumulative_moving_average(const T initial_value, const size_t sample_size) + : samples(T(sample_size)), + samples_plus_1(T(sample_size + 1U)), + average(initial_value) + { + } + + //************************************************************************* + /// Clears the average. + /// \param initial_value The initial value for the average. + //************************************************************************* + void clear(const T initial_value) + { + average = initial_value; + } + + //************************************************************************* + /// Sets the sample size. + /// \param sample_size The new sample size. + //************************************************************************* + void set_sample_size(const size_t sample_size) + { + samples = T(sample_size); + samples_plus_1 = samples + T(1); + } + + //************************************************************************* + /// Adds a new sample to the average. + /// \param new_value The value to add. + //************************************************************************* + void add(const T new_value) + { + average *= samples; + average += new_value; + average /= samples_plus_1; + } + + //************************************************************************* + /// Gets the current cumulative average. + /// \return The current average. + //************************************************************************* + T value() const + { + return average; + } + + private: + + T samples; ///< The sample size to average over. + T samples_plus_1; ///< One greater than the sample size. + T average; ///< The current cumulative average. + }; } #endif diff --git a/include/etl/version.h b/include/etl/version.h index 085e524d..92a421e8 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -38,8 +38,8 @@ SOFTWARE. ///\ingroup utilities #define ETL_VERSION_MAJOR 14 -#define ETL_VERSION_MINOR 27 -#define ETL_VERSION_PATCH 1 +#define ETL_VERSION_MINOR 28 +#define ETL_VERSION_PATCH 0 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) ETL_STRINGIFY(ETL_VERSION_MINOR) ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_W ETL_WIDE_STRING(ETL_CONCAT(ETL_CONCAT(ETL_VERSION_MAJOR, ETL_VERSION_MINOR), ETL_VERSION_PATCH)) diff --git a/support/Release notes.txt b/support/Release notes.txt index 8f2cd950..671c522a 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +14.28.0 +Added runtime sample size specialisations to etl::cumulative_moving_average. + =============================================================================== 14.27.1 Removed ETL_IF_CONSTEXPR from etl::message_timer 'tick()' diff --git a/test/test_cumulative_moving_average.cpp b/test/test_cumulative_moving_average.cpp index ac277acc..59261963 100644 --- a/test/test_cumulative_moving_average.cpp +++ b/test/test_cumulative_moving_average.cpp @@ -101,6 +101,75 @@ namespace CHECK_EQUAL(280U, cma.value()); } + //************************************************************************* + TEST(integral_signed_average_positive_runtime_sample_size) + { + typedef etl::cumulative_moving_average CMA; + CMA cma(0, SAMPLE_SIZE * 2U); + + CHECK_EQUAL(0, cma.value()); + + cma.set_sample_size(SAMPLE_SIZE); + + cma.add(9); + cma.add(1); + cma.add(8); + cma.add(2); + cma.add(7); + cma.add(3); + cma.add(6); + cma.add(4); + cma.add(5); + + CHECK_EQUAL(280, cma.value()); + } + + //************************************************************************* + TEST(integral_signed_average_negative_runtime_sample_size) + { + typedef etl::cumulative_moving_average CMA; + CMA cma(0, SAMPLE_SIZE * 2U); + + CHECK_EQUAL(0, cma.value()); + + cma.set_sample_size(SAMPLE_SIZE); + + cma.add(-9); + cma.add(-1); + cma.add(-8); + cma.add(-2); + cma.add(-7); + cma.add(-3); + cma.add(-6); + cma.add(-4); + cma.add(-5); + + CHECK_EQUAL(-280, cma.value()); + } + + //************************************************************************* + TEST(integral_unsigned_average_positive_runtime_sample_size) + { + typedef etl::cumulative_moving_average CMA; + CMA cma(0U, SAMPLE_SIZE * 2U); + + CHECK_EQUAL(0U, cma.value()); + + cma.set_sample_size(SAMPLE_SIZE); + + cma.add(9U); + cma.add(1U); + cma.add(8U); + cma.add(2U); + cma.add(7U); + cma.add(3U); + cma.add(6U); + cma.add(4U); + cma.add(5U); + + CHECK_EQUAL(280U, cma.value()); + } + //************************************************************************* TEST(floating_point_average) { @@ -121,5 +190,28 @@ namespace CHECK_CLOSE(2.82, cma.value(), 0.01); } + + //************************************************************************* + TEST(floating_point_average_runtime_sample_size) + { + typedef etl::cumulative_moving_average CMA; + CMA cma(0, SAMPLE_SIZE * 2); + + CHECK_EQUAL(0.0, cma.value()); + + cma.set_sample_size(SAMPLE_SIZE); + + cma.add(9.0); + cma.add(1.0); + cma.add(8.0); + cma.add(2.0); + cma.add(7.0); + cma.add(3.0); + cma.add(6.0); + cma.add(4.0); + cma.add(5.0); + + CHECK_CLOSE(2.82, cma.value(), 0.01); + } }; }