第4章:Zemax API入门——Zemax Extension API的基本调用
说实话,很多做光学设计的朋友,用了好几年Zemax,还是停留在手动点鼠标的阶段。我刚开始也是这样,直到有一次要批量优化几十个视场的镜头,手动操作到凌晨三点……从那以后,我下定决心把API啃下来。
这一章,咱们就聊聊Zemax的两种API:ZPL和ZOS-API。说白了,它们就是让你用代码控制Zemax的“遥控器”。
4.1 为什么要学API?
你想想看,日常设计中有多少重复劳动?
- 每次改完参数,都要手动点“更新”再去看MTF
- 要对比不同初始结构,得一个个打开文件、截图、记录
- 做公差分析时,要反复调整参数组合
这些活儿,用API几行代码就能搞定。我个人习惯是:凡是需要重复3次以上的操作,就写成脚本。省下来的时间,喝杯咖啡不香吗?
核心观点:API不是锦上添花,而是光学工程师从“熟练工”进阶到“专家”的必经之路。
4.2 ZPL——Zemax的亲儿子
ZPL(Zemax Programming Language)是Zemax自带的脚本语言。语法有点像早期的BASIC,简单粗暴,但够用。
4.2.1 ZPL能干什么?
- 读取镜头数据(曲率、厚度、玻璃等)
- 执行优化、评价像质
- 控制光线追迹、生成报告
- 批量处理文件
我在项目中遇到过最典型的场景:客户要求对20个不同波段的镜头做同样的像质评价。手动做?一天都搞不完。用ZPL写个循环,10分钟出结果。
4.2.2 第一个ZPL脚本:读取镜头数据
咱们先来个最简单的——读取第一面的曲率半径:
! 读取第一面曲率半径
GETSYSTEMDATA 1
PRINT "系统数据读取完成"
! 获取面1的曲率
GETSURFACEDATA 1
curv = SURF(1, 2) ! 第2列是曲率
PRINT "第一面曲率半径: ", 1/curv
嗯,这里要注意:ZPL的数组索引是从1开始的,不是0。我第一次写的时候就踩了这个坑,死活读不出数据,还以为是代码写错了。
4.2.3 像质评价:MTF计算
! 计算轴上视场的MTF
SETSYSTEMPROPERTY 0, 0, 0 ! 设置视场为0(轴上)
RAYTRACE 0, 0, 0, 0, 0, 0 ! 追迹主光线
! 计算MTF
MTF 0, 0, 30, 0, 0 ! 30 lp/mm,子午方向
mtf_val = MTF()
PRINT "轴上MTF@30lp/mm: ", mtf_val
小技巧:我习惯在脚本开头加一句 ! 脚本开始 的注释,方便调试时定位。另外,ZPL不支持断点调试,所以多用 PRINT 输出中间结果。
4.3 ZOS-API——更强大的选择
ZOS-API是Zemax后来推出的接口,支持C#、Python、MATLAB等语言。相比ZPL,它更灵活,功能也更强大。
4.3.1 为什么还要学ZOS-API?
| 对比项 | ZPL | ZOS-API |
|---|---|---|
| 学习难度 | 低(几十个命令) | 中(需要懂面向对象) |
| 功能覆盖 | 约70% | 接近100% |
| 数据处理 | 弱(只能PRINT) | 强(可导出到Excel/数据库) |
| 扩展性 | 差 | 好(可调用其他库) |
说白了,ZPL适合快速写个小脚本,ZOS-API适合做复杂的自动化工具。我个人的经验是:如果脚本超过50行,就改用ZOS-API。
4.3.2 Python调用ZOS-API示例
用Python调用ZOS-API,需要先安装 pythonnet 包:
import clr
import sys
# 加载ZOS-API程序集
clr.AddReference(r"C:\Program Files\Zemax OpticStudio\ZOS-API\ZOSAPI_NetHelper.dll")
from ZOSAPI import *
# 连接到Zemax
TheConnection = ZOSAPI_Connection()
TheApplication = TheConnection.ConnectAsExtension(0) # 0表示扩展模式
# 打开镜头文件
TheSystem = TheApplication.PrimarySystem
TheSystem.LoadFile(r"C:\Lens\my_lens.zmx", False)
# 读取第一面曲率
LDE = TheSystem.LDE
surface1 = LDE.GetSurfaceAt(0) # 注意:这里索引从0开始
radius = surface1.Radius
print(f"第一面曲率半径: {radius} mm")
注意:ZOS-API的索引和ZPL不同,是从0开始的。我刚开始混用的时候,经常搞混,后来干脆统一用ZOS-API的索引方式。
4.3.3 像质评价:MTF曲线数据提取
# 计算MTF
MFE = TheSystem.MFE
mtf_operand = MFE.CreateOperand(1) # 创建第1个操作数
mtf_operand.ChangeType(OperandType.MTFS) # 子午MTF
mtf_operand.GetOperandCell(1).SetValue(30) # 30 lp/mm
# 更新并获取结果
TheSystem.Tools.OpenUpdate()
mtf_value = mtf_operand.GetOperandCell(2).Value # 第2列是计算值
print(f"MTF@30lp/mm: {mtf_value}")
4.4 实战:批量读取镜头数据
咱们来个综合案例——批量读取一个文件夹下所有ZMX文件的镜头数据:
import os
import clr
# 连接Zemax
clr.AddReference(r"C:\Program Files\Zemax OpticStudio\ZOS-API\ZOSAPI_NetHelper.dll")
from ZOSAPI import *
TheConnection = ZOSAPI_Connection()
TheApplication = TheConnection.ConnectAsExtension(0)
TheSystem = TheApplication.PrimarySystem
# 遍历文件夹
folder = r"C:\Lens\Batch"
for file in os.listdir(folder):
if file.endswith(".zmx"):
filepath = os.path.join(folder, file)
TheSystem.LoadFile(filepath, False)
# 读取关键参数
LDE = TheSystem.LDE
efl = LDE.GetSurfaceAt(0).EFL # 有效焦距
fno = LDE.GetSurfaceAt(0).FNO # F数
print(f"{file}: EFL={efl:.2f} mm, F/#={fno:.2f}")
这个脚本我经常用来做初始结构筛选。把几十个镜头文件丢进去,几秒钟就能知道哪些符合设计要求。
4.5 避坑指南
我踩过的坑,你们就别再踩了:
- 版本兼容性:ZOS-API的接口在不同版本间有变化。我曾经写好的脚本,升级Zemax后跑不了,排查了半天才发现是某个方法被废弃了。建议在脚本开头加版本检查。
- 内存泄漏:频繁打开关闭镜头文件,Zemax可能会内存泄漏。我习惯每处理10个文件就重启一次连接。
- 调试困难:ZOS-API的报错信息有时很模糊。我的做法是:每个关键步骤都加try-except,把错误信息写到日志文件里。
我的习惯:写API脚本时,先手动在Zemax里操作一遍,把步骤记下来,再翻译成代码。这样不容易漏掉关键步骤。
4.6 本章小结
ZPL和ZOS-API,就像手动挡和自动挡的区别。ZPL简单直接,适合快速验证想法;ZOS-API功能全面,适合做自动化工具。我个人建议:初学者从ZPL入手,等熟悉了API的思维方式,再切换到ZOS-API。
记住一句话:凡是重复的工作,都值得自动化。 花半小时写个脚本,可能省下你未来几十个小时的时间。