Control Surface  1.1.0
MIDI Control Surface library for Arduino
Hysteresis.hpp
Go to the documentation of this file.
1 #pragma once
2 
4 AH_DIAGNOSTIC_WERROR() // Enable errors on warnings
5 
6 #include <stdint.h>
7 
8 /// @addtogroup AH_Filters
9 /// @{
10 
11 /**
12  * @brief A class for applying hysteresis to a given input.
13  *
14  * This reduces the noise by decreasing the resolution, and it prevents flipping
15  * back and forth between two values.
16  *
17  * <b>An example for `BITS` = 7 and an input from 0 to 1023</b>
18  * ```
19  * 7 ┌───◄───┬───
20  * o 6 ┌───◄───┼───►───┘
21  * u 5 ┌───◄───┼───►───┘
22  * t 4 ┌───◄───┼───►───┘
23  * p 3 ┌───◄───┼───►───┘
24  * u 2 ┌───◄───┼───►───┘
25  * t 1 ┌───◄───┼───►───┘
26  * 0 ────┴───►───┘
27  * 0 128 256 384 512 640 768 896 1023
28  * i n p u t
29  * ```
30  *
31  * @tparam BITS
32  * The number of bits to decrease in resolution.
33  * Increasing this number will result in a decrease in fluctuations.
34  */
35 template <uint8_t BITS, class T_in = uint16_t, class T_out = uint8_t>
36 class Hysteresis {
37  public:
38  /**
39  * @brief Update the hysteresis output with a new input value.
40  *
41  * @param inputLevel
42  * The input to calculate the output level from.
43  * @retval true
44  * The output level has changed.
45  * @retval false
46  * The output level is still the same.
47  */
48  bool update(T_in inputLevel) {
49  T_in prevLevelFull = (T_in(prevLevel) << BITS) | offset;
50  T_in lowerbound = prevLevel > 0 ? prevLevelFull - margin : 0;
51  T_in upperbound = prevLevel < max_out ? prevLevelFull + margin : max_in;
52  if (inputLevel < lowerbound || inputLevel > upperbound) {
53  prevLevel = inputLevel >> BITS;
54  return true;
55  }
56  return false;
57  }
58 
59  /**
60  * @brief Get the current output level.
61  *
62  * @return The output level.
63  */
64  T_out getValue() const { return prevLevel; }
65 
66  private:
67  T_out prevLevel = 0;
68  constexpr static T_in margin = (1UL << BITS) - 1;
69  constexpr static T_in offset = 1UL << (BITS - 1);
70  constexpr static T_in max_in = -1;
71  constexpr static T_out max_out = static_cast<T_out>(max_in >> BITS);
72  static_assert(max_in > 0, "Error: only unsigned types are supported");
73 };
74 
75 /// @}
76 
Warnings.hpp
AH_DIAGNOSTIC_POP
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:17
Hysteresis::margin
constexpr static T_in margin
Definition: Hysteresis.hpp:68
Hysteresis::offset
constexpr static T_in offset
Definition: Hysteresis.hpp:69
Hysteresis
A class for applying hysteresis to a given input.
Definition: Hysteresis.hpp:36
Hysteresis::max_out
constexpr static T_out max_out
Definition: Hysteresis.hpp:71
Hysteresis::max_in
constexpr static T_in max_in
Definition: Hysteresis.hpp:70
Hysteresis::update
bool update(T_in inputLevel)
Update the hysteresis output with a new input value.
Definition: Hysteresis.hpp:48
AH_DIAGNOSTIC_WERROR
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:16
Hysteresis::getValue
T_out getValue() const
Get the current output level.
Definition: Hysteresis.hpp:64
Hysteresis::prevLevel
T_out prevLevel
Definition: Hysteresis.hpp:67