FastLED 3.9.15
Loading...
Searching...
No Matches
hampel_filter_impl.h
Go to the documentation of this file.
1#pragma once
2
4#include "fl/log/log.h"
5#include "fl/stl/algorithm.h"
6#include "fl/stl/span.h"
9
10namespace fl {
11namespace detail {
12
13template <typename T, fl::size N = 0>
15 FL_STATIC_ASSERT(N == 0 || (N % 2 == 1),
16 "HampelFilter: N must be odd for an unambiguous median");
17 public:
18 explicit HampelFilterImpl(T threshold = T(3.0f))
19 : mSortedCount(0), mThreshold(threshold), mLastValue(T(0)) {}
20 explicit HampelFilterImpl(fl::size capacity, T threshold = T(3.0f))
22 mSortedCount(0), mThreshold(threshold), mLastValue(T(0)) {
23 if (capacity % 2 == 0) {
24 FL_ERROR("HampelFilter: capacity should be odd, adding 1");
27 }
28 }
29
31 if (values.size() == 0) return mLastValue;
33 for (fl::size i = 0; i < values.size(); ++i) {
34 result = update(values[i]);
35 }
36 return result;
37 }
38
39 T update(T input) {
40 T output = input;
41
42 if (mSortedCount > 0) {
43 T median = mSorted[mSortedCount / 2];
44 T mad_sum = T(0);
45 for (fl::size i = 0; i < mSortedCount; ++i) {
46 mad_sum = mad_sum + fl::abs(mSorted[i] - median);
47 }
48 T mad = div_by_count(mad_sum, mSortedCount);
49 T deviation = fl::abs(input - median);
50 if (mad == T(0)) {
51 if (!(deviation == T(0))) {
52 output = median;
53 }
54 } else if (deviation > mThreshold * mad) {
55 output = median;
56 }
57 }
58
59 if (!mRing.full()) {
60 T* base = &mSorted[0];
61 T* pos = fl::lower_bound(base, base + mSortedCount, input);
62 fl::size idx = static_cast<fl::size>(pos - base);
63 for (fl::size i = mSortedCount; i > idx; --i) {
64 mSorted[i] = mSorted[i - 1];
65 }
66 mSorted[idx] = input;
68 } else {
69 T oldest = mRing.front();
70 T* base = &mSorted[0];
71 T* rm_pos = fl::lower_bound(base, base + mSortedCount, oldest);
72 fl::size rm = static_cast<fl::size>(rm_pos - base);
73 for (fl::size i = rm; i + 1 < mSortedCount; ++i) {
74 mSorted[i] = mSorted[i + 1];
75 }
76 T* ins_pos = fl::lower_bound(base, base + mSortedCount - 1, input);
77 fl::size idx = static_cast<fl::size>(ins_pos - base);
78 for (fl::size i = mSortedCount - 1; i > idx; --i) {
79 mSorted[i] = mSorted[i - 1];
80 }
81 mSorted[idx] = input;
82 }
83 mRing.push_back(input);
84
85 mLastValue = output;
86 return mLastValue;
87 }
88
89 T value() const { return mLastValue; }
90
91 void reset() {
92 mRing.clear();
93 mSortedCount = 0;
94 mLastValue = T(0);
95 }
96
97 fl::size size() const { return mRing.size(); }
98 fl::size capacity() const { return mRing.capacity(); }
99
100 void resize(fl::size new_capacity) {
101 if (new_capacity % 2 == 0) {
102 FL_ERROR("HampelFilter: capacity should be odd, adding 1");
103 new_capacity += 1;
104 }
105 mRing = circular_buffer<T, N>(new_capacity);
106 mSorted = circular_buffer<T, N>(new_capacity);
107 mSortedCount = 0;
108 mLastValue = T(0);
109 }
110
111 private:
114 fl::size mSortedCount;
117};
118
119} // namespace detail
120} // namespace fl
uint8_t pos
Definition Blur.ino:11
circular_buffer< T, N > mSorted
FL_STATIC_ASSERT(N==0||(N % 2==1), "HampelFilter: N must be odd for an unambiguous median")
T update(fl::span< const T > values)
void resize(fl::size new_capacity)
circular_buffer< T, N > mRing
HampelFilterImpl(T threshold=T(3.0f))
HampelFilterImpl(fl::size capacity, T threshold=T(3.0f))
constexpr fl::size size() const FL_NOEXCEPT
Definition span.h:458
#define FL_ERROR(X)
Definition log.h:219
Centralized logging categories for FastLED hardware interfaces and subsystems.
fl::enable_if< fl::is_floating_point< T >::value, T >::type div_by_count(T sum, fl::size count)
Compile-time linker keep-alive hook for a single fl::Bus.
Definition bus_traits.h:48
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
Iterator lower_bound(Iterator first, Iterator last, const T &value, Compare comp) FL_NOEXCEPT
Definition algorithm.h:551
constexpr enable_if< is_fixed_point< T >::value, T >::type abs(T x) FL_NOEXCEPT
Base definition for an LED controller.
Definition crgb.hpp:179
Portable compile-time assertion wrapper.