4. 传输矩阵法(TMM)实现:矩阵构建、边界条件、反射谱与透射谱计算、Python代码实现

传输矩阵法,圈里人常叫它 TMM。说实话,这是我做光栅设计时最趁手的工具之一。你想想看,DFB 激光器的光栅结构,说白了就是一层层折射率不同的材料堆叠起来。每一层对光场的影响,都可以用一个 2×2 的矩阵来描述。把所有这些矩阵乘起来,整个器件的传输特性就出来了。

我个人习惯用 TMM 来快速验证光栅设计。比起那些复杂的数值仿真,TMM 计算快、物理图像清晰。我在项目中遇到过好几次,用 FDTD 算半天发现结果不对,回头用 TMM 一检查,原来是边界条件设错了。嗯,这方法虽然老,但真管用。

4.1 矩阵构建:从单层到多层

先说说最基本的。每一层均匀介质,光波在其中传播,可以用一个传输矩阵来表示:

M_i = [cos(k_i * d_i),  (j / n_i) * sin(k_i * d_i)]
      [j * n_i * sin(k_i * d_i),  cos(k_i * d_i)]

这里:

  • k_i = 2π * n_i / λ,波数
  • d_i 是这一层的厚度
  • n_i 是折射率(可以是复数,考虑吸收)
  • j 是虚数单位

整个光栅结构,假设有 N 层,那总的传输矩阵就是:

M_total = M_N * M_{N-1} * ... * M_1

注意乘法顺序!从入射端开始,一层层乘过去。我曾经在这上面栽过跟头,矩阵乘法的顺序搞反了,结果反射谱完全不对。排查了一下午才发现。

核心要点:传输矩阵的乘法顺序是从入射面到出射面,千万别搞反。

4.2 边界条件:连接物理世界

矩阵搭好了,怎么跟实际的入射光、反射光联系起来?这就需要边界条件了。

假设光从左侧入射,左侧介质折射率为 n_0,右侧为 n_s。那么:

  • 左侧边界:入射光场 E_in + 反射光场 E_r
  • 右侧边界:只有透射光场 E_t(假设右侧没有反射回来)

写成矩阵形式:

[E_in + E_r]     = M_total * [E_t]
[n_0*(E_in - E_r)]            [n_s * E_t]

解这个方程组,就能得到反射系数 r 和透射系数 t:

r = E_r / E_in
t = E_t / E_in

注意:如果光栅两侧的介质折射率不同,一定要在边界矩阵中正确引入。我见过有人直接用 M_total 算,忽略了边界折射率跳变,结果反射谱的纹波周期全错了。

4.3 反射谱与透射谱计算

有了 r 和 t,反射率和透射率就简单了:

R = |r|^2
T = |t|^2 * (n_s / n_0)

为什么要乘 n_s / n_0?因为光功率流在不同介质中要守恒。这个细节,很多教材上一笔带过,但实际计算时漏掉它,结果就不对了。

扫一波波长,把每个波长下的 R 和 T 算出来,就是反射谱和透射谱。DFB 光栅的反射谱会在布拉格波长附近出现一个高反射峰,这个峰的宽度和高度,直接决定了激光器的性能。

我的经验:计算反射谱时,波长扫描范围要覆盖布拉格波长两侧至少 50 nm。太窄了,你可能看不到完整的反射带边沿。

4.4 Python 代码实现

说了这么多,上代码。这是我常用的 TMM 实现,简洁够用:

import numpy as np

def tmm_layer(n, d, lam):
    """单层传输矩阵"""
    k = 2 * np.pi * n / lam
    cos_kd = np.cos(k * d)
    sin_kd = np.sin(k * d)
    
    M = np.array([
        [cos_kd, 1j * sin_kd / n],
        [1j * n * sin_kd, cos_kd]
    ])
    return M

def tmm_total(layers, lam, n0, ns):
    """计算多层结构的反射率和透射率
    layers: [(n1, d1), (n2, d2), ...]
    """
    M_total = np.eye(2, dtype=complex)
    
    for n, d in layers:
        M_layer = tmm_layer(n, d, lam)
        M_total = M_layer @ M_total
    
    # 边界条件
    A = M_total[0,0] + M_total[0,1] * ns
    B = M_total[1,0] + M_total[1,1] * ns
    
    r = (n0 - B / A) / (n0 + B / A)
    t = 2 * n0 / (n0 * A + B)
    
    R = np.abs(r)**2
    T = np.abs(t)**2 * np.real(ns) / np.real(n0)
    
    return R, T

# 示例:计算均匀布拉格光栅的反射谱
lam_range = np.linspace(1.5e-6, 1.6e-6, 1000)
n_high, n_low = 3.5, 3.3
d_high, d_low = 0.22e-6, 0.22e-6  # 四分之一波长厚度
num_periods = 20

layers = []
for _ in range(num_periods):
    layers.append((n_high, d_high))
    layers.append((n_low, d_low))

R_spectrum = []
for lam in lam_range:
    R, _ = tmm_total(layers, lam, n0=1.0, ns=1.0)
    R_spectrum.append(R)

# 找到反射峰
peak_idx = np.argmax(R_spectrum)
print(f"峰值反射率: {R_spectrum[peak_idx]:.4f}")
print(f"峰值波长: {lam_range[peak_idx]*1e9:.2f} nm")

代码说明:

  • tmm_layer() 生成单层矩阵
  • tmm_total() 组装多层并计算 R、T
  • 示例中用了 20 个周期的均匀光栅,折射率差 0.2
  • 输出峰值反射率和对应的波长

4.5 知识体系总览

下面这张图,把 TMM 的核心逻辑串起来了。从单层矩阵到多层级联,再到边界条件和谱线计算,每一步都环环相扣。

传输矩阵法(TMM)核心流程 步骤1:单层矩阵 M_i = f(n_i, d_i, λ) 步骤2:多层级联 M_total = Π M_i 步骤3:边界条件 n₀, n_s → r, t 步骤4:谱线计算 R = |r|², T = |t|²·nₛ/n₀ 波长扫描 输入:材料参数(n, d)、波长范围、边界折射率 输出:反射谱 R(λ)、透射谱 T(λ) 关键参数 • 折射率 n (可复数) • 层厚 d • 波长 λ

实用建议:刚开始写 TMM 代码时,先用一个简单的法布里-珀罗腔(两层反射镜夹一层介质)验证。如果算出来的透射峰位置和理论值对得上,那你的矩阵构建和边界条件就基本没问题了。

好了,TMM 的核心内容就这些。矩阵构建、边界条件、谱线计算,再加上 Python 代码,足够你上手做 DFB 光栅的初步设计了。记住,工具是死的,思路是活的。遇到复杂结构时,多想想每一层物理上发生了什么,矩阵自然就写对了。

专注资料整理