log2对数三阶多项式近似计算
目录
0. 目标?
1. 核心数学公式
2. 为什么要算 log₂(f),f ∈ [1,2)?
3. 变量替换:d = f - 1
4. 三阶多项式拟合公式(工程标准)
5. 系数转 Q8 定点(对应你代码的 369、185、85)
6. 归一化 f(代码最关键一步)
7. d 的计算(Q8)
8. 三阶多项式计算
9. 最终结果合并
10. 原理总结
11. 原理 → 代码 逐行对应表
12. 为什么三阶精度最高?
0. 目标?
目标:y = log₂(x) × 256(Q8 定点数)x 范围:1 ~ 32768
为什么 ×256?
因为嵌入式不能用浮点数,所以把小数放大 256 倍变成整数运算,这叫Q8 定点格式。
1. 核心数学公式
任何 x 都可以写成:其中:
- k = 整数(0~15)
- f ∈ [1, 2)
两边取 log₂:
化简:
结论
- k 很容易算(找最高位)
- f 永远落在 [1,2)
- 我们只需要算log₂(f),再 +k 就是最终结果
2. 为什么要算 log₂(f),f ∈ [1,2)?
因为:
- log₂(f) 是一条平滑曲线
- 单片机不能直接算
- 用多项式拟合曲线,就能用整数乘法算出高精度近似值
3. 变量替换:d = f - 1
因为 f ∈ [1,2)令:d=f−1则:d∈[0,1)
我们要拟合:log2(1+d)
4. 三阶多项式拟合公式(工程标准)
log₂(1+d) 的三阶泰勒展开(最佳近似):
5. 系数转 Q8 定点(对应你代码的 369、185、85)
因为我们用 Q8 格式(×256):
- 1.4427 × 256 ≈369
- 0.7213 × 256 ≈185
- 0.3333 × 256 ≈85
所以代码里的多项式变成:
6. 归一化 f(代码最关键一步)
我们需要把 x 映射到 f ∈ [1,2),并转 Q8:
移位实现(永不溢出、永不负数):
uint32_t f_q8 = ((uint32_t)x << 8) >> k;这行代码完美支持 x=1~32768,包括 <256 的值。
7. d 的计算(Q8)
d=fq8−256因为 f ∈ [1,2)所以:d ∈ [0, 255](无符号,完美!)
8. 三阶多项式计算
uint32_t d = f_q8 - 256; uint32_t d2 = (d * d) >> 8; uint32_t d3 = (d2 * d) >> 8; uint32_t term1 = (d * 369) >> 8; uint32_t term2 = (d2 * 185) >> 8; uint32_t term3 = (d3 * 85) >> 8; uint32_t logf_q8 = term1 - term2 + term3;这就是在算:
9. 最终结果合并
uint32_t res = ((uint32_t)k << 8) + logf_q8;10. 原理总结
- x = 2ᵏ · f,f ∈ [1,2)
- log₂(x) = k + log₂(f)
- log₂(f) 用三阶多项式拟合(最精准)
- 全部转为 Q8 定点整数运算(无浮点)
- 全无符号类型(无溢出、无负数)
- 支持 1~32768 全范围正确
11. 原理 → 代码 逐行对应表
| 原理公式 | 代码 |
|---|---|
| x = 2ᵏ·f | k = 最高位 |
| f_q8 = x·256 / 2ᵏ | ((uint32_t)x <<8) >>k |
| d = f-1 | d = f_q8 -256 |
| log₂(1+d) ≈1.4427d -0.7213d² +0.3333d³ | term1 - term2 + term3 |
| log₂(x) = k + log₂(f) | (k<<8) + logf_q8 |
12. 为什么三阶精度最高?
- 一阶(线性):误差大
- 二阶:误差较小
- 三阶:误差 < 0.15 LSB(几乎完美)
