raytracing
前回、raytracingライブラリでLensとThickLensの使い方と焦点の取得方法を紹介しました。

今回はThickLens関数を使ってThorlabs社で販売しているレンズを再現してみようと思います。
ちなみにThorlabs社のWebサイトはこちらです。

今回は両凸レンズとして「LB1761」、平凸レンズとして「LA2024」、両凹レンズとして「LD2297」、非球面コンデンサレンズとして「ACL7560U」、アクロマティック複レンズとして「ACN254-100-A」を再現してみます。





それでは始めていきましょう。
両凸レンズ
最初は両凸レンズで、例として「LB1761」を再現していきます。
Thorlabs社のウェブサイトにはレンズの焦点や曲率、厚さなどの情報が分かりやすく記載されていますので、その情報を用いて再現していきます。
そしてその確認方法としては、Webサイトに記載の焦点距離と再現したレンズの焦点距離を比較することで正しく再現できているかを確認します。
両凸レンズ「LB1761」に関して、Thorlabs社のウェブサイトにはこの様なレンズ情報が記載されています。
Diameter | Focal Length | Diopter | Radius of Curvature | Center Thickness | Edge Thickness | Back Focal Length |
1” | 25.4 mm | +39.4 | 24.5 mm | 9.0 mm | 1.9 mm | 22.2 mm |
また使用するガラス材はN-BK7で屈折率は「1.517」と記載されています。
再現のために用いる値は「屈折率」、「Radius of Curvature」、「Center Thickness」で確認で用いる値は「Back Focal Length」です。
ThickLens関数の使い方をおさらいすると「ThickLens(n=屈折率, R1=入射側の曲率, R2=出射側の曲率, thickness=厚さ)」です。
この関数にThorlabsのレンズ情報を当てはめると「ThickLens(n=屈折率, R1=Radius of Curvature, R2=-1 * Radius of Curvature, thickness=Center Thickness)」となります。
入射側と出射側の曲率は値は同じですが、正負の符号が違うことを注意してください。
from raytracing import *
Lens = ThickLens(n=1.517, R1=24.5, R2=-24.5, thickness=9.0)
print(Lens.frontFocalLength())
print(Lens.backFocalLength())
実行結果
22.1121576502253
22.1121576502253
Webサイトの「Back Focal Length」の値が「22.2 mm」で、再現したレンズの焦点距離が「22.11」ですのでほぼ再現できたことが確認できました。
これを図として表示していきますが、レンズ直径をここで入れておくと図の精度が上がるので、入れておくのをお勧めします。
from raytracing import *
path = ImagingPath()
path.append(Space(d=20))
path.append(ThickLens(n=1.517, R1=24.5, R2=-24.5, thickness=9.0, diameter=25.4))
path.append(Space(d=50))
path.display(ObjectRays(diameter=10, H=3, T=5))
実行結果

平凸レンズ
次に平凸レンズで、「LA2024」を例に再現していきます。
LA2024のレンズの情報はこんな感じです。
Diameter | Focal Length | Diopter | Radius of Curvature | Center Thickness | Edge Thickness | Back Focal Length |
2 mm | 4.0 mm | +250.0 | 3.1 mm | 1.0 mm | 0.8 mm | 3.44 mm |
また屈折率はガラス材としてN-SF11を用いているため、「1.785」と高めです。
今回も使うデータとしては「屈折率」、「Radius of Curvature」、「Center Thickness」で、確認のために用いる値は「Focal Length」と「Back Focal Length」です。
平凸レンズの場合は、それぞれの面での曲率が異なることから、それぞれの面での焦点距離が異なります。
そのそれぞれの焦点距離が「Focal Length」と「Back Focal Length」というわけです。
気をつけることは平な面の曲率を大幅に大きくすることで、例えば10000とかにします。
from raytracing import *
Lens = ThickLens(n=1.785, R1=3.1, R2=10000, thickness=1.0, diameter=2.0)
print(Lens.frontFocalLength())
print(Lens.backFocalLength())
実行結果
3.950269115561224
3.389722238426991
レンズのデータとして「Focal Length」は「4 mm」、「Back Focal Length」は「3.44 mm」ですのでほぼ再現できました。
図を表示してみるとこんな感じです。
from raytracing import *
path = ImagingPath()
path.append(Space(d=2))
path.append(ThickLens(n=1.785, R1=3.1, R2=10000, thickness=1.0, diameter=2.0))
path.append(Space(d=5))
path.display(ObjectRays(diameter=1, H=3, T=5))
実行結果

