Source code for sionna.phy.channel.generate_time_channel

#
# SPDX-FileCopyrightText: Copyright (c) 2021-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
"""Class for generating channel responses in the time domain"""

from typing import Optional

import torch

from sionna.phy.object import Object
from sionna.phy.channel.utils import cir_to_time_channel

__all__ = ["GenerateTimeChannel"]


[docs] class GenerateTimeChannel(Object): # pylint: disable=line-too-long r""" Generate channel responses in the time domain For each batch example, ``num_time_samples`` + ``l_max`` - ``l_min`` time steps of a channel realization are generated by this layer. These can be used to filter a channel input of length ``num_time_samples`` using the :class:`~sionna.phy.channel.ApplyTimeChannel` layer. The channel taps :math:`\bar{h}_{b,\ell}` (``h_time``) returned by this layer are computed assuming a sinc filter is used for pulse shaping and receive filtering. Therefore, given a channel impulse response :math:`(a_{m}(t), \tau_{m}), 0 \leq m \leq M-1`, generated by the ``channel_model``, the channel taps are computed as follows: .. math:: \bar{h}_{b, \ell} = \sum_{m=0}^{M-1} a_{m}\left(\frac{b}{W}\right) \text{sinc}\left( \ell - W\tau_{m} \right) for :math:`\ell` ranging from ``l_min`` to ``l_max``, and where :math:`W` is the ``bandwidth``. :param channel_model: Channel model to be used :param bandwidth: Bandwidth (:math:`W`) [Hz] :param num_time_samples: Number of time samples forming the channel input (:math:`N_B`) :param l_min: Smallest time-lag for the discrete complex baseband channel (:math:`L_{\text{min}}`) :param l_max: Largest time-lag for the discrete complex baseband channel (:math:`L_{\text{max}}`) :param normalize_channel: If set to `True`, the channel is normalized over the block size to ensure unit average energy per time step. Defaults to `False`. :param precision: Precision used for internal calculations and outputs. If set to `None`, :attr:`~sionna.phy.config.Config.precision` is used. :param device: Device for computation. If `None`, :attr:`~sionna.phy.config.Config.device` is used. :input batch_size: `None` (default) | `int`. Batch size. Defaults to `None` for channel models that do not require this parameter. :output h_time: [batch size, num_rx, num_rx_ant, num_tx, num_tx_ant, num_time_samples + l_max - l_min, l_max - l_min + 1], `torch.complex`. Channel responses. For each batch example, ``num_time_samples`` + ``l_max`` - ``l_min`` time steps of a channel realization are generated by this layer. These can be used to filter a channel input of length ``num_time_samples`` using the :class:`~sionna.phy.channel.ApplyTimeChannel` layer. .. rubric:: Examples .. code-block:: python import torch from sionna.phy.channel import RayleighBlockFading, GenerateTimeChannel channel_model = RayleighBlockFading(num_rx=1, num_rx_ant=2, num_tx=1, num_tx_ant=4) gen_channel = GenerateTimeChannel( channel_model, bandwidth=1e6, num_time_samples=100, l_min=-6, l_max=20 ) h_time = gen_channel(batch_size=32) print(h_time.shape) # torch.Size([32, 1, 2, 1, 4, 126, 27]) """ def __init__( self, channel_model, bandwidth: float, num_time_samples: int, l_min: int, l_max: int, normalize_channel: bool = False, precision: Optional[str] = None, device: Optional[str] = None, **kwargs, ) -> None: super().__init__(precision=precision, device=device, **kwargs) self._cir_sampler = channel_model self._l_min = l_min self._l_max = l_max self._l_tot = l_max - l_min + 1 self._bandwidth = bandwidth self._num_time_steps = num_time_samples self._normalize_channel = normalize_channel @property def l_min(self) -> int: """Smallest time-lag""" return self._l_min @property def l_max(self) -> int: """Largest time-lag""" return self._l_max @property def l_tot(self) -> int: """Total number of channel taps""" return self._l_tot @property def bandwidth(self) -> float: """Bandwidth [Hz]""" return self._bandwidth @property def num_time_samples(self) -> int: """Number of time samples""" return self._num_time_steps def __call__(self, batch_size: Optional[int] = None) -> torch.Tensor: """Generate time domain channel response. :param batch_size: Batch size. Defaults to `None` for channel models that do not require this parameter. :output h_time: Channel taps coefficients """ # Sample channel impulse responses h, tau = self._cir_sampler( batch_size, self._num_time_steps + self._l_tot - 1, self._bandwidth ) # Convert CIR to time domain channel h_time = cir_to_time_channel( self._bandwidth, h, tau, self._l_min, self._l_max, self._normalize_channel ) return h_time