From f4c9b12d7860cdd94d9d524c4286db19f1f42862 Mon Sep 17 00:00:00 2001 From: MickiusMousius Date: Mon, 11 Dec 2023 17:30:53 +1030 Subject: [PATCH 1/5] fix: Use a formula table to better approximate remaining battery capacity --- .../drivers/sensor/battery/battery_common.c | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/app/module/drivers/sensor/battery/battery_common.c b/app/module/drivers/sensor/battery/battery_common.c index 9afe2d5b..5bc4aaa8 100644 --- a/app/module/drivers/sensor/battery/battery_common.c +++ b/app/module/drivers/sensor/battery/battery_common.c @@ -29,15 +29,36 @@ 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 +typedef struct { + int16_t millivolts; + float slope; + float offset; +} batt_est_formula; - if (bat_mv >= 4200) { - return 100; - } else if (bat_mv <= 3450) { - return 0; +uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) { + // Lookup table of slope formulas for calculating remaining battery capacity. + // The original values used to calculate slopes come from: + // + // https://blog.ampow.com/lipo-voltage-chart/ + + const batt_est_formula lipo_formula_lookup[9] = { + {.millivolts = 4200, .slope = 0, .offset = 100}, + {.millivolts = 4150, .slope = 0.1, .offset = -320}, + {.millivolts = 4110, .slope = 0.125, .offset = -423.75}, + {.millivolts = 4020, .slope = 0.111, .offset = -366.22}, + {.millivolts = 3870, .slope = 0.133, .offset = -454.68}, + {.millivolts = 3690, .slope = 0.278, .offset = -1015.84}, + {.millivolts = 3610, .slope = 0.063, .offset = -222.47}, + {.millivolts = 3270, .slope = 0.015, .offset = -48.09}, + }; + + for (int i = 0; i < 9; i++) { + batt_est_formula current_formula = lipo_formula_lookup[i]; + if (bat_mv >= current_formula.millivolts) { + float capacity = bat_mv * current_formula.slope + current_formula.offset; + return (uint8_t)capacity; + } } - return bat_mv * 2 / 15 - 459; + return 0; } \ No newline at end of file From 86885c19bd38c40aaa0ad898b810923239aedcb1 Mon Sep 17 00:00:00 2001 From: MickiusMousius Date: Tue, 12 Dec 2023 12:42:43 +1030 Subject: [PATCH 2/5] Address feedback: Perform interpolation in code, proper use of struct & const --- .../drivers/sensor/battery/battery_common.c | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/app/module/drivers/sensor/battery/battery_common.c b/app/module/drivers/sensor/battery/battery_common.c index 5bc4aaa8..73b60e9c 100644 --- a/app/module/drivers/sensor/battery/battery_common.c +++ b/app/module/drivers/sensor/battery/battery_common.c @@ -29,34 +29,35 @@ int battery_channel_get(const struct battery_value *value, enum sensor_channel c return 0; } -typedef struct { - int16_t millivolts; - float slope; - float offset; -} batt_est_formula; - -uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) { +uint8_t lithium_ion_mv_to_pct(int16_t batt_mv) { // Lookup table of slope formulas for calculating remaining battery capacity. // The original values used to calculate slopes come from: // // https://blog.ampow.com/lipo-voltage-chart/ - - const batt_est_formula lipo_formula_lookup[9] = { - {.millivolts = 4200, .slope = 0, .offset = 100}, - {.millivolts = 4150, .slope = 0.1, .offset = -320}, - {.millivolts = 4110, .slope = 0.125, .offset = -423.75}, - {.millivolts = 4020, .slope = 0.111, .offset = -366.22}, - {.millivolts = 3870, .slope = 0.133, .offset = -454.68}, - {.millivolts = 3690, .slope = 0.278, .offset = -1015.84}, - {.millivolts = 3610, .slope = 0.063, .offset = -222.47}, - {.millivolts = 3270, .slope = 0.015, .offset = -48.09}, + // + struct lookup_point { + float millivolts; + float percent; }; - for (int i = 0; i < 9; i++) { - batt_est_formula current_formula = lipo_formula_lookup[i]; - if (bat_mv >= current_formula.millivolts) { - float capacity = bat_mv * current_formula.slope + current_formula.offset; - return (uint8_t)capacity; + static const struct lookup_point battery_lookup[] = { + {.millivolts = 4200, .percent = 100}, {.millivolts = 3870, .percent = 60}, + {.millivolts = 3690, .percent = 10}, {.millivolts = 3610, .percent = 5}, + {.millivolts = 3270, .percent = 0}, + }; + + if (batt_mv > 4200) { + return 100; + } + + for (int i = 0; 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) { + float slope = (one.percent - two.percent) / (one.millivolts - two.millivolts); + float offset = one.percent - slope * one.millivolts; + float batt_percent = (slope * batt_mv) + offset; + return (uint8_t)batt_percent; } } From d86d289d76ead0069479d42e36fd8df650c25ec0 Mon Sep 17 00:00:00 2001 From: MickiusMousius <137600636+MickiusMousius@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:18:27 +1030 Subject: [PATCH 3/5] Fix: Correct incorrect indexing of the lookup table --- app/module/drivers/sensor/battery/battery_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/module/drivers/sensor/battery/battery_common.c b/app/module/drivers/sensor/battery/battery_common.c index 73b60e9c..b582e317 100644 --- a/app/module/drivers/sensor/battery/battery_common.c +++ b/app/module/drivers/sensor/battery/battery_common.c @@ -50,7 +50,7 @@ uint8_t lithium_ion_mv_to_pct(int16_t batt_mv) { return 100; } - for (int i = 0; i < ARRAY_SIZE(battery_lookup); i++) { + 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) { @@ -62,4 +62,4 @@ uint8_t lithium_ion_mv_to_pct(int16_t batt_mv) { } return 0; -} \ No newline at end of file +} From 73646cbfc7bb7509e08142f493c5250d790c4a87 Mon Sep 17 00:00:00 2001 From: MickiusMousius Date: Wed, 13 Dec 2023 12:06:39 +1030 Subject: [PATCH 4/5] fix: Use more efficient integer operations, ensure return values don'r get out of sync with the lookup table. --- .../drivers/sensor/battery/battery_common.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/module/drivers/sensor/battery/battery_common.c b/app/module/drivers/sensor/battery/battery_common.c index b582e317..0733116a 100644 --- a/app/module/drivers/sensor/battery/battery_common.c +++ b/app/module/drivers/sensor/battery/battery_common.c @@ -36,8 +36,8 @@ uint8_t lithium_ion_mv_to_pct(int16_t batt_mv) { // https://blog.ampow.com/lipo-voltage-chart/ // struct lookup_point { - float millivolts; - float percent; + int16_t millivolts; + int16_t percent; }; static const struct lookup_point battery_lookup[] = { @@ -46,20 +46,20 @@ uint8_t lithium_ion_mv_to_pct(int16_t batt_mv) { {.millivolts = 3270, .percent = 0}, }; - if (batt_mv > 4200) { - return 100; + if (batt_mv > battery_lookup[0].millivolts) { + return battery_lookup[0].percent; } - for (int i = 1; i < ARRAY_SIZE(battery_lookup); i++) { + for (int i = 0; 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) { - float slope = (one.percent - two.percent) / (one.millivolts - two.millivolts); - float offset = one.percent - slope * one.millivolts; - float batt_percent = (slope * batt_mv) + offset; - return (uint8_t)batt_percent; + 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 0; + return battery_lookup[ARRAY_SIZE(battery_lookup) - 1].percent; } From e41c11d0a1620cb794908ceb81c5de2fad968d38 Mon Sep 17 00:00:00 2001 From: MickiusMousius Date: Mon, 18 Dec 2023 10:30:50 +1030 Subject: [PATCH 5/5] fix bad indexing of lookup table --- app/module/drivers/sensor/battery/battery_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/module/drivers/sensor/battery/battery_common.c b/app/module/drivers/sensor/battery/battery_common.c index 0733116a..f0adaf60 100644 --- a/app/module/drivers/sensor/battery/battery_common.c +++ b/app/module/drivers/sensor/battery/battery_common.c @@ -50,7 +50,7 @@ uint8_t lithium_ion_mv_to_pct(int16_t batt_mv) { return battery_lookup[0].percent; } - for (int i = 0; i < ARRAY_SIZE(battery_lookup); i++) { + 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) {