Skip to content

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

update

update(other)

Update the dictionary with elements from another dictionary.

keys

keys()

Return dictionary keys.

values

values()

Return dictionary values.

items

items()

Return dictionary items as (key, value) pairs.

get

get(key, default=None)

Get value for key, returning default if key doesn't exist.

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.

tx_pattern_fn instance-attribute

tx_pattern_fn = _load_pattern(tx_pattern, 'TX')

rx_pattern_fn instance-attribute

rx_pattern_fn = _load_pattern(rx_pattern, 'RX')

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