• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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