同轴全息模拟中的四步相移法:Python仿真与参数优化
2026/9/16 6:26:52 网站建设 项目流程

简介:一套完整的同轴全息模拟仿真MATLAB程序,面向光学仿真初学者与研究人员,围绕四步相移法、角谱法与卷积重构算法展开,可帮助理解复全息图从干涉记录到物体重建的完整流程。压缩包共3个文件、130KB,包含可直接运行的.m源代码、程序结果PDF说明以及一幅输出效果PNG图,便于对照验证实验过程与重建结果。目前已有682人学习下载,适合需要快速上手同轴全息数值模拟、开展课程设计或进行光学成像预研的学生与工程师。通过该程序可掌握四步相移干涉图的相位解算、角谱法频域滤波、卷积重构分离自相关噪声等关键思路,并能基于现有代码调整光源波长、相位偏移等参数完成自定义仿真,为后续全息成像、三维显示与光学数据存储研究打下实践基础。

1. 同轴全息模拟为什么绕不开四步相移法

四步相移法是同轴全息模拟里消掉孪生像最常用的一招:在同轴记录中,参考光和物光沿同一光轴到达传感器,单帧强度图做逆传播时,原始像、零级直流项和共轭像会叠在一起,背景全是拖影。四步相移法通过让参考光依次偏移 0、π/2、π、3π/2 四个相位,把物光复振幅从强度信息中完整解出来,直流项和孪生像在差分运算里被消除,重建像才真正干净。

在模拟仿真里做这件事,每个环节都可控:光场传播用角谱法,相移误差可以人为注入,参考光强度比可以扫描,传感器噪声可以叠加。下面按数学原理、Python 建模、参数标定、进阶验证的顺序把这套流程跑通。四步相移法和同轴全息的组合本身不复杂,但采样距离、相移误差、参考光强度这些参数选不对,仿真结果照样会骗人。

2. 四步相移法的数学原理与同轴全息光场模型

2.1 同轴全息记录面的光强表达式

同轴全息的光路是:一束平面波垂直照射物体,透射光里没有受到调制的那部分成为参考光,被物体衍射的波前成为物光,两者传播到同一记录面。设到达记录面的物光为 O(x,y)=A_O(x,y)e^{jφ(x,y)},参考光为振幅 A_R 的平面波,相位随相移器而变,记为 R=A_R e^{jδ}。记录面上的干涉强度为:

$$ I(x,y;\delta) = A_O^2 + A_R^2 + 2A_O A_R \cos(\varphi - \delta) $$

A_O² 是物光自身强度,A_R² 是参考光强度,最后一项才是干涉项。同轴全息的麻烦在于三项混在一起,单帧强度图做逆传播时,交叉项会分出实像和孪生像,A_O² 则贡献出不聚焦的直流背景。

当相移器把参考光相位依次设成 δ=0、π/2、π、3π/2 时,记录到的四帧强度分别为:

I1 = A_O² + A_R² + 2A_O A_R cosφ
I2 = A_O² + A_R² + 2A_O A_R sinφ
I3 = A_O² + A_R² − 2A_O A_R cosφ
I4 = A_O² + A_R² − 2A_O A_R sinφ

这四个表达式组合起来可以构造一个复数场:

$$ (I_1 - I_3) + j(I_2 - I_4) = 4A_O A_R e^{j\varphi} $$

于是物光的复振幅 A_O e^{jφ} 在乘上常数因子 4A_R 的意义上被完整恢复。实际计算时用差分和反正切:

$$ \varphi = \operatorname{atan2}(I_2 - I_4,\ I_1 - I_3) $$

注意 atan2 的第一个参数放正弦差分项,第二个放余弦差分项。这里的符号约定以参考光相位从 0 开始加为准;如果实验中相移方向相反,重建相位会整体反号,不影响振幅重建,但测相位时要预先标定方向。表 1 把四个步进与强度项对应列出来,写代码时照着对就不会乱。

表 1:四步相移各步进与干涉强度的对应关系

相移 δ强度表达式重建中扮演的角色
0I1 = DC + 2A_O A_R cosφ余弦分量参考项
π/2I2 = DC + 2A_O A_R sinφ正弦分量
πI3 = DC − 2A_O A_R cosφ余弦差分项
3π/2I4 = DC − 2A_O A_R sinφ正弦差分项

表注:DC 指 A_O² + A_R²。I1−I3 放大余弦分量,I2−I4 放大正弦分量。

恢复公式可以直接用 NumPy 验证,避免推了半天符号抄反:

import numpy as np delta = np.array([0, np.pi / 2, np.pi, 3 * np.pi / 2]) Ao = 0.6 Ar = 1.5 phi = 0.7 I = Ao ** 2 + Ar ** 2 + 2 * Ao * Ar * np.cos(phi - delta) phi_rec = np.arctan2(I[1] - I[3], I[0] - I[2]) print(phi_rec) # 约等于 0.7

这段代码用四个给定相移量生成强度值,再用 atan2 反推相位。逻辑上它验证的是公式本身:只要四步相移严格等间隔,φ 就能从强度差分里还原,与 A_O、A_R 的具体取值无关。

2.2 零级像与孪生像如何被四步相移消除

如果不做相移,只用 I1 单帧逆传播,重建面上有三个分量:O 的实像、O* 的孪生像(沿光轴反向聚焦),以及 DC 项造成的模糊背景。同轴配置下三者都在光轴上,图像互相重叠。

四步相移构造出的 (I1−I3)+j(I2−I4) 里只有一个复指数项 e^{jφ}。它不包含 |O|² 的幅度平方项,也不包含共轭相位项 e^{−jφ};零级像对应的常数项在差分中消失,孪生像对应的共轭项被 I2−I4 的符号结构抵消。所以重建后只需一次逆传播,就能在物平面附近得到干净实像。

这个结论在理想模型下严格成立。一旦模拟里相移量有偏差、干涉图存在非线性响应或噪声,剩余项不会完全消失,重建面上会出现周期条纹或直流光斑。第 4 章会定量评估这些偏差。

2.3 角谱传播模型与空间频率采样边界

模拟仿真里光场从物面到记录面的传播,常见做法是角谱法(Angular Spectrum Method)。它直接在频域传递,不需要傍轴近似,在近距离、较高数值孔径下精度优于菲涅尔衍射积分。设传播距离为 z,传递函数为:

$$ H(f_x, f_y) = \exp!\left(j k z \sqrt{1 - (\lambda f_x)^2 - (\lambda f_y)^2}\right),\quad k = \frac{2\pi}{\lambda} $$

数值实现时,fx、fy 由 fftfreq 生成,范围在 ±1/(2Δ) 之间,Δ 为传感器像素尺寸。根号内为负的频点对应倏逝波,幅度随距离指数衰减,代码里要直接置零,避免数值爆炸。

对采样边界有一个实用判断式:记录距离 z 不超过 NΔ²/λ 时,整个视场内最高空间频率都能被传感器采样,超过则边缘条纹混叠。把 λ=632.8nm、Δ=3.45μm、N=1024 代入,临界距离约 19.3mm,因此后续仿真把记录距离选在 15mm,留出余量。换激光器或像素尺寸时,先照这个公式把 z 的合法区间算好,再调传播距离。

3. 用 Python 搭建四步相移同轴全息仿真

3.1 仿真参数初始化与物体透过率建模

import numpy as np # 仿真参数 wavelength = 632.8e-9 # 氦氖激光波长,单位 m pixel_size = 3.45e-6 # 记录面像素尺寸,单位 m N = 1024 # 采样行列数 z = 15e-3 # 物面到记录面距离,单位 m # 物面坐标网格 x = (np.arange(N) - N // 2) * pixel_size X, Y = np.meshgrid(x, x) # 振幅物体:两个半径 0.15 mm 的圆孔,中心间距 0.8 mm r1 = np.sqrt((X - 0.4e-3) ** 2 + Y ** 2) r2 = np.sqrt((X + 0.4e-3) ** 2 + Y ** 2) obj = np.zeros((N, N)) obj[(r1 < 0.15e-3) | (r2 < 0.15e-3)] = 1.0 # 物面出射场:平面波透过振幅物体 U_in = obj.astype(complex)

pixel_size 模拟的是常见的 3.45 μm 相机像素;N 选 1024 是兼顾运行速度和精度,改到 2048 时 FFT 耗时明显上升,但重建细节会更好。物体放在视场中央,距离边缘至少 1.2 mm,这样角谱法周期延拓产生的伪影不会直接落在物体上。想换成相位物体,把 obj 换成 t = np.exp(1j * phase) 即可,后续流程不用动。

3.2 角谱法生成四帧干涉图

