Download this example
Download this example as a Jupyter Notebook or as a Python script.
Pre-layout signal integrity#
This example shows how to create a parameterized layout design and load the layout into HFSS 3D Layout for analysis and postprocessing.
Create EDB:
Add material.
Create stackup.
Create a parameterized via padstack definition.
Create ground planes.
Create a component.
Create signal vias and traces.
Create ground stitching vias.
Create HFSS analysis setup and frequency sweep.
Import EDB into HFSS 3D Layout:
Place SMA connector.
Analyze.
Plot return loss.
Here is an image of the model that is created in this example.
Keywords: HFSS 3D Layout, signal integrity.
Perform imports and define constants#
Perform required packages.
[1]:
import os
import tempfile
import time
from ansys.aedt.core import Hfss3dLayout
from ansys.aedt.core.downloads import download_file
from pyedb import Edb
Define constants.
[2]:
AEDT_VERSION = "2024.2"
NUM_CORES = 4
NG_MODE = False # Open AEDT UI when it is launched.
Create temporary directory and download example files#
Create a temporary directory where downloaded data or dumped data can be stored. If you’d like to retrieve the project data for subsequent use, the temporary folder name is given by temp_folder.name
.
[3]:
temp_folder = tempfile.TemporaryDirectory(suffix=".ansys")
sma_rf_connector = download_file(
source="component_3d",
name="SMA_RF_SURFACE_MOUNT.a3dcomp",
destination=temp_folder.name,
)
Create layout design#
Import example design#
[4]:
aedb = os.path.join(temp_folder.name, "new_layout.aedb")
edbapp = Edb(edbpath=aedb, edbversion=AEDT_VERSION)
PyAEDT INFO: Logger is initialized in EDB.
PyAEDT INFO: legacy v0.31.0
PyAEDT INFO: Python version 3.10.11 (tags/v3.10.11:7d4cc5a, Apr 5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)]
PyAEDT INFO: EDB C:\Users\ansys\AppData\Local\Temp\tmpg9hgk8xx.ansys\new_layout.aedb created correctly.
PyAEDT INFO: EDB initialized.
[5]:
# Set antipad always on.
edbapp.design_options.antipads_always_on = True
Add material definitions#
[6]:
edbapp.materials.add_conductor_material(name="copper", conductivity=58000000)
edbapp.materials.add_dielectric_material(
name="FR4_epoxy", permittivity=4, dielectric_loss_tangent=0.02
)
edbapp.materials.add_dielectric_material(
name="solder_mask", permittivity=3.1, dielectric_loss_tangent=0.035
)
[6]:
<pyedb.dotnet.edb_core.materials.Material at 0x1a159ed01f0>
Create stackup#
[7]:
edbapp.stackup.create_symmetric_stackup(
layer_count=4,
inner_layer_thickness="18um",
outer_layer_thickness="50um",
dielectric_thickness="100um",
dielectric_material="FR4_epoxy",
soldermask=True,
soldermask_thickness="20um",
)
[7]:
True
Create parameterized padstack definition#
Create signal via padstack definition.
[8]:
edbapp["$antipad"] = "0.7mm"
edbapp.padstacks.create(
padstackname="svia", holediam="0.3mm", antipaddiam="$antipad", paddiam="0.5mm"
)
PyAEDT INFO: Padstack svia create correctly
[8]:
'svia'
Create component pin padstack definition.
[9]:
edbapp.padstacks.create(
padstackname="comp_pin",
paddiam="400um",
antipaddiam="600um",
start_layer="TOP",
stop_layer="TOP",
antipad_shape="Circle",
has_hole=False,
)
PyAEDT INFO: Padstack comp_pin create correctly
[9]:
'comp_pin'
Review stackup#
[10]:
edbapp.stackup.plot(plot_definitions="svia")
[10]:
<module 'matplotlib.pyplot' from 'C:\\actions-runner\\_work\\pyaedt-examples\\pyaedt-examples\\.venv\\lib\\site-packages\\matplotlib\\pyplot.py'>
Create ground planes#
[11]:
board_width = "22mm"
board_length = "18mm"
board_center_point = [0, "5mm"]
gnd_l2 = edbapp.modeler.create_rectangle(
layer_name="L2",
net_name="GND",
center_point=board_center_point,
width=board_width,
height=board_length,
representation_type="CenterWidthHeight",
corner_radius="0mm",
rotation="0deg",
)
gnd_l3 = edbapp.modeler.create_rectangle(
layer_name="L3",
net_name="GND",
center_point=board_center_point,
width=board_width,
height=board_length,
representation_type="CenterWidthHeight",
corner_radius="0mm",
rotation="0deg",
)
gnd_bottom = edbapp.modeler.create_rectangle(
layer_name="BOT",
net_name="GND",
center_point=board_center_point,
width=board_width,
height=board_length,
representation_type="CenterWidthHeight",
corner_radius="0mm",
rotation="0deg",
)
Create a component#
[12]:
edbapp.padstacks.place(
position=[0, 0],
definition_name="comp_pin",
net_name="SIG",
is_pin=True,
via_name="1",
)
[12]:
<pyedb.dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance at 0x1e216eff970>
[13]:
comp_pins = [
edbapp.padstacks.place(
position=["-6mm", 0],
definition_name="comp_pin",
net_name="GND",
is_pin=True,
via_name="2",
),
edbapp.padstacks.place(
position=["6mm", 0],
definition_name="comp_pin",
net_name="GND",
is_pin=True,
via_name="3",
),
]
[14]:
comp_u1 = edbapp.components.create(
pins=comp_pins,
component_name="U1",
component_part_name="BGA",
placement_layer="TOP",
)
comp_u1.create_clearance_on_component(extra_soldermask_clearance=3.5e-3)
PyAEDT INFO: Correctly computed Extension at first iteration.
[14]:
True
Place vias#
Place a signal via.
[15]:
edbapp.padstacks.place(
position=[0, 0], definition_name="svia", net_name="SIG", is_pin=False
)
[15]:
<pyedb.dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance at 0x1e216efce50>
Place ground stitching vias.
[16]:
edbapp.padstacks.place(
position=["-1mm", 0], definition_name="svia", net_name="GND", is_pin=False
)
edbapp.padstacks.place(
position=["1mm", 0], definition_name="svia", net_name="GND", is_pin=False
)
edbapp.padstacks.place(
position=[0, "-1mm"], definition_name="svia", net_name="GND", is_pin=False
)
edbapp.padstacks.place(
position=[0, "1mm"], definition_name="svia", net_name="GND", is_pin=False
)
[16]:
<pyedb.dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance at 0x1e219bb0ac0>
Create signal traces#
[17]:
edbapp["width"] = "0.15mm"
edbapp["gap"] = "0.1mm"
Create signal fanout.
[18]:
sig_trace = edbapp.modeler.create_trace(
path_list=[[0, 0]],
layer_name="BOT",
width="width",
net_name="SIG",
start_cap_style="Round",
end_cap_style="Round",
corner_style="Round",
)
[19]:
sig_trace.add_point(x="0.5mm", y="0.5mm", incremental=True)
sig_trace.add_point(x=0, y="1mm", incremental=True)
sig_trace.add_point(x="-0.5mm", y="0.5mm", incremental=True)
sig_trace.add_point(x=0, y="1mm", incremental=True)
sig_path = sig_trace.get_center_line()
Create coplanar waveguide with ground with ground stitching vias.
[20]:
sig2_trace = edbapp.modeler.create_trace(
path_list=[sig_path[-1]],
layer_name="BOT",
width="width",
net_name="SIG",
start_cap_style="Round",
end_cap_style="Flat",
corner_style="Round",
)
sig2_trace.add_point(x=0, y="6mm", incremental=True)
sig2_trace.create_via_fence(distance="0.5mm", gap="1mm", padstack_name="svia")
sig2_trace.add_point(x=0, y="1mm", incremental=True)
[20]:
True
Create trace-to-ground clearance.
[21]:
sig2_path = sig2_trace.get_center_line()
path_list = [sig_path, sig2_path]
for i in path_list:
void = edbapp.modeler.create_trace(
path_list=i,
layer_name="BOT",
width="width+gap*2",
start_cap_style="Round",
end_cap_style="Round",
corner_style="Round",
)
edbapp.modeler.add_void(shape=gnd_bottom, void_shape=void)
Generate plot to review.
[22]:
edbapp.nets.plot()
PyAEDT INFO: Nets Point Generation time 0.016 seconds
[22]:
<module 'matplotlib.pyplot' from 'C:\\actions-runner\\_work\\pyaedt-examples\\pyaedt-examples\\.venv\\lib\\site-packages\\matplotlib\\pyplot.py'>
Create ports#
Create a wave port.
[23]:
sig2_trace.create_edge_port(
name="p1_wave_port",
position="End",
port_type="Wave",
reference_layer=None,
horizontal_extent_factor=10,
vertical_extent_factor=10,
pec_launch_width="0.01mm",
)
[23]:
('p1_wave_port',
<pyedb.dotnet.edb_core.edb_data.ports.WavePort at 0x1e216e85870>)
Create HFSS analysis setup#
[24]:
setup = edbapp.create_hfss_setup("Setup1")
setup.set_solution_single_frequency("5GHz", max_num_passes=1, max_delta_s="0.02")
setup.hfss_solver_settings.order_basis = "first"
Add a frequency sweep to the setup.
When the simulation results are to be used for transient SPICE analysis, you should use the following strategy:
DC point
Logarithmic sweep from 1 kHz to 100 MHz
Linear scale for higher frequencies
[25]:
setup.add_frequency_sweep(
"Sweep1",
frequency_sweep=[
["log scale", "10MHz", "100MHz", 3],
["linear scale", "0.1GHz", "5GHz", "0.2GHz"],
],
)
[25]:
<pyedb.dotnet.edb_core.sim_setup_data.data.sweep_data.SweepData at 0x1e219c38e20>
Save and close EDB#
[26]:
edbapp.save()
edbapp.close()
[26]:
True
Analyze in HFSS 3D Layout#
Load EDB into HFSS 3D Layout.#
[27]:
h3d = Hfss3dLayout(aedb, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True)
PyAEDT INFO: Python version 3.10.11 (tags/v3.10.11:7d4cc5a, Apr 5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)]
PyAEDT INFO: PyAEDT version 0.12.dev0.
PyAEDT INFO: Initializing new Desktop session.
PyAEDT INFO: Log on console is enabled.
PyAEDT INFO: Log on file C:\Users\ansys\AppData\Local\Temp\pyaedt_ansys_cbdd3c22-2ca7-4016-891c-2feee53baffb.log is enabled.
PyAEDT INFO: Log on AEDT is enabled.
PyAEDT INFO: Debug logger is disabled. PyAEDT methods will not be logged.
PyAEDT INFO: Launching PyAEDT with gRPC plugin.
PyAEDT INFO: New AEDT session is starting on gRPC port 63141
PyAEDT INFO: AEDT installation Path C:\Program Files\AnsysEM\v242\Win64
PyAEDT INFO: Ansoft.ElectronicsDesktop.2024.2 version started with process ID 6536.
PyAEDT INFO: EDB folder C:\Users\ansys\AppData\Local\Temp\tmpg9hgk8xx.ansys\new_layout.aedb has been imported to project new_layout
PyAEDT INFO: Active Design set to 0;Cell_2L1NUR
PyAEDT INFO: Aedt Objects correctly read
Place SMA RF connector#
[28]:
comp = h3d.modeler.place_3d_component(
component_path=sma_rf_connector,
number_of_terminals=1,
placement_layer="TOP",
component_name="sma_rf",
pos_x=0,
pos_y=0,
create_ports=True,
)
comp.angle = "90deg"
PyAEDT INFO: Loading Modeler.
PyAEDT INFO: Modeler loaded.
PyAEDT INFO: EDB loaded.
PyAEDT INFO: Layers loaded.
PyAEDT INFO: Primitives loaded.
PyAEDT INFO: Modeler class has been initialized! Elapsed time: 0m 0sec
Release AEDT#
[29]:
h3d.save_project()
h3d.release_desktop()
# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.
time.sleep(3)
PyAEDT INFO: Project new_layout Saved correctly
PyAEDT INFO: Desktop has been released and closed.
Clean up#
All project files are saved in the folder temp_dir.name
. If you’ve run this example as a Jupyter notebook, you can retrieve those project files. The following cell removes all temporary files, including the project folder.
[30]:
temp_folder.cleanup()
Download this example
Download this example as a Jupyter Notebook or as a Python script.