Fully parameterized design

This example shows how to use HFSS 3D Layout to create and solve a parametric design.

# sphinx_gallery_thumbnail_path = 'Resources/parametrized_edb.png'

Import the Hfss3dlayout Object

This example imports the Hfss3dlayout object and initializes it on version 2021.1.

import tempfile
from pyaedt import Edb
from pyaedt.generic.general_methods import generate_unique_name
from pyaedt import Hfss3dLayout
import os

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")
var_server = edb.active_cell.GetVariableServer()


class via_def:
    def __init__(
        self,
        name="via_def",
        hole_diam="",
        pad_diam="",
        anti_pad_diam="",
        start_layer="top",
        stop_layer="bottom",
        antipad_shape="Circle",
        x_size="",
        y_size="",
        corner_rad="",
    ):
        self.name = name
        self.hole_diam = hole_diam
        self.pad_diam = pad_diam
        self.anti_pad_diam = anti_pad_diam
        self.start_layer = start_layer
        self.stop_layer = stop_layer
        self.anti_pad_shape = antipad_shape
        self.x_size = x_size
        self.y_size = y_size
        self.corner_rad = corner_rad

    def add_via_def_to_edb(self):
        edb.core_padstack.create_padstack(
            padstackname=self.name,
            holediam=self.hole_diam,
            paddiam=self.pad_diam,
            antipaddiam=self.anti_pad_diam,
            startlayer=self.start_layer,
            endlayer=self.stop_layer,
            antipad_shape=self.anti_pad_shape,
            x_size=self.x_size,
            y_size=self.y_size,
            corner_radius=self.corner_rad,
        )


class via_instance:
    def __init__(self, pos_x="", pos_y="", rotation=0.0, net_name=""):
        self.pos_x = pos_x
        self.pos_y = pos_y
        self.rotation = rotation
        self.pos = [self.pos_x, self.pos_y]
        self.net_name = net_name

    def place_via(self, viadef=via_def()):
        edb_padstanck_inst = edb.core_padstack.place_padstack(
            position=self.pos,
            definition_name=viadef.name,
            net_name=self.net_name,
            via_name="",
            rotation=self.rotation,
            fromlayer=viadef.start_layer,
            tolayer=viadef.stop_layer,
        )


class line:
    def __init__(self, width="0.0", point_list=None, layer="", net_name=""):
        if point_list is None:
            point_list = [[0.0, 0.0], [1e-3, 0.0]]
        self.point_list = point_list
        self.width = width
        self.layer = layer
        self.net_name = net_name

    def place_line(self):
        path = edb.core_primitives.Shape("polygon", points=self.point_list)
        edb_path = edb.core_primitives.create_path(
            path, self.layer, self.width, self.net_name, start_cap_style="Flat", end_cap_style="Flat"
        )
        return edb_path


class rectangle:
    def __init__(self, lower_left_corner=[], upper_right_corner=[], voids=None):
        self.lower_left_corner = lower_left_corner
        self.upper_right_corner = upper_right_corner
        self.voids = voids

    def place_rectangle(self, layer_name="top", net_name=""):
        pts = [
            [self.lower_left_corner[0], self.lower_left_corner[1]],
            [self.upper_right_corner[0], self.lower_left_corner[1]],
            [self.upper_right_corner[0], self.upper_right_corner[1]],
            [self.lower_left_corner[0], self.upper_right_corner[1]],
        ]
        shape = edb.core_primitives.Shape("polygon", points=pts)
        if self.voids:
            shape_void = [edb.core_primitives.Shape("polygon", points=self.voids)]
        else:
            shape_void = []
        edb.core_primitives.create_polygon(main_shape=shape, layer_name=layer_name, voids=shape_void, net_name=net_name)

    def get_variable_value(self, variable_name=""):
        value = edb.edb_value()
        var_value = var_server.get_variable_value(variable_name, value)
        return value.ToDouble()

Out:

C:\Users\ansys\AppData\Local\Temp\pcb_9WVKWE.aedb
pyaedt info: Logger Started on C:\Users\ansys\AppData\Local\Temp\pyaedt20220120_152627.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_9WVKWE.aedb Created Correctly
pyaedt info: Edb Initialized

Layer stackup

if edb:
    edb.core_stackup.stackup_layers.add_layer("bottom")
    edb.core_stackup.stackup_layers.add_layer(
        "dielectric", "bottom", layerType=1, thickness="275um", material="FR4_epoxy"
    )
    edb.core_stackup.stackup_layers.add_layer("sig2", "dielectric")
    edb.core_stackup.stackup_layers.add_layer("Diel_2", "sig2", layerType=1, thickness="275um", material="FR4_epoxy")
    edb.core_stackup.stackup_layers.add_layer("sig1", "Diel_2")
    edb.core_stackup.stackup_layers.add_layer("Diel_1", "sig1", layerType=1, thickness="275um", material="FR4_epoxy")
    edb.core_stackup.stackup_layers.add_layer("top", "Diel_1")

Design variables

edb.add_design_variable("$line_width", "0.5mm")
edb.add_design_variable("$line2_width", "0.5mm")
edb.add_design_variable("$line_spacing", "0.2mm")
edb.add_design_variable("$via_spacing", "0.5mm")
edb.add_design_variable("$via_diam", "0.3mm")
edb.add_design_variable("$pad_diam", "0.6mm")
edb.add_design_variable("$anti_pad_diam", "0.7mm")
edb.add_design_variable("$pcb_len", "30mm")
edb.add_design_variable("$pcb_w", "5mm")
edb.add_design_variable("$x_size", "1.2mm")
edb.add_design_variable("$y_size", "1mm")
edb.add_design_variable("$corner_rad", "0.5mm")

#################
# Via definition
#
viadef1 = via_def(
    name="automated_via",
    hole_diam="$via_diam",
    pad_diam="$pad_diam",
    antipad_shape="Bullet",
    x_size="$x_size",
    y_size="$y_size",
    corner_rad="$corner_rad",
)
viadef1.add_via_def_to_edb()

###################
# line creation
#
net_name = "strip_line_p"
net_name2 = "strip_line_n"

Out:

pyaedt info: Creating Parameter $line_width.
pyaedt info: Creating Parameter $line2_width.
pyaedt info: Creating Parameter $line_spacing.
pyaedt info: Creating Parameter $via_spacing.
pyaedt info: Creating Parameter $via_diam.
pyaedt info: Creating Parameter $pad_diam.
pyaedt info: Creating Parameter $anti_pad_diam.
pyaedt info: Creating Parameter $pcb_len.
pyaedt info: Creating Parameter $pcb_w.
pyaedt info: Creating Parameter $x_size.
pyaedt info: Creating Parameter $y_size.
pyaedt info: Creating Parameter $corner_rad.
pyaedt info: Padstack automated_via create correctly

line placement

seg1_p = line(width="$line_width", net_name=net_name, layer="top")

seg1_p.point_list = [
    ["0.0", "($line_width+$line_spacing)/2"],
    ["$pcb_len/3-2*$via_spacing", "($line_width+$line_spacing)/2"],
    ["$pcb_len/3-$via_spacing", "($line_width+$line_spacing+$via_spacing)/2"],
    ["$pcb_len/3", "($line_width+$line_spacing+$via_spacing)/2"],
]
seg1_p.place_line()
path_port_1p = edb.core_primitives.primitives[-1]

Out:

pyaedt info: Primitives Updated

via placement

via_instance(
    pos_x="$pcb_len/3", pos_y="($line_width+$line_spacing+$via_spacing)/2", rotation=90, net_name=net_name
).place_via(viadef1)

line creation

seg2_p = line(width="$line2_width", net_name=net_name, layer="sig1")
seg2_p.point_list = [
    ["$pcb_len/3", "($line_width+$line_spacing+$via_spacing)/2"],
    ["$pcb_len/3+$via_spacing", "($line_width+$line_spacing+$via_spacing)/2"],
    ["$pcb_len/3+2*$via_spacing", "($line_width+$line_spacing)/2"],
    ["2*$pcb_len/3-2*$via_spacing", "($line_width+$line_spacing)/2"],
    ["2*$pcb_len/3-$via_spacing", "($line_width+$line_spacing+$via_spacing)/2"],
    ["2*$pcb_len/3", "($line_width+$line_spacing+$via_spacing)/2"],
]
seg2_p.place_line()

##################
# Via placement
#
via_instance(
    pos_x="2*$pcb_len/3", pos_y="($line_width+$line_spacing+$via_spacing)/2", rotation=90, net_name=net_name
).place_via(viadef1)

line creation

seg3_p = line(width="$line_width", net_name=net_name, layer="top")
seg3_p.point_list = [
    ["2*$pcb_len/3", "($line_width+$line_spacing+$via_spacing)/2"],
    ["2*$pcb_len/3+$via_spacing", "($line_width+$line_spacing+$via_spacing)/2"],
    ["2*$pcb_len/3+2*$via_spacing", "($line_width+$line_spacing)/2"],
    ["$pcb_len", "($line_width+$line_spacing)/2"],
]
seg3_p.place_line()
path_port_2p = edb.core_primitives.primitives[-1]

##################
# line n
#
# line creation
seg1_n = line(width="$line_width", net_name=net_name2, layer="top")

seg1_n.point_list = [
    ["0.0", "-($line_width+$line_spacing)/2"],
    ["$pcb_len/3-2*$via_spacing", "-($line_width+$line_spacing)/2"],
    ["$pcb_len/3-$via_spacing", "-($line_width+$line_spacing+$via_spacing)/2"],
    ["$pcb_len/3", "-($line_width+$line_spacing+$via_spacing)/2"],
]
seg1_n.place_line()

