{ "cells": [ { "cell_type": "markdown", "id": "8025c94b", "metadata": {}, "source": [ "# Compute receiver protection levels\n", "\n", "This example shows how to open an AEDT project with\n", "an EMIT design and analyze the results to determine if the received\n", "power at the input to each receiver exceeds the specified protection\n", "levels.\n", "\n", "Keywords: **EMIT**, **protection levels**." ] }, { "cell_type": "markdown", "id": "a7e9884c", "metadata": {}, "source": [ "## Perform imports and define constants\n" ] }, { "cell_type": "code", "execution_count": null, "id": "7d24834e", "metadata": {}, "outputs": [], "source": [ "import os\n", "import sys\n", "import tempfile\n", "import time" ] }, { "cell_type": "code", "execution_count": null, "id": "8006a662", "metadata": {}, "outputs": [], "source": [ "import plotly.graph_objects as go\n", "from ansys.aedt.core import Emit" ] }, { "cell_type": "markdown", "id": "dde5c286", "metadata": {}, "source": [ "from ansys.aedt.core.emit_core.emit_constants import \\\n", " InterfererType # noqa: F401" ] }, { "cell_type": "markdown", "id": "53ee96d7", "metadata": {}, "source": [ "Define constants." ] }, { "cell_type": "code", "execution_count": null, "id": "fe27eb2b", "metadata": {}, "outputs": [], "source": [ "AEDT_VERSION = \"2024.2\"\n", "NG_MODE = False # Open AEDT UI when it is launched." ] }, { "cell_type": "markdown", "id": "e0a2c5d2", "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": "97145d06", "metadata": {}, "outputs": [], "source": [ "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" ] }, { "cell_type": "markdown", "id": "0ee43182", "metadata": {}, "source": [ "## Launch AEDT with EMIT\n", "\n", "Launch AEDT with EMIT. The ``Desktop`` class initializes AEDT and starts it\n", "on the specified version and in the specified graphical mode.\n", "\n", "Check that the correct version of EMIT is installed." ] }, { "cell_type": "code", "execution_count": null, "id": "f830f998", "metadata": {}, "outputs": [], "source": [ "if AEDT_VERSION <= \"2023.1\":\n", " print(\"Warning: This example requires AEDT 2023.2 or later.\")\n", " sys.exit()" ] }, { "cell_type": "code", "execution_count": null, "id": "d355cf6d", "metadata": {}, "outputs": [], "source": [ "project_name = os.path.join(temp_folder.name, \"emit.aedt\")" ] }, { "cell_type": "code", "execution_count": null, "id": "f746b550", "metadata": {}, "outputs": [], "source": [ "emitapp = Emit(\n", " non_graphical=NG_MODE, new_desktop=True, project=project_name, version=AEDT_VERSION\n", ")" ] }, { "cell_type": "markdown", "id": "9f92733f", "metadata": {}, "source": [ "## Specify protection levels\n", "\n", "The protection levels are specified in dBm.\n", "If the damage threshold is exceeded, permanent damage to the receiver front\n", "end may occur.\n", "Exceeding the overload threshold severely densensitizes the receiver.\n", "Exceeding the intermod threshold can drive the victim receiver into non-linear\n", "operation, where it operates as a mixer.\n", "Exceeding the desense threshold reduces the signal-to-noise ratio and can\n", "reduce the maximum range, maximum bandwidth, and/or the overall link quality." ] }, { "cell_type": "code", "execution_count": null, "id": "0ed0ccf4", "metadata": {}, "outputs": [], "source": [ "header_color = \"grey\"\n", "damage_threshold = 30\n", "overload_threshold = -4\n", "intermod_threshold = -30\n", "desense_threshold = -104\n", "\n", "protection_levels = [\n", " damage_threshold,\n", " overload_threshold,\n", " intermod_threshold,\n", " desense_threshold,\n", "]" ] }, { "cell_type": "markdown", "id": "ac1f6af8", "metadata": {}, "source": [ "## Create and connect EMIT components\n", "\n", "Set up the scenario with radios connected to antennas." ] }, { "cell_type": "code", "execution_count": null, "id": "3d948c16", "metadata": {}, "outputs": [], "source": [ "bluetooth, blue_ant = emitapp.modeler.components.create_radio_antenna(\n", " \"Bluetooth Low Energy (LE)\", \"Bluetooth\"\n", ")\n", "gps, gps_ant = emitapp.modeler.components.create_radio_antenna(\"GPS Receiver\", \"GPS\")\n", "wifi, wifi_ant = emitapp.modeler.components.create_radio_antenna(\n", " \"WiFi - 802.11-2012\", \"WiFi\"\n", ")" ] }, { "cell_type": "markdown", "id": "b12ead01", "metadata": {}, "source": [ "## Configure the radios\n", "\n", "Enable the HR-DSSS bands for the Wi-Fi radio and set the power level\n", "for all transmit bands to -20 dBm." ] }, { "cell_type": "code", "execution_count": null, "id": "3a387ea7", "metadata": {}, "outputs": [], "source": [ "bands = wifi.bands()\n", "for band in bands:\n", " if \"HR-DSSS\" in band.node_name:\n", " if \"Ch 1-13\" in band.node_name:\n", " band.enabled = True\n", " band.set_band_power_level(-20)\n", "\n", "# Reduce the bluetooth transmit power\n", "bands = bluetooth.bands()\n", "for band in bands:\n", " band.set_band_power_level(-20)\n", "\n", "\n", "def get_radio_node(radio_name):\n", " \"\"\"Get the radio node that matches the\n", " given radio name.\n", "\n", " Arguments:\n", " radio_name: String name of the radio.\n", "\n", " Returns: Instance of the radio.\n", " \"\"\"\n", " if gps.name == radio_name:\n", " radio = gps\n", " elif bluetooth.name == radio_name:\n", " radio = bluetooth\n", " else:\n", " radio = wifi\n", " return radio\n", "\n", "\n", "bands = gps.bands()\n", "for band in bands:\n", " for child in band.children:\n", " if \"L2 P(Y)\" in band.node_name:\n", " band.enabled = True\n", " else:\n", " band.enabled = False" ] }, { "cell_type": "markdown", "id": "954b059a", "metadata": {}, "source": [ "## Load the results set\n", "\n", "Create a results revision and load it for analysis." ] }, { "cell_type": "code", "execution_count": null, "id": "f3db6887", "metadata": { "lines_to_next_cell": 2 }, "outputs": [], "source": [ "rev = emitapp.results.analyze()" ] }, { "cell_type": "markdown", "id": "5e609daf", "metadata": { "lines_to_next_cell": 2 }, "source": [ "## Create a legend\n", "\n", "Create a legend, defining the thresholds and colors used to display the results of\n", "the protection level analysis." ] }, { "cell_type": "code", "execution_count": null, "id": "084b4294", "metadata": { "lines_to_next_cell": 2 }, "outputs": [], "source": [ "def create_legend_table():\n", " \"\"\"Create a table showing the defined protection levels.\"\"\"\n", " protectionLevels = [\n", " \">{} dBm\".format(damage_threshold),\n", " \">{} dBm\".format(overload_threshold),\n", " \">{} dBm\".format(intermod_threshold),\n", " \">{} dBm\".format(desense_threshold),\n", " ]\n", " fig = go.Figure(\n", " data=[\n", " go.Table(\n", " header=dict(\n", " values=[\"Interference\", \"Power Level Threshold\"],\n", " line_color=\"darkslategray\",\n", " fill_color=header_color,\n", " align=[\"left\", \"center\"],\n", " font=dict(color=\"white\", size=16),\n", " ),\n", " cells=dict(\n", " values=[\n", " [\"Damage\", \"Overload\", \"Intermodulation\", \"Clear\"],\n", " protectionLevels,\n", " ],\n", " line_color=\"darkslategray\",\n", " fill_color=[\"white\", [\"red\", \"orange\", \"yellow\", \"green\"]],\n", " align=[\"left\", \"center\"],\n", " font=dict(color=[\"darkslategray\", \"black\"], size=15),\n", " ),\n", " )\n", " ]\n", " )\n", " fig.update_layout(\n", " title=dict(\n", " text=\"Protection Levels (dBm)\",\n", " font=dict(color=\"darkslategray\", size=20),\n", " x=0.5,\n", " ),\n", " width=600,\n", " )\n", " fig.show()" ] }, { "cell_type": "markdown", "id": "886cde25", "metadata": { "lines_to_next_cell": 2 }, "source": [ "## Create a scenario matrix view\n", "\n", "Create a scenario matrix view with the transmitters defined across the top\n", "and receivers down the left-most column. The power at the input to each\n", "receiver is shown in each cell of the matrix and color-coded based on the\n", "protection level thresholds defined." ] }, { "cell_type": "code", "execution_count": null, "id": "56a2ceeb", "metadata": {}, "outputs": [], "source": [ "def create_scenario_view(emis, colors, tx_radios, rx_radios):\n", " \"\"\"Create a scenario matrix-like table with the higher received\n", " power for each Tx-Rx radio combination. The colors\n", " used for the scenario matrix view are based on the highest\n", " protection level that the received power exceeds.\"\"\"\n", " fig = go.Figure(\n", " data=[\n", " go.Table(\n", " header=dict(\n", " values=[\n", " \"Tx/Rx\",\n", " \"{}\".format(tx_radios[0]),\n", " \"{}\".format(tx_radios[1]),\n", " ],\n", " line_color=\"darkslategray\",\n", " fill_color=header_color,\n", " align=[\"left\", \"center\"],\n", " font=dict(color=\"white\", size=16),\n", " ),\n", " cells=dict(\n", " values=[rx_radios, emis[0], emis[1]],\n", " line_color=\"darkslategray\",\n", " fill_color=[\"white\", colors[0], colors[1]],\n", " align=[\"left\", \"center\"],\n", " font=dict(color=[\"darkslategray\", \"black\"], size=15),\n", " ),\n", " )\n", " ]\n", " )\n", " fig.update_layout(\n", " title=dict(\n", " text=\"Protection Levels (dBm)\",\n", " font=dict(color=\"darkslategray\", size=20),\n", " x=0.5,\n", " ),\n", " width=600,\n", " )\n", " fig.show()" ] }, { "cell_type": "markdown", "id": "3f905ebf", "metadata": {}, "source": [ "## Get all the radios in the project\n", "\n", "Get lists of all transmitters and receivers in the project." ] }, { "cell_type": "markdown", "id": "7f08d667", "metadata": {}, "source": [ "> **Note:** You can uncomment the following code.\n", "\n", "rev = emitapp.results.current_revision\n", "rx_radios = rev.get_receiver_names()\n", "tx_radios = rev.get_interferer_names(InterfererType.TRANSMITTERS)\n", "domain = emitapp.results.interaction_domain()" ] }, { "cell_type": "markdown", "id": "5f242417", "metadata": {}, "source": [ "## Classify the results\n", "\n", "Iterate over all the transmitters and receivers and compute the power\n", "at the input to each receiver due to each of the transmitters. Computes\n", "which protection levels are exceeded by these power levels, if any." ] }, { "cell_type": "markdown", "id": "d73d067a", "metadata": {}, "source": [ "> **Note:** Your ability to uncomment the following code depends on whether you uncommented the earlier code.\n", "\n", "power_matrix = []\n", "all_colors = []" ] }, { "cell_type": "markdown", "id": "a3cde152", "metadata": {}, "source": [ "all_colors, power_matrix = rev.protection_level_classification(\n", " domain, global_levels=protection_levels\n", ")" ] }, { "cell_type": "markdown", "id": "8fd88d3a", "metadata": {}, "source": [ "## Create a scenario matrix-like view for the protection levels\n", "create_scenario_view(power_matrix, all_colors, tx_radios, rx_radios)" ] }, { "cell_type": "markdown", "id": "ada3f594", "metadata": {}, "source": [ "## Create a legend for the protection levels\n", "create_legend_table()" ] }, { "cell_type": "markdown", "id": "9d0dd792", "metadata": {}, "source": [ "## Release AEDT\n", "\n", "Release AEDT and close the example." ] }, { "cell_type": "code", "execution_count": null, "id": "45dbc5ff", "metadata": {}, "outputs": [], "source": [ "emitapp.save_project()\n", "emitapp.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": "f3e8ddca", "metadata": {}, "source": [ "## Clean up\n", "\n", "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", "can retrieve those project files. The following cell removes all temporary files, including the project folder." ] }, { "cell_type": "code", "execution_count": null, "id": "6b640c47", "metadata": {}, "outputs": [], "source": [ "temp_folder.cleanup()" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }