第2章:卡尔曼滤波入门:状态空间模型,线性卡尔曼滤波(KF)推导,SOC估计中的KF应用
各位同学,欢迎来到第二章。
上一章我们聊了SOC的基础概念。说实话,那只是开胃菜。真正让SOC估计从「猜」变成「算」的,就是卡尔曼滤波。我当年刚接触BMS时,看到卡尔曼滤波的公式,第一反应是——这玩意儿能用在单片机上?后来真做出来了,才发现它没那么神秘。
2.1 状态空间模型:把电池装进数学盒子
要理解卡尔曼滤波,先得搞懂状态空间模型。说白了,就是把电池系统用数学语言描述出来。
一个典型的状态空间模型包含两个方程:
- 状态方程:描述系统内部状态怎么随时间变化
- 观测方程:描述我们能测量到的数据跟状态的关系
拿电池SOC估计举例。状态变量通常选SOC本身,有时候还会加上极化电压。我习惯把SOC作为唯一状态变量,这样计算量小,适合嵌入式实现。
状态方程长这样:
x(k) = x(k-1) + (η·i(k)·Δt)/Q
其中:
- x(k) 是k时刻的SOC
- η 是库仑效率
- i(k) 是电流(放电为正)
- Δt 是采样周期
- Q 是电池容量
观测方程呢?我们测的是端电压:
y(k) = OCV(x(k)) + R₀·i(k) + v(k)
OCV是开路电压,跟SOC有非线性关系。R₀是内阻。v(k)是测量噪声。
2.2 线性卡尔曼滤波推导:一步步拆解
线性卡尔曼滤波,说白了就是五个公式来回跑。我刚开始学的时候,觉得这五个公式长得差不多,容易搞混。后来我总结了一个记忆方法——「预测-更新」两步走。
第一步:预测(时间更新)
- 状态预测:x̂(k|k-1) = A·x̂(k-1|k-1) + B·u(k)
- 误差协方差预测:P(k|k-1) = A·P(k-1|k-1)·Aᵀ + Q
第二步:更新(测量更新)
- 卡尔曼增益:K(k) = P(k|k-1)·Hᵀ·(H·P(k|k-1)·Hᵀ + R)⁻¹
- 状态更新:x̂(k|k) = x̂(k|k-1) + K(k)·(y(k) - H·x̂(k|k-1))
- 误差协方差更新:P(k|k) = (I - K(k)·H)·P(k|k-1)
你想想看,这五个公式其实就干了一件事——用测量值修正预测值。卡尔曼增益K(k)就是修正的权重。测量噪声大,K就小,我更相信预测;过程噪声大,K就大,我更相信测量。
2.3 SOC估计中的KF应用:从理论到代码
好了,理论讲完了。咱们看看怎么把卡尔曼滤波用到SOC估计上。
首先,得把电池模型线性化。前面说了,OCV-SOC是非线性的。但如果我们只在小范围内变化,可以近似看成线性。这就是扩展卡尔曼滤波(EKF)的思路,不过那是下一章的内容。这一章,我们先假设OCV-SOC是线性的。
线性化后的模型参数:
| 参数 | 含义 | 取值 |
|---|---|---|
| A | 状态转移矩阵 | 1(SOC自回归) |
| B | 控制输入矩阵 | η·Δt/Q |
| H | 观测矩阵 | ∂OCV/∂SOC(OCV曲线斜率) |
| Q | 过程噪声协方差 | 通常取1e-5 ~ 1e-3 |
| R | 测量噪声协方差 | 电压传感器方差,约1e-4 |
下面是一个简化版的C代码实现。我在实际项目中就是这么写的:
// 卡尔曼滤波SOC估计 - 简化版
typedef struct {
float x; // SOC估计值
float P; // 误差协方差
float Q; // 过程噪声
float R; // 测量噪声
float H; // 观测矩阵(OCV斜率)
} KalmanFilter;
void Kalman_Init(KalmanFilter *kf, float init_soc) {
kf->x = init_soc;
kf->P = 0.1f; // 初始不确定性
kf->Q = 1e-4f;
kf->R = 1e-4f;
kf->H = 0.8f; // OCV斜率,实际需查表
}
float Kalman_Update(KalmanFilter *kf, float current, float voltage, float dt) {
// 1. 预测
float x_pred = kf->x + (current * dt) / 3600.0f; // 安时积分
float P_pred = kf->P + kf->Q;
// 2. 计算卡尔曼增益
float K = P_pred * kf->H / (kf->H * P_pred * kf->H + kf->R);
// 3. 更新
float voltage_pred = kf->H * x_pred; // 预测电压
kf->x = x_pred + K * (voltage - voltage_pred);
kf->P = (1.0f - K * kf->H) * P_pred;
return kf->x;
}
实际应用中,有几个细节要注意:
- 初始化:初始SOC不准没关系,卡尔曼滤波会收敛。但P(0)要设大一点,表示我不信任初始值。
- 饱和处理:SOC必须在0~100%之间。我习惯在更新后加一个限幅。
- 噪声自适应:电流传感器在低电流时噪声大,可以动态调整R值。
嗯,说到这里,我想起一个案例。有一次做低温测试,-20℃下卡尔曼滤波发散得厉害。后来发现是OCV斜率变了,H矩阵没更新。从那以后,我都在代码里加了一个温度查表模块,根据温度动态调整H值。
最后,给大家一个建议:先用仿真验证,再上真电池。我习惯在MATLAB里搭好模型,跑一遍典型工况数据,看看收敛速度和稳态误差。没问题了再移植到嵌入式平台。这样能省很多调试时间。
下一章,我们会讨论扩展卡尔曼滤波(EKF),解决OCV-SOC非线性问题。到时候你会发现,线性KF是基础,EKF才是实战利器。