OFDMChannel#

class sionna.phy.channel.OFDMChannel(channel_model: sionna.phy.channel.channel_model.ChannelModel, resource_grid: sionna.phy.ofdm.resource_grid.ResourceGrid, normalize_channel: bool = False, return_channel: bool = False, precision: Literal['single', 'double'] | None = None, device: str | None = None, **kwargs)[source]#

Bases: sionna.phy.block.Block

Generate channel frequency responses and apply them to channel inputs assuming an OFDM waveform with no ICI nor ISI

For each OFDM symbol \(s\) and subcarrier \(n\), the channel output is computed as follows:

\[y_{s,n} = \widehat{h}_{s, n} x_{s,n} + w_{s,n}\]

where \(y_{s,n}\) is the channel output computed by this layer, \(\widehat{h}_{s, n}\) the frequency channel response, \(x_{s,n}\) the channel input x, and \(w_{s,n}\) the additive noise.

For multiple-input multiple-output (MIMO) links, the channel output is computed for each antenna of each receiver and by summing over all the antennas of all transmitters.

The channel frequency response for the \(s^{th}\) OFDM symbol and \(n^{th}\) subcarrier is computed from a given channel impulse response \((a_{m}(t), \tau_{m}), 0 \leq m \leq M-1\) generated by the channel_model as follows:

\[\widehat{h}_{s, n} = \sum_{m=0}^{M-1} a_{m}(s) e^{-j2\pi n \Delta_f \tau_{m}}\]

where \(\Delta_f\) is the subcarrier spacing, and \(s\) is used as time step to indicate that the channel impulse response can change from one OFDM symbol to the next in the event of mobility, even if it is assumed static over the duration of an OFDM symbol.

Parameters:
  • channel_model (sionna.phy.channel.channel_model.ChannelModel) – Channel model to be used. Must be callable with signature (batch_size, num_time_steps, sampling_frequency) -> (h, tau).

  • resource_grid (sionna.phy.ofdm.resource_grid.ResourceGrid) – Resource grid object. Must have properties: num_ofdm_symbols, subcarrier_spacing, fft_size, and ofdm_symbol_duration.

  • normalize_channel (bool) – If set to True, the channel is normalized over the resource grid to ensure unit average energy per resource element. Defaults to False.

  • return_channel (bool) – If set to True, the channel response is returned in addition to the channel output. Defaults to False.

  • precision (Literal['single', 'double'] | None) – Precision used for internal calculations and outputs. If set to None, precision is used.

  • device (str | None) – Device for computation (e.g., ‘cpu’, ‘cuda:0’). If None, device is used.

Inputs:
  • x – [batch size, num_tx, num_tx_ant, num_ofdm_symbols, fft_size], torch.complex. Channel inputs.

  • noNone (default) | Tensor, torch.float. Tensor whose shape can be broadcast to the shape of the channel outputs: [batch size, num_rx, num_rx_ant, num_ofdm_symbols, fft_size]. The (optional) noise power no is per complex dimension. If no is a scalar, noise of the same variance will be added to the outputs. If no is a tensor, it must have a shape that can be broadcast to the shape of the channel outputs. This allows, e.g., adding noise of different variance to each example in a batch. If no has a lower rank than the channel outputs, then no will be broadcast to the shape of the channel outputs by adding dummy dimensions after the last axis.

Outputs:
  • y – [batch size, num_rx, num_rx_ant, num_ofdm_symbols, fft_size], torch.complex. Channel outputs.

  • h_freq – [batch size, num_rx, num_rx_ant, num_tx, num_tx_ant, num_ofdm_symbols, fft_size], torch.complex. (Optional) Channel frequency responses. Returned only if return_channel is set to True.

Examples

import torch
from sionna.phy.channel import OFDMChannel, RayleighBlockFading

# Create a simple resource grid-like object
class SimpleResourceGrid:
    num_ofdm_symbols = 14
    fft_size = 64
    subcarrier_spacing = 15e3
    cyclic_prefix_length = 4

    @property
    def ofdm_symbol_duration(self):
        return (1 + self.cyclic_prefix_length / self.fft_size) / self.subcarrier_spacing

rg = SimpleResourceGrid()
channel_model = RayleighBlockFading(num_rx=1, num_rx_ant=2, num_tx=1, num_tx_ant=4)
ofdm_channel = OFDMChannel(channel_model, rg, return_channel=True)

x = torch.randn(32, 1, 4, 14, 64, dtype=torch.complex64)
y, h_freq = ofdm_channel(x)
print(y.shape)
# torch.Size([32, 1, 2, 14, 64])
print(h_freq.shape)
# torch.Size([32, 1, 2, 1, 4, 14, 64])

Attributes

property generate: sionna.phy.channel.generate_ofdm_channel.GenerateOFDMChannel#

Access the internal GenerateOFDMChannel

property apply: sionna.phy.channel.apply_ofdm_channel.ApplyOFDMChannel#

Access the internal ApplyOFDMChannel