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