从论文公式到 BMS 固件:FreeRTOS 与 EKF SOC 的工程结合

日期:2026-10-19。

在电脑上画出一条平滑的 SOC 曲线,和让这条曲线长期运行在 BMS 里,是两件有明显距离的事。距离往往藏在很普通的地方:温度到底是摄氏度还是十分之一摄氏度,电流和电压是不是同一时刻的样本,所谓的"500 ms 任务"究竟由谁调度,重启以后又该信任哪一个 SOC。

本文沿着一套 BMS 工程和一份独立 EKF SOC 交付代码,讨论这段距离如何缩短。BMS 工程使用 FreeRTOS、NXP SDK 和 Processor Expert 生成配置,现有容量算法包含安时积分、端点修正、SOC/SOE 同步和持久化;独立 EKF 包则实现了带电压偏置的二阶 RC 模型,并提供面向 BMS 接口的适配层。

这里有一个影响全文判断的现状:BMS 已预留 500 ms EKF 调用槽,但该位置仍为空,独立算法包尚不能视为已集成运行。 下文沿着调用链和递推公式核对现状,再讨论接入方案。公式按交付 C 代码整理;文中没有把仿真结果包装成台架经历,也没有把测试报告的历史描述当成当前固件已经具备的功能。

一、先看现有 SOC 的位置,再决定 EKF 应该放在哪里

这套工程的 SOC 并非一个每隔几百毫秒刷新一次的百分比变量。底层电流采样进入积分链,积分结果形成充放电量变化,容量模块维护当前容量与剩余容量,随后才产生 SOC 和显示数据。校准、同步、历史统计和掉电保存又会反过来影响这些状态。E1E2

flowchart LR A[电流采样与校准] --> B[1 ms 中断积分] B --> C[电量变化及累计量] C --> D[当前容量与剩余容量] D --> E[现有 SOC 和显示] F[端点校准与工况修正] --> D G[SOC 与 SOE 同步] --> D D --> H[持久化与历史统计] D -. 建议先提供初始化参考 .-> I[独立 EKF 影子估计] J[电压 电流 温度快照] -. 建议 .-> I I -. 建议 .-> K[比较日志与诊断]

如果接入 EKF 后只改显示 SOC,旧容量仍按原路径推进,那么显示、电量统计、SOE 和重启恢复就可能产生分歧。反过来,如果每轮 EKF 更新都回写容量,又会与旧算法的校准和同步争夺状态所有权。接入之前,必须回答"哪个模块在什么条件下修改哪一种状态"。更新函数只是这份接口约定中的一环。

独立包已有一个适合早期验证的选择:适配层保存影子 SOC,没有回写旧算法的容量和保护状态。这样可以先回答基本问题:输入单位是否正确,模型参数是否匹配,充放电切换时会不会出现异常,计算是否影响原调度。只有这些问题有了证据,才值得讨论如何将估计结果接入正式业务。E9

工程还存在另一条需要单独理解的路径:诊断、故障滤波、工作状态、安全等级和保护执行分别在调度链中运行。SOC 可以参与能量管理,却不能因此让模型估计直接接管过压、欠压或异常采样的处理。集成时应先画清数据流和控制流;仅凭 SOC 曲线变平滑,无法判断保护动作是否仍然满足设计要求。

阅读工程时也要区分"目录里有代码"和"当前配置启用了功能"。例如当前配置选择磷酸铁锂、关闭电池堆并机管理;数组最多容纳多少单体,只代表软件容量,不能直接当作现场实装规模。算法的估计对象必须与实际采样配置核对,不能由文件夹名称推断。

二、把二阶 RC 模型变成可以逐行对照的递推

把 EKF 拆成一次递推来看,计算顺序很清楚:先根据电流和电池模型预测下一时刻,再用测量电压修正预测。二阶 RC 模型用两个具有不同时间常数的支路描述电压动态,用欧姆电阻描述电流变化带来的即时压降。选择这个模型,是在计算量与电压动态描述能力之间作折中。

交付代码的状态向量为:
xk=zk, U1,k , U2,k , bkT x_k=z_k,\\ U_{1,k},\\ U_{2,k},\\ b_k^T xk=zk, U1,k, U2,k, bkT

