diff --git a/doc/source/conf.py b/doc/source/conf.py index e445672ba..ff5c29d02 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -26,6 +26,9 @@ from sphinx.builders.latex import LaTeXBuilder from sphinx.util import logging +os.environ["PYAEDT_NON_GRAPHICAL"] = "1" +os.environ["PYAEDT_DOC_GENERATION"] = "1" + LaTeXBuilder.supported_image_types = ["image/png", "image/pdf", "image/svg+xml"] logger = logging.getLogger(__name__) @@ -260,6 +263,7 @@ def convert_examples_into_notebooks(app): "interference_type.py", "interference.py", "hfss_emit.py", + "component_conversion.py", ) # NOTE: Only convert the examples if the workflow isn't tagged as coupling HTML and PDF build. diff --git a/examples/00_edb/legacy_standalone/GDS_workflow.py b/examples/00_edb/legacy_standalone/GDS_workflow.py new file mode 100644 index 000000000..5ba2c5f90 --- /dev/null +++ b/examples/00_edb/legacy_standalone/GDS_workflow.py @@ -0,0 +1,118 @@ +# # EDB: Edit Control File and import gds +# +# This example demonstrates how to import a gds layout for subsequent +# simulation with HFSS. + +# Perform imports. + +# + +import os +import shutil +import tempfile + +import pyedb +from pyedb.dotnet.edb_core.edb_data.control_file import ControlFile +from pyedb.misc.downloads import download_file + +# - + +# ## Fetch Example Data +# +# Download the EDB folder and copy it to a temporary folder. +# The following files are used in this example: +# +# - _sky130_fictious_dtc_exmple_contol_no_map.xml_ +# defines physical information such +# as material properties, stackup layers, and boundary conditions. +# - _dummy_layermap.map_ +# maps properties to stackup layers. + +# + +temp_dir = tempfile.TemporaryDirectory(suffix=".ansys") +control_fn = "sky130_fictitious_dtc_example_control_no_map.xml" +gds_fn = "sky130_fictitious_dtc_example.gds" +layer_map = "dummy_layermap.map" + +local_path = download_file("gds", destination=temp_dir.name) +c_file_in = os.path.join(local_path, control_fn) +c_map = os.path.join(local_path, layer_map) +gds_in = os.path.join(local_path, gds_fn) +gds_out = os.path.join(temp_dir.name, "gds_out.gds") +shutil.copy2(gds_in, gds_out) +# - + +# ## Control file +# +# A Control file is an xml file which purpose if to provide additional information during +# import phase. It can include, materials, stackup, setup, boundaries and settings. +# In this example we will import an existing xml, integrate it with a layer mapping file of gds +# and then adding setup and boundaries. + +c = ControlFile(c_file_in, layer_map=c_map) + +# ## Set up simulation +# +# This code sets up a simulation with HFSS and adds a frequency sweep. + +setup = c.setups.add_setup("Setup1", "1GHz", 0.02, 10) +setup.add_sweep("Sweep1", "0.01GHz", "5GHz", "0.1GHz") + +# ## Provide additional stackup settings +# +# After import, you can change the stackup settings and add or remove layers or materials. + +c.stackup.units = "um" +c.stackup.dielectrics_base_elevation = -100 +c.stackup.metal_layer_snapping_tolerance = "10nm" +for via in c.stackup.vias: + via.create_via_group = True + via.snap_via_group = True + +# ## Define boundary settings +# +# Boundaries can include ports, components and boundary extent. + +c.boundaries.units = "um" +c.boundaries.add_port("P1", x1=223.7, y1=222.6, layer1="Metal6", x2=223.7, y2=100, layer2="Metal6") +c.boundaries.add_extent() +comp = c.components.add_component("B1", "BGA", "IC", "Flip chip", "Cylinder") +comp.solder_diameter = "65um" +comp.add_pin("1", "81.28", "84.6", "met2") +comp.add_pin("2", "211.28", "84.6", "met2") +comp.add_pin("3", "211.28", "214.6", "met2") +comp.add_pin("4", "81.28", "214.6", "met2") +c.import_options.import_dummy_nets = True + +# ## Write XML file +# +# After all settings are ready, you can write an XML file. + +c.write_xml(os.path.join(temp_dir.name, "output.xml")) + +# ## Open EDB +# +# Import the gds and open the edb. + +# + +# Select EDB version (change it manually if needed, e.g. "2024.2") +edb_version = "2024.2" +print(f"EDB version: {edb_version}") + +edb = pyedb.Edb(gds_out, edbversion=edb_version, technology_file=os.path.join(temp_dir.name, "output.xml")) +# - + +# ## Plot stackup +# +# Plot the stackup. + +edb.stackup.plot(first_layer="met1") + +# ## Close EDB +# +# Close the project. + +edb.close_edb() + +# Clean up the temporary folder. + +temp_dir.cleanup() diff --git a/examples/00_edb/legacy_standalone/Plot_nets.py b/examples/00_edb/legacy_standalone/Plot_nets.py new file mode 100644 index 000000000..24f12b0de --- /dev/null +++ b/examples/00_edb/legacy_standalone/Plot_nets.py @@ -0,0 +1,81 @@ +# # EDB: plot nets with Matplotlib +# +# This example shows how to use the ``Edb`` class to view nets, layers and +# via geometry directly in Python. The methods demonstrated in this example +# rely on +# [matplotlib](https://matplotlib.org/cheatsheets/_images/cheatsheets-1.png). + +# ## Perform required imports +# +# Perform required imports, which includes importing a section. + +# + +import tempfile + +import pyedb +from pyedb.misc.downloads import download_file + +# - + +# ## Download the EDB and copy it into the temporary folder. + +temp_dir = tempfile.TemporaryDirectory(suffix=".ansys") +targetfolder = download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name) + +# ## Create an instance of the Electronics Database using the `pyedb.Edb` class. +# +# > Note that units are SI. + +# + +# Select EDB version (change it manually if needed, e.g. "2024.2") +edb_version = "2024.2" +print(f"EDB version: {edb_version}") + +edb = pyedb.Edb(edbpath=targetfolder, edbversion=edb_version) +# - + +# Display the nets on a layer. You can display the net geometry directly in Python using +# ``matplotlib`` from the ``pyedb.Edb`` class. + +edb.nets.plot("AVCC_1V3") + +# You can view multiple nets by passing a list containing the net +# names to the ``plot()`` method. + +edb.nets.plot(["GND", "GND_DP", "AVCC_1V3"], color_by_net=True) + +# You can display all copper on a single layer by passing ``None`` +# as the first argument. The second argument is a list +# of layers to plot. In this case, only one +# layer is to be displayed. + +edb.nets.plot(None, ["1_Top"], color_by_net=True, plot_components_on_top=True) + +# Display a side view of the layers and padstack geometry using the +# ``Edb.stackup.plot()`` method. + +edb.stackup.plot(scale_elevation=False, plot_definitions=["c100hn140", "c35"]) + +# ## Creating coaxial port on component U1 and all ddr4_dqs nets +# Selecting all nets from ddr4_dqs and component U1 and create coaxial ports +# On corresponding pins. + +comp_u1 = edb.components.instances["U1"] +signal_nets = [net for net in comp_u1.nets if "ddr4_dqs" in net.lower()] +edb.hfss.create_coax_port_on_component("U1", net_list=signal_nets) +edb.components.set_solder_ball(component="U1", sball_diam="0.3mm", sball_height="0.3mm") + +# ## Renaming all ports +# Renaming all port with _renamed string as suffix example. + +for port_name, port in edb.ports.items(): + port.name = f"{port_name}_renamed" + + +# Close the EDB. + +edb.close_edb() + +# Remove all files and the temporary directory. + +temp_dir.cleanup() diff --git a/examples/00_edb/legacy_standalone/_static/cpwg.png b/examples/00_edb/legacy_standalone/_static/cpwg.png new file mode 100644 index 000000000..7dd9227f5 Binary files /dev/null and b/examples/00_edb/legacy_standalone/_static/cpwg.png differ diff --git a/examples/00_edb/legacy_standalone/_static/diff_via.png b/examples/00_edb/legacy_standalone/_static/diff_via.png new file mode 100644 index 000000000..d444d1ccb Binary files /dev/null and b/examples/00_edb/legacy_standalone/_static/diff_via.png differ diff --git a/examples/00_edb/legacy_standalone/_static/gds.png b/examples/00_edb/legacy_standalone/_static/gds.png new file mode 100644 index 000000000..e633e23a9 Binary files /dev/null and b/examples/00_edb/legacy_standalone/_static/gds.png differ diff --git a/examples/00_edb/legacy_standalone/_static/ipc.png b/examples/00_edb/legacy_standalone/_static/ipc.png new file mode 100644 index 000000000..b55811c45 Binary files /dev/null and b/examples/00_edb/legacy_standalone/_static/ipc.png differ diff --git a/examples/00_edb/legacy_standalone/_static/plot_nets.png b/examples/00_edb/legacy_standalone/_static/plot_nets.png new file mode 100644 index 000000000..ee410a98e Binary files /dev/null and b/examples/00_edb/legacy_standalone/_static/plot_nets.png differ diff --git a/examples/00_edb/legacy_standalone/_static/siwave_dcir.png b/examples/00_edb/legacy_standalone/_static/siwave_dcir.png new file mode 100644 index 000000000..63ba977f8 Binary files /dev/null and b/examples/00_edb/legacy_standalone/_static/siwave_dcir.png differ diff --git a/examples/00_edb/legacy_standalone/differential_vias.py b/examples/00_edb/legacy_standalone/differential_vias.py new file mode 100644 index 000000000..0d1c63d11 --- /dev/null +++ b/examples/00_edb/legacy_standalone/differential_vias.py @@ -0,0 +1,83 @@ +# # EDB: geometry creation + +# This example shows how you can use EDB to create a layout. +# ## Final expected project +# +# +# +# ## Import EDB layout object +# Import the EDB layout object and initialize it on version 2023 R2. + +# + +import os +import tempfile + +import pyedb + +temp_dir = tempfile.TemporaryDirectory(suffix=".ansys") +aedb_path = os.path.join(temp_dir.name, "create_via.aedb") +print(f"AEDB file path: {aedb_path}") + +# Select EDB version (change it manually if needed, e.g. "2024.2") +edb_version = "2024.2" +print(f"EDB version: {edb_version}") + +edb = pyedb.Edb(edbpath=aedb_path, edbversion=edb_version) +# - + +# ## Add stackup layers +# Add stackup layers. +# A stackup can be created layer by layer or imported from a CSV file or XML file. + +edb.stackup.add_layer("GND") +edb.stackup.add_layer("Diel", "GND", layer_type="dielectric", thickness="0.1mm", material="FR4_epoxy") +edb.stackup.add_layer("TOP", "Diel", thickness="0.05mm") + +# ## Create signal net and ground planes +# Create a signal net and ground planes. + +points = [[0.0, 0], [100e-3, 0.0]] +edb.modeler.create_trace(points, "TOP", width=1e-3) +points = [[0.0, 1e-3], [0.0, 10e-3], [100e-3, 10e-3], [100e-3, 1e-3], [0.0, 1e-3]] +edb.modeler.create_polygon(points, "TOP") +points = [[0.0, -1e-3], [0.0, -10e-3], [100e-3, -10e-3], [100e-3, -1e-3], [0.0, -1e-3]] +edb.modeler.create_polygon(points, "TOP") + + +# ## Create vias with parametric positions +# Create vias with parametric positions. + +edb.padstacks.create("MyVia") +edb.padstacks.place([5e-3, 5e-3], "MyVia") +edb.padstacks.place([15e-3, 5e-3], "MyVia") +edb.padstacks.place([35e-3, 5e-3], "MyVia") +edb.padstacks.place([45e-3, 5e-3], "MyVia") +edb.padstacks.place([5e-3, -5e-3], "MyVia") +edb.padstacks.place([15e-3, -5e-3], "MyVia") +edb.padstacks.place([35e-3, -5e-3], "MyVia") +edb.padstacks.place([45e-3, -5e-3], "MyVia") + + +# ## Generate geometry plot + +edb.nets.plot(None, color_by_net=True) + +# ## Generate stackup plot + +edb.stackup.plot(plot_definitions="MyVia") + +# ## Save and close EDB +# Save and close EDB. + +if edb: + edb.save_edb() + edb.close_edb() +print("EDB saved correctly to {}. You can import in AEDT.".format(aedb_path)) + +# ### Clean up temporary directory +# +# The following command removes the project and the temporary directory. +# If you'd like to save this project, save it to a folder of your choice +# prior to running the following cell. + +temp_dir.cleanup() diff --git a/examples/00_edb/legacy_standalone/edb_to_ipc2581.py b/examples/00_edb/legacy_standalone/edb_to_ipc2581.py new file mode 100644 index 000000000..a28a91045 --- /dev/null +++ b/examples/00_edb/legacy_standalone/edb_to_ipc2581.py @@ -0,0 +1,72 @@ +# # EDB: IPC2581 export +# +# This example shows how you can use PyAEDT to export an IPC2581 file. +# +# Perform required imports, which includes importing a section. + +# + +import os +import tempfile + +import pyedb +from pyedb.generic.general_methods import generate_unique_name +from pyedb.misc.downloads import download_file + +# - + +# ## Download the AEDB file and copy it in the temporary folder. + +temp_dir = tempfile.TemporaryDirectory(suffix=".ansys") +targetfile = download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name) +ipc2581_file_name = os.path.join(temp_dir.name, "Ansys_Hsd.xml") +print(targetfile) + +# ## Launch EDB +# +# Launch the `pyedb.Edb` class, using EDB 2023. +# > Note that length dimensions passed to EDB are in SI units. + +# + +# Select EDB version (change it manually if needed, e.g. "2024.2") +edb_version = "2024.2" +print(f"EDB version: {edb_version}") + +edb = pyedb.Edb(edbpath=targetfile, edbversion=edb_version) +# - + +# ## Parametrize the width of a trace. + +edb.modeler.parametrize_trace_width("A0_N", parameter_name=generate_unique_name("Par"), variable_value="0.4321mm") + +# ## Create a cutout and plot it. + +signal_list = [] +for net in edb.nets.netlist: + if "PCIe" in net: + signal_list.append(net) +power_list = ["GND"] +edb.cutout( + signal_list=signal_list, + reference_list=power_list, + extent_type="ConvexHull", + expansion_size=0.002, + use_round_corner=False, + number_of_threads=4, + remove_single_pin_components=True, + use_pyaedt_extent_computing=True, + extent_defeature=0, +) +edb.nets.plot(None, None, color_by_net=True) + +# ## Export the EDB to an IPC2581 file. + +edb.export_to_ipc2581(ipc2581_file_name, "inch") +print("IPC2581 File has been saved to {}".format(ipc2581_file_name)) + +# ## Close EDB + +edb.close_edb() + +# ## Clean up the temporary directory + +temp_dir.cleanup() diff --git a/examples/00_edb/legacy_standalone/siwave_dcir.py b/examples/00_edb/legacy_standalone/siwave_dcir.py new file mode 100644 index 000000000..82a5d74d7 --- /dev/null +++ b/examples/00_edb/legacy_standalone/siwave_dcir.py @@ -0,0 +1,209 @@ +# # EDB: SIwave DC-IR Analysis +# +# This example demonstrates the use of EDB to interact with a PCB +# layout and run DC-IR analysis in SIwave. +# Perform required imports + +# + +import os +import tempfile +import time + +import pyedb +from pyedb.misc.downloads import download_file + +temp_dir = tempfile.TemporaryDirectory(suffix=".ansys") +targetfile = download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name) + +siwave_file = os.path.join(os.path.dirname(targetfile), "ANSYS-HSD_V1.siw") +print(targetfile) +aedt_file = targetfile[:-4] + "aedt" +# - + +# ## Launch Ansys Electronics Database (EDB) +# +# Instantiate an instance of the `pyedb.Edb` class using SI units. + +# + +if os.path.exists(aedt_file): + os.remove(aedt_file) + +# Select EDB version (change it manually if needed, e.g. "2024.2") +edb_version = "2024.2" +print(f"EDB version: {edb_version}") + +edb = pyedb.Edb(edbpath=targetfile, edbversion=edb_version) +# - + +# ## Identify nets and components +# +# The ``Edb.nets.netlist`` and ``Edb.components.instances`` properties contain information +# about all of the nets and components. The following cell uses this information to print the +# number of nets and components. + +print("Nets {}".format(len(edb.nets.netlist))) +start = time.time() +print("Components {}".format(len(edb.components.instances.keys()))) +print("elapsed time = ", time.time() - start) + +# ## Identify pin positions +# +# This code shows how to obtain all pins for a specific component and +# print the ``[x, y]`` position of each pin. + +pins = edb.components["U2"].pins +count = 0 +for pin in edb.components["U2"].pins.values(): + if count < 10: # Only print the first 10 pin coordinates. + print(pin.position) + elif count == 10: + print("...and many more.") + else: + pass + count += 1 + +# Get all nets connected to a specific component. Print +# the pin and the name of the net that it is connected to. + +connections = edb.components.get_component_net_connection_info("U2") +n_print = 0 # Counter to limit the number of printed lines. +print_max = 15 +for m in range(len(connections["pin_name"])): + ref_des = connections["refdes"][m] + pin_name = connections["pin_name"][m] + net_name = connections["net_name"][m] + if net_name != "" and (n_print < print_max): + print('{}, pin {} -> net "{}"'.format(ref_des, pin_name, net_name)) + n_print += 1 + elif n_print == print_max: + print("...and many more.") + n_print += 1 + +# Compute rats. + +rats = edb.components.get_rats() + +# ## Identify connected nets +# +# The ``get_dcconnected_net_list()`` method retrieves a list of +# all DC-connected power nets. Each group of connected nets is returned +# as a [set](https://docs.python.org/3/tutorial/datastructures.html#sets). +# The first argument to the method is the list of ground nets, which are +# not considered in the search for connected nets. + +GROUND_NETS = ["GND", "GND_DP"] +dc_connected_net_list = edb.nets.get_dcconnected_net_list(GROUND_NETS) +for pnets in dc_connected_net_list: + print(pnets) + +# ## Power Tree +# +# The power tree provides connectivity through all components from the VRM to +# the device. + +VRM = "U1" +OUTPUT_NET = "AVCC_1V3" +powertree_df, component_list_columns, net_group = edb.nets.get_powertree(OUTPUT_NET, GROUND_NETS) + +# Print some information about the power tree. + +print_columns = ["refdes", "pin_name", "component_partname"] +ncol = [component_list_columns.index(c) for c in print_columns] + +# This prints the header. Replace "pin_name" with "pin" to +# make the header align with the values. + +# + +print("\t".join(print_columns).replace("pin_name", "pin")) + +for el in powertree_df: + s = "" + count = 0 + for e in el: + if count in ncol: + s += "{}\t".format(e) + count += 1 + s.rstrip() + print(s) +# - + +# ## Remove unused components +# +# Delete all RLC components that are connected with only one pin. +# The ``Edb.components.delete_single_pin_rlc()`` method +# provides a useful way to +# remove components that are not needed for the simulation. + +edb.components.delete_single_pin_rlc() + +# You can also remove unused components explicitly by name. + +edb.components.delete("C380") + +# Nets can also be removed explicitly. + +edb.nets.delete("PDEN") + +# Print the top and bottom elevation of the stackup obtained using +# the ``Edb.stackup.limits()`` method. + +s = 'Top layer name: "{top}", Elevation: {top_el:.2f} ' +s += 'mm\nBottom layer name: "{bot}", Elevation: {bot_el:2f} mm' +top, top_el, bot, bot_el = edb.stackup.limits() +print(s.format(top=top, top_el=top_el * 1e3, bot=bot, bot_el=bot_el * 1e3)) + +# ## Set up for SIwave DCIR analysis +# +# Create a voltage source and then set up a DCIR analysis. + +edb.siwave.create_voltage_source_on_net("U1", "AVCC_1V3", "U1", "GND", 1.3, 0, "V1") +edb.siwave.create_current_source_on_net("IC2", "NetD3_2", "IC2", "GND", 1.0, 0, "I1") +setup = edb.siwave.add_siwave_dc_analysis("myDCIR_4") +setup.use_dc_custom_settings = True +setup.set_dc_slider = 0 +setup.add_source_terminal_to_ground("V1", 1) + +# ## Solve +# +# Save the modifications and run the analysis in SIwave. + +edb.save_edb() +edb.nets.plot(None, "1_Top", plot_components_on_top=True) + + + +# ## Export results +# +# Export all quantities calculated from the DC-IR analysis. +# The following method runs SIwave in batch mode from the command line. +# Results are written to the edb folder. +# Un-commment following lines to analyze with SIwave and export results. + +#siw_file = edb.solve_siwave() +# outputs = edb.export_siwave_dc_results( +# siw_file, +# setup.name, +# ) + +# Close EDB. After EDB is closed, it can be opened by AEDT. + +edb.close_edb() + +# ## View Layout in SIwave +# +# The SIwave user interface can be visualized and manipulated +# using the SIwave user interface. This command works on Window OS only. + +# + +# siwave = pyedb.Siwave("2024.2") +# siwave.open_project(siwave_file) +# report_file = os.path.join(temp_folder,'Ansys.htm') + +# siwave.export_siwave_report("myDCIR_4", report_file) +# siwave.close_project() +# siwave.quit_application() +# - + +# Clean up the temporary files and directory. + +temp_dir.cleanup() diff --git a/examples/00_edb/use_configuration/_static/configurator.png b/examples/00_edb/use_configuration/_static/configurator.png new file mode 100644 index 000000000..31b5a17ce Binary files /dev/null and b/examples/00_edb/use_configuration/_static/configurator.png differ diff --git a/examples/00_edb/use_configuration/_static/configurator_2.png b/examples/00_edb/use_configuration/_static/configurator_2.png new file mode 100644 index 000000000..ad82747b4 Binary files /dev/null and b/examples/00_edb/use_configuration/_static/configurator_2.png differ diff --git a/examples/00_edb/use_configuration/_static/parametrized_design.png b/examples/00_edb/use_configuration/_static/parametrized_design.png new file mode 100644 index 000000000..80bcb84b1 Binary files /dev/null and b/examples/00_edb/use_configuration/_static/parametrized_design.png differ diff --git a/examples/00_edb/use_configuration/dcir.py b/examples/00_edb/use_configuration/dcir.py new file mode 100644 index 000000000..627837561 --- /dev/null +++ b/examples/00_edb/use_configuration/dcir.py @@ -0,0 +1,155 @@ +# # DCIR Setup Leveraging EDB Configuration Format + +# ## Import the required packages + +# + +import json +import os +import tempfile + +from ansys.aedt.core import Hfss3dLayout +from ansys.aedt.core.downloads import download_file + +from pyedb import Edb + +AEDT_VERSION = "2024.2" +NG_MODE = False +# - + +# Download the example BGA Package design. + +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") +file_edb = download_file(source=r"edb/BGA_Package.aedb", destination=temp_folder.name) + +# ## Load example layout + +edbapp = Edb(file_edb, edbversion=AEDT_VERSION) + +# ## Create config file + +# Define Component with solderballs. + +cfg_components = [ + { + "reference_designator": "FCHIP", + "part_type": "other", + "solder_ball_properties": { + "shape": "cylinder", + "diameter": "0.1mm", + "height": "0.085mm", + "chip_orientation": "chip_up", + }, + "port_properties": { + "reference_offset": 0, + "reference_size_auto": False, + "reference_size_x": 0, + "reference_size_y": 0, + }, + }, + { + "reference_designator": "BGA", + "part_type": "io", + "solder_ball_properties": { + "shape": "cylinder", + "diameter": "0.45mm", + "height": "0.45mm", + "chip_orientation": "chip_down", + }, + "port_properties": { + "reference_offset": 0, + "reference_size_auto": False, + "reference_size_x": 0, + "reference_size_y": 0, + }, + }, +] + +# Define Pin Groups on Components. + +cfg_pin_groups = [ + {"name": "BGA_VSS", "reference_designator": "BGA", "net": "VSS"}, + {"name": "BGA_VDD", "reference_designator": "BGA", "net": "VDD"}, +] + +# Define sources. + +cfg_sources = [ + { + "name": "FCHIP_Current", + "reference_designator": "FCHIP", + "type": "current", + "magnitude": 2, + "distributed": True, + "positive_terminal": {"net": "VDD"}, + "negative_terminal": {"nearest_pin": {"reference_net": "VSS", "search_radius": 5e-3}}, + }, + { + "name": "BGA_Voltage", + "reference_designator": "BGA", + "type": "voltage", + "magnitude": 1, + "positive_terminal": {"pin_group": "BGA_VDD"}, + "negative_terminal": {"pin_group": "BGA_VSS"}, + }, +] + +# Define DCIR setup. + +cfg_setups = [ + { + "name": "siwave_dc", + "type": "siwave_dc", + "dc_slider_position": 1, + "dc_ir_settings": {"export_dc_thermal_data": True}, + } +] + +# Create final configuration. + +cfg = { + "components": cfg_components, + "sources": cfg_sources, + "pin_groups": cfg_pin_groups, + "setups": cfg_setups, +} + +# Create the config file. + +file_json = os.path.join(temp_folder.name, "edb_configuration.json") +with open(file_json, "w") as f: + json.dump(cfg, f, indent=4, ensure_ascii=False) + +# ## Apply Config file + +# Apply configuration to the example layout + +edbapp.configuration.load(config_file=file_json) +edbapp.configuration.run() + +# Save and close EDB. + +edbapp.save() +edbapp.close() + +# The configured EDB file is saved in a temp folder. + +print(temp_folder.name) + +# ## Load edb into HFSS 3D Layout. + +h3d = Hfss3dLayout(edbapp.edbpath, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True) + +# Solve. + +h3d.analyze(setup="siwave_dc") + +# Plot insertion loss. + +h3d.post.create_fieldplot_layers_nets(layers_nets=[["VDD_C1", "VDD"]], quantity="Voltage", setup="siwave_dc") + +# Shut Down Electronics Desktop + +h3d.close_desktop() + +# All project files are saved in the folder ``temp_file.dir``. If you've run this example as a Jupyter notebook you +# can retrieve those project files. diff --git a/examples/00_edb/use_configuration/import_components.py b/examples/00_edb/use_configuration/import_components.py new file mode 100644 index 000000000..b0dee6e9a --- /dev/null +++ b/examples/00_edb/use_configuration/import_components.py @@ -0,0 +1,121 @@ +# # Import Component Definitions +# This example shows how to import component definitions. It includes +# +# - Download an example board +# - Create a config file with component RLC and solder ball information +# - Apply the config file to the example board + +# ## Import the required packages + +# + +import json +from pathlib import Path +import tempfile + +from IPython.display import display +from ansys.aedt.core.downloads import download_file +import pandas as pd + +from pyedb import Edb + +AEDT_VERSION = "2024.2" + +# - + +# Download the example PCB data. + +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys").name +file_edb = download_file(source="edb/ANSYS-HSD_V1.aedb", destination=temp_folder) + +# ## Load example layout. + +edbapp = Edb(file_edb, edbversion=AEDT_VERSION) + +# ## Create a config file with component information + +# Keywords +# +# - **reference_designator**. Reference designator of the component. +# - **part_type**. Part type of the component. Supported types are 'resistor', 'inductor', 'capacitor', 'ic', 'io', +# 'other'. +# - **enabled**. Only available for RLC components. +# - **solder_ball_properties**. +# - **shape**. Supported types are 'cylinder', 'spheroid', 'none'. +# - **diameter**. +# - **mid_diameter**. +# - **height**. +# - **material**. +# - **port_properties**. +# - **reference_offset**. +# - **reference_size_auto**. +# - **reference_size_x**. +# - **reference_size_y**. +# - **pin_pair_model**. RLC network. Multiple pin pairs are supported. +# - **first_pin**. First pin of the pin pair. +# - **second_pin**. Second pin of the pin pair. +# - **is_parallel**. +# - **resistance**. +# - **resistance_enabled**. +# - **inductance**. +# - **inductance_enabled**. +# - **capacitance**. +# - **capacitance_enabled**. + +cfg = dict() +cfg["components"] = [ + { + "reference_designator": "U1", + "part_type": "io", + "solder_ball_properties": { + "shape": "spheroid", + "diameter": "244um", + "mid_diameter": "400um", + "height": "300um", + "material": "air", + }, + "port_properties": { + "reference_offset": "0.1mm", + "reference_size_auto": True, + "reference_size_x": 0, + "reference_size_y": 0, + }, + }, + { + "reference_designator": "C375", + "enabled": False, + "pin_pair_model": [ + { + "first_pin": "1", + "second_pin": "2", + "is_parallel": False, + "resistance": "10ohm", + "resistance_enabled": True, + "inductance": "1nH", + "inductance_enabled": False, + "capacitance": "10nF", + "capacitance_enabled": True, + } + ], + }, +] + +display(pd.DataFrame(data=[cfg["components"][0]["solder_ball_properties"]])) + +display(pd.DataFrame(data=[cfg["components"][0]["port_properties"]])) + +display(pd.DataFrame(data=cfg["components"][1]["pin_pair_model"])) + +cfg_file_path = Path(temp_folder) / "cfg.json" +with open(cfg_file_path, "w") as f: + json.dump(cfg, f, indent=4, ensure_ascii=False) + +# Load config file + +edbapp.configuration.load(cfg_file_path, apply_file=True) + +# ## Save and close Edb +# The temporary folder will be deleted once the execution of this script is finished. Replace **edbapp.save()** with +# **edbapp.save_as("C:/example.aedb")** to keep the example project. + +edbapp.save() +edbapp.close() diff --git a/examples/00_edb/use_configuration/import_material.py b/examples/00_edb/use_configuration/import_material.py new file mode 100644 index 000000000..efbd65d08 --- /dev/null +++ b/examples/00_edb/use_configuration/import_material.py @@ -0,0 +1,81 @@ +# # Import Materials +# This example shows how to import materials. + +# ### Import the required packages + +# + +import json +from pathlib import Path +import tempfile + +from IPython.display import display +from ansys.aedt.core.downloads import download_file +import pandas as pd + +from pyedb import Edb + +AEDT_VERSION = "2024.2" +NG_MODE = False + +# - + +# Download the example PCB data. + +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") +file_edb = download_file(source="edb/ANSYS-HSD_V1.aedb", destination=temp_folder.name) + +# ## Load example layout. + +edbapp = Edb(file_edb, edbversion=AEDT_VERSION) + +# ## Review materials from layout + +# Get materials from layout in a dictionary. Materials are exported together with stadckup. + +data_cfg = edbapp.configuration.get_data_from_db(stackup=True) + + +df = pd.DataFrame(data=data_cfg["stackup"]["materials"]) +display(df) + +# ## Add a new material + +data_cfg["stackup"]["materials"].append( + {"name": "soldermask", "permittivity": 3.3, "dielectric_loss_tangent": 0.02}, +) + +# ## Edit existing material properties + +data_cfg["stackup"]["materials"][1]["name"] = "fr4_epoxy" +data_cfg["stackup"]["materials"][1]["dielectric_loss_tangent"] = 0.015 + +# ## Review modified materials + +df = pd.DataFrame(data=data_cfg["stackup"]["materials"]) +display(df) + +# ## Write material definition into a json file + +file_cfg = Path(temp_folder.name) / "edb_configuration.json" +with open(file_cfg, "w") as f: + json.dump(data_cfg, f, indent=4, ensure_ascii=False) + + +# ## Load materials from json configuration file + +edbapp.configuration.load(str(file_cfg), apply_file=True) + +# ## Review materials from layout + +edbapp.materials.materials + +# ## Check modified material properties + +edbapp.materials["fr4_epoxy"].loss_tangent + +# ## Save and close Edb +# The temporary folder will be deleted once the execution of this script is finished. Replace **edbapp.save()** with +# **edbapp.save_as("C:/example.aedb")** to keep the example project. + +edbapp.save() +edbapp.close() diff --git a/examples/00_edb/use_configuration/import_padstack_definitions.py b/examples/00_edb/use_configuration/import_padstack_definitions.py new file mode 100644 index 000000000..3ea55a4e4 --- /dev/null +++ b/examples/00_edb/use_configuration/import_padstack_definitions.py @@ -0,0 +1,138 @@ +# # Import Padstack Definitions +# This example shows how to import padstack definitions. This includes +# +# - Download an example board +# - Create a config file with hole information +# - Create a config file with pad and anti-pad information + +# ## Import the required packages + +# + +import json +from pathlib import Path +import tempfile + +from IPython.display import display +from ansys.aedt.core.downloads import download_file +import pandas as pd + +from pyedb import Edb + +AEDT_VERSION = "2024.2" + +# - + +# Download the example PCB data. + +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys").name +file_edb = download_file(source="edb/ANSYS-HSD_V1.aedb", destination=temp_folder) + +# ## Load example layout. + +edbapp = Edb(file_edb, edbversion=AEDT_VERSION) + +# ## Create a config file with hole information + +# Keywords +# +# - **name**. Name of the padstack definition. +# - **hole_plating_thickness**. Hole plating thickness. +# - **hole_range**. Supported types are 'through', 'begin_on_upper_pad', 'end_on_lower_pad', 'upper_pad_to_lower_pad'. +# - **hole_parameters**. +# - **shape**. Supported types are 'circle', 'square', 'rectangle'. +# - Other parameters are shape dependent. +# - When shape is 'circle', supported parameter si 'diameter'. +# - When shape is 'square', supported parameter is 'size'. +# - When shape is 'rectangle', supported parameters are 'x_size', 'y_size'. + +cfg = dict() +cfg["padstacks"] = {} +cfg["padstacks"]["definitions"] = [ + { + "name": "v35h15", + "hole_plating_thickness": "25um", + "material": "copper", + "hole_range": "through", + "hole_parameters": { + "shape": "circle", + "diameter": "0.15mm", + }, + } +] + +df = pd.DataFrame(data=cfg["padstacks"]["definitions"]) +display(df) + +cfg_file_path = Path(temp_folder) / "cfg.json" +with open(cfg_file_path, "w") as f: + json.dump(cfg, f, indent=4, ensure_ascii=False) + +# Load config file + +edbapp.configuration.load(cfg_file_path, apply_file=True) + +# ## Create a config file with pad information + +# Keywords +# +# - **name**. Name of the padstack definition. +# - **pad_parameters**. +# - **regular_pad**. List of pad definition per layer. +# - **layer_name**. Name of the layer. +# - **shape**. Supported types are 'circle', 'square', 'rectangle', 'oval', 'bullet'. +# - Other parameters are shape dependent. +# - When shape is 'circle', supported parameter si 'diameter'. +# - When shape is 'square', supported parameter is 'size'. +# - When shape is 'rectangle', supported parameters are 'x_size', 'y_size'. +# - When shape is 'oval', supported parameters are 'x_size', 'y_size', 'corner_radius'. +# - When shape is 'bullet', supported parameters are 'x_size', 'y_size', 'corner_radius'. + +cfg = dict() +cfg["padstacks"] = {} +cfg["padstacks"]["definitions"] = [ + { + "name": "v35h15", + "pad_parameters": { + "regular_pad": [ + { + "layer_name": "1_Top", + "shape": "circle", + "offset_x": "0.1mm", + "offset_y": "0.1mm", + "rotation": "0", + "diameter": "0.5mm", + }, + { + "layer_name": "Inner1(GND1)", + "shape": "square", + "offset_x": "0.1mm", + "offset_y": "0.1mm", + "rotation": "45deg", + "size": "0.5mm", + }, + ], + "anti_pad": [{"layer_name": "1_Top", "shape": "circle", "diameter": "1mm"}], + }, + } +] + +df = pd.DataFrame(data=cfg["padstacks"]["definitions"][0]["pad_parameters"]["regular_pad"]) +display(df) + +df = pd.DataFrame(data=cfg["padstacks"]["definitions"][0]["pad_parameters"]["anti_pad"]) +display(df) + +cfg_file_path = Path(temp_folder) / "cfg.json" +with open(cfg_file_path, "w") as f: + json.dump(cfg, f, indent=4, ensure_ascii=False) + +# Load config file + +edbapp.configuration.load(cfg_file_path, apply_file=True) + +# ## Save and close Edb +# The temporary folder will be deleted once the execution of this script is finished. Replace edbapp.save() with +# edbapp.save_as("C:/example.aedb") to keep the example project. + +edbapp.save() +edbapp.close() diff --git a/examples/00_edb/use_configuration/import_ports.py b/examples/00_edb/use_configuration/import_ports.py new file mode 100644 index 000000000..748faf3a2 --- /dev/null +++ b/examples/00_edb/use_configuration/import_ports.py @@ -0,0 +1,161 @@ +# # Import Ports +# This example shows how to import ports. In this example, we are going to +# +# - Download an example board +# - Create a configuration file +# - Add a circuit port between two nets +# - Add a circuit port between two pins +# - Add a circuit port between two pin groups +# - Add a circuit port between two coordinates +# - Add a coax port +# - Add a port reference to the nearest pin +# - Add distributed ports +# - Import the configuration file + +# ## Import the required packages + +# + +import json +from pathlib import Path +import tempfile + +from ansys.aedt.core.downloads import download_file + +from pyedb import Edb + +AEDT_VERSION = "2024.2" +NG_MODE = False + +# - + +# Download the example PCB data. + +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") +file_edb = download_file(source="edb/ANSYS-HSD_V1.aedb", destination=temp_folder.name) + +# ## Load example layout + +edbapp = Edb(file_edb, edbversion=AEDT_VERSION) + +# ## Create an empty dictionary to host all configurations + +cfg = dict() + +# ## Add a circuit port between two nets + +# Keywords +# +# - **name**. Name of the port. +# - **Reference_designator**. Reference designator of the component. +# - **type**. Type of the port. Supported types are 'circuit', 'coax' +# - **positive_terminal**. Positive terminal of the port. Supported types are 'net', 'pin', 'pin_group', 'coordinates' +# - **negative_terminal**. Negative terminal of the port. Supported types are 'net', 'pin', 'pin_group', 'coordinates', +# 'nearest_pin' + +port_1 = { + "name": "port_1", + "reference_designator": "X1", + "type": "circuit", + "positive_terminal": {"net": "PCIe_Gen4_TX2_N"}, + "negative_terminal": {"net": "GND"}, +} + +# ## Add a circuit port between two pins + +port_2 = { + "name": "port_2", + "reference_designator": "C375", + "type": "circuit", + "positive_terminal": {"pin": "1"}, + "negative_terminal": {"pin": "2"}, +} + +# ## Add a circuit port between two pin groups + +pin_groups = [ + {"name": "U9_5V_1", "reference_designator": "U9", "pins": ["32", "33"]}, + {"name": "U9_GND", "reference_designator": "U9", "net": "GND"}, +] + +port_3 = { + "name": "port_3", + "type": "circuit", + "positive_terminal": {"pin_group": "U9_5V_1"}, + "negative_terminal": {"pin_group": "U9_GND"}, +} + +# ## Add a circuit port between two coordinates + +# Keywords +# +# - **layer**. Layer on which the terminal is placed +# - **point**. XY coordinate the terminal is placed +# - **net**. Name of the net the terminal is placed on + +port_4 = { + "name": "port_4", + "type": "circuit", + "positive_terminal": {"coordinates": {"layer": "1_Top", "point": ["104mm", "37mm"], "net": "AVCC_1V3"}}, + "negative_terminal": {"coordinates": {"layer": "Inner6(GND2)", "point": ["104mm", "37mm"], "net": "GND"}}, +} + +# ## Add a coax port + +port_5 = {"name": "port_5", "reference_designator": "U1", "type": "coax", "positive_terminal": {"pin": "AM17"}} + +# ## Add a port reference to the nearest pin + +# Keywords +# +# - **reference_net**. Name of the reference net +# - **search_radius**. Reference pin search radius in meter + +port_6 = { + "name": "port_6", + "reference_designator": "U15", + "type": "circuit", + "positive_terminal": {"pin": "D7"}, + "negative_terminal": {"nearest_pin": {"reference_net": "GND", "search_radius": 5e-3}}, +} + +# ## Add distributed ports + +# Keywords +# +# - **distributed**. Whether to create distributed ports. When set to True, ports are created per pin + +ports_distributed = { + "name": "ports_d", + "reference_designator": "U7", + "type": "circuit", + "distributed": True, + "positive_terminal": {"net": "VDD_DDR"}, + "negative_terminal": {"net": "GND"}, +} + +# ## Add setups in configuration + +cfg["pin_groups"] = pin_groups +cfg["ports"] = [port_1, port_2, port_3, port_4, port_5, port_6, ports_distributed] + +# ## Write configuration into as json file + +file_json = Path(temp_folder.name) / "edb_configuration.json" +with open(file_json, "w") as f: + json.dump(cfg, f, indent=4, ensure_ascii=False) + +# ## Import configuration into example layout + +edbapp.configuration.load(config_file=file_json) +edbapp.configuration.run() + +# ## Review + +edbapp.ports + +# ## Save and close Edb +# The temporary folder will be deleted once the execution of this script is finished. Replace **edbapp.save()** with +# **edbapp.save_as("C:/example.aedb")** to keep the example project. + +edbapp.save() +edbapp.close() diff --git a/examples/00_edb/use_configuration/import_setup_ac.py b/examples/00_edb/use_configuration/import_setup_ac.py new file mode 100644 index 000000000..f494ec0cc --- /dev/null +++ b/examples/00_edb/use_configuration/import_setup_ac.py @@ -0,0 +1,142 @@ +# # Import Setup AC +# This example shows how to import SIwave, HFSS setups for AC analysis. In this example, we are going to +# +# - Download an example board +# - Create a configuration file +# - add setups +# - Import the configuration file + +# ### Import the required packages + +# + +import json +from pathlib import Path +import tempfile + +from ansys.aedt.core.downloads import download_file + +from pyedb import Edb + +AEDT_VERSION = "2024.2" +NG_MODE = False + +# - + +# Download the example PCB data. + +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") +file_edb = download_file(source="edb/ANSYS-HSD_V1.aedb", destination=temp_folder.name) + +# ## Load example layout. + +edbapp = Edb(file_edb, edbversion=AEDT_VERSION) + +# ## Create an empty dictionary to host all configurations. + +cfg = dict() + +# ## Create an SIwave SYZ setup + +# Keywords +# +# - **name**. Name of the setup. +# - **type**. Type of the analysis setup. Supported types are 'siwave_ac', 'siwave_dc', 'hfss'. +# - **pi_slider_position**. PI slider position. Supported values are from '0', '1', '2'. 0:speed, 1:balanced, +# 2:accuracy. +# - **freq_sweep**. List of frequency sweeps. +# - **name**. Name of the sweep. +# - **type**. Type of the sweep. Supported types are 'interpolation', 'discrete', 'broadband'. +# - **frequencies**. Frequency distribution. +# - **distribution**. Supported distributions are 'linear_count', 'linear_scale', 'log_scale'. +# - **start**. Start frequency. Example, 1e6, "1MHz". +# - **stop**. Stop frequency. Example, 1e9, "1GHz". +# - **increment**. + +siwave_setup = { + "name": "siwave_1", + "type": "siwave_ac", + "pi_slider_position": 1, + "freq_sweep": [ + { + "name": "Sweep1", + "type": "interpolation", + "frequencies": [{"distribution": "log_scale", "start": 1e6, "stop": 1e9, "increment": 20}], + } + ], +} + +# ## Create a HFSS setup + +# Keywords +# +# - **name**. Name of the setup. +# - **type**. Type of the analysis setup. Supported types are 'siwave_ac', 'siwave_dc', 'hfss'. +# - **f_adapt**. Adaptive frequency. +# - **max_num_passes**. Maximum number of passes. +# - **max_mag_delta_s**. Convergence criteria delta S. +# - **mesh_operations**. Mesh operations. +# - **name**. Name of the mesh operation. +# - **type**. Type of the mesh operation. The supported types are 'base', 'length', 'skin_depth'. +# - **max_length**. Maximum length of elements. +# - **restrict_length**. Whether to restrict length of elements. +# - **refine_inside**. Whether to turn on refine inside objects. +# - **nets_layers_list**. {'layer_name':['net_name_1', 'net_name_2']} +# - **freq_sweep**. List of frequency sweeps. +# - **name**. Name of the sweep. +# - **type**. Type of the sweep. Supported types are 'interpolation', 'discrete', 'broadband'. +# - **frequencies**. Frequency distribution. +# - **distribution**. Supported distributions are 'linear_count', 'linear_scale', 'log_scale'. +# - **start**. Start frequency. Example, 1e6, "1MHz". +# - **stop**. Stop frequency. Example, 1e9, "1GHz". +# - **increment**. + +hfss_setup = { + "name": "hfss_1", + "type": "hfss", + "f_adapt": "5GHz", + "max_num_passes": 10, + "max_mag_delta_s": 0.02, + "mesh_operations": [ + { + "name": "mop_1", + "type": "length", + "max_length": "3mm", + "restrict_length": True, + "refine_inside": False, + "nets_layers_list": {"GND": ["1_Top", "16_Bottom"]}, + } + ], + "freq_sweep": [ + { + "name": "Sweep1", + "type": "interpolation", + "frequencies": [{"distribution": "log_scale", "start": 1e6, "stop": 1e9, "increment": 20}], + } + ], +} + +# ## Add setups in configuration + +cfg["setups"] = [siwave_setup, hfss_setup] + +# ## Write configuration into as json file + +file_json = Path(temp_folder.name) / "edb_configuration.json" +with open(file_json, "w") as f: + json.dump(cfg, f, indent=4, ensure_ascii=False) + +# ## Import configuration into example layout + +edbapp.configuration.load(config_file=file_json) +edbapp.configuration.run() + +# ## Review + +edbapp.setups + +# ## Save and close Edb +# The temporary folder will be deleted once the execution of this script is finished. Replace **edbapp.save()** with +# **edbapp.save_as("C:/example.aedb")** to keep the example project. + +edbapp.save() +edbapp.close() diff --git a/examples/00_edb/use_configuration/import_sources.py b/examples/00_edb/use_configuration/import_sources.py new file mode 100644 index 000000000..9e1d5f3c3 --- /dev/null +++ b/examples/00_edb/use_configuration/import_sources.py @@ -0,0 +1,170 @@ +# # Import Sources +# This example shows how to import voltage and current sources. In this example, we are going to +# +# - Download an example board +# - Create a configuration file +# - Add a voltage source between two nets +# - Add a current source between two pins +# - Add a current source between two pin groups +# - Add a current source between two coordinates +# - Add a current source to the nearest pin +# - Add distributed sources +# - Import the configuration file + +# ## Import the required packages + +# + +import json +from pathlib import Path +import tempfile + +from ansys.aedt.core.downloads import download_file + +from pyedb import Edb + +AEDT_VERSION = "2024.2" +NG_MODE = False + +# - + +# Download the example PCB data. + +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") +file_edb = download_file(source="edb/ANSYS-HSD_V1.aedb", destination=temp_folder.name) + +# ## Load example layout + +edbapp = Edb(file_edb, edbversion=AEDT_VERSION) + +# ## Create an empty dictionary to host all configurations + +cfg = dict() + +# ## Add a voltage source between two nets + +# Keywords +# +# - **name**. Name of the voltage source. +# - **Reference_designator**. Reference designator of the component. +# - **type**. Type of the source. Supported types are 'voltage', 'current' +# - **positive_terminal**. Supported types are 'net', 'pin', 'pin_group', 'coordinates' +# - **contact_radius**. Optional. Set circular equipotential region. +# - **inline**. Optional. When True, contact points are place in a row. +# - **num_of_contact**. Optional. Number of contact points. Default is 1. Applicable only when inline is True. +# - **negative_terminal**. Supported types are 'net', 'pin', 'pin_group', 'coordinates' +# - **equipotential**. Set equipotential region on pins when True. + +voltage_source = { + "name": "V_SOURCE_5V", + "reference_designator": "U4", + "type": "voltage", + "magnitude": 1, + "positive_terminal": {"net": "5V", "contact_radius": "1mm"}, + "negative_terminal": {"net": "GND", "contact_radius": "1mm"}, + "equipotential": True, +} + +# ## Add a current source between two pins + +current_source_1 = { + "name": "I_CURRENT_1A", + "reference_designator": "J5", + "type": "current", + "magnitude": 10, + "positive_terminal": {"pin": "15"}, + "negative_terminal": {"pin": "14"}, +} + +# ## Add a current source between two pin groups + +pin_groups = [ + {"name": "IC2_5V", "reference_designator": "IC2", "pins": ["8"]}, + {"name": "IC2_GND", "reference_designator": "IC2", "net": "GND"}, +] + +current_source_2 = { + "name": "CURRENT_SOURCE_2", + "type": "current", + "positive_terminal": {"pin_group": "IC2_5V"}, + "negative_terminal": {"pin_group": "IC2_GND"}, +} + +# ## Add a current source between two coordinates + +# Keywords +# +# - **layer**. Layer on which the terminal is placed +# - **point**. XY coordinate the terminal is placed +# - **net**. Name of the net the terminal is placed on + +current_source_3 = { + "name": "CURRENT_SOURCE_3", + "type": "current", + "equipotential": True, + "positive_terminal": {"coordinates": {"layer": "1_Top", "point": ["116mm", "41mm"], "net": "5V"}}, + "negative_terminal": {"coordinates": {"layer": "Inner1(GND1)", "point": ["116mm", "41mm"], "net": "GND"}}, +} + +# ## Add a current source reference to the nearest pin + +# Keywords +# +# - **reference_net**. Name of the reference net +# - **search_radius**. Reference pin search radius in meter + +current_source_4 = { + "name": "CURRENT_SOURCE_4", + "reference_designator": "J5", + "type": "current", + "positive_terminal": {"pin": "16"}, + "negative_terminal": {"nearest_pin": {"reference_net": "GND", "search_radius": 5e-3}}, +} + +# ## Add distributed current sources + +# Keywords +# +# - **distributed**. Whether to create distributed sources. When set to True, ports are created per pin + +sources_distributed = { + "name": "DISTRIBUTED", + "reference_designator": "U2", + "type": "current", + "distributed": True, + "positive_terminal": {"net": "5V"}, + "negative_terminal": {"net": "GND"}, +} + +# ## Add setups in configuration + +cfg["pin_groups"] = pin_groups +cfg["sources"] = [ + voltage_source, + current_source_1, + current_source_2, + current_source_3, + current_source_4, + sources_distributed, +] + +# ## Write configuration into as json file + +file_json = Path(temp_folder.name) / "edb_configuration.json" +with open(file_json, "w") as f: + json.dump(cfg, f, indent=4, ensure_ascii=False) + +# ## Import configuration into example layout + +edbapp.configuration.load(config_file=file_json) +edbapp.configuration.run() + +# ## Review + +edbapp.siwave.sources + +# ## Save and close Edb +# The temporary folder will be deleted once the execution of this script is finished. Replace **edbapp.save()** with +# **edbapp.save_as("C:/example.aedb")** to keep the example project. + +edbapp.save() +edbapp.close() diff --git a/examples/00_edb/use_configuration/import_stackup.py b/examples/00_edb/use_configuration/import_stackup.py new file mode 100644 index 000000000..446d5f4e8 --- /dev/null +++ b/examples/00_edb/use_configuration/import_stackup.py @@ -0,0 +1,83 @@ +# # Import Stackup +# This example shows how to import stackup file. + +# ## Import the required packages + +# + +import json +from pathlib import Path +import tempfile + +from IPython.display import display +from ansys.aedt.core.downloads import download_file +import pandas as pd + +from pyedb import Edb + +AEDT_VERSION = "2024.2" +NG_MODE = False + +# - + +# Download the example PCB data. + +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") +file_edb = download_file(source="edb/ANSYS-HSD_V1.aedb", destination=temp_folder.name) + +# ## Load example layout. + +edbapp = Edb(file_edb, edbversion=AEDT_VERSION) + +# ## Review original stackup definition + +# Get original stackup definition in a dictionary. Alternatively, stackup definition can be exported in a json file by +# edbapp.configuration.export() + +data_cfg = edbapp.configuration.get_data_from_db(stackup=True) + + +df = pd.DataFrame(data=data_cfg["stackup"]["layers"]) +display(df) + +# ## Modify stackup + +# Modify top layer thickness + +data_cfg["stackup"]["layers"][0]["thickness"] = 0.00005 + +# Add a solder mask layer + +data_cfg["stackup"]["layers"].insert( + 0, {"name": "soler_mask", "type": "dielectric", "material": "Megtron4", "fill_material": "", "thickness": 0.00002} +) + +# Review modified stackup + +df = pd.DataFrame(data=data_cfg["stackup"]["layers"]) +display(df.head(3)) + +# Write stackup definition into a json file + +file_cfg = Path(temp_folder.name) / "edb_configuration.json" +with open(file_cfg, "w") as f: + json.dump(data_cfg, f, indent=4, ensure_ascii=False) + + +# ## Load stackup from json configuration file + +edbapp.configuration.load(file_cfg, apply_file=True) + +# Plot stackup + +edbapp.stackup.plot() + +# Check top layer thickness + +edbapp.stackup["1_Top"].thickness + +# ## Save and close Edb +# The temporary folder will be deleted once the execution of this script is finished. Replace **edbapp.save()** with +# **edbapp.save_as("C:/example.aedb")** to keep the example project. + +edbapp.save() +edbapp.close() diff --git a/examples/00_edb/use_configuration/index.rst b/examples/00_edb/use_configuration/index.rst new file mode 100644 index 000000000..598169848 --- /dev/null +++ b/examples/00_edb/use_configuration/index.rst @@ -0,0 +1,162 @@ +Use configuration +~~~~~~~~~~~~~~~~~ + +The following examples illustrate the use of configuration files in PyEDB. +PyAEDT offers a GUI which utilizes config file. Please refer to `Configure Layout extension`_ for details. + +.. _Configure Layout extension : https://aedt.docs.pyansys.com/version/stable/User_guide/pyaedt_extensions_doc/project/configure_edb.html + + +.. grid:: 2 + + .. grid-item-card:: Power Integrity PDN analysis + :padding: 2 2 2 2 + :link: pdn_analysis + :link-type: doc + + .. image:: _static/configurator_2.png + :alt: Configurator + :width: 250px + :height: 200px + :align: center + + .. grid-item-card:: Serdes Signal Integrity Setup + :padding: 2 2 2 2 + :link: serdes + :link-type: doc + + .. image:: _static/configurator_2.png + :alt: Configurator + :width: 250px + :height: 200px + :align: center + + .. grid-item-card:: PCB Power Integrity DCIR analysys + :padding: 2 2 2 2 + :link: pcb_dc_ir + :link-type: doc + + .. image:: _static/configurator_2.png + :alt: Configurator + :width: 250px + :height: 200px + :align: center + + .. grid-item-card:: Package Power Integrity DCIR analysys + :padding: 2 2 2 2 + :link: dcir + :link-type: doc + + .. image:: _static/configurator_2.png + :alt: Configurator + :width: 250px + :height: 200px + :align: center + + .. grid-item-card:: Create Parametric Design + :padding: 2 2 2 2 + :link: post_layout_parametrize + :link-type: doc + + .. image:: _static/parametrized_design.png + :alt: Connector + :width: 250px + :height: 200px + :align: center + + Create automatically parametrized design. + + .. grid-item-card:: Stackup management + :padding: 2 2 2 2 + :link: import_stackup + :link-type: doc + + .. image:: _static/configurator.png + :alt: Configurator + :width: 250px + :height: 200px + :align: center + + .. grid-item-card:: Material management + :padding: 2 2 2 2 + :link: import_material + :link-type: doc + + .. image:: _static/configurator.png + :alt: Configurator + :width: 250px + :height: 200px + :align: center + + .. grid-item-card:: Ports setup + :padding: 2 2 2 2 + :link: import_ports + :link-type: doc + + .. image:: _static/configurator.png + :alt: Configurator + :width: 250px + :height: 200px + :align: center + + .. grid-item-card:: Simulation setup management + :padding: 2 2 2 2 + :link: import_setup_ac + :link-type: doc + + .. image:: _static/configurator.png + :alt: Configurator + :width: 250px + :height: 200px + :align: center + + + .. grid-item-card:: Padstack Definition management + :padding: 2 2 2 2 + :link: import_padstack_definitions + :link-type: doc + + .. image:: _static/configurator.png + :alt: Configurator + :width: 250px + :height: 200px + :align: center + + .. grid-item-card:: Components management + :padding: 2 2 2 2 + :link: import_components + :link-type: doc + + .. image:: _static/configurator.png + :alt: Configurator + :width: 250px + :height: 200px + :align: center + + .. grid-item-card:: Sources management + :padding: 2 2 2 2 + :link: import_sources + :link-type: doc + + .. image:: _static/configurator.png + :alt: Configurator + :width: 250px + :height: 200px + :align: center + +.. toctree:: + :hidden: + + pdn_analysis + serdes + pcb_dc_ir + dcir + import_stackup + import_material + import_ports + import_setup_ac + import_padstack_definitions + import_components + import_sources + post_layout_parametrize + diff --git a/examples/00_edb/use_configuration/pcb_dc_ir.py b/examples/00_edb/use_configuration/pcb_dc_ir.py new file mode 100644 index 000000000..2cffbd509 --- /dev/null +++ b/examples/00_edb/use_configuration/pcb_dc_ir.py @@ -0,0 +1,323 @@ +# # Set up EDB for PCB DC IR Analysis +# This example shows how to set up the electronics database (EDB) for DC IR analysis from a single +# configuration file. + +# ## Import the required packages + +# + +import json +import os +import tempfile + +from ansys.aedt.core import Hfss3dLayout, Icepak +from ansys.aedt.core.downloads import download_file + +from pyedb import Edb + +AEDT_VERSION = "2024.2" +NG_MODE = False + +# - + +# Download the example PCB data. + +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") +file_edb = download_file(source="edb/ANSYS-HSD_V1.aedb", destination=temp_folder.name) + +# ## Load example layout + +edbapp = Edb(file_edb, edbversion=AEDT_VERSION) + +# ## Create an empty dictionary to host all configurations + +cfg = dict() +cfg["sources"] = [] + +# ## Update stackup + +cfg["stackup"] = { + "layers": [ + {"name": "Top", "type": "signal", "material": "copper", "fill_material": "FR4_epoxy", "thickness": "0.035mm"}, + {"name": "DE1", "type": "dielectric", "material": "FR4_epoxy", "fill_material": "", "thickness": "0.1mm"}, + { + "name": "Inner1", + "type": "signal", + "material": "copper", + "fill_material": "FR4_epoxy", + "thickness": "0.017mm", + }, + {"name": "DE2", "type": "dielectric", "material": "FR4_epoxy", "fill_material": "", "thickness": "0.088mm"}, + { + "name": "Inner2", + "type": "signal", + "material": "copper", + "fill_material": "FR4_epoxy", + "thickness": "0.017mm", + }, + {"name": "DE3", "type": "dielectric", "material": "FR4_epoxy", "fill_material": "", "thickness": "0.1mm"}, + { + "name": "Inner3", + "type": "signal", + "material": "copper", + "fill_material": "FR4_epoxy", + "thickness": "0.017mm", + }, + { + "name": "FR4_epoxy-1mm", + "type": "dielectric", + "material": "FR4_epoxy", + "fill_material": "", + "thickness": "1mm", + }, + { + "name": "Inner4", + "type": "signal", + "material": "copper", + "fill_material": "FR4_epoxy", + "thickness": "0.017mm", + }, + {"name": "DE5", "type": "dielectric", "material": "FR4_epoxy", "fill_material": "", "thickness": "0.1mm"}, + { + "name": "Inner5", + "type": "signal", + "material": "copper", + "fill_material": "FR4_epoxy", + "thickness": "0.017mm", + }, + {"name": "DE6", "type": "dielectric", "material": "FR4_epoxy", "fill_material": "", "thickness": "0.088mm"}, + { + "name": "Inner6", + "type": "signal", + "material": "copper", + "fill_material": "FR4_epoxy", + "thickness": "0.017mm", + }, + {"name": "DE7", "type": "dielectric", "material": "FR4_epoxy", "fill_material": "", "thickness": "0.1mm"}, + { + "name": "Bottom", + "type": "signal", + "material": "copper", + "fill_material": "FR4_epoxy", + "thickness": "0.035mm", + }, + ] +} + +# ## Define voltage source + +cfg["sources"].append( + { + "name": "vrm", + "reference_designator": "U2", + "type": "voltage", + "magnitude": 1, + "positive_terminal": {"net": "1V0"}, + "negative_terminal": {"net": "GND"}, + } +) + +# ## Define current source + +cfg["sources"].append( + { + "name": "U1_1V0", + "reference_designator": "U1", + "type": "current", + "magnitude": 10, + "positive_terminal": {"net": "1V0"}, + "negative_terminal": {"net": "GND"}, + } +) + +# ## Define SIwave DC IR analysis setup + +cfg["setups"] = [ + { + "name": "siwave_1", + "type": "siwave_dc", + "dc_slider_position": 1, + "dc_ir_settings": {"export_dc_thermal_data": True}, + } +] + +# ## Define Cutout + +cfg["operations"] = { + "cutout": {"signal_list": ["1V0"], "reference_list": ["GND"], "extent_type": "ConvexHull", "expansion_size": "20mm"} +} + +# ## Define package for thermal analysis (optional) + +cfg["package_definitions"] = [ + { + "name": "package_1", + "component_definition": "ALTR-FBGA1517-Ansys", + "maximum_power": 0.5, + "therm_cond": 2, + "theta_jb": 3, + "theta_jc": 4, + "height": "1mm", + "apply_to_all": False, + "components": ["U1"], + }, +] + +# ## Write configuration into a JSON file + +file_json = os.path.join(temp_folder.name, "edb_configuration.json") +with open(file_json, "w") as f: + json.dump(cfg, f, indent=4, ensure_ascii=False) + +# ## Import configuration into example layout + +edbapp.configuration.load(config_file=file_json) + +# Apply configuration to EDB. + +edbapp.configuration.run() + +# Save and close EDB. + +edbapp.save() +edbapp.close() + +# The configured EDB file is saved in a temp folder. + +print(temp_folder.name) + +# ## Load edb into HFSS 3D Layout. + +h3d = Hfss3dLayout(edbapp.edbpath, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True) + +# ## Prepare for electro-thermal analysis in Icepak (Optional) + +h3d.modeler.set_temperature_dependence(include_temperature_dependence=True, enable_feedback=True, ambient_temp=22) + +# ## Analyze + +h3d.analyze() + +# ## Plot DC voltage + +voltage = h3d.post.create_fieldplot_layers_nets( + layers_nets=[ + ["Inner2", "1V0"], + ], + quantity="Voltage", + setup="siwave_1", +) + +file_path_image = os.path.join(temp_folder.name, "voltage.jpg") +voltage.export_image( + full_path=file_path_image, + width=640, + height=480, + orientation="isometric", + display_wireframe=True, + selections=None, + show_region=True, + show_axis=True, + show_grid=True, + show_ruler=True, +) + +# ## Plot power density + +power_density = h3d.post.create_fieldplot_layers_nets( + layers_nets=[ + ["Inner2", "no-net"], + ], + quantity="Power Density", + setup="siwave_1", +) + +file_path_image = os.path.join(temp_folder.name, "power_density.jpg") +power_density.export_image( + full_path=file_path_image, + width=640, + height=480, + orientation="isometric", + display_wireframe=True, + selections=None, + show_region=True, + show_axis=True, + show_grid=True, + show_ruler=True, +) + +# ## Save HFSS 3D Layout project + +h3d.save_project() + +# ## Create an Icepak design + +ipk = Icepak(version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=False) + +# ## Create PCB + +pcb = ipk.create_ipk_3dcomponent_pcb( + compName="PCB_pyAEDT", + setupLinkInfo=[h3d.project_file, h3d.design_name, "siwave_1", True, True], + solutionFreq=None, + resolution=0, + extent_type="Bounding Box", + powerin="0", +) + +# ## Include pckage definition from Edb + +pcb.included_parts = "Device" + +# ## Adjust air region + +region = ipk.modeler["Region"] +faces = [f.id for f in region.faces] +ipk.assign_pressure_free_opening(assignment=faces, boundary_name="Outlet") + +# ## Setup mesh + +glob_msh = ipk.mesh.global_mesh_region +glob_msh.global_region.positive_z_padding_type = "Absolute Offset" +glob_msh.global_region.positive_z_padding = "50 mm" +glob_msh.global_region.negative_z_padding_type = "Absolute Offset" +glob_msh.global_region.negative_z_padding = "80 mm" + +glob_msh = ipk.mesh.global_mesh_region +glob_msh.manual_settings = True +glob_msh.settings["EnableMLM"] = True +glob_msh.settings["EnforeMLMType"] = "2D" +glob_msh.settings["2DMLMType"] = "Auto" +glob_msh.settings["MaxElementSizeY"] = "2mm" +glob_msh.settings["MaxElementSizeX"] = "2mm" +glob_msh.settings["MaxElementSizeZ"] = "3mm" +glob_msh.settings["MaxLevels"] = "2" + +glob_msh.update() + +# ## Place monitor + +cpu = ipk.modeler["PCB_pyAEDT_U1_device"] +m1 = ipk.monitor.assign_face_monitor( + face_id=cpu.top_face_z.id, + monitor_quantity="Temperature", + monitor_name="TemperatureMonitor1", +) + +# ## Create Icepak setup + +setup1 = ipk.create_setup(MaxIterations=10) + +# Add 2-way coupling to the setup + +ipk.assign_2way_coupling(number_of_iterations=1) + +# ## Save + +ipk.save_project() + +# ## Shut Down Electronics Desktop + +ipk.release_desktop() + +# All project files are saved in the folder ``temp_file.dir``. If you've run this example as a Jupyter notebook you +# can retrieve those project files. diff --git a/examples/00_edb/use_configuration/pdn_analysis.py b/examples/00_edb/use_configuration/pdn_analysis.py new file mode 100644 index 000000000..ef6a44014 --- /dev/null +++ b/examples/00_edb/use_configuration/pdn_analysis.py @@ -0,0 +1,178 @@ +# # Set up EDB for Power Distribution Network Analysis +# This example shows how to set up the electronics database (EDB) for power integrity analysis from a single +# configuration file. + +# ## Import the required packages + +import json + +# + +import os +import tempfile + +from ansys.aedt.core import Hfss3dLayout +from ansys.aedt.core.downloads import download_file + +from pyedb import Edb + +AEDT_VERSION = "2024.2" +NG_MODE = False + +# - + +# Download the example PCB data. + +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") +download_file(source="touchstone", name="GRM32_DC0V_25degC_series.s2p", destination=temp_folder.name) +file_edb = download_file(source="edb/ANSYS-HSD_V1.aedb", destination=temp_folder.name) + +# ## Load example layout + +edbapp = Edb(file_edb, edbversion=AEDT_VERSION) + +# ## Create an empty dictionary to host all configurations + +cfg = dict() + +# ## Assign S-parameter model to capactitors. + +# Set S-parameter library path. + +cfg["general"] = {"s_parameter_library": os.path.join(temp_folder.name, "touchstone")} + +# Assign the S-parameter model. +# +# Keywords +# +# - **name**. Name of the S-parameter model in AEDT. +# - **component**_definition. Known as component part number of part name. +# - **file_path**. Touchstone file or full path to the touchstone file. +# - **apply_to_all**. When set to True, assign the S-parameter model to all components share the same +# component_definition. When set to False, Only components in "components" are assigned. +# - **components**. when apply_to_all=False, components in the list are assigned an S-parameter model. +# When apply_to_all=False, components in the list are NOT assigned. +# - **reference_net**. Reference net of the S-parameter model. + +cfg["s_parameters"] = [ + { + "name": "GRM32_DC0V_25degC_series", + "component_definition": "CAPC0603X33X15LL03T05", + "file_path": "GRM32_DC0V_25degC_series.s2p", + "apply_to_all": False, + "components": ["C110", "C206"], + "reference_net": "GND", + } +] + +# ## Define ports +# Create a circuit port between power and ground nets. +# +# Keywords +# +# - **name**. Name of the port. +# - **reference_desinator**. +# - **type**. Type of the port. Supported types are 'ciruict', 'coax'. +# - **positive_terminal**. Positive terminal of the port. Supported types are 'net', 'pin', 'pin_group', 'coordinates'. +# - **negative_terminal**. Positive terminal of the port. Supported types are 'net', 'pin', 'pin_group', 'coordinates'. + +cfg["ports"] = [ + { + "name": "port1", + "reference_designator": "U1", + "type": "circuit", + "positive_terminal": {"net": "1V0"}, + "negative_terminal": {"net": "GND"}, + } +] + +# ## Define SIwave SYZ analysis setup +# +# Keywords +# +# - **name**. Name of the setup. +# - **type**. Type of the analysis setup. Supported types are 'siwave_ac', 'siwave_dc', 'hfss'. +# - **pi_slider_position**. PI slider position. Supported values are from '0', '1', '2'. 0:speed, 1:balanced, +# 2:accuracy. +# - **freq_sweep**. List of frequency sweeps. +# - **name**. Name of the sweep. +# - **type**. Type of the sweep. Supported types are 'interpolation', 'discrete', 'broadband'. +# - **frequencies**. Frequency distribution. +# - **distribution**. Supported distributions are 'linear_count', 'linear_scale', 'log_scale'. +# - **start**. Start frequency. Example, 1e6, "1MHz". +# - **stop**. Stop frequency. Example, 1e9, "1GHz". +# - **increment**. + +cfg["setups"] = [ + { + "name": "siwave_syz", + "type": "siwave_ac", + "pi_slider_position": 1, + "freq_sweep": [ + { + "name": "Sweep1", + "type": "interpolation", + "frequencies": [{"distribution": "log_scale", "start": 1e6, "stop": 1e9, "increment": 20}], + } + ], + } +] + +# ## Define Cutout +# +# Keywords +# +# - **signal_list**. List of nets to be kept after cutout. +# - **reference_list**. List of nets as reference planes. +# - **extent_type**. Supported extend types are 'Conforming', 'ConvexHull', 'Bounding'. +# For optional input arguments, refer to method pyedb.Edb.cutout() + +cfg["operations"] = { + "cutout": { + "signal_list": ["1V0"], + "reference_list": ["GND"], + "extent_type": "ConvexHull", + } +} + +# ## Write configuration into as json file + +file_json = os.path.join(temp_folder.name, "edb_configuration.json") +with open(file_json, "w") as f: + json.dump(cfg, f, indent=4, ensure_ascii=False) + +# ## Import configuration into example layout + +edbapp.configuration.load(config_file=file_json) + +# Apply configuration to EDB. + +edbapp.configuration.run() + +# Save and close EDB. + +edbapp.save() +edbapp.close() + +# The configured EDB file is saved in a temp folder. + +print(temp_folder.name) + +# ## Load edb into HFSS 3D Layout. + +h3d = Hfss3dLayout(edbapp.edbpath, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True) + +# ## Analyze + +h3d.analyze() + +# ## Plot impedance + +solutions = h3d.post.get_solution_data(expressions="Z(port1,port1)") +solutions.plot() + +# ## Shut Down Electronics Desktop + +h3d.close_desktop() + +# All project files are saved in the folder ``temp_file.dir``. If you've run this example as a Jupyter notebook you +# can retrieve those project files. diff --git a/examples/00_edb/use_configuration/post_layout_parametrize.py b/examples/00_edb/use_configuration/post_layout_parametrize.py new file mode 100644 index 000000000..3c1f081e6 --- /dev/null +++ b/examples/00_edb/use_configuration/post_layout_parametrize.py @@ -0,0 +1,113 @@ +# # EDB: parameterized design +# +# This example shows how to +# 1. Set up an HFSS project using SimulationConfiguration class. +# 2. Create automatically parametrized design. +# +# This image shows the layout created in this example: +# +# +# + +# ## Import dependencies. + +import tempfile + +import ansys.aedt.core + +import pyedb +from pyedb.misc.downloads import download_file + +# ## Create an instance of a pyedb.Edb object. + +# + +temp_dir = tempfile.TemporaryDirectory(suffix=".ansys") +target_aedb = download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name) +print("Project is located in ", target_aedb) + +# Select EDB version (change it manually if needed, e.g. "2024.2") +edb_version = "2024.2" +print(f"EDB version: {edb_version}") + +edb = pyedb.Edb(edbpath=target_aedb, edbversion=edb_version) +print("AEDB file is located in {}".format(target_aedb)) +# - + +# ## Prepare the layout for the simulation +# +# The ``new_simulation_configuration()`` method creates an instance of +# the ``SimulationConfiguration`` class. This class helps define all preprocessing steps +# required to set up the PCB for simulation. After the simulation configuration has been defined, +# they are applied to the EDB using the ``Edb.build_simulation()`` method. + +simulation_configuration = edb.new_simulation_configuration() +simulation_configuration.signal_nets = [ + "PCIe_Gen4_RX0_P", + "PCIe_Gen4_RX0_N", + "PCIe_Gen4_RX1_P", + "PCIe_Gen4_RX1_N", +] +simulation_configuration.power_nets = ["GND"] +simulation_configuration.components = ["X1", "U1"] +simulation_configuration.do_cutout_subdesign = True +simulation_configuration.start_freq = "OGHz" +simulation_configuration.stop_freq = "20GHz" +simulation_configuration.step_freq = "10MHz" + +# Now apply the simulation setup to the EDB. + +edb.build_simulation_project(simulation_configuration) + +# ## Parameterize +# +# The layout can automatically be set up to enable parametric studies. For example, the +# impact of antipad diameter or trace width on signal integrity performance may be invested +# parametrically. + +edb.auto_parametrize_design(layers=True, materials=True, via_holes=True, pads=True, antipads=True, traces=True) +edb.save_edb() +edb.close_edb() + +# ## Open project in AEDT +# +# All manipulations thus far have been executed using the EDB API, which provides fast, +# streamlined processing of layout data in non-graphical mode. The layout and simulation +# setup can be visualized by opening it using the 3D Layout editor in AEDT. +# +# Note that there may be some delay while AEDT is being launched. + +hfss = ansys.aedt.core.Hfss3dLayout( + projectname=target_aedb, + specified_version=edb_version, + non_graphical=False, + new_desktop_session=True, +) + +# The following cell can be used to ensure that the design is valid for simulation. + +validation_info = hfss.validate_full_design() +is_ready_to_simulate = True + +# + +for s in validation_info[0]: + if "error" in s: + print(s) + is_ready_to_simulate = False + +if is_ready_to_simulate: + print("The model is ready for simulation.") +else: + print("There are errors in the model that must be fixed.") +# - + +# ## Release the application from the Python kernel +# +# It is important to release the application from the Python kernel after +# execution of the script. The default behavior of the ``release_desktop()`` method closes all open +# projects and closes the application. +# +# If you want to continue working on the project in graphical mode +# after script execution, call the following method with both arguments set to ``False``. + +hfss.release_desktop(close_projects=True, close_desktop=True) +temp_dir.cleanup() # Remove the temporary folder and files. All data will be removd! diff --git a/examples/00_edb/use_configuration/serdes.py b/examples/00_edb/use_configuration/serdes.py new file mode 100644 index 000000000..537eba2e5 --- /dev/null +++ b/examples/00_edb/use_configuration/serdes.py @@ -0,0 +1,278 @@ +# # Set up EDB for Serdes channel S-parameter extraction + +# ## Import the required packages + +import json + +# + +import os +import tempfile + +from ansys.aedt.core import Hfss3dLayout +from ansys.aedt.core.downloads import download_file + +from pyedb import Edb + +AEDT_VERSION = "2024.2" +NG_MODE = False + +# - + +# Download the example PCB data. + +temp_folder = tempfile.TemporaryDirectory(suffix=".ansys") +file_edb = download_file(source="edb/ANSYS-HSD_V1.aedb", destination=temp_folder.name) +download_file(source="touchstone", name="GRM32_DC0V_25degC_series.s2p", destination=os.path.split(file_edb)[0]) + +# ## Load example layout + +edbapp = Edb(file_edb, edbversion=AEDT_VERSION) + +# ## Create config file + +cfg_general = {"anti_pads_always_on": True, "suppress_pads": True} + +# Define dielectric materials, stackup and surface roughness model. + +cfg_stackup = { + "materials": [ + {"name": "copper", "permittivity": 1, "conductivity": 58000000.0}, + {"name": "megtron4", "permittivity": 3.77, "dielectric_loss_tangent": 0.005}, + {"name": "solder_resist", "permittivity": 3.0, "dielectric_loss_tangent": 0.035}, + ], + "layers": [ + { + "name": "Top", + "type": "signal", + "material": "copper", + "fill_material": "solder_resist", + "thickness": "0.035mm", + "roughness": { + "top": {"model": "huray", "nodule_radius": "0.5um", "surface_ratio": "5"}, + "bottom": {"model": "huray", "nodule_radius": "0.5um", "surface_ratio": "5"}, + "side": {"model": "huray", "nodule_radius": "0.5um", "surface_ratio": "5"}, + "enabled": True, + }, + }, + {"name": "DE1", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.1mm"}, + {"name": "Inner1", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"}, + {"name": "DE2", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.088mm"}, + {"name": "Inner2", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"}, + {"name": "DE3", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.1mm"}, + {"name": "Inner3", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"}, + {"name": "Megtron4-1mm", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": 0.001}, + {"name": "Inner4", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"}, + {"name": "DE5", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.1mm"}, + {"name": "Inner5", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"}, + {"name": "DE6", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.088mm"}, + {"name": "Inner6", "type": "signal", "material": "copper", "fill_material": "megtron4", "thickness": "0.017mm"}, + {"name": "DE7", "type": "dielectric", "material": "megtron4", "fill_material": "", "thickness": "0.1mm"}, + { + "name": "Bottom", + "type": "signal", + "material": "copper", + "fill_material": "solder_resist", + "thickness": "0.035mm", + }, + ], +} + +# Define Component with solderballs. + +cfg_components = [ + { + "reference_designator": "U1", + "part_type": "io", + "solder_ball_properties": {"shape": "cylinder", "diameter": "300um", "height": "300um"}, + "port_properties": { + "reference_offset": "0", + "reference_size_auto": True, + "reference_size_x": 0, + "reference_size_y": 0, + }, + } +] + +# Edit via padstack definition. Add backdrilling. + +cfg_padstacks = { + "definitions": [ + { + "name": "v40h15-2", + "material": "copper", + "hole_range": "upper_pad_to_lower_pad", + "hole_parameters": {"shape": "circle", "diameter": "0.2mm"}, + }, + { + "name": "v35h15-1", + "material": "copper", + "hole_range": "upper_pad_to_lower_pad", + "hole_parameters": {"shape": "circle", "diameter": "0.25mm"}, + }, + ], + "instances": [ + { + "name": "Via313", + "backdrill_parameters": { + "from_bottom": {"drill_to_layer": "Inner3", "diameter": "1mm", "stub_length": "0.2mm"} + }, + }, + { + "name": "Via314", + "backdrill_parameters": { + "from_bottom": {"drill_to_layer": "Inner3", "diameter": "1mm", "stub_length": "0.2mm"} + }, + }, + ], +} + +# Define ports. + +cfg_ports = [ + { + "name": "port_1", + "reference_designator": "U1", + "type": "coax", + "positive_terminal": {"net": "PCIe_Gen4_TX2_CAP_P"}, + }, + { + "name": "port_2", + "reference_designator": "U1", + "type": "coax", + "positive_terminal": {"net": "PCIe_Gen4_TX2_CAP_N"}, + }, + { + "name": "port_3", + "reference_designator": "X1", + "type": "circuit", + "positive_terminal": {"pin": "B8"}, + "negative_terminal": {"pin": "B7"}, + }, + { + "name": "port_4", + "reference_designator": "X1", + "type": "circuit", + "positive_terminal": {"pin": "B9"}, + "negative_terminal": {"pin": "B10"}, + }, +] + +# Define S-parameter assignment + +cfg_s_parameters = [ + { + "name": "cap_10nf", + "file_path": "$PROJECTDIR\\touchstone\\GRM32_DC0V_25degC_series.s2p", + "component_definition": "CAPC1005X55X25LL05T10", + "components": ["C375", "C376"], + "reference_net": "GND", + } +] + +# Define SIwave setup. + +cfg_setups = [ + { + "name": "siwave_setup", + "type": "siwave_ac", + "si_slider_position": 1, + "freq_sweep": [ + { + "name": "Sweep1", + "type": "interpolation", + "frequencies": [ + {"distribution": "linear_scale", "start": "50MHz", "stop": "20GHz", "increment": "50MHz"} + ], + } + ], + } +] + +# Define cutout. + +cfg_operations = { + "cutout": { + "signal_list": ["PCIe_Gen4_TX2_CAP_P", "PCIe_Gen4_TX2_CAP_N", "PCIe_Gen4_TX2_P", "PCIe_Gen4_TX2_N"], + "reference_list": ["GND"], + "custom_extent": [ + [0.014, 0.055], + [0.03674271504652968, 0.05493094625752912], + [0.07, 0.039], + [0.07, 0.034], + [0.05609890516829415, 0.03395233061637539], + [0.014, 0.044], + ], + } +} + +# Create final configuration. + +cfg = { + "general": cfg_general, + "stackup": cfg_stackup, + "components": cfg_components, + "padstacks": cfg_padstacks, + "ports": cfg_ports, + "s_parameters": cfg_s_parameters, + "setups": cfg_setups, + "operations": cfg_operations, +} + +# Create the config file. + +file_json = os.path.join(temp_folder.name, "edb_configuration.json") +with open(file_json, "w") as f: + json.dump(cfg, f, indent=4, ensure_ascii=False) + +# ## Apply Config file + +# Apply configuration to the example layout + +edbapp.configuration.load(config_file=file_json) +edbapp.configuration.run() + +edbapp.nets.plot(nets=[]) + +# Save and close EDB. + +edbapp.save() +edbapp.close() + +# The configured EDB file is saved in a temp folder. + +print(temp_folder.name) + +# ## Load edb into HFSS 3D Layout. + +h3d = Hfss3dLayout(edbapp.edbpath, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True) + +# Create differential pair definition. + +h3d.set_differential_pair( + differential_mode="DIFF_BGA", + assignment="port_1", + reference="port_2", +) + +h3d.set_differential_pair( + differential_mode="DIFF_CONN", + assignment="port_3", + reference="port_4", +) + +# Solve. +# Un-comment to analyze SIwave. + +#h3d.analyze(setup="siwave_setup") + +# Plot insertion loss. + +# solutions = h3d.post.get_solution_data(expressions="mag(S(DIFF_CONN,DIFF_BGA))", context="Differential Pairs") +# solutions.plot(formula="db20") + +# Shut Down Electronics Desktop + +h3d.close_desktop() + +# All project files are saved in the folder ``temp_file.dir``. If you've run this example as a Jupyter notebook you +# can retrieve those project files. diff --git a/examples/electrothermal/coaxial_hfss_icepak.py b/examples/electrothermal/coaxial_hfss_icepak.py index f39c1fb03..27e9a0a77 100644 --- a/examples/electrothermal/coaxial_hfss_icepak.py +++ b/examples/electrothermal/coaxial_hfss_icepak.py @@ -253,7 +253,7 @@ hfss.save_project() ipk = ansys.aedt.core.Icepak(version=AEDT_VERSION) -ipk.solution_type = ipk.SOLUTIONS.Icepak.SteadyTemperatureAndFlow +ipk.solution_type = ipk.SOLUTIONS.Icepak.SteadyState ipk.modeler.fit_all() # ## Solve models diff --git a/examples/high_frequency/antenna/5G_antenna_parametrics.py b/examples/high_frequency/antenna/5G_antenna_parametrics.py new file mode 100644 index 000000000..15466d452 --- /dev/null +++ b/examples/high_frequency/antenna/5G_antenna_parametrics.py @@ -0,0 +1,384 @@ +# # EDB: Layout Components +# +# This example shows how you can use EDB to create a parametric component using +# 3D Layout and use it in HFSS 3D. + +# ## Perform required imports +# +# Perform required imports, which includes importing the ``Hfss3dlayout`` object +# and initializing it on version 2023 R2. + +# + +import os +import tempfile + +import ansys.aedt.core + +import pyedb + +# - + +# ## Set non-graphical mode + +non_graphical = False + +# ## Create data classes +# +# Data classes are useful to do calculations and store variables. +# There are three data classes: ``Patch``, ``Line``, and ``Array``. + + +# + +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, "-{}/2".format(self.height)], + ["{} + {}".format(self.position, self.width), "-{}/2".format(self.height)], + ["{} + {}".format(self.position, self.width), "{}/2".format(self.height)], + [self.position, "{}/2".format(self.height)], + ] + + +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, "-{}/2".format(self.width)], + ["{} + {}".format(self.position, self.length), "-{}/2".format(self.width)], + ["{} + {}".format(self.position, self.length), "{}/2".format(self.width)], + [self.position, "{}/2".format(self.width)], + ] + + +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, "-{}/2-1e-3".format(self.width)], + ["{}+1e-3".format(self.length), "-{}/2-1e-3".format(self.width)], + ["{}+1e-3".format(self.length), "{}/2+1e-3".format(self.width)], + [-1e-3, "{}/2+1e-3".format(self.width)], + ] + + +# - + +# ## Launch EDB +# +# PyEDB.Edb allows to open existing Edb project or create a new empty project. + +# + +temp_dir = tempfile.TemporaryDirectory(suffix=".ansys") +aedb_path = os.path.join(temp_dir.name, "linear_array.aedb") + +# Select EDB version (change it manually if needed, e.g. "2024.2") +edb_version = "2024.2" +print(f"EDB version: {edb_version}") + +# Create an instance of the Edb class. +edb = pyedb.Edb(edbpath=aedb_path, edbversion=edb_version) +# - + +# Add stackup layers +layers = { + "materials": {"copper_high_cond": {"conductivity": 60000000}}, + "layers": { + "TOP": {"type": "signal", "thicness": "35um", "material": "copper_high_cond"}, + "Substrat": {"type": "dielectric", "thicness": "0.5mm", "material": "Duroid (tm)"}, + "GND": {"type": "signal", "thicness": "35um", "material": "copper"}, + "Gap": {"type": "dielectric", "thicness": "0.05mm", "material": "Air"}, + "Virt_GND": {"type": "signal", "thicness": "35um", "material": "copper"}, + }, +} + +edb.stackup.load(layers) + +# Create the first patch and feed line using the ``Patch``, ``Line``classes defined above. +# +# Define parameters: + +# + +edb["w1"] = 1.4e-3 +edb["h1"] = 1.2e-3 +edb["initial_position"] = 0.0 +edb["l1"] = 2.4e-3 +edb["trace_w"] = 0.3e-3 + +first_patch = Patch(width="w1", height="h1", position="initial_position") +edb.modeler.create_polygon(first_patch.points, "TOP", net_name="Array_antenna") +# - + +# First line + +first_line = Line(length="l1", width="trace_w", position=first_patch.width) +edb.modeler.create_polygon(first_line.points, "TOP", net_name="Array_antenna") + +# Now use the ``LinearArray`` class to create the array. + +# + +edb["w2"] = 2.29e-3 +edb["h2"] = 3.3e-3 +edb["l2"] = 1.9e-3 +edb["trace_w2"] = 0.2e-3 + +patch = Patch(width="w2", height="h2") +line = Line(length="l2", width="trace_w2") +linear_array = LinearArray(nb_patch=8, array_width=patch.height) + +current_patch = 1 +current_position = "{} + {}".format(first_line.position, first_line.length) + +while current_patch <= linear_array.nbpatch: + patch.position = current_position + edb.modeler.create_polygon(patch.points, "TOP", net_name="Array_antenna") + current_position = "{} + {}".format(current_position, patch.width) + if current_patch < linear_array.nbpatch: + line.position = current_position + edb.modeler.create_polygon(line.points, "TOP", net_name="Array_antenna") + current_position = "{} + {}".format(current_position, line.length) + current_patch += 1 + +linear_array.length = current_position +# - + +# Add the ground conductor. + +edb.modeler.create_polygon(linear_array.points, "GND", net_name="GND") + +# Add the connector pin to use to assign the port. + +edb.padstacks.create(padstackname="Connector_pin", holediam="100um", paddiam="0", antipaddiam="200um") +con_pin = edb.padstacks.place( + ["{}/4.0".format(first_patch.width), 0], + "Connector_pin", + net_name="Array_antenna", + fromlayer="TOP", + tolayer="GND", + via_name="coax", +) + +# Add a connector ground. + +edb.modeler.create_polygon(first_patch.points, "Virt_GND", net_name="GND") +edb.padstacks.create("gnd_via", "100um", "0", "0") +edb["via_spacing"] = 0.2e-3 +con_ref1 = edb.padstacks.place( + [ + "{} + {}".format(first_patch.points[0][0], "via_spacing"), + "{} + {}".format(first_patch.points[0][1], "via_spacing"), + ], + "gnd_via", + fromlayer="GND", + tolayer="Virt_GND", + net_name="GND", +) +con_ref2 = edb.padstacks.place( + [ + "{} + {}".format(first_patch.points[1][0], "-via_spacing"), + "{} + {}".format(first_patch.points[1][1], "via_spacing"), + ], + "gnd_via", + fromlayer="GND", + tolayer="Virt_GND", + net_name="GND", +) +con_ref3 = edb.padstacks.place( + [ + "{} + {}".format(first_patch.points[2][0], "-via_spacing"), + "{} + {}".format(first_patch.points[2][1], "-via_spacing"), + ], + "gnd_via", + fromlayer="GND", + tolayer="Virt_GND", + net_name="GND", +) +con_ref4 = edb.padstacks.place( + [ + "{} + {}".format(first_patch.points[3][0], "via_spacing"), + "{} + {}".format(first_patch.points[3][1], "-via_spacing"), + ], + "gnd_via", + fromlayer="GND", + tolayer="Virt_GND", + net_name="GND", +) + +# Define the port. + +edb.padstacks.set_solderball(con_pin, "Virt_GND", isTopPlaced=False, ballDiam=0.1e-3) +port_name = edb.padstacks.create_coax_port(con_pin) + +# Display the model using the ``Edb.nets.plot()`` method. + +edb.nets.plot() + +# The EDB is complete. Now close the EDB and import it into HFSS as a "Layout Component". + +edb.save_edb() +edb.close_edb() +print("EDB saved correctly to {}. You can import in AEDT.".format(aedb_path)) + +# ## 3D component in HFSS +# +# First create an instance of the ``pyaedt.Hfss`` class. If you set +# > ``non_graphical = False +# +# then AEDT user interface will be visible after the following cell is executed. +# It is now possible to monitor the progress in the UI as each of the following cells is executed. +# All commands can be run without the UI by changing the value of ``non_graphical``. + +h3d = ansys.aedt.core.Hfss( + projectname="Demo_3DComp", + designname="Linear_Array", + specified_version="2024.2", + new_desktop_session=True, + non_graphical=non_graphical, + close_on_exit=True, + solution_type="Terminal", +) + +# Set units to ``mm``. + +h3d.modeler.model_units = "mm" + +# ## Import the EDB as a 3D component +# +# One or more layout components can be imported into HFSS. +# The combination of layout data and 3D CAD data helps streamline model creation and setup. + +component = h3d.modeler.insert_layout_component(aedb_path, parameter_mapping=True) + +# ## Expose the component parameters +# +# If a layout component is parametric, you can expose and change parameters in HFSS + +# + +component.parameters + +w1_name = "{}_{}".format("w1", h3d.modeler.user_defined_component_names[0]) +h3d[w1_name] = 0.0015 +# - + +# ### Radiation Boundary Assignment +# +# The 3D domain includes the air volume surrounding the antenna. +# This antenna will be simulted from 20 GHz - 50 GHz. +# +# A "radiation boundary" will be assigned to the outer boundaries of the domain. +# This boundary should be roughly one quarter wavelength away from the radiating structure: +# +# $$ \lambda/4 = \frac{c_0}{4 f} \approx 2.8mm $$ + +# + +h3d.modeler.fit_all() + +h3d.modeler.create_air_region(2.8, 2.8, 2.8, 2.8, 2.8, 2.8, is_percentage=False) +h3d.assign_radiation_boundary_to_objects("Region") +# - + +# ### Set up analysis +# +# The finite element mesh is adapted iteratively. +# The maximum number of adaptive passes is set using the ``MaximumPasses`` property. +# This model converges such that the $S_{11}$ is independent of the mesh. +# The default accuracy setting is: +# $$ \max(|\Delta S|) < 0.02 $$ + +setup = h3d.create_setup() +setup.props["Frequency"] = "20GHz" +setup.props["MaximumPasses"] = 10 + +# Specify properties of the frequency sweep: + +sweep1 = setup.add_sweep(sweepname="20GHz_to_50GHz") +sweep1.props["RangeStart"] = "20GHz" +sweep1.props["RangeEnd"] = "50GHz" +sweep1.update() + +# Solve the project + +h3d.analyze() + +# ## Plot results outside AEDT +# +# Plot results using Matplotlib. + +trace = h3d.get_traces_for_plot() +solution = h3d.post.get_solution_data(trace[0]) +solution.plot() + +# ## Plot far fields in AEDT +# +# Plot radiation patterns in AEDT. + +# + +variations = {} +variations["Freq"] = ["20GHz"] +variations["Theta"] = ["All"] +variations["Phi"] = ["All"] +h3d.insert_infinite_sphere(name="3D") + +new_report = h3d.post.reports_by_category.far_field("db(RealizedGainTotal)", h3d.nominal_adaptive, "3D") +new_report.variations = variations +new_report.primary_sweep = "Theta" +new_report.create("Realized2D") +# - + +# ## Plot far fields in AEDT +# +# Plot radiation patterns in AEDT + +new_report.report_type = "3D Polar Plot" +new_report.secondary_sweep = "Phi" +new_report.create("Realized3D") + +# ## Plot far fields outside AEDT +# +# Plot radiation patterns outside AEDT + +solutions_custom = new_report.get_solution_data() +solutions_custom.plot_3d() + +# ## Plot E Field on nets and layers +# +# Plot E Field on nets and layers in AEDT + +h3d.post.create_fieldplot_layers_nets( + [["TOP", "Array_antenna"]], + "Mag_E", + intrinsics={"Freq": "20GHz", "Phase": "0deg"}, + plot_name="E_Layers", +) + +# ## Close AEDT +# +# After the simulation completes, the application can be released from the +# :func:`ansys.aedt.core.Desktop.release_desktop` method. +# All methods provide for saving the project before closing AEDT. + +h3d.save_project(os.path.join(temp_dir.name, "test_layout.aedt")) +h3d.release_desktop() + +# ### Clean up the temporary directory +# +# The following command removes the project and the temporary directory. +# If you'd like to save this project, save it to a folder of your choice prior +# to running the following cell. + +temp_dir.cleanup() diff --git a/examples/high_frequency/antenna/_static/patch_edb.png b/examples/high_frequency/antenna/_static/patch_edb.png new file mode 100644 index 000000000..a6e31fe73 Binary files /dev/null and b/examples/high_frequency/antenna/_static/patch_edb.png differ diff --git a/examples/high_frequency/antenna/dipole.py b/examples/high_frequency/antenna/dipole.py index 6078e4aa9..bf9b7f717 100644 --- a/examples/high_frequency/antenna/dipole.py +++ b/examples/high_frequency/antenna/dipole.py @@ -104,6 +104,7 @@ ) new_report.report_type = "3D Polar Plot" new_report.secondary_sweep = "Phi" +new_report.variations["Freq"] = ["1000MHz"] new_report.create("Realized3D") # This code generates a 2D plot. @@ -141,6 +142,7 @@ ) new_report.primary_sweep = "Theta" new_report.far_field_sphere = "3D" +new_report.variations["Freq"] = ["1000MHz"] solutions = new_report.get_solution_data() # Generate a 3D plot using Matplotlib. diff --git a/examples/high_frequency/antenna/index.rst b/examples/high_frequency/antenna/index.rst index 779ff1df1..2f8390c00 100644 --- a/examples/high_frequency/antenna/index.rst +++ b/examples/high_frequency/antenna/index.rst @@ -56,6 +56,19 @@ These examples use PyAEDT to show some antenna applications. This example shows how to use PyAEDT to model and simulate a unit cell for a frequency-selective surface in HFSS. + .. grid-item-card:: Planar Antenna with EDB + :padding: 2 2 2 2 + :link: 5G_antenna_parametrics + :link-type: doc + + .. image:: _static/patch_edb.png + :alt: FSS + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to model and simulate a unit cell for a frequency-selective surface in HFSS. + .. grid-item-card:: Circuit schematic creation and analysis :padding: 2 2 2 2 :link: ../../aedt_general/modeler/circuit_schematic @@ -105,3 +118,4 @@ These examples use PyAEDT to show some antenna applications. ../../aedt_general/modeler/circuit_schematic large_scenarios/index interferences/index + 5G_antenna_parametrics diff --git a/examples/high_frequency/layout/index.rst b/examples/high_frequency/layout/index.rst index 559934584..0552aa197 100644 --- a/examples/high_frequency/layout/index.rst +++ b/examples/high_frequency/layout/index.rst @@ -6,32 +6,6 @@ These examples use PyAEDT to show some layout applications. .. grid:: 2 - .. grid-item-card:: Layout preprocessing - :padding: 2 2 2 2 - :link: https://edb.docs.pyansys.com/version/stable/examples/legacy_standalone/index.html - :link-type: url - - .. image:: _static/pyedb.png - :alt: PyEDB - :width: 250px - :height: 200px - :align: center - - Links to examples in the AEDT documentation that show how to use the legacy PyEDB API as a standalone package. - - .. grid-item-card:: PyEDB configuration files - :padding: 2 2 2 2 - :link: https://edb.docs.pyansys.com/version/stable/examples/use_configuration/index.html - :link-type: url - - .. image:: _static/pyedb2.png - :alt: PyEDB2 - :width: 250px - :height: 200px - :align: center - - Links to examples in the PyAEDT documentation that show how to use PyEDB configuration files. - .. grid-item-card:: Power integrity :padding: 2 2 2 2 :link: power_integrity/index @@ -58,18 +32,18 @@ These examples use PyAEDT to show some layout applications. Provides signal integrity examples - .. grid-item-card:: HFSS 3D Layout GUI modificatation + .. grid-item-card:: PyEDB workflows examples :padding: 2 2 2 2 - :link: gui_manipulation + :link: workflows/index :link-type: doc - .. image:: _static/user_interface.png - :alt: UI 3D Layout + .. image:: _static/pyedb2.png + :alt: PyEDB2 :width: 250px :height: 200px :align: center - Provides HFSS 3D Layout GUI modification examples. + PyEDB related examples to worklows and file management. .. toctree:: @@ -77,4 +51,4 @@ These examples use PyAEDT to show some layout applications. power_integrity/index signal_integrity/index - gui_manipulation \ No newline at end of file + workflows/index diff --git a/examples/high_frequency/layout/power_integrity/index.rst b/examples/high_frequency/layout/power_integrity/index.rst index c24e5b8d2..8c044a47d 100644 --- a/examples/high_frequency/layout/power_integrity/index.rst +++ b/examples/high_frequency/layout/power_integrity/index.rst @@ -18,7 +18,35 @@ These examples use PyAEDT to show power integrity examples. This example shows how to use the Ansys Electronics Database (EDB) for power integrity analysis. - .. grid-item-card:: DC IR analysis + + .. grid-item-card:: Via Array + :padding: 2 2 2 2 + :link: ../../../00_edb/legacy_standalone/differential_vias + :link-type: doc + + .. image:: ../../../00_edb/legacy_standalone/_static/diff_via.png + :alt: Differential Vias + :width: 250px + :height: 200px + :align: center + + This example shows how you can use EDB to create a layout. + + .. grid-item-card:: SIwave DC-IR Analysis + :padding: 2 2 2 2 + :link: ../../../00_edb/legacy_standalone/01_edb_example + :link-type: doc + + .. image:: ../../../00_edb/legacy_standalone/_static/siwave_dcir.png + :alt: SIwave DCIR + :width: 250px + :height: 200px + :align: center + + This example demonstrates the use of EDB to interact with a PCB layout and run DC-IR analysis in SIwave. + + + .. grid-item-card:: SIwave DC IR analysis (HFSS 3D Layout) :padding: 2 2 2 2 :link: dcir :link-type: doc @@ -32,7 +60,7 @@ These examples use PyAEDT to show power integrity examples. This example shows how to configure EDB for DC IR analysis and load EDB into the HFSS 3D Layout UI for analysis and postprocessing. - .. grid-item-card:: PCB DCIR analysis + .. grid-item-card:: Q3D DCIR analysis :padding: 2 2 2 2 :link: dcir_q3d :link-type: doc @@ -110,3 +138,5 @@ These examples use PyAEDT to show power integrity examples. ../../../aedt_general/modeler/circuit_schematic ../../../aedt_general/modeler/netlist_to_schematic ../../../aedt_general/report/touchstone_file + ../../../00_edb/legacy_standalone/differential_vias + ../../../00_edb/legacy_standalone/01_edb_example \ No newline at end of file diff --git a/examples/high_frequency/layout/signal_integrity/_static/connector_example.png b/examples/high_frequency/layout/signal_integrity/_static/connector_example.png new file mode 100644 index 000000000..a1083574c Binary files /dev/null and b/examples/high_frequency/layout/signal_integrity/_static/connector_example.png differ diff --git a/examples/high_frequency/layout/signal_integrity/_static/edb_example_12_sma_connector_on_board.png b/examples/high_frequency/layout/signal_integrity/_static/edb_example_12_sma_connector_on_board.png new file mode 100644 index 000000000..1226d2420 Binary files /dev/null and b/examples/high_frequency/layout/signal_integrity/_static/edb_example_12_sma_connector_on_board.png differ diff --git a/examples/high_frequency/layout/signal_integrity/_static/parametrized_design.png b/examples/high_frequency/layout/signal_integrity/_static/parametrized_design.png new file mode 100644 index 000000000..80bcb84b1 Binary files /dev/null and b/examples/high_frequency/layout/signal_integrity/_static/parametrized_design.png differ diff --git a/examples/high_frequency/layout/signal_integrity/_static/parametrized_edb.png b/examples/high_frequency/layout/signal_integrity/_static/parametrized_edb.png new file mode 100644 index 000000000..5f708e72c Binary files /dev/null and b/examples/high_frequency/layout/signal_integrity/_static/parametrized_edb.png differ diff --git a/examples/high_frequency/layout/signal_integrity/_static/pcb_transition_parameterized.png b/examples/high_frequency/layout/signal_integrity/_static/pcb_transition_parameterized.png new file mode 100644 index 000000000..f75d4a2e6 Binary files /dev/null and b/examples/high_frequency/layout/signal_integrity/_static/pcb_transition_parameterized.png differ diff --git a/examples/high_frequency/layout/signal_integrity/index.rst b/examples/high_frequency/layout/signal_integrity/index.rst index be6e40795..97634684f 100644 --- a/examples/high_frequency/layout/signal_integrity/index.rst +++ b/examples/high_frequency/layout/signal_integrity/index.rst @@ -32,6 +32,20 @@ These examples use PyAEDT to show signal integrity examples. This example shows how to create a parameterized layout design and load the layout into HFSS 3D Layout for analysis and postprocessing. + .. grid-item-card:: Siwave differential pairs in Hfss 3D Layout + :padding: 2 2 2 2 + :link: serdes_differential + :link-type: doc + + .. image:: _static/parametrized_edb.png + :alt: Parametrized differential pairs + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to set up SYZ analysis on a + serdes channel. + .. grid-item-card:: Pre-layout Parameterized PCB :padding: 2 2 2 2 :link: pre_layout_parametrized @@ -158,7 +172,9 @@ These examples use PyAEDT to show signal integrity examples. pre_layout_parametrized ami multizone + serdes_differential circuit_transient + ../../../aedt_general/modeler/circuit_schematic ../../../aedt_general/modeler/netlist_to_schematic ../../emc/subcircuit diff --git a/examples/high_frequency/layout/signal_integrity/pre_layout.py b/examples/high_frequency/layout/signal_integrity/pre_layout.py index 5c961675c..6fdcdfda9 100644 --- a/examples/high_frequency/layout/signal_integrity/pre_layout.py +++ b/examples/high_frequency/layout/signal_integrity/pre_layout.py @@ -337,6 +337,28 @@ ) comp.angle = "90deg" +# ## Run simulation + +h3d.analyze(num_cores=4) + +# ## Visualize the return loss. + +h3d.post.create_report("dB(S(port_1, port_1))") + +# - + +# ## Create Field Plot on clip plane + + +# solutions = h3d.get_touchstone_data()[0] +# solutions.log_x = False +# solutions.plot() +cp_name = h3d.modeler.clip_plane() + +plot = h3d.post.create_fieldplot_cutplane( + cp_name, "Mag_E", h3d.nominal_adaptive, intrinsics={"Freq": "5GHz", "Phase": "0deg"} +) + # ## Release AEDT h3d.save_project() diff --git a/examples/high_frequency/layout/signal_integrity/serdes_differential.py b/examples/high_frequency/layout/signal_integrity/serdes_differential.py new file mode 100644 index 000000000..90458a4d0 --- /dev/null +++ b/examples/high_frequency/layout/signal_integrity/serdes_differential.py @@ -0,0 +1,230 @@ +# # EDB: Pin to Pin project +# +# This example demonstrates the use of the Electronics +# Database (EDB) interface to create a layout using the BOM and +# a configuration file. + +# ## Perform required imports +# +# The ``Hfss3dlayout`` class provides an interface to +# the 3D Layout editor in AEDT. +# on version 2023 R2. + +# + +import os +import tempfile + +import ansys.aedt.core + +import pyedb +from pyedb.misc.downloads import download_file + +# - + +# Download the AEDB file and copy it to a temporary folder. + +temp_dir = tempfile.TemporaryDirectory(suffix=".ansys") +target_aedb = download_file("edb/ANSYS-HSD_V1.aedb", destination=temp_dir.name) +print("Project folder is", target_aedb) + +# ## Launch EDB +# +# Launch the ``pyedb.Edb`` class using EDB 2023 R2. Length units are SI. + +# + +# Select EDB version (change it manually if needed, e.g. "2024.2") +edb_version = "2024.2" +print(f"EDB version: {edb_version}") + +edbapp = pyedb.Edb(target_aedb, edbversion=edb_version) +# - + +# ## Import definitions +# +# The definition file uses the [json](https://www.json.org/json-en.html) to +# map layout part numbers to their corresponding models. +# +# The model may be an RLC, S-parameter, or +# [SPICE](https://en.wikipedia.org/wiki/SPICE) model definition. +# Once imported, the definition is applied to the components in the layout. +# In this example, the JSON file is in the ``*.aedb`` folder and has the following format: +# ``` json +# { +# "SParameterModel": { +# "GRM32_DC0V_25degC_series": "./GRM32_DC0V_25degC_series.s2p" +# }, +# "SPICEModel": { +# "GRM32_DC0V_25degC": "./GRM32_DC0V_25degC.mod" +# }, +# "Definitions": { +# "CAPC1005X05N": { +# "Component_type": "Capacitor", +# "Model_type": "RLC", +# "Res": 1, +# "Ind": 2, +# "Cap": 3, +# "Is_parallel": false +# }, +# "'CAPC3216X180X55ML20T25": { +# "Component_type": "Capacitor", +# "Model_type": "SParameterModel", +# "Model_name": "GRM32_DC0V_25degC_series" +# }, +# "'CAPC3216X180X20ML20": { +# "Component_type": "Capacitor", +# "Model_type": "SPICEModel", +# "Model_name": "GRM32_DC0V_25degC" +# } +# } +# } +# ``` +# +# The ``Edb.components.import_definitions()`` method imports the component definitions that map +# electrical models to the components in the simulation model. + +edbapp.components.import_definition(os.path.join(target_aedb, "1_comp_definition.json")) + +# ## Import BOM +# +# The bill of materials (BOM) file provides the list of all components +# by reference designator, part name, component type, and nominal value. +# +# Components that are not contained in the BOM are deactivated in the +# simulation model. +# This example saves the CSV file in the ``aedb`` folder. +# +# ``` +# +------------+-----------------------+-----------+------------+ +# | RefDes | Part name | Type | Value | +# +============+=======================+===========+============+ +# | C380 | CAPC1005X55X25LL05T10 | Capacitor | 11nF | +# +------------+-----------------------+-----------+------------+ +# ``` +# +# Having red the information in the BOM and definitions file, electrical models can be +# assigned to all of the components in the simulation model. + +edbapp.components.import_bom( + os.path.join(target_aedb, "0_bom.csv"), + refdes_col=0, + part_name_col=1, + comp_type_col=2, + value_col=3, +) + +# ## Verify a Component +# +# Component property allows to access all components instances and their property with +# getters and setters. + +comp = edbapp.components["C1"] +comp.model_type, comp.value + +# ## Check component definition +# +# When an s-parameter model is associated to a component it will be available in +# nport_comp_definition property. + +edbapp.components.nport_comp_definition +edbapp.save_edb() + +# ## Configure the simulation setup +# +# This step enables the following: +# +# - Definition of the nets to include in the cutout region +# - Cutout details +# - Components to create the ports on +# - Simulation settings +# +# The ``Edb.new_simulaton_configuration()`` method returns an instance +# of the ``SimulationConfiguration`` class. + +# + +sim_setup = edbapp.new_simulation_configuration() +sim_setup.solver_type = sim_setup.SOLVER_TYPE.SiwaveSYZ +sim_setup.batch_solve_settings.cutout_subdesign_expansion = 0.003 +sim_setup.batch_solve_settings.do_cutout_subdesign = True +sim_setup.batch_solve_settings.use_pyaedt_cutout = True +sim_setup.ac_settings.max_arc_points = 6 +sim_setup.ac_settings.max_num_passes = 5 + +sim_setup.batch_solve_settings.signal_nets = [ + "PCIe_Gen4_TX2_CAP_P", + "PCIe_Gen4_TX2_CAP_N", + "PCIe_Gen4_TX2_P", + "PCIe_Gen4_TX2_N", +] +sim_setup.batch_solve_settings.components = ["U1", "X1"] +sim_setup.batch_solve_settings.power_nets = ["GND", "GND_DP"] +sim_setup.ac_settings.start_freq = "100Hz" +sim_setup.ac_settings.stop_freq = "6GHz" +sim_setup.ac_settings.step_freq = "10MHz" +# - + +# ## Implement the setup +# +# The cutout and all other simulation settings are applied to the simulation model. + +sim_setup.export_json(os.path.join(temp_dir.name, "configuration.json")) +edbapp.build_simulation_project(sim_setup) + +# ## Display the cutout +# +# Plot cutout once finished. The model is ready to simulate. + +edbapp.nets.plot(None, None) + +# ## Save and close EDB +# +# EDB is saved and re-opened in HFSS +# 3D Layout, where the HFSS simulation can be run. + +edbapp.save_edb() +edbapp.close_edb() + +# ## Open Electronics Desktop +# +# The EDB is opened in AEDT Hfss3DLayout. +# +# Set ``non_graphical=True`` to run the simulation in non-graphical mode. + +aedt_version = edb_version + +h3d = ansys.aedt.core.Hfss3dLayout( + specified_version=aedt_version, + projectname=target_aedb, + non_graphical=False, + new_desktop_session=False, +) + +# ## Analyze +# +# This project is ready to solve. +# Executing the following cell runs the HFSS simulation on the layout. + +h3d.analyze() + +# ## View results +# +# S-parameter data is loaded at the end of simulation. + +solutions = h3d.post.get_solution_data() + +# ## Plot results +# +# Plot S-Parameter data. + +solutions.plot(solutions.expressions, "db20") + +# ## Save and close AEDT +# +# HFSS 3D Layout is saved and closed. + +h3d.save_project() +h3d.release_desktop() + +# Clean up the temporary directory. All files and the temporary project +# folder will be deleted in the next step. + +temp_dir.cleanup() diff --git a/examples/high_frequency/layout/workflows/index.rst b/examples/high_frequency/layout/workflows/index.rst new file mode 100644 index 000000000..696bf37f3 --- /dev/null +++ b/examples/high_frequency/layout/workflows/index.rst @@ -0,0 +1,80 @@ +Workflows +~~~~~~~~~ + +These examples create end-to-end workflows with PyAEDT and PyEDB. + +.. grid:: 2 + + .. grid-item-card:: Configuration Files + :padding: 2 2 2 2 + :link: ../../../00_edb/use_configuration/index + :link-type: doc + + .. image:: ../../../00_edb/use_configuration/_static/configurator_2.png + :alt: PyEDB2 + :width: 250px + :height: 200px + :align: center + + Links to examples in the PyAEDT documentation that show how to use PyEDB configuration files. + + .. grid-item-card:: IPC2581 + :padding: 2 2 2 2 + :link: ../../../00_edb/legacy_standalone/edb_to_ipc2581 + :link-type: doc + + .. image:: ../../../00_edb/legacy_standalone/_static/ipc.png + :alt: PyEDB2 + :width: 250px + :height: 200px + :align: center + + This example shows how you can use PyAEDT to export an IPC2581 file. + + .. grid-item-card:: Plot Layout + :padding: 2 2 2 2 + :link: ../../../00_edb/legacy_standalone/Plot_nets + :link-type: doc + + .. image:: ../../../00_edb/legacy_standalone/_static/plot_nets.png + :alt: PyEDB2 + :width: 250px + :height: 200px + :align: center + + This example shows how to use the ``Edb`` class to view nets, layers and via geometry directly in Python. + + .. grid-item-card:: IC Workflow using GDS + :padding: 2 2 2 2 + :link: ../../../00_edb/legacy_standalone/GDS_workflow + :link-type: doc + + .. image:: ../../../00_edb/legacy_standalone/_static/gds.png + :alt: GDS + :width: 250px + :height: 200px + :align: center + + This example shows how to use the ``Edb`` class to manage ``GDS`` files, import them and setup analysis. + + .. grid-item-card:: HFSS 3D Layout GUI modificatation + :padding: 2 2 2 2 + :link: ../gui_manipulation + :link-type: doc + + .. image:: ../_static/user_interface.png + :alt: UI 3D Layout + :width: 250px + :height: 200px + :align: center + + Provides HFSS 3D Layout GUI modification examples. + + .. toctree:: + :hidden: + + ../../../00_edb/use_configuration/index + ../../../00_edb/legacy_standalone/edb_to_ipc2581 + ../../../00_edb/legacy_standalone/Plot_nets + ../../../00_edb/legacy_standalone/GDS_workflow + ../gui_manipulation \ No newline at end of file diff --git a/examples/high_frequency/multiphysics/_static/oven.png b/examples/high_frequency/multiphysics/_static/oven.png index e9a08e375..22c18a504 100644 Binary files a/examples/high_frequency/multiphysics/_static/oven.png and b/examples/high_frequency/multiphysics/_static/oven.png differ diff --git a/examples/high_frequency/radiofrequency_mmwave/spiral.py b/examples/high_frequency/radiofrequency_mmwave/spiral.py index f1e4dc923..c46adc140 100644 --- a/examples/high_frequency/radiofrequency_mmwave/spiral.py +++ b/examples/high_frequency/radiofrequency_mmwave/spiral.py @@ -57,6 +57,7 @@ Nr = 10 gap = 3 hfss["Tsub"] = "6" + hfss.modeler.model_units +hfss["thickness"] = f"{thickness} {hfss.modeler.model_units}" # ## Standardize polyline # @@ -101,7 +102,7 @@ def create_line(pts): hfss.modeler.create_box( [x0 - width / 2, y0 - width / 2, -gap - thickness / 2], [width, width, gap + thickness], - matname="copper", + material="copper", ) # Create port 1. @@ -129,13 +130,13 @@ def create_line(pts): # + hfss.modeler.create_box( - [x1 - 20, x1 - 20, "-Tsub-{}{}/2".format(thickness, hfss.modeler.model_units)], + [x1 - 20, x1 - 20, "-Tsub-thickness/2"], [-2 * x1 + 40, -2 * x1 + 40, "Tsub"], material="silicon", ) hfss.modeler.create_box( - [x1 - 20, x1 - 20, "-Tsub-{}{}/2".format(thickness, hfss.modeler.model_units)], + [x1 - 20, x1 - 20, "-Tsub-thickness/2"], [-2 * x1 + 40, -2 * x1 + 40, -0.1], material="PEC", ) @@ -150,9 +151,7 @@ def create_line(pts): [ x1 - 20, x1 - 20, - "-Tsub-{}{}/2 - 0.1{}".format( - thickness, hfss.modeler.model_units, hfss.modeler.model_units - ), + "-Tsub-thickness/2 - 0.1{}".format(hfss.modeler.model_units), ], [-2 * x1 + 40, -2 * x1 + 40, 100], name="airbox",