3. SOC估算方法(下):卡尔曼滤波入门、扩展卡尔曼滤波(EKF)在SOC估算中的应用

各位工程师朋友,咱们接着聊SOC估算。上一节讲了安时积分和开路电压法,这两种方法各有各的毛病。安时积分会漂,开路电压法又不能实时用。那有没有一种方法,能把两者的优点结合起来?

有,就是卡尔曼滤波。说实话,我第一次接触这东西时也觉得头大,满屏的矩阵和协方差。但后来在项目中硬啃下来,发现它其实是个很优雅的“数据融合器”。今天我就带大家把它拆开揉碎了讲。

3.1 卡尔曼滤波:一个“会学习”的滤波器

卡尔曼滤波是什么?说白了,它就是个状态观测器。你给它一个带噪声的测量值,它就能给你一个更靠谱的估计值。

我习惯用一个比喻来理解它:

  • 你有个朋友在开车,你坐在副驾。你闭着眼睛,根据上一秒的速度,猜他现在开到了哪里——这叫预测
  • 然后你睁眼看了一眼路边的里程碑——这叫测量
  • 你发现你猜的位置和里程碑差了50米。你会完全相信里程碑吗?不一定,因为里程碑可能被撞歪了。你会完全相信自己的猜测吗?也不一定,因为你刚才可能记错了速度。
  • 于是你做了一个加权平均——这叫更新

卡尔曼滤波干的就是这件事。它用两个核心公式来迭代:

# 预测步
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

这里面的K叫做卡尔曼增益。它决定了你是更相信预测,还是更相信测量。Q是过程噪声协方差,R是测量噪声协方差。这两个参数怎么调?嗯,我在项目里吃过不少亏,后面会讲。

核心思想:卡尔曼滤波不是简单地取平均,而是根据当前的不确定性动态调整权重。不确定性越大,权重越小。

3.2 为什么SOC估算要用卡尔曼滤波?

你想想看,SOC估算本质上就是个状态估计问题。电池模型是非线性的,测量有噪声,初始SOC还不一定准。卡尔曼滤波正好能解决这些问题:

  • 融合安时积分和电压测量:安时积分提供短期预测,电压测量提供长期修正。
  • 自动校正初始误差:就算初始SOC设错了,滤波器也会慢慢收敛回来。
  • 提供不确定性估计:不仅告诉你SOC是多少,还告诉你这个值有多可信。

我记得有一次做BMS项目,客户要求SOC误差在3%以内。用纯安时积分,跑两小时就漂到5%了。换成卡尔曼滤波后,误差稳稳控制在1.5%以内。效果立竿见影。

3.3 扩展卡尔曼滤波(EKF):对付非线性系统

标准的卡尔曼滤波要求系统是线性的。但电池模型呢?开路电压与SOC的关系是非线性的,RC网络的响应也是非线性的。怎么办?

EKF的思路很简单:把非线性函数在当前估计点做泰勒展开,只取一阶项。说白了,就是用切线来近似曲线。

具体来说,原来线性卡尔曼里的矩阵A和H,在EKF里变成了雅可比矩阵:

# 状态转移矩阵 A 的雅可比
A_k = ∂f/∂x | x = x_est

# 观测矩阵 H 的雅可比
H_k = ∂h/∂x | x = x_pred

这里f是状态转移函数,h是观测函数。对于电池模型,通常选择二阶RC模型:

# 状态向量: [SOC, V1, V2]^T
# V1, V2 是两个RC网络的电压

# 状态方程:
SOC_k+1 = SOC_k - (η * Δt / Q_n) * I_k
V1_k+1 = V1_k * exp(-Δt / τ1) + R1 * (1 - exp(-Δt / τ1)) * I_k
V2_k+1 = V2_k * exp(-Δt / τ2) + R2 * (1 - exp(-Δt / τ2)) * I_k

# 观测方程:
V_t = OCV(SOC_k) - V1_k - V2_k - R0 * I_k

这里面OCV(SOC)是非线性函数,需要求导。我一般用查表加线性插值,然后直接数值求导,省得推导解析表达式。

我的经验:EKF的雅可比矩阵不一定非要解析推导。数值求导(有限差分法)在大多数情况下够用,而且不容易出错。但要注意步长的选择,步长太大精度不够,步长太小容易受浮点误差影响。

3.4 EKF-SOC估算的完整流程

咱们把整个流程串起来。假设你已经在MATLAB或Python里实现了电池模型:

import numpy as np

