
一次真实的入门场景软件装好了界面打开了我却不知道下一步该点什么。Lumerical FDTD对我当时来说就是一堵墙——工具栏密密麻麻对象树里空荡荡网上搜到的教程要么跳步要么就是英文PPT截图。后来的转折点是我下决心拿二维光子晶体开刀结构只有几个圆片和矩形物理上又有一个特别直观的目标——找光子禁带。当第一张能带图在脚本终端里刷出来时那种终于懂了的感觉是刷十篇教程都给不了的。这篇博文就是按我当时走通的路子整理出来的从环境准备讲起落到一整套能直接改参数跑的 Lumerical 脚本最后把能带计算和透射谱验证两条线串起来。适合零基础但想快速上手 Lumerical FDTD 的初学者也适合正在做光子晶体课程设计、毕业设计或者刚进课题组的同学参考。1. 为什么新人学Lumerical FDTD我建议从光子晶体入手先别急着开软件想清楚一个问题为什么是光子晶体光子晶体说白了就是折射率在空间里周期性变化的材料结构。光在里面传播时就像电子在半导体晶格中那样也会遇到能带和禁带。只不过半导体禁带约束的是电子光子晶体禁带约束的是光子。这个类比是中学物理水平都能听懂的而它带来的科研价值一点也不低光子禁带意味着特定频率的光无法在结构里传播于是可以拿来做谐振腔、波导、滤波器、激光器甚至拓扑保护的光传输。但选它当 Lumerical FDTD 的入门题材不是因为它在学术上重要而是因为它对新手极其友好。我总结过三个理由。第一结构简单建模难度低。二维光子晶体只需要一个晶胞里面放一个介质柱或者挖一个空气孔再加好周期性边界条件就是一个完整的仿真模型。不需要你在 CAD 里画复杂的圆弧、布尔运算连网格细化区域都能用软件默认值。第二结果非常直观验证路径多。你能算出能带图看到清晰的禁带也可以搭一小段有限周期结构算透射谱从光过不去的波长区间再次验证同一个禁带。两条路互相印证这对新手判断我的结果对不对特别关键。做其他复杂结构时经常跑完一片云里雾里的场图根本不知道对错光子晶体没这个问题。第三计算量适中。二维 FDTD 的网格数量比三维少一到两个量级普通台式机几分钟到十几分钟就能跑完一次完整的 k 点扫描。我当时用的是 2017 年的 i7 四核电脑 16GB 内存跑得很顺畅。如果是三维光子晶体或带缺陷的腔体起步就是小时级新手排错成本会高得多。所以这篇博文的目标非常明确以二维正方格子硅柱光子晶体为原型从零搭建仿真环境完成两个核心仿真——能带结构计算和透射谱验证。过程中会用到的脚本都会贴出来你可以直接复制改参数也可以一行行跟着理解。2. 搭建仿真前必须搞懂的五个基本概念这一章不堆公式我用大白话把五个必须知道的概念讲清楚。跳过这章直接搭模型做出来的东西大概率是坏的。2.1 晶格常数、填充比和材料折射率这三个参数决定你的光子禁带光子晶体的核心三要素是晶格常数 a、介质柱半径 r或空气孔半径和材料折射率 n。晶格常数是两个相邻单元中心之间的距离单位通常取微米um。介质柱半径相对晶格常数的比例 r/a 叫做填充比它直接影响能带结构。介质和背景的折射率对比度同样关键对比度太低光感受不到周期性结构带隙很难打开对比度足够高带隙才明显。一个典型的起点是正方晶格、硅柱在空气中a 0.55 umr 0.18 umn 3.48。这个参数组合在 TM 模式电场沿柱体方向下大约在归一化频率 0.25 到 0.42 之间打开一条禁带。之后再调 r/a 或者换三角晶格能带会明显变化这部分留给你自己玩。2.2 FDTD方法如何用网格“切”开麦克斯韦方程组FDTD时域有限差分的基本思路很暴力把麦克斯韦方程组在空间和时间上都离散成一个个小格点电场放在 Yee 网格的棱边中心磁场放在面中心然后按照时间步长一步步推进模拟电磁波在结构里的传播。它不收斂边界层的近似而是直接看波在时域里的演化所以你不需要像频域方法那样对每个频率单独求解一次宽带脉冲激励就能覆盖一大段频谱。代价是什么呢计算量大、内存占用高。网格精度和仿真时间直接决定结果质量这两个参数你会在脚本里反复碰到。2.3 边界条件在光子晶体仿真里的具体角色边界条件是新手第一个重灾区。光子晶体仿真里的主角是单位晶胞——你只画了一个周期的结构却要模拟无限大的周期阵列靠的就是边界条件。Lumerical FDTD 里常用的边界条件有Periodic周期边界仿真区域两边表现为镜像周期延拓适合正入射情况但默认不带相位偏置。Bloch布洛赫边界周期性边界条件的进阶版允许边界处场带有相位偏移。能带计算扫描 k 点时就是通过设 kx、ky 来控制这个相位偏移的。计算能带结构时必须用 Bloch 边界。PML完美匹配层模拟敞开空间让波被吸收而不反射适合波导、散射等开放结构。PEC理想导体边界电场切向分量为零适合金属边界或者对称面简化。新手最容易犯的错就是把所有边都设成 PML然后跑出一个看起来很长但物理上完全不对的能带图。记牢算周期结构能带面内方向用 Bloch算有限周期结构的透射谱入射方向和出射方向用 PML垂直于结构的面方向保持 Bloch 或 PEC。2.4 光源与监视器怎么把一个单元“喊醒”并“听”出模式FDTD 里你需要一个源来激发结构里的模式还需要监视器来记录场随时间的变化。光源方面能带计算通常用偶极子源因为它是一个宽带点激励能把各种 k 下允许传播的模式都激发起来。对于二维仿真偶极子的偏振方向很关键——设 90° 对应 TM 偏振电场沿 z 轴设 0° 对应 TE 偏振电场在面内。透射谱仿真则用平面波源因为它带一个明确的传播方向和波前适合测透过率。监视器方面能带计算的核心是时间监视器timemonitor它记录某个位置上电场随时间的变化信号。这个信号做 FFT 后峰值频率就对应结构支持的模式的频率。透射谱仿真则用频域功率监视器power monitor它记录通过某个平面的能量流量从而得到透过率曲线。2.5 布里渊区与k点路径能带图的横轴怎么来能带图的横轴不是频率也不是空间坐标而是波矢 k 沿晶格倒空间高对称点的路径。以正方晶格为例第一布里渊区里的三个高对称点是 Γ中心kx0, ky0、Xkxπ/a, ky0、Mkxπ/a, kyπ/a。一张标准的能带图横轴通常是 Γ→X→M→Γ 这条折线路径纵轴是归一化频率 a/λ。这个抽象的玩意儿很多人卡在这。我的理解方式很简单k 点代表周期结构中波的传播原位相偏移量。k0 时所有晶胞同相位振动kπ/a 时相邻晶胞反相位振动。扫描不同 k 点、算出每个 k 点下结构允许的谐振频率就得到一条条能带。频率的空白区就是禁带。3. 仿真环境准备软件、硬件和界面怎么安排搭模型之前先把仿真环境这四个字落在实处。3.1 版本选择与安装注意Lumerical FDTD 现在的官方名字是 Ansys Lumerical FDTDPackages 通常包含 FDTD Solutions 和 MODE Solutions。学生和课题组一般通过学校站点授权使用个人学习可以关注官方提供的试用申请。我的建议是能用新版本就别用 2015 年之前的旧版新版本在网格算法、材料库和脚本兼容性上都有明显改进我用的 2020 R2 当时已经很稳定了。安装时需要注意Lumerical 的 License 分为本地许可证license file和网络许可证license server两种。如果你用的是学校服务器上的 license记得在“LM License Manager”里正确配置服务器地址不然软件打开后会在脚本运行时报 No license available。这是特别常见的安装坑不是软件坏了。3.2 电脑配置内存和CPU是主要瓶颈Lumerical FDTD是内存和CPU双密集型的计算软件。我在实验室机器上跑能带计算内存 16GB 绰绰有余但后来跑三维光子晶体腔体就明显不够网格一加密直接内存溢出。如果你是想长期做光子晶体仿真我建议最低 16GB 内存推荐 32GBCPU 核心数越多越好FDTD 的并行效率在多核下表现不错。GPU 加速对 FDTD 帮助不大别在那上面浪费预算。3.3 界面上的几个关键区域打开软件后别被满屏工具栏吓住。你需要关注的就四个区域对象树Object Tree在左侧按树状结构显示模型中的所有对象如 FDTD 区域、几何体、光源、监视器。点选对象后下方或右侧的属性窗口会显示它的所有参数。CAD 视图中间的 3D/2D 绘图区你能直观看到几何结构。脚本编辑器通常可以从菜单 Window 下打开支持 Lumerical 自带的脚本语言这是批量建模和参数扫描的核心工具。我这篇博文里的脚本大部分就在这个编辑器里运行。运行日志Shell脚本命令的输出窗口报错信息都在这看新手一定要养成看 Log 的习惯。记住能用脚本建模型就别用鼠标点。点出来的模型没法复现改参数要一层层找菜单而脚本可以一键重跑整个建模仿真流程。这也是为什么下面几章我全部以脚本形式呈现。4. 搭建二维光子晶体模型的关键操作步骤在写完整脚本之前我先用操作流程把模型的每个部分拆开让你知道脚本里那些命令行到底在干什么。下面以正方晶格、硅柱在空气中的 2D 光子晶体为例。4.1 新建项目和单位设置打开 Lumerical FDTD Solutions新建一个项目。软件默认采用国际单位制但 FDTD 模型里我们一般全程用微米um也就是脚本里看到的a 0.55实际上是 0.55 um。单位使用混乱是新手极易犯的错误Lumerical 的核心里单位并没有强制锁死但材料库里的折射率波长数据是按米制来的所以建议从头到尾统一用 um。4.2 创建 FDTD 模拟区域addfdtd会创建一个 FDTD 仿真区域。我们把它设成 2Dx 和 y 方向的宽度等于一个晶格常数 az 方向给一个很小的厚度比如 0.01 um。边界条件面板里x 和 y 方向选Blochz 方向选PEC。为什么 z 方向用 PEC因为 2D 仿真默认结构沿 z 方向无限延伸PEC 边界配合很小的 z 厚度能等效出一个纯 2D 的波导限制条件。这个处理在很多 2D 光子晶体算例里都能看到。4.3 画介质柱用addcircle添加一个圆圆的半径设为 r位置放在坐标原点即晶胞中心。这里要区分两种结构介质柱型是背景为空气、柱体为高折射率材料空气孔型是背景为高折射率材料、在中心挖一个空气孔。介质柱型直接在圆对象里设置材料或指定折射率 n_si空气孔型则需要把背景折射率设置为高折射率材料在 FDTD 区域属性里设 background index再把这个圆设置成空气index 1。两种结构都能打开禁带但偏振特性不同介质柱型通常支持 TE 和 TM 都有带隙空气孔型更常用于 TM 带隙石墨烯等材料的集成光学设计里空气孔结构更常见。新手建议先做介质柱型逻辑直观一点。4.4 加偶极子光源adddipole添加一个偶极子源。位置不要放在结构正中心或正对角线上——如果源落在结构对称面会存在某些模式无法被激发的问题。一个经验法则放在 (0.3a, 0.3a) 附近既不在高对称点又还在结构附近能有效激发更多模式。频率范围按归一化频率换算成实际频率。归一化频率 f_norm a/λ实际频率 f c/λ c * f_norm / a。比如 a 0.55 um归一化频率范围 0.2~0.7对应的实际频率范围大约是 1.09e14~3.82e14 Hz。脚本里可以直接填set(frequency, 1.09e14, 3.82e14)。4.5 布置时间监视器能带计算需要在晶胞里放多个探测点。位置可以沿着某一对角线均匀布置比如从 (0,0) 开始每隔 0.15a 放一个一共放 6 个。放多个监视器是因为有些模式在某一个点上是节点场强为零单独一个点会漏模式多点探测能互相补位。每加一个时间监视器脚本里用addtime然后set它的属性。4.6 设定网格精度与仿真时间网格精度这个参数很关键。set(mesh accuracy, 3)表示 Lumerical 自动生成网格的精细程度数值越大网格越密、结果越准、耗时越长。新手可以从 2 或 3 起步确认流程没跑通后再升到 4~5 验证稳定性。仿真时间从set(simulation time, 3000)这类参数控制单位是飞秒fs。时间太短导致频谱分辨率不足峰值会糊在一起时间太长则白白浪费时间。3000 fs 在 2D 光子晶体能带计算里通常是够用的你可以在结果曲线的频率分辨率不足时加长时间。5. 能带计算完整脚本与逐行解读这一章给你整套能跑通核心模型的脚本。我会先贴出完整脚本然后逐段解释每一部分在做什么。5.1 完整脚本直接复制就能改参数跑下面的脚本在 Lumerical 脚本编辑器里运行作用是搭建一个二维正方晶格介质柱型光子晶体模型并运行单次仿真。用于能带计算的 k 扫描循环我放在 5.5 节单独讲因为它需要结合你的 Lumerical 版本微调。# ------------------------------------------------------------ # PhotonicCrystal_2D_square.lsf # 二维正方晶格介质柱光子晶体 - 单胞建模与仿真 # 结构: 硅柱(折射率3.48) 在空气中 # 单位: um # ------------------------------------------------------------ # 清除所有已有对象重新开始 deleteall; # ---- 1. 参数定义 ---- a 0.55; # 晶格常数 (um) r 0.18; # 硅柱半径 (um) n_si 3.48; # 硅的折射率 f_norm_low 0.2; # 归一化频率下限 (a/lambda) f_norm_high 0.7; # 归一化频率上限 c0 2.99792458e2; # 真空中光速 (um/fs) f_low c0 * f_norm_low / a; # 实际频率下限 (THz) f_high c0 * f_norm_high / a; # 实际频率上限 (THz) # ---- 2. FDTD 模拟区域 ---- addfdtd; set(name, FDTD); # 给区域起个名字便于后用 set(dimension, 2D); set(x, 0); set(y, 0); set(z, 0); set(x span, a); set(y span, a); set(z span, 0.01); set(x min bc, Bloch); set(x max bc, Bloch); set(y min bc, Bloch); set(y max bc, Bloch); set(z min bc, PEC); set(z max bc, PEC); set(background index, 1.0); # 背景是空气 set(mesh accuracy, 3); set(simulation time, 3000); # 单位: fs # ---- 3. 硅柱 ---- addcircle; set(name, si_rod); set(radius, r); set(x, 0); set(y, 0); set(z, 0); set(material, Si (Silicon) - Palik); set(index, n_si); # ---- 4. 偶极子光源 ---- adddipole; set(name, dipole); set(x, 0.3*a); set(y, 0.3*a); set(z, 0); set(polarization angle, 90); # 90度 沿z轴偏振 (TM模) set(frequency, f_low, f_high); # ---- 5. 时间监视器 (探测点) ---- num_mon 6; # 监视器数量 for (i 1:num_mon) { addtime; name t_mon_ num2str(i); set(name, name); set(x, 0.15 * (i-1) * a); set(y, 0.15 * (i-1) * a); set(z, 0); } # ---- 6. 保存并运行 ---- save(phc_2d_square_band.fsp); run;5.2 参数区在定义什么脚本头部的参数定义了三大类几何参数、材料参数、频率范围。几何参数里a 和 r 决定了带隙位置这是物理核心。材料 n_si 用硅的折射率 3.48在近红外波段硅的折射率很稳定如果你用的材料波长范围在可见光或者中红外需要去材料库里确认色散数据或者直接指定折射率值进行无耗散近似。频率范围的换算容易晕我在脚本里预设了从归一化频率到实际频率的换算这样改结构参数时不用反复手动算。注意c0 2.99792458e2这一行因为长度单位是 um、时间单位是 fs所以光速数值上是 299.792458 um/fs也就是 2.99792458e2。5.3 FDTD区域与边界条件的脚本写法addfdtd创建区域后set挨个设置属性。x span和y span都必须正好等于一个晶格常数 a因为 Bloch 边界条件要求仿真区域就是一个周期。如果 x span 是 2a 或者 0.5a算出来的能带就不是第一布里渊区的结果后面怎么调都是错的。z span设成 0.01 um 是一个经验值太小可能导致网格在 z 方向过分压缩导致效率低下太大会引入非 2D 的纵向模式。0.005~0.02 um 之间用的人最多。set(background index, 1.0)是因为我们做介质柱型结构背景是空气。如果是空气孔型这里要改成硅的折射率 3.48。5.4 偶极子与监视器的摆放逻辑偶极子放 (0.3a, 0.3a) 是避开了很多高对称位置0、0.5a、对角线中点等这样各种对称性不同的模式都有机会被激发。偏振角 90° 对应电场沿 z 方向也就是 TM 模式想算 TE 模式就设成 0°。两个偏振的能带结构不同我做 TM 带隙时会把偏振角写成set(polarization angle, 90)。监视器数量对新手来说有个误区不是越多越好也不是越少越好。放 4~6 个足够覆盖大部分模式关键是监视器的位置不能都落在同一个对称性上。我沿 (0,0) 到 (0.75a, 0.75a) 的斜线平均布置这样每个探测点看到的模式投影不同互补效果好。5.5 k点扫描循环怎么接上去上面的脚本只跑了单个 k 点默认 kx0, ky0。完整的能带图需要对布里渊区高对称路径上的每个 k 点分别设置 Bloch 相位、运行仿真、提取峰值频率。Lumerical 里 Bloch 边界的相移通过 FDTD 区域的kx、ky属性控制不同版本可能叫 kx 或 phase shift你可以在属性窗口里搜 kx。一个典型的 k 路径扫描脚本框架如下# 能带扫描主循环 - 以正方晶格 Gamma-X-M-Gamma 为例 # 这段脚本需要在上面的单胞模型基础上运行 # 定义 k 空间路径点k 的单位为 (2*pi/a) kx_path [0, 0.5, 0.5, 0]; ky_path [0, 0.0, 0.5, 0]; k_step 20; # 每段路径上的采样点数 k_index 0; for (seg 1:3) { for (i 1:k_step) { # 线性插值当前k点 t (i-1) / (k_step-1); kx kx_path(seg) t * (kx_path(seg1) - kx_path(seg)); ky ky_path(seg) t * (ky_path(seg1) - ky_path(seg)); k_index k_index 1; # 设置 Bloch 相位 setnamed(FDTD, kx, kx * 2 * pi / a); setnamed(FDTD, ky, ky * 2 * pi / a); # 运行一次 FDTD run; # 提取所有时间监视器的电场信号做FFT找峰值 # 这一步的结果写入 frequency_peaks 矩阵最后绘制能带 # 可以直接在脚本里用 findpeaks 函数也可导出数据后用 MATLAB/Python 画图 } } # 最后的绘图可以在 Lumerical 的 Result View 里做 # 也可以导出到外部工具画。推荐外部画排版可控。这里的核心逻辑是每个 k 点就是一次独立的 FDTD 仿真。因为晶胞很小、二维仿真很快20×3 个点总共 60 次仿真也就是一两小时以内的计算量。如果每次仿真还要等很久就先用mesh accuracy 2把流程跑通再升精度。提取峰值频率的短代码逻辑是对每个时间监视器的电场分量做 FFT → 找幅度峰的频率位置 → 把所有监视器的峰并集在一起剔除重复项得到该 k 下所有本征频率。Lumerical 自带的findpeaks函数可以辅助处理但如果监视器求解数据导出成 CSV 后用 Python 的 scipy.signal.find_peaks 处理也会很舒服后面画图也方便。6. 透射谱验证把禁带“看”出来能带图是理论验证透射谱是实战验证。一个真实的光子晶体器件——比如波导或滤波器——它的禁带效果最终要通过透射谱来体现在禁带频率范围内入射光透不过去。对你来说做一次透射谱仿真等于把能带图上那条抽象的禁带映射成一条能直观看到的下降凹陷。6.1 为什么要再做一次透射谱验证能带计算里的模式分析是理想化的周期无穷大、无损耗、单胞单元。你永远不知道这些模式是否能和真实的光源耦合起来也不清楚在有限周期结构里禁带的屏蔽能力有多强。透射谱告诉我们一个有限周期比如 8×8 或 10×10的光子晶体块放在自由空间里正入射平面波经过它之后传输了多少功率。如果禁带设计正确透射谱会在对应频率区间出现明显的透过率骤降比如从 0.9 降到 0.05 以下。这就是你能在论文里直接用的验证图。6.2 有限周期结构模型N×N阵列透射谱仿真和能带计算在结构上有区别。能带计算只放一个晶胞透射谱要放一组有限阵列。以正方晶格为例你可以用脚本快速生成一个 8×8 的硅柱阵列放在仿真区域中间。仿真区域设置很关键x 和 y 方向即光传播方向和横向的边界用 PML模拟开放空间z 方向依然用 PEC 或小的 PML。光源用平面波从一侧入射另一侧放一个功率监视器测透过功率。另外还需要一个没有光子晶体结构的参考仿真叫归一化把两次透过功率相除得到真正的透射率。6.3 透射光谱脚本片段与结果解读下面的片段在现有光子晶体建模脚本基础上修改重点展示结构阵列和光源监视器的设置# 透射谱仿真 - 有限周期正方晶格光子晶体 deleteall; a 0.55; # 晶格常数 um r 0.18; # 半径 um n_si 3.48; N 8; # 每个方向的周期数 # FDTD 区域 addfdtd; set(dimension, 2D); set(x, 0); set(y, 0); set(z, 0); set(x span, N*a 2.0); # 留出空气间隔 set(y span, N*a 2.0); set(z span, 0.01); set(x min bc, PML); set(x max bc, PML); set(y min bc, PML); set(y max bc, PML); set(z min bc, PEC); set(z max bc, PEC); set(background index, 1.0); set(mesh accuracy, 2); # 生成 N x N 硅柱阵列 for (i 1:N) { for (j 1:N) { addcircle; set(name, rod_ num2str(i) _ num2str(j)); set(radius, r); set(x, (i - N/2 - 0.5) * a); set(y, (j - N/2 - 0.5) * a); set(z, 0); set(index, n_si); } } # 平面波光源 addplanewave; set(name, pw); set(direction, backward); # 向后传播向左 set(x, 3.5); # 光源放在右侧远处 set(y, 0); set(z, 0); set(frequency, f_low, f_high); # 透射功率监视器 addpower; set(name, trans_power); set(monitor type, Linear X); set(x, -3.5); set(y, 0); set(z, 0); # 保存并运行 save(phc_2d_square_transmission.fsp); run;跑通之后选一个和仿真完全相同但没有硅柱的文件再跑一遍得到背景透过功率。两条曲线相除就是归一化透射谱。结果图上你会在某个波长区间看到很大的凹陷那个凹陷对应的频率范围就和能带图里的 TM 禁带大致重叠。有一个细节值得提平面波源的频率范围要和之前能带计算一致才能直接对比。另一个容易出错的点是set(direction, backward)的方向符号不同版本可能写法不同最好是先用平面波监视器看一眼传播方向再决定放在左边还是右边。7. 结果判读与新手最容易搞混的地方跑完能带脚本后接下来是重头戏——怎么知道结果对不对。7.1 能带图的纵轴和横轴到底是什么Lumerical 官方模板画出的能带图横轴是沿布里渊区高对称点路径的归一化波矢坐标纵轴通常是频率。但从原始仿真数据里提取的频率是实际频率Hz需要先换算成归一化频率 a/λ。换算公式是 f_norm f × a / c0其中 c0 以 um/fs 为单位时所有单位要对应上。新手最常犯的错误是直接把赫兹数当作归一化频率去比对文献结果差了好几倍。比如前面那个例子里a0.55um、带隙范围实测频率约 1.5e14 Hz 到 2.2e14 Hz归一化后是 0.27 到 0.40文献里常见的就是这类 0.2~0.4 的数字。你看到0.27 到 0.40才能和人家论文对上号。7.2 归一化频率换算回真实波长的公式与实例归一化频率和实际波长的关系就像单位的密钥a/λ f_norm所以 λ a / f_norm。套进例子a0.55um、带隙在归一化频率 0.27~0.40换算成实际波长就是 1.375um 到 2.037um。这正好落在近红外通信波段附近所以硅基光子晶体在光通信波段的器件设计里特别常见。这块我建议你在脚本里写一个小的换算函数随时把仿真频率、归一化频率、波长一起打印出来省得每次手动算。7.3 TE与TM模式为什么看同一张图会吵起来偏振不同能带结构不同这是光子晶体里最常见的争吵来源。TM 模式下电场沿着柱子方向光更容易被柱子阻挡介质柱型结构通常有较宽的 TM 禁带TE 模式下电场在平面内光可以在空气区域溜过去带隙往往更窄甚至消失。所以当你说我的光子晶体有个带隙时一定要搞清楚说的是哪个偏振。论文里的能带图通常会把 TE 和 TM 两张图画在一起或者用实线/虚线区分。自己做仿真时至少在脚本阶段明确当前跑的是哪个偏振。偶极子源的polarization angle一变能带图可以差得非常多。7.4 怎么确认禁带是真实的而不是数值噪声这是决定你论文结论靠不靠谱的关键一步。我建议用三个手段交叉验证网格收敛性测试把 mesh accuracy 从 2 提到 4 或 5重跑一次看禁带的上下边界变化是否小于 1%~2%。如果网格变密后带隙位置大幅漂移说明之前的网格太粗结果不可靠。仿真时间加长把 simulation time 从 1000 fs 加到 3000~5000 fs看频率峰是否更加锐利带边界是否稳定。如果一些峰的位置随仿真时间明显变化说明没收敛到稳态。透射谱交叉验证用第 6 章的方法做有限周期透射谱看透过率凹陷的频率区间和能带禁带是否一致。这是最让人信服的验证方式别人审你的图时也最认这个。8. 照着跑一遍也会踩的坑我的真实排错记录最后分享几个我刚开始用 Lumerical FDTD 时踩过的坑有些坑在官方文档里根本找不到现成的说法只能靠试和经验。8.1 问题一仿真跑完了能带图上一堆乱峰症状FFT 之后出来的幅频曲线像一片草一样没有清晰的峰或者峰多到无法判断哪些是真实的模式。原因排查下来通常是两类一是仿真时间太短频谱分辨率不够相邻模式搅拌在一起二是监视器放在了一些场的节点位置每个监视器都漏了一部分模式合并时又产生了一些幽灵峰。我的解决方法是先把仿真时间从默认值拉到 4000~5000 fs然后增多监视器数量同时把监视器的位置从规则网格改到偏离对称性的位置比如 (0.2a, 0.15a)、(0.35a, 0.28a) 这种非对称坐标。这么做之后峰瞬间变得干净很多。8.2 问题二透射谱怎么调都衰减不到零症状理论上应该在禁带频率出现透射深谷但实际只有 20%~30% 的下降跟能带图对不上。原因可能是阵列周期数太少比如只有 3×3禁带效果还不够强或者平面波入射角度不正再或者边界条件把部分光反射回了仿真区域。我建议把周期数增加到 8×8 以上再试同时把 PML 层数从默认的 8 调到 16 或 32观察透射深谷是否改善。这一步往往是周期性下落和边界反射叠加的结果。8.3 问题三内存爆了电脑直接卡死症状网格精度调高后一运行内存直接占满电脑卡到鼠标都动不了。二维仿真还好三维光子晶体加高精度网格很容易爆内存。解决思路是先用mesh accuracy 2跑通流程确定结果物理合理后再局部加密如果局部加密还是爆可以手动在感兴趣的介质边界附近添加网格覆盖区域而不是全局提高网格精度。Lumerical 里的addmesh工具可以只加密某个矩形区域这个功能对光子晶体特别实用——介质柱表面是场变化最剧烈的地方加密那里就够了。8.4 问题四脚本报错对象不存在症状setnamed(FDTD, kx, 0.5)时提示找不到名为 FDTD 的对象或者运行到一半说监视器名不存在。这类问题百分之八九十是对象命名不一致。脚本里创建对象后我习惯立刻set(name, ...)明确命名后面统一用setnamed操作避免依赖当前选中对象这个隐式状态。还有一个坑当你用save保存模型后再次load时对象树会重建如果你的setnamed调用在load之后却没有先运行创建对象的代码对象肯定不存在。所以完整的能带扫描脚本要在循环之前保证模型对象已经创建完毕循环内部只改参数和运行。8.5 给新手的最终建议照着这篇博文跑一遍你至少能收获一个能跑通的光子晶体模型、两条验证禁带的独立路径、以及对 Lumerical 脚本的基本手感。我个人的体会是FDTD 仿真入门最难的地方不是软件操作而是建立对结果的判断力——什么是合理的、什么是不合理的。你可以通过快速地调一个参数比如把 r/a 从 0.3 改成 0.4看结果是否向预期方向变化来训练这种判断力。最后再分享一个小技巧光子晶体仿真的脚本最好用版本管理工具或者 git 管起来每次改参数前先存一个版本。我早期就吃过调了半天参数结果却叠加了很多改动最后完全不知道哪个改动导致了哪个变化的亏。把每个仿真对应的脚本和参数存好你的研究效率能提升一大截。做仿真的本质不是把软件跑通而是把一个可复现、可追溯的计算过程握在手里。