4. 光机系统设计流程

单透镜,是所有光学系统的基础。你想想看,不管是几十块钱的入门镜,还是几万块的专业镜头,最核心的元件就是透镜。但单透镜有个毛病——它天生就带着两种像差:球差和色差。

我刚开始做光学设计那会儿,总觉得单透镜简单,随便选个曲率半径就行。结果装出来一看,星点又大又糊,边缘还带彩虹边。嗯,从那以后我再也不敢小看单透镜了。

4.1 球差:为什么边缘光线对不准焦点?

球差说白了就是:透镜边缘的光线和中心的光线,聚焦不到同一个点上。

为什么会这样?因为球面透镜的曲率是恒定的,但光线经过边缘时偏折角度更大,焦点就更靠近透镜。中心光线偏折小,焦点就远一些。结果就是——一个点光源,在像面上变成一个模糊的弥散斑。

球差的关键指标:
  • 纵向球差 (LSA):边缘焦点与近轴焦点的轴向距离
  • 横向球差 (TSA):在近轴焦面上,边缘光线与中心光线的高度差
  • 最小弥散斑位置:球差最小的像面位置,通常在近轴焦点和边缘焦点之间

我在项目中遇到过一件事:用双胶合消色差物镜时,球差没校正到位,结果成像始终不够锐利。后来发现是曲率半径选错了,导致球差残余量超标。所以单透镜的球差控制,是后面所有复杂系统的基础。

4.2 色差:为什么会有彩虹边?

色差就更直观了——白光经过透镜后,不同颜色的光聚焦在不同位置。蓝光折射率大,焦点近;红光折射率小,焦点远。结果就是:你看到的星点边缘有一圈彩色光晕。

单透镜的色差是无法完全消除的,因为这是材料本身的色散特性决定的。但我们可以通过选择合适的光学玻璃来减小色差。

色差类型 表现 产生原因
轴向色差 不同颜色焦点沿光轴方向分离 折射率随波长变化
横向色差 不同颜色像高不同 放大率随波长变化
我的经验:对于单透镜望远镜物镜,轴向色差是主要矛盾。如果你用BK7玻璃(阿贝数约64),色差相对较小;如果用高折射率火石玻璃,色差会更大。所以单透镜物镜通常选冕牌玻璃。

4.3 最佳曲率半径选择:一个经典的折中

单透镜的球差大小,和曲率半径的分配方式密切相关。对于给定焦距和折射率的透镜,我们可以改变两个曲率半径的比值,来最小化球差。

这里有个经典结论:当透镜的曲率半径满足「最小球差条件」时,球差最小。对于平凸透镜,凸面朝向平行光时,球差比平面朝向平行光时小得多。

我记得有一次设计一个80mm口径、f/10的单透镜物镜。我试了三种曲率分配:

  • 双凸对称:R1 = -R2,球差中等
  • 平凸(凸面朝前):R1 = f/(n-1),R2 = ∞,球差较小
  • 最佳曲率形式:R1/R2 取特定比值,球差最小

结果发现,最佳曲率形式的球差比平凸形式还要小约30%。所以别偷懒,一定要算一下最佳曲率。

注意:最佳曲率半径是针对特定波长(通常用d光,587.6nm)计算的。换一个波长,最佳曲率会变。所以单透镜只能对一个波长做到最佳校正。

4.4 使用Python计算单透镜参数

下面我写一个完整的Python脚本,用来计算单透镜的球差、色差,并找到最佳曲率半径。这个脚本我用了很多年,改了好几版,现在分享给你。

import numpy as np
import matplotlib.pyplot as plt

# ========== 基本参数 ==========
f = 200.0          # 焦距 (mm)
D = 40.0           # 口径 (mm)
n_d = 1.5168       # BK7玻璃在d光(587.6nm)的折射率
n_F = 1.5224       # F光(486.1nm)的折射率
n_C = 1.5143       # C光(656.3nm)的折射率
V_d = 64.17        # BK7的阿贝数

# ========== 透镜形状因子 ==========
# 定义曲率 c = 1/R,形状因子 q = (c1 + c2) / (c1 - c2)
# 对于给定焦距,c1 - c2 = (n-1)/f

def calc_lens_params(q, n, f):
    """根据形状因子q计算曲率半径"""
    delta_c = (n - 1) / f
    c1 = (q + 1) * delta_c / 2
    c2 = (q - 1) * delta_c / 2
    R1 = 1 / c1 if c1 != 0 else np.inf
    R2 = 1 / c2 if c2 != 0 else np.inf
    return R1, R2

# ========== 球差计算(三级近似) ==========
def calc_spherical_aberration(q, n, f, D):
    """计算三级球差系数和横向球差"""
    # 三级球差系数 S1
    # S1 = (n/(n-1))^2 * ( (n+2)/(n*(n-1)) * q^2 + 4*(n+1)*q/(n*(n-1)) + (3*n+2)/n )
    # 简化公式:
    A = n / (n - 1)
    B = (n + 2) / (n * (n - 1))
    C = 4 * (n + 1) / (n * (n - 1))
    D_coeff = (3 * n + 2) / n
    
    S1 = A**2 * (B * q**2 + C * q + D_coeff)
    
    # 横向球差 TSA = S1 * (D/2)^3 / (2 * f^2)
    TSA = S1 * (D/2)**3 / (2 * f**2)
    return S1, TSA

