Download this example

Download this example as a Jupyter Notebook or as a Python script.


Doppler setup#

This example shows how to use PyAEDT to create a multipart scenario in HFSS SBR+ and set up a doppler analysis.

Keywords: HFSS, SBR+, doppler.

Perform imports and define constants#

Perform required imports.

[1]:
import os
import tempfile
import time

import ansys.aedt.core
from ansys.aedt.core.examples.downloads import download_multiparts
from ansys.aedt.core.examples.downloads import download_file
from ansys.aedt.core.examples.downloads import unzip

Define constants.

[2]:
AEDT_VERSION = "2025.2"
NUM_CORES = 4
NG_MODE = False  # Open AEDT UI when it is launched.

Create temporary directory#

Create a temporary directory where downloaded data or dumped data can be stored. If you’d like to retrieve the project data for subsequent use, the temporary folder name is given by temp_folder.name.

[3]:
temp_folder = tempfile.TemporaryDirectory(suffix=".ansys")

Download 3D component#

Download the 3D component that is needed to run the example.

[4]:
library_path = download_multiparts(
    local_path=temp_folder.name
)
C:\Users\ansys\AppData\Local\Temp\tmp3wnf_czo.ansys\multiparts
[5]:
zip_file = download_file(
    "frtm",
    name="doppler_sbr.results.zip",
    local_path=temp_folder.name
)
[6]:
results = os.path.join(temp_folder.name, "doppler_sbr.results")
[7]:
unzip(zip_file, results)
C:\Users\ansys\AppData\Local\Temp\tmp3wnf_czo.ansys\doppler_sbr.results

Launch HFSS and open project#

Launch HFSS and open the project.

[8]:
project_name = os.path.join(temp_folder.name, "doppler.aedt")
app = ansys.aedt.core.Hfss(
    version=AEDT_VERSION,
    solution_type="SBR+",
    new_desktop=True,
    project=project_name,
    close_on_exit=True,
    non_graphical=NG_MODE,
)
PyAEDT INFO: Python version 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)].
PyAEDT INFO: PyAEDT version 0.26.dev0.
PyAEDT INFO: Initializing new Desktop session.
PyAEDT INFO: AEDT version 2025.2.
PyAEDT INFO: New AEDT session is starting on gRPC port 61699.
PyAEDT INFO: Starting new AEDT gRPC session on port 61699.
PyAEDT INFO: Launching AEDT server with gRPC transport mode: wnua
PyAEDT INFO: Electronics Desktop started on gRPC port 61699 after 11.3 seconds.
PyAEDT INFO: AEDT installation Path C:\Program Files\ANSYS Inc\v252\AnsysEM
PyAEDT INFO: Connected to AEDT gRPC session on port 61699.
PyAEDT WARNING: Service Pack is not detected. PyAEDT is currently connecting in Insecure Mode.
PyAEDT WARNING: Please download and install latest Service Pack to use connect to AEDT in Secure Mode.
PyAEDT INFO: Project doppler has been created.
PyAEDT INFO: No design is present. Inserting a new design.
PyAEDT INFO: Added design 'HFSS_L8Y' of type HFSS.
PyAEDT INFO: AEDT objects correctly read

Creation of the “actors” in the scene is comprised of many editing steps. Disabling the autosave option helps avoid delays that occur while the project is being saved.

[9]:
app.autosave_disable()
[9]:
True

Save project and rename design#

Save the project to the temporary folder and rename the design.

[10]:
design = "doppler_sbr"
app.rename_design(design)
app.save_project()
PyAEDT INFO: Project doppler Saved correctly
[10]:
True

Set up library paths#

Specify the location of 3D components used to create the scene.

[11]:
actor_lib = os.path.join(library_path, "actor_library")
env_lib = os.path.join(library_path, "environment_library")
radar_lib = os.path.join(library_path, "radar_modules")
env_folder = os.path.join(env_lib, "road1")
person_folder = os.path.join(actor_lib, "person3")
car_folder = os.path.join(actor_lib, "vehicle1")
bike_folder = os.path.join(actor_lib, "bike1")
bird_folder = os.path.join(actor_lib, "bird1")

