Line data Source code
1 : #ifndef HEADER_fd_src_disco_gui_fd_gui_ema_h 2 : #define HEADER_fd_src_disco_gui_fd_gui_ema_h 3 : 4 : #include "../../util/fd_util_base.h" 5 : 6 : #include <float.h> 7 : #include <math.h> 8 : 9 : struct fd_gui_ema { 10 : double value; /* filtered value */ 11 : double weight; /* used for Adam-style startup debiasing */ 12 : long last_update_nanos; /* last recorded sample timestamp */ 13 : long half_life_nanos; /* Time horizon for the filter */ 14 : }; 15 : 16 : typedef struct fd_gui_ema fd_gui_ema_t; 17 : 18 : static inline void 19 : fd_gui_ema_init( fd_gui_ema_t * ema, 20 : long now_nanos, 21 0 : long half_life_nanos ) { 22 0 : ema->value = 0.0; 23 0 : ema->weight = 0.0; 24 0 : ema->last_update_nanos = now_nanos; 25 0 : ema->half_life_nanos = half_life_nanos; 26 0 : } 27 : 28 : static inline double 29 : fd_gui_ema_advance( fd_gui_ema_t * ema, 30 : long now_nanos, 31 0 : double sample ) { 32 0 : long dt = now_nanos - ema->last_update_nanos; 33 0 : if( FD_UNLIKELY( dt<=0L ) ) return ema->value; 34 : 35 0 : double alpha = 1.0 - exp( -0.69314718055994 * (double)dt / (double)ema->half_life_nanos ); 36 0 : double new_weight = fmax( alpha + (1.0 - alpha) * ema->weight, DBL_EPSILON ); 37 0 : ema->value = (alpha * sample + (1.0 - alpha) * ema->weight * ema->value) / new_weight; 38 0 : ema->weight = new_weight; 39 0 : ema->last_update_nanos = now_nanos; 40 0 : return ema->value; 41 0 : } 42 : 43 : static inline double 44 : fd_gui_ema_value( fd_gui_ema_t const * ema, 45 : long now_nanos, 46 0 : double sample ) { 47 0 : fd_gui_ema_t cpy = *ema; 48 0 : return fd_gui_ema_advance( &cpy, now_nanos, sample ); 49 0 : } 50 : 51 : #endif /* HEADER_fd_src_disco_gui_fd_gui_ema_h */