両凹レンズ
両凹レンズの例として「LD2297」を再現してみます。
Diameter | Focal Length | Diopter | Radius of Curvature | Center Thickness | Edge Thickness | Back Focal Length |
1” | -25.0 mm | -40.0 | -39.6 mm | 3.0 mm | 7.2 mm | -25.6 mm |
屈折率はガラス材としてN-SF11を用いているため、「1.785」と高めです。
再現の仕方は両凸レンズと同じで「屈折率」、「Radius of Curvature」、「Center Thickness」を再現のために使います
また確認のために用いる値は「Back Focal Length」です。
ただし両凸レンズの場合とは曲率の符号が変わることに注意してください。
from raytracing import *
Lens = ThickLens(n=1.785, R1=-39.6, R2=39.6, thickness=3.0)
print(Lens.frontFocalLength())
print(Lens.backFocalLength())
実行結果
-25.63621345297275
-25.63621345297275
図示するとこんな感じです。
from raytracing import *
path = ImagingPath()
path.append(Space(d=5))
path.append(ThickLens(n=1.785, R1=-39.6, R2=39.6, thickness=3.0, diameter=25.4))
path.append(Space(d=25))
path.display(ObjectRays(diameter=3, H=3, T=5))

非球面レンズ
非球面レンズの例として「ACL7650U」を再現してみます。
Diameter | Focal Length | Clear Aperture | Back Focal Length | Numerical Aperture | Center Thickness | Edge Thickness |
75.0 mm | 60.0 mm | >67.5 | -39.6 mm | 0.61 | 30.0 mm | 2.3 mm |
ガラス材として「B270 Optical Crown Glass」を用いていますが、ThorlabsのWebサイト上には屈折率の値が表記されていないようなので、一般的な値「1.515」を用います。
そして非球面レンズは、片側は平らなので一つの面の曲率として大幅に大きな値「10000」を用いますが、もう一つの面の曲率である「Radius of Curvature」の記載がありません。
そのため焦点距離に合う様な「R1」を数値を色々変えて探っていきます。
「ACL7650U」の場合、R1=31で大体レンズのデータと合う焦点距離が得られました。
from raytracing import *
#ACL7560
Lens = ThickLens(n=1.515, R1=31, R2=10000, thickness=30.0, diameter=75.0)
print(Lens.frontFocalLength())
print(Lens.backFocalLength())
実行結果
60.381165677170415
40.47639347281263
ただし毎回レンズのデータと合う様な曲率を探すのは大変なので、関数を作成してみました。
from raytracing import *
import numpy as np
R1_range = np.arange(0, 100, 0.01)
R2_range = [10000]
n = 1.515
f1 = 60
f2 = 40
thickness = 30
def f2R(n, R1_range, R2_range, f1, f2, thickness):
best_R1 = 0.1
best_R2 = 0.1
for R1 in R1_range:
for R2 in R2_range:
Lens_best = ThickLens(n=n, R1=best_R1, R2=best_R2, thickness=thickness)
best_f1 = Lens_best.frontFocalLength()
best_f2 = Lens_best.backFocalLength()
Lens = ThickLens(n=n, R1=R1, R2=R2, thickness=thickness)
Lens_f1 = Lens.frontFocalLength()
Lens_f2 = Lens.backFocalLength()
if abs(f1 - best_f1) > abs(f1 - Lens_f1) and abs(f2 - best_f2) > abs(f2 - Lens_f2):
best_R1 = R1
best_R2 = R2
return best_R1, best_R2
best_R1, best_R2 = f2R(n, R1_range, R2_range, f1, f2, thickness)
print(best_R1, best_R2)
Lens = ThickLens(n=n, R1=best_R1, R2=best_R2, thickness=thickness, diameter=75.0)
print(Lens.frontFocalLength())
print(Lens.backFocalLength())
実行結果
30.76 10000
59.912257696532436
40.00844041774839
屈折率やレンズの厚みの情報の他に、R1とR2の大体の範囲のリストを渡すとその中で一番近しいR1、R2を算出してくれます。
今回の場合、R1は「30.76」となり、焦点距離もほぼレンズのデータと合う値が得られました。
このデータを用い、図示してみるとこんな感じです。
from raytracing import *
path = ImagingPath()
path.append(Space(d=25))
path.append(ThickLens(n=1.515, R1=30.76, R2=1000, thickness=30, diameter=75))
path.append(Space(d=25))
path.display(ObjectRays(diameter=3, H=3, T=5))
実行結果

