diff --git a/examples/exponential-moving-average/exponential-moving-average.ino b/examples/exponential-moving-average/exponential-moving-average.ino index 7ffce1f..30ce9e2 100644 --- a/examples/exponential-moving-average/exponential-moving-average.ino +++ b/examples/exponential-moving-average/exponential-moving-average.ino @@ -2,11 +2,11 @@ const uint8_t kInputPin = 0; const uint8_t kLedPin = 13; -ExponentialMovingAverageFilter *input; +ExponentialMovingAverageFilter *input; void setup() { pinMode(kInputPin, INPUT_PULLUP); - input = new ExponentialMovingAverageFilter(filter_functions::ForAnalogRead(), 255); + input = new ExponentialMovingAverageFilter(filter_functions::ForAnalogRead(), 255); input->SetLogToSerial(true); input->SetMinRunInterval(50); diff --git a/src/exponential-moving-average-filter.h b/src/exponential-moving-average-filter.h index b870046..249185f 100644 --- a/src/exponential-moving-average-filter.h +++ b/src/exponential-moving-average-filter.h @@ -3,6 +3,8 @@ #include "filter.h" +#include + // An exponential moving average filter. This uses only integer (32-bit) math. // This supports up to 24-bit inputs. // @@ -13,47 +15,54 @@ // // An alpha of 255 means that the filter returns the current value of the input. // An alpha of 0 means the filtered value changes very slowly. -template -class ExponentialMovingAverageFilter : public Filter { - using Filter::sensor_value_; +template +class ExponentialMovingAverageFilter : public Filter { + using Filter::sensor_value_; public: - ExponentialMovingAverageFilter(uint32_t (*const ReadFromSensor)(), - uint8_t alpha); - ExponentialMovingAverageFilter(uint32_t (*const ReadFromSensor)(), - uint8_t alpha, - OutputType (*Convert)(uint32_t input)); + ExponentialMovingAverageFilter(InputType (*const ReadFromSensor)(), + InputType alpha); + ExponentialMovingAverageFilter(InputType (*const ReadFromSensor)(), + InputType alpha, + OutputType (*Convert)(InputType input)); protected: - uint32_t DoRun() override; + InputType DoRun() override; private: - uint32_t average_ = 0; + InputType average_ = 0; - const uint8_t alpha_; + const InputType alpha_; }; -template -ExponentialMovingAverageFilter::ExponentialMovingAverageFilter( - uint32_t (*const ReadFromSensor)(), uint8_t alpha) - : Filter(ReadFromSensor), alpha_(alpha) {} - -template -ExponentialMovingAverageFilter::ExponentialMovingAverageFilter( - uint32_t (*const ReadFromSensor)(), uint8_t alpha, - OutputType (*Convert)(uint32_t input)) - : Filter(ReadFromSensor, Convert), alpha_(alpha) {} - -template -uint32_t ExponentialMovingAverageFilter::DoRun() { - uint32_t old_average = average_; - average_ = (sensor_value_ * (alpha_ + 1) + (average_ * (255 - alpha_))) / 256; - if (old_average == average_ && sensor_value_ != average_) { - if (sensor_value_ > average_) { - average_++; - } else if (sensor_value_ < average_) { - average_--; +template +ExponentialMovingAverageFilter:: + ExponentialMovingAverageFilter(InputType (*const ReadFromSensor)(), + InputType alpha) + : Filter(ReadFromSensor), alpha_(alpha) {} + +template +ExponentialMovingAverageFilter:: + ExponentialMovingAverageFilter(InputType (*const ReadFromSensor)(), + InputType alpha, + OutputType (*Convert)(InputType input)) + : Filter(ReadFromSensor, Convert), alpha_(alpha) {} + +template +InputType ExponentialMovingAverageFilter::DoRun() { + InputType old_average = average_; + if (std::is_integral::value) { + average_ = + (sensor_value_ * (alpha_ + 1) + (average_ * (255 - alpha_))) / 256; + if (old_average == average_ && sensor_value_ != average_) { + if (sensor_value_ > average_) { + average_++; + } else if (sensor_value_ < average_) { + average_--; + } } + } else { + average_ = (sensor_value_ * (alpha_) + (average_ * (1.0 - alpha_))); } return average_; } diff --git a/test/exponential-moving-average-filter-float-test.cpp b/test/exponential-moving-average-filter-float-test.cpp new file mode 100644 index 0000000..4698165 --- /dev/null +++ b/test/exponential-moving-average-filter-float-test.cpp @@ -0,0 +1,42 @@ +#include "gtest/gtest.h" + +#include +#include "../src/exponential-moving-average-filter.h" +#include "run-data-test.h" + +namespace exponential_moving_average_filter_test { + +TEST(ExponentialMovingAverageFloatFilter, alpha_half) { + ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(floatRead, 0.5); + std::vector> data = { + {0, 10, 0}, + {1.0, 100, 0.4, 1.0}, + {1.0, 100, 1.0}, + {0, 100, 0, 0.6}, + {0, 100, 0, 0.001}, + }; + RunDataTest(filter, data, setFloatRead); +} + +TEST(ExponentialMovingAverageFloatFilter, alpha_full) { + ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(floatRead, 1.0); + std::vector> data = { + {0, 10, 0}, + {10.0, 100, 10.0}, + {0, 100, 0}, + }; + RunDataTest(filter, data, setFloatRead); +} + +TEST(ExponentialMovingAverageFloatFilter, alpha_low) { + ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(floatRead, 0.001); + std::vector> data = { + {0, 10, 0}, + {1.0, 500, 0, 0.5}, + {1.0, 5000, 0, 1.0}, + {1.0, 100, 0.99, 1.0}, + }; + RunDataTest(filter, data, setFloatRead); +} + +} diff --git a/test/exponential-moving-average-filter-test.cpp b/test/exponential-moving-average-filter-test.cpp index fdda68d..2d3eee5 100644 --- a/test/exponential-moving-average-filter-test.cpp +++ b/test/exponential-moving-average-filter-test.cpp @@ -7,7 +7,7 @@ namespace exponential_moving_average_filter_test { TEST(ExponentialMovingAverageFilter, alpha_half) { - ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 128); + ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 128); std::vector> data = { {0, 10, 0}, {1024, 100, 4, 1024}, @@ -19,7 +19,7 @@ TEST(ExponentialMovingAverageFilter, alpha_half) { } TEST(ExponentialMovingAverageFilter, alpha_full) { - ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 255); + ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 255); std::vector> data = { {0, 10, 0}, {1024, 100, 1024}, @@ -29,7 +29,7 @@ TEST(ExponentialMovingAverageFilter, alpha_full) { } TEST(ExponentialMovingAverageFilter, alpha_low) { - ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 0); + ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 0); std::vector> data = { {0, 10, 0}, {1024, 10, 4, 50}, @@ -43,7 +43,7 @@ TEST(ExponentialMovingAverageFilter, alpha_low) { } TEST(ExponentialMovingAverageFilter, impulse) { - ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 127); + ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 127); std::vector> data = { {0, 10, 0}, {1024, 1, 512}, @@ -77,7 +77,7 @@ float analogInToVoltage(uint32_t analogIn) { } TEST(ExponentialMovingAverageFilter, convert) { - ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 127, analogInToVoltage); + ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 127, analogInToVoltage); std::vector> data = { {0, 10, 0.0}, {1023, 100, 0.0, 3.3}, @@ -90,7 +90,7 @@ TEST(ExponentialMovingAverageFilter, filter_range) { // Tests that the filter supports 24-bit filters without overflow. // Note: 2 ^ 24 = 16777216 - ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 127); + ExponentialMovingAverageFilter *filter = new ExponentialMovingAverageFilter(analogRead, 127); std::vector> data = { {16777215, 500, 0, 16777215}, {16777215, 100, 16777215}, diff --git a/test/filter-test.cpp b/test/filter-test.cpp index b948e77..13078f6 100644 --- a/test/filter-test.cpp +++ b/test/filter-test.cpp @@ -8,7 +8,7 @@ namespace filter_test { TEST(Filter, SetMinRunInterval_default) { // Filter that returns the sensor value immediately - ExponentialMovingAverageFilter *input = new ExponentialMovingAverageFilter(analogRead, 255); + ExponentialMovingAverageFilter *input = new ExponentialMovingAverageFilter(analogRead, 255); std::vector> data = { {1, 1, 1}, {2, 1, 2}, @@ -21,7 +21,7 @@ TEST(Filter, SetMinRunInterval_default) { TEST(Filter, SetMinRunInterval_10) { // Filter that returns the sensor value immediately - ExponentialMovingAverageFilter *input = new ExponentialMovingAverageFilter(analogRead, 255); + ExponentialMovingAverageFilter *input = new ExponentialMovingAverageFilter(analogRead, 255); input->SetMinRunInterval(10); std::vector> data = { {1, 1, 1}, @@ -36,7 +36,7 @@ TEST(Filter, SetMinRunInterval_10) { } TEST(Filter, SetMinRunInterval_updates) { - ExponentialMovingAverageFilter *input = new ExponentialMovingAverageFilter(analogRead, 255); + ExponentialMovingAverageFilter *input = new ExponentialMovingAverageFilter(analogRead, 255); input->SetMinRunInterval(10); input->SetMillis(0); analogReadValue = 1;