在现代光学工程设计与制造的完整过程中,对光学表面特性的精确量化起着至关重要的作用。虽然光学设计软件提供了丰富的图形化分析窗口,但在诸如非球面公差分析检测,自由曲面加工、有限元热结构分析等实际场景中,我们常常需要直接提取出相关的一些参数,进行数据二次处理与使用。

本文以透镜表面的矢高提取为例,给大家演示一下Zpl宏语言相关语句的用法,希望能够抛砖引玉,也希望大家举一反三。

(本文所演示的基础版代码已在之晓光学工具箱小程序更新~)

一、引言

随着技术进步,在一些应用场景中,我们已经可以很容易找到非球面、二元面或自由曲面的身影。当想要评估这些表面时,使用多项式表达矢高或相位往往是不符合实际工程情况的,我们常使用离散的表面矢高和相位数值进行描述。

此外,除了几何矢高,入射角度、光程差等依赖于光学设计的物理量,在公差分析、镀膜均匀性分析和杂散光抑制研究中,离散的数值表述方式同样具有决定性意义。

通过编程手段批量读出这些参数,不仅能够突破理想的面形方程限制,还能将数据无缝导入 MATLAB 或 Python 等数值计算软件中进行二次处理。

这一类重复大量数据的读出很适合利用编程实现,接下来本文将探讨如何利用 Zemax 编程语言(ZPL)在传统版本的光学设计软件中,自动化地以高分辨率网格扫描并导出光学表面的矢高数据,从而实现从设计模型到工程数据的有效传递。

二、ZPL 宏语言概况及关键指令解析

光学表面,无论是传统的球面、二次曲面,还是日益普及的非球面,其核心特征在于表面面型对基准参考平面的偏离量。这种偏离量在光学轴向(Z轴)上的分布,被称为“矢高”(Sagitta或Sag)。

通常情况下,光学设计软件默认每个透镜的矢高度量原点是透镜的顶点位置,因此矢高有正负值的影响。标准的矢高方程即为我们经常看到的标准面面型方程:

Zemax 编程语言(ZPL)是一种类似于 BASIC 的解释型语言,赋予了用户扩展软件核心计算能力的权限。在本任务中,我们的目的是使用代码快速的输出某一个光学表面的离散矢高数据,为了这个目的,我们首先要考虑一下程序架构,如下图所示。

首先是输入部分,我们可以首先定义需要的变量,并赋予初始值,之后,利用ZPL合法语句由用户输入其中部分参数。

此部分构成程序的第一部分,如下所示:

surf_ID = 2

! 设定目标表面编号。此处设为2,即序号为2对应的表面。

! 在实际使用中,用户可根据需要修改此数值。

num_steps = 20

! 设定采样点数。点数越多,剖面曲线越平滑,但计算时间略增。

! 20步意味着将直径分为20段,共产生21个数据点。

max_aperture = SDIA(surf_ID)

!SDIA 函数直接查询镜头数据。

! SDIA(surf_ID) 返回镜头数据编辑器中该表面的半口径值。

进一步,我们可以让数据以文本查看器的形式输出,我们可以使用 PRINT 指令输出包含元数据的表头,便于数据溯源,具体语句示例如下。

PRINT "========================================"

PRINT " 光学表面矢高自动化提取报告"

PRINT "========================================"

PRINT "分析表面编号 : ", surf_ID

PRINT "自动检测半口径: ", max_aperture, " mm"

PRINT "采样分辨率 : ", num_steps, " 点"

PRINT "----------------------------------------"

PRINT " Y-坐标 (mm) 表面矢高 (mm)"

PRINT "----------------------------------------"

我们计划从透镜有效口径的一端自动扫描至透镜口径另一端,因此可以根据输入的步长进行计算:

step_size = (2 * max_aperture) / num_steps

current_y = -max_aperture

为了结果展示的比较规整,则可以设置输出数据格式为14位总宽,保留3位小数:

FORMAT 14.3

接下来就是核心的部分,我们要用FOR循环读取各个参数点的矢高数值,这个数据有对应的操作数SSAG,这里我们要用的核心函数是OCOD和OPEV。

OCOD返回的是具体操作数对应的代码,而OPEV这是ZPL中最强大的函数之一。它允许宏直接调用评价函数编辑器中的操作数。标准OPEV的写法为:

OPEV(code, int1, int2, data1, data2, data3, data4)

其中Code是OCOD返回的数值,一个常见错误是这里直接填操作数代码,这样做是不对的。后面的数据对于不同的操作数来说有不同的含义,例如对我们的案例,写作:

SAG = OCOD("SSAG")

sag_value= OPEV(SAG, surf_ID, 0, 0, current_y, 0, 0)

此时int1位置对应的是表面序号,int2不起效果,可以输入0,data1~data4与后续的列一一对应,如果这一列没有参数,输入0即可。

图片

把这一段嵌入循环语句中,即可正常工作,最终输出表格结尾部分即可。

三、计算案例

本节展示修正后的完整代码演示结果。zpl文件已上传至之晓光学工具箱小程序—光学仿真模型—程序算法案例模块。为了大家参考,进行了详细的中文注释,可以免费下载。

这里我们找了一个红外镜头,如下图所示,第一个面是光阑,我们可以读取第二个面的矢高数据:

图片

修改代码中变量的赋值,我们即可输出任意表面,给定采样密度下的矢高数据。

图片

四.总结

本文通过一个具体的ZPL宏案例,系统地阐述了光学表面矢高提取的原理、语法实现及代码优化过程。 我们从光线追迹的数学基础出发,明确了矢高作为连接光学设计与机械制造的核心参数的物理意义。

对于初学者而言,本案例不仅是一次代码编写的练习,更是一次设计思维的升级。 它演示了如何利用脚本语言打破软件GUI的限制,直接与底层数据交互。 这种能力在处理诸如非球面拟合、公差敏感度分析以及光机热耦合分析等高级任务时将变得不可或缺。

看到这里,大家也可以下载我们的案例,在自己的电脑中运行一下,修改一下。ZPL宏语言我们也正在筹备,希望把这一部分知识整合成一个系统的专题,供大家学习。当然,这也需要大家自己练习,有了这一部分内容,大家要学会举一反三,例如,可以提取某个表面上一束光在各个位置的入射角度,提取一束光再任意表面的全局坐标等。大家可以自行探索一下,把这个宏进一步完善~