4、开路电压法(OCV):OCV-SOC关系曲线标定、静置时间对OCV的影响、温度补偿策略
聊到SOC估算,开路电压法(OCV)是个绕不开的基础方法。说白了,它利用的是电池在静置状态下,端电压与剩余电量之间那个相对稳定的对应关系。很多新手觉得这方法简单,不就是查个表嘛。但实际工程里,坑可不少。
我个人习惯把OCV法比作电池的「指纹」。每款电池的OCV-SOC曲线都不一样,甚至同一款电池,不同批次的曲线也会有细微差异。所以,标定这条曲线,是后续所有工作的基础。
4.1 OCV-SOC关系曲线标定
标定曲线,听起来高大上,其实就是做实验。我见过不少工程师直接拿厂家给的曲线用,结果项目后期被精度问题折磨得够呛。我的建议是:自己动手标定,至少做一次验证。
标定的核心思路很简单:把电池从满充状态,以很小的电流(比如0.05C)逐步放电到截止电压,每放掉一定电量(比如5% SOC),就停下来静置一段时间,记录此时的端电压。反过来充电也一样。
这里有个关键点:静置时间怎么定? 我在项目中遇到过,静置时间不够,电压还没稳定下来就记录数据,标出来的曲线跟实际偏差很大。后来我总结了一套经验:
- 常温(25℃)下: 静置时间建议不少于2小时。对于磷酸铁锂这种平台电压很平的电池,我甚至建议静置3小时以上。
- 低温(0℃以下): 电池极化更严重,静置时间要延长到4-6小时。
- 高温(45℃以上): 静置时间可以适当缩短到1-1.5小时,但要注意自放电的影响。
标定完成后,我们会得到一组数据。通常我会用多项式拟合或者分段线性插值来建立OCV-SOC的映射关系。下面是一个简单的分段线性插值代码示例,用于查表:
// OCV-SOC 查表函数 (分段线性插值)
// OCV_Table[]: 标定好的OCV值数组 (单位: mV)
// SOC_Table[]: 对应的SOC值数组 (单位: %)
// OCV_Current: 当前测量的开路电压 (单位: mV)
// 返回: 估算的SOC值 (单位: %)
float OCV_to_SOC(float OCV_Current, float* OCV_Table, float* SOC_Table, uint8_t Table_Size) {
// 边界检查
if (OCV_Current <= OCV_Table[0]) return SOC_Table[0];
if (OCV_Current >= OCV_Table[Table_Size - 1]) return SOC_Table[Table_Size - 1];
// 查找区间
for (uint8_t i = 0; i < Table_Size - 1; i++) {
if (OCV_Current >= OCV_Table[i] && OCV_Current <= OCV_Table[i + 1]) {
// 线性插值
float ratio = (OCV_Current - OCV_Table[i]) / (OCV_Table[i + 1] - OCV_Table[i]);
return SOC_Table[i] + ratio * (SOC_Table[i + 1] - SOC_Table[i]);
}
}
// 理论上不会到这里
return -1.0f;
}
4.2 静置时间对OCV的影响
为什么静置时间这么重要?你想想看,电池刚充完电或者刚放完电,内部是有极化效应的。锂离子在电极材料里还没扩散均匀,这时候测出来的电压是「虚」的,不是真正的平衡电势。
我做过一个对比实验:一块磷酸铁锂电池,以1C放电到50% SOC后立即测量,电压是3.25V。静置1小时后,电压回升到3.30V。静置3小时后,稳定在3.32V。你看,差了将近70mV。对于磷酸铁锂这种平台电压,70mV对应的SOC误差可能高达10%以上。
所以,静置时间不够,OCV法基本不能用。 那在实际BMS里,我们怎么判断电池是否「静置充分」呢?
- 电流判据: 检测到电流小于某个阈值(比如0.01C),并且持续一段时间。
- 电压变化率判据: 检测到端电压的变化率小于某个值(比如1mV/min),并且持续一段时间。
- 时间判据: 直接设定一个最小静置时间(比如30分钟),但这个方法比较粗糙,不推荐单独使用。
我个人习惯把电流判据和电压变化率判据结合起来用。先检测电流是否为零,再检测电压是否稳定。这样既能保证精度,又不会因为静置时间过长而影响用户体验。
4.3 温度补偿策略
温度对OCV的影响,说白了就是电池的「脾气」会随着温度变。温度高了,化学反应活性强,开路电压会略微升高;温度低了,活性降低,电压会下降。如果不做补偿,冬天和夏天的SOC估算结果可能差好几个百分点。
我建议的温度补偿策略分两步走:
- 建立不同温度下的OCV-SOC曲线族。 至少标定-20℃、0℃、25℃、45℃四个温度点的曲线。如果条件允许,再多标几个点。
- 实时温度插值。 根据当前电池温度,在相邻的两条曲线之间做线性插值。
下面是一个温度补偿的查表示例:
| 温度 (℃) | SOC=100% OCV (mV) | SOC=50% OCV (mV) | SOC=0% OCV (mV) |
|---|---|---|---|
| -20 | 4200 | 3650 | 3200 |
| 0 | 4180 | 3620 | 3180 |
| 25 | 4160 | 3600 | 3150 |
| 45 | 4140 | 3580 | 3120 |
实际代码实现时,我会用一个二维数组来存储这个表。查表时,先根据温度找到相邻的两行,再根据OCV找到对应的SOC,最后做双线性插值。嗯,这里要注意,双线性插值的计算量稍大,如果MCU性能有限,可以考虑简化成单线性插值,精度损失在可接受范围内。
最后说一句,OCV法虽然精度高,但它有个致命弱点:需要电池长时间静置。 在车辆行驶过程中,我们几乎不可能得到真正的OCV。所以,在实际的BMS中,OCV法通常只用于初始化和校准,日常的动态估算还得靠安时积分法或者卡尔曼滤波。这部分内容,我们后面的章节会详细讲。