Hi PlanB,
Yes. Batteries are complicated, but you should be able to implement my simplified (sounds better than "crude") model in your software, that will be Good Enough (TM). We have done so in our BMS, at the cell level.
Introduction
The model takes instantaneous voltage, current and cell temperature, and one constant that you have to obtain from a measurement of voltage sag under load, at a known cell temperature. From those it estimates what the open circuit voltage of the cell would be, which can then be compared with thresholds chosen from published graphs so as to keep operation within a safe range of states-of-charge (SoC).
Of course if you're doing this only at the whole-battery level, you need to ensure that your cells remain top balanced and that they have capacities that don't differ by more than say +-5%.
Yes. Nissan Leaf cells (and pretty much any Li chemistry other than LiFePO4) has a far more linear voltage vs SoC curve than LiFePO4.
The OCV Estimation Method
Here are the best of the papers Johny found. Take a look at their voltage vs SoC graphs for single LiFePO4 cells.
http://www-personal.umich.edu/~hpeng/DSCC2013_Weng.pdf
See figure 2 on page 3.
http://www.cse.anl.gov/us-china-workshop-2011/pdfs/batteries/LiFePO4%20battery%20performances%20testing%20for%20BMS.pdf
[Edit: Broken link above replaced by
download/file.php?id=1410]
See the graph on the left of page 15.
Notice how there are two flat sections. One from 40% to 70% SoC and the other from 80% to 95% SoC. These make it impossible to use voltage to tell the state of charge within those ranges. But if all you want to do is tell when you're at 100% SoC and when you're at a chosen lower threshold such as 20% or 30% SoC, then it's doable.
But these graphs show only what happens at very slow rates of charge and discharge. They do not take into account rise or sag due to internal resistance.
So that's the first thing to take care of. Let's say the battery internal resistance (from the point of view of the PIP) is 6 milliohms, then if the PIP measures the voltage as 52.4 V when it is pulling 140 amps from the battery, the open circuit voltage would be 52.4 + (140 x 6/1000) = 53.24 volts. If you divide that by 16 you get an average cell voltage of 3.33 V. If you look that up on one of those charts, using the discharge curve (the lower one), you'll see that this could be anywhere between 80% and 95% SoC.
On the other hand, if you are charging at 300 amps and you read exactly the same voltage (52.4 V) then you can calculate the open circuit voltage to be 52.4 - (300 * 6/1000) = 50.72, which is an average cell voltage of 3.16 V. We can look this up on the charge curve (the upper one) and find that it is around 6% SoC.
So don't use the measured voltage to test against your thresholds for full and empty. Use estimated open circuit voltage which is:
estOcVoltage = measuredVoltage - measuredCurrent * intRes
where a negative current is a discharge.
So how do we measure internal resistance. We do this during commissioning: Make sure the battery is in one of those flat areas -- either 45 to 65% or 85 to 90% SoC (a half hour rested voltage of 52.8 V or 53.5 V). We record the battery temperature. Then we put a light load on it (5 to 10%), wait maybe 5 seconds for the voltage to stabilise, then record the battery voltage and current readings from the PIPs. Then increase the load (to 50 to 100%), wait another 5 seconds, and repeat the measurements. The internal resistance is obtained as:
intRes = (voltageA - voltageB) / (currentB - currentA)
If in doubt, err on the low side for your internal resistance estimate. Divide by the number of cells in series, to get the resistance per cell.
But we're not quite done, because this is not quite Good Enough (TM). That's because internal resistance (IR) varies enormously with cell temperature. The second of those papers above has a horrendous cubic approximation of the IR versus temp curve for a specific cell, but this is really dopey. It's as if they have never heard of Arrhenius' equation. The internal resistance can be approximated much more simply as the sum of a fixed component and an Arrhenius component.
intRes(T) = intResFixed + intResArrhenius(T)
For typical battery temperatures an Arrhenius component approximately halves for every 10 degree rise in Celsius temperature T. So it can be approximated as:
intResArrhenius(T) = intResArrhenius(T0) / 2^((T - T0)/10)
where T0 is any reference temperature at which we know the Arrhenius component of IR to be intResArrhenius(T0).
But we can't directly measure the two components, although the fixed component dominates at high temperatures and the Arrhenius component dominates at low temperatures. Ideally we'd measure the IR at two widely spaced temperatures (at least 10 degrees apart, preferably 20). But we often don't have that luxury.
So I make yet another "simplifying"

approximation. I assume that the two components happen to be equal at 10°C, for no other reason than that's what we find in that second paper above. So now we can write
intRes(T) = intResFixed * [1 + 2^(1-T/10)]
where T is the cell temperature
So we calculate (during commissioning) the approximate fixed component from the measured value, using the inverse of the above function.
intResFixed = intRes(T0) / [1 + 2^(1-T0/10)]
So if we happened to measure it at 10°C we'd divide the measured value by 2 to get the fixed component. If we measured it at 20° we'd divide by 1.5, and at 30°C, 1.25.
Summary
So the procedure is to periodically read the battery voltage, current and temperature. If you don't have actual battery temperature, ambient temperature is probably usable, but only for these systems that operate at 0.5C or less. Then use the temperature, and your intResFixed constant, to estimate the internal resistance according to:
intRes(T) = intResFixed * [1 + 2^(1-T/10)]
Then use this internal resistance to estimate the open circuit voltage according to:
estOcVoltage = measuredVoltage - measuredCurrent * intRes(T)
Then compare the estimated open circuit voltage against the thresholds you have chosen from those charts linked above. e.g.
3.23 * 16 = 51.7 V for 25% SoC, and
3.47 * 16 = 55.5 V for 100% SoC.
One thing you'll notice about those two papers. Although they agree on the shapes of the curves and the voltages of those flat areas, they don't quite agree on what voltages should be considered 0% and 100% SoC. This is somewhat arbitrary, but it would be nice if the industry could choose something and agree on it.
One of the fathers of MeXy the electric MX-5, along with Coulomb and Newton (Jeff Owen).