{ "cells": [ { "cell_type": "markdown", "id": "a9b77198", "metadata": {}, "source": [ "# PCB AC analysis" ] }, { "cell_type": "markdown", "id": "8ef491b3", "metadata": {}, "source": [ "This example shows how to use PyAEDT to create a design in\n", "Q3D Extractor and run a simulation starting from an EDB project.\n", "\n", "Keywords: **Q3D**, **PCB**." ] }, { "cell_type": "markdown", "id": "d80015ca", "metadata": {}, "source": [ "## Perform imports and define constants\n", "\n", "Perform required imports." ] }, { "cell_type": "code", "execution_count": null, "id": "2f78af31", "metadata": {}, "outputs": [], "source": [ "import os\n", "import tempfile\n", "import time\n", "\n", "import ansys.aedt.core\n", "import pyedb\n", "from ansys.aedt.core.examples.downloads import download_file\n" ] }, { "cell_type": "markdown", "id": "2ba99c3d", "metadata": {}, "source": [ "Define constants." ] }, { "cell_type": "code", "execution_count": null, "id": "6b347d36", "metadata": {}, "outputs": [], "source": [ "AEDT_VERSION = \"2026.1\"\n", "NUM_CORES = 4\n", "NG_MODE = False # Open AEDT UI when it is launched." ] }, { "cell_type": "markdown", "id": "425e07ac", "metadata": {}, "source": [ "## Create temporary directory\n", "\n", "Create a temporary directory where downloaded data or\n", "dumped data can be stored.\n", "If you'd like to retrieve the project data for subsequent use,\n", "the temporary folder name is given by ``temp_folder.name``." ] }, { "cell_type": "code", "execution_count": null, "id": "62384d11", "metadata": {}, "outputs": [], "source": [ "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" ] }, { "cell_type": "markdown", "id": "0ea2e6f8", "metadata": {}, "source": [ "## Set up project files and path\n", "\n", "Download needed project file and set up temporary project directory." ] }, { "cell_type": "code", "execution_count": null, "id": "31ea7deb", "metadata": {}, "outputs": [], "source": [ "project_dir = os.path.join(temp_folder.name, \"edb\")\n", "aedb_project = download_file(source=\"edb/ANSYS-HSD_V1.aedb\", local_path=project_dir)\n", "\n", "project_name = os.path.join(temp_folder.name, \"HSD\")\n", "output_edb = os.path.join(project_dir, project_name + \".aedb\")\n", "output_q3d = os.path.join(project_dir, project_name + \"_q3d.aedt\")" ] }, { "cell_type": "markdown", "id": "5ffb9d0f", "metadata": {}, "source": [ "## Open EDB and create cutout\n", "\n", "Open the EDB project and create a cutout on the selected nets\n", "before exporting to Q3D." ] }, { "cell_type": "code", "execution_count": null, "id": "86e44ecd", "metadata": { "lines_to_next_cell": 2 }, "outputs": [], "source": [ "edb = pyedb.Edb(edbpath=aedb_project, version=AEDT_VERSION)\n", "cutout_points = edb.cutout(\n", " [\"CLOCK_I2C_SCL\", \"CLOCK_I2C_SDA\"],\n", " [\"GND\"],\n", " output_aedb_path=output_edb,\n", " use_pyaedt_extent_computing=True,\n", ")" ] }, { "cell_type": "markdown", "id": "3d7e4db8", "metadata": {}, "source": [ "## Identify locations of pins\n", "\n", "Identify $(x,y)$ pin locations on the components to define where to assign sources\n", "and sinks for Q3D." ] }, { "cell_type": "code", "execution_count": null, "id": "7a872775", "metadata": {}, "outputs": [], "source": [ "pin_u13_scl = [i for i in edb.components[\"U13\"].pins.values() if i.net_name == \"CLOCK_I2C_SCL\"]\n", "pin_u1_scl = [i for i in edb.components[\"U1\"].pins.values() if i.net_name == \"CLOCK_I2C_SCL\"]\n", "pin_u13_sda = [i for i in edb.components[\"U13\"].pins.values() if i.net_name == \"CLOCK_I2C_SDA\"]\n", "pin_u1_sda = [i for i in edb.components[\"U1\"].pins.values() if i.net_name == \"CLOCK_I2C_SDA\"]" ] }, { "cell_type": "markdown", "id": "2e405d66", "metadata": {}, "source": [ "## Append Z elevation positions\n", "\n", "> **Note:** The factor 1000 converts from meters to millimeters." ] }, { "cell_type": "code", "execution_count": null, "id": "f51fd850", "metadata": {}, "outputs": [], "source": [ "location_u13_scl = [i * 1000 for i in pin_u13_scl[0].position]\n", "location_u13_scl.append(edb.components[\"U13\"].upper_elevation * 1000)\n", "\n", "location_u1_scl = [i * 1000 for i in pin_u1_scl[0].position]\n", "location_u1_scl.append(edb.components[\"U1\"].upper_elevation * 1000)\n", "\n", "location_u13_sda = [i * 1000 for i in pin_u13_sda[0].position]\n", "location_u13_sda.append(edb.components[\"U13\"].upper_elevation * 1000)\n", "\n", "location_u1_sda = [i * 1000 for i in pin_u1_sda[0].position]\n", "location_u1_sda.append(edb.components[\"U1\"].upper_elevation * 1000)" ] }, { "cell_type": "markdown", "id": "8e44999d", "metadata": {}, "source": [ "## Save and close EDB\n", "\n", "Save and close EDB. Then, open the EDB project in HFSS 3D Layout to generate the 3D model." ] }, { "cell_type": "code", "execution_count": null, "id": "399f1997", "metadata": {}, "outputs": [], "source": [ "edb.save()\n", "edb.close()\n", "\n", "h3d = ansys.aedt.core.Hfss3dLayout(output_edb, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True)" ] }, { "cell_type": "markdown", "id": "f6fd6659", "metadata": {}, "source": [ "## Set up the Q3D Project\n", "\n", "Use HFSS 3D Layout to export the model to Q3D Extractor. The named parameter\n", "``keep_net_name=True`` ensures that net names are retained when the model is exported from HFSS 3D Layout." ] }, { "cell_type": "code", "execution_count": null, "id": "a31c159c", "metadata": {}, "outputs": [], "source": [ "setup = h3d.create_setup()\n", "setup.export_to_q3d(output_q3d, keep_net_name=True)\n", "h3d.close_project()\n", "time.sleep(3)" ] }, { "cell_type": "markdown", "id": "81519937", "metadata": {}, "source": [ "Open the newly created Q3D project and display the layout." ] }, { "cell_type": "code", "execution_count": null, "id": "860543d6", "metadata": {}, "outputs": [], "source": [ "q3d = ansys.aedt.core.Q3d(output_q3d, version=AEDT_VERSION)\n", "q3d.plot(\n", " show=False,\n", " assignment=[\"CLOCK_I2C_SCL\", \"CLOCK_I2C_SDA\"],\n", " output_file=os.path.join(temp_folder.name, \"Q3D.jpg\"),\n", " plot_air_objects=False,\n", ")" ] }, { "cell_type": "markdown", "id": "5b084130", "metadata": {}, "source": [ "Use the previously calculated positions to identify faces and\n", "assign sources and sinks on nets." ] }, { "cell_type": "code", "execution_count": null, "id": "f7d0f87c", "metadata": {}, "outputs": [], "source": [ "f1 = q3d.modeler.get_faceid_from_position(location_u13_scl, assignment=\"CLOCK_I2C_SCL\")\n", "q3d.source(f1, net_name=\"CLOCK_I2C_SCL\")\n", "f1 = q3d.modeler.get_faceid_from_position(location_u13_sda, assignment=\"CLOCK_I2C_SDA\")\n", "q3d.source(f1, net_name=\"CLOCK_I2C_SDA\")\n", "f1 = q3d.modeler.get_faceid_from_position(location_u1_scl, assignment=\"CLOCK_I2C_SCL\")\n", "q3d.sink(f1, net_name=\"CLOCK_I2C_SCL\")\n", "f1 = q3d.modeler.get_faceid_from_position(location_u1_sda, assignment=\"CLOCK_I2C_SDA\")\n", "q3d.sink(f1, net_name=\"CLOCK_I2C_SDA\")" ] }, { "cell_type": "markdown", "id": "59484ff4", "metadata": {}, "source": [ "Define the solution setup and the frequency sweep ranging from DC to 2GHz." ] }, { "cell_type": "code", "execution_count": null, "id": "8db5f12f", "metadata": {}, "outputs": [], "source": [ "setup = q3d.create_setup()\n", "setup.dc_enabled = True\n", "setup.capacitance_enabled = False\n", "sweep = setup.add_sweep()\n", "sweep.add_subrange(\"LinearStep\", 0, end=2, count=0.05, unit=\"GHz\", clear=True)\n", "setup.analyze(cores=NUM_CORES)" ] }, { "cell_type": "markdown", "id": "8a735174", "metadata": {}, "source": [ "## Solve\n", "\n", "Compute AC inductance and resistance." ] }, { "cell_type": "code", "execution_count": null, "id": "148e8cf8", "metadata": {}, "outputs": [], "source": [ "traces_acl = q3d.post.available_report_quantities(quantities_category=\"ACL Matrix\")\n", "solution = q3d.post.get_solution_data(traces_acl)" ] }, { "cell_type": "markdown", "id": "556524ab", "metadata": {}, "source": [ "## Postprocess\n", "\n", "Plot AC inductance and resistance." ] }, { "cell_type": "code", "execution_count": null, "id": "8fb6437a", "metadata": {}, "outputs": [], "source": [ "_ = solution.plot()\n", "traces_acr = q3d.post.available_report_quantities(quantities_category=\"ACR Matrix\")\n", "solution2 = q3d.post.get_solution_data(traces_acr)\n", "_ = solution2.plot()" ] }, { "cell_type": "markdown", "id": "d9f8d5ef", "metadata": {}, "source": [ "## Release AEDT" ] }, { "cell_type": "code", "execution_count": null, "id": "b3bcf742", "metadata": {}, "outputs": [], "source": [ "q3d.save_project()\n", "q3d.release_desktop()\n", "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", "time.sleep(3)" ] }, { "cell_type": "markdown", "id": "010d2a1c", "metadata": {}, "source": [ "## Clean up\n", "\n", "All project files are saved in the folder ``temp_folder.name``.\n", "If you've run this example as a Jupyter notebook, you\n", "can retrieve those project files. The following cell\n", "removes all temporary files, including the project folder." ] }, { "cell_type": "code", "execution_count": null, "id": "67ff74ab", "metadata": {}, "outputs": [], "source": [ "temp_folder.cleanup()" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }