4. BMS核心算法模块规范:SOC估算算法规范

说到BMS的核心,SOC估算绝对是绕不开的硬骨头。我个人习惯把SOC比作电池的「油表」,但这个油表可比汽车油箱复杂多了。你想想看,油箱里的油是静止的,而电池里的电荷是动态的,还受温度、老化、充放电倍率影响。今天我就把安时积分法和卡尔曼滤波这两种主流方案掰开揉碎了讲。

4.1 安时积分法:最朴素的方案

安时积分法,说白了就是「电流对时间做积分」。公式很简单:

SOC(t) = SOC(0) - (∫I·dt) / Q_max × 100%

其中I是电流(放电为正),Q_max是电池最大可用容量。我在项目中遇到过一个问题:初始SOC不准,后面全盘皆输。所以安时积分法的核心痛点有两个:

  • 初始值校准:每次上电必须通过OCV(开路电压)查表得到初始SOC
  • 累积误差:电流采样误差会随时间累积,必须定期修正
⚠ 我曾经踩过的坑: 某次项目用了便宜的电流传感器,精度只有±5%。结果跑了半小时,SOC误差直接飙到8%。后来我强制要求电流传感器精度必须达到±1%以内,并且每10分钟做一次OCV校准。

代码实现上,我建议用定点数运算代替浮点数,避免MCU资源浪费:

// 安时积分核心函数
int32_t soc_ah_integrate(int32_t current_mA, uint32_t dt_ms, int32_t soc_q16) {
    // Q16格式:SOC = soc_q16 / 65536 * 100%
    int32_t delta_soc;
    // 电流积分:delta_soc = (current_mA * dt_ms) / (Q_max_mAh * 3600)
    delta_soc = (int64_t)current_mA * dt_ms * 100 / (Q_MAX_MAH * 3600);
    soc_q16 -= delta_soc;  // 放电为负
    
    // 限幅保护
    if (soc_q16 < 0) soc_q16 = 0;
    if (soc_q16 > 65536) soc_q16 = 65536;
    
    return soc_q16;
}

4.2 卡尔曼滤波:进阶玩家的选择

卡尔曼滤波,嗯,这名字听起来高大上,其实核心思想就一句话:用「预测+测量」不断修正。我刚开始学的时候也觉得难,后来发现把它拆成三步就简单了:

  1. 预测阶段:用安时积分法预测下一时刻的SOC
  2. 测量阶段:用电压模型反推SOC(通过OCV曲线)
  3. 更新阶段:根据预测和测量的误差,动态调整权重

为什么要用卡尔曼滤波?因为安时积分法怕累积误差,而电压法怕动态工况不准。两者互补,卡尔曼滤波就是那个「和事佬」。

核心公式(离散卡尔曼滤波):

// 预测
x_pred = A * x_est + B * u
P_pred = A * P_est * A^T + Q

// 更新
K = P_pred * H^T * (H * P_pred * H^T + R)^(-1)
x_est = x_pred + K * (z - H * x_pred)
P_est = (I - K * H) * P_pred

这里Q是过程噪声协方差,R是测量噪声协方差。我建议Q取0.01,R取0.1,这是我在多个项目中试出来的经验值。当然,具体值要根据电池特性微调。

💡 我的个人习惯: 卡尔曼滤波的初始化很关键。我一般先跑10秒的安时积分,等状态稳定了再启动卡尔曼滤波。否则初始协方差矩阵P设不对,滤波会发散。

4.3 SOH估算算法规范

SOH(健康状态)估算,说白了就是回答「这电池还能用多久?」。我常用的方法有两种:

方法 原理 适用场景 精度
容量衰减法 SOH = Q_current / Q_initial × 100% 长期在线监测 ±3%
内阻增长法 SOH = (R_eol - R_current) / (R_eol - R_initial) × 100% 离线诊断 ±5%

容量衰减法最直观,但需要完整的充放电周期才能计算。内阻增长法可以实时估算,但内阻测量受温度影响大。我建议两者结合:平时用内阻法做趋势判断,每50个完整周期用容量法做一次校准。

⚠ 我曾经犯过的错: 某次项目只用了容量法,结果用户经常浅充浅放,SOH半年都没更新。后来我加了强制深放策略:如果连续30天没有完整周期,就自动执行一次0.5C恒流放电到截止电压。

4.4 SOE估算算法规范

SOE(能量状态)估算,很多人把它和SOC搞混。区别在哪?SOC看的是「电量」,SOE看的是「还能做多少功」。公式如下:

SOE = (剩余能量) / (最大可用能量) × 100%

剩余能量 = ∫(V_ocv - I * R) * I * dt

这里V_ocv是开路电压,R是内阻。你想想看,同样50%的SOC,大倍率放电时内阻压降大,实际能放出的能量更少。所以SOE比SOC更能反映真实续航。

我建议SOE的更新频率设为1Hz,比SOC的10Hz慢一些。因为能量计算需要电压和电流的乘积,噪声比较大,滤波时间常数建议设为5秒。

💡 避坑指南: 我曾经在低温环境下发现SOE跳变严重。后来排查发现是内阻R随温度变化没补偿。解决方案是建立R-T(内阻-温度)二维查表,每5℃一个插值点。

4.5 三种算法的协同工作

在实际BMS中,SOC、SOH、SOE不是孤立的。我画个简单的逻辑关系:

  • SOC → SOH:SOC的累积充放电量用于计算SOH的容量衰减
  • SOH → SOC:SOH中的Q_max用于安时积分的分母
  • SOC + SOH → SOE:SOE需要SOC和SOH中的内阻参数

嗯,这里要注意:三个算法的更新周期要错开。我一般这样安排:

算法 更新周期 触发条件
SOC(安时积分) 100ms 持续运行
SOC(卡尔曼滤波) 1s 电流变化率 < 5A/s
SOH 1天 完成完整充放电
SOE 1s 持续运行

最后说一句:算法再牛,也怕硬件不给力。我建议电流采样用24位ADC,电压采样用16位ADC,温度采样用NTC加线性化电路。这些细节,往往决定了你的SOC精度是1%还是5%。