Source code for hermespy.channel.fading.tdl

# -*- coding: utf-8 -*-

from __future__ import annotations

import numpy as np

from hermespy.core import SerializableEnum
from .fading import MultipathFadingChannel

__author__ = "Tobias Kronauer"
__copyright__ = "Copyright 2024, Barkhausen Institut gGmbH"
__credits__ = ["Tobias Kronauer", "Jan Adler"]
__license__ = "AGPLv3"
__version__ = "1.3.0"
__maintainer__ = "Jan Adler"
__email__ = "jan.adler@barkhauseninstitut.org"
__status__ = "Prototype"


[docs] class TDLType(SerializableEnum): """Supported model types of the 5G TDL channel model""" A = 0 B = 1 C = 2 D = 4 E = 5
[docs] class TDL(MultipathFadingChannel): """5G TDL Multipath Fading Channel models.""" yaml_tag = "5GTDL" __rms_delay: float def __init__( self, model_type: TDLType = TDLType.A, rms_delay: float = 0.0, gain: float = 1.0, doppler_frequency: float | None = None, los_doppler_frequency: float | None = None, **kwargs, ) -> None: """ Args: model_type (TYPE): The model type. Initializes the :attr:`model_type` attribute. rms_delay (float): Root-Mean-Squared delay in seconds. Initializes the :attr:`rms_delay` attribute. alpha_device (SimulatedDevice, optional): First device linked by this :class:`MultipathFading5GTDL` channel instance. Initializes the :attr:`alpha_device` property. If not specified the channel is considered floating, meaning a call to :meth:`realize<Channel.realize>` will raise an exception. beta_device (SimulatedDevice, optional): Second device linked by this :class:`MultipathFading5GTDL` channel. Initializes the :attr:`beta_device` property. If not specified the channel is considered floating, meaning a call to :meth:`realize` will raise an exception. num_sinusoids (int, optional): Number of sinusoids used to sample the statistical distribution. doppler_frequency (float, optional) Doppler frequency shift of the statistical distribution. \***kwargs (Any): Additional `MultipathFadingChannel` initialization parameters. Raises: ValueError: If `rms_delay` is smaller than zero. ValueError: If `los_angle` is specified in combination with `model_type` D or E. """ if rms_delay < 0.0: raise ValueError("Root-Mean-Squared delay must be greater or equal to zero") self.__rms_delay = rms_delay # ETSI TR 38.900 Table 7.7.2-1: 5G TDL-A if model_type == TDLType.A: normalized_delays = np.array( [ 0, 0.3819, 0.4025, 0.5868, 0.4610, 0.5375, 0.6708, 0.5750, 0.7618, 1.5375, 1.8978, 2.2242, 2.1717, 2.4942, 2.5119, 3.0582, 4.0810, 4.4579, 4.5695, 4.7966, 5.0066, 5.3043, 9.6586, ] ) power_db = np.array( [ -13.4, 0, -2.2, -4, -6, -8.2, -9.9, -10.5, -7.5, -15.9, -6.6, -16.7, -12.4, -15.2, -10.8, -11.3, -12.7, -16.2, -18.3, -18.9, -16.6, -19.9, -29.7, ] ) rice_factors = np.zeros(normalized_delays.shape) # ETSI TR 38.900 Table 7.7.2-2: 5G TDL-B elif model_type == TDLType.B: normalized_delays = np.array( [ 0, 0.1072, 0.2155, 0.2095, 0.2870, 0.2986, 0.3752, 0.5055, 0.3681, 0.3697, 0.5700, 0.5283, 1.1021, 1.2756, 1.5474, 1.7842, 2.0169, 2.8294, 3.0219, 3.6187, 4.1067, 4.2790, 4.7834, ] ) # ETSI TR 38.900 Table 7.7.2-3: 5G TDL-C power_db = np.array( [ 0, -2.2, -4, -3.2, -9.8, -3.2, -3.4, -5.2, -7.6, -3, -8.9, -9, -4.8, -5.7, -7.5, -1.9, -7.6, -12.2, -9.8, -11.4, -14.9, -9.2, -11.3, ] ) rice_factors = np.zeros(normalized_delays.shape) # ETSI TR 38.900 Table 7.7.2-3: 5G TDL-C elif model_type == TDLType.C: normalized_delays = np.array( [ 0, 0.2099, 0.2219, 0.2329, 0.2176, 0.6366, 0.6448, 0.6560, 0.6584, 0.7935, 0.8213, 0.9336, 1.2285, 1.3083, 2.1704, 2.7105, 4.2589, 4.6003, 5.4902, 5.6077, 6.3065, 6.6374, 7.0427, 8.6523, ] ) power_db = np.array( [ -4.4, -1.2, -3.5, -5.2, -2.5, 0, -2.2, -3.9, -7.4, -7.1, -10.7, -11.1, -5.1, -6.8, -8.7, -13.2, -13.9, -13.9, -15.8, -17.1, -16, -15.7, -21.6, -22.8, ] ) rice_factors = np.zeros(normalized_delays.shape) # ETSI TR 38.900 Table 7.7.2-4: 5G TDL-D elif model_type == TDLType.D: if los_doppler_frequency is not None: raise ValueError( "Model type D does not support line of sight doppler frequency configuration" ) normalized_delays = np.array( [ 0, 0.035, 0.612, 1.363, 1.405, 1.804, 2.596, 1.775, 4.042, 7.937, 9.424, 9.708, 12.525, ] ) power_db = np.array( [ -13.5, -18.8, -21, -22.8, -17.9, -20.1, -21.9, -22.9, -27.8, -23.6, -24.8, -30.0, -27.7, ] ) rice_factors = np.zeros(normalized_delays.shape) rice_factors[0] = 13.3 los_doppler_frequency = 0.7 # ETSI TR 38.900 Table 7.7.2-5: 5G TDL-E elif model_type == TDLType.E: if los_doppler_frequency is not None: raise ValueError( "Model type E does not support line of sight doppler frequency configuration" ) normalized_delays = np.array( [ 0, 0.5133, 0.5440, 0.5630, 0.5440, 0.7112, 1.9092, 1.9293, 1.9589, 2.6426, 3.7136, 5.4524, 12.0034, 20.6519, ] ) power_db = np.array( [ -22.03, -15.8, -18.1, -19.8, -22.9, -22.4, -18.6, -20.8, -22.6, -22.3, -25.6, -20.2, -29.8, -29.2, ] ) rice_factors = np.zeros(normalized_delays.shape) rice_factors[0] = 22 los_doppler_frequency = 0.7 else: raise ValueError("Requested model type not supported") self.__model_type = TDLType(model_type) # Convert power and normalize power_profile = 10 ** (power_db / 10) power_profile /= sum(power_profile) # Scale delays delays = rms_delay * normalized_delays # Init base class with pre-defined model parameters MultipathFadingChannel.__init__( self, gain=gain, delays=delays, power_profile=power_profile, rice_factors=rice_factors, doppler_frequency=doppler_frequency, los_doppler_frequency=los_doppler_frequency, **kwargs, ) @property def model_type(self) -> TDLType: """Access the configured model type. Returns: MultipathFading5gTDL.TYPE: The configured model type. """ return self.__model_type @property def rms_delay(self) -> float: """Root mean squared channel delay. Returns: Delay in seconds. """ return self.__rms_delay