其中, zz z 是范围为 0 到 1 的 SOC; U1 U_1 U1、 U2 U_2 U2 是两个 RC 支路的模型电压; bb b 是加在电压观测方程中的偏置项。 U1 U_1 U1、 U2 U_2 U2、 bb b 的单位都是 V, zz z 无量纲。输入电流 II I 以 A 为单位,约定放电为正、充电为负; Qn Q_n Qn 是以 A·s 表示的容量, η\eta η 表示模型使用的效率系数, Ts T_s Ts 是秒单位的步长。E6

在一个采样间隔内冻结参数,并将电流视为保持不变,可写出:
ϕj =exp⁡ (− Ts RjCj ) ,j=1,2 zk− = zk−1 − ηTsIk Qn Uj,k− =ϕj Uj,k−1 +Rj(1−ϕj)Ik bk− = bk−1 \begin{aligned} \phi_j&=\exp\left(-\frac{T_s}{R_jC_j}\right),\quad j=1,2\\ z_k^-&=z_{k-1}-\frac{\eta T_s I_k}{Q_n}\\ U_{j,k}^-&=\phi_jU_{j,k-1}+R_j(1-\phi_j)I_k\\ b_k^-&=b_{k-1} \end{aligned} ϕjzk−Uj,k−bk−=exp(−RjCjTs),j=1,2=zk−1−QnηTsIk=ϕjUj,k−1+Rj(1−ϕj)Ik=bk−1

对应的实际 C 代码很短,位于 EKF/SocEst/ekf_bms.c:79--82:

c 复制代码
float soc_minus = soc_old - (ekf->eta * ekf->Ts / ekf->Qn) * input->I;
float u1_minus  = phi1 * u1_old + g1 * input->I;
float u2_minus  = phi2 * u2_old + g2 * input->I;
float b_minus   = b_old;

负号与电流方向是一对约定。放电为正时 SOC 下降;如果上层接口把充电定义为正,必须在边界处转换,否则看似合理的电流曲线会驱动完全相反的容量变化。两个 RC 状态既保留上一次极化,又接受本轮电流输入。因此它们依赖时间连续性,不能把每一行日志都当成互不相关的独立样本。

电压预测写成:
U^t,k− =OCV(zk−,Tk,Ik)+bk−− U1,k− − U2,k− −IkR0 \hat U_{t,k}^-=OCV(z_k^-,T_k,I_k)+b_k^--U_{1,k}^--U_{2,k}^--I_kR_0 U^t,k−=OCV(zk−,Tk,Ik)+bk−−U1,k−−U2,k−−IkR0

这里将电流写进 OCVOCV OCV 的参数列表,是因为代码按照充放电方向选用不同的 OCV 表,而不是说开路电压本身由瞬时负载电流直接决定。实际端电压与预测电压之差称为创新: rk= Ut,k − U^t,k− r_k=U_{t,k}-\hat U_{t,k}^- rk=Ut,k−U^t,k−。创新告诉我们"本轮预测与观测不一致多少",却不会自动告诉我们误差来自 SOC、温度、采样偏差还是参数失配。

四状态中的 bb b 为模型留下了吸收慢变电压误差的空间,但它没有独立测量支撑,不能被解释成已经识别出的电流传感器零偏,也不能据此证明两个极化状态等于电池内部真实极化。尤其在 LFP 平台区,多个状态可能用不同组合解释相似的端电压。模型输出有物理启发,不等于每一个内部状态都已被单独验证。

这一点决定了调试方式:看到电压拟合改善时,仍应检查 SOC 是否偏移、 bb b 是否持续贴近限幅、极化状态是否出现异常补偿。只看一条端电压曲线,容易把模型自由度增加带来的拟合能力误认为 SOC 识别能力提高。

三、协方差把"相信多少"写进计算,也带来了近似边界

状态预测以后,还要传播预测的不确定性。令 PP P 为状态误差协方差, QQ Q 为过程噪声协方差,则常见的 EKF 递推为:
Pk−=Ak Pk−1 AkT+Qk P_k^-=A_kP_{k-1}A_k^T+Q_k Pk−=AkPk−1AkT+Qk

