raytracing
前回、焦点距離を変化させ、特定の高さ(サイズ)の光線を得る方法を紹介しました。

今回はaytracingライブラリでアパチャーのサイズの取得方法とレンズ位置の図示の方法を紹介します。
前回までに光線や焦点距離、結像距離を図にする方法を紹介していて、現状こんな感じです。
from raytracing import *
import matplotlib.pyplot as plt
path = ImagingPath()
path.append(Space(d=50))
path.append(Lens(f=10))
path.append(Space(d=50))
angle_list = np.linspace(-10, 10, 7)
#----------位置、角度情報取得ここから----------
y_list = []; z_list = []; theta_list = []
for angle in angle_list:
ray = Ray(y=0, theta=np.radians(angle))
trace = path.trace(ray)
y_optics = []; z_optics = []; theta_optics = []
for data in trace:
y_optics.append(data.y)
z_optics.append(data.z)
theta_optics.append(data.theta)
y_list.append(y_optics)
z_list.append(z_optics)
theta_list.append(theta_optics)
#----------位置、角度情報取得ここまで----------
#----------結像位置取得ここから----------
cross_list = []
for y_ray, z_ray in zip(y_list, z_list):
z1 = z_ray[-2]; z2 = z_ray[-1]
y1 = y_ray[-2]; y2 = y_ray[-1]
cross = -y1*(z2-z1)/(y2-y1)
cross_point = cross + z1
cross_list.append(cross_point)
#----------結像位置取得ここまで----------
#----------光線プロットここから----------
fig = plt.figure()
plt.clf()
for y_optics, z_optics in zip(y_list, z_list):
plt.plot(z_optics, y_optics, color="red", lw=0.5)
#----------結像位置プロットここから----------
for point in cross_list:
plt.annotate("", xy=[point, 2], xytext=[point, 7], arrowprops=dict())
#----------結像位置プロットここまで----------
#----------焦点距離取得&プロットここから----------
position = 0
for optics in path:
optics_position = optics.B
position = position+optics_position
ffl = optics.frontFocalLength()
bfl = optics.backFocalLength()
if ffl != None and bfl != None:
plt.scatter(position+ffl, 0, color="black", s=5)
plt.scatter(position-bfl, 0, color="black", s=5)
#----------焦点距離取得&プロットここまで----------
plt.xlabel("Distance")
plt.ylabel("Height")
plt.show()
#----------光線プロットここまで----------
実行結果

この図でまだ表現できていないのがレンズ位置で、二つの焦点の真ん中にあるのですが、何も表示されていません。
光路のプログラムを書いている本人は分かるのですが、これでは他の人に見せた時にはレンズ位置は分かりません。
ということで今回はレンズ位置を表示するよう、またその際にレンズの引数としてアパチャーサイズを指定できることから、アパチャーサイズの取得方法を紹介します。
それでは始めていきましょう。
アパチャーサイズの取得方法
まずアパチャーサイズの取得方法としては、「path = ImagingPath()」で光学系を作成した後、for文を使って書く光学系を取得します。
そしてそれぞれの光学系に対して「.apertureDiameter」とします。
from raytracing import *
import matplotlib.pyplot as plt
path = ImagingPath()
path.append(Space(d=50))
path.append(Lens(f=10, diameter=5))
path.append(Space(d=50))
for optics in path:
print(optics.apertureDiameter)
実行結果
inf
5
inf
ちなみにLens関数では「diameter」は必須の引数でないので、与えないこともできます。
その場合は「diameter」は「inf」、つまり無限大となります。
from raytracing import *
import matplotlib.pyplot as plt
path = ImagingPath()
path.append(Space(d=50))
path.append(Lens(f=10))
path.append(Space(d=50))
for optics in path:
print(optics.apertureDiameter)
実行結果
inf
inf
inf
ちなみに「.apertureDiameter」は「Aperture関数」にも用いることができます。
from raytracing import *
import matplotlib.pyplot as plt
path = ImagingPath()
path.append(Space(d=50))
path.append(Aperture(diameter=10))
path.append(Lens(f=10))
path.append(Space(d=50))
for optics in path:
print(optics.apertureDiameter)
実行結果
inf
10
inf
inf
レンズ位置の図示の方法
図にレンズ位置を表示するには、前のプログラムのこちらの部分を改変していきます。
position = 0
for optics in path:
optics_position = optics.B
position = position+optics_position
ffl = optics.frontFocalLength()
bfl = optics.backFocalLength()
if ffl != None and bfl != None:
plt.scatter(position+ffl, 0, color="black", s=5)
plt.scatter(position-bfl, 0, color="black", s=5)
レンズ位置は光線の集まる位置と同じく「plt.annotate()」を用いますが、矢印の形を変えて両矢印(<->)を使ってみます。
またその際にレンズのサイズが指定されている場合はその値に、指定されていない場合はYの値の最大値、最小値の何割か(今回は5割)とします。
指定されていない場合の矢印の値を計算するためまずは「ylim_min, ylim_max = plt.ylim()」で図のYの値の最大値、最小値を取得します。
グラフの最大値、最小値の取得方法はこちらの記事で紹介していますので、よかったらどうぞ。

