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

utils.py (18518B)


      1 #
      2 # SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
      3 # SPDX-License-Identifier: Apache-2.0
      4 #
      5 """Utility functions for the nr (5G) sub-package of the Sionna library.
      6 """
      7 
      8 import numpy as np
      9 
     10 def generate_prng_seq(length, c_init):
     11     r"""Implements pseudo-random sequence generator as defined in Sec. 5.2.1
     12     in [3GPP38211]_ based on a length-31 Gold sequence.
     13 
     14     Parameters
     15     ----------
     16     length: int
     17         Desired output sequence length.
     18 
     19     c_init: int
     20         Initialization sequence of the PRNG. Must be in the range of 0 to
     21         :math:`2^{32}-1`.
     22 
     23     Output
     24     ------
     25     :[``length``], ndarray of 0s and 1s
     26         Containing the scrambling sequence.
     27 
     28     Note
     29     ----
     30     The initialization sequence ``c_init`` is application specific and is
     31     usually provided be higher layer protocols.
     32     """
     33 
     34     # check inputs for consistency
     35     assert(length%1==0), "length must be a positive integer."
     36     length = int(length)
     37     assert(length>0), "length must be a positive integer."
     38 
     39     assert(c_init%1==0), "c_init must be integer."
     40     c_init = int(c_init)
     41     assert(c_init<2**32), "c_init must be in [0, 2^32-1]."
     42     assert(c_init>=0), "c_init must be in [0, 2^32-1]."
     43 
     44     # internal parameters
     45     n_seq = 31 # length of gold sequence
     46     n_c = 1600 # defined in 5.2.1 in 38.211
     47 
     48     # init sequences
     49     c = np.zeros(length)
     50     x1 = np.zeros(length + n_c + n_seq)
     51     x2 = np.zeros(length + n_c + n_seq)
     52 
     53     #int2bin
     54     bin_ = format(c_init, f'0{n_seq}b')
     55     c_init = [int(x) for x in bin_[-n_seq:]] if n_seq else []
     56     c_init = np.flip(c_init) # reverse order
     57 
     58     # init x1 and x2
     59     x1[0] = 1
     60     x2[0:n_seq] = c_init
     61 
     62     # and run the generator
     63     for idx in range(length + n_c):
     64         x1[idx+31] = np.mod(x1[idx+3] + x1[idx], 2)
     65         x2[idx+31] = np.mod(x2[idx+3] + x2[idx+2] + x2[idx+1] + x2[idx], 2)
     66 
     67     # update output sequence
     68     for idx in range(length):
     69         c[idx] = np.mod(x1[idx+n_c] + x2[idx+n_c], 2)
     70 
     71     return c
     72 
     73 def select_mcs(mcs_index,
     74                table_index=1,
     75                channel_type="PUSCH",
     76                transform_precoding=False,
     77                pi2bpsk=False,
     78                verbose=False):
     79     # pylint: disable=line-too-long
     80     r"""Selects modulation and coding scheme (MCS) as specified in TS 38.214 [3GPP38214]_.
     81 
     82     Implements MCS tables as defined in [3GPP38214]_ for PUSCH and PDSCH.
     83 
     84     Parameters
     85     ----------
     86     mcs_index : int| [0,...,28]
     87         MCS index (denoted as :math:`I_{MCS}` in [3GPP38214]_).
     88 
     89     table_index : int, 1 (default) | 2 | 3 | 4
     90         Indicates which MCS table from [3GPP38214]_ to use. Starts with index "1".
     91 
     92     channel_type : str, "PUSCH" (default) | "PDSCH"
     93         5G NR physical channel type. Valid choices are "PDSCH" and "PUSCH".
     94 
     95     transform_precoding : bool, False (default)
     96         If True, the MCS tables as described in Sec. 6.1.4.1
     97         in [3GPP38214]_ are applied. Only relevant for "PUSCH".
     98 
     99     pi2bpsk : bool, False (default)
    100         If True, the higher-layer parameter `tp-pi2BPSK` as
    101         described in Sec. 6.1.4.1 in [3GPP38214]_ is applied. Only relevant
    102         for "PUSCH".
    103 
    104     verbose : bool, False (default)
    105         If True, additional information will be printed.
    106 
    107     Returns
    108     -------
    109     (modulation_order, target_rate) :
    110             Tuple:
    111 
    112     modulation_order : int
    113         Modulation order, i.e., number of bits per symbol.
    114 
    115     target_rate : float
    116         Target coderate.
    117     """
    118 
    119     # check inputs
    120     assert isinstance(mcs_index, int), "mcs_index must be int."
    121     assert (mcs_index>=0), "mcs_index cannot be negative."
    122     assert isinstance(table_index, int), "table_index must be int."
    123     assert (table_index>0), "table_index starts with 1."
    124     assert isinstance(channel_type, str), "channel_type must be str."
    125     assert (channel_type in ("PDSCH", "PUSCH")), \
    126                         "channel_type must be either `PDSCH` or `PUSCH`."
    127     assert isinstance(transform_precoding, bool), \
    128                                     "transform_precoding must be bool."
    129     assert isinstance(pi2bpsk, bool), "pi2bpsk must be bool."
    130     assert isinstance(verbose, bool), "verbose must be bool."
    131 
    132     if verbose:
    133         print(f"Selected MCS index {mcs_index} for {channel_type} channel " \
    134               f"and Table index {table_index}.")
    135 
    136     # without pre-coding the Tables from 5.1.3.1 are used
    137     if channel_type=="PDSCH" or transform_precoding is False:
    138 
    139         if table_index==1: # Table 5.1.3.1-1 in 38.214
    140             if verbose:
    141                 print("Applying Table 5.1.3.1-1 from TS 38.214.")
    142 
    143             assert mcs_index<29, "mcs_index not supported."
    144             mod_orders = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 6,
    145                           6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6]
    146             target_rates = [120, 157, 193, 251, 308, 379, 449, 526, 602, 679,
    147                             340, 378, 434, 490, 553, 616, 658, 438, 466, 517,
    148                             567, 616, 666, 719, 772, 822, 873, 910, 948]
    149 
    150         elif table_index==2: # Table 5.1.3.1-2 in 38.214
    151             if verbose:
    152                 print("Applying Table 5.1.3.1-2 from TS 38.214.")
    153 
    154             assert mcs_index<28, "mcs_index not supported."
    155             mod_orders = [2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6,
    156                           6, 6, 8, 8, 8, 8, 8, 8, 8, 8]
    157             target_rates = [120, 193, 308, 449, 602, 378, 434, 490, 553, 616,
    158                             658, 466, 517, 567, 616, 666, 719, 772, 822, 873,
    159                             682.5, 711, 754, 797, 841, 885, 916.5, 948]
    160 
    161         elif table_index==3: # Table 5.1.3.1-3 in 38.214
    162             if verbose:
    163                 print("Applying Table 5.1.3.1-3 from TS 38.214.")
    164 
    165             assert mcs_index<29, "mcs_index not supported."
    166             mod_orders = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4,
    167                           4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6]
    168             target_rates = [30, 40, 50, 64, 78, 99, 120, 157, 193, 251, 308,
    169                             379, 449, 526, 602, 340, 378, 434, 490, 553, 616,
    170                             438, 466, 517, 567, 616, 666, 719, 772]
    171 
    172         elif table_index==4: # Table 5.1.3.1-4 in 38.214
    173             if verbose:
    174                 print("Applying Table 5.1.3.1-4 from TS 38.214.")
    175 
    176             assert mcs_index<27, "mcs_index not supported."
    177             mod_orders = [2, 2, 2, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8,
    178                           8, 8, 8, 8, 8, 10, 10, 10, 10]
    179             target_rates = [120, 193, 449, 378, 490, 616, 466, 517, 567, 616,
    180                             666, 719, 772, 822, 873, 682.5, 711, 754, 797, 841,
    181                             885, 916.5, 948, 805.5, 853, 900.5, 948]
    182         else:
    183             raise ValueError("Unsupported table_index.")
    184 
    185     elif channel_type=="PUSCH": # only if pre-coding is true
    186 
    187         if table_index==1: # Table 6.1.4.1-1 in 38.214
    188             if verbose:
    189                 print("Applying Table 6.1.4.1-1 from TS 38.214.")
    190 
    191             assert mcs_index<28, "mcs_index not supported."
    192             # higher layer parameter as defined in 6.1.4.1
    193             if pi2bpsk:
    194                 if verbose:
    195                     print("Assuming pi2BPSK modulation.")
    196                 q=1
    197             else:
    198                 q=2
    199 
    200             mod_orders = [q, q, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 6,
    201                           6, 6, 6, 6, 6, 6, 6, 6, 6, 6]
    202             target_rates = [240/q, 314/q, 193, 251, 308, 379, 449, 526, 602,
    203                             679, 340, 378, 434, 490, 553, 616, 658, 466, 517,
    204                             567, 616, 666, 719, 772, 822, 873, 910, 948]
    205 
    206         elif table_index==2: # Table 6.1.4.1-2 in 38.214
    207             if verbose:
    208                 print("Applying Table 6.1.4.1-2 from TS 38.214.")
    209 
    210             assert mcs_index<28, "mcs_index not supported."
    211             # higher layer parameter as defined in 6.1.4.1
    212             if pi2bpsk:
    213                 if verbose:
    214                     print("Assuming pi2BPSK modulation.")
    215                 q=1
    216             else:
    217                 q=2
    218             mod_orders = [q, q, q, q, q, q, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4,
    219                           4, 4, 4, 4, 4, 4, 6, 6, 6, 6]
    220             target_rates = [60/q, 80/q, 100/q, 128/q, 156/q, 198/q, 120, 157,
    221                             193, 251, 308, 379, 449, 526, 602, 679, 378, 434,
    222                             490, 553, 616, 658, 699, 772, 567, 616, 666, 772]
    223         else:
    224             raise ValueError("Unsupported table_index.")
    225     else:
    226         raise ValueError("Unsupported channel_type.")
    227 
    228     mod_order = mod_orders[mcs_index]
    229     target_rate = target_rates[mcs_index] / 1024 # rate is given as r*1024
    230 
    231     if verbose:
    232         print("Modulation order: ", mod_order)
    233         print("Target code rate: ", target_rate)
    234 
    235     return mod_order, target_rate
    236 
    237 def calculate_tb_size(modulation_order,
    238                       target_coderate,
    239                       target_tb_size=None,
    240                       num_coded_bits=None,
    241                       num_prbs=None,
    242                       num_ofdm_symbols=None,
    243                       num_dmrs_per_prb=None,
    244                       num_layers=1,
    245                       num_ov=0,
    246                       tb_scaling=1.,
    247                       verbose=True):
    248     # pylint: disable=line-too-long
    249     r"""Calculates transport block (TB) size for given system parameters.
    250 
    251     This function follows the basic procedure as defined in TS 38.214 Sec.
    252     5.1.3.2 and Sec. 6.1.4.2 [3GPP38214]_.
    253 
    254     Parameters
    255     ----------
    256     modulation_order : int
    257         Modulation order, i.e., number of bits per QAM symbol.
    258 
    259     target_coderate : float
    260         Target coderate.
    261 
    262     target_tb_size: None (default) | int
    263         Target transport block size, i.e., how many information bits can be
    264         encoded into a slot for the given slot configuration. If provided,
    265         ``num_prbs``, ``num_ofdm_symbols`` and ``num_dmrs_per_prb`` will be
    266         ignored.
    267 
    268     num_coded_bits: None (default) | int
    269         How many coded bits can be fit into a given slot. If provided,
    270         ``num_prbs``, ``num_ofdm_symbols`` and ``num_dmrs_per_prb`` will be
    271         ignored.
    272 
    273     num_prbs : None (default) | int
    274         Total number of allocated PRBs per OFDM symbol where 1 PRB equals 12
    275         subcarriers.
    276 
    277     num_ofdm_symbols : None (default) | int
    278         Number of OFDM symbols allocated for transmission. Cannot be larger
    279         than 14.
    280 
    281     num_dmrs_per_prb : None (default) | int
    282         Number of DMRS (i.e., pilot) symbols per PRB that are NOT used for data
    283         transmission. Sum over all ``num_ofdm_symbols`` OFDM symbols.
    284 
    285     num_layers: int, 1 (default)
    286         Number of MIMO layers.
    287 
    288     num_ov : int, 0 (default)
    289         Number of unused resource elements due to additional
    290         overhead as specified by higher layer.
    291 
    292     tb_scaling: float, 0.25 | 0.5 | 1 (default)
    293         TB scaling factor for PDSCH as defined in TS 38.214 Tab. 5.1.3.2-2.
    294         Valid choices are 0.25, 0.5 and 1.0.
    295 
    296     verbose : bool, False (default)
    297         If True, additional information will be printed.
    298 
    299     Returns
    300     -------
    301     (tb_size, cb_size, num_cbs, cw_length, tb_crc_length, cb_crc_length, cw_lengths) :
    302             Tuple:
    303 
    304     tb_size : int
    305         Transport block size, i.e., how many information bits can be encoded
    306         into a slot for the given slot configuration.
    307 
    308     cb_size : int
    309         Code block (CB) size. Determines the number of
    310         information bits (including TB/CB CRC parity bits) per codeword.
    311 
    312     num_cbs : int
    313         Number of code blocks. Determines into how many CBs the TB is segmented.
    314 
    315     cw_lengths : list of ints
    316         Each list element defines the codeword length of each of the ``num_cbs``
    317         codewords after LDPC encoding and rate-matching. The total number of
    318         coded bits is :math:`\sum` ``cw_lengths``.
    319 
    320     tb_crc_length : int
    321         Length of the TB CRC.
    322 
    323     cb_crc_length : int
    324         Length of each CB CRC.
    325 
    326     Note
    327     ----
    328     Due to rounding, ``cw_lengths`` (=length of each codeword after encoding),
    329     can be slightly different within a transport block. Thus,
    330     ``cw_lengths`` is given as a list of ints where each list elements denotes
    331     the number of codeword bits of the corresponding codeword after
    332     rate-matching.
    333     """
    334 
    335     # supports two modi:
    336     # a) target_tb_size and num_coded_bits given
    337     # b) available res in slot given
    338 
    339     # mode a)
    340     if target_tb_size is not None:
    341 
    342         if num_coded_bits is None:
    343             raise ValueError("num_coded_bits cannot be None if " \
    344                              "target_tb_size is provided.")
    345         assert num_coded_bits%1==0, "num_coded_bits must be int."
    346         num_coded_bits = int(num_coded_bits)
    347 
    348         assert num_coded_bits%num_layers==0, \
    349             "num_coded_bits must be a multiple of num_layers."
    350 
    351         assert num_coded_bits%modulation_order==0, \
    352             "num_coded_bits must be a multiple of modulation_order."
    353 
    354         assert target_tb_size%1==0, "target_tb_size must be int."
    355         n_info = int(target_tb_size)
    356 
    357         assert target_tb_size<num_coded_bits, \
    358             "Invalid transport block parameters. target_tb_size must be less " \
    359             "than the requested num_coded_bits excluding the overhead for the "\
    360             "TB CRC."
    361 
    362     else:
    363         if num_coded_bits is not None:
    364             print("num_coded_bits will be ignored if target_tb_size " \
    365                   "is None.")
    366 
    367         assert num_ofdm_symbols in range(1, 15),\
    368                 "num_ofdm_symbols must be in the range from 1 to 14."
    369         assert num_prbs in range(1, 276),\
    370                 "num_prbs must be in the range from 1 to 276."
    371 
    372         assert tb_scaling in (0.25, 0.5, 1.), \
    373                             "tb_scaling must be in (0.25,0.5,1.)."
    374 
    375         # compute number of data symbols per prb
    376         n_re_per_prb = 12*num_ofdm_symbols - num_dmrs_per_prb - num_ov
    377 
    378         # number of coded bits that fit into the given slot configuration
    379         num_coded_bits = int(tb_scaling * n_re_per_prb  \
    380                             * modulation_order * num_layers * num_prbs)
    381 
    382         # number of allocated REs
    383         # the max. number of REs per PRB is limited to 156 in 38.214
    384         n_re = min(156, n_re_per_prb) * num_prbs
    385 
    386         # include tb_scaling as defined in Tab. 5.1.3.2-2 38.214
    387         n_info = target_coderate * tb_scaling * n_re \
    388                  * modulation_order * num_layers
    389 
    390     if n_info <= 3824:
    391         c=1
    392         # go to step 3 in 38.214 5.1.3.2
    393         n = max(3, np.floor(np.log2(n_info)) - 6)
    394         n_info_q = max(24, 2**n * np.floor(n_info/2**n))
    395 
    396         # explicit lengths given in Tab 5.1.3.2-1
    397         tab51321 = [24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128,
    398                     136, 144, 152, 160, 168, 176, 184, 192, 208, 224, 240, 256,
    399                     272, 288, 304, 320, 336, 352, 368, 384, 408, 432, 456, 480,
    400                     504, 528, 552, 576, 608, 640, 672, 704, 736, 768, 808, 848,
    401                     888, 928, 984, 1032, 1064, 1128, 1160, 1192, 1224, 1256,
    402                     1288, 1320, 1352, 1416, 1480, 1544, 1608, 1672, 1736, 1800,
    403                     1864, 1928, 2024, 2088, 2152, 2216, 2280, 2408, 2472, 2536,
    404                     2600, 2664, 2728, 2792, 2856, 2976, 3104, 3240, 3368, 3496,
    405                     3624, 3752, 3824]
    406 
    407         # find closest TBS that is not less n_info
    408         for tbs in tab51321:
    409             if tbs>=n_info_q:
    410                 break
    411     else:
    412         # go to step 4 in 38.212 5.3.1.2
    413         n = np.floor(np.log2(n_info-24)) - 5
    414         # "ties in the round function are broken towards next largest integer"
    415         n_info_q = max(3840, 2**n * np.round((n_info-24)/2**n))
    416 
    417         if target_coderate<=1/4:
    418             c = np.ceil((n_info_q + 24) / 3816)
    419             tbs = 8 * c * np.ceil((n_info_q + 24) / (8 * c)) - 24
    420         else:
    421             if n_info > 8424:
    422                 c = np.ceil((n_info_q + 24) / 8424)
    423                 tbs = 8 * c * np.ceil((n_info_q + 24) / (8*c)) - 24
    424             else:
    425                 c = 1
    426                 tbs = 8 * np.ceil((n_info_q + 24) / 8) - 24
    427 
    428     # TB CRC see 6.2.1 in 38.212
    429     if tbs>3824:
    430         tb_crc_length = 24
    431     else:
    432         tb_crc_length = 16
    433 
    434     # if tbs > max CB length, CRC-24 is added; see 5.2.2 in 38.212
    435     if c>1: # if multiple CBs exists, additional CRC is applied
    436         cb_crc_length = 24
    437     else:
    438         cb_crc_length = 0
    439 
    440     cb_size = (tbs + tb_crc_length)/c + cb_crc_length # bits per CW
    441     # internal sanity check
    442     assert (cb_size%1==0), "cb_size not an integer."
    443 
    444     # c is the number of code blocks
    445     num_cbs = int(c)
    446     cb_size = int(cb_size)
    447     tb_size = int(tbs)
    448 
    449     # cb_length as specified in 5.4.2.1 38.212
    450     # remark: the length can be different for multiple cws due to rounding
    451     # thus a list of lengths is generated
    452     cw_length = []
    453 
    454     for j in range(num_cbs):
    455         # first blocks are floored
    456         if j <= num_cbs \
    457               - np.mod(num_coded_bits/(num_layers*modulation_order),num_cbs)-1:
    458             l = num_layers * modulation_order \
    459               * np.floor(num_coded_bits / (num_layers*modulation_order*num_cbs))
    460             cw_length += [int(l)]
    461         else: # last blocks are ceiled
    462             l = num_layers * modulation_order \
    463               * np.ceil(num_coded_bits / (num_layers*modulation_order*num_cbs))
    464             cw_length += [int(l)]
    465     # sanity check that total length matches to total number of cws
    466     assert num_coded_bits==np.sum(cw_length), \
    467                         "Internal error: invalid codeword lengths."
    468 
    469     effective_rate = tb_size / num_coded_bits
    470 
    471     if verbose:
    472         print("Modulation order:", modulation_order)
    473         if target_coderate is not None:
    474             print(f"Target coderate: {target_coderate:.3f}")
    475         print(f"Effective coderate: {effective_rate:.3f}")
    476         print("Number of layers:", num_layers)
    477         print("------------------")
    478         print("Info bits per TB: ", tb_size)
    479         print("TB CRC length: ", tb_crc_length)
    480         print("Total number of coded TB bits:", num_coded_bits)
    481         print("------------------")
    482         print("Info bits per CB:", cb_size)
    483         print("Number of CBs:", num_cbs)
    484         print("CB CRC length: ", cb_crc_length)
    485         print("Output CB lengths:", cw_length)
    486 
    487     return tb_size, cb_size, num_cbs, cw_length, tb_crc_length, cb_crc_length