Aerial Omniverse Digital Twin
Aerial Omniverse Digital Twin (24-1)

Additional Information

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

In presence of a high number of emitted rays (i.e., exceeding 500,000) and scattering events per ray, it is also recommended that

  • the total number of UE per RU does not exceed 1000

  • the total number of links, across the whole population of RUs and UEs - where a link is here intended as a wireless connection between two antenna elements, does not exceed 10,000.

If such large simulation size is desired and during a simulation there is an error log reporting that the simulation does not succeed, lowering the number of emitted rays, the number of scattering events, or turning off the diffusion is suggested.

Functionally,

  • across the selected maximum number of scattering events, diffraction currently can only occur once per ray

  • only direct diffuse scattering (diffuse vertex is in line-of-sight to both the RU and the UE) with a Lambertian pattern is supported

  • the number of rays or paths considered for each RU-UE pair is limited to a max of

    • \(500 \times\) Number of RU antenna elements \(\times\) Number of UE antenna elements

    strongest paths

  • EM engine currently only supports the following antenna models:

    • isotropic,

    • infinitesimal dipole,

    • halfwave dipole,

    • microstrip patch,

    • and custom user input.

  • In the latter case, it is only possible to import one custom model.

  • The radiation solid of a single element is replicated across the whole antenna array. For point sources represented by isotropic of infinitesimal current elements, this is not an issue, but for antennas of finite dimensions (half-wave dipole, microstrip patch, custom user input), this means that there is no account of mutual coupling across antenna elements. Mutual coupling calculations for halfwave dipoles and microstrip antennas, as well as support for using a different radiation solid per each element in the antenna array will be added in a future release.

RAN simulation

For RAN simulation, here are some of the fixed configurations and limitations. We plan to introduce additional features and enhance flexibility in future releases.

  • Supports only 4 transmit antennas (or 2 dual-polarized antennas) and 4 receiver antennas (or 2 dual-polarized antennas).

  • Supports only a 100 MHz bandwidth with 273 PRBs.

  • Supports only Single-User MIMO (SU-MIMO).

  • Supports only 30 kHz subcarrier spacing.

  • If a UE does not have any rays with any of the RUs, it is not currently supported. The use of Spawn Zone to restrict the mobility range of UEs is recommended.

  • Beamforming is not applied.

  • MMSE-IRC is applied indiscriminately at the receivers.

  • The power settings for all gNBs and UEs must be identical across cells and UEs.

  • DMRS positions are fixed in 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.

  • HARQ, if enabled, will allow a maximum of 4 transmissions (i.e. a new transmission, followed by 3 re-transmissions), in case of CRC failures. Transmissions are associated with redundancy versions (RV) in the order of 0, 2, 3, 1.

  • In addition to the noise figure, a fixed thermal noise of -174 dBm/Hz is added at each receiver antenna.

MAC scheduler

  • Non-adaptive HARQ re-transmission: the same scheduling solution (PRB allocation, layer and MCS selection) for the original transmissions are always reused for the HARQ re-transmissions. Further improvement is possible by employing advanced algorithms that may alter the scheduling decisions for re-transmissions.

  • layer selection: the current layer selection algorithm is not optimized for the data transmissions without beamforming as being used in the RAN Simulation. An improved data transmission performance can be expected by employing a layer selection algorithm customized for no beamforming cases.

  • MCS selection: currently RAN Simulation has only integrated an SINR-to-MCS lookup table for single-layer transmissions under AWGN channel. The SINR-to-MCS mappings in this lookup table may not be accurate for transmissions with more than one layers. This can be improved by using separate SINR-to-MCS lookup tables under varied numbers of layers and different channel characteristics generated from link level simulations.

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 (1.0.0 for this release)

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
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
tap_power array(array(float32)) Power of the raypath channel tap in Watts

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 of antenna element indices for the RU antenna panel
ue_ant_el tuple(uint32, uint32, uint32) Tuple 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 of antenna element indices for the RU antenna panel
ue_ant_el tuple(uint32, uint32, uint32) Tuple 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

