第1章:开路电压法(OCV)——OCV-SOC曲线标定、查表法实现、温度补偿策略
大家好,我是你们的老朋友。今天咱们聊聊开路电压法,也就是OCV。
说实话,OCV法是所有SOC估算方法里最直观的一种。你想想看,电池静置久了,端电压和剩余电量之间有个相对稳定的对应关系。这个关系,就是OCV-SOC曲线。
但这里有个坑——曲线标定做不好,后面查表全是错的。我在项目中遇到过好几次,标定数据没处理好,结果查出来的SOC偏差超过10%。嗯,这期咱们就把这块彻底讲透。
1.1 OCV-SOC曲线标定:别小看这步
标定曲线,说白了就是给电池拍一张“电压-电量”的证件照。怎么拍?我习惯用小电流间歇放电法。
具体步骤是这样的:
- 把电池充满到4.2V(或者厂家规定的上限)
- 静置1-2小时,等电压稳定
- 记录当前电压和SOC(此时SOC=100%)
- 以0.05C小电流放电,放出5%的电量
- 再次静置1小时
- 记录电压和SOC(此时SOC=95%)
- 重复步骤4-6,直到电压降到截止电压
为什么要静置这么久?因为电池有极化效应。刚放完电时,电压是虚的,得等它“缓过来”。我曾经偷懒只静置30分钟,结果标出来的曲线在低SOC段偏差很大,后来查了好久才发现是静置时间不够。
关键点:标定时的电流越小越好,0.05C是业界常用值。电流大了,极化电压会污染数据。
标定完成后,你会得到一组数据点。比如这样:
| SOC (%) | OCV (V) |
|---|---|
| 100 | 4.200 |
| 95 | 4.125 |
| 90 | 4.060 |
| ... | ... |
| 5 | 3.400 |
| 0 | 3.200 |
注意,不同化学体系的电池,曲线形状差异很大。磷酸铁锂的OCV曲线中间有一段特别平,几乎没变化。三元锂就好很多,斜率明显。我做磷酸铁锂项目时,那段平缓区真是让人头疼——电压变一点点,SOC可能跳好几个点。
1.2 查表法实现:代码怎么写?
标定完曲线,接下来就是查表。查表法说白了就是:给一个电压,返回一个SOC。
我常用的方法是线性插值。假设你测到的电压是3.850V,落在3.800V和3.900V之间,那就按比例算SOC。
代码实现很简单:
// OCV查表函数,线性插值
// ocv_table: 电压数组(升序)
// soc_table: 对应的SOC数组
// ocv: 当前测量的开路电压
// table_size: 表格长度
float ocv_to_soc(float *ocv_table, float *soc_table, float ocv, int table_size) {
// 边界处理:超出范围直接返回端点值
if (ocv <= ocv_table[0]) return soc_table[0];
if (ocv >= ocv_table[table_size-1]) return soc_table[table_size-1];
// 二分查找,找到ocv落在哪两个点之间
int low = 0, high = table_size - 1;
while (high - low > 1) {
int mid = (low + high) / 2;
if (ocv_table[mid] <= ocv) low = mid;
else high = mid;
}
// 线性插值
float v_low = ocv_table[low];
float v_high = ocv_table[high];
float s_low = soc_table[low];
float s_high = soc_table[high];
float ratio = (ocv - v_low) / (v_high - v_low);
return s_low + ratio * (s_high - s_low);
}
小技巧:表格点不要太多,20-30个点就够。点太多反而增加查表时间,而且对精度提升有限。我一般用25个点,每4% SOC一个点,平缓区可以加密到2%一个点。
这里有个细节——二分查找。别用顺序查找,太慢了。嵌入式MCU主频不高,二分查找O(log n)的复杂度,100个点也只要7次比较。我见过有人用顺序查找,查一次表要几十微秒,实时性根本没法保证。
1.3 温度补偿策略:别被温度骗了
OCV-SOC曲线不是一成不变的。温度一变,曲线就飘。你想想看,冬天零下10度,电池电压比夏天低不少,但实际电量可能没少那么多。
我做过一个实验:同一块电池,25°C时OCV=3.800V对应SOC=50%;到了-10°C,同样的3.800V,实际SOC只有35%左右。如果不做温度补偿,误差能到15%。
怎么补偿?我推荐多温度标定+查表补偿的方法。
具体做法:
- 在-20°C、0°C、25°C、45°C四个温度点分别标定OCV-SOC曲线
- 实际使用时,根据当前温度,在两条曲线之间做线性插值
代码实现也不复杂:
// 温度补偿查表
// 假设有4组OCV表,对应-20, 0, 25, 45度
// temp_tables[4][TABLE_SIZE] 存储四组电压数据
// soc_table 是公共的SOC轴
// temp: 当前温度
float ocv_to_soc_temp_comp(float temp_tables[4][TABLE_SIZE],
float *soc_table,
float ocv,
float temp) {
// 找到当前温度落在哪两个标定温度之间
float temp_points[4] = {-20, 0, 25, 45};
int idx_low, idx_high;
if (temp <= temp_points[0]) {
// 低于最低温度,直接用最低温度的表
return ocv_to_soc(temp_tables[0], soc_table, ocv, TABLE_SIZE);
} else if (temp >= temp_points[3]) {
// 高于最高温度,直接用最高温度的表
return ocv_to_soc(temp_tables[3], soc_table, ocv, TABLE_SIZE);
} else {
// 找到区间
for (int i = 0; i < 3; i++) {
if (temp >= temp_points[i] && temp < temp_points[i+1]) {
idx_low = i;
idx_high = i+1;
break;
}
}
// 分别查两个温度下的SOC
float soc_low = ocv_to_soc(temp_tables[idx_low], soc_table, ocv, TABLE_SIZE);
float soc_high = ocv_to_soc(temp_tables[idx_high], soc_table, ocv, TABLE_SIZE);
// 温度线性插值
float ratio = (temp - temp_points[idx_low]) /
(temp_points[idx_high] - temp_points[idx_low]);
return soc_low + ratio * (soc_high - soc_low);
}
}
警告:温度补偿不是万能的。在极端温度下(比如-30°C以下),电池内阻剧增,OCV法本身就不太准了。这时候建议结合安时积分法一起用,别单靠OCV。
另外,温度传感器要贴在电池表面,别贴在模组外壳上。我见过一个项目,温度传感器贴在电池模组外壳上,测出来的温度比实际电芯温度低了5度,补偿出来的SOC偏差很大。后来改成贴在电芯极柱附近,问题就解决了。
1.4 实际应用中的避坑指南
最后,我总结几个实战中容易踩的坑:
- 静置时间不够:电池刚充放电完,极化电压没消除,测出来的OCV是假的。我建议至少静置1小时,磷酸铁锂需要更久。
- 忽略老化:电池用久了,OCV曲线会漂移。新电池和老电池的曲线不一样。我习惯每半年重新标定一次,或者用在线学习算法动态修正。
- 查表精度不够:有些MCU的ADC分辨率只有10位,测电压误差就有几个毫伏。在OCV曲线平缓区,几个毫伏的误差能导致SOC偏差好几个点。建议用12位以上的ADC。
- 温度补偿只做线性:实际上温度对OCV的影响不是完全线性的,尤其在低温区。如果条件允许,可以多标定几个温度点,用分段线性或者多项式拟合。
好了,这一章就到这里。OCV法虽然基础,但做扎实了,能解决很多实际问题。下一章咱们聊聊安时积分法,那个又是另一番天地了。
核心要点回顾:
- OCV-SOC曲线标定要用小电流间歇放电法,静置时间要足够
- 查表用二分查找+线性插值,效率高精度够
- 温度补偿至少做4个温度点,线性插值即可
- 注意静置时间、老化、ADC精度这些细节
公众号:蓝海资料掘金营,微信deep3321