Define environment#

Define the background environment.

[12]:
road1 = app.modeler.add_environment(input_dir=env_folder, name="Bari")
prim = app.modeler
PyAEDT INFO: Modeler class has been initialized! Elapsed time: 0m 0sec
PyAEDT INFO: Parsing C:\Users\ansys\AppData\Local\Temp\tmp3wnf_czo.ansys\doppler.aedt.
PyAEDT INFO: File C:\Users\ansys\AppData\Local\Temp\tmp3wnf_czo.ansys\doppler.aedt correctly loaded. Elapsed time: 0m 0sec
PyAEDT INFO: aedt file load time 0.01594853401184082

Place actors#

Place actors in the environment. This code places persons, birds, bikes, and cars in the environment.

[13]:
person1 = app.modeler.add_person(
    input_dir=person_folder,
    speed=1.0,
    global_offset=[25, 1.5, 0],
    yaw=180,
    name="Massimo",
)
person2 = app.modeler.add_person(
    input_dir=person_folder,
    speed=1.0,
    global_offset=[25, 2.5, 0],
    yaw=180,
    name="Devin",
)
car1 = app.modeler.add_vehicle(
    input_dir=car_folder, speed=8.7, global_offset=[3, -2.5, 0], name="LuxuryCar"
)
bike1 = app.modeler.add_vehicle(
    input_dir=bike_folder,
    speed=2.1,
    global_offset=[24, 3.6, 0],
    yaw=180,
    name="Alberto_in_bike",
)
bird1 = app.modeler.add_bird(
    input_dir=bird_folder,
    speed=1.0,
    global_offset=[19, 4, 3],
    yaw=120,
    pitch=-5,
    flapping_rate=30,
    name="Pigeon",
)
bird2 = app.modeler.add_bird(
    input_dir=bird_folder,
    speed=1.0,
    global_offset=[6, 2, 3],
    yaw=-60,
    pitch=10,
    name="Eagle",
)
PyAEDT INFO: Adding person: Massimo_0
PyAEDT INFO: Adding person: Devin_1
PyAEDT INFO: Adding vehicle: LuxuryCar_0
PyAEDT INFO: Adding vehicle: Alberto_in_bike_0
PyAEDT INFO: Adding Vehicle: Pigeon_0
PyAEDT INFO: Adding Vehicle: Eagle_1

Place radar#

Place radar on the car. The radar is created relative to the car’s coordinate system.

[14]:
radar1 = app.create_sbr_radar_from_json(
    radar_file=radar_lib,
    name="Example_1Tx_1Rx",
    offset=[2.57, 0, 0.54],
    use_relative_cs=True,
    relative_cs_name=car1.cs_name,
)
PyAEDT INFO: Adding radar module:  Example_1Tx_1Rx_0
PyAEDT INFO: Native component Parametric Beam Example_1Tx_1Rx_0_tx1 has been correctly created.
PyAEDT INFO: Native component Parametric Beam Example_1Tx_1Rx_0_rx1 has been correctly created.
PyAEDT INFO: Boundary SBRTxRxSettings SBRTxRxSettings has been created.
PyAEDT INFO: Group Created:  Example_1Tx_1Rx_0

Create setup#

Create setup and validate it. The create_sbr_pulse_doppler_setup() method creates a setup and a parametric sweep on the time variable with a duration of two seconds. The step is computed automatically from CPI.

[15]:
setup, sweep = app.create_sbr_pulse_doppler_setup(sweep_time_duration=2, velocity_resolution=0.05)
app.set_sbr_current_sources_options()
app.validate_simple()
PyAEDT WARNING: Field Observation Domain not defined
PyAEDT INFO: SBR+ current source options correctly applied.
[15]:
True