交付实现使用的观测线性化结构为:
Hk= dOCVdz , −1, −1, 1 H_k=\left\\frac{dOCV}{dz},\\ -1,\\ -1,\\ 1\\right Hk=dzdOCV, −1, −1, 1

随后计算:
Sk =HkPk−HkT+R Kk =Pk−HkT/Sk xk =xk−+Kkrk Pk =(I−KkHk)Pk− \begin{aligned} S_k&=H_kP_k^-H_k^T+R\\ K_k&=P_k^-H_k^T/S_k\\ x_k&=x_k^-+K_kr_k\\ P_k&=(I-K_kH_k)P_k^- \end{aligned} SkKkxkPk=HkPk−HkT+R=Pk−HkT/Sk=xk−+Kkrk=(I−KkHk)Pk−

这里协方差更新式中的 II I 是单位矩阵,与前文表示输入电流的 II I 含义不同。电压测量为标量,所以创新协方差 SS S 也是标量;四个状态分别获得一个修正增益。程序的主要任务由此变得具体:查参数、预测状态、传播协方差、算预测电压与创新、计算增益、修正状态和协方差。E7E8

flowchart TD A[状态与有效输入] --> B[按 SOC 温度及方向查参数] B --> C[状态预测与协方差预测] C --> D[预测电压及 OCV 斜率] D --> E[计算创新 r 与协方差 S] E --> F[计算增益 K] F --> G[修正 SOC U1 U2 b] G --> H[更新协方差与数值约束] H --> I[输出并保存下一轮状态]

公式里的雅可比需要与代码使用的近似区分。当前实现按 A=diag⁡(1,ϕ1,ϕ2,1)A=\operatorname{diag}(1,\phi_1,\phi_2,1) A=diag(1,ϕ1,ϕ2,1) 展开协方差传播。RC 参数随 SOC 和温度查表变化,但这里把本步参数当作常数,没有把参数随 SOC 变化产生的全部导数纳入。温度是本模型的外部输入,并不是被漏掉的一列状态。观测矩阵也使用 OCV 斜率,没有完整展开 R0 R_0 R0 随 SOC 变化等项。这是一种局部近似实现;评价它是否足够,需要看对应工况下的预测误差和稳定性,不能称为包含全部参数依赖的严格雅可比。

LFP 的平台区使这个问题更明显:相当一段 SOC 变化只带来很小的 OCV 变化,电压对 SOC 的约束较弱。程序将 OCV 斜率下限设为 0.005 V/单位 SOC,即每 1 个 SOC 百分点至少对应 0.05 mV 的线性化灵敏度。这是人为设置的计算约束;若真实曲线更平,线性化就会偏离它,不能由此宣称恢复了真实观测信息。即便斜率变大,也不能简单推断 SOC 增益必然变大,因为 HH H 同时进入增益的分子和分母,协方差的交叉项也参与运算。

数值保护同样要按实际能力描述。代码对 SOC 和偏置作限幅,对 SS S 设置小量保护,协方差更新以后再对称化。对称化能消除浮点计算造成的部分非对称,却不能单独保证矩阵半正定;状态限幅以后,协方差也没有自动完成一致的约束修正。回放时可以先记录协方差对角项、有限性和创新统计,检查长时间递推后是否出现异常,再据此判断是否需要 Joseph 形式等改进。矩阵只有四阶,也仍然需要这类数值检查。

还有一个容易被注释带偏的数值:初始化中的 R=0.01R=0.01 R=0.01 在计算 SS S 时作为方差相加。电压以 V 为单位,则标准差是 0.01=0.1 \sqrt{0.01}=0.1 0.01 =0.1 V,即 100 mV,并非注释中的约 10 mV。E6E8 这足以要求核对标定依据,却还不足以直接修改参数。测量噪声、模型误差与工况不确定性如何分配,应该由数据支持;根据注释改一个小数点,同样可能破坏原有调参结果。

四、输入契约比更新函数的名字更值得审查

