Battery %: use LiPo discharge curve with variable shutdown threshold

Replace linear voltage-to-percent formula with a LiPo discharge curve
lookup table and linear interpolation. The curve is then rescaled so
that low_batt_mv (configurable shutdown threshold) maps to 0% and
4200mV maps to 100%, preserving the non-linear shape regardless of
the chosen threshold.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-05-10 19:47:12 +02:00
parent 03085f0715
commit 35b2b008c8

View File

@@ -558,13 +558,34 @@ class HomeScreen : public UIScreen {
#ifndef BATT_MIN_MILLIVOLTS
#define BATT_MIN_MILLIVOLTS 3200
#endif
#ifndef BATT_MAX_MILLIVOLTS
#define BATT_MAX_MILLIVOLTS 4200
#endif
// 0% anchor: low_batt_mv if set, otherwise BATT_MIN_MILLIVOLTS
int minMv = (_node_prefs && _node_prefs->low_batt_mv > 0)
? (int)_node_prefs->low_batt_mv : BATT_MIN_MILLIVOLTS;
int pct = ((int)batteryMilliVolts - minMv) * 100 / (BATT_MAX_MILLIVOLTS - minMv);
// LiPo discharge curve: voltage (mV) → raw capacity (%)
static const struct { uint16_t mv; uint8_t pct; } CURVE[] = {
{3200, 0}, {3300, 3}, {3400, 8}, {3500, 15},
{3600, 25}, {3650, 33}, {3700, 45}, {3750, 58},
{3800, 68}, {3900, 77}, {4000, 86}, {4100, 93}, {4200, 100}
};
static const int CURVE_LEN = sizeof(CURVE) / sizeof(CURVE[0]);
auto curveAt = [&](int mv) -> int {
if (mv <= (int)CURVE[0].mv) return CURVE[0].pct;
if (mv >= (int)CURVE[CURVE_LEN-1].mv) return CURVE[CURVE_LEN-1].pct;
for (int i = 1; i < CURVE_LEN; i++) {
if (mv <= (int)CURVE[i].mv) {
int span_mv = CURVE[i].mv - CURVE[i-1].mv;
int span_pct = CURVE[i].pct - CURVE[i-1].pct;
return CURVE[i-1].pct + (mv - (int)CURVE[i-1].mv) * span_pct / span_mv;
}
}
return 100;
};
int low_mv = (_node_prefs && _node_prefs->low_batt_mv > 0)
? (int)_node_prefs->low_batt_mv : BATT_MIN_MILLIVOLTS;
int raw_pct = curveAt((int)batteryMilliVolts);
int low_pct = curveAt(low_mv);
// rescale so low_mv = 0% and 4200mV = 100%
int pct = (low_pct >= 100) ? 0
: (raw_pct - low_pct) * 100 / (100 - low_pct);
if (pct < 0) pct = 0;
if (pct > 100) pct = 100;