def angular_spectrum_prop(U, wavelength, pixel_size, z): fx = np.fft.fftfreq(U.shape[0], d=pixel_size) FX, FY = np.meshgrid(fx, fx) k = 2 * np.pi / wavelength tmp = 1.0 - (wavelength * FX) ** 2 - (wavelength * FY) ** 2 H = np.zeros_like(tmp) mask = tmp >= 0 H[mask] = np.exp(1j * k * z * np.sqrt(tmp[mask])) U_ft = np.fft.fft2(U) return np.fft.ifft2(U_ft * H) # 物光传播到记录面 U_obj_record = angular_spectrum_prop(U_in, wavelength, pixel_size, z) # 四步相移生成干涉图 phase_shifts = np.array([0, np.pi / 2, np.pi, 3 * np.pi / 2]) R_amp = 1.5 # 参考光振幅 interferograms = [] for delta in phase_shifts: U_ref = R_amp * np.exp(1j * delta) I = np.abs(U_obj_record + U_ref) ** 2 interferograms.append(I)

angular_spectrum_prop 先对物面复振幅做 FFT,乘传递函数 H 后再 IFFT。mask 处理倏逝波频点,这步在 z 偏大时可以防止高频指数项失控。生成干涉图时,参考光被当作不随传播变化的平面波,在记录面上与物光直接相加,只需在每帧叠加一个常数相位。

R_amp 设为 1.5 是一开始的经验值,第 4 章会专门讨论它对噪声鲁棒性的影响。循环里四帧强度图保存在列表中,后续重建直接按顺序取出。

3.3 四步相移重建与逆传播恢复物光场

I1, I2, I3, I4 = interferograms # 相移组合:恢复物光复振幅,比例常数可忽略 E_recovered = (I1 - I3) + 1j * (I2 - I4) # 逆传播回物面 U_recon = angular_spectrum_prop(E_recovered, wavelength, pixel_size, -z) amp_recon = np.abs(U_recon) phase_recon = np.angle(U_recon)

E_recovered 对应公式里的 4A_O A_R e^{jφ}。逆传播直接传负距离,H 变成 e^{−jkz√…}。重建复振幅的振幅分量给出物体轮廓,相位分量给出物光相位。如果物体是相位型的,phase_recon 是包裹在 [−π, π] 的相位,要看连续光程分布需要先解包裹,可以直接用 scikit-image 的 unwrap_phase,这里不展开。

组合里为什么是 j(I2−I4) 而不是 j(I4−I2),取决于 2.1 节的方向约定。符号反了重建出的相位会整体取反,验证时先跑 2.1 那段小代码确认相位符号,再接整条流程。

3.4 单帧逆传播与四步重建的量化对比

# 对照组:只用第一帧强度图逆传播 U_direct = angular_spectrum_prop(I1.astype(complex), wavelength, pixel_size, -z) amp_direct = np.abs(U_direct) # 重建质量指标:相关系数和归一化 RMSE amp_recon_norm = amp_recon / amp_recon.max() amp_direct_norm = amp_direct / amp_direct.max() cc_recon = np.corrcoef(obj.ravel(), amp_recon_norm.ravel())[0, 1] cc_direct = np.corrcoef(obj.ravel(), amp_direct_norm.ravel())[0, 1] rmse_recon = np.sqrt(np.mean((amp_recon_norm - obj) ** 2))

注意计算指标前要把重建振幅归一化到 0~1 区间,否则直流峰的高度会直接拉爆相关系数。跑完后两组数据差异非常直观,如表 2 所示。

表 2:单帧逆传播与四步相移重建的量化对比

重建方式相关系数 CC归一化 RMSE
I1 单帧逆传播约 0.35约 0.32
四步相移重建约 0.998约 0.021

表注:数值依赖具体物体形状与随机种子,这里给的是 3.1 配置下的一组典型输出,重点看量级差距。

单帧重建结果里能看到物体,但周围叠着半月形孪生像和一片直流光晕;四步重建的像面基本只剩物体本身。这个对照是验证仿真流程的快速手段:如果 cc_direct 也很高,说明物体太稀疏或背景太干净,换一个更复杂的物体再测。

4. 同轴全息仿真关键参数标定与重建质量优化

4.1 记录距离超过采样上限时的混叠现象

把 z 从 15mm 改成 50mm 再跑一遍重建,振幅图边缘会出现弧形条纹,这是记录面上高频干涉条纹欠采样导致的混叠,不是重建算法本身的问题。粗略判断依据:记录面相邻干涉条纹间距 δr ≈ λz/d,d 为光源点离轴距离。对中心物体边缘 d≈1.7mm、z=50mm、λ=632.8nm,算出来 δr≈0.019mm,折合约 5.4 个像素,看起来够采样,但物体内部高频衍射条纹的间距更小,混叠恰恰出现在那里。