##################
# via placement
#

via_instance(
    pos_x="$pcb_len/3", pos_y="-($line_width+$line_spacing+$via_spacing)/2", rotation=-90, net_name=net_name2
).place_via(viadef1)

##################
# line creation
#

seg2_n = line(width="$line2_width", net_name=net_name2, layer="sig1")
seg2_n.point_list = [
    ["$pcb_len/3", "-($line_width+$line_spacing+$via_spacing)/2"],
    ["$pcb_len/3+$via_spacing", "-($line_width+$line_spacing+$via_spacing)/2"],
    ["$pcb_len/3+2*$via_spacing", "-($line_width+$line_spacing)/2"],
    ["2*$pcb_len/3-2*$via_spacing", "-($line_width+$line_spacing)/2"],
    ["2*$pcb_len/3-$via_spacing", "-($line_width+$line_spacing+$via_spacing)/2"],
    ["2*$pcb_len/3", "-($line_width+$line_spacing+$via_spacing)/2"],
]
seg2_n.place_line()

##################
# via placement
#

via_instance(
    pos_x="2*$pcb_len/3", pos_y="-($line_width+$line_spacing+$via_spacing)/2", rotation=-90, net_name=net_name2
).place_via(viadef1)

line creation

seg3_p = line(width="$line_width", net_name=net_name2, layer="top")
seg3_p.point_list = [
    ["2*$pcb_len/3", "-($line_width+$line_spacing+$via_spacing)/2"],
    ["2*$pcb_len/3+$via_spacing", "-($line_width+$line_spacing+$via_spacing)/2"],
    ["2*$pcb_len/3+2*$via_spacing", "-($line_width+$line_spacing)/2"],
    ["$pcb_len", "-($line_width+$line_spacing)/2"],
]
seg3_p.place_line()

Out:

<Ansys.Ansoft.Edb.Cell.Primitive.Path object at 0x000001D051B68190>

GND plane

rectangle(
    lower_left_corner=[0.0, "-$pcb_w/2"],
    upper_right_corner=["$pcb_len", "$pcb_w/2"],
    voids=[
        ["$pcb_len/3", "-($line_width+$line_spacing+$via_spacing+$anti_pad_diam)/2"],
        ["2*$pcb_len/3", "-($line_width+$line_spacing+$via_spacing+$anti_pad_diam)/2"],
        ["2*$pcb_len/3", "($line_width+$line_spacing+$via_spacing+$anti_pad_diam)/2"],
        ["$pcb_len/3", "($line_width+$line_spacing+$via_spacing+$anti_pad_diam)/2"],
    ],
).place_rectangle("sig1", "gnd")

gnd_plane = edb.core_primitives.primitives[-1]
#
rectangle(lower_left_corner=[0.0, "-$pcb_w/2"], upper_right_corner=["$pcb_len", "$pcb_w/2"]).place_rectangle(
    "sig2", "gnd"
)

rectangle(lower_left_corner=[0.0, "-$pcb_w/2"], upper_right_corner=["$pcb_len", "$pcb_w/2"]).place_rectangle(
    "bottom", "gnd"
)

saving edb

edb.save_edb()
edb.close_edb()

Out:

pyaedt info: EDB file release time: 0.00ms

True

opening edb in aedt

h3d = Hfss3dLayout(projectname=os.path.join(aedb_path, "edb.def"), specified_version="2021.2", 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 8036.
pyaedt info: Logger Started on C:\Users\ansys\Documents\Ansoft\pyaedt20220120_152639.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_9WVKWE.aedb\edb.def has been imported to project pcb_9WVKWE
pyaedt info: Active design is set to Cell_VPPL6U
pyaedt.generic.LoadAEDTFile._read_aedt_file: 0.0s
pyaedt info: AEDT Load time 0.015621185302734375
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_9WVKWE.aedb
pyaedt info: EDB Version 2021.2
pyaedt info: EDB Standalone True
pyaedt info: Database Opened
pyaedt info: Cell Cell_VPPL6U 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

creating wave ports

h3d.create_wave_port_from_two_conductors(["line_0", "line_3"], [0, 0])
h3d.create_wave_port_from_two_conductors(["line_5", "line_2"], [5, 5])

Out:

'Port3:T1'

adding hfss simulation setup

setup = h3d.create_setup()
h3d.create_linear_count_sweep(
    setupname=setup.name,
    unit="GHz",
    freqstart=0,
    freqstop=10,
    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 0x000001D051C393A0>

start hfss solver. Uncomment to solve h3d.analyze_nominal()

h3d.release_desktop()

Out:

True

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

Gallery generated by Sphinx-Gallery