4. 点列图与波像差的关系:几何光线与波前的联系,从点列图到波前的桥梁

前面几章我们聊了点列图怎么算、怎么看。但有个问题我一直想跟你聊聊——点列图说到底只是几何光线的落点统计,它跟真实的物理光学之间,到底差了什么?

说白了,点列图是“射线”的视角,而波前是“相位”的视角。这两者之间,其实有一座桥。今天我们就来走一走这座桥。

4.1 从几何光线到波前:一个思想实验

想象一束平行光射入镜头。在几何光学里,我们追迹每一条光线,看它们最后落在像面上的位置。但在物理光学里,光是以波的形式传播的——波前是等相位面,光线其实是波前的法线方向。

嗯,这里要注意:光线和波前是垂直的。这个关系是理解点列图与波像差之间联系的关键。

核心关系:

  • 光线方向 = 波前的梯度方向(法线)
  • 光线路径长度差 = 波前相位差
  • 点列图弥散 = 波前畸变的几何表现

我在项目中遇到过一位同事,他只看点列图优化镜头,RMS半径压到很小,但成像就是不够锐利。后来一测波前,发现波像差有0.3λ。这就是典型的“几何好、物理差”——点列图骗了你。

4.2 波像差的数学表达

波像差通常用 OPD(Optical Path Difference) 来表示。它描述的是实际波前与理想球面波前之间的光程差。

数学上,我们可以写成:

W(x, y) = OPD(x, y) = [实际光程] - [理想光程]

其中 (x, y) 是出瞳面上的坐标。这个 W(x, y) 就是波像差函数。

你想想看,如果 W(x, y) = 0,说明波前是完美的球面,成像就是衍射极限。如果 W(x, y) 不为零,波前就发生了畸变。

4.3 点列图与波像差的定量关系

这里有个重要的公式,我个人觉得是光学设计里最优雅的关系之一:

Δx = (∂W/∂x) * (f / n)
Δy = (∂W/∂y) * (f / n)

其中:

  • Δx, Δy 是光线在像面上的横向位移(就是点列图里的坐标)
  • W 是波像差函数
  • f 是焦距
  • n 是像方折射率

看到了吗?点列图上的每一个点,本质上就是波像差函数的梯度。波前越扭曲,梯度越大,点列图就越散。

我的经验: 在做初始结构优化时,我习惯先看点列图,因为它计算快、直观。但到了精调阶段,我一定会切到波前图(OPD Fan)去看。点列图告诉你“光线偏了多少”,波前图告诉你“为什么偏”。

4.4 从点列图反推波前:Zernike多项式拟合

既然点列图是波前的梯度,那理论上我们可以从点列图反推波前。怎么做?用Zernike多项式拟合。

Zernike多项式是一组在单位圆上正交的基函数,非常适合描述光学系统的波像差。常见的项包括:

Zernike项 名称 物理意义
Z₄ 离焦 像面位置偏移
Z₅, Z₆ 像散 子午/弧矢焦点分离
Z₇, Z₈ 彗差 非对称弥散
Z₉ 球差 孔径边缘与中心焦点偏移
Z₁₁ 三叶草 高阶非对称像差

拟合的过程大致是这样的:

  1. 从点列图获取一组光线坐标 (Δxᵢ, Δyᵢ)
  2. 建立Zernike梯度矩阵(每个Zernike项对x和y的偏导)
  3. 用最小二乘法求解Zernike系数
  4. 重构波前 W(x, y)

我曾经用这个方法帮一个团队排查问题。他们的镜头点列图看起来还行,但成像总有点“雾感”。我拟合出波前后发现,Z₄(离焦)项有0.15λ,Z₉(球差)有0.12λ。调整了空气间隔后,波像差降到0.05λ以下,成像立刻通透了很多。

4.5 点列图到波前的桥梁:知识结构图

下面这张图总结了点列图与波像差之间的核心关系:

