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
---------------------------------------------------------------------------
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.