行业资讯

基于扩展卡尔曼滤波的锂电池SOC估算:从原理到MATLAB/Simulink仿真实践

发布时间:2026/8/4 17:52:53
基于扩展卡尔曼滤波的锂电池SOC估算:从原理到MATLAB/Simulink仿真实践 在实际的电池管理系统BMS开发中准确估算锂电池的荷电状态State of Charge, SOC是核心挑战之一。SOC直接反映了电池的剩余电量其估算精度直接影响电动汽车的续航里程预测、能量管理策略以及电池的寿命和安全。然而SOC无法通过传感器直接测量它受到电池老化、温度、充放电倍率等多种因素的耦合影响是一个典型的状态估计问题。卡尔曼滤波及其扩展算法因其在处理动态系统噪声和测量噪声方面的优势已成为解决这一问题的经典且有效的方法。本文旨在为从事BMS算法开发、嵌入式软件或新能源汽车相关领域的工程师和研究者提供一个从理论到实践的完整指南。我们将深入探讨如何将卡尔曼滤波应用于锂电池SOC估算并构建一个可运行、可观测的仿真模型。文章不仅会解释卡尔曼滤波的核心思想更会聚焦于如何将其与电池模型如等效电路模型结合处理实际工程中的非线性问题。通过一个完整的MATLAB/Simulink仿真案例你将理解如何搭建模型、设置参数、运行仿真并分析结果最终掌握一套可用于实际项目前期验证的SOC估算方法。1. 理解SOC估算与卡尔曼滤波的结合点在直接进入代码和仿真之前必须厘清两个核心概念为什么SOC需要“估算”而不是“测量”以及卡尔曼滤波为何适合这项任务。1.1 荷电状态SOC的本质与挑战SOC定义为当前电池剩余容量与其标称容量的比值通常以百分比表示。其数学定义简单SOC Q_remaining / Q_nominal * 100%。但问题在于Q_remaining剩余容量无法直接获得。在实际应用中最朴素的方法是安时积分法Coulomb Counting其公式为SOC(t) SOC(t0) (1/Q_nominal) * ∫ i(τ) dτ积分区间从t0到t。这种方法严重依赖电流传感器精度和初始SOC值SOC(t0)的准确性。任何微小的电流测量漂移或初始误差都会在积分过程中不断累积导致估算结果随时间严重发散。因此纯积分法无法单独用于长时、高精度的SOC估算。为了修正积分误差必须引入其他可观测的物理量进行反馈校正。电池端电压是一个与SOC存在非线性映射关系的可观测量。通过建立描述电池内部动态的数学模型如等效电路模型将模型预测的端电压与实际测量的端电压进行比较其差值即“新息”或“残差”就包含了SOC误差的信息。卡尔曼滤波正是一种利用这种“预测-测量-校正”框架最优地融合模型预测和实际测量从而高精度估计系统内部状态如SOC的算法。1.2 卡尔曼滤波的核心思想与工程化适配标准卡尔曼滤波KF针对的是线性高斯系统。其核心是一个五步循环状态预测、协方差预测、卡尔曼增益计算、状态更新、协方差更新。对于工程师而言可以将其理解为一个“带置信度的传感器融合器”。状态预测根据上一时刻的状态如SOC、极化电压和系统模型包括输入电流预测当前时刻的状态。这个预测是有误差的误差大小由过程噪声协方差矩阵Q描述。测量预测根据预测的状态通过观测模型通常是电池的端电压方程预测当前时刻的观测值端电压。增益计算与状态更新将实际测量的端电压与预测的端电压进行比较。卡尔曼增益K决定了我们应该在多大程度上信任这个测量差值来修正我们的状态预测。如果测量噪声很大R大则K小更相信模型预测反之则更相信测量。协方差更新更新状态估计的不确定性协方差矩阵P为下一轮迭代做准备。然而电池系统本质上是非线性的。电池的开路电压OCV与SOC的关系是非线性的模型参数如内阻也随SOC、温度变化。因此标准KF不能直接应用。工程上主要采用两种扩展扩展卡尔曼滤波EKF对非线性系统模型和观测模型进行一阶泰勒展开在局部线性化然后应用标准KF公式。这是最常用、实现相对简单的方法。无迹卡尔曼滤波UKF采用无迹变换来近似非线性函数的概率分布通常比EKF有更高的精度和更好的数值稳定性尤其对于强非线性系统但计算量稍大。本文将重点介绍实现更广泛、更易于理解的EKF方法并提供一个完整的仿真框架。理解了EKF迁移到UKF或其他非线性滤波器将更加顺畅。2. 仿真环境准备与电池模型建立在开始算法实现前需要准备好仿真环境和定义清晰的电池模型。这是所有后续工作的基础。2.1 工具与环境准备我们选择MATLAB/Simulink作为仿真平台因为它提供了强大的矩阵运算、控制系统工具箱和直观的模型搭建界面非常适合算法原型验证。必需软件MATLAB R2018b或更高版本推荐R2020b以上需安装Simulink和Control System Toolbox。推荐工具Simscape Electrical可用于更精细的电池物理建模但非必需优化工具箱用于参数辨识。工作目录创建一个独立的项目文件夹例如BMS_SOC_EKF_Simulation用于存放所有脚本、模型和数据文件。2.2 建立电池等效电路模型ECM为了应用卡尔曼滤波我们需要一个能够描述电池外部特性端电压、电流与内部状态SOC、极化效应关系的数学模型。二阶RC等效电路模型因其在精度和复杂度间的良好平衡而被广泛采用。该模型包含以下组件开路电压源OCV(SOC)反映SOC与电池电势的非线性关系是模型的核心。欧姆内阻R0代表电池的瞬时内阻产热主要来源。两个RC并联网络(R1, C1)和(R2, C2)分别模拟电池的短时电化学极化和长时浓度极化动态特性。其状态空间方程可描述如下状态方程描述内部状态演化SOC(k1) SOC(k) - (η * Δt / Qn) * I(k) w1(k) U1(k1) exp(-Δt/(R1*C1)) * U1(k) R1*(1 - exp(-Δt/(R1*C1))) * I(k) w2(k) U2(k1) exp(-Δt/(R2*C2)) * U2(k) R2*(1 - exp(-Δt/(R2*C2))) * I(k) w3(k)其中[SOC; U1; U2]为状态向量I为输入电流放电为正充电为负η为库仑效率通常充电小于1放电等于1Qn为额定容量w为过程噪声。观测方程描述可测量的端电压Ut(k) OCV(SOC(k)) - I(k)*R0 - U1(k) - U2(k) v(k)其中Ut为观测到的端电压v为测量噪声。2.3 获取模型关键参数OCV-SOC曲线与RC参数模型参数R0, R1, C1, R2, C2以及OCV(SOC)函数需要通过实验数据辨识获得。对于仿真我们可以使用公开数据集或构造一组合理的典型参数。以下是一个用于仿真的锂电池参数示例基于某三元锂电池数据近似我们将其保存在一个MATLAB脚本文件battery_params.m中% battery_params.m - 定义电池模型参数 % 电池基本信息 battery.Q_nominal 2.3 * 3600; % 额定容量单位As (2.3Ah) battery.eta 1; % 库仑效率简化设为1 % 等效电路模型参数 (ECM Parameters) battery.R0 0.025; % 欧姆内阻单位Ohm battery.R1 0.015; % 第一个极化电阻单位Ohm battery.C1 2400; % 第一个极化电容单位F battery.R2 0.020; % 第二个极化电阻单位Ohm battery.C2 18000; % 第二个极化电容单位F % OCV-SOC 查表数据 (典型三元锂电池需根据实际电池测试) % SOC 从 0 到 1间隔 0.1 battery.SOC_lookup 0:0.1:1; battery.OCV_lookup [3.0, 3.4, 3.55, 3.65, 3.73, 3.78, 3.84, 3.92, 4.02, 4.12, 4.2]; % 可以使用 polyfit 或 fit 函数生成一个多项式拟合函数便于计算 % battery.OCV_fun (soc) interp1(battery.SOC_lookup, battery.OCV_lookup, soc, spline);在实际项目中需要通过HPPC混合脉冲功率特性测试等实验来精确辨识这些参数。仿真中我们可以利用这些参数生成“真实”的电池行为数据再用EKF算法去估算以验证算法性能。3. 扩展卡尔曼滤波EKF算法的实现有了电池模型接下来就是将EKF算法与模型结合。我们将分步骤在MATLAB中实现一个完整的EKF-SOC估算器。3.1 定义状态向量与系统方程首先在MATLAB中定义离散化的状态空间方程。创建一个函数文件battery_state_eq.m。function [x_next, A, B] battery_state_eq(x, I, dt, battery) % 电池状态方程及雅可比矩阵计算 (用于EKF) % 输入 % x: 当前状态 [SOC; U1; U2] % I: 输入电流 (A) % dt: 采样时间 (s) % battery: 包含所有电池参数的结构体 % 输出 % x_next: 下一时刻状态预测 % A: 状态转移矩阵的雅可比 (df/dx) % B: 控制输入矩阵的雅可比 (df/du) SOC x(1); U1 x(2); U2 x(3); Qn battery.Q_nominal; eta battery.eta; R1 battery.R1; C1 battery.C1; R2 battery.R2; C2 battery.C2; % 状态预测 SOC_next SOC - (eta * dt / Qn) * I; tau1 R1 * C1; alpha1 exp(-dt / tau1); U1_next alpha1 * U1 R1 * (1 - alpha1) * I; tau2 R2 * C2; alpha2 exp(-dt / dt2); U2_next alpha2 * U2 R2 * (1 - alpha2) * I; x_next [SOC_next; U1_next; U2_next]; % 计算雅可比矩阵 A df/dx A zeros(3,3); A(1,1) 1; % d(SOC_next)/d(SOC) A(2,2) alpha1; % d(U1_next)/d(U1) A(3,3) alpha2; % d(U2_next)/d(U2) % 其他偏导为0 % 计算雅可比矩阵 B df/du (uI) B zeros(3,1); B(1) -eta * dt / Qn; % d(SOC_next)/dI B(2) R1 * (1 - alpha1); % d(U1_next)/dI B(3) R2 * (1 - alpha2); % d(U2_next)/dI end3.2 定义观测方程及其雅可比矩阵接着定义观测方程端电压计算及其对状态的偏导雅可比矩阵H。创建文件battery_measure_eq.m。function [V_est, H] battery_measure_eq(x, I, battery) % 电池观测方程及雅可比矩阵计算 (用于EKF) % 输入 % x: 当前状态 [SOC; U1; U2] % I: 输入电流 (A) % battery: 包含所有电池参数的结构体 % 输出 % V_est: 估计的端电压 % H: 观测矩阵的雅可比 (dh/dx) SOC x(1); U1 x(2); U2 x(3); R0 battery.R0; % 通过查表或拟合函数计算OCV OCV interp1(battery.SOC_lookup, battery.OCV_lookup, SOC, spline); % 估计端电压 V_est OCV - I * R0 - U1 - U2; % 计算雅可比矩阵 H dh/dx H zeros(1,3); % dV/dSOC d(OCV)/dSOC % 这里使用数值微分来近似OCV-SOC曲线的斜率更准确的做法是存储导数曲线 dSOC 1e-6; OCV_plus interp1(battery.SOC_lookup, battery.OCV_lookup, SOCdSOC, spline); H(1) (OCV_plus - OCV) / dSOC; % 近似为OCV-SOC曲线在当前SOC点的斜率 H(2) -1; % dV/dU1 H(3) -1; % dV/dU2 end3.3 实现EKF迭代主循环现在将上述部分组合起来编写EKF的主估计算法。通常将其封装成一个函数或在一个脚本中实现。创建主脚本main_EKF_SOC_estimation.m。%% 主脚本EKF SOC估算仿真 clear; close all; clc; addpath(genpath(pwd)); % 添加当前目录及子目录到路径 % 1. 加载电池参数 battery_params; % 运行参数脚本载入battery结构体 % 2. 生成或加载仿真输入数据 (电流序列I_meas和电压序列V_meas) % 这里以UDDS城市道路循环工况的一部分为例生成仿真数据 load(simulated_battery_data.mat); % 假设该文件包含时间t, 电流I_meas, 真实电压V_meas_true % 注意在实际仿真中我们需要先用电池模型和“真实”SOC生成V_meas_true并添加噪声得到V_meas。 % 此处为简化假设I_meas和V_meas已准备好。 % 3. 初始化EKF参数 dt mean(diff(t)); % 采样时间 x_est [0.8; 0; 0]; % 初始状态估计 [SOC; U1; U2]初始SOC猜测为80% P_est diag([1e-4, 1e-4, 1e-4]); % 初始估计误差协方差矩阵表示对初始估计的不确定性 Q diag([1e-7, 1e-6, 1e-6]); % 过程噪声协方差矩阵需要调参 R 1e-4; % 测量噪声协方差电压测量噪声需要调参 n_states length(x_est); n_steps length(t); SOC_est_history zeros(n_steps, 1); V_est_history zeros(n_steps, 1); % 4. EKF主循环 for k 1:n_steps % 步骤1状态预测 [x_pred, A, B] battery_state_eq(x_est, I_meas(k), dt, battery); P_pred A * P_est * A Q; % 预测误差协方差 % 步骤2测量更新 [V_pred, H] battery_measure_eq(x_pred, I_meas(k), battery); K P_pred * H / (H * P_pred * H R); % 卡尔曼增益计算 x_est x_pred K * (V_meas(k) - V_pred); % 状态更新 P_est (eye(n_states) - K * H) * P_pred; % 协方差更新 % 存储结果 SOC_est_history(k) x_est(1); V_est_history(k) V_pred; % 存储的是预测电压也可用更新后的状态重新计算 end % 5. 绘制结果 figure; subplot(2,1,1); plot(t, SOC_true, b-, LineWidth, 1.5, DisplayName, 真实SOC); hold on; plot(t, SOC_est_history, r--, LineWidth, 1.5, DisplayName, EKF估算SOC); xlabel(时间 (s)); ylabel(SOC); legend; grid on; title(SOC估算结果对比); subplot(2,1,2); plot(t, V_meas, k., MarkerSize, 5, DisplayName, 测量电压); hold on; plot(t, V_est_history, g-, LineWidth, 1.5, DisplayName, 模型预测电压); xlabel(时间 (s)); ylabel(端电压 (V)); legend; grid on; title(端电压拟合情况);4. 在Simulink中搭建可视化仿真模型虽然脚本可以实现算法但在Simulink中搭建模型更直观便于集成复杂的工况输入和进行参数敏感性分析。下面概述搭建步骤。4.1 创建顶层模型新建一个Simulink模型命名为BMS_EKF_SOC_Sim.slx。从Simulink Library Browser中拖入以下模块From Workspace用于导入时间t、电流I_meas和电压V_meas数据。设置Data为[t, I_meas, V_meas]。MATLAB Function将前面编写的battery_state_eq和battery_measure_eq函数逻辑整合到一个或多个MATLAB Function模块中实现EKF迭代。也可以使用Embedded MATLAB Function。Memory用于存储上一时刻的状态估计x_est和协方差P_est实现迭代。Scope用于观察SOC估算结果、电压误差等信号。To Workspace将仿真结果如估算的SOC导出到MATLAB工作区。4.2 配置EKF迭代子系统在MATLAB Function模块中你需要编写类似主脚本循环中的代码。由于Simulink是时序驱动的每次调用Function模块就相当于执行一次EKF迭代。关键是要处理好状态的持久化使用persistent变量或通过输入输出端口连接Memory模块。一个简化的EKF函数模块内部代码框架如下function [SOC_est, V_est] EKF_Iteration(I_meas, V_meas, dt) % 输入当前测量电流、电压、采样时间 % 输出当前时刻SOC估计值、模型预测电压 % 注意此函数为简化示例需完整实现状态和协方差的持久化存储 persistent x_est P_est; % 持久化变量在仿真期间保持值 if isempty(x_est) % 初始化 x_est [0.8; 0; 0]; P_est diag([1e-4, 1e-4, 1e-4]); end % 定义电池参数应作为参数传入或定义为全局常量 battery struct(Q_nominal, 2.3*3600, R0, 0.025, ...); % --- EKF 预测步骤 --- [x_pred, A, B] my_battery_state_eq(x_est, I_meas, dt, battery); P_pred A * P_est * A diag([1e-7, 1e-6, 1e-6]); % --- EKF 更新步骤 --- [V_pred, H] my_battery_measure_eq(x_pred, I_meas, battery); K P_pred * H / (H * P_pred * H 1e-4); x_est x_pred K * (V_meas - V_pred); P_est (eye(3) - K * H) * P_pred; % --- 输出 --- SOC_est x_est(1); V_est V_pred; end4.3 连接信号与运行仿真将From Workspace模块的输出信号电流、电压连接到EKF函数模块的输入。将EKF模块输出的SOC_est和V_est分别连接到Scope和To Workspace模块。配置仿真时间为数据的总时长求解器选择定步长离散求解器如discrete。运行仿真后你可以在Scope中实时观察SOC的估算过程并与导入的“真实”SOC如果有进行比较。5. 参数调优、结果分析与验证算法搭建完成后其性能严重依赖于噪声协方差矩阵Q和R的设置以及初始状态的准确性。5.1 噪声协方差矩阵Q和R的调优Q和R不是通过物理测量直接得到的而是作为滤波器设计参数需要根据对系统模型信心和传感器精度的理解进行调节。过程噪声协方差 Q表示你对模型预测的不信任程度。如果模型非常精确Q可以设小如果模型简化较多或工况复杂Q应设大。通常Q是一个对角阵对角线元素分别对应SOC、U1、U2状态的过程噪声方差。SOC的过程噪声通常很小因为安时积分相对确定而极化电压的噪声可能稍大。调参方法从一个较小的值如1e-8开始逐渐增大观察滤波器收敛速度和稳定性。Q越大滤波器越信任测量收敛快但可能波动大Q越小越信任模型收敛慢但平滑。测量噪声协方差 R表示你对电压传感器精度的评估。可以通过传感器数据手册或实测数据的标准差来估算。例如如果电压测量误差的标准差约为0.01V那么R可以设为(0.01)^2 1e-4。一个实用的调参流程是固定一个合理的R基于传感器精度。将Q的对角线元素设为很小的值如1e-10运行仿真观察SOC估算曲线是否严重滞后于真实SOC。逐步增大Q直到估算曲线能较好地跟踪真实SOC的变化同时不会引入过多的噪声波动。微调Q中不同状态对应的元素例如如果SOC跟踪慢但极化电压跟踪快可以适当增大Q中对应SOC的元素。5.2 评估估算精度的关键指标仿真结果不能只看曲线是否“贴合”需要用定量指标评估最大绝对误差MAEmax(abs(SOC_true - SOC_est))。反映最差情况下的误差。均方根误差RMSEsqrt(mean((SOC_true - SOC_est).^2))。综合反映整体误差水平。收敛性在仿真开始时给定一个错误的初始SOC例如真实SOC为80%初始猜测为50%观察EKF需要多长时间或多少容量将估算值收敛到真实值附近例如误差小于3%。这是评价算法鲁棒性的关键。工况适应性在动态变化的电流工况如UDDS、NEDC下观察估算误差是否稳定。好的算法应在静态、缓变和剧烈动态工况下都保持良好性能。在MATLAB中计算这些指标并添加到主脚本的绘图之后% 计算并显示误差指标 SOC_error SOC_true - SOC_est_history; MAE max(abs(SOC_error)); RMSE sqrt(mean(SOC_error.^2)); fprintf(SOC估算性能指标:\n); fprintf(最大绝对误差 (MAE): %.4f%%\n, MAE*100); fprintf(均方根误差 (RMSE): %.4f%%\n, RMSE*100); % 绘制误差曲线 figure; plot(t, SOC_error*100, LineWidth, 1.5); xlabel(时间 (s)); ylabel(SOC估算误差 (%)); title(SOC估算误差随时间变化); grid on;6. 常见问题排查与工程实践建议在实际实现和调试EKF-SOC估算器时会遇到一些典型问题。6.1 算法发散或不收敛问题现象可能原因检查与解决思路SOC估算值迅速变得极大或极小或剧烈振荡。1.噪声协方差Q/R设置严重不合理。2.状态空间模型或雅可比矩阵计算有误。3.OCV-SOC曲线数据点过少或插值方法不当导致斜率计算异常。4.数值计算问题如矩阵(H*P_pred*H R)奇异或接近奇异。1.检查Q/R量级确保R与电压测量误差方差匹配约(0.01)^2量级Q比R小几个数量级开始调试。2.单元测试模型函数用固定输入单独测试battery_state_eq和battery_measure_eq验证输出是否合理。3.检查OCV-SOC数据绘制OCV-SOC曲线检查是否单调在SOC边界处外推是否合理。考虑使用更平滑的插值方法如spline或拟合函数。4.增加数值稳定性在计算卡尔曼增益时对(H*P_pred*H R)进行数值检查必要时添加一个极小正则项。使用double精度计算。6.2 估算结果滞后严重问题现象可能原因检查与解决思路SOC估算曲线能反映趋势但始终比真实SOC“慢半拍”在电流变化时尤为明显。1.过程噪声Q设置过小滤波器过于信任模型对测量的响应迟钝。2.电池模型参数不准确特别是极化电阻电容R1/C1, R2/C2未能正确反映电池动态。3.未考虑温度影响模型参数在仿真工况下已发生变化。1.增大Q矩阵中对应SOC和极化状态的分量让滤波器更快响应测量残差。2.重新进行参数辨识确保HPPC测试工况能激发电池的动态特性并使用优化算法如最小二乘法精确拟合RC参数。3.引入温度补偿建立关键参数如R0, R1, C1与温度的关系表在状态估计中根据实测温度查表更新参数。6.3 初始SOC误差收敛慢问题现象可能原因检查与解决思路仿真开始时给定一个较大的初始SOC误差算法需要很长时间或很大容量变化才能修正过来。1.测量噪声R设置过大导致卡尔曼增益K过小滤波器不信任测量值。2.OCV-SOC曲线在当前SOC区间过于平坦导致观测矩阵H的值很小测量对SOC的修正能力弱。3.初始误差协方差P_est设置过小滤波器过于自信初始猜测。1.适当减小R但需在传感器精度范围内。2.分析OCV-SOC曲线斜率在平坦区单纯依赖电压修正SOC是困难的。需要结合安时积分或利用电池静置后的开路电压来重新标定SOC。3.增大初始P_est特别是P_est(1,1)对应SOC的初始不确定性告诉滤波器你对初始SOC猜测很不确定。6.4 工程实践关键建议离线参数辨识与在线参数更新模型参数尤其是内阻会随电池老化SOH和温度显著变化。在量产BMS中需要设计在线参数辨识算法通常基于递归最小二乘法RLS或准备多组标定好的参数表根据SOH和温度进行切换。多模型融合与加权单一的等效电路模型可能无法在所有SOC和温度范围内都保持高精度。可以考虑准备多个模型根据工况选择或进行加权融合。安时积分作为基础EKF的输出是“修正后”的SOC。在工程实现中通常仍会维护一个安时积分的结果。EKF的作用是周期性地或在特定条件下如静置、满充对这个积分结果进行校准防止其发散。鲁棒性处理在代码中增加健全性检查。例如检查估算的SOC是否在[0, 1]合理范围内检查卡尔曼增益矩阵是否出现异常值当电压测量值长时间严重偏离模型预测时可能传感器故障能够触发故障诊断并切换到安全模式。从仿真到嵌入式代码的迁移仿真验证通过后需要将算法用C语言手动实现并关注定点化、计算效率、内存占用等问题。确保矩阵运算库如ARM CMSIS-DSP的可用性并对关键函数进行优化。通过本仿真研究你不仅掌握了基于卡尔曼滤波的锂电池SOC估算算法原理更获得了一套从模型建立、算法实现、仿真验证到问题排查的完整工程实践路径。在实际BMS项目中可以此为基础逐步加入温度补偿、老化修正、多模型等高级特性构建出满足车规级要求的鲁棒SOC估算模块。