点列图 → 波前:核心关系图 点列图 光线落点统计 波前 等相位面 梯度关系 Δx = ∂W/∂x · f/n Δy = ∂W/∂y · f/n Zernike多项式拟合 从离散光线 → 连续波前 像差分解 球差/彗差/像散 MTF预测 波前 → 光学传递函数 公差分析 波前敏感度 💡 点列图是波前的“导数”,波前是点列图的“积分” 两者互补,缺一不可

4.6 实际工程中的注意事项

聊了这么多理论,说点实际的。我在工程中总结了几条经验:

避坑指南:

  • 点列图好 ≠ 波前好:我曾经遇到一个系统,点列图RMS只有3μm,但波前有0.25λ的球差。原因是光线分布虽然集中,但相位分布不均匀——这在干涉测量中会直接表现为条纹畸变。
  • 采样密度要够:从点列图拟合波前时,至少需要50-100条光线,否则Zernike系数不稳定。我一般用128×128的网格。
  • 注意边缘光线:点列图边缘的点对波前拟合影响很大,因为它们对应高梯度的区域。如果边缘光线追迹不准,拟合出的波前会严重失真。

4.7 一个简单的Python示例

最后,给你一个从点列图到波前拟合的Python代码片段。这个代码我经常在项目初期用来快速评估像差:

import numpy as np
from scipy.optimize import lstsq

def zernike_gradient(x, y, terms):
    """
    计算Zernike多项式的梯度
    x, y: 归一化出瞳坐标 (-1 ~ 1)
    terms: 需要计算的Zernike项索引列表
    """
    # 这里只展示Z₄(离焦)和Z₅(像散)的梯度
    # 实际使用需要完整的Zernike梯度矩阵
    n_rays = len(x)
    n_terms = len(terms)
    G = np.zeros((2*n_rays, n_terms))
    
    for j, term in enumerate(terms):
        if term == 4:  # 离焦: Z₄ = 2r² - 1
            r = np.sqrt(x**2 + y**2)
            # ∂Z₄/∂x = 4x, ∂Z₄/∂y = 4y
            G[:n_rays, j] = 4 * x
            G[n_rays:, j] = 4 * y
        elif term == 5:  # 像散: Z₅ = r²cos(2θ)
            # ∂Z₅/∂x = 2x, ∂Z₅/∂y = -2y
            G[:n_rays, j] = 2 * x
            G[n_rays:, j] = -2 * y
    
    return G

# 假设有点列图数据
# dx, dy: 光线在像面上的偏移(单位:mm)
# f: 焦距(mm)
# n: 像方折射率

dx = np.array([...])  # 你的点列图x坐标
dy = np.array([...])  # 你的点列图y坐标
f = 100.0
n = 1.0

# 归一化出瞳坐标
x_pupil = np.array([...])  # 对应光线的出瞳x坐标
y_pupil = np.array([...])  # 对应光线的出瞳y坐标

# 构建梯度矩阵
terms = [4, 5]  # 只拟合离焦和像散
G = zernike_gradient(x_pupil, y_pupil, terms)

# 构建观测向量(光线偏移)
b = np.concatenate([dx * n / f, dy * n / f])

# 最小二乘求解Zernike系数
coeffs, residuals, _, _ = lstsq(G, b, rcond=None)

print(f"Z₄ (离焦) 系数: {coeffs[0]:.4f}")
print(f"Z₅ (像散) 系数: {coeffs[1]:.4f}")

小提示: 实际项目中,我建议直接用Zemax或Code V的API来获取光线数据和Zernike系数,比自己写拟合要可靠得多。但理解这个原理,能帮你判断软件给出的结果是否合理。

好了,这一章我们聊了从点列图到波前的桥梁——梯度关系、Zernike拟合、工程注意事项。说白了,点列图和波前就像一枚硬币的两面,一个看位置,一个看相位。只有把两者结合起来,你才能真正理解一个光学系统的成像质量。