Solve and release AEDT#

Solve and release AEDT. To solve, uncomment the app.analyze_setup command to activate the simulation.

[16]:
# app.analyze_setup(sweep.name)

Doppler post-processing#

Once the design is solved, you can get the raw data inside the .aedtresults directory. The format of this data is called FRTM. PyAEDT offers sophisticated tools for FRTM post-processing FRTM

[17]:
from ansys.aedt.core.visualization.advanced.frtm_visualization import get_results_files
from ansys.aedt.core.visualization.advanced.frtm_visualization import FRTMPlotter
from ansys.aedt.core.visualization.advanced.frtm_visualization import FRTMData

Load FRTM files#

You can load all the FRTM files inside a directory or you could load one single file.

[18]:
doppler_data_frames = {}
frames_dict = get_results_files(results)
[19]:
for frame, data_frame in frames_dict.items():
    doppler_data = FRTMData(data_frame)
    doppler_data_frames[frame] = doppler_data

FRTM plotter#

You can perform multiple post-processing operations like range-doppler or direction of arrival.

[20]:
frtm_plotter = FRTMPlotter(doppler_data_frames)
frame_number = frtm_plotter.frames[0]
frtm_plotter.plot_range_doppler(frame=frame_number)
frtm_plotter.plot_range_angle_map(frame=frame_number, polar=True)
[20]:
Class: ansys.aedt.core.visualization.plot.matplotlib.ReportPlotter
Error in callback <function _draw_all_if_interactive at 0x0000027199138DC0> (for post_execute), with arguments args (),kwargs {}:
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\pyplot.py:278, in _draw_all_if_interactive()
    276 def _draw_all_if_interactive() -> None:
    277     if matplotlib.is_interactive():
--> 278         draw_all()

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_pylab_helpers.py:131, in Gcf.draw_all(cls, force)
    129 for manager in cls.get_all_fig_managers():
    130     if force or manager.canvas.figure.stale:
--> 131         manager.canvas.draw_idle()

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\backend_bases.py:1893, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
   1891 if not self._is_idle_drawing:
   1892     with self._idle_draw_cntx():
-> 1893         self.draw(*args, **kwargs)

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\backends\backend_agg.py:382, in FigureCanvasAgg.draw(self)
    379 # Acquire a lock on the shared font cache.
    380 with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
    381       else nullcontext()):
--> 382     self.figure.draw(self.renderer)
    383     # A GUI class may be need to update a window using this draw, so
    384     # don't forget to call the superclass.
    385     super().draw()

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\artist.py:94, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     92 @wraps(draw)
     93 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 94     result = draw(artist, renderer, *args, **kwargs)
     95     if renderer._rasterizing:
     96         renderer.stop_rasterizing()

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     68     if artist.get_agg_filter() is not None:
     69         renderer.start_filter()
---> 71     return draw(artist, renderer)
     72 finally:
     73     if artist.get_agg_filter() is not None:

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\figure.py:3251, in Figure.draw(self, renderer)
   3249 if self.axes and self.get_layout_engine() is not None:
   3250     try:
-> 3251         self.get_layout_engine().execute(self)
   3252     except ValueError:
   3253         pass

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\layout_engine.py:278, in ConstrainedLayoutEngine.execute(self, fig)
    275 w_pad = self._params['w_pad'] / width
    276 h_pad = self._params['h_pad'] / height
--> 278 return do_constrained_layout(fig, w_pad=w_pad, h_pad=h_pad,
    279                              wspace=self._params['wspace'],
    280                              hspace=self._params['hspace'],
    281                              rect=self._params['rect'],
    282                              compress=self._compress)

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_constrained_layout.py:101, in do_constrained_layout(fig, h_pad, w_pad, hspace, wspace, rect, compress)
     99 renderer = fig._get_renderer()
    100 # make layoutgrid tree...
--> 101 layoutgrids = make_layoutgrids(fig, None, rect=rect)
    102 if not layoutgrids['hasgrids']:
    103     _api.warn_external('There are no gridspecs with layoutgrids. '
    104                        'Possibly did not call parent GridSpec with the'
    105                        ' "figure" keyword')

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_constrained_layout.py:196, in make_layoutgrids(fig, layoutgrids, rect)
    194     gs = ax.get_gridspec()
    195     if gs is not None:
--> 196         layoutgrids = make_layoutgrids_gs(layoutgrids, gs)
    198 return layoutgrids

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_constrained_layout.py:238, in make_layoutgrids_gs(layoutgrids, gs)
    232     if rep not in layoutgrids:
    233         layoutgrids[rep] = mlayoutgrid.LayoutGrid(
    234             parent=subspeclb,
    235             name='top',
    236             nrows=1, ncols=1,
    237             parent_pos=(subplot_spec.rowspan, subplot_spec.colspan))
--> 238     layoutgrids[gs] = mlayoutgrid.LayoutGrid(
    239             parent=layoutgrids[rep],
    240             name='gridspec',
    241             nrows=gs._nrows, ncols=gs._ncols,
    242             width_ratios=gs.get_width_ratios(),
    243             height_ratios=gs.get_height_ratios())
    244 return layoutgrids

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_layoutgrid.py:100, in LayoutGrid.__init__(self, parent, parent_pos, parent_inner, name, ncols, nrows, h_pad, w_pad, width_ratios, height_ratios)
     97 # set these margins to zero by default. They will be edited as
     98 # children are filled.
     99 self.reset_margins()
--> 100 self.add_constraints(parent)
    102 self.h_pad = h_pad
    103 self.w_pad = w_pad

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_layoutgrid.py:137, in LayoutGrid.add_constraints(self, parent)
    134 self.parent_constraints(parent)
    135 # define relative widths of the grid cells to each other
    136 # and stack horizontally and vertically.
--> 137 self.grid_constraints()

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_layoutgrid.py:234, in LayoutGrid.grid_constraints(self)
    231 h = self.tops[0] - self.margins['top'][0] - self.margins['topcb'][0]
    232 h = (h - self.bottoms[0] - self.margins['bottom'][0] -
    233      self.margins['bottomcb'][0])
--> 234 h0 = h / self.height_ratios[0]
    235 # from top to bottom:
    236 for i in range(1, self.nrows):

ZeroDivisionError: float division by zero
../../../../_images/examples_high_frequency_antenna_large_scenarios_doppler_36_3.png
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\IPython\core\formatters.py:343, in BaseFormatter.__call__(self, obj)
    341     pass
    342 else:
--> 343     return printer(obj)
    344 # Finally look for special method names
    345 method = get_real_method(obj, self.print_method)

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\IPython\core\pylabtools.py:170, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    167     from matplotlib.backend_bases import FigureCanvasBase
    168     FigureCanvasBase(fig)
--> 170 fig.canvas.print_figure(bytes_io, **kw)
    171 data = bytes_io.getvalue()
    172 if fmt == 'svg':

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\backend_bases.py:2157, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2154     # we do this instead of `self.figure.draw_without_rendering`
   2155     # so that we can inject the orientation
   2156     with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2157         self.figure.draw(renderer)
   2158 if bbox_inches:
   2159     if bbox_inches == "tight":

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\artist.py:94, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     92 @wraps(draw)
     93 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 94     result = draw(artist, renderer, *args, **kwargs)
     95     if renderer._rasterizing:
     96         renderer.stop_rasterizing()

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     68     if artist.get_agg_filter() is not None:
     69         renderer.start_filter()
---> 71     return draw(artist, renderer)
     72 finally:
     73     if artist.get_agg_filter() is not None:

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\figure.py:3251, in Figure.draw(self, renderer)
   3249 if self.axes and self.get_layout_engine() is not None:
   3250     try:
-> 3251         self.get_layout_engine().execute(self)
   3252     except ValueError:
   3253         pass

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\layout_engine.py:278, in ConstrainedLayoutEngine.execute(self, fig)
    275 w_pad = self._params['w_pad'] / width
    276 h_pad = self._params['h_pad'] / height
--> 278 return do_constrained_layout(fig, w_pad=w_pad, h_pad=h_pad,
    279                              wspace=self._params['wspace'],
    280                              hspace=self._params['hspace'],
    281                              rect=self._params['rect'],
    282                              compress=self._compress)

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_constrained_layout.py:101, in do_constrained_layout(fig, h_pad, w_pad, hspace, wspace, rect, compress)
     99 renderer = fig._get_renderer()
    100 # make layoutgrid tree...
--> 101 layoutgrids = make_layoutgrids(fig, None, rect=rect)
    102 if not layoutgrids['hasgrids']:
    103     _api.warn_external('There are no gridspecs with layoutgrids. '
    104                        'Possibly did not call parent GridSpec with the'
    105                        ' "figure" keyword')

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_constrained_layout.py:196, in make_layoutgrids(fig, layoutgrids, rect)
    194     gs = ax.get_gridspec()
    195     if gs is not None:
--> 196         layoutgrids = make_layoutgrids_gs(layoutgrids, gs)
    198 return layoutgrids

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_constrained_layout.py:238, in make_layoutgrids_gs(layoutgrids, gs)
    232     if rep not in layoutgrids:
    233         layoutgrids[rep] = mlayoutgrid.LayoutGrid(
    234             parent=subspeclb,
    235             name='top',
    236             nrows=1, ncols=1,
    237             parent_pos=(subplot_spec.rowspan, subplot_spec.colspan))
--> 238     layoutgrids[gs] = mlayoutgrid.LayoutGrid(
    239             parent=layoutgrids[rep],
    240             name='gridspec',
    241             nrows=gs._nrows, ncols=gs._ncols,
    242             width_ratios=gs.get_width_ratios(),
    243             height_ratios=gs.get_height_ratios())
    244 return layoutgrids

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_layoutgrid.py:100, in LayoutGrid.__init__(self, parent, parent_pos, parent_inner, name, ncols, nrows, h_pad, w_pad, width_ratios, height_ratios)
     97 # set these margins to zero by default. They will be edited as
     98 # children are filled.
     99 self.reset_margins()
--> 100 self.add_constraints(parent)
    102 self.h_pad = h_pad
    103 self.w_pad = w_pad

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_layoutgrid.py:137, in LayoutGrid.add_constraints(self, parent)
    134 self.parent_constraints(parent)
    135 # define relative widths of the grid cells to each other
    136 # and stack horizontally and vertically.
--> 137 self.grid_constraints()

File C:\actions-runner\_work\pyaedt-examples\pyaedt-examples\.venv\lib\site-packages\matplotlib\_layoutgrid.py:234, in LayoutGrid.grid_constraints(self)
    231 h = self.tops[0] - self.margins['top'][0] - self.margins['topcb'][0]
    232 h = (h - self.bottoms[0] - self.margins['bottom'][0] -
    233      self.margins['bottomcb'][0])
--> 234 h0 = h / self.height_ratios[0]
    235 # from top to bottom:
    236 for i in range(1, self.nrows):

ZeroDivisionError: float division by zero
<Figure size 1200x800 with 3 Axes>

Release AEDT#

Release AEDT and close the example.

[21]:
app.save_project()
app.release_desktop()
# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.
time.sleep(3)
PyAEDT INFO: Project doppler Saved correctly
PyAEDT INFO: Desktop has been released and closed.

Clean up#

All project files are saved in the folder temp_folder.name. If you’ve run this example as a Jupyter notebook, you can retrieve those project files. The following cell removes all temporary files, including the project folder.

[22]:
temp_folder.cleanup()

Download this example

Download this example as a Jupyter Notebook or as a Python script.