そして各光学系の焦点を取得する際に同時にサイズも取得します。
その後、レンズのサイズが「inf」の場合はグラフの最大値、最小値の何割かを表示するレンズのサイズとし、それ以外、つまり指定されている場合はそのサイズでグラフ上に図示するようにします。
from raytracing import *
import matplotlib.pyplot as plt
path = ImagingPath()
path.append(Space(d=50))
path.append(Lens(f=10, diameter=5))
path.append(Space(d=50))
angle_list = np.linspace(-10, 10, 21)
#----------位置、角度情報取得ここから----------
y_list = []; z_list = []; theta_list = []
for angle in angle_list:
ray = Ray(y=0, theta=np.radians(angle))
trace = path.trace(ray)
y_optics = []; z_optics = []; theta_optics = []
for data in trace:
y_optics.append(data.y)
z_optics.append(data.z)
theta_optics.append(data.theta)
y_list.append(y_optics)
z_list.append(z_optics)
theta_list.append(theta_optics)
#----------位置、角度情報取得ここまで----------
#----------結像位置取得ここから----------
cross_list = []
for y_ray, z_ray in zip(y_list, z_list):
z1 = z_ray[-2]; z2 = z_ray[-1]
y1 = y_ray[-2]; y2 = y_ray[-1]
cross = -y1*(z2-z1)/(y2-y1)
cross_point = cross + z1
cross_list.append(cross_point)
#----------結像位置取得ここまで----------
#----------光線プロットここから----------
fig = plt.figure()
plt.clf()
for y_optics, z_optics in zip(y_list, z_list):
plt.plot(z_optics, y_optics, color="red", lw=0.5)
#----------結像位置プロットここから----------
for point in cross_list:
plt.annotate("", xy=[point, 2], xytext=[point, 7], arrowprops=dict())
#----------結像位置プロットここまで----------
ylim_min, ylim_max = plt.ylim()
#----------焦点距離取得&プロットここから----------
position = 0
for optics in path:
optics_position = optics.B
position = position+optics_position
ffl = optics.frontFocalLength()
bfl = optics.backFocalLength()
dia = optics.apertureDiameter
if ffl != None and bfl != None:
plt.scatter(position+ffl, 0, color="black", s=5)
plt.scatter(position-bfl, 0, color="black", s=5)
if dia == float(inf):
plt.annotate("", xy=[position, 0.5*ylim_min], xytext=[position, 0.5*ylim_max], arrowprops=dict(arrowstyle='<->'))
else:
plt.annotate("", xy=[position, -dia/2], xytext=[position, dia/2], arrowprops=dict(arrowstyle='<->'))
#----------焦点距離取得&プロットここまで----------
plt.xlabel("Distance")
plt.ylabel("Height")
plt.show()
#----------光線プロットここまで----------
実行結果

