| 48 | Now that we have the individual arrays, let's see how many entries each has: |
| 49 | {{{#!python |
| 50 | print('AP Rx: {0}, AP Tx: {1}'.format(len(rx_ap), len(tx_ap))) |
| 51 | print('STA Rx: {0}, STA Tx: {1}'.format(len(rx_sta), len(tx_sta))) |
| 52 | }}} |
| 53 | |
| 54 | This will print {{{AP Rx: 318628, AP Tx: 298222}}} and {{{STA Rx: 302648, STA Tx: 312515}}}. Clearly there are many Tx and Rx events. |
| 55 | |
| 56 | Let's figure out how much time elapsed between the first and last reception at the STA: |
| 57 | {{{#!python |
| 58 | t0 = rx_sta['timestamp'][0] |
| 59 | t1 = rx_sta['timestamp'][-1] |
| 60 | print('STA Rx Timespan: {0} seconds'.format( (t1-t0)/1E6 )) |
| 61 | }}} |
| 62 | |
| 63 | This will print {{{STA Rx Timespan: 498.055775 seconds}}}. Looks like the logs have ~8 minutes worth of data. |
| 64 | |
| 65 | Next let's check out the distribution of rates for packets received at the AP. |
| 66 | |
| 67 | {{{#!python |
| 68 | print(np.bincount(rx_ap['rate'])) |
| 69 | }}} |
| 70 | |
| 71 | This will print {{{[ 0 22337 19696 27653 36418 46428 58915 69641 37540]}}}. |
| 72 | |
| 73 | The MAC code encodes rates as integers 1 to 8 (for 6 to 54 Mbps). |
| 74 | |
| 75 | The numpy bincount method counts the number of each unique value in the input vector, returning the count for every value from 0 to the highest value. Thus, the vector {{{rx_ap['rate']}}} had 8 unique values (integers 1 to 8). The zero in the output array indicates the value {{{0}}} did not occur in the input. |
| 76 | |
| 77 | So we can clearly see the AP received more packets at higher rates. |
| 78 | |
| 79 | Let's look at the distribution of rates vs time to see if we can understand why. |
| 80 | {{{#!python |
| 81 | plot(rx_ap['timestamp'], rx_ap['rate'],'.') |
| 82 | }}} |
| 83 | |
| 84 | This will produce a plot: |
| 85 | |
| 86 | [[Image(wlan_exp_log_txrx_ex_t_vs_rate.png, width=350)]] |
| 87 | |
| 88 | The X-axis is the Rx timestamp in microseconds. The Y-axis the rate value (integers in 1 to 8). There's a clear pattern- each rate was used for a fixed interval. But how long? |
| 89 | |
| 90 | {{{#!python |
| 91 | rx_ap_idx_7 = (rx_ap['rate'] == 7) |
| 92 | first_r7 = min(rx_ap['timestamp'][rx_ap_idx_7]) |
| 93 | last_r7 = max(rx_ap['timestamp'][rx_ap_idx_7]) |
| 94 | |
| 95 | print('{0} seconds'.format( (last_r7 - first_r7)/1E6 )) |
| 96 | }}} |
| 97 | |
| 98 | This will print {{{60.005337 seconds}}}. So the experiment used each rate for about 1 minute. |
| 99 | |
| 100 | Notice the indexing trick in the code above. The variable {{{rx_ap_idx_7}}} contains booleans indicating which elements passed the test, {{{True}}} here for receptions with rate of 7. This boolean array is then used as the slice argument to the {{{timestamp}}} array to select only the rate = 7 entries. Using a boolean array as a slice argument is a very fast way to filter a numpy array for further processing. |
| 101 | |
| 102 | |
| 103 | |
| 104 | pattern is clear- each rate was used for about 1 minute. And this explains the distribute of rates above- a higher rate means shorter packet duration, so in a fixed interval (i.e. 1 minute) more packets can be transmitted. |