☰
微透镜阵列仿真与数据处理:Zemax+MATLAB助力光场相机和波前传感器
2026/10/2 3:26:42 网站建设 项目流程

微透镜阵列这东西,做光场相机和Shack-Hartmann波前传感器的人迟早都要正面硬刚。它看起来就是一片几十微米口径的小透镜按周期排开,放在主镜头像面或者传感器前面,但它的口径、焦距、阵列周期、填充因子这些参数,直接决定了角度采样能力、波前检测精度和最终的成像质量。我前后在Zemax里折腾过不少微透镜阵列的建模,也用MATLAB做过光线数据导出、子图像重排和光斑质心提取,今天把这套从仿真到数据处理的完整链路拆开来讲。

这篇内容适合正在做光场相机系统设计、波前传感器开发,或者毕业论文要搭一套微透镜阵列仿真平台的人。我会尽量把思路讲透——不光是给参数、给步骤,更重要的是讲清楚每一步为什么这么做,以及哪些地方会踩坑。

1. 先把微透镜阵列的功能吃透,再谈建模

很多新手拿到微透镜阵列就直接开建,结果建出来的模型要么追迹报错,要么和实物对不上。问题根源在于没弄清楚微透镜阵列在系统里到底扮演什么角色。

1.1 微透镜阵列解决的核心问题

微透镜阵列本质上是一组按规则周期排列的微型光学元件,单个透镜口径通常在几十微米到几百微米之间。它解决的问题只有一个:在传感器平面上同时获取光线的空间信息和角度信息。

以光场相机为例,主镜头把场景成像在一个平面上,如果直接放普通传感器,只能记录光的强度分布,角度信息全部丢失。但在像面位置放一块微透镜阵列,主镜头的出瞳会被分割成多个子孔径,每个微透镜把对应子孔径的光线投影到后面的传感器上,形成一个“宏像素”。宏像素内部的强度分布就包含了光线方向信息,这就是Lytro等光场相机的基本原理。

波前传感器(尤其是Shack-Hartmann型)则是把微透镜阵列放在被测波前处,每个微透镜作为一个子孔径,将局部波前聚焦到传感器上。当波前存在像差时,子孔径焦斑会偏移,偏移量与局部波前斜率成正比。通过测量所有子孔径光斑的质心位移,就能重构整个波前。

搞清楚这个功能定位很重要,因为Zemax里的建模参数不是随便设的——微透镜的焦距决定了对角度或波前斜率的灵敏度,口径和阵列周期决定了空间分辨率,填充因子决定了光能利用率,这些参数都会直接影响后续仿真结果。

1.2 光场相机和波前传感器的关键参数差别

虽然都用微透镜阵列,但两类系统对参数的要求差别很大。

光场相机这边,核心匹配关系是主镜头F数等于微透镜F数。为什么?因为微透镜阵列放在主镜头像面上,主镜头出瞳被微透镜阵列切割后,每个微透镜都应对准主镜头光瞳。如果两者F数不匹配,会出现两个问题:

  • 微透镜F数小于主镜头F数时,子图像在传感器上溢出,像素间串扰;
  • 微透镜F数大于主镜头F数时,子图像直径小于微透镜口径,角度采样分辨率浪费。

所以在Zemax里建模光场相机,第一步就要把主镜头F数和微透镜F数对齐。举个实际例子,如果主镜头F数是2.8,微透镜口径是100微米,那么微透镜焦距应设为280微米左右。

波前传感器这边,核心是光斑偏移量与波前斜率的关系Δx = f·tan(θ),f是微透镜焦距,θ是局部波前斜率。为了测量微弱波前畸变,需要较长的微透镜焦距,让偏移量在传感器上足够大;但焦距长了,可测的动态范围又会变小。Zemax仿真时需要在这两者之间权衡,我一般会先用Zemax做一个单子孔径模型扫参,看不同焦距和口径组合下的光斑偏移线性区间。

再说一个容易被忽略的参数——填充因子。光场相机希望填充因子接近100%,这样空间采样不丢信息,所以通常用方形孔径微透镜;波前传感器对填充因子要求宽松一些,圆形孔径也可以,但要注意边缘子孔径的光能利用率下降会导致质心提取精度变差。

