☰
基于Simulink的锂电池SOC估计EKF仿真模型搭建与调试
2026/10/20 8:25:13 网站建设 项目流程

做电池管理系统(BMS)或者写电池状态估算算法的人,大概率都见过这样的场面:充满电显示SOC 100%,开出去没多远突然掉到85%;或者充放电循环多次后,电量显示忽高忽低,像“薛定谔的猫”。我最近基于Simulink搭了一套锂电池SOC估计EKF仿真模型,把安时积分、开路电压、扩展卡尔曼滤波这三样东西串到同一条仿真链路上,跑通了从电池建模、参数设置到误差打分的完整流程。这篇就把模型怎么搭、参数怎么定、坑具体踩在哪里,一步步说清楚。

这篇内容适合三类人:刚接手BMS算法方向、需要用Simulink做算法验证的工程师;做毕业设计或课题、要交付“仿真+算法”结果的学生;以及纯做电化学、想明白SOC为什么能靠端电压和电流“估”出来的研究者。文章不堆公式,但核心公式一个不缺,实操细节按可复现的标准写,跟着做就能把模型跑起来。

1. 为什么SOC要“估”而不是“算”:安时积分法的边界

1.1 安时积分法的三个硬伤

安时积分法的思路非常直观:SOC(k+1) = SOC(k) - η·Ts·I(k)/Qn,说白了就是给电流“记账”,累计流进流出的电量。只要电流采样够准、初始SOC给得准、容量Qn是常数,这套方法在数学上是闭环的。但工程现实是,这三个“只要”没有一个能真正满足。

第一个硬伤是初值不可知。电池不是每次上车都从满电开始,上一次停车时的SOC本来就是个未知数。安时积分从一个错误的初值出发,误差不会缩小,只会原封不动地带下去。通俗讲,它只有记账功能,没有纠错功能。

第二个硬伤是电流传感器的零漂和噪声会持续累加。拿100Ah电池、0.05A的电流测量偏置举例:持续放电50小时,积分电量就会少算2.5Ah,对应SOC就差了2.5%。电流噪声经过积分之后,还会变成一个随机游走式的漂移,时间越长方差越大,SOC曲线会越来越“毛”。

第三个硬伤是Qn不是常数。容量受温度、老化、放电倍率共同影响,新电池和用了两年的电池,同样积分出的Ah数对应的SOC百分比并不相等。库仑效率η也不是严格等于1,尤其是在低温、大倍率工况下,充进去的电和放出来的电并不完全可逆。

1.2 SOC在数学上是个“状态估计问题”

如果我们把电池看作一个动态系统,能测到的物理量只有端电压U_t和电流I,而SOC恰恰是测不到的“隐藏状态”。这就不应该用积分去算,而应该用状态估计的思路去做:用一个模型预测SOC,再用端电压测量值去修正预测值。

端电压和SOC之间确实存在联系,就是开路电压-荷电状态曲线(OCV-SOC曲线)。但电池有内阻,有极化现象,测量到的端电压并不等于开路电压,中间还隔着欧姆压降和RC网络的极化电压。所以SOC估计问题天然是一个多状态问题:SOC、极化电压U1、极化电压U2都需要被估计出来,端电压只是外界能看到的那个“投影”。

这就把问题归入了卡尔曼滤波框架。卡尔曼滤波处理的就是“有噪声的动态系统状态估计”,它的思想是:模型不可全信,测量也不可全信,用协方差把两边的不确定性都量化出来,再做加权融合。

1.3 EKF的适用边界和代价

锂电池的OCV-SOC关系是强非线性的,标准卡尔曼滤波要求系统是线性的,所以这里用扩展卡尔曼滤波(EKF)。EKF的做法就是把非线性函数在估计点附近做一阶泰勒展开,用雅可比矩阵代替线性卡尔曼里的状态转移矩阵和观测矩阵。

