2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[nannos]オープンソフトで試すRigorous Coupled Wave Analysis(RCWA) ~Blazed Gratingの光シミュレーション~

2
Last updated at Posted at 2026-03-23

はじめに

前回の記事ではRCWA(Fourier modal methodとも呼ばれる)のオープンソースのシミュレータnannosをご紹介しました。

nannosのサイトはこちら

今回はnannosを用いてブレーズド回折格子の透過・反射スペクトルをシミュレーションしてみたので、ご紹介します。

今回の計算対象

こちらが今回計算する構造です。
基板上にとげとげのグレーティング(ブレーズド回折格子)が形成された構造の透過率、反射率(及び各回折次数のスペクトル)のシミュレーションを実施します。

図1.png

以下が1周期分を切り出した誘電率分布です。
図2.png
RCWAでは斜目の傾斜構造をそのまま取り込んで計算することはできず、上の図のように階段近似して計算することになります。
今回は1次元周期のブレーズド回折格子で、
- 周期サイズは1 um
- 三角構造の高さ0.8 um, 底辺の長さ1 umとしました。
- 基板の屈折率は1. 5
- 三角構造の屈折率は2.0
- それ以外の媒質は空気に設定

計算するにあたり、
- グレーティングの奥行き方向に振動する電場で入射する場合をS偏光
- 周期方向に振動する電場で入社する場合をp偏光
としました。

シミュレーション結果

今回は計算に含めるハーモニクスの数(構造内のモード解析で含める逆格子ベクトルの数)を51として計算してみました。
こちらが回折光のスペクトルになります。
図3.png

続いてこちらが透過率・反射率のシミュレーション結果です。
図4.png

計算に用いたスクリプト

import numpy as np
import matplotlib.pyplot as plt
import nannos as nn

# ============================================================
# 1. 基本パラメータ
# ============================================================
period = 1.0
height = 0.8
nslices = 40

n_sup = 1.0
n_sub = 1.45
n_gr  = 2.0

eps_sup = n_sup**2
eps_sub = n_sub**2
eps_gr  = n_gr**2

# ---- ブレーズ設定
blaze_mode = "both"     # "right", "left", "both"
peak_pos  = 0.5
etched_groove = False

# 入射条件(上から)
theta_deg = 0.0
phi_deg   = 0.0

polarizations = {
    "P": 0.0,
    "S": 90.0,
}

wavelengths = np.linspace(1.3, 1.7, 61)

nh = 51
orders_to_plot = [-2, -1, 0, 1, 2]

Nx, Ny = 1024, 16
Ly = period

# ============================================================
# 2. Lattice
# ============================================================
lattice = nn.Lattice(
    [[period, 0.0], [0.0, Ly]],
    discretization=(Nx, Ny)
)
X, Y = lattice.grid
frac = (X / period) % 1.0

# ============================================================
# 3. ブレーズ構造生成(★ z方向反転 ★)
# ============================================================
def make_blazed_layers():
    layers = [lattice.Layer("Superstrate", epsilon=eps_sup)]
    dz = height / nslices

    for k in range(nslices):
        zc = (k + 0.5) * dz
        zh = zc / height
        zh_inv = 1.0 - zh   # ★ z方向反転

        if blaze_mode == "right":
            in_ramp = frac < zh_inv

        elif blaze_mode == "left":
            in_ramp = frac > (1.0 - zh_inv)

        elif blaze_mode == "both":
            dist = np.abs(frac - peak_pos)
            max_dist = max(peak_pos, 1.0 - peak_pos)
            dist_norm = dist / max_dist
            in_ramp = dist_norm < zh_inv

        else:
            raise ValueError("Invalid blaze_mode")

        if not etched_groove:
            eps = lattice.ones() * eps_sup
            eps[in_ramp] = eps_gr
        else:
            eps = lattice.ones() * eps_gr
            eps[in_ramp] = eps_sup

        layers.append(
            lattice.Layer(
                f"Blaze_{k:02d}",
                thickness=dz,
                epsilon=eps
            )
        )

    layers.append(lattice.Layer("Substrate", epsilon=eps_sub))
    return layers

