透镜模型结构¶
让我们使用GeometricalOptics.jl
软件包建立一个理想透镜模型。我们将展示如何在一张画布上绘制多幅光束传播图,并在此图上实施光线优化程序,使图的信息量最大。
光学系统参数¶
要指定镜头参数,您需要连接(并可能安装)GeometricalOptics
库。
Pkg.add( url="https://github.com/airspaced-nk5/GeometricalOptics.jl#master" )
Pkg.add( "Optim" )
using GeometricalOptics
gr(); # Библиотека лучше работает с этим механизмом отрисовки графиков
现在我们可以指定多个球面透镜和图像平面:
| 对象 | 类型 | 材料 | 折射率 | 半径 R1 (mm) | 半径 R2 (mm) | 厚度 | 到跟踪 pov.| 的距离 | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | | 透镜 | 双折射 | SK16 | 1.6204 | 22 | 430 | 3 | 6 | | 透镜 | 双曲面 | F2 | 1.6200 | 22 | 20 | 20 | 1 | 6 | | 透镜 | 双凸面 | SK16 | 1.6204 | 78 | 16 | 16 | 3 | 34 |
光学系统的最后一个元件是像面。
只要我们不考虑衍射和波长,测量单位(毫米)在计算中并不重要。
透镜的厚度等于光束沿光轴穿过透镜的路径长度。
半径 R1 和 R2 指的是每个透镜两侧的曲率半径:R1 表示离光源较近的 "输入 "侧的曲率半径,R2 表示离像面较近的透镜输出侧的曲率半径。
让我们来描述一下这个光学系统,并建立一个小的可视化模型:
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) )
通过这个小型可视化系统,我们可以看到所有给定的元素。
将光线对准光圈光阑¶
现在假设系统在凹透镜后 2 毫米处有一个光圈光阑。
我们希望让光束以一定的入射角度通过它,并确保它们聚焦在像面上。
我们可以将模型分成两部分,并对从光圈向两个方向的传播进行建模(一个模型用于表面
[6:end]
,另一个用于[5:-1:1]
)。但由于光线只需在接近第一个透镜时平行(光线通过光圈时不会相互平行),因此我们必须找出每条光线通过光圈时的角度。
让我们反其道而行之,"优化 "两个参数:光束宽度和中心光束在 Y 轴上的指向。*我们的目标是找到射线正好穿过光阑的光束参数。
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) )
如果我们放大光圈的图像,就会发现我们的第一近似值与理想值相差不大,但为了进行精确计算,我们需要将光束的发射点稍微移动一下。
光束与光轴的角度不会改变。我们只需对光束进行定位,使其正好通过光圈。这有助于计算传感器尺寸和其他有趣的结果。
plot!( xlimits=(p_s .+ [10, 14]), ylimits=(-3,3), aspect_ratio=:none, size=(500,500) )
现在让我们创建一个优化程序。
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]'] )
优化后的光学系统如下:
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) )
仔细观察光圈,可以看到光斑的正确位置。
plot!( xlimits=(p_s .+ [10, 14]), ylimits=(-3,3), aspect_ratio=:none, size=(500,500) )
图库
GeometricalOptics.jl
中没有明确考虑镜头尺寸。在某些情况下,例如在创建 Zernike 多项式时,光束通过特定区域外会导致开发者定义的错误。
结论¶
通过将光学设计功能纳入优化程序,光学系统设计的许多步骤都可以实现自动化。光束由单条光线组成,使用函数trace_extract_terminus
和其类似函数可以获得它们在系统任意截面上的参数。
只需少量附加代码,就能完成自动对焦范围的计算和其他任务。
数据源¶
[1] 在 Zemax 中构建理想光学[电子资源] //科普杂志 "3D 世界":网站。URL: http://mir-3d-world.ipo.spb.ru/2016/3dworld_4_2016.pdf (地址日期:2024 年 11 月 5 日)。