MALAB / Octave API Documentation for Quadriga-Lib v0.11.5
Overview
Array antenna functions
Channel functions
Channel generation functions
Channel statistics
| 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 | Calculates RMS delay spread from per-CIR delays and linear-scale powers |
| calc_rician_k_factor | Calculate the Rician K-Factor from channel impulse response data |
Miscellaneous / Tools
| calc_rotation_matrix | Calculates a 3x3 rotation matrix from a 3-element orientation vector |
| cart2geo | Convert elementwise Cartesian coordinates to azimuth/elevation angles and vector length |
| fast_sincos | Fast, approximate sine/cosine for MATLAB numeric arrays |
| geo2cart | Convert elementwise azimuth/elevation angles to Cartesian coordinates |
| interp | 2D and 1D linear interpolation. |
| version | Returns the quadriga-lib version number |
| write_png | Write data to a PNG file |
Site-specific simulation tools
Array antenna functions
arrayant_calc_beamwidth - Calculates the beam width of array antenna elements in degree
- Computes azimuth and elevation beamwidth at a given dB threshold (default 3 dB = FWHM)
- Also returns the azimuth and elevation pointing angles of the main beam
- Sub-grid resolution is achieved by bilinear interpolation of the field pattern (≈100x finer grid in
each direction than the antenna sampling grid)
- Calculated per element, not per port; ignores element coupling
Usage:
% Input as struct (struct mode)
[ beamwidth_az, beamwidth_el, az_point_ang, el_point_ang ] = quadriga_lib.arrayant_calc_beamwidth( arrayant );
[ beamwidth_az, beamwidth_el, az_point_ang, el_point_ang ] = quadriga_lib.arrayant_calc_beamwidth( arrayant, i_element, threshold_dB );
% Separate inputs (split mode)
[ beamwidth_az, beamwidth_el, az_point_ang, el_point_ang ] = ...
quadriga_lib.arrayant_calc_beamwidth( e_theta_re, e_theta_im, e_phi_re, e_phi_im, azimuth_grid, elevation_grid );
[ beamwidth_az, beamwidth_el, az_point_ang, el_point_ang ] = ...
quadriga_lib.arrayant_calc_beamwidth( e_theta_re, e_theta_im, e_phi_re, e_phi_im, azimuth_grid, elevation_grid, i_element, threshold_dB );
Inputs (struct mode):
arrayant — Struct containing the arrayant data; field layout as documented in arrayant_generate;
a struct array may contain a frequency-dependent model
i_element (optional) — Element index; 1-based; if not provided or empty, the beamwidth is
calculated for all elements; uint64; [n_out] or empty
threshold_dB (optional) — Threshold in dB; default: 3 (equivalent to FWHM)
Inputs (split mode):
e_theta_re — e-theta field component, real part; [n_elevation, n_azimuth, n_elements]
e_theta_im — e-theta field component, imaginary part; [n_elevation, n_azimuth, n_elements]
e_phi_re — e-phi field component, real part; [n_elevation, n_azimuth, n_elements]
e_phi_im — e-phi field component, imaginary part; [n_elevation, n_azimuth, n_elements]
azimuth_grid — Azimuth angles in rad, -π to π, sorted; [n_azimuth]
elevation_grid — Elevation angles in rad, -π/2 to π/2, sorted; [n_elevation]
i_element (optional) — Element index; 1-based; if not provided or empty, the beamwidth
is calculated for all elements; uint64; [n_out] or empty
threshold_dB (optional) — Threshold in dB; default: 3 (equivalent to FWHM)
Output Arguments:
beamwidth_az — Azimuth beamwidth in degree; [n_out, n_freq]; with n_out = n_elements when i_element is omitted/empty
beamwidth_el (optional) — Elevation beamwidth in degree; [n_out, n_freq]
az_point_ang (optional) — Azimuth pointing angle of the main beam in degree; [n_out, n_freq]
el_point_ang (optional) — Elevation pointing angle of the main beam in degree; [n_out, n_freq]
See also:
arrayant_calc_directivity - Calculates the directivity in dBi of array antenna elements
- Directivity = 10 log10(peak radiation intensity / mean over 4π); isotropic radiator = 0 dBi
- Calculated per element, not per port; ignores element coupling
Usage:
% Input as struct (struct mode)
directivity = quadriga_lib.arrayant_calc_directivity(arrayant);
directivity = quadriga_lib.arrayant_calc_directivity(arrayant, i_element);
% Separate inputs (split mode)
directivity = quadriga_lib.arrayant_calc_directivity(e_theta_re, e_theta_im, e_phi_re, ...
e_phi_im, azimuth_grid, elevation_grid);
directivity = quadriga_lib.arrayant_calc_directivity(e_theta_re, e_theta_im, e_phi_re, ...
e_phi_im, azimuth_grid, elevation_grid, i_element);
Inputs (struct mode):
arrayant — Struct containing the arrayant data; field layout as documented in arrayant_generate;
a struct array may contain a frequency-dependent model
i_element (optional) — Element index; 1-based; if not provided or empty, the directivity is
calculated for all elements; uint64; [n_out] or empty
Inputs (split mode):
e_theta_re — e-theta field component, real part; [n_elevation, n_azimuth, n_elements]
e_theta_im — e-theta field component, imaginary part; [n_elevation, n_azimuth, n_elements]
e_phi_re — e-phi field component, real part; [n_elevation, n_azimuth, n_elements]
e_phi_im — e-phi field component, imaginary part; [n_elevation, n_azimuth, n_elements]
azimuth_grid — Azimuth angles in rad, -π to π, sorted; [n_azimuth]
elevation_grid — Elevation angles in rad, -π/2 to π/2, sorted; [n_elevation]
i_element (optional) — Element index; 1-based; if not provided or empty, the directivity is
calculated for all elements; uint64; [n_out] or empty
Output Argument:
directivity - Directivity of the antenna pattern in dBi; [n_out, n_freq];
with n_out = n_elements when i_element is omitted/empty.
See also:
arrayant_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:
% Minimal example (input/output = struct)
arrayant_out = quadriga_lib.arrayant_combine_pattern(arrayant_in);
% Optional inputs: freq, azimuth_grid, elevation_grid
arrayant_out = quadriga_lib.arrayant_combine_pattern(arrayant_in, freq, azimuth_grid, elevation_grid);
% Separate outputs, struct input
[e_theta_re, e_theta_im, e_phi_re, e_phi_im, azimuth_grid, elevation_grid, element_pos, ...
coupling_re, coupling_im, freq, name] = quadriga_lib.arrayant_combine_pattern(arrayant_in);
% Separate inputs
arrayant_out = quadriga_lib.arrayant_combine_pattern([], freq, azimuth_grid, elevation_grid, ...
e_theta_re, e_theta_im, e_phi_re, e_phi_im, azimuth_grid, elevation_grid, element_pos, ...
coupling_re, coupling_im, freq, name);
Examples:
The following example creates a unified linear array of 4 dipoles, spaced at half-wavelength. The
elements are then coupled with each other (i.e., they receive the same signal). The effective pattern
is calculated using
arrayant_combine_pattern.
% Generate dipole pattern
ant = quadriga_lib.generate_arrayant('dipole');
% Duplicate 4 times
ant.e_theta_re = repmat(ant.e_theta_re, [1,1,4]);
ant.e_theta_im = repmat(ant.e_theta_im, [1,1,4]);
ant.e_phi_re = repmat(ant.e_phi_re, [1,1,4]);
ant.e_phi_im = repmat(ant.e_phi_im, [1,1,4]);
ant.element_pos = repmat(ant.element_pos, [1,4]);
% Set element positions and coupling matrix
ant.element_pos(2,:) = [ -0.75, -0.25, 0.25, 0.75]; % lambda, along y-axis
ant.coupling_re = [ 1 ; 1 ; 1 ; 1 ]/sqrt(4);
ant.coupling_im = [ 0 ; 0 ; 0 ; 0 ];
% Calculate effective pattern
ant_c = quadriga_lib.arrayant_combine_pattern( ant );
% Plot gain
plot( ant.azimuth_grid*180/pi, [ 10*log10( ant.e_theta_re(91,:,1).^2 ); 10*log10( ant_c.e_theta_re(91,:).^2 ) ]);
axis([-180 180 -20 15]); ylabel('Gain (dBi)'); xlabel('Azimth angle (deg)'); legend('Dipole','Array')
Input Arguments:
arrayant_in [1]
Struct containing the arrayant data with the following fields:
e_theta_re |
e-theta field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_theta_im |
e-theta field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_re |
e-phi field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_im |
e-phi field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Size: [n_azimuth] |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Size: [n_elevation] |
element_pos |
Antenna element (x,y,z) positions, optional |
Size: [3, n_elements] |
coupling_re |
Coupling matrix, real part, optional |
Size: [n_elements, n_ports] |
coupling_im |
Coupling matrix, imaginary part, optional |
Size: [n_elements, n_ports] |
center_freq |
Center frequency in [Hz], optional |
Scalar |
name |
Name of the array antenna object, optional |
String |
If an empty array is passed, array antenna data is provided as separate inputs (Inputs 5-15)
freq [2] (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 [3] (optional)
Alternative azimuth angles for the output in [rad], -pi to pi, sorted, Size: [n_azimuth_out],
If not given, arrayant_in.azimuth_grid is used instead.
elevation_grid [4] (optional)
Alternative elevation angles for the output in [rad], -pi/2 to pi/2, sorted, Size: [n_elevation_out],
If not given, arrayant_in.elevation_grid is used instead.
Output Arguments:
arrayant_out
Struct containing the arrayant data with the following fields:
e_theta_re |
e-theta field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_theta_im |
e-theta field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_re |
e-phi field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_im |
e-phi field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
azimuth_grid |
Azimuth angles in [rad] -pi to pi, sorted |
Size: [n_azimuth] |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Size: [n_elevation] |
element_pos |
Antenna element (x,y,z) positions |
Size: [3, n_elements] |
coupling_re |
Coupling matrix, real part |
Size: [n_elements, n_ports] |
coupling_im |
Coupling matrix, imaginary part |
Size: [n_elements, n_ports] |
center_freq |
Center frequency in [Hz], default = 0.3 GHz |
Scalar |
name |
Name of the array antenna object |
String |
Can be returned as separate outputs.
arrayant_copy_element - Create copies of array antenna elements
Usage:
arrayant_out = quadriga_lib.arrayant_copy_element(arrayant_in, source_element, dest_element);
Input Arguments:
arrayant_in [1] (required)
Struct containing the arrayant data with the following fields:
e_theta_re |
e-theta field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_theta_im |
e-theta field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_re |
e-phi field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_im |
e-phi field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Size: [n_azimuth] |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Size: [n_elevation] |
element_pos |
Antenna element (x,y,z) positions, optional |
Size: [3, n_elements] |
coupling_re |
Coupling matrix, real part, optional |
Size: [n_elements, n_ports] |
coupling_im |
Coupling matrix, imaginary part, optional |
Size: [n_elements, n_ports] |
center_freq |
Center frequency in [Hz], optional |
Scalar |
name |
Name of the array antenna object, optional |
String |
source_element [2] (required)
Index of the source elements (1-based), scalar or vector
dest_element [3] (optional)
Index of the destination elements (1-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
Struct containing the arrayant data with the following fields:
e_theta_re |
e-theta field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_theta_im |
e-theta field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_re |
e-phi field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_im |
e-phi field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
azimuth_grid |
Azimuth angles in [rad] -pi to pi, sorted |
Size: [n_azimuth] |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Size: [n_elevation] |
element_pos |
Antenna element (x,y,z) positions |
Size: [3, n_elements] |
coupling_re |
Coupling matrix, real part |
Size: [n_elements, n_ports] |
coupling_im |
Coupling matrix, imaginary part |
Size: [n_elements, n_ports] |
center_freq |
Center frequency in [Hz], default = 0.3 GHz |
Scalar |
name |
Name of the array antenna object |
String |
arrayant_export_obj_file - Creates a Wavefront OBJ file for visualizing the shape of the antenna pattern
Usage:
quadriga_lib.arrayant_export_obj_file( fn, arrayant, directivity_range, colormap, ...
object_radius, icosphere_n_div, i_element );
Input Arguments:
fn [1]
Filename of the OBJ file, string
arrayant [2]
Struct containing the arrayant data with the following fields:
e_theta_re |
e-theta field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_theta_im |
e-theta field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_re |
e-phi field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_im |
e-phi field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Size: [n_azimuth] |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Size: [n_elevation] |
element_pos |
Antenna element (x,y,z) positions, optional |
Size: [3, n_elements] |
name |
Name of the array antenna object, optional |
String |
directivity_range [3]
Directivity range of the antenna pattern visualization in dB
colormap [4]
Colormap for the visualization, string, supported are 'jet', 'parula', 'winter', 'hot', 'turbo',
'copper', 'spring', 'cool', 'gray', 'autumn', 'summer', Optional, default = 'jet'
object_radius [5]
Radius in meters of the exported object
icosphere_n_div [6]
Map pattern to an Icosphere with given number of subdivisions
element [7]
Antenna element indices, 1-based, empty = export all
arrayant_generate - Generates predefined array antenna models
- Dispatches to one of several C++ generator functions based on the
type string
- Supported types:
omni, dipole (or short-dipole), half-wave-dipole, xpol, custom,
ula, 3GPP (or 3gpp), multibeam, multibeam_sep
- All positional arguments after
type are optional and type-specific; use [] to skip and fall
back to defaults
Usage:
% Simple antennas (v-pol)
ant = quadriga_lib.arrayant_generate('omni', res);
ant = quadriga_lib.arrayant_generate('dipole', res);
ant = quadriga_lib.arrayant_generate('half-wave-dipole', res);
% Cross-polarized isotropic
ant = quadriga_lib.arrayant_generate('xpol', res);
% Custom 3dB beamwidth
ant = quadriga_lib.arrayant_generate('custom', res, freq, az_3dB, el_3dB, rear_gain_lin);
% Uniform linear array (N horizontal elements, half-wavelength spacing by default)
ant = quadriga_lib.arrayant_generate('ula', res, freq, [], [], [], [], N, pol, [], spacing);
% Uniform linear array with custom per-element pattern struct
ant = quadriga_lib.arrayant_generate('ula', res, freq, [], [], [], [], N, [], [], spacing, ...
[], [], [], [], pattern);
% 3GPP-NR array (default 3GPP element pattern)
ant = quadriga_lib.arrayant_generate('3GPP', res, freq, [], [], [],
M, N, pol, tilt, spacing, Mg, Ng, dgv, dgh);
% 3GPP-NR array with custom element beamwidth
ant = quadriga_lib.arrayant_generate('3GPP', res, freq, az_3dB, el_3dB, rear_gain_lin, ...
M, N, pol, tilt, spacing, Mg, Ng, dgv, dgh);
% 3GPP-NR array with custom per-element pattern struct
ant = quadriga_lib.arrayant_generate('3GPP', res, freq, [], [], [], ...
M, N, pol, tilt, spacing, Mg, Ng, dgv, dgh, pattern);
% Multi-beam M×N array (one combined beam / one beam per direction)
ant = quadriga_lib.arrayant_generate('multibeam', res, freq, az_3dB, el_3dB, rear_gain_lin, ...
M, N, pol, beam_angles, spacing);
ant = quadriga_lib.arrayant_generate('multibeam_sep', res, freq, az_3dB, el_3dB, rear_gain_lin, ...
M, N, pol, beam_angles, spacing);
% Separate outputs (must request exactly 11)
[e_theta_re, e_theta_im, e_phi_re, e_phi_im, azimuth_grid, elevation_grid, ...
element_pos, coupling_re, coupling_im, center_freq, name] = quadriga_lib.arrayant_generate( ... );
Inputs (common):
type — Antenna model type; string (see Usage above)
res (optional) — Pattern sampling grid resolution in degrees; default: 1
freq (optional) — Center frequency in Hz; default: 299792458
Inputs (type custom, 3GPP, multibeam, multibeam_sep):
az_3dB (optional) — Azimuth 3dB beamwidth in degrees; default: 90 for custom, else
triggers 3GPP / multibeam internal defaults
el_3dB (optional) — Elevation 3dB beamwidth in degrees; default: 90 for custom, else
triggers 3GPP / multibeam internal defaults
rear_gain_lin (optional) — Front-to-back gain ratio (linear); default: 0
Inputs (type ula, 3GPP, multibeam, multibeam_sep):
M (optional) — Number of vertical elements per panel; default: 1; ignored for ula
N (optional) — Number of horizontal elements per panel; default: 1
pol (optional) — Polarization mode; default: 1:
|
pol |
Description |
|
1 |
Vertical polarization |
|
2 |
H/V polarization (2NM elements) |
|
3 |
±45° polarization (2NM elements) |
|
4 |
Vertical, vertical elements combined (N elements) |
|
5 |
H/V, vertical elements combined (2N elements) |
|
6 |
±45°, vertical elements combined (2N elements) |
spacing (optional) — Inter-element spacing in wavelengths; default: 0.5
Inputs (type 3GPP only):
tilt (optional) — Electrical downtilt in degrees; applies to pol 4–6; default: 0
Mg (optional) — Number of vertically stacked panels; default: 1
Ng (optional) — Number of horizontally stacked panels; default: 1
dgv (optional) — Panel spacing in vertical direction in wavelengths; default: 0.5
dgh (optional) — Panel spacing in horizontal direction in wavelengths; default: 0.5
Inputs (type ula, 3GPP):
pattern (optional) — Custom per-element pattern struct used for 3GPP or ULA; same format as
outputs; overrides default 3GPP/ULA element pattern; other struct fields if present are ignored
Inputs (type multibeam, multibeam_sep):
beam_angles — Beam steering angles, [3, n_beams]; rows are
[azimuth_deg; elevation_deg; weight]; multibeam combines beams via MRT weighting,
multibeam_sep produces one independent beam per column (weights ignored)
Outputs:
ant — Struct with fields:
|
Field |
Description |
Size |
|
e_theta_re |
e-theta field component, real part |
[n_elevation, n_azimuth, n_elements] |
|
e_theta_im |
e-theta field component, imaginary part |
[n_elevation, n_azimuth, n_elements] |
|
e_phi_re |
e-phi field component, real part |
[n_elevation, n_azimuth, n_elements] |
|
e_phi_im |
e-phi field component, imaginary part |
[n_elevation, n_azimuth, n_elements] |
|
azimuth_grid |
Azimuth angles in rad, -π to π, sorted |
[n_azimuth] |
|
elevation_grid |
Elevation angles in rad, -π/2 to π/2, sorted |
[n_elevation] |
|
element_pos |
Element (x,y,z) positions in meters |
[3, n_elements] |
|
coupling_re |
Coupling matrix, real part |
[n_elements, n_ports] |
|
coupling_im |
Coupling matrix, imaginary part |
[n_elements, n_ports] |
|
center_freq |
Center frequency in Hz |
scalar |
|
name |
Name of the array antenna object |
string |
If ant is used as an input to other fuctions, fields e_theta_re, e_theta_im, e_phi_re, e_phi_im, azimuth_grid,
elevation_grid are mandatory; remaining fields are optional (defaults: unit coupling, zero positions, 299792458 Hz)."
arrayant_interpolate - Interpolate polarimetric array antenna field patterns (single- and multi-frequency)
- Interpolates complex e-theta (V) and e-phi (H) field components at the requested
azimuth / elevation angles.
- Single-frequency mode: pass a 1-element struct (or arrayant data via separate inputs);
returns up to 8 outputs including the optional
dist, azimuth_loc, elevation_loc,
and gamma as matrices of size [n_out, n_ang]
- Multi-frequency mode is selected automatically when
arrayant is a struct array with
more than one element or when freq is non-empty; for each target frequency, the two
bracketing center_freq entries are located and blended via SLERP.
- Separate arrayant inputs are accepted in single-frequency mode only
Usage:
% Single-frequency, struct input
[V_re, V_im, H_re, H_im, dist, azimuth_loc, elevation_loc, gamma] = ...
quadriga_lib.arrayant_interpolate( arrayant, azimuth, elevation, element, orientation, element_pos );
% Single-frequency, separate arrayant inputs
[V_re, V_im, H_re, H_im, dist, azimuth_loc, elevation_loc, gamma] = ...
quadriga_lib.arrayant_interpolate( [], azimuth, elevation, element, orientation, element_pos, [], ...
e_theta_re, e_theta_im, e_phi_re, e_phi_im, azimuth_grid, elevation_grid );
% Multi-frequency, struct array input
[V_re, V_im, H_re, H_im] = ...
quadriga_lib.arrayant_interpolate( arrayant_multi, azimuth, elevation, element, orientation, element_pos, freq );
Inputs:
arrayant (optional) — Struct (single-frequency) or struct array (multi-frequency)
containing the arrayant data; field layout as in arrayant_generate. Pass [] to provide
the data via separate inputs (single-frequency only)
azimuth — Azimuth angles in rad, in [-π, π]; single or double precision;
[1, n_ang] for planar-wave mode (same angles for all elements) or [n_out, n_ang] for
per-element angles (spherical-wave mode)
elevation — Elevation angles in rad, in [-π/2, π/2]; single or double; shape must
match azimuth
element (optional) — 1-based element indices to interpolate; duplicates allowed;
defaults to [1:n_elements] when empty; [1, n_out], [n_out, 1], or []; uint32 or double
orientation (optional) — Antenna orientation (bank, tilt, heading) in rad; East is
the default broadside; [3, 1], [3, n_out], [3, 1, n_ang], [3, n_out, n_ang], or []
element_pos (optional) — Override element positions in m; [3, n_out] or [];
falls back to arrayant.element_pos (or zeros) when empty
freq (optional, struct input only) — Target frequencies in Hz; [n_freq]. When passing a
struct array, freq may be omitted or [], in which case the center_freq values of the struct
array entries are used as target frequencies (no interpolation between bands, one output slice per entry).
Inputs (separate arrayant data, required when `arrayant` is `[]`, single-frequency only):
e_theta_re — e-theta real part; [n_elevation, n_azimuth, n_elements]
e_theta_im — e-theta imaginary part; [n_elevation, n_azimuth, n_elements]
e_phi_re — e-phi real part; [n_elevation, n_azimuth, n_elements]
e_phi_im — e-phi imaginary part; [n_elevation, n_azimuth, n_elements]
azimuth_grid — Azimuth sample grid in rad, sorted, in [-π, π]; [n_azimuth]
elevation_grid — Elevation sample grid in rad, sorted, in [-π/2, π/2]; [n_elevation]
Derived sizes:
n_azimuth |
Number of azimuth samples in the pattern |
n_elevation |
Number of elevation samples in the pattern |
n_elements |
Number of antenna elements in the pattern |
n_ang |
Number of interpolation angles |
n_out |
Number of output elements (n_elements if element is empty, else numel(element)) |
n_freq |
Number of target frequencies (multi-frequency mode only) |
Outputs:
V_re — Real part of the interpolated e-theta (vertical) field component;
[n_out, n_ang] in single-freq mode, [n_out, n_ang, n_freq] in multi-freq mode
V_im — Imaginary part of the e-theta component; same size as V_re
H_re — Real part of the interpolated e-phi (horizontal) field component; same size as V_re
H_im — Imaginary part of the e-phi component; same size as V_re
dist (single-frequency only) — Effective distances between the antenna elements
projected onto the wavefront plane; used for phase computation; [n_out, n_ang]
azimuth_loc (single-frequency only) — Azimuth angles in the local (rotated) element
frame in rad; [n_out, n_ang]
elevation_loc (single-frequency only) — Elevation angles in the local element frame in
rad; [n_out, n_ang]
gamma (single-frequency only) — Polarization rotation angles in rad; [n_out, n_ang]
See also:
arrayant_qdant_read - Reads array antenna data from QDANT files
- The QuaDRiGa array antenna exchange format (QDANT) is an XML format for storing antenna
pattern data
- Without
id, all entries are read: returns a struct array when the file has multiple entries
(frequency-dependent model) or a single struct when it has exactly one entry
- With
id, a single entry is read; useful for picking one frequency from a multi-frequency
file
- Separate-fields output (11 or 12 outputs) is only available when the result is a single
entry (i.e.
id was provided, or the file contains exactly one entry)
Usage:
% Multi-frequency read (struct array, all entries)
[ ant, layout ] = quadriga_lib.arrayant_qdant_read( fn );
% Single-frequency read (struct output)
[ ant, layout ] = quadriga_lib.arrayant_qdant_read( fn, id );
% Single-frequency read (separate fields)
[ e_theta_re, e_theta_im, e_phi_re, e_phi_im, azimuth_grid, elevation_grid, element_pos, ...
coupling_re, coupling_im, center_freq, name, layout ] = quadriga_lib.arrayant_qdant_read( fn, id );
Inputs:
fn — Path to the QDANT file; string; must not be empty
id (optional) — 1-based ID of the antenna entry to read; pass [] or omit to read
every entry in the file
Outputs:
ant — Arrayant struct (single entry) or struct array (multiple entries); field layout
as documented in arrayant_generate
layout (optional) — Matrix of element IDs describing how entries are arranged in the
file; datatype: uint32
e_theta_re, e_theta_im, e_phi_re, e_phi_im, azimuth_grid, elevation_grid,
element_pos, coupling_re, coupling_im, center_freq, name — Separate-field
outputs with contents and sizes as in arrayant_generate; only available when the result
is a single entry
See also:
arrayant_qdant_write - Writes array antenna data to QDANT files
- The QuaDRiGa array antenna exchange format (QDANT) is an XML format for storing antenna pattern data
- Multiple array antennas can be stored in the same file using distinct
id values
- If writing to an existing file without specifying an
id, the data is appended at the end and
the returned id_in_file identifies its location in the file
- An optional
layout can be provided to organize the data inside the file
- Passing a struct array (multiple elements) writes a frequency-dependent model with sequential
1-based IDs; in this mode any existing file is overwritten and
id/layout must be omitted
Usage:
% Arrayant as struct
id_in_file = quadriga_lib.arrayant_qdant_write( fn, arrayant, id, layout );
% Arrayant as separate inputs
id_in_file = quadriga_lib.arrayant_qdant_write( fn, [], id, layout, e_theta_re, e_theta_im, e_phi_re, ...
e_phi_im, azimuth_grid, elevation_grid, element_pos, coupling_re, coupling_im, center_freq, name );
Inputs:
fn — Output QDANT filename; string; must not be empty
arrayant (optional) — Struct containing the arrayant data; field layout as documented
in arrayant_generate; pass [] to provide the data via separate inputs instead; a struct
array writes a frequency-dependent model and requires id and layout to be omitted
id (optional) — Target ID of the antenna inside the file; default: max-ID in existing
file + 1 (or 1 if the file does not exist)
layout (optional) — Matrix organizing multiple antenna IDs within the file; must only
reference IDs present in the file; datatype: uint32
Inputs (separate arrayant data, required when `arrayant` is `[]`):
e_theta_re — e-theta field component, real part; [n_elevation, n_azimuth, n_elements]
e_theta_im — e-theta field component, imaginary part; [n_elevation, n_azimuth, n_elements]
e_phi_re — e-phi field component, real part; [n_elevation, n_azimuth, n_elements]
e_phi_im — e-phi field component, imaginary part; [n_elevation, n_azimuth, n_elements]
azimuth_grid — Azimuth angles in rad, -π to π, sorted; [n_azimuth]
elevation_grid — Elevation angles in rad, -π/2 to π/2, sorted; [n_elevation]
element_pos (optional) — Element (x,y,z) positions; [3, n_elements]; default: zeros
coupling_re (optional) — Coupling matrix, real part; [n_elements, n_ports]; default: identity
coupling_im (optional) — Coupling matrix, imaginary part; [n_elements, n_ports]; default: zeros
center_freq (optional) — Center frequency in Hz; default: 299792458
name (optional) — Name of the array antenna object; string
Outputs:
id_in_file — ID assigned to the antenna in the file after writing; set to 0 in
multi-frequency (struct array) mode
See also:
arrayant_rotate_pattern - Rotates antenna patterns
Description:
This MATLAB 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.
This is essential in antenna design and optimization, enabling engineers to tailor the radiation
pattern for enhanced performance. The function also adjusts the sampling grid for non-uniformly
sampled antennas, such as parabolic antennas with small apertures, ensuring accurate and efficient
computations. The 3 rotations are applies 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)
Usage:
% Minimal example (input/output = struct)
arrayant_out = quadriga_lib.arrayant_rotate_pattern(arrayant_in, bank, tilt, head, usage, element);
% Separate outputs, struct input
[e_theta_re, e_theta_im, e_phi_re, e_phi_im, azimuth_grid, elevation_grid, element_pos, ...
coupling_re, coupling_im, freq, name] = quadriga_lib.arrayant_rotate_pattern(arrayant_in, ...
bank, tilt, head, usage, element);
% Separate inputs
arrayant_out = quadriga_lib.arrayant_rotate_pattern([], bank, tilt, head, usage, element, ...
e_theta_re, e_theta_im, e_phi_re, e_phi_im, azimuth_grid, elevation_grid, element_pos, ...
coupling_re, coupling_im, freq, name);
Input Arguments:
arrayant_in [1]
Struct containing the arrayant data with the following fields:
e_theta_re |
e-theta field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_theta_im |
e-theta field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_re |
e-phi field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_im |
e-phi field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Size: [n_azimuth] |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Size: [n_elevation] |
element_pos |
Antenna element (x,y,z) positions, optional |
Size: [3, n_elements] |
coupling_re |
Coupling matrix, real part, optional |
Size: [n_elements, n_ports] |
coupling_im |
Coupling matrix, imaginary part, optional |
Size: [n_elements, n_ports] |
center_freq |
Center frequency in [Hz], optional |
Scalar |
name |
Name of the array antenna object, optional |
String |
If an empty array is passed, array antenna data is provided as separate inputs (Inputs 7-17)
x_deg [2] (optional)
The rotation angle around x-axis (bank angle) in [degrees]
y_deg [3] (optional)
The rotation angle around y-axis (tilt angle) in [degrees]
z_deg [4] (optional)
The rotation angle around z-axis (heading angle) in [degrees]
usage [5] (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) |
usage = 1 |
Rotate only pattern, adjusts sampling grid |
usage = 2 |
Rotate only polarization |
usage = 3 |
Rotate both, but do not adjust the sampling grid |
element [6] (optional)
The element indices for which the pattern should be transformed. Optional parameter. Values must
be between 1 and n_elements. If this parameter is not provided (or an empty array is passed),
all elements will be rotated by the same angles. Size: [1, n_elements] or empty []
Output Arguments:
arrayant_out
Struct containing the arrayant data with the following fields:
e_theta_re |
e-theta field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_theta_im |
e-theta field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_re |
e-phi field component, real part |
Size: [n_elevation, n_azimuth, n_elements] |
e_phi_im |
e-phi field component, imaginary part |
Size: [n_elevation, n_azimuth, n_elements] |
azimuth_grid |
Azimuth angles in [rad] -pi to pi, sorted |
Size: [n_azimuth] |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Size: [n_elevation] |
element_pos |
Antenna element (x,y,z) positions |
Size: [3, n_elements] |
coupling_re |
Coupling matrix, real part |
Size: [n_elements, n_ports] |
coupling_im |
Coupling matrix, imaginary part |
Size: [n_elements, n_ports] |
center_freq |
Center frequency in [Hz], default = 0.3 GHz |
Scalar |
name |
Name of the array antenna object |
String |
Can be returned as separate outputs.
generate_speaker - Generate a parametric frequency-dependent loudspeaker directivity model
Description:
- Returns one arrayant per frequency sample; each has a single element with the real-valued
directivity pattern in
e_theta_re and center_frequency set to the corresponding frequency.
- Multi-driver systems (e.g. two-way) are built by calling this function per driver and combining
results via
append and element_pos; crossover behavior emerges from overlapping bandpass
responses.
- Frequency response is a Butterworth-style bandpass:
H(f) = 1/sqrt(1+(f_low/f)^(2n)) · 1/sqrt(1+(f/f_high)^(2n)),
where n = slope_dB_per_octave / 6; -3 dB at the cutoff frequencies.
- Sensitivity scales amplitude linearly relative to 85 dB SPL:
sens_lin = 10^((sensitivity - 85) / 20).
- If
frequencies is empty, third-octave band center frequencies are auto-generated from one band
below lower_cutoff to one band above upper_cutoff, clipped to 20-20000 Hz.
- Speed of sound assumed to be 344 m/s.
- Driver models (
driver_type):
piston - circular piston in baffle, D(theta) = 2·J1(ka·sin theta)/(ka·sin theta),
rotationally symmetric, narrows with increasing ka
horn - separable cosine-power cos^n(angle) with frequency-dependent blend toward omni
below horn_control_freq
omni - frequency-independent omnidirectional pattern.
- Enclosure models (
radiation_type):
monopole - no modification
hemisphere - sealed box with baffle-step transition, f_baffle = c/(pi·sqrt(W·H))
dipole - figure-8, R = abs(cos(theta_off)) with sign inversion in rear hemisphere
cardioid - R = 0.5·(1+cos(theta_off))
- For
"horn", if horn_control_freq = 0, it is auto-derived as f_ctrl = c/(2pi·radius).
Usage:
arrayant = quadriga_lib.generate_speaker( driver_type, radius, lower_cutoff, upper_cutoff, ...
lower_rolloff_slope, upper_rolloff_slope, sensitivity, radiation_type, hor_coverage, ...
ver_coverage, horn_control_freq, baffle_width, baffle_height, frequencies, ...
angular_resolution );
Inputs:
driver_type (optional) - Driver directivity model: "piston", "horn", or "omni";
default: "piston"
radius (optional) - Effective radiating radius; cone/dome radius for piston, mouth radius
for horn; default: 0.05
lower_cutoff (optional) - Lower -3 dB bandpass frequency; default: 80
upper_cutoff (optional) - Upper -3 dB bandpass frequency; default: 12000
lower_rolloff_slope (optional) - Low-frequency rolloff in dB/octave (12 dB/oct = 2nd-order
Butterworth); default: 12
upper_rolloff_slope (optional) - High-frequency rolloff in dB/octave; default: 12
sensitivity (optional) - On-axis sensitivity in dB SPL at 1W/1m; 85 dB gives unity
amplitude; default: 85
radiation_type (optional) - Enclosure radiation model: "monopole", "hemisphere",
"dipole", or "cardioid"; default: "hemisphere"
hor_coverage (optional) - Horn horizontal coverage angle in degrees; 0 defaults to 90;
default: 0
ver_coverage (optional) - Horn vertical coverage angle in degrees; 0 defaults to 60;
default: 0
horn_control_freq (optional) - Horn pattern control frequency; 0 auto-derives from
radius; default: 0
baffle_width (optional) - Baffle width; used by "hemisphere" model; default: 0.15
baffle_height (optional) - Baffle height; used by "hemisphere" model; default: 0.25
frequencies (optional) - Frequency sample points; auto-generated third-octave bands if
empty; [n_freq]
angular_resolution (optional) - Azimuth and elevation sampling grid resolution in
degrees; default: 5
Outputs:
arrayant - Struct array with one arrayant per frequency sample; directivity is stored in
e_theta_re; dipole rear hemisphere encoded with negative sign for 180 degree phase inversion;
see arrayant_generate for struct fields; [n_freq]
Channel functions
baseband_freq_response - Transforms the channel into frequency domain and returns the frequency response
Usage:
[ hmat_re, hmat_im ] = quadriga_lib.baseband_freq_response( coeff_re, coeff_im, delay, pilot_grid, bandwidth, i_snap );
Input Arguments:
coeff_re
Channel coefficients, real part, Size: [ n_rx, n_tx, n_path, n_snap ]
coeff_im
Channel coefficients, imaginary part, Size: [ n_rx, n_tx, n_path, n_snap ]
delays
Propagation delay in seconds, Size: [ n_rx, n_tx, n_path, n_snap ] or [ 1, 1, n_path, n_snap ]
or [ n_path, n_snap ]
pilot_grid
Sub-carrier positions relative to the bandwidth. The carrier positions are given relative to the
bandwidth where '0' is the begin of the spectrum (i.e., the center frequency f0) and '1' is
equal to f0+bandwidth. To obtain the channel frequency response centered around f0, the
input variable 'pilot_grid' must be set to '(-N/2:N/2)/N', where N is the number of sub-
carriers. Vector of length: [ n_carriers ]
bandwidth
The baseband bandwidth in [Hz], scalar
i_snap (optional)
Snapshot indices for which the frequency response should be generated (1-based index). If this
variable is not given, all snapshots are processed. Length: [ n_out ]
Output Argument:
hmat_re
Freq. domain channel matrices (H), real part, Size [ n_rx, n_tx, n_carriers, n_out ]
hmat_im
Freq. domain channel matrices (H), imaginary part, Size [ 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:
quadriga_lib.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_re, coeff_im, 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_re
Channel coefficients, real part, Size: [ n_rx, n_tx, n_path, n_snap ]
coeff_im
Channel coefficients, imaginary part, Size: [ n_rx, n_tx, n_path, n_snap ]
i_snap
(optional)
Snapshot indices, optional, 1-based, range [1 ... n_snap]
Output Argument:
This function does not return a value. It writes the OBJ file directly to disk.
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.hdf5_create_file is used to create an
empty file with a predetermined custom storage layout.
Usage:
quadriga_lib.hdf5_create_file( fn, storage_dims );
Input Arguments:
fn
Filename of the HDF5 file, string
storage_dims (optional)
Size of the dimensions of the storage space, vector with 1-4 elements, i.e. [nx], [nx, ny],
[nx,ny,nz] or [nx,ny,nz,nw]. By default, nx = 65536, ny = 1, nz = 1, nw = 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.hdf5_read_channel is designed to read both structured and unstructured data from the
file.
Usage:
[ par, rx_position, tx_position, coeff_re, coeff_im, delay, center_freq, name, initial_pos, ...
path_gain, path_length, path_polarization, path_angles, path_fbs_pos, path_lbs_pos, no_interact, ...
interact_coord, rx_orientation, tx_orientation ] = quadriga_lib.hdf5_read_channel( fn, location, snap );
Input Arguments:
fn
Filename of the HDF5 file, string
location (optional)
Storage location inside the file; 1-based; vector with 1-4 elements, i.e. [ix], [ix, iy],
[ix,iy,iz] or [ix,iy,iz,iw]; Default: ix = iy = iz = iw = 1
snap (optional)
Snapshot range; optional; vector, default = read all
Output Arguments:
par
Unstructured data as struct, may be empty if no unstructured data is present
- Structured data: (outputs 2-19, single precision)
rx_position |
Receiver positions |
[3, n_snap] or [3, 1] |
tx_position |
Transmitter positions |
[3, n_snap] or [3, 1] |
coeff_re |
Channel coefficients, real part |
[n_rx, n_tx, n_path, n_snap] |
coeff_im |
Channel coefficients, imaginary part |
[n_rx, n_tx, n_path, n_snap] |
delay |
Propagation delays in seconds |
[n_rx, n_tx, n_path, n_snap] or [1, 1, n_path, n_snap] |
center_freq |
Center frequency in [Hz] |
[n_snap, 1] 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 |
[n_path, n_snap] |
path_length |
Path length from TX to RX phase center in m |
[n_path, n_snap] |
polarization |
Polarization transfer function, interleaved complex |
[8, n_path, n_snap] |
path_angles |
Departure and arrival angles {AOD, EOD, AOA, EOA} in rad |
[n_path, 4, n_snap] |
path_fbs_pos |
First-bounce scatterer positions |
[3, n_path, n_snap] |
path_lbs_pos |
Last-bounce scatterer positions |
[3, n_path, n_snap] |
no_interact |
Number interaction points of paths with the environment |
uint32, [n_path, n_snap] |
interact_coord |
Interaction coordinates |
[3, max(sum(no_interact)), n_snap] |
rx_orientation |
Transmitter orientation |
[3, n_snap] or [3, 1] |
tx_orientation |
Receiver orientation |
[3, n_snap] or [3, 1] |
Caveat:
- Empty outputs are returned if data set does not exist in the file
- All structured data is stored in single precision. Hence, outputs are also in single precision.
- Unstructured datatypes are returned as stored in the HDF file (same type, dimensions and storage order)
- Typically,
n_path may vary for each snapshot. In such cases, n_path is set to the maximum value found
within the range of snapshots, and any missing paths are padded with zeroes.
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.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:
dset = quadriga_lib.hdf5_read_dset( fn, location, name );
Input Arguments:
fn
Filename of the HDF5 file, string
location (optional)
Storage location inside the file; 1-based; vector with 1-4 elements, i.e. [ix], [ix, iy],
[ix,iy,iz] or [ix,iy,iz,iw]; Default: ix = iy = iz = iw = 1
name
Name of the dataset; String
Output Argument:
dset
Output data. Type and size is defined by the dataspace in the file
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.hdf5_read_dset_names retrieves the names of all these
datasets, returning them as a cell array of strings.
Usage:
names = quadriga_lib.hdf5_read_dset_names( fn, location );
Input Arguments:
fn
Filename of the HDF5 file, string
location (optional)
Storage location inside the file; 1-based; vector with 1-4 elements, i.e. [ix], [ix, iy],
[ix,iy,iz] or [ix,iy,iz,iw]; Default: ix = iy = iz = iw = 1
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.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:
[ storage_dims, has_data ] = quadriga_lib.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.hdf5_reshape_layout.
Usage:
quadriga_lib.hdf5_reshape_layout( fn, storage_dims );
Input Arguments:
fn
Filename of the HDF5 file, string
storage_dims
Size of the dimensions of the storage space, vector with 1-4 elements, i.e. [nx], [nx, ny],
[nx,ny,nz] or [nx,ny,nz,nw]. By default, nx = 65536, ny = 1, nz = 1, nw = 1
An error is thrown if the number of elements in the file is different from the given size.
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:
storage_dims = quadriga_lib.hdf5_write_channel( fn, location, par, rx_position, tx_position, ...
coeff_re, coeff_im, delay, center_freq, name, initial_pos, path_gain, path_length, ...
path_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
location (optional)
Storage location inside the file; 1-based; vector with 1-4 elements, i.e. [ix], [ix, iy],
[ix,iy,iz] or [ix,iy,iz,iw]; Default: ix = iy = iz = iw = 1
par
Unstructured data as struct, can be empty if no unstructured data should be written
- Structured data: (inputs 4-21, single or double precision)
rx_position |
Receiver positions |
[3, n_snap] or [3, 1] |
tx_position |
Transmitter positions |
[3, n_snap] or [3, 1] |
coeff_re |
Channel coefficients, real part |
[n_rx, n_tx, n_path, n_snap] |
coeff_im |
Channel coefficients, imaginary part |
[n_rx, n_tx, n_path, n_snap] |
delay |
Propagation delays in seconds |
[n_rx, n_tx, n_path, n_snap] or [1, 1, n_path, n_snap] |
center_freq |
Center frequency in [Hz] |
[n_snap, 1] 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 |
[n_path, n_snap] |
path_length |
Path length from TX to RX phase center in m |
[n_path, n_snap] |
polarization |
Polarization transfer function, interleaved complex |
[8, n_path, n_snap] |
path_angles |
Departure and arrival angles {AOD, EOD, AOA, EOA} in rad |
[n_path, 4, n_snap] |
path_fbs_pos |
First-bounce scatterer positions |
[3, n_path, n_snap] |
path_lbs_pos |
Last-bounce scatterer positions |
[3, n_path, n_snap] |
no_interact |
Number interaction points of paths with the environment |
uint32, [n_path, n_snap] |
interact_coord |
Interaction coordinates |
[3, max(sum(no_interact)), n_snap] |
rx_orientation |
Transmitter orientation |
[3, n_snap] or [3, 1] |
tx_orientation |
Receiver orientation |
[3, n_snap] or [3, 1] |
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.hdf5_write_dset writes a single unstructured dataset.
Usage:
storage_dims = quadriga_lib.hdf5_write_dset( fn, location, name, data );
Input Arguments:
fn
Filename of the HDF5 file, string
location (optional)
Storage location inside the file; 1-based; vector with 1-4 elements, i.e. [ix], [ix, iy],
[ix,iy,iz] or [ix,iy,iz,iw]; Default: ix = iy = iz = iw = 1
name
Name of the dataset; String
data
Data to be written
Output Argument:
storage_dims
Size of the dimensions of the storage space, vector with 4 elements, i.e. [nx,ny,nz,nw].
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
- Parses a QRT file and extracts snapshot counts, origin/destination counts, frequency count,
CIR offsets, names, positions, orientations, and file version
- All output arguments are optional; MATLAB only computes outputs that are requested
- When
no_dest == 0 in the file, one implicit RX named "RX" is assumed; dest_names and
cir_offset reflect this
Usage:
[ no_cir, no_orig, no_dest, no_freq, cir_offset, orig_names, dest_names, version, freq, ...
cir_pos, cir_orientation, orig_pos, orig_orientation ] = quadriga_lib.qrt_file_parse( fn );
Input Arguments:
fn — Path to the QRT file; string
Output Arguments:
no_cir — Number of channel snapshots per origin point; uint64 scalar
no_orig — Number of origin points (TX); uint64 scalar
no_dest — Number of destination points (RX); uint64 scalar
no_freq — Number of frequency bands; uint64 scalar
cir_offset — CIR offset per destination; uint64; [no_dest]
orig_names — Names of origin points; cell array of strings; [no_orig]
dest_names — Names of destination points; cell array of strings; [no_dest]
version — QRT file version number; int32 scalar
freq — Frequencies as stored in the file; usually in GHz; single; [no_freq]
cir_pos — CIR positions in Cartesian coordinates; single; [no_cir, 3]
cir_orientation — CIR orientations as Euler angles; single; [no_cir, 3]
orig_pos — Origin (TX) positions in Cartesian coordinates; single; [no_orig, 3]
orig_orientation — Origin (TX) orientations as Euler angles; single; [no_orig, 3]
qrt_file_read - Read ray-tracing CIR data from a QRT file
- Reads channel impulse response data from QRT files
- All output arguments are optional; MATLAB only computes outputs that are requested
- If
downlink = true, origin is TX and destination is RX; if false, roles are swapped
Usage:
[ center_freq, tx_pos, tx_orientation, rx_pos, rx_orientation, fbs_pos, lbs_pos, path_gain, ...
path_length, M, aod, eod, aoa, eoa, path_coord, no_int, coord ] = ...
quadriga_lib.qrt_file_read( fn, i_cir, i_orig, downlink, normalize_M );
Input Arguments:
fn — Path to the QRT file; string
i_cir (optional) — Snapshot indices; 1-based; uint64; [n_out] or empty; default: read all
i_orig (optional) — Origin index; 1-based; uint64; scalar; default: 1
downlink (optional) — If true, origin=TX, destination=RX; if false, roles are
swapped; logical scalar; default: true
normalize_M (optional) — Controls M and path_gain scaling where PL is the propagation-only path loss
- v4/v5 (EM): FSPL = 32.45 + 20·log10(f_GHz) + 20·log10(d_m) [dB]
- v6 (scalar): 20·log10(d_m) + α(f)·d_m [dB], with α from ISO 9613-1 at T=20°C, RH=50%, p=1 atm
|
normalize_M |
M |
path_gain |
|
0 |
As stored in QRT file |
-PL |
|
1 |
Max column power = 1 |
-PL minus material losses |
Output Arguments:
center_freq — Center frequency in Hz; [n_freq]
tx_pos — Transmitter position in Cartesian coordinates; [3, n_out]
tx_orientation — Transmitter orientation (bank, tilt, heading); [3, n_out]
rx_pos — Receiver position in Cartesian coordinates; [3, n_out]
rx_orientation — Receiver orientation (bank, tilt, heading); [3, n_out]
fbs_pos — First-bounce scatterer positions; Cell of length n_out; elements [3, n_path]
lbs_pos — Last-bounce scatterer positions; Cell of length n_out; elements [3, n_path]
path_gain — Path gain on linear scale; Cell of length n_out; elements [n_path, n_freq]
path_length — Absolute path length TX to RX phase center; Cell of length n_out; elements [n_path]
M — Polarization transfer matrix; Cell of length n_out;
elements [8, n_path, n_freq] or [2, n_path, n_freq] for v6 files
aod — Departure azimuth angles; Cell of length n_out; elements [n_path]
eod — Departure elevation angles; Cell of length n_out; elements [n_path]
aoa — Arrival azimuth angles; Cell of length n_out; elements [n_path]
eoa — Arrival elevation angles; Cell of length n_out; elements [n_path]
path_coord — Interaction coordinates per path; Cell of length n_out;
elements Cell of length n_path, each [3, n_interact + 2]
no_int — Number of mesh interactions per path; 0 indicates LOS; uint32;
Cell of length n_out; elements [n_path]
coord — Interaction coordinates (flat, concatenated across paths); single;
Cell of length n_out; elements [3, sum(no_int)]
See also:
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, n_snap] or shared [1, 1, n_path, n_snap].
Usage:
[ coeff_re_q, coeff_im_q, delay_q ] = quadriga_lib.quantize_delays( coeff_re, coeff_im, delay, ...
tap_spacing, max_no_taps, power_exponent, fix_taps );
Input Arguments:
coeff_re (required)
Channel coefficients, real part. 4D array of size [n_rx, n_tx, n_path, n_snap] (double).
coeff_im (required)
Channel coefficients, imaginary part. 4D array of size [n_rx, n_tx, n_path, n_snap] (double).
delay (required)
Path delays in seconds. 4D array of size [n_rx, n_tx, n_path, n_snap] or
[1, 1, n_path, n_snap] (double).
tap_spacing (optional)
Spacing of the delay bins in seconds. Scalar double. Default: 5e-9
max_no_taps (optional)
Maximum number of output taps. Scalar integer. 0 = unlimited. Default: 48
power_exponent (optional)
Interpolation exponent. Scalar double. Default: 1.0
fix_taps (optional)
Delay sharing mode. Scalar integer (0-3). Default: 0
0 = per tx-rx pair and snapshot, 1 = single grid for all,
2 = per snapshot, 3 = per tx-rx pair.
Output Arguments:
coeff_re_q
Output coefficients, real part. 4D array of size [n_rx, n_tx, n_taps, n_snap] (double).
coeff_im_q
Output coefficients, imaginary part. 4D array of size [n_rx, n_tx, n_taps, n_snap] (double).
delay_q
Output delays in seconds. 4D array of size [n_rx, n_tx, n_taps, n_snap] or
[1, 1, n_taps, n_snap] (double).
Channel generation functions
get_channels_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.get_channels_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
Struct array of length n_users containing the channel data with the following fields:
|
Field |
Description |
Type |
|
name |
Channel name |
String |
|
tx_position |
Transmitter positions (AP for downlink, STA for uplink) |
Size: [3, 1] or [3, n_snap] |
|
rx_position |
Receiver positions (STA for downlink, AP for uplink) |
Size: [3, 1] or [3, n_snap] |
|
tx_orientation |
Transmitter orientation, Euler angles (AP for downlink, STA for uplink) |
Size: [3, 1] or [3, n_snap] |
|
rx_orientation |
Receiver orientation, Euler angles (STA for downlink, AP for uplink) |
Size: [3, 1] or [3, n_snap] |
|
coeff_re |
Channel coefficients, real part |
Size: [n_rx, n_tx, n_path, n_snap] |
|
coeff_im |
Channel coefficients, imaginary part |
Size: [n_rx, n_tx, n_path, n_snap] |
|
delay |
Propagation delays in seconds |
Size: [n_rx, n_tx, n_path, n_snap] |
|
path_gain |
Path gain before antenna, linear scale |
Size: [n_path, n_snap] |
|
center_frequency |
Center Frequency in Hz |
Scalar |
See also:
get_channels_irs - Calculate channel coefficients for intelligent reflective surfaces (IRS)
Description:
- Calculates MIMO channel coefficients and delays for IRS-assisted communication using two channel segments:
1. TX → IRS; 2. IRS → RX
- The IRS is modeled as a passive antenna array with phase shifts defined via its coupling matrix.
- IRS codebook entries can be selected via a port index (
i_irs).
- Supports combining paths from both segments to form
n_path_irs valid output paths, subject to a gain threshold.
- Optional second IRS array allows different antenna behavior for TX-IRS and IRS-RX directions.
Usage:
[ coeff_re, coeff_im, delays, active_path, aod, eod, aoa, eoa ] = quadriga_lib.get_channels_irs( ...
ant_tx, ant_rx, ant_irs, ...
fbs_pos_1, lbs_pos_1, path_gain_1, path_length_1, M_1, ...
fbs_pos_2, lbs_pos_2, path_gain_2, path_length_2, M_2, ...
tx_pos, tx_orientation, rx_pos, rx_orientation, irs_pos, irs_orientation, ...
i_irs, threshold_dB, center_freq, use_absolute_delays, active_path, ant_irs_2 );
Input Arguments:
ant_tx [1] (required)
Struct containing the transmit (TX) arrayant data with the following fields:
e_theta_re |
e-theta field component, real part |
Size: [n_elevation_tx, n_azimuth_tx, n_elements_tx] |
e_theta_im |
e-theta field component, imaginary part |
Size: [n_elevation_tx, n_azimuth_tx, n_elements_tx] |
e_phi_re |
e-phi field component, real part |
Size: [n_elevation_tx, n_azimuth_tx, n_elements_tx] |
e_phi_im |
e-phi field component, imaginary part |
Size: [n_elevation_tx, n_azimuth_tx, n_elements_tx] |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Size: [n_azimuth_tx] |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Size: [n_elevation_tx] |
element_pos |
Antenna element (x,y,z) positions, optional |
Size: [3, n_elements_tx] |
coupling_re |
Coupling matrix, real part, optional |
Size: [n_elements_tx, n_ports_tx] |
coupling_im |
Coupling matrix, imaginary part, optional |
Size: [n_elements_tx, n_ports_tx] |
ant_rx [2] (required)
Struct containing the receive (RX) arrayant data with the following fields:
e_theta_re |
e-theta field component, real part |
Size: [n_elevation_rx, n_azimuth_rx, n_elements_rx] |
e_theta_im |
e-theta field component, imaginary part |
Size: [n_elevation_rx, n_azimuth_rx, n_elements_rx] |
e_phi_re |
e-phi field component, real part |
Size: [n_elevation_rx, n_azimuth_rx, n_elements_rx] |
e_phi_im |
e-phi field component, imaginary part |
Size: [n_elevation_rx, n_azimuth_rx, n_elements_rx] |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Size: [n_azimuth_rx] |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Size: [n_elevation_rx] |
element_pos |
Antenna element (x,y,z) positions, optional |
Size: [3, n_elements_rx] |
coupling_re |
Coupling matrix, real part, optional |
Size: [n_elements_rx, n_ports_rx] |
coupling_im |
Coupling matrix, imaginary part, optional |
Size: [n_elements_rx, n_ports_rx] |
ant_irs [3] (required)
Struct containing the intelligent reflective surface (IRS) model:
e_theta_re |
e-theta field component, real part |
Size: [n_elevation_irs, n_azimuth_irs, n_elements_irs] |
e_theta_im |
e-theta field component, imaginary part |
Size: [n_elevation_irs, n_azimuth_irs, n_elements_irs] |
e_phi_re |
e-phi field component, real part |
Size: [n_elevation_irs, n_azimuth_irs, n_elements_irs] |
e_phi_im |
e-phi field component, imaginary part |
Size: [n_elevation_irs, n_azimuth_irs, n_elements_irs] |
azimuth_grid |
Azimuth angles in [rad], -pi to pi, sorted |
Size: [n_azimuth_irs] |
elevation_grid |
Elevation angles in [rad], -pi/2 to pi/2, sorted |
Size: [n_elevation_irs] |
element_pos |
Antenna element (x,y,z) positions, optional |
Size: [3, n_elements_irs] |
coupling_re |
Coupling matrix, real part, optional |
Size: [n_elements_irs, n_ports_irs] |
coupling_im |
Coupling matrix, imaginary part, optional |
Size: [n_elements_irs, n_ports_irs] |
fbs_pos_1 [4] (required)
First-bounce scatterer positions of TX → IRS paths, Size: [ 3, n_path_1 ].
lbs_pos_1 [5] (required)
Last-bounce scatterer positions of TX → IRS paths, Size [3, n_path_1].
path_gain_1 [6] (required)
Path gains (linear) for TX → IRS paths, Length n_path_1.
path_length_1 [7] (required)
Path lengths for TX → IRS paths, Length n_path_1.
M_1 [8] (required)
Polarization transfer matrix for TX → IRS paths, Size [8, n_path_1].
fbs_pos_2 [9] (required)
First-bounce scatterer positions of IRS → RX paths, Size: [ 3, n_path_2 ]
lbs_pos_2 [10] (required)
Last-bounce scatterer positions of IRS → RX paths, Size [3, n_path_2]
path_gain_2 [11] (required)
Path gains (linear) for IRS → RX paths, Length n_path_2.
path_length_2 [12] (required)
Path lengths for IRS → RX paths, Length n_path_2.
M_2 [13] (required)
Polarization transfer matrix for IRS → RX paths, Size [8, n_path_2].
tx_pos [14] (required)
Transmitter position in 3D Cartesian coordinates, Size: [3,1] or [1,3]
tx_orientation [15] (required)
3-element vector describing the orientation of the transmit antenna in Euler angles (bank, tilt, heading),
Size: [3,1] or [1,3]
rx_pos [16] (required)
Receiver position in 3D Cartesian coordinates, Size: [3,1] or [1,3]
rx_orientation [17] (required)
3-element vector describing the orientation of the receive antenna, Size: [3,1] or [1,3]
irs_pos [18] (required)
IRS position in 3D Cartesian coordinates, Size: [3,1] or [1,3]
irs_orientation [19] (required)
3-element (Euler) vector in Radians describing the orientation of the IRS, Size: [3,1] or [1,3]
i_irs [20] (optional)
Index of IRS codebook entry (port number), Scalar, Default: 0.
threshold_dB [21] (optional)
Threshold (in dB) below which paths are discarded, Scalar, Default: -140.0.
center_freq [22] (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 [23] (optional)
If true, the LOS delay is included for all paths; Default is false, i.e. delays are normalized
to the LOS delay.
active_path [24] (optional)
Optional bitmask for selecting active TX-IRS and IRS-RX path pairs. Ignores threshold_dB when provided.
ant_irs_2 [25] (optional)
Optional second IRS array (TX side for IRS → RX paths) for asymmetric IRS behavior. Same structure as for ant_irs
Output Arguments:
coeff_re
Channel coefficients, real part, Size: [ n_ports_rx, n_ports_tx, n_path ]
coeff_im
Channel coefficients, imaginary part, Size: [ n_ports_rx, n_ports_tx, n_path ]
delays
Propagation delay in seconds, Size: [ n_ports_rx, n_ports_tx, n_path ]
active_path (optional)
Boolean mask of length n_path_1 * n_path_2, indicating which path combinations were used.
aod (optional)
Azimuth of Departure angles in [rad], Size: [ n_ports_rx, n_ports_tx, n_path ]
eod (optional)
Elevation of Departure angles in [rad], Size: [ n_ports_rx, n_ports_tx, n_path ]
aoa (optional)
Azimuth of Arrival angles in [rad], Size: [ n_ports_rx, n_ports_tx, n_path ]
eoa (optional)
Elevation of Arrival angles in [rad], Size: [ n_ports_rx, n_ports_tx, n_path ]
get_channels_planar - Calculate MIMO channel coefficients for planar wave paths
- Computes complex channel coefficients and delays for all TX/RX element pairs across
n_path propagation paths.
- Interpolates antenna patterns for both arrays, accounting for element positions, orientation, and polarization.
- LOS path detection is distance-based (angles ignored).
- Polarization transfer matrix
M must be normalized; rows are interleaved real/imag components.
- If
add_fake_los_path is true, a zero-power LOS path is appended, making output size n_path+1.
- Setting
center_frequency = 0 disables phase calculation (delays still computed).
use_absolute_delays = false subtracts the straight-line TX↔RX distance from all path lengths before
converting to delay.
Usage:
[ coeff_re, coeff_im, delays, rx_Doppler ] = quadriga_lib.get_channels_planar( tx_array, rx_array, ...
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:
tx_array — Transmit antenna array; n_tx = number of ports after element coupling, see arrayant_generate
rx_array — Receive antenna array; n_rx = number of ports after element coupling, see arrayant_generate
aod — Departure azimuth angles; rad; [n_path, 1]
eod — Departure elevation angles; rad; [n_path, 1]
aoa — Arrival azimuth angles; rad; [n_path, 1]
eoa — Arrival elevation angles; rad; [n_path, 1]
path_gain — Path gains in linear scale; [n_path, 1]
path_length — Total path lengths from TX to RX phase center; [n_path, 1]
M — Polarization transfer matrix, interleaved (ReVV, ImVV, ReVH, ImVH, ReHV, ImHV, ReHH, ImHH); [8, n_path]
tx_pos — Transmitter position; [3, 1]
tx_orientation — Transmitter orientation as Euler angles (bank, tilt, heading); [3, 1]
rx_pos — Receiver position; [3, 1]
rx_orientation — Receiver orientation as Euler angles (bank, tilt, heading); [3, 1]
center_freq (optional) — Center frequency; set to 0 or skip/leave empty to skip phase computation
use_absolute_delays (optional) — If true, delays include the LOS component; Default: false
add_fake_los_path (optional) — If true, prepends a zero-power LOS path when none is present; Default: false
Output Arguments:
coeff_re — Real part of channel coefficients; [n_rx, n_tx, n_path(+1)]
coeff_im — Imaginary part of channel coefficients; [n_rx, n_tx, n_path(+1)]
delay — Propagation delays in seconds; [n_rx, n_tx, n_path(+1)]
rx_Doppler — Doppler weights for moving RX; positive = moving toward path, negative = away; [1, n_path(+1)]
See also:
get_channels_spherical - Calculate MIMO channel coefficients and delays for spherical wave propagation
- Computes complex channel coefficients and propagation delays for all TX/RX element pairs and paths,
using spherical wave assumption with per-element phase and delay.
- Interpolates antenna patterns for both arrays, accounting for element positions and array orientation
(bank/tilt/heading Euler angles).
- Polarization coupling is applied via the 8-row transfer matrix
M (interleaved Re/Im for VV, VH, HV, HH components).
- If
center_frequency == 0, phase calculation is disabled and only delays are computed.
- If
use_absolute_delays == false, the minimum delay (LOS delay) is subtracted from all paths.
- If
add_fake_los_path == true, a zero-power LOS path is prepended when no LOS path is detected.
Usage:
[ coeff_re, coeff_im, delays, aod, eod, aoa, eoa ] = quadriga_lib.get_channels_spherical( tx_array, rx_array, ...
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, use_avx2 );
Inputs:
tx_array — Transmit antenna array; n_tx = number of ports after element coupling, see arrayant_generate
rx_array — Receive antenna array; n_rx = number of ports after element coupling, see arrayant_generate
fbs_pos — First-bounce scatterer positions; [3, n_path]
lbs_pos — Last-bounce scatterer positions; [3, n_path]
path_gain — Path gains in linear scale; [n_path, 1]
path_length — Total path lengths from TX to RX phase center; [n_path, 1]
M — Polarization transfer matrix, interleaved (ReVV, ImVV, ReVH, ImVH, ReHV, ImHV, ReHH, ImHH); [8, n_path]
tx_pos — Transmitter position; [3, 1]
tx_orientation — Transmitter orientation as Euler angles (bank, tilt, heading); [3, 1]
rx_pos — Receiver position; [3, 1]
rx_orientation — Receiver orientation as Euler angles (bank, tilt, heading); [3, 1]
center_freq (optional) — Center frequency; set to 0 or skip/leave empty to skip phase computation
use_absolute_delays (optional) — If true, delays include the LOS component; Default: false
add_fake_los_path (optional) — If true, prepends a zero-power LOS path when none is present; Default: false
use_avx2 (optional) — If true, use AVX2 for antenna interpolation; faster, but less accurate;
ignored when not supported; Default: false
Outputs:
coeff_re — Real part of channel coefficients; [n_rx, n_tx, n_path(+1)]
coeff_im — Imaginary part of channel coefficients; [n_rx, n_tx, n_path(+1)]
delay — Propagation delays in seconds; [n_rx, n_tx, n_path(+1)]
aod (optional) — Azimuth of departure; [n_rx, n_tx, n_path(+1)]
eod (optional) — Elevation of departure; [n_rx, n_tx, n_path(+1)]
aoa (optional) — Azimuth of arrival; [n_rx, n_tx, n_path(+1)]
eoa (optional) — Elevation of arrival; [n_rx, n_tx, n_path(+1)]
See also:
Channel statistics
acdf - Calculate the empirical averaged cumulative distribution function (CDF)
- Computes per-column empirical CDFs by histogramming into bins and taking the normalized cumulative sum
- Averaged CDF is obtained by quantile-space averaging: for a fine probability grid, x-values from each column CDF are averaged,
then mapped back to the bin grid
- Quantile statistics (mean and std) are reported at the 0.1, 0.2, ..., 0.9 probability levels
Inf and NaN values are excluded from computation
- If
bins is empty, equally spaced bins spanning the data range are generated
Usage:
[ cdf_per_set, bins_out, cdf_avg, mu, sig ] = quadriga_lib.acdf( data, bins_in, n_bins );
Inputs:
data — Input data matrix; each column is one independent data set, [n_samples, n_sets]
bins_in (optional) — Bin centers; used as-is if non-empty, [n_bins_in]
n_bins (optional) — Number of bins when auto-generating; must be >= 2; ignored when
non-empty bins_in are provided
Outputs:
cdf_per_set (optional) — Individual CDFs, one per column of data, [n_bins_out, n_sets]
bins_out (optional) — Auto-generated bins; copy of bins_in when
non-empty bins_in are provided, [n_bins_out = n_bins] or [n_bins_out = n_bins_in]
cdf_avg (optional) — Averaged CDF via quantile-space averaging across data sets, [n_bins]
mu (optional) — Mean of the 0.1–0.9 quantiles across data sets, [9]
sig (optional) — Standard deviation of the 0.1–0.9 quantiles across data sets, [9]
calc_angular_spread - Calculate azimuth and elevation angular spreads with spherical wrapping
- Computes RMS azimuth and elevation angular spreads from power-weighted angles; each column
of
az/el/powers is one CIR; zero-power paths can be used to pad CIRs with fewer paths
- RMS spread formula:
sqrt(sum(pw .* d^2)) where d are wrapped deviations from the
circular mean (3GPP TR 38.901 second-moment definition)
- When
wrapping = true, 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, avoiding pole singularity artifacts
- When
wrapping = false, spreads are computed directly from raw angles; orientation is
zero and phi/theta equal the input az/el
- When
calc_bank_angle = true, an optimal bank angle maximizing azimuth spread is derived
analytically from eigenvectors of the 2x2 power-weighted covariance matrix of centered
angles; only used when wrapping = true
- When
quantize > 0, paths within that angular distance are grouped and their powers
summed before computing spreads
Usage:
[ as, es, orientation, phi, theta ] = quadriga_lib.calc_angular_spread( az, el, powers, ...
wrapping, calc_bank_angle, quantize );
Inputs:
az — Azimuth angles; range -pi to pi; [n_path, n_cir]
el — Elevation angles; range -pi/2 to pi/2; [n_path, n_cir]
powers — Path powers in [W]; [n_path, n_cir]
wrapping (optional) — If true, enables spherical rotation; default: false
calc_bank_angle (optional) — If true, computes optimal bank angle analytically;
only used when wrapping = true; default: false
quantize (optional) — Angular quantization step in [deg]; paths within this
distance are grouped; default: 0 (no quantization)
Outputs:
as — RMS azimuth angular spread; [n_cir]
es — RMS elevation angular spread; [n_cir]
orientation — Power-weighted mean orientation in Euler angles [bank; tilt; heading]; [3, n_cir]
phi — Rotated azimuth angles; [n_path, n_cir]
theta — Rotated elevation angles; [n_path, n_cir]
calc_cross_polarization_ratio - Calculate the cross-polarization ratio (XPR) for linear and circular polarization bases
- Computes aggregate XPR from polarization transfer matrices using the total-power-ratio
method: co-pol and cross-pol powers are summed across all qualifying paths per CIR, and
XPR is their ratio
- XPR is computed in both the linear V/H basis and the circular LHCP/RHCP basis via the
Jones matrix transform
M_circ = T M_lin T^-1
- LOS paths are identified by comparing path length against the direct TX-RX distance
dTR; paths with path_length < dTR + window_size are excluded by default
- Polarization transfer matrix
M is stored column-major with interleaved real/imaginary
parts, 8 rows per path:
[Re(M_vv); Im(M_vv); Re(M_vh); Im(M_vh); Re(M_hv); Im(M_hv); Re(M_hh); Im(M_hh)]
- Normalization of
M does not affect XPR (cancels in the ratio) but does affect pg
- If cross-pol power is zero and co-pol is positive, XPR is set to infinity; if both are
zero, XPR is set to 0
- TX/RX positions may be fixed
[3, 1] or mobile [3, n_cir]
Usage:
[ xpr, pg ] = quadriga_lib.calc_cross_polarization_ratio( powers, M, path_length, ...
tx_pos, rx_pos, include_los, window_size );
Inputs:
powers — Path powers in [W]; [n_path, n_cir]
M — Polarization transfer matrices with interleaved real/imag parts; [8, n_path, n_cir]
path_length — Absolute TX-to-RX path lengths; [n_path, n_cir]
tx_pos — Transmitter position [x; y; z]; [3, 1] (fixed) or [3, n_cir] (mobile)
rx_pos — Receiver position [x; y; z]; [3, 1] (fixed) or [3, n_cir] (mobile)
include_los (optional) — If true, includes LOS and near-LOS paths in the XPR
calculation; default: false
window_size (optional) — LOS exclusion window; paths within dTR + window_size
are excluded when include_los = false; default: 0.01
Outputs:
xpr (optional) — XPR on linear scale; [n_cir, 6]; columns:
|
Col |
Description |
|
1 |
Aggregate linear XPR (total V+H co-pol / total V+H cross-pol) |
|
2 |
V-XPR: sum(abs(M_vv)^2) / sum(abs(M_hv)^2) |
|
3 |
H-XPR: sum(abs(M_hh)^2) / sum(abs(M_vh)^2) |
|
4 |
Aggregate circular XPR (total L+R co-pol / total L+R cross-pol) |
|
5 |
LHCP XPR: sum(abs(M_LL)^2) / sum(abs(M_RL)^2) |
|
6 |
RHCP XPR: sum(abs(M_RR)^2) / sum(abs(M_LR)^2) |
pg (optional) — Total path gain summed over all paths (including LOS) as
0.5 sum(powers (abs(M_vv)^2 + abs(M_hv)^2 + abs(M_vh)^2 + abs(M_hh)^2)); [n_cir]
calc_delay_spread - Calculates RMS delay spread from per-CIR delays and linear-scale powers
- Paths with power below
p_max / 10^(0.1 * threshold) are excluded; the default threshold
of 100 dB effectively includes all paths
- When
granularity > 0, paths falling into the same delay bin of width granularity have
their powers summed before computing the spread; function recurses on the binned profile
Usage:
[ ds, mean_delay ] = quadriga_lib.calc_delay_spread( delays, powers, threshold, granularity );
Inputs:
delays — Delays in [s] per CIR; [n_path, n_cir]
powers — Path powers on linear scale in [W]; [n_path, n_cir]
threshold (optional) — Power threshold in [dB] relative to strongest path; paths
below threshold are excluded; default: 100
granularity (optional) — Bin width in [s] for grouping paths in the delay domain;
default: 0 (no grouping)
Outputs:
ds — RMS delay spread in [s] per CIR; [n_cir]
mean_delay (optional) — Mean delay in [s] per CIR; [n_cir]
See also:
calc_rician_k_factor - Calculate the Rician K-Factor from channel impulse response data
- KF = LOS power / NLOS power; LOS paths are those with length ≤
dTR + window_size, where
dTR is the direct TX-RX distance
- If total NLOS power is zero, KF is set to infinity; if total LOS power is zero, KF is
set to 0
- TX/RX positions may be fixed
[3, 1] (reused for all snapshots) or mobile [3, n_cir]
Usage:
[ kf, pg ] = quadriga_lib.calc_rician_k_factor( powers, path_length, tx_pos, rx_pos, window_size );
Inputs:
powers — Path powers in [W]; [n_path, n_cir]
path_length — Absolute TX-to-RX path lengths; [n_path, n_cir]
tx_pos — Transmitter position [x; y; z]; [3, 1] (fixed) or [3, n_cir] (mobile)
rx_pos — Receiver position [x; y; z]; [3, 1] (fixed) or [3, n_cir] (mobile)
window_size (optional) — LOS window; paths with length ≤ dTR + window_size are
treated as LOS; default: 0.01
Outputs:
kf (optional) — Rician K-Factor on linear scale; [n_cir]
pg (optional) — Total path gain (sum of all path powers) in [W]; [n_cir]
Miscellaneous / Tools
calc_rotation_matrix - Calculates a 3x3 rotation matrix from a 3-element orientation vector
Description:
In linear algebra, a rotation matrix is a transformation matrix that is used to perform a rotation
in Euclidean space. The rotation of a rigid body (or three-dimensional coordinate system with a
fixed origin) is described by a single rotation about some axis. Such a rotation may be uniquely
described by three real-valued parameters. The idea behind Euler rotations is to split the complete
rotation of the coordinate system into three simpler constitutive rotation. This function calculates
the 3x3 rotation matrix
R from the intrinsic Euler angles.
Usage:
rotation = quadriga_lib.calc_rotation_matrix( orientation, invert_y_axis, transpose )
Example:
The following example obtains the 3x3 matrix R for a 45 degree rotation around the z-axis:
bank = 0;
tilt = 0;
heading = 45 * pi/180;
orientation = [ bank; tilt; heading ];
rotation = quadriga_lib.calc_rotation_matrix( orientation );
R = reshape( rotation, 3, 3 );
Input Arguments:
orientation
Euler angles (bank, tilt, head) in [rad]; Single or double precision, Size: [3, n_row, n_col]
invert_y_axis
Optional parameter. If set to 1, the rotation around the y-axis is inverted.
transpose
Optional parameter. If set to 1, the output is transposed.
Output Argument:
rotation
The rotation matrix, i.e. a transformation matrix that is used to perform a rotation in 3D
Euclidean space; Size: [9, n_row, n_col]
cart2geo - Convert elementwise Cartesian coordinates to azimuth/elevation angles and vector length
- Computes:
len = sqrt(x² + y² + z²), az = atan2(y, x), el = asin(clamp(z / len, -1, 1))
- Inputs are arbitrary 3D vectors (not required to be unit-length);
len returns the Euclidean norm
z/len is clamped to [-1, 1] before asin to guard against len == 0 and rounding artifacts
pushing abs(z/len) slightly above 1
- Option to provide a single
[3, n, m] cube or separate x, y, z [n, m] inputs
Usage:
[ az, el, len ] = quadriga_lib.cart2geo( x, y, z, use_kernel );
Inputs:
x — X-coordinates or combined input; [n, m] or [3, n, m]
y — Y-coordinates; [n, m] or empty
z — Z-coordinates; [n, m] or empty
use_kernel (optional) — Kernel selection: 0 = auto (AVX2 if available, else GENERIC),
1 = GENERIC, 2 = AVX2 (throws if AVX2 unavailable); default: 1
Outputs:
az — Azimuth angles in radians; [n, m]
el — Elevation angles in radians; [n, m]
len (optional) — Euclidean vector length sqrt(x² + y² + z²); [n, m]
fast_sincos - Fast, approximate sine/cosine for MATLAB numeric arrays
Description:
Computes elementwise sine and/or cosine for input angles in radians.
- Works on vectors, matrices, and 3-D arrays
- Accepts any numeric input class; best performance with single precision
- Outputs are always single precision
- Results are approximate and may differ from MATLAB
sin / cos
- For x in [-pi, pi], the maximum absolute error is 2^(-22.1), and larger otherwise
- For x in [-500, 500], the maximum absolute error is 2^(-16.0)
- Request one or two outputs to control which results are returned
- With one output, set the optional
cosineOnly flag to true to return cosine instead of sine
Usage:
[s, c] = arrayant_lib.fast_sincos(x);
s = arrayant_lib.fast_sincos(x);
c = arrayant_lib.fast_sincos(x, true);
Input Arguments:
x (input)
Numeric array of angles in radians. Any size/shape.
cosineOnly = false (optional input)
Logical scalar. When requesting a single output, set to true to return cos(x); otherwise returns
sin(x).
Output Arguments:
s
Single-precision sin(x). Same size as x.
c
Single-precision cos(x). Same size as x.
Examples:
% Input as single for best performance
x = single(linspace(0, 2*pi, 1000));
% Compute sine and cosine
[s, c] = arrayant_lib.fast_sincos(x);
% Compute only sine (single output)
s = arrayant_lib.fast_sincos(x);
% Compute only cosine (single output with flag)
c = arrayant_lib.fast_sincos(x, true);
% Double input is accepted; outputs remain single
xd = linspace(0, 2*pi, 8);
s_only = arrayant_lib.fast_sincos(xd); % class(s_only) == 'single'
c_only = arrayant_lib.fast_sincos(xd, true); % class(c_only) == 'single'
geo2cart - Convert elementwise azimuth/elevation angles to Cartesian coordinates
- Conversion:
x = cos(el) cos(az) len, y = cos(el) sin(az) len, z = sin(el) len
- Optional outputs
sAZ, cAZ, sEL, cEL return intermediate sin/cos values; omit from the
output list to skip their computation
- Defaults to the GENERIC kernel (
use_kernel=1) to preserve full double precision, matching
MATLAB's default numeric type
- Set
use_kernel=0 for auto-selection or use_kernel=2 to force AVX2; the AVX2 kernel
computes in single precision internally (inputs narrowed to float, results widened back)
Usage:
split = true;
[ x, y, z, sAZ, cAZ, sEL, cEL ] = quadriga_lib.fast_geo2cart( az, el, len, use_kernel, split );
split = false;
cart = quadriga_lib.fast_geo2cart( az, el, len, use_kernel, split );
Inputs:
az — Azimuth angles in radians; [n, m]
el — Elevation angles in radians; [n, m]
len (optional) — Euclidean vector length sqrt(x^2 + y^2 + z^2); [n, m]; default: 1
use_kernel (optional) — Kernel selection: 0 = auto (AVX2 if available, else GENERIC),
1 = GENERIC, 2 = AVX2 (throws if AVX2 unavailable); default: 1
split (optional) — If true, return x/y/z and optional sin/cos as separate [n, m]
matrices. If false, return a single combined [3, n, m] cube; sin/cos outputs unavailable
in this mode; default: false
Outputs:
x_or_cart — If split=true: X-coordinates [n, m]. If split=false: combined cube
with components along the first dim, [3, n, m]
y — Y-coordinates; [n, m] or empty
z — Z-coordinates; [n, m] or empty
sAZ (optional) — sin(az); [n, m] or empty
cAZ (optional) — cos(az); [n, m] or empty
sEL (optional) — sin(el); [n, m] or empty
cEL (optional) — cos(el); [n, m] or empty
interp - 2D and 1D linear interpolation.
Description:
This function implements 2D and 1D linear interpolation.
Usage:
dataI = quadriga_lib.interp( x, y, data, xI, yI ); % 2D case
dataI = quadriga_lib.interp( x, [], data, xI ); % 1D case
Input Arguments:
x
Vector of sample points in x direction for which data is provided; single or double; Length: [nx]
y
Vector of sample points in y direction for which data is provided; single or double; Length: [ny]
Must be an empty array [] in case of 1D interpolation.
data
The input data tensor; single or double; Size: [ny, nx, ne] or [1, nx, ne] for 1D case
The 3rd dimension enables interpolation for mutiple datasets simultaneously.
xI
Vector of sample points in x direction for which data should be interpolated; single or double;
Length: [nxI]
yI
Vector of sample points in y direction for which data should be interpolated; single or double;
Length: [nyI]
Output Arguments:
dataI
The interpolated dat; single or double (same as data);
Size: [nyI, nxI, ne] or [1, nxI, ne] for 1D case
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:
quadriga_lib.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:
[ gain, coord ] = quadriga_lib.calc_diffraction_gain( orig, dest, mesh, mtl_prop, ...
center_frequency, lod, verbose, sub_mesh_index, use_kernel, gpu_id );
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; [n_mesh, 1]
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
Outputs:
gain (optional) — Diffraction gain per TX-RX pair, linear scale; [n_pos, 1]
coord (optional) — Diffracted path coordinates excluding endpoints; [3, n_seg-1, n_pos]
See also:
generate_diffraction_paths - Generate elliptic propagation paths and weights for diffraction gain estimation
- Generates inputs required by quadriga_lib.calc_diffraction_gain: elliptic-arc paths sampling
the Fresnel ellipsoid volume between each TX-RX pair, plus per-segment weights
- Each ellipsoid has
n_path paths, each with n_seg segments; orig and dest lie on the
semi-major axis
- Weights are derived from the knife-edge diffraction model; initial weights normalized so
sum(prod(weights,3),2) = 1
Usage:
[ rays, weights ] = quadriga_lib.generate_diffraction_paths( orig, dest, center_frequency, lod );
Inputs:
orig — TX positions; [n_pos, 3]
dest — RX positions; [n_pos, 3]
center_frequency — Center frequency in Hz
lod — Level of detail; controls n_path and n_seg:
|
lod |
n_path |
n_seg |
Note |
|
1 |
7 |
3 |
- |
|
2 |
19 |
3 |
- |
|
3 |
37 |
4 |
- |
|
4 |
61 |
5 |
- |
|
5 |
1 |
2 |
debug |
|
6 |
2 |
2 |
debug |
Outputs:
rays — Coordinates of path waypoints (x, y, z stacked along the 4th dimension, endpoints
excluded); [n_pos, n_path, n_seg-1, 3]
weights (optional) — Per-segment weights; [n_pos, n_path, n_seg]
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:
[ center, length, vert, direction ] = quadriga_lib.icosphere( n_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 (optional) — Distance from origin to face plane; equals the magnitude of each
center vector; [n_faces]
vert (optional) — Vertex offsets from face center {x1,y1,z1,x2,y2,z2,x3,y3,z3}; [n_faces, 9]
direction (optional) — 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]
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 or 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:
[ mesh, mtl_prop, vert_list, face_ind, obj_ind, mtl_ind, obj_names, mtl_names, bsdf ] = ...
quadriga_lib.obj_file_read( fn );
% Use a custom material definition file
[ mesh, mtl_prop, vert_list, face_ind, obj_ind, mtl_ind, obj_names, mtl_names, bsdf ] = ...
quadriga_lib.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 (optional) — Triangle vertex coordinates as {X1,Y1,Z1,X2,Y2,Z2,X3,Y3,Z3} per row; [n_mesh, 9]
mtl_prop (optional) — Material properties; [n_mesh, 9]; Columns:
|
Index |
Symbol |
Property |
|
1 |
a |
ε_r at fRef |
|
2 |
b |
Frequency exponent for ε_r |
|
3 |
c |
σ at fRef [S/m] |
|
4 |
d |
Frequency exponent for σ |
|
5 |
att |
Penetration loss at fRef [dB] |
|
6 |
attB |
Frequency exponent for att |
|
7 |
alpha |
Distance absorption at fRef [dB/m] |
|
8 |
alphaB |
Frequency exponent for alpha |
|
9 |
fRef |
Reference frequency [GHz] |
vert_list (optional) — All vertex positions in the file; [n_vert, 3]
face_ind (optional) — 1-based indices into vert_list per triangle; uint64; [n_mesh, 3]
obj_ind (optional) — 1-based object index per triangle; uint64; [n_mesh]
mtl_ind (optional) — 1-based material index per triangle; uint64; [n_mesh]
obj_names (optional) — Object names; cell array of strings; length = max(obj_ind)
mtl_names (optional) — Material names; cell array of strings; length = max(mtl_ind)
bsdf (optional) — Principled BSDF values from the .mtl file; [n_mtl, 17]; columns:
|
Index |
Property |
Range |
Default |
|
1 |
Base Color Red |
0–1 |
0.8 |
|
2 |
Base Color Green |
0–1 |
0.8 |
|
3 |
Base Color Blue |
0–1 |
0.8 |
|
4 |
Transparency (alpha) |
0–1 |
1.0 |
|
5 |
Roughness |
0–1 |
0.5 |
|
6 |
Metallic |
0–1 |
0.0 |
|
7 |
Index of refraction (IOR) |
0–4 |
1.45 |
|
8 |
Specular IOR adjustment |
0–1 |
0.5 |
|
9 |
Emission Red |
0–1 |
0.0 |
|
10 |
Emission Green |
0–1 |
0.0 |
|
11 |
Emission Blue |
0–1 |
0.0 |
|
12 |
Sheen |
0–1 |
0.0 |
|
13 |
Clearcoat |
0–1 |
0.0 |
|
14 |
Clearcoat roughness |
0–1 |
0.0 |
|
15 |
Anisotropic |
0–1 |
0.0 |
|
16 |
Anisotropic rotation |
0–1 |
0.0 |
|
17 |
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 |
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.point_cloud_aabb( points, sub_cloud_index, vec_size );
Inputs:
points — 3D point coordinates; [n_points, 3]
sub_cloud_index (optional) — 1-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
Outputs:
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:
[ pointsR, sub_cloud_index, forward_index, reverse_index ] = ...
quadriga_lib.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:
pointsR — Reorganized point cloud with points grouped by sub-cloud; [n_pointsR, 3]
sub_cloud_index — 1-based starting index of each sub-cloud within pointsR; [n_sub]
forward_index (optional) — 1-based index map from points to pointsR; padding
entries are 0; [n_pointsR]
reverse_index (optional) — 1-based index map from pointsR back to points;
[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.point_inside_mesh( points, mesh, obj_ind, distance );
Inputs:
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:
result— Indicator: 0 = outside, 1 = inside any object (no obj_ind), or 1-based object
index (with obj_ind); size [n_points]
ray_mesh_interact - Calculates reflection, transmission, or refraction of EM/acoustic waves at mesh surfaces
Description:
- Computes interaction of plane waves with planar interfaces between homogeneous isotropic media
- Supports beam-based modeling via triangular ray tubes (
trivec, tridir)
- Face side determined by vertex order; CCW winding = front, CW = back (right-hand rule);
front-side hit with FBS≠SBS → air-to-media; back-side hit with FBS≠SBS → media-to-air;
FBS=SBS with opposing normals → media-to-media
- Rays with
fbs_ind = 0 (no interaction) are omitted from output, so n_rayN ≤ n_ray
- Output direction encoding (spherical/Cartesian) matches input
tridir format
- Overlapping mesh geometry must be avoided (materials are transparent to radio waves)
- Types 3–4 (scalar) use TE-only reflection with no total internal reflection, suitable for
acoustic simulation with impedance-mapped material parameters (ε derived from Z)
Usage:
[ origN, destN, gainN, xprmatN, trivecN, tridirN, orig_lengthN, fbs_angleN, thicknessN, edge_lengthN, ...
normal_vecN, out_typeN ] = quadriga_lib.ray_mesh_interact( interaction_type, center_frequency, ...
orig, dest, fbs, sbs, mesh, mtl_prop, fbs_ind, sbs_ind, trivec, tridir, orig_length );
Inputs:
interaction_type — 0 = EM reflection, 1 = EM transmission, 2 = EM refraction, 3 = scalar reflection, 4 = scalar transmission
center_frequency — Center frequency
orig, dest — Ray origin and destination in GCS; [n_ray, 3]
fbs, sbs — First/second interaction points in GCS; [n_ray, 3]
mesh — Triangle mesh faces; see obj_file_read; [n_mesh, 9]
mtl_prop — Material properties; see obj_file_read; [n_mesh, 9]
fbs_ind, sbs_ind — 1-based mesh face indices per ray (0 = no hit); uint32; [n_ray]
trivec (optional) — Beam wavefront triangle vertices relative to origin;
order [v1x v1y v1z v2x v2y v2z v3x v3y v3z]; [n_ray, 9]
tridir (optional) — Vertex-ray directions; [n_ray, 6] for spherical
[v1az v1el v2az v2el v3az v3el] or [n_ray, 9] for Cartesian
orig_length (optional) — Accumulated path length at origin; default: 0; [n_ray]
Outputs:
origN — New origins after interaction (offset 0.001 m along travel direction); [n_rayN, 3]
destN — New destinations accounting for direction change; [n_rayN, 3]
gainN — Interaction gain (linear, includes in-medium attenuation, excludes FSPL);
averaged over TE/TM polarizations for types 0–2, TE-only for types 3–4; [n_rayN]
xprmatN — For types 0–2: polarization transfer matrix, interleaved complex
[ReVV ImVV ReVH ImVH ReHV ImHV ReHH ImHH]; for types 3–4 (scalar):
[Re Im 0 0 0 0 0 0] where Re+jIm is the scalar pressure coefficient; includes
interaction gain, TE/TM coefficients, incidence plane orientation, in-medium
attenuation (excludes FSPL); [n_rayN, 8]
trivecN, tridirN — Updated beam geometry/direction (format matches input);
empty if trivec/tridir not provided
orig_lengthN — Path length from orig to origN, added to input orig_length if given; [n_rayN]
fbs_angleN — Incidence angle at FBS; [n_rayN]
thicknessN — Material thickness (FBS-to-SBS distance); [n_rayN]
edge_lengthN — Max edge length of ray tube triangle at new origin (Inf if partial hit); [n_rayN]
normal_vecN — FBS and SBS normal vectors [Nx_F Ny_F Nz_F Nx_S Ny_S Nz_S]; [n_rayN, 6]
out_typeN — Interaction type code (int32); [n_rayN]
|
Code |
Description |
|
1 |
Single hit, outside→inside |
|
2 |
Single hit, inside→outside |
|
3 |
Single hit, inside→outside, total reflection |
|
4 |
Media-to-media, M2 hit first |
|
5 |
Media-to-media, M1 hit first |
|
6 |
Media-to-media, M1 hit first, total reflection |
|
7 |
Overlapping faces, outside→inside |
|
8 |
Overlapping faces, inside→outside |
|
9 |
Overlapping faces, inside→outside, total reflection |
|
10 |
Edge hit, outside→inside→outside |
|
11 |
Edge hit, inside→outside→inside |
|
12 |
Edge hit, inside→outside→inside, total reflection |
|
13 |
Edge hit, outside→inside |
|
14 |
Edge hit, inside→outside |
|
15 |
Edge hit, inside→outside, total reflection |
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.ray_point_intersect( orig, trivec, tridir, points, ...
sub_cloud_index, 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) — 1-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; [n_points, 1]
ray_ind — Per-point list of 1-based ray indices that intersected that point; zero-padded to
a regular 2D array (zero entries indicate unused slots); uint32; [max_hits, n_points]
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:
[ fbs, sbs, no_interact, fbs_ind, sbs_ind ] = quadriga_lib.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; 1-based; [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:
subdivide_triangles - Subdivide triangles into smaller triangles
- Uniformly subdivides each input triangle into
n_div x n_div smaller triangles
- Output count:
n_triangles_out = n_triangles_in · n_div · n_div
- Material properties are duplicated from parent triangle to all sub-triangles
Usage:
[ triangles_out, mtl_prop_out ] = quadriga_lib.subdivide_triangles( triangles_in, n_div, mtl_prop_in );
Inputs:
triangles_in — Mesh vertices as [ v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z ]; [n_triangles_in, 9]
n_div — Number of subdivisions per edge
mtl_prop (optional) — Material properties; see obj_file_read; [n_triangles_in, 9]
Outputs:
triangles_out — Subdivided mesh vertices, same column layout as triangles_in; [n_triangles_out, 9]
mtl_prop_out (optional) — Material properties for subdivided triangles; [n_triangles_out, 9]
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.triangle_mesh_aabb( mesh, sub_mesh_index, vec_size );
Inputs:
mesh — 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_in is provided, material rows are reordered and padded in the same way
Usage:
[ triangles_out, sub_mesh_index, mesh_index, mtl_prop_out ] = ...
quadriga_lib.triangle_mesh_segmentation( triangles_in, target_size, vec_size, mtl_prop_in );
Inputs:
triangles_in — 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_in (optional) — Material properties; see obj_file_read; [n_mesh, 9]
Outputs:
triangles_out — Reordered and padded triangle vertices; [n_meshR, 9]
sub_mesh_index — 1-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_meshR]
mtl_prop_out — Reordered and padded material properties; [n_meshR, 9]