本文将使用ZOS-API创建自定义分析 (User Analysis),以测量激光雷达系统的飞行时间 (TOF)。此分析将读取ZRD文件,提取其数据并绘制到达探测器的光线的飞行时间。
作者 Sandrine Auriol
附件下载
什么是自定义分析?
ZOS-API (应用程序接口 (Application Programming Interface) ) 可以使用最新的软件技术连接和定制应用程序。应用程序与OpticStudio之间的连接有四种程序模式,但可以分为两大类:
1) 完全控制(独立 (Standalone) 模式和自定义扩展 (User Extensions) 模式),这种情况下,用户通常完全控制镜头设计和用户界面;
2) 有限访问(自定义操作数 (User Operands) 模式和自定义分析模式),这种情况下,用户使用现有镜头文件的副本进行处理和分析。
自定义分析模式用于填充自定义分析的数据。这些数据是用OpticStudio提供的现有图形来显示,用于大多数分析。此模式不允许对当前镜头系统或用户界面进行更改(即:在这种模式下只允许对系统的副本进行更改)。自定义分析可以用C++ (COM) 或C# (.NET) 编写。本文的自定义分析是用C#编写的。
有关自定义分析的更多信息,请点击编程 (Programming) 选项卡>关于ZOS-API (About the ZOS-API) >自定义分析 (User Analysis),查看内置帮助文件。
打开新的编程模板
使用C#创建自定义分析:
使用Windows资源管理器打开解决方案文件夹 ‘..\Documents\Zemax\ZOS-API Projects\CSharpUserAnalysisApplication1’。 Visual Studio 也打开了新的解决方案。该解决方案包含模板代码,该模板代码可以用作任何自定义分析的基础模板。在Visual Studio中,用户自定义分析被编译为可执行文件,然后将可执行文件复制到 \Zemax\ZOS-API\User Analysis 文件夹中,以便OpticStudio可以使用。
打开激光雷达文件
可以在本文的附件链接中下载文件“Flash_NSC_Final.zar” ,该文件中包含代表快闪激光雷达的系统,激光雷达位于货车的顶部,货车在路上,路上还有两个行人和一堵立着的绿色墙体。
激光雷达向场景中发射激光脉冲:
光照射到周围的物体上发生散射,部分光被散射回激光雷达探测器。
如下图所示:来自红色行人的散射光到达了激光雷达探测器的一个单位像素上。
激光雷达会将接收到返回信号花费的时长记录下来,即飞行时间,并将飞行时间转换为距离。像素的位置可表明入射光的方向。
这两个值都表明散射光线来自站在离货车10米远的红色行人。OpticStudio实际上测量的不是时间,而是光线路径长度,也就是物体和探测器之间的距离。
探测器查看器 (Detector Viewer) 可以显示探测器上辐射特性的测量结果,但它不显示从激光雷达光源返回到激光雷达探测器的光线经过的距离。这就是ZOS-API派上用场的时候!自定义分析可以显示探测器到物体的距离数据,从而反映飞行时间的信息。
使用光线数据库查看器读取ZRD文件
ZRD文件即光线数据库文件,光线路径长度可以在ZRD文件中读取。
运行光线追迹 (Ray Trace) 并通过选中保存光线 (Save Rays) 将光线保存为ZRD文件。
点击分析 (Analyze) >光线数据库查看器,可以显示照射到探测器17上的光线的路径长度。将“使用字符串 (Apply Filter) ”设置为H17来过滤照射到探测器17上的光线。
例如,光线1的第8段已经到达探测器17,该光线的路径长度4E4 (40m) 是所有光线段的光线路径长度之和。光线经过物体,然后回到探测器。物体到探测器的距离是该路径的一半,即20米。
所以,物体到探测器的距离可以通过读取照射到探测器的每条光线的路径长度来确定,可以使用ZOS-API自动完成此操作。
使用ZOS-API读取ZRD文件
当使用ZOS-API启动新项目时,先查看位于编程 (Programming) >ZOS-API帮助 (ZOS-API Help) >ZOS-API语法帮助 (ZOS-API Syntax Help) 中的示例是个好习惯。
示例05:“解析ZRD文件”展示了如何读取ZRD文件,可以在此处作为参考。
自定义分析代码包含以下命令:
- OpenRayDatabaseReader:打开光线数据查看器,读取ZRD文件,然后得到结果:
IZRDReader ZRDReader = TheSystem.Tools.OpenRayDatabaseReader();
ZRDReader.ZRDFile = ‘<path>\Flash_LIDAR_NSC.ZRD’;
ZRDReader.RunAndWaitForCompletion();
var ZRDResult = ZRDReader.GetResults();
- ReadNextResult:读取光线。
success_NextResult = ZRDResult.ReadNextResult(out rayNumber, out waveIndex, out wlUM, out numSegments);
- ReadNextSegmentFull:读取光线的正弦值。
success_NextSegmentFull = ZRDResult.ReadNextSegmentFull(out segmentLevel, out segmentParent, out hitObj, out hitFace, out insideOf,
out RayStatus, out x, out y, out z, out l, out m, out n, out exr, out exi, out eyr, out eyi, out ezr, out ezi, out intensity, out pathLength, out xybin, out lmbin, out xNorm, out yNorm, out zNorm, out index, out startingPhase, out phaseOf, out phaseAt);
对于光线的各段,读取的值为:
-
-
out pathLength: 把光线每一分段的路径相加就得到了光线的路径长度。
-
out x, out y, out z: 最后一段光线的x, y, z坐标,用来找出光线落在哪个像素上。
- out intensity: 最后一段光线的强度。
-
填充数据阵列
将结果存储在二维数组中(探测器的x和y方向的像素数)。
数组(像素x,像素y) =数据
数组中的数据可以是光线的路径长度、强度等。
为了将光线赋值给像素,使用 GetMatrix 将探测器上光线最后一段的坐标 (x_LastSegment, y_LastSegment) 从全局坐标转换为探测器上的局部坐标:
TheSystem.NCE.GetMatrix(detector, out double R11, out double R12, out double R13, out double R21, out double R22, out double R23, out double R31, out double R32, out double R33, out double Xo, out double Yo, out double Zo);
然后将光线最后一段赋值给探测器上的像素 [i,j]。
有4个数组结果:
- array_OPL [i,j] 包含到达探测器像素的光线路径长度的平均值 [i,j] 除以2。它是物体到探测器的距离。
- array_TOF [i,j] 包含飞行时间数据。它是将路径长度转得到的时间。光在空气中的速度是299792公里/秒。飞行时间是路径长度的2倍除以光速。
这个值是读出的光线路径长度近似值,并不是光程,而是路径长度。但是,当到物体的距离远大于通过光学元件的路径时,这个假设是有效的。
- array_nb_hit [i,j] 包含击中探测器像素 [i,j] 的光线数。
- array_flux [i,j] 包含到达探测器像素 [i,j] 的光线通量之和。
如果探测器像素上的通量值 array_flux [i,j] 小于 MinFlux 定义的限制值时,探测器值为0,该像素就会被认定为噪声。
//Define (declare and initialize arrays)
double[,] array_OPL = new double[ypixels, xpixels];
double[,] array_TOF = new double[ypixels, xpixels];
double[,] array_nb_hit = new double[ypixels, xpixels];
double[,] array_flux = new double[ypixels, xpixels];
到达探测器上-X像素的光来自+X视场。为了避免在自定义分析中出现翻转的图像,结果数组包含从+X到-X和从+Y到-Y的数据。
绘制结果图像
自定义分析创建数组图形。
目前有四种类型的数据可以用于计算和显示:二维折线图 (2D Line Plot)、二维网格图 (2D Grid Plot)、2D RGB网格图 (2D RGB Grid Plot) 和文本数据 (Text Data)。
使用 MakeGridPlot
建立“飞行时间”分析的二维网格图,将结果存储在数组中。X轴和Y轴代表探测器像素,Z轴可以代表物体的距离、飞行时间、光线击中探测器的次数或通量。 IUserGridData
接口的 SetDataSafe 函数可将数组作为输入。
IUserGridData gridPlot = TheAnalysisData.MakeGridPlot("Time of Flight");
gridPlot.XLabel = "Pixel X coordinate value";
gridPlot.YLabel = "Pixel Y coordinate value";
gridPlot.SetDataSafe(array_OPL);
注意,每次自定义分析只允许使用一种数据格式。
自定义分析将显示已保存的ZRD文件和特定探测器的结果。结果可以是以下四个数组中的任意一个:从物体到探测器的距离、飞行时间、照射到探测器像素上的光线数或探测器像素上的通量。
所有这些选项都是设置对话框的一部分,包括上面提到的窗体控件和显示选项。
创建设置
自定义分析包含的设置对话框,使自定义分析更加通用。设置存储在由键值对组成的词库中。这意味着每个设置都是通过用户自定义的字符串键引用的,该字符串具有与之相关联的特定类型。当第一次启动分析时,词库是空的。任何添加到设置词库 (Settings Dictionary) 的条目都会在两次更新之间保存,并且可以与会话一起存储。以下类型可以存储在设置中:整数、浮点数(32位)、双精度数(64位)、布尔、字符串、字节。
库的声明是在Program.cs文件中完成的,然后在设置和分析之间传递变量。下面是TOF自定义分析中的键的词库:
//declare public variables called keys to pass between settings and analysis
public const string S_filter = "filter";
public const string S_ShowAs = "ShowAs";
public const string S_ZRDFile = "ZRDFile";
public const string S_FirstTime = "FirstTime";
public const string S_ShowData = "ShowData";
public const string S_MinFlux = "MinFlux";
除了 S_FirstTime 之外的所有键都是关于设置的。 S_FirstTime 键用于记录自定义分析是否首次启动。如果不是首次,则说明还没有设置。将显示一条要求用户先进行设置的消息。
// Basic checks
if (!FirstTime)
{
IUserTextData userText = TheAnalysisData.MakeText();
userText.Data = "Run the settings first";
return;
}
设置是在单独的类中定义的,这个类称为AnalysisSettingsForm
。AnalysisSettingsForm
类是自定义分析模板的一部分。这个类定义了默认值以及设置窗口的设计:
自定义分析模板将创建空的设置窗口。通过使用工具箱 (Toolbox),可以手动添加Windows窗体来定义设置。例如,通过显示ZRD文件下拉列表的组合框完成ZRD文件的选择。用于输入探测器序号的是文本框。
自定义分析模板在Program.cs文件中包含名为 ShowUserAnalysisSettings 的函数。该函数将显示要修改的设置的窗体,然后恢复设置。
在代码中,定义了名为 SettingsForm 的对象,它是 AnalysisSettingsForm 类的实例。然后显示窗体。当用户定义了设置并单击OK时,将为键分配值。
TheSettings.SetStringValue(S_filter, SettingsForm.filter);
TheSettings.SetStringValue(S_ZRDFile, SettingsForm.ZRDFile);
TheSettings.SetStringValue(S_ShowAs, SettingsForm.ShowAs);
TheSettings.SetStringValue(S_ShowData, SettingsForm.ShowData);
TheSettings.SetStringValue(S_MinFlux, SettingsForm.MinFlux);
TheSettings.SetBooleanValue(S_FirstTime, true);
例如,“Show As”设置是读取SettingsForm.ShowData的代码,然后设置S_ShowData键的值。
当使用Program.cs文件中的RunUserAnalysis函数运行自定义分析时,将读取S_ShowData键,并将该值赋给名为ShowData的变量。
// Read the public variables / keys
// Define new variables (out) and assign a value to those variables
TheSettings.GetBooleanValue(S_FirstTime, out bool FirstTime);
TheSettings.GetStringValue(S_filter, out string filter);
TheSettings.GetStringValue(S_ShowAs, out string ShowAs);
TheSettings.GetStringValue(S_ZRDFile, out string ZRDFile);
TheSettings.GetStringValue(S_ShowData, out string ShowData);
TheSettings.GetStringValue(S_MinFlux, out string MinFlux);
根据设置和 ShowData 的值的不同,会显示不同的输出:
switch (ShowData)
{
case "Distance to Object":
gridPlot.ValueLabel = "Distance to Object: Half Path length in m";
gridPlot.SetDataSafe(array_OPL);
break;
case "Number of Hits":
gridPlot.ValueLabel = "Number of Hits";
gridPlot.SetDataSafe(array_nb_hit);
break;
case "Time Of Flight":
gridPlot.ValueLabel = "Time of Flight in us";
gridPlot.SetDataSafe(array_TOF);
break;
default:
gridPlot.ValueLabel = "Flux in W";
gridPlot.SetDataSafe(array_flux);
break;
}
保存、构建和移动可执行文件
可以在发布模式 (Release Mode) 中构建解决方案。调试时可以使用调试模式。但是要将自定义分析作为插件分配,请将其设置为发布模式,因为调试库是不可重新分配的。
然后,可以将可执行文件从解决方案文件夹 (在 ‘…Documents\Zemax\ZOS-API Projects\...’中) 复制到‘...Documents\Zemax OpticStudio\ZOS-API\User Analysis’中。
运行自定义分析
检查TOF自定义分析,打开OpticStudio,打开镜头文件 “Flash_LIDAR_NSC.zar”。在编程 (Programming) 选项卡>自定义分析 (User Analyses) 下,现在应该有了新创建的分析。
首先,定义设置:
点击OK生成显示周围物体距离的图形:
未来可能:时间相关的分析
在本例中,探测器读取光的路径长度,但是没有考虑时间的概念,这可以使用ZOS-API完成。
激光雷达的光源是脉冲激光。分析如下:
- 以脉冲激光器的形式发出光
- 以给定的频率记录ZRD文件
- 显示/处理结果
KA-01800
评论
文章评论已关闭。