Generator¶
The generator module handles MIMO channel generation from ray tracing data. This module computes channel matrices from geometric ray paths and antenna array configurations.
Below is an ascii diagram of how the simulations from the ray tracers are converted into DeepMIMO scenarios (by the converter module, following the DeepMIMO SPEC), and then loaded and used to generate channels.
┌───────────────────┐ ┌────────────────┐ ┌────────────────┐
│ WIRELESS INSITE │ ──▶ │ SIONNA_RT │ ──▶ │ AODT │
└─────────┬─────────┘ └───────┬────────┘ └───────┬────────┘
│ │ │
└──────────────┬────────┴──────────────┬───────┘
▼ ▼
┌───────────────┐ ┌───────────────┐
│ dm.convert() │ │ dm.convert() │
└──────┬────────┘ └──────┬────────┘
│ │
└──────────────┬────────┘
▼
┌────────────────┐
│ DEEPMIMO │
│ SCENARIOS │
└──────┬─────────┘
▼
┌────────────────────────┐
│ dataset = dm.load() │
└──────────┬─────────────┘
▼
┌──────────────────────────────┐
│ dataset.compute_channels() │
└──────────────┬───────────────┘
▼
┌────────────────┐
│ dataset.plot()│
└────────────────┘
DeepMIMO Package Structure:
deepmimo/
├── core/ (Data models: Scene, Materials, RayTracingParameters, TxRxSet)
├── datasets/ (Dataset classes, load/generate, visualization, sampling)
├── generator/ (Channel computation)
│ ├── channel.py (MIMO channel generation)
│ ├── geometry.py (Antenna array functions)
│ └── ant_patterns.py (Antenna patterns)
├── api/ (Database operations: download, upload, search)
├── utils/ (Utilities: I/O, scenarios, geometry)
└── integrations/ (Export to other simulators)
Channel Parameters¶
The ChannelParameters class manages parameters for MIMO channel generation.
import deepmimo as dm
# Load a scenario
dataset = dm.load('asu_campus_3p5')
# Instantiate channel parameters
params = dm.ChannelParameters()
# Configure BS antenna array
params.bs_antenna.shape = [8, 1] # 8x1 array
params.bs_antenna.spacing = 0.5 # Half-wavelength spacing
params.bs_antenna.rotation = [0, 0, 0] # No rotation
# Configure UE antenna array
params.ue_antenna.shape = [1, 1] # Single antenna
params.ue_antenna.spacing = 0.5
params.ue_antenna.rotation = [0, 0, 0]
# Configure OFDM parameters
params.ofdm.subcarriers = 512 # Number of subcarriers
params.ofdm.bandwidth = 10e6 # 10 MHz bandwidth
params.ofdm.selected_subcarriers = [0] # Which subcarriers to generate
# Generate frequency-domain channels
params.doppler = False
params.freq_domain = True
channels = dataset.compute_channels(params)
Channel generation examples
See the Channel Generation section of the DeepMIMO Manual for more examples.
| Parameter | Default Value | Description |
|---|---|---|
bs_antenna.shape |
[8, 1] | BS antenna array dimensions (horizontal, vertical) |
bs_antenna.spacing |
0.5 | BS antenna spacing (wavelengths) |
bs_antenna.rotation |
[0, 0, 0] | BS rotation angles (degrees around x,y,z) |
ue_antenna.shape |
[1, 1] | UE antenna array dimensions (horizontal, vertical) |
ue_antenna.spacing |
0.5 | UE antenna spacing (wavelengths) |
ue_antenna.rotation |
[0, 0, 0] | UE rotation angles (degrees around x,y,z) |
ofdm.subcarriers |
512 | Number of OFDM subcarriers |
ofdm.selected_subcarriers |
512 | Indices of selected OFDM subcarriers |
ofdm.bandwidth |
10e6 | OFDM bandwidth (Hz) |
freq_domain |
True | Boolean for generating the channel in frequency (OFDM) |
doppler |
False | Boolean for adding Doppler frequency shifts to the channel |
Note 1: Rotation angles follow the right-hand rule. Note 2: The default orientation of an antenna panel is along the +X axis.
Bases: DotDict
Class for managing channel generation parameters.
This class provides an interface for setting and accessing various parameters needed for MIMO channel generation, including: - BS/UE antenna array configurations - OFDM parameters - Channel domain settings (time/frequency)
The parameters can be accessed directly using dot notation (e.g. params.bs_antenna.shape)
or using dictionary notation (e.g. params['bs_antenna']['shape']).
Examples:
Default parameters
params = ChannelParameters()
Specific parameters
params = ChannelParameters(doppler=True, freq_domain=True)
Nested parameters (lists are converted to numpy arrays during validation)
params = ChannelParameters(bs_antenna={"shape": [4, 4]})
Initialize channel generation parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict | None
|
Optional dictionary containing channel parameters to override defaults |
None
|
**kwargs
|
Any
|
Additional parameters to override defaults. These will be merged with data if provided. For nested parameters, provide as dicts (e.g. bs_antenna={'shape': [4,4]}). Only specified fields are overridden; other fields keep default values. Lists are converted to numpy arrays during validation. |
{}
|
DEFAULT_PARAMS
class-attribute
¶
DEFAULT_PARAMS = {
PARAMSET_ANT_BS: {
PARAMSET_ANT_SHAPE: array([8, 1]),
PARAMSET_ANT_SPACING: 0.5,
PARAMSET_ANT_ROTATION: array([0, 0, 0]),
PARAMSET_ANT_RAD_PAT: PARAMSET_ANT_RAD_PAT_VALS[0],
},
PARAMSET_ANT_UE: {
PARAMSET_ANT_SHAPE: array([1, 1]),
PARAMSET_ANT_SPACING: 0.5,
PARAMSET_ANT_ROTATION: array([0, 0, 0]),
PARAMSET_ANT_RAD_PAT: PARAMSET_ANT_RAD_PAT_VALS[0],
},
PARAMSET_DOPPLER_EN: 0,
PARAMSET_NUM_PATHS: MAX_PATHS,
PARAMSET_FD_CH: 1,
PARAMSET_OFDM: {
PARAMSET_OFDM_SC_NUM: 512,
PARAMSET_OFDM_SC_SAMP: arange(1),
PARAMSET_OFDM_BANDWIDTH: 10000000.0,
PARAMSET_OFDM_LPF: 0,
},
}
validate ¶
validate(n_ues)
Validate channel generation parameters.
This method checks that channel generation parameters are valid and consistent with the dataset configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_ues
|
int
|
Number of UEs to validate against |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ChannelParameters |
ChannelParameters
|
Self for method chaining |
Raises:
| Type | Description |
|---|---|
ValueError
|
If parameters are invalid or inconsistent |
hasattr ¶
hasattr(key)
Safely check if a key exists in the dictionary.
This method provides a safe way to check for attribute existence without raising KeyError, similar to Python's built-in hasattr().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The key to check for |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the key exists, False otherwise |
to_dict ¶
to_dict()
Convert DotDict back to a regular dictionary.
Returns:
| Name | Type | Description |
|---|---|---|
dict |
dict
|
Regular dictionary representation |
deepcopy ¶
deepcopy()
Create a deep copy of the DotDict instance.
This method creates a completely independent copy of the DotDict, including nested dictionaries and numpy arrays. This ensures that modifications to the copy won't affect the original.
Returns:
| Name | Type | Description |
|---|---|---|
DotDict |
DotDict
|
A deep copy of this instance |
Compute MIMO channel matrices with Doppler over an explicit time axis.
If times is None and num_timestamps is None -> single snapshot at t=0 (squeezed 4-D).
If times is a scalar or 1D array -> uses it directly (seconds).
If num_timestamps is provided (and times is None)
-> builds times from OFDM symbol spacing.
Returns:
| Name | Type | Description |
|---|---|---|
ndarray
|
If freq_domain: |
|
ndarray
|
[n_users, n_rx_ant, n_tx_ant, n_subcarriers] (single t) or |
|
ndarray
|
[n_users, n_rx_ant, n_tx_ant, n_subcarriers, N_t] (multi t) |
|
Else |
ndarray
|
|
ndarray
|
[n_users, n_rx_ant, n_tx_ant, n_paths] (single t) or |
|
ndarray
|
[n_users, n_rx_ant, n_tx_ant, n_paths, N_t] (multi t) |
Compute Channels¶
Once a dataset is loaded, channels can be computed using the compute_channels() method:
import deepmimo as dm
# Load dataset
dataset = dm.load('asu_campus_3p5')
# Configure channel parameters
params = dm.ChannelParameters()
params.bs_antenna.shape = [8, 1]
params.ue_antenna.shape = [1, 1]
# Compute channels
channels = dataset.compute_channels(params)
Compute MIMO channel matrices with Doppler over an explicit time axis.
If times is None and num_timestamps is None -> single snapshot at t=0 (squeezed 4-D).
If times is a scalar or 1D array -> uses it directly (seconds).
If num_timestamps is provided (and times is None)
-> builds times from OFDM symbol spacing.
Returns:
| Name | Type | Description |
|---|---|---|
ndarray
|
If freq_domain: |
|
ndarray
|
[n_users, n_rx_ant, n_tx_ant, n_subcarriers] (single t) or |
|
ndarray
|
[n_users, n_rx_ant, n_tx_ant, n_subcarriers, N_t] (multi t) |
|
Else |
ndarray
|
|
ndarray
|
[n_users, n_rx_ant, n_tx_ant, n_paths] (single t) or |
|
ndarray
|
[n_users, n_rx_ant, n_tx_ant, n_paths, N_t] (multi t) |
Doppler¶
Doppler effects can be added to the generated channels (in time or frequency domain) in three different ways: - Set Doppler directly: Manually set the Doppler frequencies per user (and optionally, per path) - Set Speeds directly: Manually set the TX, RX or object speeds, which automatically computes Doppler frequencies - Set Time Reference: Automatically compute TX, RX and object speeds across scenes (only works with Dynamic Datasets)
Note
To add Doppler to the channel, set doppler=True in the channel parameters.
For more details about working with datasets and its methods, see the Datasets API.
Set Doppler¶
You can directly specify Doppler shifts in three ways:
# Same Doppler shift for all users
dopplers1 = 10 # [Hz]
dataset.set_doppler(dopplers1)
dataset.compute_channels(dm.ChannelParameters(doppler=True))
# Different Doppler shift for different users
dopplers2 = np.random.randint(20, 51, size=(dataset.n_ue,))
dataset.set_doppler(dopplers2)
dataset.compute_channels(dm.ChannelParameters(doppler=True))
# Different Doppler shift for different users and paths
dopplers3 = np.random.randint(20, 51, size=(dataset.n_ue, dataset.max_paths))
dataset.set_doppler(dopplers3)
dataset.compute_channels(dm.ChannelParameters(doppler=True))
Set Velocities¶
You can set velocities for receivers, transmitters, and objects in the scene. This will in turn add doppler to the paths that interact with those entities:
# Set rx velocities manually (same for all users)
dataset.rx_vel = [5, 0, 0] # (x, y, z) [m/s]
# Set rx velocities manually (different per users)
min_speed, max_speed = 0, 10
random_velocities = np.zeros((dataset.n_ue, 3))
random_velocities[:, :2] = np.random.uniform(min_speed, max_speed, size=(dataset.n_ue, 2))
dataset.rx_vel = random_velocities # Note: z = 0 assumes users at ground level
# Set tx velocities manually
dataset.tx_vel = [0, 0, 0]
# Set object velocities manually
dataset.set_obj_vel(obj_idx=[1, 3, 6], vel=[[0, 5, 0], [0, 5, 6], [0, 0, 3]])
# Note: object indices should match the indices/ids in dataset.scene.objects
dataset.compute_channels(dm.ChannelParameters(doppler=True))
Set Timestamps¶
For Dynamic Datasets (i.e. multi-scene datasets), setting timestamps will automatically compute velocities for the receivers, transmitters or objects that move across scenes:
# Uniform snapshots
dataset.set_timestamps(10) # seconds between scenes
# Non-uniform snapshots
times = [0, 1.5, 2.3, 4.4, 5.8, 7.1, 8.9, 10.2, 11.7, 13.0]
dataset.set_timestamps(times) # timestamps of each scene
After setting timestamps, you can access the computed velocities:
print(f'timestamps: {dataset.timestamps}')
print(f'rx_vel: {dataset.rx_vel}')
print(f'tx_vel: {dataset.tx_vel}')
print(f'obj_vel: {[obj.vel for obj in dataset.scene.objects]}')
Note
Setting timestamps requires a Dynamic Dataset. Provide a folder containing one subfolder per scene (ray-tracing results per snapshot). See the Datasets API for more information.
Antenna Patterns¶
The generator module supports custom antenna patterns for more realistic channel modeling.
Class for handling antenna radiation patterns.
This class manages the radiation patterns for both TX and RX antennas, providing a unified interface for pattern application in signal power calculations.
Attributes:
| Name | Type | Description |
|---|---|---|
tx_pattern_fn |
Optional[Callable]
|
Function implementing TX antenna pattern. |
rx_pattern_fn |
Optional[Callable]
|
Function implementing RX antenna pattern. |
Initialize antenna patterns for transmitter and receiver.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tx_pattern
|
str
|
Transmitter antenna pattern type from PARAMSET_ANT_RAD_PAT_VALS. |
required |
rx_pattern
|
str
|
Receiver antenna pattern type from PARAMSET_ANT_RAD_PAT_VALS. |
required |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If specified pattern type is not supported. |
apply ¶
apply(power, aoa_theta, aoa_phi, aod_theta, aod_phi)
Apply antenna patterns to input power.
This function applies both TX and RX antenna patterns to modify the input power values based on arrival and departure angles.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
power
|
ndarray
|
Input power values. |
required |
aoa_theta
|
ndarray
|
Angle of arrival theta angles in radians. |
required |
aoa_phi
|
ndarray
|
Angle of arrival phi angles in radians. |
required |
aod_theta
|
ndarray
|
Angle of departure theta angles in radians. |
required |
aod_phi
|
ndarray
|
Angle of departure phi angles in radians. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: Modified power values after applying antenna patterns. |
apply_batch ¶
apply_batch(power, aoa_theta, aoa_phi, aod_theta, aod_phi)
Apply antenna patterns to powers in batch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
power
|
ndarray
|
Powers array with shape (n_users, n_paths) |
required |
aoa_theta
|
ndarray
|
Angle of arrival elevation angles (n_users, n_paths) |
required |
aoa_phi
|
ndarray
|
Angle of arrival azimuth angles (n_users, n_paths) |
required |
aod_theta
|
ndarray
|
Angle of departure elevation angles (n_users, n_paths) |
required |
aod_phi
|
ndarray
|
Angle of departure azimuth angles (n_users, n_paths) |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: Modified powers with antenna patterns applied (n_users, n_paths) |
Geometry Functions¶
Geometric functions for beamforming and array processing:
import deepmimo as dm
# Generate steering vector
steering_vector = dm.steering_vec(
array_shape=[8, 1],
angles=[45, 30], # [azimuth, elevation]
spacing=0.5
)
Calculate the steering vector for an antenna array.
This function computes the normalized array response vector for a given array geometry and steering direction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array
|
NDArray
|
Array of antenna positions |
required |
phi
|
float
|
Azimuth angle in degrees. (0°=+x, 90°=+y) Defaults to 0. |
0
|
theta
|
float
|
Elevation angle in degrees. (0°=xy-plane, 90°=+z) Defaults to 0. |
0
|
spacing
|
float
|
Antenna spacing in wavelengths. Defaults to 0.5. |
0.5
|
Returns:
| Name | Type | Description |
|---|---|---|
NDArray |
NDArray
|
Complex normalized steering (array response) vector |