ID uint32 ID of the panel as defined in the UI stage widget
carrier_freq float32 Carrier frequency associated with this panel
radiated_power float32 Radiated power (in Watts) associated with this panel
is_dual_polarized boolean Indicates if panel is dual-polarized. 1=dual polarization, 0=single polarization.
num_hor_el uint32 Number of columns in the planar array
num_ver_el uint32 Number of rows in the planar array
ant_el_types array(enum) Type of antenna. Isotropic=0, Infinitesimal_dipole=1, Halfwave_dipole=2, Rec_microstrip_patch=3, User_input=4
hor_spacing float32 Spacing of horizontal antenna elements in cm
vert_spacing float32 Spacing of vertical antenna elements in cm
roll_first_pol float32 Rotation (in radians) of the antenna element, corresponding to the first polarization
roll_second_pol float32 Rotation (in radians) of the antenna element, corresponding to the second polarization. Only used for dual-polarized elements.

7. 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
height float32 Height of the UE in meters
mech_tilt float32 Tilt of of UE antenna panel in degrees
panel array(uint32) Array of panels 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]
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]

8. 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
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 IDs associated with this RU
position array(float32) Position of the RU in the stage. The array contains 3 elements (x, y, z).

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

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

11. training_result

Field

Type

Comment

time_idx uint32 Current time index of the simulation
name string Optional name of a model
training_losses array(tuple(uint32,float32)) Training losses: there may be multiple iterations trained for a given time index, so format is [(iteration0, loss0), (iteration1, loss1), …]
validation_losses array(tuple(uint32,float32)) Optional validation losses, same format as training losses
test_losses array(tuple(uint32,float32)) Optional test losses, same format as training losses
baseline_losses array(tuple(uint32,float32)) Baseline losses, same format as training losses
title string Optional title of loss plot in the UI, e.g. Training Loss
y_label string Optional y-label of loss plot in the UI, e.g. MSE (dB)
x_label string Optional x-label of loss plot in the UI, e.g. Slot

12. world

Field

Type

Comment

prim_path string Prim path of the building
material string Name of material assigned to this prim
is_rf_active uint8 If geometry of the structure is considered by the EM solver (0=not considered, 1=considered)
is_rf_diffuse uint8 If geometry of the structure is considered for diffusion in the EM solver (0=not considered, 1=considered)

13. materials

Field

Type

Comment

label string Captures the material set in the UI stage
itu_r_p2040_a float64 ITU-R P2040 ‘a’ parameter \(^{[1]}\)
itu_r_p2040_b float64 ITU-R P2040 ‘b’ parameter \(^{[1]}\)
itu_r_p2040_c float64 ITU-R P2040 ‘c’ parameter \(^{[1]}\)
itu_r_p2040_d float64 ITU-R P2040 ‘d’ parameter \(^{[1]}\)
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 in the effective roughness (ER) model
exponent_alpha_r int32 Integer exponent parameter for the directivity of the scattering lobe in the specular reflection direction in the ER model
exponent_alpha_i int32 Integer exponent parameter for the directivity of the back-scattering lobe in the incidence direction in the double-lobe model
lambda_r float64 Ratio between the specular-direction scattering power and the total scattering power in double-lobe model

[1] Table 3 of ITU, “Effects of building materials and structures on radio wave propagation above about 100 MHz”, Recommendation P.2040-3, August 2023.

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 of the development container. Refer to the Installation section of this guide for how to start the development container. Then identify the name of the database of interest by using the clickhouse-client or using the database name in the Configurations tab in the UI.

Copy
Copied!
            

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

Copy
Copied!
            

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:

Copy
Copied!
            

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.

Copy
Copied!
            

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:

Copy
Copied!
            

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 CFR

  • scs: Subcarrier spacing

  • ue_fc: Center frequency of the UE

  • ru_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++. The source code to the reader is provided in the examples/ directory and can be compiled into a shared library in the development container. See Readme_chapi.md for more details. The library provides the following Python bindings:

  • cfrs = read_cfrs_db(hostname,database)

  • cirs,delays = read_cfrs_db(hostname,database)

For example:

Copy
Copied!
            

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:

Copy
Copied!
            

python3 extract_CIR.py --database <database_name> --hostname <hostname>

Copy
Copied!
            

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

Copy
Copied!
            

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:

Copy
Copied!
            

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.

Copy
Copied!
            

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:

Copy
Copied!
            

python plot_CFR.py -filename sample-<time_idx>.dat --sample <time_idx> --RU <tx_id> --UE <rx_id>

Jupyter notebooks

It may be convenient to execute the post processing scripts via Jupyter notebooks, if running on a different machine than the backend. The following notebooks are available in the examples/ directory:

  • extract_CFR_sample.ipynb

  • extract_CIR_sample.ipynb

  • Fast Clickhouse Access.ipynb

The Jupyter Notebooks can be accessed by opening a web browser using the address of the backend http://omniverse-server:8888/. The webpage may ask for a token the first time. As mentioned in the Installation section of this guide, the token is shown at the end of the install process. The token may also be found on the backend server, in the docker compose examples.

Copy
Copied!
            

cd <path to source top level installation>/examples docker compose -f docker-compose-examples.yaml logs | grep token=

The EM engine is developed directly by NVIDIA, but it modularly embedded in the Aerial Omniverse Digital Twin through a specific interface. With future releases, there will be support for swapping in and out different EM engines. This section aims at preparing for such a possibility by providing an overview of the key mechanics of NVIDIA’s EM engine.

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 theaerial_emsolver_api.h header and make use of the C++/CUDA primitive data types.

Data types

  • d_complex

    Copy
    Copied!
                

    typedef thrust::complex<float> d_complex

    Thrust complex data type used in both host code and device code.

  • d_complex4

    Copy
    Copied!
                

    typedef struct d_complex4 { d_complex m[4]{}; } d_complex4

    An array of four d_complex elements.

  • Matrix4x4

    Copy
    Copied!
                

    typedef struct Matrix4x4 { float m[4][4]{}; } Matrix4x4

    A \(4\times4\) matrix of d_complex elements.

  • BuildingEdge

    Copy
    Copied!
                

    struct BuildingEdge { float3 p1{}; float3 p2{}; float3 e{}; float3 e1{}; float3 e2{}; float3 n1{}; float3 n2{}; int material_id1{}; int material_id2{}; int diffuse_attr_1{}; int diffuse_attr_2{}; }

    A struct storing geometry data of each building edge in the scene.

    Member

    Description

    p1 the first building edge vertex point (type float3), in centimeters
    p2 the second building edge vertex point (type float3), in centimeters
    e unit vector from p1 to p2 (type float3)
    e1 unit vector tangent to the first half plane describing the building edge (type float3)
    e2 unit vector tangent to the second half plane describing the building edge (type float3)
    n1 normal vector to the first half plane describing the building edge (type float3)
    n2 normal vector to the second half plane describing the building edge (type float3)
    material_id1 material index of the first half plane describing the building edge (type int)
    material_id2 material index of the second half plane describing the building edge (type int)
    diffuse_attr_1 diffuse attribute of the first half plane describing the building edge (type int); 0 if the surface is non-diffuse and 1 otherwise
    diffuse_attr_2 diffuse attribute of the second half plane describing the building edge (type int); 0 if the surface is non-diffuse and 1 otherwise

    An illustration of the geometry data associated with an edge is shown in the figure below.

    building_edge_data.png

    EMMaterial

    Copy
    Copied!
                

    struct EMMaterial { float4 abcd{}; float roughness_rms{}; float k_xpol{}; float scattering_coeff{} int exponent_alpha_R{} int exponent_alpha_I{} float lambda_R{} }

    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 1
    roughness_rms the root mean square of the surface roughness (type float), in meters
    k_xpol scattering cross-polarization/col-polarization power ratio (type float)
    scattering_coeff scattering coefficient in the effective roughness (ER) model 2 (type float)
    exponent_alpha_R integer exponent for the directivity of the scattering lobe (type int)
    exponent_alpha_I integer exponent parameter for the directivity of the back-scattering lobe in the double-lobe model (type int)
    lambda_R ratio between the specular-direction scattering power and the total scattering power in the double-lobe model (type float)
  • EM_INTERACT_TYPE

    Copy
    Copied!
                

    enum EM_INTERACT_TYPE : unsigned int { Emission = 0, Reflection = 1, Diffraction = 2, Diffuse = 3, Reception = 4, Reserved, }

    An enumeration of EM interaction types per ray.

  • RayPath

    Copy
    Copied!
                

    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+2]{}; float3 points[MAX_NUM_INTERACTIONS+2]{}; int prim_ids[MAX_NUM_INTERACTIONS+2]{}; float3 normals[MAX_NUM_INTERACTIONS+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* prim_ids, float3* normals, int tx_id, int rx_id, int rx_index, int num_points, int txrxPairID) : tx_ij{tx_ij[0], tx_ij[1]}, rx_ij{rx_ij[0], rx_ij[1]} { this->tx_id = tx_id; this->rx_id = rx_id; this->rx_index = rx_index; this->num_points = num_points; for(int i=0; i<num_points; i++) { this->points[i] = make_float3(points[i].x, points[i].y, points[i].z); this->prim_ids[i] = prim_ids[i]; this->normals[i] = make_float3(normals[i].x, normals[i].y, normals[i].z); this->point_types[i] = point_types[i]; } for(int i=0; i<4; i++) { this->cir_ampl[i] = d_complex(0.0, 0.0); } this->cir_delay = 0.0; } }

    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 and j for vertical index) of the antenna element within the RU panel
    rx_ij two-element array of indices (type int, i for horizontal index and j for vertical index) of the antenna element within the UE panel
    rx_index index of the UE (type int)
    point_types an array of EM_INTERACT_TYPE storing the EM interaction types for points along the path
    points an array of float3 storing the (x, y, z) coordinates of interaction points, in centimeters
    prim_ids an array of int storing the indices of the geometry primitive at the interaction points: the hit triangle index for a reflection, hit edge index for a diffraction, -1s otherwise
    normals an array of float3 storing the normals at the interaction points
    num_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

    *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

    Copy
    Copied!
                

    enum ANTENNA_TYPE : unsigned int { Isotropic = 0, Infinitesimal_dipole = 1, Halfwave_dipole = 2, Rec_microstrip_patch = 3, User_input = 4 }

    An enumeration for the antenna types currently supported by the EM solver.

  • AntennaPattern

    Copy
    Copied!
                

    struct AntennaPattern { std::vector<float> thetas{}; std::vector<float> phis{}; std::vector<d_complex> ampls_theta{}; std::vector<d_complex> ampls_phi{}; int num_thetas{}; int num_phis{}; }

    A struct storing a user input antenna pattern.

    Member

    Description

    thetas a vector storing elevation angles (type float) in radians
    phis a vector storing azimuth angles (type float) in radians
    ampls_theta a vector storing complex-valued amplitudes (type d_complex) of the antenna radiated field along the theta direction
    ampls_phi a vector storing complex-valued amplitudes (type d_complex) of the antenna radiated field along the phi direction
    num_thetas number of theta angles (type int)
    num_phis number of phi angles (type int)
  • AntennaPanel

    Copy
    Copied!
                

    struct AntennaPanel { int id{}; std::vector<ANTENNA_TYPE> antenna_element_types{}; double reference_freq{}; double radiated_power{}; bool dual_polarized{}; unsigned int num_loc_antenna_horz{}; unsigned 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{}; }

    An struct storing information for a given antenna panel.

    Member

    Description

    id ID of the panel (type int)
    antenna_element_types a vector of ANTENNA_TYPE values indicating the types of the antenna elements in the panel
    reference_freq center frequency (type double) of the panel, in Hertz
    radiated_power radiated power (type double) of the panel, in Watts
    dual_polarized a bool variable to indicate if the panel antennas are dual- (true) or single- polarized (false)
    num_loc_antenna_horz number of antenna elements (type unsigned int) in the planar array along a row
    num_loc_antenna_vert number of antenna elements (type unsigned int) in the planar array along a column
    antenna_spacing_horz horizontal antenna element spacing (type double), in centimeters
    antenna_spacing_vert vertical antenna element spacing (type double), in centimeters
    antenna_roll_angle_first_polz angular displacement of the antenna element realizing the first polarization (type double), in radians
    antenna_roll_angle_second_polz angular displacement of the element realizing the second polarization (type double), in radians
  • TXInfo

    Copy
    Copied!
                

    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<ANTENNA_TYPE> antenna_element_types{}; 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 centimeters
    Ttx a Matrix4x4 transformation matrix for the RU combining translation and rotation, in centimeters
    panel_id a vector of indices (type int) identifying the panels used by the RU; currently only size 1 is supported
    height height (type float) calculated from RU base to the RU center, in centimeters
    mech_azimuth_deg mechanical azimuth (type float) of the RU, in degrees
    mech_tilt_deg mechanical tilt (type float) of the RU, in degrees
    carrier_freq carrier frequency (type float) of the RU, in Hertz
    subcarrier_spacing sub-carrier spacing (type float), in Hertz
    fft_size FFT size (type int) used for wideband CFR calculation
    radiated_power radiated power (type float) of the RU, in Watts
    antenna_element_types a vector of ANTENNA_TYPE values indicating the types of the antenna elements used in the RU panel
    dual_polarized_antenna a bool variable to indicate if the antenna panel is composed by dual- (true) or single- polarized (false) elements
    antenna_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 polarization
    num_loc_antenna_horz number of antenna elements (type unsigned int) in the horizontal direction within the antenna panel
    num_loc_antenna_vert number of antenna elements (type unsigned int) in the vertical direction within the antenna panel
    loc_antenna vector of (x, y, z) of antenna positions within the antenna panel (type float3), in centimeters
    ij_antenna a vector of pairs of indices (type int) storing horizontal and vertical indices of the antenna elements in the RU antenna panel
  • RXInfo

    Copy
    Copied!
                

    struct RXInfo { int rx_ID{}; float3 rx_center{}; Matrix4x4 Trx{}; std::vector<int> panel_id{}; float radiated_power{}; std::vector<ANTENNA_TYPE> antenna_element_types{}; 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 centimeters
    Trx a Matrix4x4 transformation matrix for the UE combining translation and rotation, in centimeters
    panel_id a vector of indices (type int) identifying the panels used by the UE; currently only size 1 is supported
    radiated_power radiated power (type float) of the UE, in Watts
    antenna_element_types a vector of ANTENNA_TYPE values indicating the types of the antenna elements used in the UE panel
    dual_polarized_antenna a bool variable to indicate if the antenna panel is composed by dual- (true) or single- polarized (false) elements
    antenna_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 polarization
    num_loc_antenna_horz number of antenna elements (type unsigned int) in the horizontal direction within the antenna panel
    num_loc_antenna_vert number of antenna elements (type unsigned int) in the vertical direction within the antenna panel
    loc_antenna vector of (x, y, z) of antenna positions within the antenna panel (type float3), in centimeters
    ij_antenna a vector of pairs of indices (type int) storing horizontal and vertical indices of the antenna elements in the RU antenna panel
  • AntennaInfo

    Copy
    Copied!
                

    struct AntennaInfo { bool has_user_input_tx_antenna{}; AntennaPattern tx_antenna_pattern{}; bool has_user_input_rx_antenna{}; AntennaPattern rx_antenna_pattern{}; }

    The EM engine supports several classical antenna patterns listed in ANTENNA_TYPE, and also custom antenna patterns in the format specified by AntennaPattern. The AntennaInfo struct stores the information of whether some customized antenna pattern is used for a node (RU/UE) and the corresponding antenna pattern.

    Member

    Description

    has_user_input_tx_antenna a bool variable to indicate whether a User_input antenna type is used for a RU
    tx_antenna_pattern AntennaPattern struct storing the antenna pattern for the RU
    has_user_input_rx_antenna a bool variable to indicate whether a User_input antenna type is used for an UE
    rx_antenna_pattern AntennaPattern struct storing the antenna pattern for the UE
  • GeometryInfo

    Copy
    Copied!
                

    struct GeometryInfo { std::vector<float3> building_mesh_vertices{}; std::vector<int> triangle_material_ids{}; std::vector<int> triangle_diffuse_attr{}; std::vector<BuildingEdge> building_edges{}; std::unordered_map<std::string, std::pair<int,EMMaterial>> material_dict{}; };

    A struct storing information for the geometries in the scene.

    Member

    Description

    building_mesh_vertices a vector of vertices (type float3) of the buildings in the scene*, in centimeters
    triangle_material_ids a vector of material indices (type int) of the building triangles
    triangle_diffuse_attr a vector of diffuse attributes (type int) of the building triangles, 0 if the triangle is non-diffuse and 1 otherwise
    building_edges a vector of building edges (type BuildingEges)
    material_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>

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

  • RTConfig

    Copy
    Copied!
                

    struct RTConfig { int num_rays_in_thousands{}; int max_num_bounces{}; bool use_only_first_antenna_pair{}; bool calc_tau_mins{}; bool simulate_ran{}; }

    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)
    use_only_first_antenna_pair a bool variable, when set to true only the results for the first RU-UE antenna pair are returned from runEMSolver()
    calc_tau_mins a bool variable, when set to true, runEMSolver() returns the minimum propagation delays
    simulate_ran a bool variable, when set to true the full RAN simulation is enabled