仿真脚本通常直接使用 A、V、℃,固件接口却常用整数缩放值。适配层负责把这些数值转换成模型输入,接口约定因而不能只列变量名,还要列出单位、符号、量程、失效标志和样本时间。

输入 本工程接口约定 EKF 内部约定
电流 10 mA,放电正、充电负 A,乘 0.01
平均单体电压 mV V,乘 0.001
平均温度 整数 ℃ ℃,此版本无需缩放
SOC 0~1000 对应 0~100% 0~1,乘 0.001
总容量 mAh 先转 Ah,再在初始化中转 A·s

温度是本次代码对照里最直观的例子。BMS 的 GetGCellAvgTempAPI 返回整数摄氏度,而独立适配器读取后乘了 0.1。E10 适配器中的原文如下,分别位于 EKF/SocEst/ekf_adapter.c:21,82,这里的注释反映适配器自身假设,与目标 BMS 接口不一致:

c 复制代码
#define EKF_TEMP_SCALE    (0.1f)     /* 温度 0.1℃ -> ℃ */
c 复制代码
sEkfIn.temp        = (float)temp * EKF_TEMP_SCALE;

直接连接这两个版本时,25 ℃ 会进入模型成为 2.5 ℃,随后又被参数边界夹到低温端。程序没有越界,结果甚至可能十分平滑,但参数已不再对应真实工况。查表的边界保护因此不能替代单位检查。

flowchart LR A[现场 25 ℃] --> B[BMS 返回整数 25] B --> C[现有适配器乘 0.1] C --> D[模型收到 2.5 ℃] D --> E[查表夹到低温边界] E --> F[程序继续运行但参数失配]

容量则容易出现另一种混淆:电芯名义容量、当前学习容量和算法归一化容量并不是同一个概念。适配器优先取总容量,异常时回退标称容量,再由 Ah 转为 A·s。若两个来源都无效,预测公式中的分母仍需被保护。不能认为"已经有回退"就意味着一定获得了有效容量。

用一个说明性算例检验数量级:假设容量 300 Ah、电流 150 A、步长 0.5 s、效率取 1,则单步 SOC 减少 150×0.5/(300×3600)=6.94444×10−5150\times0.5/(300\times3600)=6.94444\times10^{-5} 150×0.5/(300×3600)=6.94444×10−5,也就是约 0.00694444 个百分点。这不是实测成绩,只用于检查接口和量纲。若恒定输入下的纯预测量偏离这个数量级,应优先检查千分 SOC、容量单位、秒与毫秒,而不是马上调 QQ Q 和 RR R。

输入契约还应覆盖数据来源。单体平均电压与二阶单体模型组合时,估计对象接近一个等效平均单体;改用最高或最低单体电压,测量对象就变了。此时 SOC 究竟代表整组平均能量状态,还是更接近限制单体的可用边界,需要重新定义。不能把平均电压改成最低电压以后,只凭曲线更接近某一参考,就认为物理含义保持不变。

接口能读到数值,也不代表这组数据可以用于估计。温度异常哨兵、采样通信中断、旧电压配新电流、浮点 NaN,都可能通过普通赋值进入算法。一种可落地的做法是把快照定义为带时间、序号、有效标志和来源的结构体,在进入算法前集中校验。这样函数收到的才是一次可解释的测量,而不只是几个全局变量的瞬时读数。

五、FreeRTOS 中的 500 ms,不只是给 Ts 写上 0.5

这套工程同时存在硬件中断、独立任务、软件定时器和业务轮询槽。理解它们的嵌套关系,是把模型时间步长落实到运行时间的前提。

硬件 1 ms 中断调用电流积分;软件 10 ms 回调内有十个业务槽,因此每个槽的名义执行周期为 100 ms。容量计算放在其中一个槽,进入容量函数以后又交替处理两类容量,所以相应分支名义上每 200 ms 执行一次。不能把"积分 1 ms"理解为"全部容量状态每 1 ms 更新",也不能只看外层 10 ms 定时器就认定业务每 10 ms 执行。E1E2

