光学薄膜設計ソフトの設計 その30 - 薄膜を表すオブジェクトの設計 [考え中 - 光学薄膜設計]
えー、まっ、そのー、一億三千万の、日本国民がですね、三十七万七千八百三十五平方キロメートルという日本にですね、暮らしとるわけですよ!?いや、すべってるがな。スタック深さ1なのでなにをやっていたかすっかり忘れてしまった。前回、といってももう1ヶ月近く前、光学薄膜設計用の計算エンジンの具体的なオブジェクトの設計を始めて、計算の中心になるOTFLayerオブジェクトの実装方針を決めた。その続きを考えようと思う。
OTFSnellCoefficient
まず、OTFLayerで使っているスネル係数のことをちょっと。
これは入射角と物理的には同じ意味だけど、ちょっとだけ計算をまとめることができるのでひとつのクラスにした。
このinterfaceは
@interface OTFSnellCoefficient : OTFDependedVariable { OTFVariable *iIndex; OTFVariable *angle; } - (id)initWithVariableRIndex:(id)iIndexVar andAngle:(id)angleVar; - (complex)cosValueForReflactiveIndex:(complex)rIndex; @endというようなものにする。ほとんどOTFDependedVariableと同じなんだけど入射側の屈折率オブジェクトと入射角変数を保持して、スネル係数 の値を計算する。
しかし、OTFLayerにとってこの値が必要なのではなく、さらに自分の媒質mでの屈折角のcosの値
が必要なだけなので、OTFSnellCoefficientオブジェクトに自分の媒質の屈折率の値を渡して計算してもらうのがcosValueForReflactiveIndex:メソッド。入射媒質の屈折率niは実数でなければならない(無限に厚い吸収のある媒質から薄膜へは光は届かないので計算できない)が、自分の媒質が吸収を持つ場合や、nm<niで入射角が大きくて全反射の条件になる場合は式-5.2は複素数になることに注意して計算の実装をする。
式-5.2の値は入射角が変更されなければ値は変わらないので、この値はキャッシュする方が効率的である。こないだ考えたOTFDependedVariableの実装では、どの変数に変更があったかまではわからないので入射角が変わっていなくても他の変数が変われば再計算されてしまう。
ここんとこが効率に大きく影響するなら考え直すことにする。
具体的な実装はOTFMergableとして動作させるためのコード以外は
- (void)updateValue { double ang = [angle realValue]; if (ang != 0.0) { double ind = [iIndex realValue]; val = (double complex)(ind * sin(ang)); } else val = 0.0; } - (complex)cosValueForReflactiveIndex:(double complex)rIndex { complex ret; if (isPureReal(rIndex)) { double rind = creal(rIndex); double snel = creal(val); if (snel == 0.0) ret = (double complex)rind; else { double insidesqrt = rind * rind - snel * snel; if (insidesqrt > 0.0) ret = (double complex)sqrt(insidesqrt); else ret = sqrt(insidesqrt) * I; } } } else { double snel = creal(val); if (snel == 0.0) ret = rIndex; else ret = csqrt(rIndex * rIndex - snel * snel); } return ret; }みたいな感じにする。途中に何度か現れるdouble complexへのキャストはなくてもいい。単に未来の自分への注意。
場合分けがあるのは計算量が少ない場合を優先的に計算するため
- 垂直入射かそうでないか
- 渡された屈折率が実数か複素数か
OTFFilmComposition
OTFFilmCompositionはOTFLayerの配列と、薄膜の両側の媒質を保持して、層の特性マトリクスから特性アドミタンスを計算するオブジェクト。
また、このオブジェクトはmergableである必要(OTFMergableのサブクラス)はないけど、変数の変化によって値を更新することは必要なのでOTFSuccessorのサブクラスにする。まったく変数の値を変更しない再計算でないかぎり、特性アドミタンスの値は計算し直しになって、値が要求されたらいつも計算し直すのと変わらないので、わざわざOTFSuccessorのサブクラスにする必要はないけど、まあ、せっかくだから。
どうやって初期化するか、というのは結構悩ましい。とりあえずinterfaceは
@interface OTFFilmComposition : OTFSuccessor { OTFOpticalCharateristics *oChar; OTFRefractiveIndex *baseMedium; NSMutableArray *layers; // array of OTFLayer ordered from base to top(outer) OTFRefractiveIndex *outerMedium; OTFSnellCoefficient *snellCoef; admittanceVector advector; } - (id)initWithOpticalCharacteristics:(OTFOpticalCharateristics *)oc baseIndexMedium:(NSString *)baseMediumName andOuterIndexMedium:(NSString *)outerMediumName;としよう。OTFLayerCompositionを確保しているOTFOpticalCharacteristicsから波長、入射角、偏光の変数をもらって、OTFLayerそれぞれに渡してやる必要がある。入射角は前節のOTFSnellCoefficientを作って渡す。
従って初期化はOTFOpticalCharateristicsへのポインタと薄膜の上下の媒質の名前をもらうことにする。上下の媒質を最適化の変数にすることはないはずなので、これは変数オブジェクトではなく、単に名前をもらって自前で生成することにする。
初期化が終わると薄膜のないふたつの媒質の境界を表すことになる。
これに層をひとつずつ追加するメソッドを書くことにする。つまり
- (void)addNewLayerWithThicknessVariable:(OTFVariable *)thicknessVar andRefractiveIndex:(OTFRefractiveIndex *)rIndex;これが呼ばれると、OTFLayerを作って必要な設定をして、NSMutableArrayであるlayersに追加する。屈折率の波長変数の設定はこのメソッドを呼ぶ側の責任で行うことにする。どうせ、このメソッドを呼ぶのはOTFOpticalCharacteristicsだけなので大きな問題はない。
OTFOpticalCharacteristics
OTFOpticalCharacteristicsはOTFFilmCompositionが保持しているアドミタンスから具体的な反射率や透過率、位相等を計算する。このクラスが外部とのインターフェイスになって、そのまえのOTFFilmComposition、OTFLayer、OTFSnellCoefficientなどは外部から直接生成したり、値を変更したりということはない。
interfaceは
@interface OTFOpticalCharateristics : OTFSuccessorで、波長、入射角、変更のみっつの変数は自分で生成して、init...で渡された媒質の名前を使ってOTFFilmCompositionを生成する。{ OTFVariable *lambda; OTFVariable *iAngle; OTFVariable *polar; OTFFilmComposition *compo; admittanceVector *advec; } - (id)initWithbaseMedium:(NSString *)baseMedium andOuterMedium:(NSString *)outerMedium;
そして別のカテゴリを作って
@interface OTFOpticalCharateristics (OTFComputables) - (complex)reflectanceCoefficient; - (complex)transmittanceCoefficient; - (double)reflectance; - (double)transmittance; - (double)absorption; - (double)reflectedPhase; - (double)reflectedAmplitude; - (double)transmittedAmplitude; - (unsigned int)numberOfComputables; - (NSString *)descriptionOfComputableIndexAt:(int)n; - (SEL)computableIndexAt:(int)n; - (SEL)computableForDescription:(NSString *)descr; - (NSString *)descriptionForComputable:(SEL)selector; @endで、光学特性のうち計算可能なものを列挙する。OTFOpticalCharateristicsを使って計算するときはcomputableIndexAt:かcomputableForDescription:メソッドを使ってセレクタを得て、OTFOpticalCharateristicsから計算結果をもらうようにする。
こうすることで、ユーザに対してdescriptionを表示して計算の内容を選択してもらい、計算可能な特性を追加したときにも、他のクラスを書き換えずにすむようにする。
実装は数学の通りなので省略する。細かい話をごちゃごちゃとしすぎた。次回はもうちょっと大づかみな話にしよう。
コメント 0