写真レンズ解析プログラムとは
2020年9月2日に作成を開始した、Pythonによるプログラム。
プログラム作成目的
もともと以下の漠然としたニーズが(自分の中で)あった。
- 持っているレンズの性能くらいは(できれば他の人よりも)知っておきたい
- レンズに興味があっても、自分で買ったり作ったりして実験するにはハードルが高すぎる
- 写真レンズのデータは特許に記されているものの、解析は難しい
- これを解析するためのツールはピンからキリまであり、その幅が極端に大きい
- そもそもどんな機能が必要で何が出来れば嬉しいのか
従って勉強も兼ねて作ってしまえ!と思うのは妥当であった。
ここで上記のニーズ、そして素人レベルの技量によって生じた制約は以下のようになった。
- 当面は幾何光学による解析のみを行う
- 屈折面のみからなる共軸光学系を対象とする
- レンズ断面と光路図の描画
- 結像性能欠陥(収差)の評価
1つ目は技量による制約で、2つ目は写真用交換レンズの傾向として最低限満たすべき条件である。
当初は3つ目が主題だった。最近は4つ目にシフトしてきたが、3つ目に関係する課題は依然として残されている。
このページの目的
何をすればいいか分からなくなってきたので、
やってきたこと・やりたいことを一覧にし、今後の開発で何を優先すべきかに対する指標とする。
しかし冗長に書いてもうんざりなので、簡単な備忘録的まとめに留める。
いまできること
前提条件
パッケージ、レンズ要素、レンズデータ
パッケージ
- math
- numpy
- matplotlib
- tkinter
- openpyxl
- os
- threading
- glob
レンズ要素
屈折のみからなる共軸光学系のみを対象とする。反射や軸外しは想定外。
球面・非球面に対応。ただし非球面は多項式近似のみで、係数のデータを要する。
絞りは1つのみ。手動で元データをいじくり、F値を変える。
初面が凹面だと計算できない可能性がある。魚眼レンズなどの画角が180度を超えるもの(半画角が90度を超えるもの)は対象外。
レンズデータ
xlsx形式のExcel読み込み。規定フォルダ内に、レンズ1つあたり1つのExcelファイルを正しく作れば、プログラムが自動で後述の解析を行える。
必要なデータは以下の通り。
- 曲率
- 非球面の場合は各種の係数
- レンズ間隔
- 屈折率
- 分散
- レンズ有効径
- 絞り直径
- 絞り位置
- バックフォーカス
- センサー高さ
センサー高さ、バックフォーカスは自分で設定する必要がある。実は古い特許には書いていない場合も多い。
データ上、物界・像界の屈折率は何でも入れられるようになっているが、光線追跡の初期条件を設定するプログラムが空気の1.0以外に対応していないので、これ以外を入れると光線追跡できなくなる可能性がある。従って実のところは1.0に限定。
絞りはレンズの一部ではなく「別の特殊部品」として計算しているため、絞り位置は初面からの距離で設定する。特許データには見られない形式なので、データ作成には注意を要する。
非球面の場合、係数を別のシートに記入する。次数に制限はないが、各次数に対して具体的な数値を入力する必要がある。
解析系
硝材の設定、光路図、収差図、その他の解析、データ保存
硝材の設定
色収差を計算するために、硝材(光学ガラスの種類)を設定する必要がある。
硝材は4社のデータに対応。ただし最近のデータのみで、過去のデータは無い。
特許にある屈折率と分散から、もっともらしいデータを自分で選択する。
光路図
レンズ断面と、センサーの中央・7割高さ・端に至る、主光線・上側マージナル光線・下側マージナル光線の描画。
収差図
- 中央・7割高さ・端におけるメリジョナル・サジタル横収差の描画
- 球面収差とOSC、M/Sの各非点収差、中心射影方式による像面湾曲を示す縦収差図
- 上記のそれぞれに対し、3つの波長をまとめて描画(色収差に相当)
その他の解析
以下は色収差に非対応だが、 * スポットダイアグラム(中央・7割高さ・端) * 幾何光学的MTF(10 LP/mm、30 LP/mmのM/Sそれぞれ)
データ保存
グラフは全てjpegかpngで保存可能。保存したい場所を選び、名前を設定することが可能。
硝材データは保存できず、毎回の計算で設定しなおす。
(特筆すべき)内部の数値計算系
初期条件設定・光路図、スポットダイアグラム、幾何光学的MTF
初期条件設定・光路図
計算したいExcelのデータファイルを選択しボタンを押すと、光路図の計算を開始する。
このとき、まず光線行列解析により、近軸的に以下を求める。
- 焦点距離
- 入射瞳半径
- 射出瞳半径
- 射出瞳位置
この数値は解析の基本となるので、解析中は保存される。ただし現行のプログラムでは表示されない。
光路図の計算は、センサーの中央・7割高さ・端それぞれにおいて以下のように行われる。
- 上で計算した射出瞳位置を狙ってセンサー側から主光線の逆光線追跡
- 主光線データを順方向に変換・保存
- 主光線データをもとに上下マージナル光線を計算・保存
- 主光線データをもとに左右マージナル光線を計算・保存
解析中、これら主光線と4本のマージナル光線のデータは常に保存され、収差図の基本として使われる。
スポットダイアグラム
まずレンズ初面の直前において、上で求めた主光線位置を中心に、タテヨコともに入射瞳直径の正方形領域を直交メッシュに区切る。
各格子点から主光線に平行な光線を出し、それがセンサーに交差する点をまとめて散布図に表示することでスポットダイアグラムを描画する。
幾何光学的MTF
スポットダイアグラムをフーリエ変換する。
今後やりたいこと
プログラム寄りなもの
計算速度
計算速度がボトルネックとなっているのが、スポットダイアグラムとMTF特性図の2つである。
特にMTFについては、現在の計算性能では信頼性のおける結果を得るのは不可能(時間を犠牲にするなら話は別である)。
以下に、最近実装した改善案とその結果を示す。即採用となった結果と、思いのほか性能が上がらなかった結果があり、興味深い内容となった。
最近行った改善
最近行った改善策では、
- 今まで1本の光線につき1回光線追跡の関数を使用していた
- 関数の呼び出しは内部の変数(特にレンズデータ)呼び出しも含むから、時間かかりそうだぞ
- 一気に複数の光線の初期条件を入れられないか?
- 行列(numpy配列)で計算できそうだ
- 非球面のとき光線とレンズの交点は近似で求める必要があるから、その段階だけは別々に計算しなきゃ
という手順(よりは紆余曲折あったが)を踏んで、確かに場合により高速化できた。以下、スポットダイアグラムの計算において同様の初期条件で計算した結果を示すと、
屈折面数 | うち非球面枚数 | レンズタイプ | 元の計算時間 [s] | 改造後の計算時間 [s] | 計算時間の比 |
---|---|---|---|---|---|
18 | 0 | 望遠 | 1.99 | 0.683 | 0.343 |
19 | 0 | 広角 | 3.44 | 0.680 | 0.198 |
18 | 1 | 広角 | 4.46 | 3.76 | 0.843 |
27 | 4 | 広角 | 10.9 | 14.2 | 1.30 |
ただし面倒だったので、データは1回の試行による。とはいえ毎回こんな傾向があるのは確かである。比を取って比較するのが適切かは置いておくとして、結果により以下のことが伺える。
- 球面しかないレンズは早い
- 改造は球面のみの広角レンズに特に効果的だった
- 非球面が1面でも入ると改善効果は薄くなる
- 屈折面も非球面数も多い場合、改造は裏目に出る
- 改造は屈折面数に関係ないので、時間増は非球面の近似計算に起因すると予想できる
- 余談だが、計算中に表示させるプログレスバーの動きが格段に良くなった
とすると、次に行うべきは近似計算の改善である。現行のプログラムでは収束の堅牢さと処理の単純さから二分法を選択している。ニュートン法では収束しない場合が散見されたため、Dekker法やBrent法などの堅牢かつ高速なプログラムを用いる必要がある。
Dekker法をまず簡単に組んで用いたところ、計算速度への効果は期待したほどではなかった。
屈折面数 | うち非球面枚数 | 二分法での計算時間 [s] | Dekker法での計算時間 [s] | 計算時間の比 |
---|---|---|---|---|
18 | 1 | 3.76 | 3.37 | 0.896 |
27 | 4 | 14.2 | 17.3 | 1.22 |
原因として挙げた仮定は、
- 大して反復回数が減少していないのではないか
- 処理(特に条件分岐)の複雑化が想定より大きく影響している
まず1つ目を調べたところ、二分法だと反復が最低25回、最大37回だった一方で、Dekker法では最低2~4回、最大11回と大幅に効率化されていることが判明した。
従って今後は条件分岐の効率化を求めることになる。
pythonファイルどうしの関係を見直す
プログラムの規模として、どうしても複数ファイル、複数クラスを横断するほかないが、
- どの関数が何を必要とし、何をreturnするのか
- 例外処理はどう行われ何がreturnされるのか
- 同一ファイル内にどのクラスを入れるか
- 同一クラス内にどの関数を入れるか
- つまり、関数をもっと細分化する必要は無いか
- 逆に一体化して良いものは無いか
といった基本的な部分がまだ固まっていない。より見やすいコードを目指したいし、これをおろそかにすると例外処理で沼にハマりそう。まずは上の2つから見直したい。
硝材の保存
いま、Excelファイルのシート1にレンズの基本データ、シート2に非球面データを入れている。そうすると、硝材データはシート3を新たに作成するのが濃厚な手段だ。
硝材データ案
つまりシートをこんな感じにする。
- 基本データ
- 非球面係数のデータ
- 硝材データ(New!)
ただ、硝材シートを新たに作るとなると問題が生じる。
今のところシート読み込みをシート名ではなくシートの順番(つまり配列のような形)で読み込ませているのだが、現状では球面のみでできたレンズ系に対して非球面のシート(つまりシート2)を要しない。このとき
- 基本データ
- 硝材データ
の2つで事足りるが、これでは硝材データを非球面データと勘違いして読み込んでしまうだろう。
従って改善策は以下の2つが考えられる。
- 空のシート2(ダミー非球面シート)を作る
- プログラム全体をシート名で読み込ませるよう変更する
Excel読み込みで使用しているopenpyxlは内部で勝手にシート番号をつけてくれる他、我々がつけたシート名でも読み込み可能なので、上記はどちらも達成できる。ただし前者だと無用なシートができるし、後者だと命名ミスで動かなくなることが有り得る。
吟味したいが、たぶんシート名読み込みになるだろう。
レンズ系の基礎
パワー配置
特許ではよく「第何レンズ~第何レンズを第1群とし...」といった表記がされる。設計においても、複数のレンズが集まった「群」をひとつの薄肉レンズとみなして初期設計する。
従って群というコンポーネントは非常に重要となる。これを解析するプログラムを含められないか。
コンポーネントの選択さえできれば、あとは光線行列解析で焦点距離や主点位置などが求められるので、計算はそう難しいことではない。
問題はおそらく選択する画面とか選択方法、あとは結果の表示だろう。tkinterの表・チェックボックス・プルダウンなどの機能を見比べる必要がある。
硝材の配置を可視化
硝材の配置がどうなっているかは素人目線で少し気になる。
屈折率の強いレンズとか、分散がおかしいレンズ(異常分散ガラス)がどこに配置されているかが一目で分かれば楽しいだろう。
これを実現する1つの案が、レンズ断面図を光軸上下で分け、上に屈折率、下に分散のカラーバー(数字が大きいほど色が濃くなるやつ)でレンズを塗りつぶす方法である。
あまり一般的ではないが、できれば面白いと思う。見やすくなるかは分からない。
初面凹面の対応
現在、光線の初期位置をレンズ頂点に接する平面としているため、もし初面が凹面だとレンズ内部から発光しているような様子になる。
考えられる改善方法は、初期位置を頂点からオフセットしておくものだ。ただしオフセット量を
- なにかの定数
- 凹面が前にせり出している量(サグ量)の最大値
とする2つの方法が考えられる。
実は開発初期、これを考慮して一つ目の方法を取っていた。ただ、定数を足し引きする計算の箇所がうまく管理できず、得られたデータがオフセットを含むか否かが判断しにくかったこともあり、現在は頂点の接平面となっている。
従って、どちらの方法を取るにせよ
- 欲しいデータはレンズ頂点基準か光線の初期位置基準か
- どこでオフセットを加えてどこで引くのか
はキッチリと押さえておく必要がありそうだ。ちなみに現行の光線追跡計算上、光線データはレンズ頂点を原点とするのが楽である。
収差関係
収差係数
収差係数といって、設計値と近軸光線追跡データの四則演算だけで収差量が評価できる指標がある。
これを計算して表にするボタンがあると嬉しい。
ただし収差係数の式は多岐に渡る。本国で有名なのはおそらく松居吉哉氏の『レンズ設計法』にある式だと思われる。一方、私が導出できたのは中川治平氏の『レンズ設計工学』にある式で、確か何かしらの定数で除するか否かという点で相違があった。片や3次収差論で世界的に有名なのはBerek氏の『レンズ設計の原理』で、ここでの式がどういうものだったかは覚えていない。
導出できていない式を、自習も兼ねたプログラムに実装するのは忍びない。一方で、敢えてマイノリティーな式で計算させるのも悩ましい。
おそらくカッチリ数式を表記したreadmeの作成は必要になるだろうが、加えて上記2、3パターンの選択形式とするべきか悩む。
歪曲シミュレーション
いま、既に歪曲収差を縦収差図の形で表示できる。しかし実際に格子状の物体がどう歪むかをシミュレーションできれば非常に便利だ。
想定しているのはレンズメーカーのシグマなどがポツポツと出しているような一般的な図で、理想的な格子と歪曲された格子を重ねて描くもの。
基準となる格子を設定する必要があるため、センサーサイズ、特に縦横比を設定する必要がありそうだ。また、格子の描画が簡単にできるものか調査する必要がある。
発展した光学
ここら辺から、聞きかじった知識でしか書けないレベル(難しいの)。ぶっちゃけ計算できなくてもいいかな(諦め)。
波面収差
光線ではなく波として捉え、収差を波面の乱れとして考える方法。
図示はできないが、以下に示すものの基礎となる。
点像分布関数
PSF(point spread function)と呼ばれるもの。計算するには、たぶん瞳関数も必要。
点光源がどのような輝度分布を持ってセンサーで結像するかを表していて、解析できれば嬉しい。
波動光学的MTF
より精密なMTF特性図。