anomaly-detection-material-parameters-calibration

Sionna param calibration (research proj)
git clone https://git.ea.contact/anomaly-detection-material-parameters-calibration
Log | Files | Refs | README

umi_scenario.py (7899B)


      1 #
      2 # SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
      3 # SPDX-License-Identifier: Apache-2.0
      4 #
      5 """3GPP TR39.801 urban microcell (UMi) channel model."""
      6 
      7 import tensorflow as tf
      8 
      9 from sionna import SPEED_OF_LIGHT
     10 from sionna.utils import log10
     11 from . import SystemLevelScenario
     12 
     13 
     14 class UMiScenario(SystemLevelScenario):
     15     r"""
     16     3GPP TR 38.901 urban microcell (UMi) channel model scenario.
     17 
     18     Parameters
     19     -----------
     20     carrier_frequency : float
     21         Carrier frequency [Hz]
     22 
     23     o2i_model : str
     24         Outdoor to indoor (O2I) pathloss model, used for indoor UTs.
     25         Either "low" or "high" (see section 7.4.3 from 38.901 specification)
     26 
     27     ut_array : PanelArray
     28         Panel array configuration used by UTs
     29 
     30     bs_array : PanelArray
     31         Panel array configuration used by BSs
     32 
     33     direction : str
     34         Link direction. Either "uplink" or "downlink"
     35 
     36     enable_pathloss : bool
     37         If set to `True`, apply pathloss. Otherwise, does not. Defaults to True.
     38 
     39     enable_shadow_fading : bool
     40         If set to `True`, apply shadow fading. Otherwise, does not.
     41         Defaults to True.
     42 
     43     dtype : tf.DType
     44         Defines the datatype for internal calculations and the output
     45         dtype. Defaults to `tf.complex64`.
     46     """
     47 
     48     #########################################
     49     # Public methods and properties
     50     #########################################
     51 
     52     def clip_carrier_frequency_lsp(self, fc):
     53         r"""Clip the carrier frequency ``fc`` in GHz for LSP calculation
     54 
     55         Input
     56         -----
     57         fc : float
     58             Carrier frequency [GHz]
     59 
     60         Output
     61         -------
     62         : float
     63             Clipped carrier frequency, that should be used for LSp computation
     64         """
     65         if fc < 2.:
     66             fc = tf.cast(2., self._dtype.real_dtype)
     67         return fc
     68 
     69     @property
     70     def min_2d_in(self):
     71         r"""Minimum indoor 2D distance for indoor UTs [m]"""
     72         return tf.constant(0.0, self._dtype.real_dtype)
     73 
     74     @property
     75     def max_2d_in(self):
     76         r"""Maximum indoor 2D distance for indoor UTs [m]"""
     77         return tf.constant(25.0, self._dtype.real_dtype)
     78 
     79     @property
     80     def los_probability(self):
     81         r"""Probability of each UT to be LoS. Used to randomly generate LoS
     82         status of outdoor UTs.
     83 
     84         Computed following section 7.4.2 of TR 38.901.
     85 
     86         [batch size, num_ut]"""
     87 
     88         distance_2d_out = self._distance_2d_out
     89         los_probability = ( (18./distance_2d_out) +
     90             tf.exp(-distance_2d_out/36.0)*(1.-18./distance_2d_out) )
     91         los_probability = tf.where(tf.math.less(distance_2d_out, 18.0),
     92             tf.constant(1.0, self._dtype.real_dtype), los_probability)
     93         return los_probability
     94 
     95     @property
     96     def rays_per_cluster(self):
     97         r"""Number of rays per cluster"""
     98         return tf.constant(20, tf.int32)
     99 
    100     @property
    101     def los_parameter_filepath(self):
    102         r""" Path of the configuration file for LoS scenario"""
    103         return 'UMi_LoS.json'
    104 
    105     @property
    106     def nlos_parameter_filepath(self):
    107         r""" Path of the configuration file for NLoS scenario"""
    108         return'UMi_NLoS.json'
    109 
    110     @property
    111     def o2i_parameter_filepath(self):
    112         r""" Path of the configuration file for indoor scenario"""
    113         return 'UMi_O2I.json'
    114 
    115     #########################
    116     # Utility methods
    117     #########################
    118 
    119     def _compute_lsp_log_mean_std(self):
    120         r"""Computes the mean and standard deviations of LSPs in log-domain"""
    121 
    122         batch_size = self.batch_size
    123         num_bs = self.num_bs
    124         num_ut = self.num_ut
    125         distance_2d = self.distance_2d
    126         h_bs = self.h_bs
    127         h_bs = tf.expand_dims(h_bs, axis=2) # For broadcasting
    128         h_ut = self.h_ut
    129         h_ut = tf.expand_dims(h_ut, axis=1) # For broadcasting
    130 
    131         ## Mean
    132         # DS
    133         log_mean_ds = self.get_param("muDS")
    134         # ASD
    135         log_mean_asd = self.get_param("muASD")
    136         # ASA
    137         log_mean_asa = self.get_param("muASA")
    138         # SF.  Has zero-mean.
    139         log_mean_sf = tf.zeros([batch_size, num_bs, num_ut],
    140                                 self._dtype.real_dtype)
    141         # K.  Given in dB in the 3GPP tables, hence the division by 10
    142         log_mean_k = self.get_param("muK")/10.0
    143         # ZSA
    144         log_mean_zsa = self.get_param("muZSA")
    145         # ZSD
    146         log_mean_zsd_los = tf.math.maximum(
    147             tf.constant(-0.21, self._dtype.real_dtype),
    148             -14.8*(distance_2d/1000.0) + 0.01*tf.abs(h_ut-h_bs)+0.83)
    149         log_mean_zsd_nlos = tf.math.maximum(
    150             tf.constant(-0.5, self._dtype.real_dtype),
    151             -3.1*(distance_2d/1000.0) + 0.01*tf.maximum(h_ut-h_bs,0.0)+0.2)
    152         log_mean_zsd = tf.where(self.los, log_mean_zsd_los, log_mean_zsd_nlos)
    153 
    154         lsp_log_mean = tf.stack([log_mean_ds,
    155                                 log_mean_asd,
    156                                 log_mean_asa,
    157                                 log_mean_sf,
    158                                 log_mean_k,
    159                                 log_mean_zsa,
    160                                 log_mean_zsd], axis=3)
    161 
    162         ## STD
    163         # DS
    164         log_std_ds = self.get_param("sigmaDS")
    165         # ASD
    166         log_std_asd = self.get_param("sigmaASD")
    167         # ASA
    168         log_std_asa = self.get_param("sigmaASA")
    169         # SF. Given in dB in the 3GPP tables, hence the division by 10
    170         # O2I and NLoS cases just require the use of a predefined value
    171         log_std_sf = self.get_param("sigmaSF")/10.0
    172         # K. Given in dB in the 3GPP tables, hence the division by 10.
    173         log_std_k = self.get_param("sigmaK")/10.0
    174         # ZSA
    175         log_std_zsa = self.get_param("sigmaZSA")
    176         # ZSD
    177         log_std_zsd = self.get_param("sigmaZSD")
    178 
    179         lsp_log_std = tf.stack([log_std_ds,
    180                                log_std_asd,
    181                                log_std_asa,
    182                                log_std_sf,
    183                                log_std_k,
    184                                log_std_zsa,
    185                                log_std_zsd], axis=3)
    186 
    187         self._lsp_log_mean = lsp_log_mean
    188         self._lsp_log_std = lsp_log_std
    189 
    190         # ZOD offset
    191         zod_offset = -tf.math.pow(tf.constant(10.0, self._dtype.real_dtype),
    192             -1.5*log10(tf.maximum(tf.constant(10.0, self._dtype.real_dtype),
    193             distance_2d))+3.3)
    194         zod_offset = tf.where(self.los,tf.constant(0.0, self._dtype.real_dtype),
    195             zod_offset)
    196         self._zod_offset = zod_offset
    197 
    198     def _compute_pathloss_basic(self):
    199         r"""Computes the basic component of the pathloss [dB]"""
    200 
    201         distance_2d = self.distance_2d
    202         distance_3d = self.distance_3d
    203         fc = self.carrier_frequency # Carrier frequency (Hz)
    204         h_bs = self.h_bs
    205         h_bs = tf.expand_dims(h_bs, axis=2) # For broadcasting
    206         h_ut = self.h_ut
    207         h_ut = tf.expand_dims(h_ut, axis=1) # For broadcasting
    208 
    209         # Beak point distance
    210         h_e = 1.0
    211         h_bs_prime = h_bs - h_e
    212         h_ut_prime = h_ut - h_e
    213         distance_breakpoint = 4*h_bs_prime*h_ut_prime*fc/SPEED_OF_LIGHT
    214 
    215         ## Basic path loss for LoS
    216 
    217         pl_1 = 32.4 + 21.0*log10(distance_3d) + 20.0*log10(fc/1e9)
    218         pl_2 = (32.4 + 40.0*log10(distance_3d) + 20.0*log10(fc/1e9)
    219             - 9.5*log10(tf.square(distance_breakpoint)+tf.square(h_bs-h_ut)))
    220         pl_los = tf.where(tf.math.less(distance_2d, distance_breakpoint),
    221             pl_1, pl_2)
    222 
    223         ## Basic pathloss for NLoS and O2I
    224 
    225         pl_3 = (35.3*log10(distance_3d) + 22.4 + 21.3*log10(fc/1e9)
    226             - 0.3*(h_ut-1.5))
    227         pl_nlos = tf.math.maximum(pl_los, pl_3)
    228 
    229         ## Set the basic pathloss according to UT state
    230 
    231         # Expand to allow broadcasting with the BS dimension
    232         # LoS
    233         pl_b = tf.where(self.los, pl_los, pl_nlos)
    234 
    235         self._pl_b = pl_b