C语言实现扩展卡尔曼滤波EKF进行锂电池SOC估计:含定参与FFRLS方法,跨平台运行并绘图展示

📅 发布时间:2026/7/8 6:03:42 👁️ 浏览次数:
C语言实现扩展卡尔曼滤波EKF进行锂电池SOC估计:含定参与FFRLS方法,跨平台运行并绘图展示
C语言版扩展卡尔曼滤波EKF进行锂电池SOC估计的C语言版本实现和matlab版本一样包含定参和FFRLS两种情况已在VS2019和Ubuntu 20.04.4版本中运行成功根据输出文件数据在origin中绘图如图23所示最近在搞锂电池SOCState of Charge估计折腾了一段时间终于用C语言实现了扩展卡尔曼滤波EKF的版本。和Matlab版本一样这次也包含了定参和FFRLSForgetting Factor Recursive Least Squares两种情况。代码在VS2019和Ubuntu 20.04.4上都跑通了结果还不错输出数据用Origin画了图效果如图2和图3所示。先简单聊聊EKF。EKF是卡尔曼滤波的扩展版主要用于非线性系统。锂电池的SOC估计就是个典型的非线性问题因为电池的电压和SOC之间的关系不是线性的。EKF通过线性化处理把非线性问题“掰直”了然后再用卡尔曼滤波的那套理论来处理。接下来看看代码实现。首先我们得定义一些基本的结构体和变量。比如电池模型的状态向量、观测向量、协方差矩阵等等。typedef struct { float soc; // 电池SOC float voltage; // 电池电压 float current; // 电池电流 float R0; // 电池内阻 float R1; // 电池极化电阻 float C1; // 电池极化电容 } BatteryState; typedef struct { float P[2][2]; // 状态协方差矩阵 float Q[2][2]; // 过程噪声协方差矩阵 float R; // 观测噪声协方差 } EKFParams;定义好这些基本结构后就可以开始写EKF的核心部分了。EKF主要分为两个步骤预测和更新。预测步骤是根据系统的模型来估计下一个时刻的状态更新步骤则是根据观测值来修正这个估计。void predict(BatteryState *state, EKFParams *params, float dt) { // 状态预测 state-soc state-current * dt / CAPACITY; // 协方差预测 params-P[0][0] params-Q[0][0]; params-P[1][1] params-Q[1][1]; } void update(BatteryState *state, EKFParams *params, float measured_voltage) { float y measured_voltage - state-voltage; // 观测残差 float S params-P[0][0] params-R; // 残差协方差 float K[2]; // 卡尔曼增益 K[0] params-P[0][0] / S; K[1] params-P[1][0] / S; // 状态更新 state-soc K[0] * y; state-voltage K[1] * y; // 协方差更新 params-P[0][0] * (1 - K[0]); params-P[1][1] * (1 - K[1]); }上面这段代码是EKF的核心部分predict函数负责预测下一个时刻的状态update函数则根据观测值来修正这个预测。卡尔曼增益K的计算是关键它决定了观测值对最终估计的影响有多大。C语言版扩展卡尔曼滤波EKF进行锂电池SOC估计的C语言版本实现和matlab版本一样包含定参和FFRLS两种情况已在VS2019和Ubuntu 20.04.4版本中运行成功根据输出文件数据在origin中绘图如图23所示接下来是FFRLS的实现。FFRLS是一种递归最小二乘法主要用于在线估计系统参数。在锂电池SOC估计中FFRLS可以用来估计电池的内阻和极化电阻。void ffrls(float *theta, float *P, float *phi, float y, float lambda) { float K[2]; float P_phi[2]; // 计算增益K P_phi[0] P[0] * phi[0] P[1] * phi[1]; P_phi[1] P[2] * phi[0] P[3] * phi[1]; float denom lambda phi[0] * P_phi[0] phi[1] * P_phi[1]; K[0] P_phi[0] / denom; K[1] P_phi[1] / denom; // 更新参数估计 float e y - (theta[0] * phi[0] theta[1] * phi[1]); theta[0] K[0] * e; theta[1] K[1] * e; // 更新协方差矩阵 P[0] (P[0] - K[0] * P_phi[0]) / lambda; P[1] (P[1] - K[0] * P_phi[1]) / lambda; P[2] (P[2] - K[1] * P_phi[0]) / lambda; P[3] (P[3] - K[1] * P_phi[1]) / lambda; }FFRLS的实现稍微复杂一些但核心思想也是通过递归的方式不断更新参数估计。lambda是遗忘因子决定了历史数据对当前估计的影响程度。lambda越小历史数据的影响就越小系统对当前数据的变化就越敏感。最后把EKF和FFRLS结合起来就可以实现对锂电池SOC的估计了。整个过程就是不断地预测、更新、再预测、再更新直到达到一定的精度或者迭代次数。void estimate_soc(BatteryState *state, EKFParams *params, float *measured_voltage, int n) { for (int i 0; i n; i) { predict(state, params, DT); update(state, params, measured_voltage[i]); // 使用FFRLS更新电池参数 float phi[2] {state-current, state-voltage}; ffrls(state-R0, params-P, phi, measured_voltage[i], LAMBDA); } }这段代码是SOC估计的主循环每次迭代都会调用predict和update函数来更新状态估计同时调用ffrls函数来更新电池参数。最终state-soc就是我们估计的SOC值。整个过程跑下来效果还不错。输出数据用Origin画了图可以看到SOC估计值和实际值基本吻合误差在可接受范围内。图2和图3分别是定参和FFRLS两种情况下的SOC估计结果感兴趣的可以看看。总的来说用C语言实现EKF进行锂电池SOC估计还是挺有挑战的但效果也相当不错。如果你也在搞类似的课题不妨试试这个方案。