A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-80211e-txop.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016 Sébastien Deronne
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
7 */
8
9#include "ns3/command-line.h"
10#include "ns3/internet-stack-helper.h"
11#include "ns3/ipv4-address-helper.h"
12#include "ns3/log.h"
13#include "ns3/mobility-helper.h"
14#include "ns3/on-off-helper.h"
15#include "ns3/pointer.h"
16#include "ns3/qos-txop.h"
17#include "ns3/ssid.h"
18#include "ns3/string.h"
19#include "ns3/udp-client-server-helper.h"
20#include "ns3/udp-server.h"
21#include "ns3/wifi-mac.h"
22#include "ns3/wifi-net-device.h"
23#include "ns3/yans-wifi-channel.h"
24#include "ns3/yans-wifi-helper.h"
25
26// This is an example that illustrates 802.11 QoS for different Access Categories.
27// It defines 4 independent Wi-Fi networks (working on different logical channels
28// on the same "ns3::YansWifiPhy" channel object).
29// Each network contains one access point and one station. Each station continuously
30// transmits data packets to its respective AP.
31//
32// Network topology (numbers in parentheses are channel numbers):
33//
34// BSS A (36) BSS B (40) BSS C (44) BSS D (48)
35// * * * * * * * *
36// | | | | | | | |
37// AP A STA A AP B STA B AP C STA C AP D STA D
38//
39// The configuration is the following on the 4 networks:
40// - STA A sends AC_BE traffic to AP A with default AC_BE TXOP value of 0 (1 MSDU);
41// - STA B sends AC_BE traffic to AP B with non-default AC_BE TXOP of 4096 us;
42// - STA C sends AC_VI traffic to AP C with default AC_VI TXOP of 4096 us;
43// - STA D sends AC_VI traffic to AP D with non-default AC_VI TXOP value of 0 (1 MSDU);
44//
45// The user can select the distance between the stations and the APs, can enable/disable the RTS/CTS
46// mechanism and can choose the payload size and the simulation duration. Example: ./ns3 run
47// "wifi-80211e-txop --distance=10 --simulationTime=20s --payloadSize=1000"
48//
49// The output prints the throughput measured for the 4 cases/networks described above. When TXOP is
50// enabled, results show increased throughput since the channel is granted for a longer duration.
51// TXOP is enabled by default for AC_VI and AC_VO, so that they can use the channel for a longer
52// duration than AC_BE and AC_BK.
53
54using namespace ns3;
55
56NS_LOG_COMPONENT_DEFINE("80211eTxop");
57
58/**
59 * Keeps the maximum duration among all TXOPs
60 */
62{
63 /**
64 * Callback connected to TXOP duration trace source.
65 *
66 * \param startTime TXOP start time
67 * \param duration TXOP duration
68 * \param linkId the ID of the link
69 */
70 void Trace(Time startTime, Time duration, uint8_t linkId);
71 Time m_max{Seconds(0)}; //!< maximum TXOP duration
72};
73
74void
75TxopDurationTracer::Trace(Time startTime, Time duration, uint8_t linkId)
76{
77 if (duration > m_max)
78 {
79 m_max = duration;
80 }
81}
82
83int
84main(int argc, char* argv[])
85{
86 uint32_t payloadSize{1472}; // bytes
87 Time simulationTime{"10s"};
88 meter_u distance{5};
89 bool enablePcap{false};
90 bool verifyResults{false}; // used for regression
91 Time txopLimit{"4096us"};
92
93 CommandLine cmd(__FILE__);
94 cmd.AddValue("payloadSize", "Payload size in bytes", payloadSize);
95 cmd.AddValue("simulationTime", "Simulation time", simulationTime);
96 cmd.AddValue("distance",
97 "Distance in meters between the station and the access point",
98 distance);
99 cmd.AddValue("enablePcap", "Enable/disable pcap file generation", enablePcap);
100 cmd.AddValue("verifyResults",
101 "Enable/disable results verification at the end of the simulation",
102 verifyResults);
103 cmd.Parse(argc, argv);
104
106 wifiStaNodes.Create(4);
107 NodeContainer wifiApNodes;
108 wifiApNodes.Create(4);
109
112 phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
113 phy.SetChannel(channel.Create());
114
116 wifi.SetStandard(WIFI_STANDARD_80211a);
117 wifi.SetRemoteStationManager("ns3::IdealWifiManager");
119
120 NetDeviceContainer staDeviceA;
121 NetDeviceContainer staDeviceB;
122 NetDeviceContainer staDeviceC;
123 NetDeviceContainer staDeviceD;
124 NetDeviceContainer apDeviceA;
125 NetDeviceContainer apDeviceB;
126 NetDeviceContainer apDeviceC;
127 NetDeviceContainer apDeviceD;
128 Ssid ssid;
129
130 // Network A
131 ssid = Ssid("network-A");
132 phy.Set("ChannelSettings", StringValue("{36, 20, BAND_5GHZ, 0}"));
133 mac.SetType("ns3::StaWifiMac", "QosSupported", BooleanValue(true), "Ssid", SsidValue(ssid));
134 staDeviceA = wifi.Install(phy, mac, wifiStaNodes.Get(0));
135
136 mac.SetType("ns3::ApWifiMac",
137 "QosSupported",
138 BooleanValue(true),
139 "Ssid",
140 SsidValue(ssid),
141 "EnableBeaconJitter",
142 BooleanValue(false));
143 apDeviceA = wifi.Install(phy, mac, wifiApNodes.Get(0));
144
145 // Network B
146 ssid = Ssid("network-B");
147 phy.Set("ChannelSettings", StringValue("{40, 20, BAND_5GHZ, 0}"));
148 mac.SetType("ns3::StaWifiMac", "QosSupported", BooleanValue(true), "Ssid", SsidValue(ssid));
149
150 staDeviceB = wifi.Install(phy, mac, wifiStaNodes.Get(1));
151
152 mac.SetType("ns3::ApWifiMac",
153 "QosSupported",
154 BooleanValue(true),
155 "Ssid",
156 SsidValue(ssid),
157 "EnableBeaconJitter",
158 BooleanValue(false));
159 apDeviceB = wifi.Install(phy, mac, wifiApNodes.Get(1));
160
161 // Modify EDCA configuration (TXOP limit) for AC_BE
162 Ptr<NetDevice> dev = wifiApNodes.Get(1)->GetDevice(0);
164 Ptr<WifiMac> wifi_mac = wifi_dev->GetMac();
165 PointerValue ptr;
166 Ptr<QosTxop> edca;
167 wifi_mac->GetAttribute("BE_Txop", ptr);
168 edca = ptr.Get<QosTxop>();
169 edca->SetTxopLimit(txopLimit);
170
171 // Trace TXOP duration for BE on STA1
172 dev = wifiStaNodes.Get(1)->GetDevice(0);
173 wifi_dev = DynamicCast<WifiNetDevice>(dev);
174 wifi_mac = wifi_dev->GetMac();
175 wifi_mac->GetAttribute("BE_Txop", ptr);
176 edca = ptr.Get<QosTxop>();
177 TxopDurationTracer beTxopTracer;
178 edca->TraceConnectWithoutContext("TxopTrace",
179 MakeCallback(&TxopDurationTracer::Trace, &beTxopTracer));
180
181 // Network C
182 ssid = Ssid("network-C");
183 phy.Set("ChannelSettings", StringValue("{44, 20, BAND_5GHZ, 0}"));
184 mac.SetType("ns3::StaWifiMac", "QosSupported", BooleanValue(true), "Ssid", SsidValue(ssid));
185
186 staDeviceC = wifi.Install(phy, mac, wifiStaNodes.Get(2));
187
188 mac.SetType("ns3::ApWifiMac",
189 "QosSupported",
190 BooleanValue(true),
191 "Ssid",
192 SsidValue(ssid),
193 "EnableBeaconJitter",
194 BooleanValue(false));
195 apDeviceC = wifi.Install(phy, mac, wifiApNodes.Get(2));
196
197 // Trace TXOP duration for VI on STA2
198 dev = wifiStaNodes.Get(2)->GetDevice(0);
199 wifi_dev = DynamicCast<WifiNetDevice>(dev);
200 wifi_mac = wifi_dev->GetMac();
201 wifi_mac->GetAttribute("VI_Txop", ptr);
202 edca = ptr.Get<QosTxop>();
203 TxopDurationTracer viTxopTracer;
204 edca->TraceConnectWithoutContext("TxopTrace",
205 MakeCallback(&TxopDurationTracer::Trace, &viTxopTracer));
206
207 // Network D
208 ssid = Ssid("network-D");
209 phy.Set("ChannelSettings", StringValue("{48, 20, BAND_5GHZ, 0}"));
210 mac.SetType("ns3::StaWifiMac", "QosSupported", BooleanValue(true), "Ssid", SsidValue(ssid));
211
212 staDeviceD = wifi.Install(phy, mac, wifiStaNodes.Get(3));
213
214 mac.SetType("ns3::ApWifiMac",
215 "QosSupported",
216 BooleanValue(true),
217 "Ssid",
218 SsidValue(ssid),
219 "EnableBeaconJitter",
220 BooleanValue(false));
221 apDeviceD = wifi.Install(phy, mac, wifiApNodes.Get(3));
222
223 // Modify EDCA configuration (TXOP limit) for AC_VO
224 dev = wifiApNodes.Get(3)->GetDevice(0);
225 wifi_dev = DynamicCast<WifiNetDevice>(dev);
226 wifi_mac = wifi_dev->GetMac();
227 wifi_mac->GetAttribute("VI_Txop", ptr);
228 edca = ptr.Get<QosTxop>();
229 edca->SetTxopLimit(MicroSeconds(0));
230
231 /* Setting mobility model */
234 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
235
236 // Set position for APs
237 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
238 positionAlloc->Add(Vector(10.0, 0.0, 0.0));
239 positionAlloc->Add(Vector(20.0, 0.0, 0.0));
240 positionAlloc->Add(Vector(30.0, 0.0, 0.0));
241 // Set position for STAs
242 positionAlloc->Add(Vector(distance, 0.0, 0.0));
243 positionAlloc->Add(Vector(10 + distance, 0.0, 0.0));
244 positionAlloc->Add(Vector(20 + distance, 0.0, 0.0));
245 positionAlloc->Add(Vector(30 + distance, 0.0, 0.0));
246 // Remark: while we set these positions 10 meters apart, the networks do not interact
247 // and the only variable that affects transmission performance is the distance.
248
249 mobility.SetPositionAllocator(positionAlloc);
250 mobility.Install(wifiApNodes);
251 mobility.Install(wifiStaNodes);
252
253 /* Internet stack */
255 stack.Install(wifiApNodes);
256 stack.Install(wifiStaNodes);
257
259 address.SetBase("192.168.1.0", "255.255.255.0");
260 Ipv4InterfaceContainer StaInterfaceA;
261 StaInterfaceA = address.Assign(staDeviceA);
262 Ipv4InterfaceContainer ApInterfaceA;
263 ApInterfaceA = address.Assign(apDeviceA);
264
265 address.SetBase("192.168.2.0", "255.255.255.0");
266 Ipv4InterfaceContainer StaInterfaceB;
267 StaInterfaceB = address.Assign(staDeviceB);
268 Ipv4InterfaceContainer ApInterfaceB;
269 ApInterfaceB = address.Assign(apDeviceB);
270
271 address.SetBase("192.168.3.0", "255.255.255.0");
272 Ipv4InterfaceContainer StaInterfaceC;
273 StaInterfaceC = address.Assign(staDeviceC);
274 Ipv4InterfaceContainer ApInterfaceC;
275 ApInterfaceC = address.Assign(apDeviceC);
276
277 address.SetBase("192.168.4.0", "255.255.255.0");
278 Ipv4InterfaceContainer StaInterfaceD;
279 StaInterfaceD = address.Assign(staDeviceD);
280 Ipv4InterfaceContainer ApInterfaceD;
281 ApInterfaceD = address.Assign(apDeviceD);
282
283 /* Setting applications */
284 uint16_t port = 5001;
285 UdpServerHelper serverA(port);
286 ApplicationContainer serverAppA = serverA.Install(wifiApNodes.Get(0));
287 serverAppA.Start(Seconds(0.0));
288 serverAppA.Stop(simulationTime + Seconds(1.0));
289
290 InetSocketAddress destA(ApInterfaceA.GetAddress(0), port);
291
292 OnOffHelper clientA("ns3::UdpSocketFactory", destA);
293 clientA.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
294 clientA.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
295 clientA.SetAttribute("DataRate", StringValue("100000kb/s"));
296 clientA.SetAttribute("PacketSize", UintegerValue(payloadSize));
297 clientA.SetAttribute("Tos", UintegerValue(0x70)); // AC_BE
298
299 ApplicationContainer clientAppA = clientA.Install(wifiStaNodes.Get(0));
300 clientAppA.Start(Seconds(1.0));
301 clientAppA.Stop(simulationTime + Seconds(1.0));
302
303 UdpServerHelper serverB(port);
304 ApplicationContainer serverAppB = serverB.Install(wifiApNodes.Get(1));
305 serverAppB.Start(Seconds(0.0));
306 serverAppB.Stop(simulationTime + Seconds(1.0));
307
308 InetSocketAddress destB(ApInterfaceB.GetAddress(0), port);
309
310 OnOffHelper clientB("ns3::UdpSocketFactory", destB);
311 clientB.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
312 clientB.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
313 clientB.SetAttribute("DataRate", StringValue("100000kb/s"));
314 clientB.SetAttribute("PacketSize", UintegerValue(payloadSize));
315 clientB.SetAttribute("Tos", UintegerValue(0x70)); // AC_BE
316
317 ApplicationContainer clientAppB = clientB.Install(wifiStaNodes.Get(1));
318 clientAppB.Start(Seconds(1.0));
319 clientAppB.Stop(simulationTime + Seconds(1.0));
320
321 UdpServerHelper serverC(port);
322 ApplicationContainer serverAppC = serverC.Install(wifiApNodes.Get(2));
323 serverAppC.Start(Seconds(0.0));
324 serverAppC.Stop(simulationTime + Seconds(1.0));
325
326 InetSocketAddress destC(ApInterfaceC.GetAddress(0), port);
327
328 OnOffHelper clientC("ns3::UdpSocketFactory", destC);
329 clientC.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
330 clientC.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
331 clientC.SetAttribute("DataRate", StringValue("100000kb/s"));
332 clientC.SetAttribute("PacketSize", UintegerValue(payloadSize));
333 clientC.SetAttribute("Tos", UintegerValue(0xb8)); // AC_VI
334
335 ApplicationContainer clientAppC = clientC.Install(wifiStaNodes.Get(2));
336 clientAppC.Start(Seconds(1.0));
337 clientAppC.Stop(simulationTime + Seconds(1.0));
338
339 UdpServerHelper serverD(port);
340 ApplicationContainer serverAppD = serverD.Install(wifiApNodes.Get(3));
341 serverAppD.Start(Seconds(0.0));
342 serverAppD.Stop(simulationTime + Seconds(1.0));
343
344 InetSocketAddress destD(ApInterfaceD.GetAddress(0), port);
345
346 OnOffHelper clientD("ns3::UdpSocketFactory", destD);
347 clientD.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
348 clientD.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
349 clientD.SetAttribute("DataRate", StringValue("100000kb/s"));
350 clientD.SetAttribute("PacketSize", UintegerValue(payloadSize));
351 clientD.SetAttribute("Tos", UintegerValue(0xb8)); // AC_VI
352
353 ApplicationContainer clientAppD = clientD.Install(wifiStaNodes.Get(3));
354 clientAppD.Start(Seconds(1.0));
355 clientAppD.Stop(simulationTime + Seconds(1.0));
356
357 if (enablePcap)
358 {
359 phy.EnablePcap("AP_A", apDeviceA.Get(0));
360 phy.EnablePcap("STA_A", staDeviceA.Get(0));
361 phy.EnablePcap("AP_B", apDeviceB.Get(0));
362 phy.EnablePcap("STA_B", staDeviceB.Get(0));
363 phy.EnablePcap("AP_C", apDeviceC.Get(0));
364 phy.EnablePcap("STA_C", staDeviceC.Get(0));
365 phy.EnablePcap("AP_D", apDeviceD.Get(0));
366 phy.EnablePcap("STA_D", staDeviceD.Get(0));
367 }
368
369 Simulator::Stop(simulationTime + Seconds(1.0));
371
372 /* Show results */
373 double totalPacketsThroughA = DynamicCast<UdpServer>(serverAppA.Get(0))->GetReceived();
374 double totalPacketsThroughB = DynamicCast<UdpServer>(serverAppB.Get(0))->GetReceived();
375 double totalPacketsThroughC = DynamicCast<UdpServer>(serverAppC.Get(0))->GetReceived();
376 double totalPacketsThroughD = DynamicCast<UdpServer>(serverAppD.Get(0))->GetReceived();
377
379
380 auto throughput = totalPacketsThroughA * payloadSize * 8 / simulationTime.GetMicroSeconds();
381 std::cout << "AC_BE with default TXOP limit (0ms): " << '\n'
382 << " Throughput = " << throughput << " Mbit/s" << '\n';
383 if (verifyResults && (throughput < 28 || throughput > 29))
384 {
385 NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!");
386 exit(1);
387 }
388
389 throughput = totalPacketsThroughB * payloadSize * 8 / simulationTime.GetMicroSeconds();
390 std::cout << "AC_BE with non-default TXOP limit (4.096ms): " << '\n'
391 << " Throughput = " << throughput << " Mbit/s" << '\n';
392 if (verifyResults && (throughput < 36.5 || throughput > 37))
393 {
394 NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!");
395 exit(1);
396 }
397 std::cout << " Maximum TXOP duration = " << beTxopTracer.m_max.GetMicroSeconds() << " us"
398 << '\n';
399 if (verifyResults &&
400 (beTxopTracer.m_max < MicroSeconds(3008) || beTxopTracer.m_max > txopLimit))
401 {
402 NS_LOG_ERROR("Maximum TXOP duration " << beTxopTracer.m_max
403 << " is not in the expected boundaries!");
404 exit(1);
405 }
406
407 throughput = totalPacketsThroughC * payloadSize * 8 / simulationTime.GetMicroSeconds();
408 std::cout << "AC_VI with default TXOP limit (4.096ms): " << '\n'
409 << " Throughput = " << throughput << " Mbit/s" << '\n';
410 if (verifyResults && (throughput < 36.5 || throughput > 37.5))
411 {
412 NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!");
413 exit(1);
414 }
415 std::cout << " Maximum TXOP duration = " << viTxopTracer.m_max.GetMicroSeconds() << " us"
416 << '\n';
417 if (verifyResults &&
418 (viTxopTracer.m_max < MicroSeconds(3008) || viTxopTracer.m_max > txopLimit))
419 {
420 NS_LOG_ERROR("Maximum TXOP duration " << viTxopTracer.m_max
421 << " is not in the expected boundaries!");
422 exit(1);
423 }
424
425 throughput = totalPacketsThroughD * payloadSize * 8 / simulationTime.GetMicroSeconds();
426 std::cout << "AC_VI with non-default TXOP limit (0ms): " << '\n'
427 << " Throughput = " << throughput << " Mbit/s" << '\n';
428 if (verifyResults && (throughput < 31.5 || throughput > 32.5))
429 {
430 NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!");
431 exit(1);
432 }
433
434 return 0;
435}
holds a vector of ns3::Application pointers.
void Start(Time start) const
Start all of the Applications in this container at the start time given as a parameter.
Ptr< Application > Get(uint32_t i) const
Get the Ptr<Application> stored in this container at a given index.
void Stop(Time stop) const
Arrange for all of the Applications in this container to Stop() at the Time given as a parameter.
Parse command-line arguments.
an Inet address class
aggregate IP/TCP/UDP functionality to existing Nodes.
A helper class to make life easier while doing simple IPv4 address assignment in scripts.
holds a vector of std::pair of Ptr<Ipv4> and interface index.
Ipv4Address GetAddress(uint32_t i, uint32_t j=0) const
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition node.cc:138
A helper to make it easier to instantiate an ns3::OnOffApplication on a set of nodes.
AttributeValue implementation for Pointer.
Ptr< T > Get() const
Definition pointer.h:223
Smart pointer class similar to boost::intrusive_ptr.
Handles the packet queue and stores DCF/EDCA access parameters (one Txop per AC).
Definition qos-txop.h:52
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
Hold variables of type string.
Definition string.h:45
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
Create a server application which waits for input UDP packets and uses the information carried into t...
Hold an unsigned integer type.
Definition uinteger.h:34
helps to create WifiNetDevice objects
create MAC layers for a ns3::WifiNetDevice.
@ DLT_IEEE802_11_RADIO
Include Radiotap link layer information.
manage and create wifi channel objects for the YANS model.
static YansWifiChannelHelper Default()
Create a channel helper in a default working state.
Make it easy to create and manage PHY objects for the YANS model.
uint16_t port
Definition dsdv-manet.cc:33
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:243
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
@ WIFI_STANDARD_80211a
address
Definition first.py:36
stack
Definition first.py:33
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
ssid
Definition third.py:82
channel
Definition third.py:77
mac
Definition third.py:81
wifi
Definition third.py:84
mobility
Definition third.py:92
wifiStaNodes
Definition third.py:73
phy
Definition third.py:78
Keeps the maximum duration among all TXOPs.
void Trace(Time startTime, Time duration, uint8_t linkId)
Callback connected to TXOP duration trace source.
Time m_max
maximum TXOP duration
std::ofstream throughput