5G linear array antenna

This example shows how to use HFSS 3D Layout to create and solve a 5G linear array antenna.

# sphinx_gallery_thumbnail_path = 'Resources/5gantenna.png'
import tempfile
from pyaedt import Edb
from pyaedt.generic.general_methods import generate_unique_name
from pyaedt import Hfss3dLayout
import os


class Patch:
    def __init__(self, width=0.0, height=0.0, position=0.0):
        self.width = width
        self.height = height
        self.position = position

    @property
    def points(self):
        return [
            [self.position, -self.height / 2],
            [self.position + self.width, -self.height / 2],
            [self.position + self.width, self.height / 2],
            [self.position, self.height / 2],
        ]


class Line:
    def __init__(self, length=0.0, width=0.0, position=0.0):
        self.length = length
        self.width = width
        self.position = position

    @property
    def points(self):
        return [
            [self.position, -self.width / 2],
            [self.position + self.length, -self.width / 2],
            [self.position + self.length, self.width / 2],
            [self.position, self.width / 2],
        ]


class LinearArray:
    def __init__(self, nb_patch=1, array_length=10e-3, array_width=5e-3):
        self.nbpatch = nb_patch
        self.length = array_length
        self.width = array_width

    @property
    def points(self):
        return [
            [-1e-3, -self.width / 2 - 1e-3],
            [self.length + 1e-3, -self.width / 2 - 1e-3],
            [self.length + 1e-3, self.width / 2 + 1e-3],
            [-1e-3, self.width / 2 + 1e-3],
        ]


tmpfold = tempfile.gettempdir()
aedb_path = os.path.join(tmpfold, generate_unique_name("pcb") + ".aedb")
print(aedb_path)
edb = Edb(edbpath=aedb_path, edbversion="2021.2")

Out:

C:\Users\ansys\AppData\Local\Temp\pcb_YKRULP.aedb
pyaedt info: Logger Started on C:\Users\ansys\AppData\Local\Temp\pyaedt20220120_152552.log
pyaedt info: Logger Initialized in EDB
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Objects Initialized
pyaedt info: Edb C:\Users\ansys\AppData\Local\Temp\pcb_YKRULP.aedb Created Correctly
pyaedt info: Edb Initialized

Create a Stackup

This method adds the stackup layers.

if edb:
    edb.core_stackup.stackup_layers.add_layer("Virt_GND")
    edb.core_stackup.stackup_layers.add_layer("Gap", "Virt_GND", layerType=1, thickness="0.05mm", material="Air")
    edb.core_stackup.stackup_layers.add_layer("GND", "Gap")
    edb.core_stackup.stackup_layers.add_layer("Substrat", "GND", layerType=1, thickness="0.5mm", material="Duroid (tm)")
    edb.core_stackup.stackup_layers.add_layer("TOP", "Substrat")

Creating the linear array. First patch

first_patch = Patch(width=1.4e-3, height=1.2e-3, position=0.0)
first_patch_poly = edb.core_primitives.Shape("polygon", points=first_patch.points)
edb.core_primitives.create_polygon(first_patch_poly, "TOP", net_name="Array_antenna")
# First line
first_line = Line(length=2.4e-3, width=0.3e-3, position=first_patch.width)
first_line_poly = edb.core_primitives.Shape("polygon", points=first_line.points)
edb.core_primitives.create_polygon(first_line_poly, "TOP", net_name="Array_antenna")

Out:

pyaedt info: Primitives Updated

<Ansys.Ansoft.Edb.Cell.Primitive.Polygon object at 0x000001D051DF2C40>

Linear array

patch = Patch(width=2.29e-3, height=3.3e-3)
line = Line(length=1.9e-3, width=0.2e-3)
linear_array = LinearArray(nb_patch=8, array_width=patch.height)

current_patch = 1
current_position = first_line.position + first_line.length

while current_patch <= linear_array.nbpatch:
    patch.position = current_position
    patch_shape = edb.core_primitives.Shape("polygon", points=patch.points)
    edb.core_primitives.create_polygon(patch_shape, "TOP", net_name="Array_antenna")
    current_position += patch.width
    if current_patch < linear_array.nbpatch:
        line.position = current_position
        line_shape = edb.core_primitives.Shape("polygon", points=line.points)
        edb.core_primitives.create_polygon(line_shape, "TOP", net_name="Array_antenna")
        current_position += line.length
    current_patch += 1

