ESP-LiveControl  1.99.1
HTTP server, AJAX API backend and Vue.js web application implementing self-contained, zero-install WiFi remote control of hardware modules attached to the Espressif ESP32 SoC
adc_filter_interpolation.hpp
1 
7 #ifndef ADC_FILTER_HPP__
8 #define ADC_FILTER_HPP__
9 
10 #include <array>
11 #include "esp_log.h"
12 
13 
21 template <size_t N>
23 {
24 public:
25  // Checks N is power of two and size limit is due to uint32_t result_sum
26  static_assert(N <= 1<<16 && (N & (N-1)) == 0);
27 
29  {
30  initialize(0);
31  }
32  MovingAverageUInt16(uint16_t init_value)
33  {
34  initialize(init_value);
35  }
36 
46  void initialize(uint16_t init_value) {
47  input_buffer.fill(init_value);
48  result_sum = N * init_value;
49  }
50 
55  void input_data(uint16_t value_in) {
56  auto value_out = input_buffer[current_index];
57  input_buffer[current_index] = value_in;
58  current_index = (current_index + 1) % N;
59  result_sum = result_sum + value_in - value_out;
60  }
61 
66  uint16_t get_result() {
67  return result_sum / N;
68  }
69 
70 protected:
71  size_t current_index = 0;
72  std::array<uint16_t, N> input_buffer;
73  uint32_t result_sum;
74 };
75 
76 
86 template<size_t N>
88 {
89 public:
90  EquidistantPWLInt32(const std::array<float, N> &lut,
91  int32_t in_fsr_bot = 0,
92  int32_t in_fsr_top = 1)
93  : _lut{lut}
94  {
95  set_input_full_scale_range(in_fsr_bot, in_fsr_top);
96  }
97 
98  void set_input_full_scale_range(int32_t in_fsr_bot, int32_t in_fsr_top) {
99  assert(in_fsr_top > in_fsr_bot);
100  _in_fsr_bot = in_fsr_bot;
101  _in_fsr_top = in_fsr_top;
102  _in_fsr_inv = 1.0f / (in_fsr_top - in_fsr_bot);
103  }
104 
105  float interpolate(int32_t x) {
106  static_assert(1 < N && N < INT32_MAX, "Filter length must be in this range");
107  constexpr auto n_lut_intervals = size_t{N - 1};
108  size_t lut_index;
109  float partial_intervals;
110  if (x > _in_fsr_bot) {
111  if (x < _in_fsr_top) {
112  auto n = static_cast<int64_t>(n_lut_intervals) * (x - _in_fsr_bot);
113  auto d = _in_fsr_top - _in_fsr_bot;
114  auto quot_rem = lldiv(n, d);
115  partial_intervals = _in_fsr_inv * static_cast<float>(quot_rem.rem);
116  lut_index = static_cast<size_t>(quot_rem.quot);
117  } else {
118  lut_index = n_lut_intervals;
119  partial_intervals = 0.0f;
120  }
121  } else {
122  lut_index = 0;
123  partial_intervals = 0.0f;
124  }
125  // Interpolation interval start and end values
126  auto interval_start = _lut[lut_index];
127  float interval_end;
128  if (lut_index < n_lut_intervals) {
129  interval_end = _lut[lut_index + 1];
130  } else {
131  interval_end = interval_start;
132  }
133  return interval_start + partial_intervals * (interval_end - interval_start);
134  }
135 
136 protected:
137  const std::array<float, N> _lut;
138  int32_t _in_fsr_bot;
139  int32_t _in_fsr_top;
140  float _in_fsr_inv;
141 };
142 
143 
153 template<size_t N>
155 {
156 public:
157  EquidistantPWLUInt16(const std::array<float, N> &lut,
158  uint16_t in_fsr_bot = 0,
159  uint16_t in_fsr_top = 1)
160  : _lut{lut}
161  {
162  set_input_full_scale_range(in_fsr_bot, in_fsr_top);
163  }
164 
165  void set_input_full_scale_range(uint16_t in_fsr_bot, uint16_t in_fsr_top) {
166  assert(in_fsr_top > in_fsr_bot);
167  // 32-bit is native and fast int, also avoid unsigned int promotion
168  _in_fsr_bot = in_fsr_bot;
169  _in_fsr_top = in_fsr_top;
170  _in_fsr_inv = 1.0f / (in_fsr_top - in_fsr_bot);
171  }
172 
173  float interpolate(uint16_t x) {
174  static_assert(1 < N && N < INT16_MAX, "Filter length must be in this range");
175  constexpr auto n_lut_intervals = size_t{N - 1};
176  size_t lut_index;
177  float partial_intervals;
178  if (x > _in_fsr_bot) {
179  if (x < _in_fsr_top) {
180  auto n = static_cast<int32_t>(n_lut_intervals) * (x - _in_fsr_bot);
181  auto d = _in_fsr_top - _in_fsr_bot;
182  auto quot_rem = div(n, d);
183  partial_intervals = _in_fsr_inv * static_cast<float>(quot_rem.rem);
184  lut_index = static_cast<size_t>(quot_rem.quot);
185  } else {
186  lut_index = n_lut_intervals;
187  partial_intervals = 0.0f;
188  }
189  } else {
190  lut_index = 0;
191  partial_intervals = 0.0f;
192  }
193  // Interpolation interval start and end values
194  auto interval_start = _lut[lut_index];
195  float interval_end;
196  if (lut_index < n_lut_intervals) {
197  interval_end = _lut[lut_index + 1];
198  } else {
199  interval_end = interval_start;
200  }
201  return interval_start + partial_intervals * (interval_end - interval_start);
202  }
203 
204 protected:
205  const std::array<float, N> _lut;
206  uint16_t _in_fsr_bot;
207  uint16_t _in_fsr_top;
208  float _in_fsr_inv;
209 };
210 
211 
221 template<size_t N>
223 {
224 public:
225  EquidistantPWLUInt32(const std::array<float, N> &lut,
226  uint32_t in_fsr_bot = 0,
227  uint32_t in_fsr_top = 1)
228  : _lut{lut}
229  {
230  set_input_full_scale_range(in_fsr_bot, in_fsr_top);
231  }
232 
233  void set_input_full_scale_range(uint32_t in_fsr_bot, uint32_t in_fsr_top) {
234  assert(in_fsr_top > in_fsr_bot);
235  // 32-bit is native and fast int, also avoid unsigned int promotion
236  _in_fsr_bot = in_fsr_bot;
237  _in_fsr_top = in_fsr_top;
238  _in_fsr_inv = 1.0f / (in_fsr_top - in_fsr_bot);
239  }
240 
241  float interpolate(uint32_t x) {
242  static_assert(1 < N && N < INT32_MAX, "Filter length must be in this range");
243  constexpr auto n_lut_intervals = size_t{N - 1};
244  size_t lut_index;
245  float partial_intervals;
246  if (x > _in_fsr_bot) {
247  if (x < _in_fsr_top) {
248  auto n = static_cast<int64_t>(n_lut_intervals) * (x - _in_fsr_bot);
249  auto d = _in_fsr_top - _in_fsr_bot;
250  auto quot_rem = lldiv(n, d);
251  partial_intervals = _in_fsr_inv * static_cast<float>(quot_rem.rem);
252  lut_index = static_cast<size_t>(quot_rem.quot);
253  } else {
254  lut_index = n_lut_intervals;
255  partial_intervals = 0.0f;
256  }
257  } else {
258  lut_index = 0;
259  partial_intervals = 0.0f;
260  }
261  // Interpolation interval start and end values
262  auto interval_start = _lut[lut_index];
263  float interval_end;
264  if (lut_index < n_lut_intervals) {
265  interval_end = _lut[lut_index + 1];
266  } else {
267  interval_end = interval_start;
268  }
269  return interval_start + partial_intervals * (interval_end - interval_start);
270  }
271 
272 protected:
273  const std::array<float, N> _lut;
274  uint32_t _in_fsr_bot;
275  uint32_t _in_fsr_top;
276  float _in_fsr_inv;
277 };
278 
279 
280 #endif
Piecewise linear interpolation of look-up-table (LUT) values.
Definition: adc_filter_interpolation.hpp:88
Piecewise linear interpolation of look-up-table (LUT) values.
Definition: adc_filter_interpolation.hpp:155
Piecewise linear interpolation of look-up-table (LUT) values.
Definition: adc_filter_interpolation.hpp:223
Does a recursive moving average over N values.
Definition: adc_filter_interpolation.hpp:23
void input_data(uint16_t value_in)
Read in a new datum and update the filter.
Definition: adc_filter_interpolation.hpp:55
uint16_t get_result()
Get filter output value.
Definition: adc_filter_interpolation.hpp:66
void initialize(uint16_t init_value)
Initializes the moving average filter with a start value.
Definition: adc_filter_interpolation.hpp:46