GoogleColab によるpythonで行う太陽電池に使用する反射防止膜の光学シミュレーター

先日、凸版印刷勤務の当研究室のOBと色々やりとりをしておりました。

社会人インタビューvol.9。総合印刷会社(品質保証)編

滋賀と反射防止フィルムを満喫しているようで安心している所です。私も経験がありますが、東京から離れて生活すると仕事、プライベート含めて様々な人に支えられながら生活できているんだな~と改めて実感すると思いますので日々成長しているようで頼もしく思います。

外光の反射を遮断して、極力ディスプレイの透過光を視認するためにディスプレイの最表面に使用される反射防止フィルムですが、これには結構高度な光学設計がされております。数nmオーダで膜厚を制御して反射率やら透過光をコントロールしております。マクスウェルの方程式から派生する多層膜における電磁波の反射と透過メカニズムは、ポインティングベクトルやらフレネル係数やら用いてモデル化されております。

反射防止フィルムに少しでも興味がわけば以下の書籍が参考になると思います。

————-
プラズモニクス―基礎と応用
https://bookclub.kodansha.co.jp/product?item=0000147833

————-

ただ反射光と透過光を制御しているだけと思われがちですが、ディスプレイ技術以外にも眼鏡レンズに反射防止フィルムを適用することで、視界を改善し、目の疲れを軽減できます。また、カメラレンズに使えば画像品質を向上させることも可能であり、自動車のフロントガラスやサイドウィンドウに適用することで、運転者の視界を改善し、事故リスクを軽減できます。

そして、何より反射防止フィルムを太陽電池に貼り付け、太陽電池の光学特性を最適化し、エネルギー変換効率を向上させることはSDGs的にメリットがあります!

単純なようで応用が広い、そんな反射防止フィルムの光学シミュレーターについて今回は簡単に紹介してみようと思います。今回も研究室でよく紹介するgoogle colabで行いますので、興味が湧いたら、是非実施してみるといいでしょう。

以下のコードが太陽電池に反射防止フィルムを適用するための簡単な光学シミュレーターの例です。透過行列法:TMM (Transfer Matrix Method) を使って簡単に反射率と透過率を計算することが可能となります。

まずは、必要なライブラリをインストールします。

!pip install numpy
!pip install scipy
!pip install matplotlib

次に、新しいセルに以下のコードを貼り付けて、シミュレーションのために必要な関数を定義します。s波とかp波とかは電子システム工学科のメンバーならすぐ理解できるはずです。

import numpy as np
import matplotlib.pyplot as plt

def fresnel_coefficients(theta, n1, n2):
    theta_t = np.arcsin(n1 * np.sin(theta) / n2)
    r_s = (n1 * np.cos(theta) - n2 * np.cos(theta_t)) / (n1 * np.cos(theta) + n2 * np.cos(theta_t))
    r_p = (n1 * np.cos(theta_t) - n2 * np.cos(theta)) / (n1 * np.cos(theta_t) + n2 * np.cos(theta))
    t_s = 1 + r_s
    t_p = 1 + r_p
    return r_s, r_p, t_s, t_p

def transfer_matrix_method(layers, theta, wavelengths):
    R = np.zeros_like(wavelengths)
    T = np.zeros_like(wavelengths)

    for i, wavelength in enumerate(wavelengths):
        n = [layer["n"](wavelength) for layer in layers]
        d = [layer["d"] for layer in layers]

        M = np.identity(2)
        for j in range(1, len(layers) - 1):
            n_j, n_j1 = n[j], n[j + 1]
            d_j = d[j]
            theta_j = np.arcsin(n[0] * np.sin(theta) / n_j)
            theta_j1 = np.arcsin(n_j * np.sin(theta_j) / n_j1)
            delta = 2 * np.pi * n_j * d_j * np.cos(theta_j) / wavelength

            M_j = np.array([[np.cos(delta), 1j * np.sin(delta) / (n_j * np.cos(theta_j))],
                           [1j * n_j * np.sin(delta) * np.cos(theta_j), np.cos(delta)]])
            M = np.dot(M, M_j)

       r_s, r_p, t_s, t_p = fresnel_coefficients(theta, n[0], n[-1])
       M = np.dot(M, np.array([[t_s, 0], [0, t_p]]))
       M = np.linalg.inv(M)

       r_s, r_p, t_s, t_p = fresnel_coefficients(theta, n[-1], n[0])
       M = np.dot(M, np.array([[t_s, 0], [0, t_p]]))

       r = np.abs(M[1, 0] / M[0, 0])
       t = 1 / np.abs(M[0, 0])

       R[i] = r ** 2
       T[i] = t ** 2

    return R, T

