From 5ceaa1b879249dbc38c2981beb0634c70e21b37d Mon Sep 17 00:00:00 2001 From: MickiusMousius Date: Sun, 13 Apr 2025 14:01:48 +0930 Subject: [PATCH] Fix: Use a lookup table & interpolation to better estimate remaining battery capacity The old battery capacity estimate code uses a linear approximation to estimate the remaining battery capacity. This is computationally very efficient, however, the estimate is very inaccurate once below 60%. This change uses a small table of bounded functions to provide a more accurate estimate of remaining capacity. The values in the table re-implement the old estimation "curve". --- .../drivers/sensor/battery/battery_common.c | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/app/module/drivers/sensor/battery/battery_common.c b/app/module/drivers/sensor/battery/battery_common.c index 9afe2d5b4..d2524f000 100644 --- a/app/module/drivers/sensor/battery/battery_common.c +++ b/app/module/drivers/sensor/battery/battery_common.c @@ -29,15 +29,37 @@ int battery_channel_get(const struct battery_value *value, enum sensor_channel c return 0; } -uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) { - // Simple linear approximation of a battery based off adafruit's discharge graph: - // https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages +uint8_t lithium_ion_mv_to_pct(int16_t batt_mv) { + // Lookup table of slope formulas for calculating remaining battery capacity. + // + // The current set of values acheives the same as: bat_mv * 2 / 15 - 459; + // + // Future updates sould include more complete lookup tables for different + // battery types slectable through config flags. + struct lookup_point { + int16_t millivolts; + int16_t percent; + }; - if (bat_mv >= 4200) { - return 100; - } else if (bat_mv <= 3450) { - return 0; + static const struct lookup_point battery_lookup[] = { + {.millivolts = 4200, .percent = 100}, + {.millivolts = 3450, .percent = 0}, + }; + + if (batt_mv > battery_lookup[0].millivolts) { + return battery_lookup[0].percent; } - return bat_mv * 2 / 15 - 459; -} \ No newline at end of file + for (int i = 1; i < ARRAY_SIZE(battery_lookup); i++) { + struct lookup_point one = battery_lookup[i - 1]; + struct lookup_point two = battery_lookup[i]; + if (batt_mv >= two.millivolts) { + const int t = batt_mv - one.millivolts; + const int dx = two.millivolts - one.millivolts; + const int dy = two.percent - one.percent; + return one.percent + dy * t / dx; + } + } + + return battery_lookup[ARRAY_SIZE(battery_lookup) - 1].percent; +}