sunsili 发表于 2024-4-2 11:48:56

OpenEMS 免费开源的电磁场求解器

OpenEMS 免费开源的电磁场求解器

“ openEMS 是一个使用 FDTD 方法的开源电磁场求解器。可以通过 Matlab、Octave 或 Python 接口调用。 ”

简介openEMS 是一款基于有限差分时域 (FDTD) 方法的免费开源电磁场求解器。它使用了 FDTD 方法的改进版本(称为等效电路 FDTD 或 EC-FDTD),在离散空间和时间中求解麦克斯韦方程,以三维全波方式直接模拟电磁波的传播。它具有分析射频/微波电路设计、天线、雷达、元材料和医学研究等重要应用问题的潜力。该引擎用 C++ 编写,通过一套广泛的 Matlab/Octave 或 Python 接口定义仿真,编程灵活。一个单独的库 CSXCAD 也是 openEMS 项目的一部分,用于处理 FDTD 仿真中使用的几何图形。为了帮助编程,还为 CSXCAD 提供了一个简单的图形用户界面,称为 AppCSXCAD,用于检查 3D 模型。该项目由杜伊斯堡-埃森大学通用和理论电气工程(ATE)实验室的 Thorsten Liebig 于 2010 年 2 月启动和维护。openEMS 采用 GNU 通用公共许可证第 3 版或更高版本,CSXCAD 采用 GNU 宽通用公共许可证第 3 版或更高版本。openEMS的仓库及文档:网站: https://openEMS.de文档: https://docs.openEMS.de
Github: https://github.com/thliebig/openEMS-Project
主要功能
[*]三维笛卡尔坐标(x,y,z)和柱坐标(ρ, φ, z)。
[*]全分级网格。
[*]子网格可减少柱坐标的模拟时间
[*]吸收边界条件(MUR、PML)
[*]vtk 或 hdf5 文件格式的时域和频域场转储
[*]用于天线仿真的近场到远场(NF2FF)变换。
[*]坐标相关材料定义
[*]坐标相关激励定义(例如模式分布)
[*]Matlab/Octave 和 Python 接口
[*]灵活的后处理例程(主要在 Matlab/Octave 中进行)
[*]多线程、SIMD(SSE)和 MPI 支持并行 FDTD。
[*]跨平台支持,包括 Linux、FreeBSD、macOS 和 Windows,并已在 x86、ARM 和 POWER9 CPU 上成功构建。
示例2.4 G 简易平面天线(Simple Patch Antenna)示例包含以下内容:

[*]设置平面(贴片)、基板和接地。
[*]设置叠加馈电端口。
[*]添加近场到远场(nf2ff)记录盒。
[*]计算天线的 S 参数。
[*]计算并绘制远场图案
导入库imp
ort
os, tempfile
from pylab
import
*

from
CSXCAD
import
ContinuousStructure
from openEMS
import
openEMS
from openEMS.physical_constants
import
*
通用参数设置Sim_Path = os.path.join(tempfile.gettempdir(), 'Simp_Patch')

post_proc_only = False

# patch width (resonant length) in x-direction
patch_width= 32
#
# patch length in y-direction
patch_length = 40

#substrate setup
substrate_epsR   = 3.38
substrate_kappa= 1e-3 * 2*pi*2.45e9 * EPS0*substrate_epsR
substrate_width= 60
substrate_length = 60
substrate_thickness = 1.524
substrate_cells = 4

#setup feeding
feed_pos = -6
#feeding position in x-direction
feed_R = 50   
#feed resistance

# size of the simulation box
SimBox = np.array()

# setup FDTD parameter & excitation function
f0 = 2e9
# center frequency
fc = 1e9
# 20 dB corner frequency
FDTD设置
[*]将仿真限制为 30k 个时间步长
[*]定义-40 分贝的降低结束标准
FDTD = openEMS(NrTS=30000, EndCriteria=1e-4)
FDTD.SetGaussExcite( f0,
fc
)
FDTD.SetBoundaryCond( [
'MUR'
,
'MUR'
,
'MUR'
,
'MUR'
,
'MUR'
,
'MUR'
] )


CSX = ContinuousStructure()
FDTD.SetCSX(CSX)
mesh = CSX.GetGrid()
mesh.SetDeltaUnit(1e-3)
mesh_res = C0/(f0+
fc
)/1e-3/20
生成属性、基元和网格#initialize the mesh with the "air-box" dimensions
mesh.AddLine('x', [-SimBox/2, SimBox/2])
mesh.AddLine('y', [-SimBox/2, SimBox/2]          )
mesh.AddLine('z', [-SimBox/3, SimBox*2/3]      )

# create patch
patch = CSX.AddMetal( 'patch' )
# create a perfect electric conductor (PEC)
start = [-patch_width/2, -patch_length/2, substrate_thickness]
stop= [ patch_width/2 , patch_length/2, substrate_thickness]
patch.AddBox(priority=10, start=start, stop=stop)
# add a box-primitive to the metal property 'patch'
FDTD.AddEdges2Grid(dirs='xy', properties=patch, metal_edge_res=mesh_res/2)

# create substrate
substrate = CSX.AddMaterial( 'substrate', epsilon=substrate_epsR, kappa=substrate_kappa)
start = [-substrate_width/2, -substrate_length/2, 0]
stop= [ substrate_width/2,substrate_length/2, substrate_thickness]
substrate.AddBox( priority=0, start=start, stop=stop )

# add extra cells to discretize the substrate thickness
mesh.AddLine('z', linspace(0,substrate_thickness,substrate_cells+1))

# create ground (same size as substrate)
gnd = CSX.AddMetal( 'gnd' )
# create a perfect electric conductor (PEC)
start=0
stop =0
gnd.AddBox(start, stop, priority=10)

FDTD.AddEdges2Grid(dirs='xy', properties=gnd)

# apply the excitation & resist as a current source
start =
stop=
port = FDTD.AddLumpedPort(1, feed_R, start, stop, 'z', 1.0, priority=5, edges2grid='xy')

mesh.SmoothMeshLines('all', mesh_res, 1.4)

# Add the nf2ff recording box
nf2ff = FDTD.CreateNF2FFBox()
运行仿真if
0
:
# debugging only
    CSX_file = os.path.join(Sim_Path,
'simp_patch.xml'
)
if
not
os.path.exists(Sim_Path):
      os.mkdir(Sim_Path)
    CSX.Write2XML(CSX_file)
from
CSXCAD
import
AppCSXCAD_BIN
    os.system(AppCSXCAD_BIN +
' "{}"'
.format(CSX_file))

if
not
post_proc_only:
    FDTD.Run(Sim_Path, verbose=
3
, cleanup=
True
)
后处理和绘图f = np.linspace(max(
1e9
,f0-fc),f0+fc,
401
)
port.CalcPort(Sim_Path, f)
s11 = port.uf_ref/port.uf_inc
s11_dB =
20.0
*np.log10(np.abs(s11))
figure()
plot(f/
1e9
, s11_dB,
'k-'
, linewidth=
2
, label=
'$S_{11}
生成的图形文档及 Q&A
[*]https://wiki.openems.de/index.php/Main_Page.html
[*]https://github.com/thliebig/openEMS-Project/discussions
FDTD 教程:https://eecs.wsu.edu/~schneidj/ufdtd/index.php


)
grid()
legend()
ylabel(
'S-Parameter (dB)'
)
xlabel(
'Frequency (GHz)'
)

idx = np.where((s11_dB<
-10
) & (s11_dB==np.min(s11_dB)))[
0
]
if
not
len
(idx)==
1
:
print
(
'No resonance frequency found for far-field calulation'
)
else
:
    f_res = f[idx[
0
]]
    theta = np.arange(
-180.0
,
180.0
,
2.0
)
    phi   = [
0.
,
90.
]
    nf2ff_res = nf2ff.CalcNF2FF(Sim_Path, f_res, theta, phi, center=[
0
,
0
,
1e-3
])

    figure()
    E_norm =
20.0
*np.log10(nf2ff_res.E_norm[
0
]/np.max(nf2ff_res.E_norm[
0
])) + nf2ff_res.Dmax[
0
]
    plot(theta, np.squeeze(E_norm[:,
0
]),
'k-'
, linewidth=
2
, label=
'xz-plane'
)
    plot(theta, np.squeeze(E_norm[:,
1
]),
'r--'
, linewidth=
2
, label=
'yz-plane'
)
    grid()
    ylabel(
'Directivity (dBi)'
)
    xlabel(
'Theta (deg)'
)
    title(
'Frequency: {} GHz'
.format(f_res/
1e9
))
    legend()

Zin = port.uf_tot/port.if_tot
figure()
plot(f/
1e9
, np.
real
(Zin),
'k-'
, linewidth=
2
, label=
'$\Re\{Z_{in}\}
生成的图形文档及 Q&A
[*]https://wiki.openems.de/index.php/Main_Page.html
[*]https://github.com/thliebig/openEMS-Project/discussions
FDTD 教程:https://eecs.wsu.edu/~schneidj/ufdtd/index.php


)
plot(f/
1e9
, np.
imag
(Zin),
'r--'
, linewidth=
2
, label=
'$\Im\{Z_{in}\}
生成的图形文档及 Q&A
[*]https://wiki.openems.de/index.php/Main_Page.html
[*]https://github.com/thliebig/openEMS-Project/discussions
FDTD 教程:https://eecs.wsu.edu/~schneidj/ufdtd/index.php


)
grid()
legend()
ylabel(
'Zin (Ohm)'
)
xlabel(
'Frequency (GHz)'
)

show()
生成的图形文档及 Q&A
[*]https://wiki.openems.de/index.php/Main_Page.html
[*]https://github.com/thliebig/openEMS-Project/discussions
FDTD 教程:https://eecs.wsu.edu/~schneidj/ufdtd/index.php

页: [1]
查看完整版本: OpenEMS 免费开源的电磁场求解器