采集更新率还要与这些周期分开。1 ms 中断执行积分,不能证明 ADC 或电流芯片每 1 ms 提供一帧独立新样本;在尚未追完驱动与数据发布时序之前,只能确认积分调用周期。采集更新率、积分步长、容量任务周期和 EKF 周期是四个不同问题,记录与验证时应分别命名。

50 ms 回调调用 SOC/SOE 业务,后者使用二十槽轮询;其中第 2 和第 12 槽预留 EKF,间隔十个 50 ms,才构成名义 500 ms 入口。E3 BMS 的实际代码是:

c 复制代码
/*500ms周期*/
case 2:
case 12:
    /*SOC、SOE扩展卡尔曼算法任务*/
    ;
    break;

独立适配器把 Ts T_s Ts 固定为 0.5 s,与这个预留位置在数值上匹配,但预留代码仍为空。另一个头文件注释提到"定时器中断每秒调用",也不能据此决定实际集成上下文。注释、入口和调用链必须相互对照。

flowchart TD A[硬件 1 ms 中断] --> B[电流积分] C[软件 10 ms 回调] --> D[十槽轮询] D --> E[容量入口名义 100 ms] E --> F[内部交替分支名义 200 ms] G[软件 50 ms 回调] --> H[SOC 二十槽轮询] H --> I[槽 2 与槽 12] I --> J[名义 500 ms EKF 预留位置] J --> K[当前为空 尚未接入]

这段计算在哪个任务里执行,会直接影响调度判断。工程以 xTimerCreate 创建多个周期函数,传入第四参数的 RTOS_ID_TIMER* 是定时器 ID,虽然附近注释容易使人联想到优先级,却不构成多个独立的定时器任务。回调共享定时器服务任务;当前配置中它的优先级为 3。E4

FreeRTOS 官方手册说明,软件定时器回调在同一个服务任务中执行,回调不应调用会使该任务阻塞的接口。因此,若把完整 EKF、慢速外设访问或记录写入直接塞进回调,一个函数的耗时便会影响其他回调的完成时间。周期到了只意味着调度条件成立,不意味着采样和计算必然在那个时刻完成。

当前源码组合还暴露了一项配置矛盾:业务任务声明优先级 12~18,而 configMAX_PRIORITIES 为 8;所附内核创建任务时将超限值截到 7。E5 静态推论是这些任务的预期优先级差异会丢失。是否与设备实际部署一致,仍需核对构建配置和二进制。它提醒我们:不能只看任务宏的数字,就画出想象中的抢占关系。

是否为 EKF 建立独立任务,要由执行时间和调度抖动的测量结果决定。若采用独立任务,可让周期入口只提交快照或通知,由任务完成计算并发布影子结果;但消息积压、丢样策略和过期判断也要随之明确。新建任务本身不会自动解决时间一致性。

固定步长模型要求真实输入与该步长假设相符。短暂抖动可能可以接受,连续漏算却不能用下一轮的一次 0.5 s 更新默默覆盖。按真实时间调整步长是一种方案,但同时涉及 RC 离散系数、过程噪声和区间电流表达,不能只改一个 Ts T_s Ts。另一种方案是在有完整样本时补做多个固定步长预测,前提是每段输入确实存在,不能用最新电流回填未知历史。

六、参数表和编译宏,必须与模型一起交付

如果把 EKF 理解成"一个 C 文件加几组经验参数",复现实验会很困难。这份实现至少包含三类相互关联的内容:状态递推、RC 查表、OCV 样条。它们共同决定预测电压,任何一类换版本,都可能改变最终 SOC。

RC 参数使用 SOC 与温度网格双线性插值,当前表的 SOC 范围为 5%~95%,温度范围为 15~35 ℃;OCV 使用 SOC 方向的分段三次系数,温度方向插值,温度覆盖 10~45 ℃。越界夹到边界意味着继续使用边界模型,不等于模型已在边界以外通过验证。E11

充电和放电分别使用不同表,按电流正负切换,零电流选择放电表。这个选择在程序里很简单,在工况上却需要关注切换连续性。电流在零附近抖动时,模型可能反复改变表分支;预测电压出现的变化又可能被 EKF 分配给 SOC 或偏置。先把切表点的创新与状态变化画出来,才能判断是否需要经过标定的方向判定、滞回或过渡策略。

