source: ReferenceDesigns/w3_802.11/python/examples/log/log_process_throughput_vs_time.py

Last change on this file was 6320, checked in by chunter, 5 years ago

1.8.0 release wlan-exp

File size: 8.6 KB
Line 
1"""
2------------------------------------------------------------------------------
3Mango 802.11 Reference Design - Experiments Framework - Log Throughput vs Time
4------------------------------------------------------------------------------
5License:   Copyright 2014-2019, Mango Communications. All rights reserved.
6           Distributed under the WARP license (http://warpproject.org/license)
7------------------------------------------------------------------------------
8This script uses the WLAN Exp Log utilities to parse raw log data and
9plot the throughput vs time using the pandas framework.
10
11Hardware Setup:
12    - None.  Parsing log data can be done completely off-line
13
14Required Script Changes:
15    - Set *_LOGFILE to the file name of your WLAN Exp log HDF5 file
16
17------------------------------------------------------------------------------
18"""
19import os
20import sys
21import numpy as np
22import pandas as pd
23import matplotlib.pyplot as plt
24
25import wlan_exp.log.util as log_util
26import wlan_exp.log.util_hdf as hdf_util
27import wlan_exp.log.util_sample_data as sample_data_util
28
29#-----------------------------------------------------------------------------
30# Process filenames
31#-----------------------------------------------------------------------------
32
33DEFAULT_AP_LOGFILE  = 'ap_two_node_two_flow_capture.hdf5'
34DEFAULT_STA_LOGFILE = 'sta_two_node_two_flow_capture.hdf5'
35
36logfile_error   = False
37
38# Use log file given as command line argument, if present
39if(len(sys.argv) != 1):
40    LOGFILE_AP = str(sys.argv[1])
41    LOGFILE_STA = str(sys.argv[2])
42
43    # Check if the string argument matchs a local file
44    if not (os.path.isfile(LOGFILE_AP) and os.path.isfile(LOGFILE_STA)):
45        # User specified non-existant files - give up and exit
46        logfile_error = True
47else:
48    # No command line arguments - check if default files exists locally
49    LOGFILE_AP = DEFAULT_AP_LOGFILE
50    LOGFILE_STA = DEFAULT_STA_LOGFILE
51
52    if not (os.path.isfile(LOGFILE_AP) and os.path.isfile(LOGFILE_STA)):
53        # No local files specified or found - check for matching sample data file
54        try:
55            LOGFILE_AP = sample_data_util.get_sample_data_file(DEFAULT_AP_LOGFILE)
56            LOGFILE_STA = sample_data_util.get_sample_data_file(DEFAULT_STA_LOGFILE)
57            print("Local log files not found - Using sample data files!")
58
59        except IOError as e:
60            logfile_error = True
61
62if logfile_error:
63    print("ERROR: Log files {0} and {1} not found".format(LOGFILE_AP, LOGFILE_STA))
64    sys.exit()
65else:
66    print("Reading log files:")
67    print(  "'{0}' ({1:5.1f} MB)".format(LOGFILE_AP, (os.path.getsize(LOGFILE_AP)/2**20)))
68    print(  "'{0}' ({1:5.1f} MB)".format(LOGFILE_STA, (os.path.getsize(LOGFILE_STA)/2**20)))
69
70#-----------------------------------------------------------------------------
71# Main script
72#-----------------------------------------------------------------------------
73exit_script = False
74
75# Extract the log data and index from the log files
76log_data_ap       = hdf_util.hdf5_to_log_data(filename=LOGFILE_AP)
77raw_log_index_ap  = hdf_util.hdf5_to_log_index(filename=LOGFILE_AP)
78
79log_data_sta      = hdf_util.hdf5_to_log_data(filename=LOGFILE_STA)
80raw_log_index_sta = hdf_util.hdf5_to_log_index(filename=LOGFILE_STA)
81
82# Generate indexes with just Tx and Rx events
83entries_filt  = ['NODE_INFO', 'RX_OFDM', 'TX_HIGH', 'TX_LOW']
84entries_merge = {'RX_OFDM': ['RX_OFDM', 'RX_OFDM_LTG'],
85                 'TX_HIGH': ['TX_HIGH', 'TX_HIGH_LTG'],
86                 'TX_LOW' : ['TX_LOW', 'TX_LOW_LTG']}
87
88log_index_txrx_ap  = log_util.filter_log_index(raw_log_index_ap,  include_only=entries_filt, merge=entries_merge)
89log_index_txrx_sta = log_util.filter_log_index(raw_log_index_sta, include_only=entries_filt, merge=entries_merge)
90
91# Generate numpy arrays
92log_np_ap  = log_util.log_data_to_np_arrays(log_data_ap,  log_index_txrx_ap)
93log_np_sta = log_util.log_data_to_np_arrays(log_data_sta, log_index_txrx_sta)
94
95# Extract tne NODE_INFO's and determine each node's MAC address
96try:
97    addr_ap  = log_np_ap['NODE_INFO']['wlan_mac_addr']
98except:
99    print("ERROR: Log for AP did not contain a NODE_INFO.  Cannot determine MAC Address of AP.\n")
100    exit_script = True
101
102try:
103    addr_sta = log_np_sta['NODE_INFO']['wlan_mac_addr']
104except:
105    print("ERROR: Log for STA did not contain a NODE_INFO.  Cannot determine MAC Address of STA.\n")
106    exit_script = True
107
108# Extract Tx entry arrays
109try:
110    tx_ap  = log_np_ap['TX_HIGH']
111except:
112    print("ERROR: Log for AP did not contain any transmissions.\n")
113    exit_script = True
114
115try:
116    tx_sta = log_np_sta['TX_HIGH']
117except:
118    print("ERROR: Log for STA did not contain any transmissions.\n")
119    exit_script = True
120
121# Extract Rx entry arrays
122try:
123    rx_ap  = log_np_ap['RX_OFDM']
124except:
125    print("ERROR: Log for AP did not contain any receptions.\n")
126    exit_script = True
127
128try:
129    rx_sta = log_np_sta['RX_OFDM']
130except:
131    print("ERROR: Log for STA did not contain any receptions.\n")
132    exit_script = True
133
134
135# Exit the script if necessary
136if exit_script:
137    print("Too many errors to continue.  Exiting...")
138    sys.exit(0)
139
140print('AP  Rx: {0:10d}, AP  Tx: {1:10d}'.format(len(rx_ap), len(tx_ap)))
141print('STA Rx: {0:10d}, STA Tx: {1:10d}'.format(len(rx_sta), len(tx_sta)))
142
143
144# Get RX_OFDM entry constants
145RX_CONSTS = log_util.get_entry_constants('RX_OFDM')
146
147# Resample docs: http://stackoverflow.com/questions/17001389/pandas-resample-documentation
148rs_interval = 1 #msec
149rolling_window = 1000 #samples
150
151# Select non-duplicate packets from partner node
152rx_ap_idx      = ((rx_ap['addr2'] == addr_sta) & 
153                  (((rx_ap['flags'] & RX_CONSTS.flags.DUPLICATE) == 0) &
154                   ((rx_ap['flags'] & RX_CONSTS.flags.FCS_GOOD) != 0) & 
155                   ((rx_ap['pkt_type'] == RX_CONSTS.pkt_type.DATA) | 
156                    (rx_ap['pkt_type'] == RX_CONSTS.pkt_type.QOSDATA) |
157                    (rx_ap['pkt_type'] == RX_CONSTS.pkt_type.NULLDATA))))
158                     
159rx_ap_from_sta = rx_ap[rx_ap_idx]
160
161if (len(rx_ap_from_sta) == 0):
162    print("WARNING:  No packets received at AP from STA.")
163
164rx_ap_t        = rx_ap_from_sta['timestamp']
165rx_ap_len      = rx_ap_from_sta['length']
166# Select non-duplicate packets from partner node
167rx_sta_idx     = ((rx_sta['addr2'] == addr_ap) & 
168                  (((rx_sta['flags'] & RX_CONSTS.flags.DUPLICATE) == 0) &
169                   ((rx_sta['flags'] & RX_CONSTS.flags.FCS_GOOD) != 0) & 
170                   ((rx_sta['pkt_type'] == RX_CONSTS.pkt_type.DATA) | 
171                    (rx_sta['pkt_type'] == RX_CONSTS.pkt_type.QOSDATA) |
172                    (rx_sta['pkt_type'] == RX_CONSTS.pkt_type.NULLDATA))))
173                   
174rx_sta_from_ap = rx_sta[rx_sta_idx]
175
176if (len(rx_sta_from_ap) == 0):
177    print("WARNING:  No packets received at STA from AP.")
178
179rx_sta_t       = rx_sta_from_ap['timestamp']
180rx_sta_len     = rx_sta_from_ap['length']
181
182# Convert to Pandas series
183rx_ap_t_pd    = pd.to_datetime(rx_ap_t, unit='us')
184rx_ap_len_pd  = pd.Series(rx_ap_len, index=rx_ap_t_pd)
185
186rx_sta_t_pd   = pd.to_datetime(rx_sta_t, unit='us')
187rx_sta_len_pd = pd.Series(rx_sta_len, index=rx_sta_t_pd)
188
189# Resample
190rx_ap_len_rs  = rx_ap_len_pd.resample('%dL' % rs_interval).sum().fillna(value=0)
191rx_sta_len_rs = rx_sta_len_pd.resample('%dL' % rs_interval).sum().fillna(value=0)
192
193# Merge the indexes
194t_idx = rx_ap_len_rs.index.union(rx_sta_len_rs.index)
195
196if (len(t_idx) == 0):
197    print("ERROR:  No throughput to plot.")
198    print("    Please check that there is data between the AP and STA.  Exiting...")
199    sys.exit(0)
200
201# Reindex both Series to the common index, filling 0 in empty slots
202rx_ap_len_rs  = rx_ap_len_rs.reindex(t_idx, fill_value=0)
203rx_sta_len_rs = rx_sta_len_rs.reindex(t_idx, fill_value=0)
204
205# Compute rolling means
206rx_xput_ap_r  = rx_ap_len_rs.rolling(window=rolling_window).mean()
207rx_xput_sta_r  = rx_sta_len_rs.rolling(window=rolling_window).mean()
208
209# Set NaN values to 0 (no packets == zero throughput)
210rx_xput_ap_r  = rx_xput_ap_r.fillna(value=0)
211rx_xput_sta_r = rx_xput_sta_r.fillna(value=0)
212
213# Create x axis values
214t_sec = t_idx.astype('int64') / 1.0E9
215plt_t = np.linspace(0, (max(t_sec) - min(t_sec)), len(t_sec))
216
217# Rescale xputs to bits/sec
218plt_xput_ap  = rx_xput_ap_r  * (1.0e-6 * 8.0 * (1.0/(rs_interval * 1e-3)))
219plt_xput_sta = rx_xput_sta_r * (1.0e-6 * 8.0 * (1.0/(rs_interval * 1e-3)))
220
221
222# Create figure to plot data
223plt.close('all')
224plt.figure(1)
225plt.clf()
226
227plt.plot(plt_t, plt_xput_ap, 'r', label='STA -> AP Flow')
228plt.plot(plt_t, plt_xput_sta, 'b', label='AP -> STA Flow')
229plt.plot(plt_t, plt_xput_ap + plt_xput_sta, 'g', label='Sum of Flows')
230
231plt.xlim(min(plt_t), max(plt_t))
232
233plt.grid('on')
234
235plt.legend(loc='lower center')
236plt.xlabel('Time (sec)')
237plt.ylabel('Throughput (Mb/sec)')
238
239plt.savefig('Two_Node_Througput_vs_Time.png')
Note: See TracBrowser for help on using the repository browser.