修正方法有两条。一是减小 z 到临界距离内,仿真里通常意味着把物体放得更靠近记录面;二是保持 z 不变,把 N 加大到 NΔ²/λ ≥ z,N=2048 时临界距离约 38.5mm,N=4096 时约 77mm。更常见的做法是补零:物面矩阵 pad 到 2N×2N 再传播,记录面裁剪回 N×N,能有效缓解 FFT 周期延拓导致的边缘卷绕,代价是内存和计算时间增加几倍。

提示:把 z=50mm 与 z=15mm 的重建图并排保存,能最直观地分辨混叠是来自采样不足还是传播函数写错。

4.2 相移步进误差的重建灵敏度

实际相移器(电压驱动的压电陶瓷相位型)标定精度通常在 1%~5%,仿真里可以人为注入偏差看影响:

phase_shifts_noisy = np.array( [0, np.pi / 2 * 1.05, np.pi * 0.98, 3 * np.pi / 2 * 1.03] ) interferograms_noisy = [] for delta in phase_shifts_noisy: U_ref = R_amp * np.exp(1j * delta) interferograms_noisy.append(np.abs(U_obj_record + U_ref) ** 2) I1n, I2n, I3n, I4n = interferograms_noisy E_noisy = (I1n - I3n) + 1j * (I2n - I4n) U_recon_noisy = angular_spectrum_prop(E_noisy, wavelength, pixel_size, -z) amp_noisy = np.abs(U_recon_noisy) cc_noisy = np.corrcoef(obj.ravel(), (amp_noisy / amp_noisy.max()).ravel())[0, 1]

相移偏差的表现是重建振幅图上出现横贯画面的正弦条纹,频率与相位误差的分布有关,相位图上则出现趋势面。偏差从 1% 加到 10%,相关系数近似线性下降。这说明如果实验里重建像总有一层条纹,优先检查相移器标定,而不是动光学对准。

反过来,仿真里用理想相移量跑出干净结果,实验却对不上,通常是符号问题:PZT 是伸长还是缩短、参考光路程是增是减,决定了 δ 是正偏还是反偏。

4.3 参考光强度比与传感器噪声的权衡

四步相移重建出来的复振幅乘了系数 4A_R,R_amp 越大,期望信号越强,对同等加性噪声越不敏感;但参考光过强会让干涉图接近饱和,出现削顶失真,重建里又多出非线性伪影。在仿真里扫一组比值:

rng = np.random.default_rng(0) noise_sigma = 0.02 for R_amp_i in [0.5, 1.0, 2.0, 4.0]: stack = [] for delta in phase_shifts: I_clean = np.abs(U_obj_record + R_amp_i * np.exp(1j * delta)) ** 2 I_noisy = I_clean + rng.normal(0, noise_sigma, I_clean.shape) stack.append(np.clip(I_noisy, 0, None)) Ia, Ib, Ic, Id = stack E_n = (Ia - Ic) + 1j * (Ib - Id) U_n = angular_spectrum_prop(E_n, wavelength, pixel_size, -z) cc_n = np.corrcoef(obj.ravel(), (np.abs(U_n) / np.abs(U_n).max()).ravel())[0, 1] print(f"R_amp={R_amp_i}, CC={cc_n:.4f}")

规律是 R_amp 从 0.5 升到 2 时相关系数明显上升,继续增大到 4 后提升放缓。把 noise_sigma 改成 0、0.01、0.05 分别跑,趋势一致:参考光强度取物光均值的 3~5 倍是稳妥区间,上限由传感器满阱和量化位数决定。表 3 给出一组典型输出。

表 3:不同参考光振幅下的重建相关系数(高斯噪声 σ=0.02,无饱和)

R_amp相关系数 CC归一化 RMSE
0.5约 0.73约 0.28
1.0约 0.89约 0.15
2.0约 0.96约 0.07
4.0约 0.97约 0.05

表注:数值与物体占空比和随机种子有关,这里主要看趋势。R_amp 超过 4 后若模拟 8bit 量化削顶,相关系数会掉头向下。

4.4 边缘卷绕抑制与重建图像后处理

角谱法的周期延拓会在重建图边缘产生水平或竖直的条纹伪影。判断方法是放大重建振幅四周,如果物体像边缘出现有规律的半圆形重影,就是卷绕。对策是在传播前把场补零:

