做气体激光吸收光谱的同行应该都有这种体会:不管你是做TDLAS,还是搞光声光谱,最终都绕不过一个核心部件——多次反射池。Herriott池作为几十年来最经典的多次反射池结构,靠两个球面反射镜就能把光程拉长几十倍甚至上百倍,结构简单、调节方便,但设计起来又牵一发动全身:镜间距、曲率半径、入射位置和入射角度只要差一点点,光斑分布和反射次数就完全不是你想的那样。这篇文章就用VirtualLab Fusion,把我从参数计算、光路建模到仿真验证的整个流程拆开讲一遍,包括我踩过的坑和最后确定的经验做法,给正在做类似光学仿真的朋友一份能直接参考的作业。
先说清楚,这篇内容不是软件官方教程式的逐菜单讲解,而是基于实际项目需求的建模思路。Herriott池仿真最难的不是模型本身,而是“你为什么要这样建模”——所以文里会穿插大量设计逻辑和工程判断,适合已经接触过VirtualLab或者Zemax、对光学仿真有一定概念的人,当然如果你只是刚入门,照着后面的流程走一遍也能跑通大部分环节。
1. 为什么用VirtualLab Fusion来做Herriott池仿真
1.1 先把Herriott池本身讲清楚
Herriott池的原始结构很朴素:两个曲率半径相同的球面反射镜,彼此相对放置,间距一般小于两倍曲率半径。一束光从第一个镜面的某个位置入射,在两个镜面之间来回反射,每次反射后光束在镜面上的落点都会发生偏移,最终在镜面上形成一圈规则分布的光斑阵列。只要入射位置、入射角度和镜间距匹配得当,光可以在池内往返几十次甚至上百次,等效光程就从这个“空间长度”变成了“光程路径总长”。
典型应用场景主要集中在这几块:TDLAS气体检测里用来提升吸收灵敏度,光声光谱里用来增强光与介质的相互作用,另外在腔衰荡光谱、激光频率稳定等方向也常看到它的身影。我在实际项目中用得最多的还是近红外波段的痕量气体测量,工作波长一般在1.4微米到2微米之间,对光斑重叠和反射次数的控制要求都比较严格。Herriott池之所以被大量采用,除了结构简单之外,还在于它不像White池那样需要三块镜面调校,常规情况下只需要调节入射光束的方向就能完成光路对准,这对工程现场调试来说非常友好。
不过结构简单不代表设计简单。镜面上每个光斑的位置变化遵循的是矩阵光学规律,本质上和光学谐振腔的稳定性问题一模一样。设计Herriott池时真正要回答的问题是:给定两个球面镜的曲率半径和间距,光应该从哪里入射、以什么角度入射,才能让光斑不重叠、不逃逸,并且在预设的圈数后闭合。
1.2 VirtualLab Fusion比传统光线追迹工具强在哪
我最早用Zemax和CODE V做过类似多次反射系统的建模,坦白讲,纯光线追迹工具做Herriott池也能画出光路,但它只能告诉你“光线走到哪了”,而很多实际影响系统性能的物理效应,比如光斑的衍射扩展、部分相干光的传播、高阶模的场分布变化,光线追迹是给不出答案的。Herriott池在工作状态下光要在镜面间往返几十次,即便一开始是准直性很好的高斯光束,经过几十次反射和衍射之后,光斑尺寸和波前曲率都会发生变化,这些变化直接决定了后续光斑是否能稳定分布在镜面上,以及最终耦合出去的能量效率。
VirtualLab Fusion的强项在于它把几何光学和物理光学放在了同一个建模框架里。你在同一套模型中可以先用几何光线快速检查光路是否合理、有没有光线逃逸,再切换到场追迹模式,观察真实高斯光束经过多次反射后的振幅分布和相位分布,把“光线视角”和“波前视角”统一起来。这对Herriott池这种高反射次数、光程很长、衍射效应不可忽略的系统来说特别关键。
此外,VirtualLab有一个很实用的能力:灵活性极高的参数化建模。镜面间距、入射角、光源位置这些都可以设成参数,然后用内部的参数扫描功能批量计算不同配置下的光斑阵列。我之前用Zemax做类似扫描时需要手动一组一组改,或者写复杂的宏和操作数,VirtualLab里做参数扫描的流程要直观很多。对于前期摸索“究竟哪种入射条件能获得目标反射次数”这类问题,这个能力能节省大量时间。
2. 建模之前先把参数算清楚
2.1 决定光斑轨迹与反射次数的核心思路
很多人一上来就直接在仿真软件里摆两个镜面,然后随便给一束光,发现光路乱飞,或者光斑重叠在一起,就开始怀疑软件有问题。其实问题基本都出在没做前期的矩阵计算。Herriott池的光斑序列是可以用2×2的ABCD矩阵预测的,我把这个计算过程直接写成了一个小脚本,在摆到VirtualLab之前就把光斑分布的基本规律摸清楚,建模过程会顺利很多。
基本模型是这样的:光从第一个镜面反射一次之后,到第二个镜面反射,再回到第一个镜面,这构成一个往返周期。把每一段自由空间传播近似为距离d的矩阵,把每个凹面镜反射近似为焦距f=R/2的薄透镜变换,就可以写出往返传输矩阵。用复数坐标或二维坐标迭代这个矩阵,就能得到光斑在镜面上的序列位置。
import numpy as np # 参数定义 R = 200.0 # 反射镜曲率半径,单位mm d = 180.0 # 镜间距,单位mm n_round = 20 # 计算往返次数 # ABCD矩阵 # 单程传播 T = np.array([[1.0, d], [0.0, 1.0]]) # 凹面镜反射,等效焦距f=R/2 M_ref = np.array([[1.0, 0.0], [-2.0/R, 1.0]]) # 一次往返矩阵:从镜1出发 -> 传播d -> 镜2反射 -> 传播d -> 镜1反射 M_total = M_ref @ T @ M_ref @ T # 初始光斑位置和斜率,单位mm,斜率单位为弧度 y0 = 5.0 theta0 = 0.0 state = np.array([y0, theta0]) y_list = [] for i in range(n_round): y_list.append(state[0]) state = M_total @ state for i, y in enumerate(y_list): print(f"往返 {i}: 光斑高度 y = {y:.3f} mm")这个脚本的意义在于先把“镜面上光斑每一步落在哪”画出来。注意,我这里只列了纵向坐标y,实际三维情况下x和y两个方向都要算,只要在计算里把两个方向的初始条件分别代入即可。矩阵迭代的结果可以判断两件关键事情:第一,光斑会不会在某个循环中回到初始位置附近,形成闭合圈;第二,相邻光斑是不是均匀排列,有没有重叠风险。
稳定条件可以借腔体稳定判据来理解:对于两个相同曲率半径R的球面镜、间距d的系统,往返矩阵的半迹需要落在合理区间内,光路才会稳定地圈在镜面之间而不是发散出去。工程上比较常用的取值范围是镜间距d在0.5R到1.5R之间,但具体到某个光斑闭合状态,还要看入射位置和入射斜率共同决定。
2.2 参数选择与边界条件
我在实际项目中一般按这样的顺序来确定初始参数:先定R和d,然后定光源工作波长和束腰大小,最后再调入射位置和入射角度。反射镜曲率半径的选择主要受空间尺寸约束,比如管道内安装、光学平台占用面积这些工程条件。镜间距d则直接决定单次反射的光程步长,在总光程需求确定的前提下,d越大,所需的反射次数越少,但对入射角度和光斑控制的要求会变低;d越小,反射次数越多,等效光程可以拉得很长,但光斑更容易重叠,调试也越敏感。
入射位置和入射角度的调节是Herriott池设计的灵魂。严格来说,这两个量决定了光斑在镜面上画出的图案形态:入射点靠近镜面中心、入射角较小,光斑圈就小;入射点偏到边缘、入射角较大,光斑圈就大。想让光斑均匀铺开且不重叠,就要让单位往返的光斑角度步进和预设的闭合条件匹配。
我习惯把“闭合条件”理解为:如果希望一束光在镜面上走满一圈后回到初始位置,那就要求往返N次对应的角度积累正好是2π的整数倍。这个关系用前面矩阵算出来的序列可以直接验证,周期性一目了然。如果闭合条件不满足,光斑就会继续在镜面上“转圈”但始终不回到起点,反射次数无法精确控制,光学设计上会很难受。
提示:在做参数计算时,一定要记得把镜面实际口径考虑进去。镜面上光斑轨迹半径如果超过了反射镜的有效光学口径,光线就会从镜子边缘溜出去,仿真里表现为光斑突然丢失或能量明显下降。矩阵计算只告诉你光斑位置,口径限制还得靠几何约束去检查。
2.3 从计算到仿真:为什么不能完全跳过理论预研
有朋友问过我,VirtualLab建模那么方便,直接在里面微调参数不就行了,何必还在外面写Python脚本算一遍?我的看法是,VirtualLab是验证设计的工具,没那么适合做全空间盲搜式的优化。用矩阵预研先用十分钟把可行区域圈出来,进VirtualLab之后只需要在很小范围内精调,效率完全不一样。另外一个原因是光斑序列的周期性问题:仿真软件里镜面位置一旦定位,光线路径是确定的,来回微调入射角时,光斑的闭合圈数可能会在某个区间内突变,如果对理论预期没有概念,很容易被仿真结果带偏,以为系统有问题其实只是进入了不同的闭合模式。
3. VirtualLab Fusion里的完整建模流程
3.1 光源与反射镜组件设置
仿真开始前先把单位系统设置好,光学仿真里最忌讳的是单位不一致。VirtualLab里默认支持毫米和纳米混用,波长用纳米,几何尺寸用毫米,这个组合最省事。我的典型设置如下:
| 参数 | 数值 | 说明 |
|---|---|---|
| 工作波长 | 1550 nm | 近红外通信与气体检测常用 |
| 反射镜曲率半径 R | 200 mm | 凹面球面镜 |
| 镜间距 d | 180 mm | 先按预研初值 |
| 光源类型 | 高斯光束 | 束腰0.5 mm,束腰位置在入射镜面附近 |
| 镜面有效口径 | 25.4 mm | 一英寸光学件对应口径 |
光源建模是容易被忽略的一步。Herriott池的入射光通常来自单模光纤准直器或半导体激光器的准直输出,因此用高斯光束模型最合适。VirtualLab的光源编辑器里可以设置束腰半径、束腰位置和光束方向。我习惯把束腰放在入射镜面的前方,这样光进入池内时近似为平行光,后续的光斑轨迹判断会清晰很多。
反射镜的建模更直接:在组件库里选择球面镜,输入曲率半径R和口径。如果需要考虑实际镀膜,还可以指定反射率的波长依赖特性。要注意的是,VirtualLab里镜面法线方向和曲率半径的正负号约定关系到仿真结果,不同坐标系下正负号可能完全不同,设置完之后先用单次反射测试一下,确认反射方向正确再继续搭多反射系统,这个验证步骤能节省很多排查时间。
3.2 多次反射路径的搭建方式
Herriott池的仿真在VirtualLab里有两种主流实现方式,我两种都用过,可以根据目标灵活切换。
第一种是“等效展开法”。因为Herriott池中的光在两个镜面之间反复传播,从物理光学的角度看,它等价于光通过一串周期透镜序列。具体做法是只保留第一个镜面作为真实组件,后面每一个往返用一组“自由空间传播 + 等效反射变换”来表示。这种方式适合快速估算光斑演变规律,建模简单,但没法直观地看到光斑在真实镜面上的空间位置。
第二种是“实际组件布局法”。把两个球面镜按照真实位置摆放,然后让光源发出的光依次经过镜1、镜2、镜1、镜2……这样循环传播。在VirtualLab中,光束传播路径可以串联多个传播段和光学组件,每个反射节点都对应一次真实镜面反射。这种方式最贴近物理实际,能直接读取镜面上的光斑分布,也是我日常调试中使用最多的方法。
实际动手时我推荐的做法是:先用“实际组件布局法”搭一个包含多轮往返的系统,比如先用4次反射验证光路逻辑,然后在“光路编辑器”里把反射次数逐步增加到目标值。每一步都检查探测器上的光斑位置是否和矩阵预测一致,这样可以及时定位设置错误,而不是等到几十次反射之后发现光路完全乱了。
这里有个VirtualLab的便利之处:你不需要真的把两组反射镜组件复制几十遍,光路中可以定义重复的循环传播段。具体操作上需要在传播序列里添加多个相同镜面组件,并把它们视为同一物理位置,如果你的版本支持参数阵列或列表,可以进一步简化。
3.3 探测器布局与结果输出
想要评估Herriott池的关键性能,至少需要三个探测器:
第一个是镜面光斑分布探测器。放在入射镜面和出射镜面上,观察光斑的二维强度分布。这里重点看三点:光斑数目是否与预期一致,光斑是否均匀、不重叠,光斑是否落在镜面有效口径内。第二步是光程验证探测器。可以用VirtualLab的光程分析功能,也可以简单地对探测到的光斑计数:如果从入瞳到出瞳经历了N次反射,光程就是N×d。更严格的做法是在光路中设置光学路径长度检测点,直接读取累积光程。第三是耦合效率探测器,这个对于实际工程尤其关键:出射光要重新耦合进光纤或者照射到光电探测器上,就需要在出射位置分析光斑的尺寸和相位是否满足耦合条件。
我遇到的一次典型调试过程是这样的:预研矩阵算出来在镜间距182毫米时,经过22次往返后光斑闭合,于是直接在VirtualLab里设置d=182mm,入射位置和角度按矩阵给出的条件设置。结果光斑数量是正确的,但个别光斑有轻微的重叠倾向,原因在于真实高斯光束经过多次衍射后,光斑尺寸比几何光线追迹预测的大,相邻光斑边缘开始相接。解决办法是把入射光斑稍微缩小一点,同时把镜间距增加0.5毫米,让光斑步进间距略增大,才最终得到一个干净的分布。
提示:深度观察光斑时,VirtualLab的探测器可以减少采样点数来加速预览,但最终评估光斑重叠时必须把网格分辨率调高,否则相邻光斑的交叉区域会被平滑掉,你看不出来问题。
4. 常见问题与排查技巧实测
4.1 光斑逃逸与重叠问题
这是Herriott池仿真里出现频率最高的问题,而且往往是两个问题同时出现:光斑数量比预期多或比预期少,镜面上若干光斑死死地挤在一起,或者干脆有几个光斑跑到口径外面。排查顺序很重要,我的做法是先验证几何关系,再看物理效应。
几何关系的排查要点是确认入射位置和入射斜率是不是矩阵计算里用的那个值。VirtualLab里设置光束方向时,是通过定义光束传播矢量实现的,很容易因为坐标系差异导致实际入射角度和设计值不一致。我建议在光源后面加一个临时角度验证屏,直接读出光束在第一个镜面上的落点和入射角,和设计值比对一下再继续。
排除几何设置问题之后,光斑重叠基本就是衍射扩展导致的。高斯光束在每个往返过程中都会因为传播距离产生一定程度的发散,虽然两个凹面镜的聚焦作用会抑制发散,但对于光程很长的系统来说,几十次往返后的光斑尺寸和初始状态差别很大。应对办法有三种:减小入射高斯光束的束腰,让初始光斑本身更小;增大光斑步进间距,让相邻光斑离得更远;或者适当调整镜间距,把光斑轨迹圆半径做大。
4.2 计算资源与网格设置经验
VirtualLab的物理光学仿真精度与网格采样点数量直接相关,但Herriott池光程几十个往返,如果每个传播段都用高密度网格,计算时间会不可接受地暴涨。我的经验是分阶段设置精度:在方案探索阶段,用1024×1024甚至更低的网格密度,重点看光斑位置和大致的重叠情况;确认方案可行之后,再针对最终设计用2048×2048或更高密度做一次精细验证。记住物理光学仿真有个特点,网格和采样策略会影响结果的相位精度,低精度下看到的相位数据只能作为趋势参考,不能作为最终判断依据。
另外要养成定期清理探测器结果的习惯。VirtualLab里调试时会叠加大量探测器窗口,每个高分辨率探测器都占用内存,几十个探测器同时打开有可能导致仿真变慢甚至闪退。我一般只保留上一个调试节点的两个关键探测器,其余输出去到数据文件里留存。
4.3 镀膜与反射率对结果的影响
很多刚开始做仿真的人会忽略反射镜镀膜的波长特性,默认反射率100%。对于纯几何光路考察这没问题,但如果你关心最终耦合效率,镀膜就必须建模。典型的Herriott池反射镜会镀高反介质膜,在目标波长范围的反射率能达到99.5%以上,但如果工作波段比较宽,不同波长的反射率差异会导致透过损耗不同。尤其是做吸收光谱仿真时,如果池内往返次数有几十次,每圈损失0.5%,累积下来也有10%以上,这个损失在系统链路预算里完全不可忽略。
VirtualLab里可以为镜面设置波长相关的反射率特性,有实测镀膜数据就直接导入数据文件,没有数据就先建立简单的均匀反射率模型,至少把能量衰减的趋势评估出来。还需要留意的是一定要检查仿真中“反射率是否同时影响透射方向”。如果镜面反射率设为95%,应该有5%的能量在每次反射时透射出去,这部分能量如果被忽略,能量守恒就不对,后续的光功率分析会出现明显偏差。
4.4 高反射次数下相位与干涉效应
最后记录一个比较容易困扰人的现象:在反射次数较高、光斑排列接近规则的条件下,镜面上相邻光斑之间可能产生干涉效应,光斑强度分布出现明暗条纹。这不是软件出错了,而是因为各次反射光在探测面上相干叠加。使用高相干的激光光源时,这种现象真实存在,而且在实际光学系统中也确实会出现。
判断这类现象要不要处理,取决于应用场景。如果你做的是宽谱光源的多次反射池,光源相干长度很短,仿真中应该使用非相干叠加模式,避免出现人为的干涉条纹;如果你用的是窄线宽激光器,那么相干叠加的强度分布反而是需要重点关注的,因为它直接反映了系统的波前质量。VirtualLab的场追迹引擎默认会保留相位信息,叠加方式需要你根据光源特性主动设置,这个决定直接影响仿真结果的物理含义。
一点个人经验收尾
做了几个Herriott池项目之后,我最大的体会是仿真做得再好,也代替不了装调时的耐心。VirtualLab能帮你把设计空间快速收敛,但镜面间距的实际值、入射光斑的真实尺寸这些变量,总会有和仿真对不上的地方。我的习惯是所有仿真结果都留下一个批次记录,标明当时的参数版本,这样现场调试遇到问题,能迅速定位是哪个设计假设没被满足。如果你正准备用VirtualLab做类似的多次反射系统,建议从矩阵计算开始,先花十分钟把光斑闭合规律搞清楚,再进软件搭建模型,最后用探测器数据反推验证,这条路径我可以很负责任地说,比盲目在软件里来回拖动参数高效得多。