linear_array.length = current_position

Adding ground

gnd_shape = edb.core_primitives.Shape("polygon", points=linear_array.points)
edb.core_primitives.create_polygon(gnd_shape, "GND", net_name="GND")

Out:

<Ansys.Ansoft.Edb.Cell.Primitive.Polygon object at 0x000001D051DE0B80>

Connector central pin

edb.core_padstack.create_padstack(padstackname="Connector_pin", holediam="100um", paddiam="0", antipaddiam="200um")
con_pin = edb.core_padstack.place_padstack(
    [first_patch.width / 4, 0],
    "Connector_pin",
    net_name="Array_antenna",
    fromlayer="TOP",
    tolayer="GND",
    via_name="coax",
)

Out:

pyaedt info: Padstack Connector_pin create correctly

Connector GND

virt_gnd_shape = edb.core_primitives.Shape("polygon", points=first_patch.points)
edb.core_primitives.create_polygon(virt_gnd_shape, "Virt_GND", net_name="GND")
edb.core_padstack.create_padstack("gnd_via", "100um", "0", "0", "GND", "Virt_GND")
con_ref1 = edb.core_padstack.place_padstack(
    [first_patch.points[0][0] + 0.2e-3, first_patch.points[0][1] + 0.2e-3],
    "gnd_via",
    fromlayer="GND",
    tolayer="Virt_GND",
    net_name="GND",
)
con_ref2 = edb.core_padstack.place_padstack(
    [first_patch.points[1][0] - 0.2e-3, first_patch.points[1][1] + 0.2e-3],
    "gnd_via",
    fromlayer="GND",
    tolayer="Virt_GND",
    net_name="GND",
)
con_ref3 = edb.core_padstack.place_padstack(
    [first_patch.points[2][0] - 0.2e-3, first_patch.points[2][1] - 0.2e-3],
    "gnd_via",
    fromlayer="GND",
    tolayer="Virt_GND",
    net_name="GND",
)
con_ref4 = edb.core_padstack.place_padstack(
    [first_patch.points[3][0] + 0.2e-3, first_patch.points[3][1] - 0.2e-3],
    "gnd_via",
    fromlayer="GND",
    tolayer="Virt_GND",
    net_name="GND",
)

Out:

pyaedt info: Padstack gnd_via create correctly

Adding excitation port

edb.core_padstack.set_solderball(con_pin, "Virt_GND", isTopPlaced=False, ballDiam=0.1e-3)
port_name = edb.core_padstack.create_coax_port(con_pin)

Out:

pyaedt error: Method set_solderball Failed:  Attribute Error. Please Check again
Method set_solderball Failed:  Attribute Error. Please Check again
pyaedt error: 'int' object has no attribute 'GetPadstackDef'
'int' object has no attribute 'GetPadstackDef'
pyaedt error: Arguments Provided:
Arguments Provided:
pyaedt error:     padstackInst = 4294967296
    padstackInst = 4294967296
pyaedt error:     sballLayer_name = Virt_GND
    sballLayer_name = Virt_GND
pyaedt error:     isTopPlaced = False
    isTopPlaced = False
pyaedt error:     ballDiam = 0.0001
    ballDiam = 0.0001
pyaedt error: Error in :   File "C:\actions-runner\_work\PyAEDT\PyAEDT\pyaedt\edb_core\padstack.py", line 200, in set_solderball
Error in :   File "C:\actions-runner\_work\PyAEDT\PyAEDT\pyaedt\edb_core\padstack.py", line 200, in set_solderball
pyaedt error: Check Online documentation on: https://aedtdocs.pyansys.com/search.html?q=set_solderball
Check Online documentation on: https://aedtdocs.pyansys.com/search.html?q=set_solderball
pyaedt error: Method create_coax_port Failed:  Attribute Error. Please Check again
Method create_coax_port Failed:  Attribute Error. Please Check again
pyaedt error: 'int' object has no attribute 'GetComponent'
'int' object has no attribute 'GetComponent'
pyaedt error: Arguments Provided:
Arguments Provided:
pyaedt error:     padstackinstance = 4294967296
    padstackinstance = 4294967296