2. Zemax里微透镜阵列建模思路拆解

Zemax建模微透镜阵列,首先要回答一个问题:用序列模式还是非序列模式?这个选择决定了后面所有操作的复杂度。

2.1 序列模式与非序列模式的选择逻辑

序列模式适合光线有序传播的系统,追迹速度快,像差分析方便,适合单透镜建模和系统优化。但微透镜阵列是成百上千个面型重复排列,序列模式下每颗微透镜都要单独定义一组面,工作量大,而且阵列尺寸一大文件就爆炸。

非序列模式支持真正的阵列对象(NSC内的Array Object),可以一次性生成完整的微透镜阵列,支持光线分裂、散射和衍射效应,更贴近真实的物理过程。缺点是追迹速度慢,像差分析工具不如序列模式顺手。

实际项目中我的做法是分情况选择:

  • 只仿真单个微透镜的成像特性或焦斑分布,用序列模式就够了;
  • 仿真完整的光场相机或波前传感器系统,尤其是要分析阵列边缘效应、子图像串扰时,直接用非序列模式。

2.2 三种主流Zemax建模方案对比

目前我在Zemax里用过三种可行的方案,各有适用场景。

方案一:非序列模式的Lenslet Array对象

Zemax非序列模式内置了Lenslet Array对象,可以直接定义子透镜数量、口径、曲率半径、排列方式(方形或六角形)等参数。这是最省事的方式,适合快速搭建整体系统模型。但是要注意,Lenslet Array对象用的是理想透镜近似,如果微透镜面型不是标准球面,或者需要加上非球面系数,内置对象就不够用了。

方案二:序列模式多重结构模拟子透镜

利用多重结构编辑器(Multi-Configuration Editor)定义多个结构,每个结构对应微透镜阵列中的一个子透镜或一组子透镜,通过改变每个结构的表面曲率、偏心等参数模拟阵列效果。优点是可以用Zemax强大的分析功能(MTF、点列图、波前图),缺点也很明显——阵列规模一大,结构数量呈线性增长,文件体积膨胀,而且多重结构之间不可能完全模拟阵列的整体光场分布。

方案三:序列模式用户自定义面(User Defined Surface, UDS)

通过Zemax用户自定义面接口,用DLL或者ZPL宏描述微透镜阵列的面型函数,把整个阵列作为一个特殊表面处理。这个方案灵活性最高,可以精确描述任意面型,包括非球面、自由曲面微透镜,追迹速度也比非序列模式快。但需要自己写面型算法,开发成本高,适合有编程能力的光学工程师。

2.3 我的选型建议和参数初始化方法

如果是快速验证系统可行性,我用方案一,先把系统框架跑通,确认微透镜数量、口径、焦距和传感器尺寸匹配。等到了要出结果、写论文或者出工程文档的阶段,我会切到方案三或者方案二的混合模式。

这里讲一下参数初始化逻辑。无论用哪种方案,都必须先算清楚几个核心量:

假设微透镜阵列中单个子透镜口径为D_mla,焦距为f_mla,阵列周期为P。光场相机中需要满足:

P = D_mla(方形孔径满填充),且f_mla = D_mla × F_main

其中F_main是主镜头F数。传感器上每个宏像素的像素数N_pix约等于主镜头光瞳直径与微透镜口径之比,这个比值其实就是角度采样数。Zemax建模时,我把这些参数做成长度,方便在优化函数里约束主镜头出瞳与微透镜阵列的匹配。

参数建议用Zemax的操作数来控制。在序列模式下,可以通过EFFL(有效焦距)、OPLT、OPGT等操作数把主镜头F数和微透镜焦距约束到目标值;在非序列模式下,建议直接手动计算好再输入,因为非序列模式下优化操作数不太好直接约束阵列内部参数。

3. 光场相机和波前传感器的Zemax仿真侧重点

同样的微透镜阵列,在光场相机和波前传感器里的仿真流程差别很大。这里分开讲。

3.1 光场相机仿真:三层结构匹配是核心

