Control Surface stm32
MIDI Control Surface library for Arduino
FilteredAnalog.hpp
Go to the documentation of this file.
1#pragma once
2
4AH_DIAGNOSTIC_WERROR() // Enable errors on warnings
5
6#include <AH/Filters/EMA.hpp>
11#include <AH/Math/MinMaxFix.hpp>
12#include <AH/STL/type_traits> // std::enable_if, std::is_constructible
13#include <AH/STL/utility> // std::forward
15
17
22template <uint8_t FilterShiftFactor, class FilterType, class AnalogType>
24 constexpr static uint8_t value =
25 min(sizeof(FilterType) * CHAR_BIT - ADC_BITS - FilterShiftFactor,
26 sizeof(AnalogType) * CHAR_BIT - ADC_BITS);
27};
28
34template <class MappingFunction, uint8_t Precision = 10,
35 uint8_t FilterShiftFactor = ANALOG_FILTER_SHIFT_FACTOR,
36 class FilterType = ANALOG_FILTER_TYPE, class AnalogType = analog_t,
37 uint8_t IncRes = MaximumFilteredAnalogIncRes<
38 FilterShiftFactor, FilterType, AnalogType>::value>
40 public:
52 AnalogType initial = 0)
53 : analogPin(analogPin), mapFn(std::forward<MappingFunction>(mapFn)),
54 filter(increaseBitDepth<ADC_BITS + IncRes, Precision, AnalogType,
55 AnalogType>(initial)) {}
56
66 void reset(AnalogType value = 0) {
67 AnalogType widevalue = increaseBitDepth<ADC_BITS + IncRes, Precision,
68 AnalogType, AnalogType>(value);
69 filter.reset(widevalue);
70 hysteresis.setValue(widevalue);
71 }
72
80 AnalogType widevalue = getRawValue();
81 filter.reset(widevalue);
82 hysteresis.setValue(widevalue);
83 }
84
101 void map(MappingFunction fn) { mapFn = std::forward<MappingFunction>(fn); }
102
110 const MappingFunction &getMappingFunction() const { return mapFn; }
111
121 bool update() {
122 AnalogType input = getRawValue(); // read the raw analog input value
123 input = filter.filter(input); // apply a low-pass EMA filter
124 input = mapFnHelper(input); // apply the mapping function
125 return hysteresis.update(input); // apply hysteresis, and return true
126 // if the value changed since last time
127 }
128
139 AnalogType getValue() const { return hysteresis.getValue(); }
140
148 float getFloatValue() const {
149 return getValue() * (1.0f / (ldexpf(1.0f, Precision) - 1.0f));
150 }
151
156 AnalogType getRawValue() const {
157 AnalogType value = ExtIO::analogRead(analogPin);
158#ifdef ESP8266
159 if (value > 1023)
160 value = 1023;
161#endif
162 return increaseBitDepth<ADC_BITS + IncRes, ADC_BITS, AnalogType>(value);
163 }
164
168 constexpr static AnalogType getMaxRawValue() {
169 return (1ul << (ADC_BITS + IncRes)) - 1ul;
170 }
171
179 static void setupADC() {
180#if HAS_ANALOG_READ_RESOLUTION
181 analogReadResolution(ADC_BITS);
182#endif
183 }
184
185 private:
189 template <typename M = MappingFunction>
190 typename std::enable_if<std::is_constructible<bool, M>::value,
191 AnalogType>::type
192 mapFnHelper(AnalogType input) {
193 return bool(mapFn) ? mapFn(input) : input;
194 }
195
200 template <typename M = MappingFunction>
201 typename std::enable_if<!std::is_constructible<bool, M>::value,
202 AnalogType>::type
203 mapFnHelper(AnalogType input) {
204 return mapFn(input);
205 }
206
207 private:
210
212
213 static_assert(
214 ADC_BITS + IncRes + FilterShiftFactor <= sizeof(FilterType) * CHAR_BIT,
215 "Error: FilterType is not wide enough to hold the maximum value");
216 static_assert(
217 ADC_BITS + IncRes <= sizeof(AnalogType) * CHAR_BIT,
218 "Error: AnalogType is not wide enough to hold the maximum value");
219 static_assert(
220 Precision <= ADC_BITS + IncRes,
221 "Error: Precision is larger than the increased ADC precision");
222 static_assert(EMA_t::supports_range(AnalogType(0), getMaxRawValue()),
223 "Error: EMA filter type doesn't support full ADC range");
224
226 Hysteresis<ADC_BITS + IncRes - Precision, AnalogType, AnalogType>
228};
229
263template <uint8_t Precision = 10,
264 uint8_t FilterShiftFactor = ANALOG_FILTER_SHIFT_FACTOR,
265 class FilterType = ANALOG_FILTER_TYPE, class AnalogType = analog_t,
266 uint8_t IncRes = MaximumFilteredAnalogIncRes<
267 FilterShiftFactor, FilterType, AnalogType>::value>
269 : public GenericFilteredAnalog<AnalogType (*)(AnalogType), Precision,
270 FilterShiftFactor, FilterType, AnalogType,
271 IncRes> {
272 public:
281 FilteredAnalog(pin_t analogPin, AnalogType initial = 0)
282 : GenericFilteredAnalog<AnalogType (*)(AnalogType), Precision,
283 FilterShiftFactor, FilterType, AnalogType,
284 IncRes>(analogPin, nullptr, initial) {}
285
295
298 using MappingFunction = AnalogType (*)(AnalogType);
299
307 void invert() {
308 constexpr AnalogType maxval = FilteredAnalog::getMaxRawValue();
309 this->map([](AnalogType val) -> AnalogType { return maxval - val; });
310 }
311};
312
314
#define END_AH_NAMESPACE
#define BEGIN_AH_NAMESPACE
analog_t(*)(analog_t) MappingFunction
Definition: Def.hpp:21
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:37
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:36
A class that reads and filters an analog input.
FilteredAnalog(pin_t analogPin, AnalogType initial=0)
Construct a new FilteredAnalog object.
FilteredAnalog()
Construct a new FilteredAnalog object.
void invert()
Invert the analog value.
AnalogType(*)(AnalogType) MappingFunction
A function pointer to a mapping function to map analog values.
FilteredAnalog base class with generic MappingFunction.
GenericFilteredAnalog(pin_t analogPin, MappingFunction mapFn, AnalogType initial=0)
Construct a new GenericFilteredAnalog object.
void resetToCurrentValue()
Reset the filtered value to the value that's currently being measured at the analog input.
static void setupADC()
Select the configured ADC resolution.
std::enable_if<!std::is_constructible< bool, M >::value, AnalogType >::type mapFnHelper(AnalogType input)
Helper function that applies the mapping function without checking if it's enabled.
void map(MappingFunction fn)
Specify a mapping function/functor that is applied to the analog value after filtering and before app...
AnalogType getRawValue() const
Read the raw value of the analog input without any filtering or mapping applied, but with its bit dep...
void reset(AnalogType value=0)
Reset the filter to the given value.
std::enable_if< std::is_constructible< bool, M >::value, AnalogType >::type mapFnHelper(AnalogType input)
Helper function that applies the mapping function if it's enabled.
AnalogType getValue() const
Get the filtered value of the analog input (with the mapping function applied).
float getFloatValue() const
Get the filtered value of the analog input with the mapping function applied as a floating point numb...
bool update()
Read the analog input value, apply the mapping function, and update the average.
MappingFunction & getMappingFunction()
Get a reference to the mapping function.
Hysteresis< ADC_BITS+IncRes - Precision, AnalogType, AnalogType > hysteresis
const MappingFunction & getMappingFunction() const
Get a reference to the mapping function.
static constexpr AnalogType getMaxRawValue()
Get the maximum value that can be returned from getRawValue.
Exponential moving average filter.
Definition: EMA.hpp:58
A class for applying hysteresis to a given input.
Definition: Hysteresis.hpp:36
analog_t analogRead(pin_t pin)
An ExtIO version of the Arduino function.
constexpr auto min(const T &a, const U &b) -> decltype(b< a ? b :a)
Return the smaller of two numbers/objects.
Definition: MinMaxFix.hpp:15
T_out increaseBitDepth(T_in in)
Increase the bit depth of the given value from Bits_in bits wide to Bits_out bits wide,...
uint16_t analog_t
The type returned from analogRead and similar functions.
constexpr pin_t NO_PIN
A special pin number that indicates an unused or invalid pin.
constexpr uint8_t ANALOG_FILTER_SHIFT_FACTOR
The factor for the analog filter: Difference equation: where .
constexpr uint8_t ADC_BITS
The bit depth to use for the ADC (Analog to Digital Converter).
uint16_t ANALOG_FILTER_TYPE
The unsigned integer type to use for analog inputs during filtering.
uint16_t pin_t
The type for Arduino pins (and ExtendedIOElement pins).
Helper to determine how many of the remaining bits of the filter data types can be used to achieve hi...