{
"cells": [
{
"cell_type": "markdown",
"id": "c1c6e818",
"metadata": {},
"source": [
"# Frequency Selective Surface\n",
"\n",
"This example shows how to use PyAEDT to model and simulate a frequency-selective\n",
"surface (FSS) by applying the periodic (Floquet) boundary condition at\n",
"the boundaries of a unit cell.\n",
"\n",
"Keywords: **HFSS**, **FSS**, **Floquet**."
]
},
{
"cell_type": "markdown",
"id": "ab6b53a5",
"metadata": {},
"source": [
"## Prerequisites\n",
"\n",
"### Perform imports"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "731762de",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import tempfile\n",
"import time\n",
"from pathlib import Path\n",
"import ansys.aedt.core\n",
"from ansys.aedt.core.examples.downloads import download_file"
]
},
{
"cell_type": "markdown",
"id": "fb4ffd10",
"metadata": {},
"source": [
"### Define constants\n",
"Constants help ensure consistency and avoid repetition throughout the example."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b863deb6",
"metadata": {},
"outputs": [],
"source": [
"AEDT_VERSION = \"2025.1\"\n",
"NG_MODE = False # Open AEDT UI when it is launched."
]
},
{
"cell_type": "markdown",
"id": "9a730c31",
"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": "ebe9937a",
"metadata": {},
"outputs": [],
"source": [
"temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n",
"temp_path = Path(temp_folder.name)"
]
},
{
"cell_type": "markdown",
"id": "3951d9c0",
"metadata": {},
"source": [
"### Launch HFSS\n",
"\n",
"The Ansys Electronics Desktop (AEDT) will be launched\n",
"and an HFSS design will be inserted into the project."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "42d910bb",
"metadata": {},
"outputs": [],
"source": [
"project_name = temp_path / \"FSS.aedt\"\n",
"hfss = ansys.aedt.core.Hfss(\n",
" version=AEDT_VERSION, \n",
" project=str(project_name), \n",
" design=\"SquarePatch\",\n",
" non_graphical=NG_MODE,\n",
" solution_type=\"Modal\",\n",
")"
]
},
{
"cell_type": "markdown",
"id": "37fc4b65",
"metadata": {},
"source": [
"### Define a parameter\n",
"\n",
"Parameters can be defined in HFSS to run parametric studies. In this example,\n",
"``\"patch_dim\"`` will be used to modify the size of a square conducting\n",
"patch in the center of the FSS."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "546903db",
"metadata": {},
"outputs": [],
"source": [
"hfss[\"patch_dim\"] = \"10mm\""
]
},
{
"cell_type": "markdown",
"id": "89dda9cd",
"metadata": {},
"source": [
"The parameter is assigned to the HFSS design as shown here.\n",
"
"
]
},
{
"cell_type": "markdown",
"id": "11af07ca",
"metadata": {},
"source": [
"## Model Preparation\n",
"\n",
"### Define the unit cell\n",
"\n",
"The FSS unit cell will be defined from a 3D component.\n",
"The 3D component is downloaded from the \n",
"[example data repository](https://github.com/ansys/example-data/tree/main/pyaedt) \n",
"and inserted into the HFSS design."
]
},
{
"cell_type": "markdown",
"id": "122f0a45",
"metadata": {},
"source": [
"1. Download the component."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "940a6fa6",
"metadata": {},
"outputs": [],
"source": [
"component_path = Path(download_file(\"fss_3d_component\", local_path=str(temp_path)))"
]
},
{
"cell_type": "markdown",
"id": "dd188ae2",
"metadata": {},
"source": [
"2. Get the file name of the 3D component.\n",
" > **Note:** It should be the only file in the ``component_path`` folder."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bd293aa1",
"metadata": {},
"outputs": [],
"source": [
"unit_cell_paths = [f for f in component_path.glob(\"*.a3dcomp\")]\n",
"unit_cell_path = unit_cell_paths[0]"
]
},
{
"cell_type": "markdown",
"id": "bdc44b45",
"metadata": {},
"source": [
"3. Insert the dipole as a 3D component into the HFSS model.\n",
"the HFSS model."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a05117eb",
"metadata": {},
"outputs": [],
"source": [
"comp = hfss.modeler.insert_3d_component(str(unit_cell_path))"
]
},
{
"cell_type": "markdown",
"id": "42ad96a5",
"metadata": {},
"source": [
"You can retrieve the names of all 3D components defined in the HFSS design\n",
"as shown below. In this case, only one component has been defined."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fa1b5a88",
"metadata": {},
"outputs": [],
"source": [
"component_names = hfss.modeler.user_defined_component_names"
]
},
{
"cell_type": "markdown",
"id": "985d6c48",
"metadata": {},
"source": [
"You can also get the name of each component using the\n",
"``name`` property.\n",
"\n",
"Check that only one 3D component has been placed in the HFSS design."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6745bad3",
"metadata": {},
"outputs": [],
"source": [
"same = comp.name == component_names[0]\n",
"if same and len(component_names) == 1:\n",
" msg = f\"The single 3D component in this HFSS design is named '{comp.name}'.\"\n",
"else:\n",
" msg =\"Something went wrong!\"\n",
"print(msg)"
]
},
{
"cell_type": "markdown",
"id": "175888d2",
"metadata": {},
"source": [
"### Set component parameters\n",
"The 3D component is a parameteric model. \n",
"\n",
"
\n",
"\n",
"The HFSS parameter ``patch_dim`` can be assigned to\n",
"the component parameter ``a`` to modify the size of the patch\n",
"in the unit cell.\n",
"\n",
"> **Note:** Multiple instances of a 3D component can be used having different\n",
"> parameter values for each instance. For example, consider\n",
"> creating a \"super-cell\" having multiple component instances to improve the bandwidth\n",
"> of the FSS."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1ce59f47",
"metadata": {},
"outputs": [],
"source": [
"comp.parameters[\"a\"] = \"patch_dim\""
]
},
{
"cell_type": "markdown",
"id": "88456ea2",
"metadata": {},
"source": [
"### Extend the solution domain\n",
"\n",
"Extend the solution domain in the $+z$ direction. If the\n",
"Floquet port is placed too close to the 3D structure, evanescent \n",
"fields on the Floquet port surface can\n",
"lead to erroneous results.\n",
"\n",
"The unit cell model is extended away from the \n",
"patch by ``z_extent``. The phase reference\n",
"will later be moved back to the surface of the FSS by deembedding the\n",
"port solution.\n",
"\n",
"
"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7788a4ba",
"metadata": {},
"outputs": [],
"source": [
"period_x, period_y, z_dim = hfss.modeler.get_bounding_dimension()\n",
"\n",
"z_extent = 2 * (period_x + period_y)\n",
"region = hfss.modeler.create_air_region(\n",
" z_pos=z_extent,\n",
" is_percentage=False,\n",
")\n",
"\n",
"[x_min, y_min, z_min, x_max, y_max, z_max] = region.bounding_box"
]
},
{
"cell_type": "markdown",
"id": "07b25492",
"metadata": {},
"source": [
"### Assign boundary conditions and sources\n",
"\n",
"Assign the lattice pair periodic boundary conditions."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "45152eb4",
"metadata": {},
"outputs": [],
"source": [
"boundaries = hfss.auto_assign_lattice_pairs(assignment=region.name)\n",
"\n",
"msg = \"The periodic boundary conditions are: \"\n",
"msg += str(boundaries)\n",
"print(msg)"
]
},
{
"cell_type": "markdown",
"id": "8876f398",
"metadata": {},
"source": [
"The Floquet port is asigned to the top surface of the solution domain\n",
"where the plane\n",
"wave is incident on the FSS. The following arguments\n",
"define the periodicity of the FSS.\n",
"- ``lattice_origin``\n",
"- ``lattice_a_end``\n",
"- ``lattice_b_end``\n",
"\n",
"The phase reference is deembedded to the surface of the FSS."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "49aad2e5",
"metadata": {},
"outputs": [],
"source": [
"floquet_boundary = hfss.create_floquet_port(\n",
" assignment=region.top_face_z,\n",
" lattice_origin=[0, 0, z_max],\n",
" lattice_a_end=[0, y_max, z_max],\n",
" lattice_b_end=[x_max, 0, z_max],\n",
" name=\"port_z_max\",\n",
" deembed_distance=z_extent,\n",
" )"
]
},
{
"cell_type": "markdown",
"id": "0691e9ff",
"metadata": {},
"source": [
"### Define solution setup\n",
"\n",
"The solution setup specifies details used to run\n",
"the analysis in HFSS. In this example adaptive mesh\n",
"refinement runs at 10 GHz while default values are\n",
"used for all other settings. \n",
"\n",
"The frequency sweep is used to specify the range over which scattering\n",
"parameters will be calculated."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ade5ec30",
"metadata": {},
"outputs": [],
"source": [
"setup = hfss.create_setup(\"MySetup\")\n",
"setup.props[\"Frequency\"] = \"10GHz\"\n",
"setup.props[\"MaximumPasses\"] = 10\n",
"hfss.create_linear_count_sweep(\n",
" setup=setup.name,\n",
" units=\"GHz\",\n",
" start_frequency=6,\n",
" stop_frequency=15,\n",
" num_of_freq_points=401,\n",
" name=\"sweep1\",\n",
" sweep_type=\"Interpolating\",\n",
" interpolation_tol=6,\n",
" save_fields=False,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "550d4b87",
"metadata": {},
"source": [
"### Run analysis\n",
"\n",
"Save the project and run the analysis."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f59a9105",
"metadata": {},
"outputs": [],
"source": [
"hfss.save_project()\n",
"hfss.analyze()"
]
},
{
"cell_type": "markdown",
"id": "44c74182",
"metadata": {},
"source": [
"## Postprocess\n",
"\n",
"The syntax used to plot network parameters (S-, Y-, Z-) can be complicated. The\n",
"method ``get_traces_for_plot()`` is helpful to retrieve the names of valid\n",
"traces to use for ploting.\n",
"\n",
"We'll plot imaginary impedance, $ \\Im (Z_{i,j}) $ \n",
"where $ i $, and $ j $ indices correspond to the two\n",
"linear polarization states."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cf600d66",
"metadata": {},
"outputs": [],
"source": [
"plot_data = hfss.get_traces_for_plot(category=\"im(Z\")\n",
"msg = \"The imaginary wave impedance can be displayed using \"\n",
"msg += \"the traces\\n\"\n",
"msg += \"\".join([\"--> \" + name + \"\\n\" for name in plot_data])\n",
"print(msg)"
]
},
{
"cell_type": "markdown",
"id": "2b5513ad",
"metadata": {},
"source": [
"The Floquet port was automatically named \"port_z_max\".\n",
"Due to symmetry, only the first two parameters are unique.\n",
"\n",
"### Generate a report in HFSS"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1ea553c6",
"metadata": {},
"outputs": [],
"source": [
"report = hfss.post.create_report(plot_data[0:2])"
]
},
{
"cell_type": "markdown",
"id": "1e98b203",
"metadata": {},
"source": [
"### Retrieve data for postprocessing in Matplotlib\n",
"\n",
"The method ``get_solution_data()`` retrieves data from the report in HFSS \n",
"and makes it available for postprocessing with Matplotlib. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "85ee48db",
"metadata": {},
"outputs": [],
"source": [
"solution = report.get_solution_data()\n",
"plt = solution.plot(solution.expressions)"
]
},
{
"cell_type": "markdown",
"id": "676d11f5",
"metadata": {},
"source": [
"## Release AEDT"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "12eebea8",
"metadata": {},
"outputs": [],
"source": [
"hfss.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": "89521fbc",
"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 removes\n",
"all temporary files, including the project folder."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "40b7d557",
"metadata": {},
"outputs": [],
"source": [
"temp_folder.cleanup()"
]
}
],
"metadata": {
"jupytext": {
"cell_metadata_filter": "-all",
"main_language": "python",
"notebook_metadata_filter": "-all"
}
},
"nbformat": 4,
"nbformat_minor": 5
}