SOC measurement and how it works


Thank you for the invitation link . Based on the SOC estimation and calculation i know that this is done by first estimation when first powered on then by actual current capacity measurement CC after . But at what point in the code does this switch over occur. In order to fully rate a battery system correct and for the bms to calculate the SOC what needs to happen after first boot ? Does the battery Need a full charge till the bms terminates ? Then a full discharge till the bms terminates at Low voltage cut off and if this maybe the case should these figures be 2.5v per cell low voltage and 3.65v per cell high voltage disconnection ? And at this point after 1 full charge and 1 full discharge does the battery change to Coulomb counting ?


// SOC calculation based on average cell open circuit voltage

void bq769x0::resetSOC(int percent)
if (percent <= 100 && percent >= 0)
coulombCounter = nominalCapacity * percent / 100.0;
else // reset based on OCV
printf(“NumCells: %d, voltage: %d V\n”, getNumberOfConnectedCells(), getBatteryVoltage());
int voltage = getBatteryVoltage() / getNumberOfConnectedCells();

    coulombCounter = 0;  // initialize with totally depleted battery (0% SOC)

    for (int i = 0; i < NUM_OCV_POINTS; i++)
        if (OCV[i] <= voltage) {
            if (i == 0) {
                coulombCounter = nominalCapacity;  // 100% full
            else {
                // interpolate between OCV[i] and OCV[i-1]
                coulombCounter = (double) nominalCapacity / (NUM_OCV_POINTS - 1.0) *
                (NUM_OCV_POINTS - 1.0 - i + ((float)voltage - OCV[i])/(OCV[i-1] - OCV[i]));


based on this code the assumption is that when the battery is at over 100% and under 0% then the bms will not use the OCV points . However based on a test i have just conducted the battery is reaching the 2.5v range and the SOC still reads 32% unless the cells that are ignored and reporting 0.000v are interfering with the SOC calculation even though bms.getcellvoltages specifies only the valid cells ?


There are two typical ways for SOC calculation:

  1. Measure the open circuit voltage and calculate the SOC based on known (stored) OCV map of the used cell.
  2. Coulomb counting, starting from a known SOC.

Normally, a combination of both is used.

Especially for LiFePO4 cells, method 1 is quite difficult, as the OCV curve is very flat. So after startup, the estimation will always have a low accuracy.

After a full charge of the battery, the SOC is reset to 100% and coulomb counting starts to get a more accurate SOC.

Coulomb counting accuracy needs a correct setting of the battery capacity, of course. Unfortunately, it suffers from SOC drift, as current measurement errors accumulate. So it needs a full charge to re-calibrate every now and then.



to clarify things a bit: the current bq769x0 library source code has no SoC calibration built in. resetSOC() ist only called once at startup. From this time on the coulomb counter is used to calculate the SoC. If resetSOC() is called with an argument between 0 and 100 this value is used as SoC without further calculation. If it’s called without argument like in the original main.cpp it calculates the SoC based on the given OCV points.
I tried to develop a simple calibration routine myself, but i’m not entirely happy with it yet. Stay tuned…