Skip to content

Commit 4465edb

Browse files
committed
Helper: Add battery percentage from millivolts function using OCV battery chemistry mapping
Signed-off-by: Luis Garcia <[email protected]>
1 parent 6d32193 commit 4465edb

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

src/helpers/Battery.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#include <stddef.h>
2+
#include "Battery.h"
3+
4+
// Build the OCV table from the configured macro.
5+
// 11 entries: 100%, 90%, ..., 0%.
6+
static const uint16_t kOcvTable[] = { OCV_ARRAY };
7+
static const size_t kOcvTableSize = sizeof(kOcvTable) / sizeof(kOcvTable[0]);
8+
9+
#if defined(__cplusplus) && __cplusplus >= 201103L
10+
static_assert(kOcvTableSize == 11,
11+
"OCV_ARRAY must contain exactly 11 entries: 100%, 90%, ..., 0%.");
12+
#endif
13+
14+
int batteryPercentFromMilliVolts(uint16_t batteryMilliVolts) {
15+
const uint8_t stepPct = 10; // distance between table entries (100 → 90 → ... → 0)
16+
const size_t n = kOcvTableSize; // should be 11
17+
18+
if (n != 11 || batteryMilliVolts <= 0) {
19+
// Error: invalid OCV_ARRAY table size or voltage
20+
return -1;
21+
}
22+
23+
// Above or equal to "full" voltage → clamp to 100%
24+
if (batteryMilliVolts >= kOcvTable[0]) {
25+
return 100;
26+
}
27+
28+
// Below or equal to "empty" voltage → clamp to 0%
29+
if (batteryMilliVolts <= kOcvTable[n - 1]) {
30+
return 0;
31+
}
32+
33+
// Find the segment [i, i+1] where:
34+
// vHigh >= batteryMilliVolts >= vLow
35+
// and map that to [pctHigh, pctLow] = [100 - 10*i, 100 - 10*(i+1)]
36+
for (size_t i = 0; i < n - 1; ++i) {
37+
uint16_t vHigh = kOcvTable[i]; // higher voltage, higher %
38+
uint16_t vLow = kOcvTable[i + 1]; // lower voltage, lower %
39+
40+
if (batteryMilliVolts <= vHigh && batteryMilliVolts >= vLow) {
41+
uint8_t pctHigh = 100 - i * stepPct;
42+
uint8_t pctLow = 100 - (i + 1) * stepPct;
43+
44+
uint16_t dv = vHigh - vLow;
45+
if (dv == 0) {
46+
return pctLow;
47+
}
48+
49+
// How far are we from the low voltage towards the high, as a fraction of the segment?
50+
uint16_t pv = batteryMilliVolts - vLow; // in [0, dv]
51+
52+
// Interpolate percentage within this 10% band.
53+
uint8_t deltaPct = (uint32_t)pv * stepPct / dv;
54+
int pct = pctLow + deltaPct;
55+
56+
// Clamp to [0, 100]
57+
if (pct < 0) pct = 0;
58+
if (pct > 100) pct = 100;
59+
return pct;
60+
}
61+
}
62+
63+
// Should be unreachable if the table is monotonic and cases above are handled.
64+
return -1;
65+
}

src/helpers/Battery.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#pragma once
2+
3+
#include <stdint.h>
4+
#include <stddef.h>
5+
6+
// -----------------------------------------------------------------------------
7+
// Open Circuit Voltage (OCV) map configuration
8+
//
9+
// OCV_ARRAY must expand to 11 integer millivolt values, corresponding to:
10+
//
11+
// 100%, 90%, 80%, 70%, 60%, 50%, 40%, 30%, 20%, 10%, 0%
12+
//
13+
// in *descending* voltage order.
14+
//
15+
// -----------------------------------------------------------------------------
16+
17+
#ifndef OCV_ARRAY
18+
#ifdef CELL_TYPE_LIFEPO4
19+
#define OCV_ARRAY 3400, 3350, 3320, 3290, 3270, 3260, 3250, 3230, 3200, 3120, 3000
20+
#elif defined(CELL_TYPE_LEADACID)
21+
#define OCV_ARRAY 2120, 2090, 2070, 2050, 2030, 2010, 1990, 1980, 1970, 1960, 1950
22+
#elif defined(CELL_TYPE_ALKALINE)
23+
#define OCV_ARRAY 1580, 1400, 1350, 1300, 1280, 1250, 1230, 1190, 1150, 1100, 1000
24+
#elif defined(CELL_TYPE_NIMH)
25+
#define OCV_ARRAY 1400, 1300, 1280, 1270, 1260, 1250, 1240, 1230, 1210, 1150, 1000
26+
#elif defined(CELL_TYPE_LTO)
27+
#define OCV_ARRAY 2700, 2560, 2540, 2520, 2500, 2460, 2420, 2400, 2380, 2320, 1500
28+
#else
29+
// Default Li-Ion / Li-Po
30+
#define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100
31+
#endif
32+
#endif
33+
34+
35+
/**
36+
* Convert a battery voltage (in millivolts) to approximate state-of-charge (%),
37+
* using the OCV curve defined by OCV_ARRAY.
38+
*
39+
* Assumes:
40+
* - OCV_ARRAY has 11 entries, in descending order.
41+
* - These correspond to 100, 90, 80, ..., 0 percent.
42+
* - The input batteryMilliVolts is in the same scale as the OCV values.
43+
*
44+
* Returns an integer percentage in [0, 100] or -1 on error.
45+
*/
46+
int batteryPercentFromMilliVolts(uint16_t batteryMilliVolts);

0 commit comments

Comments
 (0)