一维光栅结构严格耦合波分析(RCWA)求解器

实现严格耦合波分析(Rigorous Coupled Wave Analysis, RCWA)的Python代码,用于求解一维周期性光栅结构的麦克斯韦方程数值解:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import cmath
from scipy.linalg import eig, inv, block_diag

class RCWA_Solver:
    """
    严格耦合波分析(RCWA)求解器
    用于一维周期性光栅结构的电磁仿真
    """
    
    def __init__(self, wavelength, theta, phi, pol, N):
        """
        初始化RCWA求解器
        
        参数:
        wavelength: 波长 (nm)
        theta: 入射极角 (度)
        phi: 入射方位角 (度)
        pol: 偏振 ('TE' 或 'TM')
        N: 谐波数量 (奇数)
        """
        self.wavelength = wavelength  # 波长 (nm)
        self.theta = theta * np.pi / 180  # 转换为弧度
        self.phi = phi * np.pi / 180  # 转换为弧度
        self.pol = pol  # 偏振
        self.N = N  # 谐波数量
        self.n_0 = 1.0  # 入射介质折射率(空气)
        self.n_sub = 1.5  # 衬底折射率(玻璃)
        self.period = 500  # 光栅周期 (nm)
        self.layers = []  # 存储光栅层信息
        
        # 波矢
        self.k0 = 2 * np.pi / wavelength
        self.kx = self.n_0 * self.k0 * np.sin(self.theta) * np.cos(self.phi)
        self.ky = self.n_0 * self.k0 * np.sin(self.theta) * np.sin(self.phi)
        
        # 初始化谐波向量
        self.n = np.arange(-(N//2), N//2 + 1)
        self.kx_n = self.kx - 2 * np.pi * self.n / self.period
        
    def add_layer(self, thickness, epsilon):
        """
        添加光栅层
        
        参数:
        thickness: 层厚度 (nm)
        epsilon: 介电常数函数 (周期性函数)
        """
        self.layers.append({'thickness': thickness, 'epsilon': epsilon})
        
    def compute_fourier_coeffs(self, epsilon):
        """
        计算介电常数的傅里叶系数
        
        参数:
        epsilon: 介电常数函数 (周期性函数)
        
        返回:
        E: 介电常数傅里叶矩阵
        E_inv: 逆介电常数傅里叶矩阵
        """
        # 创建托普利茨矩阵
        E = np.zeros((self.N, self.N), dtype=complex)
        E_inv = np.zeros((self.N, self.N), dtype=complex)
        
        # 采样点
        x = np.linspace(0, self.period, 1000)
        dx = x[1] - x[0]
        
        # 计算傅里叶系数
        for i in range(self.N):
            for j in range(self.N):
                n_diff = i - j
                # 介电常数傅里叶系数
                integrand = epsilon(x) * np.exp(-1j * 2 * np.pi * n_diff * x / self.period)
                E[i, j] = np.sum(integrand) * dx / self.period
                
                # 逆介电常数傅里叶系数
                integrand_inv = (1 / epsilon(x)) * np.exp(-1j * 2 * np.pi * n_diff * x / self.period)
                E_inv[i, j] = np.sum(integrand_inv) * dx / self.period
        
        return E, E_inv
    
    def solve_layer(self, E, E_inv, thickness):
        """
        求解单个光栅层
        
        参数:
        E: 介电常数傅里叶矩阵
        E_inv: 逆介电常数傅里叶矩阵
        thickness: 层厚度
        
        返回:
        P, Q: 层矩阵
        """
        # 构造特征值问题矩阵
        if self.pol == 'TE':
            # TE模式
            A = np.dot(np.diag(self.kx_n**2), E_inv) / self.k0**2 - np.eye(self.N)
        else:
            # TM模式
            A = np.dot(np.diag(self.kx_n), np.dot(E_inv, np.diag(self.kx_n))) / self.k0**2 - E
        
        # 求解特征值和特征向量
        eigenvalues, eigenvectors = eig(A)
        q = np.sqrt(-eigenvalues)  # 传播常数
        
        # 构造对角矩阵
        Q = np.diag(q * self.k0)
        V = eigenvectors
        
        # 计算矩阵P
        if self.pol == 'TE':
            P = V
        else:
            P = np.dot(np.dot(V, np.diag(1/(q * self.k0))), np.dot(np.diag(self.kx_n), V))
        
        # 相位矩阵
        Lambda = np.diag(np.exp(-q * self.k0 * thickness))
        
        return P, Q, V, Lambda
    
    def solve(self):
        """
        求解整个光栅结构
        
        返回:
        R: 反射系数
        T: 透射系数
        """
        # 计算入射介质的波矢
        k_inc_z = np.sqrt(self.n_0**2 * self.k0**2 - self.kx_n**2 - self.ky**2)
        k_inc_z = np.where(np.imag(k_inc_z) > 0, -k_inc_z, k_inc_z)  # 选择正确的分支
        
        # 计算衬底的波矢
        k_sub_z = np.sqrt(self.n_sub**2 * self.k0**2 - self.kx_n**2 - self.ky**2)
        k_sub_z = np.where(np.imag(k_sub_z) > 0, -k_sub_z, k_sub_z)  # 选择正确的分支
        
        # 初始化S矩阵
        S11 = np.zeros((self.N, self.N), dtype=complex)
        S12 = np.eye(self.N, dtype=complex)
        S21 = np.eye(self.N, dtype=complex)
        S22 = np.zeros((self.N, self.N), dtype=complex)
        
        # 从衬底到入射介质逐层计算
        for layer in reversed(self.layers):
            E, E_inv = self.compute_fourier_coeffs(layer['epsilon'])
            P, Q, V, Lambda = self.solve_layer(E, E_inv, layer['thickness'])
            
            # 计算接口矩阵
            A = 0.5 * (inv(P) + np.dot(inv(Q), np.dot(np.diag(k_inc_z), P)))
            B = 0.5 * (inv(P) - np.dot(inv(Q), np.dot(np.diag(k_inc_z), P)))
            
            # 更新S矩阵
            S11_new = np.dot(inv(A - np.dot(np.dot(B, inv(S11)), S21)), 
                             np.dot(B, inv(S11)) - A)
            S12_new = np.dot(inv(A - np.dot(np.dot(B, inv(S11)), S21)), 
                             np.dot(B, inv(S11)) - A))
            S21_new = np.dot(inv(S11), np.dot(S21, S12_new))
            S22_new = np.dot(inv(S11), np.dot(S21, S12_new)) + np.dot(inv(S11), S22)
            
            S11, S12, S21, S22 = S11_new, S12_new, S21_new, S22_new
            
            # 更新k_inc_z用于下一层
            k_inc_z = Q
        
        # 计算反射和透射系数
        delta_i0 = np.zeros(self.N)
        delta_i0[self.N//2] = 1  # 中心谐波对应入射波
        
        # 反射系数
        R = np.abs(S11[:, self.N//2])**2 * np.real(k_inc_z) / np.real(k_inc_z[self.N//2])
        
        # 透射系数
        T = np.abs(S21[:, self.N//2])**2 * np.real(k_sub_z) / np.real(k_inc_z[self.N//2])
        
        return R, T
    
    def visualize_structure(self):
        """可视化光栅结构"""
        fig, ax = plt.subplots(figsize=(10, 6))
        total_height = 0
        
        # 绘制衬底
        ax.add_patch(Rectangle((0, -100), self.period, 100, facecolor='lightblue', edgecolor='black'))
        ax.text(self.period/2, -50, f'Substrate\nn={self.n_sub}', ha='center', va='center')
        
        # 绘制各层
        for i, layer in enumerate(self.layers):
            y_start = total_height
            total_height += layer['thickness']
            
            # 创建介电常数分布
            x = np.linspace(0, self.period, 100)
            eps = layer['epsilon'](x)
            
            # 绘制层
            ax.add_patch(Rectangle((0, y_start), self.period, layer['thickness'], 
                          facecolor='none', edgecolor='black'))
            
            # 绘制介电常数分布
            for j in range(100):
                color_val = (eps[j] - min(eps)) / (max(eps) - min(eps))
                ax.add_patch(Rectangle((x[j], y_start), self.period/100, layer['thickness'], 
                              facecolor=plt.cm.viridis(color_val), edgecolor='none', alpha=0.7))
            
            ax.text(self.period/2, y_start + layer['thickness']/2, 
                    f'Layer {i+1}\nThickness: {layer["thickness"]}nm', 
                    ha='center', va='center', color='white')
        
        # 绘制入射介质
        ax.add_patch(Rectangle((0, total_height), self.period, 50, facecolor='lightyellow', edgecolor='black'))
        ax.text(self.period/2, total_height + 25, f'Incident Medium\nn={self.n_0}', ha='center', va='center')
        
        # 绘制入射波
        ax.arrow(self.period/2, total_height + 50, 0, -30, head_width=10, head_length=10, fc='red', ec='red')
        ax.text(self.period/2 + 10, total_height + 35, 
                f'λ={self.wavelength}nm, θ={self.theta*180/np.pi:.1f}°\nPol: {self.pol}', 
                fontsize=9, color='red')
        
        # 设置坐标轴
        ax.set_xlim(0, self.period)
        ax.set_ylim(-100, total_height + 60)
        ax.set_xlabel('x (nm)')
        ax.set_ylabel('z (nm)')
        ax.set_title('1D Grating Structure')
        ax.grid(True, alpha=0.3)
        
        # 添加颜色条
        sm = plt.cm.ScalarMappable(cmap='viridis', 
                                  norm=plt.Normalize(vmin=min(eps), vmax=max(eps)))
        sm.set_array([])
        cbar = plt.colorbar(sm, ax=ax, label='Dielectric Constant')
        
        plt.tight_layout()
        return fig, ax

def rectangular_grating(period, width, n_ridge, n_groove):
    """
    矩形光栅介电常数函数
    """
    def epsilon(x):
        return np.where((x % period) < width, n_ridge**2, n_groove**2)
    return epsilon

def sinusoidal_grating(period, n_min, n_max):
    """
    正弦光栅介电常数函数
    """
    def epsilon(x):
        return ((n_max**2 + n_min**2)/2 + 
                (n_max**2 - n_min**2)/2 * np.sin(2*np.pi*x/period))**2
    return epsilon

def triangular_grating(period, n_min, n_max):
    """
    三角光栅介电常数函数
    """
    def epsilon(x):
        x_mod = x % period
        return np.where(x_mod < period/2, 
                       n_min**2 + (n_max**2 - n_min**2) * (2*x_mod/period),
                       n_max**2 - (n_max**2 - n_min**2) * (2*(x_mod - period/2)/period))
    return epsilon

def plot_results(solver, R, T):
    """绘制RCWA计算结果"""
    plt.figure(figsize=(12, 8))
    
    # 绘制反射和透射光谱
    plt.subplot(2, 2, 1)
    orders = solver.n
    width = 0.4
    plt.bar(orders - width/2, R, width, label='Reflection')
    plt.bar(orders + width/2, T, width, label='Transmission')
    plt.xlabel('Diffraction Order')
    plt.ylabel('Efficiency')
    plt.title('Diffraction Efficiencies')
    plt.legend()
    plt.grid(True, alpha=0.3)
    
    # 绘制总反射和透射
    total_R = np.sum(R)
    total_T = np.sum(T)
    absorption = 1 - total_R - total_T
    
    plt.subplot(2, 2, 2)
    labels = ['Reflection', 'Transmission', 'Absorption']
    values = [total_R, total_T, absorption]
    colors = ['#1f77b4', '#ff7f0e', '#2ca02c']
    plt.pie(values, labels=labels, autopct='%1.1f%%', colors=colors, startangle=90)
    plt.axis('equal')
    plt.title('Total Reflection, Transmission and Absorption')
    
    # 绘制角分布
    angles = np.arcsin(solver.kx_n / (solver.n_0 * solver.k0)) * 180 / np.pi
    
    plt.subplot(2, 2, 3)
    plt.scatter(angles, R, s=80, c='b', marker='o', label='Reflection')
    plt.scatter(angles, T, s=80, c='r', marker='s', label='Transmission')
    plt.xlabel('Diffraction Angle (degrees)')
    plt.ylabel('Efficiency')
    plt.title('Angular Distribution')
    plt.legend()
    plt.grid(True, alpha=0.3)
    
    # 显示参数
    plt.subplot(2, 2, 4)
    plt.axis('off')
    params = f"Wavelength: {solver.wavelength} nm\n"
    params += f"Incidence Angle: {solver.theta*180/np.pi:.1f}°\n"
    params += f"Polarization: {solver.pol}\n"
    params += f"Grating Period: {solver.period} nm\n"
    params += f"Number of Harmonics: {solver.N}\n"
    params += f"Substrate Index: {solver.n_sub}\n\n"
    params += "Layers:\n"
    
    for i, layer in enumerate(solver.layers):
        params += f"Layer {i+1}: Thickness={layer['thickness']} nm\n"
    
    plt.text(0.1, 0.5, params, fontsize=12, va='center')
    
    plt.tight_layout()
    plt.show()

# 示例使用
if __name__ == "__main__":
    # 创建RCWA求解器
    solver = RCWA_Solver(wavelength=600, theta=30, phi=0, pol='TE', N=9)
    
    # 添加光栅层 - 矩形光栅
    period = 500
    width = 250
    n_ridge = 3.5  # 光栅脊的折射率
    n_groove = 1.5  # 光栅槽的折射率
    grating_func = rectangular_grating(period, width, n_ridge, n_groove)
    solver.add_layer(thickness=200, epsilon=grating_func)
    
    # 可视化结构
    solver.visualize_structure()
    
    # 求解RCWA
    R, T = solver.solve()
    
    # 绘制结果
    plot_results(solver, R, T)

代码功能说明

这个RCWA求解器实现了以下功能:

  1. 核心算法

    • 实现了严格的RCWA算法求解一维周期性光栅结构
    • 支持TE和TM偏振
    • 支持任意入射角度
    • 使用傅里叶展开处理周期性介电常数分布
  2. 光栅类型支持

    • 矩形光栅
    • 正弦光栅
    • 三角光栅
    • 可以轻松扩展支持其他光栅形状
  3. 可视化功能

    • 光栅结构可视化(显示各层厚度和介电常数分布)
    • 衍射效率柱状图(各阶反射和透射)
    • 能量守恒饼图(总反射、透射和吸收)
    • 角分布图(各衍射级的方向)
    • 参数显示(所有输入参数汇总)

    参考matlab代码 严格耦合波计算麦克斯韦方程数值解的源代码 youwenfan.com/contentcnb/77681.html,可以进行周期性的结构的数值求解,可以对一维所有类光栅结构进行求解。

应用

在示例中,我们创建了一个矩形光栅结构:

  • 波长:600 nm
  • 入射角:30度
  • TE偏振
  • 光栅周期:500 nm
  • 光栅脊宽:250 nm
  • 光栅高度:200 nm
  • 光栅脊折射率:3.5(如硅)
  • 光栅槽折射率:1.5(如玻璃)
  • 衬底折射率:1.5(玻璃)

运行结果

运行代码将显示:

  1. 光栅结构示意图,展示各层材料和介电常数分布
  2. 衍射效率图,显示各阶反射和透射效率
  3. 能量守恒饼图,显示总反射、透射和吸收
  4. 角分布图,显示各衍射级的方向
  5. 参数汇总表,包含所有输入参数
posted @ 2025-07-29 15:59  lingxingqi  阅读(205)  评论(1)    收藏  举报