代价有两个。第一,一阶线性化在强非线性区域会引入较大误差,尤其是磷酸铁锂电池,在SOC 20%~80%的平台区OCV斜率接近0,此时端电压几乎不随SOC变化,EKF会面临“弱可观测”问题,增益变小,修正能力变弱。第二,雅可比矩阵的计算必须正确,符号错一个、斜率方向反了,滤波器会直接发散,而不是温和地报错。

不过对多数三元锂电池和储能铁锂电池应用,只要OCV表建得够密、模型参数标定到位,EKF是性价比极高的方案,计算量远小于粒子滤波,精度又能压制住安时积分的累积误差。

2. 电池建模是EKF的地基:等效电路模型怎么选、参数怎么定

2.1 从Rint到二阶RC,模型选型不是越复杂越好

EKF的“模型”指的不是数学公式,而是电池本身的等效电路模型。最原始的叫Rint模型,一个开路电压源串一个内阻R0,它只能描述稳态端电压,完全没法表达电池充放电停止后电压回弹的动态过程。用它做SOC估计,观测残差会非常大,滤波器会疯狂修正SOC去“硬补”模型误差,估计结果全是毛刺。

好一点是一阶RC模型,在R0基础上加一个RC并联网络,用来表达电化学极化。一阶模型对三元电池的短时间脉冲响应描述尚可,但面对持续几十秒到几分钟的负载变化(比如动态工况),浓差极化的慢过程就漏掉了,残差里还会带出明显的时间相关成分。

二阶RC模型加两个RC网络,一个快时间常数(约几秒到几十秒),一个慢时间常数(约几十秒到几百秒),分别对应电化学极化和浓差极化。它的复杂度只比一阶多一个状态,但对动态端电压的拟合精度提升明显。三阶RC模型精度还会再高一点,但参数辨识难度和EKF计算量都在涨,边际收益越来越小。我这次模型选的就是二阶RC。

2.2 参数辨识的HPPC思路

模型里的R0、R1、C1、R2、C2和OCV-SOC曲线,不能拍脑袋定,需要用HPPC(混合脉冲功率特性)测试数据来辨识。HPPC的做法是:对电池施加一个10秒的恒定电流脉冲,然后静置足够长时间让电压回弹,记录完整的端电压响应曲线。

从这条曲线上可以读出三样东西:脉冲瞬间的电压跳变对应R0;脉冲结束后的快速回弹段对应R1-C1网络;缓慢回弹段对应R2-C2网络。实际操作时,我会先把OCV确定下来,用脉冲前静置末段的稳定电压作为该SOC点的开路电压,然后把电压响应曲线用最小二乘去拟合指数函数,解出电阻电容参数。

2.3 模型参数对EKF的影响要点

参数对SOC估计的影响,关键不在参数本身有多准,而在于参数和OCV表的相对关系。最容易出问题的是OCV曲线斜率在平台区太小:当dOCV/dSOC趋近0时,H矩阵对应位置的元素非常小,卡尔曼增益K变小,端电压的新息无法有效修正SOC,EKF退化成安时积分。

另一个容易被忽视的是RC时间常数。如果τ2设置得比实际小,静置回弹被模型高估,滤波器会把“电压还没回弹到位”误判成“SOC偏低”,产生系统性的负向偏差。所以模型参数一旦定下来,我不建议为了调EKF效果好而去反向改电池参数,那是自欺欺人的做法。

下面是二阶RC模型的一套典型参考参数,具体数值应该按自己电池的HPPC数据来标定:

参数物理含义参考值
Qn额定容量2.9Ah
η库仑效率0.995
R0欧姆内阻0.05Ω
R1电化学极化内阻0.02Ω
C1电化学极化电容2500F
R2浓差极化内阻0.03Ω
C2浓差极化电容5000F
τ1快RC时间常数50s
τ2慢RC时间常数150s

3. EKF从公式到锂电池落地:状态方程、观测方程与雅可比矩阵

