Q3D Extractor: PCB analysis#

This example shows how you can use PyAEDT to create a design in Q3D Extractor and run a simulation starting from an EDB Project.

Perform required imports#

Perform required imports.

import os
import pyaedt

Set AEDT version#

Set AEDT version.

aedt_version = "2024.1"

Setup project files and path#

Download of needed project file and setup of temporary project directory.

project_dir = pyaedt.generate_unique_folder_name()
aedb_project = pyaedt.downloads.download_file('edb/ANSYS-HSD_V1.aedb',destination=project_dir)

project_name = pyaedt.generate_unique_name("HSD")
output_edb = os.path.join(project_dir, project_name + '.aedb')
output_q3d = os.path.join(project_dir, project_name + '_q3d.aedt')

Open EDB#

Open the edb project and created a cutout on the selected nets before exporting to Q3D.

edb = pyaedt.Edb(aedb_project, edbversion=aedt_version)
edb.cutout(["CLOCK_I2C_SCL", "CLOCK_I2C_SDA"], ["GND"], output_aedb_path=output_edb,
                              use_pyaedt_extent_computing=True, )
C:\actions-runner\_work\pyaedt\pyaedt\.venv\lib\site-packages\pyedb\dotnet\edb_core\components.py:182: DeprecationWarning: Use new property :func:`instances` instead.
  warnings.warn("Use new property :func:`instances` instead.", DeprecationWarning)

[[0.05144426092331123, 0.02870618555822053], [0.051507567732030704, 0.028387920738624846], [0.05165833184521132, 0.028023943971865067], [0.05183861438361972, 0.027754132085975027], [0.051963277357883246, 0.02760222981232462], [0.053777229532324555, 0.025788277637883304], [0.05392913180597483, 0.025663614663619865], [0.05415580049377229, 0.025512159488548385], [0.05441782786354536, 0.02538745261280736], [0.06473069662795325, 0.022204467947163603], [0.06483058727470829, 0.02217918947920218], [0.06500618407822036, 0.022144261103311254], [0.06520174524046095, 0.02212500001], [0.07179825761953895, 0.02212500001], [0.07199381878177934, 0.022144261103311212], [0.0723120836013751, 0.02220756791203067], [0.07267606036813512, 0.022358332025211397], [0.07294587225402517, 0.02253861456361987], [0.07309777452767545, 0.02266327753788331], [0.0740599412389342, 0.023625444249142077], [0.07421954256727642, 0.023833440749776783], [0.07443614991723896, 0.02420861568520458], [0.0745724466120828, 0.02471728187526527], [0.0745724466120828, 0.026282715184734545], [0.07443614991723915, 0.02679138137479491], [0.07415343353250461, 0.02728106051728747], [0.07378106403728785, 0.02765343001250433], [0.07347367549883911, 0.027830900867923555], [0.07337953919844722, 0.027878813335211135], [0.05488997543599179, 0.0360913298157531], [0.054678487766160536, 0.03615841638650295], [0.05444461588177951, 0.03620493639668876], [0.054249054719539, 0.03622419749], [0.05351810219436954, 0.03622419749], [0.05325817127675032, 0.03618997693549525], [0.05283971800976488, 0.03607785272053635], [0.052383660380235446, 0.03581454772536155], [0.05198383903463851, 0.03541472637976482], [0.05172053403946369, 0.03495866875023531], [0.05161337712231406, 0.034558753691050305], [0.05157992975286406, 0.03433747779237247], [0.05142573106834311, 0.030307359602748676], [0.05142499983, 0.0302691225047116], [0.05142499983, 0.028901746720461016]]

Identify pins position#

Identify [x,y] pin locations on the components to define where to assign sources and sinks for Q3D and append Z elevation.

pin_u13_scl = [i for i in edb.components["U13"].pins.values() if i.net_name == "CLOCK_I2C_SCL"]
pin_u1_scl = [i for i in edb.components["U1"].pins.values() if i.net_name == "CLOCK_I2C_SCL"]
pin_u13_sda = [i for i in edb.components["U13"].pins.values() if i.net_name == "CLOCK_I2C_SDA"]
pin_u1_sda = [i for i in edb.components["U1"].pins.values() if i.net_name == "CLOCK_I2C_SDA"]

Append Z Positions#

Note: The factor 100 converts from “meters” to “mm”

