3、开路电压法(OCV):OCV-SOC曲线标定、OCV-SOC曲线拟合(多项式/分段线性)、OCV法的优缺点与适用场景

聊完了安时积分法,咱们来看看另一个经典方法——开路电压法。说实话,这是我最喜欢用来做初始SOC校准的方法,没有之一。你想想看,电池在静置足够长时间后,它的端电压和SOC之间存在着近乎一一对应的关系。这个关系,就是我们常说的OCV-SOC曲线。

但这里有个坑——不是随便测个电压就能查SOC的。电池刚充完电或者刚放完电,极化效应还在,这时候测出来的电压是虚的。我早年吃过这个亏,以为静置半小时就够了,结果标定出来的曲线偏差很大。后来我养成了一个习惯:至少静置2小时,磷酸铁锂甚至要4小时以上。

3.1 OCV-SOC曲线标定

标定这条曲线,说白了就是做实验。我一般用两种方法:

  • 增量放电法:把电池充满,然后每次放出固定电量(比如5%SOC),静置足够长时间,记录开路电压。重复这个过程直到放空。
  • 混合脉冲法:这个更精细一些,每个SOC点做一次充放电脉冲,然后静置,取静置结束时的电压作为OCV。

我个人习惯用增量放电法,操作简单,数据也够用。但要注意一点——温度对OCV的影响不可忽视。同一个SOC,25℃和0℃测出来的电压能差几十毫伏。所以标定的时候,最好在多个温度点下做,形成一个三维的OCV-SOC-Temp表格。

标定流程总结:

  1. 电池恒流恒压充满(0.05C截止)
  2. 静置2小时以上
  3. 放出5%SOC电量(0.2C倍率)
  4. 静置1小时,记录OCV
  5. 重复步骤3-4,直到放电截止电压
  6. 在不同温度下重复上述过程

我的小技巧:标定磷酸铁锂电池时,中间那段平台区电压变化特别平缓,SOC从20%到80%电压几乎不变。这时候我会加密采样点,比如每2%SOC测一个点,不然拟合出来的曲线在平台区误差会很大。

3.2 OCV-SOC曲线拟合

标定完数据,接下来就是拟合了。说白了,就是把离散的电压-SOC点连成一条连续的曲线,方便程序查表或者计算。常用的方法有两种:

3.2.1 多项式拟合

多项式拟合简单粗暴,一个公式搞定。我一般用6到8阶多项式:

// 多项式拟合示例(8阶)
// OCV = a0 + a1*SOC + a2*SOC^2 + ... + a8*SOC^8

// 拟合系数(三元锂电池,25℃)
double coeff[9] = {
    3.0012,    // a0
    1.2345,    // a1
    -0.5678,   // a2
    0.2345,    // a3
    -0.0891,   // a4
    0.0213,    // a5
    -0.0034,   // a6
    0.0003,    // a7
    -0.00001   // a8
};

double getOCVFromSOC(double soc) {
    double ocv = 0.0;
    double soc_pow = 1.0;
    for(int i = 0; i < 9; i++) {
        ocv += coeff[i] * soc_pow;
        soc_pow *= soc;
    }
    return ocv;
}

多项式拟合的优点是计算快,一个循环就搞定。但缺点也很明显——边缘效应。在SOC接近0%或100%时,多项式容易跑偏,出现不合理的电压值。我曾经遇到过拟合出来的曲线在SOC=0%时电压反而比SOC=5%还高,这显然不对。

3.2.2 分段线性拟合

这个方法更实用,尤其适合嵌入式系统。把OCV-SOC曲线分成若干段,每段用一条直线近似:

// 分段线性插值示例
typedef struct {
    float soc;    // SOC点
    float ocv;    // 对应的OCV值
} OCV_Point;

// 标定数据表(三元锂,25℃)
OCV_Point ocv_table[] = {
    {0.0,  3.00},
    {0.05, 3.20},
    {0.10, 3.35},
    {0.20, 3.50},
    {0.30, 3.58},
    {0.40, 3.63},
    {0.50, 3.67},
    {0.60, 3.70},
    {0.70, 3.73},
    {0.80, 3.78},
    {0.90, 3.90},
    {0.95, 4.00},
    {1.00, 4.20}
};

float getSOCFromOCV(float ocv) {
    // 边界检查
    if(ocv <= ocv_table[0].ocv) return ocv_table[0].soc;
    if(ocv >= ocv_table[N-1].ocv) return ocv_table[N-1].soc;
    
    // 查找区间
    for(int i = 0; i < N-1; i++) {
        if(ocv >= ocv_table[i].ocv && ocv <= ocv_table[i+1].ocv) {
            // 线性插值
            float ratio = (ocv - ocv_table[i].ocv) / 
                         (ocv_table[i+1].ocv - ocv_table[i].ocv);
            return ocv_table[i].soc + ratio * 
                   (ocv_table[i+1].soc - ocv_table[i].soc);
        }
    }
    return ocv_table[N-1].soc;
}

我的建议:对于三元锂电池,分段线性用12-15个点就够了。但磷酸铁锂不行,平台区太长了,我一般会在平台区加密到每5%SOC一个点,总共20-25个点才能保证精度。

3.3 OCV法的优缺点与适用场景

聊了这么多,咱们来总结一下开路电压法的优缺点。嗯,这里我得说点大实话。

优点 缺点
  • 精度高,误差可控制在1-2%以内
  • 不受电流积分误差累积影响
  • 可以校准安时积分法的累积误差
  • 实现简单,查表或多项式计算即可
  • 需要长时间静置(1-4小时)
  • 动态工况下无法使用
  • 磷酸铁锂平台区分辨率低
  • 温度影响大,需要多温度标定
  • 电池老化后曲线会偏移

避坑指南:我曾经在一个项目中只用OCV法做SOC估算,结果客户反馈说车辆启动后SOC跳变严重。后来才发现,电池刚充完电,极化电压还没消退,OCV法查出来的SOC比实际高了10%。从那以后,我坚持OCV法只用于静置超过2小时的场景,动态工况必须结合安时积分或卡尔曼滤波。

适用场景:

  • 初始SOC校准:车辆上电时,如果电池已经静置足够久,用OCV法确定初始SOC,然后切换到安时积分法。
  • 充电结束判断:充电完成后,用OCV法验证是否真的充满了。
  • 定期校准:每隔一段时间(比如每100次充放电循环),让电池静置一次,用OCV法校准SOC。
  • 实验室测试:在实验室环境下,OCV法是最可靠的SOC参考标准。

说白了,OCV法就像一把尺子,你不能一直拿着它量,但每隔一段时间用它来校准一下其他工具,效果会好很多。在实际的BMS中,我从来不会单独用OCV法,而是把它和安时积分法、卡尔曼滤波结合起来,取长补短。这个后面几章会详细讲,先卖个关子。