A Discrete-Event Network Simulator
API
tx-duration-test.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2009 CTTC
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Authors: Nicola Baldo <nbaldo@cttc.es>
19  * S├ębastien Deronne <sebastien.deronne@gmail.com>
20  */
21 
22 #include "ns3/log.h"
23 #include "ns3/simulator.h"
24 #include "ns3/test.h"
25 #include "ns3/yans-wifi-phy.h"
26 #include "ns3/he-ru.h"
27 #include "ns3/wifi-psdu.h"
28 #include "ns3/packet.h"
29 #include "ns3/dsss-phy.h"
30 #include "ns3/erp-ofdm-phy.h"
31 #include "ns3/he-phy.h" //includes OFDM, HT, and VHT
32 #include <numeric>
33 
34 using namespace ns3;
35 
36 NS_LOG_COMPONENT_DEFINE ("InterferenceHelperTxDurationTest");
37 
44 class TxDurationTest : public TestCase
45 {
46 public:
47  TxDurationTest ();
48  virtual ~TxDurationTest ();
49  void DoRun (void) override;
50 
51 
52 private:
66  bool CheckPayloadDuration (uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration);
67 
81  bool CheckTxDuration (uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration);
82 
95  static bool CheckHeMuTxDuration (std::list<uint32_t> sizes, std::list<HeMuUserInfo> userInfos,
96  uint16_t channelWidth, uint16_t guardInterval,
97  Time knownDuration);
98 
113  static Time CalculateTxDurationUsingList (std::list<uint32_t> sizes, std::list<uint16_t> staIds,
114  WifiTxVector txVector, WifiPhyBand band);
115 };
116 
118  : TestCase ("Wifi TX Duration")
119 {
120 }
121 
123 {
124 }
125 
126 bool
127 TxDurationTest::CheckPayloadDuration (uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
128 {
129  WifiTxVector txVector;
130  txVector.SetMode (payloadMode);
131  txVector.SetPreambleType (preamble);
132  txVector.SetChannelWidth (channelWidth);
133  txVector.SetGuardInterval (guardInterval);
134  txVector.SetNss (1);
135  txVector.SetStbc (0);
136  txVector.SetNess (0);
138  Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy> ();
139  if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_OFDM
140  || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT
141  || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_VHT
142  || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HE)
143  {
144  band = WIFI_PHY_BAND_5GHZ;
145  }
146  Time calculatedDuration = phy->GetPayloadDuration (size, txVector, band);
147  if (calculatedDuration != knownDuration)
148  {
149  std::cerr << "size=" << size
150  << " mode=" << payloadMode
151  << " channelWidth=" << channelWidth
152  << " guardInterval=" << guardInterval
153  << " datarate=" << payloadMode.GetDataRate (channelWidth, guardInterval, 1)
154  << " known=" << knownDuration
155  << " calculated=" << calculatedDuration
156  << std::endl;
157  return false;
158  }
159  if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HE)
160  {
161  //Durations vary depending on frequency; test also 2.4 GHz (bug 1971)
162  band = WIFI_PHY_BAND_2_4GHZ;
163  calculatedDuration = phy->GetPayloadDuration (size, txVector, band);
164  knownDuration += MicroSeconds (6);
165  if (calculatedDuration != knownDuration)
166  {
167  std::cerr << "size=" << size
168  << " mode=" << payloadMode
169  << " channelWidth=" << channelWidth
170  << " guardInterval=" << guardInterval
171  << " datarate=" << payloadMode.GetDataRate (channelWidth, guardInterval, 1)
172  << " known=" << knownDuration
173  << " calculated=" << calculatedDuration
174  << std::endl;
175  return false;
176  }
177  }
178  return true;
179 }
180 
181 bool
182 TxDurationTest::CheckTxDuration (uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
183 {
184  WifiTxVector txVector;
185  txVector.SetMode (payloadMode);
186  txVector.SetPreambleType (preamble);
187  txVector.SetChannelWidth (channelWidth);
188  txVector.SetGuardInterval (guardInterval);
189  txVector.SetNss (1);
190  txVector.SetStbc (0);
191  txVector.SetNess (0);
193  Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy> ();
194  if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_OFDM
195  || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT
196  || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_VHT
197  || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HE)
198  {
199  band = WIFI_PHY_BAND_5GHZ;
200  }
201  Time calculatedDuration = phy->CalculateTxDuration (size, txVector, band);
202  Time calculatedDurationUsingList = CalculateTxDurationUsingList (std::list<uint32_t> {size}, std::list<uint16_t> {SU_STA_ID},
203  txVector, band);
204  if (calculatedDuration != knownDuration || calculatedDuration != calculatedDurationUsingList)
205  {
206  std::cerr << "size=" << size
207  << " mode=" << payloadMode
208  << " channelWidth=" << +channelWidth
209  << " guardInterval=" << guardInterval
210  << " datarate=" << payloadMode.GetDataRate (channelWidth, guardInterval, 1)
211  << " preamble=" << preamble
212  << " known=" << knownDuration
213  << " calculated=" << calculatedDuration
214  << " calculatedUsingList=" << calculatedDurationUsingList
215  << std::endl;
216  return false;
217  }
218  if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HE)
219  {
220  //Durations vary depending on frequency; test also 2.4 GHz (bug 1971)
221  band = WIFI_PHY_BAND_2_4GHZ;
222  calculatedDuration = phy->CalculateTxDuration (size, txVector, band);
223  calculatedDurationUsingList = CalculateTxDurationUsingList (std::list<uint32_t> {size}, std::list<uint16_t> {SU_STA_ID},
224  txVector, band);
225  knownDuration += MicroSeconds (6);
226  if (calculatedDuration != knownDuration || calculatedDuration != calculatedDurationUsingList)
227  {
228  std::cerr << "size=" << size
229  << " mode=" << payloadMode
230  << " channelWidth=" << channelWidth
231  << " guardInterval=" << guardInterval
232  << " datarate=" << payloadMode.GetDataRate (channelWidth, guardInterval, 1)
233  << " preamble=" << preamble
234  << " known=" << knownDuration
235  << " calculated=" << calculatedDuration
236  << " calculatedUsingList=" << calculatedDurationUsingList
237  << std::endl;
238  return false;
239  }
240  }
241  return true;
242 }
243 
244 bool
245 TxDurationTest::CheckHeMuTxDuration (std::list<uint32_t> sizes, std::list<HeMuUserInfo> userInfos,
246  uint16_t channelWidth, uint16_t guardInterval,
247  Time knownDuration)
248 {
249  NS_ASSERT (sizes.size () == userInfos.size () && sizes.size () > 1);
250  NS_ABORT_MSG_IF (channelWidth < std::accumulate (std::begin (userInfos), std::end (userInfos), 0,
251  [](const uint16_t prevBw, const HeMuUserInfo &info)
252  { return prevBw + HeRu::GetBandwidth (info.ru.GetRuType ()); }),
253  "Cannot accommodate all the RUs in the provided band"); //MU-MIMO (for which allocations use the same RU) is not supported
254  WifiTxVector txVector;
256  txVector.SetChannelWidth (channelWidth);
257  txVector.SetGuardInterval (guardInterval);
258  txVector.SetStbc (0);
259  txVector.SetNess (0);
260  std::list<uint16_t> staIds;
261  uint16_t staId = 1;
262  for (const auto & userInfo : userInfos)
263  {
264  txVector.SetHeMuUserInfo (staId, userInfo);
265  staIds.push_back (staId++);
266  }
267  Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy> ();
268  std::list<WifiPhyBand> testedBands {WIFI_PHY_BAND_5GHZ, WIFI_PHY_BAND_2_4GHZ}; //Durations vary depending on frequency; test also 2.4 GHz (bug 1971)
269  for (auto & testedBand : testedBands)
270  {
271  if (testedBand == WIFI_PHY_BAND_2_4GHZ)
272  {
273  knownDuration += MicroSeconds (6);
274  }
275  Time calculatedDuration = NanoSeconds (0);
276  uint32_t longuestSize = 0;
277  auto iterStaId = staIds.begin ();
278  for (auto & size : sizes)
279  {
280  Time ppduDurationForSta = phy->CalculateTxDuration (size, txVector, testedBand, *iterStaId);
281  if (ppduDurationForSta > calculatedDuration)
282  {
283  calculatedDuration = ppduDurationForSta;
284  staId = *iterStaId;
285  longuestSize = size;
286  }
287  ++iterStaId;
288  }
289  Time calculatedDurationUsingList = CalculateTxDurationUsingList (sizes, staIds, txVector, testedBand);
290  if (calculatedDuration != knownDuration || calculatedDuration != calculatedDurationUsingList)
291  {
292  std::cerr << "size=" << longuestSize
293  << " band=" << testedBand
294  << " staId=" << staId
295  << " nss=" << +txVector.GetNss (staId)
296  << " mode=" << txVector.GetMode (staId)
297  << " channelWidth=" << channelWidth
298  << " guardInterval=" << guardInterval
299  << " datarate=" << txVector.GetMode (staId).GetDataRate (channelWidth, guardInterval, txVector.GetNss (staId))
300  << " known=" << knownDuration
301  << " calculated=" << calculatedDuration
302  << " calculatedUsingList=" << calculatedDurationUsingList
303  << std::endl;
304  return false;
305  }
306  }
307  return true;
308 }
309 
310 Time
311 TxDurationTest::CalculateTxDurationUsingList (std::list<uint32_t> sizes, std::list<uint16_t> staIds,
312  WifiTxVector txVector, WifiPhyBand band)
313 {
314  NS_ASSERT (sizes.size () == staIds.size ());
315  WifiConstPsduMap psduMap;
316  auto itStaId = staIds.begin ();
317  WifiMacHeader hdr;
318  hdr.SetType (WIFI_MAC_CTL_ACK); //so that size may not be empty while being as short as possible
319  for (auto & size : sizes)
320  {
321  // MAC header and FCS are to deduce from size
322  psduMap[*itStaId++] = Create<WifiPsdu> (Create<Packet> (size - hdr.GetSerializedSize () - 4), hdr);
323  }
324  return WifiPhy::CalculateTxDuration (psduMap, txVector, band);
325 }
326 
327 void
329 {
330  bool retval = true;
331 
332  //IEEE Std 802.11-2007 Table 18-2 "Example of LENGTH calculations for CCK"
333  retval = retval
334  && CheckPayloadDuration (1023, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (744))
335  && CheckPayloadDuration (1024, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (745))
336  && CheckPayloadDuration (1025, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (746))
337  && CheckPayloadDuration (1026, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (747));
338 
339  NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11b CCK duration failed");
340 
341  //Similar, but we add PHY preamble and header durations
342  //and we test different rates.
343  //The payload durations for modes other than 11mbb have been
344  //calculated by hand according to IEEE Std 802.11-2007 18.2.3.5
345  retval = retval
346  && CheckTxDuration (1023, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (744 + 96))
347  && CheckTxDuration (1024, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (745 + 96))
348  && CheckTxDuration (1025, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (746 + 96))
349  && CheckTxDuration (1026, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (747 + 96))
350  && CheckTxDuration (1023, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (744 + 192))
351  && CheckTxDuration (1024, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (745 + 192))
352  && CheckTxDuration (1025, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (746 + 192))
353  && CheckTxDuration (1026, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (747 + 192))
354  && CheckTxDuration (1023, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (1488 + 96))
355  && CheckTxDuration (1024, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (1490 + 96))
356  && CheckTxDuration (1025, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (1491 + 96))
357  && CheckTxDuration (1026, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (1493 + 96))
358  && CheckTxDuration (1023, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (1488 + 192))
359  && CheckTxDuration (1024, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (1490 + 192))
360  && CheckTxDuration (1025, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (1491 + 192))
361  && CheckTxDuration (1026, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (1493 + 192))
362  && CheckTxDuration (1023, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (4092 + 96))
363  && CheckTxDuration (1024, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (4096 + 96))
364  && CheckTxDuration (1025, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (4100 + 96))
365  && CheckTxDuration (1026, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (4104 + 96))
366  && CheckTxDuration (1023, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (4092 + 192))
367  && CheckTxDuration (1024, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (4096 + 192))
368  && CheckTxDuration (1025, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (4100 + 192))
369  && CheckTxDuration (1026, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (4104 + 192))
370  && CheckTxDuration (1023, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (8184 + 192))
371  && CheckTxDuration (1024, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (8192 + 192))
372  && CheckTxDuration (1025, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (8200 + 192))
373  && CheckTxDuration (1026, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (8208 + 192))
374  && CheckTxDuration (1023, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (8184 + 192))
375  && CheckTxDuration (1024, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (8192 + 192))
376  && CheckTxDuration (1025, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (8200 + 192))
377  && CheckTxDuration (1026, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (8208 + 192));
378 
379  //values from http://mailman.isi.edu/pipermail/ns-developers/2009-July/006226.html
380  retval = retval && CheckTxDuration (14, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (304));
381 
382  //values from http://www.oreillynet.com/pub/a/wireless/2003/08/08/wireless_throughput.html
383  retval = retval
384  && CheckTxDuration (1536, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (1310))
385  && CheckTxDuration (76, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (248))
386  && CheckTxDuration (14, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (203));
387 
388  NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11b duration failed");
389 
390  //802.11a durations
391  //values from http://www.oreillynet.com/pub/a/wireless/2003/08/08/wireless_throughput.html
392  retval = retval
393  && CheckTxDuration (1536, OfdmPhy::GetOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (248))
394  && CheckTxDuration (76, OfdmPhy::GetOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (32))
395  && CheckTxDuration (14, OfdmPhy::GetOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (24));
396 
397  NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11a duration failed");
398 
399  //802.11g durations are same as 802.11a durations but with 6 us signal extension
400  retval = retval
401  && CheckTxDuration (1536, ErpOfdmPhy::GetErpOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (254))
402  && CheckTxDuration (76, ErpOfdmPhy::GetErpOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (38))
403  && CheckTxDuration (14, ErpOfdmPhy::GetErpOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (30));
404 
405  NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11g duration failed");
406 
407  //802.11n durations
408  retval = retval
409  && CheckTxDuration (1536, HtPhy::GetHtMcs7 (), 20, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (228))
410  && CheckTxDuration (76, HtPhy::GetHtMcs7 (), 20, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (48))
411  && CheckTxDuration (14, HtPhy::GetHtMcs7 (), 20, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (40))
412  && CheckTxDuration (1536, HtPhy::GetHtMcs0 (), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (1742400))
413  && CheckTxDuration (76, HtPhy::GetHtMcs0 (), 20, 400, WIFI_PREAMBLE_HT_MF, MicroSeconds (126))
414  && CheckTxDuration (14, HtPhy::GetHtMcs0 (), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (57600))
415  && CheckTxDuration (1536, HtPhy::GetHtMcs6 (), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (226800))
416  && CheckTxDuration (76, HtPhy::GetHtMcs6 (), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (46800))
417  && CheckTxDuration (14, HtPhy::GetHtMcs6 (), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (39600))
418  && CheckTxDuration (1536, HtPhy::GetHtMcs7 (), 40, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (128))
419  && CheckTxDuration (76, HtPhy::GetHtMcs7 (), 40, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (44))
420  && CheckTxDuration (14, HtPhy::GetHtMcs7 (), 40, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (40))
421  && CheckTxDuration (1536, HtPhy::GetHtMcs7 (), 40, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (118800))
422  && CheckTxDuration (76, HtPhy::GetHtMcs7 (), 40, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (43200))
423  && CheckTxDuration (14, HtPhy::GetHtMcs7 (), 40, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (39600));
424 
425  NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11n duration failed");
426 
427  //802.11ac durations
428  retval = retval
429  && CheckTxDuration (1536, VhtPhy::GetVhtMcs8 (), 20, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (196))
430  && CheckTxDuration (76, VhtPhy::GetVhtMcs8 (), 20, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (48))
431  && CheckTxDuration (14, VhtPhy::GetVhtMcs8 (), 20, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
432  && CheckTxDuration (1536, VhtPhy::GetVhtMcs8 (), 20, 400, WIFI_PREAMBLE_VHT_SU, MicroSeconds (180))
433  && CheckTxDuration (76, VhtPhy::GetVhtMcs8 (), 20, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (46800))
434  && CheckTxDuration (14, VhtPhy::GetVhtMcs8 (), 20, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
435  && CheckTxDuration (1536, VhtPhy::GetVhtMcs9 (), 40, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (108))
436  && CheckTxDuration (76, VhtPhy::GetVhtMcs9 (), 40, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
437  && CheckTxDuration (14, VhtPhy::GetVhtMcs9 (), 40, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
438  && CheckTxDuration (1536, VhtPhy::GetVhtMcs9 (), 40, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (100800))
439  && CheckTxDuration (76, VhtPhy::GetVhtMcs9 (), 40, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
440  && CheckTxDuration (14, VhtPhy::GetVhtMcs9 (), 40, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
441  && CheckTxDuration (1536, VhtPhy::GetVhtMcs0 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (460))
442  && CheckTxDuration (76, VhtPhy::GetVhtMcs0 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (60))
443  && CheckTxDuration (14, VhtPhy::GetVhtMcs0 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (44))
444  && CheckTxDuration (1536, VhtPhy::GetVhtMcs0 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (417600))
445  && CheckTxDuration (76, VhtPhy::GetVhtMcs0 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (57600))
446  && CheckTxDuration (14, VhtPhy::GetVhtMcs0 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (43200))
447  && CheckTxDuration (1536, VhtPhy::GetVhtMcs9 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (68))
448  && CheckTxDuration (76, VhtPhy::GetVhtMcs9 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
449  && CheckTxDuration (14, VhtPhy::GetVhtMcs9 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
450  && CheckTxDuration (1536, VhtPhy::GetVhtMcs9 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (64800))
451  && CheckTxDuration (76, VhtPhy::GetVhtMcs9 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
452  && CheckTxDuration (14, VhtPhy::GetVhtMcs9 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
453  && CheckTxDuration (1536, VhtPhy::GetVhtMcs8 (), 160, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (56))
454  && CheckTxDuration (76, VhtPhy::GetVhtMcs8 (), 160, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
455  && CheckTxDuration (14, VhtPhy::GetVhtMcs8 (), 160, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
456  && CheckTxDuration (1536, VhtPhy::GetVhtMcs8 (), 160, 400, WIFI_PREAMBLE_VHT_SU, MicroSeconds (54))
457  && CheckTxDuration (76, VhtPhy::GetVhtMcs8 (), 160, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
458  && CheckTxDuration (14, VhtPhy::GetVhtMcs8 (), 160, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600));
459 
460  NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11ac duration failed");
461 
462  //802.11ax SU durations
463  retval = retval
464  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (1485600))
465  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (125600))
466  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (71200))
467  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (764800))
468  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (84800))
469  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
470  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (397600))
471  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (71200))
472  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
473  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (220800))
474  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
475  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
476  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (1570400))
477  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (130400))
478  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (72800))
479  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (807200))
480  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (87200))
481  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
482  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (418400))
483  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (72800))
484  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
485  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (231200))
486  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
487  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
488  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (1740))
489  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (140))
490  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (76))
491  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (892))
492  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (92))
493  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
494  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (460))
495  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (76))
496  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
497  && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (252))
498  && CheckTxDuration (76, HePhy::GetHeMcs0 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
499  && CheckTxDuration (14, HePhy::GetHeMcs0 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
500  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (139200))
501  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
502  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
503  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (98400))
504  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
505  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
506  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (71200))
507  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
508  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
509  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
510  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
511  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
512  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (144800))
513  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
514  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
515  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (101600))
516  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
517  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
518  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (72800))
519  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
520  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
521  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
522  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
523  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
524  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (156))
525  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
526  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
527  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (108))
528  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
529  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
530  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (76))
531  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
532  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
533  && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
534  && CheckTxDuration (76, HePhy::GetHeMcs11 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
535  && CheckTxDuration (14, HePhy::GetHeMcs11 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60));
536 
537  NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11ax SU duration failed");
538 
539  //802.11ax MU durations
540  retval = retval
541  && CheckHeMuTxDuration (std::list<uint32_t> {1536,
542  1536},
543  std::list<HeMuUserInfo> { {{HeRu::RU_242_TONE, 1, true}, HePhy::GetHeMcs0 (), 1},
544  {{HeRu::RU_242_TONE, 2, true}, HePhy::GetHeMcs0 (), 1} },
545  40, 800, NanoSeconds (1493600)) //equivalent to HE_SU for 20 MHz with 2 extra HE-SIG-B (i.e. 8 us)
546  && CheckHeMuTxDuration (std::list<uint32_t> {1536,
547  1536},
548  std::list<HeMuUserInfo> { {{HeRu::RU_242_TONE, 1, true}, HePhy::GetHeMcs1 (), 1},
549  {{HeRu::RU_242_TONE, 2, true}, HePhy::GetHeMcs0 (), 1} },
550  40, 800, NanoSeconds (1493600)) //shouldn't change if first PSDU is shorter
551  && CheckHeMuTxDuration (std::list<uint32_t> {1536,
552  76},
553  std::list<HeMuUserInfo> { {{HeRu::RU_242_TONE, 1, true}, HePhy::GetHeMcs0 (), 1},
554  {{HeRu::RU_242_TONE, 2, true}, HePhy::GetHeMcs0 (), 1} },
555  40, 800, NanoSeconds (1493600));
556 
557  NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11ax MU duration failed");
558 
559  Simulator::Destroy ();
560 }
561 
569 {
570 public:
572  virtual ~HeSigBDurationTest ();
573  void DoRun (void) override;
574 
575 private:
584  static WifiTxVector BuildTxVector (uint16_t bw, std::list <HeMuUserInfo> userInfos);
585 };
586 
588  : TestCase ("Check HE-SIG-B duration computation")
589 {
590 }
591 
593 {
594 }
595 
597 HeSigBDurationTest::BuildTxVector (uint16_t bw, std::list <HeMuUserInfo> userInfos)
598 {
599  WifiTxVector txVector;
601  txVector.SetChannelWidth (bw);
602  txVector.SetGuardInterval (3200);
603  txVector.SetStbc (0);
604  txVector.SetNess (0);
605  std::list<uint16_t> staIds;
606  uint16_t staId = 1;
607  for (const auto & userInfo : userInfos)
608  {
609  txVector.SetHeMuUserInfo (staId, userInfo);
610  staIds.push_back (staId++);
611  }
612  return txVector;
613 }
614 
615 void
617 {
618  const auto & hePhy = WifiPhy::GetStaticPhyEntity(WIFI_MOD_CLASS_HE);
619 
620  //20 MHz band
621  std::list<HeMuUserInfo> userInfos;
622  userInfos.push_back ({{HeRu::RU_106_TONE, 1, true}, HePhy::GetHeMcs11 (), 1});
623  userInfos.push_back ({{HeRu::RU_106_TONE, 2, true}, HePhy::GetHeMcs10 (), 4});
624  WifiTxVector txVector = BuildTxVector (20, userInfos);
625  NS_TEST_EXPECT_MSG_EQ (hePhy->GetSigMode (WIFI_PPDU_FIELD_SIG_B, txVector), VhtPhy::GetVhtMcs5 (), "HE-SIG-B should be sent at MCS 5");
626  std::pair<std::size_t, std::size_t> numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
627  NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 2, "Both users should be on HE-SIG-B content channel 1");
628  NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 0, "Both users should be on HE-SIG-B content channel 2");
629  NS_TEST_EXPECT_MSG_EQ (hePhy->GetDuration (WIFI_PPDU_FIELD_SIG_B, txVector), MicroSeconds (4), "HE-SIG-B should only last one OFDM symbol");
630 
631  //40 MHz band, even number of users per HE-SIG-B content channel
632  userInfos.push_back ({{HeRu::RU_52_TONE, 5, true}, HePhy::GetHeMcs4 (), 1});
633  userInfos.push_back ({{HeRu::RU_52_TONE, 6, true}, HePhy::GetHeMcs6 (), 2});
634  userInfos.push_back ({{HeRu::RU_52_TONE, 7, true}, HePhy::GetHeMcs5 (), 3});
635  userInfos.push_back ({{HeRu::RU_52_TONE, 8, true}, HePhy::GetHeMcs6 (), 2});
636  txVector = BuildTxVector (40, userInfos);
637  NS_TEST_EXPECT_MSG_EQ (hePhy->GetSigMode (WIFI_PPDU_FIELD_SIG_B, txVector), VhtPhy::GetVhtMcs4 (), "HE-SIG-B should be sent at MCS 4");
638  numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
639  NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 2, "Two users should be on HE-SIG-B content channel 1");
640  NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 4, "Four users should be on HE-SIG-B content channel 2");
641  NS_TEST_EXPECT_MSG_EQ (hePhy->GetDuration (WIFI_PPDU_FIELD_SIG_B, txVector), MicroSeconds (4), "HE-SIG-B should only last one OFDM symbol");
642 
643  //40 MHz band, odd number of users per HE-SIG-B content channel
644  userInfos.push_back ({{HeRu::RU_26_TONE, 13, true}, HePhy::GetHeMcs3 (), 1});
645  txVector = BuildTxVector (40, userInfos);
646  NS_TEST_EXPECT_MSG_EQ (hePhy->GetSigMode (WIFI_PPDU_FIELD_SIG_B, txVector), VhtPhy::GetVhtMcs3 (), "HE-SIG-B should be sent at MCS 3");
647  numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
648  NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 2, "Two users should be on HE-SIG-B content channel 1");
649  NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 5, "Five users should be on HE-SIG-B content channel 2");
650  NS_TEST_EXPECT_MSG_EQ (hePhy->GetDuration (WIFI_PPDU_FIELD_SIG_B, txVector), MicroSeconds (8), "HE-SIG-B should last two OFDM symbols");
651 
652  //80 MHz band
653  userInfos.push_back ({{HeRu::RU_242_TONE, 3, true}, HePhy::GetHeMcs1 (), 1});
654  userInfos.push_back ({{HeRu::RU_242_TONE, 4, true}, HePhy::GetHeMcs4 (), 1});
655  txVector = BuildTxVector (80, userInfos);
656  NS_TEST_EXPECT_MSG_EQ (hePhy->GetSigMode (WIFI_PPDU_FIELD_SIG_B, txVector), VhtPhy::GetVhtMcs1 (), "HE-SIG-B should be sent at MCS 1");
657  numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
658  NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 3, "Three users should be on HE-SIG-B content channel 1");
659  NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 6, "Six users should be on HE-SIG-B content channel 2");
660  NS_TEST_EXPECT_MSG_EQ (hePhy->GetDuration (WIFI_PPDU_FIELD_SIG_B, txVector), MicroSeconds (16), "HE-SIG-B should last four OFDM symbols");
661 
662  //160 MHz band
663  userInfos.push_back ({{HeRu::RU_996_TONE, 1, false}, HePhy::GetHeMcs1 (), 1});
664  txVector = BuildTxVector (160, userInfos);
665  NS_TEST_EXPECT_MSG_EQ (hePhy->GetSigMode (WIFI_PPDU_FIELD_SIG_B, txVector), VhtPhy::GetVhtMcs1 (), "HE-SIG-B should be sent at MCS 1");
666  numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
667  NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 4, "Four users should be on HE-SIG-B content channel 1");
668  NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 7, "Seven users should be on HE-SIG-B content channel 2");
669  NS_TEST_EXPECT_MSG_EQ (hePhy->GetDuration (WIFI_PPDU_FIELD_SIG_B, txVector), MicroSeconds (20), "HE-SIG-B should last five OFDM symbols");
670 }
671 
679 {
680 public:
682  virtual ~PhyHeaderSectionsTest ();
683  void DoRun (void) override;
684 
685 
686 private:
696 };
697 
699  : TestCase ("PHY header sections consistency")
700 {
701 }
702 
704 {
705 }
706 
707 void
710 {
711  NS_TEST_EXPECT_MSG_EQ (obtained.size (), expected.size (), "The expected map size (" << expected.size () << ") was not obtained (" << obtained.size () << ")");
712 
713  auto itObtained = obtained.begin ();
714  auto itExpected = expected.begin ();
715  for (;itObtained != obtained.end () || itExpected != expected.end ();)
716  {
717  WifiPpduField field = itObtained->first;
718  auto window = itObtained->second.first;
719  auto mode = itObtained->second.second;
720 
721  WifiPpduField fieldRef = itExpected->first;
722  auto windowRef = itExpected->second.first;
723  auto modeRef = itExpected->second.second;
724 
725  NS_TEST_EXPECT_MSG_EQ (field, fieldRef, "The expected PPDU field (" << fieldRef << ") was not obtained (" << field << ")");
726  NS_TEST_EXPECT_MSG_EQ (window.first, windowRef.first, "The expected start time (" << windowRef.first << ") was not obtained (" << window.first << ")");
727  NS_TEST_EXPECT_MSG_EQ (window.second, windowRef.second, "The expected stop time (" << windowRef.second << ") was not obtained (" << window.second << ")");
728  NS_TEST_EXPECT_MSG_EQ (mode, modeRef, "The expected mode (" << modeRef << ") was not obtained (" << mode << ")");
729  ++itObtained;
730  ++itExpected;
731  }
732 }
733 
734 void
736 {
737  Time ppduStart = Seconds (1.0);
738  Ptr<PhyEntity> phyEntity;
740  WifiTxVector txVector;
741  WifiMode nonHtMode;
742 
743 
744  // ==================================================================================
745  // 11b (HR/DSSS)
746  phyEntity = Create<DsssPhy> ();
747  txVector.SetMode (DsssPhy::GetDsssRate1Mbps ());
748  txVector.SetChannelWidth (22);
749 
750  // -> long PPDU format
752  nonHtMode = DsssPhy::GetDsssRate1Mbps ();
753  sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
754  ppduStart + MicroSeconds (144) },
755  nonHtMode } },
756  { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (144),
757  ppduStart + MicroSeconds (192) },
758  nonHtMode } } };
759  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
760 
761  // -> long PPDU format if data rate is 1 Mbps (even if preamble is tagged short)
763  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
764 
765  // -> short PPDU format
766  txVector.SetMode (DsssPhy::GetDsssRate11Mbps ());
767  nonHtMode = DsssPhy::GetDsssRate2Mbps ();
769  sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
770  ppduStart + MicroSeconds (72) },
771  nonHtMode } },
772  { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (72),
773  ppduStart + MicroSeconds (96) },
774  nonHtMode } } };
775  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
776 
777 
778  // ==================================================================================
779  // 11a (OFDM)
781 
782  // -> one iteration per variant: default, 10 MHz, and 5 MHz
783  std::map<OfdmPhyVariant, std::size_t> variants { //number to use to deduce rate and BW info for each variant
784  { OFDM_PHY_DEFAULT, 1},
785  { OFDM_PHY_10_MHZ, 2},
786  { OFDM_PHY_5_MHZ, 4}
787  };
788  for (auto variant : variants)
789  {
790  phyEntity = Create<OfdmPhy> (variant.first);
791  std::size_t ratio = variant.second;
792  uint16_t bw = 20 / ratio; //MHz
793  txVector.SetChannelWidth (bw);
794  txVector.SetMode (OfdmPhy::GetOfdmRate (12000000 / ratio, bw));
795  nonHtMode = OfdmPhy::GetOfdmRate (6000000 / ratio, bw);
796  sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
797  ppduStart + MicroSeconds (16 * ratio) },
798  nonHtMode } },
799  { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (16 * ratio),
800  ppduStart + MicroSeconds (20 * ratio) },
801  nonHtMode } } };
802  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
803  }
804 
805 
806  // ==================================================================================
807  // 11g (ERP-OFDM)
808  phyEntity = Create<ErpOfdmPhy> ();
809  txVector.SetChannelWidth (20);
810  txVector.SetMode (ErpOfdmPhy::GetErpOfdmRate (54000000));
811  nonHtMode = ErpOfdmPhy::GetErpOfdmRate6Mbps ();
812  sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
813  ppduStart + MicroSeconds (16) },
814  nonHtMode } },
815  { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (16),
816  ppduStart + MicroSeconds (20) },
817  nonHtMode } } };
818  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
819 
820 
821  // ==================================================================================
822  // 11n (HT)
823  phyEntity = Create<HtPhy> (4);
824  txVector.SetChannelWidth (20);
825  txVector.SetMode (HtPhy::GetHtMcs6 ());
826  nonHtMode = OfdmPhy::GetOfdmRate6Mbps ();
827  WifiMode htSigMode = nonHtMode;
828 
829  // -> HT-mixed format for 2 SS and no ESS
831  txVector.SetNss (2);
832  txVector.SetNess (0);
833  sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
834  ppduStart + MicroSeconds (16) },
835  nonHtMode } },
836  { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (16),
837  ppduStart + MicroSeconds (20) },
838  nonHtMode } },
839  { WIFI_PPDU_FIELD_HT_SIG, { { ppduStart + MicroSeconds (20),
840  ppduStart + MicroSeconds (28) },
841  htSigMode } },
842  { WIFI_PPDU_FIELD_TRAINING, { { ppduStart + MicroSeconds (28),
843  ppduStart + MicroSeconds (40) }, // 1 HT-STF + 2 HT-LTFs
844  htSigMode } } };
845  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
846  txVector.SetChannelWidth (20); //shouldn't have any impact
847  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
848 
849  // -> HT-mixed format for 3 SS and 1 ESS
850  txVector.SetNss (3);
851  txVector.SetNess (1);
852  sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (28),
853  ppduStart + MicroSeconds (52) }, // 1 HT-STF + 5 HT-LTFs (4 data + 1 extension)
854  htSigMode };
855  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
856 
857 
858  // ==================================================================================
859  // 11ac (VHT)
860  phyEntity = Create<VhtPhy> ();
861  txVector.SetChannelWidth (20);
862  txVector.SetNess (0);
863  txVector.SetMode (VhtPhy::GetVhtMcs7 ());
864  WifiMode sigAMode = nonHtMode;
865  WifiMode sigBMode = VhtPhy::GetVhtMcs0 ();
866 
867  // -> VHT SU format for 5 SS
869  txVector.SetNss (5);
870  sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
871  ppduStart + MicroSeconds (16) },
872  nonHtMode } },
873  { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (16),
874  ppduStart + MicroSeconds (20) },
875  nonHtMode } },
876  { WIFI_PPDU_FIELD_SIG_A, { { ppduStart + MicroSeconds (20),
877  ppduStart + MicroSeconds (28) },
878  sigAMode } },
879  { WIFI_PPDU_FIELD_TRAINING, { { ppduStart + MicroSeconds (28),
880  ppduStart + MicroSeconds (56) }, // 1 VHT-STF + 6 VHT-LTFs
881  sigAMode } } };
882  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
883 
884  // -> VHT SU format for 7 SS
885  txVector.SetNss (7);
886  sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (28),
887  ppduStart + MicroSeconds (64) }, // 1 VHT-STF + 8 VHT-LTFs
888  sigAMode };
889  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
890 
891  // -> VHT MU format for 3 SS
893  txVector.SetNss (3);
894  sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (28),
895  ppduStart + MicroSeconds (48) }, // 1 VHT-STF + 4 VHT-LTFs
896  sigAMode };
897  sections[WIFI_PPDU_FIELD_SIG_B] = { { ppduStart + MicroSeconds (48),
898  ppduStart + MicroSeconds (52) },
899  sigBMode };
900  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
901  txVector.SetChannelWidth (80); //shouldn't have any impact
902  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
903 
904 
905  // ==================================================================================
906  // 11ax (HE)
907  phyEntity = Create<HePhy> ();
908  txVector.SetChannelWidth (20);
909  txVector.SetNss (2); //HE-LTF duration assumed to be always 8 us for the time being (see note in HePhy::GetTrainingDuration)
910  txVector.SetMode (HePhy::GetHeMcs9 ());
911  std::map<uint16_t, HeMuUserInfo> userInfoMap = { { 1, { {HeRu::RU_106_TONE, 1, true}, HePhy::GetHeMcs4 (), 2 } },
912  { 2, { {HeRu::RU_106_TONE, 1, true}, HePhy::GetHeMcs9 (), 1 } } };
913  sigAMode = HePhy::GetVhtMcs0 ();
914  sigBMode = HePhy::GetVhtMcs4 (); //because of first user info map
915 
916  // -> HE SU format
918  sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
919  ppduStart + MicroSeconds (16) },
920  nonHtMode } },
921  { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (16),
922  ppduStart + MicroSeconds (24) }, // L-SIG + RL-SIG
923  nonHtMode } },
924  { WIFI_PPDU_FIELD_SIG_A, { { ppduStart + MicroSeconds (24),
925  ppduStart + MicroSeconds (32) },
926  sigAMode } },
927  { WIFI_PPDU_FIELD_TRAINING, { { ppduStart + MicroSeconds (32),
928  ppduStart + MicroSeconds (52) }, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
929  sigAMode } } };
930  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
931 
932  // -> HE ER SU format
934  sections[WIFI_PPDU_FIELD_SIG_A] = { { ppduStart + MicroSeconds (24),
935  ppduStart + MicroSeconds (40) }, // 16 us HE-SIG-A
936  sigAMode };
937  sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (40),
938  ppduStart + MicroSeconds (60) }, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
939  sigAMode };
940  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
941 
942  // -> HE TB format
944  txVector.SetHeMuUserInfo (1, userInfoMap.at (1));
945  txVector.SetHeMuUserInfo (2, userInfoMap.at (2));
946  sections[WIFI_PPDU_FIELD_SIG_A] = { { ppduStart + MicroSeconds (24),
947  ppduStart + MicroSeconds (32) },
948  sigAMode };
949  sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (32),
950  ppduStart + MicroSeconds (56) }, // 1 HE-STF (@ 8 us) + 2 HE-LTFs (@ 8 us)
951  sigAMode };
952  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
953 
954  // -> HE MU format
956  sections[WIFI_PPDU_FIELD_SIG_A] = { { ppduStart + MicroSeconds (24),
957  ppduStart + MicroSeconds (32) },
958  sigAMode };
959  sections[WIFI_PPDU_FIELD_SIG_B] = { { ppduStart + MicroSeconds (32),
960  ppduStart + MicroSeconds (36) }, // only one symbol
961  sigBMode };
962  sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (36),
963  ppduStart + MicroSeconds (56) }, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
964  sigBMode };
965  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
966  txVector.SetChannelWidth (160); //shouldn't have any impact
967  CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
968 }
969 
977 {
978 public:
980 };
981 
983  : TestSuite ("wifi-devices-tx-duration", UNIT)
984 {
985  AddTestCase (new HeSigBDurationTest, TestCase::QUICK);
986  AddTestCase (new TxDurationTest, TestCase::QUICK);
987  AddTestCase (new PhyHeaderSectionsTest, TestCase::QUICK);
988 }
989 
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
uint32_t GetSerializedSize(void) const override
static TxDurationTestSuite g_txDurationTestSuite
the test suite
A suite of tests to run.
Definition: test.h:1343
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
void SetStbc(bool stbc)
Sets if STBC is being used.
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:283
The 5 GHz band.
Definition: wifi-phy-band.h:37
encapsulates test code
Definition: test.h:1153
uint8_t GetNss(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the number of spatial streams.
represent a single transmission modeA WifiMode is implemented by a single integer which is used to lo...
Definition: wifi-mode.h:47
PHY header sections consistency test.
static Time CalculateTxDurationUsingList(std::list< uint32_t > sizes, std::list< uint16_t > staIds, WifiTxVector txVector, WifiPhyBand band)
Calculate the overall Tx duration returned by WifiPhy for list of sizes.
std::map< WifiPpduField, PhyHeaderChunkInfo > PhyHeaderSections
A map of PhyHeaderChunkInfo elements per PPDU field.
Definition: phy-entity.h:301
phy
Definition: third.py:93
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode...
SYNC + SFD fields for DSSS or ERP, shortSYNC + shortSFD fields for HR/DSSS or ERP, HT-GF-STF + HT-GF-LTF1 fields for HT-GF, L-STF + L-LTF fields otherwise.
WifiPreamble
The type of preamble to be used by an IEEE 802.11 transmission.
virtual ~TxDurationTest()
bool CheckTxDuration(uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
Check if the overall tx duration returned by InterferenceHelper corresponds to a known value...
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1313
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
WifiPpduField
The type of PPDU field (grouped for convenience)
void DoRun(void) override
Implementation to actually run this TestCase.
void DoRun(void) override
Implementation to actually run this TestCase.
std::pair< std::size_t, std::size_t > GetNumRusPerHeSigBContentChannel(void) const
Get the number of RUs per HE-SIG-B content channel.
WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:159
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
void SetNss(uint8_t nss)
Sets the number of Nss.
void DoRun(void) override
Implementation to actually run this TestCase.
void CheckPhyHeaderSections(PhyEntity::PhyHeaderSections obtained, PhyEntity::PhyHeaderSections expected)
Check if map of PHY header sections returned by a given PHY entity corresponds to a known value...
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
RuType GetRuType(void) const
Get the RU type.
Definition: he-ru.cc:167
HeRu::RuSpec ru
RU specification.
The 2.4 GHz band.
Definition: wifi-phy-band.h:35
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
WifiPhyBand
Identifies the PHY band.
Definition: wifi-phy-band.h:32
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
static WifiTxVector BuildTxVector(uint16_t bw, std::list< HeMuUserInfo > userInfos)
Build a TXVECTOR for HE MU with the given bandwith and user informations.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
HE-SIG-B duration test.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1289
PhyHeaderSections GetPhyHeaderSections(const WifiTxVector &txVector, Time ppduStart) const
Return a map of PHY header chunk information per PPDU field.
Definition: phy-entity.cc:209
STF + LTF fields (excluding those in preamble for HT-GF)
Tx Duration Test Suite.
void SetNess(uint8_t ness)
Sets the Ness number.
static bool CheckHeMuTxDuration(std::list< uint32_t > sizes, std::list< HeMuUserInfo > userInfos, uint16_t channelWidth, uint16_t guardInterval, Time knownDuration)
Check if the overall Tx duration returned by WifiPhy for a HE MU PPDU corresponds to a known value...
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1305
PHY header field for DSSS or ERP, short PHY header field for HR/DSSS or ERP, field not present for HT...
Tx Duration Test.
HE MU specific user transmission parameters.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
#define SU_STA_ID
Definition: wifi-mode.h:32
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:100
Implements the IEEE 802.11 MAC header.
bool CheckPayloadDuration(uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
Check if the payload tx duration returned by InterferenceHelper corresponds to a known value...