{ "cells": [ { "cell_type": "markdown", "id": "979fb2c3", "metadata": {}, "source": [ "# PCB AC analysis" ] }, { "cell_type": "markdown", "id": "17edd7ed", "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": "081ea8ae", "metadata": {}, "source": [ "## Perform imports and define constants\n", "\n", "Perform required imports." ] }, { "cell_type": "code", "execution_count": null, "id": "ccfbdad8", "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": "dd92f897", "metadata": {}, "source": [ "Define constants." ] }, { "cell_type": "code", "execution_count": null, "id": "d79d611b", "metadata": {}, "outputs": [], "source": [ "AEDT_VERSION = \"2025.2\"\n", "NUM_CORES = 4\n", "NG_MODE = False # Open AEDT UI when it is launched." ] }, { "cell_type": "markdown", "id": "6bb8ce5b", "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": "c9a68d18", "metadata": {}, "outputs": [], "source": [ "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" ] }, { "cell_type": "markdown", "id": "bd22ec28", "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": "3f4dceab", "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": "a49e8bd0", "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": "55de2ed3", "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": "8044276f", "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": "33b50774", "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": "3a57addb", "metadata": {}, "source": [ "## Append Z elevation positions\n", "\n", "> **Note:** The factor 1000 converts from meters to millimeters." ] }, { "cell_type": "code", "execution_count": null, "id": "105b5ebe", "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": "c254d0a1", "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": "14ad666f", "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": "08cf1a60", "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": "13ccd4fa", "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": "b8f50b87", "metadata": {}, "source": [ "Open the newly created Q3D project and display the layout." ] }, { "cell_type": "code", "execution_count": null, "id": "387d8c3b", "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": "051e4d26", "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": "150fb8be", "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": "332f4d33", "metadata": {}, "source": [ "Define the solution setup and the frequency sweep ranging from DC to 2GHz." ] }, { "cell_type": "code", "execution_count": null, "id": "8d91fef1", "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": "41d90790", "metadata": {}, "source": [ "## Solve\n", "\n", "Compute AC inductance and resistance." ] }, { "cell_type": "code", "execution_count": null, "id": "e1e0fd01", "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": "921d8835", "metadata": {}, "source": [ "## Postprocess\n", "\n", "Plot AC inductance and resistance." ] }, { "cell_type": "code", "execution_count": null, "id": "80ef181d", "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": "b2419bbc", "metadata": {}, "source": [ "## Release AEDT" ] }, { "cell_type": "code", "execution_count": null, "id": "c14fc32f", "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": "64302fc8", "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": "3a84a77d", "metadata": {}, "outputs": [], "source": [ "temp_folder.cleanup()" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }