Python API Documentation for Quadriga-Lib v0.11.0
Notes
Overview
Array antenna functions
Channel functions
Miscellaneous / Tools
| acdf | Calculate the empirical averaged cumulative distribution function (CDF) |
| calc_angular_spread | Calculate azimuth and elevation angular spreads with spherical wrapping |
| calc_cross_polarization_ratio | Calculate the cross-polarization ratio (XPR) for linear and circular polarization bases |
| calc_delay_spread | Calculate the RMS delay spread in [s] |
| calc_rician_k_factor | Calculate the Rician K-Factor from channel impulse response data |
| cart2geo | Transform Cartesian (x,y,z) coordinates to Geographic (az, el, length) coordinates |
| components | Returns the version numbers of all quadriga-lib sub-components |
| version | Returns the quadriga-lib version number |
| write_png | Write data to a PNG file |
Site-Specific Simulation Tools
Array antenna functions
calc_directivity - Calculates the directivity (in dBi) of array antenna elements
combine_pattern - Calculate effective radiation patterns for array antennas
-
Description:
An array antenna consists of multiple individual elements. Each element occupies a specific position
relative to the array's phase-center, its local origin. Elements can also be inter-coupled,
represented by a coupling matrix. By integrating the element radiation patterns, their positions,
and the coupling weights, one can determine an effective radiation pattern observable by a receiver
in the antenna's far field. Leveraging these effective patterns is especially beneficial in antenna
design, beamforming applications such as in 5G systems, and in planning wireless communication
networks in complex environments like urban areas. This streamlined approach offers a significant
boost in computation speed when calculating MIMO channel coefficients, as it reduces the number of
necessary operations. The function arrayant_combine_pattern is designed to compute these effective
radiation patterns.
-
Usage:
from quadriga_lib import arrayant
# Minimal example
arrayant_out = arrayant.combine_pattern(arrayant)
# Optional inputs: freq, azimuth_grid, elevation_grid
arrayant_out = arrayant.combine_pattern(arrayant, freq, azimuth_grid, elevation_grid)
-
Input Arguments:
arrayant
Dictionary containing the arrayant data with the following keys:
e_theta_re |
e-theta field component, real part |
Shape: (n_elevation, n_azimuth, n_elements) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_elevation, n_azimuth, n_elements) |
e_phi_re |
e-phi field component, real part |
Shape: (n_elevation, n_azimuth, n_elements) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_elevation, n_azimuth, n_elements) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation) |
element_pos |
Antenna element (x,y,z) positions |
Shape: (3, n_elements) |
coupling_re |
Coupling matrix, real part |
Shape: (n_elements, n_ports) |
coupling_im |
Coupling matrix, imaginary part |
Shape: (n_elements, n_ports) |
center_freq |
Center frequency in [Hz], optional |
Scalar |
name |
Name of the array antenna object, optional |
String |
freq (optional)
An alternative value for the center frequency. Overwrites the value given in arrayant_in. If
neither freq not arrayant_in["center_freq") are given, an error is thrown.
azimuth_grid (optional)
Alternative azimuth angles for the output in [rad], -pi to pi, sorted, Shape: (n_azimuth_out),
If not given, arrayant_in["azimuth_grid") is used instead.
elevation_grid (optional)
Alternative elevation angles for the output in [rad], -pi/2 to pi/2, sorted, Shape: (n_elevation_out),
If not given, arrayant_in["elevation_grid") is used instead.
-
Output Arguments:
arrayant_out
Dictionary containing the arrayant data with the following keys:
e_theta_re |
e-theta field component, real part |
Shape: (n_elevation_out, n_azimuth_out, n_ports) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_azimuth_out, n_azimuth_out, n_ports) |
e_phi_re |
e-phi field component, real part |
Shape: (n_azimuth_out, n_azimuth_out, n_ports) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_azimuth_out, n_azimuth_out, n_ports) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth_out) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_azimuth_out) |
element_pos |
Antenna element (x,y,z) positions, set to 0 |
Shape: (3, n_ports) |
coupling_re |
Coupling matrix, real part, identity matrix |
Shape: (n_ports, n_ports) |
coupling_im |
Coupling matrix, imaginary part, zero matrix |
Shape: (n_ports, n_ports) |
center_freq |
Center frequency in [Hz] |
Scalar |
name |
Name of the array antenna object, same as input |
String |
copy_element - Create copies of array antenna elements
-
Description:
Copies one or more antenna elements to new positions within the arrayant, expanding the element
count if necessary. Supports both single-frequency arrayants (3D pattern fields) and multi-frequency
arrayants (4D pattern fields). For multi-frequency inputs, element copying is applied consistently
across all frequency entries.
The function auto-detects whether the input is single-frequency or multi-frequency by inspecting
the dimensionality of the e_theta_re field (3D = single, 4D = multi).
-
Usage:
from quadriga_lib import arrayant
# Single-frequency: copy element 0 to position 1
arrayant_out = arrayant.copy_element(ant, source_element=[0], dest_element=[1])
# Single-frequency: copy element 0 to positions 2 and 3
arrayant_out = arrayant.copy_element(ant, source_element=[0], dest_element=[2, 3])
# Multi-frequency (4D patterns): same interface
speaker_out = arrayant.copy_element(speaker, source_element=[0], dest_element=[1])
# Copy multiple sources to multiple destinations (must be same length)
arrayant_out = arrayant.copy_element(ant, source_element=[0, 1], dest_element=[2, 3])
-
Input Arguments:
arrayant [1] (required)
Dictionary containing the arrayant data. Pattern fields may be 3D (single-frequency) or
4D (multi-frequency, 4th dimension = frequency). The following keys are expected:
e_theta_re |
e-theta field component, real part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_phi_re |
e-phi field component, real part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements) |
coupling_re |
Coupling matrix, real part, optional |
Shape: (n_elem, n_ports) or (n_elem, n_ports, n_freq) |
coupling_im |
Coupling matrix, imaginary part, optional |
Shape: (n_elem, n_ports) or (n_elem, n_ports, n_freq) |
center_freq |
Center frequency in [Hz], optional |
Scalar or 1D array (n_freq) |
name |
Name of the array antenna object, optional |
String |
source_element [2] (required)
Index of the source elements (0-based), scalar or vector
dest_element [3] (optional)
Index of the destination elements (0-based), either as a vector or as a scalar. If source_element
is also a vector, dest_element must have the same length.
-
Output Arguments:
arrayant_out
Dictionary containing the arrayant data with the copied elements. Output format matches the
input format (3D for single-frequency, 4D for multi-frequency).
export_obj_file - Creates a Wavefront OBJ file for visualizing the shape of the antenna pattern
-
Usage:
from quadriga_lib import arrayant
arrayant.export_obj_file( fn, arrayant, directivity_range, colormap,
object_radius, icosphere_n_div, i_element )
-
Input Arguments:
fn
Filename of the OBJ file, string
arrayant
Dictionary containing array antenna data with at least the following keys:
e_theta_re |
Real part of e-theta field component |
Shape: (n_elevation, n_azimuth, n_elements_c) |
e_theta_im |
Imaginary part of e-theta field component |
Shape: (n_elevation, n_azimuth, n_elements_c) |
e_phi_re |
Real part of e-phi field component |
Shape: (n_elevation, n_azimuth, n_elements_c) |
e_phi_im |
Imaginary part of e-phi field component |
Shape: (n_elevation, n_azimuth, n_elements_c) |
azimuth_grid |
Azimuth angles in [rad] -pi to pi, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements) |
name |
Name of the array antenna object |
String |
directivity_range
Directivity range of the antenna pattern visualization in dB
colormap
Colormap for the visualization, string, supported are 'jet', 'parula', 'winter', 'hot', 'turbo',
'copper', 'spring', 'cool', 'gray', 'autumn', 'summer', Optional, default = 'jet'
object_radius
Radius in meters of the exported object
icosphere_n_div
Map pattern to an Icosphere with given number of subdivisions
element
Antenna element indices, 0-based, empty = export all
generate - Generates predefined array antenna models
-
Description:
This functions can be used to generate a variety of pre-defined array antenna models, including 3GPP
array antennas used for 5G-NR simulations. The first argument is the array type. The following input
arguments are then specific to this type.
-
Usage:
from quadriga_lib import arrayant
# Isotropic radiator, vertical polarization
arrayant = arrayant.generate('omni', res)
# Short dipole radiating with vertical polarization
arrayant = arrayant.generate('dipole', res)
# Half-wave dipole radiating with vertical polarization
arrayant = arrayant.generate('half-wave-dipole', res)
# Cross-polarized isotropic radiator
arrayant = arrayant.generate('xpol', res)
# A unified linear array with isotropic patterns
arrayant = arrayant.generate('ula', res=30, N=4, freq=2.4e9, spacing=0.7)
# An antenna with a custom 3dB beam with (in degree)
arrayant = arrayant.generate('custom', res, az_3dB, el_3db, rear_gain_lin)
# 3GPP-NR antenna model (example for 2x2, V-polarized, 0.7λ spacing)
arrayant = arrayant.generate('3gpp', M=2, N=2, freq=3.7e9, pol=1, spacing=0.7)
# Planar multi-element antenna with support for multiple beam directions
arrayant = arrayant.generate('multibeam', M=6, N=6, freq=3.7e9, pol=1, spacing=0.7, az=[-30.0, 30.0], el=[0.0, 0.0])
-
Input Arguments:
type
Antenna model type, string
res
Pattern resolution in [deg], scalar, default = 1 deg
freq
The center frequency in [Hz], scalar, default = 299792458 Hz
-
Input arguments for type `custom`, `3gpp` and `multibeam`:
az_3dB
3dB beam width in azimuth direction in [deg], scalar,
default for custom = 90 deg, default for 3gpp = 67 deg, multibeam = 120 deg
el_3db
3dB beam width in elevation direction in [deg], scalar,
default for custom = 90 deg, default for 3gpp = 67 deg, multibeam = 120 deg
rear_gain_lin
Isotropic gain (linear scale) at the back of the antenna, scalar, default = 0.0
-
Input arguments for type `3gpp` and `multibeam`:
M
Number of vertically stacked elements for 3gpp and multibeam, scalar, default = 1
N
Number of horizontally stacked elements for 3gpp, ula and multibeam, scalar, default = 1
pol
Polarization indicator to be applied for each of the M elements:
pol = 1 |
vertical polarization (default value), 3gpp and multibeam |
pol = 2 |
H/V polarized elements, results in 2NM elements, 3gpp and multibeam |
pol = 3 |
+/-45° polarized elements, results in 2NM elements, 3gpp and multibeam |
pol = 4 |
vertical polarization, combines elements in vertical direction, results in N elements, 3gpp only |
pol = 5 |
H/V polarization, combines elements in vertical direction, results in 2N elements, 3gpp only |
pol = 6 |
+/-45° polarization, combines elements in vertical direction, results in 2N elements, 3gpp only |
Polarization indicator is ignored when a custom pattern is provided.
tilt
The electric downtilt angle in [deg], Only relevant for pol = 4/5/6, 3gpp only, scalar, default = 0
spacing
Element spacing in [λ] for 3gpp, ula and multibeam, scalar, default = 0.5
Mg
Number of nested panels in a column, 3gpp only, scalar, default = 1
Ng
Number of nested panels in a row, 3gpp only, scalar, default = 1
dgv
Panel spacing in vertical direction in [λ], 3gpp only, scalar, default = 0.5
dgh
Panel spacing in horizontal direction in [λ], 3gpp only, scalar, default = 0.5
beam_az
Azimuth beam angles (degrees), multibeam only, Vector of length n_beams. Default: [0.0]
beam_el
Elevation beam angles (degrees), multibeam only, Vector of length n_beams. Default: [0.0]
beam_weight
Scaling factors for each beam, multibeam only, The vector must have the same length as beam_az and beam_el.
Values are normalized so that their sum equals 1. Can be used to prioritize beams.
Default: {1.0}
separate_beams
If set to true, create a separate beam for each angle pair (ignores weights), multibeam only
apply_weights
Switch to apply the beam-forming weights
pattern (optional)
Dictionary containing a custom pattern (default = empty) with at least the following keys:
e_theta_re |
Real part of e-theta field component |
Shape: (n_elevation, n_azimuth, n_elements_c) |
e_theta_im |
Imaginary part of e-theta field component |
Shape: (n_elevation, n_azimuth, n_elements_c) |
e_phi_re |
Real part of e-phi field component |
Shape: (n_elevation, n_azimuth, n_elements_c) |
e_phi_im |
Imaginary part of e-phi field component |
Shape: (n_elevation, n_azimuth, n_elements_c) |
azimuth_grid |
Azimuth angles in [rad] -pi to pi, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation) |
-
Output Arguments:
arrayant
Dictionary containing the arrayant data with the following keys:
e_theta_re |
e-theta field component, real part |
Shape: (n_elevation, n_azimuth, n_elements) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_elevation, n_azimuth, n_elements) |
e_phi_re |
e-phi field component, real part |
Shape: (n_elevation, n_azimuth, n_elements) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_elevation, n_azimuth, n_elements) |
azimuth_grid |
Azimuth angles in [rad] -pi to pi, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation) |
element_pos |
Antenna element (x,y,z) positions |
Shape: (3, n_elements) |
coupling_re |
Coupling matrix, real part |
Shape: (n_elements, n_ports) |
coupling_im |
Coupling matrix, imaginary part |
Shape: (n_elements, n_ports) |
center_freq |
Center frequency in [Hz], optional, default = 0.3 GHz |
Scalar |
name |
Name of the array antenna object |
String |
generate_speaker - Generates a parametric loudspeaker directivity model
-
Description:
This function generates frequency-dependent loudspeaker radiation patterns by combining a driver
directivity model with an enclosure radiation modifier and a Butterworth-style bandpass frequency
response. Returns a multi-frequency arrayant dictionary where the pattern fields are 4D arrays
(the 4th dimension is frequency) and center_freq is a 1D array of frequency samples in Hz.
Multi-driver speakers (e.g. two-way systems) are modelled by generating each driver separately and
combining them via arrayant_concat_multi. Crossover behavior emerges naturally from overlapping
bandpass responses.
Three driver types are supported:
piston: Circular piston in a baffle using the classical Bessel J1 formula. Transitions from
omnidirectional at low ka to progressively narrower beaming at high ka.
horn: Separable cosine-power directivity with frequency-dependent pattern control. Below the
horn control frequency, the pattern blends toward omnidirectional.
omni: Frequency-independent omnidirectional pattern (suitable for subwoofers).
Four enclosure radiation types modify the base driver pattern:
monopole: No modification (4π radiation). Appropriate for subwoofers in free space.
hemisphere: Sealed box on a finite baffle with frequency-dependent baffle step transition.
dipole: Open baffle / planar speaker with figure-8 pattern.
cardioid: Monopole + dipole combination with null at the rear.
The frequency response follows a Butterworth-style bandpass filter. If no frequency vector is
provided, third-octave band center frequencies are auto-generated covering the range from one band
below the lower cutoff to one band above the upper cutoff, clipped to 20–20000 Hz.
-
Usage:
from quadriga_lib import arrayant
# Default piston driver (4-inch, 80 Hz – 12 kHz)
speaker = arrayant.generate_speaker()
# Horn tweeter with custom coverage
speaker = arrayant.generate_speaker(
driver_type='horn',
radius=0.025,
lower_cutoff=1500.0,
upper_cutoff=20000.0,
radiation_type='hemisphere',
hor_coverage=90.0,
ver_coverage=60.0
)
# Omnidirectional subwoofer with steep rolloff
speaker = arrayant.generate_speaker(
driver_type='omni',
radius=0.165,
lower_cutoff=30.0,
upper_cutoff=300.0,
lower_rolloff_slope=24.0,
upper_rolloff_slope=24.0,
sensitivity=90.0,
radiation_type='monopole'
)
# Piston driver at specific frequencies
import numpy as np
speaker = arrayant.generate_speaker(
frequencies=np.array([100.0, 500.0, 1000.0, 5000.0, 10000.0]),
angular_resolution=5.0
)
-
Input Arguments:
driver_type
Driver directivity model, string. Supported values: "piston" (cone/dome via Bessel function),
"horn" (cosine-power with frequency-dependent pattern control), "omni" (omnidirectional
subwoofer). Default: "piston"
radius
Effective radiating radius in meters, scalar. For "piston": cone or dome radius. For "horn":
mouth radius (pattern control frequency auto-derived if not specified). Default: 0.05 (~4-inch driver)
lower_cutoff
Lower −3 dB frequency of the bandpass response in Hz, scalar. Default: 80.0
upper_cutoff
Upper −3 dB frequency of the bandpass response in Hz, scalar. Default: 12000.0
lower_rolloff_slope
Low-frequency rolloff slope in dB per octave, scalar. Butterworth order = slope / 6
(e.g. 12 dB/oct = 2nd order). Default: 12.0
upper_rolloff_slope
High-frequency rolloff slope in dB per octave, scalar. Default: 12.0
sensitivity
On-axis sensitivity in dB SPL at 1W/1m, scalar. Scales amplitude linearly relative to 85 dB
reference. Default: 85.0
radiation_type
Enclosure radiation modifier, string. Supported values: "monopole", "hemisphere",
"dipole", "cardioid". Default: "hemisphere"
hor_coverage
Horizontal coverage angle in degrees, scalar. Horn driver only. 0 = auto (90°). Default: 0.0
ver_coverage
Vertical coverage angle in degrees, scalar. Horn driver only. 0 = auto (60°). Default: 0.0
horn_control_freq
Horn pattern control frequency in Hz, scalar. 0 = auto-derived from mouth radius. Default: 0.0
baffle_width
Enclosure baffle width in meters, scalar. Piston driver only (used for baffle step model).
Default: 0.15
baffle_height
Enclosure baffle height in meters, scalar. Piston driver only. Default: 0.25
frequencies
Frequency sample points in Hz, 1D numpy array. If empty, third-octave bands are auto-generated.
Default: empty (auto)
angular_resolution
Angular grid resolution in degrees, scalar. Used to generate azimuth and elevation grids.
Default: 5.0
-
Output Argument:
speaker
Dictionary containing the multi-frequency arrayant data with the following keys:
e_theta_re |
e-theta field component, real part |
Shape: (n_elevation, n_azimuth, n_elements, n_freq) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_elevation, n_azimuth, n_elements, n_freq) |
e_phi_re |
e-phi field component, real part |
Shape: (n_elevation, n_azimuth, n_elements, n_freq) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_elevation, n_azimuth, n_elements, n_freq) |
azimuth_grid |
Azimuth angles in [rad], −π to π, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], −π/2 to π/2 |
Shape: (n_elevation) |
element_pos |
Antenna element (x,y,z) positions |
Shape: (3, n_elements) |
coupling_re |
Coupling matrix, real part |
Shape: (n_elements, n_ports) or (n_elements, n_ports, n_freq) |
coupling_im |
Coupling matrix, imaginary part |
Shape: (n_elements, n_ports) or (n_elements, n_ports, n_freq) |
center_freq |
Frequency samples in Hz |
Shape: (n_freq) - 1D array |
name |
Name of the array antenna object |
String |
get_channels_multifreq - Calculate channel coefficients for spherical waves across multiple frequencies
-
Description:
- Extends
get_channels_spherical to support frequency-dependent antenna patterns, path gains,
and polarization transfer (Jones) matrices across multiple output frequencies.
- Geometry is computed once: departure angles, arrival angles, element-resolved path delays, and LOS
path detection are frequency-independent and reused for all output frequencies. This avoids redundant
trigonometry and distance calculations.
- Four frequency grids are aligned by interpolation:
| 1. |
TX array frequencies (defined by center_freq in the ant_tx dictionary) |
| 2. |
RX array frequencies (defined by center_freq in the ant_rx dictionary) |
| 3. |
Input sample frequencies (freq_in) at which path_gain and M are provided |
| 4. |
Target output frequencies (freq_out) at which coefficients and delays are returned |
- For each output frequency, TX and RX antenna patterns are interpolated from their respective
multi-frequency entries using spherical interpolation (SLERP) with linear fallback, the same
algorithm used in
arrayant_interpolate_multi.
- Path gain is interpolated linearly across frequency. The Jones matrix
M is interpolated using
SLERP for each complex entry pair to preserve phase coherence.
- Extrapolation is handled by clamping to the nearest available frequency entry in all four grids.
- Propagation speed can be set to support both radio (speed of light, default) and acoustic
(speed of sound, ~343 m/s) simulations. This affects wavelength, wave number, and delay calculations.
- The Jones matrix
M supports two formats: 8 rows for full polarimetric
(ReVV, ImVV, ReVH, ImVH, ReHV, ImHV, ReHH, ImHH), or 2 rows for scalar pressure waves
(ReVV, ImVV only), where VH, HV, and HH entries are implicitly zero.
- Antenna element coupling is applied using the coupling matrices from the antenna dictionary.
If coupling varies with frequency, provide 3D coupling arrays
(n_elem, n_ports, n_freq).
- Antenna dictionaries accept both 3D patterns (single-frequency, clamped for all output
frequencies) and 4D patterns (multi-frequency, 4th dimension = frequency).
-
Usage:
from quadriga_lib import arrayant
import numpy as np
coeff_re, coeff_im, delays = arrayant.get_channels_multifreq( ant_tx, ant_rx,
fbs_pos, lbs_pos, path_gain, path_length, M, tx_pos, tx_orientation, rx_pos, rx_orientation,
freq_in, freq_out, use_absolute_delays, add_fake_los_path, propagation_speed )
-
Input Arguments:
ant_tx (required)
Dictionary containing the transmit (TX) arrayant data. Pattern fields may be 3D
(single-frequency) or 4D (multi-frequency, 4th dimension = frequency). The following keys
are expected:
e_theta_re |
e-theta field component, real part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_phi_re |
e-phi field component, real part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements) |
coupling_re |
Coupling matrix, real part, optional |
Shape: (n_elem, n_ports) or (n_elem, n_ports, n_freq) |
coupling_im |
Coupling matrix, imaginary part, optional |
Shape: (n_elem, n_ports) or (n_elem, n_ports, n_freq) |
center_freq |
Center frequency in [Hz], optional |
Scalar or 1D array (n_freq) |
name |
Name of the array antenna object, optional |
String |
ant_rx (required)
Dictionary containing the receive (RX) arrayant data (same format as ant_tx).
fbs_pos (required)
First-bounce scatterer positions. For single-bounce models, identical to lbs_pos.
Shape: ( 3, n_path )
lbs_pos (required)
Last-bounce scatterer positions. For single-bounce models, identical to fbs_pos.
Shape: ( 3, n_path )
path_gain (required)
Path gain in linear scale. Each column corresponds to one input frequency.
Shape: ( n_path, n_freq_in )
path_length (required)
Absolute path lengths from TX to RX phase center in meters.
Shape: ( n_path )
M (required)
Polarization transfer matrix in interleaved complex format. Each slice along the 3rd dimension
corresponds to one input frequency. Full polarimetric format uses 8 rows:
(ReVV, ImVV, ReVH, ImVH, ReHV, ImHV, ReHH, ImHH). Scalar pressure format uses 2 rows:
(ReVV, ImVV), with VH, HV, and HH implicitly zero.
Shape: ( 8, n_path, n_freq_in ) or ( 2, n_path, n_freq_in )
tx_pos (required)
Transmitter position in 3D Cartesian coordinates [m], Shape: (3)
tx_orientation (required)
Transmitter antenna orientation in Euler angles (bank, tilt, heading) [rad], Shape: (3)
rx_pos (required)
Receiver position in 3D Cartesian coordinates [m], Shape: (3)
rx_orientation (required)
Receiver antenna orientation in Euler angles (bank, tilt, heading) [rad], Shape: (3)
freq_in (required)
Input sample frequencies in [Hz] at which path_gain and M are defined.
Shape: ( n_freq_in )
freq_out (required)
Target frequencies in [Hz] at which to compute output coefficients and delays.
Shape: ( n_freq_out )
use_absolute_delays (optional)
If true, the LOS delay is included in all path delays. Default: False, i.e. delays are
normalized so that the LOS path has zero delay.
add_fake_los_path (optional)
If true, adds a zero-power LOS path as the first path when no LOS path was detected.
Default: False
propagation_speed (optional)
Wave propagation speed in [m/s]. Default: 299792458.0 (speed of light for radio simulations).
Set to ~343.0 for acoustic simulations in air.
-
Derived inputs:
n_freq_in |
Number of input frequency samples (columns of path_gain, slices of M) |
n_freq_out |
Number of output frequency samples (length of freq_out) |
n_path |
Number of propagation paths (columns of fbs_pos) |
n_ports_tx |
Number of TX antenna ports after coupling |
n_ports_rx |
Number of RX antenna ports after coupling |
-
Output Arguments:
coeff_re
Channel coefficients, real part, 4D array with the 4th dimension being frequency.
Shape: ( n_ports_rx, n_ports_tx, n_path, n_freq_out )
coeff_im
Channel coefficients, imaginary part, 4D array with the 4th dimension being frequency.
Shape: ( n_ports_rx, n_ports_tx, n_path, n_freq_out )
delays
Propagation delays in seconds, 4D array with the 4th dimension being frequency.
Shape: ( n_ports_rx, n_ports_tx, n_path, n_freq_out )
-
Example:
from quadriga_lib import arrayant
import numpy as np
# Build a 2-way speaker as TX (source)
tx_woofer = arrayant.generate_speaker(
driver_type='piston', radius=0.083,
lower_cutoff=50.0, upper_cutoff=3000.0,
lower_rolloff_slope=12.0, upper_rolloff_slope=24.0, sensitivity=87.0,
radiation_type='hemisphere', baffle_width=0.20, baffle_height=0.30,
frequencies=np.array([100.0, 500.0, 1000.0, 5000.0, 10000.0]),
angular_resolution=10.0)
# Omnidirectional microphone as RX (single-frequency, clamped for all output frequencies)
rx = arrayant.generate('omni')
# Simple LOS path setup
fbs_pos = np.array([[0.5], [0.0], [0.0]]) # Scatterer at RX position
lbs_pos = np.array([[0.5], [0.0], [0.0]])
path_length = np.array([1.0]) # 1 meter distance
# Frequency-flat path gain and scalar Jones matrix at two input frequencies
freq_in = np.array([100.0, 10000.0])
path_gain = np.ones((1, 2)) # Unit gain at both frequencies
M = np.zeros((2, 1, 2)) # Scalar pressure (2 rows)
M[0, 0, 0] = 1.0; M[0, 0, 1] = 1.0 # ReVV = 1 at both frequencies
# Compute channel at 3 output frequencies using speed of sound
freq_out = np.array([200.0, 1000.0, 5000.0])
coeff_re, coeff_im, delays = arrayant.get_channels_multifreq(
tx_woofer, rx, fbs_pos, lbs_pos, path_gain, path_length, M,
np.zeros(3), # TX at origin
np.zeros(3), # TX orientation (no rotation)
np.array([1.0, 0.0, 0.0]), # RX at (1, 0, 0)
np.zeros(3), # RX orientation (no rotation)
freq_in, freq_out,
propagation_speed=343.0) # Speed of sound for acoustics
# coeff_re.shape = (1, n_tx_ports, 1, 3) — one RX port, one path, 3 output frequencies
-
Caveat:
- Input data is directly accessed from Python memory, without copying if it is provided in
double precision and is in F-contiguous (column-major) order.
- Other formats (e.g. single precision inputs or C-contiguous (row-major) order) will be converted
to double automatically, causing additional computation steps.
- To improve performance of repeated computations (e.g. in loops), consider preparing the data
in F-contiguous double precision to avoid unnecessary copies.
-
See also:
get_channels_planar - Calculate channel coefficients for planar waves
-
Description:
In this function, the wireless propagation channel between a transmitter and a receiver is calculated,
based on a single transmit and receive position. Additionally, interaction points with the environment,
which are derived from either Ray Tracing or Geometric Stochastic Models such as QuaDRiGa, are
considered. The calculation is performed under the assumption of planar wave propagation. For accurate
execution of this process, several pieces of input data are required:
- The 3D Cartesian (local) coordinates of both the transmitter and the receiver.
- The azimuth/elevation departure and arrval angles.
- The polarization transfer matrix for each propagation path.
- Antenna models for both the transmitter and the receiver.
- The orientations of the antennas.
-
Usage:
from quadriga_lib import arrayant
coeff_re, coeff_im, delays, rx_Doppler = arrayant.get_channels_planar( ant_tx, ant_rx,
aod, eod, aoa, eoa, path_gain, path_length, M, tx_pos, tx_orientation, rx_pos, rx_orientation,
center_freq, use_absolute_delays, add_fake_los_path );
-
Input Arguments:
ant_tx (required)
Dictionary containing the transmit (TX) arrayant data with the following keys:
e_theta_re |
e-theta field component, real part |
Shape: (n_elevation_tx, n_azimuth_tx, n_elements_tx) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_elevation_tx, n_azimuth_tx, n_elements_tx) |
e_phi_re |
e-phi field component, real part |
Shape: (n_elevation_tx, n_azimuth_tx, n_elements_tx) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_elevation_tx, n_azimuth_tx, n_elements_tx) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth_tx) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation_tx) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements_tx) |
coupling_re |
Coupling matrix, real part, optional |
Shape: (n_elements_tx, n_ports_tx) |
coupling_im |
Coupling matrix, imaginary part, optional |
Shape: (n_elements_tx, n_ports_tx) |
ant_rx (required)
Dictionary containing the receive (RX) arrayant data with the following keys:
e_theta_re |
e-theta field component, real part |
Shape: (n_elevation_rx, n_azimuth_rx, n_elements_rx) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_elevation_rx, n_azimuth_rx, n_elements_rx) |
e_phi_re |
e-phi field component, real part |
Shape: (n_elevation_rx, n_azimuth_rx, n_elements_rx) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_elevation_rx, n_azimuth_rx, n_elements_rx) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth_rx) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation_rx) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements_rx) |
coupling_re |
Coupling matrix, real part, optional |
Shape: (n_elements_rx, n_ports_rx) |
coupling_im |
Coupling matrix, imaginary part, optional |
Shape: (n_elements_rx, n_ports_rx) |
aod (required)
Departure azimuth angles in [rad], Shape: ( n_path )
eod (required)
Departure elevation angles in [rad], Shape: ( n_path )
aoa (required)
Arrival azimuth angles in [rad], Shape: ( n_path )
eoa (required)
Arrival elevation angles in [rad], Shape: ( n_path )
path_gain (required)
Path gain (linear scale), Shape: ( n_path )
path_length (required)
Total path length in meters, Shape: ( n_path )
M (required)
Polarization transfer matrix, interleaved complex values (ReVV, ImVV, ReVH, ImVH, ReHV, ImHV, ReHH, ImHH),
Shape: ( 8, n_path )
tx_pos (required)
Transmitter position in 3D Cartesian coordinates; Shape: (3)
tx_orientation (required)
3-element vector describing the orientation of the transmit antenna in Euler angles (bank, tilt, heading),
Shape: (3,1) or (1,3)
rx_pos (required)
Receiver position in 3D Cartesian coordinates, Shape: (3)
rx_orientation (required)]
3-element vector describing the orientation of the receive antenna in Euler angles,
Shape: (3)
center_freq (optional)
Center frequency in [Hz]; optional; If the value is not provided or set to 0, phase calculation
in coefficients is disabled, i.e. that path length has not influence on the results. This can be
used to calculate the antenna response for a specific angle and polarization. Scalar value
use_absolute_delays (optional)
If true, the LOS delay is included for all paths; Default is false, i.e. delays are normalized
to the LOS delay.
add_fake_los_path (optional)
If true, adds a zero-power LOS path as the first path in case where no LOS path was present.
Default: false
-
Derived inputs:
n_azimuth_tx |
Number of azimuth angles in the TX antenna pattern |
n_elevation_tx |
Number of elevation angles in the TX antenna pattern |
n_elements_tx |
Number of physical antenna elements in the TX array antenna |
n_ports_tx |
Number of ports (after coupling) in the TX array antenna |
n_azimuth_rx |
Number of azimuth angles in the RX antenna pattern |
n_elevation_rx |
Number of elevation angles in the RX antenna pattern |
n_elements_rx |
Number of physical antenna elements in the RX array antenna |
n_ports_rx |
Number of ports (after coupling) in the RX array antenna |
n_path |
Number of propagation paths |
-
Output Arguments:
coeff_re
Channel coefficients, real part, Shape: ( n_ports_tx, n_ports_rx, n_path )
coeff_im
Channel coefficients, imaginary part, Shape: ( n_ports_tx, n_ports_rx, n_path )
delays
Propagation delay in seconds, Shape: ( n_ports_tx, n_ports_rx, n_path )
rx_Doppler
Doppler weights for moving RX, Shape: ( 1, n_path )
-
Caveat:
- Input data is directly accessed from Python memory, without copying if it is provided in
double precision and is in F-contiguous (column-major) order
- Other formats (e.g. single precision inputs or C-contiguous (row-major) order) will be converted
to double automatically, causing additional computation steps.
- To improve performance of repeated computations (e.g. in loops), consider preparing the data
accordingly to avoid unecessary computations.
get_channels_spherical - Calculate channel coefficients from path data and antenna patterns
-
Description:
In this function, the wireless propagation channel between a transmitter and a receiver is calculated,
based on a single transmit and receive position. Additionally, interaction points with the environment,
which are derived from either Ray Tracing or Geometric Stochastic Models such as QuaDRiGa, are
considered. The calculation is performed under the assumption of spherical wave propagation. For accurate
execution of this process, several pieces of input data are required:
- The 3D Cartesian (local) coordinates of both the transmitter and the receiver.
- The specific interaction positions of the propagation paths within the environment.
- The polarization transfer matrix for each propagation path.
- Antenna models for both the transmitter and the receiver.
- The orientations of the antennas.
-
Usage:
from quadriga_lib import arrayant
# Return only coefficients and delays
coeff_re, coeff_im, delays = arrayant.get_channels_spherical( ant_tx, ant_rx,
fbs_pos, lbs_pos, path_gain, path_length, M, tx_pos, tx_orientation, rx_pos, rx_orientation,
center_freq, use_absolute_delays, add_fake_los_path );
# Return additional departure and arrival angles
coeff_re, coeff_im, delays, aod, eod, aoa, eoa = arrayant.get_channels_spherical( ant_tx, ant_rx,
fbs_pos, lbs_pos, path_gain, path_length, M, tx_pos, tx_orientation, rx_pos, rx_orientation,
center_freq, use_absolute_delays, add_fake_los_path, angles=1 );
-
Input Arguments:
ant_tx (required)
Dictionary containing the transmit (TX) arrayant data with the following keys:
e_theta_re |
e-theta field component, real part |
Shape: (n_elevation_tx, n_azimuth_tx, n_elements_tx) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_elevation_tx, n_azimuth_tx, n_elements_tx) |
e_phi_re |
e-phi field component, real part |
Shape: (n_elevation_tx, n_azimuth_tx, n_elements_tx) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_elevation_tx, n_azimuth_tx, n_elements_tx) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth_tx) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation_tx) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements_tx) |
coupling_re |
Coupling matrix, real part, optional |
Shape: (n_elements_tx, n_ports_tx) |
coupling_im |
Coupling matrix, imaginary part, optional |
Shape: (n_elements_tx, n_ports_tx) |
ant_rx (required)
Dictionary containing the receive (RX) arrayant data with the following keys:
e_theta_re |
e-theta field component, real part |
Shape: (n_elevation_rx, n_azimuth_rx, n_elements_rx) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_elevation_rx, n_azimuth_rx, n_elements_rx) |
e_phi_re |
e-phi field component, real part |
Shape: (n_elevation_rx, n_azimuth_rx, n_elements_rx) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_elevation_rx, n_azimuth_rx, n_elements_rx) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth_rx) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation_rx) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements_rx) |
coupling_re |
Coupling matrix, real part, optional |
Shape: (n_elements_rx, n_ports_rx) |
coupling_im |
Coupling matrix, imaginary part, optional |
Shape: (n_elements_rx, n_ports_rx) |
fbs_pos (required)
First interaction point of the rays and the environment, Shape: ( 3, n_path )
lbs_pos (required)
Last interaction point of the rays and the environment; For single-bounce models, this must be
identical to fbs_pos, Shape: ( 3, n_path )
path_gain (required)
Path gain (linear scale), Shape: ( n_path )
path_length (required)
Total path length in meters, Shape: ( n_path )
M (required)
Polarization transfer matrix, interleaved complex values (ReVV, ImVV, ReVH, ImVH, ReHV, ImHV, ReHH, ImHH),
Shape: ( 8, n_path )
tx_pos (required)
Transmitter position in 3D Cartesian coordinates; Shape: (3)
tx_orientation (required)
3-element vector describing the orientation of the transmit antenna in Euler angles (bank, tilt, heading),
Shape: (3,1) or (1,3)
rx_pos (required)
Receiver position in 3D Cartesian coordinates, Shape: (3)
rx_orientation (required)]
3-element vector describing the orientation of the receive antenna in Euler angles,
Shape: (3)
center_freq (optional)
Center frequency in [Hz]; optional; If the value is not provided or set to 0, phase calculation
in coefficients is disabled, i.e. that path length has not influence on the results. This can be
used to calculate the antenna response for a specific angle and polarization. Scalar value
use_absolute_delays (optional)
If true, the LOS delay is included for all paths; Default is false, i.e. delays are normalized
to the LOS delay.
add_fake_los_path (optional)
If true, adds a zero-power LOS path as the first path in case where no LOS path was present.
Default: false
angles (optional flag)
Switch to return the angles in antenna-local coordinates. Default: 0, false
-
Derived inputs:
n_azimuth_tx |
Number of azimuth angles in the TX antenna pattern |
n_elevation_tx |
Number of elevation angles in the TX antenna pattern |
n_elements_tx |
Number of physical antenna elements in the TX array antenna |
n_ports_tx |
Number of ports (after coupling) in the TX array antenna |
n_azimuth_rx |
Number of azimuth angles in the RX antenna pattern |
n_elevation_rx |
Number of elevation angles in the RX antenna pattern |
n_elements_rx |
Number of physical antenna elements in the RX array antenna |
n_ports_rx |
Number of ports (after coupling) in the RX array antenna |
n_path |
Number of propagation paths |
-
Output Arguments:
coeff_re
Channel coefficients, real part, Shape: ( n_ports_rx, n_ports_tx, n_path )
coeff_im
Channel coefficients, imaginary part, Shape: ( n_ports_rx, n_ports_tx, n_path )
delays
Propagation delay in seconds, Shape: ( n_ports_rx, n_ports_tx, n_path )
aod (optional)
Azimuth of Departure angles in [rad], Shape: ( n_ports_rx, n_ports_tx, n_path ),
Only returned when angles flag is set to 1.
eod (optional)
Elevation of Departure angles in [rad], Shape: ( n_ports_rx, n_ports_tx, n_path ),
Only returned when angles flag is set to 1.
aoa (optional)
Azimuth of Arrival angles in [rad], Shape: ( n_ports_rx, n_ports_tx, n_path ),
Only returned when angles flag is set to 1.
eoa (optional)
Elevation of Arrival angles in [rad], Shape: ( n_ports_rx, n_ports_tx, n_path ),
Only returned when angles flag is set to 1.
-
Caveat:
- Input data is directly accessed from Python memory, without copying if it is provided in
double precision and is in F-contiguous (column-major) order
- Other formats (e.g. single precision inputs or C-contiguous (row-major) order) will be converted
to double automatically, causing additional computation steps.
- To improve performance of repeated computations (e.g. in loops), consider preparing the data
accordingly to avoid unecessary computations.
interpolate - Interpolate array antenna field patterns
-
Description:
- This function interpolates polarimetric antenna field patterns for a given set of azimuth and
elevation angles. It supports both single-frequency arrayants (3D pattern fields) and multi-frequency
arrayants (4D pattern fields). The function auto-detects the input format by inspecting the
dimensionality of the
e_theta_re field (3D = single-frequency, 4D = multi-frequency).
- For multi-frequency inputs, the function interpolates both spatially (azimuth/elevation) and across
frequency, producing output fields with an additional frequency dimension. Target frequencies for
the multi-frequency path are specified via the
frequency parameter. The options dist and
local_angles are only available for the single-frequency path without frequency.
- If a single-frequency arrayant (3D patterns) is used together with the
frequency parameter, the
function performs spatial interpolation once and replicates the 2D result across all requested
frequencies, yielding 3D output of shape (n_out, n_ang, n_freq_out). This allows uniform output
shapes regardless of whether the underlying arrayant is frequency-dependent or not.
-
Usage:
from quadriga_lib import arrayant
# Minimal example (single-frequency, 3D patterns)
vr,vi,hr,hi = arrayant.interpolate(arrayant, azimuth, elevation)
# Output as complex type
v,h = arrayant.interpolate(arrayant, azimuth, elevation, complex=1)
# Generate projected distance (single-frequency only)
vr,vi,hr,hi,dist = arrayant.interpolate(arrayant, azimuth, elevation, dist=1)
v,h,dist = arrayant.interpolate(arrayant, azimuth, elevation, complex=1, dist=1)
# Additional inputs
vr,vi,hr,hi = arrayant.interpolate(arrayant, azimuth, elevation, element, orientation, element_pos)
# Output angles in antenna-local coordinates (single-frequency only)
vr,vi,hr,hi,az_local,el_local,gamma = arrayant.interpolate(arrayant, azimuth, elevation, orientation=ori, local_angles=1)
# Multi-frequency interpolation (4D patterns)
vr,vi,hr,hi = arrayant.interpolate(speaker, azimuth, elevation, frequency=freqs)
v,h = arrayant.interpolate(speaker, azimuth, elevation, frequency=freqs, complex=1)
# Single-frequency arrayant with frequency duplication (output is 3D, duplicated across freqs)
vr,vi,hr,hi = arrayant.interpolate(ant, azimuth, elevation, frequency=freqs)
-
Input Arguments:
arrayant (required)
Dictionary containing array antenna data. Pattern fields may be 3D (single-frequency) or
4D (multi-frequency, 4th dimension = frequency). The following keys are expected:
e_theta_re |
Real part of e-theta field component |
Shape: (n_elevation, n_azimuth, n_elements) or (n_elevation, n_azimuth, n_elements, n_freq) |
e_theta_im |
Imaginary part of e-theta field component |
Shape: (n_elevation, n_azimuth, n_elements) or (n_elevation, n_azimuth, n_elements, n_freq) |
e_phi_re |
Real part of e-phi field component |
Shape: (n_elevation, n_azimuth, n_elements) or (n_elevation, n_azimuth, n_elements, n_freq) |
e_phi_im |
Imaginary part of e-phi field component |
Shape: (n_elevation, n_azimuth, n_elements) or (n_elevation, n_azimuth, n_elements, n_freq) |
azimuth_grid |
Azimuth angles in [rad] -pi to pi, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements) |
center_freq |
Center frequency in [Hz], optional |
Scalar or 1D array (n_freq) |
azimuth (required)
Azimuth angles in [rad] for which the field pattern should be interpolated. Values must be between -pi and pi.
| Option 1: |
Use the same angles for all antenna elements (planar wave approximation) |
|
Shape: (1, n_ang) |
| Option 2: |
Provide different angles for each array element (e.g. for spherical waves) |
|
Shape: (n_out, n_ang) |
elevation (required)
Elevation angles in [rad] for which the field pattern should be interpolated. Values must be between -pi/2 and pi/2.
| Option 1: |
Use the same angles for all antenna elements (planar wave approximation) |
|
Shape: (1, n_ang) |
| Option 2: |
Provide different angles for each array element (e.g. for spherical waves) |
|
Shape: [n_out, n_ang) |
element (optional)
The element indices for which the interpolation should be done. Optional parameter. Values must
be between 0 and n_elements-1. It is possible to duplicate elements, i.e. by passing [1,1,2].
If this parameter is not provided (or an empty array is passed), i_element is initialized
to [0:n_elements-1]. In this case, n_out = n_elements.
Shape: (1, n_out) or (n_out, 1) or empty ()
orientation (optional)
This (optional) 3-element vector describes the orientation of the array antenna or of individual
array elements using Euler angles in [rad].
Shape: (3, 1) or (3, n_out) or (3, 1, n_ang) or (3, n_out, n_ang) or empty ()
element_pos (optional)
Alternative positions of the array antenna elements in local cartesian coordinates (using units of [m]).
If this parameter is not given, element positions from arrayant are used. If the arrayant has no
positions, they are initialized to [0,0,0]. For example, when duplicating the first element by setting
element = [1,1], different element positions can be set for the two elements in the output.
Shape: (3, n_out) or empty ()
frequency (optional)
Target frequencies in [Hz] for multi-frequency interpolation. When the input arrayant has 4D
pattern fields, each requested frequency is interpolated between the two bracketing entries;
out-of-range frequencies are clamped to the nearest entry. When the input arrayant has 3D
pattern fields, the spatial interpolation is performed once and the result is duplicated across
all requested frequencies. In both cases, the output shape gains a frequency dimension
(n_out, n_ang, n_freq_out). If empty, no frequency dimension is added (single-frequency
path returns 2D outputs). The options dist and local_angles are not available when
frequency is provided.
Shape: (n_freq_out) or empty ()
complex (optional flag)
If set to 1, output is returned in complex notation. This reduces performance due to additional
copies of the data in memory. Default: 0, false
dist (optional flag)
Switch to calculate the effective distances for phase calculation. Only available for single-frequency
arrayants (3D patterns). Default: 0, false
local_angles (optional flag)
Switch to return the angles in antenna-local coordinates. These differ from the input when the
orientation of the antenna is adjusted. Only available for single-frequency arrayants (3D patterns).
Default: 0, false
fast_access (optional flag)
If arrayant data is provided as numpy.ndarray of type double in Fortran-contiguous (column-major)
order, arrayant_interpolate can access the Python memory directly without a conversion of the
data. This will increase performance and is done by default. If the data is not in the correct
format, a conversion is done in the background. Setting fast_access to 1 will skip the conversion
and throw an error if the arrayant data is not correctly formatted. Only applies to the single-
frequency path. Default: 0, false (convert)
-
Derived inputs:
n_azimuth |
Number of azimuth angles in the field pattern |
n_elevation |
Number of elevation angles in the field pattern |
n_elements |
Number of antenna elements in the field pattern of the array antenna |
n_ang |
Number of interpolation angles |
n_out |
Number of antenna elements in the generated output (may differ from n_elements) |
n_freq |
Number of frequency entries in the multi-frequency arrayant (4D input only) |
n_freq_out |
Number of target frequencies (multi-frequency path only) |
-
Output Arguments (single-frequency path):
vr
Real part of the interpolated e-theta (vertical) field component. Shape (n_out, n_ang)
vi
Imaginary part of the interpolated e-theta (vertical) field component. Shape (n_out, n_ang)
hr
Real part of the interpolated e-phi (horizontal) field component. Shape (n_out, n_ang)
hi
Imaginary part of the interpolated e-phi (horizontal) field component. Shape (n_out, n_ang)
dist (optional)
The effective distances between the antenna elements when seen from the direction of the
incident path. The distance is calculated by a projection of the array positions on the normal
plane of the incident path. This is needed for calculating the phase of the antenna response.
Only returned when dist flag is set to 1. Shape (n_out, n_ang)
azimuth_loc (optional)
The azimuth angles in [rad] for the local antenna coordinate system, i.e., after applying the
'orientation'. If no orientation vector is given, these angles are identical to the input
azimuth angles. Only returned when local_angles flag is set to 1. Shape (n_out, n_ang)
elevation_loc (optional)
The elevation angles in [rad] for the local antenna coordinate system, i.e., after applying the
'orientation'. If no orientation vector is given, these angles are identical to the input
elevation angles. Only returned when local_angles flag is set to 1. Shape (n_out, n_ang)
gamma (optional)
Polarization rotation angles in [rad]. Only returned when local_angles flag is set to 1.
Shape (n_out, n_ang)
-
Output Arguments (multi-frequency path):
vr
Real part of the interpolated e-theta (vertical) field component. Shape (n_out, n_ang, n_freq_out)
vi
Imaginary part of the interpolated e-theta (vertical) field component. Shape (n_out, n_ang, n_freq_out)
hr
Real part of the interpolated e-phi (horizontal) field component. Shape (n_out, n_ang, n_freq_out)
hi
Imaginary part of the interpolated e-phi (horizontal) field component. Shape (n_out, n_ang, n_freq_out)
v (complex mode)
Complex-valued interpolated e-theta (vertical) field component. Shape (n_out, n_ang, n_freq_out)
h (complex mode)
Complex-valued interpolated e-phi (horizontal) field component. Shape (n_out, n_ang, n_freq_out)
qdant_read - Reads array antenna data from QDANT files
-
Description:
- The QuaDRiGa array antenna exchange format (QDANT) is a file format used to store antenna pattern
data in XML. This function reads pattern data from the specified file.
- Supports both single-entry and multi-entry (multi-frequency) reading:
- Single-entry (id ≥ 1): Reads one antenna entry from the file. Pattern fields are returned as
3D arrays
(n_el, n_az, n_elem). This is the default behavior.
- Multi-entry (id = 0): Reads all antenna entries from the file and returns them as a single
multi-frequency arrayant dict. Pattern fields are returned as 4D arrays
(n_el, n_az, n_elem, n_freq), center frequencies as a 1D array, and coupling matrices as 3D
arrays if they vary across entries. This is the inverse of qdant_write with 4D input.
-
Usage:
from quadriga_lib import arrayant
# Read a single antenna entry (default: first entry)
data = arrayant.qdant_read('antenna.qdant')
data = arrayant.qdant_read('antenna.qdant', id=2)
# Read all entries as multi-frequency arrayant (4D patterns)
data = arrayant.qdant_read('speaker.qdant', id=0)
-
Input Arguments:
fn
Filename of the QDANT file, string
id (optional)
ID of the antenna to be read from the file. Default: 1 (read first entry).
Set to 0 to read all entries as a multi-frequency arrayant.
-
Output Arguments:
data
Dictionary containing the data in the QDANT file with the following keys:
For single-entry (id ≥ 1):
e_theta_re |
e-theta field component, real part |
Shape: (n_el, n_az, n_elem) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_el, n_az, n_elem) |
e_phi_re |
e-phi field component, real part |
Shape: (n_el, n_az, n_elem) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_el, n_az, n_elem) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation) |
element_pos |
Antenna element (x,y,z) positions |
Shape: (3, n_elements) |
coupling_re |
Coupling matrix, real part |
Shape: (n_elements, n_ports) |
coupling_im |
Coupling matrix, imaginary part |
Shape: (n_elements, n_ports) |
center_freq |
Center frequency in [Hz] |
Scalar |
name |
Name of the array antenna object |
String |
layout |
Layout of multiple array antennas |
Matrix |
For multi-entry (id = 0):
e_theta_re |
e-theta field component, real part |
Shape: (n_el, n_az, n_elem, n_freq) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_el, n_az, n_elem, n_freq) |
e_phi_re |
e-phi field component, real part |
Shape: (n_el, n_az, n_elem, n_freq) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_el, n_az, n_elem, n_freq) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation) |
element_pos |
Antenna element (x,y,z) positions |
Shape: (3, n_elements) |
coupling_re |
Coupling matrix, real part |
Shape: (n_elem, n_ports) or (n_elem, n_ports, n_freq) |
coupling_im |
Coupling matrix, imaginary part |
Shape: (n_elem, n_ports) or (n_elem, n_ports, n_freq) |
center_freq |
Center frequencies in [Hz] |
Shape: (n_freq) |
name |
Name of the array antenna object |
String |
layout |
Layout of multiple array antennas |
Matrix |
-
See also:
- qdant_write (for writing QDANT data)
- QuaDRiGa Array Antenna Exchange Format (QDANT)
qdant_write - Writes array antenna data to QDANT files
-
Description:
- The QuaDRiGa array antenna exchange format (QDANT) is a file format used to store antenna pattern
data in XML. This function writes pattern data to the specified file.
- Supports both single-frequency arrayants (3D pattern fields) and multi-frequency arrayants
(4D pattern fields). The function auto-detects the format by inspecting the dimensionality of
e_theta_re (3D = single, 4D = multi).
- Single-frequency: Writes one antenna entry to the file. The
id parameter controls where the
entry is placed. Multiple antennas can be stored in the same file by calling this function
repeatedly with different IDs.
- Multi-frequency: Writes all frequency entries as sequential IDs (1-based) to the file. The file
is overwritten if it already exists. A layout matrix is created automatically. The
id and layout
parameters are ignored for multi-frequency inputs.
-
Usage:
from quadriga_lib import arrayant
# Single-frequency: write with optional ID
id_in_file = arrayant.qdant_write('antenna.qdant', ant)
id_in_file = arrayant.qdant_write('antenna.qdant', ant, id=2)
# Multi-frequency (4D patterns): writes all frequencies sequentially
arrayant.qdant_write('speaker.qdant', speaker)
-
Input Arguments:
fn [1]
Filename of the QDANT file, string
arrayant [2] (optional)
Dictionary containing the arrayant data. Pattern fields may be 3D (single-frequency) or
4D (multi-frequency, 4th dimension = frequency). The following keys are expected:
e_theta_re |
e-theta field component, real part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_phi_re |
e-phi field component, real part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements) |
coupling_re |
Coupling matrix, real part, optional |
Shape: (n_elem, n_ports) or (n_elem, n_ports, n_freq) |
coupling_im |
Coupling matrix, imaginary part, optional |
Shape: (n_elem, n_ports) or (n_elem, n_ports, n_freq) |
center_freq |
Center frequency in [Hz], optional |
Scalar or 1D array (n_freq) |
name |
Name of the array antenna object, optional |
String |
id [3] (optional, single-frequency only)
ID of the antenna to be written to the file, optional, Default: Max-ID in existing file + 1.
Ignored for multi-frequency inputs.
layout [4] (optional, single-frequency only)
Layout of multiple array antennas. Must only contain element ids that are present in the file.
Ignored for multi-frequency inputs.
-
Output Argument:
id_in_file
For single-frequency: ID of the antenna in the file after writing.
For multi-frequency: always returns 0 (all entries are written sequentially starting at ID 1).
# See also:
- qdant_read (for reading QDANT data)
- QuaDRiGa Array Antenna Exchange Format (QDANT)
rotate_pattern - Rotates antenna patterns
-
Description:
- This function transforms the radiation patterns of array antenna elements, allowing for
precise rotations around the three principal axes (x, y, z) of the local Cartesian coordinate system.
The 3 rotations are applied in the order: 1. rotation around the x-axis (bank angle);
2. rotation around the y-axis (tilt angle), 3. rotation around the z-axis (heading angle).
- Supports both single-frequency arrayants (3D pattern fields) and multi-frequency arrayants
(4D pattern fields). For multi-frequency inputs, the rotation is applied consistently across all
frequency entries. The function auto-detects the format by inspecting the dimensionality of
e_theta_re (3D = single, 4D = multi).
- Note on usage modes for multi-frequency: Grid adjustment (usage 0 and 1) is not supported for
multi-frequency arrayants because all frequency entries must share the same angular grid. The multi-
frequency path automatically maps usage 0 → 3 (pattern + polarization, no grid adjust) and
usage 1 → 4 (pattern only, no grid adjust). Usage 2 (polarization only) works identically in both
paths.
-
Usage:
from quadriga_lib import arrayant
# Single-frequency: rotate all elements by 45 deg bank
arrayant_out = arrayant.rotate_pattern(ant, x_deg=45.0)
# Single-frequency: rotate only elements 0 and 1 (0-based)
arrayant_out = arrayant.rotate_pattern(ant, z_deg=90.0, element=[0, 1])
# Multi-frequency (4D patterns): same interface
speaker_out = arrayant.rotate_pattern(speaker, y_deg=10.0)
-
Input Arguments:
arrayant
Dictionary containing the arrayant data. Pattern fields may be 3D (single-frequency) or
4D (multi-frequency, 4th dimension = frequency). The following keys are expected:
e_theta_re |
e-theta field component, real part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_phi_re |
e-phi field component, real part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_el, n_az, n_elem) or (n_el, n_az, n_elem, n_freq) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements) |
coupling_re |
Coupling matrix, real part, optional |
Shape: (n_elem, n_ports) or (n_elem, n_ports, n_freq) |
coupling_im |
Coupling matrix, imaginary part, optional |
Shape: (n_elem, n_ports) or (n_elem, n_ports, n_freq) |
center_freq |
Center frequency in [Hz], optional |
Scalar or 1D array (n_freq) |
name |
Name of the array antenna object, optional |
String |
x_deg (optional)
The rotation angle around x-axis (bank angle) in [degrees]. Default: 0.0
y_deg (optional)
The rotation angle around y-axis (tilt angle) in [degrees]. Default: 0.0
z_deg (optional)
The rotation angle around z-axis (heading angle) in [degrees]. Default: 0.0
usage (optional)
The optional parameter 'usage' can limit the rotation procedure either to the pattern or polarization.
usage = 0 |
Rotate both, pattern and polarization, adjusts sampling grid (default; multi-freq: no grid adjust) |
usage = 1 |
Rotate only pattern, adjusts sampling grid (multi-freq: no grid adjust) |
usage = 2 |
Rotate only polarization |
usage = 3 |
Rotate both, but do not adjust the sampling grid |
usage = 4 |
Rotate only pattern, do not adjust the sampling grid |
element (optional)
The element indices for which the pattern should be transformed. Optional parameter. Values must
be between 0 and n_elements-1 (0-based). If this parameter is not provided (or an empty array is
passed), all elements will be rotated by the same angles. Shape: (n_elements) or empty ()
-
Output Arguments:
arrayant_out
Dictionary containing the arrayant data with the rotated patterns. Output format matches the
input format (3D for single-frequency, 4D for multi-frequency).
Channel functions
baseband_freq_response - Compute the frequency-domain channel response from time-domain coefficients
-
Description:
- Transforms channel impulse response data into the frequency domain and returns the channel transfer
function H(f) at specified sub-carrier or output frequencies.
- Supports two operating modes determined by the dimensionality of the input coefficient arrays:
1. Single-frequency (3D inputs): Each list item is a 3D array of shape
(n_rx, n_tx, n_path).
Calls baseband_freq_response per snapshot using a DFT with AVX2 acceleration.
2. Multi-frequency (4D inputs): Each list item is a 4D array of shape
(n_rx, n_tx, n_path, n_freq_in). Calls baseband_freq_response_multi per snapshot using
SLERP interpolation of the coefficient envelope across frequency.
- Coefficients can be provided as a single complex array (
coeff) or as separate real and imaginary
parts (coeff_re, coeff_im). Providing both is an error.
- The output frequency grid can be defined in two ways:
1.
bandwidth + pilot_grid (or carriers): baseband offsets, for single-frequency mode.
2. freq_in + freq_out: absolute frequencies in Hz, works for both single-frequency and
multi-frequency mode. For single-frequency inputs, bandwidth and pilot_grid are derived
internally from freq_out.
- When using multi-frequency mode, the
remove_delay_phase flag (default True) undoes the
delay-induced phase baked into coefficients by get_channels_multifreq before SLERP interpolation,
then re-applies it analytically at each output frequency. Set to False only if the input
coefficients are pure slowly-varying envelopes without baked-in delay phase.
- Snapshots are processed in parallel using OpenMP. The number of paths
n_path may vary across
snapshots, but n_rx, n_tx, and (for 4D) n_freq_in must be consistent.
-
Usage:
import quadriga_lib
# Single-frequency with bandwidth + carriers
hmat = quadriga_lib.channel.baseband_freq_response( coeff=coeff, delay=delay, bandwidth=100e6 )
# Single-frequency with freq_in + freq_out
hmat = quadriga_lib.channel.baseband_freq_response( coeff=coeff, delay=delay,
freq_in=np.array([2.0e9]), freq_out=np.linspace(1.95e9, 2.05e9, 128) )
# Multi-frequency with separate re/im
hmat = quadriga_lib.channel.baseband_freq_response( coeff_re=cre, coeff_im=cim, delay=delay,
freq_in=freq_in, freq_out=freq_out )
-
Input Arguments:
coeff (optional)
Channel coefficients, complex-valued. List of length n_snap. Each item is a numpy array of
shape (n_rx, n_tx, n_path) (single-freq) or (n_rx, n_tx, n_path, n_freq_in) (multi-freq).
Mutually exclusive with coeff_re / coeff_im.
delay
Propagation delays in seconds, real-valued. List of length n_snap. Each item is a numpy array
of shape (n_rx, n_tx, n_path) or (1, 1, n_path) (single-freq), or the same shapes with an
additional 4th dimension n_freq_in (multi-freq). For multi-freq, a 3D delay is broadcast to
all input frequencies (since delays are frequency-independent).
bandwidth (optional)
Baseband bandwidth in Hz. Used with pilot_grid or carriers to define sub-carrier positions.
Cannot be combined with freq_out. Default: 0.0
carriers (optional)
Number of equally spaced carriers across the bandwidth. Only used if pilot_grid is not given
and freq_out is not given. Default: 128
pilot_grid (optional)
Sub-carrier positions relative to bandwidth (0 = center freq, 1 = center + bandwidth).
1D numpy array of length n_carriers.
snap (optional)
0-based snapshot indices to process. If not given, all snapshots are processed.
1D numpy array of length n_out.
coeff_re (optional)
Real part of channel coefficients. Same list/shape structure as coeff.
Must be provided together with coeff_im. Mutually exclusive with coeff.
coeff_im (optional)
Imaginary part of channel coefficients. Must match coeff_re in structure and shape.
freq_in (optional)
Input sample frequencies in Hz, 1D numpy array. Required for multi-freq (4D) inputs.
For single-freq (3D) inputs, used together with freq_out to derive baseband parameters.
freq_out (optional)
Output carrier frequencies in Hz, 1D numpy array. Required for multi-freq (4D) inputs.
For single-freq (3D) inputs, can replace bandwidth + pilot_grid.
remove_delay_phase (optional)
If True (default), removes the delay-induced phase baked into coefficients by channel
generation functions (e.g. get_channels_multifreq) before SLERP interpolation in multi-freq
mode. Has no effect in single-freq mode.
-
Output Argument:
hmat
Complex-valued frequency-domain channel matrix, numpy array of shape
(n_rx, n_tx, n_carriers, n_out).
channel_export_obj_file - Export path data to a Wavefront OBJ file for visualization in Blender
-
Description:
This function exports path data to a Wavefront OBJ file, which can be used for visualization in 3D
software such as Blender. It supports various colormaps for color-coding the paths based on their
gain values. In addition, the function allows you to control the maximum number of paths displayed,
set gain thresholds for color-coding and selection.
-
Usage:
from quadriga_lib import channel
channel.channel_export_obj_file( fn, max_no_paths, gain_max, gain_min, colormap, radius_max,
radius_min, n_edges, rx_position, tx_position, no_interact, interact_coord, center_freq,
coeff, i_snap )
-
Input Arguments:
fn
Filename of the OBJ file, string, required
max_no_paths (optional)
Maximum number of paths to be shown, optional, default: 0 = export all above gain_min
gain_max (optional)
Maximum path gain in dB (only for color-coding), optional, default = -60.0
gain_min (optional)
Minimum path gain in dB (for color-coding and path selection), optional, default = -140.0
colormap (optional)
Colormap for the visualization, string, supported are 'jet', 'parula', 'winter', 'hot', 'turbo',
'copper', 'spring', 'cool', 'gray', 'autumn', 'summer', optional, default = 'jet'
radius_max (optional)
Maximum tube radius in meters, optional, default = 0.05
radius_min (optional)
Minimum tube radius in meters, optional, default = 0.01
n_edges (optional)
Number of vertices in the circle building the tube, must be >= 3, optional, default = 5
rx_position
Receiver positions, required, size [3, n_snap] or [3, 1]
tx_position
Transmitter positions, required, size [3, n_snap] or [3, 1]
no_interact
Number interaction points of paths with the environment, required, uint32, Size [n_path, n_snap]
interact_coord
Interaction coordinates, required, Size [3, max(sum(no_interact)), n_snap]
center_freq
Center frequency in [Hz], required, Size [n_snap, 1] or scalar
coeff
Channel coefficients, complex valued, required only if path_polarization is not given,
Size [n_rx, n_tx, n_path, n_snap]
i_snap
(optional)
Snapshot indices, optional, 0-based, range [0 ... n_snap - 1]
get_ieee_indoor - Generate indoor MIMO channel realizations for IEEE TGn/TGac/TGax/TGah models
-
Description:
- Generates one or multiple indoor channel realizations based on IEEE TGn/TGac/TGax/TGah model definitions.
- 2D model: no elevation angles are used; azimuth angles and planar motion are considered.
- For 3D antenna models (default models from arrayant generate), only the azimuth cut at
elevation_grid = 0 is used
- Supports channel model types
A, B, C, D, E, F (as defined by TGn) via ChannelType.
- Can generate MU-MIMO channels (
n_users > 1) with per-user distances/floors and optional angle
offsets according to TGac.
- Optional time evolution via
observation_time, update_rate, and mobility parameters.
-
Declaration:
from quadriga_lib import channel
chan = channel.get_ieee_indoor(ap_array, sta_array, ChannelType, CarrierFreq_Hz,
tap_spacing_s, n_users, observation_time, update_rate, speed_station_kmh, speed_env_kmh,
Dist_m, n_floors, uplink, offset_angles, n_subpath, Doppler_effect, seed,
KF_linear, XPR_NLOS_linear, SF_std_dB_LOS, SF_std_dB_NLOS, dBP_m );
-
ap_array:
ap_array
Dictionary containing the access point array antenna with n_tx elements (= ports after element coupling)
e_theta_re |
e-theta field component, real part |
Shape: (n_elevation_ap, n_azimuth_ap, n_elements_ap) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_elevation_ap, n_azimuth_ap, n_elements_ap) |
e_phi_re |
e-phi field component, real part |
Shape: (n_elevation_ap, n_azimuth_ap, n_elements_ap) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_elevation_ap, n_azimuth_ap, n_elements_ap) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth_ap) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation_ap) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements_ap) |
coupling_re |
Coupling matrix, real part, optional |
Shape: (n_elements_ap, n_ports_ap) |
coupling_im |
Coupling matrix, imaginary part, optional |
Shape: (n_elements_ap, n_ports_ap) |
sta_array
Dictionary containing the mobile station array antenna with n_rx elements (= ports after element coupling)
e_theta_re |
e-theta field component, real part |
Shape: (n_elevation_sta, n_azimuth_sta, n_elements_sta) |
e_theta_im |
e-theta field component, imaginary part |
Shape: (n_elevation_sta, n_azimuth_sta, n_elements_sta) |
e_phi_re |
e-phi field component, real part |
Shape: (n_elevation_sta, n_azimuth_sta, n_elements_sta) |
e_phi_im |
e-phi field component, imaginary part |
Shape: (n_elevation_sta, n_azimuth_sta, n_elements_sta) |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Shape: (n_azimuth_sta) |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Shape: (n_elevation_sta) |
element_pos |
Antenna element (x,y,z) positions, optional |
Shape: (3, n_elements_sta) |
coupling_re |
Coupling matrix, real part, optional |
Shape: (n_elements_sta, n_ports_sta) |
coupling_im |
Coupling matrix, imaginary part, optional |
Shape: (n_elements_sta, n_ports_sta) |
ChannelType
Channel model type as defined by TGn. String. Supported: A, B, C, D, E, F.
CarrierFreq_Hz = 5.25e9 (optional)
Carrier frequency in Hz.
tap_spacing_s = 10e-9 (optional)
Tap spacing in seconds. Must be equal to 10 ns / 2^k (TGn default = 10e-9).
n_users = 1 (optional)
Number of users (only for TGac, TGah). Output struct array length equals n_users.
observation_time = 0 (optional)
Channel observation time in seconds. 0 creates a static channel.
update_rate = 1e-3 (optional)
Channel update interval in seconds (only relevant when observation_time > 0).
speed_station_kmh = 0 (optional)
Station movement speed in km/h. Movement direction is AoA_offset. Only relevant when observation_time > 0.
speed_env_kmh = 1.2 (optional)
Environment movement speed in km/h. Default 1.2 for TGn, use 0.089 for TGac. Only relevant when observation_time > 0.
vector Dist_m = [4.99] (optional)
TX-to-RX distance(s) in meters. Length n_users or length 1 (same distance for all users).
vector n_floors = [0] (optional)
Number of floors for TGah model (per user), up to 4 floors. Length n_users or length 1.
uplink = false (optional)
Channel direction flag. Default is downlink; set to true to generate reverse (uplink) direction.
offset_angles = [] (optional)
Offset angles in degree for MU-MIMO channels. Empty uses model defaults (TGac auto for n_users > 1).
Shape [4, n_users] with rows: AoD LOS, AoD NLOS, AoA LOS, AoA NLOS.
n_subpath = 20 (optional)
Number of sub-paths per path/cluster used for Laplacian angular spread mapping.
Doppler_effect = 50 (optional)
Special Doppler effects: models D, E (fluorescent lights, value = mains freq.) and F (moving vehicle speed in km/h).
Use 0 to disable.
seed = -1 (optional)
Numeric seed for repeatability. -1 disables the fixed seed and uses the system random device.
KF_linear = NAN (optional)
Overwrites the model-specific KF-value. If this parameter is NAN (default) or negative, model defaults are used:
A/B/C (KF = 1 for d < dBP, 0 otherwise); D (KF = 2 for d < dBP, 0 otherwise); E/F (KF = 4 for d < dBP, 0 otherwise).
KF is applied to the first tap only. Breakpoint distance is ignored for KF_linear >= 0.
XPR_NLOS_linear = NAN (optional)
Overwrites the model-specific Cross-polarization ratio. If this parameter is NAN (default) or negative,
the model default of 2 (3 dB) is used. XPR is applied to all NLOS taps.
SF_std_dB_LOS = NAN (optional)
Overwrites the model-specific shadow fading for LOS channels. If this parameter is NAN (default),
the model default of 3 dB is used. SF_std_dB_LOS is applied to all LOS channels, where the
AP-STA distance d < dBP.
SF_std_dB_NLOS = NAN (optional)
Overwrites the model-specific shadow fading for LOS channels. If this parameter is NAN (default),
the model defaults are A/B: 4 dB, C/D: 5 dB, E/F: 6 dB. SF_std_dB_NLOS is applied to all NLOS channels,
where the AP-STA distance d >= dBP.
dBP_m = NAN (optional)
Overwrites the model-specific breakpoint distance. If this parameter is NAN (default) or negative,
the model defaults are A/B/C: 5 m, D: 10 m, E: 20 m, F: 30 m.
-
Returns:
chan
List of length n_users containing dictionaries of channel data with the following keys.
name |
Channel name |
String |
tx_position |
Transmitter positions (AP for downlink, STA for uplink) |
Shape: (3, 1) or (3, n_snap) |
rx_position |
Receiver positions (STA for downlink, AP for uplink) |
Shape: (3, 1) or (3, n_snap) |
tx_orientation |
Transmitter orientation, Euler angles (AP for downlink, STA for uplink) |
Shape: (3, 1) or (3, n_snap) |
rx_orientation |
Receiver orientation, Euler angles (STA for downlink, AP for uplink) |
Shape: (3, 1) or (3, n_snap) |
coeff |
Channel coefficients, complex valued |
list of [n_rx, n_tx, n_path_s] |
delay |
Propagation delays in seconds |
list of [n_rx, n_tx, n_path_s] |
path_gain |
Path gain before antenna, linear scale |
list of [n_path_s] |
hdf5_create_file - Create a new HDF5 channel file with a custom storage layout
-
Description:
Quadriga-Lib offers an HDF5-based method for storing and managing channel data. A key feature of this
library is its ability to organize multiple channels within a single HDF5 file while enabling access
to individual data sets without the need to read the entire file. In this system, channels can be
structured in a multi-dimensional array. For instance, the first dimension might represent the Base
Station (BS), the second the User Equipment (UE), and the third the frequency. However, it is important
to note that the dimensions of the storage layout must be defined when the file is initially created
and cannot be altered thereafter. The function quadriga_lib.channel.hdf5_create_file is used to create an
empty file with a predetermined custom storage layout.
-
Usage:
from quadriga_lib import channel
channel.hdf5_create_file( fn, nx, ny, nz, nw )
-
Input Arguments:
fn
Filename of the HDF5 file, string
nx (optional)
Number of elements on the x-dimension, Default = 65536
ny (optional)
Number of elements on the x-dimension, Default = 1
nz (optional)
Number of elements on the x-dimension, Default = 1
nw (optional)
Number of elements on the x-dimension, Default = 1
hdf5_read_channel - Reads channel data from HDF5 files
-
Description:
Quadriga-Lib provides an HDF5-based solution for storing and organizing channel data. This data
comprises various well-defined sets, including channel coefficients, positions of transmitters and
receivers, as well as path data that reflects the interaction of radio waves with the environment.
Typically, these datasets are multi-dimensional, encompassing data for n_rx receive antennas,
n_tx transmit antennas, n_path propagation paths, and n_snap snapshots. Snapshots are
particularly useful for recording data across different locations (such as along a trajectory) or
various frequencies. It is important to note that not all datasets include all these dimensions.
The library also supports the addition of extra datasets of any type or shape, which can be useful
for incorporating descriptive data or analysis results. To facilitate data access, the function
quadriga_lib.channel.hdf5_read_channel is designed to read both structured and unstructured data from the
file.
-
Usage:
from quadriga_lib import channel
data = channel.hdf5_read_channel( fn, ix, iy, iz, iw, snap )
-
Input Arguments:
fn
Filename of the HDF5 file, string
ix
Storage index for x-dimension, Default = 0
iy
Storage index for y-dimension, Default = 0
iz
Storage index for z-dimension, Default = 0
iw
Storage index for w-dimension, Default = 0
snap (optional)
Snapshot range, 0-based notation; optional; vector, default: empty = read all
-
Output Arguments:
data
Dictionary containing the data in the HDF file with the following keys:
par |
Dictionary of unstructured data |
Variable |
rx_position |
Receiver positions |
[3, n_snap] or [3, 1] |
tx_position |
Transmitter positions |
[3, n_snap] or [3, 1] |
coeff |
Channel coefficients, complex valued |
list of [n_rx, n_tx, n_path_s] |
delay |
Propagation delays in seconds |
list of [n_rx, n_tx, n_path_s] or [1, 1, n_path_s] |
center_freq |
Center frequency in [Hz] |
[n_snap] or scalar |
name |
Name of the channel |
String |
initial_pos |
Index of reference position, 1-based |
uint32, scalar |
path_gain |
Path gain before antenna, linear scale |
list of [n_path_s] |
path_length |
Path length from TX to RX phase center in m |
list of [n_path_s] |
polarization |
Polarization transfer function, complex valued |
list of [4, n_path_s] |
path_angles |
Departure and arrival angles {AOD, EOD, AOA, EOA} in rad |
list of [n_path, 4_s] |
path_fbs_pos |
First-bounce scatterer positions |
list of [3, n_path_s] |
path_lbs_pos |
Last-bounce scatterer positions |
list of [3, n_path_s] |
no_interact |
Number interaction points of paths with the environment |
uint32, list of [n_path_s] |
interact_coord |
Interaction coordinates |
list of [3, max(sum(no_interact))] |
rx_orientation |
Receiver orientation |
[3, n_snap] or [3] |
tx_orientation |
Transmitter orientation |
[3, n_snap] or [3] |
-
Caveat:
- Only datasets that are present in the HDF file are returned in the dictionary.
- Although the data is stored in single precision, it is converted to double precision by default.
hdf5_read_dset - Read a single unstructured dataset from an HDF5 file
-
Description:
Quadriga-Lib offers a solution based on HDF5 for storing and organizing channel data. In addition
to structured datasets, the library facilitates the inclusion of extra datasets of various types
and shapes. This feature is particularly beneficial for integrating descriptive data or analysis
results. The function quadriga_lib.channel.hdf5_read_dset retrieves a single unstructured dataset.
The output type of the function is defined by the datatype in the file. An empty matrix is returned
if the dataset does not exist in the file.
-
Usage:
from quadriga_lib import channel
dset = channel.hdf5_read_dset( fn, ix, iy, iz, iw, name )
-
Input Arguments:
fn
Filename of the HDF5 file, string
ix
Storage index for x-dimension, Default = 0
iy
Storage index for y-dimension, Default = 0
iz
Storage index for z-dimension, Default = 0
iw
Storage index for w-dimension, Default = 0
name
Name of the dataset; String
-
Output Argument:
dset
Output data. Type and size is defined by the dataspace in the file
-
Caveat:
- Only datasets that are present in the HDF file are returned in the dictionary.
hdf5_read_dset_names - Read the names of unstructured data fields from an HDF5 file
-
Description:
Quadriga-Lib offers a solution based on HDF5 for storing and organizing channel data. In addition
to structured datasets, the library facilitates the inclusion of extra datasets of various types
and shapes. This feature is particularly beneficial for integrating descriptive data or analysis
results. Users can add any number of such unstructured datasets, each identified by a unique
dataset name. The function quadriga_lib.channel.hdf5_read_dset_names retrieves the names of all
these datasets, returning them as a list of strings.
-
Usage:
from quadriga_lib import channel
names = channel.hdf5_read_dset_names( fn, ix, iy, iz, iw );
-
Input Arguments:
fn
Filename of the HDF5 file, string
ix
Storage index for x-dimension, Default = 0
iy
Storage index for y-dimension, Default = 0
iz
Storage index for z-dimension, Default = 0
iw
Storage index for w-dimension, Default = 0
-
Output Argument:
names
List of names of all these at the given location in the files; Cell array of strings
hdf5_read_layout - Read the storage layout of channel data inside an HDF5 file
hdf5_reshape_layout - Reshapes the storage layout inside an existing HDF5 file
hdf5_write_channel - Writes channel data to HDF5 files
-
Description:
Quadriga-Lib provides an HDF5-based solution for storing and organizing channel data. This function
can be used to write structured and unstructured data to an HDF5 file.
-
Usage:
from quadriga_lib import channel
storage_dims = channel.hdf5_write_channel( fn, ix, iy, iz, iw, par, rx_pos, tx_pos, ...
coeff, delay, center_freq, name, initial_pos, path_gain, path_length, ...
polarization, path_angles, path_fbs_pos, path_lbs_pos, no_interact, interact_coord, ...
rx_orientation, tx_orientation )
-
Input Arguments:
fn
Filename of the HDF5 file, string
ix
Storage index for x-dimension, Default = 0
iy
Storage index for y-dimension, Default = 0
iz
Storage index for z-dimension, Default = 0
iw
Storage index for w-dimension, Default = 0
par
Dictionary of unstructured data, can be empty if no unstructured data should be written
- Structured data: (double precision)
Each snapshot may have a different number of paths n_path_s. Variable-length data is provided as lists.
rx_pos |
Receiver positions |
[3, n_snap] or [3, 1] |
tx_pos |
Transmitter positions |
[3, n_snap] or [3, 1] |
coeff |
Channel coefficients, complex valued |
list of [n_rx, n_tx, n_path_s] |
delay |
Propagation delays in seconds |
list of [n_rx, n_tx, n_path_s] or [1, 1, n_path_s] |
center_freq |
Center frequency in [Hz] |
[n_snap] or scalar |
name |
Name of the channel |
String |
initial_pos |
Index of reference position, 1-based |
uint32, scalar |
path_gain |
Path gain before antenna, linear scale |
list of [n_path_s] |
path_length |
Path length from TX to RX phase center in m |
list of [n_path_s] |
polarization |
Polarization transfer function, complex valued |
list of [4, n_path_s] |
path_angles |
Departure and arrival angles {AOD, EOD, AOA, EOA} in rad |
list of [n_path, 4_s] |
path_fbs_pos |
First-bounce scatterer positions |
list of [3, n_path_s] |
path_lbs_pos |
Last-bounce scatterer positions |
list of [3, n_path_s] |
no_interact |
Number interaction points of paths with the environment |
uint32, list of [n_path_s] |
interact_coord |
Interaction coordinates |
list of [3, max(sum(no_interact))] |
rx_orientation |
Transmitter orientation |
[3, n_snap] or [3] |
tx_orientation |
Receiver orientation |
[3, n_snap] or [3] |
-
Output Arguments:
storage_dims
Size of the dimensions of the storage space, vector with 4 elements, i.e. [nx,ny,nz,nw].
-
Caveat:
- If the file exists already, the new data is added to the exisiting file
- If a new file is created, a storage layout is created to store the location of datasets in the file
- For
location = [ix] storage layout is [65536,1,1,1] or [ix,1,1,1] if (ix > 65536)
- For
location = [ix,iy] storage layout is [1024,64,1,1]
- For
location = [ix,iy,iz] storage layout is [256,16,16,1]
- For
location = [ix,iy,iz,iw] storage layout is [128,8,8,8]
- You can create a custom storage layout by creating the file first using "
hdf5_create_file"
- You can reshape the storage layout by using "
hdf5_reshape_storage", but the total number of elements must not change
- Inputs can be empty or missing.
- All structured data is written in single precision (but can can be provided as single or double)
- Unstructured datatypes are maintained in the HDF file
- Supported unstructured types: string, double, float, (u)int32, (u)int64
- Supported unstructured size: up to 3 dimensions
- Storage order of the unstructured data is maintained
hdf5_write_dset - Writes unstructured data to a HDF5 file
-
Description:
Quadriga-Lib offers a solution based on HDF5 for storing and organizing channel data. In addition
to structured datasets, the library facilitates the inclusion of extra datasets of various types
and shapes. This feature is particularly beneficial for integrating descriptive data or analysis
results. The function quadriga_lib.channel.hdf5_write_dset writes a single unstructured dataset.
-
Usage:
from quadriga_lib import channel
channel.hdf5_write_dset( fn, ix, iy, iz, iw, name, data );
-
Input Arguments:
fn
Filename of the HDF5 file, string
ix
Storage index for x-dimension, Default = 0
iy
Storage index for y-dimension, Default = 0
iz
Storage index for z-dimension, Default = 0
iw
Storage index for w-dimension, Default = 0
name
Name of the dataset; String
-
Caveat:
- Throws an error if dataset already exists at this location
- Throws an error if file does not exist (use hdf5_create_file)
- Supported types: string, double, float, (u)int32, (u)int64
- Supported size: up to 3 dimensions
- Storage order is maintained
qrt_file_parse - Read metadata from a QRT file
-
Usage:
from quadriga_lib import channel
# Separate outputs
no_cir, no_orig, no_dest, no_freq, cir_offset, orig_names, dest_names, version, fGHz, cir_pos, cir_orientation, orig_pos, orig_orientation = channel.qrt_file_parse( fn )
# Output as tuple
data = channel.qrt_file_parse( fn )
-
Input Argument:
fn
Filename of the QRT file, string
-
Output Arguments:
no_cir
Number of channel snapshots per origin point
no_orig
Number of origin points (e.g., TXs)
no_dest
Number of destinations (RX)
no_freq
Number of frequencies
cir_offset
CIR offset for each destination
orig_names
Names of the origin points (TXs), list of strings
dest_names
Names of the destination points (RXs), list of strings
fGHz
Center frequency in GHz as stored in the QRT file, numpy array of floats
cir_pos
CIR positions in Cartesian coordinates, numpy array of shape [no_cir, 3]
cir_orientation
CIR orientation in Euler angles in rad, numpy array of shape [no_cir, 3]
orig_pos
Origin (TX) positions in Cartesian coordinates, numpy array of shape [no_orig, 3]
orig_orientation
Origin (TX) orientations in Euler angles in rad, numpy array of shape [no_orig, 3]
qrt_file_read - Read ray-tracing data from QRT file
quantize_delays - Fixes the path delays to a grid of delay bins
-
Description:
- For channel emulation with finite delay resolution, path delays must be mapped to a fixed grid
of delay bins (taps). This function approximates each path delay using two adjacent taps with
power-weighted coefficients, producing smooth transitions in the frequency domain.
- For a path at fractional offset δ between tap indices, two taps are created with complex
coefficients scaled by (1−δ)^α and δ^α, where α is the power
exponent.
- Input delays may be per-antenna
[n_rx, n_tx, n_path_s] or shared [1, 1, n_path_s]. Output
delay shape depends on fix_taps mode.
- The number of paths
n_path_s may differ across snapshots.
-
Usage:
import quadriga_lib
coeff_re_q, coeff_im_q, delay_q = quadriga_lib.channel.quantize_delays(
coeff_re, coeff_im, delay, tap_spacing=5e-9, max_no_taps=48, power_exponent=1.0, fix_taps=0)
-
Arguments:
list *coeff_re (input)
Channel coefficients, real part. List of n_snap numpy arrays, each of shape
[n_rx, n_tx, n_path_s]. The number of paths may differ per snapshot.
list *coeff_im (input)
Channel coefficients, imaginary part. Same shapes as coeff_re.
list *delay (input)
Path delays in seconds. List of n_snap numpy arrays, each of shape
[n_rx, n_tx, n_path_s] or [1, 1, n_path_s].
float tap_spacing = 5e-9 (input)
Spacing of the delay bins in seconds.
int max_no_taps = 48 (input)
Maximum number of output taps. 0 means unlimited.
float power_exponent = 1.0 (input)
Interpolation exponent. Use 1.0 for narrowband or 0.5 for wideband.
int fix_taps = 0 (input)
Delay sharing mode: 0 = per tx-rx pair and snapshot, 1 = single grid for all,
2 = per snapshot, 3 = per tx-rx pair.
-
Returns:
np.ndarray coeff_re_q (output)
Output coefficients, real part. 4D array of shape [n_rx, n_tx, n_taps, n_snap].
np.ndarray coeff_im_q (output)
Output coefficients, imaginary part. 4D array of shape [n_rx, n_tx, n_taps, n_snap].
np.ndarray delay_q (output)
Output delays in seconds. 4D array of shape [n_rx, n_tx, n_taps, n_snap] or
[1, 1, n_taps, n_snap].
Miscellaneous / Tools
acdf - Calculate the empirical averaged cumulative distribution function (CDF)
-
Description:
- Calculates the empirical CDF from the given data matrix, where each column represents an
independent data set (e.g., repeated experiment runs).
- Individual CDFs are computed per column and an averaged CDF is obtained by interpolation in
quantile space.
Inf and NaN values in the data are excluded from the computation.
- If
bins is None or empty, 201 equally spaced bins spanning the data range are generated.
-
Usage:
import quadriga_lib
result = quadriga_lib.tools.acdf( data, bins, n_bins )
-
Arguments:
np.ndarray data (input)
Input data matrix. Shape (n_samples, n_sets). Each column is one data set.
np.ndarray bins = None (optional input)
Bin centers for the histogram. Shape (n_bins,). If None or empty, bins are auto-generated.
int n_bins = 201 (input)
Number of bins to generate when bins are auto-generated. Must be at least 2.
-
Returns:
dict with keys:
"bins" — Bin centers, shape (n_bins,).
"Sh" — Individual CDFs, shape (n_bins, n_sets).
"Sc" — Averaged CDF, shape (n_bins,).
"mu" — Mean quantiles at 0.1–0.9, shape (9,).
"sig" — Std of quantiles at 0.1–0.9, shape (9,).
-
Example:
import numpy as np
import quadriga_lib
data = np.random.randn(10000, 5)
result = quadriga_lib.tools.acdf(data)
bins = result["bins"] # 201 bin centers
Sh = result["Sh"] # Individual CDFs, shape (201, 5)
Sc = result["Sc"] # Averaged CDF, shape (201,)
mu = result["mu"] # Mean quantiles, shape (9,)
sig = result["sig"] # Std of quantiles, shape (9,)
calc_angular_spread - Calculate azimuth and elevation angular spreads with spherical wrapping
-
Description:
- Calculates the RMS azimuth and elevation angular spreads from a set of power-weighted angles.
- Inputs use lists of 1D numpy arrays so that each CIR can have a different number of paths.
- Uses optional spherical coordinate wrapping to avoid the pole singularity: the power-weighted mean
direction is computed in Cartesian coordinates and all paths are rotated so the centroid lies
on the equator before computing spreads.
- Without spherical wrapping, azimuth spread near the poles is inflated (large azimuth spread
despite energy being focused into a small solid angle). This method corrects for that.
- Optionally computes an optimal bank (roll) angle that maximizes azimuth spread and minimizes
elevation spread, corresponding to the principal axes of the angular power distribution.
- Setting
wrapping to true enables spherical wrapping.
-
Usage:
import quadriga_lib
as_spread, es_spread, orientation, phi, theta = quadriga_lib.tools.calc_angular_spread( az, el, powers)
as_spread, es_spread, orientation, phi, theta = quadriga_lib.tools.calc_angular_spread(
az, el, powers, wrapping=True, calc_bank_angle=True, quantize=0.0)
-
Arguments:
list of np.ndarray az (input)
Azimuth angles in [rad]. List of length n_cir, each element is a 1D array of length n_path.
list of np.ndarray el (input)
Elevation angles in [rad]. List of length n_cir, each element is a 1D array of length n_path.
list of np.ndarray powers (input)
Path powers in [W]. List of length n_cir, each element is a 1D array of length n_path.
bool wrapping = False (input)
If True, enable spherical rotation. Default: False (use raw angles)
bool calc_bank_angle = False (input)
If True, compute the optimal bank angle analytically.
float quantize = 0.0 (input)
Angular quantization step in [deg]. Set to 0 for no quantization.
-
Returns:
np.ndarray azimuth_spread (output)
RMS azimuth angular spread in [rad]. Shape (n_cir,).
np.ndarray elevation_spread (output)
RMS elevation angular spread in [rad]. Shape (n_cir,).
np.ndarray orientation (output)
Mean-angle orientation [bank, tilt, heading] in [rad]. Shape (3, n_cir).
list of np.ndarray phi (output)
Rotated azimuth angles in [rad]. List of length n_cir.
list of np.ndarray theta (output)
Rotated elevation angles in [rad]. List of length n_cir.
-
Example:
import numpy as np
import quadriga_lib
az = [np.array([0.1, -0.1, 0.05]), np.array([0.2, -0.2, 0.1, -0.1])]
el = [np.array([0.0, 0.0, 0.0]), np.array([0.05, -0.05, 0.0, 0.0])]
powers = [np.array([1.0, 1.0, 0.5]), np.array([2.0, 1.0, 1.5, 0.5])]
as_spread, es_spread, orient, phi, theta = quadriga_lib.tools.calc_angular_spread(az, el, powers)
calc_cross_polarization_ratio - Calculate the cross-polarization ratio (XPR) for linear and circular polarization bases
-
Description:
- Computes the aggregate cross-polarization ratio (XPR) from the polarization transfer matrices
of all channel impulse responses (CIRs) using the total-power-ratio method.
- For each CIR, the total co-polarized and cross-polarized received powers are accumulated
across all qualifying paths, and the XPR is obtained as a single ratio of the totals.
- In addition to the linear V/H basis, the XPR is also computed in the circular LHCP/RHCP basis.
- The LOS path is identified by comparing each path's absolute length against the direct
TX-RX distance. All paths with
path_length < dTR + window_size are excluded from
the XPR calculation by default (controlled by include_los).
- If the total cross-polarized power is zero, the XPR is set to 0 (undefined).
-
Usage:
import quadriga_lib
xpr, pg = quadriga_lib.tools.calc_cross_polarization_ratio( powers, M, path_length, tx_pos, rx_pos )
xpr, pg = quadriga_lib.tools.calc_cross_polarization_ratio( powers, M, path_length, tx_pos, rx_pos, include_los, window_size )
-
Arguments:
list of np.ndarray powers (input)
Path powers in Watts. List of length n_cir, each element is a 1D array of length n_path.
list of np.ndarray M (input)
Polarization transfer matrices. List of length n_cir, each element is a 2D array of size [8, n_path].
list of np.ndarray path_length (input)
Absolute path length from TX to RX in meters. List of length n_cir, each element is a 1D array of length n_path.
np.ndarray tx_pos (input)
Transmitter position. Size [3, 1] (fixed) or [3, n_cir] (mobile).
np.ndarray rx_pos (input)
Receiver position. Size [3, 1] (fixed) or [3, n_cir] (mobile).
bool include_los = False (input)
If True, include LOS paths in the XPR calculation.
float window_size = 0.01 (input)
LOS window size in meters.
-
Returns:
np.ndarray xpr (output)
Cross-polarization ratio, linear scale. Size [n_cir, 6].
Columns: 0=aggregate linear, 1=V-XPR, 2=H-XPR, 3=aggregate circular, 4=LHCP, 5=RHCP.
np.ndarray pg (output)
Total path gain over all paths. 1D array of length [n_cir].
calc_delay_spread - Calculate the RMS delay spread in [s]
-
Description:
- Computes the root-mean-square (RMS) delay spread from a given set of delays and corresponding
linear-scale powers for each channel impulse response (CIR).
- An optional power threshold in [dB] relative to the strongest path can be applied. Paths with
power below
p_max(dB) - threshold are excluded from the calculation.
- An optional granularity parameter in [s] groups paths in the delay domain. Powers of paths
falling into the same delay bin are summed before computing the delay spread.
- Optionally returns the mean delay for each CIR.
-
Usage:
import quadriga_lib
ds, mean_delay = quadriga_lib.tools.calc_delay_spread(delays, powers, threshold=100.0, granularity=0.0)
-
Arguments:
list of np.ndarray delays (input)
Delays in [s]. A list of length n_cir, where each element is a 1D numpy array of path delays.
list of np.ndarray powers (input)
Path powers on a linear scale [W]. Same structure as delays.
float threshold = 100.0 (input)
Power threshold in [dB] relative to the strongest path. Default: 100 dB.
float granularity = 0.0 (input)
Window size in [s] for grouping paths in the delay domain. Default: 0 (no grouping).
-
Returns:
np.ndarray ds (output)
RMS delay spread in [s] for each CIR. Shape (n_cir,).
np.ndarray mean_delay (output)
Mean delay in [s] for each CIR. Shape (n_cir,).
-
Example:
import numpy as np
import quadriga_lib
delays = [np.array([0.0, 1e-6, 2e-6])]
powers = [np.array([1.0, 0.5, 0.25])]
ds, mean_delay = quadriga_lib.calc_delay_spread(delays, powers)
calc_rician_k_factor - Calculate the Rician K-Factor from channel impulse response data
-
Description:
- The Rician K-Factor (KF) is defined as the ratio of signal power in the dominant line-of-sight
(LOS) path to the power in the scattered (non-line-of-sight, NLOS) paths.
- The LOS path is identified by matching the absolute path length with the direct distance between
TX and RX positions (
dTR).
- All paths arriving within
dTR + window_size are considered LOS and their power is summed.
- Paths arriving after
dTR + window_size are considered NLOS and their power is summed.
- If the total NLOS power is zero, the K-Factor is set to infinity.
- If the total LOS power is zero, the K-Factor is set to zero.
- The transmitter and receiver positions can be fixed (shape
(3,) or (3, 1)) or mobile
(shape (3, n_cir)). Fixed positions are reused for all channel snapshots.
- Output
pg returns the total path gain (sum of all path powers) for each snapshot.
-
Usage:
import quadriga_lib
kf, pg = quadriga_lib.tools.calc_rician_k_factor( powers, path_length, tx_pos, rx_pos, window_size=0.01 )
-
Arguments:
list of ndarray powers (input)
Path powers in Watts [W]. List of length n_cir, where each element is a 1D numpy array of
length n_path.
list of ndarray path_length (input)
Absolute path lengths from TX to RX phase center in meters. List of length n_cir, where each
element is a 1D numpy array of length n_path matching the corresponding entry in powers.
ndarray tx_pos (input)
Transmitter position in Cartesian coordinates. Shape (3,) or (3, 1) for fixed TX, or
(3, n_cir) for mobile TX.
ndarray rx_pos (input)
Receiver position in Cartesian coordinates. Shape (3,) or (3, 1) for fixed RX, or
(3, n_cir) for mobile RX.
float window_size = 0.01 (input)
LOS window size in meters. Paths with length ≤ dTR + window_size are considered LOS.
-
Returns:
ndarray kf (output)
Rician K-Factor on linear scale. Shape (n_cir,).
ndarray pg (output)
Total path gain (sum of path powers). Shape (n_cir,).
cart2geo - Transform Cartesian (x,y,z) coordinates to Geographic (az, el, length) coordinates
components - Returns the version numbers of all quadriga-lib sub-components
version - Returns the quadriga-lib version number
write_png - Write data to a PNG file
-
Description:
- Converts input data into a color-coded PNG file for visualization
- Support optional selection of a colormap, as well a minimum and maximum value limits
- Uses the LodePNG library for PNG writing
-
Declaration:
import quadriga_lib
quadriga_lib.tools.write_png( fn, data, colormap, min_val, max_val, log_transform )
-
Arguments:
fn
Filename of the PNG file, string, required
data
Data matrix, required, size [N, M]
colormap (optional)
Colormap for the visualization, string, supported are 'jet', 'parula', 'winter', 'hot', 'turbo',
'copper', 'spring', 'cool', 'gray', 'autumn', 'summer', optional, default = 'jet'
min_val (optional)
Minimum value. Values below this value will have be encoded with the color of the smallest value.
If NAN is provided (default), the lowest values is determined from the data.
max_val (optional)
Maximum value. Values above this value will have be encoded with the color of the largest value.
If NAN is provided (default), the largest values is determined from the data.
log_transform (optional)
If enabled, the data values are transformed to the log-domain (10*log10(data)) before processing.
Default: false (disabled)
Site-Specific Simulation Tools
icosphere - Construct a geodesic polyhedron (icosphere), a convex polyhedron made from triangles
-
Description:
An icosphere is constructed by subdividing faces of an icosahedron, a polyhedron with 20 faces,
12 vertices and 30 edges, and then projecting the new vertices onto the surface of a sphere. The
resulting mesh has 6 triangles at each vertex, except for 12 vertices which have 5 triangles.
The approximate equilateral triangles have roughly the same edge length and surface area.
-
Usage:
from quadriga_lib import RTtools
center, length, vert, direction = RTtools.icosphere( no_div, radius, direction_xyz )
-
Input Arguments:
no_div
Number of divisions per edge of the generating icosahedron. The resulting number of faces is
equal to no_face = 20 · no_div^2
radius
Radius of the sphere in meters
direction_xyz
Direction format indicator: 0 = Spherical (default), 1 = Cartesian
-
Output Arguments (tuple containing 4 values):
center
Position of the center point of each triangle; Shape: ( no_face, 3 )
length
Length of the vector pointing from the origin to the center point. This number is smaller than
1 since the triangles are located inside the unit sphere; Shape: ( no_face )
vert
The 3 vectors pointing from the center point to the vertices of each triangle; the values are
in the order [ v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z ]; Shape: ( no_face, 9 )
direction
The directions of the vertex-rays. If the format indicator direction_xyz is set to 0, the
output is in geographic coordinates (azimuth and elevation angle in rad); the values are in the
order ( v1az, v1el, v2az, v2el, v3az, v3el ];Shape: ( no_face, 6 ) If the format indicator
direction_xyz is set to 1, the output is in Cartesian coordinates and the values are in the
order [ v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z ]; Shape: ( no_face, 9 )
mitsuba_xml_file_write - Write geometry and material data to a Mitsuba 3 XML scene file.
-
Description:
Converts a triangular surface mesh into the XML format understood by Mitsuba 3
www.mitsuba-renderer.org.
The generated file can be loaded directly by NVIDIA Sionna RT for differentiable radio-propagation
simulations.
- Converts a 3D geometry mesh into Mitsuba 3 XML format for use with rendering tools.
- Enables exporting models from
quadriga-lib to be used with Mitsuba 3 or Sionna RT:
- Mitsuba 3: Research-oriented retargetable rendering system.
- NVIDIA Sionna: Hardware-accelerated differentiable ray tracer for wireless propagation, built on Mitsuba 3.
- Supports grouping faces into named objects and assigning materials by name.
- Optionally maps materials to ITU default presets used by Sionna RT.
-
Usage:
from quadriga_lib import RTtools
RTtools.mitsuba_xml_file_write( fn, vert_list, face_ind, obj_id, mtl_id, obj_names, mtl_names, bsdf, map_to_itu )
-
Input Arguments:
fn
Output file name (including path and .xml extension).
vert_list
Vertex list, size [n_vert, 3], each row is a vertex (x, y, z) in Cartesian coordinates [m].
face_ind
Face indices (0-based), size [n_mesh, 3], each row defines a triangle via vertex indices.
obj_id (input)
Object indices (1-based), size [n_mesh]. Assigns each triangle to an object.
mtl_id (input)
Material indices (1-based), size [n_mesh]. Assigns each triangle to a material.
obj_names
List of object names. Length must be equal to max(obj_ind).
mtl_names
List of material names. Length must be equal to max(mtl_ind).
bsdf = [] (optional input)
Material reflectivity data (BSDF parameters), size [len(mtl_names), 17]. If omitted, the null BSDF is used.
Note that Sionna RT ignores all BSDF parameters. They are only used by the Mitsuma rendering system.
See obj_file_read for a definition of the data fields.
map_to_itu = false (optional input)
If true, maps material names to ITU-defined presets used by Sionna RT. Default: false
-
See also:
obj_file_read - Reads a triangulated 3D polygon mesh from a Wavefront OBJ file
-
Description:
The function imports a polygon mesh from an OBJ file. The OBJ file format is a straightforward data
format, representing 3D geometry. It details the position of each vertex and defines polygons as lists
of these vertices. By default, vertices are arranged in a counter-clockwise order, eliminating the
need for explicit declaration of face normals. When exporting the mesh from software like Blender,
it's essential to triangulate the mesh and include material definitions. If the material name
exists in the material database, the function loads the corresponding properties.
Otherwise, it defaults to using standard properties.
-
Usage:
from quadriga_lib import RTtools
# Return as separate variables
mesh, mtl_prop, vert_list, face_ind, obj_ind, mtl_ind, obj_names, mtl_names, bsdf = RTtools.obj_file_read( fn )
# Return as tuple with 8 elements
data = RTtools.obj_file_read( fn )
# Use a custom material definition file
data = RTtools.obj_file_read( fn, materials_csv )
-
Input Arguments:
fn
Filename of the OBJ file, string
materials_csv (optional)
Path to optional CSV file containing custom material properties. If empty, default ITU-R P.2040-3
materials are used. CSV format: Header row with columns 'name', 'a', 'b', 'c', 'd', 'att' (order can vary).
Each row defines a material with: name (string), electromagnetic parameters a,b,c,d (doubles),
and additional attenuation att (dB). Relative permittivity: eta = a * f_GHz^b; Conductivity:
sigma = c * f_GHz^d
-
Output Arguments:
mesh, data[0]
Vertices of the triangular mesh in global Cartesian coordinates. Each face is described by 3 points
in 3D-space. Hence, a face has 9 values in the order [ v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z ];
Size: [ no_mesh, 9 ]
mtl_prop, data[1]
Material properties of each mesh element; If no material is defined for an object, the properties
for vacuum are used. Size: [ no_mesh, 5 ]
vert_list, data[2]
List of vertices found in the OBJ file; Size: [ no_vert, 3 ]
face_ind, data[3]
Triangular faces are defined by three vertices. Vertex indices match the corresponding vertex elements
of the previously defined vert_list (0-based).
uint32; Size: [ no_mesh, 3 ]
obj_id, data[4]
Mesh elements in the OBJ file can be grouped into objects (e.g. 12 triangles define the walls of a
cube). Each object is identified by a unique ID (1-based index of obj_names).
uint32; Size: [ no_mesh, 1 ]
mtl_id, data[5]
Each mesh element gets assigned a material and each unique material gets assigned an ID (1-based
index of mtl_names). Different faces of an object can have different materials. If no material is
defined in the OBJ file, the id is set to 0 and no entry is made in mtl_names.
uint32; Size: [ no_mesh, 1 ]
obj_names, data[6]
Names of the objects in the OBJ file; List of strings
mtl_names, data[7]
Names of the materials in the OBJ file; List of strings
bsdf, data[8]
Principled BSDF (Bidirectional Scattering Distribution Function) values extracted from the
.MTL file. Size [mtl_names.size(), 17]. Values are:
| 0 |
Base Color Red |
Range 0-1 |
Default = 0.8 |
| 1 |
Base Color Green |
Range 0-1 |
Default = 0.8 |
| 2 |
Base Color Blue |
Range 0-1 |
Default = 0.8 |
| 3 |
Transparency (alpha) |
Range 0-1 |
Default = 1.0 (fully opaque) |
| 4 |
Roughness |
Range 0-1 |
Default = 0.5 |
| 5 |
Metallic |
Range 0-1 |
Default = 0.0 |
| 6 |
Index of refraction (IOR) |
Range 0-4 |
Default = 1.45 |
| 7 |
Specular Adjustment to the IOR |
Range 0-1 |
Default = 0.5 (no adjustment) |
| 8 |
Emission Color Red |
Range 0-1 |
Default = 0.0 |
| 9 |
Emission Color Green |
Range 0-1 |
Default = 0.0 |
| 10 |
Emission Color Blue |
Range 0-1 |
Default = 0.0 |
| 11 |
Sheen |
Range 0-1 |
Default = 0.0 |
| 12 |
Clearcoat |
Range 0-1 |
Default = 0.0 |
| 13 |
Clearcoat roughness |
Range 0-1 |
Default = 0.0 |
| 14 |
Anisotropic |
Range 0-1 |
Default = 0.0 |
| 15 |
Anisotropic rotation |
Range 0-1 |
Default = 0.0 |
| 16 |
Transmission |
Range 0-1 |
Default = 0.0 |
-
Material properties:
Each material is defined by its electrical properties. Radio waves that interact with a building will
produce losses that depend on the electrical properties of the building materials, the material
structure and the frequency of the radio wave. The fundamental quantities of interest are the electrical
permittivity (ϵ) and the conductivity (σ). A simple regression model for the frequency dependence is
obtained by fitting measured values of the permittivity and the conductivity at a number of frequencies.
The five parameters returned in mtl_prop then are:
- Real part of relative permittivity at f = 1 GHz (a)
- Frequency dependence of rel. permittivity (b) such that ϵ = a · f^b
- Conductivity at f = 1 GHz (c)
- Frequency dependence of conductivity (d) such that σ = c· f^d
- Fixed attenuation in dB applied to each transition
A more detailed explanation together with a derivation can be found in ITU-R P.2040. The following
list of material is currently supported and the material can be selected by using the usemtl tag
in the OBJ file. When using Blender, the simply assign a material with that name to an object or face.
In addition, custom properties can be set by assigning adding the 5 properties after the material
name, separated by :, e.g.:
usemtl custom::2.1:0.1:0.1:0.5:20
The following materials are defined by default:
| Name |
a |
b |
c |
d |
Att |
max fGHz |
|
| vacuum / air |
1.0 |
0.0 |
0.0 |
0.0 |
0.0 |
100 |
|
| textiles |
1.5 |
0.0 |
5e-5 |
0.62 |
0.0 |
100 |
|
| plastic |
2.44 |
0.0 |
2.33e-5 |
1.0 |
0.0 |
100 |
|
| ceramic |
6.5 |
0.0 |
0.0023 |
1.32 |
0.0 |
100 |
|
| sea_water |
80.0 |
-0.25 |
4.0 |
0.58 |
0.0 |
100 |
|
| sea_ice |
3.2 |
-0.022 |
1.1 |
1.5 |
0.0 |
100 |
|
| water |
80.0 |
-0.18 |
0.6 |
1.52 |
0.0 |
20 |
|
| water_ice |
3.17 |
-0.005 |
5.6e-5 |
1.7 |
0.0 |
20 |
|
| itu_concrete |
5.24 |
0.0 |
0.0462 |
0.7822 |
0.0 |
100 |
|
| itu_brick |
3.91 |
0.0 |
0.0238 |
0.16 |
0.0 |
40 |
|
| itu_plasterboard |
2.73 |
0.0 |
0.0085 |
0.9395 |
0.0 |
100 |
|
| itu_wood |
1.99 |
0.0 |
0.0047 |
1.0718 |
0.0 |
100 |
|
| itu_glass |
6.31 |
0.0 |
0.0036 |
1.3394 |
0.0 |
100 |
|
| itu_ceiling_board |
1.48 |
0.0 |
0.0011 |
1.075 |
0.0 |
100 |
|
| itu_chipboard |
2.58 |
0.0 |
0.0217 |
0.78 |
0.0 |
100 |
|
| itu_plywood |
2.71 |
0.0 |
0.33 |
0.0 |
0.0 |
40 |
|
| itu_marble |
7.074 |
0.0 |
0.0055 |
0.9262 |
0.0 |
60 |
|
| itu_floorboard |
3.66 |
0.0 |
0.0044 |
1.3515 |
0.0 |
100 |
|
| itu_metal |
1.0 |
0.0 |
1.0e7 |
0.0 |
0.0 |
100 |
|
| itu_very_dry_ground |
3.0 |
0.0 |
0.00015 |
2.52 |
0.0 |
10 |
|
| itu_medium_dry_ground |
15.0 |
-0.1 |
0.035 |
1.63 |
0.0 |
10 |
|
| itu_wet_ground |
30.0 |
-0.4 |
0.15 |
1.3 |
0.0 |
10 |
|
| itu_vegetation |
1.0 |
0.0 |
1.0e-4 |
1.1 |
0.0 |
100 |
|
| irr_glass |
6.27 |
0.0 |
0.0043 |
1.1925 |
23.0 |
100 |
|
point_cloud_aabb - Calculates the axis-aligned bounding box (AABB) for a 3D point cloud or a set of sub-clouds
point_cloud_segmentation - Rearranges elements of a point cloud into smaller sub-clouds
-
Description:
This function processes a large 3D point cloud by clustering closely spaced points and recursively
partitioning it into smaller sub-clouds, each below a specified size threshold. It minimizes the
axis-aligned bounding box of each sub-cloud while striving to maintain a target number of points
per cluster.
Sub-clouds are aligned to a specified SIMD vector size (e.g., for AVX or CUDA), with padding applied
as needed. The function outputs a reorganized version of the input points (pointsR), where points
are grouped by sub-cloud, and provides forward and reverse index maps to track the reordering. This
organization is particularly useful for optimizing spatial processing tasks such as bounding volume
hierarchies or GPU batch execution.
-
Usage:
from quadriga_lib import RTtools
# Output as tuple
data = RTtools.point_cloud_segmentation( points, target_size, vec_size )
# Unpacked outputs
points_out, sub_cloud_ind, forward_ind, reverse_ind = RTtools.point_cloud_segmentation( points, target_size, vec_size )
-
Input Arguments:
points
Points in 3D-Cartesian space; Size: [ n_points, 3 ]
target_size (optional)
The target number of elements of each sub-cloud. Default value = 1024. For best performance, the
value should be around 10 * sgrt( n_points )
vec_size (optional)
Vector size for SIMD processing (e.g. 8 for AVX2, 32 for CUDA). Default value = 1.
For values > 1,the number of rows for each sub-cloud in the output is increased to a multiple
of vec_size. For padding, zero-sized triangles are placed at the center of the AABB of
the corresponding sub-cloud.
-
Output Arguments:
points_out, data[0]
Points in 3D-Cartesian space; singe or double precision; Size: [ n_points_out, 3 ]
sub_cloud_ind, data[1]
Start indices of the sub-clouds in 0-based notation. Type: uint32; Vector of length [ n_sub_cloud ]
forward_ind, data[2]
Indices for mapping elements of "points_in" to "points_out"; 1-based;
Length: [ n_points_out ]; For vec_size > 1, the added elements not contained in the input
are indicated by zeros.
reverse_ind, data[3]
Indices for mapping elements of "points_out" to "points"; 0-based; Length: [ n_points ]
point_inside_mesh - Test whether 3D points are inside a triangle mesh using raycasting
-
Description:
- Uses raycasting to determine whether each 3D point lies inside a triangle mesh.
- Requires that the mesh is watertight and all normals are pointing outwards.
- For each point, multiple rays are cast in various directions.
- If any ray intersects a mesh element with a negative incidence angle, the point is classified as inside.
- Output can be binary (0 = outside, 1 = inside) or labeled with object indices.
-
Usage:
from quadriga_lib import RTtools
result = RTtools.point_inside_mesh( points, mesh, obj_ind, distance )
-
Input Arguments:
points (input)
3D point coordinates to test, size [n_points, 3].
mesh (input)
Triangular mesh faces. Each row represents a triangle using 3 vertices in row-major format
(x1,y1,z1,x2,y2,z2,x3,y3,z3), size [n_mesh, 9].
obj_ind (optional input)
Optional object index for each mesh element (1-based), size [n_mesh]. If provided, the return
vector will contain the index of the enclosing object instead of binary values.
distance (optional input)
Optional distance in meters from objects that should be considered as inside the object.
Possible range: 0 - 20 m. Using this parameter significantly increases computation time.
-
Output Arguments:
result
For each point: Returns 0 if the point is outside the mesh (or all objects), 1 if inside
(or close to) any mesh object (if obj_ind not given), or returns the 1-based object index
if obj_ind is provided. Size: [n_points]
ray_point_intersect - Calculates which 3D points are intersected by volumetric ray beams
-
Description:
Unlike traditional ray tracing (rays are infinitesimal lines), beam tracing models rays as
volumes. Each beam is defined by a triangular wavefront whose three vertices diverge as the
beam propagates, capturing real-world spread (e.g., radio-wave divergence) and enabling realistic
energy distribution across the beam’s cross-section. Because beams have volume, intersection tests
are volumetric rather than line-to-geometry.
A ray beam is specified by:
- An origin point.
- Three aperture vectors from the origin to the vertices of an initial triangular wavefront
that defines the beam’s cross-section at the origin.
- Three per-vertex direction vectors (one per vertex) that govern how each vertex, and thus the
triangle, diverges as the beam extends. Directions need not be normalized.
What the function does
- Tests whether each point in a 3D Cartesian point cloud lies inside any of the defined ray beams.
- For every input point, returns a list of 0-based ray indices of beams that intersect that point.
Performance & usage notes
- Optional support for pre-segmented point clouds (e.g., from point_cloud_segmentation) to reduce computation.
- All internal computations use single-precision floats for speed.
- Utilizes AVX2 vectorization when supported by the CPU.
- For best accuracy, use a small tube radius and well-distributed points.
-
Usage:
from quadriga_lib import RTtools
hit_count, ray_ind = RTtools.ray_point_intersect( orig, trivec, tridir, points, sub_cloud_ind, target_size )
-
Input Arguments:
orig
Ray origins in 3D Cartesian coordinates; Shape: (n_ray, 3)
trivec
Three vectors from each ray’s origin to the vertices of the triangular propagation tube (beam);
Order per row: [v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z]; Shape: (n_ray, 9)
tridir
Directions of the three vertex rays in Cartesian coordinates. Normalization not required.
Order per row: [d1x, d1y, d1z, d2x, d2y, d2z, d3x, d3y, d3z]; Shape: (n_ray, 9)
points
3D Cartesian coordinates of the point cloud to test. Shape: (n_points, 3)
sub_cloud_ind (optional)
0-based start indices of sub-clouds used to partition points for performance. If not provided
(empty array), sub-clouds may be computed automatically. Passing a scalar 0 disables sub-cloud calculation.
Shape: (n_sub_cloud,) (strictly increasing; typically starts with 0)
target_size (optional)
Desired sub-cloud size used only if sub_cloud_ind is not given or empty (guides automatic segmentation).
If it is not given (set to 0) and sub_cloud_ind is empty or also not given, the optimal valued is computed
from the number of points.
-
Output Arguments:
hit_count
Number of ray beams that hit a point. Shape: (n_points, )
ray_ind
List of length n_points; each list entry is a 1-D array of 0-based ray indices that hit that point.
Entries may be empty if no hit was detected.
-
See also:
ray_triangle_intersect - Calculates the intersection of rays and triangles in three dimensions
-
Description:
- This function implements the Möller–Trumbore ray-triangle intersection algorithm, known for its
efficiency in calculating the intersection of a ray and a triangle in three-dimensional space.
This method achieves its speed by eliminating the need for precomputed plane equations of the plane
containing the triangle.
- The algorithm defines the ray using two points: an origin and a destination. Similarly, the triangle
is specified by its three vertices.
- To enhance performance, this implementation leverages AVX2 intrinsic functions and OpenMP, when
available, to speed up the computational process.
-
Usage:
from quadriga_lib import RTtools
# Output as tuple
data = RTtools.ray_triangle_intersect( orig, dest, mesh, sub_mesh_index )
# Unpacked outputs
fbs, sbs, no_interact, fbs_ind, sbs_ind = RTtools.ray_triangle_intersect( orig, dest, mesh, sub_mesh_index )
-
Input Arguments:
orig
Ray origins in 3D Cartesian coordinates; Size: [ no_ray, 3 ]
dest
Ray destinations in 3D Cartesian coordinates; Size: [ no_ray, 3 ]
mesh
Vertices of the triangular mesh in global Cartesian coordinates. Each face is described by 3 points
in 3D-space. Hence, a face has 9 values in the order [ v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z ];
Size: [ no_mesh, 9 ]
sub_mesh_index (optional)
Start indices of the sub-meshes in 0-based notation. If this parameter is not given, intersections
are calculated for each mesh element, leading to poor performance for large meshes.
Vector of length [ n_sub_mesh ]
-
Output Arguments:
fbs, data[0]
First interaction point between the rays and the triangular mesh. If no interaction was found, the
FBS location is equal to dest. Size: [ no_ray, 3 ]
sbs, data[1]
Second interaction point between the rays and the triangular mesh. If no interaction was found, the
SBS location is equal to dest. Size: [ no_ray, 3 ]
no_interact, data[2]
Total number of interactions between the origin point and the destination; uint32; Length: [ no_ray ]
fbs_ind, data[3]
Index of the triangle that was hit by the ray at the FBS location; 1-based; uint32; Length: [ no_ray ]
sbs_ind, data[4]
Index of the triangle that was hit by the ray at the SBS location; 1-based; uint32; Length: [ no_ray ]
-
Caveat:
- All internal computation are done in single precision to achieve an additional 2x improvement in
speed compared to double precision when using AVX2 intrinsic instructions
-
See also:
triangle_mesh_aabb - Calculate the axis-aligned bounding box (AABB) of a triangle mesh and its sub-meshes
triangle_mesh_segmentation - Rearranges elements of a triangle mesh into smaller sub-meshes
-
Description:
This function processes the elements of a large triangle mesh by clustering those that are
closely spaced. The resulting mesh retains the same elements but rearranges their order.
The function aims to minimize the size of the axis-aligned bounding box around each cluster,
referred to as a sub-mesh, while striving to maintain a specific number of elements within
each cluster.
This approach is particularly useful in computer graphics and simulation applications where
managing computational resources efficiently is crucial. By organizing the mesh elements into
compact clusters, the function enhances rendering performance and accelerates computational
tasks, such as collision detection and physics simulations. It allows for quicker processing
and reduced memory usage, making it an essential technique in both real-time graphics rendering
and complex simulation environments.
-
Usage:
from quadriga_lib import RTtools
# Output as tuple
data = RTtools.triangle_mesh_segmentation( triangles, target_size, vec_size, mtl_prop )
# Unpacked outputs
triangles_out, sub_mesh_index, mesh_index, mtl_prop_out = RTtools.triangle_mesh_segmentation( triangles, target_size, vec_size, mtl_prop )
-
Input Arguments:
triangles
Vertices of the triangular mesh in global Cartesian coordinates. Each face is described by 3
points in 3D-space: [ v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z ]; Size: [ n_triangles, 9 ]
target_size (optional)
The target number of elements of each sub-mesh. Default value = 1024. For best performance, the
value should be around sgrt( n_triangles )
vec_size (optional)
Vector size for SIMD processing (e.g. 8 for AVX2, 32 for CUDA). Default value = 1.
For values > 1,the number of rows for each sub-mesh in the output is increased to a multiple
of vec_size. For padding, zero-sized triangles are placed at the center of the AABB of
the corresponding sub-mesh.
mtl_prop_in (optional)
Material properties of each mesh element; Size: [ n_triangles, 5 ]
If this is not provided, the corresponding mtl_prop_out will be empty.
-
Output Arguments:
triangles_out, data[0]
Vertices of the clustered mesh in global Cartesian coordinates; Size: [ n_triangles_out, 9 ]
sub_mesh_index, data[1]
Start indices of the sub-meshes in 0-based notation. Type: int; Vector of length [ n_sub_mesh ]
mesh_index, data[2]
Indices for mapping elements of "triangles_in" to "triangles_out"; 1-based;
Length: [ n_triangles_out ]; For vec_size > 1, the added elements not contained in the input
are indicated by zeros.
mtl_prop_out, data[3]
Material properties for the sub-divided triangle mesh elements. The values for the new faces are
copied from mtl_prop_in; Size: [ n_triangles_out, 5 ]; For vec_size > 1, the added elements
will contain the vacuum / air material.