3.1 三状态离散状态空间方程

把二阶RC模型离散化,状态向量取x = [SOC, U1, U2]^T,输入量为电流I,观测量为端电压U_t。离散时间步长Ts,状态方程如下:

SOC(k+1) = SOC(k) - η·Ts·I(k)/Qn

U1(k+1) = exp(-Ts/τ1)·U1(k) + R1·(1 - exp(-Ts/τ1))·I(k)

U2(k+1) = exp(-Ts/τ2)·U2(k) + R2·(1 - exp(-Ts/τ2))·I(k)

观测方程写为:

U_t(k) = OCV(SOC(k)) - U1(k) - U2(k) - R0·I(k)

这段看着简单,但符号约定一定要统一。我这里是放电电流为正,所以SOC在放电时减小;如果方向定义反了,整个EKF的收敛方向就完全错误,估计值会一路朝着反方向跑。

3.2 雅可比矩阵:解析法还是数值差分

EKF需要两个雅可比矩阵。状态转移雅可比A是状态方程对x的偏导,因为SOC更新与U1、U2无关,U1、U2更新与SOC无关,这个矩阵恰好是常值矩阵:

A = [[1, 0, 0], [0, exp(-Ts/τ1), 0], [0, 0, exp(-Ts/τ2)]]

观测雅可比H是观测方程对x的偏导。P矩阵第一列是OCV对SOC的斜率,这个斜率不能直接写表达式,因为OCV是查表函数,多用数值差分计算:

H = [dOCV/dSOC, -1, -1]

数值差分时我用中心差分而不是单边差分,步长delta取1e-3(SOC以小数表示时)。如果用百分比0~100表示SOC,步长取0.01左右,别搞混。

3.3 Q、R、P0三个矩阵的物理含义

EKF调参会卡死很多人,主要原因是不理解这三个协方差矩阵到底代表什么。

P0是初始状态估计的协方差。初始SOC把握越小,P0(1,1)就要设得越大。比如你认为初始SOC可能有±20%的误差,那么在SOC以0~1小数表示时,P0(1,1)可以给到0.04这个量级。P0给太小,滤波器会“相信”初始估计,收敛很慢。

Q是过程噪声协方差,对应模型预测的不确定性。Q(1,1)和电流传感器误差直接相关,SOC的方差增长率大约是(Ts/Qn)^2乘以电流噪声方差。但也别算得太“抠门”,模型本身还有误差,工程上通常把Q(1,1)设得比理论值大一些,给滤波器留跟踪余量。

R是测量噪声协方差,对应端电压传感器的噪声。电压测量精度如果是±5mV,R给(0.005)^2 = 2.5e-5这个量级比较合理。R太小,滤波器会过度相信单个电压采样点,输出噪声大;R太大,修正力度弱,SOC偏差消除慢。

下面是一套可以直接起步的初值,后面再根据仿真结果微调:

矩阵对角元素初始值说明
P0[0.01, 1e-4, 1e-4]SOC初值按±10%不确定度假设
Q[1e-7, 1e-6, 1e-6]SOC通道稍小,RC通道稍大
R2.5e-5对应5mV电压噪声

4. Simulink仿真模型搭建:模块划分、代码实现与参数配置

4.1 顶层结构:真实电池、EKF估计器、误差打点三部分

我搭Simulink模型的习惯,是把“真实被控对象”和“估计器”严格分开。顶层模型分三个子系统:

第一个是电池模型子系统,输入电流I,内部用二阶RC模型算出真实SOC和端电压Vt,真实SOC作为后续对比的基准真值。仿真里我们可以知道真值,这是Simulink做算法验证的最大优势,工程实测工况是拿不到真值SOC的。

第二个是EKF估计器子系统,输入电流I和端电压测量值Vt_meas,输出估计SOC。这里我给Vt_meas人为叠加一个高斯白噪声模块,标准差设5mV,用来模拟真实电压传感器的测量噪声。不加噪声的仿真是“闭卷考试”,加了噪声才是“开卷考真实力”。

