1#!/usr/bin/env python3 2# 3# Copyright 2018 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the 'License'); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an 'AS IS' BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16import time 17from enum import Enum 18 19from acts.controllers.cellular_lib.BaseSimulation import BaseSimulation 20from acts.controllers.cellular_lib.LteCellConfig import LteCellConfig 21from acts.controllers.cellular_lib.NrCellConfig import NrCellConfig 22from acts.controllers.cellular_lib import BaseCellularDut 23 24 25class IPAddressType(Enum): 26 """ IP Address types""" 27 IPV4 = "IPV4" 28 IPV6 = "IPV6" 29 IPV4V6 = "IPV4V6" 30 31 32class TransmissionMode(Enum): 33 """ Transmission modes for LTE (e.g., TM1, TM4, ...) """ 34 TM1 = "TM1" 35 TM2 = "TM2" 36 TM3 = "TM3" 37 TM4 = "TM4" 38 TM7 = "TM7" 39 TM8 = "TM8" 40 TM9 = "TM9" 41 42 43class MimoMode(Enum): 44 """ Mimo modes """ 45 MIMO_1x1 = "1x1" 46 MIMO_2x2 = "2x2" 47 MIMO_4x4 = "4x4" 48 49 50class SchedulingMode(Enum): 51 """ Traffic scheduling modes (e.g., STATIC, DYNAMIC) """ 52 DYNAMIC = "DYNAMIC" 53 STATIC = "STATIC" 54 55 56class DuplexMode(Enum): 57 """ DL/UL Duplex mode """ 58 FDD = "FDD" 59 TDD = "TDD" 60 61 62class ModulationType(Enum): 63 """DL/UL Modulation order.""" 64 QPSK = 'QPSK' 65 Q16 = '16QAM' 66 Q64 = '64QAM' 67 Q256 = '256QAM' 68 69 70# Bandwidth [MHz] to RB group size 71RBG_DICTIONARY = {20: 4, 15: 4, 10: 3, 5: 2, 3: 2, 1.4: 1} 72 73# Bandwidth [MHz] to total RBs mapping 74TOTAL_RBS_DICTIONARY = {20: 100, 15: 75, 10: 50, 5: 25, 3: 15, 1.4: 6} 75 76# Bandwidth [MHz] to minimum number of DL RBs that can be assigned to a UE 77MIN_DL_RBS_DICTIONARY = {20: 16, 15: 12, 10: 9, 5: 4, 3: 4, 1.4: 2} 78 79# Bandwidth [MHz] to minimum number of UL RBs that can be assigned to a UE 80MIN_UL_RBS_DICTIONARY = {20: 8, 15: 6, 10: 4, 5: 2, 3: 2, 1.4: 1} 81 82 83class LteSimulation(BaseSimulation): 84 """ Single-carrier LTE simulation. """ 85 # Test config keywords 86 KEY_FREQ_BANDS = "freq_bands" 87 88 # Cell param keywords 89 PARAM_RRC_STATUS_CHANGE_TIMER = "rrcstatuschangetimer" 90 91 # Units in which signal level is defined in DOWNLINK_SIGNAL_LEVEL_DICTIONARY 92 DOWNLINK_SIGNAL_LEVEL_UNITS = "RSRP" 93 94 # RSRP signal levels thresholds (as reported by Android) in dBm/15KHz. 95 # Excellent is set to -75 since callbox B Tx power is limited to -30 dBm 96 DOWNLINK_SIGNAL_LEVEL_DICTIONARY = { 97 'excellent': -62, 98 'high': -110, 99 'medium': -115, 100 'weak': -120, 101 'disconnected': -170 102 } 103 104 # Transmitted output power for the phone (dBm) 105 UPLINK_SIGNAL_LEVEL_DICTIONARY = { 106 'max': 27, 107 'high': 13, 108 'medium': 3, 109 'low': -20 110 } 111 112 # Allowed bandwidth for each band. 113 allowed_bandwidth_dictionary = { 114 1: [5, 10, 15, 20], 115 2: [1.4, 3, 5, 10, 15, 20], 116 3: [1.4, 3, 5, 10, 15, 20], 117 4: [1.4, 3, 5, 10, 15, 20], 118 5: [1.4, 3, 5, 10], 119 7: [5, 10, 15, 20], 120 8: [1.4, 3, 5, 10], 121 10: [5, 10, 15, 20], 122 11: [5, 10], 123 12: [1.4, 3, 5, 10], 124 13: [5, 10], 125 14: [5, 10], 126 17: [5, 10], 127 18: [5, 10, 15], 128 19: [5, 10, 15], 129 20: [5, 10, 15, 20], 130 21: [5, 10, 15], 131 22: [5, 10, 15, 20], 132 24: [5, 10], 133 25: [1.4, 3, 5, 10, 15, 20], 134 26: [1.4, 3, 5, 10, 15], 135 27: [1.4, 3, 5, 10], 136 28: [3, 5, 10, 15, 20], 137 29: [3, 5, 10], 138 30: [5, 10], 139 31: [1.4, 3, 5], 140 32: [5, 10, 15, 20], 141 33: [5, 10, 15, 20], 142 34: [5, 10, 15], 143 35: [1.4, 3, 5, 10, 15, 20], 144 36: [1.4, 3, 5, 10, 15, 20], 145 37: [5, 10, 15, 20], 146 38: [20], 147 39: [5, 10, 15, 20], 148 40: [5, 10, 15, 20], 149 41: [5, 10, 15, 20], 150 42: [5, 10, 15, 20], 151 43: [5, 10, 15, 20], 152 44: [3, 5, 10, 15, 20], 153 45: [5, 10, 15, 20], 154 46: [10, 20], 155 47: [10, 20], 156 48: [5, 10, 15, 20], 157 49: [10, 20], 158 50: [3, 5, 10, 15, 20], 159 51: [3, 5], 160 52: [5, 10, 15, 20], 161 65: [5, 10, 15, 20], 162 66: [1.4, 3, 5, 10, 15, 20], 163 67: [5, 10, 15, 20], 164 68: [5, 10, 15], 165 69: [5], 166 70: [5, 10, 15], 167 71: [5, 10, 15, 20], 168 72: [1.4, 3, 5], 169 73: [1.4, 3, 5], 170 74: [1.4, 3, 5, 10, 15, 20], 171 75: [5, 10, 15, 20], 172 76: [5], 173 85: [5, 10], 174 252: [20], 175 255: [20] 176 } 177 178 # Dictionary of lower DL channel number bound for each band. 179 LOWEST_DL_CN_DICTIONARY = { 180 1: 0, 181 2: 600, 182 3: 1200, 183 4: 1950, 184 5: 2400, 185 6: 2650, 186 7: 2750, 187 8: 3450, 188 9: 3800, 189 10: 4150, 190 11: 4750, 191 12: 5010, 192 13: 5180, 193 14: 5280, 194 17: 5730, 195 18: 5850, 196 19: 6000, 197 20: 6150, 198 21: 6450, 199 22: 6600, 200 23: 7500, 201 24: 7700, 202 25: 8040, 203 26: 8690, 204 27: 9040, 205 28: 9210, 206 29: 9660, 207 30: 9770, 208 31: 9870, 209 32: 9920, 210 33: 36000, 211 34: 36200, 212 35: 36350, 213 36: 36950, 214 37: 37550, 215 38: 37750, 216 39: 38250, 217 40: 38650, 218 41: 39650, 219 42: 41590, 220 43: 45590, 221 66: 66436, 222 67: 67336 223 } 224 225 # Peak throughput lookup tables for each TDD subframe 226 # configuration and bandwidth 227 # yapf: disable 228 tdd_config4_tput_lut = { 229 0: { 230 5: {'DL': 3.82, 'UL': 2.63}, 231 10: {'DL': 11.31,'UL': 9.03}, 232 15: {'DL': 16.9, 'UL': 20.62}, 233 20: {'DL': 22.88, 'UL': 28.43} 234 }, 235 1: { 236 5: {'DL': 6.13, 'UL': 4.08}, 237 10: {'DL': 18.36, 'UL': 9.69}, 238 15: {'DL': 28.62, 'UL': 14.21}, 239 20: {'DL': 39.04, 'UL': 19.23} 240 }, 241 2: { 242 5: {'DL': 5.68, 'UL': 2.30}, 243 10: {'DL': 25.51, 'UL': 4.68}, 244 15: {'DL': 39.3, 'UL': 7.13}, 245 20: {'DL': 53.64, 'UL': 9.72} 246 }, 247 3: { 248 5: {'DL': 8.26, 'UL': 3.45}, 249 10: {'DL': 23.20, 'UL': 6.99}, 250 15: {'DL': 35.35, 'UL': 10.75}, 251 20: {'DL': 48.3, 'UL': 14.6} 252 }, 253 4: { 254 5: {'DL': 6.16, 'UL': 2.30}, 255 10: {'DL': 26.77, 'UL': 4.68}, 256 15: {'DL': 40.7, 'UL': 7.18}, 257 20: {'DL': 55.6, 'UL': 9.73} 258 }, 259 5: { 260 5: {'DL': 6.91, 'UL': 1.12}, 261 10: {'DL': 30.33, 'UL': 2.33}, 262 15: {'DL': 46.04, 'UL': 3.54}, 263 20: {'DL': 62.9, 'UL': 4.83} 264 }, 265 6: { 266 5: {'DL': 6.13, 'UL': 4.13}, 267 10: {'DL': 14.79, 'UL': 11.98}, 268 15: {'DL': 23.28, 'UL': 17.46}, 269 20: {'DL': 31.75, 'UL': 23.95} 270 } 271 } 272 273 tdd_config3_tput_lut = { 274 0: { 275 5: {'DL': 5.04, 'UL': 3.7}, 276 10: {'DL': 15.11, 'UL': 17.56}, 277 15: {'DL': 22.59, 'UL': 30.31}, 278 20: {'DL': 30.41, 'UL': 41.61} 279 }, 280 1: { 281 5: {'DL': 8.07, 'UL': 5.66}, 282 10: {'DL': 24.58, 'UL': 13.66}, 283 15: {'DL': 39.05, 'UL': 20.68}, 284 20: {'DL': 51.59, 'UL': 28.76} 285 }, 286 2: { 287 5: {'DL': 7.59, 'UL': 3.31}, 288 10: {'DL': 34.08, 'UL': 6.93}, 289 15: {'DL': 53.64, 'UL': 10.51}, 290 20: {'DL': 70.55, 'UL': 14.41} 291 }, 292 3: { 293 5: {'DL': 10.9, 'UL': 5.0}, 294 10: {'DL': 30.99, 'UL': 10.25}, 295 15: {'DL': 48.3, 'UL': 15.81}, 296 20: {'DL': 63.24, 'UL': 21.65} 297 }, 298 4: { 299 5: {'DL': 8.11, 'UL': 3.32}, 300 10: {'DL': 35.74, 'UL': 6.95}, 301 15: {'DL': 55.6, 'UL': 10.51}, 302 20: {'DL': 72.72, 'UL': 14.41} 303 }, 304 5: { 305 5: {'DL': 9.28, 'UL': 1.57}, 306 10: {'DL': 40.49, 'UL': 3.44}, 307 15: {'DL': 62.9, 'UL': 5.23}, 308 20: {'DL': 82.21, 'UL': 7.15} 309 }, 310 6: { 311 5: {'DL': 8.06, 'UL': 5.74}, 312 10: {'DL': 19.82, 'UL': 17.51}, 313 15: {'DL': 31.75, 'UL': 25.77}, 314 20: {'DL': 42.12, 'UL': 34.91} 315 } 316 } 317 318 tdd_config2_tput_lut = { 319 0: { 320 5: {'DL': 3.11, 'UL': 2.55}, 321 10: {'DL': 9.93, 'UL': 11.1}, 322 15: {'DL': 13.9, 'UL': 21.51}, 323 20: {'DL': 20.02, 'UL': 41.66} 324 }, 325 1: { 326 5: {'DL': 5.33, 'UL': 4.27}, 327 10: {'DL': 15.14, 'UL': 13.95}, 328 15: {'DL': 33.84, 'UL': 19.73}, 329 20: {'DL': 44.61, 'UL': 27.35} 330 }, 331 2: { 332 5: {'DL': 6.87, 'UL': 3.32}, 333 10: {'DL': 17.06, 'UL': 6.76}, 334 15: {'DL': 49.63, 'UL': 10.5}, 335 20: {'DL': 65.2, 'UL': 14.41} 336 }, 337 3: { 338 5: {'DL': 5.41, 'UL': 4.17}, 339 10: {'DL': 16.89, 'UL': 9.73}, 340 15: {'DL': 44.29, 'UL': 15.7}, 341 20: {'DL': 53.95, 'UL': 19.85} 342 }, 343 4: { 344 5: {'DL': 8.7, 'UL': 3.32}, 345 10: {'DL': 17.58, 'UL': 6.76}, 346 15: {'DL': 51.08, 'UL': 10.47}, 347 20: {'DL': 66.45, 'UL': 14.38} 348 }, 349 5: { 350 5: {'DL': 9.46, 'UL': 1.55}, 351 10: {'DL': 19.02, 'UL': 3.48}, 352 15: {'DL': 58.89, 'UL': 5.23}, 353 20: {'DL': 76.85, 'UL': 7.1} 354 }, 355 6: { 356 5: {'DL': 4.74, 'UL': 3.9}, 357 10: {'DL': 12.32, 'UL': 13.37}, 358 15: {'DL': 27.74, 'UL': 25.02}, 359 20: {'DL': 35.48, 'UL': 32.95} 360 } 361 } 362 363 tdd_config1_tput_lut = { 364 0: { 365 5: {'DL': 4.25, 'UL': 3.35}, 366 10: {'DL': 8.38, 'UL': 7.22}, 367 15: {'DL': 12.41, 'UL': 13.91}, 368 20: {'DL': 16.27, 'UL': 24.09} 369 }, 370 1: { 371 5: {'DL': 7.28, 'UL': 4.61}, 372 10: {'DL': 14.73, 'UL': 9.69}, 373 15: {'DL': 21.91, 'UL': 13.86}, 374 20: {'DL': 27.63, 'UL': 17.18} 375 }, 376 2: { 377 5: {'DL': 10.37, 'UL': 2.27}, 378 10: {'DL': 20.92, 'UL': 4.66}, 379 15: {'DL': 31.01, 'UL': 7.04}, 380 20: {'DL': 42.03, 'UL': 9.75} 381 }, 382 3: { 383 5: {'DL': 9.25, 'UL': 3.44}, 384 10: {'DL': 18.38, 'UL': 6.95}, 385 15: {'DL': 27.59, 'UL': 10.62}, 386 20: {'DL': 34.85, 'UL': 13.45} 387 }, 388 4: { 389 5: {'DL': 10.71, 'UL': 2.26}, 390 10: {'DL': 21.54, 'UL': 4.67}, 391 15: {'DL': 31.91, 'UL': 7.2}, 392 20: {'DL': 43.35, 'UL': 9.74} 393 }, 394 5: { 395 5: {'DL': 12.34, 'UL': 1.08}, 396 10: {'DL': 24.78, 'UL': 2.34}, 397 15: {'DL': 36.68, 'UL': 3.57}, 398 20: {'DL': 49.84, 'UL': 4.81} 399 }, 400 6: { 401 5: {'DL': 5.76, 'UL': 4.41}, 402 10: {'DL': 11.68, 'UL': 9.7}, 403 15: {'DL': 17.34, 'UL': 17.95}, 404 20: {'DL': 23.5, 'UL': 23.42} 405 } 406 } 407 # yapf: enable 408 409 # Peak throughput lookup table dictionary 410 tdd_config_tput_lut_dict = { 411 'TDD_CONFIG1': 412 tdd_config1_tput_lut, # DL 256QAM, UL 64QAM & MAC padding turned OFF 413 'TDD_CONFIG2': 414 tdd_config2_tput_lut, # DL 256QAM, UL 64 QAM ON & MAC padding OFF 415 'TDD_CONFIG3': 416 tdd_config3_tput_lut, # DL 256QAM, UL 64QAM & MAC padding ON 417 'TDD_CONFIG4': 418 tdd_config4_tput_lut # DL 256QAM, UL 64 QAM OFF & MAC padding ON 419 } 420 421 def __init__(self, 422 simulator, 423 log, 424 dut, 425 test_config, 426 calibration_table, 427 nr_mode=None): 428 """ Initializes the simulator for a single-carrier LTE simulation. 429 430 Args: 431 simulator: a cellular simulator controller 432 log: a logger handle 433 dut: a device handler implementing BaseCellularDut 434 test_config: test configuration obtained from the config file 435 calibration_table: a dictionary containing path losses for 436 different bands. 437 438 """ 439 440 super().__init__(simulator, log, dut, test_config, calibration_table, 441 nr_mode) 442 443 self.num_carriers = None 444 445 # Force device to LTE only so that it connects faster 446 try: 447 if self.nr_mode and 'nr' == self.nr_mode: 448 self.dut.set_preferred_network_type( 449 BaseCellularDut.PreferredNetworkType.NR_LTE) 450 else: 451 self.dut.set_preferred_network_type( 452 BaseCellularDut.PreferredNetworkType.LTE_ONLY) 453 except Exception as e: 454 # If this fails the test should be able to run anyways, even if it 455 # takes longer to find the cell. 456 self.log.warning('Setting preferred RAT failed: {}'.format(e)) 457 458 # Get LTE CA frequency bands setting from the test configuration 459 if self.KEY_FREQ_BANDS not in test_config: 460 self.log.warning("The key '{}' is not set in the config file. " 461 "Setting to null by default.".format( 462 self.KEY_FREQ_BANDS)) 463 464 self.freq_bands = test_config.get(self.KEY_FREQ_BANDS, True) 465 466 def setup_simulator(self): 467 """ Do initial configuration in the simulator. """ 468 if self.nr_mode and 'nr' == self.nr_mode: 469 self.log.info('Initializes the callbox to Nr Nsa scenario') 470 self.simulator.setup_nr_nsa_scenario() 471 else: 472 self.log.info('Initializes the callbox to LTE scenario') 473 self.simulator.setup_lte_scenario() 474 475 def configure(self, parameters): 476 """ Configures simulation using a dictionary of parameters. 477 478 Processes LTE configuration parameters. 479 480 Args: 481 parameters: a configuration dictionary if there is only one carrier, 482 a list if there are multiple cells. 483 """ 484 # If there is a single item, put in a list 485 if not isinstance(parameters, list): 486 parameters = [parameters] 487 488 # Pass only PCC configs to BaseSimulation 489 super().configure(parameters[0]) 490 491 new_cell_list = [] 492 for cell in parameters: 493 if LteCellConfig.PARAM_BAND not in cell: 494 raise ValueError( 495 "The configuration dictionary must include a key '{}' with " 496 "the required band number.".format( 497 LteCellConfig.PARAM_BAND)) 498 499 band = cell[LteCellConfig.PARAM_BAND] 500 501 if isinstance(band, str) and not band.isdigit(): 502 # If band starts with n then it is an NR band 503 if band[0] == 'n' and band[1:].isdigit(): 504 # If the remaining string is only the band number, add 505 # the cell and continue 506 new_cell_list.append(cell) 507 continue 508 509 ca_class = band[-1].upper() 510 band_num = band[:-1] 511 512 if ca_class in ['A', 'C']: 513 # Remove the CA class label and add the cell 514 cell[LteCellConfig.PARAM_BAND] = band_num 515 new_cell_list.append(cell) 516 elif ca_class == 'B': 517 raise RuntimeError('Class B LTE CA not supported.') 518 else: 519 raise ValueError('Invalid band value: ' + band) 520 521 # Class C means that there are two contiguous carriers 522 if ca_class == 'C': 523 new_cell_list.append(dict(cell)) 524 bw = int(cell[LteCellConfig.PARAM_BW]) 525 dl_earfcn = LteCellConfig.PARAM_DL_EARFCN 526 new_cell_list[-1][ 527 dl_earfcn] = self.LOWEST_DL_CN_DICTIONARY[int( 528 band_num)] + bw * 10 - 2 529 else: 530 # The band is just a number, so just add it to the list 531 new_cell_list.append(cell) 532 533 # verify mimo mode parameter is provided 534 for cell in new_cell_list: 535 if not LteCellConfig.PARAM_MIMO in cell: 536 raise ValueError( 537 'The config dictionary must include parameter "{}" with the' 538 ' mimo mode.'.format(self.PARAM_MIMO)) 539 540 if cell[LteCellConfig.PARAM_MIMO] not in (m.value 541 for m in MimoMode): 542 raise ValueError( 543 'The value of {} must be one of the following:' 544 '1x1, 2x2 or 4x4.'.format(self.PARAM_MIMO)) 545 546 # Logs new_cell_list for debug 547 self.log.info('new cell list: {}'.format(new_cell_list)) 548 549 self.simulator.set_band_combination( 550 [c[LteCellConfig.PARAM_BAND] for c in new_cell_list], 551 [MimoMode(c[LteCellConfig.PARAM_MIMO]) for c in new_cell_list]) 552 553 self.num_carriers = len(new_cell_list) 554 555 # Setup the base stations with the obtain configuration 556 self.cell_configs = [] 557 for i in range(self.num_carriers): 558 band = new_cell_list[i][LteCellConfig.PARAM_BAND] 559 if isinstance(band, str) and band[0] == 'n': 560 self.cell_configs.append(NrCellConfig(self.log)) 561 else: 562 self.cell_configs.append(LteCellConfig(self.log)) 563 self.cell_configs[i].configure(new_cell_list[i]) 564 self.simulator.configure_bts(self.cell_configs[i], i) 565 566 # Now that the band is set, calibrate the link if necessary 567 self.load_pathloss_if_required() 568 569 # This shouldn't be a cell parameter but instead a simulation config 570 # Setup LTE RRC status change function and timer for LTE idle test case 571 if self.PARAM_RRC_STATUS_CHANGE_TIMER not in parameters[0]: 572 self.log.info( 573 "The test config does not include the '{}' key. Disabled " 574 "by default.".format(self.PARAM_RRC_STATUS_CHANGE_TIMER)) 575 self.simulator.set_lte_rrc_state_change_timer(False) 576 else: 577 timer = int(parameters[0][self.PARAM_RRC_STATUS_CHANGE_TIMER]) 578 self.simulator.set_lte_rrc_state_change_timer(True, timer) 579 self.rrc_sc_timer = timer 580 581 def calibrated_downlink_rx_power(self, bts_config, rsrp): 582 """ LTE simulation overrides this method so that it can convert from 583 RSRP to total signal power transmitted from the basestation. 584 585 Args: 586 bts_config: the current configuration at the base station 587 rsrp: desired rsrp, contained in a key value pair 588 """ 589 590 power = self.rsrp_to_signal_power(rsrp, bts_config) 591 592 self.log.info( 593 "Setting downlink signal level to {} RSRP ({} dBm)".format( 594 rsrp, power)) 595 596 # Use parent method to calculate signal level 597 return super().calibrated_downlink_rx_power(bts_config, power) 598 599 def downlink_calibration(self, rat=None, power_units_conversion_func=None): 600 """ Computes downlink path loss and returns the calibration value. 601 602 See base class implementation for details. 603 604 Args: 605 rat: ignored, replaced by 'lteRsrp' 606 power_units_conversion_func: ignored, replaced by 607 self.rsrp_to_signal_power 608 609 Returns: 610 Downlink calibration value and measured DL power. Note that the 611 phone only reports RSRP of the primary chain 612 """ 613 614 return super().downlink_calibration( 615 rat='lteDbm', 616 power_units_conversion_func=self.rsrp_to_signal_power) 617 618 def rsrp_to_signal_power(self, rsrp, bts_config): 619 """ Converts rsrp to total band signal power 620 621 RSRP is measured per subcarrier, so total band power needs to be 622 multiplied by the number of subcarriers being used. 623 624 Args: 625 rsrp: desired rsrp in dBm 626 bts_config: a base station configuration object 627 Returns: 628 Total band signal power in dBm 629 """ 630 631 bandwidth = bts_config.bandwidth 632 633 if bandwidth == 100: # This assumes 273 RBs. TODO: b/229163022 634 power = rsrp + 35.15 635 elif bandwidth == 20: # 100 RBs 636 power = rsrp + 30.79 637 elif bandwidth == 15: # 75 RBs 638 power = rsrp + 29.54 639 elif bandwidth == 10: # 50 RBs 640 power = rsrp + 27.78 641 elif bandwidth == 5: # 25 RBs 642 power = rsrp + 24.77 643 elif bandwidth == 3: # 15 RBs 644 power = rsrp + 22.55 645 elif bandwidth == 1.4: # 6 RBs 646 power = rsrp + 18.57 647 else: 648 raise ValueError("Invalid bandwidth value.") 649 650 return power 651 652 def maximum_downlink_throughput(self): 653 """ Calculates maximum achievable downlink throughput in the current 654 simulation state. 655 656 Returns: 657 Maximum throughput in mbps. 658 659 """ 660 return sum( 661 self.bts_maximum_downlink_throughtput(self.cell_configs[bts_index]) 662 for bts_index in range(self.num_carriers)) 663 664 def bts_maximum_downlink_throughtput(self, bts_config): 665 """ Calculates maximum achievable downlink throughput for a single 666 base station from its configuration object. 667 668 Args: 669 bts_config: a base station configuration object. 670 671 Returns: 672 Maximum throughput in mbps. 673 674 """ 675 if bts_config.mimo_mode == MimoMode.MIMO_1x1: 676 streams = 1 677 elif bts_config.mimo_mode == MimoMode.MIMO_2x2: 678 streams = 2 679 elif bts_config.mimo_mode == MimoMode.MIMO_4x4: 680 streams = 4 681 else: 682 raise ValueError('Unable to calculate maximum downlink throughput ' 683 'because the MIMO mode has not been set.') 684 685 bandwidth = bts_config.bandwidth 686 rb_ratio = bts_config.dl_rbs / TOTAL_RBS_DICTIONARY[bandwidth] 687 mcs = bts_config.dl_mcs 688 689 max_rate_per_stream = None 690 691 tdd_subframe_config = bts_config.dlul_config 692 duplex_mode = bts_config.get_duplex_mode() 693 694 if duplex_mode == DuplexMode.TDD: 695 if bts_config.dl_256_qam_enabled: 696 if mcs == 27: 697 if bts_config.mac_padding: 698 max_rate_per_stream = self.tdd_config_tput_lut_dict[ 699 'TDD_CONFIG3'][tdd_subframe_config][bandwidth][ 700 'DL'] 701 else: 702 max_rate_per_stream = self.tdd_config_tput_lut_dict[ 703 'TDD_CONFIG2'][tdd_subframe_config][bandwidth][ 704 'DL'] 705 else: 706 if mcs == 28: 707 if bts_config.mac_padding: 708 max_rate_per_stream = self.tdd_config_tput_lut_dict[ 709 'TDD_CONFIG4'][tdd_subframe_config][bandwidth][ 710 'DL'] 711 else: 712 max_rate_per_stream = self.tdd_config_tput_lut_dict[ 713 'TDD_CONFIG1'][tdd_subframe_config][bandwidth][ 714 'DL'] 715 716 elif duplex_mode == DuplexMode.FDD: 717 if (not bts_config.dl_256_qam_enabled and bts_config.mac_padding 718 and mcs == 28): 719 max_rate_per_stream = { 720 3: 9.96, 721 5: 17.0, 722 10: 34.7, 723 15: 52.7, 724 20: 72.2 725 }.get(bandwidth, None) 726 if (not bts_config.dl_256_qam_enabled and bts_config.mac_padding 727 and mcs == 27): 728 max_rate_per_stream = { 729 1.4: 2.94, 730 }.get(bandwidth, None) 731 elif (not bts_config.dl_256_qam_enabled 732 and not bts_config.mac_padding and mcs == 27): 733 max_rate_per_stream = { 734 1.4: 2.87, 735 3: 7.7, 736 5: 14.4, 737 10: 28.7, 738 15: 42.3, 739 20: 57.7 740 }.get(bandwidth, None) 741 elif bts_config.dl_256_qam_enabled and bts_config.mac_padding and mcs == 27: 742 max_rate_per_stream = { 743 3: 13.2, 744 5: 22.9, 745 10: 46.3, 746 15: 72.2, 747 20: 93.9 748 }.get(bandwidth, None) 749 elif bts_config.dl_256_qam_enabled and bts_config.mac_padding and mcs == 26: 750 max_rate_per_stream = { 751 1.4: 3.96, 752 }.get(bandwidth, None) 753 elif (bts_config.dl_256_qam_enabled and not bts_config.mac_padding 754 and mcs == 27): 755 max_rate_per_stream = { 756 3: 11.3, 757 5: 19.8, 758 10: 44.1, 759 15: 68.1, 760 20: 88.4 761 }.get(bandwidth, None) 762 elif (bts_config.dl_256_qam_enabled and not bts_config.mac_padding 763 and mcs == 26): 764 max_rate_per_stream = { 765 1.4: 3.96, 766 }.get(bandwidth, None) 767 768 if not max_rate_per_stream: 769 raise NotImplementedError( 770 "The calculation for MAC padding = {} " 771 "and mcs = {} is not implemented.".format( 772 "FULLALLOCATION" if bts_config.mac_padding else "OFF", 773 mcs)) 774 775 return max_rate_per_stream * streams * rb_ratio 776 777 def maximum_uplink_throughput(self): 778 """ Calculates maximum achievable uplink throughput in the current 779 simulation state. 780 781 Returns: 782 Maximum throughput in mbps. 783 784 """ 785 786 return self.bts_maximum_uplink_throughtput(self.cell_configs[0]) 787 788 def bts_maximum_uplink_throughtput(self, bts_config): 789 """ Calculates maximum achievable uplink throughput for the selected 790 basestation from its configuration object. 791 792 Args: 793 bts_config: an LTE base station configuration object. 794 795 Returns: 796 Maximum throughput in mbps. 797 798 """ 799 800 bandwidth = bts_config.bandwidth 801 rb_ratio = bts_config.ul_rbs / TOTAL_RBS_DICTIONARY[bandwidth] 802 mcs = bts_config.ul_mcs 803 804 max_rate_per_stream = None 805 806 tdd_subframe_config = bts_config.dlul_config 807 duplex_mode = bts_config.get_duplex_mode() 808 809 if duplex_mode == DuplexMode.TDD: 810 if bts_config.ul_64_qam_enabled: 811 if mcs == 28: 812 if bts_config.mac_padding: 813 max_rate_per_stream = self.tdd_config_tput_lut_dict[ 814 'TDD_CONFIG3'][tdd_subframe_config][bandwidth][ 815 'UL'] 816 else: 817 max_rate_per_stream = self.tdd_config_tput_lut_dict[ 818 'TDD_CONFIG2'][tdd_subframe_config][bandwidth][ 819 'UL'] 820 else: 821 if mcs == 23: 822 if bts_config.mac_padding: 823 max_rate_per_stream = self.tdd_config_tput_lut_dict[ 824 'TDD_CONFIG4'][tdd_subframe_config][bandwidth][ 825 'UL'] 826 else: 827 max_rate_per_stream = self.tdd_config_tput_lut_dict[ 828 'TDD_CONFIG1'][tdd_subframe_config][bandwidth][ 829 'UL'] 830 831 elif duplex_mode == DuplexMode.FDD: 832 if mcs == 23 and not bts_config.ul_64_qam_enabled: 833 max_rate_per_stream = { 834 1.4: 2.85, 835 3: 7.18, 836 5: 12.1, 837 10: 24.5, 838 15: 36.5, 839 20: 49.1 840 }.get(bandwidth, None) 841 elif mcs == 28 and bts_config.ul_64_qam_enabled: 842 max_rate_per_stream = { 843 1.4: 4.2, 844 3: 10.5, 845 5: 17.2, 846 10: 35.3, 847 15: 53.0, 848 20: 72.6 849 }.get(bandwidth, None) 850 851 if not max_rate_per_stream: 852 raise NotImplementedError( 853 "The calculation fir mcs = {} is not implemented.".format( 854 "FULLALLOCATION" if bts_config.mac_padding else "OFF", 855 mcs)) 856 857 return max_rate_per_stream * rb_ratio 858 859 def calibrate(self, band): 860 """ Calculates UL and DL path loss if it wasn't done before 861 862 Before running the base class implementation, configure the base station 863 to only use one downlink antenna with maximum bandwidth. 864 865 Args: 866 band: the band that is currently being calibrated. 867 """ 868 869 # Save initial values in a configuration object so they can be restored 870 restore_config = LteCellConfig(self.log) 871 restore_config.mimo_mode = self.cell_configs[0].mimo_mode 872 restore_config.transmission_mode = \ 873 self.cell_configs[0].transmission_mode 874 restore_config.bandwidth = self.cell_configs[0].bandwidth 875 876 # Set up a temporary calibration configuration. 877 temporary_config = LteCellConfig(self.log) 878 temporary_config.mimo_mode = MimoMode.MIMO_1x1 879 temporary_config.transmission_mode = TransmissionMode.TM1 880 temporary_config.bandwidth = max( 881 self.allowed_bandwidth_dictionary[int(band)]) 882 self.simulator.configure_bts(temporary_config) 883 self.cell_configs[0].incorporate(temporary_config) 884 885 super().calibrate(band) 886 887 # Restore values as they were before changing them for calibration. 888 self.simulator.configure_bts(restore_config) 889 self.cell_configs[0].incorporate(restore_config) 890 891 def start_traffic_for_calibration(self): 892 """ If MAC padding is enabled, there is no need to start IP traffic. """ 893 if not self.cell_configs[0].mac_padding: 894 super().start_traffic_for_calibration() 895 896 def stop_traffic_for_calibration(self): 897 """ If MAC padding is enabled, IP traffic wasn't started. """ 898 if not self.cell_configs[0].mac_padding: 899 super().stop_traffic_for_calibration() 900 901 def get_measured_ul_power(self, samples=5, wait_after_sample=3): 902 """ Calculates UL power using measurements from the callbox and the 903 calibration data. 904 905 Args: 906 samples: the numble of samples to average 907 wait_after_sample: time in seconds to wait in between samples 908 909 Returns: 910 the ul power at the UE antenna ports in dBs 911 """ 912 ul_power_sum = 0 913 samples_left = samples 914 915 while samples_left > 0: 916 ul_power_sum += self.simulator.get_measured_pusch_power() 917 samples_left -= 1 918 time.sleep(wait_after_sample) 919 920 # Got enough samples, return calibrated average 921 if self.dl_path_loss: 922 return ul_power_sum / samples + self.ul_path_loss 923 else: 924 self.log.warning('No uplink calibration data. Returning ' 925 'uncalibrated values as measured by the ' 926 'callbox.') 927 return ul_power_sum / samples 928 929 def start(self): 930 """ Set the signal level for the secondary carriers, as the base class 931 implementation of this method will only set up downlink power for the 932 primary carrier component. 933 934 After that, attaches the secondary carriers.""" 935 936 super().start() 937 938 if self.num_carriers > 1: 939 if self.sim_dl_power: 940 self.log.info('Setting DL power for secondary carriers.') 941 942 for bts_index in range(1, self.num_carriers): 943 new_config = LteCellConfig(self.log) 944 new_config.output_power = self.calibrated_downlink_rx_power( 945 self.cell_configs[bts_index], self.sim_dl_power) 946 self.simulator.configure_bts(new_config, bts_index) 947 self.cell_configs[bts_index].incorporate(new_config) 948 949 self.simulator.lte_attach_secondary_carriers(self.freq_bands) 950 951 def send_sms(self, message): 952 """ Sends an SMS message to the DUT. 953 954 Args: 955 message: the SMS message to send. 956 """ 957 self.simulator.send_sms(message) 958