class EKF_SOC:
    def __init__(self, dt, Q_n, R0, R1, R2, tau1, tau2):
        self.dt = dt
        self.Q_n = Q_n  # 标称容量
        self.R0, self.R1, self.R2 = R0, R1, R2
        self.tau1, self.tau2 = tau1, tau2
        
        # 初始状态
        self.x = np.array([0.5, 0.0, 0.0])  # [SOC, V1, V2]
        self.P = np.eye(3) * 0.1  # 初始协方差
        
        # 噪声协方差(需要调参)
        self.Q = np.diag([1e-5, 1e-6, 1e-6])
        self.R = np.array([[1e-3]])
        
    def predict(self, I):
        # 状态预测
        SOC, V1, V2 = self.x
        SOC_pred = SOC - (self.dt / self.Q_n) * I
        V1_pred = V1 * np.exp(-self.dt / self.tau1) + self.R1 * (1 - np.exp(-self.dt / self.tau1)) * I
        V2_pred = V2 * np.exp(-self.dt / self.tau2) + self.R2 * (1 - np.exp(-self.dt / self.tau2)) * I
        self.x_pred = np.array([SOC_pred, V1_pred, V2_pred])
        
        # 雅可比矩阵 A
        A = np.array([
            [1, 0, 0],
            [0, np.exp(-self.dt / self.tau1), 0],
            [0, 0, np.exp(-self.dt / self.tau2)]
        ])
        
        # 协方差预测
        self.P_pred = A @ self.P @ A.T + self.Q
        
    def update(self, V_meas, I):
        # 观测预测
        SOC_pred = self.x_pred[0]
        OCV = self.ocv_lookup(SOC_pred)  # 查表函数
        V_pred = OCV - self.x_pred[1] - self.x_pred[2] - self.R0 * I
        
        # 雅可比矩阵 H(对SOC求导)
        dOCV_dSOC = (self.ocv_lookup(SOC_pred + 0.01) - self.ocv_lookup(SOC_pred - 0.01)) / 0.02
        H = np.array([[dOCV_dSOC, -1, -1]])
        
        # 卡尔曼增益
        S = H @ self.P_pred @ H.T + self.R
        K = self.P_pred @ H.T @ np.linalg.inv(S)
        
        # 状态更新
        innovation = V_meas - V_pred
        self.x = self.x_pred + K.flatten() * innovation
        
        # 协方差更新
        self.P = (np.eye(3) - K @ H) @ self.P_pred
        
        return self.x[0]  # 返回SOC估计值

注意:EKF对初始值敏感。如果初始SOC偏差太大(比如超过20%),滤波器可能收敛很慢甚至发散。我建议在系统上电时先用开路电压法粗估一个SOC,再交给EKF去微调。

3.5 调参经验与避坑指南

EKF最难的不是公式推导,而是调参。Q和R的取值直接影响滤波效果。我曾经在一个项目中,Q设得太小,滤波器几乎不相信测量值,结果SOC一直跟着安时积分漂。后来把Q调大了一个数量级,效果立刻好了。

这里分享几个经验:

参数 物理含义 调参建议
Q(过程噪声) 模型的不确定性 模型越不准,Q越大。一般从1e-5开始试
R(测量噪声) 传感器的噪声水平 根据电压采样精度定。12位ADC大概1e-3量级
P0(初始协方差) 对初始状态的信任度 初始SOC越不确定,P0越大。一般设0.1~1

还有一个坑:电池老化后参数会变。R0、R1、R2都会随着循环次数增加而变化。如果你用固定参数跑EKF,时间长了误差会越来越大。我建议每隔一段时间做一次参数辨识,或者用自适应EKF(AEKF)在线更新参数。

一句话总结:EKF把安时积分的“短期记忆”和开路电压法的“长期校准”结合在了一起。它不完美,但在工程实践中,是SOC估算最主流、最可靠的方法之一。

3.6 本章知识体系

下面这张图展示了EKF-SOC估算的核心逻辑,从模型建立到滤波迭代,再到参数调优,每一步都环环相扣:

EKF-SOC估算核心逻辑 输入:电流I、电压V 电池模型:二阶RC等效电路 状态:[SOC, V1, V2] 观测:Vt = OCV - V1 - V2 - R0*I EKF迭代过程 预测步 x_pred, P_pred 更新步 K, x_est, P_est 迭代反馈 输出:SOC估计值 ± 误差 关键调参:Q(过程噪声) | R(测量噪声) | P0(初始协方差) | 模型参数(R0, R1, R2, τ) 注意:电池老化后需重新辨识参数,否则误差会逐渐增大

好了,EKF在SOC估算中的应用就讲到这里。这套方法我在多个项目中验证过,只要参数调得好,精度完全能满足工程需求。下一节咱们聊聊更高级的无迹卡尔曼滤波(UKF)和粒子滤波,看看它们又是怎么解决非线性问题的。


公众号:蓝海资料掘金营,微信deep3321