第三个是数据对比区,用Scope把真实SOC、估计SOC、SOC误差、端电压新息同时录进去。仿真结束后,我再把数据导入工作空间算RMSE和最大误差。

4.2 EKF核心代码:MATLAB Function实现

EKF估计器我建议用MATLAB Function块实现,核心代码不长,逻辑在一百行以内能写完。把它封装成函数,方便在Simulink里反复调用,也方便单独做单元测试。

function [soc_est, U1_est, U2_est, P] = ekf_update(... soc_est, U1_est, U2_est, P, Vt_meas, I, Ts, p) % p 为参数结构体:Qn, eta, R0, R1, C1, R2, C2, Q, R tau1 = p.R1 * p.C1; tau2 = p.R2 * p.C2; a1 = exp(-Ts / tau1); a2 = exp(-Ts / tau2); b1 = p.R1 * (1 - a1); b2 = p.R2 * (1 - a2); % 1. 状态预测 soc_pred = soc_est - p.eta * Ts / p.Qn * I; U1_pred = a1 * U1_est + b1 * I; U2_pred = a2 * U2_est + b2 * I; x_pred = [soc_pred; U1_pred; U2_pred]; A = [1, 0, 0; 0, a1, 0; 0, 0, a2]; P_pred = A * P * A' + p.Q; % 2. 测量预测与雅可比 ocv_pred = interp1(p.soc_lut, p.ocv_lut, soc_pred, 'linear', 'extrap'); y_pred = ocv_pred - U1_pred - U2_pred - p.R0 * I; delta = 1e-3; dOcv = (interp1(p.soc_lut, p.ocv_lut, soc_pred + delta, 'linear', 'extrap') - ... interp1(p.soc_lut, p.ocv_lut, soc_pred - delta, 'linear', 'extrap')) / (2 * delta); H = [dOcv, -1, -1]; % 3. 卡尔曼增益与修正 S = H * P_pred * H' + p.R; K = P_pred * H' / S; innov = Vt_meas - y_pred; x_est = x_pred + K * innov; P = (eye(3) - K * H) * P_pred; P = (P + P') / 2; soc_est = x_est(1); U1_est = x_est(2); U2_est = x_est(3); end

