1113 字
6 分钟
STM32传感器标定实战:最小二乘法二次曲线拟合工程实现(附完整代码)

引言#

传感器标定是嵌入式系统中提升精度的关键步骤。温度、压力、电流等传感器普遍存在非线性误差,通过二次曲线拟合可大幅提高测量准确度。

在PC端我们习惯调用MATLAB/Eigen,但在STM32这种资源受限平台,移植大型矩阵库既耗内存又慢。本文采用代数解析法(克莱姆法则推导正规方程解),给出可直接拷贝的完整C代码,无需任何外部库,在开启FPU的STM32F4上计算7个标定点仅需几十微秒。


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

目标:找到系数 (a_0, a_1, a_2),使二次多项式
[ y = a_0 + a_1 x + a_2 x^2 ]
与观测点 ((x_i, y_i)) 的误差平方和最小。

通过对误差函数求偏导并令其为零,得到三元正规方程组。利用克莱姆法则可直接求出解析解,避免矩阵求逆运算,非常适合嵌入式实时计算。


2. 优化后的工程实现(直接可用)#

typedef struct {
double a0; // 常数项
double a1; // 一次项系数
double a2; // 二次项系数
} QuadraticCoeff;
/**
* @brief 最小二乘法二次曲线拟合(解析法,无矩阵库)
* @param x 输入数组(自变量,如ADC值)
* @param y 输入数组(标准值)
* @param n 数据点个数(推荐5~10个)
* @return 拟合系数结构体
*/
QuadraticCoeff fit_quadratic(double *x, double *y, int n) {
QuadraticCoeff coeff = {0.0, 0.0, 0.0};
if (n < 3) return coeff; // 至少3个点
double s0 = n;
double s1 = 0.0, s2 = 0.0, s3 = 0.0, s4 = 0.0;
double t0 = 0.0, t1 = 0.0, t2 = 0.0;
for (int i = 0; i < n; i++) {
double xi = x[i];
double x2 = xi * xi;
double x3 = x2 * xi;
double x4 = x3 * xi;
double yi = y[i];
s1 += xi;
s2 += x2;
s3 += x3;
s4 += x4;
t0 += yi;
t1 += yi * xi;
t2 += yi * x2;
}
// 行列式(det)
double det = s0 * (s2 * s4 - s3 * s3) -
s1 * (s1 * s4 - s2 * s3) +
s2 * (s1 * s3 - s2 * s2);
if (fabs(det) < 1e-12) return coeff; // 奇异矩阵(数据线性或重合)
// 克莱姆法则求解 a0, a1, a2
coeff.a0 = (t0 * (s2 * s4 - s3 * s3) - t1 * (s1 * s4 - s2 * s3) + t2 * (s1 * s3 - s2 * s2)) / det;
coeff.a1 = (s0 * (t1 * s4 - t2 * s3) - s1 * (t0 * s4 - t2 * s2) + s2 * (t0 * s3 - t1 * s2)) / det;
coeff.a2 = (s0 * (s2 * t2 - s3 * t1) - s1 * (s1 * t2 - s3 * t0) + s2 * (s1 * t1 - s2 * t0)) / det;
return coeff;
}

使用示例(标定后实时修正):

QuadraticCoeff c = fit_quadratic(adc_values, standard_values, 7);
double corrected = c.a0 + c.a1 * raw + c.a2 * raw * raw;

3. STM32 FPU配置与性能实测(2018年实践)#

  • 必须开启:Keil/IAR中设置 Use FPU = Hard + Floating Point ABI = Hardfp
  • 实测数据(STM32F407 168MHz):7个点拟合仅需 28~45μs,完全支持在线实时标定。
  • 内存占用:代码+栈 < 300字节,无额外堆需求。

4. 标定工程CheckList(上线必查)#

  1. 标定点个数是否 ≥5 且均匀分布在量程内?
  2. 是否开启了STM32 FPU硬浮点?
  3. 输入数据是否已做归一化(x范围过大时建议除以1000避免数值溢出)?
  4. det防除零保护是否生效?
  5. 拟合后残差是否在可接受范围内(建议打印验证)?
  6. 标定系数是否存入Flash/EEPROM(掉电不丢失)?

5. 常见避坑指南#

  • 标定点全部集中在一段区间 → det接近0,拟合失效(必须覆盖全量程)。
  • 未用FPU而用软件浮点 → 计算速度慢10倍以上。
  • 原始数据未滤波直接拟合 → 噪声导致系数剧烈抖动。
  • x值范围过大(如ADC 0~4095) → 数值不稳定,建议先归一化到[0,1]。
  • 只标定一次就固化 → 温度漂移后精度下降,建议周期性重标定。

6. 总结#

最小二乘法二次曲线拟合是嵌入式传感器标定的高效利器。通过解析法+累乘优化+克莱姆法则,我们在STM32上实现了零外部库、微秒级实时计算。

工程铁律点要多且散、FPU要硬开、det要判零、结果要存Flash

掌握此方法,你就能轻松完成温度、压力、流量、电池SOC等高精度标定,让STM32的测量精度从“够用”升级到“专业级”。

STM32传感器标定实战:最小二乘法二次曲线拟合工程实现(附完整代码)
https://hw.rscclub.website/posts/stm32zxecfsf/
作者
杨月昌
发布于
2018-12-16
许可协议
CC BY-NC-SA 4.0