4、最小二乘法原理:数学推导与斜截距求解
各位做嵌入式校准的同行,今天我们来啃一块硬骨头——最小二乘法。
说实话,我刚入行时也觉得这东西太数学了。直到有一次,我调试一台高精度万用表,发现ADC采集的数据总是飘。用最小二乘法一拟合,问题立马清晰了。从那以后,我就把这方法当成了吃饭的家伙。
4.1 最小二乘法的核心思想
先问大家一个问题:你有一堆测量点,想找一条直线来描述它们。怎么找?
最小二乘法的答案很简单——让所有点到直线的垂直距离的平方和最小。
为什么是平方?不是绝对值?
嗯,这里有个小故事。我刚开始做校准算法时,试过用绝对值距离。结果发现,绝对值函数在零点不可导,优化起来特别麻烦。而平方函数处处可导,用微积分就能轻松求解。这就是数学家的智慧——选一个好算的误差函数。
核心公式:
误差平方和 S = Σ(yᵢ - (a·xᵢ + b))²
其中 a 是斜率,b 是截距,我们要找到使 S 最小的 a 和 b。
4.2 数学推导:一步步来
推导过程其实不复杂。我习惯把它分成三步走:
- 写出误差函数——就是上面那个 S
- 对 a 和 b 分别求偏导——让导数等于0
- 解方程组——得到 a 和 b 的表达式
咱们一步步看。
首先,对 b 求偏导:
∂S/∂b = -2 Σ(yᵢ - a·xᵢ - b) = 0
→ Σyᵢ - a·Σxᵢ - n·b = 0
→ b = (Σyᵢ - a·Σxᵢ) / n
然后,对 a 求偏导:
∂S/∂a = -2 Σxᵢ·(yᵢ - a·xᵢ - b) = 0
→ Σxᵢ·yᵢ - a·Σxᵢ² - b·Σxᵢ = 0
把 b 的表达式代入第二个方程,整理后得到:
a = (n·Σxᵢ·yᵢ - Σxᵢ·Σyᵢ) / (n·Σxᵢ² - (Σxᵢ)²)
b = (Σyᵢ - a·Σxᵢ) / n
实战小技巧:
我在嵌入式平台上实现时,会先计算几个统计量:
- Σx、Σy、Σx²、Σxy
- n 是数据点数
这样只需要一次循环就能算出所有中间结果,效率很高。
4.3 斜率和截距的物理意义
在万用表校准中,这两个参数有明确的物理含义:
| 参数 | 物理意义 | 理想值 |
|---|---|---|
| 斜率 a | 增益误差 | 1.0(无增益误差) |
| 截距 b | 偏移误差 | 0.0(无偏移误差) |
举个例子。你测量一个标准电压源,得到一组数据:
标准值(V) 测量值(V)
1.000 1.002
2.000 2.005
3.000 3.008
4.000 4.011
5.000 5.014
用最小二乘法拟合,得到 a=1.003,b=-0.001。这说明什么?
斜率 a=1.003,意味着每1V的输入,测量值偏大0.003V,这是增益误差。截距 b=-0.001,意味着有-1mV的偏移。
我曾经踩过的坑:
有一次,我直接用原始ADC码值做拟合,结果斜率算出来是0.000几。后来才意识到,ADC码值和电压值量级差太多,导致数值计算精度丢失。我的建议是:
- 先把数据归一化到同一量级
- 或者用双精度浮点数计算
否则,在8位单片机上跑,结果可能完全不对。
4.4 嵌入式实现要点
在嵌入式系统里实现最小二乘法,有几个地方要特别注意:
- 数值稳定性——当数据点很多时,Σx² 可能非常大,容易溢出。我习惯用增量式更新,每来一个点就更新一次统计量。
- 定点数实现——如果MCU没有FPU,可以用Q15或Q31格式。但要注意,除法运算要特别小心。
- 异常处理——当所有x值相同时,分母为0。这种情况在现实中很少见,但代码里一定要处理。
推荐的数据类型:
对于12位ADC、16位MCU的系统:
- 中间累加用32位整数
- 最终结果用浮点数
- 如果必须用定点,保留至少8位小数精度
4.5 一个完整的计算示例
咱们用手算一遍,加深理解。
假设有3个数据点:(1,2), (2,4), (3,6)
先算统计量:
n = 3
Σx = 1+2+3 = 6
Σy = 2+4+6 = 12
Σx² = 1+4+9 = 14
Σxy = 1×2 + 2×4 + 3×6 = 2+8+18 = 28
代入公式:
a = (3×28 - 6×12) / (3×14 - 6²)
= (84 - 72) / (42 - 36)
= 12 / 6
= 2.0
b = (12 - 2.0×6) / 3
= (12 - 12) / 3
= 0.0
结果 a=2.0, b=0.0,完美拟合 y=2x 这条直线。
验证小技巧:
算完后,把第一个点和最后一个点代入直线方程,看看中间点是否在直线上。如果偏差很大,说明数据本身就不是线性关系,或者计算有误。
4.6 实际校准中的应用
在万用表校准中,我们通常这样做:
- 用标准源输出5~10个校准点
- 记录ADC的原始读数
- 用最小二乘法拟合出斜率和截距
- 将这两个参数存入EEPROM
- 正常测量时,用 y = (x - b) / a 反算真实值
你想想看,这个过程其实就是在做「反向校准」。我们不是去调整硬件,而是在软件里把测量值修正回来。
我个人习惯在出厂前做一次全量程校准,然后在关键温度点做二次校准。这样既能保证精度,又不会让校准时间太长。
好了,最小二乘法的原理和推导就讲到这里。下一章我们聊聊如何在嵌入式平台上高效实现这个算法,包括定点数优化和内存管理。到时候我会分享一个我在STM32上实际跑过的代码框架。