资讯动态

FDTD近远场变换实战:从近场记录到远场方向图

发布时间:2026/10/27 16:56:52 来源:尧图企业网站定制
简介基于FDTD时域有限差分方法的MATLAB近远场转换程序面向电磁仿真方向学生以及天线设计、雷达散射等相关研究人员解决FDTD只能直接计算近场数据、难以输出远场方向图的常见问题。压缩包内共1个m脚本包体仅4KB核心程序near_to_far_EM.m清晰展示了完整仿真链路FDTD网格与时间步长选择、激励源设置、PML吸收边界、时域逐步迭代、近场数据暂存随后利用傅里叶变换将时域近场转换到空间频域远场并生成方向图结果。代码模块划分明确关键环节均有注释既适合初学者借此理解FDTD原理与近远场变换流程也能为中高级研究者提供可修改、可拓展的算法参考在MATLAB中直接打开即可运行无需额外依赖。这一程序已有829人学习下载对于天线辐射效率分析、远场特性评估等实际工程场景具有直接借鉴价值是MATLAB环境下学习电磁仿真的实用材料。1. near_to_far_EM.zip 是什么为什么 FDTD 的近远场变换值得单独打包看到near_to_far_EM.zip这类包名时做 FDTD 近远场near to far的人多半会心一笑这又是一套把电磁仿真工程、监视器设置和远场后处理脚本绑在一起的成套工具。FDTD 仿真本身算的是近场区域的时域响应但天线、散射、光栅周期结构真正要交出去的是远场方向图、增益和波束形状。near_to_far_EM.zip 要解决的就是这条从“记录面电磁场”到“无限远方向图”的链路。这套东西适合想快速拿到远场数据又不想每次重新搭流程的人无论是验证贴片天线、估算纳米天线偏振转换效率还是做光栅衍射分析都需要“近场记录 → 远场投影 → 方向图输出”三步。你不需要理解全部电磁理论但必须知道记录面布在哪里、哪个函数做了变换、哪些参数不能乱调。下面把我的做法和踩过的坑拆开讲。2. 近远场变换的原理与关键参数从近场记录到远场方向图中间发生了什么2.1 为什么不能直接仿真远场而要用近远场变换刚开始做 FDTD 时我一度想把探针放在仿真区域很远处直接测远场。结果发现既不经济也不正确。FDTD 的仿真区域被完美匹配层PML截断边界之外没有真实网格探针放不进去就算把边界扩大远场区要仿真十几个波长甚至几十个波长网格数量会爆炸时域收敛也慢得多。近远场变换是一种后处理在结构周围取一个闭合面记录面上每一处的切向电场和磁场然后用 Huygens 等效原理把这层虚拟面上的电磁流当辐射源外推到任意远的观测点。这个变换不要求物理空间里真的存在那些远场距离所以可以在小仿真区域内完成任务。通俗说FDTD 只负责把近场“黑匣子”内的场算准近远场变换负责把黑匣子表面的信息翻译成远区方向图。这里有个容易误用的点近远场变换的输入是切向场不是某个点的单一场分量。因此记录面必须能同时拿到 E 和 H如果你只放了一个电场监视器换出来的只是近似结果幅度和相位都会有问题。常见做法是放一个电场监视器记录 E另外再用磁场监视器记录 H或者直接用能同时输出 E/H 的 monitor 类型。我一般会把这个闭合面做成六个平面上、下、左、右、前、后而不是只放一个平面否则等效面不闭合辐射源会“漏”。还有一个维度上的细节三维仿真要用闭合面二维仿真则是一条闭合曲线。很多人在二维光栅仿真里只放一条直线监视器然后去做远场出来的方向图只有对称平面上的形状缺失了另一维空间的扩展。如果你做的是 2.5D 或旋转对称结构最好先用解析解算一遍确认模型维度再决定监视器形态。这里最容易翻车因为软件不报错但结果物理上是错的。2.2 近场记录面的布设与采样参数记录面放哪里直接决定远场能不能用。放太近结构表面的倏逝波还没衰减会被当成辐射源方向图在某些角度出现假的旁瓣放太远可能会伸进 PML 区域或者把仿真区域撑大好几倍白白拖慢求解。我常用的经验值是记录面离结构表面约 0.51 个波长。对于介质天线或纳米结构这个距离足够让高次模衰减又不至于影响硬件开销。另一个关键参数是记录面上的空间采样。近远场变换本质是对面上场做带限插值如果面网格太粗高角度部分会折叠方向图主瓣旁边会出现栅瓣如果网格太细仿真内存和脚本运行时间成倍上涨。我一般建议记录面网格在 λ/10 以内。对于大尺寸结构可以在远离结构的面上适当放宽但最低不要低于 λ/15否则微带天线这类低 Q 结构的相位误差会直接变成主瓣指向偏差。下表是我做近远场仿真时常用的一组起点参数参数推荐值说明记录面类型闭合六面体六个面都要记录 E 和 H记录面到结构距离0.51 波长避开倏逝波也不要进 PML面网格步长λ/10 以内太粗出栅瓣太细拖慢分析频率单频优先宽带就要逐点做远场投影角度范围theta -90°90°phi 0360°覆盖上半空间或全空间频率点这里多说一句。FDTD 一个宽带脉冲能算出一段频率内的近场但farfield3d这类函数每次只对一个频率做变换。如果你要 1.51.6 GHz 的完整方向图最好在脚本里循环频率点而不是一次想拿全频带远场。循环次数多了后处理时间线性增长但至少结果可控。从工程效率看我一般先开一版短仿真只跑 5000 个时间步把记录面远近粗调一遍确认方向图主瓣位置没有跳变再开始细网格和长仿真。这样做的好处是近远场变换对记录面位置的敏感性可以尽早暴露。否则一上来就全尺寸跑等到出图才发现记录面离结构太近只能重新跑白白烧掉半天机时。2.3 脚本语言里的 addmode 与 farfield3d模式激励到远场的一条龙很多人一开始是在 GUI 里点按钮做远场投影但工程一多就得脚本化。Lumerical 的脚本语言里有两个命令最常用addmode用来加模式光源farfield3d用来做远场投影。模式源对波导型器件尤其重要。我先给一个最小脚本# Lumerical 脚本模式源激励 近远场变换 lambda0 1550e-9; freq c / lambda0; # 添加模式源并选到你要的传播模式 addmode; set(name, mode_source); set(wavelength, lambda0); # 模式序号按软件版本可能是 mode selection / mode index查看属性后修改 set(mode selection, 1); # 执行 FDTD 仿真 run; # 对名为 near_field_box 的监视器做远场投影 Efar farfield3d(near_field_box, freq, -90, 90, -180, 180);这段脚本的逻辑很直白先定义波长和频率addmode创建模式源run跑完时域仿真最后farfield3d把近场监视器上的时域结果变换成指定角度网格上的远场电场。farfield3d的角度参数分别是 theta 起始/结束角和 phi 起始/结束角单位是度。需要说明的是mode selection这个属性名在不同版本里有过调整有的叫mode index有的叫selected mode。第一次跑的时候别懒先选中模式源对象用set配合属性名补全否则模式选不对后面所有方向图都会偏。farfield3d返回的Efar通常是一个结构体或大矩阵包含 theta 网格、phi 网格以及对应的电场复振幅。输出格式因版本而异别硬记字段名先执行完这条命令在工作区里打印一下Efar的字段再继续。这也是我反复踩坑后学到的习惯脚本函数签名可以靠记忆返回结构只能靠现场看。脚本化还有一个好处是“后悔药”。GUI 里点错一个角度范围就废一张图脚本里只要把角度循环包一层就能自动输出多个切面和多个频率点。我习惯把addmode、set、run、farfield3d四步写成一个独立函数参数放在文件头。以后换结构时只改监视器名和波长列表不用再进 GUI 一步步点。这个习惯在交付多个频点方向图时特别省力。3. 从 near_to_far_EM 工程到远场数据最小可复现操作流程3.1 拿到工程包后先检查的三件事我不会拿到near_to_far_EM结构就先跑仿真。先检查三件事可以省一晚上排错时间。第一记录面是不是闭合的。常见工程包里放了一个或者两个平面监视器这在某些定向辐射问题里够用但如果是散射问题或者半球方向图单面监视器算出来的结果会缺一块。我会在 GUI 里把监视器对象全部列出来确认六个方向的监视器都在。第二监视器名字和脚本里的字符串是否一致。脚本是死板匹配对象名的大小写差一个字母farfield3d直接报错或者静默计算空数据。第三检查当前分析的频率点是否落在监视器记录的频谱范围内。如果监视器的频率限制太窄就算近场记录到了远场变换也会得到一堆 NaN。下面这段脚本用来检查监视器名和频率范围可以直接贴在脚本开头# 检查监视器是否可被远场变换使用 monitor_name near_field_box; select(monitor_name); ? get(name); # 确认选中对象和名字匹配 ? get(wavelength start); ? get(wavelength stop); # 如果返回的是空或0说明这个监视器没做频率记录这里为什么用select加get在 FDTD 脚本里select是按名字选中对象get读属性。这一步的价值是把“脚本里写的名字”和“工程里实际的对象名字”对一遍避免后续函数用错对象。很多人一上来就调farfield3d报错后才发现监视器名字少了一个字母这类低级问题最浪费生命。3.2 配置并校验记录面空间采样如果工程包里的监视器已经存在但网格采样不确定我会把监视器的空间步长读出来按 2.2 节的判断标准校准。这一步不能省Lumerical 的监视器默认为“自动采样”仿真时实际采样点取决于 FDTD 网格网格粗的地方记录面也跟着粗直接导致远场栅瓣。一种稳定的做法是手工指定记录面上的采样步长并且让记录面的法向和切向都满足 λ/10。脚本如下# 设置监视器空间采样 select(near_field_box); set(use span, 1); set(x span, 1.5e-6); set(y span, 1.5e-6); set(z span, 1.5e-6); # 关键参数把记录面网格压到 lambda/10 以下 set(spatial interpolation, accurate); set(x step, 1e-7); set(y step, 1e-7); set(z step, 1e-7);这段脚本里的x step等参数在不同版本里叫法略有差异但思路是一致的手动指定步长而不是让软件按 FDTD 网格默认生成。我习惯把记录面的步长取成 λ/10波长 1550 nm 时步长约 155 nm如果设备是金属纳米结构建议更细到 λ/15。设置完之后跑几十步就够检查不用完整仿真直接在监视器结果里看记录面网格数是否达到预期。这里需要提醒一个计算量陷阱记录面网格从 λ/10 加密到 λ/20内存占用不是线性翻倍而是随采样点平方增长。如果只需要 090° 的半球方向图把记录面尺寸缩小而不是无限加密。很多新手沉迷于“精确”把记录面设到 λ/40结果仿真内存爆了。近远场变换不是 FDTD 求解它的精度受限于输入近场精度而近场精度由 FDTD 网格决定不是记录面越细越好。另外监视器平面不一定正好落在 Yee 网格的电场或磁场采样位置。如果记录面与结构表面平行但坐标不在网格中心近场监视器会做插值插值误差在快速变化的近场区会被放大。我一般会把监视器放到网格节点对齐的位置方法是在脚本里把坐标取成网格步长的整数倍或者干脆用软件的对齐功能吸附到网格。这个细节对微带馈电这类强局域场特别重要。3.3 运行近远场提取从近场监视器到远场矩阵检查完监视器就可以跑正式流程。我给的流程是先run跑完 FDTD然后调用farfield3d输出远场再保存成.mat文件供外部绘图的脚本。# 近远场提取主流程 monitor near_field_box; freq c / 1550e-9; # 执行仿真如果之前跑过这步会重新算注意开关 run; # 核心变换theta -90~90phi 0~360 far farfield3d(monitor, freq, -90, 90, 0, 360); # 取远场电场幅度归一化后保存 theta far.theta; phi far.phi; F abs(far.E)^2; F F / max(F(:)); # 保存为 mat 文件供 Python 或 MATLAB 画图 save(far_field.mat, theta, phi, F);逻辑说明run会重新执行整个 FDTD 仿真如果你的工程很大但近场结果已经存在不需要每次重跑可以把run注释掉直接执行下面的变换。farfield3d的输入里freq是 Hz 的频率而不是角频率我习惯写成c/lambda避免用波数混淆。返回的far.E是复数电场abs(far.E)^2得到辐射强度max(F(:))做归一化是为了后面对比方向图形状。save保存的是矩阵数据不是图片。之所以建议这一步就落盘是因为farfield3d在交互式会话里计算结果驻留在内存一旦脚本重跑或软件重启远场矩阵就丢了。先存成.mat后面不管用哪套绘图工具都不愁。如果在执行farfield3d时返回 NaN多半是监视器上没有记录到数据或者频率越界。先检查run之后监视器的近场数据是否合法再检查频率设置。有一个比较隐蔽的原因某些版本里farfield3d要求监视器必须在“远场投影范围”内超出等效面支持的最高角分辨率就会在边缘返回 NaN。这时候把角度范围缩小或者把监视器向外移nan 就消失了。3.4 用 Python 把远场矩阵画成方向图.mat文件用 MATLAB 直接打开最方便但很多团队后处理统一用 Python我就用scipy.io.loadmat读数据再画不同切面的方向图。下面代码读取并画 H 面切面import numpy as np from scipy.io import loadmat import matplotlib.pyplot as plt # 读取保存的远场数据 d loadmat(far_field.mat) theta np.radians(d[theta].flatten()) phi np.radians(d[phi].flatten()) F d[F] # 假定 F 的形状是 (nphi, ntheta)取 phi 0 切面 idx_phi 0 U F[idx_phi, :] # 绘制极坐标方向图 plt.figure(figsize(6, 6)) ax plt.subplot(111, projectionpolar) ax.plot(theta, U, lw2, labelphi0) ax.set_theta_direction(-1) ax.set_thetamin(-90) ax.set_thetamax(90) plt.legend() plt.tight_layout() plt.savefig(far_field_phi0.png, dpi200)参数说明theta和phi在保存时已经是度读进来要转成弧度再用极坐标投影。set_thetamin和set_thetamax把横轴范围限制在 -90° 到 90°方便看前半球。idx_phi控制取哪个方位切面一般先取 0 和 90 度两个正交切面分别对应 E 面和 H 面。有个小坑某些 FDTD 版本输出theta的顺序是从 -90 到 90而另一些版本是 0 到 180绘制前先打印theta.min()和theta.max()否则极坐标图会反向翻转主瓣位置看着像镜像。我指导过的好几个项目都出现过这个问题最后都是先打印范围解决。4. 近远场脚本调试与常见问题排查方向图偏移、增益误差和 GPU 加速的坑4.1 远场主瓣角度整体偏移现象仿真天线中心频率 2.45 GHz方向图主瓣应该在 30°结果脚本画出来是 -25°或者从 30° 变成 130°明显翻转。原因这个现象多数不是 FDTD 算错了而是坐标定义和角度范围不匹配。一种情况是监视器记录面的法向坐标系与远场函数默认的 theta 起始方向不一致。比如记录面放在 Z 平面而脚本里farfield3d的 theta 范围是 -90° 到 90°软件默认从 X 或 Y 开始转看到的主瓣位置就会在另一个象限。另一种情况是记录面没有闭合只有部分面有场等效面的法向向量不完整远场投影后出现镜像瓣。解决先画一张近场记录面上的 E 分布确认激励源的传播方向与记录面法向是否一致。然后在脚本里固定 phi 的切面打印主瓣对应的 theta 角再和理论对比。我通常会在脚本开头设置一个theta_offset变量如果记录面法向绕轴转了 90°就把角度范围整体偏转而不是硬拗数据。还有一种更快的验证把光源换成理想偶极子激励算出来的方向图理论上肯定有解析对称性如果主瓣角度还是偏那就不是结构问题而是坐标约定问题。4.2 远场强度比预期低好几个 dB现象同一结构文献里峰值增益 8 dBi我这边算出来只有 2 dBi方向图形状差不多但幅度整体往下沉。原因最常见的是记录面不闭合导致一部分辐射功率从缺口漏走。我遇到过只放了顶面和底面记录面、前后左右没放的情况远场幅度直接扣掉一半。另一个常见原因是监视器太靠近结构近场内包含大量非辐射场远场变换时这些非辐射分量会干扰幅度。解决把记录面改成闭合六面体并向外移到 0.5 个波长以上。改完再看幅度一般能恢复几个 dB。还有一点是归一化基准如果你把远场除以了源功率但源是模式源时功率没归一化到 1 W那结果自然低。在脚本里检查光源的“power”设置或者用方向性系数计算见第 5 章方向性系数与激励功率无关。如果方向性系数和你预期接近说明幅度问题是归一化而不是仿真错。这里有个容易忽略的点近场记录面如果被 PML 部分吸收等效面上会缺角。解决办法是把监视器整体向内收一点确保六个面都在 PML 内边界之前。判断方法很简单在近场场图上看到边缘幅度突然衰减基本就是被 PML 摸到了。我之前有一次怎么调都少 3 dB最后发现盒子一个角伸进了 PML收回来立刻正常。4.3 GPU 开了但脚本还是很慢现象仿真的 FDTD 求解部分在 GPU 上跑得很快但一执行farfield3d就转圈十几分钟都出不来或者整个脚本调用run也没感觉到 GPU 加速。原因FDTD 求解器支持 GPU 加速但远场变换是后处理多半跑在 CPU 上而且farfield3d是对整个角度网格做双重积分复杂度与角度步长的平方成正比。如果把角度步长设到 0.1°相当于 91×3601 个角度点再叠加记录面的空间采样后处理自然比求解还慢。另外如果脚本里用了addmode后没有在求解器设置里勾选 GPU那么模式求解那一步也走 CPU。解决先确认 GPU 是否开启。在 Lumerical 的仿真区域或求解器属性里找到 GPU 开关把目标 GPU 选上同时把 FDTD 网格限制在显示卡显存能容纳的范围。然后单独把farfield3d的角度步长从 0.1° 放宽到 0.5° 或 1°波形形状不会有肉眼可见变化速度能快几十倍。最后把run和farfield3d拆开仿真跑完存 FDTD 结果后处理脚本单独读结果算远场不要每次调参数都从头跑时域。这属于工程上的常规优化没必要让 GPU 空转。还要注意显存占用。GPU 加速意味着 FDTD 网格数据要载入显存监视器记录面又会让近场数据留在显存里。如果显存不够软件会自动回退到 CPU表面上看着 GPU 开启实际计算设备还是 CPU。我一般会在运行日志里看设备类型确认这一轮真的跑在 GPU 上如果没有就先减网格或把监视器切分。近远场变换本身不是 GPU 加速的主要受益者别指望开了 GPU 后处理会起飞。4.4 远场结果和文献对不上现象结构参数照着文献复刻近场电场分布一致但远场方向图不一样半功率波束宽度差 5°旁瓣电平差 2 dB。原因文献可能用的是不同频率点或不同极化分量。近远场变换通常输出两个正交极化分量你要比较的是共极化还是交叉极化如果不做极化分离直接看幅度就会出现“方向图峰值相同但波束宽度不对”。另一种可能是监视器的频率范围没覆盖到傅里叶变换的有效频带导致频谱泄漏方向图在边界处振荡。解决先分极化分量比较确认文献给的是总场还是某个极化分量。再检查监视器的时间窗有没有截干净FDTD 默认会自动判断收敛但强谐振结构需要更长的运行时间如果仿真没充分收敛远场会在低电平区出现波纹。我会人为地把仿真时间延长 20% 再算一次如果方向图变化小于 0.1 dB说明收敛如果变化明显就是截断伪迹需要调整运行时间而不是怀疑后处理。我在做硅光波导交叉的时候遇到过这类问题近场 E 分布和文献完全一致远场旁瓣偏高。后来发现文献的远场没有包含衬底漏模而我的记录面把衬底方向也算进去了。近远场变换是“记录面上所有场都等效成辐射”它不会替你区分导波和辐射。如果你只关心结构上半空间就把记录面做成一个带底面的半封闭盒或者在后处理时把底面贡献去掉。这里没有通用标准答案关键是要知道文献的统计口径。5. 进阶把 near_to_far 结果变成工程可用的方向图与偏振效率5.1 用角度网格积分算方向性系数远场幅度归一化只能看形状不能直接当增益。要报告“方向性系数”需要对辐射强度做球面积分。假设你已经把F存成了网格数据使用下方 Python 代码import numpy as np # theta 和 phi 单位是度先转弧度 theta np.radians(d[theta].flatten()) phi np.radians(d[phi].flatten()) U d[F] # shape (nphi, ntheta) # 方向性 4*pi*Umax / ∫∫ U sinθ dθdφ sin_theta np.sin(theta) integral np.trapz(U * sin_theta, theta, axis1) integral np.trapz(integral, phi) D_max 4 * np.pi * U.max() / integral D_dBi 10 * np.log10(D_max) print(f峰值方向性: {D_dBi:.2f} dBi)这里np.trapz是梯形积分精度足以应付大多数方向图。注意事项积分前确认theta是 0 到 180°。如果farfield3d输出的是 -9090°要加 90° 平移成球坐标的 theta否则sin(theta)会出现负值积分结果彻底错误。这也是我在 4.1 节强调角度范围的原因。5.2 偏振转换效率的远场积分纳米天线和光栅常见需求是计算偏振转换效率PCE。定义是交叉极化辐射功率占总辐射功率的比例。近远场输出一般按E_theta和E_phi或者两个正交线性分量存只要把对应分量做功率积分再比一下即可# 假设 far.E 里有 E1 和 E2 两个正交分量 E1 d[E1] E2 d[E2] U_total abs(E1)**2 abs(E2)**2 U_cross abs(E2)**2 # 根据坐标定义确定哪个是交叉极化 PCE np.trapz(np.trapz(U_cross * np.sin(theta), theta, axis1), phi) / \ np.trapz(np.trapz(U_total * np.sin(theta), theta, axis1), phi) print(PCE: , PCE)参数说明这个计算成立的条件是记录面闭合且角度网格覆盖了整个辐射半球。如果记录面只取了前向区域PCE 会偏大或偏小因为漏掉的方向可能以某种偏振为主。换算成 dB 时PCE 通常写成 dB但别把 0.3 直接写成 -5 dB 而不说明基准。我一般在报告里写百分比和 dBi 两列。偏振转换效率对近场监视器的相位一致性格外敏感。两个正交极化分量在监视器面上的相位差如果记录不准积分出的 PCE 会严重偏离。所以在跑 PCE 前先算一个已知结构的极化纯度做标定比如一个在 x 方向极化的线天线其交叉极化理论上应该非常低。如果基线都歪说明近场监视器的采样或校准不合适不要急着调后处理。5.3 验证手法换一个记录面位置结果必须不变近远场变换有一个很好的自检性质等效面放远一点或近一点最终远场方向图应该不变。我每次交付前会做一次“双层验证”在结构外 0.6λ 和 1.0λ 各放一组记录面跑完两组远场比较主瓣和旁瓣。如果两组结果几乎重合说明变换有效如果差异明显问题通常在近场记录精度而不是远场脚本。这时候回头改 FDTD 网格而不是继续调后处理参数。这个习惯也适用于判断监视器尺寸把记录面做大一圈方向图不该有明显变化。如果变了说明原来的记录面截断了一部分高角度辐射。我也用这个方式检查过不少从网上下载的near_to_far_EM类工程包有的包近场记录面离结构太近方向图像被污染过一样。把记录面外移后结果立刻正常。所以如果你准备长期做这类仿真我强烈建议不要只依赖别人给的监视器位置而是自己跑一次双层验证。这个习惯让我避免过不止一次误报误投希望也能帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