pyaedt error: Error in :   File "C:\actions-runner\_work\PyAEDT\PyAEDT\pyaedt\edb_core\padstack.py", line 233, in create_coax_port
Error in :   File "C:\actions-runner\_work\PyAEDT\PyAEDT\pyaedt\edb_core\padstack.py", line 233, in create_coax_port
pyaedt error: Check Online documentation on: https://aedtdocs.pyansys.com/search.html?q=create_coax_port
Check Online documentation on: https://aedtdocs.pyansys.com/search.html?q=create_coax_port

saving edb

if edb:
    edb.standalone = False
    edb.save_edb()
    edb.close_edb()
print("EDB saved correctly to {}. You can import in AEDT.".format(aedb_path))

Out:

pyaedt info: EDB file release time: 0.00ms
EDB saved correctly to C:\Users\ansys\AppData\Local\Temp\pcb_YKRULP.aedb. You can import in AEDT.

Launch Hfss3d Layout and open Edb

project = os.path.join(aedb_path, "edb.def")
h3d = Hfss3dLayout(projectname=project, specified_version="2021.2", new_desktop_session=True, non_graphical=False)

Out:

Launching PyAEDT outside Electronics Desktop with CPython and Pythonnet
Launching AEDT installation C:\Program Files\AnsysEM\AnsysEM21.2\Win64
===================================================================================
pyaedt info: Launching AEDT with module Pythonnet.
pyaedt info: Ansoft.ElectronicsDesktop.2021.2 Started with process ID 5436.
pyaedt info: Logger Started on C:\Users\ansys\Documents\Ansoft\pyaedt20220120_152607.log
pyaedt info: pyaedt v0.5.dev1
pyaedt info: Python version 3.8.10 (tags/v3.8.10:3d8993a, May  3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)]
pyaedt info: EDB folder C:\Users\ansys\AppData\Local\Temp\pcb_YKRULP.aedb\edb.def has been imported to project pcb_YKRULP
pyaedt info: Active design is set to Cell_ME06CG
pyaedt.generic.LoadAEDTFile._read_aedt_file: 0.0s
pyaedt info: AEDT Load time 0.0
pyaedt info: Design Loaded
pyaedt info: Successfully loaded project materials !
pyaedt info: Materials Loaded
pyaedt info: Analysis Loaded
pyaedt info: Loading Modeler.
pyaedt info: Modeler loaded.
pyaedt info: Logger Initialized in EDB
pyaedt info: EDB Path C:\Users\ansys\AppData\Local\Temp\pcb_YKRULP.aedb
pyaedt info: EDB Version 2021.2
pyaedt info: EDB Standalone True
pyaedt info: Database Opened
pyaedt info: Cell Cell_ME06CG Opened
pyaedt info: C:\actions-runner\_work\PyAEDT\PyAEDT\pyaedt\dlls\EDBLib
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Refreshing the Components dictionary.
pyaedt info: Objects Initialized
pyaedt info: Builder Initialized
pyaedt info: Edb Initialized
pyaedt info: EDB loaded.
pyaedt info: Layers loaded.
pyaedt info: Primitives loaded.
pyaedt info: Modeler Loaded

Create Setup and Sweeps

setup = h3d.create_setup()
setup.props["AdaptiveSettings"]["SingleFrequencyDataList"]["AdaptiveFrequencyData"]["AdaptiveFrequency"] = "20GHz"
setup.props["AdaptiveSettings"]["SingleFrequencyDataList"]["AdaptiveFrequencyData"]["MaxPasses"] = 4
setup.update()
h3d.create_linear_count_sweep(
    setupname=setup.name,
    unit="GHz",
    freqstart=20,
    freqstop=50,
    num_of_freq_points=1001,
    sweepname="sweep1",
    sweep_type="Interpolating",
    interpolation_tol_percent=1,
    interpolation_max_solutions=255,
    save_fields=False,
    use_q3d_for_dc=False,
)

Out:

pyaedt info: Linear count sweep sweep1 has been correctly created

<pyaedt.modules.SetupTemplates.SweepHFSS3DLayout object at 0x000001D051D097F0>

Solve Setup

h3d.analyze_nominal()
h3d.post.create_rectangular_plot(["db(S({0},{1}))".format(port_name, port_name)])
h3d.save_project()
h3d.release_desktop()

Out:

pyaedt info: Solving design setup MySetupAuto
pyaedt info: Design setup MySetupAuto solved correctly
pyaedt info: Solution not supported
pyaedt info: Saving pcb_YKRULP Project

True

Total running time of the script: ( 0 minutes 35.441 seconds)

Gallery generated by Sphinx-Gallery