location_u13_scl = [i * 1000 for i in pin_u13_scl[0].position]
location_u13_scl.append(edb.components["U13"].upper_elevation * 1000)

location_u1_scl = [i * 1000 for i in pin_u1_scl[0].position]
location_u1_scl.append(edb.components["U1"].upper_elevation * 1000)

location_u13_sda = [i * 1000 for i in pin_u13_sda[0].position]
location_u13_sda.append(edb.components["U13"].upper_elevation * 1000)

location_u1_sda = [i * 1000 for i in pin_u1_sda[0].position]
location_u1_sda.append(edb.components["U1"].upper_elevation * 1000)

Save and close Edb#

Save, close Edb and open it in Hfss 3D Layout to generate the 3D model.

edb.save_edb()
edb.close_edb()

h3d = pyaedt.Hfss3dLayout(output_edb, version=aedt_version, non_graphical=True, new_desktop=True)
C:\actions-runner\_work\_tool\Python\3.10.9\x64\lib\subprocess.py:1072: ResourceWarning: subprocess 7692 is still running
  _warn("subprocess %s is still running" % self.pid,
C:\actions-runner\_work\pyaedt\pyaedt\.venv\lib\site-packages\pyaedt\generic\settings.py:428: ResourceWarning: unclosed file <_io.TextIOWrapper name='D:\\Temp\\pyaedt_ansys.log' mode='a' encoding='cp1252'>
  self._logger = val

Export to Q3D#

Create a dummy setup and export the layout in Q3D. keep_net_name will reassign Q3D nets names from Hfss 3D Layout.

setup = h3d.create_setup()
setup.export_to_q3d(output_q3d, keep_net_name=True)
h3d.close_project()
True

Open Q3D#

Launch the newly created q3d project and plot it.

q3d = pyaedt.Q3d(output_q3d)
q3d.plot(assignment=["CLOCK_I2C_SCL", "CLOCK_I2C_SDA"], show=False,
         output_file=os.path.join(q3d.working_directory, "Q3D.jpg"), plot_air_objects=False)
Q3D from EDB
<pyaedt.generic.plot.ModelPlotter object at 0x0000018D9FEEB9D0>

Assign Source and Sink#

Use previously calculated position to identify faces and assign sources and sinks on nets.

f1 = q3d.modeler.get_faceid_from_position(location_u13_scl, assignment="CLOCK_I2C_SCL")
q3d.source(f1, net_name="CLOCK_I2C_SCL")
f1 = q3d.modeler.get_faceid_from_position(location_u13_sda, assignment="CLOCK_I2C_SDA")
q3d.source(f1, net_name="CLOCK_I2C_SDA")
f1 = q3d.modeler.get_faceid_from_position(location_u1_scl, assignment="CLOCK_I2C_SCL")
q3d.sink(f1, net_name="CLOCK_I2C_SCL")
f1 = q3d.modeler.get_faceid_from_position(location_u1_sda, assignment="CLOCK_I2C_SDA")
q3d.sink(f1, net_name="CLOCK_I2C_SDA")
<pyaedt.modules.Boundary.BoundaryObject object at 0x0000018E03B44B20>

Create Setup#

Create a setup and a frequency sweep from DC to 2GHz. Analyze project.

setup = q3d.create_setup()
setup.dc_enabled = True
setup.capacitance_enabled = False
sweep = setup.add_sweep()
sweep.add_subrange("LinearStep", 0, end=2, count=0.05, unit="GHz", save_single_fields=False, clear=True)
setup.analyze()

ACL Report#

Compute ACL solutions and plot them.

traces_acl = q3d.post.available_report_quantities(quantities_category="ACL Matrix")
solution = q3d.post.get_solution_data(traces_acl)
solution.plot()
Simulation Results Plot
<Figure size 2000x1000 with 1 Axes>

ACR Report#

Compute ACR solutions and plot them.

traces_acr = q3d.post.available_report_quantities(quantities_category="ACR Matrix")
solution2 = q3d.post.get_solution_data(traces_acr)
solution2.plot()
Simulation Results Plot
<Figure size 2000x1000 with 1 Axes>

Close AEDT#

After the simulation completes, you can close AEDT or release it using the release_desktop method. All methods provide for saving projects before closing.

q3d.release_desktop()
True

Total running time of the script: (8 minutes 51.497 seconds)

Gallery generated by Sphinx-Gallery