Engee 文档
Notebook

构建镜头模型

让我们用这个包建立一个理想镜头的模型 GeometricalOptics.jl. 我们将展示如何在一个画布上显示光束传播的几个图形,并在这个图形上实现射线优化过程,使图形的信息量最大。

光学系统参数

要指定镜头参数,您需要连接(并可能安装)库 GeometricalOptics.

In [ ]:
Pkg.add( url="https://github.com/airspaced-nk5/GeometricalOptics.jl#master" )
Pkg.add( "Optim" )
In [ ]:
using GeometricalOptics
gr(); # 该库使用这种图形渲染机制效果更好。

现在我们可以指定几个球面透镜和一个像平面。:

/物体/类型|材料|折射率|半径R1(mm)|半径R2(mm)|厚度/跟踪距离。 |
| ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- |
/镜头/双凸/[SK16](https://refractiveindex.info/?shelf=glass&book ;=HIKARI-SK&page;=SK16) | 1.6204 | 22 | 430 | 3 | 6 |
/镜头/biconcave/[F2](https://refractiveindex.info/?shelf=glass&book ;=肖特-F&页;=F2) | 1.6200 | 22 | 20 | 1 | 6 |
/镜头/双凸/[SK16](https://refractiveindex.info/?shelf=glass&book ;=HIKARI-SK&page;=SK16) | 1.6204 | 78 | 16 | 3 | 34 |

光学系统的最后一个元件是像平面

测量单位(毫米)在计算中不起特殊作用,只要我们不考虑衍射和波长。

透镜的厚度等于光线沿着光轴穿过透镜的路径长度。

半径R1和R2被理解为每个透镜的每一侧的曲率半径:R1表征位于更靠近光源的"输入"侧的曲率半径,R2是位于更靠近像平面的透镜的输出侧。

让我们来描述这个光学系统,并建立一个小的可视化。:

In [ ]:
surfsList = [ spherical, spherical,
              spherical, spherical,
              spherical, spherical,
              zplane]

p_s = 10; # 图的左边缘到第一折射面的距离
stations = p_s .+ [ 0., 3., 9., 10., 16., 19., 53. ]
radii = [ 22., -430., -22., 20., 78., -16., 0.0 ]
coeffsList = [ [s, r] for (s,r) in zip(stations, radii)]

# 镜片材质,依序:SK16、F2、SK16
nList = [ 1., 1.6204,
          1., 1.6200,
          1., 1.6204,
          1.]

optSta = opticalstack( coeffsList, surfsList, nList );

test_bundle = bundle( [0.], (-3:3:3), 0., 0., 0. );
p_lens = optSta( test_bundle; rend = "YZ", halfdomain=3.5 )

plot!( ylimits=(-5,5), aspect_ratio=:none, size=(600,200) )
Out[0]:

一个小小的可视化让我们看到所有指定的元素。

将光束瞄准孔径

现在让我们假设该系统具有位于凹透镜后2毫米的光圈。

我们希望将光束穿过它,设置一定的入射角,并确保它们聚焦在图像平面上。

我们可以将模型分成两部分,并模拟膜片在两个方向上的传播(一个表面模型) [6:end],另一个为 [5:-1:1]). 但是由于射线只有在接近第一个透镜时才应该平行(它们在穿过光阑时不会相互平行),我们必须在穿过光阑时寻找每条射线的角度。

让我们走另一条路,"优化"两个参数:光束宽度和光束中心光束指向的Y轴上的点。 我们的目标是找到射线正好穿过膜片的光束的参数。

In [ ]:
angles = [0.0, 0.1, 0.2];             # 每束射线的角度
colors = [:blue, :green, :red];       # 每个束都有自己的颜色
ypositions_init = [ 0., 3.0, 5.0];    # 沿Y轴发送中心射线的点的近似位置
bundle_halfwidth = 3;                 # 光束的半径

p = plot();                           # 让我们绘制一些图表

for (angle, ypos, pc, plot_surface) in zip(angles, ypositions_init, colors, [true, false, false])
    b = bundle([0.], range(-bundle_halfwidth,bundle_halfwidth,length=3) .- ypos, 0., angle, 0.)
    optSta( b; rend = "YZ", color = pc, plobj = p, halfdomain=5.5, issurfplot=plot_surface )
end

plot!( p, p_s.+[12., 12.], [-2.5, 2.5], lw=2, lc=:black, markershape=:diamond, markercolor=:white );
plot!( p, ylimits=(-8,8), size=(900,400) )
Out[0]:

如果我们放大光圈的图像,我们会看到我们的第一个近似值离所需的近似值不是很远,但是为了进行准确的计算,我们需要将光束发送的点移动一点。

光束与光轴的角度不会改变。 我们只是在寻找如何定位光束,使其精确地穿过隔膜。 这对于计算传感器尺寸和其他有趣的结果很有用。

In [ ]:
plot!( xlimits=(p_s .+ [10, 14]), ylimits=(-3,3), aspect_ratio=:none, size=(500,500) )
Out[0]:

现在让我们创建一个优化过程。

In [ ]:
using Optim

# 以光圈"结束"的新配置(尽管您可以在任何镜头之间添加zplane)
optSta2 = opticalstack( [coeffsList[1:4]; [[p_s+12.]]], [surfsList[1:4]; zplane], [nList[1:4] ; 1.0] );

# 我们将优化的功能
function f(x, in_angle)
    b_hw = x[1]       # 光束半径
    ypos = x[2]       # 光束中心的Y偏移
    
    b = bundle([0.], range(-b_hw,b_hw,length=3) .- ypos, 0., in_angle, 0.);
    
    # 让我们研究光束与第6表面相交处的光斑
    t_info = GeometricalOptics.trace_extract_terminus( optSta2( b ), 6, coord="y" );
    
    # 两个优化标准:光点的两个边界都必须与光圈的大小相匹配
    q1 = abs( minimum( t_info ) - (-2.5))
    q2 = abs( maximum( t_info ) - ( 2.5)) 
    return q1 + q2
end

angles_hw_list = []
y_positions_list = []
for (angle,y_pos_init) in zip(angles, ypositions_init)
    # 我们分别对需要的每个角度值进行优化。
    res = optimize(x -> f(x, angle), [bundle_halfwidth, y_pos_init])
    angle_optim, ypos_optim = Optim.minimizer( res )
    push!( angles_hw_list, angle_optim )
    push!( y_positions_list, ypos_optim )
end

# 让我们显示一个优化结果表。
display([["光束方向"; "光束宽度"; "Y的起点"] [angles angles_hw_list y_positions_list]'] )
3×4 Matrix{Any}:
 "Направление луча"       0.0         0.1      0.2
 "Ширина пучка"           3.1232      3.13102  3.15749
 "Отправная точка по Y"  -5.40173e-8  2.44082  4.98689

优化后,光学系统看起来像这样:

In [ ]:
p = plot(); # 用于绘制多个图形的画布

for (angle, ypos, b_hw, pc, plot_surface) in zip(angles, y_positions_list, angles_hw_list, colors, [true, false, false])
    b = bundle([0.], range(-b_hw,b_hw,length=3) .- ypos, 0., angle, 0.)
    optSta( b; rend = "YZ", color = pc, plobj = p, halfdomain=5.5, issurfplot=plot_surface )
end

plot!( p, p_s.+[12., 12.], [-2.5, 2.5], lw=2, lc=:black, markershape=:diamond, markercolor=:white );
plot!( p, ylimits=(-8,8), size=(900,400) )

仔细检查膜片可以让你看到光点的正确位置。

In [ ]:
plot!( xlimits=(p_s .+ [10, 14]), ylimits=(-3,3), aspect_ratio=:none, size=(500,500) )
Out[0]:

库中的镜头尺寸 GeometricalOptics.jl 它们在视觉上没有被考虑在内。 在某些情况下,例如,当创建多项式Цернике,光束在某个区域之外的通过导致开发人员提供的误差。

结论

如果将光学电路计算功能包装在优化过程中,则可以自动化许多光学系统设计步骤。 光束由单独的光线组成,它们在系统任何部分的参数都可以使用函数获得 trace_extract_terminus 对她подобных.

在少量额外代码的帮助下,可以计算AF范围和其他任务。

数据来源

[[1]](http://mir-3d-world.ipo.spb.ru/2016/3dworld_4_2016.pdf )在Zemax中构建理想光学[电子资源]//科普杂志"3D世界世界":网站。 网址:http://mir-3d-world.ipo.spb.ru/2016/3dworld_4_2016.pdf (请求日期:05.11.2024)。