资讯动态

MATLAB实现电池SOC估算算法对比:安时积分、EKF与UEKF

发布时间:2026/10/19 7:34:37 来源:尧图企业网站定制
在做电池管理系统BMS算法预研时我一直想找一套能同时横向对比多种SOC估算策略的MATLAB仿真工程。市面上的开源代码大多只覆盖单一路线要么只有安时积分要么只写EKF能把安时积分法、扩展卡尔曼滤波EKF、以及基于无迹变换的UEKF无迹扩展卡尔曼滤波放在同一个框架下对比的完整项目并不多。这套代码恰好补齐了这个缺口。拿到后我先用标准工况跑通了全流程再花时间把三套算法的公式推导、MATLAB实现细节和调试过程逐行过了一遍。这篇就把整个实现过程、参数调节心得和踩坑记录整理出来供做电池SOC估计、BMS算法研究或者相关课程设计的同学参考。先说明一个容易混淆的点标题里的“UEKF”写作无迹扩展卡尔曼滤波算法实际工程项目里更多称它为UKFUnscented Kalman Filter无迹卡尔曼滤波它的本质是在扩展卡尔曼滤波的框架里引入无迹变换来替代一阶泰勒展开。下文统一沿用标题叫法用UEKF实现逻辑上就是UKF路线。1. 电池SOC估算的核心问题与方案架构1.1 为什么SOC估算这么棘手锂电池的SOC在工程上定义为当前可用容量占额定容量的百分比。手机上看电量百分比可以接受误差动力电池和储能电池不行。SOC估不准会直接引发两类问题一是充电时过充造成正极材料结构损坏和析锂风险二是放电时过放负极材料容易出现不可逆容量衰减。整车或储能系统中BMS的核心任务之一就是把这个百分比尽量算准、算稳。SOC估算难在三个层面电池开路电压OCV与SOC之间的关系是强非线性的且充电和放电方向上的OCV曲线存在滞后回环同一个SOC对应的OCV可能相差几十毫伏。电池内阻、可用容量会随温度、老化、电流倍率实时漂移模型参数不是恒定值。电流传感器存在零漂偏移和量化噪声纯积分类的估算方法误差会长期累积。所以在工业界SOC估算很少依赖单一方法。常见路线有开路电压查表法、安时积分法、卡尔曼滤波类在线估计法、神经网络回归法等。安时积分简单可靠但没有闭环修正能力卡尔曼滤波类方法可以用实测端电压持续修正状态估计误差恰好互补。这套MATLAB工程项目采用“安时积分做基准、EKF做基础滤波、UEKF做非线性增强对照”的组合架构在同一个仿真平台上跑三种算法便于直接比较精度和收敛特性。1.2 三种算法路线对比与选型逻辑做任何算法选型前先明确评估指标否则优化起来没有方向。这套工程里重点关注四项估计误差SOC估计值与参考真值之间的均方根误差RMSE和最大绝对误差。收敛速度当初始SOC给得不准时算法需要多长时间回到真实值附近。实时性单步迭代的计算量能否满足实际控制器在线运行要求。鲁棒性对电流噪声、电压噪声、容量误差和参数漂移的适应能力。三种典型方案的对比如下方案核心思路优点主要不足适用场景安时积分法对电流时间积分推算剩余电量简单直观、计算量极小、无模型依赖无闭环修正初值误差和电流偏移会不断累积短时估算、成本敏感的低端BMSEKF一阶泰勒展开线性化状态空间模型对一般非线性有修正能力计算量适中需要推导雅可比矩阵强非线性区域误差偏大中等精度BMS模型平滑时效果好UEKFUKF无迹变换采样逼近非线性分布无需雅可比精度可达二阶强非线性适应好计算量大一些参数维度较高时协方差稳定性要求高高精度BMS、动态工况复杂场景从表格能看出来三个方法之间不是替代关系而是“基准对照、基础方法、进阶方法”的递进关系。工程上用安时积分容易实现但是容易误差越积越大所以要给EKF和UEKF观察对比滤波收敛误差。1.3 仿真代码的整体模块划分这份MATLAB工程拿到手建议先看整体结构再动手改参数。按功能可以把代码切分为七个模块电池与工况参数定义段额定容量、初始SOC、采样时间、仿真时长。OCV-SOC标定段通过实验数据拟合开路电压与SOC映射关系。工况电流生成段可配置恒流放电、脉冲放电、动态工况序列。参考SOC真值生成段利用理想无偏电流计算真实SOC轨迹。安时积分法估计段仅基于电流积分实现估算。EKF估计段建立状态空间模型执行预测更新递推。UEKF估计段sigma点采样、非线性传播、统计矩更新。误差统计与可视化段绘制SOC曲线对比、误差曲线、RMSE指标。建议先把原工程直接跑通确认仿真曲线输出正常再逐个模块拆开读。不要一上来就乱改滤波器协方差矩阵否则连发散问题出在哪一步都定位不出来。2. 安时积分法的原理与MATLAB实现2.1 核心公式与误差累积机制安时积分法也叫库仑计数法公式非常简单SOC(k) SOC(k-1) - [η·i(k)·Δt] / (Q_nom·3600)参数含义SOC(k-1)上一时刻的荷电状态。i(k)当前时刻电流放电为正、充电为负单位安培。Δt采样步长单位秒。η库仑效率放电时取1充电时通常取0.98~0.99。Q_nom额定容量单位安时。这里有个单位换算容易踩坑Q_nom是安时i·Δt是安秒需要除以3600转成安时再参与计算。代码里如果忘记换算SOC变化会快3600倍仿真曲线看起来就像瞬间放空。安时积分的真正问题不在公式本身而在误差累积机制。假设电流传感器存在0.01A的零漂偏移对一块100Ah的电池连续工作10小时累计误差就是0.01×10/100 0.001只有0.1%看起来不大。但如果传感器零漂达到0.5A同样10小时的累计误差就有5%已经超出很多BMS的精度要求。更麻烦的是初始SOC如果给错积分法永远无法自我纠正因为它没有任何反馈通道。这也就是为什么纯安时积分在实际BMS中一定要配合静置工况下的OCV修正。2.2 MATLAB实现步骤与代码解读安时积分法在MATLAB里实现很简单核心循环如下function soc_count ampere_hour_integration(I, dt, Q_nom, soc_init, eta) N length(I); soc_count zeros(N, 1); soc_count(1) soc_init; for k 2:N soc_count(k) soc_count(k-1) - (eta * I(k) * dt) / (Q_nom * 3600); end end这段代码里I是电流向量放电方向为正。第k步的SOC等于上一步SOC减去当前步消耗的电量比例。如果充电阶段电流为负SOC会上升符合物理含义。实际工程里电流不是理想的连续信号传感器采样有量化误差因此更稳妥的做法是在修正初始化后使用cumtrapz做累积梯形积分或者直接循环累加。对于仿真验证循环累加和cumtrapz都能接受两者差异只在几分之一秒内不会影响结论。2.3 安时积分段的经验笔记库仑效率不要拍脑袋设成1。充电时锂离子会有部分损耗仿真中设0.98~0.99更贴近真实。电流方向约定必须全局统一建议放电为正、充电为负否则后面滤波算法里的状态方程符号会乱掉。安时积分的误差是确定性趋势不是零均值噪声滤波算法无法消除这种偏移只能靠OCV修正或电流传感器在线校准。3. EKF核心电池模型搭建与滤波器推导3.1 戴维南等效电路与状态空间方程EKF估算SOC不能凭空滤波必须先有电池的数学模型。这套工程采用一阶戴维南Thevenin等效电路模型开路电压源OCV、欧姆内阻R0、一个RC并联网络用来描述极化效应。RC网络里的R_p是极化电阻C_p是极化电容两者共同决定极化电压V_p的动态响应。模型端电压方程V_t OCV(SOC) - R0·i - V_p状态向量选择x [SOC, V_p]^T状态方程写为SOC(k1) SOC(k) - [η·i(k)·Δt] / (Q_nom·3600)V_p(k1) exp(-Δt/τ)·V_p(k) R_p·(1 - exp(-Δt/τ))·i(k)其中τ R_p·C_p是极化时间常数。第一个式子描述SOC随电流积分的变化第二个式子是一阶RC电路的离散化解含义是极化电压以时间常数τ指数衰减同时受电流激励驱动。从状态方程可以看出状态转移本身是线性的难点全在测量方程中OCV(SOC)这个非线性映射。EKF的做法是在每个时刻对OCV-SOC曲线做一阶泰勒展开用切线近似原曲线然后套用标准卡尔曼滤波的递推框架。3.2 OCV-SOC非线性的标定与拟合OCV-SOC曲线的准确性直接决定滤波效果。理想做法是拿到电池实验数据做分段倍率充放电后静置记录每个SOC点对应的稳定开路电压。工程仿真中如果拿不到实测数据常用多项式拟合实验数据来近似。拟合阶数不宜过高阶数太高会出现过拟合和数值震荡阶数太低又无法表达中间平台的平缓过渡。MATLAB里拟合多项式最小二乘很简单p polyfit(soc_vec, ocv_vec, 8); ocv_func (soc) polyval(p, soc);代码中soc_vec是从0到1离散化的SOC序列ocv_vec是对应的开路电压序列。多项式拟合在SOC两端会出现轻微发散尤其是接近0%和100%的区间因为实验数据在两端稀疏。建议在拟合后检查端点值如果出现明显扭曲可以对端点附近数据加权或改用分段样条拟合。3.3 EKF递推流程与MATLAB关键代码EKF每一时刻分两大步预测和更新。预测步x_pred f(x_est, I(k)); A [1, 0; 0, exp(-dt/tau)]; P_pred A * P_est * A Q;f是状态方程函数A是状态转移矩阵。因为状态方程是线性的所以这里的A是精确的不存在线性化误差。更新步H矩阵是测量方程对状态向量的偏导数即雅可比矩阵。端电压方程对SOC的偏导就是dOCV/dSOC对V_p的偏导是-1H [polyval(p_diff, soc_est), -1]; K P_pred * H / (H * P_pred * H R); x_est x_pred K * (V_meas - h(x_pred, I(k))); P_est (eye(2) - K * H) * P_pred;代码里polyval(p_diff, soc_est)是对OCV-SOC多项式求导后再代入当前SOC值。注意MATLAB的/运算符是解线性方程组这里写成矩阵右除等价于(PH)(HPHR)^(-1)数值上更稳定。EKF全套实现的伪代码可以整合为% 初始化 x_est [0.8; 0]; % 初始SOC和极化电压 P_est diag([0.1, 0.01]); for k 2:N % 预测 soc_pred x_est(1) - (eta * I(k) * dt) / (Q_nom * 3600); vp_pred exp(-dt/tau) * x_est(2) R_p * (1-exp(-dt/tau)) * I(k); x_pred [soc_pred; vp_pred]; A [1, 0; 0, exp(-dt/tau)]; P_pred A * P_est * A Q; % 更新 dOCV polyval(p_diff, x_pred(1)); H [dOCV, -1]; K P_pred * H / (H * P_pred * H R); v_pred polyval(p, x_pred(1)) - R0 * I(k) - x_pred(2); x_est x_pred K * (V_meas(k) - v_pred); P_est (eye(2) - K * H) * P_pred; end这里用一个细节说明EKF的工作原理当实测端电压V_meas高于模型预测值v_pred时残差为正卡尔曼增益K会把这个差异折算成对SOC的修正量。如果残差主要来自模型偏差而不是真实SOC变化滤波结果就会被带偏所以要保证模型参数尽量准确。3.4 EKF协方差矩阵调试心得EKF的调试核心在Q和R矩阵的选取上这两个矩阵分别反映模型不确定性和测量噪声强度。Q矩阵是过程噪声协方差对应状态方程的信任程度。Q太小时滤波器认为模型非常准修正能力弱估计结果会出现迟滞Q太大时滤波器对单次测量值过于敏感SOC曲线会剧烈抖动。R矩阵是测量噪声协方差对应端电压测量噪声水平。R太小会让滤波器盲目相信单次电压测量容易被噪声带偏R太大则会过度平滑响应变慢。实际调试建议先固定R再逐步增大Q。仿真中用电压传感器噪声标准差估算R的初始值比如电压噪声为0.01V则R0.01^21e-4。Q的初始值可以参考SOC过程噪声和极化电压过程噪声百分比估算再根据收敛速度和稳态误差微调。我自己的经验是Q对角线数量级可以设为SOC方差的1e-6~1e-4之间极化电压方差在1e-5~1e-3之间具体数值要结合工况噪声水平反复试。这类参数没有万能值换一组电池参数就得重新标定。4. UEKF无迹扩展卡尔曼滤波的建模与实现要点4.1 为什么还要引入UEKFEKF虽然适用范围广但有一个绕不开的约束它把非线性函数用一阶泰勒展开近似这在OCV-SOC曲线比较平滑的区域问题不大一旦进入曲线拐点区或者极化电压快速变化区线性化误差就会显著放大导致状态估计偏差。高阶项被直接截断信息丢失后就很难补回来。UEKF的核心思路是用无迹变换来处理非线性。选定一组带权值的sigma点让这些点直接通过非线性函数传播再用传播后的点集统计均值和协方差。这种方式不需要求导不需要雅可比矩阵精度上可以等价于二阶泰勒展开但实现上比推导二阶展开公式简单得多。打个类比EKF相当于拿一根切线去拟合弯曲的道路离切点近时误差小弯道急的地方就偏离了UEKF相当于在这条弯道上选几个有代表性的点把点逐个沿着真实道路走过去再根据这些点重新拟合出路况弯道再急也能抓住大体走向。4.2 sigma点选取与权重计算无迹变换标准做法是对n维状态向量取2n1个sigma点。假设当前状态均值为x̄协方差为P则sigma点按下式生成χ_0 x̄χ_i x̄ (sqrt((nλ)P))_i, i1,...,nχ_{in} x̄ - (sqrt((nλ)P))_i其中sqrt表示矩阵平方根可以用Cholesky分解得到。λ是尺度参数满足λ α^2·(nκ) - nα决定sigma点离均值的散布距离通常取0.001~1之间κ一般取0或3-n。对应权重为W_0^m λ/(nλ)W_0^c λ/(nλ) (1 - α^2 β)W_i^m W_i^c 1/[2(nλ)], i1,...,2nβ用于引入状态分布先验信息高斯分布时取2效果最好。MATLAB里生成sigma点的代码可以这样写function chi sigma_points(x, P, alpha, beta, kappa) n length(x); lambda alpha^2 * (n kappa) - n; chi zeros(n, 2*n 1); chi(:,1) x; sqrtP chol((n lambda) * P, lower); for i 1:n chi(:, i1) x sqrtP(:, i); chi(:, i1n) x - sqrtP(:, i); end end这样生成的是列向量排列的sigma点矩阵每一列代表一个采样点。Cholesky分解要求P是正定矩阵所以协方差维护非常重要一旦P出现非正定chol就会报错整个滤波随之崩溃。这也是UEKF调参时最常见的发散原因。4.3 UEKF递推流程与代码骨架UEKF在结构上仍然遵循经典卡尔曼滤波的预测-更新框架只是每一步都改为sigma点传播。整体流程如下。预测步将上一时刻的sigma点代入状态方程得到传播后的sigma点集加权计算预测均值和预测协方差X_pred zeros(n, 2*n1); for i 1:2*n1 X_pred(:,i) state_func(chi(:,i), I(k), dt); end x_pred sum(W_m .* X_pred, 2); P_pred zeros(n,n); for i 1:2*n1 diff X_pred(:,i) - x_pred; P_pred P_pred W_c(i) * (diff * diff); end P_pred P_pred Q;更新步将预测sigma点代入测量方程得到端电压预测点集计算测量均值、协方差和状态-测量互协方差进而得到卡尔曼增益Z_pred zeros(1, 2*n1); for i 1:2*n1 Z_pred(i) measure_func(X_pred(:,i), I(k)); end z_pred sum(W_m .* Z_pred, 2); S_z 0; S_xz zeros(n, 1); for i 1:2*n1 dz Z_pred(i) - z_pred; dx X_pred(:,i) - x_pred; S_z S_z W_c(i) * (dz * dz); S_xz S_xz W_c(i) * (dx * dz); end S_z S_z R; K S_xz / S_z; x_est x_pred K * (V_meas(k) - z_pred); P_est P_pred - K * S_z * K;这段代码里的state_func和measure_func分别对应离散状态方程和端电压方程和EKF里的模型完全一致只是不再需要计算雅可比矩阵H。正因为不需要求导UEKF对模型表达形式的适应性强很多哪怕把OCV-SOC曲线换成表格插值形式都能直接工作。4.4 UEKF与EKF的差异及调试注意点初次跑UEKF对比EKF时最明显的感受是UEKF的SOC估计曲线更稳定尤其在动态工况下大幅度加载和卸载电流的瞬间不会出现EKF那种尖峰式抖动。原因是sigma点保留了更多非线性信息测量更新对非线性区域的修正更平滑。UEKF调试时要特别注意三个参数α取值越小sigma点越靠近均值数值上更稳定但覆盖非线性范围也变小α太大会让sigma点跑太远局部线性假设失效。协方差矩阵P必须保持正定初始化时不要给对角线太大的值过大的P虽然能加快初始收敛但容易让Cholesky分解失效。测量噪声R的标定相同情况下UEKF不要设太小否则计算出的S_z矩阵条件数差求逆不稳定。我的实践体会是先确定模型参数再做滤波顺序不要反过来。很多UEKF跑发散并不是算法问题而是状态方程和测量方程里单位换算错误或者SOC方向符号反了。先单独调试安时积分确认SOC变化方向正确再上EKF最后上UEKF每一步的调试成本会小很多。5. 仿真对比结果与典型现象分析5.1 实验设置与指标说明我在本地复现这套工程时采用的实验条件如下电池额定容量100Ah标称电压3.7V。一阶RC模型参数R00.02ΩRp0.015Ω极化电容Cp1000F。采样周期1s仿真时长3600s。工况采用混合动态电流序列包含2C大倍率脉冲、1C持续放电和回馈充电段。端电压测量噪声标准差0.01V电流测量噪声标准差0.5A。初始SOC参考真值0.9三种算法的初始值均设置为0.8故意制造0.1的初始误差用于观察收敛能力。评价指标统一用SOC估计误差e SOC_est - SOC_true的均方根误差RMSE和最大绝对误差MAXE再统计进入稳态误差带的时间。5.2 三种算法的结果走向分析安时积分法的结果最直观因为没有反馈修正初始SOC误差0.1会一直保留在曲线上不仅不收敛还会随着电流积分误差累积越来越大。如果工况电流平均值不为零SOC曲线会在参考真值下方缓慢漂移漂移速度取决于电流传感器零偏和库仑效率误差。EKF的表现比安时积分好不少。初始阶段由于P矩阵初始值较大卡尔曼增益高大约十几秒内就能把0.1的SOC误差修正到误差带内。在OCV-SOC曲线较平滑的中间区间EKF的稳态误差能控制在1%左右。但进入SOC接近0.2以下的低电量区间时OCV曲线斜率明显增大一阶线性化误差集中暴露EKF的误差有所上升偶尔会出现小幅度波动。UEKF在同样条件下的收敛速度略慢于EKF原因在于sigma点传播的初始协方差调整需要多几步迭代但一旦进入稳态测试结果非常平稳。尤其是在动态工况的大电流脉冲变化过程中UEKF的SOC误差曲线没有出现明显的尖峰稳态RMSE相比EKF大约能降低三到四成最大绝对误差同样小得多。5.3 初始误差条件下的收敛行为对比这个点上三种方案的差异非常直观值得单独拎出来分析。安时积分法对初始SOC误差完全无修正能力它就像一个不带方向盘的车起步偏了就一直偏下去而且累积误差还会让偏差越来越大。EKF的收敛来源于端电压残差反馈。初始SOC给定0.8但真实是0.9时模型预测的开路电压偏低端电压预测误差通过卡尔曼增益转换成SOC修正量所以能在短时间内拉回正确值。收敛快慢由初始P和Q/R比共同决定P初始越大收敛越猛但振荡也会更明显。UEKF在相同初始条件下收敛更平滑因为它对非线性函数的处理精度更高每一轮修正量都经过sigma点统计加权不容易出现修正过头的情况。如果只看“从初始误差回到2%误差带”的时间EKF通常会更快如果看收敛后的波动方差UEKF优势更明显。这提醒我们选方案不能只看单一指标要结合目标工况更看重响应还是稳态精度。5.4 一个常被忽略的比较维度计算量仿真平台上两种滤波器的单步耗时差异基本可以忽略但移植到嵌入式MCU时就要慎重。EKF的计算量主要分布在雅可比矩阵乘法和协方差更新上UEKF还要额外计算2n1个sigma点的传播计算量大约是EKF的三到五倍。做工程选型时如果主控芯片算力受限EKF往往更实用如果算力冗余且追求精度UEKF值得上。仿真阶段最好两种都保留后续硬件测试时再按指标取舍。这套MATLAB工程的对比逻辑设计得比较合理它不只是比较两条滤波曲线还保留了安时积分作为基准对照能清楚看到滤波器闭环修正带来的增益到底有多大。6. 常见问题排查与项目扩展建议6.1 代码运行阶段的高频问题汇总我在跑这套代码时遇到的问题和排查思路做成速查表供参考。问题现象可能原因处理办法SOC曲线瞬间冲到0或1电流方向符号反向或容量单位换算错误先验证单步SOC变化确认I放电为正确认dt转小时EKF估计值发散为NaN协方差矩阵非正定或者R过小导致增益矩阵数值爆炸检查P初始化把R调大一个数量级重试UEKF的chol函数报错P矩阵失去正定性检查有无异常电压残差减小初始P或者给P加微小对角扰动OCV-SOC多项式在SOC接近0或1时出现不合理的电压倒挂多项式拟合端部震荡改用分段拟合或对SOC两端的拟合数据加权约束滤波曲线跟随电压曲线剧烈波动Q过大测量噪声信任过度减小Q同时检查端电压测量噪声设置是否合理安时积分和滤波曲线长时间平行不重合初始SOC设置不同或电流方向约定不统一统一三套算法的初始状态和电流符号约定有一条通用排查思路先用恒定电流小倍率放电工况测试如果连最简单的恒流工况都跑不对不要往动态工况或者参数标定上浪费时间。先确保电池模型和安时积分对再调试滤波器。6.2 模型标定阶段的常见陷阱RC参数标定是这套工程里最容易引入隐性误差的环节。用脉冲充放电实验数据做参数辨识时要特别注意静置时间必须足够长让极化电压完全恢复到稳定状态否则R_p和C_p的辨识值会耦合进OCV误差里。还有库仑效率的实际取值问题。工程上常见的做法是充电按0.98~0.99估算但不同温度下锂离子电池的库仑效率并不相同低温充电时损耗明显更大。仿真如果忽略这一点冬天低温工况下SOC估算偏差会显著增大。OCV-SOC曲线的温度修正也值得关注。常温下标定的OCV曲线在0℃或45℃下使用时同一SOC对应的OCV变化量可能超过几十毫伏对滤波器的测量更新形成系统性偏差。更精细的做法是做不同温度下的OCV表按当前温度插值使用。6.3 后续扩展方向建议这套工程已经跑通三条算法的对比扩展空间非常大。可以往双扩展卡尔曼滤波方向走同时在线辨识电池模型参数和SOC解决温度、老化引起的参数漂移问题。也可以加入带遗忘因子的递推最小二乘法在线更新RC参数再把更新后的参数传给EKF或UEKF使用。这两种方案都是目前BMS研究的热门方向。仿真层的延展可以做工况库扩展接入真实道路采集的电流电压数据或者标准工况测试序列观察三种算法在真实驾驶工况下的表现差异。再往下一层可以把MATLAB代码转换为嵌入式C代码在硬件在环平台上做实时性验证这一步会暴露很多仿真阶段注意不到的内存和时序问题。最后分享一点实操体会这套项目做完我最大的体会是滤波算法再花哨也要建立在正确的电池模型上。很多同学把大量时间花在调卡尔曼增益和协方差矩阵上结果发现误差来源其实是OCV曲线拟合不准或电流方向反了这种返工最不值得。强烈建议先花几天时间把电池等效电路模型和安时积分法彻底跑透再进入滤波部分。如果后续继续扩展这套代码我建议优先做两件事第一把电池模型参数从固定值改成在线辨识让三个算法在参数漂移下的表现差异体现出来第二加入不同温度下的OCV数据表看看滤波器对温度变化的适应能力。这些方向一旦展开这套MATLAB工程就从一个静态对比Demo变成一个可持续迭代的算法验证平台价值会高很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