Python API Documentation for Quadriga-Lib v0.11.5
Notes
Overview
Array antenna functions
Channel functions
Channel generation functions
| get_ieee_indoor | Generate indoor MIMO channel realizations for IEEE TGn/TGac/TGax/TGah models |
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
Description:
Directivity is a parameter of an antenna or which measures the degree to which the radiation emitted
is concentrated in a single direction. It is the ratio of the radiation intensity in a given direction
from the antenna to the radiation intensity averaged over all directions. Therefore, the directivity
of a hypothetical isotropic radiator is 1, or 0 dBi.
Usage:
from quadriga_lib import arrayant
directivity = arrayant.calc_directivity(arrayant, element)
Input Arguments:
arrayant_in
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 (optional)
Element index, 0-based. If not provided or empty, the directivity is calculated for all elements in the
array antenna. Shape: (n_out) or empty
Output Argument:
directivity
Directivity of the antenna pattern in dBi, Shape: [n_out) or [n_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]
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
Description:
Quadriga-Lib provides an HDF5-based solution for the storage and organization of channel data. A
notable feature of this library is its capacity to manage multiple channels within a single HDF5
file. In this framework, channels can be arranged in a multi-dimensional array format.
The function
quadriga_lib.channel.hdf5_read_layout is designed to read the storage layout from an
existing file. Furthermore, it also generates an array that marks the locations within the layout
where data already exists. This functionality aids in efficiently managing and accessing channel
data within the HDF5 file structure.
Usage:
from quadriga_lib import channel
storage_dims, has_data = channel.hdf5_read_layout( fn )
Input Argument:
fn
Filename of the HDF5 file, string
Output Arguments:
storage_dims
Size of the dimensions of the storage space, vector with 4 elements, i.e. [nx,ny,nz,nw].
has_data
Array indicating if data exists (value 1) or not (value 0); uint32; Size: [nx,ny,nz,nw]
hdf5_reshape_layout - Reshapes the storage layout inside an existing HDF5 file
Description:
Quadriga-Lib provides an HDF5-based solution for the storage and organization of channel data. A
notable feature of this library is its capacity to manage multiple channels within a single HDF5
file. In this framework, channels can be arranged in a multi-dimensional array format.
Once an HDF5 file has been created, the number of channels in the storage layout is fixed.
However, it is possible to reshape the layout using
quadriga_lib.channel.hdf5_reshape_layout.
Usage:
from quadriga_lib import channel
channel.hdf5_reshape_layout( fn, storage_dims );
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_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
data
Data to be written
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
version
QRT file version
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
Usage:
from quadriga_lib import channel
data = channel.qrt_file_read( fn, i_cir, i_orig, downlink )
Input Arguments:
fn
Filename of the QRT file, string
cir
Snapshot index in the file, Default = 0
orig
Origin index (for downlink Origin = TX), Default = 0
downlink
Switch for uplink / downlink direction, Default = true (downlink)
normalize_M
Switch for different normalization options:
| 0 |
M as in QRT file, path_gain as FSPL (no normalization) |
| 1 |
M has sum-column power is 2, path_gain is FSPL + material losses (default) |
Output Arguments:
data
Dictionary containing the data in the HDF file with the following keys:
center_freq |
Center frequency in [Hz] |
Length [n_freq] |
tx_pos |
Transmitter position |
Length [3] |
tx_orientation |
Transmitter orientation, Euler angles, rad |
Length [3] |
rx_pos |
Receiver position |
Length [3] |
rx_orientation |
Receiver orientation, Euler angles, rad |
Length [3] |
fbs_pos |
First-bounce scatterer positions |
Size [3, n_path] |
lbs_pos |
Last-bounce scatterer positions |
Size [3, n_path] |
path_gain |
Path gain before antenna, linear scale |
Size [n_path, n_freq] |
path_length |
Path length from TX to RX phase center in m |
Length [n_path] |
M |
Polarization transfer function, interleaved complex |
Size [8, n_path, n_freq] or [2, n_path, n_freq] |
aod |
Departure azimuth angles in [rad] |
Length [n_path] |
eod |
Departure elevation angles in [rad] |
Length [n_path] |
aoa |
Arrival azimuth angles in [rad] |
Length [n_path] |
eoa |
Arrival elevation angles in [rad] |
Length [n_path] |
path_coord |
Interaction coordinates |
List of [3, n_int_s] |
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].
Channel generation functions
get_ieee_indoor - Generate indoor MIMO channel realizations for IEEE TGn/TGac/TGax/TGah models
- Generates one or multiple indoor channel realizations based on IEEE TGn/TGac/TGax/TGah model definitions
- 2D model: azimuth angles and planar motion only, no elevation
- Supported channel types:
A, B, C, D, E, F (TGn definitions)
- MU-MIMO supported (
n_users > 1) with per-user distances/floors and optional angle offsets per TGac
- Time-evolving channels via
observation_time, update_rate, and mobility parameters; observation_time = 0.0 yields a static channel
- Default KF (linear): A/B/C → 1 (LOS) / 0 (NLOS), D → 2/0, E/F → 4/0; applied to first tap only; breakpoint ignored when
KF_linear >= 0
- Default XPR NLOS: 2 (3 dB); default SF LOS: 3 dB; default SF NLOS: A/B → 4 dB, C/D → 5 dB, E/F → 6 dB
- Default breakpoint distance: A/B/C → 5 m, D → 10 m, E → 20 m, F → 30 m
- Floor floor penetration loss according to TGah for CarrierFreq < 1 GHz and TGax for above 1 GHz
- NAN or negative value for any override parameter restores the model default
Usage:
chan = quadriga_lib.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, n_walls, wall_loss )
Inputs:
ap_array — Access point array antenna; n_tx = number of ports after element coupling, see arrayant-generate
sta_array — Mobile station array antenna; n_rx = number of ports after element coupling, see arrayant-generate
ChannelType — Model type string; one of "A", "B", "C", "D", "E", "F"
CarrierFreq_Hz (optional) — Carrier frequency; default: 5.25e9
tap_spacing_s (optional) — Tap spacing in seconds; must equal 10 ns / 2^k; default: 10e-9
n_users (optional) — Number of users (TGac/TGah/TGax only); output vector length equals n_users; default: 1
observation_time (optional) — Channel observation time in seconds; default: 0
update_rate (optional) — Channel update interval in seconds; relevant only when observation_time > 0; default: 1e-3
speed_station_kmh (optional) — Station speed in km/h; movement direction is AoA_offset; relevant only when observation_time > 0; default: 0
speed_env_kmh (optional) — Environment speed in km/h; use 0.089 for TGac; relevant only when observation_time > 0; default: 1.2 (TGn)
Dist_m (optional) — TX-to-RX distance(s); (n_users,) or (1,); default: 4.99
n_floors (optional) — Number of floors per user for TGah or TGax models; (n_users,) or (1,); default: 0
uplink (optional) — Set true to generate uplink (reverse) direction; default: false
offset_angles (optional) — Azimuth offset angles in degrees; rows: AoD LOS, AoD NLOS, AoA LOS, AoA NLOS;
empty uses TGac auto-defaults for n_users > 1; (4, n_users); default: [] (auto-generate)
n_subpath (optional) — Sub-paths per cluster for Laplacian angular spread mapping; default: 20
Doppler_effect (optional) — Special Doppler: models D/E use mains frequency (Hz), model F uses vehicle speed (km/h); 0 disables; default: 50
seed (optional) — RNG seed for repeatability; -1 uses the system random device; default: -1
KF_linear (optional) — Overrides model KF (linear scale); NAN or negative restores model default; default: NAN
XPR_NLOS_linear (optional) — Overrides NLOS cross-polarization ratio (linear scale); NAN or negative restores model default; default: NAN
SF_std_dB_LOS (optional) — Overrides LOS shadow fading std in dB (applied when d < dBP); NAN restores model default; default: NAN
SF_std_dB_NLOS (optional) — Overrides NLOS shadow fading std in dB (applied when d >= dBP); NAN restores model default; default: NAN
dBP_m (optional) — Overrides breakpoint distance; NAN or negative restores model default; default: NAN
n_walls (optional) — Number of walls per user TGax models; (n_users,) or (1,); default: 0
wall_loss (optional) — Penetration loss for a single wall; TGax defines 5 or 7; default: 5
Output:
chan
List of length n_users containing dictionaries of channel data with the following keys.
|
Key |
Description |
Type |
|
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) |
|
center_frequency |
Center Frequency in Hz |
Scalar |
See also:
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
Description:
This function transforms Cartesian (x,y,z) coordinates to Geographic (azimuth, elevation, length)
coordinates. A geographic coordinate system is a three-dimensional reference system that locates
points on the surface of a sphere. A point has three coordinate values: azimuth, elevation and length
where azimuth and elevation measure angles. In the geographic coordinate system, the elevation angle
θ = 90° points to the zenith and θ = 0° points to the horizon.
Usage:
import quadriga_lib
geo_coords = quadriga_lib.tools.cart2geo(cart_coords)
Input Argument:
cart_coords
Cartesian coordinates (x,y,z), Shape: (3, n_row, n_col)
Output Arguments:
geo_coords
Geographic coordinates, Shape: (3, n_row, n_col)
First row: Azimuth angles in [rad], values between -pi and pi.
Second row: Elevation angles in [rad], values between -pi/2 and pi/2.
Third row: Vector length, i.e. the distance from the origin to the point defined by x,y,z.
components - Returns the version numbers of all quadriga-lib sub-components
Usage:
components = quadriga_lib.components()
version - Returns the quadriga-lib version number
Usage:
version = quadriga_lib.version();
Caveat:
- If Quadriga-Lib was compiled with AVX2 support and the CPU supports intrinsic AVX2 instructions,
an suffix
_AVX2 is added after the 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
calc_diffraction_gain - Calculate diffraction gain for multiple TX-RX pairs using a 3D triangular mesh
- Estimates diffraction gain by evaluating Fresnel ellipsoid obstruction; each TX-RX path is divided
into
n_path elliptic-arc paths (controlled by lod), each approximated by n_seg line segments
- Segment attenuation is combined via weighted summation calibrated to 2D UTD coefficients,
generalized to arbitrary 3D shapes
- Optional sub-mesh indexing (see triangle_mesh_segmentation) accelerates computation by skipping
triangles whose bounding box does not intersect the TX-RX path
Usage:
# Output as tuple
data = quadriga_lib.RTtools.calc_diffraction_gain( orig, dest, mesh, mtl_prop, center_frequency,
lod, verbose, sub_mesh_index, use_kernel, gpu_id, scalar_mode )
# Unpacked outputs
gain, coord = RTtools.calc_diffraction_gain( orig, dest, mesh, mtl_prop, center_frequency,
lod, verbose, sub_mesh_index, use_kernel, gpu_id, scalar_mode )
Inputs:
orig — TX positions; (n_pos, 3)
dest — RX positions; (n_pos, 3)
mesh — Triangle vertices, each row {X1,Y1,Z1,X2,Y2,Z2,X3,Y3,Z3}; (n_mesh, 9)
mtl_prop — Material properties; see obj_file_read; (n_mesh, 9)
center_frequency — Center frequency
lod (optional) — Level of detail (0–6), controls n_path and n_seg; see generate_diffraction_paths
verbose (optional) — Verbosity level
sub_mesh_index (optional) — 0-based sub-mesh index for acceleration; see triangle_mesh_segmentation; uint32; (n_mesh,)
use_kernel (optional) — Kernel selection: 0 = auto, 1 = GENERIC, 2 = AVX2, 3 = CUDA; error if unavailable
gpu_id (optional) — CUDA device ID; ignored for non-CUDA kernels
scalar_mode (optional) — If true, uses scalar transmission (TE-only reflection coefficient,
energy-conservation transmission) instead of EM TE/TM averaging. Default false (EM mode).
Outputs:
gain (optional) — Diffraction gain per TX-RX pair, linear scale; (n_pos,)
coord (optional) — Diffracted path coordinates excluding endpoints; (3, n_seg-1, n_pos)
See also:
icosphere - Construct a geodesic polyhedron from recursive icosahedron subdivision
- Produces 20 · n_div² triangular faces, each pointing outward from origin
- All vertices lie on a sphere of specified radius
- Suitable for uniform angular sampling (ray tracing, antenna patterns, spatial grids)
Usage:
# Output as tuple
data = quadriga_lib.RTtools.icosphere( no_div, radius, direction_xyz )
# Unpacked outputs
center, length, vert, direction = quadriga_lib.RTtools.icosphere( no_div, radius, direction_xyz )
Inputs:
n_div — Number of subdivisions; generates 20 · n_div² faces; default: 1
radius — Radius of icosphere in meters; default: 1
direction_xyz (optional) — Output directions in Cartesian (true) or spherical
azimuth/elevation (false); default: false
Outputs:
center — Face center coordinates in Cartesian space; each vector points radially outward
from origin with magnitude equal to the inradius of the face; (n_faces, 3)
length — Distance from origin to face plane; equals the magnitude of each
center vector; (n_faces,)
vert — Vertex offsets from face center {x1,y1,z1,x2,y2,z2,x3,y3,z3}; (n_faces, 9)
direction — Edge directions; spherical {az1,el1,az2,el2,az3,el3} or Cartesian
{x1,y1,z1,x2,y2,z2,x3,y3,z3} per direction_xyz flag; (n_faces, 6) or [n_faces, 9)
mitsuba_xml_file_write - Write a triangular mesh to a Mitsuba 3 XML scene file
- Converts quadriga-lib mesh data structures to Mitsuba 3 XML format, loadable by NVIDIA Sionna RT for
differentiable radio-propagation simulations
- Supports grouping faces into named objects with per-face material assignments
- Optionally maps material names to ITU-defined presets used by Sionna RT
- Creates a subdirectory
<stem>_meshes/ next to the XML file and writes one binary PLY file per object into it;
both the XML and the mesh folder must be distributable together
- Objects whose faces reference more than one material are automatically split into sub-objects (one per material)
and renamed
<obj_name>_<mtl_name>; the effective object count in the output may therefore exceed the length of obj_names
Usage:
quadriga_lib.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 path including .xml extension
vert_list — Vertex coordinates (x, y, z); (n_vert, 3)
face_ind — Triangle definitions as 0-based vertex indices; uint64; (n_mesh, 3)
obj_ind — 1-based object index per triangle; length must match obj_names; uint64; (n_mesh,)
mtl_ind — 1-based material index per triangle; length must match mtl_names; uint64; (n_mesh,)
obj_names — Object names; list of strings; length must equal max(obj_ind)
mtl_names — Material names; list of strings; length must equal max(mtl_ind)
bsdf (optional) — BSDF material parameters per material; ignored by Sionna RT, used only by Mitsuba renderer; see obj_file_read for field definitions; (mtl_names.size(), 17)
map_to_itu_materials (optional) — If true, maps material names to ITU presets recognised by Sionna RT
See also:
obj_file_read - Read a Wavefront .obj file and extract geometry and material information
- Parses a triangulated Wavefront
.obj file; quads and n-gons are not supported
- Materials applied per triangle via
usemtl tag; unknown/missing materials default to "vacuum" (ε_r = 1, σ = 0, Att = 0, α = 0)
- Material name matching is case-sensitive
- Default materials follow ITU-R P.2040-3 Table 3 (1–40 GHz; ground materials limited to 1–10 GHz)
- Default material tag syntax:
usemtl itu_concrete (or itu_brick, itu_wood, etc.)
- Custom material tag syntax:
usemtl Name::a:b:c:d:att:attB:alpha:alphaB:fRef
- ε_r(f) = a · (f/fRef)^b (relative permittivity)
- σ(f) = c · (f/fRef)^d [S/m] (conductivity)
- Att(f) = att · (f/fRef)^attB [dB] (fixed penetration loss)
- α(f) = alpha · (f/fRef)^alphaB [dB/m] (distance-dependent absorption)
- Trailing fields are optional; defaults are
b=c=d=att=attB=alpha=alphaB=0, fRef=1 GHz
Usage:
# Return as separate variables
mesh, mtl_prop, vert_list, face_ind, obj_ind, mtl_ind, obj_names, mtl_names, bsdf =
quadriga_lib.RTtools.obj_file_read( fn )
# Return as tuple with 9 elements
data = RTtools.obj_file_read( fn )
# Use a custom material definition file
data = RTtools.obj_file_read( fn, materials_csv )
Inputs:
fn — Path to the .obj file
materials_csv (optional) — Path to CSV file with custom material properties.
Required columns: name, a. Optional columns: b, c, d, att, attB, alpha, alphaB, fRef.
Column order is flexible; missing optional columns default to 0 (fRef → 1).
If empty, ITU-R P.2040-3 defaults are used.
Outputs:
mesh — Triangle vertex coordinates as {X1,Y1,Z1,X2,Y2,Z2,X3,Y3,Z3} per row; (n_mesh, 9)
mtl_prop — Material properties; (n_mesh, 9); Columns:
|
Index |
Symbol |
Property |
|
0 |
a |
ε_r at fRef |
|
1 |
b |
Frequency exponent for ε_r |
|
2 |
c |
σ at fRef [S/m] |
|
3 |
d |
Frequency exponent for σ |
|
4 |
att |
Penetration loss at fRef [dB] |
|
5 |
attB |
Frequency exponent for att |
|
6 |
alpha |
Distance absorption at fRef [dB/m] |
|
7 |
alphaB |
Frequency exponent for alpha |
|
8 |
fRef |
Reference frequency [GHz] |
vert_list — All vertex positions in the file; (n_vert, 3)
face_ind — 0-based indices into vert_list per triangle; uint64; (n_mesh, 3)
obj_ind — 1-based object index per triangle; uint64; (n_mesh, )
mtl_ind — 1-based material index per triangle; uint64; (n_mesh, )
obj_names — Object names; list of strings; length = max(obj_ind)
mtl_names — Material names; list os strings; length = max(mtl_ind)
bsdf — Principled BSDF values from the .mtl file; (n_mtl, 17); columns:
|
Index |
Property |
Range |
Default |
|
0 |
Base Color Red |
0–1 |
0.8 |
|
1 |
Base Color Green |
0–1 |
0.8 |
|
2 |
Base Color Blue |
0–1 |
0.8 |
|
3 |
Transparency (alpha) |
0–1 |
1.0 |
|
4 |
Roughness |
0–1 |
0.5 |
|
5 |
Metallic |
0–1 |
0.0 |
|
6 |
Index of refraction (IOR) |
0–4 |
1.45 |
|
7 |
Specular IOR adjustment |
0–1 |
0.5 |
|
8 |
Emission Red |
0–1 |
0.0 |
|
9 |
Emission Green |
0–1 |
0.0 |
|
10 |
Emission Blue |
0–1 |
0.0 |
|
11 |
Sheen |
0–1 |
0.0 |
|
12 |
Clearcoat |
0–1 |
0.0 |
|
13 |
Clearcoat roughness |
0–1 |
0.0 |
|
14 |
Anisotropic |
0–1 |
0.0 |
|
15 |
Anisotropic rotation |
0–1 |
0.0 |
|
16 |
Transmission |
0–1 |
0.0 |
Default material table:
- For all defaults below:
attB = alpha = alphaB = 0 and fRef = 1 GHz:
|
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 |
See also:
point_cloud_aabb - Compute the axis-aligned bounding boxes (AABB) of a 3D point cloud
- Each row of the output contains
{x_min, x_max, y_min, y_max, z_min, z_max} for one sub-cloud
- If
sub_cloud_index is empty or omitted, the entire input is treated as a single cloud; last
index spans to end of points
- Output row count is zero-padded to the nearest multiple of
vec_size; padding rows are zeros
Usage:
aabb = quadriga_lib.RTtools.point_cloud_aabb( points, sub_cloud_ind, vec_size )
Input Arguments:
points — 3D point coordinates; (n_points, 3)
sub_cloud_index (optional) — 0-based row indices marking the start of each sub-cloud;
use point_cloud_segmentation to generate; uint32; (n_sub,)
vec_size (optional) — SIMD alignment padding factor (e.g. 4, 8, 16); default: 1
Output Argument:
aabb — Bounding box matrix; (n_out, 6) where n_out is n_sub padded to a multiple of vec_size
See also:
point_cloud_segmentation - Reorganize a point cloud into spatial sub-clouds for efficient processing
- Recursively partitions a 3D point cloud into sub-clouds by splitting along bounding box axes at the midpoint
- Sub-clouds can be padded to a multiple of
vec_size for SIMD alignment; padding points are placed at the sub-cloud AABB center
- Produces a reorganized point array and index maps to track reordering
Usage:
# Output as tuple
data = quadriga_lib.RTtools.point_cloud_segmentation( points, target_size, vec_size )
# Unpacked outputs
points_out, sub_cloud_ind, forward_ind, reverse_ind =
quadriga_lib.RTtools.point_cloud_segmentation( points, target_size, vec_size )
Inputs:
points — Original 3D point cloud; (n_points, 3)
target_size (optional) — Maximum points per sub-cloud before padding; default: 1024
vec_size (optional) — SIMD/CUDA alignment; sub-cloud size is padded to a multiple of
this value; no padding when 1; default: 1
Outputs:
points_out — Reorganized point cloud with points grouped by sub-cloud; (n_points_out, 3)
sub_cloud_index — 0-based starting index of each sub-cloud within points_out; uint32; (n_sub,)
forward_index (optional) — 1-based index map from points to points_out; padding entries are 0; uint32; (n_points_out,)
reverse_index (optional) — 0-based index map from points_out back to points; uint32; (n_points,)
point_inside_mesh - Test whether 3D points are inside a triangle mesh using raycasting
- Always casts 4 rays per point in near-tetrahedral directions (rotated regular tetrahedron,
scaled to 1000 m) for inside/outside detection
- When
distance > 0, adds icosphere-sampled rays at subdivision level ⌈distance⌉ + 1
(e.g. subdiv 2 for distance ≤ 1 m, subdiv 3 for ≤ 2 m), substantially increasing ray count
- A point is inside if any ray hits a face with a negative incidence angle, or if the ray
thickness at FBS is below 1 mm (surface proximity)
- Mesh must be watertight with all normals pointing outward
- If
obj_ind is provided, returns the 1-based enclosing object index instead of binary 0/1
Usage:
result = quadriga_lib.RTtools.point_inside_mesh( points, mesh, obj_ind, distance )
Input Arguments:
points — 3D coordinates of test points; (n_points, 3)
mesh — Triangle faces in row-major vertex format {x1,y1,z1,x2,y2,z2,x3,y3,z3}; (n_mesh, 9)
obj_ind (optional) — 1-based object index per mesh element; enables per-object output; (n_mesh,)
distance (optional) — Surface proximity threshold; points within this distance
of the mesh surface are classified as inside; increases ray count to 4 + N_icosphere(⌈distance⌉ + 1);
range: 0–20 m; Default: 0
Output Arguments:
result— Indicator: 0 = outside, 1 = inside any object (no obj_ind), or 1-based object
index (with obj_ind); uint32; size (n_points,)
See also:
ray_point_intersect - Calculate intersections of ray beams with points in 3D space
- Models rays as volumetric beams defined by a triangular wavefront that diverges from the origin, enabling energy spread simulation
- Returns, for each point, the list of ray indices whose beam intersects that point
- All internal computations use single precision
Usage:
hit_count, ray_ind = quadriga_lib.RTtools.ray_point_intersect( orig, trivec, tridir, points, sub_cloud_ind, use_kernel, gpu_id )
Inputs:
orig — Ray origin positions in global Cartesian coordinates; (n_ray, 3)
trivec — Vectors from ray origin center to triangular wavefront vertices, order
{v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z}; (n_ray, 9)
tridir — Direction vectors of the three vertex-rays in Cartesian coordinates; not normalized;
order {d1x, d1y, d1z, d2x, d2y, d2z, d3x, d3y, d3z}; (n_ray, 9)
points — 3D point cloud coordinates; (n_points, 3)
sub_cloud_index (optional) — 0-based segment boundary indices for the point cloud
(see quadriga_lib.point_cloud_segmentation); uint32; (n_sub,)
use_kernel (optional) — Compute kernel selector: 0 = auto, 1 = GENERIC, 2 = AVX2,
3 = CUDA; throws if unavailable; auto mode selects CUDA when n_points >= 10000 and CUDA is
available, else AVX2, else GENERIC; default: 0
gpu_id (optional) — CUDA device ID; ignored when not using CUDA; default: 0
Outputs:
hit_count — Number of beams intersecting each point; uint32; (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; uint32
See also:
ray_triangle_intersect - Compute ray-triangle intersections in 3D using the Möller–Trumbore algorithm
- Counts the total number of intersections between
orig and dest
- Computes the coordinates and object IDs of the first two intersections per ray (FBS/SBS)
- Internal computations always use single precision for AVX2 and CUDA kernels; only GENERIC has
double support
Usage:
# Output as tuple
data = RTtools.ray_triangle_intersect( orig, dest, mesh, sub_mesh_index, aabb, use_kernel, gpu_id )
# Unpacked outputs
fbs, sbs, no_interact, fbs_ind, sbs_ind = RTtools.ray_triangle_intersect( orig, dest, mesh, sub_mesh_index, aabb, use_kernel, gpu_id )
Inputs:
orig — Ray origins in GCS; (n_ray, 3)
dest — Ray destinations in GCS; (n_ray, 3)
mesh — Triangular mesh; each row: {x1 y1 z1 x2 y2 z2 x3 y3 z3}; (n_mesh, 9)
sub_mesh_index (optional) — Start indices of sub-meshes in mesh; enables AABB-accelerated traversal; 0-based; uint32; (n_sub)
aabb (optional) — Pre-computed axis-aligned bounding boxes per sub-mesh; each row:
{x_min x_max y_min y_max z_min z_max}; if empty or omitted, AABBs are computed from mesh; (n_sub, 6)
use_kernel (optional) — Compute kernel selector: 0 = auto, 1 = GENERIC, 2 = AVX2, 3 = CUDA;
throws if unavailable; auto mode selects CUDA when n_ray >= 10000 and CUDA is available, else AVX2,
else GENERIC.
gpu_id (optional) — CUDA device ID; ignored when not using CUDA
Outputs:
fbs — First-bounce intersection points in GCS; (n_ray, 3)
sbs — Second-bounce intersection points in GCS; (n_ray, 3)
no_interact — Total number of intersections per ray between orig and dest; uint32; (n_ray,)
fbs_ind — 1-based index of first intersected mesh element; 0 = none; uint32; (n_ray,)
sbs_ind — 1-based index of second intersected mesh element; 0 = none; uint32; (n_ray,)
See also:
triangle_mesh_aabb - Calculate the axis-aligned bounding box (AABB) of a triangle mesh and its sub-meshes
- Computes the AABB for each sub-mesh; used to accelerate ray tracing by cheaply excluding non-intersecting geometry
- Each triangle row:
{x1, y1, z1, x2, y2, z2, x3, y3, z3}
- Output columns:
{x_min, x_max, y_min, y_max, z_min, z_max}
- If
vec_size > 1, output rows are padded to the next multiple of vec_size
Usage:
aabb = quadriga_lib.RTtools.triangle_mesh_aabb( triangles, sub_mesh_index, vec_size )
Inputs:
triangles — Triangle mesh vertices in global Cartesian coordinates; (n_triangles, 9)
sub_mesh_index (optional) — 1-based start indices of sub-meshes; if omitted, the AABB
of the entire mesh is returned; uint32; (n_sub,)
vec_size (optional) — Alignment size for SIMD/CUDA padding (e.g., 8 for AVX2, 32 for CUDA); default: 1
Output:
aabb — Axis-aligned bounding boxes, one row per sub-mesh; (n_sub_aligned, 6)
See also:
triangle_mesh_segmentation - Reorganize a 3D triangular mesh into spatially clustered sub-meshes for faster processing
- Recursively partitions mesh by axis-aligned bounding box until each sub-mesh contains no more than
target_size triangles
- Output mesh retains all original triangles but in reordered sequence; sub-meshes are padded with zero-sized dummy triangles to align row counts to
vec_size
- Dummy triangles are placed at the AABB center of their sub-mesh;
mesh_index uses 0 to mark padding entries
- If
mtl_prop is provided, material rows are reordered and padded in the same way
Usage:
# Output as tuple
data = quadriga_lib.RTtools.triangle_mesh_segmentation( triangles, target_size, vec_size, mtl_prop )
# Unpacked outputs
triangles_out, sub_mesh_index, mesh_index, mtl_propR =
quadriga_lib.RTtools.triangle_mesh_segmentation( triangles, target_size, vec_size, mtl_prop )
Inputs:
triangles — Triangle vertices, each row {x1,y1,z1,x2,y2,z2,x3,y3,z3}; (n_mesh, 9)
target_size (optional) — Target triangle count per sub-mesh; for best performance set
near sqrt(n_mesh); default: 1024
vec_size (optional) — SIMD/GPU alignment size (e.g. 8 for AVX2, 32 for CUDA); each
sub-mesh row count is rounded up to a multiple of this value; default: 1
mtl_prop (optional) — Material properties; see obj_file_read; (n_mesh, 9)
Outputs:
triangles_out — Reordered and padded triangle vertices; (n_triangles_out, 9)
sub_mesh_index — 0-based start indices of sub-meshes in triangles_out; uint32; (n_sub,)
mesh_index — 1-based mapping from original to reorganized mesh (0 = padding); uint32; (n_triangles_out, )
mtl_prop_out — Reordered and padded material properties; (n_triangles_out, 9)