白光干涉的光谱域深度测量:从光谱到深度谱
Spectral-domain white-light interferometry, from spectrum to A-scan
光谱域白光干涉(spectral-domain white-light interferometry,也叫 spectral-domain OCT 的 A-scan)用一次光谱采集同时得到整条光路上所有反射面的位置,不需要机械扫描。本文把它的原理、分辨率与量程、处理流程一次讲清楚,后面几篇笔记都以这里的记号为基础。
1. 记号与约定#
- 波长 ,波数 (单位 ),角波数 。
- 反射面的几何深度 ,所在介质折射率 。
- 对光谱 作傅里叶变换,共轭变量记为 ,单位是长度,等于往返光程差(OPD)。
- 本站统一把深度轴定义为 ("表观深度")。空气中它等于几何深度,介质中等于 ( 为群折射率,见下)。
2. 干涉光谱的形式#
设参考光场幅度为 ,各反射面的幅度为 、深度为 ,光源光谱包络为 ,则光谱仪记录的是
展开后是三类项:
- 第一类是直流项(不含条纹)。
- 第二类是参考与各反射面之间的干涉,条纹频率正比于 ,这是我们要的信号。
- 第三类是反射面两两之间的干涉(自相关项),会在 处出现假峰。
对 做傅里叶变换,第 个条纹分量在
处出现峰。所以宽带测量读到的是群折射率 乘几何深度,不是相位折射率 。这一点对透过硅测量 TSV 深度很关键(见 TSV 深度的白光干涉测量)。
3. 分辨率与量程#
设光谱覆盖 到 ,在波数上的宽度
对 个在波数上均匀分布的采样点:
两个式子的含义:
- 分辨率只由带宽决定,与采样点数无关。带宽越宽越好。
- 量程等于 个分辨单元。点数固定时,分辨率和量程互相绑定:要看更深,就得增加像素数,或者接受更粗的分辨率。
几个典型波段(空气中,):
| 波段 | () | 分辨单元 | 量程 |
|---|---|---|---|
| 400–700 nm | 1.071 | 0.47 μm | 239 μm |
| 1200–1400 nm | 0.119 | 4.2 μm | 2.15 mm |
| 1260–1360 nm | 0.058 | 8.6 μm | 4.38 mm |
可见光宽谱给亚微米分辨率,但量程只有 0.2 mm 量级;近红外窄带反过来。透过硅测量时,表中数值要再除以 才是硅里的几何深度。
是一个 FFT 格点的间距(名义分辨率)。实际峰宽还取决于窗函数和光源光谱形状。在本文的仿真(400–700 nm,平滑的高斯型光源包络)里,单个反射面的峰半高全宽(FWHM)是:
- 矩形窗:0.59 μm,约 1.3 倍名义值;
- Hann 窗:0.96 μm,约 2.1 倍名义值。
4. 处理流程#
- 扣背景。 暗噪声、参考光谱(或无样品时的光谱)先扣掉,得到干涉项。
- 重采样。 光谱仪的像素在波长上均匀,FFT 要求在波数上均匀。用三次样条把 插值到均匀的 网格。
- 去慢变基线。 光源包络和直流项会在零深度附近漏出一大片,用低阶多项式或滑动平均去掉。
- 加窗。 抑制旁瓣,代价是峰变宽(见第 6 节)。
- 补零 FFT。 补零 4–8 倍只是对谱做内插,让峰形更平滑、峰位更好找,并不提高分辨率。
- 取模、找峰。 对峰做抛物线内插,得到亚格点的位置。
import numpy as np
from scipy.interpolate import CubicSpline
def depth_profile(lam_um, I, pad=8):
"""lam_um: wavelengths in um (ascending); I: background-corrected spectrum."""
sigma = 1.0 / lam_um # 1/um, descending
s = np.linspace(sigma.min(), sigma.max(), len(I)) # uniform in sigma
Iu = CubicSpline(sigma[::-1], I[::-1])(s) # 1) resample
t = np.linspace(-1, 1, len(Iu))
x = Iu - np.polyval(np.polyfit(t, Iu, 3), t) # 2) remove slow baseline
x = x * np.hanning(len(x)) # 3) window
A = np.abs(np.fft.rfft(x, n=pad * len(x))) # 4) zero-padded FFT
opd = np.fft.rfftfreq(pad * len(x), d=s[1] - s[0]) # conjugate of sigma = OPD (um)
return opd / 2, A # z_app = OPD / 2
def parabolic_peak(z, A):
"""Sub-bin peak position from the three samples around the maximum."""
i = int(np.argmax(A))
y0, y1, y2 = A[i - 1], A[i], A[i + 1]
return z[i] + 0.5 * (y0 - y2) / (y0 - 2 * y1 + y2) * (z[1] - z[0])5. 为什么必须先重采样#
偷懒的做法是直接对按波长均匀的数据做 FFT。结果是条纹频率沿光谱"啁啾":长波一侧条纹稀,短波一侧条纹密,傅里叶变换没法把它们聚成一个尖峰。
在上面的仿真里:
| 真实深度 | 重采样后 | 直接 FFT |
|---|---|---|
| 30 μm | 峰在 30.01 μm,FWHM 0.96 μm | 峰在 26.8 μm,FWHM 约 14 μm,峰高只有 27% |
| 150 μm | 峰在 150.00 μm,FWHM 1.00 μm | 峰位 133.6 μm,FWHM 约 50 μm,峰高只有 13% |
不仅位置偏了,峰也塌成一个包。深度越大,条纹越密,问题越严重。
重采样要用三次样条或更高阶的内插,不要用线性内插。条纹较密时(比如 150 μm 处每周期只有 3 个点左右),线性内插会明显压低条纹幅度。
6. 常见的坑#
- 窗函数是在分辨率和旁瓣之间换。 矩形窗峰最窄,但第一旁瓣只比主峰低约 13 dB,强反射面的旁瓣会淹没旁边的弱信号;Hann 窗旁瓣约 −31 dB,峰宽约 1.6 倍(上面实测 0.59 → 0.96 μm)。弱信号(比如深孔底部)旁边有强反射面时,宁可牺牲分辨率。
- 混叠。 超过量程的反射会折回量程内,变成"假深度",见 薄层标准具伪影。
- 自相关项。 多个反射面时,两两之间的干涉会在差值深度处冒出峰(上图 25 μm 处)。反射面一多,容易把它当成真实结构。
- 色散。 介质里 不是常数,相位不再严格线性于 ,峰会展宽。介质越厚、带宽越宽越明显。可以在 FFT 前乘以二次相位项做数值补偿(需要解析信号)。
- 波长轴标定。 波长轴有常数偏移 时,深度读数的相对误差约为 。仿真验证:1 nm 偏移、深度 100 μm 时读数偏小 0.41%(约 0.4 μm)。需要亚微米的绝对精度时,光谱仪必须用谱线灯标定,最好用已知厚度的标准件再标一遍。