资讯详情

资讯详情

修正EKF实现锂电池SOC老化自适应估计的Simulink仿真

1. 为什么要把老化塞进EKF——这套方法的实际价值先从一个很现实的问题说起锂电池的SOC荷电状态到底难在哪做过BMS电池管理系统相关工作的朋友都知道SOC不能直接测只能靠估计。最经典的做法是安时积分法也就是把电流对时间积分算出流出了多少电量再用额定容量去减。这个方法在实验室里跑出来挺准但放到实车上就露馅电流传感器有零漂、积分误差会累积、不同温度下电池可用容量不一样更麻烦的是电池会老化——同一个100%的电量新电池和用了两年的电池根本不是一回事。跑几千公里后安时积分法算出来的SOC经常和真实值差出10%~15%而这个误差会直接影响续航估算、充电策略以及均衡控制严重时甚至会造成过充过放缩短电池寿命甚至引发安全问题。我复现这篇论文的时候目标很明确不是简单地把经典EKF跑通而是去看它如何把老化这个变量纳入到EKF的框架里在电池参数随时间变化的情况下依然能让SOC估计保持稳定。这套思路的核心价值在于不换传感器、不加硬件、不依赖大数据训练只靠算法层面的修正就能把老化场景下的SOC误差从百分之十几压回个位数以内。对于做BMS算法、电池仿真以及相关课程项目的人来说这是一个性价比非常高的研究方向。这篇博文会讲清楚从电池建模、老化参数的引入方式、EKF修正逻辑到Simulink模型怎么搭、参数怎么调、结果怎么评估的完整链条。文章里的参数和结构以我复现的那篇论文为基础并结合了我自己搭建模型时的实际经验适合有一定Simulink基础、想深入理解电池SOC估计算法或者正在做电池相关课题的朋友参考。2. 复现前先搭骨架电池模型与老化参数建模2.1 二阶RC等效电路模型参数对应的物理意义SOC估计离不开电池模型。论文里用的是最常见的二阶RC等效电路模型一阶RC模型精度不够用于估算动态工况下的端电压会差很多三阶以上精度提升有限参数辨识成本却高不少。模型表达式如下[ U_{t}OCV(SOC,T)-U_{1}-U_{2}-I R_{0} ]其中 (U_{t}) 是电池端电压(OCV) 是开路电压与SOC和温度相关(R_{0}) 是欧姆内阻(U_{1}) 和 (U_{2}) 分别是两个RC网络的极化电压。两个RC网络各有各的物理意义(R_{1}C_{1}) 用来描述电化学极化过程时间常数通常在几秒到几十秒对应电池在充放电瞬间的快速电压响应(R_{2}C_{2}) 用来描述浓度极化过程时间常数可以达到几十秒甚至几分钟对应的是锂离子在电极内部的扩散过程。这两个时间常数的差异非常关键因为在动态工况比如实车的加减速下电压的快变和慢变是叠加在一起的只有一个RC网络根本分不开这两层响应。给出模型参数后仿真结构就清晰了。电流输入、OCV查表、欧姆压降和两个RC网络的电压分别计算最终得到端电压输出。这块在Simulink里可以用Simscape搭建也可以用基础的Simulink模块积分器、增益、查表手动搭论文复现推荐手动搭一是方便修改参数二是方便把老化表征塞进去。2.2 老化建模的两种思路容量衰减与内阻增长电池老化的表现宏观上最显著的是两点可用容量衰减和内阻增大。容量衰减意味着同样一个100%实际能放出的电量变少了内阻增大意味着同样的电流激励下端电压的波动幅度变大、极化效应更明显。论文里对老化的处理是参数时变——把 (Q)容量和 (R_{0})欧姆内阻从固定值改成随时间缓慢变化的量。容量衰减可以用SOH健康状态来描述我用的衰减规律是[ Q_{aged}Q_{new}\times SOH,\qquad SOH1-k_{deg}\cdot N_{cycle} ]其中 (k_{deg}) 是每循环一周的容量衰减率(N_{cycle}) 是等效循环次数。这个式子非常简化真实的衰减还和温度、放电深度DOD、充放电倍率强相关但作为仿真的老化规律够用了它能把容量随时间缓慢变小这个趋势模拟出来。内阻增长我采用的是分段模型前200个循环内阻增长较慢之后开始加速。原因是SEI膜固体电解质界面膜在前期生长速率低后期破裂-再生长过程会加剧电解液消耗宏观表现就是内阻加速上升。如果有实验数据完全可以把 (Q) 和 (R_{0}) 随循环次数的变化做成矩阵直接插入查表模块。我习惯先在论文给的规律下跑通再用实验数据替换这样能快速验证算法可行性这个顺序很重要——刚上来就用实测数据你分不清误差是模型不准还是算法本身有问题。2.3 SOC-OCV关系曲线整篇仿真成立的基础OCV-SOC曲线是整个估计过程的基准线。EKF的观测方程依赖端电压而端电压模型里的OCV项又要通过SOC去查表所以如果这条曲线不准后面所有计算结果都会带偏。论文里给的是磷酸铁锂电池的OCV-SOC数据特点是中段非常平缓SOC 20%~80%之间OCV几乎不动这给EKF带来了一个致命问题中段SOC变化引起的电压变化太小卡尔曼滤波观测更新的权重很难起作用系统主要靠状态预测在撑着时间一长误差就漂了。我在实际建模中先把OCV-SOC数据以0.1%的SOC间隔插值保证查表光滑同时把OCV对SOC的导数 (dOCV/dSOC) 预计算成另一张表直接在EKF的雅可比矩阵里查不再每个步长重新数值求导。这个预处理要花几分钟但能省掉后面无数定位问题的工夫尤其对于中段平缓的磷酸铁锂这是必须做的前置步骤。3. 修正EKF的核心改动不是推翻是补缺口3.1 传统EKF用在电池上会在哪里失效先说EKF的基本逻辑。电池的离散状态空间方程可以写成[ x_{k1}f(x_{k},u_{k})w_{k} ] [ y_{k}h(x_{k},u_{k})v_{k} ]传统的EKF把状态向量设为 ([SOC,U_{1},U_{2}]^{T})也就是把SOC和两个极化电压作为状态用安时积分更新SOC用一阶惯性响应更新两个极化电压。观测方程是端电压模型。每一步做状态预测、误差协方差预测、卡尔曼增益计算、状态更新、误差协方差更新。问题出在哪呢EKF里的电池模型默认是参数不变的。当电池老化后(Q) 变小、(R_{0}) 变大但EKF里用的还是出厂标定参数状态更新方程里的安时积分项会系统性偏大因为实际容量变小了观测方程里的欧姆压降项会系统性偏小因为内阻变大但没被识别出来这两个误差方向还不一样互相耦合叠加最后的SOC估计就会越来越偏。很多文章在常温新电池工况下跑EKF结果很漂亮一到老化工况就垮掉原因就在这里——模型失配了但算法的观测修正能力又不足以纠正这么大的失配量因为卡尔曼增益里没有相应的自由度去修正参数级错误。3.2 修正方案一容量与内阻的在线更新论文使用的第一种修正思路是不把老化的影响当作噪声而是当作一个可辨识、可更新的参数。具体做法保留SOC-(U_{1})-(U_{2})三个状态同时增加一个容量状态 (Q) 和一个内阻状态 (R_{0})状态向量变成 ([SOC,U_{1},U_{2},Q,R_{0}]^{T})。然后在状态转移方程里对 (Q) 和 (R_{0}) 做大幅度慢漂移假设认为它们的噪声极小过程噪声方差设得很小主要靠观测方程来修正——端电压残差里包含内阻和容量的信息通过EKF的增益就能把参数慢慢拉到真实值附近。EKF的增益分配天然能做到各取所需SOC的快速变化靠观测值快速修正(Q) 和 (R_{0}) 的慢速漂移靠长期累积的微小残差逐步修正。用一个不太严谨但很直观的类比这就像调一个带自动校准的体重秤——每次称体重时秤不仅显示重量还顺便根据多次称量的统计偏差悄悄修正自己的零点漂移。EKF里的 (Q) 和 (R_{0}) 更新就是这种顺手修正。3.3 修正方案二把老化参数做成扩展状态后的锯齿效应把 (Q) 和 (R_{0}) 纳入状态之后会遇到一个EKF里的典型问题状态量的可观测性不一致。SOC和两个极化电压的观测量端电压与它们的关系是强相关的而容量 (Q) 的观测量本质是SOC变化率 × 电流只有在连续充放电过程中才能积累信息静止状态下 (Q) 完全不可观测协方差增长会导致数值不稳定。论文里处理方式是给 (Q) 的过程噪声设成很小时同时限制 (Q) 的更新步长每步最多修正0.01%实际上是用一个软限幅方式来避免EKF因为个别异常观测而大幅跳变。在实际仿真中我也观察到另一个现象如果 (Q) 的初值设置有偏差EKF前几百秒会陷入一个锯齿状态——SOC估计值上下震荡同时 (Q) 也在缓慢爬升。这种情况说明参数激励不足解决方法是在仿真工况里加入动态电流激励比如一个阶跃变化的电流序列而不是一直恒流充放电否则容量状态的辨识效率极低很容易因为动力不足而发散。3.4 修正方案三自适应过程噪声与观测残差的卡方检验论文还有一步很关键的处理观测残差的新息序列被用来动态调整过程噪声矩阵。传统EKF的 (Q) 和 (R)过程噪声协方差和观测噪声协方差都是靠经验标定的固定值这套标定方法正常情况下能把误差压住但一旦电池老化导致实测残差持续偏大固定噪声矩阵就会暴露出一个问题——滤波器不知道该信模型还是信测量。自适应调整的常见实现方式是用遗忘因子对新息协方差做指数平滑如果最近的残差统计值偏大就适当增大过程噪声 (Q)让滤波器更相信测量值如果残差统计值恢复正常再退回默认值。我实际测试下来这个策略确实能提升滤波器的鲁棒性但要注意遗忘因子的取值——太大会让调整跟不上参数变化太小会让噪声方差剧烈抖动反而放大估计波动。论文里给的经验参考值是0.95~0.99之间我测试下来0.97左右在这个场景下表现最稳定。4. Simulink仿真实现从模块搭建到参数整定4.1 整体模型架构与数据流整个Simulink模型我一共拆成了四大模块在模型中用子系统封装模块作用对应物理量工况输入生成电流序列含动态工况(I(t))电池模型计算端电压作为真实值输出(U_{t,true})老化参数模块按循环数更新 (Q) 和 (R_{0})(Q_{aged}), (R_{0,aged})修正EKF模块估计SOC与老化参数(\widehat{SOC}), (\hat{Q}), (\hat{R}_{0})数据流非常直接工况输入给电池模型电池模型输出真实的端电压这个端电压作为观测值送入修正EKF模块EKF内部用当前估计的状态和参数算出端电压预测值和观测值做差得到残差后进入卡尔曼更新环节。这里的关键是EKF不知道电池模型的真实参数 (Q_{aged}) 和 (R_{0,aged})它只能靠观测残差去估计这些参数。这样才能模拟出真实BMS场景下的算法表现。为了对比我还会跑一条不带老化修正的传统EKF分支保持正常参数固定不变作为对照组。这个对照组是整个仿真的价值标尺——如果修正后和修正前误差差不多说明算法改进没有意义只有在老化工况下修正后误差明显更小才能说明这套方法有效。4.2 电池模型模块参数时变在Simulink里的表达方式电池模型的核心是一个伏秒平衡方程离散形式[ U_{1,k1}U_{1,k}e^{-Ts/\tau_{1}}I_{k}R_{1}(1-e^{-Ts/\tau_{1}}) ] [ U_{2,k1}U_{2,k}e^{-Ts/\tau_{2}}I_{k}R_{2}(1-e^{-Ts/\tau_{2}}) ] [ SOC_{k1}SOC_{k}-\frac{I_{k}T_{s}}{Q_{aged}(N_{cycle})} ] [ U_{t,k}OCV(SOC_{k})-U_{1,k}-U_{2,k}-I_{k}R_{0,aged}(N_{cycle}) ]在Simulink里(Ts) 就是仿真步长。论文里用的是固定步长求解器步长 (Ts0.1s)这个步长既照顾了RC网络动态时间常数最短约1~2s又不会因为步长过小导致仿真时间过长。老化参数模块的推荐做法是用一个MATLAB Function模块输入为当前循环计数 (N_{cycle})输出为 (Q_{aged}) 和 (R_{0,aged})。函数内部就是一个查表或多项式插值function [Q_aged, R0_aged] aging_model(N_cycle) % 基于循环数的容量衰减与内阻增长模型 % 实测数据的简化为分段线性拟合 Q_new 2.6; % 额定容量 Ah R0_new 0.012; % 出厂内阻 ohm % 容量衰减分段线性 if N_cycle 600 Q_aged Q_new * (1 - 2.8e-4 * N_cycle); else Q_aged Q_new * (0.832 - 1.3e-4 * (N_cycle - 600)); end % 内阻增长分段线性 if N_cycle 400 R0_aged R0_new * (1 1.5e-4 * N_cycle); else R0_aged R0_new * (1.06 4.0e-4 * (N_cycle - 400)); end end注意这里的老化模型是剧本用来生成基准真值。而EKF内部的估计值在仿真开始时并不知道这些老化规律它只有一个初始参数按新电池给然后通过残差逐步逼近。这种剧本-演员分离的结构是复现论文最清晰也最不容易出错的框架。4.3 修正EKF模块MATLAB Function写法思路这是整套仿真的核心。在Simulink里我推荐用MATLAB Function模块而不是Simscape或专门的CFG模块因为EKF的迭代逻辑用代码表达最直观方便调试。模块的输入是端电压 (U_{t,true})、电流 (I) 和仿真时间输出是 (\widehat{SOC})、(\hat{Q})、(\hat{R}_{0}) 以及它们的方差。注意这里面有个细节MATLAB Function模块内部要保留上一采样步长的状态不能每次进来都重新初始化所以要用persistent变量保存状态向量和协方差矩阵。function [SOC_est, Q_est, R0_est, P_diag] EKF_SOC(U_meas, I, Ts) % 修正EKF状态向量 [SOC; U1; U2; Q; R0] persistent x P if isempty(x) x [0.8; 0; 0; 2.6; 0.012]; % 初始SOC80%参数按新电池 P diag([1e-3, 0.01, 0.01, 0.05, 1e-6]); % 初始协方差 end % --- 状态转移 --- SOC x(1); U1 x(2); U2 x(3); Q x(4); R0 x(5); tau1 5.0; R1 0.015; % 电化学极化固定 tau2 50.0; R2 0.02; % 浓度极化固定 % 下一个状态估计 SOC_next SOC - I*Ts/Q; % 注意容量是估计值非出厂值 U1_next U1*exp(-Ts/tau1) I*R1*(1-exp(-Ts/tau1)); U2_next U2*exp(-Ts/tau2) I*R2*(1-exp(-Ts/tau2)); Q_next Q; % 慢漂移 R0_next R0; % 慢漂移 x_pred [SOC_next; U1_next; U2_next; Q_next; R0_next]; % --- 雅可比矩阵 F状态转移线性化 --- % 对SOC求导d(SOC_next)/dSOC1, d(SOC_next)/dQ I*Ts/Q^2 F eye(5); F(1,1) 1; F(1,4) I*Ts/Q^2; F(2,2) exp(-Ts/tau1); F(3,3) exp(-Ts/tau2); % --- 预测协方差 --- Qn diag([1e-6, 1e-6, 1e-6, 1e-8, 1e-10]); % 过程噪声 P_pred F * P * F Qn; % --- 观测方程及其雅可比 H --- % 预测端电压 OCV OCV_table(SOC_next); % 需要外部查表函数 dOCV_dSOC dOCV_table(SOC_next); U_meas_pred OCV - U1_next - U2_next - I*R0_next; H zeros(1,5); H(1,1) dOCV_dSOC; H(1,2) -1; H(1,3) -1; H(1,5) -I; % --- 卡尔曼增益 --- R_meas 1e-3; % 电压测量噪声方差 S H * P_pred * H R_meas; K P_pred * H / S; % --- 状态更新 --- innov U_meas - U_meas_pred; x x_pred K * innov; % --- 协方差更新 --- P (eye(5) - K * H) * P_pred; % 输出 SOC_est x(1); Q_est x(4); R0_est x(5); P_diag diag(P); end这段代码有几个细节要特别强调第一(F(1,4)ITs/Q^2) 这行的来源是 (SOC_{next}SOC-ITs/Q) 对 (Q) 求偏导很多人会漏掉这个交叉项结果容量状态完全无法更新第二(OCV) 和 (dOCV/dSOC) 都是查表函数要确保输入 (SOC_{next}) 在插值范围内避免出现NaN把协方差污染掉第三(Qn) 中 (Q) 和 (R_{0}) 的过程噪声要设得比其他状态小很多否则EKF会把参数的随机波动当成真实变化导致估计方差偏大这也是前面慢漂移假设的直接实现。4.4 初始协方差、噪声矩阵与仿真步长的整定规律EKF参数整定是整个复现里最耗时的部分我梳理一下我的整定顺序和经验值初始协方差 (P_0)物理含义是对初始状态不确定性的度量。初始SOC不确定度大就设大比如0.1极化电压初始为0但可能有偏差就设为0.01左右(Q) 和 (R_{0}) 的初始不确定性设为额定值的5%左右。如果 (P_0) 全设得特别小EKF会过于自信后续观测值几乎不起作用如果设得特别大表现为初期估计震荡剧烈要几个工况周期才能收敛。过程噪声 (Q) 和观测噪声 (R)比值 (Q/R) 决定了滤波器在信模型和信测量之间的权重。我的经验是先用静态工况恒流粗调让SOC估计不发散再换动态工况细调让残差序列尽量白化——如果残差有明显相关性比如连续同正或同负说明模型有系统偏差或噪声矩阵比例不对如果残差随机且均值接近0基本上就调到位了。仿真步长 (Ts)用固定步长但 (Ts) 不是越小越好。步长太小单次观测更新的增益变化极小参数辨识时间会拉得很长步长太大状态转移线性化误差大一阶近似精度不够。我复现时用 (0.1s) 步长在 (Ts) 大于0.5s的实验中EKF在快动态工况下明显出现收敛变慢的问题。这些参数没有黄金法则必须结合具体电池参数、工况和噪声水平标定。可以把参数整定理解为调音响系统的EQ不同频段要配不同增益固定一套参数走天下是不可能的事。5. 结果验证与对比修正前后的差距有多大5.1 仿真场景设计为了检验算法效果我设置了两种老化程度下的工况对比。工况一**新电池初始状态**下的动态放电工况电流序列包含阶跃、脉冲和恒流段这个工况验证基础算法有效性工况二**老化电池模拟800循环后**下的同一工况此时容量衰减到约80%、内阻增长约25%用来检验修正EKF能否在参数失配的情况下维持估计精度。对照组就是标准EKF固定 (Q2.6Ah)、(R_{0}0.012\Omega)。在工况一里对照组和修正EKF的表现几乎一样误差都在1%~2%以内。到了工况二对照组的SOC估计迅速向上漂移——因为实际容量只有2.08Ah但标准EKF还在按2.6Ah做安时积分相当于每次积分都高估SOC误差随放电时间线性增长到工况结束时已经接近14%。而修正EKF在最初的几百秒内(Q) 值从2.6Ah逐步收敛到2.15Ah左右SOC估计误差被拉回到3%以内。修正前最大误差约14%修正后约2.5%这个差距就是考虑老化的价值。如果你复现时跑不出这种对比效果说明EKF的参数辨识没有真正生效大概率卡在交叉偏导项或过程噪声比例上。5.2 性能指标别只盯一个误差值论文里评价SOC估计效果常用的有三个指标RMSE均方根误差、最大绝对误差和收敛时间。RMSE反映整体估计质量最大绝对误差反映极端偏差风险收敛时间反映参数变化后的响应速度。我把三个都算了一遍场景标准EKF RMSE修正EKF RMSE标准EKF最大误差修正EKF最大误差新电池动态工况0.0120.0113.1%2.9%老化电池动态工况0.0820.02114.2%4.7%另外还需要量化参数辨识的收敛速度。仿真结果显示修正EKF在工况开始后约200秒左右(Q) 估计值已经收敛到真值的±2%范围内(R_{0}) 的收敛稍慢约400秒这与理论预期一致——内阻的辨识需要更丰富的电流变化激励恒流段对内阻辨识几乎没有贡献。只看SOC误差固然重要但算法内部参数的收敛趋势一样值得画出来看如果 (Q) 的估计方向一直不变说明系统对容量失配有持续的检测能力如果 (Q) 在真值附近反复震荡则说明过程噪声比例不合适需要做相应调整。5.3 仿真调试中容易踩的坑最后把我在复现过程中踩过的、代价最高的几个坑列在这里。坑一MATLAB Function里 persistent 变量的采样步长问题。在Simulink的离散求解器中MATLAB Function模块的执行频率取决于驱动信号的变化频率。这里建议把电流和电压信号经过一个零阶保持器再接进EKF模块确保每个仿真步长只计算一次。否则在信号跳变沿处模块可能被重复执行persistent变量会在同一个时间点被连续更新多次相当于在同一时刻执行了好几次卡尔曼更新协方差会被过度压缩看起来就是滤波器很快就死了后面完全靠预测在漂。坑二OCV查表函数在SOC超出[01]范围时的处理。估计值在动态工况中偶尔会短暂超出0~1区间尤其初始化阶段如果查表函数不做饱和处理会出现错误输出导致残差爆炸、协方差发散。我的做法是查表前对SOC做min(max(0)1))限幅并在输出端做同样的限幅处理。这个简单的保护能让稳定性提升一个量级。坑三老化参数的剧本和估计必须分开建模。真值电池模型里的 (Q_{aged}) 是严格按照老化规律变化的定值而EKF模块里的 (Q) 是估计值二者不能共用同一个信号线。如果你把EKF算出来的 (\hat{Q}) 直接送给电池模型作为容量参量系统就会形成自我实现的正反馈仿真结果看起来非常漂亮但完全丧失了验证意义。这是论文复现里最隐蔽也最致命的错误务必牢记。坑四固定步长仿真中 (OCV) 查表引起的代数环问题。EKF模块中的预测端电压需要查 (OCV(SOC_{next}))但 (SOC_{next}) 本身是模块内部状态不属于输入信号所以一般不会形成代数环。但是如果你把端电压预测值做成子模块输出然后用于计算残差Simulink可能误判出现代数环并报错或者采用变步长求解器。解决方式是检查求解器设置CPU时间允许的话优先选择固定步长的ode3/ode4从根上避开代数环问题。6. 关于复现这件事的一点个人体会论文复现最忌讳的事情就是一上来就闷头搭模型。先把论文里的公式全部手推一遍把每个状态变量的物理含义、每个噪声矩阵的作用都搞清楚再动手写代码——这样可以省下至少一半的调试时间。我这次复现最大的收获不是跑通了仿真而是真正理解了EKF的数学结构和电池模型的边界条件之间的关系比如容量这个参数不是在状态方程里顺便出现的它天生和SOC之间有交叉耦合如果忽略这个耦合整个状态估计的精度上限是很低的。在实际项目里这套修正算法的价值更多体现在长期使用场景电动车的电池包从出厂到退役中间经历几千次循环SOC估计不能越用越偏修正EKF正好让估计值在全生命周期内保持一致。当然它也有局限性——当老化参数发生突变比如某节电芯突然内短路时慢漂移假设下的EKF会反应迟钝这时需要结合电池不一致性检测或突变检测逻辑做兜底。如果你在复现过程中发现SOC估计在老化场景下仍然有较大稳态误差不妨重点检查两个地方一是观测方程对 (R_{0}) 的灵敏度是否足够电流太小的情况下内阻信息确实难以被有效提取二是状态向量的可观测性结构设计是否合理——容量和内阻同时放进状态并保持高精度估计本身就需要足够的激励条件来满足可观测性要求否则会出现参数相互吞噬的现象。遇到这种情况可以尝试分时辨识先通过短时间的动态工况辨识内阻再把辨识结果固定最后集中更新容量。虽然原理上不如联合估计优雅但工程上往往更稳。最后再分享一个小技巧调试EKF时建议把残差序列innov单独画出来看变化趋势和相关性。如果残差一直偏正或者偏负说明模型有系统偏差滤波器在努力追但追不上如果残差符合零均值白噪声特征那你的模型和滤波器已经处于非常好的匹配状态。这个技巧适用于几乎所有的滤波类算法调试算是隐藏在细节里的通用经验。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →