Implemented battery linear interpolation with discharge curve
This commit is contained in:
parent
65e476df3e
commit
ce5f6a949e
1 changed files with 48 additions and 8 deletions
|
@ -42,17 +42,57 @@ struct bvd_data {
|
||||||
uint8_t state_of_charge;
|
uint8_t state_of_charge;
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) {
|
struct charge_level {
|
||||||
// Simple linear approximation of a battery based off adafruit's discharge graph:
|
int16_t mv;
|
||||||
// https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages
|
uint8_t pct;
|
||||||
|
};
|
||||||
|
|
||||||
if (bat_mv >= 4200) {
|
#define BATTERY_CHARGE_LEVEL_LUT_COUNT 27
|
||||||
return 100;
|
struct charge_level charge_level_lut[BATTERY_CHARGE_LEVEL_LUT_COUNT] = {
|
||||||
} else if (bat_mv <= 3450) {
|
{3434, 0}, {3457, 4}, {3487, 8}, {3520, 12}, {3545, 15}, {3577, 19}, {3595, 23},
|
||||||
return 0;
|
{3609, 27}, {3618, 31}, {3625, 35}, {3633, 38}, {3643, 42}, {3656, 46}, {3672, 50},
|
||||||
|
{3696, 54}, {3733, 58}, {3767, 62}, {3796, 65}, {3825, 69}, {3862, 73}, {3899, 77},
|
||||||
|
{3936, 81}, {3976, 85}, {4023, 88}, {4068, 92}, {4120, 96}, {4177, 100}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts LiIon battery voltage to percentage.
|
||||||
|
* @details The function uses a LUT and linear interpolation for estimating charge status
|
||||||
|
* based on the battery voltage. The LUT contains the discharge curve of the battery.
|
||||||
|
*/
|
||||||
|
static uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) {
|
||||||
|
|
||||||
|
uint8_t charge_state = 0;
|
||||||
|
|
||||||
|
// If battery voltage exceeds LUT maximum voltage, assume fully charged state
|
||||||
|
if (bat_mv >= charge_level_lut[BATTERY_CHARGE_LEVEL_LUT_COUNT-1].mv) {
|
||||||
|
charge_state = 100;
|
||||||
|
} else {
|
||||||
|
// Otherwise, traverse LUT and interpolate
|
||||||
|
for (uint8_t lut_idx = 0; lut_idx < BATTERY_CHARGE_LEVEL_LUT_COUNT - 1; lut_idx++) {
|
||||||
|
if (charge_level_lut[lut_idx].mv <= bat_mv &&
|
||||||
|
bat_mv <= charge_level_lut[lut_idx + 1].mv) {
|
||||||
|
// Look for a voltage that lies between two adjacent LUT indices
|
||||||
|
|
||||||
|
// Calculate the distance to the next lower voltage in the LUT
|
||||||
|
double distLower = bat_mv - charge_level_lut[lut_idx].mv;
|
||||||
|
|
||||||
|
// Calculate the distance between the voltages of the adjacent LUT indices
|
||||||
|
double distAdjacent =
|
||||||
|
charge_level_lut[lut_idx + 1].mv - charge_level_lut[lut_idx].mv;
|
||||||
|
|
||||||
|
// Calculate the linear slope within the chosen bracket
|
||||||
|
double slope = (charge_level_lut[lut_idx + 1].pct - charge_level_lut[lut_idx].pct) /
|
||||||
|
distAdjacent;
|
||||||
|
|
||||||
|
// Resolve linear equation
|
||||||
|
charge_state = charge_level_lut[lut_idx].pct + slope * distLower;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bat_mv * 2 / 15 - 459;
|
// If not in range of the LUT, this returns 0
|
||||||
|
return charge_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan) {
|
static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue