Open ended stub antenna#
An open-ended stub antenna is a simple radiating element consisting of a transmission line (typically microstrip or coaxial cable) with one end open-circuited, allowing electromagnetic energy to radiate directly into free space.
import gmsh
import math
from palacetoolkit.viz import view_mesh
from palacetoolkit.mesh import (
Entity,
run_meshing_pipeline,
generate_3d_mesh,
refine_near_surfaces
)
from palacetoolkit.simulation import Simulation
Paramters#
l1 : Ground plane length along x-axis, specified as a scalar in meters
w1 : Ground plane width along y-axis, specified as a scalar in meters
h : Patch height along z-axis, specified as a scalar in meters.
strip_line_length : Notch length along x-axis, specified as a scalar in meters.
strip_lined_width: Notch width along y-axis, specified as a scalar in meters.
air_height : Air-domain height reference for sizing the enclosing sphere, specified as a scalar in meters.
air_margin : Air-domain margin along x and y axes used for sphere sizing, specified as a scalar in meters.
freq : Simulation frequency in GHz, specified as a scalar.
filename : Output mesh filename, specified as a string.
l1: float = 0.06
w1: float = 0.06
strip_line_length: float = 0.04
strip_line_width: float = 0.002
h: float = 0.0013
air_height: float = 0.025
air_margin: float = 0.025
freq: float = 3.3
filename: str = "open_ended_antenna.msh"
wavelength = 3e8 / (freq * 1e9)
Model initialization#
gmsh.initialize()
gmsh.model.add("patch_antenna")
kernel = gmsh.model.occ
Geometry construction#
# Total domain bounds
total_xmin = -l1/2 - air_margin
total_xmax = l1/2 + air_margin
total_ymin = -w1/2 - air_margin
total_ymax = w1/2 + air_margin
total_zmax = h + air_height
# Substrate box
substrate = kernel.addBox(-l1/2, -w1/2, 0, l1, w1, h)
# Ground plane
ground_plane = kernel.addRectangle(-l1/2, -w1/2, 0, l1, w1)
# Top conductor
strip_line_1 = kernel.addRectangle(-l1/2, -strip_line_width/2, h, strip_line_length, strip_line_width)
# gap bewteen the ground plane and the bottom of the lumped port.
gap = 0
# lumped port
lumped_port = kernel.addRectangle(-l1/2 + gap, -strip_line_width/2, 0, h - gap, strip_line_width)
kernel.rotate([(2, lumped_port)], -l1/2, 0, 0, 0, 1, 0, -math.pi/2)
# Air sphere
airsphere_radius = max(abs(total_xmin), abs(total_xmax), abs(total_ymin), abs(total_ymax), total_zmax)
air_sphere = kernel.addSphere(0.0, 0.0, 0.0, airsphere_radius)
# Synchronize everything!
kernel.synchronize()
# Define the entities which later will become the physical groups.
entities = [
Entity("air_sphere", dim=3, btype="dielectric", mesh_order=2, tags=[air_sphere], eps_r=1.0, mu_r=1.0, loss_tan=0.0),
Entity("substrate", dim=3, btype="dielectric", mesh_order=1, tags=[substrate], eps_r=2.2, mu_r=1.0, loss_tan=0.0009),
Entity("top_conductor", dim=2, btype="pec", mesh_order=1, tags=[strip_line_1]),
Entity("ground_plane", dim=2, btype="pec", mesh_order=1, tags=[ground_plane]),
Entity("lumped_port", dim=2, btype="lumped_port", mesh_order=0, tags=[lumped_port], R=50.0, direction="+Z")
]
# Boolean operations to guarantee a nice mesh, algo it returns the
# physical group map.
pg_map = run_meshing_pipeline(entities)
# Refine near the top conductor and locally the lumped port
refine_near_surfaces(entities[2].dimtags,
wavelength,
ppw_near=50,
ppw_far=30,
set_as_background=True,
local_refinements = {entities[-1].dimtags[0]: 150})
# Mesh sizes
mesh_sizes = {
"substrate": wavelength / 12,
"air_sphere": wavelength / 4,
"lumped_port": wavelength / 150,
"ground_plane" : wavelength / 10,
"top_conductor": wavelength / 50
}
# Generate the 3d mesh.
generate_3d_mesh(entities, mesh_sizes, filename, optimize = True)
Physical group 'air_sphere' (dim=3): pg=1, tags=[2]
Physical group 'substrate' (dim=3): pg=2, tags=[1]
Physical group 'top_conductor' (dim=2): pg=3, tags=[8]
Physical group 'ground_plane' (dim=2): pg=4, tags=[7]
Physical group 'lumped_port' (dim=2): pg=5, tags=[9]
Physical group 'air_sphere__None' (dim=2): pg=6, tags=[16]
Physical group 'air_sphere__substrate' (dim=2): pg=7, tags=[10, 11, 13, 15, 14, 12]
ppw_near=50 ppw_far=30
SizeMax=0.0030 transition=0.0227
global: 4 curves, SizeMin=0.0018
local (2, 9): 4 curves, SizeMin=0.0006
Merged 2 fields with Min → field 5
Info : Meshing 1D...
Info : [ 0%] Meshing curve 24 (Line)
Info : [ 10%] Meshing curve 25 (Line)
Info : [ 10%] Meshing curve 26 (Line)
Info : [ 20%] Meshing curve 27 (Line)
Info : [ 20%] Meshing curve 28 (Line)
Info : [ 30%] Meshing curve 29 (Line)
Info : [ 30%] Meshing curve 30 (Line)
Info : [ 30%] Meshing curve 31 (Line)
Info : [ 40%] Meshing curve 32 (Line)
Info : [ 40%] Meshing curve 33 (Line)
Info : [ 50%] Meshing curve 34 (Line)
Info : [ 50%] Meshing curve 35 (Line)
Info : [ 60%] Meshing curve 36 (Line)
Info : [ 60%] Meshing curve 37 (Line)
Info : [ 60%] Meshing curve 38 (Line)
Info : [ 70%] Meshing curve 39 (Line)
Info : [ 70%] Meshing curve 40 (Line)
Info : [ 80%] Meshing curve 41 (Line)
Info : [ 80%] Meshing curve 42 (Line)
Info : [ 80%] Meshing curve 43 (Line)
Info : [ 90%] Meshing curve 45 (Circle)
Info : [100%] Meshing curve 47 (Line)
Info : Done meshing 1D (Wall 0.0227882s, CPU 0.023435s)
Info : Meshing 2D...
Info : [ 0%] Meshing surface 7 (Plane, MeshAdapt)
Info : [ 20%] Meshing surface 8 (Plane, MeshAdapt)
Info : [ 30%] Meshing surface 9 (Plane, MeshAdapt)
Info : [ 40%] Meshing surface 10 (Plane, MeshAdapt)
Info : [ 50%] Meshing surface 11 (Plane, MeshAdapt)
Info : [ 60%] Meshing surface 12 (Plane, MeshAdapt)
Info : [ 70%] Meshing surface 13 (Plane, MeshAdapt)
Info : [ 80%] Meshing surface 14 (Plane, MeshAdapt)
Info : [ 90%] Meshing surface 15 (Plane, MeshAdapt)
Info : [100%] Meshing surface 16 (Sphere, MeshAdapt)
Info : Done meshing 2D (Wall 2.3741s, CPU 2.35231s)
Info : Meshing 3D...
Info : 3D Meshing 2 volumes with 1 connected component
Info : Tetrahedrizing 7351 nodes...
Info : Done tetrahedrizing 7359 nodes (Wall 0.0740404s, CPU 0.069042s)
Info : Reconstructing mesh...
Info : - Creating surface mesh
Info : - Identifying boundary edges
Info : - Recovering boundary
Info : Done reconstructing mesh (Wall 0.215381s, CPU 0.197498s)
Info : Found volume 2
Info : Found volume 1
Info : It. 0 - 0 nodes created - worst tet radius 15.8281 (nodes removed 0 0)
Info : It. 500 - 500 nodes created - worst tet radius 3.01409 (nodes removed 0 0)
Info : It. 1000 - 1000 nodes created - worst tet radius 2.48289 (nodes removed 0 0)
Info : It. 1500 - 1500 nodes created - worst tet radius 2.19831 (nodes removed 0 0)
Info : It. 2000 - 2000 nodes created - worst tet radius 2.01023 (nodes removed 0 0)
Info : It. 2500 - 2500 nodes created - worst tet radius 1.87804 (nodes removed 0 0)
Info : It. 3000 - 3000 nodes created - worst tet radius 1.77311 (nodes removed 0 0)
Info : It. 3500 - 3500 nodes created - worst tet radius 1.6934 (nodes removed 0 0)
Info : It. 4000 - 4000 nodes created - worst tet radius 1.62406 (nodes removed 0 0)
Info : It. 4500 - 4500 nodes created - worst tet radius 1.56586 (nodes removed 0 0)
Info : It. 5000 - 5000 nodes created - worst tet radius 1.51457 (nodes removed 0 0)
Info : It. 5500 - 5500 nodes created - worst tet radius 1.4705 (nodes removed 0 0)
Info : It. 6000 - 6000 nodes created - worst tet radius 1.43014 (nodes removed 0 0)
Info : It. 6500 - 6500 nodes created - worst tet radius 1.39468 (nodes removed 0 0)
Info : It. 7000 - 7000 nodes created - worst tet radius 1.36281 (nodes removed 0 0)
Info : It. 7500 - 7500 nodes created - worst tet radius 1.33488 (nodes removed 0 0)
Info : It. 8000 - 8000 nodes created - worst tet radius 1.30946 (nodes removed 0 0)
Info : It. 8500 - 8500 nodes created - worst tet radius 1.28468 (nodes removed 0 0)
Info : It. 9000 - 9000 nodes created - worst tet radius 1.26165 (nodes removed 0 0)
Info : It. 9500 - 9500 nodes created - worst tet radius 1.24006 (nodes removed 0 0)
Info : It. 10000 - 10000 nodes created - worst tet radius 1.21952 (nodes removed 0 0)
Info : It. 10500 - 10500 nodes created - worst tet radius 1.20277 (nodes removed 0 0)
Info : It. 11000 - 11000 nodes created - worst tet radius 1.18561 (nodes removed 0 0)
Info : It. 11500 - 11500 nodes created - worst tet radius 1.16931 (nodes removed 0 0)
Info : It. 12000 - 12000 nodes created - worst tet radius 1.15293 (nodes removed 0 0)
Info : It. 12500 - 12500 nodes created - worst tet radius 1.13751 (nodes removed 0 0)
Info : It. 13000 - 13000 nodes created - worst tet radius 1.12296 (nodes removed 0 0)
Info : It. 13500 - 13500 nodes created - worst tet radius 1.1098 (nodes removed 0 0)
Info : It. 14000 - 14000 nodes created - worst tet radius 1.09709 (nodes removed 0 0)
Info : It. 14500 - 14500 nodes created - worst tet radius 1.08546 (nodes removed 0 0)
Info : It. 15000 - 15000 nodes created - worst tet radius 1.07404 (nodes removed 0 0)
Info : It. 15500 - 15500 nodes created - worst tet radius 1.0625 (nodes removed 0 0)
Info : It. 16000 - 16000 nodes created - worst tet radius 1.05158 (nodes removed 0 0)
Info : It. 16500 - 16500 nodes created - worst tet radius 1.04114 (nodes removed 0 0)
Info : It. 17000 - 17000 nodes created - worst tet radius 1.03064 (nodes removed 0 0)
Info : It. 17500 - 17500 nodes created - worst tet radius 1.02124 (nodes removed 0 0)
Info : It. 18000 - 18000 nodes created - worst tet radius 1.01253 (nodes removed 0 0)
Info : It. 18500 - 18500 nodes created - worst tet radius 1.0038 (nodes removed 0 0)
Info : 3D refinement terminated (26079 nodes total):
Info : - 1 Delaunay cavities modified for star shapeness
Info : - 0 nodes could not be inserted
Info : - 147911 tetrahedra created in 1.26757 sec. (116688 tets/s)
Info : 0 node relocations
Info : Done meshing 3D (Wall 1.88412s, CPU 1.86293s)
Info : Optimizing mesh...
Info : Optimizing volume 1
Info : Optimization starts (volume = 4.68e-06) with worst = 0.043499 / average = 0.765452:
Info : 0.00 < quality < 0.10 : 11 elements
Info : 0.10 < quality < 0.20 : 42 elements
Info : 0.20 < quality < 0.30 : 58 elements
Info : 0.30 < quality < 0.40 : 76 elements
Info : 0.40 < quality < 0.50 : 113 elements
Info : 0.50 < quality < 0.60 : 224 elements
Info : 0.60 < quality < 0.70 : 797 elements
Info : 0.70 < quality < 0.80 : 1513 elements
Info : 0.80 < quality < 0.90 : 1954 elements
Info : 0.90 < quality < 1.00 : 686 elements
Info : 109 edge swaps, 0 node relocations (volume = 4.68e-06): worst = 0.170489 / average = 0.776728 (Wall 0.00127495s, CPU 0.001333s)
Info : 111 edge swaps, 0 node relocations (volume = 4.68e-06): worst = 0.170489 / average = 0.776554 (Wall 0.00161795s, CPU 0.001698s)
Info : No ill-shaped tets in the mesh :-)
Info : 0.00 < quality < 0.10 : 0 elements
Info : 0.10 < quality < 0.20 : 1 elements
Info : 0.20 < quality < 0.30 : 1 elements
Info : 0.30 < quality < 0.40 : 78 elements
Info : 0.40 < quality < 0.50 : 110 elements
Info : 0.50 < quality < 0.60 : 215 elements
Info : 0.60 < quality < 0.70 : 809 elements
Info : 0.70 < quality < 0.80 : 1521 elements
Info : 0.80 < quality < 0.90 : 1956 elements
Info : 0.90 < quality < 1.00 : 684 elements
Info : Optimizing volume 2
Info : Optimization starts (volume = 0.000691485) with worst = 0.00995949 / average = 0.774371:
Info : 0.00 < quality < 0.10 : 299 elements
Info : 0.10 < quality < 0.20 : 929 elements
Info : 0.20 < quality < 0.30 : 1647 elements
Info : 0.30 < quality < 0.40 : 2640 elements
Info : 0.40 < quality < 0.50 : 4182 elements
Info : 0.50 < quality < 0.60 : 7314 elements
Info : 0.60 < quality < 0.70 : 15270 elements
Info : 0.70 < quality < 0.80 : 32557 elements
Info : 0.80 < quality < 0.90 : 51512 elements
Info : 0.90 < quality < 1.00 : 26087 elements
Info : 2833 edge swaps, 108 node relocations (volume = 0.000691485): worst = 0.146052 / average = 0.786592 (Wall 0.0896043s, CPU 0.090486s)
Info : 2850 edge swaps, 110 node relocations (volume = 0.000691485): worst = 0.249473 / average = 0.786642 (Wall 0.117308s, CPU 0.118229s)
Info : No ill-shaped tets in the mesh :-)
Info : 0.00 < quality < 0.10 : 0 elements
Info : 0.10 < quality < 0.20 : 0 elements
Info : 0.20 < quality < 0.30 : 7 elements
Info : 0.30 < quality < 0.40 : 2648 elements
Info : 0.40 < quality < 0.50 : 4039 elements
Info : 0.50 < quality < 0.60 : 7230 elements
Info : 0.60 < quality < 0.70 : 15182 elements
Info : 0.70 < quality < 0.80 : 32926 elements
Info : 0.80 < quality < 0.90 : 51938 elements
Info : 0.90 < quality < 1.00 : 25960 elements
Info : Done optimizing mesh (Wall 0.34924s, CPU 0.326631s)
Info : 26079 nodes 160343 elements
Info : Optimizing mesh (Netgen)...
Info : Optimizing volume 1
Info : CalcLocalH: 1847 Points 5377 Elements 3682 Surface Elements
Info : Remove Illegal Elements
Info : 399 illegal tets
Info : SplitImprove
Info : badmax = 79.1788
Info : 55 splits performed
Info : SwapImprove
Info : 66 swaps performed
Info : SwapImprove2
Info : 1 swaps performed
Info : 311 illegal tets
Info : SplitImprove
Info : badmax = 30.1979
Info : 60 splits performed
Info : SwapImprove
Info : 32 swaps performed
Info : SwapImprove2
Info : 6 swaps performed
Info : 167 illegal tets
Info : SplitImprove
Info : badmax = 1829.43
Info : 44 splits performed
Info : SwapImprove
Info : 9 swaps performed
Info : SwapImprove2
Info : 3 swaps performed
Info : 57 illegal tets
Info : SplitImprove
Info : badmax = 3076.72
Info : 17 splits performed
Info : SwapImprove
Info : 3 swaps performed
Info : SwapImprove2
Info : 0 swaps performed
Info : 16 illegal tets
Info : SplitImprove
Info : badmax = 952.702
Info : 3 splits performed
Info : SwapImprove
Info : 0 swaps performed
Info : SwapImprove2
Info : 0 swaps performed
Info : 10 illegal tets
Info : SplitImprove
Info : badmax = 952.702
Info : 2 splits performed
Info : SwapImprove
Info : 0 swaps performed
Info : SwapImprove2
Info : 0 swaps performed
Info : 7 illegal tets
Info : SplitImprove
Info : badmax = 952.702
Info : 2 splits performed
Info : SwapImprove
Info : 1 swaps performed
Info : SwapImprove2
Info : 0 swaps performed
Info : 0 illegal tets
Info : Volume Optimization
Info : CombineImprove
Info : 48 elements combined
Info : ImproveMesh
Info : Total badness = 9677.41
Info : Total badness = 9485.14
Info : SplitImprove
Info : badmax = 36.321
Info : 1 splits performed
Info : ImproveMesh
Info : Total badness = 9490.21
Info : Total badness = 9477.09
Info : SwapImprove
Info : 278 swaps performed
Info : SwapImprove2
Info : 0 swaps performed
Info : ImproveMesh
Info : Total badness = 8983.19
Info : Total badness = 8900.51
Info : CombineImprove
Info : 6 elements combined
Info : ImproveMesh
Info : Total badness = 8843.31
Info : Total badness = 8838.64
Info : SplitImprove
Info : badmax = 13.2784
Info : 0 splits performed
Info : ImproveMesh
Info : Total badness = 8838.64
Info : Total badness = 8838.36
Info : SwapImprove
Info : 40 swaps performed
Info : SwapImprove2
Info : 0 swaps performed
Info : ImproveMesh
Info : Total badness = 8768.92
Info : Total badness = 8747.16
Info : CombineImprove
Info : 3 elements combined
Info : ImproveMesh
Info : Total badness = 8723.24
Info : Total badness = 8721.58
Info : SplitImprove
Info : badmax = 13.2756
Info : 0 splits performed
Info : ImproveMesh
Info : Total badness = 8721.58
Info : Total badness = 8721.53
Info : SwapImprove
Info : 20 swaps performed
Info : SwapImprove2
Info : 0 swaps performed
Info : ImproveMesh
Info : Total badness = 8699.54
Info : Total badness = 8688.24
Info : Optimizing volume 2
Info : CalcLocalH: 26075 Points 139930 Elements 14694 Surface Elements
Info : Remove Illegal Elements
Info : 0 illegal tets
Info : Volume Optimization
Info : CombineImprove
Info : 1265 elements combined
Info : ImproveMesh
Info : Total badness = 181848
Info : Total badness = 173241
Info : SplitImprove
Info : badmax = 14.1834
Info : 0 splits performed
Info : ImproveMesh
Info : Total badness = 173241
Info : Total badness = 171897
Info : SwapImprove
Info : 7804 swaps performed
Info : SwapImprove2
Info : 0 swaps performed
Info : ImproveMesh
Info : Total badness = 158135
Info : Total badness = 154358
Info : CombineImprove
Info : 287 elements combined
Info : ImproveMesh
Info : Total badness = 151838
Info : Total badness = 151261
Info : SplitImprove
Info : badmax = 8.91933
Info : 0 splits performed
Info : ImproveMesh
Info : Total badness = 151261
Info : Total badness = 151150
Info : SwapImprove
Info : 952 swaps performed
Info : SwapImprove2
Info : 0 swaps performed
Info : ImproveMesh
Info : Total badness = 150467
Info : Total badness = 149885
Info : CombineImprove
Info : 56 elements combined
Info : ImproveMesh
Info : Total badness = 149406
Info : Total badness = 149297
Info : SplitImprove
Info : badmax = 7.26293
Info : 0 splits performed
Info : ImproveMesh
Info : Total badness = 149297
Info : Total badness = 149269
Info : SwapImprove
Info : 268 swaps performed
Info : SwapImprove2
Info : 0 swaps performed
Info : ImproveMesh
Info : Total badness = 149165
Info : Total badness = 148999
Info : Done optimizing mesh (Wall 7.31954s, CPU 7.3046s)
Info : Writing 'open_ended_antenna.msh'...
Mesh saved to open_ended_antenna.mshInfo : Done writing 'open_ended_antenna.msh'
Nodes: 24598
Elements: 144515
Mesh visualization.#
# Render the physical groups. The air sphere is rendered transparent.
view_mesh(filename, transparent_groups= "air_sphere__None")
Loading mesh file: open_ended_antenna.msh
Groups to render transparent: air_sphere__None
Mesh loaded successfully with 2 cell blocks
Found 14694 triangles total
Physical group tags in mesh: {3: 'top_conductor', 4: 'ground_plane', 5: 'lumped_port', 6: 'air_sphere__None', 7: 'air_sphere__substrate'}
Generate palace JSON config#
config_filename: str = "op_spalace.conf"
freq_min: float = 3.0
freq_max: float = 3.5
freq_step: float = 0.005
eps_r: float = 2.2
loss_tan: float = 0.0009
port_impedance: float = 50.0
solver_order: int = 2
sim = Simulation()
def attr(name):
return [pg_map[name]] if name in pg_map else []
sim.set_mesh_file(f"/work/{filename}")
sim.set_config_option("Problem.Output", "/work/results/open_ended_antenna/")
sim.set_config_option("Domains.Materials", [
{
"Attributes": attr("substrate"),
"Permittivity": eps_r,
"Permeability": 1.0,
"LossTan": loss_tan
},
{
"Attributes": attr("air"),
"Permittivity": 1.0,
"Permeability": 1.0
}
])
sim.set_config_option("Boundaries.PEC", {
"Attributes": attr("ground_plane") + attr("patch")
})
sim.set_config_option("Boundaries.LumpedPort", [
{
"Index": 1,
"Attributes": attr("lumped_port"),
"R": port_impedance,
"Excitation": True,
"Direction": "+Z"
}
])
sim.set_config_option("Boundaries.Absorbing", {
"Attributes": attr("farfield"),
"Order": 1
})
sim.set_config_option("Solver.Order", solver_order)
sim.set_config_option("Solver.Driven.MinFreq", freq_min)
sim.set_config_option("Solver.Driven.MaxFreq", freq_max)
sim.set_config_option("Solver.Driven.FreqStep", freq_step)
sim.set_config_option("Solver.Driven.AdaptiveTol", 0.001)
config_path = sim.write_config(config_filename)
print(f"Wrote {config_path}")
Palace config written to op_spalace.conf
Wrote op_spalace.conf