図示することができましたが、実はこの方法まだ欠点があります。
レンズの直径を指定した場合で、光線がその直径に入らない場合、それ以降は光線が計算されないため図に表示されず、光線が止まった感じになってしまいます。
from raytracing import *
import matplotlib.pyplot as plt
path = ImagingPath()
path.append(Space(d=50))
path.append(Lens(f=10, diameter=5))
path.append(Space(d=50))
angle_list = np.linspace(-10, 10, 7)
#----------位置、角度情報取得ここから----------
y_list = []; z_list = []; theta_list = []
for angle in angle_list:
ray = Ray(y=0, theta=np.radians(angle))
trace = path.trace(ray)
y_optics = []; z_optics = []; theta_optics = []
for data in trace:
y_optics.append(data.y)
z_optics.append(data.z)
theta_optics.append(data.theta)
y_list.append(y_optics)
z_list.append(z_optics)
theta_list.append(theta_optics)
#----------位置、角度情報取得ここまで----------
#----------結像位置取得ここから----------
cross_list = []
for y_ray, z_ray in zip(y_list, z_list):
z1 = z_ray[-2]; z2 = z_ray[-1]
y1 = y_ray[-2]; y2 = y_ray[-1]
cross = -y1*(z2-z1)/(y2-y1)
cross_point = cross + z1
cross_list.append(cross_point)
#----------結像位置取得ここまで----------
#----------光線プロットここから----------
fig = plt.figure()
plt.clf()
for y_optics, z_optics in zip(y_list, z_list):
plt.plot(z_optics, y_optics, color="red", lw=0.5)
#----------結像位置プロットここから----------
for point in cross_list:
plt.annotate("", xy=[point, 2], xytext=[point, 7], arrowprops=dict())
#----------結像位置プロットここまで----------
ylim_min, ylim_max = plt.ylim()
#----------焦点距離取得&プロットここから----------
position = 0
for optics in path:
optics_position = optics.B
position = position+optics_position
ffl = optics.frontFocalLength()
bfl = optics.backFocalLength()
dia = optics.apertureDiameter
if ffl != None and bfl != None:
plt.scatter(position+ffl, 0, color="black", s=5)
plt.scatter(position-bfl, 0, color="black", s=5)
if dia == float(inf):
plt.annotate("", xy=[position, 0.5*ylim_min], xytext=[position, 0.5*ylim_max], arrowprops=dict(arrowstyle='<->'))
else:
plt.annotate("", xy=[position, -dia/2], xytext=[position, dia/2], arrowprops=dict(arrowstyle='<->'))
#----------焦点距離取得&プロットここまで----------
plt.xlabel("Distance")
plt.ylabel("Height")
plt.show()
#----------光線プロットここまで----------
実行結果

ちゃんとした解決方法は次回に回しますが、とりあえずは光線の数を増やすことでレンズに入る光線に関しては図に表示されるようになります。
from raytracing import *
import matplotlib.pyplot as plt
path = ImagingPath()
path.append(Space(d=50))
path.append(Lens(f=10, diameter=5))
path.append(Space(d=50))
angle_list = np.linspace(-10, 10, 21)
#----------位置、角度情報取得ここから----------
y_list = []; z_list = []; theta_list = []
for angle in angle_list:
ray = Ray(y=0, theta=np.radians(angle))
trace = path.trace(ray)
y_optics = []; z_optics = []; theta_optics = []
for data in trace:
y_optics.append(data.y)
z_optics.append(data.z)
theta_optics.append(data.theta)
y_list.append(y_optics)
z_list.append(z_optics)
theta_list.append(theta_optics)
#----------位置、角度情報取得ここまで----------
#----------結像位置取得ここから----------
cross_list = []
for y_ray, z_ray in zip(y_list, z_list):
z1 = z_ray[-2]; z2 = z_ray[-1]
y1 = y_ray[-2]; y2 = y_ray[-1]
cross = -y1*(z2-z1)/(y2-y1)
cross_point = cross + z1
cross_list.append(cross_point)
#----------結像位置取得ここまで----------
#----------光線プロットここから----------
fig = plt.figure()
plt.clf()
for y_optics, z_optics in zip(y_list, z_list):
plt.plot(z_optics, y_optics, color="red", lw=0.5)
#----------結像位置プロットここから----------
for point in cross_list:
plt.annotate("", xy=[point, 2], xytext=[point, 7], arrowprops=dict())
#----------結像位置プロットここまで----------
ylim_min, ylim_max = plt.ylim()
#----------焦点距離取得&プロットここから----------
position = 0
for optics in path:
optics_position = optics.B
position = position+optics_position
ffl = optics.frontFocalLength()
bfl = optics.backFocalLength()
dia = optics.apertureDiameter
if ffl != None and bfl != None:
plt.scatter(position+ffl, 0, color="black", s=5)
plt.scatter(position-bfl, 0, color="black", s=5)
if dia == float(inf):
plt.annotate("", xy=[position, 0.5*ylim_min], xytext=[position, 0.5*ylim_max], arrowprops=dict(arrowstyle='<->'))
else:
plt.annotate("", xy=[position, -dia/2], xytext=[position, dia/2], arrowprops=dict(arrowstyle='<->'))
#----------焦点距離取得&プロットここまで----------
plt.xlabel("Distance")
plt.ylabel("Height")
plt.show()
#----------光線プロットここまで----------
実行結果

ということで次回はraytracingライブラリでレンズに入らなかった光線を除外した光線図を描く方法を紹介します。
ではでは今回はこんな感じで。
コメント