电芯分支也有明确差异:默认参数选择 CATL 285 Ah,定义 CELL_EVE_314 才切至 EVE 314 Ah;测试报告描述的对象为 EVE 314 Ah,而 BMS 默认项目注释又指向标准 280 Ah。E12 这些数值不能靠"都差不多三百安时"合并理解。容量缩放解决不了 OCV 曲线和动态参数差异,编译成功也证明不了选中了正确的参数表。

要复现一次运行,日志中至少需要留下源码提交、编译宏、电芯对象、RC 表版本、OCV 表版本、容量来源、初始状态和噪声参数。这些信息共同回答"同一段数据为什么两次结果不同"。只有固件文件名和一张曲线图,通常不足以定位差异。

参数辨识与在线估计也应该分工清楚。离线辨识为模型提供适用范围内的动态关系,在线 EKF 在这些关系与观测之间分配不确定性。如果温度单位错了,或型号表选错了,在线增加一个偏置状态可能暂时改善电压创新,却不会把错误模型自动变成正确模型。出现持续补偿时,应先排除基础输入与参数版本,再讨论滤波器调参。

七、异常处理要回答"下一步怎么办"

论文中的递推通常假设测量不断到来、数值始终有限、容量始终为正。工程需要补上每个假设失败以后的路径。这份适配器在首次 Ready 后初始化,读取旧 SOC 作为初值;容量无效时回退标称容量。它已经提供基本接入骨架,但当前函数内还不足以覆盖 Ready 丢失、无效温度、缺测和连续过期数据等情形。E9E13

最容易混淆的处理是"跳过一轮"。跳过测量修正而继续预测,与冻结整个滤波器,含义不同。前者仍需要可靠的区间电流和经过时间,后者则让内部状态停留在旧时刻。重新收到样本时,要知道自己距离哪个时刻有多远,否则一个普通的通信恢复事件就会成为不连续状态跳转。

以下流程是建议方案,尚未在当前工程实现:

flowchart TD A[等待输入快照] --> B{时间和数据有效吗} B -- 否 --> C[记录原因与失效时长] C --> D{仍可可靠预测吗} D -- 是 --> E[执行明确的预测降级策略] D -- 否 --> F[停止发布有效估计] B -- 是 --> G{需要初始化或恢复吗} G -- 是 --> H[检查容量 初值和参数版本] G -- 否 --> I[执行预测及测量修正] H --> I I --> J{数值及创新检查通过吗} J -- 是 --> K[发布带有效标志的影子结果] J -- 否 --> C

恢复策略要考虑电池在失效期间是否带载。断电后重新上电,可以利用历史容量提供先验;足够静置并满足条件时,也可以考虑 OCV 初始化。可是带载电压并不等于开路电压,直接反查 SOC 会把欧姆压降和极化误差一起写入初值。初值来源和初始协方差应一起设计:来源不可靠却把协方差设得很小,会让滤波器对错误初值过分自信。

按这些职责拆分,任务结构可以写成下面的伪代码。它用于讨论接入设计,尚未接入,也不能直接编译:

text 复制代码
每个估计周期:
    取得带单调采样时间的电压、电流、温度快照
    校验单位、有效位、年龄和容量来源
    依据失效时长决定初始化、预测或暂停
    执行一步模型与滤波计算
    检查有限性、创新、状态边界与计算耗时
    发布影子结果及原因码
    由低优先级记录路径保存诊断数据

日志本身也有语义边界。当前影子结构中的 tick++ 是调用计数,不能当作真实时间戳测量抖动。输出 SOC、极化状态和偏置为本轮修正后的状态,而输出预测电压与 error_Ut 仍对应修正前的电压预测及创新。把它们画在一起时应明确前后关系,不能标成"后验拟合残差",否则会误读算法的即时修正能力。E8

八、从影子运行走向工程结果,需要一条能复查的验证链