Class AerialEMSolver

  • AerialEMSolver()

    Copy
    Copied!
                

    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 to be considered
    [in] rx_info a vector of RXInfo structs storing the information of the UEs to be considered
    [in] antenna_info AntenaInfo struct storing the information of the user’s input for the antenna 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()

    Copy
    Copied!
                

    ~AerialEMSolver()

    Destructor for the AerialEMSolver object.

  • allocateDeviceMemForResults()

    Copy
    Copied!
                

    int32_t allocateDeviceMemForResults(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_indices a vector of indices (type uint32_t) for the RUs to be simulated
    [in] rx_indices a vector of vectors of indices (type uint32_t) of selected UEs for each selected RUs
    [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 of tx_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 of tx_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>, <ru_ant_idx>, <ue_ant_pol_idx>, <ru_ant_pol_idx>. Similar arrangement is used for the minimum delay results.

    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 having two single-polarized antennas, are:

    CFRs_mem_arrangement.png

  • runEMSolver()

    Copy
    Copied!
                

    int32_t runEMSolver(const unsigned int time_idx, const std::vector<TXInfo>& tx_info, const std::vector<RXInfo>& rx_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 to be considered
    [in] rx_info a vector of RXInfo structs storing the information of all the UEs to be considered
    [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 RU 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 of tx_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 of tx_indices
  • copyResultsFromDeviceToHost()

    Copy
    Copied!
                

    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 of tx_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()

    Copy
    Copied!
                

    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 of tx_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

    Copy
    Copied!
                

    enum class EMLogLevel {ERROR=0, NOTIFY=1, WARNING=2, INFO=3, DEBUG=4, VERBOSE=5}

    An enumeration for the level of logging.

  • EMLogCallback

    Copy
    Copied!
                

    EMLogCallback = std::function<void(EMLogLevel, const std::string&)>

    Callback function prototype.

  • registerLogCallback()

    Copy
    Copied!
                

    int32_t registerLogCallback(EMLogCallback func)

    Function to register a callback function (type EMLogCallback) for error handling.

  • deregisterLogCallback()

    Copy
    Copied!
                

    int32_t deregisterLogCallback()

    Function to deregister the currently registered callback function.

The source code for the RAN digital twin can be found in the folder aodt_sim, a subfolder of backend_bundle. This source code can be modified using the released development container. To launch the development container, we can use the aodt_sim\container\run_aodt_sim_devel.sh script, which will launch the development container in daemon mode, and then use docker exec -it c_aodt_sim_$USER /bin/bash to start a shell session inside the development 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. To build the aodt_sim executable, we can follow these instructions, starting on the host where aodt_sim runs:

Copy
Copied!
            

cd aodt_sim # Here GPU is set to 0 to use GPU device 0 inside the container. # Set to desired GPU number. GPU=0 ./container/run_aodt_sim_devel.sh docker exec -it c_aodt_sim_$USER /bin/bash # Inside the development container # Set SM to the value for the GPU being used. Examples include # A100=80, H100=90, L40=89 SM=80 cmake -Bbuild -GNinja -DCMAKE_CUDA_ARCHITECTURES=$SM -DNVTX_ENABLED=OFF -DENABLE_CCACHE=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo cmake --build build # Test the build OMNI_USER=omniverse OMNI_PASS=aerial_123456 ./build/aodt_sim --nucleus omniverse://omniverse-server

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.


[1]

ITU, “Effects of building materials and structures on radio wave propagation above about 100 MHz”, Recommendation P.2040-3, August 2023.

[2]

V. Degli-Esposti, F. Fuschini, E. M. Vitucci, and G. Falciasecca, “Measurement and modelling of scattering from buildings,” IEEE Trans. Antennas Propag., vol. 55, no. 1, pp. 143–153, January 2007.

Previous Release Notes
© Copyright 2024, NVIDIA. Last updated on Jul 19, 2024.