stack = make_blazed_layers()

# ============================================================
# 4. 誘電率分布表示
# ============================================================

# ---- ε(x,y)
pick = [1, 1 + nslices // 2, nslices]
fig, axs = plt.subplots(1, 3, figsize=(10, 3), constrained_layout=True)

for ax, idx in zip(axs, pick):
    plt.sca(ax)
    im = stack[idx].plot(cmap="viridis")[0]
    ax.set_title(stack[idx].name)
    plt.colorbar(im, ax=ax, orientation="horizontal")

plt.suptitle("Permittivity ε(x,y)")
plt.show()

# ---- ε(x,z)
eps_xz = np.zeros((nslices, Nx))
for k in range(nslices):
    eps_xz[k, :] = np.real(stack[1 + k].epsilon[:, 0])

plt.figure(figsize=(8, 4))
plt.imshow(
    eps_xz,
    origin="lower",
    aspect="auto",
    extent=[0, period, 0, height],
    cmap="viridis"
)
plt.xlabel("x [um]")
plt.ylabel("z [um]")
plt.title("Blazed grating cross section (high-index z-inverted)")
plt.colorbar(label="epsilon")
plt.tight_layout()
plt.show()

# ============================================================
# 5. スペクトル計算
# ============================================================
def run_spectrum(psi_deg):
    Rtot, Ttot = [], []
    Tm = {m: [] for m in orders_to_plot}
    Rm = {m: [] for m in orders_to_plot}

    for lam in wavelengths:
        pw = nn.PlaneWave(lam, angles=(theta_deg, phi_deg, psi_deg))
        sim = nn.Simulation(stack, pw, nh=nh)

        R, T = sim.diffraction_efficiencies()
        Rtot.append(float(R))
        Ttot.append(float(T))

        Ri, Ti = sim.diffraction_efficiencies(orders=True)
        for m in orders_to_plot:
            Tm[m].append(float(sim.get_order(Ti, (m, 0))))
            Rm[m].append(float(sim.get_order(Ri, (m, 0))))

    return np.array(Rtot), np.array(Ttot), Tm, Rm

results = {pol: run_spectrum(psi) for pol, psi in polarizations.items()}

# ============================================================
# 6. スペクトル表示
# ============================================================
for pol, (Rtot, Ttot, Tm, Rm) in results.items():
    plt.figure(figsize=(8, 5))
    for m in orders_to_plot:
        plt.plot(wavelengths, Tm[m], label=f"T(m={m})")
    plt.title(f"{pol}-pol Transmitted orders")
    plt.xlabel("Wavelength [um]")
    plt.ylabel("Efficiency")
    plt.legend()
    plt.tight_layout()
    plt.show()

# ---- 全R/T
plt.figure(figsize=(7, 5))
for pol, (Rtot, Ttot, *_rest) in results.items():
    plt.plot(wavelengths, Ttot, label=f"{pol}-pol T")
    plt.plot(wavelengths, Rtot, "--", label=f"{pol}-pol R")
plt.xlabel("Wavelength [um]")
plt.ylabel("Efficiency")
plt.title("Total Transmission / Reflection")
plt.legend()
plt.tight_layout()
plt.show()

まとめ

今回オープンソースのRCWAシミュレータであるnannosを使ってブレーズド回折格子の透過率・反射率を求めてみました。今回は1次元周期の構造でしたが、2次元構造も対応しているので次回はより複雑な構造のシミュレーションを試していきます。

※本記事は筆者個人の見解であり、所属組織の公式見解を示すものではありません。

問い合わせフォームのご連絡

問い合わせ

光学シミュレーションソフトの導入や技術相談、
設計解析委託をお考えの方はサイバネットシステムにお問合せください。

光学ソリューションサイトについては以下の公式サイトを参照:
👉 [光学ソリューションサイト(サイバネット)]

光学分野のエンジニアリングサービスについては以下の公式サイトを参照:
👉 [光学エンジニアリングサービス(サイバネット)]

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?