966 字
5 分钟
基于 STM32 的最小二乘法二次曲线拟合应用

一、 背景概述#

在工业传感器应用中,精确度是系统的核心指标。由于传感器材料特性、非线性响应或环境干扰,其输出往往呈现非线性偏移。为了矫正这些误差,通常需要通过**标定(Calibration)**过程推导出一条修正曲线。

在 PC 端,我们可以轻松调用复杂的矩阵运算库进行拟合,但在嵌入式系统(如 STM32)中,内存和主频资源有限。如何在不移植大型矩阵库的前提下,高效、高精度地实现二次曲线拟合?本文将分享一种优化的代数解析法,直接在 STM32F4 上实现实时标定。


二、 数学模型:最小二乘法二次拟合#

我们的目标是找到一组系数 ,使得拟合出的二次多项式 与实际观测点 的误差平方和最小:

根据最小二乘法原理,通过对误差函数求偏导并令其为零,可以得到正规方程组(Normal Equations):

由于阶数较低(二次),我们可以通过**克莱姆法则(Cramer’s Rule)**推导出系数的直接解析表达式,从而避开复杂的矩阵求逆运算。


三、 解决方案与工程实现#

1. 硬件加速建议#

STM32F4 系列具备 FPU(浮点运算单元)。在编译器设置中,请务必开启硬浮点运算(Hardfp),这将使 doublefloat 的运算速度提升数倍。

2. 优化后的 C 语言实现#

原代码中频繁调用 pow() 函数会消耗大量的 CPU 周期,优化方案改用累乘,并加入 FPU 友好的数据类型。

/**
* @brief 二次曲线拟合计算函数
* @param x: 传感器采集数据数组
* @param y: 标准输出数据数组
* @param n: 数据点个数
*/
void fit_quadratic_curve(double *x, double *y, int n) {
double s0 = n;
double s1 = 0, s2 = 0, s3 = 0, s4 = 0; // x的幂次方累加
double t0 = 0, t1 = 0, t2 = 0; // y与x幂次方的乘积累加
for (int i = 0; i < n; i++) {
double x1 = x[i];
double x2 = x1 * x1;
double x3 = x2 * x1;
double x4 = x3 * x1;
double y1 = y[i];
s1 += x1;
s2 += x2;
s3 += x3;
s4 += x4;
t0 += y1;
t1 += y1 * x1;
t2 += y1 * x2;
}
// 计算分母行列式 (通过解析化简提高实时性)
double det = s0 * (s2 * s4 - s3 * s3) -
s1 * (s1 * s4 - s2 * s3) +
s2 * (s1 * s3 - s2 * s2);
if (fabs(det) < 1e-12) return; // 防止除零错误
// 克莱姆法则求解系数
a0 = (t0 * (s2 * s4 - s3 * s3) - t1 * (s1 * s4 - s2 * s3) + t2 * (s1 * s3 - s2 * s2)) / det;
a1 = (s0 * (t1 * s4 - t2 * s3) - s1 * (t0 * s4 - t2 * s2) + s2 * (t0 * s3 - t1 * s2)) / det;
a2 = (s0 * (s2 * t2 - s3 * t1) - s1 * (s1 * t2 - s3 * t0) + s2 * (s1 * t1 - s2 * t0)) / det;
}

四、 性能评估与应用考量#

  1. 运算效率:在开启 FPU 的 STM32F407 上,计算 7 个点的二次拟合耗时在微秒级,完全满足在线实时标定的要求。
  2. 内存占用:由于避开了 Eigen 或 Arm_Math 等大型库,该函数仅占用极少量堆栈,非常适合 RAM 资源紧张的单片机环境。
  3. 稳定性:当数据点 跨度过小或趋于线性时,行列式 det 可能趋于 0,代码中加入了防除零保护。

五、 结论#

通过解析法实现最小二乘法二次曲线拟合,是在嵌入式系统中平衡“计算精度”与“系统开销”的最优解。在传感器标定、电池 SOC 估算、电机参数辨识等领域,该算法能显著提升系统的智能化水平。

基于 STM32 的最小二乘法二次曲线拟合应用
https://hw.rscclub.website/posts/stm32zxecfsf/
作者
杨月昌
发布于
2018-12-16
许可协议
CC BY-NC-SA 4.0