{ "cells": [ { "cell_type": "markdown", "id": "89a0320f", "metadata": {}, "source": [ "# PCB Signal Integrity Analysis Using PyEDB\n", "\n", "This example demonstrates a complete end-to-end PCB signal integrity workflow:\n", "\n", "1. Load an existing high-speed digital PCB layout from an EDB file.\n", "2. Explore the board—inspect the stackup, nets, and components.\n", "3. Configure the design using a single JSON file: update stackup materials with\n", " frequency-dependent properties and surface roughness models, assign measured\n", " S-parameter data to decoupling capacitors, create coaxial ports on the IC and\n", " circuit ports on the connector, backdrill via stubs, define a focused design\n", " cutout, and set up a SIwave AC analysis.\n", "4. Apply the configuration and visualize the result.\n", "5. Open the configured EDB in HFSS 3D Layout, assign differential pairs, and run\n", " the SIwave solver.\n", "6. Post-process and plot the differential insertion loss (SDD21) for the PCIe\n", " Gen4 channel.\n", "\n", "Keywords: **EDB**, **PyEDB**, **signal integrity**, **SIwave**, **HFSS 3D Layout**,\n", "**PCIe**, **differential pairs**, **S-parameters**" ] }, { "cell_type": "markdown", "id": "f7c7b814", "metadata": {}, "source": [ "## Prerequisites\n", "\n", "### Perform imports" ] }, { "cell_type": "code", "execution_count": null, "id": "f08d1cb5", "metadata": {}, "outputs": [], "source": [ "import json\n", "import os\n", "import tempfile\n", "import time\n", "\n", "import matplotlib.pyplot as plt\n", "from ansys.aedt.core import Hfss3dLayout\n", "from ansys.aedt.core.examples.downloads import download_file\n", "from pyedb import Edb\n" ] }, { "cell_type": "markdown", "id": "ae2cf7d0", "metadata": {}, "source": [ "### Define constants\n", "\n", "Constants help ensure consistency and avoid repetition throughout the example." ] }, { "cell_type": "code", "execution_count": null, "id": "edb3612c", "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": "b442c876", "metadata": {}, "source": [ "### Create temporary directory\n", "\n", "Create a temporary working directory.\n", "The name of the working folder is stored in ``temp_folder.name``.\n", "\n", "> **Note:** The final cell in the notebook cleans up the temporary folder. If you want to\n", "> retrieve the AEDT project and data, do so before executing the final cell in the notebook." ] }, { "cell_type": "code", "execution_count": null, "id": "423fee6a", "metadata": {}, "outputs": [], "source": [ "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" ] }, { "cell_type": "markdown", "id": "8018b42b", "metadata": {}, "source": [ "### Download example PCB layout\n", "\n", "Download the ANSYS high-speed digital (HSD) PCB reference design. This 16-layer\n", "board includes DDR4 and PCIe Gen4 interfaces, a multi-layer copper/dielectric\n", "stackup, decoupling capacitors, and a BGA IC (U1) connected to an edge connector (X1).\n", "\n", "A measured S-parameter file for the decoupling capacitor is also downloaded." ] }, { "cell_type": "markdown", "id": "be76222d", "metadata": {}, "source": [ "> **Note:** For execution of this example on your local machine, you may\n", "> download or clone the [example-data](https://github.com/ansys/example-data)\n", "> repo and add the\n", "> following lines so that files for this example are copied from that local\n", "> source.\n", "\n", "``` python\n", "from ansys.aedt.core import settings\n", "settings.use_local_example_data = True\n", "settings.local_example_folder = r'/path/to/local/example-data'\n", "```" ] }, { "cell_type": "code", "execution_count": null, "id": "fc9dafeb", "metadata": {}, "outputs": [], "source": [ "file_edb = download_file(source=\"pyaedt/edb/ANSYS-HSD_V1.aedb\", local_path=temp_folder.name)" ] }, { "cell_type": "code", "execution_count": null, "id": "bb020bc7", "metadata": {}, "outputs": [], "source": [ "download_file(\n", " source=\"touchstone\",\n", " name=\"GRM32_DC0V_25degC_series.s2p\",\n", " local_path=os.path.dirname(file_edb),\n", ")" ] }, { "cell_type": "markdown", "id": "5f3ae34f", "metadata": {}, "source": [ "## Explore the PCB Layout\n", "\n", "Open the PCB as an ``Edb`` instance\n", "and inspect the stackup, nets, and components. This is useful for\n", "identifying the layer names, net names, and\n", "component reference designators that will be referenced later in the configuration." ] }, { "cell_type": "code", "execution_count": null, "id": "bd94affe", "metadata": {}, "outputs": [], "source": [ "edbapp = Edb(edbpath=file_edb, version=AEDT_VERSION)" ] }, { "cell_type": "markdown", "id": "9229b9c3", "metadata": {}, "source": [ "### Inspect the stackup\n", "\n", "List all layers with their type and thickness. Layer names returned here are used\n", "verbatim in the ``stackup.layers`` section of the configuration dictionary." ] }, { "cell_type": "code", "execution_count": null, "id": "5397a3e9", "metadata": {}, "outputs": [], "source": [ "print(\"Stackup layers:\")\n", "for name, layer in edbapp.stackup.layers.items():\n", " print(f\" '{name}': type={layer.type}, thickness={layer.thickness*1E6:.1f} µm\")\n", " print(\"--------------------------------------------\")" ] }, { "cell_type": "markdown", "id": "1feaae48", "metadata": {}, "source": [ "### Inspect nets and components" ] }, { "cell_type": "code", "execution_count": null, "id": "e497f728", "metadata": {}, "outputs": [], "source": [ "print(f\"\\nTotal nets : {len(edbapp.nets.netlist)}\")\n", "print(f\"Total components: {len(edbapp.components.instances)}\")" ] }, { "cell_type": "markdown", "id": "99c686d5", "metadata": {}, "source": [ "Print the reference designator,\n", "part number and connected net names for components.\n", "Select only the first component instance for\n", "inductors \"L\", capacitors \"C\" and the BGA \"U\"." ] }, { "cell_type": "markdown", "id": "c4c9114d", "metadata": {}, "source": [ "Count the types of components in the PCB." ] }, { "cell_type": "code", "execution_count": null, "id": "72a152b1", "metadata": {}, "outputs": [], "source": [ "resistors = {k: v for k, v in edbapp.components.instances.items() if k.lower().startswith(\"r\")}\n", "caps = {k: v for k, v in edbapp.components.instances.items() if k.lower().startswith(\"c\")}\n", "ics = {k: v for k, v in edbapp.components.instances.items() if k.lower().startswith(\"u\")}\n", "print(f\"There are {len(resistors)} resistors, {len(caps)} capacitors and {len(ics)} IC's.\")" ] }, { "cell_type": "markdown", "id": "85bd8e69", "metadata": {}, "source": [ "Print the reference designator and number of pins for each IC." ] }, { "cell_type": "code", "execution_count": null, "id": "35656de3", "metadata": {}, "outputs": [], "source": [ "for refdes, comp in ics.items():\n", " s = f\"{refdes} has {comp.numpins} pins and is on layer '{comp.placement_layer}'.\"\n", " print(s)" ] }, { "cell_type": "markdown", "id": "1721a7e8", "metadata": {}, "source": [ "The BGA is component ``\"U1\"`` which is an instance of the\n", "``EDBComponent`` class.\n", "\n", "Print the bounding box $(x,y)$ coordinates for ``\"U1\"``.\n", "> **Note:** Lateral\n", "> dimensions are in mm." ] }, { "cell_type": "code", "execution_count": null, "id": "3fda0b89", "metadata": {}, "outputs": [], "source": [ "refdes = \"U1\"\n", "x1, y1, x2, y2 = ics[refdes].bounding_box\n", "print_str = f'\"{refdes}\" bounding box:\\n'\n", "print_str += f\" (x={x1*1000:.2f}mm, y={y1*1000:.2f}mm) lower left\\n\"\n", "print_str += f\" (x={x2*1000:.2f}mm, y={y2*1000:.2f}mm) upper right.\"\n", "print(print_str)" ] }, { "cell_type": "markdown", "id": "6b3bb7f1", "metadata": {}, "source": [ "Information about the device pin connections can be accessed\n", "through the ``pins`` property." ] }, { "cell_type": "code", "execution_count": null, "id": "fed89de8", "metadata": {}, "outputs": [], "source": [ "ground_pins = [pin for pin, pin_instance in ics[refdes].pins.items() if pin_instance.net.name == \"GND\"]\n", "print(f'Component \"{refdes}\" has {len(ground_pins)} pins connected to the net \"GND\".')" ] }, { "cell_type": "markdown", "id": "9cf4fc66", "metadata": {}, "source": [ "### Visualize the full board\n", "\n", "Plot all nets color-coded by net name to view the copper coverage." ] }, { "cell_type": "code", "execution_count": null, "id": "175cb499", "metadata": {}, "outputs": [], "source": [ "edbapp.nets.plot(None, color_by_net=True, show_legend=False)" ] }, { "cell_type": "markdown", "id": "e3b3b8c7", "metadata": {}, "source": [ "Plot the PCB stackup cross-section showing layer thicknesses and materials." ] }, { "cell_type": "code", "execution_count": null, "id": "f3acd649", "metadata": {}, "outputs": [], "source": [ "edbapp.stackup.plot()" ] }, { "cell_type": "markdown", "id": "ae8dd40f", "metadata": {}, "source": [ "## Model Preparation\n", "\n", "All EDB simulation settings are expressed as a Python dictionary that is\n", "serialized to a JSON file. The ``edb.configuration`` API loads this file and\n", "applies every setting in a single ``run()`` call.\n", "\n", "Each subsection below builds one key of the configuration dictionary and\n", "explains the relevant API keywords." ] }, { "cell_type": "markdown", "id": "f5a520fe", "metadata": {}, "source": [ "### General settings\n", "\n", "- **anti_pads_always_on**: Keep anti-pads (clearances around vias) visible at\n", " all frequencies. This improves accuracy for high-frequency broadband analysis.\n", "- **suppress_pads**: Remove floating pads on layers where the padstack is not\n", " connected. This reduces mesh complexity without affecting electrical results.\n", "- **s_parameter_library**: Root folder for S-parameter files referenced by\n", " relative path in the ``s_parameters`` section." ] }, { "cell_type": "code", "execution_count": null, "id": "ba496f34", "metadata": {}, "outputs": [], "source": [ "cfg_general = {\n", " \"anti_pads_always_on\": True,\n", " \"suppress_pads\": True,\n", " \"s_parameter_library\": os.path.join(os.path.dirname(file_edb), \"touchstone\"),\n", "}" ] }, { "cell_type": "markdown", "id": "923237c8", "metadata": {}, "source": [ "### Update stackup materials\n", "\n", "Replace default material assignments with accurate, frequency-dependent values.\n", "Panasonic [Megtron4](https://na.industrial.panasonic.com/products/electronic-materials/circuit-board-materials/lineup/megtron-series/series/127607)\n", "is a common high-performance PCB laminate used in server and networking\n", "boards.\n", "\n", "Surface roughness significantly affects insertion loss above ~5 GHz. The Huray\n", "model describes copper roughness using a sphere-on-a-plane geometric\n", "approximation defined by\n", "the nodule radius and the ratio of rough surface area to the ideal flat area.\n", "\n", "Keywords for layers:\n", "\n", "- **name**: Must match the layer name in the EDB exactly (see stackup inspection above).\n", "- **type**: ``signal`` for copper layers, ``dielectric`` for insulating layers.\n", "- **material**: Conductor or dielectric material name (defined in ``materials``).\n", "- **fill_material**: Dielectric fill between traces on signal layers.\n", "- **thickness**: Layer thickness as a string with units or as a float in meters.\n", "- **roughness.model**: Surface roughness model. ``huray`` is recommended for\n", " high-frequency PCB analysis.\n", "- **roughness.nodule_radius**: Average radius of copper nodules.\n", "- **roughness.surface_ratio**: Ratio of rough to flat surface area (dimensionless).\n", "- **roughness.enabled**: Set to ``True`` to activate the roughness model." ] }, { "cell_type": "code", "execution_count": null, "id": "d0c5fe21", "metadata": {}, "outputs": [], "source": [ "cfg_stackup = {\n", " \"materials\": [\n", " {\"name\": \"copper\", \"permittivity\": 1.0, \"conductivity\": 58000000.0},\n", " {\"name\": \"megtron4\", \"permittivity\": 3.77, \"dielectric_loss_tangent\": 0.005},\n", " {\"name\": \"solder_resist\", \"permittivity\": 3.0, \"dielectric_loss_tangent\": 0.035},\n", " ],\n", " \"layers\": [\n", " {\n", " \"name\": \"Top\",\n", " \"type\": \"signal\",\n", " \"material\": \"copper\",\n", " \"fill_material\": \"solder_resist\",\n", " \"thickness\": \"0.035mm\",\n", " \"roughness\": {\n", " \"top\": {\"model\": \"huray\", \"nodule_radius\": \"0.5um\", \"surface_ratio\": \"5\"},\n", " \"bottom\": {\"model\": \"huray\", \"nodule_radius\": \"0.5um\", \"surface_ratio\": \"5\"},\n", " \"side\": {\"model\": \"huray\", \"nodule_radius\": \"0.5um\", \"surface_ratio\": \"5\"},\n", " \"enabled\": True,\n", " },\n", " },\n", " {\"name\": \"DE1\", \"type\": \"dielectric\", \"material\": \"megtron4\", \"fill_material\": \"\", \"thickness\": \"0.1mm\"},\n", " {\"name\": \"Inner1\", \"type\": \"signal\", \"material\": \"copper\", \"fill_material\": \"megtron4\", \"thickness\": \"0.017mm\"},\n", " {\"name\": \"DE2\", \"type\": \"dielectric\", \"material\": \"megtron4\", \"fill_material\": \"\", \"thickness\": \"0.088mm\"},\n", " {\"name\": \"Inner2\", \"type\": \"signal\", \"material\": \"copper\", \"fill_material\": \"megtron4\", \"thickness\": \"0.017mm\"},\n", " {\"name\": \"DE3\", \"type\": \"dielectric\", \"material\": \"megtron4\", \"fill_material\": \"\", \"thickness\": \"0.1mm\"},\n", " {\"name\": \"Inner3\", \"type\": \"signal\", \"material\": \"copper\", \"fill_material\": \"megtron4\", \"thickness\": \"0.017mm\"},\n", " {\"name\": \"Megtron4-1mm\", \"type\": \"dielectric\", \"material\": \"megtron4\", \"fill_material\": \"\", \"thickness\": \"1mm\"},\n", " {\"name\": \"Inner4\", \"type\": \"signal\", \"material\": \"copper\", \"fill_material\": \"megtron4\", \"thickness\": \"0.017mm\"},\n", " {\"name\": \"DE5\", \"type\": \"dielectric\", \"material\": \"megtron4\", \"fill_material\": \"\", \"thickness\": \"0.1mm\"},\n", " {\"name\": \"Inner5\", \"type\": \"signal\", \"material\": \"copper\", \"fill_material\": \"megtron4\", \"thickness\": \"0.017mm\"},\n", " {\"name\": \"DE6\", \"type\": \"dielectric\", \"material\": \"megtron4\", \"fill_material\": \"\", \"thickness\": \"0.088mm\"},\n", " {\"name\": \"Inner6\", \"type\": \"signal\", \"material\": \"copper\", \"fill_material\": \"megtron4\", \"thickness\": \"0.017mm\"},\n", " {\"name\": \"DE7\", \"type\": \"dielectric\", \"material\": \"megtron4\", \"fill_material\": \"\", \"thickness\": \"0.1mm\"},\n", " {\n", " \"name\": \"Bottom\",\n", " \"type\": \"signal\",\n", " \"material\": \"copper\",\n", " \"fill_material\": \"solder_resist\",\n", " \"thickness\": \"0.035mm\",\n", " },\n", " ],\n", "}" ] }, { "cell_type": "markdown", "id": "bf1b34d5", "metadata": {}, "source": [ "### Configure the IC component\n", "\n", "U1 is the host IC in BGA packaging. Assigning solder ball geometry enables the\n", "configuration framework to automatically create coaxial wave ports on each ball\n", "connected to the specified nets.\n", "\n", "Keywords:\n", "\n", "- **reference_designator**: Reference designator of the component in the EDB.\n", "- **part_type**: ``io`` for IC drivers/receivers, ``other`` for generic components.\n", "- **solder_ball_properties.shape**: Solder ball cross-section, ``cylinder`` or ``sphere``.\n", "- **solder_ball_properties.diameter** / **height**: Geometry of the solder ball.\n", "- **port_properties.reference_size_auto**: When ``True``, the reference plane\n", " size is computed automatically from the pitch and ball diameter." ] }, { "cell_type": "code", "execution_count": null, "id": "b55085c3", "metadata": {}, "outputs": [], "source": [ "cfg_components = [\n", " {\n", " \"reference_designator\": \"U1\",\n", " \"part_type\": \"io\",\n", " \"solder_ball_properties\": {\n", " \"shape\": \"cylinder\",\n", " \"diameter\": \"300um\",\n", " \"height\": \"300um\",\n", " },\n", " \"port_properties\": {\n", " \"reference_offset\": \"0\",\n", " \"reference_size_auto\": True,\n", " \"reference_size_x\": 0,\n", " \"reference_size_y\": 0,\n", " },\n", " }\n", "]" ] }, { "cell_type": "markdown", "id": "c303533b", "metadata": {}, "source": [ "### Assign measured S-parameter models to decoupling capacitors\n", "\n", "Measured [Touchstone®](https://ibis.org/touchstone_ver2.1/touchstone_ver2_1.pdf)\n", "data captures real-world parasitic effects (ESL, ESR,\n", "self-resonance) that ideal RLC models cannot represent. This is especially\n", "important for decoupling capacitors in a PDN-aware S-parameter analysis.\n", "\n", "Keywords:\n", "\n", "- **name**: Label for this S-parameter assignment in the AEDT project.\n", "- **component_definition**: Part number that identifies which component type\n", " receives this model.\n", "- **file_path**: Touchstone file path, relative to ``general.s_parameter_library``.\n", "- **apply_to_all**: When ``False``, only the components listed in ``components``\n", " receive the model; all others of the same part type keep their default model.\n", "- **components**: Specific reference designators to assign when ``apply_to_all``\n", " is ``False``.\n", "- **reference_net**: Net used as the ground reference for the S-parameter model." ] }, { "cell_type": "code", "execution_count": null, "id": "308e756d", "metadata": {}, "outputs": [], "source": [ "cfg_s_parameters = [\n", " {\n", " \"name\": \"cap_10nf\",\n", " \"component_definition\": \"CAPC1005X55X25LL05T10\",\n", " \"file_path\": \"GRM32_DC0V_25degC_series.s2p\",\n", " \"apply_to_all\": True,\n", " \"components\": [\"C375\", \"C376\"],\n", " \"reference_net\": \"GND\",\n", " }\n", "]" ] }, { "cell_type": "markdown", "id": "b5c0f256", "metadata": {}, "source": [ "### Define ports\n", "\n", "Create one coaxial port per differential net at the IC (\"U1\") end, and one circuit\n", "port per differential pair at the connector (\"X1\") end. The resulting 4-port model\n", "is comprised of\n", "two ports at each end of the the PCIe channel.\n", "\n", "Keywords:\n", "\n", "- **type**: ``coax`` creates a cylindrical wave port around the solder ball.\n", " ``circuit`` creates a lumped port between two specified terminals.\n", "- **positive_terminal.net**: For a coax port, the net specifies which solder ball\n", " on the component is assigned to the port.\n", "- **positive_terminal.pin** / **negative_terminal.pin**: For a circuit port,\n", " specify the exact pin names (as printed on the component)." ] }, { "cell_type": "code", "execution_count": null, "id": "6ee75065", "metadata": {}, "outputs": [], "source": [ "cfg_ports = [\n", " # IC-side coaxial ports on the PCIe Gen4 TX differential pair.\n", " {\n", " \"name\": \"port_U1_p\",\n", " \"reference_designator\": \"U1\",\n", " \"type\": \"coax\",\n", " \"positive_terminal\": {\"net\": \"PCIe_Gen4_TX2_CAP_P\"},\n", " },\n", " {\n", " \"name\": \"port_U1_n\",\n", " \"reference_designator\": \"U1\",\n", " \"type\": \"coax\",\n", " \"positive_terminal\": {\"net\": \"PCIe_Gen4_TX2_CAP_N\"},\n", " },\n", " # Connector-side circuit ports on the mating edge connector (X1).\n", " {\n", " \"name\": \"port_X1_p\",\n", " \"reference_designator\": \"X1\",\n", " \"type\": \"circuit\",\n", " \"positive_terminal\": {\"pin\": \"B8\"},\n", " \"negative_terminal\": {\"pin\": \"B7\"},\n", " },\n", " {\n", " \"name\": \"port_X1_n\",\n", " \"reference_designator\": \"X1\",\n", " \"type\": \"circuit\",\n", " \"positive_terminal\": {\"pin\": \"B9\"},\n", " \"negative_terminal\": {\"pin\": \"B10\"},\n", " },\n", "]" ] }, { "cell_type": "markdown", "id": "94560152", "metadata": {}, "source": [ "### Configure via backdrills\n", "\n", "Via stubs—the unused portion of a through-hole via below the last active\n", "layer—can act as quarter-wave resonators and cause sharp cutouts in insertion\n", "loss at high frequency. Backdrilling removes these stubs after PCB fabrication.\n", "\n", "Keywords for instances:\n", "\n", "- **name**: Via instance name as it appears in the EDB.\n", "- **backdrill_parameters.from_bottom.drill_to_layer**: Deepest layer reached\n", " by the backdrilled hole (stub is the portion from this layer to the bottom).\n", "- **backdrill_parameters.from_bottom.diameter**: Diameter of the backdrill bit.\n", "- **backdrill_parameters.from_bottom.stub_length**: Remaining stub length after\n", " drilling, accounting for tool tolerance." ] }, { "cell_type": "code", "execution_count": null, "id": "6d309728", "metadata": {}, "outputs": [], "source": [ "cfg_padstacks = {\n", " \"definitions\": [\n", " {\n", " \"name\": \"v40h15-2\",\n", " \"material\": \"copper\",\n", " \"hole_range\": \"upper_pad_to_lower_pad\",\n", " \"hole_parameters\": {\"shape\": \"circle\", \"diameter\": \"0.2mm\"},\n", " },\n", " {\n", " \"name\": \"v35h15-1\",\n", " \"material\": \"copper\",\n", " \"hole_range\": \"upper_pad_to_lower_pad\",\n", " \"hole_parameters\": {\"shape\": \"circle\", \"diameter\": \"0.25mm\"},\n", " },\n", " ],\n", " \"instances\": [\n", " {\n", " \"name\": \"Via313\",\n", " \"backdrill_parameters\": {\n", " \"from_bottom\": {\n", " \"drill_to_layer\": \"Inner3\",\n", " \"diameter\": \"1mm\",\n", " \"stub_length\": \"0.2mm\",\n", " }\n", " },\n", " },\n", " {\n", " \"name\": \"Via314\",\n", " \"backdrill_parameters\": {\n", " \"from_bottom\": {\n", " \"drill_to_layer\": \"Inner3\",\n", " \"diameter\": \"1mm\",\n", " \"stub_length\": \"0.2mm\",\n", " }\n", " },\n", " },\n", " ],\n", "}" ] }, { "cell_type": "markdown", "id": "5d707d35", "metadata": {}, "source": [ "### Define the analysis setup\n", "\n", "Use a SIwave AC setup for full-wave S-parameter extraction from 50 MHz to 20 GHz.\n", "This range covers PCIe Gen4 (16 GT/s, Nyquist frequency ~8 GHz) and higher\n", "harmonics that affect eye opening and jitter.\n", "\n", "Keywords:\n", "\n", "- **type**: ``siwave_ac`` for SIwave SYZ analysis; ``hfss`` for full-wave HFSS.\n", "- **si_slider_position**: Controls the accuracy-vs-speed trade-off.\n", " ``0`` = speed, ``1`` = balanced (recommended), ``2`` = accuracy.\n", "- **freq_sweep.type**: ``interpolation`` uses adaptive frequency sampling and\n", " is faster than ``discrete`` for smooth S-parameter curves.\n", "- **frequencies.distribution**: ``linear_scale`` places points uniformly in\n", " frequency; ``log_scale`` is preferred for PDN impedance plots." ] }, { "cell_type": "code", "execution_count": null, "id": "0c87fd22", "metadata": {}, "outputs": [], "source": [ "cfg_setups = [\n", " {\n", " \"name\": \"siwave_ac\",\n", " \"type\": \"siwave_ac\",\n", " \"si_slider_position\": 1,\n", " \"freq_sweep\": [\n", " {\n", " \"name\": \"Sweep1\",\n", " \"type\": \"interpolation\",\n", " \"frequencies\": [\n", " {\n", " \"distribution\": \"linear_scale\",\n", " \"start\": \"50MHz\",\n", " \"stop\": \"20GHz\",\n", " \"increment\": \"50MHz\",\n", " }\n", " ],\n", " }\n", " ],\n", " }\n", "]" ] }, { "cell_type": "markdown", "id": "220d6c74", "metadata": {}, "source": [ "### Define the design cutout\n", "\n", "Trim the board to the region containing the PCIe channel. The cutout removes\n", "all copper and dielectric outside the specified polygon, reducing\n", "the required compute resources while retaining the relevant transmission\n", "lines, vias, return-path planes, and decoupling capacitors.\n", "\n", "Keywords:\n", "\n", "- **signal_list**: Nets that must be fully retained inside the cutout boundary.\n", "- **reference_list**: Reference plane nets (typically ``GND``) that follow the\n", " signal boundary with their own expansion.\n", "- **custom_extent**: Polygon vertices ``[x_m, y_m]`` in meters that define a\n", " user-drawn cutout boundary. When omitted, use ``extent_type`` to choose an\n", " automatic bounding algorithm (``ConvexHull``, ``Conforming``, ``Bounding``)." ] }, { "cell_type": "code", "execution_count": null, "id": "a9e7c6ca", "metadata": {}, "outputs": [], "source": [ "cfg_operations = {\n", " \"cutout\": {\n", " \"signal_list\": [\n", " \"PCIe_Gen4_TX2_CAP_P\",\n", " \"PCIe_Gen4_TX2_CAP_N\",\n", " \"PCIe_Gen4_TX2_P\",\n", " \"PCIe_Gen4_TX2_N\",\n", " ],\n", " \"reference_list\": [\"GND\"],\n", " \"custom_extent\": [\n", " [0.014, 0.055],\n", " [0.03674271504652968, 0.05493094625752912],\n", " [0.07, 0.039],\n", " [0.07, 0.034],\n", " [0.05609890516829415, 0.03395233061637539],\n", " [0.014, 0.044],\n", " ],\n", " }\n", "}" ] }, { "cell_type": "markdown", "id": "0be21a6a", "metadata": {}, "source": [ "### Assemble configuration dictionary and write to a JSON file" ] }, { "cell_type": "code", "execution_count": null, "id": "9ea26c66", "metadata": {}, "outputs": [], "source": [ "cfg = {\n", " \"general\": cfg_general,\n", " \"stackup\": cfg_stackup,\n", " \"components\": cfg_components,\n", " \"padstacks\": cfg_padstacks,\n", " \"ports\": cfg_ports,\n", " \"s_parameters\": cfg_s_parameters,\n", " \"setups\": cfg_setups,\n", " \"operations\": cfg_operations,\n", "}\n", "\n", "file_json = os.path.join(temp_folder.name, \"edb_configuration.json\")\n", "with open(file_json, \"w\") as f:\n", " json.dump(cfg, f, indent=4, ensure_ascii=False)" ] }, { "cell_type": "markdown", "id": "693c1995", "metadata": {}, "source": [ "### Apply configuration to EDB\n", "\n", "``configuration.load()`` reads the JSON file. ``configuration.run()`` applies\n", "every section to the open EDB in the correct dependency order (stackup →\n", "components → padstacks → ports → sources → setups → cutout)." ] }, { "cell_type": "code", "execution_count": null, "id": "43258078", "metadata": {}, "outputs": [], "source": [ "edbapp.configuration.load(config_file=file_json)\n", "edbapp.configuration.run()" ] }, { "cell_type": "markdown", "id": "e3a8c075", "metadata": {}, "source": [ "### Visualize the cutout result\n", "\n", "Plot the extracted channel region to confirm that all signal nets and the\n", "surrounding ground planes were retained correctly." ] }, { "cell_type": "code", "execution_count": null, "id": "d5671acf", "metadata": {}, "outputs": [], "source": [ "edbapp.nets.plot(\n", " nets=[\n", " \"PCIe_Gen4_TX2_CAP_P\",\n", " \"PCIe_Gen4_TX2_CAP_N\",\n", " \"PCIe_Gen4_TX2_P\",\n", " \"PCIe_Gen4_TX2_N\",\n", " \"GND\",\n", " ],\n", " color_by_net=True,\n", ")" ] }, { "cell_type": "markdown", "id": "b58a7af5", "metadata": {}, "source": [ "### Save and close EDB" ] }, { "cell_type": "code", "execution_count": null, "id": "4bb460eb", "metadata": {}, "outputs": [], "source": [ "edbapp.save()\n", "edbapp.close()" ] }, { "cell_type": "markdown", "id": "84cf2cda", "metadata": {}, "source": [ "## Simulate in HFSS 3D Layout\n", "\n", "Open the configured EDB directly in HFSS 3D Layout to drive the SIwave solver.\n", "The same AEDB file is used—no import or conversion step is needed." ] }, { "cell_type": "code", "execution_count": null, "id": "506a1a5e", "metadata": {}, "outputs": [], "source": [ "h3d = Hfss3dLayout(\n", " edbapp.edbpath,\n", " version=AEDT_VERSION,\n", " non_graphical=NG_MODE,\n", " new_desktop=True,\n", ")" ] }, { "cell_type": "markdown", "id": "4547e705", "metadata": {}, "source": [ "### Defining differential pairs\n", "\n", "Map the four single-ended ports defined in the EDB to two mixed-mode ports.\n", "HFSS 3D Layout and SIwave use these definitions to compute differential\n", "(SDD) and common-mode (SCC) S-parameters.\n", "\n", "- **differential_mode**: Name of the mixed-mode port (used in result expressions).\n", "- **assignment**: The positive (P) single-ended port name.\n", "- **reference**: The negative (N) single-ended port name." ] }, { "cell_type": "code", "execution_count": null, "id": "f6ddb782", "metadata": {}, "outputs": [], "source": [ "h3d.set_differential_pair(\n", " differential_mode=\"DIFF_U1\",\n", " assignment=\"port_U1_p\",\n", " reference=\"port_U1_n\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "099c71d0", "metadata": {}, "outputs": [], "source": [ "h3d.set_differential_pair(\n", " differential_mode=\"DIFF_X1\",\n", " assignment=\"port_X1_p\",\n", " reference=\"port_X1_n\",\n", ")" ] }, { "cell_type": "markdown", "id": "d48ecec3", "metadata": {}, "source": [ "### Run the analysis" ] }, { "cell_type": "code", "execution_count": null, "id": "48fded1d", "metadata": {}, "outputs": [], "source": [ "h3d.analyze(setup=\"siwave_ac\")" ] }, { "cell_type": "markdown", "id": "371c93e5", "metadata": {}, "source": [ "## Postprocess\n", "\n", "Extract the mixed-mode S-parameter solution data and plot the differential\n", "insertion loss SDD21. For a PCIe Gen4 channel this should be better than\n", "−3 dB up to the Nyquist frequency (~8 GHz) to meet the channel operating\n", "margin (COM) specification." ] }, { "cell_type": "markdown", "id": "d9263f08", "metadata": {}, "source": [ "### Retrieve solution data" ] }, { "cell_type": "code", "execution_count": null, "id": "59f78578", "metadata": {}, "outputs": [], "source": [ "solutions = h3d.post.get_solution_data(\n", " expressions=\"mag(S(DIFF_X1,DIFF_U1))\",\n", " context=\"Differential Pairs\",\n", ")" ] }, { "cell_type": "markdown", "id": "55d11a05", "metadata": {}, "source": [ "### Plot differential insertion loss (SDD21)" ] }, { "cell_type": "code", "execution_count": null, "id": "242a8ad9", "metadata": {}, "outputs": [], "source": [ "plot_data = solutions.get_expression_data(convert_to_SI=True, formula=\"db20\")\n", "freq, sdd21_db = plot_data" ] }, { "cell_type": "code", "execution_count": null, "id": "d9139c51", "metadata": {}, "outputs": [], "source": [ "plt.figure(figsize=(10, 5))\n", "plt.plot(freq, sdd21_db, linewidth=2)\n", "plt.axhline(y=-3, color=\"r\", linestyle=\"--\", linewidth=1, label=\"−3 dB reference\")\n", "plt.title(\"PCIe Gen4 Channel – Differential Insertion Loss (SDD21)\")\n", "plt.xlabel(\"Frequency [Hz]\")\n", "plt.ylabel(\"SDD21 [dB]\")\n", "plt.xlim([min(freq), max(freq)])\n", "plt.grid(True)\n", "plt.legend()\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "de0f741c", "metadata": {}, "source": [ "## Finish\n", "\n", "### Save the project" ] }, { "cell_type": "code", "execution_count": null, "id": "ef96a18e", "metadata": {}, "outputs": [], "source": [ "h3d.save_project()\n", "h3d.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": "0d3f4fbb", "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": "4004bcd7", "metadata": {}, "outputs": [], "source": [ "temp_folder.cleanup()" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }