把Gerber变成电磁波:推荐一款基于Gerber的openEMS仿真工具 - gerber2ems
“ 画完PCB,打板之前,你是不是也心里打鼓:
“这根差分线到底90 Ω还是88 Ω?Stub 会不会把 5 GHz 信号打回原形?”
跑去借 50 GHz 网络分析仪?贵到哭。
用商业 SI 软件?授权费能再买一辆车。
别急,今天给你安利一个宝藏项目:gerber2ems,结合开源的 openEMS solver, 让你用家里电脑能跑 3D 全波 FDTD,直接看 S 参数、阻抗曲线,还带动画的那种! ”

项目背景Antmicro 这帮老哥日常给 FPGA、RISC-V 板子做高速接口,信号完整性必须过关。可他们偏偏钟爱开源:KiCad 画板、openEMS solver。于是干脆写了 gerber2ems:把“Gerber + 钻孔+ 叠层”一键翻译成 openEMS 能吃的 3D 模型,跑完还能跟 VNA 实测对波。项目指路
关于 openEMS 的使用,可以参考:
gerber2ems 是一个 Python 脚本,旨在使用开源工具简化信号完整性 (SI) 仿真流程。它接收 PCB 生产文件(Gerber、钻孔文件、叠层信息)作为输入,并使用 openEMS 来仿真走线的信号完整性性能。openEMS 是一款免费开源的电磁场求解器,采用 FDTD (时域有限差分) 方法:
https://github.com/thliebig/openEMS-Project/
安装 OpenEMS
安装以下软件包 (在 Debian/Ubuntu 上):
sudo apt updatesudo apt install build-essential cmake git libhdf5-dev libvtk9-dev libboost-all-dev libcgal-dev libtinyxml-dev qtbase5-dev libvtk9-qt-dev cython3 pippip install --break-system-packages numpy scipy matplotlib h5py setuptools# 推荐使用此命令,因为 Debian 安装的 numpy 版本较旧,常导致版本冲突
克隆仓库、编译并安装 openEMS。
建议使用 bb991bb3 这次提交 (commit),这是与 gerber2ems 一同测试过的最新版本。
git clone https://github.com/thliebig/openEMS-Project.gitpushd ./openEMS-Projectgit checkout bb991bb3git submodule update --init --recursive./update_openEMS.sh ~/opt/openEMS --pythonpopd
安装 gerber2ems 脚本
1. 安装依赖:
sudo apt install gerbv python3.11 pipxpipx ensurepath
2. 克隆并安装 gerber2ems:
gitclonehttps://github.com/antmicro/gerber2ems.gitpushd./gerber2emspipx install --system-site-packages .popd
ems2paraview 命令,还需运行 sudo apt install paraview python3-paraview。
你可以使用内置的示例来测试 gerber2ems。这些示例是我们的开源硬件信号完整性测试板(https://openhardware.antmicro.com/boards/si-simulation-test-board/)的切片,使用 KiCad SI wrapper生成。部分选定的示例在专用的 vna.csv 文件中包含了 VNA (矢量网络分析仪) 的测量数据,这使我们能够将 openEMS 的仿真结果与真实世界的测量数据进行比较。
cd ./gerber2ems/examples/stub_shortgerber2ems -a
如需快速查阅,请使用 gerber2ems --help。
要仿真一条走线,请遵循以下步骤:
准备输入文件并将它们放入 fab/ 文件夹 (详见PCB 输入文件准备部分)。
准备配置文件 simulation.json (详见配置准备部分)。
运行 gerber2ems -a (过程详见几何结构创建部分)。
在 ems/results 目录中查看结果 (详见结果部分)。
运行 gerber2ems -a --export-field 并使用 Paraview 查看电场动画 (详见 Paraview 部分)。
结果
下面展示了 stub_short 示例的仿真输出。该软件返回以下几类输出:
仿真过程中收集的阻抗和 S 参数数据,以带表头的 CSV 格式存储。
每次激励期间测量的各 S 参数的图表。

每次激励的 S-11 参数图。

每个激励端口的阻抗随频率变化的图表。

stub_short 示例包含一个 vna.csv 文件,可用于验证仿真结果。

项目准备
仿真整个 PCB 对资源消耗极大,因此,尽可能分离出一个小尺寸的感兴趣区域:不需要的走线、铺铜等都应移除。如果整个层都是多余的,你可以在后续步骤中移除它们。
应在坐标文件中使用虚拟元器件标记感兴趣的端口。其标号应以 "SP" 开头,后跟端口号。
钻孔文件的原点应置于左下角。
在现实中被端接且会存在于仿真中的每条走线或铺铜,都应使用仿真端口进行端接或连接到地。
目前,电容不参与仿真。对于高频仿真,可以用一条走线将其短路来近似处理。
脚本需要多个输入文件来创建几何结构。这些文件都应位于 "fab" 文件夹中,具体如下:
Gerber 文件 - 每个需要仿真的铜层都应有一个对应的 Gerber 文件,命名格式如下:"<可选文本>-<来自叠层文件的名称>.gbr"
叠层文件 - 一个描述 PCB 叠层的文件,名为 stackup.json。格式示例:
{"layers": [{"name": "F.Cu","type": "copper","color": null,"thickness": 0.035,"material": null,"epsilon": null,"lossTangent": null},{"name": "dielectric 1","type": "core","color": null,"thickness": 0.2,"material": "FR4","epsilon": 4.5,"lossTangent": 0.02}],"format_version": "1.0"}
钻孔文件 - Excellon 格式的带电镀通孔的钻孔文件。文件名应以 "-PTH.drl" 结尾。
坐标文件 - 描述端口位置的文件。文件名应以 "-pos.csv" 结尾。
坐标应相对于左下角给出。
端口的区域根据 simulation.json 文件中的 Width (宽度) 和 Length (长度) 值,使用下表中的公式计算:
| 旋转 [°] | X 范围 | Y 范围 | 波传播方向 |
| 0 | (PosX−Width/2,PosX+Width/2) | (PosY,PosY+Length) | 沿 Y 轴 |
| 90 | (PosX−Length,PosX) | (PosY−Width/2,PosY+Width/2) | 与 X 轴相反 |
| 180 | (PosX−Width/2,PosX+Width/2) | (PosY−Length,PosY) | 与 Y 轴相反 |
| 270 | (PosX,PosX+Length) | (PosY−Width/2,PosY+Width/2) | 沿 X 轴 |
文件示例:
# Ref Val Package PosX PosY Rot SideSP1 Simulation_Port Simulation_Port 3.0000 11.7500 180.0000 top
simulation.json 文件用于配置整个仿真过程。你可以在 example_gerbers 文件夹中找到示例文件。此文件中的所有尺寸单位均为微米 (micrometers)。该配置文件包含三个部分:
format_version - 指定配置文件的格式。编写新配置时,应使用最新的支持版本 (可在 constants.py 文件中查看)。
frequency - start 指定了感兴趣的最低频率,stop 指定了最高频率 (单位:Hz)。
max_steps - 仿真的最大步数,达到此步数后仿真将无条件停止。
pixel_size - 像素大小,单位为微米。用于 Gerber 转换 (默认值:5) (由于 libcairo 的限制,对于较大的板子需要增加此值,但应尽量保持其尽可能小)。
via/plating_thickness - 过孔电镀层厚度 (单位:微米)。
via/filling_epsilon - 过孔填充材料的介电常数。如果未填充,则应为 1。
inter_layers - 相邻 PCB 层之间 Z 轴上的网格线数量 (默认值:4)。
optimal - 基本网格间距 (单位:微米) (用于金属边缘的单元) (默认值:50)。
diagonal - 网格间距 (单位:微米) (用于有对角线路径的区域) (默认值:50)。
perpendicular - 网格间距 (单位:微米) (用于路径与网格垂直的区域) (默认值:200)。
max - 最大网格间距 (单位:微米) (用于板区之外) (默认值:500)。
cell_ratio/xy - 最佳相邻单元尺寸比 (X/Y 轴) (默认值:1.2)。
cell_ratio/z - 最佳相邻单元尺寸比 (Z 轴) (默认值:1.5)。
margin/xy - X/Y 轴的边距大小 (单位:微米) (网格超出 PCB 的距离) (默认值:1000)。
margin/z - Z 轴的边距大小 (单位:微米) (默认值:1000)。
margin/from_trace - 根据感兴趣网络的边界框限制仿真空间 (默认值:True) (如果为 False,则使用板的边界框)。
网格间距选项应遵循:
optimal<=diagonal<=perpendicular<=max<=λmin/10
ports 是一个端口列表。每个端口都有以下参数:
width - 端口宽度 (单位:微米)。
length - 端口长度 (端口目前由微带线片段组成,其长度应至少为网格单元尺寸的 8 倍) (单位:微米)。
impedance - 端口的端接阻抗 (驱动器或接收器的阻抗) (单位:欧姆)。
layer - 端口所在的铜层编号 (从顶部开始计数)。
plane - 微带线参考平面所在的铜层编号 (从顶部开始计数)。
excite - 仿真器是否应将此端口用作输入端口 (对于多个激励端口,它们将在单独的仿真中被激励)。
differential_pairs/traces 是被仿真信号的列表。每个信号可以有以下字段:
start_p, stop_p, start_n, stop_n - 用于信号的端口号 (差分对)。
start, stop - 用于信号的端口号 (单端走线)。
name - 可选名称,用于识别信号。
nets - 在生成网格时要包含的网络列表 (例如 ["/CSI_A_CLK_N","/CSI_A_CLK_P"])。如果未指定,将使用 netinfo.json 文件中的数据。如果该文件也不存在,则在生成网格时会考虑所有网络 (GND除外)。
这是一个通过 -g 标志启动的自动步骤。该脚本会定位创建几何结构所需的所有文件 (Gerber、钻孔文件、pnp 文件、叠层文件、仿真配置文件)。然后,它使用 gerbv 将 Gerber 文件转换为 PNG。接着,这些 PNG 被处理成三角形并输入到几何结构中。此过程还会添加过孔和端口的几何形状。所有物体都根据叠层文件放置在正确的 Z 轴高度上。
你可以使用 AppCSXCAD (在安装 openEMS 时已安装) 查看生成的几何结构,它被保存在 ems/geometry/geometry.xml 文件中。
这是一个通过 -s 标志启动的自动步骤。该脚本会加载几何结构和配置文件。它将所有信息输入引擎并开始仿真,对每个激励端口进行迭代。
在这一步,用户应验证指定的时间步数是否足够。引擎建议它至少是脉冲长度的 3 倍:
```激励信号长度为: 3211 时间步 (3.18343e-10s)最大时间步数: 10000 ( --> 3.11429 * 激励信号长度)```
仿真器将几何结构转换为 voxels,并开始为网格中的每个边求解麦克斯韦方程组。它会执行一定数量的时间步 (在配置中指定的最大数量),然后退出。对于每个时间步,来自铜层之间平面的电场数据被保存到 ems/simulation 文件夹的文件中。端口电压和电流数据也会被保存。
在仿真过程中,其中一个端口使用高斯脉冲 (具有宽带频率内容) 进行激励。这个脉冲穿过网络并从其他端口输出 (也可能辐射到板外)。
你可以通过查看引擎输出来监控仿真过程:
[@ 20s] 时间步: 4620 || 速度: 294.4 MC/s (3.372e-03 s/TS) || 能量: ~4.16e-16 (- 7.15dB)
通过这种方式,你可以看到:
当前处于哪个时间步
仿真器每秒处理多少网格体素
系统中剩余多少能量
在仿真过程中,能量应随着其通过端口离开而下降 (激励脉冲结束后),但由于不精确性和辐射能量,它不会降到 0。
仿真结束后,用户可以使用 Paraview 验证数据 (在下文的一个章节中描述)。
这是一个通过 -p 标志启动的自动步骤。该脚本会加载每个激励端口的仿真数据。然后,它进行 FFT (快速傅里叶变换) 以获取频域数据。接着,它将入射波和反射波数据转换为阻抗和 S 参数。这些数据以 CSV 格式保存在 ems/results/S-parameters 文件夹中。这些数据也会被自动绘制成图表,图表保存在 ems/results 中。
Paraview
要在 Paraview 中查看仿真数据,请遵循以下步骤:
运行 gerber2ems -a --export-field
运行 ems2paraview
是一个仿真的端口号,在 simulation.json 中定义,要列出所有可用端口,请使用:ems2paraview -l。
dump locations 可以省略 ,或者你可以从以下列表中选择一个或多个关键字:
outer - 在板表面上方 100 微米处转储场
cu-outer - 在外部铜层的 Z 坐标位置转储场
cu-inner - 在内部铜层的 Z 坐标位置转储场
substrate - 在每个介电层的中间转储场
--oversampling - 可以添加此项以增加导出场的频率 (通常 OpenEMS 每几百个时间步转储一次 Field) ( 默认值为 4)。
警告
Field 导出文件可能轻易占用数百 GB 的存储空间。
要生成动画,按以下步骤操作:
生成一个 PCB 的 blend 模型 (参见 picknblend:https://antmicro.github.io/picknblend/quickstart.html)
使用 --export-field 标志并增加过采样率 (--oversampling 16) 运行 gerber2ems
将生成的 *.vtr 文件转换为灰度 png 图片 (运行 ems2png)
在 blender 中打开 PCB 的 blend 文件,并附加 EMS_Plane (File>>Append..>>EMS_Plane.blend/Object/EMS_Plane)
设置平面尺寸 (它应与切片大小大致相同)
进入 Shading (着色) 工作区
在左侧的每个纹理节点中,点击文件夹图标并选择第三步生成的编号最小的 png (例如,第一条走线使用 simulation_images/e_field_0_0000,第二条使用 simulation_images/e_field_1_0000)。
如果动画只需要显示一条走线,用一个设置为黑色的 RGB 节点替换掉另一个纹理节点。
在纹理节点上,将源类型从 Single Image (单个图像) 更改为 Image Sequence (图像序列),并用相应走线生成的图像数量更新 Frames (帧数) 字段。
将视图模式设置为 rendered (渲染),并将 EMS_Plane 定位在 PCB 纹理上相应走线的正上方 (你可能需要切换到一个场较强且覆盖大部分走线的帧)。
选择 EMS_Plane 并在图像序列的第一帧和最后一帧应用任意类型的关键帧。
在 blendcfg.yaml 中添加一个新的预设:
ems_animation:CAMERAS:PHOTO1: truePOSITIONS:TOP: trueRENDERER:FPS: 25SCENE:RENDERED_OBJECT: Object/EMS_PlaneOUTPUTS:- ANIMATION:
13. 运行 pcbooth -b .blend -c ems_animation
提示
可以考虑创建一个新的 blend 文件,而不是直接使用 picknblend 的输出。在这个新文件中,将 picknblend 的输出作为链接的 blender 模型添加进来。这将允许你重复使用基础的 blender 模型来展示不同的走线仿真,并能防止 gerber2blend/picknblend 意外刷新模型。
结束语
虽然gerber2ems目前对复杂电源网络仿真支持有限,且大板子仍需高性能硬件支持,但它无疑为硬件开发者打开了信号仿真民主化的大门。下次做SI验证时,不妨让它帮你省下几千刀软件费!全部0条评论
快来发表一下你的评论吧 !