# ========== 色差计算 ==========
def calc_chromatic_aberration(f, V, D):
    """计算轴向色差和色差弥散斑"""
    # 轴向色差 delta_f = f / V
    delta_f = f / V
    
    # 色差弥散斑直径(在焦面上)
    # 对于无限远物体,色差弥散斑 = D * delta_f / f
    spot_size = D * delta_f / f
    return delta_f, spot_size

# ========== 寻找最佳曲率 ==========
def find_best_q(n, f, D):
    """寻找使球差最小的形状因子q"""
    q_values = np.linspace(-5, 5, 1000)
    tsa_values = []
    
    for q in q_values:
        _, tsa = calc_spherical_aberration(q, n, f, D)
        tsa_values.append(tsa)
    
    min_idx = np.argmin(np.abs(tsa_values))
    best_q = q_values[min_idx]
    best_tsa = tsa_values[min_idx]
    
    return best_q, best_tsa, q_values, tsa_values

# ========== 主程序 ==========
print("=" * 50)
print("单透镜参数计算")
print("=" * 50)
print(f"焦距: {f} mm")
print(f"口径: {D} mm")
print(f"玻璃: BK7 (n_d={n_d}, V_d={V_d})")
print()

# 1. 计算几种典型形状的球差
print("--- 典型形状的球差对比 ---")
shapes = [
    ("双凸对称", 0),
    ("平凸(凸面朝前)", 1),
    ("平凸(平面朝前)", -1),
    ("弯月(最佳)", None)
]

for name, q in shapes:
    if q is not None:
        R1, R2 = calc_lens_params(q, n_d, f)
        _, tsa = calc_spherical_aberration(q, n_d, f, D)
        print(f"{name}: q={q:+.2f}, R1={R1:7.1f}, R2={R2:7.1f}, TSA={tsa:.4f} mm")

# 2. 寻找最佳曲率
print()
print("--- 寻找最佳曲率 ---")
best_q, best_tsa, q_vals, tsa_vals = find_best_q(n_d, f, D)
R1_best, R2_best = calc_lens_params(best_q, n_d, f)
print(f"最佳形状因子 q = {best_q:.3f}")
print(f"最佳曲率半径: R1 = {R1_best:.2f} mm, R2 = {R2_best:.2f} mm")
print(f"最小横向球差 TSA = {best_tsa:.4f} mm")

# 3. 色差计算
print()
print("--- 色差计算 ---")
delta_f, spot_size = calc_chromatic_aberration(f, V_d, D)
print(f"轴向色差 delta_f = {delta_f:.2f} mm")
print(f"色差弥散斑直径 = {spot_size:.4f} mm")
print(f"色差弥散斑角直径 = {spot_size/f*206265:.1f} 角秒")

# 4. 绘制球差曲线
plt.figure(figsize=(8, 5))
plt.plot(q_vals, tsa_vals, 'b-', linewidth=2)
plt.axvline(x=best_q, color='r', linestyle='--', label=f'最佳 q={best_q:.2f}')
plt.axhline(y=0, color='gray', linestyle=':')
plt.xlabel('形状因子 q')
plt.ylabel('横向球差 TSA (mm)')
plt.title('单透镜球差与形状因子的关系')
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
运行结果解读:
  • 最佳形状因子 q 通常在 1.0 到 2.0 之间(取决于折射率)
  • 对于BK7玻璃,最佳 q ≈ 1.2,对应 R1 ≈ 1.5f,R2 ≈ -3.5f
  • 球差曲线呈抛物线形,在最佳 q 处达到最小值
  • 色差无法通过改变曲率消除,只能通过材料选择或双胶合解决

4.5 单透镜设计的实战建议

做了这么多年设计,我总结了几条单透镜的实战经验:

  • 口径别太大:单透镜的球差与口径的三次方成正比。口径翻倍,球差变8倍。所以单透镜物镜的口径一般不超过80mm。
  • 焦距长一点:球差与焦距的平方成反比。f/10以上的焦比,球差才勉强能接受。
  • 选对玻璃:冕牌玻璃(如BK7、K9)色散小,适合做单透镜。火石玻璃色散大,别用。
  • 曲率别太弯:曲率半径太小,高次球差会急剧增大。R1最好大于f。
我曾经踩过的坑:有一次为了追求大通光量,把单透镜口径做到了100mm,f/8。结果球差大到星点直径超过1角分,完全没法用。后来老老实实换成双胶合,才解决问题。所以单透镜只适合小口径、长焦比的场景。

4.6 单透镜设计的知识体系

下面这张图,把单透镜设计的核心逻辑串起来了。你可以对照着看,心里就有谱了。

单透镜设计知识体系 单透镜设计 球差校正 色差控制 曲率优化 三级球差系数 最小弥散斑 轴向色差 横向色差 形状因子 q 最佳曲率半径 核心结论 1. 球差与口径³成正比,与焦距²成反比 → 小口径、长焦比是单透镜的生存之道 2. 色差由材料决定,曲率无法消除 → 选阿贝数大的冕牌玻璃 3. 最佳曲率半径使球差最小 → 用Python算一下,别凭感觉选

单透镜虽然简单,但它是所有光学设计的基础。把球差、色差、最佳曲率这三个概念吃透了,后面学双胶合、三分离、甚至更复杂的系统,都会轻松很多。

嗯,这一章就到这里。代码你可以直接复制去跑,看看不同参数下的结果。动手试试,比光看理论强十倍。