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)。