メインコンテンツまでスキップ

方形パッチアンテナの形状作成とメッシュ生成

本例では、電子情報通信学会の規範問題「方形パッチアンテナ(プローブ給電)」[1,2] を題材に、電磁界解析に使用する形状とメッシュを Gmsh で作成します。

パッチアンテナは、誘電体基板の上面にある金属のパッチと、下面のグランドプレーンから構成されます。ここでは、給電部と周囲の空気も含めてモデル化します。本例ではメッシュの作成までを扱い、電磁界解析は実行しません。

Gmsh は Tanager パッケージには含まれていません。別途 pip install gmsh でインストールしてください。Gmsh は Tanager とは異なるライセンス で提供されています。

import gmsh, math

モデルの寸法と周波数​

基板は 80 mm × 80 mm、厚さ 1.53 mm、上面のパッチは 28.5 mm 角です。給電位置はパッチ中心から X 方向に 4.8 mm ずらしています。これらの寸法をメートル(m)で指定します。

周波数範囲は 2~3 GHz を想定しています。高い方の周波数(3 GHz)では波長が短くなるため、それを目安にメッシュの最大要素サイズを決めます。一方、低い方の周波数(2 GHz)では波長が長くなるため、アンテナを囲む空気領域の広さを決める目安にします。ここで周波数を設定しても、電磁界解析が実行されるわけではありません。

freq_min = 2e9
freq_max = 3e9

ground_width = 80e-3
patch_width = 28.5e-3
thick = 1.53e-3
feed_center_x = 4.8e-3
feed_diameter = 1.25e-3
feed_width = 2*feed_diameter

radiation_radius = 0.5*ground_width+0.25*(3e8/freq_min)
max_edge_length = (3e8/freq_max)/5

形状の作成​

Gmsh の OpenCASCADE 機能を使い、基板を直方体、導体や給電部を面、周囲の空気を球状の領域として作成します。最初に Gmsh を初期化し、モデルを用意します。

gmsh.initialize()
gmsh.model.add("patchAntenna")
gmsh.option.setNumber("Geometry.OCCBooleanPreserveNumbering",1)

誘電体基板・パッチ・グランドプレーン​

誘電体基板の上面に正方形のパッチを、下面にグランドプレーンを配置します。パッチとグランドプレーンは厚みのない面として作成します。これらの面は、電磁界解析で金属を完全導体(PEC)として扱うための境界になります。

substrate_tag = gmsh.model.occ.addBox(
-0.5*ground_width,-0.5*ground_width,0,
ground_width,ground_width,thick
)
patch_tag = gmsh.model.occ.addRectangle(
-0.5*patch_width,-0.5*patch_width,thick,
patch_width,patch_width
)
ground_tag = gmsh.model.occ.addRectangle(
-0.5*ground_width,-0.5*ground_width,0,
ground_width,ground_width
)

給電部​

実際のプローブ給電では、グランドプレーン側から基板を貫く導体を通してパッチに電力を供給します。この例では細かな導体形状を作らず、グランドプレーンとパッチの間に立つ小さな面を集中ポートとして使います。

Gmsh では、まず XY 平面に長方形を作り、X 軸の周りに 90° 回転して XZ 平面に立てています。ポートの位置は feed_center_x、高さは基板の厚さ thick で決まります。

port_tag = gmsh.model.occ.addRectangle(
feed_center_x-0.5*feed_width,0,0,
feed_width,thick
)
gmsh.model.occ.rotate(
[(2,port_tag)],
feed_center_x,0,0,
1,0,0,
math.pi/2
)

形状の接続​

基板と導体面、給電面を個別に作成しただけでは、それぞれの境界がメッシュ上で正しく共有されないことがあります。そこで fragment() を使い、接している部分が共通の境界になるように形状を分割します。これにより、基板内部の給電面もメッシュ上で識別でき、導体面やポート面に境界条件を設定できます。

この操作で Gmsh の識別番号が変わる場合があるため、後続の処理には fragment() の結果から取得した番号を使用します。

_,entities = gmsh.model.occ.fragment(
[(3,substrate_tag)],
[(2,patch_tag),(2,ground_tag),(2,port_tag)]
)

substrate_entities,patch_entities,ground_entities,port_entities = entities
substrate_tag = [tag for dim,tag in substrate_entities if dim == 3]
patch_tag = [tag for dim,tag in patch_entities if dim == 2]
ground_tag = [tag for dim,tag in ground_entities if dim == 2]
port_tag = [tag for dim,tag in port_entities if dim == 2]

アンテナ周囲の空気領域​

アンテナから出た電磁波は、基板の外側の空気中へ広がります。そこで、アンテナ全体を包む球を作り、その内側を空気の計算領域として使います。

ただし、球をそのまま使うと、基板がある場所まで空気として扱われてしまいます。球から基板の部分を取り除くことで、誘電体基板と空気が重ならない領域を作ります。球の外側の面は、後の電磁界解析で不要な反射を抑えるための吸収境界(ABC)として使います。

sphere_tag = gmsh.model.occ.addSphere(
0,0,0.5*thick,radiation_radius,
angle1=-math.pi/2,
angle2=math.pi/2,
angle3=2*math.pi
)

radiation,_ = gmsh.model.occ.cut(
[(3,sphere_tag)],
[(3,tag) for tag in substrate_tag],
removeObject=True,
removeTool=False
)
radiation_tag = [tag for dim,tag in radiation if dim == 3]

# 空気領域を囲む外側の球面を、吸収境界用の面として取得します。
_,surface_loops = gmsh.model.occ.getSurfaceLoops(radiation_tag[0])
radiation_surfaces = {tag for loop in surface_loops for tag in loop}
absorbing_surfaces = [max(
radiation_surfaces,
key=lambda tag: gmsh.model.occ.getMass(2,tag)
)]

材料と境界条件のためのグループ分け​

電磁界解析では、基板に誘電体の材料特性を、周囲の空気に空気の材料特性を与えます。また、パッチとグランドプレーンには完全導体(PEC)、球の外面には吸収境界(ABC)、給電面には集中ポートの条件を設定します。

そのため、ここで Gmsh の **Physical Group(物理グループ)**を使い、それぞれの体積や面に名前と番号を付けます。この番号は、後でメッシュを読み込む解析ソフトウェアが、どこに材料や境界条件を適用するかを判断するための目印になります。ここではグループ分けのみを行い、材料や境界条件の計算はまだ行いません。

gmsh.model.occ.synchronize()

dim3 = 3
dim2 = 2

substrate_domain = 1
radiation_domain = 2
pec_bc = 1
absorbing_bc = 2
port_bc = 3

gmsh.model.addPhysicalGroup(dim3,substrate_tag,substrate_domain,"Substrate")
gmsh.model.addPhysicalGroup(dim3,radiation_tag,radiation_domain,"Radiation")
gmsh.model.addPhysicalGroup(dim2,patch_tag+ground_tag,pec_bc,"PEC")
gmsh.model.addPhysicalGroup(dim2,absorbing_surfaces,absorbing_bc,"ABC")
gmsh.model.addPhysicalGroup(dim2,port_tag,port_bc,"Lumped Port")
3

メッシュの細分化​

パッチの端では電界が急に変化しやすく、メッシュが粗いとその変化を十分に表現できないことがあります。このため、パッチ外周の4辺に近い部分だけメッシュを細かくし、離れた場所では要素を大きくして、全体の要素数が増えすぎないようにします。

下のコードでは、まずパッチ外周からの距離を計算し(Distance)、その距離に応じて要素サイズを変えます(Threshold)。外周付近の目標サイズは 2 mm、離れた場所での最大サイズは 20 mm です。

# 給電面との交線などを除き、メッシュを細かくしたいパッチ外周を取得します。
patch_perimeter = []
patch_edges = gmsh.model.getBoundary(
[(2,tag) for tag in patch_tag],
combined=True,
oriented=False
)
for dim,tag in patch_edges:
if dim == 1:
x,y,_ = gmsh.model.occ.getCenterOfMass(1,tag)
if (abs(abs(x)-0.5*patch_width) < 1e-9 or
abs(abs(y)-0.5*patch_width) < 1e-9):
patch_perimeter.append(tag)

patch_perimeter = sorted(set(patch_perimeter))
if not patch_perimeter:
raise RuntimeError("Could not identify the patch perimeter curves")

# パッチ外周からの距離に応じて目標要素サイズを変えます。
# 外周に近いほど細かくし、離れた場所では大きな要素を使います。
distance_field = gmsh.model.mesh.field.add("Distance")
gmsh.model.mesh.field.setNumbers(
distance_field,"CurvesList",patch_perimeter
)
gmsh.model.mesh.field.setNumber(distance_field,"Sampling",200)

threshold_field = gmsh.model.mesh.field.add("Threshold")
gmsh.model.mesh.field.setNumber(threshold_field,"InField",distance_field)
gmsh.model.mesh.field.setNumber(threshold_field,"SizeMin",max_edge_length/10)
gmsh.model.mesh.field.setNumber(threshold_field,"SizeMax",max_edge_length)
gmsh.model.mesh.field.setNumber(threshold_field,"DistMin",0.0)
gmsh.model.mesh.field.setNumber(threshold_field,"DistMax",3*max_edge_length)
gmsh.model.mesh.field.setAsBackgroundMesh(threshold_field)

メッシュの生成と保存​

基板と空気の領域を、小さな四面体に分割して3次元メッシュを作成します。ここでは、頂点だけでなく辺の途中にも節点を置く2次要素を使用します。1次要素に比べ、球状の外面などの曲面をより滑らかに表現できます。

メッシュは patchAntenna.msh という名前で保存します。ファイル形式には、後の有限要素解析で読み込めるよう Gmsh MSH 2.2 を指定しています。生成した形状や要素の分割状態は Gmsh で確認できます。

gmsh.option.setNumber("Mesh.CharacteristicLengthMax",max_edge_length)
gmsh.option.setNumber("Mesh.ElementOrder",2)
gmsh.option.setNumber("Mesh.HighOrderOptimize",1)

gmsh.model.mesh.generate(3)
gmsh.option.setNumber("Mesh.MshFileVersion",2.2)
gmsh.write("patchAntenna.msh")

# 任意:デスクトップ環境がある場合は、Gmsh のビューアを起動できます。
# gmsh.fltk.run()

gmsh.finalize()

参考文献​

[1] 電子情報通信学会 エレクトロニクスシミュレーション研究会, 「方形パッチアンテナ(プローブ給電)」, 電磁界シミュレーション規範問題.

[2] 平野 拓一, 岡部 寛, 大貫 進一郎, 「電磁界シミュレーション規範問題 ― コネクタを含む励振部のモデル化 ―」, 2014 Microwave Workshops & Exhibition (MWE 2014), ワークショップ07, 2014年12月11日.