アクロマティック複レンズ
アクロマティック複レンズとは複数の屈折率や曲率の異なるレンズを貼り合わせて作ったレンズです。
今回は「ACN254-100-A」を例として再現してみます。
レンズのデータとしてはこんな感じです。
Diameter | fa | fb | R1 | R2 | R3 | tc1 | tc2 | te | Materials |
25.4 mm | -100.1 mm | -103.6 mm | -52.0 mm | 49.9 mm | 600 mm | 2.0 mm | 4.0 mm | 7.7 mm | N-BAK4/SF5 |
屈折率はガラス材がN-BAK4とSF5とのことなので、一般的な値「1.567」と「1.668」を使いましょう。
アクロマティック複レンズの場合は2つのレンズを貼り合わせているため、まずはデータを二つのレンズに分解します。
1つ目のレンズはR1が-52.0 mm、R2が49.9 mm厚みがtc1の2.0 mm、屈折率がN-BAK4の1.567となります。
2つ目のレンズはR1が1枚目のレンズのR2であるため49.9 mm、R2がR3の値を取り600 mm、厚みはtc2を取り4.0 mm、屈折率はSF5のため1.668です。
ここで問題なのが焦点距離の計算で、「Lens.frontFocalLength()」や「Lens.backFocalLength()」はあくまでもそれぞれのレンズの焦点距離です。
そのためアクロマティック複レンズ全体の焦点距離の計算には使えません。
そこで用いるのがABCD行列解析の結果です。
ということで試してみましょう。
from raytracing import *
path = ImagingPath()
path.append(Space(d=25))
path.append(ThickLens(n=1.567, R1=-52, R2=49.9, thickness=2, diameter=25.4))
path.append(ThickLens(n=1.668, R1=49.9, R2=600, thickness=4, diameter=25.4))
print(path)
path.append(Space(d=100))
path.display(ObjectRays(diameter=3, H=3, T=5))
実行結果
| 1.035 29.547 |
| |
| 0.010 1.252 |
f=-99.959

ABCD行列解析の結果で出てくる「f」はそこまでの光学系の焦点距離であるため、アクロマティック複レンズ単体で評価する場合はアクロマティック複レンズの焦点距離であると見なすことができます。
実際上の例ではカタログ値としての焦点距離が「-100.1」であるのに対し、再現したレンズの焦点距離が「-99.959」と算出され、ほぼ同じ値となりました。
これで大体レンズ自体の再現ができる様になったかと思います。
次回はraytracingでApertureやCurvedMirror、DielectricInterface、DielectricSlabを紹介します。
ではでは今回はこんな感じで。
コメント