From bf37ac53a3dd5c666027932027502c72e69b6996 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 4 Nov 2024 08:10:05 +0100 Subject: [PATCH] improved FPS calc resolution, added averaging & multiplier compileflags Fixed point calculation for improved accuracy, dithering in debug builds only. Averaging and optional multiplier can be set as compile flags, example for speed testing with long averaging and a 10x multiplier: -D FPS_CALC_AVG=200 -D FPS_MULTIPLIER=10 The calculation resolution is limited (9.7bit fixed point) so values larger than 200 can hit resolution limit and get stuck before reaching the final value. If WLED_DEBUG is defined, dithering is added to the returned value so sub-frame accuracy is possible in post-processingwithout enabling the multiplier. --- wled00/FX.h | 10 +++++++++- wled00/FX_fcn.cpp | 16 +++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index ad39a7c06..1579a5bcb 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -47,6 +47,14 @@ #define FRAMETIME_FIXED (1000/WLED_FPS) #define FRAMETIME strip.getFrameTime() +// FPS calculation (can be defined as compile flag for debugging) +#ifndef FPS_CALC_AVG +#define FPS_CALC_AVG 7 // average FPS calculation over this many frames (moving average) +#endif +#ifndef FPS_MULTIPLIER +#define FPS_MULTIPLIER 1 // dev option: multiplier to get sub-frame FPS without floats +#endif + /* each segment uses 82 bytes of SRAM memory, so if you're application fails because of insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ #ifdef ESP8266 @@ -729,7 +737,7 @@ class WS2812FX { // 96 bytes _transitionDur(750), _targetFps(WLED_FPS), _frametime(FRAMETIME_FIXED), - _cumulativeFps(2), + _cumulativeFps(50<<6), _isServicing(false), _isOffRefreshRequired(false), _hasWhiteChannel(false), diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index f45256f0f..395451466 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1412,10 +1412,12 @@ void WS2812FX::show() { unsigned long showNow = millis(); size_t diff = showNow - _lastShow; - size_t fpsCurr = 200; - if (diff > 0) fpsCurr = 1000 / diff; - _cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2; // "+2" for proper rounding (2/4 = 0.5) - _lastShow = showNow; + + if (diff > 0) { // skip calculation if no time has passed + size_t fpsCurr = (1000<<7) / diff; // fixed point 9.7 bit + _cumulativeFps = (FPS_CALC_AVG * _cumulativeFps + fpsCurr + FPS_CALC_AVG / 2) / (FPS_CALC_AVG + 1); // "+FPS_CALC_AVG/2" for proper rounding + _lastShow = showNow; + } } /** @@ -1432,7 +1434,11 @@ bool WS2812FX::isUpdating() const { */ uint16_t WS2812FX::getFps() const { if (millis() - _lastShow > 2000) return 0; - return _cumulativeFps +1; + #ifdef WLED_DEBUG + return (FPS_MULTIPLIER * (_cumulativeFps + (random16() & 63))) >> 7; // + random("0.5") for dithering + #else + return (FPS_MULTIPLIER * _cumulativeFps) >> 7; // _cumulativeFps is stored in fixed point 9.7 bit + #endif } void WS2812FX::setTargetFps(uint8_t fps) {