有一点要特别提醒:代码里interp1用到了’extrap’外插选项。SOC估计值在收敛过程中可能短暂超出查表范围,不加上外插,Simulink会直接报错导致仿真中断。另外,P在更新后要做一次对称化处理,即P = (P + P') / 2,这能有效避免协方差矩阵在长时间仿真中偏离对称结构。

4.3 仿真工况与采样参数设置

EKF是离散算法,Simulink里要选离散求解器,比如定步长离散求解器,固定步长设1秒。RC时间常数最慢150秒,采样周期1秒足够捕捉动态。有些同学直接用连续求解器跑离散EKF,结果就是样条插值和固定步长行为对不上,白白浪费时间排查。

电流工况我建议至少跑三种:第一种恒流放电,1C持续放电到接近下限,验证SOC长时跟踪能力;第二种脉冲工况,1C放电10秒、静置100秒,循环几十次,验证电流突变时端电压回弹情况下的估计稳定性;第三种动态工况,从标准驾驶循环电流数据降采样后导入Signal Editor,验证随机负载下的表现。

初始条件故意让它错:把真实SOC初值设为85%,EKF估计器初始SOC设为60%,制造25个百分点的初值误差。这样跑仿真,能直接看到EKF能不能在几百秒内把估计值拉到真值附近,而安时积分在这个条件下永远拉不回来。这才是EKF的价值展示环节。

5. 调试实录:EKF在仿真中翻车的五种典型场景

5.1 初始误差下收敛慢:P0设置不合理

第一次跑仿真时,我明明设置了25%的初始SOC误差,结果估计SOC花了快两千秒才收敛,而且初始段出现明显的“平台期”,SOC几乎没有移动。查了之后发现是P0(1,1)给得太小,滤波器认为初始SOC很可信,卡尔曼增益K非常小,测量新息完全推不动SOC。

解决思路很直接:把P0(1,1)从1e-4提高到1e-2量级,同时保留RC通道的P0为1e-4。改完再跑,收敛时间缩短到大概一百秒内,初始段还能看到系统在“大幅度校正”SOC的摆动,这是P0偏大时正常的行为,不是故障。

这里也顺带解释一个现象:EKF开头如果有短暂的SOC方向性校正,说明初始误差确实被看到了;如果开头SOC纹丝不动,不是EKF没生效,而是P0给得太保守,K被压制了。

5.2 Q和R的搭配失衡:系统化扫描代替“玄学调参”

Q和R是最容易被当成“玄学”的部分,但其实有章法。我的调参顺序是:先把R固定下来,根据电压传感器噪声定死,不动态改;然后扫Q(1,1)。每组仿真跑完,看两条曲线:SOC估计误差曲线的收敛速度和稳态波动幅度。

Q(1,1)太小(比如1e-9)时,SOC曲线被模型“焊死”,误差消除慢,曲线平滑但存在长时间恒定偏差。Q(1,1)太大(比如1e-4)时,SOC会被每个电压噪声样本带着跳,收敛虽然快,但稳态波动大,看起来像锯齿。比较合适的区间通常落在1e-7到1e-6之间。

我建议把这个扫描过程电子表格化:每一行记录Q值、RMSE、最大误差、收敛时间四个指标。选RMSE和最大误差都相对低、曲线又不毛糙的点作为最终参数。不要凭感觉一次调一个数,那样只是碰运气。

5.3 雅可比矩阵出错:从“瞬间发散”到“软性偏差”

雅可比算错的后果分两种。最严重的一种是符号反了,比如dOcv的计算用了soc_pred减而不是加delta,H矩阵的符号系统性错误,卡尔曼增益方向反了,仿真开始后几百毫秒内SOC估计值直接冲到0或1,然后一飞冲天。

还有一种更隐蔽的软性偏差:数值差分步长delta选得太大,dOcv被平滑掉一部分,导致修正力度不足,SOC误差收敛到某个固定偏置就不再动了。检查方法很简单,把dOcv单独拉出来打印,对照OCV曲线手动算一下斜率,看数量级是否匹配。SOC以小数表示时,dOcv的单位是V,典型值在0.05到0.5之间,如果你打印出来是0.0005,那基本是单位或步长出问题了。

5.4 长时间静置后电压回弹造成的误判

脉冲工况跑完后我会加一段30分钟零电流静置,模拟电池停车休息。这个阶段端电压会慢慢回弹,真实电池的回弹过程比较长,而二阶RC模型只有一个150秒的时间常数,到了静置后半段,模型预测的U2已经快要衰减到0,实际电池还有残余极化电压。

结果就是测量端电压比模型预测的偏高,EKF把这个残差误判为“SOC偏低了”,于是把SOC往低修正。反映在曲线上,静置期间真实SOC几乎不变,估计SOC却往下掉了一两个百分点。这个现象不是参数没调好,而是模型本身对超长静置过程描述不完备。

工程上的做法是加静置检测:当电流接近0且持续超过阈值后,降低观测更新的权重,或者切换到OCV插值修正模式。仿真里你至少要知道这个误差来源存在,别把静置段的偏差全部算到EKF头上。

5.5 代数环和协方差退化

MATLAB Function块里如果直接用当前时刻的估计SOC去计算当前时刻的观测方程,而观测方程又依赖当前时刻的输入电压,Simulink会检测到代数环。最直接的提醒是仿真变慢或求解器报错。解决办法是在状态量输出后加Unit Delay,让滤波器基于上一拍的估计值来做当前拍的新息更新,这样更符合EKF的离散序列逻辑。

协方差退化问题则出现在长时间仿真中:P矩阵虽然做了对称化,但还是可能因为数值误差失去半正定性,尤其是卡尔曼增益很大时。除了对称化处理,我还会在每一步后做一次特征值检查,发现负特征值就钳位到0;更稳妥的写法是直接用Joseph形式的协方差更新公式,它在理论上有更好的数值稳定性。

故障现象根因处理手段
初始SOC不收敛P0(1,1)过小提高到0.01量级
稳态曲线锯齿严重Q过大Q(1,1)下调一个数量级
长期恒定偏差dOcv数值差分错误或步长过大校验斜率及量纲
静置段SOC往下掉慢极化模型误差加静置检测降权
仿真卡顿或发散代数环/P非正定加Unit Delay、用Joseph形式更新

6. 仿真结果怎么看:误差指标、调参策略与工程化差距

6.1 用RMSE和最大误差量化估计表现

跑完仿真第一步,先把真实SOC和估计SOC导到工作空间,计算均方根误差RMSE和最大绝对误差MAXE。我这次仿真在1C脉冲工况下,初始SOC误差25%、电压噪声5mV的设置下,RMSE大概在0.8%到1.5%之间,最大误差出现在初始收敛段能到2%左右,稳态段最大误差会缩小到1%以内。不同电池参数和噪声水平下数字会有浮动,但量级可以作为参考。

单看RMSE还不够,还要看误差曲线随时间的变化趋势。理想曲线应该是:初始段一次性收敛,中间没有二次跳变,稳态在0附近小幅波动。如果误差曲线在某个工况切换点出现一个“鼓包”,说明模型在那个动态段的预测有系统偏差,值得回去查RC参数。

6.2 从仿真到工程落地的三个差距

仿真通过不等于产品可用,至少有三个差距需要正视野。第一个是电流传感器噪声和零漂的真实性。仿真里我给的是纯高斯白噪声,但实际电流传感器的零漂往往带温度漂移和低频率漂移,这会让Q(1,1)的标定在台架上失效。工程上通常要外加零漂校准算法和电流偏置估计,甚至把它也扩展成EKF的状态。

第二个是温度变化。OCV-SOC曲线、内阻、容量都随温度变化剧烈,仿真如果不加温度补偿,冬天低温环境下估计误差会显著变大。工程化的做法是把OCV表变成OCV(SOC,温度)的二维查表,同时用温度修正Qn。

第三个是算力约束。EKF本身的矩阵运算量很小,3x3矩阵在任何MCU上都不是负担,真正的成本在OCV表的二维插值和代码生成后的定点化处理。如果做嵌入式移植,协方差矩阵建议改成单精度浮点,并做好溢出保护。

6.3 从EKF出发还能往哪走

这套模型跑顺之后,很自然的扩展方向有三个。第一个是参数在线辨识,把R0、R1、C1、R2、C2也纳入滤波框架,构成“双EKF”或“联合EKF”,状态估计和参数更新同时跑,应对老化后参数漂移。第二个是换UKF,Sigma点滤波在OCV平台区这种强非线性区域的估计精度通常比EKF更好,代价是计算量翻几倍。第三个是SOC与SOH联合估计,把容量Qn作为慢时变状态量,通过长期观测来追踪电池健康度衰减,这套模型里其实已经预留了容量作为参数的入口,改起来并不难。

我对这套Simulink模型最深的感受是:EKF不是“无脑滤波”,它能发挥多少功力,七成取决于电池模型精度和参数标定,两成取决于Q/R的物理意义是否理解到位,真正落到矩阵公式上的反而是最后一小步。如果哪天你调试时发现估计SOC和真值之间总有一截恒定偏差,优先去查OCV表建得准不准,别急着动Q和R,那是绝大多数调参玄学的真正根源。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询