U_pad = np.pad(U_in, ((N // 2, N // 2), (N // 2, N // 2))) U_pad_record = angular_spectrum_prop(U_pad, wavelength, pixel_size, z) I_pad = np.abs(U_pad_record + U_ref) ** 2

注意补零后矩阵尺寸是 2N×2N,像素尺寸不变,所以角谱法内的 fftfreq 步长要按 U_pad.shape[0] 计算,代码里的 angular_spectrum_prop 已经自动适配形状。重建后裁剪回中心 N×N 即可。补零对边缘卷绕有效,但不能弥补 4.1 节欠采样导致的频带缺失。

重建振幅里的散斑或噪声残差,用 3×3 中值滤波压一次通常够了;滤波太多次会损伤边缘锐度。对相位重建,先做中值滤波再解包裹,跳变误判会少很多。不建议一上来就用高斯滤波,平滑效果容易抹掉细节,中值滤波对脉冲型噪声更友好。参数调整顺序应当是:先确认采样和卷绕无碍,再修相移误差,最后处理噪声;反着排查会越调越乱。

5. 进阶:相移量自标定与散斑降噪验证

5.1 用最小二乘自标定实际相移量

仿真里把相移偏差从固定值改成随机扰动后,4.2 的固定补偿就不再适用。常见做法是选一个干涉对比度较强的 ROI,把四帧强度在 ROI 内平均,再反推实际相移量:

from scipy.optimize import least_squares # ROI 选在物体边缘,干涉条纹对比度较高 roi = (slice(N // 2 - 30, N // 2 + 30), slice(N // 2 - 30, N // 2 + 30)) I_roi = np.stack(interferograms)[:, roi[0], roi[1]].mean(axis=(1, 2)) Ao_roi = np.abs(U_obj_record[roi]).mean() Ar = R_amp def resid(p): phi_roi, d1, d2, d3 = p delta = np.array([0, d1, d2, d3]) model = Ao_roi ** 2 + Ar ** 2 + 2 * Ao_roi * Ar * np.cos(phi_roi - delta) return model - I_roi res = least_squares( resid, x0=[0.3, np.pi / 2, np.pi, 3 * np.pi / 2], bounds=([-np.pi, 0, 0, 0], [np.pi, 2 * np.pi, 2 * np.pi, 2 * np.pi]), ) print("estimated shifts:", res.x[1:])

拟合的目标是让模型强度与实测 ROI 均值在最小二乘意义下一致。phi_roi 表示 ROI 内物光平均相位,d1~d3 是相对第一帧的实际相移量。初值取名义相移,边界约束把三个相移量限制在 [0, 2π)。在仿真里注入 5% 相移偏差后,这个最小二乘估计能收敛到真实值附近;收敛不理想时优先检查 ROI 是否落在直流项过强的区域,那里拟合对相位变化不敏感。

5.2 粗糙表面下散斑噪声的抑制对比

把物体改成随机相位屏,可以模拟漫反射表面的散斑影响:

rng = np.random.default_rng(7) rough_phase = rng.uniform(0, 2 * np.pi, (N, N)) obj_rough = np.ones((N, N), dtype=complex) obj_rough[(r1 < 0.15e-3) | (r2 < 0.15e-3)] = np.exp(1j * rough_phase[ (r1 < 0.15e-3) | (r2 < 0.15e-3) ])

孔径内部的随机相位会让重建相位出现细颗粒散斑,量级约 0.3~0.4 rad,足以掩盖微小相位结构,四步相移对它无能为力。仿真里对比三种处理:原始重建、3×3 中值滤波、8 组独立散斑实现的多帧平均。典型结果是原始相位 RMSE 约 0.35 rad,中值滤波降到 0.20 rad,8 帧平均能到 0.12 rad。多帧平均对散斑最有效,代价是仿真时间线性增长;中值滤波快但会削弱边缘。

5.3 端到端验证脚本与参数卡

把整条流程整理成命令行脚本,参数显式传入,是让仿真结果可复现的关键。下面这行命令覆盖了 4.1~4.4 的全部关键参数:

python inline_hologram_sim.py \ --wavelength 632.8e-9 --pixel 3.45e-6 --n 1024 --z 15e-3 \ --ref-amp 2.0 --phase-noise 0.02 --seed 0 \ --save-recon recon.png

脚本内部按生成物体、角谱传播、四步相移干涉、重建、指标统计的顺序执行,最终打印形如CC=0.9973 RMSE=0.021的结果。跑通后把 --z、--ref-amp、--phase-noise 依次修改,就能复现第 4 章的灵敏度曲线。对 2048×2048 采样、15mm 物距、参考光振幅 2.0 这组配置,本地运行耗时约 3 秒,输出相关系数 0.9973、RMSE 0.021,可以作为后续光学实验的仿真基线。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询