1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server.wifi; 17 18 import static com.android.server.wifi.util.InformationElementUtil.BssLoad.INVALID; 19 import static com.android.server.wifi.util.InformationElementUtil.BssLoad.MAX_CHANNEL_UTILIZATION; 20 import static com.android.server.wifi.util.InformationElementUtil.BssLoad.MIN_CHANNEL_UTILIZATION; 21 22 import android.annotation.NonNull; 23 import android.content.Context; 24 import android.net.wifi.ScanResult; 25 import android.net.wifi.WifiAnnotations.WifiStandard; 26 import android.net.wifi.WifiInfo; 27 import android.net.wifi.nl80211.DeviceWiphyCapabilities; 28 import android.util.Log; 29 30 import com.android.wifi.resources.R; 31 32 /** 33 * A class that predicts network throughput based on RSSI, channel utilization, channel width, 34 * WiFi standard (PHY/MAC mode), Nss and other radio information. 35 */ 36 public class ThroughputPredictor { 37 private static final String TAG = "WifiThroughputPredictor"; 38 private boolean mVerboseLoggingEnabled = false; 39 40 // Default value of channel utilization at 2G when channel utilization is not available from 41 // BssLoad IE or from link layer stats 42 public static final int CHANNEL_UTILIZATION_DEFAULT_2G = MAX_CHANNEL_UTILIZATION * 6 / 16; 43 // Default value of channel utilization at 5G when channel utilization is not available from 44 // BssLoad IE or from link layer stats 45 public static final int CHANNEL_UTILIZATION_DEFAULT_ABOVE_2G = MAX_CHANNEL_UTILIZATION / 16; 46 // Channel utilization boost when bluetooth is in the connected mode 47 public static final int CHANNEL_UTILIZATION_BOOST_BT_CONNECTED_2G = MAX_CHANNEL_UTILIZATION / 4; 48 //TODO: b/145133625 Need to consider 6GHz 49 50 // Number of data tones per OFDM symbol 51 private static final int NUM_TONE_PER_SYM_LEGACY = 48; 52 private static final int NUM_TONE_PER_SYM_11N_20MHZ = 52; 53 private static final int NUM_TONE_PER_SYM_11N_40MHZ = 108; 54 private static final int NUM_TONE_PER_SYM_11AC_20MHZ = 52; 55 private static final int NUM_TONE_PER_SYM_11AC_40MHZ = 108; 56 private static final int NUM_TONE_PER_SYM_11AC_80MHZ = 234; 57 private static final int NUM_TONE_PER_SYM_11AC_160MHZ = 468; 58 private static final int NUM_TONE_PER_SYM_11AX_BE_20MHZ = 234; 59 private static final int NUM_TONE_PER_SYM_11AX_BE_40MHZ = 468; 60 private static final int NUM_TONE_PER_SYM_11AX_BE_80MHZ = 980; 61 private static final int NUM_TONE_PER_SYM_11AX_BE_160MHZ = 1960; 62 private static final int NUM_TONE_PER_SYM_11BE_320MHZ = 1960 * 2; 63 64 // 11ag OFDM symbol duration in ns 65 private static final int SYM_DURATION_LEGACY_NS = 4000; 66 // 11n OFDM symbol duration in ns with 0.4us guard interval 67 private static final int SYM_DURATION_11N_NS = 3600; 68 // 11ac OFDM symbol duration in ns with 0.4us guard interval 69 private static final int SYM_DURATION_11AC_NS = 3600; 70 // 11ax/be OFDM symbol duration in ns with 0.8us guard interval 71 private static final int SYM_DURATION_11AX_BE_NS = 13600; 72 private static final int MICRO_TO_NANO_RATIO = 1000; 73 74 // The scaling factor for integer representation of bitPerTone and MAX_BITS_PER_TONE_XXX 75 private static final int BIT_PER_TONE_SCALE = 1000; 76 private static final int MAX_BITS_PER_TONE_LEGACY = 77 (int) Math.round((6 * 3.0 * BIT_PER_TONE_SCALE) / 4.0); 78 private static final int MAX_BITS_PER_TONE_11N = 79 (int) Math.round((6 * 5.0 * BIT_PER_TONE_SCALE) / 6.0); 80 private static final int MAX_BITS_PER_TONE_11AC = 81 (int) Math.round((8 * 5.0 * BIT_PER_TONE_SCALE) / 6.0); 82 private static final int MAX_BITS_PER_TONE_11AX = 83 (int) Math.round((10 * 5.0 * BIT_PER_TONE_SCALE) / 6.0); 84 private static final int MAX_BITS_PER_TONE_11BE = 85 (int) Math.round((12 * 5.0 * BIT_PER_TONE_SCALE) / 6.0); 86 87 // snrDb-to-bitPerTone lookup table (LUT) used at low SNR 88 // snr = Math.pow(10.0, snrDb / 10.0); 89 // bitPerTone = (int) (Math.log10(1 + snr) / Math.log10(2.0) * BIT_PER_TONE_SCALE) 90 private static final int TWO_IN_DB = 3; 91 private static final int SNR_DB_TO_BIT_PER_TONE_HIGH_SNR_SCALE = BIT_PER_TONE_SCALE / TWO_IN_DB; 92 private static final int SNR_DB_TO_BIT_PER_TONE_LUT_MIN = -10; // minimum snrDb supported by LUT 93 private static final int SNR_DB_TO_BIT_PER_TONE_LUT_MAX = 9; // maximum snrDb supported by LUT 94 private static final int[] SNR_DB_TO_BIT_PER_TONE_LUT = {0, 171, 212, 262, 323, 396, 484, 586, 95 706, 844, 1000, 1176, 1370, 1583, 1812, 2058, 2317, 2588, 2870, 3161}; 96 // Thermal noise floor power in dBm integrated over 20MHz with 5.5dB noise figure at 25C 97 private static final int NOISE_FLOOR_20MHZ_DBM = -96; 98 // A fudge factor to represent HW implementation margin in dB. 99 // Predicted throughput matches pretty well with OTA throughput with this fudge factor. 100 private static final int SNR_MARGIN_DB = 16; 101 private static final int MAX_NUM_SPATIAL_STREAM_11BE = 16; 102 private static final int MAX_NUM_SPATIAL_STREAM_11AX = 8; 103 private static final int MAX_NUM_SPATIAL_STREAM_11AC = 8; 104 private static final int MAX_NUM_SPATIAL_STREAM_11N = 4; 105 private static final int MAX_NUM_SPATIAL_STREAM_LEGACY = 1; 106 107 private static final int B_MODE_MAX_MBPS = 11; 108 private final Context mContext; 109 ThroughputPredictor(Context context)110 ThroughputPredictor(Context context) { 111 mContext = context; 112 } 113 114 /** 115 * Enable/Disable verbose logging. 116 * 117 * @param verbose true to enable and false to disable. 118 */ enableVerboseLogging(boolean verbose)119 public void enableVerboseLogging(boolean verbose) { 120 mVerboseLoggingEnabled = verbose; 121 } 122 123 /** 124 * Predict maximum Tx throughput supported by connected network at the highest RSSI 125 * with the lowest channel utilization 126 * @return predicted maximum Tx throughput in Mbps 127 */ predictMaxTxThroughput(@onNull WifiNative.ConnectionCapabilities capabilities)128 public int predictMaxTxThroughput(@NonNull WifiNative.ConnectionCapabilities capabilities) { 129 return predictThroughputInternal(capabilities.wifiStandard, capabilities.is11bMode, 130 capabilities.channelBandwidth, WifiInfo.MAX_RSSI, 131 capabilities.maxNumberTxSpatialStreams, MIN_CHANNEL_UTILIZATION, 0); 132 } 133 134 /** 135 * Predict maximum Rx throughput supported by connected network at the highest RSSI 136 * with the lowest channel utilization 137 * @return predicted maximum Rx throughput in Mbps 138 */ predictMaxRxThroughput(@onNull WifiNative.ConnectionCapabilities capabilities)139 public int predictMaxRxThroughput(@NonNull WifiNative.ConnectionCapabilities capabilities) { 140 return predictThroughputInternal(capabilities.wifiStandard, capabilities.is11bMode, 141 capabilities.channelBandwidth, WifiInfo.MAX_RSSI, 142 capabilities.maxNumberRxSpatialStreams, MIN_CHANNEL_UTILIZATION, 0); 143 } 144 145 /** 146 * Predict Tx throughput with current connection capabilities, RSSI and channel utilization 147 * @return predicted Tx throughput in Mbps 148 */ predictTxThroughput(@onNull WifiNative.ConnectionCapabilities capabilities, int rssiDbm, int frequency, int channelUtilization)149 public int predictTxThroughput(@NonNull WifiNative.ConnectionCapabilities capabilities, 150 int rssiDbm, int frequency, int channelUtilization) { 151 int channelUtilizationFinal = getValidChannelUtilization(frequency, 152 INVALID, channelUtilization, false); 153 return predictThroughputInternal(capabilities.wifiStandard, capabilities.is11bMode, 154 capabilities.channelBandwidth, rssiDbm, capabilities.maxNumberTxSpatialStreams, 155 channelUtilizationFinal, frequency); 156 } 157 158 /** 159 * Predict Rx throughput with current connection capabilities, RSSI and channel utilization 160 * @return predicted Rx throughput in Mbps 161 */ predictRxThroughput(@onNull WifiNative.ConnectionCapabilities capabilities, int rssiDbm, int frequency, int channelUtilization)162 public int predictRxThroughput(@NonNull WifiNative.ConnectionCapabilities capabilities, 163 int rssiDbm, int frequency, int channelUtilization) { 164 int channelUtilizationFinal = getValidChannelUtilization(frequency, 165 INVALID, channelUtilization, false); 166 return predictThroughputInternal(capabilities.wifiStandard, capabilities.is11bMode, 167 capabilities.channelBandwidth, rssiDbm, capabilities.maxNumberRxSpatialStreams, 168 channelUtilizationFinal, frequency); 169 } 170 171 /** 172 * Predict network throughput given by the current channel condition and RSSI 173 * @param deviceCapabilities Phy Capabilities of the device 174 * @param wifiStandardAp the highest wifi standard supported by AP 175 * @param channelWidthAp the channel bandwidth of AP 176 * @param rssiDbm the scan RSSI in dBm 177 * @param frequency the center frequency of primary 20MHz channel 178 * @param maxNumSpatialStreamAp the maximum number of spatial streams supported by AP 179 * @param channelUtilizationBssLoad the channel utilization ratio indicated from BssLoad IE 180 * @param channelUtilizationLinkLayerStats the channel utilization ratio detected from scan 181 * @param isBluetoothConnected whether the bluetooth adaptor is in connected mode 182 * @return predicted throughput in Mbps 183 */ predictThroughput(DeviceWiphyCapabilities deviceCapabilities, @WifiStandard int wifiStandardAp, int channelWidthAp, int rssiDbm, int frequency, int maxNumSpatialStreamAp, int channelUtilizationBssLoad, int channelUtilizationLinkLayerStats, boolean isBluetoothConnected)184 public int predictThroughput(DeviceWiphyCapabilities deviceCapabilities, 185 @WifiStandard int wifiStandardAp, 186 int channelWidthAp, int rssiDbm, int frequency, int maxNumSpatialStreamAp, 187 int channelUtilizationBssLoad, int channelUtilizationLinkLayerStats, 188 boolean isBluetoothConnected) { 189 190 if (deviceCapabilities == null) { 191 Log.e(TAG, "Null device capabilities passed to throughput predictor"); 192 return 0; 193 } 194 195 int maxNumSpatialStreamDevice = Math.min(deviceCapabilities.getMaxNumberTxSpatialStreams(), 196 deviceCapabilities.getMaxNumberRxSpatialStreams()); 197 198 if (mContext.getResources().getBoolean( 199 R.bool.config_wifiFrameworkMaxNumSpatialStreamDeviceOverrideEnable)) { 200 maxNumSpatialStreamDevice = mContext.getResources().getInteger( 201 R.integer.config_wifiFrameworkMaxNumSpatialStreamDeviceOverrideValue); 202 } 203 204 int maxNumSpatialStream = Math.min(maxNumSpatialStreamDevice, maxNumSpatialStreamAp); 205 206 // Get minimum standard support between device and AP 207 int wifiStandard; 208 switch (wifiStandardAp) { 209 case ScanResult.WIFI_STANDARD_11BE: 210 if (deviceCapabilities.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE)) { 211 wifiStandard = ScanResult.WIFI_STANDARD_11BE; 212 break; 213 } 214 //FALL THROUGH 215 case ScanResult.WIFI_STANDARD_11AX: 216 if (deviceCapabilities.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX)) { 217 wifiStandard = ScanResult.WIFI_STANDARD_11AX; 218 break; 219 } 220 //FALL THROUGH 221 case ScanResult.WIFI_STANDARD_11AC: 222 if (deviceCapabilities.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC)) { 223 wifiStandard = ScanResult.WIFI_STANDARD_11AC; 224 break; 225 } 226 //FALL THROUGH 227 case ScanResult.WIFI_STANDARD_11N: 228 if (deviceCapabilities.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N)) { 229 wifiStandard = ScanResult.WIFI_STANDARD_11N; 230 break; 231 } 232 //FALL THROUGH 233 default: 234 wifiStandard = ScanResult.WIFI_STANDARD_LEGACY; 235 } 236 237 // Calculate channel width 238 int channelWidth; 239 switch (channelWidthAp) { 240 case ScanResult.CHANNEL_WIDTH_320MHZ: 241 if (deviceCapabilities.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_320MHZ)) { 242 channelWidth = ScanResult.CHANNEL_WIDTH_320MHZ; 243 break; 244 } 245 // FALL THROUGH 246 case ScanResult.CHANNEL_WIDTH_160MHZ: 247 if (deviceCapabilities.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_160MHZ)) { 248 channelWidth = ScanResult.CHANNEL_WIDTH_160MHZ; 249 break; 250 } 251 // FALL THROUGH 252 case ScanResult.CHANNEL_WIDTH_80MHZ: 253 if (deviceCapabilities.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)) { 254 channelWidth = ScanResult.CHANNEL_WIDTH_80MHZ; 255 break; 256 } 257 // FALL THROUGH 258 case ScanResult.CHANNEL_WIDTH_40MHZ: 259 if (deviceCapabilities.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)) { 260 channelWidth = ScanResult.CHANNEL_WIDTH_40MHZ; 261 break; 262 } 263 // FALL THROUGH 264 default: 265 channelWidth = ScanResult.CHANNEL_WIDTH_20MHZ; 266 } 267 268 if (mVerboseLoggingEnabled) { 269 StringBuilder sb = new StringBuilder(); 270 Log.d(TAG, sb.append("AP Nss: ").append(maxNumSpatialStreamAp) 271 .append(", Device Nss: ").append(maxNumSpatialStreamDevice) 272 .append(", freq: ").append(frequency) 273 .toString()); 274 } 275 276 int channelUtilization = getValidChannelUtilization(frequency, 277 channelUtilizationBssLoad, 278 channelUtilizationLinkLayerStats, 279 isBluetoothConnected); 280 281 return predictThroughputInternal(wifiStandard, false/* is11bMode */, channelWidth, 282 rssiDbm, maxNumSpatialStream, channelUtilization, frequency); 283 } 284 predictThroughputInternal(@ifiStandard int wifiStandard, boolean is11bMode, int channelWidth, int rssiDbm, int maxNumSpatialStream, int channelUtilization, int frequency)285 private int predictThroughputInternal(@WifiStandard int wifiStandard, boolean is11bMode, 286 int channelWidth, int rssiDbm, int maxNumSpatialStream, int channelUtilization, 287 int frequency) { 288 289 // channel bandwidth in MHz = 20MHz * (2 ^ channelWidthFactor); 290 int channelWidthFactor; 291 int numTonePerSym; 292 int symDurationNs; 293 int maxBitsPerTone; 294 if (maxNumSpatialStream < 1) { 295 Log.e(TAG, "maxNumSpatialStream < 1 due to wrong implementation. Overridden to 1"); 296 maxNumSpatialStream = 1; 297 } 298 if (wifiStandard == ScanResult.WIFI_STANDARD_LEGACY) { 299 // For simplicity, use legacy OFDM parameters to predict 11b rate 300 numTonePerSym = NUM_TONE_PER_SYM_LEGACY; 301 channelWidthFactor = 0; 302 maxNumSpatialStream = MAX_NUM_SPATIAL_STREAM_LEGACY; 303 maxBitsPerTone = MAX_BITS_PER_TONE_LEGACY; 304 symDurationNs = SYM_DURATION_LEGACY_NS; 305 } else if (wifiStandard == ScanResult.WIFI_STANDARD_11N) { 306 if (channelWidth == ScanResult.CHANNEL_WIDTH_20MHZ) { 307 numTonePerSym = NUM_TONE_PER_SYM_11N_20MHZ; 308 channelWidthFactor = 0; 309 } else { 310 numTonePerSym = NUM_TONE_PER_SYM_11N_40MHZ; 311 channelWidthFactor = 1; 312 } 313 maxNumSpatialStream = Math.min(maxNumSpatialStream, MAX_NUM_SPATIAL_STREAM_11N); 314 maxBitsPerTone = MAX_BITS_PER_TONE_11N; 315 symDurationNs = SYM_DURATION_11N_NS; 316 } else if (wifiStandard == ScanResult.WIFI_STANDARD_11AC) { 317 if (channelWidth == ScanResult.CHANNEL_WIDTH_20MHZ) { 318 numTonePerSym = NUM_TONE_PER_SYM_11AC_20MHZ; 319 channelWidthFactor = 0; 320 } else if (channelWidth == ScanResult.CHANNEL_WIDTH_40MHZ) { 321 numTonePerSym = NUM_TONE_PER_SYM_11AC_40MHZ; 322 channelWidthFactor = 1; 323 } else if (channelWidth == ScanResult.CHANNEL_WIDTH_80MHZ) { 324 numTonePerSym = NUM_TONE_PER_SYM_11AC_80MHZ; 325 channelWidthFactor = 2; 326 } else { 327 numTonePerSym = NUM_TONE_PER_SYM_11AC_160MHZ; 328 channelWidthFactor = 3; 329 } 330 maxNumSpatialStream = Math.min(maxNumSpatialStream, MAX_NUM_SPATIAL_STREAM_11AC); 331 maxBitsPerTone = MAX_BITS_PER_TONE_11AC; 332 symDurationNs = SYM_DURATION_11AC_NS; 333 } else if (wifiStandard == ScanResult.WIFI_STANDARD_11AX) { 334 if (channelWidth == ScanResult.CHANNEL_WIDTH_20MHZ) { 335 numTonePerSym = NUM_TONE_PER_SYM_11AX_BE_20MHZ; 336 channelWidthFactor = 0; 337 } else if (channelWidth == ScanResult.CHANNEL_WIDTH_40MHZ) { 338 numTonePerSym = NUM_TONE_PER_SYM_11AX_BE_40MHZ; 339 channelWidthFactor = 1; 340 } else if (channelWidth == ScanResult.CHANNEL_WIDTH_80MHZ) { 341 numTonePerSym = NUM_TONE_PER_SYM_11AX_BE_80MHZ; 342 channelWidthFactor = 2; 343 } else { 344 numTonePerSym = NUM_TONE_PER_SYM_11AX_BE_160MHZ; 345 channelWidthFactor = 3; 346 } 347 maxNumSpatialStream = Math.min(maxNumSpatialStream, MAX_NUM_SPATIAL_STREAM_11AX); 348 maxBitsPerTone = MAX_BITS_PER_TONE_11AX; 349 symDurationNs = SYM_DURATION_11AX_BE_NS; 350 } else if (wifiStandard == ScanResult.WIFI_STANDARD_11BE) { 351 if (channelWidth == ScanResult.CHANNEL_WIDTH_20MHZ) { 352 numTonePerSym = NUM_TONE_PER_SYM_11AX_BE_20MHZ; 353 channelWidthFactor = 0; 354 } else if (channelWidth == ScanResult.CHANNEL_WIDTH_40MHZ) { 355 numTonePerSym = NUM_TONE_PER_SYM_11AX_BE_40MHZ; 356 channelWidthFactor = 1; 357 } else if (channelWidth == ScanResult.CHANNEL_WIDTH_80MHZ) { 358 numTonePerSym = NUM_TONE_PER_SYM_11AX_BE_80MHZ; 359 channelWidthFactor = 2; 360 } else if (channelWidth == ScanResult.CHANNEL_WIDTH_160MHZ) { 361 numTonePerSym = NUM_TONE_PER_SYM_11AX_BE_160MHZ; 362 channelWidthFactor = 3; 363 } else { 364 numTonePerSym = NUM_TONE_PER_SYM_11BE_320MHZ; 365 channelWidthFactor = 4; 366 } 367 maxNumSpatialStream = Math.min(maxNumSpatialStream, MAX_NUM_SPATIAL_STREAM_11BE); 368 maxBitsPerTone = MAX_BITS_PER_TONE_11BE; 369 symDurationNs = SYM_DURATION_11AX_BE_NS; 370 } else { 371 return WifiInfo.LINK_SPEED_UNKNOWN; 372 } 373 374 // 6Ghz RSSI boost 375 if (mContext.getResources().getBoolean(R.bool.config_wifiEnable6GhzBeaconRssiBoost) 376 && ScanResult.is6GHz(frequency)) { 377 switch (channelWidth) { 378 case ScanResult.CHANNEL_WIDTH_40MHZ: 379 rssiDbm += 3; 380 break; 381 case ScanResult.CHANNEL_WIDTH_80MHZ: 382 rssiDbm += 6; 383 break; 384 case ScanResult.CHANNEL_WIDTH_160MHZ: 385 rssiDbm += 9; 386 break; 387 case ScanResult.CHANNEL_WIDTH_320MHZ: 388 rssiDbm += 12; 389 break; 390 default: 391 // do nothing 392 } 393 } 394 395 // noiseFloorDbBoost = 10 * log10 * (2 ^ channelWidthFactor) 396 int noiseFloorDbBoost = TWO_IN_DB * channelWidthFactor; 397 int noiseFloorDbm = NOISE_FLOOR_20MHZ_DBM + noiseFloorDbBoost + SNR_MARGIN_DB; 398 int snrDb = rssiDbm - noiseFloorDbm; 399 400 int bitPerTone = calculateBitPerTone(snrDb); 401 bitPerTone = Math.min(bitPerTone, maxBitsPerTone); 402 403 long bitPerToneTotal = bitPerTone * maxNumSpatialStream; 404 long numBitPerSym = bitPerToneTotal * numTonePerSym; 405 int phyRateMbps = (int) ((numBitPerSym * MICRO_TO_NANO_RATIO) 406 / (symDurationNs * BIT_PER_TONE_SCALE)); 407 408 int airTimeFraction = calculateAirTimeFraction(channelUtilization, channelWidthFactor); 409 410 int throughputMbps = (phyRateMbps * airTimeFraction) / MAX_CHANNEL_UTILIZATION; 411 412 if (is11bMode) { 413 throughputMbps = Math.min(throughputMbps, B_MODE_MAX_MBPS); 414 } 415 if (mVerboseLoggingEnabled) { 416 StringBuilder sb = new StringBuilder(); 417 Log.d(TAG, sb.append(" BW: ").append(channelWidth) 418 .append(" RSSI: ").append(rssiDbm) 419 .append(" Nss: ").append(maxNumSpatialStream) 420 .append(" Mode: ").append(wifiStandard) 421 .append(" symDur: ").append(symDurationNs) 422 .append(" snrDb ").append(snrDb) 423 .append(" bitPerTone: ").append(bitPerTone) 424 .append(" rate: ").append(phyRateMbps) 425 .append(" throughput: ").append(throughputMbps) 426 .toString()); 427 } 428 return throughputMbps; 429 } 430 431 // Calculate the number of bits per tone based on the input of SNR in dB 432 // The output is scaled up by BIT_PER_TONE_SCALE for integer representation calculateBitPerTone(int snrDb)433 private static int calculateBitPerTone(int snrDb) { 434 int bitPerTone; 435 if (snrDb <= SNR_DB_TO_BIT_PER_TONE_LUT_MAX) { 436 int lut_in_idx = Math.max(snrDb, SNR_DB_TO_BIT_PER_TONE_LUT_MIN) 437 - SNR_DB_TO_BIT_PER_TONE_LUT_MIN; 438 lut_in_idx = Math.min(lut_in_idx, SNR_DB_TO_BIT_PER_TONE_LUT.length - 1); 439 bitPerTone = SNR_DB_TO_BIT_PER_TONE_LUT[lut_in_idx]; 440 } else { 441 // bitPerTone = Math.log10(1+snr)/Math.log10(2) can be approximated as 442 // Math.log10(snr) / 0.3 = log10(10^(snrDb/10)) / 0.3 = snrDb / 3 443 // SNR_DB_TO_BIT_PER_TONE_HIGH_SNR_SCALE = BIT_PER_TONE_SCALE / 3 444 bitPerTone = snrDb * SNR_DB_TO_BIT_PER_TONE_HIGH_SNR_SCALE; 445 } 446 return bitPerTone; 447 } 448 getValidChannelUtilization(int frequency, int channelUtilizationBssLoad, int channelUtilizationLinkLayerStats, boolean isBluetoothConnected)449 private int getValidChannelUtilization(int frequency, int channelUtilizationBssLoad, 450 int channelUtilizationLinkLayerStats, boolean isBluetoothConnected) { 451 int channelUtilization; 452 boolean is2G = ScanResult.is24GHz(frequency); 453 if (isValidUtilizationRatio(channelUtilizationBssLoad)) { 454 channelUtilization = channelUtilizationBssLoad; 455 } else if (isValidUtilizationRatio(channelUtilizationLinkLayerStats)) { 456 channelUtilization = channelUtilizationLinkLayerStats; 457 } else { 458 channelUtilization = is2G ? CHANNEL_UTILIZATION_DEFAULT_2G : 459 CHANNEL_UTILIZATION_DEFAULT_ABOVE_2G; 460 } 461 462 if (is2G && isBluetoothConnected) { 463 channelUtilization += CHANNEL_UTILIZATION_BOOST_BT_CONNECTED_2G; 464 channelUtilization = Math.min(channelUtilization, MAX_CHANNEL_UTILIZATION); 465 } 466 if (mVerboseLoggingEnabled) { 467 StringBuilder sb = new StringBuilder(); 468 Log.d(TAG, sb.append(" utilization (BssLoad) ").append(channelUtilizationBssLoad) 469 .append(" utilization (LLStats) ").append(channelUtilizationLinkLayerStats) 470 .append(" isBluetoothConnected: ").append(isBluetoothConnected) 471 .append(" final utilization: ").append(channelUtilization) 472 .toString()); 473 } 474 return channelUtilization; 475 } 476 477 /** 478 * Check if the channel utilization ratio is valid 479 */ isValidUtilizationRatio(int utilizationRatio)480 private static boolean isValidUtilizationRatio(int utilizationRatio) { 481 return (utilizationRatio <= MAX_CHANNEL_UTILIZATION 482 && utilizationRatio >= MIN_CHANNEL_UTILIZATION); 483 } 484 485 // Calculate the available airtime fraction value which is multiplied by 486 // MAX_CHANNEL_UTILIZATION for integer representation. It is calculated as 487 // (1 - channelUtilization / MAX_CHANNEL_UTILIZATION) * MAX_CHANNEL_UTILIZATION calculateAirTimeFraction(int channelUtilization, int channelWidthFactor)488 private int calculateAirTimeFraction(int channelUtilization, int channelWidthFactor) { 489 int airTimeFraction20MHz = MAX_CHANNEL_UTILIZATION - channelUtilization; 490 int airTimeFraction = airTimeFraction20MHz; 491 // For the cases of 40MHz or above, need to take 492 // (1 - channelUtilization / MAX_CHANNEL_UTILIZATION) ^ (2 ^ channelWidthFactor) 493 // because channelUtilization is defined for primary 20MHz channel 494 for (int i = 1; i <= channelWidthFactor; ++i) { 495 airTimeFraction *= airTimeFraction; 496 airTimeFraction /= MAX_CHANNEL_UTILIZATION; 497 } 498 if (mVerboseLoggingEnabled) { 499 Log.d(TAG, " airTime20: " + airTimeFraction20MHz + " airTime: " + airTimeFraction); 500 } 501 return airTimeFraction; 502 } 503 } 504