扩展卡尔曼滤波(EKF)与自适应扩展卡尔曼滤波(AEKF)SOC 估算实现文档(基于本工程)
本文档面向工程 S32K146OFBMU_B/,给出可直接落地到现有调度与接口的 EKF/AEKF SOC 估算实现方案。
工程当前 SOC 以“安时积分 + 修正 + 平滑显示”为主,且在 SocSoeLibAllTask() 中预留了“SOC/SOE 扩展卡尔曼”分支但未实现(空语句)。本方案将 EKF/AEKF 作为“估算器”,对安时积分 SOC 做在线校正,并与现有 CorrGNowCapBySocAPI() 等接口兼容。
目录
理论基础
1) 为什么需要 EKF/AEKF
本工程当前 SOC 主体为安时积分(Coulomb Counting),在动态工况下会受到以下误差累积影响:
电流零漂/比例误差:积分误差随时间累积。
容量、效率、温度的非线性:电池有效容量、充电效率随温度/倍率变化。
端电压与 SOC 的非线性关系:静置或小电流工况下,端电压更能约束 SOC;大电流时必须考虑内阻与极化。
EKF 用“电池模型 + 电压观测”持续校正 SOC;AEKF 在 EKF 基础上进一步在线自适应噪声协方差((Q/R)),提升跨工况鲁棒性。
2) EKF/AEKF 在本工程里的角色
建议采用“安时积分作为预测,EKF/AEKF 作为校正”:
预测(Prediction):根据采样电流积分更新 SOC(工程已有成熟实现)。
校正(Update):用端电压(或平均单体电压)与模型生成的估计电压比较(创新量),对 SOC 做修正。
对外输出:仍走工程现有 SOC 输出链路(显示平滑、组间同步、修正策略等),EKF/AEKF 只给出“建议 SOC/容量修正量”。
电池等效电路模型
本工程未看到现成的 OCV-SOC 查表和 RC 模型参数表,因此 EKF/AEKF 必须补齐两类基础能力:
OCV(SOC, T):开路电压与 SOC/温度的映射(查表 + 插值)。
ECM 参数(R0、R1、C1…):至少一阶 Thevenin(1RC)即可支撑工程级 EKF。
1) 推荐模型:一阶 Thevenin(1RC)
状态选取(最小可用形态):
[ \mathbf{x}= \begin{bmatrix} z \ v_p \end{bmatrix} ]
(z):SOC(0~1)
(v_p):极化电压(V)
输入:
- (i):电流(A),本工程约定:负号为充电(见
GetGSampOutCurrAPI()注释)。
观测:
- (v):端电压(V),可选用电池组采样总电压或单体平均电压映射后的等效值。
连续模型:
[ \dot{z} = -\frac{\eta(i,T)}{Q_n(T,SOH)} i ] [ \dot{v}_p = -\frac{1}{R_1 C_1} v_p + \frac{1}{C_1} i ] [ v = OCV(z,T) - iR_0 - v_p ]
其中:
(R_0):欧姆内阻
(R_1,C_1):极化支路参数
(\eta):库伦效率(可先简化为 1,后续在调参中加入充电效率)
(Q_n):当前可用容量(可取工程
GetGroupTotalCapAPI()或其温度/衰减修正版本)
2) 离散化(适配本工程周期)
本工程 SOC/SOE 总任务 SocSoeLibAllTask() 在 50ms 触发,内部有 500ms 分支可放 EKF/AEKF。
若 EKF 运行周期为 (\Delta t = 0.5s),则:
[ z_{k+1} = z_k - \frac{\eta}{Q_n} i_k \Delta t ] [ v_{p,k+1} = a v_{p,k} + b i_k ]
其中:
[ a=e^{-\Delta t/(R_1 C_1)},\quad b=R_1(1-a) ]
观测方程:
[ v_k = OCV(z_k,T_k) - i_kR_0 - v_{p,k} ]
3) OCV-SOC 查表与插值
建议使用分段线性插值:
输入:SOC(0
1 或 01000)、温度(可先只做 25℃一条曲线,后扩展多温度面)输出:OCV(V,或 mV)
导数:EKF 需要 (\frac{dOCV}{dz})(可由相邻点斜率近似)
EKF算法实现
1) EKF 结构(2 状态 1 观测)
预测:
[ \hat{x}{k|k-1} = f(\hat{x}{k-1|k-1}, u_k) ] [ P_{k|k-1} = F_k P_{k-1|k-1} F_k^T + Q ]
更新:
[ y_k = v_k - h(\hat{x}{k|k-1},u_k) ] [ S_k = H_k P{k|k-1} H_k^T + R ] [ K_k = P_{k|k-1} H_k^T S_k^{-1} ] [ \hat{x}{k|k}=\hat{x}{k|k-1}+K_k y_k ] [ P_{k|k}=(I-K_k H_k)P_{k|k-1} ]
2) 雅可比矩阵(离散模型)
对 (x=[z, v_p]^T):
- 状态转移雅可比(线性近似):
[ F_k= \begin{bmatrix} 1 & 0 \ 0 & a \end{bmatrix} ]
- 观测雅可比:
[ H_k= \begin{bmatrix} \frac{dOCV}{dz} & -1 \end{bmatrix} ]
3) 输入/观测量的工程单位换算
本工程可直接用以下接口(注意单位与符号):
电压:
GetGSampSumVoltAPI():电池组采样总电压,单位 0.1VGetGCellAvgVoltAPI():单体平均电压,单位 1mV
电流:
GetGSampOutCurrAPI(),单位 0.1A,负号为充电温度:
GetGCellAvgTempAPI(),单位 1℃SOC:
GetGRealSocMilliAPI()或GetGBattSocAPI(),单位 0.1%
建议在 EKF 内部统一使用 SI 单位(V/A/s),并将 SOC 使用 01 浮点或 01000 整型(千分比)统一。
4) EKF 输出如何回灌到工程 SOC
工程提供 “按 SOC 修正容量”接口:
CorrGNowCapBySocAPI(u16 soc):按目标 SOC(0.1%)修正当前容量
建议策略:
EKF 更新后的 (z) 转换为
soc_milli = z * 1000(0.1%)设置“允许修正阈值”(例如 0.5% 以上才修正),避免抖动
在电池信息就绪且非严重保护时才允许修正(例如参考
EnerGetGroupBattReadyHook()与保护状态 Hook)
AEKF算法实现
AEKF 的关键是让 (Q/R) 随工况变化而自适应,工程上常用两类做法(推荐从简单稳定的开始):
1) 基于创新量的 R 自适应(推荐起步)
创新量 (y_k) 反映“电压预测误差”。当电压噪声或模型失配变大时,增大 (R) 可以降低对电压的信任,避免 SOC 被错误拉动。
一种工程可用形式:
[ R_k = clamp(R_{min},\ \lambda R_{k-1} + (1-\lambda) y_k^2,\ R_{max}) ]
(\lambda):遗忘因子(例如 0.95~0.995)
clamp:限定上下界防止数值发散
2) Q 自适应(适合模型不确定较大场景)
当倍率变化导致极化参数变化明显时,增大过程噪声 (Q)(尤其是 (v_p) 的过程噪声)能提高对变化的跟踪能力。
可用简单规则:
当 (|i|) 大于某阈值或变化率大时:增大 (Q_{v_p})
静置/小电流时:减小 (Q_{v_p}),并可启用 OCV 强约束
3) 与工况模式联动(本工程强烈建议)
本工程已有充放电状态与工作状态接口(例如 GetGChgDhgStateAPI()、GetGWorkStateAPI()),可用来切换 AEKF 参数集:
静置(Idle):小电流,R 小、Q 小,强化 OCV 约束
放电(Dhg):R 适中、Q 适中
充电(Chg):考虑库伦效率 (\eta < 1),并适当增大 R(充电时电压波动更敏感)
系统集成方案
1) 现有调度与接入点(必须遵守本工程时序)
调度链路:
Task50ms()周期调用SocSoeLibAllTask()(见Sources/OSUser/OSUserHOOK.c)SocSoeLibAllTask()内部sTime0~19 循环:case 2/12:500ms 周期,注释为 “SOC、SOE 扩展卡尔曼算法任务”,目前为空(见Sources/Funtion/SocLib/SocUserAPI.c)
因此 EKF/AEKF 建议在 case 2 与 case 12 中调用:
SocEkfTask_500ms()或SocAekfTask_500ms()
2) 数据流(建议实现形态)
输入(来自现有系统信息层接口):
(v):
GetGSampSumVoltAPI()或GetGCellAvgVoltAPI()(i):
GetGSampOutCurrAPI()(T):
GetGCellAvgTempAPI()初始 (z):
GetGRealSocMilliAPI()(或上电恢复 SOC)容量 (Q_n):
GetGroupTotalCapAPI()(mAh)或工程已有修正后的容量接口(若存在)
输出(回灌到现有 SOC 体系):
CorrGNowCapBySocAPI(soc_ekf)(建议带阈值/限速)可选:将 EKF 估算的极化电压、创新量、R/Q 自适应值作为调试量记录(便于调参)
3) 与现有 SOC 修正/同步/显示的关系
本工程已有:
SocSoeAllCorrTask():温度修正、电压末端步进修正、多源融合修正SocSoeTogetherSyncTask()/SocSoeGroupSyncTask():SOC/SOE 同步SocDisplay.c:显示平滑
建议 EKF/AEKF 的输出定位为“更可靠的真实 SOC”,再由现有模块完成显示与同步。
也就是说:EKF 不直接改显示值,而是改“真实 SOC(容量)”,最终通过现有链路自然传递。
代码实现
1) 推荐新增文件组织(贴合现有工程结构)
在 Sources/Funtion/SocLib/ 新增:
SocEkf.h / SocEkf.c:EKF 核心(含模型、预测/更新)SocAekf.h / SocAekf.c:AEKF 扩展(或在SocEkf.c内可配置开关)BatteryModel.h / BatteryModel.c:OCV 查表、dOCV/dSOC、ECM 参数获取(可按温度/SOH/倍率分段)
在 Sources/Funtion/Parameter/ 或 Sources/Funtion/SocLib/ 增加参数入口(两种方式二选一):
参数表方式:支持 EEPROM/Flash 参数化(适配不同电芯)
常量表方式:先固化一条电芯曲线,便于快速跑通,再做参数化
2) 对接 SocSoeLibAllTask() 的改动点
在 Sources/Funtion/SocLib/SocUserAPI.c 的 case 2/12 中调用 EKF/AEKF 任务函数(500ms)。
3) 必须实现的最小接口(建议)
EKF/AEKF 模块对外提供:
void SocEkfInit(void);void SocEkfTask500ms(void);u16 SocEkfGetSocMilli(void);(可选)
BatteryModel 模块提供:
float OcvFromSoc(float soc_0_1, float temp_c);float dOcvdSoc(float soc_0_1, float temp_c);void EcmParamGet(float soc_0_1, float temp_c, float soh_0_1, float* r0, float* r1, float* c1);
参数调优
1) 先决条件(否则 EKF 很难收敛)
电流标定:电流零漂/比例误差需可控(否则 EKF 会长期“追着错误跑”)
电压标定:电压采样偏差会直接映射到 SOC 偏差
容量基准:
Q_n要与实际电池匹配(至少同量级),且随 SOH/温度变化要能被近似
2) ECM 参数(R0、R1、C1)初值建议
没有离线辨识数据时,可用“可收敛的保守初值”先跑通:
(R_0):用静置小电流阶跃下的 (\Delta V/\Delta I) 粗估
(R_1,C_1):让极化时间常数 (\tau=R_1C_1) 处在 5~60s 的合理范围(取决于电芯)
3) 噪声协方差 (Q/R) 调参要点
R(电压测量噪声):
R 小:SOC 更“相信电压”,收敛快但可能抖动
R 大:SOC 更“相信积分”,稳定但纠偏慢
Qz(SOC 过程噪声):
- 通常很小(预测主要由积分决定),用于容纳积分模型误差
Qvp(极化状态噪声):
- 决定对动态极化的跟踪能力,倍率变化大则应增大
AEKF 调参建议:
- 先固定 Q,只做 R 自适应(创新量法),等稳定后再做 Q 的工况自适应。
4) 工况门限建议
静置判定:(|i| < I_{idle}) 且持续 (t_{idle})(例如 (|i|<0.02C),持续 60s)
更新使能:
电池未就绪时禁用(参考
EnerGetGroupBattReadyHook())高压/低压保护、严重故障时禁用(避免模型失效)
测试验证
1) 分阶段验证策略(推荐)
阶段A:离线回放验证(推荐先做)
采集(或录波)电压/电流/温度/原 SOC
在 PC 端跑同一套 EKF/AEKF(或用同参数对比)
对比:SOC 漂移、动态响应、静置收敛
阶段B:台架动态工况
恒流充放电、脉冲功率、UDDS 类工况
对比真值:高精度库伦计/容量计
阶段C:整机长期漂移
温度变化、不同倍率、不同 SOH 条件下
指标:SOC 偏差均值/方差、末端一致性、静置收敛速度
2) 关键观测指标(建议记录)
EKF:创新量 (y)、增益 (K)、估算电压 (\hat{v})
AEKF:(R_k)、(Q_k) 的在线变化
估算状态:(z)、(v_p)
触发条件:静置判定、更新使能/禁止原因
3) 回归与安全性
EKF/AEKF 上线后必须验证对现有功能无负面影响:
SOC 不应出现突跳(现有显示平滑可辅助,但源 SOC 仍需限幅/限速)
保护阈值与限值计算依赖 SOC 的模块(如限流)要在典型工况下回归