def plot_reflectance_transmittance(wavelengths, R, T):
    plt.figure()
    plt.plot(wavelengths, R, label='Reflectance')
    plt.plot(wavelengths, T, label='Transmittance')
    plt.xlabel('Wavelength (nm)')
    plt.ylabel('Fraction')
    plt.legend()
    plt.show()

wavelengths = np.linspace(300, 800, 500)

# 空気、反射防止フィルム (シリコン窒化物)、太陽電池 (シリコン) の屈折率データ
n_air = 1
n_si3n4 = 2.1
n_si = 3.5

# 層構造の定義
layers = [
    {"n": lambda wl: n_air, "d": 0},
    {"n": lambda wl: n_si3n4, "d": 100},
    {"n": lambda wl: n_si, "d": 0},
]

theta = np.radians(8) # 入射角 (8°)
R, T = transfer_matrix_method(layers, theta, wavelengths)
plot_reflectance_transmittance(wavelengths, R, T)

最後に、太陽電池の反射防止フィルムをシミュレーションするための設定を行い、結果をプロットします。

今回は反射防止フィルムとしてシリコン窒化物 (Si3N4) を使用し、厚さを 100 nm に設定した太陽電池のシミュレーションを行いました。外は空気で内部はシリコン(太陽電池)になっています。光の入射角は 8° と設定した結果が以下のようになります。

もちろん、実際の現場のメンバーからすれば、こんな理想的な3層構造ではありませんし、材料も違うし、厚さも均一にはなりません。ただ、これを使って実際にものを扱っているエンジニアのノウハウで色々影響因子を追加していくことにより、シミュレーターが一気に精度を増していきます。これにはやはり数年の経験が必要になってくると思います。

以上、このシミュレーターにより、異なる反射防止フィルム材料や厚さを試すことで、太陽電池の性能を評価できます。ただ、毎回数値を手打ちして結果を比較するのも非常にあれなので、せっかくなら最適化するプログラムも組んで考えていきましょう!

from scipy.optimize import minimize

def optimize_AR_coating(layers, theta, wavelengths):
    def objective(x):
        layers[1]["n"] = lambda wl: x[0]
        layers[1]["d"] = x[1]
        R, _ = transfer_matrix_method(layers, theta, wavelengths)
        return np.mean(R)

    initial_guess = [2.1, 100]
    bounds = [(1.0, None), (0, None)] # 屈折率は1以上、膜厚は0以上
    result = minimize(objective, initial_guess, method='L-BFGS-B', bounds=bounds)
    return result.x

optimal_n, optimal_d = optimize_AR_coating(layers, theta, wavelengths)
print(f"Optimal refractive index: {optimal_n:.4f}")
print(f"Optimal thickness (nm): {optimal_d:.4f}")

# 最適化された反射防止膜の層構造を定義
optimized_layers = [
    {"n": lambda wl: n_air, "d": 0},
    {"n": lambda wl: optimal_n, "d": optimal_d},
    {"n": lambda wl: n_si, "d": 0},
]

R_opt, T_opt = transfer_matrix_method(optimized_layers, theta, wavelengths)
plot_reflectance_transmittance(wavelengths, R_opt, T_opt)

このコードでは、最適化された反射防止膜の屈折率が1以上に制約され、膜厚が0以上に制約されます。これにより、物理的に実現可能な範囲での最適化が行われます。これにより、ある程度の目安はわかってきますので、これを用いて細かい調整を行えば、比較的短時間で反射防止フィルムの設定が可能になります。まあ、今回のケースでは透過率がいまいちですが、、、

シミュレータと実験の往復でものづくりを進めていくと、理論と経験がスパイラル的にレベルアップしていきますのでおすすめです。電子システム工学科のメンバーも是非実施してみてください。

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)