A Discrete-Event Network Simulator
API
tx-duration-test.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009 CTTC
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Authors: Nicola Baldo <nbaldo@cttc.es>
18  * Sébastien Deronne <sebastien.deronne@gmail.com>
19  */
20 
21 #include "ns3/dsss-phy.h"
22 #include "ns3/eht-phy.h" //includes OFDM, HT, VHT and HE
23 #include "ns3/erp-ofdm-phy.h"
24 #include "ns3/he-ru.h"
25 #include "ns3/log.h"
26 #include "ns3/packet.h"
27 #include "ns3/simulator.h"
28 #include "ns3/test.h"
29 #include "ns3/wifi-psdu.h"
30 #include "ns3/yans-wifi-phy.h"
31 
32 #include <numeric>
33 
34 using namespace ns3;
35 
36 NS_LOG_COMPONENT_DEFINE("InterferenceHelperTxDurationTest");
37 
44 class TxDurationTest : public TestCase
45 {
46  public:
48  ~TxDurationTest() override;
49  void DoRun() override;
50 
51  private:
65  bool CheckPayloadDuration(uint32_t size,
66  WifiMode payloadMode,
67  uint16_t channelWidth,
68  uint16_t guardInterval,
69  WifiPreamble preamble,
70  Time knownDuration);
71 
85  bool CheckTxDuration(uint32_t size,
86  WifiMode payloadMode,
87  uint16_t channelWidth,
88  uint16_t guardInterval,
89  WifiPreamble preamble,
90  Time knownDuration);
91 
105  static bool CheckMuTxDuration(std::list<uint32_t> sizes,
106  std::list<HeMuUserInfo> userInfos,
107  uint16_t channelWidth,
108  uint16_t guardInterval,
109  WifiPreamble preamble,
110  Time knownDuration);
111 
126  static Time CalculateTxDurationUsingList(std::list<uint32_t> sizes,
127  std::list<uint16_t> staIds,
128  WifiTxVector txVector,
129  WifiPhyBand band);
130 };
131 
133  : TestCase("Wifi TX Duration")
134 {
135 }
136 
138 {
139 }
140 
141 bool
143  WifiMode payloadMode,
144  uint16_t channelWidth,
145  uint16_t guardInterval,
146  WifiPreamble preamble,
147  Time knownDuration)
148 {
149  WifiTxVector txVector;
150  txVector.SetMode(payloadMode);
151  txVector.SetPreambleType(preamble);
152  txVector.SetChannelWidth(channelWidth);
153  txVector.SetGuardInterval(guardInterval);
154  txVector.SetNss(1);
155  txVector.SetStbc(0);
156  txVector.SetNess(0);
157  std::list<WifiPhyBand> testedBands;
158  Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy>();
159  if (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_OFDM)
160  {
161  testedBands.push_back(WIFI_PHY_BAND_5GHZ);
162  }
163  if (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_HE)
164  {
165  testedBands.push_back(WIFI_PHY_BAND_6GHZ);
166  }
167  if (payloadMode.GetModulationClass() != WIFI_MOD_CLASS_VHT)
168  {
169  testedBands.push_back(WIFI_PHY_BAND_2_4GHZ);
170  }
171  for (auto& testedBand : testedBands)
172  {
173  if ((testedBand == WIFI_PHY_BAND_2_4GHZ) &&
174  (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_OFDM))
175  {
176  knownDuration +=
177  MicroSeconds(6); // 2.4 GHz band should be at the end of the bands to test
178  }
179  Time calculatedDuration = phy->GetPayloadDuration(size, txVector, testedBand);
180  if (calculatedDuration != knownDuration)
181  {
182  std::cerr << "size=" << size << " band=" << testedBand << " mode=" << payloadMode
183  << " channelWidth=" << channelWidth << " guardInterval=" << guardInterval
184  << " datarate=" << payloadMode.GetDataRate(channelWidth, guardInterval, 1)
185  << " known=" << knownDuration << " calculated=" << calculatedDuration
186  << std::endl;
187  return false;
188  }
189  }
190  return true;
191 }
192 
193 bool
195  WifiMode payloadMode,
196  uint16_t channelWidth,
197  uint16_t guardInterval,
198  WifiPreamble preamble,
199  Time knownDuration)
200 {
201  WifiTxVector txVector;
202  txVector.SetMode(payloadMode);
203  txVector.SetPreambleType(preamble);
204  txVector.SetChannelWidth(channelWidth);
205  txVector.SetGuardInterval(guardInterval);
206  txVector.SetNss(1);
207  txVector.SetStbc(0);
208  txVector.SetNess(0);
209  std::list<WifiPhyBand> testedBands;
210  Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy>();
211  if (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_OFDM)
212  {
213  testedBands.push_back(WIFI_PHY_BAND_5GHZ);
214  }
215  if (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_HE)
216  {
217  testedBands.push_back(WIFI_PHY_BAND_6GHZ);
218  }
219  if (payloadMode.GetModulationClass() != WIFI_MOD_CLASS_VHT)
220  {
221  testedBands.push_back(WIFI_PHY_BAND_2_4GHZ);
222  }
223  for (auto& testedBand : testedBands)
224  {
225  if ((testedBand == WIFI_PHY_BAND_2_4GHZ) &&
226  (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_OFDM))
227  {
228  knownDuration +=
229  MicroSeconds(6); // 2.4 GHz band should be at the end of the bands to test
230  }
231  Time calculatedDuration = phy->CalculateTxDuration(size, txVector, testedBand);
232  Time calculatedDurationUsingList =
233  CalculateTxDurationUsingList(std::list<uint32_t>{size},
234  std::list<uint16_t>{SU_STA_ID},
235  txVector,
236  testedBand);
237  if (calculatedDuration != knownDuration ||
238  calculatedDuration != calculatedDurationUsingList)
239  {
240  std::cerr << "size=" << size << " band=" << testedBand << " mode=" << payloadMode
241  << " channelWidth=" << +channelWidth << " guardInterval=" << guardInterval
242  << " datarate=" << payloadMode.GetDataRate(channelWidth, guardInterval, 1)
243  << " preamble=" << preamble << " known=" << knownDuration
244  << " calculated=" << calculatedDuration
245  << " calculatedUsingList=" << calculatedDurationUsingList << std::endl;
246  return false;
247  }
248  }
249  return true;
250 }
251 
252 bool
253 TxDurationTest::CheckMuTxDuration(std::list<uint32_t> sizes,
254  std::list<HeMuUserInfo> userInfos,
255  uint16_t channelWidth,
256  uint16_t guardInterval,
257  WifiPreamble preamble,
258  Time knownDuration)
259 {
260  NS_ASSERT(sizes.size() == userInfos.size() && sizes.size() > 1);
262  channelWidth < std::accumulate(
263  std::begin(userInfos),
264  std::end(userInfos),
265  0,
266  [](const uint16_t prevBw, const HeMuUserInfo& info) {
267  return prevBw + HeRu::GetBandwidth(info.ru.GetRuType());
268  }),
269  "Cannot accommodate all the RUs in the provided band"); // MU-MIMO (for which allocations
270  // use the same RU) is not supported
271  WifiTxVector txVector;
272  txVector.SetPreambleType(preamble);
273  txVector.SetChannelWidth(channelWidth);
274  txVector.SetGuardInterval(guardInterval);
275  txVector.SetStbc(0);
276  txVector.SetNess(0);
277  if (IsEht(preamble))
278  {
279  txVector.SetEhtPpduType(0);
280  }
281  std::list<uint16_t> staIds;
282 
283  uint16_t staId = 1;
284  for (const auto& userInfo : userInfos)
285  {
286  txVector.SetHeMuUserInfo(staId, userInfo);
287  staIds.push_back(staId++);
288  }
289  txVector.SetSigBMode(VhtPhy::GetVhtMcs0());
290  txVector.SetRuAllocation({192, 192});
291 
292  Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy>();
293  std::list<WifiPhyBand> testedBands{
296  WIFI_PHY_BAND_2_4GHZ}; // Durations vary depending on frequency; test also 2.4 GHz (bug
297  // 1971)
298  for (auto& testedBand : testedBands)
299  {
300  if (testedBand == WIFI_PHY_BAND_2_4GHZ)
301  {
302  knownDuration +=
303  MicroSeconds(6); // 2.4 GHz band should be at the end of the bands to test
304  }
305  Time calculatedDuration = NanoSeconds(0);
306  uint32_t longuestSize = 0;
307  auto iterStaId = staIds.begin();
308  for (auto& size : sizes)
309  {
310  Time ppduDurationForSta =
311  phy->CalculateTxDuration(size, txVector, testedBand, *iterStaId);
312  if (ppduDurationForSta > calculatedDuration)
313  {
314  calculatedDuration = ppduDurationForSta;
315  staId = *iterStaId;
316  longuestSize = size;
317  }
318  ++iterStaId;
319  }
320  Time calculatedDurationUsingList =
321  CalculateTxDurationUsingList(sizes, staIds, txVector, testedBand);
322  if (calculatedDuration != knownDuration ||
323  calculatedDuration != calculatedDurationUsingList)
324  {
325  std::cerr << "size=" << longuestSize << " band=" << testedBand << " staId=" << staId
326  << " nss=" << +txVector.GetNss(staId) << " mode=" << txVector.GetMode(staId)
327  << " channelWidth=" << channelWidth << " guardInterval=" << guardInterval
328  << " datarate="
329  << txVector.GetMode(staId).GetDataRate(channelWidth,
330  guardInterval,
331  txVector.GetNss(staId))
332  << " known=" << knownDuration << " calculated=" << calculatedDuration
333  << " calculatedUsingList=" << calculatedDurationUsingList << std::endl;
334  return false;
335  }
336  }
337  return true;
338 }
339 
340 Time
342  std::list<uint16_t> staIds,
343  WifiTxVector txVector,
344  WifiPhyBand band)
345 {
346  NS_ASSERT(sizes.size() == staIds.size());
347  WifiConstPsduMap psduMap;
348  auto itStaId = staIds.begin();
349  WifiMacHeader hdr;
350  hdr.SetType(WIFI_MAC_CTL_ACK); // so that size may not be empty while being as short as possible
351  for (auto& size : sizes)
352  {
353  // MAC header and FCS are to deduce from size
354  psduMap[*itStaId++] =
355  Create<WifiPsdu>(Create<Packet>(size - hdr.GetSerializedSize() - 4), hdr);
356  }
357  return WifiPhy::CalculateTxDuration(psduMap, txVector, band);
358 }
359 
360 void
362 {
363  bool retval = true;
364 
365  // IEEE Std 802.11-2007 Table 18-2 "Example of LENGTH calculations for CCK"
366  retval = retval &&
368  DsssPhy::GetDsssRate11Mbps(),
369  22,
370  800,
372  MicroSeconds(744)) &&
374  DsssPhy::GetDsssRate11Mbps(),
375  22,
376  800,
378  MicroSeconds(745)) &&
380  DsssPhy::GetDsssRate11Mbps(),
381  22,
382  800,
384  MicroSeconds(746)) &&
386  DsssPhy::GetDsssRate11Mbps(),
387  22,
388  800,
390  MicroSeconds(747));
391 
392  NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11b CCK duration failed");
393 
394  // Similar, but we add PHY preamble and header durations
395  // and we test different rates.
396  // The payload durations for modes other than 11mbb have been
397  // calculated by hand according to IEEE Std 802.11-2007 18.2.3.5
398  retval = retval &&
399  CheckTxDuration(1023,
400  DsssPhy::GetDsssRate11Mbps(),
401  22,
402  800,
404  MicroSeconds(744 + 96)) &&
405  CheckTxDuration(1024,
406  DsssPhy::GetDsssRate11Mbps(),
407  22,
408  800,
410  MicroSeconds(745 + 96)) &&
411  CheckTxDuration(1025,
412  DsssPhy::GetDsssRate11Mbps(),
413  22,
414  800,
416  MicroSeconds(746 + 96)) &&
417  CheckTxDuration(1026,
418  DsssPhy::GetDsssRate11Mbps(),
419  22,
420  800,
422  MicroSeconds(747 + 96)) &&
423  CheckTxDuration(1023,
424  DsssPhy::GetDsssRate11Mbps(),
425  22,
426  800,
428  MicroSeconds(744 + 192)) &&
429  CheckTxDuration(1024,
430  DsssPhy::GetDsssRate11Mbps(),
431  22,
432  800,
434  MicroSeconds(745 + 192)) &&
435  CheckTxDuration(1025,
436  DsssPhy::GetDsssRate11Mbps(),
437  22,
438  800,
440  MicroSeconds(746 + 192)) &&
441  CheckTxDuration(1026,
442  DsssPhy::GetDsssRate11Mbps(),
443  22,
444  800,
446  MicroSeconds(747 + 192)) &&
447  CheckTxDuration(1023,
448  DsssPhy::GetDsssRate5_5Mbps(),
449  22,
450  800,
452  MicroSeconds(1488 + 96)) &&
453  CheckTxDuration(1024,
454  DsssPhy::GetDsssRate5_5Mbps(),
455  22,
456  800,
458  MicroSeconds(1490 + 96)) &&
459  CheckTxDuration(1025,
460  DsssPhy::GetDsssRate5_5Mbps(),
461  22,
462  800,
464  MicroSeconds(1491 + 96)) &&
465  CheckTxDuration(1026,
466  DsssPhy::GetDsssRate5_5Mbps(),
467  22,
468  800,
470  MicroSeconds(1493 + 96)) &&
471  CheckTxDuration(1023,
472  DsssPhy::GetDsssRate5_5Mbps(),
473  22,
474  800,
476  MicroSeconds(1488 + 192)) &&
477  CheckTxDuration(1024,
478  DsssPhy::GetDsssRate5_5Mbps(),
479  22,
480  800,
482  MicroSeconds(1490 + 192)) &&
483  CheckTxDuration(1025,
484  DsssPhy::GetDsssRate5_5Mbps(),
485  22,
486  800,
488  MicroSeconds(1491 + 192)) &&
489  CheckTxDuration(1026,
490  DsssPhy::GetDsssRate5_5Mbps(),
491  22,
492  800,
494  MicroSeconds(1493 + 192)) &&
495  CheckTxDuration(1023,
496  DsssPhy::GetDsssRate2Mbps(),
497  22,
498  800,
500  MicroSeconds(4092 + 96)) &&
501  CheckTxDuration(1024,
502  DsssPhy::GetDsssRate2Mbps(),
503  22,
504  800,
506  MicroSeconds(4096 + 96)) &&
507  CheckTxDuration(1025,
508  DsssPhy::GetDsssRate2Mbps(),
509  22,
510  800,
512  MicroSeconds(4100 + 96)) &&
513  CheckTxDuration(1026,
514  DsssPhy::GetDsssRate2Mbps(),
515  22,
516  800,
518  MicroSeconds(4104 + 96)) &&
519  CheckTxDuration(1023,
520  DsssPhy::GetDsssRate2Mbps(),
521  22,
522  800,
524  MicroSeconds(4092 + 192)) &&
525  CheckTxDuration(1024,
526  DsssPhy::GetDsssRate2Mbps(),
527  22,
528  800,
530  MicroSeconds(4096 + 192)) &&
531  CheckTxDuration(1025,
532  DsssPhy::GetDsssRate2Mbps(),
533  22,
534  800,
536  MicroSeconds(4100 + 192)) &&
537  CheckTxDuration(1026,
538  DsssPhy::GetDsssRate2Mbps(),
539  22,
540  800,
542  MicroSeconds(4104 + 192)) &&
543  CheckTxDuration(1023,
544  DsssPhy::GetDsssRate1Mbps(),
545  22,
546  800,
548  MicroSeconds(8184 + 192)) &&
549  CheckTxDuration(1024,
550  DsssPhy::GetDsssRate1Mbps(),
551  22,
552  800,
554  MicroSeconds(8192 + 192)) &&
555  CheckTxDuration(1025,
556  DsssPhy::GetDsssRate1Mbps(),
557  22,
558  800,
560  MicroSeconds(8200 + 192)) &&
561  CheckTxDuration(1026,
562  DsssPhy::GetDsssRate1Mbps(),
563  22,
564  800,
566  MicroSeconds(8208 + 192)) &&
567  CheckTxDuration(1023,
568  DsssPhy::GetDsssRate1Mbps(),
569  22,
570  800,
572  MicroSeconds(8184 + 192)) &&
573  CheckTxDuration(1024,
574  DsssPhy::GetDsssRate1Mbps(),
575  22,
576  800,
578  MicroSeconds(8192 + 192)) &&
579  CheckTxDuration(1025,
580  DsssPhy::GetDsssRate1Mbps(),
581  22,
582  800,
584  MicroSeconds(8200 + 192)) &&
585  CheckTxDuration(1026,
586  DsssPhy::GetDsssRate1Mbps(),
587  22,
588  800,
590  MicroSeconds(8208 + 192));
591 
592  // values from http://mailman.isi.edu/pipermail/ns-developers/2009-July/006226.html
593  retval = retval && CheckTxDuration(14,
594  DsssPhy::GetDsssRate1Mbps(),
595  22,
596  800,
598  MicroSeconds(304));
599 
600  // values from http://www.oreillynet.com/pub/a/wireless/2003/08/08/wireless_throughput.html
601  retval = retval &&
602  CheckTxDuration(1536,
603  DsssPhy::GetDsssRate11Mbps(),
604  22,
605  800,
607  MicroSeconds(1310)) &&
608  CheckTxDuration(76,
609  DsssPhy::GetDsssRate11Mbps(),
610  22,
611  800,
613  MicroSeconds(248)) &&
614  CheckTxDuration(14,
615  DsssPhy::GetDsssRate11Mbps(),
616  22,
617  800,
619  MicroSeconds(203));
620 
621  NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11b duration failed");
622 
623  // 802.11a durations
624  // values from http://www.oreillynet.com/pub/a/wireless/2003/08/08/wireless_throughput.html
625  retval = retval &&
626  CheckTxDuration(1536,
627  OfdmPhy::GetOfdmRate54Mbps(),
628  20,
629  800,
631  MicroSeconds(248)) &&
632  CheckTxDuration(76,
633  OfdmPhy::GetOfdmRate54Mbps(),
634  20,
635  800,
637  MicroSeconds(32)) &&
638  CheckTxDuration(14,
639  OfdmPhy::GetOfdmRate54Mbps(),
640  20,
641  800,
643  MicroSeconds(24));
644 
645  NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11a duration failed");
646 
647  // 802.11g durations are same as 802.11a durations but with 6 us signal extension
648  retval = retval &&
649  CheckTxDuration(1536,
650  ErpOfdmPhy::GetErpOfdmRate54Mbps(),
651  20,
652  800,
654  MicroSeconds(254)) &&
655  CheckTxDuration(76,
656  ErpOfdmPhy::GetErpOfdmRate54Mbps(),
657  20,
658  800,
660  MicroSeconds(38)) &&
661  CheckTxDuration(14,
662  ErpOfdmPhy::GetErpOfdmRate54Mbps(),
663  20,
664  800,
666  MicroSeconds(30));
667 
668  NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11g duration failed");
669 
670  // 802.11n durations
671  retval =
672  retval &&
673  CheckTxDuration(1536,
674  HtPhy::GetHtMcs7(),
675  20,
676  800,
678  MicroSeconds(228)) &&
679  CheckTxDuration(76, HtPhy::GetHtMcs7(), 20, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds(48)) &&
680  CheckTxDuration(14, HtPhy::GetHtMcs7(), 20, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds(40)) &&
681  CheckTxDuration(1536,
682  HtPhy::GetHtMcs0(),
683  20,
684  400,
686  NanoSeconds(1742400)) &&
687  CheckTxDuration(76, HtPhy::GetHtMcs0(), 20, 400, WIFI_PREAMBLE_HT_MF, MicroSeconds(126)) &&
688  CheckTxDuration(14, HtPhy::GetHtMcs0(), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds(57600)) &&
689  CheckTxDuration(1536,
690  HtPhy::GetHtMcs6(),
691  20,
692  400,
694  NanoSeconds(226800)) &&
695  CheckTxDuration(76, HtPhy::GetHtMcs6(), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds(46800)) &&
696  CheckTxDuration(14, HtPhy::GetHtMcs6(), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds(39600)) &&
697  CheckTxDuration(1536,
698  HtPhy::GetHtMcs7(),
699  40,
700  800,
702  MicroSeconds(128)) &&
703  CheckTxDuration(76, HtPhy::GetHtMcs7(), 40, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds(44)) &&
704  CheckTxDuration(14, HtPhy::GetHtMcs7(), 40, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds(40)) &&
705  CheckTxDuration(1536,
706  HtPhy::GetHtMcs7(),
707  40,
708  400,
710  NanoSeconds(118800)) &&
711  CheckTxDuration(76, HtPhy::GetHtMcs7(), 40, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds(43200)) &&
712  CheckTxDuration(14, HtPhy::GetHtMcs7(), 40, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds(39600));
713 
714  NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11n duration failed");
715 
716  // 802.11ac durations
717  retval = retval &&
718  CheckTxDuration(1536,
719  VhtPhy::GetVhtMcs8(),
720  20,
721  800,
723  MicroSeconds(196)) &&
724  CheckTxDuration(76,
725  VhtPhy::GetVhtMcs8(),
726  20,
727  800,
729  MicroSeconds(48)) &&
730  CheckTxDuration(14,
731  VhtPhy::GetVhtMcs8(),
732  20,
733  800,
735  MicroSeconds(40)) &&
736  CheckTxDuration(1536,
737  VhtPhy::GetVhtMcs8(),
738  20,
739  400,
741  MicroSeconds(180)) &&
742  CheckTxDuration(76,
743  VhtPhy::GetVhtMcs8(),
744  20,
745  400,
747  NanoSeconds(46800)) &&
748  CheckTxDuration(14,
749  VhtPhy::GetVhtMcs8(),
750  20,
751  400,
753  NanoSeconds(39600)) &&
754  CheckTxDuration(1536,
755  VhtPhy::GetVhtMcs9(),
756  40,
757  800,
759  MicroSeconds(108)) &&
760  CheckTxDuration(76,
761  VhtPhy::GetVhtMcs9(),
762  40,
763  800,
765  MicroSeconds(40)) &&
766  CheckTxDuration(14,
767  VhtPhy::GetVhtMcs9(),
768  40,
769  800,
771  MicroSeconds(40)) &&
772  CheckTxDuration(1536,
773  VhtPhy::GetVhtMcs9(),
774  40,
775  400,
777  NanoSeconds(100800)) &&
778  CheckTxDuration(76,
779  VhtPhy::GetVhtMcs9(),
780  40,
781  400,
783  NanoSeconds(39600)) &&
784  CheckTxDuration(14,
785  VhtPhy::GetVhtMcs9(),
786  40,
787  400,
789  NanoSeconds(39600)) &&
790  CheckTxDuration(1536,
791  VhtPhy::GetVhtMcs0(),
792  80,
793  800,
795  MicroSeconds(460)) &&
796  CheckTxDuration(76,
797  VhtPhy::GetVhtMcs0(),
798  80,
799  800,
801  MicroSeconds(60)) &&
802  CheckTxDuration(14,
803  VhtPhy::GetVhtMcs0(),
804  80,
805  800,
807  MicroSeconds(44)) &&
808  CheckTxDuration(1536,
809  VhtPhy::GetVhtMcs0(),
810  80,
811  400,
813  NanoSeconds(417600)) &&
814  CheckTxDuration(76,
815  VhtPhy::GetVhtMcs0(),
816  80,
817  400,
819  NanoSeconds(57600)) &&
820  CheckTxDuration(14,
821  VhtPhy::GetVhtMcs0(),
822  80,
823  400,
825  NanoSeconds(43200)) &&
826  CheckTxDuration(1536,
827  VhtPhy::GetVhtMcs9(),
828  80,
829  800,
831  MicroSeconds(68)) &&
832  CheckTxDuration(76,
833  VhtPhy::GetVhtMcs9(),
834  80,
835  800,
837  MicroSeconds(40)) &&
838  CheckTxDuration(14,
839  VhtPhy::GetVhtMcs9(),
840  80,
841  800,
843  MicroSeconds(40)) &&
844  CheckTxDuration(1536,
845  VhtPhy::GetVhtMcs9(),
846  80,
847  400,
849  NanoSeconds(64800)) &&
850  CheckTxDuration(76,
851  VhtPhy::GetVhtMcs9(),
852  80,
853  400,
855  NanoSeconds(39600)) &&
856  CheckTxDuration(14,
857  VhtPhy::GetVhtMcs9(),
858  80,
859  400,
861  NanoSeconds(39600)) &&
862  CheckTxDuration(1536,
863  VhtPhy::GetVhtMcs8(),
864  160,
865  800,
867  MicroSeconds(56)) &&
868  CheckTxDuration(76,
869  VhtPhy::GetVhtMcs8(),
870  160,
871  800,
873  MicroSeconds(40)) &&
874  CheckTxDuration(14,
875  VhtPhy::GetVhtMcs8(),
876  160,
877  800,
879  MicroSeconds(40)) &&
880  CheckTxDuration(1536,
881  VhtPhy::GetVhtMcs8(),
882  160,
883  400,
885  MicroSeconds(54)) &&
886  CheckTxDuration(76,
887  VhtPhy::GetVhtMcs8(),
888  160,
889  400,
891  NanoSeconds(39600)) &&
892  CheckTxDuration(14,
893  VhtPhy::GetVhtMcs8(),
894  160,
895  400,
897  NanoSeconds(39600));
898 
899  NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11ac duration failed");
900 
901  // 802.11ax SU durations
902  retval =
903  retval &&
904  CheckTxDuration(1536,
905  HePhy::GetHeMcs0(),
906  20,
907  800,
909  NanoSeconds(1485600)) &&
910  CheckTxDuration(76,
911  HePhy::GetHeMcs0(),
912  20,
913  800,
915  NanoSeconds(125600)) &&
916  CheckTxDuration(14, HePhy::GetHeMcs0(), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds(71200)) &&
917  CheckTxDuration(1536,
918  HePhy::GetHeMcs0(),
919  40,
920  800,
922  NanoSeconds(764800)) &&
923  CheckTxDuration(76, HePhy::GetHeMcs0(), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds(84800)) &&
924  CheckTxDuration(14, HePhy::GetHeMcs0(), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds(57600)) &&
925  CheckTxDuration(1536,
926  HePhy::GetHeMcs0(),
927  80,
928  800,
930  NanoSeconds(397600)) &&
931  CheckTxDuration(76, HePhy::GetHeMcs0(), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds(71200)) &&
932  CheckTxDuration(14, HePhy::GetHeMcs0(), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds(57600)) &&
933  CheckTxDuration(1536,
934  HePhy::GetHeMcs0(),
935  160,
936  800,
938  NanoSeconds(220800)) &&
939  CheckTxDuration(76,
940  HePhy::GetHeMcs0(),
941  160,
942  800,
944  NanoSeconds(57600)) &&
945  CheckTxDuration(14,
946  HePhy::GetHeMcs0(),
947  160,
948  800,
950  NanoSeconds(57600)) &&
951  CheckTxDuration(1536,
952  HePhy::GetHeMcs0(),
953  20,
954  1600,
956  NanoSeconds(1570400)) &&
957  CheckTxDuration(76,
958  HePhy::GetHeMcs0(),
959  20,
960  1600,
962  NanoSeconds(130400)) &&
963  CheckTxDuration(14,
964  HePhy::GetHeMcs0(),
965  20,
966  1600,
968  NanoSeconds(72800)) &&
969  CheckTxDuration(1536,
970  HePhy::GetHeMcs0(),
971  40,
972  1600,
974  NanoSeconds(807200)) &&
975  CheckTxDuration(76,
976  HePhy::GetHeMcs0(),
977  40,
978  1600,
980  NanoSeconds(87200)) &&
981  CheckTxDuration(14,
982  HePhy::GetHeMcs0(),
983  40,
984  1600,
986  NanoSeconds(58400)) &&
987  CheckTxDuration(1536,
988  HePhy::GetHeMcs0(),
989  80,
990  1600,
992  NanoSeconds(418400)) &&
993  CheckTxDuration(76,
994  HePhy::GetHeMcs0(),
995  80,
996  1600,
998  NanoSeconds(72800)) &&
999  CheckTxDuration(14,
1000  HePhy::GetHeMcs0(),
1001  80,
1002  1600,
1004  NanoSeconds(58400)) &&
1005  CheckTxDuration(1536,
1006  HePhy::GetHeMcs0(),
1007  160,
1008  1600,
1010  NanoSeconds(231200)) &&
1011  CheckTxDuration(76,
1012  HePhy::GetHeMcs0(),
1013  160,
1014  1600,
1016  NanoSeconds(58400)) &&
1017  CheckTxDuration(14,
1018  HePhy::GetHeMcs0(),
1019  160,
1020  1600,
1022  NanoSeconds(58400)) &&
1023  CheckTxDuration(1536,
1024  HePhy::GetHeMcs0(),
1025  20,
1026  3200,
1028  MicroSeconds(1740)) &&
1029  CheckTxDuration(76, HePhy::GetHeMcs0(), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(140)) &&
1030  CheckTxDuration(14, HePhy::GetHeMcs0(), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(76)) &&
1031  CheckTxDuration(1536,
1032  HePhy::GetHeMcs0(),
1033  40,
1034  3200,
1036  MicroSeconds(892)) &&
1037  CheckTxDuration(76, HePhy::GetHeMcs0(), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(92)) &&
1038  CheckTxDuration(14, HePhy::GetHeMcs0(), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1039  CheckTxDuration(1536,
1040  HePhy::GetHeMcs0(),
1041  80,
1042  3200,
1044  MicroSeconds(460)) &&
1045  CheckTxDuration(76, HePhy::GetHeMcs0(), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(76)) &&
1046  CheckTxDuration(14, HePhy::GetHeMcs0(), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1047  CheckTxDuration(1536,
1048  HePhy::GetHeMcs0(),
1049  160,
1050  3200,
1052  MicroSeconds(252)) &&
1053  CheckTxDuration(76, HePhy::GetHeMcs0(), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1054  CheckTxDuration(14, HePhy::GetHeMcs0(), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1055  CheckTxDuration(1536,
1056  HePhy::GetHeMcs11(),
1057  20,
1058  800,
1060  NanoSeconds(139200)) &&
1061  CheckTxDuration(76,
1062  HePhy::GetHeMcs11(),
1063  20,
1064  800,
1066  NanoSeconds(57600)) &&
1067  CheckTxDuration(14,
1068  HePhy::GetHeMcs11(),
1069  20,
1070  800,
1072  NanoSeconds(57600)) &&
1073  CheckTxDuration(1536,
1074  HePhy::GetHeMcs11(),
1075  40,
1076  800,
1078  NanoSeconds(98400)) &&
1079  CheckTxDuration(76,
1080  HePhy::GetHeMcs11(),
1081  40,
1082  800,
1084  NanoSeconds(57600)) &&
1085  CheckTxDuration(14,
1086  HePhy::GetHeMcs11(),
1087  40,
1088  800,
1090  NanoSeconds(57600)) &&
1091  CheckTxDuration(1536,
1092  HePhy::GetHeMcs11(),
1093  80,
1094  800,
1096  NanoSeconds(71200)) &&
1097  CheckTxDuration(76,
1098  HePhy::GetHeMcs11(),
1099  80,
1100  800,
1102  NanoSeconds(57600)) &&
1103  CheckTxDuration(14,
1104  HePhy::GetHeMcs11(),
1105  80,
1106  800,
1108  NanoSeconds(57600)) &&
1109  CheckTxDuration(1536,
1110  HePhy::GetHeMcs11(),
1111  160,
1112  800,
1114  NanoSeconds(57600)) &&
1115  CheckTxDuration(76,
1116  HePhy::GetHeMcs11(),
1117  160,
1118  800,
1120  NanoSeconds(57600)) &&
1121  CheckTxDuration(14,
1122  HePhy::GetHeMcs11(),
1123  160,
1124  800,
1126  NanoSeconds(57600)) &&
1127  CheckTxDuration(1536,
1128  HePhy::GetHeMcs11(),
1129  20,
1130  1600,
1132  NanoSeconds(144800)) &&
1133  CheckTxDuration(76,
1134  HePhy::GetHeMcs11(),
1135  20,
1136  1600,
1138  NanoSeconds(58400)) &&
1139  CheckTxDuration(14,
1140  HePhy::GetHeMcs11(),
1141  20,
1142  1600,
1144  NanoSeconds(58400)) &&
1145  CheckTxDuration(1536,
1146  HePhy::GetHeMcs11(),
1147  40,
1148  1600,
1150  NanoSeconds(101600)) &&
1151  CheckTxDuration(76,
1152  HePhy::GetHeMcs11(),
1153  40,
1154  1600,
1156  NanoSeconds(58400)) &&
1157  CheckTxDuration(14,
1158  HePhy::GetHeMcs11(),
1159  40,
1160  1600,
1162  NanoSeconds(58400)) &&
1163  CheckTxDuration(1536,
1164  HePhy::GetHeMcs11(),
1165  80,
1166  1600,
1168  NanoSeconds(72800)) &&
1169  CheckTxDuration(76,
1170  HePhy::GetHeMcs11(),
1171  80,
1172  1600,
1174  NanoSeconds(58400)) &&
1175  CheckTxDuration(14,
1176  HePhy::GetHeMcs11(),
1177  80,
1178  1600,
1180  NanoSeconds(58400)) &&
1181  CheckTxDuration(1536,
1182  HePhy::GetHeMcs11(),
1183  160,
1184  1600,
1186  NanoSeconds(58400)) &&
1187  CheckTxDuration(76,
1188  HePhy::GetHeMcs11(),
1189  160,
1190  1600,
1192  NanoSeconds(58400)) &&
1193  CheckTxDuration(14,
1194  HePhy::GetHeMcs11(),
1195  160,
1196  1600,
1198  NanoSeconds(58400)) &&
1199  CheckTxDuration(1536,
1200  HePhy::GetHeMcs11(),
1201  20,
1202  3200,
1204  MicroSeconds(156)) &&
1205  CheckTxDuration(76, HePhy::GetHeMcs11(), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1206  CheckTxDuration(14, HePhy::GetHeMcs11(), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1207  CheckTxDuration(1536,
1208  HePhy::GetHeMcs11(),
1209  40,
1210  3200,
1212  MicroSeconds(108)) &&
1213  CheckTxDuration(76, HePhy::GetHeMcs11(), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1214  CheckTxDuration(14, HePhy::GetHeMcs11(), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1215  CheckTxDuration(1536,
1216  HePhy::GetHeMcs11(),
1217  80,
1218  3200,
1220  MicroSeconds(76)) &&
1221  CheckTxDuration(76, HePhy::GetHeMcs11(), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1222  CheckTxDuration(14, HePhy::GetHeMcs11(), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1223  CheckTxDuration(1536,
1224  HePhy::GetHeMcs11(),
1225  160,
1226  3200,
1228  MicroSeconds(60)) &&
1229  CheckTxDuration(76,
1230  HePhy::GetHeMcs11(),
1231  160,
1232  3200,
1234  MicroSeconds(60)) &&
1235  CheckTxDuration(14, HePhy::GetHeMcs11(), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60));
1236 
1237  NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11ax SU duration failed");
1238 
1239  // 802.11ax MU durations
1240  retval = retval &&
1242  std::list<uint32_t>{1536, 1536},
1243  std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, 0, 1},
1244  {{HeRu::RU_242_TONE, 2, true}, 0, 1}},
1245  40,
1246  800,
1248  NanoSeconds(
1249  1493600)) // equivalent to HE_SU for 20 MHz with 2 extra HE-SIG-B (i.e. 8 us)
1250  && CheckMuTxDuration(std::list<uint32_t>{1536, 1536},
1251  std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, 1, 1},
1252  {{HeRu::RU_242_TONE, 2, true}, 0, 1}},
1253  40,
1254  800,
1256  NanoSeconds(1493600)) // shouldn't change if first PSDU is shorter
1257  && CheckMuTxDuration(std::list<uint32_t>{1536, 76},
1258  std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, 0, 1},
1259  {{HeRu::RU_242_TONE, 2, true}, 0, 1}},
1260  40,
1261  800,
1263  NanoSeconds(1493600));
1264 
1265  NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11ax MU duration failed");
1266 
1267  // 802.11be MU durations
1268  retval = retval &&
1269  CheckMuTxDuration(std::list<uint32_t>{1536, 1536},
1270  std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, 0, 1},
1271  {{HeRu::RU_242_TONE, 2, true}, 0, 1}},
1272  40,
1273  800,
1275  NanoSeconds(1493600)) // equivalent to 802.11ax MU
1276  && CheckMuTxDuration(std::list<uint32_t>{1536, 1536},
1277  std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, 1, 1},
1278  {{HeRu::RU_242_TONE, 2, true}, 0, 1}},
1279  40,
1280  800,
1282  NanoSeconds(1493600)) // shouldn't change if first PSDU is shorter
1283  && CheckMuTxDuration(std::list<uint32_t>{1536, 76},
1284  std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, 0, 1},
1285  {{HeRu::RU_242_TONE, 2, true}, 0, 1}},
1286  40,
1287  800,
1289  NanoSeconds(1493600));
1290 
1291  NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11be MU duration failed");
1292 
1293  Simulator::Destroy();
1294 }
1295 
1303 {
1304  public:
1306  ~HeSigBDurationTest() override;
1307  void DoRun() override;
1308 
1309  private:
1318  static WifiTxVector BuildTxVector(uint16_t bw, std::list<HeMuUserInfo> userInfos);
1319 };
1320 
1322  : TestCase("Check HE-SIG-B duration computation")
1323 {
1324 }
1325 
1327 {
1328 }
1329 
1331 HeSigBDurationTest::BuildTxVector(uint16_t bw, std::list<HeMuUserInfo> userInfos)
1332 {
1333  WifiTxVector txVector;
1335  txVector.SetChannelWidth(bw);
1336  txVector.SetGuardInterval(3200);
1337  txVector.SetStbc(0);
1338  txVector.SetNess(0);
1339  std::list<uint16_t> staIds;
1340  uint16_t staId = 1;
1341  for (const auto& userInfo : userInfos)
1342  {
1343  txVector.SetHeMuUserInfo(staId, userInfo);
1344  staIds.push_back(staId++);
1345  }
1346  return txVector;
1347 }
1348 
1349 void
1351 {
1352  const auto& hePhy = WifiPhy::GetStaticPhyEntity(WIFI_MOD_CLASS_HE);
1353 
1354  // 20 MHz band
1355  std::list<HeMuUserInfo> userInfos;
1356  userInfos.push_back({{HeRu::RU_106_TONE, 1, true}, 11, 1});
1357  userInfos.push_back({{HeRu::RU_106_TONE, 2, true}, 10, 4});
1358  WifiTxVector txVector = BuildTxVector(20, userInfos);
1359  txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
1360  txVector.SetRuAllocation({96});
1361  NS_TEST_EXPECT_MSG_EQ(hePhy->GetSigMode(WIFI_PPDU_FIELD_SIG_B, txVector),
1362  VhtPhy::GetVhtMcs5(),
1363  "HE-SIG-B should be sent at MCS 5");
1364  std::pair<std::size_t, std::size_t> numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel();
1365  NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.first,
1366  2,
1367  "Both users should be on HE-SIG-B content channel 1");
1368  NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.second,
1369  0,
1370  "Both users should be on HE-SIG-B content channel 2");
1371  NS_TEST_EXPECT_MSG_EQ(hePhy->GetDuration(WIFI_PPDU_FIELD_SIG_B, txVector),
1372  MicroSeconds(4),
1373  "HE-SIG-B should only last one OFDM symbol");
1374 
1375  // 40 MHz band, even number of users per HE-SIG-B content channel
1376  userInfos.push_back({{HeRu::RU_52_TONE, 5, true}, 4, 1});
1377  userInfos.push_back({{HeRu::RU_52_TONE, 6, true}, 6, 2});
1378  userInfos.push_back({{HeRu::RU_52_TONE, 7, true}, 5, 3});
1379  userInfos.push_back({{HeRu::RU_52_TONE, 8, true}, 6, 2});
1380  txVector = BuildTxVector(40, userInfos);
1381  txVector.SetSigBMode(VhtPhy::GetVhtMcs4());
1382  txVector.SetRuAllocation({96, 112});
1383  NS_TEST_EXPECT_MSG_EQ(hePhy->GetSigMode(WIFI_PPDU_FIELD_SIG_B, txVector),
1384  VhtPhy::GetVhtMcs4(),
1385  "HE-SIG-B should be sent at MCS 4");
1386  numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel();
1387  NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.first,
1388  2,
1389  "Two users should be on HE-SIG-B content channel 1");
1390  NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.second,
1391  4,
1392  "Four users should be on HE-SIG-B content channel 2");
1393  NS_TEST_EXPECT_MSG_EQ(hePhy->GetDuration(WIFI_PPDU_FIELD_SIG_B, txVector),
1394  MicroSeconds(4),
1395  "HE-SIG-B should only last one OFDM symbol");
1396 
1397  // 40 MHz band, odd number of users per HE-SIG-B content channel
1398  userInfos.push_back({{HeRu::RU_26_TONE, 14, true}, 3, 1});
1399  txVector = BuildTxVector(40, userInfos);
1400  txVector.SetSigBMode(VhtPhy::GetVhtMcs3());
1401  txVector.SetRuAllocation({96, 15});
1402  NS_TEST_EXPECT_MSG_EQ(hePhy->GetSigMode(WIFI_PPDU_FIELD_SIG_B, txVector),
1403  VhtPhy::GetVhtMcs3(),
1404  "HE-SIG-B should be sent at MCS 3");
1405  numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel();
1406  NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.first,
1407  2,
1408  "Two users should be on HE-SIG-B content channel 1");
1409  NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.second,
1410  5,
1411  "Five users should be on HE-SIG-B content channel 2");
1412  NS_TEST_EXPECT_MSG_EQ(hePhy->GetDuration(WIFI_PPDU_FIELD_SIG_B, txVector),
1413  MicroSeconds(8),
1414  "HE-SIG-B should last two OFDM symbols");
1415 
1416  // 80 MHz band
1417  userInfos.push_back({{HeRu::RU_242_TONE, 3, true}, 1, 1});
1418  userInfos.push_back({{HeRu::RU_242_TONE, 4, true}, 4, 1});
1419  txVector = BuildTxVector(80, userInfos);
1420  txVector.SetSigBMode(VhtPhy::GetVhtMcs1());
1421  txVector.SetRuAllocation({96, 15, 192, 192});
1422  NS_TEST_EXPECT_MSG_EQ(hePhy->GetSigMode(WIFI_PPDU_FIELD_SIG_B, txVector),
1423  VhtPhy::GetVhtMcs1(),
1424  "HE-SIG-B should be sent at MCS 1");
1425  numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel();
1426  NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.first,
1427  3,
1428  "Three users should be on HE-SIG-B content channel 1");
1429  NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.second,
1430  6,
1431  "Six users should be on HE-SIG-B content channel 2");
1432  NS_TEST_EXPECT_MSG_EQ(hePhy->GetDuration(WIFI_PPDU_FIELD_SIG_B, txVector),
1433  MicroSeconds(16),
1434  "HE-SIG-B should last four OFDM symbols");
1435 
1436  // 160 MHz band
1437  userInfos.push_back({{HeRu::RU_996_TONE, 1, false}, 1, 1});
1438  txVector = BuildTxVector(160, userInfos);
1439  txVector.SetSigBMode(VhtPhy::GetVhtMcs1());
1440  txVector.SetRuAllocation({96, 15, 192, 192, 208, 208, 208, 208});
1441  NS_TEST_EXPECT_MSG_EQ(hePhy->GetSigMode(WIFI_PPDU_FIELD_SIG_B, txVector),
1442  VhtPhy::GetVhtMcs1(),
1443  "HE-SIG-B should be sent at MCS 1");
1444  numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel();
1445  NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.first,
1446  4,
1447  "Four users should be on HE-SIG-B content channel 1");
1448  NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.second,
1449  7,
1450  "Seven users should be on HE-SIG-B content channel 2");
1451  NS_TEST_EXPECT_MSG_EQ(hePhy->GetDuration(WIFI_PPDU_FIELD_SIG_B, txVector),
1452  MicroSeconds(20),
1453  "HE-SIG-B should last five OFDM symbols");
1454 }
1455 
1463 {
1464  public:
1466  ~PhyHeaderSectionsTest() override;
1467  void DoRun() override;
1468 
1469  private:
1478  PhyEntity::PhyHeaderSections expected);
1479 };
1480 
1482  : TestCase("PHY header sections consistency")
1483 {
1484 }
1485 
1487 {
1488 }
1489 
1490 void
1493 {
1494  NS_ASSERT_MSG(obtained.size() == expected.size(),
1495  "The expected map size (" << expected.size() << ") was not obtained ("
1496  << obtained.size() << ")");
1497 
1498  auto itObtained = obtained.begin();
1499  auto itExpected = expected.begin();
1500  for (; itObtained != obtained.end() || itExpected != expected.end();)
1501  {
1502  WifiPpduField field = itObtained->first;
1503  auto window = itObtained->second.first;
1504  auto mode = itObtained->second.second;
1505 
1506  WifiPpduField fieldRef = itExpected->first;
1507  auto windowRef = itExpected->second.first;
1508  auto modeRef = itExpected->second.second;
1509 
1510  NS_TEST_EXPECT_MSG_EQ(field,
1511  fieldRef,
1512  "The expected PPDU field (" << fieldRef << ") was not obtained ("
1513  << field << ")");
1515  windowRef.first,
1516  "The expected start time (" << windowRef.first
1517  << ") was not obtained (" << window.first
1518  << ")");
1520  windowRef.second,
1521  "The expected stop time (" << windowRef.second
1522  << ") was not obtained (" << window.second
1523  << ")");
1524  NS_TEST_EXPECT_MSG_EQ(mode,
1525  modeRef,
1526  "The expected mode (" << modeRef << ") was not obtained (" << mode
1527  << ")");
1528  ++itObtained;
1529  ++itExpected;
1530  }
1531 }
1532 
1533 void
1535 {
1536  Time ppduStart = Seconds(1.0);
1537  Ptr<PhyEntity> phyEntity;
1539  WifiTxVector txVector;
1540  WifiMode nonHtMode;
1541 
1542  // ==================================================================================
1543  // 11b (HR/DSSS)
1544  phyEntity = Create<DsssPhy>();
1545  txVector.SetMode(DsssPhy::GetDsssRate1Mbps());
1546  txVector.SetChannelWidth(22);
1547 
1548  // -> long PPDU format
1550  nonHtMode = DsssPhy::GetDsssRate1Mbps();
1551  sections = {
1552  {WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(144)}, nonHtMode}},
1554  {{ppduStart + MicroSeconds(144), ppduStart + MicroSeconds(192)}, nonHtMode}},
1555  };
1556  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1557 
1558  // -> long PPDU format if data rate is 1 Mbps (even if preamble is tagged short)
1560  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1561 
1562  // -> short PPDU format
1563  txVector.SetMode(DsssPhy::GetDsssRate11Mbps());
1564  nonHtMode = DsssPhy::GetDsssRate2Mbps();
1566  sections = {
1567  {WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(72)}, nonHtMode}},
1569  {{ppduStart + MicroSeconds(72), ppduStart + MicroSeconds(96)}, nonHtMode}},
1570  };
1571  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1572 
1573  // ==================================================================================
1574  // 11a (OFDM)
1576 
1577  // -> one iteration per variant: default, 10 MHz, and 5 MHz
1578  std::map<OfdmPhyVariant, std::size_t> variants{
1579  // number to use to deduce rate and BW info for each variant
1580  {OFDM_PHY_DEFAULT, 1},
1581  {OFDM_PHY_10_MHZ, 2},
1582  {OFDM_PHY_5_MHZ, 4},
1583  };
1584  for (auto variant : variants)
1585  {
1586  phyEntity = Create<OfdmPhy>(variant.first);
1587  std::size_t ratio = variant.second;
1588  uint16_t bw = 20 / ratio; // MHz
1589  txVector.SetChannelWidth(bw);
1590  txVector.SetMode(OfdmPhy::GetOfdmRate(12000000 / ratio, bw));
1591  nonHtMode = OfdmPhy::GetOfdmRate(6000000 / ratio, bw);
1592  sections = {
1594  {{ppduStart, ppduStart + MicroSeconds(16 * ratio)}, nonHtMode}},
1596  {{ppduStart + MicroSeconds(16 * ratio), ppduStart + MicroSeconds(20 * ratio)},
1597  nonHtMode}},
1598  };
1599  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1600  }
1601 
1602  // ==================================================================================
1603  // 11g (ERP-OFDM)
1604  phyEntity = Create<ErpOfdmPhy>();
1605  txVector.SetChannelWidth(20);
1606  txVector.SetMode(ErpOfdmPhy::GetErpOfdmRate(54000000));
1607  nonHtMode = ErpOfdmPhy::GetErpOfdmRate6Mbps();
1608  sections = {
1609  {WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(16)}, nonHtMode}},
1611  {{ppduStart + MicroSeconds(16), ppduStart + MicroSeconds(20)}, nonHtMode}},
1612  };
1613  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1614 
1615  // ==================================================================================
1616  // 11n (HT)
1617  phyEntity = Create<HtPhy>(4);
1618  txVector.SetChannelWidth(20);
1619  txVector.SetMode(HtPhy::GetHtMcs6());
1620  nonHtMode = OfdmPhy::GetOfdmRate6Mbps();
1621  WifiMode htSigMode = nonHtMode;
1622 
1623  // -> HT-mixed format for 2 SS and no ESS
1625  txVector.SetNss(2);
1626  txVector.SetNess(0);
1627  sections = {
1628  {WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(16)}, nonHtMode}},
1630  {{ppduStart + MicroSeconds(16), ppduStart + MicroSeconds(20)}, nonHtMode}},
1632  {{ppduStart + MicroSeconds(20), ppduStart + MicroSeconds(28)}, htSigMode}},
1634  {{ppduStart + MicroSeconds(28), ppduStart + MicroSeconds(40)}, // 1 HT-STF + 2 HT-LTFs
1635  htSigMode}},
1636  };
1637  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1638  txVector.SetChannelWidth(20); // shouldn't have any impact
1639  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1640 
1641  // -> HT-mixed format for 3 SS and 1 ESS
1642  txVector.SetNss(3);
1643  txVector.SetNess(1);
1644  sections[WIFI_PPDU_FIELD_TRAINING] = {
1645  {ppduStart + MicroSeconds(28),
1646  ppduStart + MicroSeconds(52)}, // 1 HT-STF + 5 HT-LTFs (4 data + 1 extension)
1647  htSigMode};
1648  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1649 
1650  // ==================================================================================
1651  // 11ac (VHT)
1652  phyEntity = Create<VhtPhy>();
1653  txVector.SetChannelWidth(20);
1654  txVector.SetNess(0);
1655  txVector.SetMode(VhtPhy::GetVhtMcs7());
1656  WifiMode sigAMode = nonHtMode;
1657  WifiMode sigBMode = VhtPhy::GetVhtMcs0();
1658 
1659  // -> VHT SU format for 5 SS
1661  txVector.SetNss(5);
1662  sections = {
1663  {WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(16)}, nonHtMode}},
1665  {{ppduStart + MicroSeconds(16), ppduStart + MicroSeconds(20)}, nonHtMode}},
1667  {{ppduStart + MicroSeconds(20), ppduStart + MicroSeconds(28)}, sigAMode}},
1669  {{ppduStart + MicroSeconds(28), ppduStart + MicroSeconds(56)}, // 1 VHT-STF + 6 VHT-LTFs
1670  sigAMode}},
1671  };
1672  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1673 
1674  // -> VHT SU format for 7 SS
1675  txVector.SetNss(7);
1676  sections[WIFI_PPDU_FIELD_TRAINING] = {
1677  {ppduStart + MicroSeconds(28), ppduStart + MicroSeconds(64)}, // 1 VHT-STF + 8 VHT-LTFs
1678  sigAMode};
1679  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1680 
1681  // -> VHT MU format for 3 SS
1683  txVector.SetNss(3);
1684  sections[WIFI_PPDU_FIELD_TRAINING] = {
1685  {ppduStart + MicroSeconds(28), ppduStart + MicroSeconds(48)}, // 1 VHT-STF + 4 VHT-LTFs
1686  sigAMode};
1687  sections[WIFI_PPDU_FIELD_SIG_B] = {{ppduStart + MicroSeconds(48), ppduStart + MicroSeconds(52)},
1688  sigBMode};
1689  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1690  txVector.SetChannelWidth(80); // shouldn't have any impact
1691  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1692 
1693  // ==================================================================================
1694  // 11ax (HE)
1695  phyEntity = Create<HePhy>();
1696  txVector.SetChannelWidth(20);
1697  txVector.SetNss(2); // HE-LTF duration assumed to be always 8 us for the time being (see note in
1698  // HePhy::GetTrainingDuration)
1699  txVector.SetMode(HePhy::GetHeMcs9());
1700  std::map<uint16_t, HeMuUserInfo> userInfoMap = {{1, {{HeRu::RU_106_TONE, 1, true}, 4, 2}},
1701  {2, {{HeRu::RU_106_TONE, 1, true}, 9, 1}}};
1702  sigAMode = HePhy::GetVhtMcs0();
1703  sigBMode = HePhy::GetVhtMcs4(); // because of first user info map
1704 
1705  // -> HE SU format
1707  sections = {
1708  {WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(16)}, nonHtMode}},
1710  {{ppduStart + MicroSeconds(16), ppduStart + MicroSeconds(24)}, // L-SIG + RL-SIG
1711  nonHtMode}},
1713  {{ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(32)}, sigAMode}},
1715  {{ppduStart + MicroSeconds(32),
1716  ppduStart + MicroSeconds(52)}, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
1717  sigAMode}},
1718  };
1719  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1720 
1721  // -> HE ER SU format
1723  sections[WIFI_PPDU_FIELD_SIG_A] = {
1724  {ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(40)}, // 16 us HE-SIG-A
1725  sigAMode};
1726  sections[WIFI_PPDU_FIELD_TRAINING] = {
1727  {ppduStart + MicroSeconds(40),
1728  ppduStart + MicroSeconds(60)}, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
1729  sigAMode};
1730  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1731 
1732  // -> HE TB format
1734  txVector.SetHeMuUserInfo(1, userInfoMap.at(1));
1735  txVector.SetHeMuUserInfo(2, userInfoMap.at(2));
1736  sections[WIFI_PPDU_FIELD_SIG_A] = {{ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(32)},
1737  sigAMode};
1738  sections[WIFI_PPDU_FIELD_TRAINING] = {
1739  {ppduStart + MicroSeconds(32),
1740  ppduStart + MicroSeconds(56)}, // 1 HE-STF (@ 8 us) + 2 HE-LTFs (@ 8 us)
1741  sigAMode};
1742  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1743 
1744  // -> HE MU format
1746  txVector.SetSigBMode(sigBMode);
1747  txVector.SetRuAllocation({96});
1748  sections[WIFI_PPDU_FIELD_SIG_A] = {{ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(32)},
1749  sigAMode};
1750  sections[WIFI_PPDU_FIELD_SIG_B] = {
1751  {ppduStart + MicroSeconds(32), ppduStart + MicroSeconds(36)}, // only one symbol
1752  sigBMode};
1753  sections[WIFI_PPDU_FIELD_TRAINING] = {
1754  {ppduStart + MicroSeconds(36),
1755  ppduStart + MicroSeconds(56)}, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
1756  sigBMode};
1757  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1758  txVector.SetChannelWidth(160); // shouldn't have any impact
1759  txVector.SetRuAllocation({96, 113, 113, 113, 113, 113, 113, 113});
1760 
1761  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1762 
1763  // ==================================================================================
1764  // 11be (EHT)
1765  sections.erase(WIFI_PPDU_FIELD_SIG_A); // FIXME: do we keep using separate type for 11be?
1766  sections.erase(WIFI_PPDU_FIELD_SIG_B); // FIXME: do we keep using separate type for 11be?
1767  phyEntity = Create<EhtPhy>();
1768  txVector.SetChannelWidth(20);
1769  txVector.SetNss(2); // EHT-LTF duration assumed to be always 8 us for the time being (see note
1770  // in HePhy::GetTrainingDuration)
1771  txVector.SetMode(EhtPhy::GetEhtMcs9());
1772  userInfoMap = {{1, {{HeRu::RU_106_TONE, 1, true}, 4, 2}},
1773  {2, {{HeRu::RU_106_TONE, 1, true}, 9, 1}}};
1774  WifiMode uSigMode = EhtPhy::GetVhtMcs0();
1775  WifiMode ehtSigMode = EhtPhy::GetVhtMcs4(); // because of first user info map
1776 
1777  // -> EHT TB format
1779  txVector.SetHeMuUserInfo(1, userInfoMap.at(1));
1780  txVector.SetHeMuUserInfo(2, userInfoMap.at(2));
1781  sections[WIFI_PPDU_FIELD_U_SIG] = {{ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(32)},
1782  uSigMode};
1783  sections[WIFI_PPDU_FIELD_TRAINING] = {
1784  {ppduStart + MicroSeconds(32),
1785  ppduStart + MicroSeconds(56)}, // 1 EHT-STF (@ 8 us) + 2 EHT-LTFs (@ 8 us)
1786  uSigMode};
1787  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1788 
1789  // -> EHT MU format
1791  txVector.SetEhtPpduType(0); // EHT MU transmission
1792  txVector.SetRuAllocation({96});
1793  sections[WIFI_PPDU_FIELD_U_SIG] = {{ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(32)},
1794  uSigMode};
1795  sections[WIFI_PPDU_FIELD_EHT_SIG] = {
1796  {ppduStart + MicroSeconds(32), ppduStart + MicroSeconds(36)}, // only one symbol
1797  ehtSigMode};
1798  sections[WIFI_PPDU_FIELD_TRAINING] = {
1799  {ppduStart + MicroSeconds(36),
1800  ppduStart + MicroSeconds(56)}, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
1801  ehtSigMode};
1802  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1803  txVector.SetChannelWidth(160); // shouldn't have any impact
1804  txVector.SetRuAllocation({96, 113, 113, 113, 113, 113, 113, 113});
1805 
1806  CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1807 }
1808 
1816 {
1817  public:
1819 };
1820 
1822  : TestSuite("wifi-devices-tx-duration", UNIT)
1823 {
1824  AddTestCase(new HeSigBDurationTest, TestCase::QUICK);
1825  AddTestCase(new TxDurationTest, TestCase::QUICK);
1826  AddTestCase(new PhyHeaderSectionsTest, TestCase::QUICK);
1827 }
1828 
HE-SIG-B duration test.
static WifiTxVector BuildTxVector(uint16_t bw, std::list< HeMuUserInfo > userInfos)
Build a TXVECTOR for HE MU with the given bandwidth and user information.
void DoRun() override
Implementation to actually run this TestCase.
~HeSigBDurationTest() override
PHY header sections consistency test.
void DoRun() 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.
Tx Duration Test.
~TxDurationTest() override
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.
static bool CheckMuTxDuration(std::list< uint32_t > sizes, std::list< HeMuUserInfo > userInfos, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
Check if the overall Tx duration returned by WifiPhy for a MU PPDU corresponds to a known value.
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.
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.
void DoRun() override
Implementation to actually run this TestCase.
Tx Duration Test Suite.
RuType GetRuType() const
Get the RU type.
Definition: he-ru.cc:435
std::map< WifiPpduField, PhyHeaderChunkInfo > PhyHeaderSections
A map of PhyHeaderChunkInfo elements per PPDU field.
Definition: phy-entity.h:327
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:305
A suite of tests to run.
Definition: test.h:1256
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
Implements the IEEE 802.11 MAC header.
uint32_t GetSerializedSize() const override
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
represent a single transmission mode
Definition: wifi-mode.h:50
WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:185
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:122
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetStbc(bool stbc)
Sets if STBC is being used.
void SetNess(uint8_t ness)
Sets the Ness number.
void SetEhtPpduType(uint8_t type)
Set the EHT_PPDU_TYPE parameter.
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
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.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
void SetRuAllocation(const RuAllocation &ruAlloc)
Set RU Allocation of SIG-B common field.
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.
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
std::pair< std::size_t, std::size_t > GetNumRusPerHeSigBContentChannel() const
Get the number of RUs per HE-SIG-B content channel.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetNss(uint8_t nss)
Sets the number of Nss.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#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:251
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1360
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1372
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
WifiPreamble
The type of preamble to be used by an IEEE 802.11 transmission.
WifiPhyBand
Identifies the PHY band.
Definition: wifi-phy-band.h:33
WifiPpduField
The type of PPDU field (grouped for convenience)
@ WIFI_PREAMBLE_LONG
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_ER_SU
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PREAMBLE_HE_SU
@ WIFI_PREAMBLE_VHT_MU
@ WIFI_PREAMBLE_VHT_SU
@ WIFI_PREAMBLE_SHORT
@ WIFI_PREAMBLE_HT_MF
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
Definition: wifi-phy-band.h:39
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
Definition: wifi-phy-band.h:35
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Definition: wifi-phy-band.h:37
@ WIFI_MOD_CLASS_OFDM
OFDM (Clause 17)
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ OFDM_PHY_10_MHZ
Definition: ofdm-phy.h:46
@ OFDM_PHY_DEFAULT
Definition: ofdm-phy.h:45
@ OFDM_PHY_5_MHZ
Definition: ofdm-phy.h:47
@ WIFI_PPDU_FIELD_SIG_B
SIG-B field.
@ WIFI_PPDU_FIELD_TRAINING
STF + LTF fields (excluding those in preamble for HT-GF)
@ WIFI_PPDU_FIELD_NON_HT_HEADER
PHY header field for DSSS or ERP, short PHY header field for HR/DSSS or ERP, field not present for HT...
@ WIFI_PPDU_FIELD_EHT_SIG
EHT-SIG field.
@ WIFI_PPDU_FIELD_HT_SIG
HT-SIG field.
@ WIFI_PPDU_FIELD_PREAMBLE
SYNC + SFD fields for DSSS or ERP, shortSYNC + shortSFD fields for HR/DSSS or ERP,...
@ WIFI_PPDU_FIELD_U_SIG
U-SIG field.
@ WIFI_PPDU_FIELD_SIG_A
SIG-A field.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
@ WIFI_MAC_CTL_ACK
phy
Definition: third.py:82
HE MU specific user transmission parameters.
HeRu::RuSpec ru
RU specification.
static TxDurationTestSuite g_txDurationTestSuite
the test suite
#define SU_STA_ID
Definition: wifi-mode.h:34