光场相机的系统结构是“主镜头 + 微透镜阵列 + 传感器”三层。Zemax建模时我的思路是:

第一步,建立主镜头模型。主镜头可以是理想薄透镜(用于原理验证),也可以是实际镜头设计(用于定量分析)。如果用的是理想透镜,设置为理想面型(如Paraxial),并记录其F数和出瞳位置。

第二步,在主镜头像面位置放置微透镜阵列。这里有一个关键点:微透镜阵列并不是正好放在主镜头的几何像面上,而是放在像面前方或后方一个特定的距离,这个距离就是微透镜的焦距。也就是说,微透镜阵列到传感器的距离等于微透镜焦距f_mla,这样才能实现“主镜头出瞳被微透镜阵列成像到传感器上”。

第三步,设置传感器平面。在非序列模式下,传感器表面设置为探测器对象,尺寸要能覆盖整个阵列投影面积。我一般会先计算传感器总尺寸:

传感器总尺寸 = 微透镜数量 × 微透镜口径 + 边缘预留

比如100×100的阵列,口径100微米,传感器就得至少10mm×10mm,还要加上子图像可能溢出的余量。

仿真时最重要的是设置合适的光线数量。光线太少,子图像内部强度分布会呈颗粒状;光线太多,追迹时间又不可接受。我实测下来,NSC模式下每条光线至少分到1000条左右才能在100微米级微透镜上得到接近衍射极限的光斑分布。

还有一点,光场相机仿真后处理很依赖子图像阵列的整齐排列。所以Zemax里的坐标轴选择很关键,我习惯把微透镜阵列面设为全局坐标参考面,探测器使用局部坐标匹配,避免后期数据对不准。

3.2 波前传感器仿真:光斑偏移和质心的精度

Shack-Hartmann波前传感器其实比光场相机简单一些,因为不需要考虑主镜头孔径匹配问题,只需要让入射波前经过微透镜阵列后在探测器上形成光斑阵列。

Zemax仿真里我重点做的是两件事:

第一,建立子孔径焦点偏移模型。把微透镜阵列定义为NSC中的Lenslet Array,在阵列后面f_mla距离处放置探测器。入射波前通过在系统入瞳位置设置倾斜面或泽尼克相位面来模拟不同的波前畸变。

第二,扫描波前畸变量级,记录每个子孔径焦斑的质心偏移。比如在入瞳面施加一个Zernike离焦项,系数设为0.2波长到1波长,分别在MATLAB里提取探测器图像的光斑位置,拟合出波前斜率与实际施加系数之间的线性响应曲线。

有一点要特别注意:波前传感器的微透镜阵列往往直径比较小(几十微米),衍射效应不可忽略。Zemax的几何光线追迹在探测器上得到的光斑只是一个几何弥散圆,不能反映真实的衍射光斑分布。这种情况下要在NSC中启用衍射计算方法,或者用POD(Physical Optics Propagation)传播工具。否则仿真出来的光斑尺寸偏小,质心提取的噪声特性会和实际系统差很远。

4. MATLAB和Zemax联动:打通数据通路的关键

Zemax建完模型只是第一步,真正有工程价值的结果都要靠MATLAB来做——不管是光场相机的子图像重排还是波前传感器的质心提取和波前重建。所以这一步很关键。

4.1 三种数据交互方式怎么选

我用过三种方式连接MATLAB和Zemax,各自适用场景不同。

DDE方式(老版本Zemax)。Zemax 13之前的版本支持DDE接口,MATLAB里可以用ddeinit('zemax', 'optical')建立通道,通过执行Zemax命令来加载文件、追迹光线、获取数据。优点是方便,缺点很明显:DDE传输效率低,而且新版本已经逐步移除了DDE支持。

ZOS-API方式(推荐)。Zemax 13之后提供了ZOS-API,通过.NET COM组件与MATLAB交互,功能覆盖系统修改、光线追迹、数据获取、分析调用。这是目前最主流的接法。MATLAB里通过actxserver创建COM对象连接。

文本文件中间交换。Zemax里通过脚本或手动操作导出光线数据到文本文件,MATLAB再读取处理。这种方式最笨但最通用,适合数据量不大、接口不好使的情况。

现在的工程实践里,我只推荐ZOS-API。用它可以做到MATLAB驱动Zemax批量修改参数、批量仿真、自动导出数据,整个流程自动化程度高,可复现性也好。

4.2 ZOS-API直连Zemax的MATLAB示例

下面给一个最小可用的MATLAB连接Zemax的示例框架:

% 连接Zemax ZOS-API(需保证Zemax已打开并加载了光学系统) import ZOSAPI; TheConnection = ZOSAPI.ZOSAPI_Connection(); TheApp = TheConnection.ConnectAsEditor(0); % 0表示连接到当前打开的Zemax实例 TheSys = TheApp.TheSystem; % 获取系统参数 fprintf('系统文件:%s\n', TheSys.SystemFile); fprintf('单位:%s\n', TheSys.SystemData.Units); % 使用光线追迹获取探测器数据(需要根据具体分析对象调整) TheNCE = TheSys.NCE; % 依次处理每个非序列对象... % 断开连接 clear TheSys; clear TheApp;

这个框架能跑通的话,后面批量仿真就可以做成循环。比如我要仿真不同微透镜焦距下的光斑偏移,直接在MATLAB里修改Zemax对象参数,重新追迹,然后把探测器数据批量取回。

需要说明的是,ZOS-API调用时有一点容易踩坑:MATLAB的版本和Zemax的版本需要匹配,COM接口注册要正常。如果连接时报“未注册”之类的错误,先检查.NET框架版本和Zemax安装是否完整,顺便确认在MATLAB里执行了NET.addAssembly加载对应的DLL。

4.3 MATLAB端核心处理算法:光场重排和质心提取

ZOS-API把Zemax的光线数据或探测器图像拿到MATLAB之后,下一步就是做两件核心的事。

光场相机这边,要把原始的宏像素图像重排成光场参数化表示。假设Zemax探测器导出的原始图像是I_raw,每个宏像素尺寸为M×M像素,那么重排逻辑如下:

% 光场数据重排:将原始平面重排为四维光场 % 宏像素数量为[nx, ny],每个宏像素M×M像素 LF = zeros(nx, ny, M, M); for i = 1:nx for j = 1:ny LF(i, j, :, :) = I_raw((i-1)*M+1:i*M, (j-1)*M+1:j*M); end end % LF(i,j,:,:)即是宏像素(i,j)内的角度采样,可以用squeeze提取子孔径图像 sub_aperture_view = squeeze(LF(i, j, :, :));

这样重排之后,固定角度坐标(M1,M2)抽取所有宏像素对应位置,就能得到某个视角下的子孔径图像,后面可以做数字对焦、深度估计等处理。

波前传感器这边,核心是质心提取。Zemax探测器给出的图像是一个二维灰度矩阵,要找到每个子孔径内光斑的质心坐标。基础质心算法就是计算灰度加权平均位置:

function [cx, cy] = centroid(img) total = sum(img(:)); if total == 0 cx = 0; cy = 0; return; end [rows, cols] = size(img); [X, Y] = meshgrid(1:cols, 1:rows); cx = sum(sum(X .* img)) / total; cy = sum(sum(Y .* img)) / total; end

当然实际的质心提取要比这个复杂,需要先做阈值分割去掉噪声、剔除边界,还要考虑CMOS的固定模式噪声。更稳健的做法是先用一个高斯窗对每个子孔径图像加权,再计算质心,这样抗噪性能会好很多。实测下来,同样的原始数据,加权质心比重心法精度高大约1/4像素,对波前重建结果影响非常明显。

5. 实操避坑记录:这几类问题我基本都遇到过

仿真做得多了,哪些环节容易翻车基本心里有数。这里挑几类最常见的问题分享出来,希望能帮后来人少走弯路。

5.1 Zemax光线追迹失败和收敛性问题

微透镜阵列的特点是子透镜尺寸小、曲率半径短,在序列模式下很容易出现光线全反射(TIR)或者追迹不到探测器的情况。尤其是曲率半径和口径比很高的时候,边缘光线入射角超过临界角,就会报错。

解决办法有两类:

一是检查微透镜矢高。球面微透镜的矢高公式是s = R - sqrt(R² - (D/2)²)。如果矢高过大(比如超过10微米),追迹时边缘光线的光程差计算容易出错。建议先用MATLAB或简单公式预先计算矢高,确认在合理范围内再导入Zemax。

二是检查入瞳直径和微透镜口径的匹配。入射光束孔径如果大于微透镜有效口径,很大一部分光线会被阵列边缘遮挡,甚至在非序列模式里直接绕过微透镜打到探测器上形成背景噪声。这种情况需要先设置孔径光阑,确保入射光束恰好覆盖阵列的有效区域。

5.2 数据交换中的坐标系陷阱

这是最坑的问题之一。Zemax和MATLAB的坐标定义在方向上有差异,尤其是探测器图像的坐标原点位置。Zemax探测器图像的原点在左下角,MATLAB矩阵索引从左上角开始。如果直接从Zemax导出图像矩阵然后在MATLAB里做质心提取,不做y轴翻转,结果会整体偏移。

我的习惯是在数据交换时统一约定。所有从Zemax导出的图像矩阵先做一次flipud(上下翻转),确保坐标体系与MATLAB一致。再用一个已知位置的光斑做标定,验证坐标转换正确后再处理实际数据。

另外,非序列模式下Zemax探测器数据可以导出为文本格式,里面附带像素位置信息。建议优先使用带坐标的数据,不要只导灰度值,这样MATLAB端处理时可以重建平面坐标。

5.3 仿真耗时优化心得

微透镜阵列仿真的最大痛点是速度。一个10×10的阵列,每颗微透镜覆盖100×100像素,如果每像素要追迹10条光线,就是百万级光线量级,NSC模式追迹时间可能长达几十分钟甚至数小时。

我的优化经验有三条:

第一,合理设置光线数量。先跑一个粗光线数(比如每像素100条),确认系统没有大问题后,再加大到每像素1000条做最终精度仿真。不要一开始就满配。

第二,利用阵列对称性。如果是方形周期排列且入射光场具有对称性,可以只仿真四分之一或二分之一的阵列区域,然后在MATLAB里对称展开。这个方法我实测能把仿真时间压缩到原来的四分之一。

第三,在Zemax里适当调大“光线分裂”和“散射”的阈值,抑制非必要的光线分裂计算。对于探测器图像,如果不需要精确的光能分布,可以直接关闭分裂,只做纯几何追迹。

5.4 探测器图像噪声与质心偏移的耦合

最后一个常见坑:Zemax仿真得到的理想光斑图样没有噪声,但实际传感器必然有读出噪声和暗电流。如果拿理想仿真结果直接做质心提取,精度很高,但和实测差距很大。

我的处理方式是,在MATLAB里对Zemax得到的理想探测器图像主动加入高斯白噪声和背景偏置,模拟真实的传感器响应。然后再做质心提取和波前重建。这样做出来的仿真灵敏度分析结果才更具参考价值。

经验上,加入约满阱1%的高斯噪声后,质心提取精度会有明显下降,这与实际相机的实测趋势一致。如果你的目的是设计指标分配,建议提前在链路里加入噪声模型,避免把仿真指标做得过于“理想”。


这套Zemax + MATLAB实现微透镜阵列仿真的流程,核心要点可以归结为:先搞清光场相机和波前传感器对微透镜阵列的不同参数需求,再用Zemax选择合适的建模路径(序列/非序列),最后通过ZOS-API打通MATLAB数据处理链路。每一步都有严格的物理约束和工程权衡,不是光有软件操作就能做好的。

我个人在实际操作中最大的体会是,微透镜阵列仿真里那些看起来“差不多就行”的参数——比如微透镜F数偏差、探测器像素尺寸、光斑质心的邻域选择——往往对最终精度的影响要以微米、亚像素来算。建议所有参数都先通过公式推算一遍,再用Zemax穿插验证,最后在MATLAB里做统计评估,形成闭环。这套思路无论你是做光场相机还是波前传感器,都适用。

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

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

立即咨询