pub struct LevelEstimator { /* private fields */ }Expand description
Approximate state-of-charge estimator for gauge-less boards: a rest-gated OCV table with a median filter, a discharge-direction clamp, and quantized output.
Feed it every monitor sample via Self::sample. It moves at two
speeds:
- Every quiet sample sets a ceiling. A terminal voltage that is not sagging relaxes downward toward true OCV, so the table can only overstate what is in the pack; the level is capped to that reading immediately. This is what keeps a stale estimate — most visibly the one bootstrapped from a charger’s elevated rail — from surviving long after the pack has been unplugged.
- A rested window of [
LEVEL_WINDOW] samples anchors. Only after [LEVEL_REST_MS] of quiet (no external power, no reported load) does the median become the level outright, and only then is the discharge clamp re-established.
Anchored levels never rise while discharging, so the output is stable and monotone between charge sessions. A charge since the last anchor invalidates the stored level in both directions, so until the next anchor the ceiling replaces it rather than capping it — which is how a partial charge shows up without waiting out a full window.
While charging there is no level at all: charging voltage is not
comparable to the discharge table, so the estimate is withdrawn rather
than frozen at its pre-charge value. It returns on the first quiet
reading after the charger goes away. The one exception is the
Charged classification, which is a charger’s completion signal and
therefore an exact calibration point: it pins the level to 100. Boards
whose charger reports no completion never see that state and simply
report nothing for as long as they are plugged in.