谷动谷力

标题: OpenEMS 免费开源的电磁场求解器 [打印本页]

作者: sunsili    时间: 2024-4-2 11:48
标题: 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
主要功能
示例
2.4 G 简易平面天线(Simple Patch Antenna)
示例包含以下内容:
导入库
  1. imp
  2. ort
  3. os, tempfile
  4. from pylab
  5. import
  6. *

  7. from
  8. CSXCAD
  9. import
  10. ContinuousStructure
  11. from openEMS
  12. import
  13. openEMS
  14. from openEMS.physical_constants
  15. import
  16. *
复制代码

通用参数设置
  1. Sim_Path = os.path.join(tempfile.gettempdir(), 'Simp_Patch')

  2. post_proc_only = False

  3. # patch width (resonant length) in x-direction
  4. patch_width  = 32
  5. #
  6. # patch length in y-direction
  7. patch_length = 40

  8. #substrate setup
  9. substrate_epsR   = 3.38
  10. substrate_kappa  = 1e-3 * 2*pi*2.45e9 * EPS0*substrate_epsR
  11. substrate_width  = 60
  12. substrate_length = 60
  13. substrate_thickness = 1.524
  14. substrate_cells = 4

  15. #setup feeding
  16. feed_pos = -6
  17. #feeding position in x-direction
  18. feed_R = 50     
  19. #feed resistance

  20. # size of the simulation box
  21. SimBox = np.array([200, 200, 150])

  22. # setup FDTD parameter & excitation function
  23. f0 = 2e9
  24. # center frequency
  25. fc = 1e9
  26. # 20 dB corner frequency
复制代码

FDTD设置
  1. FDTD = openEMS(NrTS=30000, EndCriteria=1e-4)
  2. FDTD.SetGaussExcite( f0,
  3. fc
  4. )
  5. FDTD.SetBoundaryCond( [
  6. 'MUR'
  7. ,
  8. 'MUR'
  9. ,
  10. 'MUR'
  11. ,
  12. 'MUR'
  13. ,
  14. 'MUR'
  15. ,
  16. 'MUR'
  17. ] )


  18. CSX = ContinuousStructure()
  19. FDTD.SetCSX(CSX)
  20. mesh = CSX.GetGrid()
  21. mesh.SetDeltaUnit(1e-3)
  22. mesh_res = C0/(f0+
  23. fc
  24. )/1e-3/20
复制代码

生成属性、基元和网格
  1. #initialize the mesh with the "air-box" dimensions
  2. mesh.AddLine('x', [-SimBox[0]/2, SimBox[0]/2])
  3. mesh.AddLine('y', [-SimBox[1]/2, SimBox[1]/2]          )
  4. mesh.AddLine('z', [-SimBox[2]/3, SimBox[2]*2/3]        )

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

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

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

  20. # create ground (same size as substrate)
  21. gnd = CSX.AddMetal( 'gnd' )
  22. # create a perfect electric conductor (PEC)
  23. start[2]=0
  24. stop[2] =0
  25. gnd.AddBox(start, stop, priority=10)

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

  27. # apply the excitation & resist as a current source
  28. start = [feed_pos, 0, 0]
  29. stop  = [feed_pos, 0, substrate_thickness]
  30. port = FDTD.AddLumpedPort(1, feed_R, start, stop, 'z', 1.0, priority=5, edges2grid='xy')

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

  32. # Add the nf2ff recording box
  33. nf2ff = FDTD.CreateNF2FFBox()
复制代码

运行仿真
  1. if
  2. 0
  3. :  
  4. # debugging only
  5.     CSX_file = os.path.join(Sim_Path,
  6. 'simp_patch.xml'
  7. )
  8. if
  9. not
  10. os.path.exists(Sim_Path):
  11.         os.mkdir(Sim_Path)
  12.     CSX.Write2XML(CSX_file)
  13. from
  14. CSXCAD
  15. import
  16. AppCSXCAD_BIN
  17.     os.system(AppCSXCAD_BIN +
  18. ' "{}"'
  19. .format(CSX_file))

  20. if
  21. not
  22. post_proc_only:
  23.     FDTD.Run(Sim_Path, verbose=
  24. 3
  25. , cleanup=
  26. True
  27. )
复制代码

后处理和绘图
  1. f = np.linspace(max(
  2. 1e9
  3. ,f0-fc),f0+fc,
  4. 401
  5. )
  6. port.CalcPort(Sim_Path, f)
  7. s11 = port.uf_ref/port.uf_inc
  8. s11_dB =
  9. 20.0
  10. *np.log10(np.abs(s11))
  11. figure()
  12. plot(f/
  13. 1e9
  14. , s11_dB,
  15. 'k-'
  16. , linewidth=
  17. 2
  18. , label=
  19. '$S_{11}
  20. [align=left]生成的图形[/align][align=left] [/align][align=left] [/align] [align=left]文档及 Q&A[/align][list]
  21. [*][p=24, null, left]https://wiki.openems.de/index.php/Main_Page.html[/p]
  22. [*][p=24, null, left]https://github.com/thliebig/openEMS-Project/discussions[/p]
  23. [/list]FDTD 教程:https://eecs.wsu.edu/~schneidj/ufdtd/index.php


  24. )
  25. grid()
  26. legend()
  27. ylabel(
  28. 'S-Parameter (dB)'
  29. )
  30. xlabel(
  31. 'Frequency (GHz)'
  32. )

  33. idx = np.where((s11_dB<
  34. -10
  35. ) & (s11_dB==np.min(s11_dB)))[
  36. 0
  37. ]
  38. if
  39. not
  40. len
  41. (idx)==
  42. 1
  43. :
  44. print
  45. (
  46. 'No resonance frequency found for far-field calulation'
  47. )
  48. else
  49. :
  50.     f_res = f[idx[
  51. 0
  52. ]]
  53.     theta = np.arange(
  54. -180.0
  55. ,
  56. 180.0
  57. ,
  58. 2.0
  59. )
  60.     phi   = [
  61. 0.
  62. ,
  63. 90.
  64. ]
  65.     nf2ff_res = nf2ff.CalcNF2FF(Sim_Path, f_res, theta, phi, center=[
  66. 0
  67. ,
  68. 0
  69. ,
  70. 1e-3
  71. ])

  72.     figure()
  73.     E_norm =
  74. 20.0
  75. *np.log10(nf2ff_res.E_norm[
  76. 0
  77. ]/np.max(nf2ff_res.E_norm[
  78. 0
  79. ])) + nf2ff_res.Dmax[
  80. 0
  81. ]
  82.     plot(theta, np.squeeze(E_norm[:,
  83. 0
  84. ]),
  85. 'k-'
  86. , linewidth=
  87. 2
  88. , label=
  89. 'xz-plane'
  90. )
  91.     plot(theta, np.squeeze(E_norm[:,
  92. 1
  93. ]),
  94. 'r--'
  95. , linewidth=
  96. 2
  97. , label=
  98. 'yz-plane'
  99. )
  100.     grid()
  101.     ylabel(
  102. 'Directivity (dBi)'
  103. )
  104.     xlabel(
  105. 'Theta (deg)'
  106. )
  107.     title(
  108. 'Frequency: {} GHz'
  109. .format(f_res/
  110. 1e9
  111. ))
  112.     legend()

  113. Zin = port.uf_tot/port.if_tot
  114. figure()
  115. plot(f/
  116. 1e9
  117. , np.
  118. real
  119. (Zin),
  120. 'k-'
  121. , linewidth=
  122. 2
  123. , label=
  124. '$\Re\{Z_{in}\}
  125. [align=left]生成的图形[/align][align=left] [/align][align=left] [/align] [align=left]文档及 Q&A[/align][list]
  126. [*][p=24, null, left]https://wiki.openems.de/index.php/Main_Page.html[/p]
  127. [*][p=24, null, left]https://github.com/thliebig/openEMS-Project/discussions[/p]
  128. [/list]FDTD 教程:https://eecs.wsu.edu/~schneidj/ufdtd/index.php


  129. )
  130. plot(f/
  131. 1e9
  132. , np.
  133. imag
  134. (Zin),
  135. 'r--'
  136. , linewidth=
  137. 2
  138. , label=
  139. '$\Im\{Z_{in}\}
  140. [align=left]生成的图形[/align][align=left] [/align][align=left] [/align] [align=left]文档及 Q&A[/align][list]
  141. [*][p=24, null, left]https://wiki.openems.de/index.php/Main_Page.html[/p]
  142. [*][p=24, null, left]https://github.com/thliebig/openEMS-Project/discussions[/p]
  143. [/list]FDTD 教程:https://eecs.wsu.edu/~schneidj/ufdtd/index.php


  144. )
  145. grid()
  146. legend()
  147. ylabel(
  148. 'Zin (Ohm)'
  149. )
  150. xlabel(
  151. 'Frequency (GHz)'
  152. )

  153. show()
复制代码

生成的图形
文档及 Q&A
FDTD 教程:https://eecs.wsu.edu/~schneidj/ufdtd/index.php






欢迎光临 谷动谷力 (http://bbs.sunsili.com/) Powered by Discuz! X3.2