2、开路电压法(OCV):OCV-SOC关系曲线、OCV查表法实现、OCV法的优缺点、静置时间对OCV的影响

2.1 OCV-SOC关系曲线——电池的“身份证”

做BMS这么多年,我始终觉得开路电压法是最直观的SOC估算方法。说白了,就是利用电池静置时的端电压来反推剩余电量。每款电池都有自己独特的OCV-SOC曲线,就像人的指纹一样。

这条曲线怎么来的?把电池充满电(SOC=100%),然后静置足够长时间,记录开路电压。接着放掉5%的电量,再静置,再记录。重复这个过程直到放空。把这些点连起来,就是OCV-SOC曲线。

我遇到过不少新手问:“能不能用标准曲线?”我的回答是:千万别偷懒。不同厂家、不同批次的电池,曲线差异可能很大。特别是磷酸铁锂电池,中间那段平台区几乎平得像一条直线,稍微有点测量误差,SOC偏差就是10%以上。

核心要点:OCV-SOC曲线是电池的固有特性,但受温度、老化影响。建议在25℃下标定基准曲线,再补充不同温度下的修正系数。

这里我画了一张图,帮你理解OCV-SOC曲线的典型形态:

典型OCV-SOC关系曲线 SOC (%) 0 25 50 75 100 开路电压 (V) 2.5V 3.0V 3.5V 4.2V 三元锂 磷酸铁锂 平台区(电压变化极小)

你看,三元锂的曲线比较陡峭,电压随SOC变化明显。磷酸铁锂就麻烦多了,中间那段平台区电压几乎不变。我做过一个项目,用磷酸铁锂电池做储能,OCV法在30%-70%区间基本失效,最后不得不改用安时积分+卡尔曼滤波。

2.2 OCV查表法实现——代码里怎么玩

曲线有了,怎么在代码里用?最常用的就是查表法。把OCV-SOC曲线离散化成一张表,存到Flash里。运行时根据测得的开路电压,查表得到对应的SOC。

我个人习惯用线性插值,精度够用,计算量也小。来看看代码怎么写:

/* OCV-SOC查找表(25℃,三元锂电池) */
const float ocv_table[] = {
    2.50, 2.80, 3.00, 3.20, 3.40, 
    3.55, 3.65, 3.75, 3.85, 4.00, 4.20
};
const float soc_table[] = {
    0.0,  5.0,  10.0, 20.0, 30.0, 
    40.0, 50.0, 60.0, 70.0, 85.0, 100.0
};
#define TABLE_SIZE  (sizeof(ocv_table) / sizeof(ocv_table[0]))

/* 线性插值查表函数 */
float ocv_to_soc(float voltage) {
    uint8_t i;
    
    /* 边界处理 */
    if (voltage <= ocv_table[0]) return soc_table[0];
    if (voltage >= ocv_table[TABLE_SIZE - 1]) return soc_table[TABLE_SIZE - 1];
    
    /* 查找区间 */
    for (i = 0; i < TABLE_SIZE - 1; i++) {
        if (voltage >= ocv_table[i] && voltage < ocv_table[i + 1]) {
            break;
        }
    }
    
    /* 线性插值 */
    float ratio = (voltage - ocv_table[i]) / (ocv_table[i + 1] - ocv_table[i]);
    return soc_table[i] + ratio * (soc_table[i + 1] - soc_table[i]);
}

实战技巧:我建议把OCV表按温度分段存储。比如-20℃、0℃、25℃、45℃各一张表。运行时根据当前温度选择最近的两张表做二次插值。这样温度补偿就做进去了。

查表法的实现其实不复杂,但有几个坑要注意。我曾经在一个项目中,因为OCV表的分辨率不够,导致SOC跳变严重。后来把表从11个点增加到21个点,问题就解决了。

2.3 OCV法的优缺点——没有银弹

任何方法都有两面性,OCV法也不例外。我整理了一个表格,方便你对比:

优点 缺点
  • 原理简单,实现容易
  • 不依赖历史数据,无累积误差
  • 计算量小,适合低端MCU
  • 初始SOC校准很准
  • 需要电池充分静置(30分钟以上)
  • 动态工况下无法使用
  • 磷酸铁锂电池平台区精度差
  • 受温度影响大,需要温度补偿
  • 电池老化后曲线会偏移

说白了,OCV法最适合做静态校准。比如电动车过夜充电后,或者设备关机重启时,用OCV法把SOC初始化一下。但在行驶过程中,还得靠安时积分或其他方法。

注意:千万不要在电池有负载或充电电流时测量OCV。这时候测到的是端电压,不是开路电压。我见过有人直接用负载电压查表,SOC误差能到30%以上。

2.4 静置时间对OCV的影响——心急吃不了热豆腐

这个问题容易被忽视,但恰恰很关键。电池从充放电状态切换到静置状态后,电压不会立刻稳定下来。因为电池内部的电化学反应和离子扩散需要时间。

我做过实测:

  • 静置1分钟:电压还在快速变化,误差约50-80mV
  • 静置10分钟:变化趋缓,误差约10-20mV
  • 静置30分钟:基本稳定,误差约3-5mV
  • 静置2小时:完全稳定,误差小于1mV

你想想看,50mV的电压误差,在三元锂电池的陡峭区可能对应5%的SOC误差,但在磷酸铁锂的平台区,可能对应20%以上的SOC误差。所以静置时间不够,OCV法基本白搭。

我曾经在一个项目中,为了缩短用户等待时间,把静置时间从30分钟压缩到10分钟。结果用户反馈SOC不准,充电到100%后一晚上掉到80%。后来改回30分钟静置判断,问题就解决了。

我的建议:在代码里加一个静置计时器。检测到电池电流小于C/50(比如50Ah电池,电流小于1A)且持续30分钟以上,才认为进入静置状态,这时候才能用OCV法校准SOC。

另外,不同化学体系的电池,极化恢复时间也不同。三元锂快一些,磷酸铁锂慢一些。大倍率充放电后,极化更严重,需要更长的静置时间。嗯,这里要注意,如果电池刚经历过3C以上的大电流充放电,我建议静置时间至少翻倍。

好了,关于开路电压法的核心内容就这些。记住一句话:OCV法是好工具,但要用对场景。静态校准用它,动态估算别指望它。


专注资料整理