现有报告给出了 1.79 个 SOC 百分点的 RMSE,但报告明确说明参考 SOC 字段无效,指标相对 BMS_SOC 计算。E14 它能描述两种估计之间的一致性,不能直接证明相对独立真值的绝对误差。如果 EKF 初值来自旧 BMS,两者又共享电流和容量信息,那么"接近旧算法"尤其需要谨慎解释。

报告还描述了输出限速和充放电选压策略,当前交付适配器却始终读取平均电压,所读核心代码也不包含报告所述输出速率限制。E15 这个差异说明需要找到实验对应版本,不能据此否认其他版本曾完成实验,也不能将报告效果迁移到当前快照。

验证可以从一份可重放的样本开始。保存输入原值及单位、样本时间、有效标志、参数版本和初始化条件,在桌面端按固件运算顺序运行相同模型,再让板端影子任务处理同一类数据。这样可以将模型差异、浮点差异和调度问题分开定位。只保留最终百分比,会让大多数问题失去上下文。

定位一次偏差时,最好能从该轮 SOC 回到输入快照,再回到预测状态、预测电压和创新。若桌面端与板端从某一轮开始分离,这条记录链能帮助缩小检查范围;若两端逐步结果一致却都偏离独立参考,问题就需要回到模型、参数及参考数据上继续查。这里需要的是可重复的定位过程,单张曲线无法提供同样的检查条件。

flowchart LR A[可追溯原始样本] --> B[桌面端重放同一版本] A --> C[板端影子运行] B --> D[逐步比较状态与创新] C --> D D --> E[工况分组统计] E --> F[独立参考与误差评估] F --> G[明确状态所有权后讨论接入]

验证顺序应从便于定位的情形逐渐扩展。恒流段检查容量变化和电流符号,静置段观察极化衰减,电流阶跃检查动态响应,充放电切换检查表分支,温度边界检查夹值行为;再加入无效温度、缺测、重启和长期运行。每一种工况都应有明确判据,例如是否发布无效标志、是否出现非有限数、周期是否超时,而不只写"曲线正常"。

有独立参考以后,还要将误差按温度、SOC 区间、电流大小和方向分组。一个全程 RMSE 可能掩盖平台区长期偏移,也可能被长时间静置段稀释。对于储能系统,充放端点的可用容量、重启连续性和切换过程往往比总平均误差更直接影响使用体验。需要评价的既有估计数值,也有错误何时发生、持续多久、是否被系统识别。

调度验证应与算法验证并行。记录计算耗时、任务栈余量、通知积压和采样到发布的延迟,检查 EKF 运行以后原通信与保护任务的时间行为。配置中的主频、堆大小、定时器栈深只是起点,不能替代测量。尤其在共享软件定时器上下文中,平均耗时很短也不足以排除偶发长延迟。

走到正式接入前,还需要一次状态所有权设计评审:EKF 输出是否只供显示、是否修正容量、修正何时生效、端点校准怎样作用、SOE 如何同步、持久化保存什么、恢复后谁提供初值。把这些问题写成接口和状态转换,理论中的递推才有了稳定的工程边界。这套工程的下一步已经足够具体:先修正接口单位的冲突,核对调度配置,补齐影子日志,并复现报告对应的版本。完成这些工作后,才有依据决定 EKF 应该接管哪些状态。

相关推荐
掘金小豆1 小时前
Spring AI 实战:从一次可运行的模型调用到 RAG 体系
后端·程序员·ai编程
前端小万1 小时前
探索副业五个月,最终以放弃告终
前端·后端·面试
用户87359865635871 小时前
Bias-Variance Tradeoff
后端
今天早睡1 小时前
TypedDict 还是 Pydantic?
后端
木易 士心1 小时前
Java 后端驱动远程手机自动化:ADB + Python + 内网穿透实战全解
java·后端·智能手机·自动化
用户1494484813201 小时前
从入口拦截到最终对账:我如何设计一套高并发秒杀系统
后端·架构
Jeromefromhk1 小时前
把服务器当代码管
后端
闽林致远1 小时前
C++ 插件化后台服务架构实践
后端
用户125758524361 小时前
GoFrame Vue3开源后台管理系统推荐:数据库与Worker要求怎么验
数据库·后端·go