Additional Information#
Known limitations#
EM engine#
The key parameters for the EM engine are:
the number of rays emitted at every RU
the maximum number of scattering events for each ray
the number of frequency samples for the wideband CFR
the number of UEs
the number of antennas for the antenna panels in use.
These parameters are directly linked to the consumption of GPU RAM during the operation of the EM engine. The corresponding limits are as per the following table.
Parameter |
Maximum value |
---|---|
Number of rays emitted at every RU |
1,000,000 |
Maximum number of scattering events per ray |
5 |
Maximum number of scattering events per ray with transmission included |
10 |
Number of frequency samples (FFT size) for the wideband CFR |
4096 |
Number of UEs |
10,000 |
Number of antenna elements per RU panel |
64 |
Number of antenna elements per UE panel |
8 |
For extensive simulations, if an error occurs in the logs indicating that the simulation cannot succeed, it is suggested to lower the number of emitted rays, reduce the number of scattering events, make the population of UEs sparser, or turn off diffusion.
Additionally,
across the selected maximum number of scattering events, diffraction can only occur once per ray
only direct diffuse scattering (diffuse vertex is in line-of-sight to both the RU and the UE) is currently possible
in a ray with transmissions, only specular reflections can occur
only the following antenna models are supported directly:
isotropic,
polarized isotropic,
infinitesimal dipole,
halfwave dipole,
microstrip patch,
\(\epsilon_r=4.8\)
\(L = \dfrac{\lambda}{2 \sqrt{\epsilon_r}}\) (\(\lambda\) being the wavelength of the carrier)
\(W = 1.5 L\)
3GPP-type for radio unit element [1],
all others need to be added through custom user input with files, either at antenna element level or panel level.
Active Element Patterns can currently only be calculated for halfwave dipoles.
RAN simulation#
For RAN simulations,
At the RU, only 64 or 4 antennas are supported. At the UE, only 4 antennas are supported.
Only a 100 MHz bandwidth with 273 PRBs is supported.
When the RU is equipped with 4 antennas, only SU-MIMO is supported.
Only 30 kHz subcarrier spacing is supported.
Beamforming is not applied when RU has 4 antennas. When RU has 64 antennas, regularized ZF beamforming is applied.
MMSE-IRC is applied indiscriminately at the receivers.
DMRS positions are fixed at symbols 2, 3, 10, and 11.
PRBs are scheduled at the PRB group level, with each PRB group containing 4 PRBs.
HARQ, if enabled,
operates on a per-slot basis, assuming perfect knowledge of control channel information and immediate retransmission at a slot after a failed transmission slot;
will allow a maximum of 4 transmissions (i.e., a new transmission, followed by three retransmissions), in the event of CRC failures. Transmissions are associated with redundancy versions (RV) in the order of 0, 2, 3, 1.
In addition to a fixed thermal noise of -174 dBm/Hz, a noise figure is added at each receiver antenna.
The SRS are scheduled exclusively on every S slot, and the S slot is dedicated solely to SRS.
For an SRS slot, all 14 symbols can be allocated for SRS transmission when the RU has four antennas. If the RU has 64 antennas, only four symbols can be allocated for SRS transmission.
MAC scheduler#
HARQ re-transmission is non-adaptive: the same scheduling solution (PRB allocation, layer and MCS selection) for the original transmissions is always reused for the HARQ re-transmissions. Further improvement is possible by employing advanced algorithms that may alter the scheduling decisions for re-transmissions and will be considered in future releases.
layer selection is suboptimal: the current layer selection algorithm has not been optimized. An improved data transmission performance can be expected by employing a layer selection algorithm tailored to the lack of beamforming. AODT will offer an optimal and beamforming-aware layer selection algorithm when beamforming is fully supported.
MCS selection: currently, the MCS selection algorithm relies on a SINR-to-MCS lookup table derived for single-layer transmissions under an AWGN channel. The SINR-to-MCS mappings in this lookup table may not be accurate for transmissions with multiple layers. This can be improved using separate SINR-to-MCS lookup tables for different numbers of layers and other channel characteristics.
Urban Mobility (experimental)#
The Urban Mobility model does not recognize manual UEs and UEs created from GPX files. Consequently, collisions between vehicles and such UEs may occur.
A spawn zone is required to enable Urban Mobility, and by extension, dynamic scattering from cars.
Due to the OSM (OpenStreetMap) import process, the road network utilized by Urban Mobility may include areas that stretch beyond the physical constraints of the spawn zone area. As a result, UE and vehicle trajectories may extend beyond the spawn zone.
If the road network obtained from the spawn zone does not support the requested number of vehicles or UEs, then a smaller number than requested may be generated. This can be alleviated by expanding the size of the spawn zone, but there is no guarantee that the desired setting can be achieved.
Due to the stochastic nature of the simulations in SUMO, vehicles with trajectories that have a duration smaller than requested will be removed. This may result in fewer vehicles than requested despite a sufficiently large spawn zone. The issue can be alleviated by regenerating the mobility or by increasing the maximum number of requested cars (currently limited to 50), which will allow SUMO to sample from a larger set of vehicular mobility trajectories.
When the simulation is run using duration and interval, instead of slots, interval cannot exceed 100ms. This is due to the presence of vehicle acceleration: without limiting interval, the movement of the cars would look jittery and unnatural.
Graphical interface: worker connection#
For large simulations (e.g., 100,000 slots or 1,000 UEs), the UI may lose connection with the EM Solver Worker during execution. This is a known issue that can cause the simulation to stop unexpectedly or restart from the beginning.
Workaround: Use headless mode for large simulations to avoid UI-Worker connection issues.
Note: This limitation is to be addressed in future releases with improved heartbeat mechanisms.
Graphical interface: parameters missing#
When opening a new map from the viewer, after working on a previous map (e.g., switching from tokyo_small.usd to kyoto_small.usd), the UI console may display
omni.kit.environment.core
errors and the Scenario parameters may not be visible.Workaround: Restart the graphical interface and reopen the map to reinstate Scenario parameters.
Database schemas#
The simulation data generated by the Aerial Omniverse Digital Twin is saved to a Clickhouse database. The following section describes the database tables and example Python scripts to access that data.
Database Tables#
1. db_info#
Field |
Type |
Comment |
---|---|---|
scene_url |
string |
Path to the scene on the Nucleus server |
scene_timestamp |
string |
Timestamp of when the scene was originally opened |
db_author |
string |
Database author, as specified in the UI Configuration tab |
db_notes |
string |
Any additional notes, as specified in the UI Configuration tab |
db_timestamp |
string |
Database timestamp, as specified in the UI Configuration tab |
db_schemas_version |
string |
The version of database schemas |
db_content |
string |
Serialized prims from the simulation for DB replay |
du_asset_path |
string |
Path to DU assets on the Nucleus server |
ru_asset_path |
string |
Path to RU assets on the Nucleus server |
ue_asset_path |
string |
Path to UE assets on the Nucleus server |
vehicle_asset_path |
string |
Path to vehicle assets on the Nucleus server |
material_asset_path |
string |
Path to material assets on the Nucleus server |
opt_in_tables |
array(string) |
List of opt-in table names |
opt_in_tables_options |
array(tuple(string, string)) |
List of opt-in table options: <table, option> |
2. time_info#
Field |
Type |
Comment |
---|---|---|
time_idx |
uint32 |
Time index of the simulation |
batch_idx |
uint32 |
Batch index of the simulation |
slot_idx |
uint32 |
Slot index of the simulation |
symbol_idx |
uint32 |
Symbol index of the simulation |
3. raypaths#
Field |
Type |
Comment |
---|---|---|
time_idx |
uint32 |
Time index of the simulation |
ru_id |
uint32 |
RU ID as defined in the UI stage widget |
ue_id |
uint32 |
UE ID as defined in the UI stage widget |
ru_ant_el |
tuple(uint32, uint32) |
Tuple <h,v> of antenna element indices for the RU antenna panel |
ue_ant_el |
tuple(uint32, uint32) |
Tuple <h,v> of antenna element indices for the UE antenna panel |
interaction_types |
array(enum) |
Type of interactions: emission = 0, reflection = 1, diffraction = 2, diffuse = 3, reception = 4, transmission = 5 |
points |
array(tuple(float32, float32, float32)) |
Stores the (x, y, z) coordinates of interaction points |
normals |
array(tuple(float32, float32, float32)) |
Stores the (x, y, z) normals at the interaction points |
ampl_re |
array(float32) |
Real parts of the raypath channel tap amplitude for four UE-RU polarization combinations* |
ampl_im |
array(float32) |
Imaginary parts of the raypath channel tap amplitude for four UE-RU polarization combinations |
prim_ids |
array(int32) |
Stores the prim ID in the USD map of the interaction points** |
object_ids |
array(int32) |
Stores the object ID in the USD map of the interaction points** |
*ampl_re[i*2 + j]
is for the UE’s \(i\)-th polarization and RU’s \(j\)-th polarization, for \(i \in \left[0, 1\right]\) and \(j \in \left[0, 1\right]\), the same as cir_ampl
in RayPath (see EM engine interface section).
** see EM_INTERACT_TYPE
in EM engine interface section for details
4. cirs#
Field |
Type |
Comment |
---|---|---|
time_idx |
uint32 |
Time index of the simulation |
ru_id |
uint32 |
RU ID as defined in the UI stage widget |
ue_id |
uint32 |
UE ID as defined in the UI stage widget |
ru_ant_el |
tuple(uint32, uint32, uint32) |
Tuple <h,v,p> of antenna element indices for the RU antenna panel |
ue_ant_el |
tuple(uint32, uint32, uint32) |
Tuple <h,v,p> of antenna element indices for the UE antenna panel |
cir_re |
array(float32) |
Real part of the channel impulse response |
cir_im |
array(float32) |
Imaginary part of the channel impulse response |
cir_delay |
array(float32) |
Propagation delay in seconds |
where, in the tuple<h,v,p>
h is the index of the element in horizontal dimension
v is the index of the element in vertical dimension
p is the index of the polarization
5. cfrs#
Field |
Type |
Comment |
---|---|---|
time_idx |
uint32 |
Time index of the simulation |
ru_id |
uint32 |
RU ID as defined in the UI stage widget |
ue_id |
uint32 |
UE ID as defined in the UI stage widget |
ru_ant_el |
tuple(uint32, uint32, uint32) |
Tuple <h,v,p> of antenna element indices for the RU antenna panel |
ue_ant_el |
tuple(uint32, uint32, uint32) |
Tuple <h,v,p> of antenna element indices for the UE antenna panel |
cfr_re |
array(float32) |
Real part of the channel frequency response |
cfr_im |
array(float32) |
Imaginary part of the channel frequency response |
where, in the tuple<h,v,p>
h is the index of the element in horizontal dimension
v is the index of the element in vertical dimension
p is the index of the polarization dimension.
6. panels#
Field |
Type |
Comment |
---|---|---|
panel_id |
uint32 |
Index of the panel |
panel_name |
string |
Name of the panel as defined in the UI stage widget |
antenna_names |
array(string) |
Name of antenna elements in the panel |
antenna_pattern_indices |
array(uint32) |
Index of the antenna elements |
frequencies |
array(float32) |
Frequencies for the radiation patterns of the antenna elements, in Hertz |
thetas |
array(float32) |
Elevation angles of the radiation pattern of the antenna elements, in radians |
phis |
array(float32) |
Azimuth angles of the radiation pattern of the antenna elements, in radians |
reference_freq |
float32 |
Center frequency of the panel |
Field |
Type |
Comment |
---|---|---|
dual_polarized |
uint8 |
Indicates if panel is dual-polarized. 1=dual polarization, 0=single polarization. |
num_loc_antenna_horz |
uint32 |
Number of columns in the planar array |
nnum_loc_antenna_vert |
uint32 |
Number of rows in the planar array |
antenna_spacing_horz |
float32 |
Horizontal spacing of the antenna elements, in cm |
antenna_spacing_vert |
float32 |
Vertical spacing of the antenna elements, in cm |
antenna_roll_angle_first_polz |
float32 |
Rotation (in radians) of the antenna element, corresponding to the first polarization |
antenna_roll_angle_second_polz |
float32 |
Rotation (in radians) of the antenna element, corresponding to the second polarization. Only used for dual-polarized elements. |
7. patterns#
Field |
Type |
Comment |
---|---|---|
pattern_id |
uint32 |
Index of the pattern |
pattern_type |
uint32 |
Type of the antenna element: isotropic = 0, infinitesimal = 1, halfwave_dipole = 2, rec_microstrip = 3, custom >= 100 |
e_theta_re |
array(array(float32)) |
Real part of the antenna radiated field along |
e_theta_im |
array(array(float32)) |
Imaginary part of the antenna radiated field along |
e_phi_re |
array(array(float32)) |
Real part of the antenna radiated field along |
e_phi_im |
array(array(float32)) |
Imaginary part of the antenna radiated field along |
8. ues#
Field |
Type |
Comment |
---|---|---|
ID |
uint32 |
UE ID as defined in the UI stage widget |
is_manual |
boolean |
Indicates if the UE was generated manually (1) or procedurally (0) |
is_manual_mobility |
boolean |
Whether or not the manual UE has waypoints explicitly added by the user |
radiated_power |
float32 |
UE’s radiated power (in Watts) |
height |
float32 |
Height of the UE in meters |
mech_tilt |
float32 |
Tilt of of UE antenna panel in degrees |
panel |
array(uint32) |
Array of antenna panel indices for this UE |
batch_indices |
array(uint32) |
Array of batch indices for this UE |
waypoint_ids |
array(array(uint32)) |
Per-batch waypoint identifiers [batch, ids] |
waypoint_points |
array(array(tuple(float32,float32,float32))) |
Per-batch waypoint positions [batch, waypoints(x, y, z)] |
waypoint_stops |
array(array(float32)) |
Per-batch waypoint stop times in seconds [batch, stops] |
Field |
Type |
Comment |
---|---|---|
waypoint_speeds |
array(array(float32)) |
Per-batch waypoint speeds in m/s [batch, speeds] |
trajectory_ids |
array(array(uint32)) |
Per-batch waypoint identifiers along UE trajectory [batch, ids] |
trajectory_points |
array(array(tuple(float32,float32,float32))) |
Per-batch points along UE trajectory [batch, points(x, y, z)] |
trajectory_stops |
array(array(float32)) |
Per-batch stop times (in seconds) along UE trajectory [batch, stops] |
trajectory_speeds |
array(array(float32)) |
Per-batch speed (in m/s) at waypoints along UE trajectory [batch, speeds] |
route_positions |
array(array(tuple(float32,float32,float32))) |
Per-batch positions along sampled route [batch, points(x, y, z)] |
route_orientations |
array(array(tuple(float32,float32,float32))) |
Per-batch UE orientations along sampled route [batch, orientations(x, y, z)] |
route_speeds |
array(array(float32)) |
Per-batch speeds (in m/s) along sampled route. [batch, speeds] |
route_times |
array(array(float32)) |
Per-batch times (in seconds) along sampled route. [batch, times] |
bler_target |
float32 |
Target BLER for the UE |
is_indoor_mobility |
boolean |
Whether the user has indoor mobility |
9. rus#
Field |
Type |
Comment |
---|---|---|
ID |
uint32 |
RU ID as defined in the UI stage widget |
subcarrier_spacing |
float32 |
Subcarrier spacing (in Hz) |
fft_size |
uint32 |
Number of frequency samples used in the wideband CFR calculation |
radiated_power |
float32 |
RU’s radiated power (in Watts) |
height |
float32 |
Height of the RU in meters |
mech_azimuth |
float32 |
Mechanical azimuth rotation angle of the RU, in degrees |
mech_tilt |
float32 |
Mechanical tilt angle of the RU, in degrees |
panel |
array(uint32) |
Array of antenna panel indices for this RU |
position |
array(float32) |
Position of the RU in the stage. The array contains 3 elements (x, y, z). |
du_id |
uint32 |
Index of the DU that this RU is associated with. |
du_manual_assign |
boolean |
Whether or not this RU is manually assgined to the DU |
10. dus#
Field |
Type |
Comment |
---|---|---|
ID |
uint32 |
DU ID as defined in the UI stage widget |
subcarrier_spacing |
float32 |
Subcarrier spacing (in Hz) |
fft_size |
uint32 |
Number of frequency samples used in the wideband CFR calculation |
num_antennas |
uint32 |
Number of antenna for the DU |
max_channel_bandwidth |
float32 |
Maximum channel bandwidth supported by the DU |
position |
array(float32) |
The (x , y, z) coordinates of the DU, in the same unit as USD map |
11. scenario#
Field |
Type |
Comment |
---|---|---|
default_ue_panel |
string |
The default panel ID assigned to UEs |
default_ru_panel |
string |
The default panel ID assigned to RUs |
num_emitted_rays_in_thousands |
int32 |
Number of emitted rays (x 1000) |
num_scene_interactions_per_ray |
int32 |
Number of interactions that a ray has with the environment. 0 = no interaction (line of sight) |
max_paths_per_ru_ue_pair |
uint32 |
Maximum number of raypaths per RU/UE |
ray_sparsity |
int32 |
Ratio of total computed rays to rays shown in the UI |
num_batches |
int32 |
Number of batches, where each batch represents a re-drop of the UE in a different position |
slots_per_batch |
int32 |
Number of slots to simulate for each batch |
symbols_per_slot |
int32 |
Number of symbols in a slot. Either 1 or 14. |
duration |
float32 |
The duration (in seconds) of the simulation |
interval |
float32 |
The sampling time (in seconds) of the simulation |
Field |
Type |
Comment |
---|---|---|
enable_wideband_cfrs |
Boolean |
True=>CFRs contain frequency points for the entire FFT size. False=>CFRs contain one frequency point at the center frequency. |
num_ues |
uint32 |
The total number of UEs in the simulation |
ue_height |
float32 |
UE height in meters |
ue_min_speed |
float32 |
Minimum UE speed in meters per second |
ue_max_speed |
float32 |
Maximum UE speed in meters per second |
is_seeded |
uint8 |
Indicates if mobility is seeded or not |
seed |
uint32 |
Seed used to define the randomness of UE batch drops and trajectories |
simulate_ran |
boolean |
Enable RAN simulations |
enable_training |
boolean |
Enable training simulations |
diffuse_type |
enum |
Diffuse type: Lambertian = 0, Directional = 1 |
rx_sphere_radius_m |
float32 |
Reception sphere radius, in meters |
percentage_indoor_ues |
float32 |
The percentage of indoor UEs in the simulation |
12. telemetry#
Field |
Type |
Comment |
---|---|---|
batch_id |
uint32 |
The batch index of the simulation |
slot_id |
unit32 |
The slot index within the batch |
link |
string |
If this telemetry result is for downlink (“DL”) or uplink (“UL”) |
ru_id |
uint32 |
RU ID |
ue_id |
uint32 |
UE ID |
startPrb |
uint32 |
Start PRB that the scheduler has assigned to this UE |
nPrb |
uint32 |
Number of PRBs that the scheduler has assigned to this UE |
mcs |
uint8 |
MCS index that the scheduler has assigned to this UE |
layers |
uint8 |
Number of layers used by this UE |
tbs |
uint32 |
Transport block (TB) size (in bytes) that was scheduled for this UE |
rv |
uint8 |
The redundancy version used for this transmission |
outcome |
uint32 |
If the transport block was successfully decoded (1) or not (0) |
scs |
float32 |
Subcarrier spacing (in Hz) |
preEqSinr |
float32 |
Pre-equalization SINR |
postEqSinr |
float32 |
Post-equalization SINR |
13. ran_config#
Field |
Type |
Comment |
---|---|---|
tdd_pattern |
string |
TDD pattern |
srs_slots |
array(uint32) |
List of slot numbers within a frame where SRS transmission occurs. |
pusch_slots |
array(uint32) |
List of slot numbers within a frame where PUSCH transmission occurs. |
dl_harq_enabled |
uint8 |
Indicates whether if DL HARQ is enabled |
ul_harq_enabled |
uint8 |
Indicates whether if UL HARQ is enabled |
beamforming_csi |
string |
The source of beamforming CSI: either “CFR” or “SRS”. |
mac_csi |
string |
The source of MAC scheduling CSI: either “CFR” or “SRS”. |
pusch_channel_estimation |
string |
The method used for PUSCH channel estimation: “MMSE” |
scheduler_mode |
string |
PRB scheduling algorithm: “PF” or “RR” |
mu_mimo_enabled |
uint8 |
Indicates whether MU-MIMO is enabled |
dl_srs_snr_thr |
float32 |
SRS SNR threshold for determining MU-MIMO feasibility in the downlink |
ul_srs_snr_thr |
float32 |
SRS SNR threshold for determining MU-MIMO feasibility in the uplink |
dl_chan_corr_thr |
float32 |
Channel correlation threshold for MU-MIMO grouping decisions in the downlink |
ul_chan_corr_thr |
float32 |
Channel correlation threshold for MU-MIMO grouping decisions in the uplink |
beamforming_enabled |
uint8 |
Indicates whether beamforming is enabled |
beamforming_scheme |
string |
Beamforming scheme: “Subcarrier level ZF beamforming”, “PRBG level ZF beamforming” or “UEG level ZF beamforming” |
srs_channel_estimation |
string |
The method used for SRS channel estimation: “MMSE” or “RKHS” |
15. world#
Reserved
16. materials#
Field |
Type |
Comment |
---|---|---|
label |
string |
Captures the material set in the UI stage |
itu_r_p2040_a |
float64 |
ITU-R P2040 ‘a’ parameter [2] |
itu_r_p2040_b |
float64 |
ITU-R P2040 ‘b’ parameter [2] |
itu_r_p2040_c |
float64 |
ITU-R P2040 ‘c’ parameter [2] |
itu_r_p2040_d |
float64 |
ITU-R P2040 ‘d’ parameter [2] |
scattering_xpd |
float64 |
Scattering cross-polarization/co-polarization power ratio |
rms_roughness |
float64 |
Root mean squared of the surface roughness |
scattering_coeff |
float64 |
Scattering coefficient |
exponent_alpha_r |
int32 |
Integer exponent parameter for the forward scattering lobe in the Directional diffuse model |
exponent_alpha_i |
int32 |
Integer exponent parameter for the barward scattering lobe in the Directional diffuse model |
lambda_r |
float64 |
Ratio between the forward scattering power and the total scattering power in the Directional diffuse model |
thickness_m |
float64 |
Thickness of the material in meters |
17. scatterers#
Field |
Type |
Comment |
---|---|---|
ID |
uint32 |
Scatterer ID as automatically assigned by Urban Mobility |
is_indoor_mobility |
boolean |
Indicates if the scatterer is indoor (1) or outdoor (0) |
batch_indices |
array(uint32) |
Array of batch indices for this scatterer |
route_positions |
array(array(tuple(float32,float32,float32))) |
Per-batch positions along sampled route [batch, points(x, y, z)] |
route_orientations |
array(array(tuple(float32,float32,float32))) |
Per-batch scatterer rotations (in degrees) along sampled route [batch, orientations(x, y, z)] |
route_speeds |
array(array(float32)) |
Per-batch speeds in m/s along sampled route. [batch, speeds] |
route_times |
array(array(float32)) |
Per-batch times (in seconds) along sampled route. [batch, times] |
Accessing the results in the database#
Some examples of how to access the database results are bundled with the source code in the examples/ directory. These scripts serve as a template, and can be extended for your own data analysis.
Example clickhouse scripts#
There are two ways to run the ClickHouse scripts - using the Jupyter notebooks or as Python scripts. Both approaches are explained below.
To run as scripts, the necessary packages are available inside the development container. Refer to the Installation section of this guide for instructions on starting the development container. Then, identify the name of the database of interest by using the clickhouse-client
or by entering the database name in the Configurations tab of the UI.
$ clickhouse-client
:) show databases
In this section, we use RU
interchangeably with tx
and UE
interchangeably with rx
. The examples assume the following database configuration:
Database Name: yoda_2024_4_15_13_4_6
hostname: localhost
1. extract_CIR_sample.py#
This script is provided to illustrate access to the cirs table in the database.
python3 extract_CIR_sample.py --hostname <hostname> --database <database_name> --sample <time_idx> --RU <tx_id> --UE <rx_id>
For example to retrieve the CIR for sample 5, for ue_0002 and ru_0001, run the folllowing command:
python3 extract_CIR_sample.py --hostname "localhost" --database "yoda_2024_4_15_13_4_6" --sample 5 --RU 1 --UE 2
The script fetches the desired CIRs and writes them to the binary file sample-cir-<time_idx>.dat. The binary file can be accessed using the pickle Python module. The pickled data structures have the following definition:
data: holds the complex amplitude of each raypath
delay: holds the associated time of arrival in seconds
The shape of the data and delay dictionaries is [time_idx, tx_id, rx_id]
, where the inner-most dimension rx_id
is a flat array of size
\( \left(Max_{Paths}, N_{hor.}^{\left(rx\right)} \times N_{vert.}^{\left(rx\right)} \times N_{pol.}^{\left(rx\right)}, N_{hor.}^{\left(tx\right)} \times N_{vert.}^{\left(tx\right)} \times N_{pol.}^{\left(tx\right)} \right) \)
\(Max_{Paths}\) is the length of the CIR in samples,
\(N_{hor.}^{yx}\) is the number of horizontal antenna sites (without considering polarization) in the \(yx\) panel
\(N_{vert.}^{yx}\) is the number of vertical antenna sites (without considering polarization) in the \(yx\) panel
\(N_{pol.}^{yx}\) is the number of used polarizations per antenna site in the \(yx\) panel.
That is, the array is flattened according to the following order:
[\(h_{0}v_{0}p_{0}\), \(h_{0}v_{0}p_{1}\) … \(h_{0}v_{N_{vert}}p_{1}\) … \(h_{N_{hor}}v_{N_{vert}}p_{1}\) ] , where, h,v,p correspond to the horizontal, vertical and polarization dimension of the antenna panel.
2. extract_CFR_sample.py#
The extract_CFR_sample.py
reads the channel frequency response (CFR) from the cfrs table.
python3 extract_CIR_sample.py --hostname <hostname> --database <database_name> --sample <time_idx> --RU <tx_id> --UE <rx_id>
For example, if we need the CFR for sample 5, for ue_0002 and ru_0001, run the following command:
python3 extract_CFR_sample.py --hostname "localhost" --database "yoda_2024_4_15_13_4_6" --sample 5 --RU 1 --UE 2
The script fetches the desired CFRs and adds it to a dictionary that is then written to the sample-cfr-<time_idx>.dat binary file. The pickled data structure contains a dictionary data
that holds the channel frequency response for the specified RU and UE antenna pairs. The shape of data
is similar to the shape of the CIR from the previous section, except that the innermost flattened array is of size:
\(
\left(NFFT,
N_{hor.}^{\left(rx\right)} \times N_{vert.}^{\left(rx\right)} \times N_{pol.}^{\left(rx\right)}, N_{hor.}^{\left(tx\right)} \times N_{vert.}^{\left(tx\right)} \times N_{pol.}^{\left(tx\right)}
\right)
\)
where \(NFFT\) is the size of the FFT to convert from the time domain samples to frequency domain samples.
Besides the CFR, the script also dumps the following scalar quantities:
fft_size
: Size of the CFRscs
: Subcarrier spacingue_fc
: Center frequency of the UEru_fc
: Center frequency of the RU
3. extract_CIR.py and extract_CFR.py#
The scripts extract_CIR.py
and extract_CFR.py
extract data for all RU/UE antenna pairs and all time samples. To speed up reading such a large amount of data from the database, these scripts make use of a fast reader written in C++. A precompiled library called chapi_bindings.
cfrs = read_cfrs_db(hostname,database)
cirs,delays = read_cfrs_db(hostname,database)
For example:
cfrs = read_cfrs_db("localhost","yoda_2024_4_15_13_4_6")
cirs,delays = read_cfrs_db("localhost",yoda_2024_4_15_13_4_6)
These bindings are called by extract_CIR.py
and extract_CFR.py
in order to generate pickle files cirs.dat
or cfrs.dat
. The usage is as follows:
python3 extract_CIR.py --database <database_name> --hostname <hostname>
PYTHONPATH=build/examples python3 examples/extract_CIR_sample.py --database "yoda_2024_4_15_13_4_6" --hostname "localhost"
Note that unlike extract_CFR_sample.py
, the read_cfrs_db()
function only returns the CFRs, not the other scalar quantities.
5. plot_PDP_from_CIR.py#
The script produces a figure of the channel impulse response associated with one of the RU/UE antenna links.
python3 plot_PDP_from_CIR.py --filename sample-cir-<time_idx>.dat --sample <time_idx> --RU <tx_id> --UE <rx_id> --suppress
6. plot_PDP_from_CFR.py#
The channel impulse response can also be calculated and plotted using the channel frequency response data by running:
python3 plot_PDP_from_CFR.py --filename sample-cir-<time_idx>.dat --sample <time_idx> --RU <tx_id> --UE <rx_id>
7. plot_PAS_from_CIR.py#
This script uses the rays in the raypaths table to calculate the uplink power angular spectrum.
python3 plot_PAS_from_CIR.py --filename sample-cir-<time_idx>.dat --sample <time_idx> --RU <tx_id> --UE <rx_id> --angle [azimuth|zenith] --suppress
8. plot_CFR.py#
Finally, to visualize the channel frequency response, run:
python plot_CFR.py -filename sample-<time_idx>.dat --sample <time_idx> --RU <tx_id> --UE <rx_id>
9. channel_metric.py#
This script calculates the SINR for a specified link. SINR is calculated using the CFRs, and is termed as CFRS SINR. When RAN is enabled, the pre-equalization SINR is read from the telemetry database and presented alongside CFRS SINR. SINRs are calulated for every sample for which the simulation is run. The script also plots the CDF of SINR(s).
python channel_metric.py --hostname <hostname> --database <database_name> --RU <tx_id> --UE <rx_id>
Jupyter notebooks#
The scripts can be conveniently run through Jupyter notebooks. The following notebooks are available in the examples/notebooks directory:
CFR.ipynb
CIR.ipynb
ExportData.ipynb
ImportData.ipynb
The Jupyter Notebooks can be accessed by opening a web browser using the address of the backend http://omniverse-server:8888/.
Accessing Rx signal data from an H5 file#
When running in RAN simulation mode, if a filename is specified for “RX FT filename” in config_ran.json, the received signals (i.e., I/Q samples) are saved to an H5 file with the specified filename for each PDSCH/PUSCH slot. Below is an example of how to access the data using a Python script:
import h5py
file_path = "/home/aerial/asim_em/rx_dump.h5"
with h5py.File(file_path, 'r') as h5_file:
slot = '0'
dataset_name = 'mRxSignal'
rx_data = h5_file[slot][dataset_name][:] # shape: (active cell num, rx ant num, symbol num, subcarrier num)
slot_type = h5_file[slot]["slot_type"][:] # 0: DL, 1: UL
Running Headless Simulation from an YAML file#
Headless simulation, configured by a YAML file, enables
simulating a saved scenario from the database using updated parameters
and running a new simulation from scratch.
The YAML file serves as a representation of the configuration that would otherwise be obtained through the graphical user interface. This section outlines the YAML file format and lists the available configurations for customization.
The YAML file contains a db
(optional) and a sim
(required) section, as shown below.
db:
# Configurations related to database. Only required if starting from scratch.
sim:
# Headless counterpart of "Stage" widget in the graphical user interface.
The command to launch healdess simulation is
aerial:/aodt/aodt_sim/src_py$ python -m aodt.app.sim --log=<log level> --nats_server_url=<path to NATs server> --nats_subject=<NATs subject> --db-replay --db-host=<path to clickhouse server> --db-name-source=<source database from which to replay> --db-name-destination=<new database to write results into> --sim-config=<path to config file in YAML>
where the config file is passed through --sim-config
.
‘db’ section#
An example of the ‘db’ section is given below. When simulating a source database, the ‘db’ section is optional, and any field not specified in the YAML file will use the value from the source database.
db:
reset: false # (Required) set true only if user wants to erase db_content in source DB and reset it to a standard scenario with 1 DU, 1 RU and 1UE, even if the source DB exists.
scene_url: omniverse://omniverse-server/Users/aerial/demo/plateau/tokyo_small.usd # (Optional) only required if 'reset' is true or it is a new simulation from scratch.
db_author: "aerial-sim" # (Optional)
db_notes: "example simulation config" # (Optional)
opt_in_tables: ["cfrs", "cirs", "raypaths", "telemetry", "training_result"] # (Optional) List[str]. Counterpart to "Opt-in DB tables" of "Configuration" tab in UI.
opt_in_tables_options: # (Optional) Dict[str, str]
"raypaths": "first" # "full" to save with all antenna pairs.
‘sim’ section#
The sim
section can configure the following folders: Scenario
, UEs
, RUs
, DUs
, Panels
, Materials
, World/spawn_zone
, World/scatterers
, World/buildings/exterior
, World/buildings/interior
and World/buildings
. They share a similar configuration format as below.
sim:
<folder>: # folder corresponds to the top level hierarcy (2nd or 3rd level for "World") on the stage menu in UI
asset: <path_to_asset_file> # Only required if
# (1) simulating from scratch, or
# (2) `reset: true` in `db` section.
# `add` is non-empty below
# Only available for `UEs`, `RUs`, `DUs`, `World/scatterers` and `Materials`
add: a list of dictionaries # Specify how to add prims. Only available for `UEs`, `RUs`, `DUs` and `World/spawn_zone`.
# The attributes of the added prim will be copied from
# (1) any prim existing in the source database, or
# (2) description in `asset` if no prim exists in the source database
- id: <ID_of_prim> # See guidelines under UEs/RUs/DUs for details.
- waypoints or position: # Can be both Cartesian and georeferenced coordinates.
delete_ids: a list # Specify which prims to delete. Only available for `UEs`, `RUs` and `DUs`.
# It can be either a list of IDs, e.g., [3, 5], or ['*'] for all.
update: a list of dictionaries # Specify the attributes that are updated over their default/old values..
# Updates are applied on groups of prims. Prims are the objects under a folder name
# Each group contains one or many or prims.
# Prims are added to a group by adding their prim id to the ids list.
# Thus each ids list corresponds to a group.
# Each group contains attributes with value to be changed.
# These attributes are changed for all prims that belong to the group.
# The non-specified attributes will take value from
# (1) source database if YAML file is used to simulate a source database, or
# (2) default values if YAML file is to run a simulation from scrach.
# Updates are applied in the order specified.
# Prims from `add` will be updated if they are included in `ids` below.
- ids: # a list of target IDs for the 1st group of prims.
attributes: # a dictionary of attribute-value pairs for the 1st group of prims.
attr_names: vals # available attr_names are detailed below.
# attr_name is composed of hierarchies and must be provided with the full hierarchies.
- ids: # a list of target IDs for the 2nd group of prims.
attributes: # a dictionary of attribute-value pairs for the 2nd group of prims.
attr_names: vals
- ...
A table summarizing the configurable fields of each folder is given below.
Folder |
asset |
add |
delete_ids |
update |
---|---|---|---|---|
|
✗ |
✗ |
✗ |
✓ |
|
✓ |
✓ |
✓ |
✓ |
|
✓ |
✓ |
✓ |
✓ |
|
✓ |
✓ |
✓ |
✓ |
|
✗ |
✗ |
✗ |
✓ |
|
✓ |
✗ |
✗ |
✓ |
|
✗ |
✓ |
✗ |
✓ |
|
✓ |
✗ |
✗ |
✗ |
|
✗ |
✗ |
✗ |
✓ |
|
✗ |
✗ |
✗ |
✓ |
|
✗ |
✗ |
✗ |
✓ |
To simulate from scratch, the sim
field needs to have the following fields: UEs
, RUs
, DUs
, Materials
, World/scatterers
. An example is
sim:
UEs:
asset: omniverse://omniverse-server/Users/aerial/assets/ue.usda
RUs:
asset: omniverse://omniverse-server/Users/aerial/assets/gnb.usda
DUs:
asset: omniverse://omniverse-server/Users/aerial/assets/du.usda
Materials:
asset: omniverse://omniverse-server/Users/aerial/assets/material.usda
World/scatterers:
asset: omniverse://omniverse-server/Users/aerial/assets/car_small.usda
In the following sections, all configurable attribute names are detailed in this documentation. The counterpart in the UI will be given for each attribute.
Scenario
#
The Scenario
under sim
is the counterpart of Scenario in the Stage widget in the UI.
sim:
Scenario: # only `update` should be provided.
update: # must be a list. No `ids` to specify.
- attributes: # must be a dictionary. All configurable attr_names are given below.
# The attr_name needs to be full, e.g.,
# used sim:ue:panel_type but not ue:panel_type
# "Default Panels" in UI
sim:ue:panel_type: "panel_01" # User Equipment (UE)
sim:gnb:panel_type: "panel_02" # Radio Unit (RU)
# "Simulation" in UI
sim:is_full: false # Simulate RAN
sim:simulation_mode: 0 # Simulation Mode
sim:samples_per_slot: 0 # Samples per Slot
sim:slots_per_batch: 0 # Slots per Batch
sim:batches: 1 # Number of Batches
sim:duration: 1.0 # Duration
sim:interval: 1.0 # Interval
# "Ray Tracing" in UI
sim:em:diffuse_type: 1 # EM Diffusion Material
sim:em:interactions: 5 # Ray Bounces
sim:em:max_num_paths_per_ant_pair: 500 # Max Paths
sim:em:rays: 500 # Emitted Rays (in thousands)
sim:enable_wideband: true # Enable Wideband CFRs
# "Ray Visualization" in UI
pathViz:enableTemperatureColor: true # Enable Temperature Color
pathViz:maxDynamicRangeDB: 200 # Max Dynamic Range
pathViz:maxNumPaths: 1000 # Max Visible Ray Paths
pathViz:raysSparsity: 1 # Ray Sparsity
pathViz:raysWidth: 8.0 # Ray Width
# "User Equipments" in UI
sim:is_seeded: false # Enable Seeded Mobility
sim:seed: 0 # Mobility Seed
sim:num_procedural_ues: 0 # Number of Procedural UEs
sim:perc_indoor_procedural_ues: 0.0 # Indoor Procedural UEs
sim:ue:height: 1.5 # Capsule Height
sim:ue:radius: 0.5 # Capsule Radius
sim:em:sphere_radius: 2.0 # Reception Sphere Radius
sim:ueMaxSpeed: 2.5 # Max Speed
sim:ueMinSpeed: 1.5 # Min Speed
um:enable_urban_mobility: false # Enable Urban Mobility
sim:enable_dynamic_scattering: false # Enable Dynamic Scattering. Set true only if um:enable_urban_mobility=true
um:num_vehicles: 0 # Max Number of Vehicles. Non-zero only if sim:enable_dynamic_scattering=true
sim:ue:gpx_file_paths: [] # GPX File Paths
UEs
#
The UEs
under sim
are the counterparts of “UEs” in the Stage widget in the UI. An example with all attributes is given below, where the default values are from ue.usda
. In the example, we show two groups (one with ids=['*']
and one with ids=[2, 8, 79]
) of updates. The waypoints
can be both in Cartesian and geocentric coordinates.
sim:
UEs:
asset: omniverse://omniverse-server/Users/aerial/assets/ue.usda # Only required and used if `reset` is true, or if the YAML file is used to simulate from scratch.
add: # UEs added from `add` will be set as manual UE
- id: 1 # ue_0001 is added as a manual UE
waypoints: # add a single waypoint using Cartesian coordinates with unit in meters.
# If Cartesian coordinates are used, must be a dictionary with keys 'x', 'y' and 'z'.
# Check "Cursor Location" in UI for values to use.
# The waypoints specified here are validated and corrected in the same manner as that in UI, i.e.,
# a waypoint outside the map or within a building is replaced to the nearest point.
- x: 150.20604
y: 99.50866
z: 1.25000
- id: 204 # ue_0204 is added as a manual UE
waypoints: # add multiple waypoints using georeferenced coordinate.
- lat: 35.66376818087683
lon: 139.7459968717682
- lat: 35.663622296081414
lon: 139.74622811587614
- lat: 35.66362516562424
lon: 139.74653110368598
delete_ids: ['*'] # delete all UES under "UEs" except for the ones added above in 'add' section.
# It can also be a list of target IDs, e.g., [2, 3, 4] for ue_0002, ue_0003, ue_0004.
update:
- ids: ['*'] # 1st group of update: applied to all objects under UEs.
attributes: # All configurable attr_names are given below.
# The attr_name needs to be full, e.g.,
# used aerial:ue:user_id but not ue:user_id
aerial:ue:user_id: 0 # ID. min=0, max=10000.
aerial:ue:bler_target: 0.1 # BLER Target. min=0.0, max=1.0.
aerial:ue:manual: false # Manually Created.
aerial:ue:mech_tilt: 0.0 # Mech. Tilt. unit=deg, min=0.0, max=360.0.
aerial:ue:panel_type: "panel_01" # Panel Type. combo_options.
aerial:ue:radiated_power: 26.0 # Radiated Power. unit=dBm, min=-20.0, max=60.0.
aerial:ue:initial_mech_azimuth: 0.0 # Angle for the initial heading of the UE
aerial:ue:waypoint_speed: [0.0] # A list containing speeds in meters per second at each waypoint
aerial:ue:waypoint_pause_duration: [0.0] # A list containing pause durations in seconds at each waypoint
aerial:ue:waypoint_azimuth_offset: [0.0] # A list containing azimuth offsets in degrees at each waypoint
aerial:ue:waypoint_arrival_time: [-1.0] # A list containing arrival times in seconds at each waypoint. Only used for GPX imported users.
- ids: [2, 8, 79] # 2nd group of update: applied to ue_0002, ue_0008 and ue_0079.
attributes:
aerial:ue:bler_target: 0.2
RUs
#
The RUs
under sim
are the counterparts of “RUs” in the Stage widget in the UI. An example with all admissible attributes is given below, where the default values are from gnb.usda
. In the example, we show two groups (one with ids=['*']
and one with ids=[1]
) of updates. The position
can be both Cartesian and geocentric coordinates.
sim:
RUs:
asset: omniverse://omniverse-server/Users/aerial/assets/gnb.usda # Only required and used if `reset` is true, or if the YAML file is used to simulate from scratch.
add:
- id: 1 # add ru_0001
position: # add through Cartesian coordinates with unit in meters.
x: 159.37732
y: 144.13693
z: 34.30854
- id: 2 # add ru_0002
position: # add through geocentric coordinates
lat: 35.66356389841298
lon: 139.74686323425487
delete_ids: ['*'] # delete all ru under "RUs" except the ones added above in 'add' section.
# It can also be a list of target IDs, e.g., [1, 4] for ru_0001, ru_0004.
update:
- ids: ['*'] # the 1st group of operations target at all RUs.
attributes: # All configurable attr_names are given below.
# The attr_name needs to be full, e.g.,
# used aerial:gnb:carrier_freq but not gnb:carrier_freq
aerial:gnb:carrier_freq: 3600 # Carrier frequency
aerial:gnb:cell_id: 0 # Cell ID. User is not recommended to update this attribute.
aerial:gnb:height: 2.5 # Height (m)
aerial:gnb:mech_azimuth: 0.0 # Mech. Azimuth (degrees)
aerial:gnb:mech_tilt: 0.0 # Mech. Tilt (degrees)
aerial:gnb:panel_type: panel_02 # Panel Type
aerial:gnb:radiated_power: 43 # Radiated Power (dBm)
aerial:gnb:du_id: 1 # Distributed unit (DU) ID
aerial:gnb:du_manual_assign: 0 # Manually assigns a DU
- ids: [1] # # the 2nd group of operations target at ru_0001.
attributes:
aerial:gnb:radiated_power: 60
DUs
#
The DUs
under sim
are the counterparts of “DUs” in the Stage widget in the UI. An example with all attributes is given below, where the default values are from du.usda
. In the example, we show two groups (one with ids=['*']
and one with ids=[1]
) of updates. The position
can be both Cartesian and geocentric coordinates.
sim:
DUs:
asset: omniverse://omniverse-server/Users/aerial/assets/du.usda # Only required and used if `reset` is true, or if the YAML file is used to simulate from scratch.
add:
- id: 1 # add du_0001
position: # add through Cartesian coordinates with unit in meters. Can also be added through georeferenced coordinate.
x: 0
y: 0
z: 100
delete_ids: ['*'] # delete all ue under "DUs" except the ones added above in 'add' section.
# It can also be a list of target IDs, e.g., [2, 4] for du_0002, du_0004.
update:
- ids: ['*'] # the 1st group of operations target at all DUs.
attributes: # All configurable attr_names are given below.
# The attr_name needs to be full, e.g.,
# used aerial:du:id but not du:id
aerial:du:id: 0 # ID
aerial:du:fft_size: 4096 # Waveform FFT size
aerial:du:subcarrier_spacing: 30.0 # Sub-carrier spacing. Unit in KHz.
aerial:du:num_antennas: 4 # Number of antenna elements. Must be the same as the panel size of the RU's panel.
aerial:du:reference_freq: 3600.0 # Center Frequency. Unit in MHz.
aerial:du:max_channel_bandwidth: 100.0 # Max channel bandwidth. Unit in MHz.
- ids: [1] # the 2nd group of operations target at du_0001.
attributes:
aerial:du:num_antennas: 64
Panels
#
The Panels
under sim
are the counterparts of Panels
in the Stage widget in the UI. An example with all attributes is given below. The fields asset
, add,
and delete_ids
should not be provided. In the example, we show two groups (one with ids=[1]
and one with ids=[2]
) of updates. Only built-in panel types (isotropic
, infinitesimal_dipole
, halfwave_dipole
, rec_microstrip_patch
, threeGPP_38901
, polarized_isotropic
) are supported for aerial:panel:antenna_elements
.
sim:
Panels:
update:
- attributes: # All configurable attr_names are given below.
# The attr_name needs to be full
aerial:panel:antenna_elements:
- isotropic # When a single antenna element type is provided, it will be automatically
# replicated to fill all positions in the panel array based on the panel's
# configuration (dual_polarized, num_horizontal_elements, num_vertical_elements).
# In this example, panel_01 will be updated to have 64 isotropic elements.
aerial:panel:dual_polarized: true # Dual Polarized
aerial:panel:num_horizontal_elements: 4 # Horizontal Elements
aerial:panel:horizontal_spacing: 46.0 # Horizontal Spacing
aerial:panel:num_vertical_elements: 8 # Vertical Elements
aerial:panel:vertical_spacing: 46.0 # Vertical Spacing
aerial:panel:roll_first_pol_element: 0 # Roll of First Pol. Element. Unit in degrees.
aerial:panel:roll_second_pol_element: 90 # Roll of Second Pol. Element. Unit in degrees.
aerial:panel:reference_freq: 3600
ids:
- 1 # the 1st group of operations target at panel_01
- attributes:
aerial:panel:antenna_elements:
- isotropic
- infinitesimal_dipole # user can also provide a full list of elements.
# The length of the list must be compatible to panel
# configuration (dual_polarized, num_horizontal_elements, num_vertical_elements).
aerial:panel:dual_polarized: false
aerial:panel:num_horizontal_elements: 1
aerial:panel:num_vertical_elements: 2
aerial:panel:reference_freq: 3600
ids:
- 2 # the 2nd group of operations target at panel_02
Materials
#
The Materials
under sim
are the counterparts of “Materials” in the Stage widget in the UI. An example with all attributes is given below, where the default values are from materials.usda
. The fields add
and delete_ids
should not be provided.
sim:
Materials:
asset: omniverse://omniverse-server/Users/aerial/assets/material.usda # Only required and used if `reset` is true, or if the YAML file is used to simulate from scratch.
update:
- ids: ['*']
attributes: # All configurable attr_names are given below.
# The attr_name needs to be full
id: 0 # ID
a: 1.0 # ITU-R P.2040 a
b: 0.0 # ITU-R P.2040 b
c: 10000000.0 # ITU-R P.2040 c
d: 0.0 # ITU-R P.2040 d
exponent_alpha_i: 10 # Backward Scattering Lobe Exponent
exponent_alpha_r: 10 # Forward Scattering Lobe Exponent
lambda_r: 1.0 # Forward Scattering Lobe/Total Power Ratio
roughness_rms: 0.0 # RMS Roughness
scattering_coeff: 0.0 # Scattering Coefficient
k_xpol: 0.05 # Scattering XPD
thickness: 0.1 # Thickness
The file materials.usda
requires that each material be defined under the standard
category. In other words, materials.usda
should have the following structure:
def "standard"
{
def Scope "<material_name>"
{
<attributes>
}
}
World/spawn_zone
#
The World/spawn_zone
under sim
is the counterpart of “World/spawn_zone” in the Stage widget in the UI. An example with all attributes is given below, where the default values are set internally. The fields asset
, delete_ids
should not be provided for configuration. The position
can be expressed in both Cartesian and geocentric coordinates. The correct way to configure World/spawn_zone
is to
use
position
(\([p_x, p_y, 0]\)) underadd
to specify the center of the spawn zone,use
xformOp:scale
(\([s_x, s_y, 1]\)) to specify the scaling of each side of the rectangular zone. The created spawn zone will be a rectangle centered at \([p_x, p_y, 0]\), with dimension \(100 \cdot s_x \times 100 \cdot s_y\).
sim:
World/spawn_zone:
add:
- position: # support both Cartesian coordinate (meter) and georeferenced coordinate.
x: 0.0
y: 10.0
z: 0.0 # must be zero.
update: # no "ids" should be given.
- attributes: # All configurable attr_names are given below.
# The attr_name needs to be full
xformOp:scale: [2, 2.40717, 1] # scale in x, y and z axis. Must be in the format of [x, y, 1]
# In this example, the spawn zone is a rectangle with side length as 200m and 240.717m.
xformOp:rotateXYZ: [0, 0, -70] # rotate angle around the z axis. Must be in the format of [0, 0, z]
NOTE: In simulating a source database, use position
under add
to update the center of the spawn zone.
World/scatterers
#
The World/scatterers
under sim
is the counterpart of “World/scatterers” in the Stage widget in the UI. An example with all attributes is given below, where the default values are from car_small.usda
. Only asset
should be provided. Attribute updates are not currently supported, and the only way to change parameters is to update car_small.usda
directly.
sim:
World/scatterers:
asset: omniverse://omniverse-server/Users/aerial/assets/car_small.usda
World/buildings/exterior
#
The World/buildings/exterior
under sim
is the counterpart of “World/buildings/exterior” in the Stage widget in the UI. Only update
can be configured. It is solely for building prims directly in the World/buildings/exterior
folder.
sim:
World/buildings/exterior:
update:
- ids: ['*'] # an example to demonstrate how to update for all exterior buildings in the 1st group of operations.
attributes: # All configurable attr_names are given below.
# The attr_name needs to be full
AerialRFdS: 1.0 # Diffuse Surface Element Area
AerialRFDiffuse: true # Enable Diffusion
AerialRFDiffraction: true # Enable Diffraction
AerialRFTransmission: true # Enable Transmission
AerialRFMesh: true # Enable RF
# The following is an example for updating two specific buildings in the 2nd group of operations.
# The building name must match exactly the one in USD map
- ids: [bldg_987d65a7_288f_4356_a639_3d058320f652, bldg_cccd0c62_5b12_4b25_b177_b862f33988cb]
attributes:
AerialRFdS: 10.0
World/buildings/interior
#
Similar to World/buildings/exterior
.
World/buildings
#
Similar to World/buildings/exterior
. This is for legacy USD maps where all buildings are in “World/buildings”.
EM engine interface#
The EM engine is developed directly by NVIDIA, but it is modularly embedded in the Aerial Omniverse Digital Twin through a specific interface. This allows supporting the integration of different EM engines if necessary. This section aims at preparing for such a possibility by providing an overview of the key mechanics of such an interface.
NVIDIA’s EM engine API provides functions to
manage the device memory,
perform EM calculations,
and copy results to host memory.
All classes, member functions and variables are defined in the aerial_emsolver_api.h
header and make use of the C++/CUDA primitive data types.
Data types#
d_complex
typedef cuda::std::complex<float> d_complex
Complex-valued data type used in both host code and device code.
d_complex4
typedef struct d_complex4 { d_complex m[4]{}; } d_complex4
An array of four
d_complex
elements.Matrix4x4
typedef struct Matrix4x4 { float m[4][4]{}; [[nodiscard]] bool operator==(const Matrix4x4 &other) const; } Matrix4x4
A \(4\times4\) matrix of
float
elements.EMMaterial
struct EMMaterial { float4 abcd{}; float roughness_rms{}; float k_xpol{}; float scattering_coeff{}; int exponent_alpha_R{}; int exponent_alpha_I{}; float lambda_R{}; float thickness_m{}; [[nodiscard]] bool operator==(const EMMaterial &other) const; }
A struct storing EM material parameters.
Member
Description
abcd
a
float4
storing ITU-R P2040 a, b, c, and d parameters for calculating the relative permittivity [2]roughness_rms
the root mean square of the surface roughness (type
float
), in metersk_xpol
scattering cross-polarization/col-polarization power ratio (type
float
)scattering_coeff
scattering coefficient in the effective roughness (ER) model [3], [4] (type
float
)exponent_alpha_R
integer exponent of the forward scattering lobe (in the specular reflection direction) in the Directional diffuse model (type
int
)exponent_alpha_I
integer exponent of the backward scattering lobe (in the incidence direction) in the Directional diffuse model (type
int
)lambda_R
ratio between the forward scattering power and the total scattering power in the Directional diffuse model (type
float
)thickness_m
thickness of the single-layer material (type
float
), in meters
The diffuse model can be either Lambertian or Directional, and there are two ways to tune the diffuse scattering pattern:
using a fixed positive
scattering_coeff
(the ER model), which does not depend on the incidence angle of the impinging wave. This coefficient is used to calculate the reflection reduction factor and the fraction of power used for diffuse scattering. In this case , theroughness_rms
parameter is ignored, as the sets of(abcd, scattering_coeff, k_xpol)
and(abcd, scattering_coeff, k_xpol, exponent_alpha_R, exponent_alpha_I, lambda_R, thickness_m)
are sufficient for Lambertian and Directional diffuse models, respectively.using
roughness_rms
to characterize the Rayleigh reflection reduction factor [5], [6] and the fraction of power for diffuse scattering. In this case, thescattering_coeff
parameter is ignored, as the sets of(abcd, roughness_rms, k_xpol)
and(abcd, roughness_rms, k_xpol, exponent_alpha_R, exponent_alpha_I, lambda_R, thickness_m)
are sufficient for Lambertian and Directional diffuse models, respectively.
By default, for a material with a positive scattering_coeff
, the first method is used. Otherwise, if scattering_coeff = 0.0
, then the second method is used. For the Directional diffuse model, the formulation [4] is reciprocal. When lambda_R = 1.0
, the Directional diffuse model becomes a single-lobe diffuse (SLD) model, and the forward lobe contains the total diffuse scattering power. Alternatively, the model will utilize two lobes.
For reflection and transmission coefficients, the single-layer slab model with a single thickness in ITU Recommendation P.2040-3 is used.
EM_INTERACT_TYPE
enum EM_INTERACT_TYPE : unsigned int { Emission = 0, Reflection = 1, Diffraction = 2, Diffuse = 3, Reception = 4, Transmission = 5, Reserved, }
An enumeration of EM interaction types per ray.
EM_DIFFUSE_TYPE
enum EM_DIFFUSE_TYPE : unsigned int { Lambertian = 0, Directional = 1 }
An enumeration of EM diffuse type.
RayPath
struct RayPath { int tx_id{}; int rx_id{}; int tx_ij[2]{}; int rx_ij[2]{}; int rx_index{}; EM_INTERACT_TYPE point_types[MAX_NUM_INTERACTIONS_WITH_TRANSMISSION+2]{}; float3 points[MAX_NUM_INTERACTIONS_WITH_TRANSMISSION+2]{}; int object_ids[MAX_NUM_INTERACTIONS_WITH_TRANSMISSION + 2]{}; int prim_ids[MAX_NUM_INTERACTIONS_WITH_TRANSMISSION+2]{}; float3 normals[MAX_NUM_INTERACTIONS_WITH_TRANSMISSION+2]{}; int num_points{}; d_complex cir_ampl[4]{}; float cir_delay{}; __host__ __device__ RayPath() {} __host__ __device__ RayPath(int *tx_ij, int *rx_ij, float3 *points, EM_INTERACT_TYPE *point_types, int *object_ids, int *prim_ids, float3 *normals, int tx_id, int rx_id, int rx_index, int num_points); [[nodiscard]] bool operator==(const RayPath &other) const; }
A struct storing geometry and EM data of a propagation path.
Member
Description
tx_id
ID of the RU (type
int
)rx_id
ID of the UE (type
int
)tx_ij
two-element array of indices (type
int
,i
for horizontal index andj
for vertical index) of the antenna element within the RU panelrx_ij
two-element array of indices (type
int
,i
for horizontal index andj
for vertical index) of the antenna element within the UE panelrx_index
index of the UE (type
int
)point_types
an array of
EM_INTERACT_TYPE
storing the EM interaction types for points along the pathpoints
an array of
float3
storing the (x, y, z) coordinates of interaction points, in the same unit as USD map*object_ids
an array of
int
storing the indices of the geometry object at the interaction points. The building object, if present, is indexed by 0, followed by the vehicular objects starting from 1. If the building is not present, the first vehicular object is indexed by 0 insteadprim_ids
an array of
int
storing the indices of the geometry primitive at the interaction points: the hit triangle index for a reflection, diffusion or transmission, the hit edge index for a diffraction, the hit tri-1s otherwise. The triangle index is local to the building mesh or the base (pre-trasform) scatterer meshnormals
an array of
float3
storing the normals at the interaction pointsnum_points
number of interaction points from the RU to UE (type
int
)cir_ampl
an array of four complex-valued elements storing the path CIR amplitude for four UE-RU polarization combinations**
cir_delay
propagation delay of the path (type
float
), in seconds*The map unit is determined by
Meters Per Unit
in the USD file. For example, a map is in meters ifMeters Per Unit = 1
and in centimeters ifMeters Per Unit = 0.01
. **cir_ampl[i*2 + j]
is for the UE’s \(i\)-th polarization and RU’s \(j\)-th polarization, for \(i \in \left[0, 1\right]\) and \(j \in \left[0, 1\right]\).ANTENNA_TYPE
enum ANTENNA_TYPE : unsigned int { Isotropic = 0, Infinitesimal_dipole = 1, Halfwave_dipole = 2, Rec_microstrip_patch = 3, ThreeGPP_38901 = 4, Polarized_Isotropic = 5 }
An enumeration for the built-in antenna types currently supported by the EM solver.
AntennaPattern
struct AntennaPattern { int pattern_type{}; std::vector<std::vector<d_complex>> ampls_theta{}; std::vector<std::vector<d_complex>> ampls_phi{}; [[nodiscard]] bool operator==(const AntennaPattern &other) const; }
A struct storing a radiation pattern for a given antenna element, for either a built-in or a custom antenna type. The current version only supports patterns at a single frequency.
Member
Description
pattern_type
an integer indicating the radiation pattern type as defined in the
ANTENNA_TYPE
enum (typeint
)ampls_theta
a two-dimensional vector storing complex-valued amplitudes (type
d_complex
) of the antenna radiated field along the theta direction, each inner vector stores the amplitudes for one frequencyampls_phi
a two-dimensional vector storing complex-valued amplitudes (type
d_complex
) of the antenna radiated field along the phi direction, each inner vector stores the amplitudes for one frequencyFor built-in antenna types, the radiation fields are analytically calculated by the EM engine, and the
ampls_theta
andampls_phi
member variables are ignored. For example, for anInfinitesimal_dipole
pattern type, theAntennaPattern
object is:AntennaPattern pattern = {.pattern_type = 1, .ampls_theta = {}, .ampls_phi = {}};
AntennaPanel
struct AntennaPanel { std::string panel_name{}; std::vector<std::string> antenna_names{}; std::vector<int> antenna_pattern_indices{}; std::vector<float> frequencies{}; std::vector<float> thetas{}; std::vector<float> phis{}; double reference_freq{}; bool dual_polarized{}; int num_loc_antenna_horz{}; int num_loc_antenna_vert{}; double antenna_spacing_horz{}; double antenna_spacing_vert{}; double antenna_roll_angle_first_polz{}; double antenna_roll_angle_second_polz{}; [[nodiscard]] bool operator==(const AntennaPanel &other) const; }
An struct storing information for a given antenna panel. The number of antenna elements in a panel is
num_loc_antenna_horz*num_loc_antenna_vert*num_polarizations
.Member
Description
panel_name
name of the panel (type
string
)antenna_names
a vector of names (type
string
) of all antenna elements in the panelantenna_pattern_indices
a vector of indices (type
int
) to thepatterns
vector for the antenna elements in the panelfrequencies
a vector of frequencies (type
float
) for the antenna radiation patterns of the antenna elements in the panel, in Hertzthetas
a vector storing elevation angles (type
float
) of the radiation pattern for all antenna elements in the panel, in radiansphis
a vector storing azimuth angles (type
float
) of the radiation pattern for all antenna elements in the panel, in radiansreference_freq
center frequency (type
double
) of the panel, in Hertzdual_polarized
a
bool
variable to indicate if the panel antennas are dual- (true) or single- polarized (false)num_loc_antenna_horz
number of antenna element locations (type
int
) in the planar array along a rownum_loc_antenna_vert
number of antenna element locations (type
int
) in the planar array along a columnantenna_spacing_horz
horizontal antenna element spacing (type
double
), in centimetersantenna_spacing_vert
vertical antenna element spacing (type
double
), in centimetersantenna_roll_angle_first_polz
angular displacement of the antenna element realizing the first polarization (type
double
), in radiansantenna_roll_angle_second_polz
angular displacement of the element realizing the second polarization (type
double
), in radiansAntennaInfo
struct AntennaInfo { std::vector<AntennaPanel> panels{}; std::vector<AntennaPattern> patterns{}; [[nodiscard]] bool operator==(const AntennaInfo &other) const; }
A struct encapsulating information of all antenna panels and antenna radiation patterns.
Member
Description
panels
vector of panels (type
AntennaPanel
)patterns
vector of patterns (type
AntennaPattern
)TXInfo
struct TXInfo { int tx_ID{}; float3 tx_center{}; Matrix4x4 Ttx{}; std::vector<int> panel_id{}; float height{}; float mech_azimuth_deg{}; float mech_tilt_deg{}; float carrier_freq{}; float carrier_bandwidth{}; float subcarrier_spacing{}; int fft_size{}; float radiated_power{}; std::vector<std::string> antenna_names{}; std::vector<int> antenna_pattern_indices{}; bool dual_polarized_antenna{}; std::vector<float3> antenna_rotation_angles{}; int num_loc_antenna_horz{}; int num_loc_antenna_vert{}; std::vector<float3> loc_antenna{}; std::vector<std::pair<int, int>> ij_antenna{}; }
An struct storing RU information.
Member
Description
tx_ID
ID of the RU (type
int
)tx_center
(x , y, z) coordinates of the RU center (type
float3
), in the same unit as USD mapTtx
a
Matrix4x4
transformation matrix for the RU combining translation and rotation, in the same unit as USD mappanel_id
a vector of indices (type
int
) identifying the panels used by the RU; currently only size 1 is supportedheight
height (type
float
) calculated from RU base to the RU center, in centimetersmech_azimuth_deg
mechanical azimuth (type
float
) of the RU, in degreesmech_tilt_deg
mechanical tilt (type
float
) of the RU, in degreescarrier_freq
carrier frequency (type
float
) of the RU, in Hertzsubcarrier_spacing
sub-carrier spacing (type
float
), in Hertzfft_size
FFT size (type
int
) used for wideband CFR calculationradiated_power
radiated power (type
float
) of the RU, in Wattsantenna_names
a vector of names (type
string
) of all antenna elements in the RU panelantenna_pattern_indices
a vector of indices (type
int
) to thepatterns
vector for the antenna elements in the RU paneldual_polarized_antenna
a
bool
variable to indicate if the RU antenna panel is composed by dual- (true) or single- polarized (false) elementsantenna_rotation_angles
a vector of triplets storing rotation angles (type
float3
) of the antennas: the first triplet is for the first polarization, and in case of dual-polarized antennas, the second triplet is for the second polarizationnum_loc_antenna_horz
number of antenna element locations (type
int
) in the horizontal direction within the RU antenna panelnum_loc_antenna_vert
number of antenna element locations (type
int
) in the vertical direction within the RU antenna panelloc_antenna
vector of (x, y, z) of antenna positions within the RU antenna panel (type
float3
), in the same unit as USD map*ij_antenna
a vector of pairs of indices (type
int
) storing horizontal and vertical indices of the antenna elements in the RU antenna panelNote: The antenna locations and the
(i, j)
antenna indices in theTXInfo
are order-consistent: e.g. the element at location indexed by(i, j)
with polarizationp
, isantenna_names[i*num_loc_antenna_vert*num_polarizations + j*num_polarizations + p - 1]
, wherenum_polarizations
is 1 for single-polarized panels and 2 for dual-polarized panels. In addition,(i, j) = (0, 0)
indicates the bottom-left antenna location in the antenna array. These conventions are also used forRXInfo
struct below. It is worth noticing that, in the graphical interface, the top and the bottom of the array are inverted, i.e., what is at the top in the graphical interface is considered at the bottom in EM solver.RXInfo
struct RXInfo { int rx_ID{}; float3 rx_center{}; Matrix4x4 Trx{}; std::vector<int> panel_id{}; float radiated_power{}; std::vector<std::string> antenna_names{}; std::vector<int> antenna_pattern_indices{}; bool dual_polarized_antenna{}; std::vector<float3> antenna_rotation_angles{}; int num_loc_antenna_horz{}; int num_loc_antenna_vert{}; std::vector<float3> loc_antenna{}; std::vector<std::pair<int, int>> ij_antenna{}; }
An struct storing UE information.
Member
Description
rx_ID
ID of the UE (type
int
)rx_center
(x , y, z) coordinates of the UE center (type
float3
), in the same unit as USD mapTrx
a
Matrix4x4
transformation matrix for the UE combining translation and rotation, in the same unit as USD mappanel_id
a vector of indices (type
int
) identifying the panels used by the UE; currently only size 1 is supportedradiated_power
radiated power (type
float
) of the UE, in Wattsantenna_names
a vector of names (type
string
) of all antenna elements in the UE panelantenna_pattern_indices
a vector of indices (type
int
) to thepatterns
vector for the antenna elements in the UE paneldual_polarized_antenna
a
bool
variable to indicate if the UE antenna panel is composed by dual- (true) or single- polarized (false) elementsantenna_rotation_angles
a vector of triplets storing rotation angles (type
float3
) of the antennas: the first triplet is for the first polarization, and in case of dual-polarized antennas, the second triplet is for the second polarizationnum_loc_antenna_horz
number of antenna element locations (type
int
) in the horizontal direction within the UE antenna panelnum_loc_antenna_vert
number of antenna element locations (type
int
) in the vertical direction within the UE antenna panelloc_antenna
vector of (x, y, z) of antenna positions within the RU antenna panel (type
float3
), in the same unit as USD mapij_antenna
a vector of pairs of indices (type
int
) storing horizontal and vertical indices of the antenna elements in the UE antenna panelMesh
struct Mesh { std::vector<float3> mesh_vertices{}; std::vector<int> triangle_material_ids{}; bool is_diffusion{}; bool is_diffraction{}; bool is_transmission{}; float diffuse_dS_sqm = 1.0; [[nodiscard]] bool operator==(const Mesh &other) const; };
A struct storing information of a triangular mesh in the scene.
Member
Description
mesh_vertices
a vector of vertices (type
float3
) of the triangular mesh*, in the same unit as USD maptriangle_material_ids
a vector of material indices (type
int
) of the mesh’s trianglesis_diffusion
flag (type
boolean
) to indicate if the mesh is enabled for diffuse (True
) or not (False
)is_diffraction
flag (type
boolean
) to indicate if the mesh is enabled for diffraction (True
) or not (False
)is_transmission
flag (type
boolean
) to indicate if the mesh is enabled for transmission (True
) or not (False
)diffuse_dS_sqm
(type
float
) the area of the diffuse surface element in square meterNotes: The vertices are grouped in tuples of 3 elements for the building triangles, e.g., vertices {[0], [1], [2]} for the first triangle, vertices {[3], [4], [5]} for the second triangles and so on. For each triangle, the vertex winding order is counter-clockwise so that its front face normal points outward for the building meshes and upward for the ground meshes.
SCATTERER_TYPE
enum SCATTERER_TYPE : int { Vehicle = 0 };
An enumeration for the scatterer type.
ScattererInfo
struct ScattererInfo { int id{}; SCATTERER_TYPE type{}; int mesh_ind{}; Matrix4x4 transform{}; [[nodiscard]] bool operator==(const ScattererInfo &other) const; };
A struct storing information of a scatterer in the scene.
Member
Description
id
index of the scatterer (type
int
)SCATTERER_TYPE
type of the scatterer (type
EM_INTERACT_TYPE
)mesh_id
index of the base (pre-transform) mesh in the the array
geometry_info.scatterer_mesh
used for the scatterer (typeint
)transform
transformation matrix for the scatterer combining translation and rotation, in the same unit as USD map (type
Matrix4x4
)GeometryInfo
struct GeometryInfo { std::vector<Mesh> building_mesh{}; std::vector<Mesh> terrain_mesh{}; std::vector<Mesh> scatterer_mesh{}; std::vector<ScattererInfo> scatterer_info{}; std::unordered_map<std::string, std::pair<int,EMMaterial>> material_dict{}; float meters_per_unit = 0.01f; [[nodiscard]] bool operator==(const GeometryInfo &other) const; };
A struct storing information for the geometries in the scene.
Member
Description
building_mesh
a vector of building meshes (type
Mesh
) in the sceneterrain_mesh
a vector of terrain meshes (type
Mesh
) in the scenescatterer_mesh
a vector of scatterer meshes (type
Mesh
), each holds the base (pre-transform) mesh and related metadata for each type of scatterer in the scenescatterer_info
a vector of
ScattererInfo
structs storing the information of the scatterers in the scenematerial_dict
an unordered map for the material dictionary storing all materials in the scene: key is the material name (type
string
) and value is a pair of<int, EMMaterial>
meters_per_unit
a constant value of the amount of meters in the spatial units of the meshes (type
float
), default value is 0.010.01
RTConfig
struct RTConfig { int num_rays_in_thousands{}; int max_num_bounces{}; float rx_sphere_radius_cm{}; EM_DIFFUSE_TYPE em_diffuse_type{}; bool use_only_first_antenna_pair{}; bool calc_tau_mins{}; bool simulate_ran{}; int max_num_paths_per_ant_pair{}; [[nodiscard]] bool operator==(const RTConfig &other) const; }
A struct storing the configuration of the raytracing parameters.
Member
Description
num_rays_in_thousands
number of emitted rays in thousands (type
int
)max_num_bounces
maximum number of scattering events for each emitted ray (type
int
)rx_sphere_radius_cm
reception sphere radius (type
float
), in centimetersdiffuse_type
diffuse type to indicate the diffuse scattering model (type
EM_DIFFUSE_TYPE
): Lambertian = 0, Directional = 1use_only_first_antenna_pair
a
bool
variable, when set totrue
only the results for the first RU-UE antenna pair are returned fromrunEMSolver()
calc_tau_mins
a
bool
variable, when set totrue
,runEMSolver()
returns the minimum propagation delayssimulate_ran
a
bool
variable, when set totrue
the full RAN simulation is enabledmax_num_paths_per_ant_pair
the maximum number of strongest paths retained per RU-UE antenna pair (type
int
)
Compute mutual coupling patterns#
compute_mutual_coupling_patterns()
std::vector<emsolver::AntennaPattern> compute_mutual_coupling_patterns(const emsolver::AntennaPanel &panel);
Compute antenna patterns including the effect of mutual coupling.
Supported CUDA archictectures#
supported_cuda_architectures()
std::vector<uint32_t> supported_cuda_architectures();
Returns list of supported cuda architectures based on emsolver library compilation, e.g. [80, 86, 89, 90].
Class AerialEMSolver#
AerialEMSolver()
AerialEMSolver(const std::vector<TXInfo>& tx_info, const std::vector<RXInfo>& rx_info, const AntennaInfo& antenna_info, const GeometryInfo& geometry_info, const RTConfig& rt_cfg, cudaStream_t ext_stream);
Constructor for the AerialEMSolver object.
In/out
Parameter
Description
[in]
tx_info
a vector of
TXInfo
structs storing the information of the RUs[in]
rx_info
a vector of
RXInfo
structs storing the information of the UEs[in]
antenna_info
AntennaInfo
struct storing the information of all antenna panels and antenna radiation patterns[in]
geometry_info
GeometryInfo
struct storing the information of the scene geometry and materials[in]
rt_cfg
RTConfig
struct storing the ray tracing configurations[in]
ext_stream
CUDA stream index (type
cudaStream_t
)~AerialEMSolver()
~AerialEMSolver()
Destructor for the AerialEMSolver object.
allocateDeviceMemForResults()
int32_t allocateDeviceMemForResults(const std::vector<TXInfo>& tx_info, const std::vector<RXInfo>& rx_info, const std::vector<uint32_t>& tx_indices, const std::vector<std::vector<uint32_t>>& rx_indices, const RTConfig& rt_cfg, const int symbols_per_slot, std::vector<d_complex*>& d_all_CFR_results, std::vector<float*>& d_all_tau_mins);
Allocation of device (GPU) memory to store the results of the EM engine.
In/out
Parameter
Description
[in]
tx_info
a vector of
TXInfo
structs storing the information of all the RUs[in]
rx_info
a vector of
RXInfo
structs storing the information of all the UEs[in]
tx_indices
a vector of indices (type
uint32_t
) for the RUs whose results need to be computed[in]
rx_indices
a vector of vectors of indices (type
uint32_t
) of selected UEs for each RUs whose results need to be computed[in]
rt_cfg
RTConfig
struct storing the raytracing configuration[in]
symbols_per_slot
number of symbols (type
int
) in one slot (either 1 or 14)[out]
d_all_CFR_results
a vector of device pointers (type
d_complex
), each pointing to memory address holding the CFRs for the UEs associated to a given RU. The content of the vector follows the content oftx_indices
[out]
d_all_tau_mins
a vector of device pointers (type
float
), each pointing to memory address holding the minimum propagation delay for the UEs associated to a given RU. The content of the vector follows the content oftx_indices
All CFR results for the \(i\)-th RU, i.e.,
d_all_CFR_results_i = d_all_CFR_results[i]
, are stored in the device memory as a flattened representation of multidimensional array whose indices, in order, are<ue_idx>, <symbol_idx>, <freq_idx>, <ue_ant_idx>, <ue_ant_pol_idx>, <ru_ant_idx>, <ru_ant_pol_idx>
.For example, the first 6 elements of
d_all_CFR_results_i
, with the \(i\)-the RU being equipped with dual-polarized antennas and all associated UEs also having dual-polarized antennas, are:For the minimum delay results, there is one minimum delay for all RU-UE antenna pairs (i.e., one value for one RU-UE pair, and
d_all_CFR_results[i]
holds the minimun delays from \(i\)-th RU to its associated UEs).runEMSolver()
int32_t runEMSolver(const unsigned int time_idx, const std::vector<TXInfo>& tx_info, const std::vector<RXInfo>& rx_info, const AntennaInfo& antenna_info, const GeometryInfo &geometry_info, const std::vector<uint32_t>& tx_indices, std::vector<std::vector<uint32_t>>& rx_indices, const RTConfig& rt_cfg, const int symbol_idx, const int symbols_per_slot, std::vector<RayPath>& all_ray_path_results, std::vector<d_complex*>& d_all_CFR_results, std::vector<float*>& d_all_tau_mins);
Launch the EM engine.
In/out
Parameter
Description
[in]
time_idx
time index (type
unsigned int
) in the simulation[in]
tx_info
a vector of
TXInfo
structs storing the information of all the RUs[in]
rx_info
a vector of
RXInfo
structs storing the information of all the UEs[in]
antenna_info
AntennaInfo
struct storing the information of all antenna panels and antenna radiation patterns[in]
geometry_info
GeometryInfo
struct storing the information of the scene geometry and materials[in]
tx_indices
a vector of indices (type
uint32_t
) for the RUs whose results need to be computed[in]
rx_indices
a vector of vectors of indices (type
uint32_t
) of selected UEs for each RUs whose results need to be computed[in]
rt_cfg
RTConfig
struct storing the ray tracing configurations[in]
symbol_idx
symbol index (type
int
) within a slot[in]
symbols_per_slot
number of symbols (type
int
) in one slot (either 1 or 14)[in]
all_ray_path_results
a vector of
RayPath
structs storing all propagation results from all selected RUs to their associated UEs[out]
d_all_CFR_results
a vector of device pointers (type
d_complex
), each pointing to memory address holding the CFRs for the UEs associated to a given RU. The content of the vector follows the content oftx_indices
[out]
d_all_tau_mins
a vector of device pointers (type
float
), each pointing to memory address holding the minimum propagation delay for the UEs associated to a given RU. The content of the vector follows the content oftx_indices
copyResultsFromDeviceToHost()
int32_t copyResultsFromDeviceToHost(const std::vector<uint32_t>& tx_indices, const std::vector<std::vector<uint32_t>>& rx_indices, const RTConfig& rt_cfg, const int symbols_per_slot, const std::vector<d_complex*>& d_all_CFR_results, std::vector<std::vector<d_complex>>* all_CFR_results);
Copy the results of the EM engine from device to host.
In/out
Parameter
Description
[in]
tx_indices
a vector of indices (type
uint32_t
) for the RUs whose results need to be computed[in]
rx_indices
a vector of vectors of indices (type
uint32_t
) of selected UEs for each RUs whose results need to be computed[in]
rt_cfg
RTConfig
struct storing the ray tracing configurations[in]
symbols_per_slot
number of symbols (type
int
) in one slot (either 1 or 14)[in]
d_all_CFR_results
a vector of device pointers (type
d_complex
), each pointing to memory address holding the CFRs for the UEs associated to a given RU. The content of the vector follows the content oftx_indices
[out]
all_CFR_results
a pointer to a host-side vector of vectors for the CFR results, with the inner vector holding the CFRs from one RU to its associated UEs and the outer vector following
tx_indices
deAllocateDeviceMemForResults()
int32_t deAllocateDeviceMemForResults(const RTConfig& rt_cfg, std::vector<d_complex*>& d_all_CFR_results, std::vector<float*>& d_all_tau_mins);
Deallocate device memory previously used for the EM engine results.
In/out
Parameter
Description
[in]
rt_cfg
RTConfig
struct storing the ray tracing configurations[in]
d_all_CFR_results
a vector of device pointers (type
d_complex
): each of them pointing to a device memory that holds complex-valued amplitude of the CFRs from one RU to its associated UEs. The size of the vector is equal to size of the tx_indices[in]
d_all_tau_mins
a vector of device pointers (type
float
), each pointing to memory address holding the minimum propagation delay for the UEs associated to a given RU. The content of the vector follows the content oftx_indices
Error handling#
The EM engine has built-in error handling. The function where the error or invalid condition occurs is recorded and error messages are propagated to both the local and console and the Console tab in the graphical interface.
EMLogLevel
enum class EMLogLevel {ERROR=0, NOTIFY=1, WARNING=2, INFO=3, DEBUG=4, VERBOSE=5}
An enumeration for the level of logging.
EMLogCallback
EMLogCallback = std::function<void(EMLogLevel, const std::string&)>;
Callback function prototype.
registerLogCallback()
int32_t registerLogCallback(EMLogCallback func);
Function to register a callback function (type
EMLogCallback
) for error handling.deregisterLogCallback()
int32_t deregisterLogCallback();
Function to deregister the currently registered callback function.
Source code and dev. container#
The run_aodt_sim_devel.sh
script mounts the source code into the container so that edits and builds within the development container persist on the host disk.
Before running the code inside the dev. container, the aodt_sim
container started by the install script must be stopped.
cd $HOME/aodt_1.3.0/backend
docker compose stop worker
Once the container is stopped, we can follow these instructions to build the aodt_sim
executable:
cd aodt_sim
# Set to desired GPU number. E.g., 0 to use GPU device 0 from inside the container.
GPU=0 ./container/run_aodt_sim_devel.sh
docker exec -it c_aodt_sim_$USER /bin/bash
# Inside the development container
cmake -Bbuild -GNinja -DCMAKE_CUDA_ARCHITECTURES="80;86;89;90" -DNVTX_ENABLED=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build
export PYTHONPATH=$PYTHONPATH:/opt/nvidia/packman/lib/python:/opt/nvidia/aodt_sim/build/src_py/aodt
# Test the build
cd src_py
OMNI_USER=omniverse OMNI_PASS=aerial_123456 python -u -m aodt.app.sim --nats_server_url=nats-server:4222 --nats_subject=aerial --log debug
The example above assumes that the installation scripts have been executed. As part of the installation, lines have been added to the /etc/hosts
file that resolves the IP addresses of omniverse-server
and clickhouse
; both will resolve to the IP address of the backend server.
Notable bug fixes and improvements in release 1.3#
Improved Edge Detection#
Two main improvements to diffraction points:
Improved detection of diffraction edges for rays passing very close to the edge.
Fixed cases where a ray could miss an edge and continue through a building as if the building were transparent. In such scenarios, the next edge would be detected, but the ray would approach from the interior, resulting in physically inconsistent coefficients.
Fixed normal ambiguity#
The reflection and transmission coefficients are functions of the direction of the normal to the impinged surface. In previous releases, when transmission is enabled, the indoor normals can point outwards, thus creating wrong results. From release 1.3, the normals for such reflections are calculated correctly.
Fixed UE orientation#
UE orientation in the second sample was often inexact due to a copy from the first sample. From release 1.3, the orientation is always correct and reflecting the movement of the UE.
Fixed frequency-domain correlation#
When rays hit a point at the border between two objects of different materials, the frequency response of the channel had the wrong frequency correlation function. This is now fixed.
Bug reporting#
When reporting bugs to NVIDIA, the following information ensures that the error can be reproduced and correctly addressed.
The Aerial Omniverse Digital Twin release version
The system configuration where the bug occurs
A detailed description of the issue (errors or unexpected outcomes) and of the steps to reproduce it.
Bugs can be reported via the NVIDIA Aerial Developer Forum, for which a developer account and is necessary.