LCOV - code coverage report
Current view: top level - src/AH/Filters - Hysteresis.hpp (source / functions) Hit Total Coverage
Test: 00f463b534fbea22f0b596e091a60715679e3064 Lines: 15 15 100.0 %
Date: 2024-11-03 16:33:35 Functions: 13 13 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <AH/Settings/NamespaceSettings.hpp>
       4             : 
       5             : #include <stdint.h>
       6             : 
       7             : BEGIN_AH_NAMESPACE
       8             : 
       9             : /// @addtogroup    AH_Filters
      10             : /// @{
      11             : 
      12             : /**
      13             :  * @brief   A class for applying hysteresis to a given input.
      14             :  *
      15             :  * This reduces the noise by decreasing the resolution, and it prevents flipping
      16             :  * back and forth between two values.
      17             :  *
      18             :  * <b>An example for `BITS` = 7 and an input from 0 to 1023</b>
      19             :  * ```
      20             :  *    7                                                     ┌───◄───┬───
      21             :  * o  6                                             ┌───◄───┼───►───┘
      22             :  * u  5                                     ┌───◄───┼───►───┘
      23             :  * t  4                             ┌───◄───┼───►───┘
      24             :  * p  3                     ┌───◄───┼───►───┘
      25             :  * u  2             ┌───◄───┼───►───┘
      26             :  * t  1     ┌───◄───┼───►───┘
      27             :  *    0 ────┴───►───┘
      28             :  *      0      128     256     384     512     640     768     896    1023
      29             :  *                                  i n p u t
      30             :  * ```
      31             :  *
      32             :  * @tparam  BITS
      33             :  *          The number of bits to decrease in resolution.
      34             :  *          Increasing this number will result in a decrease in fluctuations.
      35             :  */
      36             : template <uint8_t Bits, class T_in = uint16_t, class T_out = uint8_t>
      37             : class Hysteresis {
      38             :   public:
      39             :     /**
      40             :      * @brief   Update the hysteresis output with a new input value.
      41             :      *
      42             :      * @param   inputLevel
      43             :      *          The input to calculate the output level from.
      44             :      * @retval  true
      45             :      *          The output level has changed.
      46             :      * @retval  false
      47             :      *          The output level is still the same.
      48             :      */
      49         100 :     bool update(T_in inputLevel) {
      50         100 :         T_in prevLevelFull = (T_in(prevLevel) << Bits) | offset;
      51         100 :         T_in lowerbound = prevLevel > 0 ? prevLevelFull - margin : 0;
      52         100 :         T_in upperbound = prevLevel < max_out ? prevLevelFull + margin : max_in;
      53         100 :         if (inputLevel < lowerbound || inputLevel > upperbound) {
      54          34 :             setValue(inputLevel);
      55          34 :             return true;
      56             :         }
      57          66 :         return false;
      58             :     }
      59             : 
      60             :     /**
      61             :      * @brief   Get the current output level.
      62             :      *
      63             :      * @return  The output level.
      64             :      */
      65         123 :     T_out getValue() const { return prevLevel; }
      66             : 
      67             :     /** 
      68             :      * @brief   Forcefully update the internal state to the given level.
      69             :      */
      70          36 :     void setValue(T_in inputLevel) { prevLevel = inputLevel >> Bits; }
      71             : 
      72             :   private:
      73             :     T_out prevLevel = 0;
      74             :     constexpr static T_in margin = (1ul << Bits) - 1ul;
      75             :     constexpr static T_in offset = Bits >= 1 ? 1ul << (Bits - 1) : 0;
      76             :     constexpr static T_in max_in = static_cast<T_in>(-1);
      77             :     constexpr static T_out max_out = static_cast<T_out>(max_in >> Bits);
      78             :     static_assert(max_in > 0, "Error: only unsigned types are supported");
      79             : };
      80             : 
      81             : template <class T_in, class T_out>
      82             : class Hysteresis<0, T_in, T_out> {
      83             :   public:
      84          10 :     bool update(T_in inputLevel) {
      85          10 :         bool changed = inputLevel != prevLevel;
      86          10 :         prevLevel = inputLevel;
      87          10 :         return changed;
      88             :     }
      89             : 
      90          10 :     T_out getValue() const { return prevLevel; }
      91             :     void setValue(T_in inputLevel) const { prevLevel = inputLevel; }
      92             : 
      93             :   private:
      94             :     T_in prevLevel = 0;
      95             : };
      96             : 
      97             : /// @}
      98             : 
      99             : END_AH_NAMESPACE

Generated by: LCOV version 1.15