第二章:数学基础——正交多项式与Zernike的“身份证”
做自由曲面设计,绕不开Zernike多项式。但很多人一上来就背系数、记公式,结果拟合出来的面型全是“假收敛”。
我个人习惯,先搞清楚它的数学底子——正交性。这东西就像人的身份证,有了它,每个多项式才独立,不会互相“打架”。
2.1 正交多项式:为什么我们需要“正交”?
先问个问题:为什么不用普通的幂级数(比如 x, x², x³)去拟合曲面?
我在项目里试过。用幂级数拟合一个非球面,系数之间严重耦合。你调一个低阶项,高阶项也跟着变,迭代半天不收敛。说白了,就是基函数不正交。
正交的定义:两个函数 f(x) 和 g(x) 在区间 [a,b] 上,如果满足:
∫ f(x) · g(x) · w(x) dx = 0 (a 到 b)
其中 w(x) 是权函数,那它们就是正交的。
正交的好处很明显:
- 系数独立:每个系数只代表对应项的分量,互不干扰。
- 最小二乘拟合稳定:法方程矩阵是对角阵,直接除就出结果,不用求逆。
- 截断误差可控:你丢掉高阶项,低阶项系数不变。
核心观点:正交多项式是拟合的“正交坐标系”。就像用 xyz 轴描述空间点一样,每个轴独立,不会因为移动一个点而改变另一个轴的读数。
2.2 Gram-Schmidt正交化:从“杂乱”到“正交”的标准化流程
现实中,我们拿到的原始多项式集往往不正交。比如单位圆上的幂级数。怎么办?
Gram-Schmidt 过程就是干这个的。它像一台“正交化机器”,输入一组线性无关的基,输出一组正交基。
算法步骤(我习惯用 Python 实现):
- 取第一个基函数 φ₀(x) = f₀(x),直接归一化。
- 对第 k 个基函数 fₖ(x),减去它在前面所有已正交化基函数上的投影:
φₖ(x) = fₖ(x) - Σ ⟨fₖ, φⱼ⟩ / ⟨φⱼ, φⱼ⟩ · φⱼ(x) (j=0 到 k-1) - 归一化:φₖ(x) = φₖ(x) / √⟨φₖ, φₖ⟩
嗯,这里要注意:数值上,Gram-Schmidt 容易因为舍入误差丢失正交性。我建议用 Modified Gram-Schmidt (MGS),每次投影完立即减去,稳定性好很多。
我的经验:在 Matlab 里直接用 orth() 或 qr() 函数,底层就是 MGS。Python 里用 numpy.linalg.qr 的 mode='reduced' 也能得到正交基。别自己手写原始 GS,除非你想调试数值稳定性。
2.3 Zernike多项式的正交性证明
Zernike 多项式定义在单位圆盘上。它的正交性分两部分:
- 角度方向:用三角函数 cos(mθ) 和 sin(mθ),在 [0, 2π] 上天然正交。
- 径向方向:用 Jacobi 多项式的特例——Zernike 径向多项式 Rₙᵐ(ρ),在 [0,1] 上带权函数 ρ 正交。
完整正交关系:
∫∫ Zₙᵐ(ρ,θ) · Zₙ'ᵐ'(ρ,θ) · ρ dρ dθ = π/(2n+2) · δₙₙ' · δₘₘ'
其中 δ 是 Kronecker delta。注意权函数 ρ 来自极坐标的面积元 dA = ρ dρ dθ。
为什么这个正交性这么重要?
我在做自由曲面拟合时,经常需要判断“这个面型主要有哪些像差成分”。如果基函数不正交,你算出来的系数会互相“串扰”,根本分不清是球差还是彗差。Zernike 的正交性保证了:每个系数直接对应一种像差模式的贡献量。
避坑指南:我曾经用非标准化的 Zernike 多项式做拟合,结果系数和标准泽尼克系数差了一个常数因子。后来才发现,不同文献对 Zernike 的归一化方式不同(比如 Noll 归一化 vs. ANSI 标准)。拟合前一定要确认你用的多项式集是 正交归一 的,否则系数没有物理意义。
2.4 知识结构图:正交化与Zernike的关系
下面这张图展示了从原始多项式到 Zernike 正交基的完整路径:
2.5 正交性验证:一个简单的数值实验
光说不练假把式。我写了个小代码片段,验证 Zernike 多项式的正交性:
import numpy as np
from scipy.special import eval_jacobi
def zernike_radial(n, m, rho):
"""Zernike径向多项式 R_n^m(rho)"""
# 使用Jacobi多项式实现
s = (n - abs(m)) // 2
if s < 0:
return np.zeros_like(rho)
coeff = (-1)**s * np.sqrt(2*n+2) # 归一化因子
# 实际计算略,这里用scipy的jacobi
return eval_jacobi(s, abs(m), 0, 1 - 2*rho**2) * rho**abs(m)
# 生成采样点
N = 200
rho = np.linspace(0, 1, N)
theta = np.linspace(0, 2*np.pi, N)
RHO, THETA = np.meshgrid(rho, theta)
# 计算两个Zernike项
Z1 = zernike_radial(2, 0, RHO) # 离焦
Z2 = zernike_radial(4, 0, RHO) # 球差
# 计算内积(带权函数rho)
integrand = Z1 * Z2 * RHO
integral = np.trapz(np.trapz(integrand, rho, axis=1), theta)
print(f"内积 ⟨Z₂⁰, Z₄⁰⟩ = {integral:.2e}")
# 输出应该接近 0(10^-15 量级)
小技巧:验证正交性时,采样点要足够密,尤其在 ρ 接近 0 的区域。我一般用 500×500 的网格,积分用 Simpson 法则,精度更高。
2.6 常见正交多项式对比
| 多项式类型 | 定义域 | 权函数 | 典型应用 |
|---|---|---|---|
| Legendre | [-1, 1] | 1 | 一维函数拟合 |
| Chebyshev | [-1, 1] | 1/√(1-x²) | 极小化最大误差 |
| Hermite | (-∞, ∞) | e^{-x²} | 量子力学、概率 |
| Zernike | 单位圆盘 | ρ | 光学波前、自由曲面 |
你看,Zernike 的独特之处在于定义域是圆盘,权函数是 ρ。这正好匹配圆形光瞳和极坐标采样。其他多项式在圆域上都不正交。