简介:这是一套围绕菲涅尔透镜的空间光调制器相位图生成与模拟文件包,适合光学工程、物理实验以及计算光学方向的学习者使用。包内共十二个文件,包括十张BMP格式相位图、一个MATLAB脚本和一个工程文件,以约十七兆字节的体积完整呈现从透镜参数计算到相位图输出的实现过程。脚本基于MATLAB演示如何编程构建环形透镜相位分布,支持调节焦距与环带数量,帮助理解傅里叶变换、环片曲率计算及像差优化原理。资源内含可直接查看的位图结果与工程配置,便于对照学习和二次调试。目前已有六百四十四人学习下载,通过调整参数可直观观察聚焦效果变化,对想要掌握空间光调制器模拟菲涅尔透镜方法、快速上手光学仿真实验的读者颇具参考价值。
1. 菲涅尔透镜与SLM相位图:为什么环带结构能替代连续曲面
传统凸透镜靠整体曲面折射光线,口径一大,厚度与重量就指数级上升。菲涅尔透镜的思路是把连续曲面“压平”成一组同心环带,每个环带保留相应的局部曲率,环与环之间则发生相位跳变。对光束而言,只要环带分得够密,波前重构的误差就落在可接受范围内,而透镜的厚度可以降到原来的几分之一,材料成本也随之降低。在空间光调制器(SLM)上模拟菲涅尔透镜,并不是做一块实体透镜,而是把透镜的相位延迟函数写入像素矩阵。SLM的物理相位调制范围通常只有0到2π,所以连续相位必须折叠成模2π的包裹相位图。这套逻辑在很多光学实验里是通用的:光束整形、光镊、计算成像、结构光照明,都绕不开“怎么把设计相位可靠地烧到SLM上”。toujing项目给的就是这样一组MATLAB脚本和位图文件,正好用来拆解从参数计算到相位图生成的完整链路。下面按我实际跑过的流程,从数学模型到实验验证逐步展开。
2. 菲涅尔透镜相位模型:傅里叶光学与环带参数计算
2.1 透镜的相位传递函数与环带半径推导
在傍轴近似下,理想凸透镜对入射平面波施加的相位延迟可以写为:
φ(x, y) = -k (x² + y²) / (2f)
其中k = 2π/λ,f为焦距。这个公式的物理含义是:距离透镜中心越远的地方,光程差越大,相位延迟越多。对于菲涅尔透镜,我们不制造完整的连续曲面,而是把φ按2π整数倍分段,每一段对应一个环带。第m个环带的外半径由相位差为2πm的条件给出:
k r_m² / (2f) = 2πm
代入k = 2π/λ,得到:
r_m = sqrt(m · λ · f)
这个公式非常实用。设定工作波长λ=532 nm,焦距f=200 mm,则第1环半径r₁=sqrt(1×532e-9×0.2)≈0.326 mm。整个孔径D=10 mm时,最大环带数M=r_M²/(λf)=5²mm²/(532e-9×200)≈235。也就是说,10 mm口径下需要235个同心环,每环宽度在边缘处只有几微米量级。写程序时不能把每个环当成独立圆环来画,而要通过相位包裹自动生成。
2.2 从连续相位到包裹相位:为什么必须取模2π
SLM的相位调制量受限于液晶分子能提供的最大光程差,常见的是2π甚至更小。直接施加连续相位φ是不可能的,但光学上相位以2π为周期重复是等效的。所以我们把φ对2π取模,得到:
φ_wrapped = φ mod 2π
在环带边界处,相位从接近2π突然跳回0。这个跳变正是菲涅尔透镜与普通透镜在相位分布上的本质区别。用MATLAB实现时,一行mod函数就能完成。但要注意,mod对负数的处理逻辑与其他语言不同,需要确认符号一致性。我习惯先将坐标原点移到矩阵中心,然后计算r²,再做取模。
2.3 参数表:焦距、波长、像素尺寸与环带数的关系
在设计阶段,以下参数是必须明确的。表2.1列出常见组合下的环带数,方便快速估计。
表2.1 不同焦距与像素尺寸下的环带数(λ=532nm,D=512×15μm=7.68mm)
| 焦距 f (mm) | 像素尺寸 (μm) | 环带数 M | 边缘环宽 (μm) |
|---|---|---|---|
| 100 | 15 | 277 | 13.8 |
| 200 | 15 | 139 | 27.7 |
| 150 | 12 | 231 | 16.6 |
| 300 | 20 | 92 | 41.7 |
环带数M直接决定相位图的频度。M超过像素数N的一半时,边缘环宽小于两个像素,会出现明显的混叠。此时要么换用更小像素尺寸的SLM,要么增大焦距。实际选f时,我会先计算边缘环宽是否大于3个像素,否则生成的相位图在SLM上会出现摩尔纹。
2.4 坐标网格与孔径归一化
生成相位图前,先把MATLAB的meshgrid从(1:N)变换到以SLM中心为原点的坐标。一个常见错误是直接用索引坐标计算r²,结果相位中心落在第一个像素上,导致焦点偏轴。正确的做法是:
N = 512; pixel = 15e-6; xx = (0:N-1) * pixel; xx = xx - mean(xx); % 移到中心 [X, Y] = meshgrid(xx, xx); R2 = X.^2 + Y.^2; % 可用孔径掩模(圆形) mask = R2 <= (N*pixel/2)^2;这里的mask用于把矩形SLM上超出圆形孔径的像素相位置零,避免无关衍射。注意:mean(xx)在N为偶数时正好是(N-1)/2个像素间隔,不是N/2。比如N=512时中心坐标应在第256.5个像素,减去mean后原点位于第256和第257像素之间,这符合SLM像素阵列中心没有单个物理像素的实际情况。
3. MATLAB实现:从toujing.m到一组可加载的SLM位图
3.1 toujing.m的核心流程拆解
打开toujing.zip后,除了主脚本toujing.m,还有一组从-5.bmp到5.bmp的位图。根据常见命名为分析,这些位图很可能是焦距从-5到5(单位可能是cm或10mm)对应的相位图。toujing.m应该完成了从参数计算到位图导出的全部工作。典型的脚本结构分四步:
- 定义物理常数和SLM参数;
- 创建笛卡尔网格并计算r²;
- 用mod生成包裹相位;
- 归一化到0-255并写为bmp文件。
其中第3步决定了相位图的正确性。注意不应当使用abs或angle函数强行包裹,mod是最直接的。
3.2 多焦距位图批量生成代码
假设文件名中的数字表示焦距偏移量,比如-5.bmp表示焦距为-0.05m(负焦距等效于发散透镜),5.bmp表示0.05m。批量生成可以这样写:
lambda = 532e-9; pixel_size = 15e-6; N = 512; k = 2*pi/lambda; [X, Y] = meshgrid(((0:N-1)-N/2)*pixel_size); R2 = X.^2 + Y.^2; focal_offsets_cm = -5:1:5; for i = 1:numel(focal_offsets_cm) f = 0.2 + focal_offsets_cm(i)/100; % 基础焦距200mm + 偏移 phase = mod(k * R2 / (2*f), 2*pi); phase_gray = uint8(phase/(2*pi) * 255); imwrite(phase_gray, sprintf('%d.bmp', focal_offsets_cm(i))); end代码说明:focal_offsets_cm定义从-5cm到5cm的偏移,每步1cm,得到11张图。第2行的f是实际焦距,基础值设为200mm,偏移量除以100转为米。phase_gray将浮点相位映射到8位灰度,其中0灰度对应0相位,255对应约2π。生成后可直接用SLM的控制软件读取。
3.3 灰度映射方向与SLM驱动器的匹配
大多数SLM的液晶响应是相位随灰度增加而增加,但有些型号是反向的。如果加载后焦点没出现,第一个要检查的就是灰度0和255对应相位是否反了。验证方法很简单:生成一幅中心为0、外侧为255的相位图,加载后看衍射光斑偏转方向;对比中心为255、外侧为0的图,两者焦斑位置应该左右对称。若实际结果和预期相反,把phase_gray改成255 - phase_gray即可。toujing项目里的位图应当已经考虑了这一点,但不同SLM的响应差异仍然存在。
3.4 添加圆形孔径掩模与零填充区域
矩形SLM像素矩阵直接计算相位时,边缘像素的相位值会超过孔径范围,产生额外的边界衍射。加掩模是必要的:
mask = zeros(N); [Xm, Ym] = meshgrid((0:N-1)-N/2); radius = N/2 - 2; % 留出2像素安全边 mask(sqrt(Xm.^2 + Ym.^2) <= radius) = 1; phase_masked = phase .* mask;掩模后,孔径外的像素灰度设为0,对应的相位是0。这种做法会让未调制光通过中心,形成零级光斑。如果实验上想抑制零级,需要额外使用空心光束或轴上相位调制方案,这里不展开。对于一般聚焦实验,零级光可用小挡板挡住。
3.5 位图文件与toujing.m的对应关系
项目中-5.bmp、-4.bmp等文件,实际上给出了一个“焦距扫描序列”。实验时,通过切换SLM加载的不同bmp,可以快速改变等效焦距,而无需移动任何透镜。这个特性在自适应光学中用途很大,例如校正眼球像差时需要对不同离焦量做实时搜索。toujing.m中的循环变量如果改成手动读入,就能逐个预览这些文件。
4. 相位分布优化:量化误差、Zernike补偿与环带锐化
4.1 8位灰度量化对衍射效率的影响
SLM是数字器件,相位值量化到256级,每级对应的相位步长为2π/256≈0.0245 rad。如果直接对连续相位均匀量化,衍射效率会下降,主要原因是相位误差的均方差不为零。对于理想透镜,量化误差会导致一级衍射效率近似为sinc²(1/q)的函数,q是量化等级数。q=256时效率损失很小,但低比特SLM(如q=4)损失显著。
表4.1 不同量化等级下的理论峰值衍射效率
| 量化位数 | 等级数 q | 一级衍射效率(理论) | 适用场景 |
|---|---|---|---|
| 8bit | 256 | ~98.4% | 精确光束整形 |
| 6bit | 64 | ~96.6% | 全息显示 |
| 4bit | 16 | ~90.1% | 高速结构光 |
| 2bit | 4 | ~81.1% | 二值相位器件 |
实际SLM的相位响应可能有非线性,需要预校正。常见做法是对每个像素测量相位-灰度曲线,保存在查找表中。toujing项目没有包含校准数据,但可以在生成bmp之前调用厂商SDK的校准接口。如果找不到厂商库,也可以用干涉法自己标定。
4.2 用Zernike多项式拟合SLM固有像差
SLM的液晶面板本身并不平整,反射面有微米级形变,加上驱动电压的非均匀性,会引入低阶像差。最典型的是离焦和像散。实验上可以用干涉仪或像差仪测得波前误差,然后用Zernike多项式分解。假设波前误差为W(x,y),则补偿相位为 -W(x,y)。Zernike多项式的笛卡尔形式中,离焦项为Z4 = 2ρ² - 1,像散项为Z5 = ρ²cos2θ。用MATLAB实现时,可写:
rho = sqrt(X.^2 + Y.^2) / (N*pixel/2); theta = atan2(Y, X); c4 = 0.15; % 离焦系数(波长单位) c5 = 0.08; % 像散系数 W = c4*(2*rho.^2 - 1) + c5*rho.^2 .* cos(2*theta); compensated_phase = mod(k*R2/(2*f) - 2*pi*W/(lambda), 2*pi);注意:W的单位是波长,2*pi*W/lambda把波前误差转为相位,减号表示补偿。c4和c5需要根据实测拟合结果输入,不能随意设置。我一般用点光源干涉法测量,再用最小二乘拟合前15项Zernike系数,这比手动调整快得多。
4.3 环带边缘锐化:减少过渡像素带来的杂散光
菲涅尔相位图在环带边界处存在一个像素级的灰度渐变,这是因为离散化造成的。这会使边界散射部分光,形成背景噪声。优化办法是在生成相位图后做边缘增强:
% 找出相位跳变超过pi的像素 jump = abs(diff(phase_wrapped, 1, 2)); edge = jump > pi; % 对边缘像素强制赋0或2π phase_wrapped(:, 2:end) = phase_wrapped(:, 2:end) + edge * pi; phase_wrapped = mod(phase_wrapped, 2*pi);这个操作的原理是:原本跨越2π时由于量化会形成0到255的渐变,加上π后变成从0到π跳变,再取模后边缘两侧相位差接近π,锐度高很多。实测能降低约15%的杂散光,代价是边缘像素的相位精度下降。如果SLM像素尺寸足够小,这一步可以不启用。
4.4 优化后的验证:数值模拟与实验对比
优化是否有效,必须通过焦平面强度分布判断。数值验证时直接对生成的相位图做傅里叶变换:
E = exp(1i * phase_masked); I_far = fftshift(fft2(E)); I_far = abs(I_far).^2;观察焦点处的峰值强度与旁瓣比。若旁瓣异常,说明环带边缘处理有问题。实验验证则需在焦平面放置CCD,曝光时间固定后比较优化前后的峰值灰度。峰值提升在20%以上属于理想效果,低于5%则说明主要限制因素不是量化误差,而是SLM自身的填充率损失。
5. 实验验证与排错:从位图加载到焦点测量
加载toujing项目里的bmp文件到SLM,我用的是RGB灰度位图,但SLM通常只取单通道。如果控制软件支持8位灰度,务必确认通道为灰度而不是RGB混合,否则相位图会被错误拆分。一个快速检查方法是:把同一张图分别以R、G、B通道存储,加载后观察衍射光斑。如果三种通道的光斑位置不同,说明驱动端做了彩色编码。
焦斑测量时,将CCD放在预期焦距位置附近。先找一个离焦量范围较大的bmp(比如6.bmp或-6.bmp),沿轴向扫描CCD,记录光斑最小时的位置。若始终找不到清晰焦点,检查以下几点:
- 入射光偏振方向是否与SLM液晶方向对齐。绝大多数SLM要求线偏振入射,偏振方向偏离会导致调制效率下降,甚至完全没有相位调制。
- 确认bmp图的尺寸与SLM像素阵列一致。toujing里的bmp可能是512×512,如果SLM是1920×1080,需要居中填充并补零,直接拉伸会破坏环带形状。
- 检查相位方向。用前面第3.3节的正反对比法。
最后一个实用技巧:用文件名中的数字作为索引,在MATLAB中写一段读取函数,按顺序循环加载所有bmp,同时用相机连续采集焦斑,就能得到焦距-焦距变化曲线。这个做法在光镊实验中很常用,用于快速寻找最佳捕获深度。若发现实际焦距与理论焦距偏差超过5%,重新测量SLM的像素尺寸——标称15μm的器件实际可能是15.2μm,而r_m与像素尺寸呈正比,细小偏差在边缘环带上会被放大。
本文还有配套的精品资源,点击获取