A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
34using namespace ns3;
35
36NS_LOG_COMPONENT_DEFINE("InterferenceHelperTxDurationTest");
37
45{
46 public:
48 ~TxDurationTest() override;
49 void DoRun() override;
50
51 private:
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
141bool
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
193bool
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
252bool
253TxDurationTest::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 }
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
340Time
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
360void
362{
363 bool retval = true;
364
365 // IEEE Std 802.11-2007 Table 18-2 "Example of LENGTH calculations for CCK"
366 retval = retval &&
369 22,
370 800,
372 MicroSeconds(744)) &&
375 22,
376 800,
378 MicroSeconds(745)) &&
381 22,
382 800,
384 MicroSeconds(746)) &&
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,
401 22,
402 800,
404 MicroSeconds(744 + 96)) &&
405 CheckTxDuration(1024,
407 22,
408 800,
410 MicroSeconds(745 + 96)) &&
411 CheckTxDuration(1025,
413 22,
414 800,
416 MicroSeconds(746 + 96)) &&
417 CheckTxDuration(1026,
419 22,
420 800,
422 MicroSeconds(747 + 96)) &&
423 CheckTxDuration(1023,
425 22,
426 800,
428 MicroSeconds(744 + 192)) &&
429 CheckTxDuration(1024,
431 22,
432 800,
434 MicroSeconds(745 + 192)) &&
435 CheckTxDuration(1025,
437 22,
438 800,
440 MicroSeconds(746 + 192)) &&
441 CheckTxDuration(1026,
443 22,
444 800,
446 MicroSeconds(747 + 192)) &&
447 CheckTxDuration(1023,
449 22,
450 800,
452 MicroSeconds(1488 + 96)) &&
453 CheckTxDuration(1024,
455 22,
456 800,
458 MicroSeconds(1490 + 96)) &&
459 CheckTxDuration(1025,
461 22,
462 800,
464 MicroSeconds(1491 + 96)) &&
465 CheckTxDuration(1026,
467 22,
468 800,
470 MicroSeconds(1493 + 96)) &&
471 CheckTxDuration(1023,
473 22,
474 800,
476 MicroSeconds(1488 + 192)) &&
477 CheckTxDuration(1024,
479 22,
480 800,
482 MicroSeconds(1490 + 192)) &&
483 CheckTxDuration(1025,
485 22,
486 800,
488 MicroSeconds(1491 + 192)) &&
489 CheckTxDuration(1026,
491 22,
492 800,
494 MicroSeconds(1493 + 192)) &&
495 CheckTxDuration(1023,
497 22,
498 800,
500 MicroSeconds(4092 + 96)) &&
501 CheckTxDuration(1024,
503 22,
504 800,
506 MicroSeconds(4096 + 96)) &&
507 CheckTxDuration(1025,
509 22,
510 800,
512 MicroSeconds(4100 + 96)) &&
513 CheckTxDuration(1026,
515 22,
516 800,
518 MicroSeconds(4104 + 96)) &&
519 CheckTxDuration(1023,
521 22,
522 800,
524 MicroSeconds(4092 + 192)) &&
525 CheckTxDuration(1024,
527 22,
528 800,
530 MicroSeconds(4096 + 192)) &&
531 CheckTxDuration(1025,
533 22,
534 800,
536 MicroSeconds(4100 + 192)) &&
537 CheckTxDuration(1026,
539 22,
540 800,
542 MicroSeconds(4104 + 192)) &&
543 CheckTxDuration(1023,
545 22,
546 800,
548 MicroSeconds(8184 + 192)) &&
549 CheckTxDuration(1024,
551 22,
552 800,
554 MicroSeconds(8192 + 192)) &&
555 CheckTxDuration(1025,
557 22,
558 800,
560 MicroSeconds(8200 + 192)) &&
561 CheckTxDuration(1026,
563 22,
564 800,
566 MicroSeconds(8208 + 192)) &&
567 CheckTxDuration(1023,
569 22,
570 800,
572 MicroSeconds(8184 + 192)) &&
573 CheckTxDuration(1024,
575 22,
576 800,
578 MicroSeconds(8192 + 192)) &&
579 CheckTxDuration(1025,
581 22,
582 800,
584 MicroSeconds(8200 + 192)) &&
585 CheckTxDuration(1026,
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,
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,
604 22,
605 800,
607 MicroSeconds(1310)) &&
610 22,
611 800,
613 MicroSeconds(248)) &&
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,
628 20,
629 800,
631 MicroSeconds(248)) &&
634 20,
635 800,
637 MicroSeconds(32)) &&
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,
651 20,
652 800,
654 MicroSeconds(254)) &&
657 20,
658 800,
660 MicroSeconds(38)) &&
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,
675 20,
676 800,
678 MicroSeconds(228)) &&
681 CheckTxDuration(1536,
683 20,
684 400,
686 NanoSeconds(1742400)) &&
689 CheckTxDuration(1536,
691 20,
692 400,
694 NanoSeconds(226800)) &&
697 CheckTxDuration(1536,
699 40,
700 800,
702 MicroSeconds(128)) &&
705 CheckTxDuration(1536,
707 40,
708 400,
710 NanoSeconds(118800)) &&
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,
720 20,
721 800,
723 MicroSeconds(196)) &&
726 20,
727 800,
729 MicroSeconds(48)) &&
732 20,
733 800,
735 MicroSeconds(40)) &&
736 CheckTxDuration(1536,
738 20,
739 400,
741 MicroSeconds(180)) &&
744 20,
745 400,
747 NanoSeconds(46800)) &&
750 20,
751 400,
753 NanoSeconds(39600)) &&
754 CheckTxDuration(1536,
756 40,
757 800,
759 MicroSeconds(108)) &&
762 40,
763 800,
765 MicroSeconds(40)) &&
768 40,
769 800,
771 MicroSeconds(40)) &&
772 CheckTxDuration(1536,
774 40,
775 400,
777 NanoSeconds(100800)) &&
780 40,
781 400,
783 NanoSeconds(39600)) &&
786 40,
787 400,
789 NanoSeconds(39600)) &&
790 CheckTxDuration(1536,
792 80,
793 800,
795 MicroSeconds(460)) &&
798 80,
799 800,
801 MicroSeconds(60)) &&
804 80,
805 800,
807 MicroSeconds(44)) &&
808 CheckTxDuration(1536,
810 80,
811 400,
813 NanoSeconds(417600)) &&
816 80,
817 400,
819 NanoSeconds(57600)) &&
822 80,
823 400,
825 NanoSeconds(43200)) &&
826 CheckTxDuration(1536,
828 80,
829 800,
831 MicroSeconds(68)) &&
834 80,
835 800,
837 MicroSeconds(40)) &&
840 80,
841 800,
843 MicroSeconds(40)) &&
844 CheckTxDuration(1536,
846 80,
847 400,
849 NanoSeconds(64800)) &&
852 80,
853 400,
855 NanoSeconds(39600)) &&
858 80,
859 400,
861 NanoSeconds(39600)) &&
862 CheckTxDuration(1536,
864 160,
865 800,
867 MicroSeconds(56)) &&
870 160,
871 800,
873 MicroSeconds(40)) &&
876 160,
877 800,
879 MicroSeconds(40)) &&
880 CheckTxDuration(1536,
882 160,
883 400,
885 MicroSeconds(54)) &&
888 160,
889 400,
891 NanoSeconds(39600)) &&
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,
906 20,
907 800,
909 NanoSeconds(1485600)) &&
912 20,
913 800,
915 NanoSeconds(125600)) &&
917 CheckTxDuration(1536,
919 40,
920 800,
922 NanoSeconds(764800)) &&
925 CheckTxDuration(1536,
927 80,
928 800,
930 NanoSeconds(397600)) &&
933 CheckTxDuration(1536,
935 160,
936 800,
938 NanoSeconds(220800)) &&
941 160,
942 800,
944 NanoSeconds(57600)) &&
947 160,
948 800,
950 NanoSeconds(57600)) &&
951 CheckTxDuration(1536,
953 20,
954 1600,
956 NanoSeconds(1570400)) &&
959 20,
960 1600,
962 NanoSeconds(130400)) &&
965 20,
966 1600,
968 NanoSeconds(72800)) &&
969 CheckTxDuration(1536,
971 40,
972 1600,
974 NanoSeconds(807200)) &&
977 40,
978 1600,
980 NanoSeconds(87200)) &&
983 40,
984 1600,
986 NanoSeconds(58400)) &&
987 CheckTxDuration(1536,
989 80,
990 1600,
992 NanoSeconds(418400)) &&
995 80,
996 1600,
998 NanoSeconds(72800)) &&
1001 80,
1002 1600,
1004 NanoSeconds(58400)) &&
1005 CheckTxDuration(1536,
1007 160,
1008 1600,
1010 NanoSeconds(231200)) &&
1011 CheckTxDuration(76,
1013 160,
1014 1600,
1016 NanoSeconds(58400)) &&
1017 CheckTxDuration(14,
1019 160,
1020 1600,
1022 NanoSeconds(58400)) &&
1023 CheckTxDuration(1536,
1025 20,
1026 3200,
1028 MicroSeconds(1740)) &&
1031 CheckTxDuration(1536,
1033 40,
1034 3200,
1036 MicroSeconds(892)) &&
1039 CheckTxDuration(1536,
1041 80,
1042 3200,
1044 MicroSeconds(460)) &&
1047 CheckTxDuration(1536,
1049 160,
1050 3200,
1052 MicroSeconds(252)) &&
1055 CheckTxDuration(1536,
1057 20,
1058 800,
1060 NanoSeconds(139200)) &&
1061 CheckTxDuration(76,
1063 20,
1064 800,
1066 NanoSeconds(57600)) &&
1067 CheckTxDuration(14,
1069 20,
1070 800,
1072 NanoSeconds(57600)) &&
1073 CheckTxDuration(1536,
1075 40,
1076 800,
1078 NanoSeconds(98400)) &&
1079 CheckTxDuration(76,
1081 40,
1082 800,
1084 NanoSeconds(57600)) &&
1085 CheckTxDuration(14,
1087 40,
1088 800,
1090 NanoSeconds(57600)) &&
1091 CheckTxDuration(1536,
1093 80,
1094 800,
1096 NanoSeconds(71200)) &&
1097 CheckTxDuration(76,
1099 80,
1100 800,
1102 NanoSeconds(57600)) &&
1103 CheckTxDuration(14,
1105 80,
1106 800,
1108 NanoSeconds(57600)) &&
1109 CheckTxDuration(1536,
1111 160,
1112 800,
1114 NanoSeconds(57600)) &&
1115 CheckTxDuration(76,
1117 160,
1118 800,
1120 NanoSeconds(57600)) &&
1121 CheckTxDuration(14,
1123 160,
1124 800,
1126 NanoSeconds(57600)) &&
1127 CheckTxDuration(1536,
1129 20,
1130 1600,
1132 NanoSeconds(144800)) &&
1133 CheckTxDuration(76,
1135 20,
1136 1600,
1138 NanoSeconds(58400)) &&
1139 CheckTxDuration(14,
1141 20,
1142 1600,
1144 NanoSeconds(58400)) &&
1145 CheckTxDuration(1536,
1147 40,
1148 1600,
1150 NanoSeconds(101600)) &&
1151 CheckTxDuration(76,
1153 40,
1154 1600,
1156 NanoSeconds(58400)) &&
1157 CheckTxDuration(14,
1159 40,
1160 1600,
1162 NanoSeconds(58400)) &&
1163 CheckTxDuration(1536,
1165 80,
1166 1600,
1168 NanoSeconds(72800)) &&
1169 CheckTxDuration(76,
1171 80,
1172 1600,
1174 NanoSeconds(58400)) &&
1175 CheckTxDuration(14,
1177 80,
1178 1600,
1180 NanoSeconds(58400)) &&
1181 CheckTxDuration(1536,
1183 160,
1184 1600,
1186 NanoSeconds(58400)) &&
1187 CheckTxDuration(76,
1189 160,
1190 1600,
1192 NanoSeconds(58400)) &&
1193 CheckTxDuration(14,
1195 160,
1196 1600,
1198 NanoSeconds(58400)) &&
1199 CheckTxDuration(1536,
1201 20,
1202 3200,
1204 MicroSeconds(156)) &&
1207 CheckTxDuration(1536,
1209 40,
1210 3200,
1212 MicroSeconds(108)) &&
1215 CheckTxDuration(1536,
1217 80,
1218 3200,
1220 MicroSeconds(76)) &&
1223 CheckTxDuration(1536,
1225 160,
1226 3200,
1228 MicroSeconds(60)) &&
1229 CheckTxDuration(76,
1231 160,
1232 3200,
1234 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,
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
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
1331HeSigBDurationTest::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
1349void
1351{
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),
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),
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),
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),
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),
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:
1479};
1480
1482 : TestCase("PHY header sections consistency")
1483{
1484}
1485
1487{
1488}
1489
1490void
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
1511 fieldRef,
1512 "The expected PPDU field (" << fieldRef << ") was not obtained ("
1513 << field << ")");
1514 NS_TEST_EXPECT_MSG_EQ(window.first,
1515 windowRef.first,
1516 "The expected start time (" << windowRef.first
1517 << ") was not obtained (" << window.first
1518 << ")");
1519 NS_TEST_EXPECT_MSG_EQ(window.second,
1520 windowRef.second,
1521 "The expected stop time (" << windowRef.second
1522 << ") was not obtained (" << window.second
1523 << ")");
1525 modeRef,
1526 "The expected mode (" << modeRef << ") was not obtained (" << mode
1527 << ")");
1528 ++itObtained;
1529 ++itExpected;
1530 }
1531}
1532
1533void
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>();
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
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{
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.
static WifiMode GetDsssRate5_5Mbps()
Return a WifiMode for HR/DSSS at 5.5 Mbps.
static WifiMode GetDsssRate1Mbps()
Return a WifiMode for DSSS at 1 Mbps.
static WifiMode GetDsssRate11Mbps()
Return a WifiMode for HR/DSSS at 11 Mbps.
static WifiMode GetDsssRate2Mbps()
Return a WifiMode for DSSS at 2 Mbps.
static WifiMode GetEhtMcs9()
Return MCS 9 from EHT MCS values.
static WifiMode GetErpOfdmRate(uint64_t rate)
Return a WifiMode for ERP-OFDM corresponding to the provided rate.
static WifiMode GetErpOfdmRate6Mbps()
Return a WifiMode for ERP-OFDM at 6 Mbps.
static WifiMode GetErpOfdmRate54Mbps()
Return a WifiMode for ERP-OFDM at 54 Mbps.
static WifiMode GetHeMcs9()
Return MCS 9 from HE MCS values.
static WifiMode GetHeMcs11()
Return MCS 11 from HE MCS values.
static WifiMode GetHeMcs0()
Return MCS 0 from HE MCS values.
RuType GetRuType() const
Get the RU type.
Definition: he-ru.cc:435
static uint16_t GetBandwidth(RuType ruType)
Get the approximate bandwidth occupied by a RU.
Definition: he-ru.cc:744
@ RU_26_TONE
Definition: he-ru.h:42
@ RU_996_TONE
Definition: he-ru.h:47
@ RU_106_TONE
Definition: he-ru.h:44
@ RU_52_TONE
Definition: he-ru.h:43
@ RU_242_TONE
Definition: he-ru.h:45
static WifiMode GetHtMcs0()
Return MCS 0 from HT MCS values.
static WifiMode GetHtMcs6()
Return MCS 6 from HT MCS values.
static WifiMode GetHtMcs7()
Return MCS 7 from HT MCS values.
static WifiMode GetOfdmRate6Mbps()
Return a WifiMode for OFDM at 6 Mbps.
static WifiMode GetOfdmRate54Mbps()
Return a WifiMode for OFDM at 54 Mbps.
static WifiMode GetOfdmRate(uint64_t rate, uint16_t bw=20)
Return a WifiMode for OFDM corresponding to the provided rate and the channel bandwidth (20,...
Definition: ofdm-phy.cc:413
std::map< WifiPpduField, PhyHeaderChunkInfo > PhyHeaderSections
A map of PhyHeaderChunkInfo elements per PPDU field.
Definition: phy-entity.h:327
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:140
encapsulates test code
Definition: test.h:1060
@ QUICK
Fast test.
Definition: test.h:1065
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
static WifiMode GetVhtMcs0()
Return MCS 0 from VHT MCS values.
static WifiMode GetVhtMcs5()
Return MCS 5 from VHT MCS values.
static WifiMode GetVhtMcs3()
Return MCS 3 from VHT MCS values.
static WifiMode GetVhtMcs1()
Return MCS 1 from VHT MCS values.
static WifiMode GetVhtMcs4()
Return MCS 4 from VHT MCS values.
static WifiMode GetVhtMcs9()
Return MCS 9 from VHT MCS values.
static WifiMode GetVhtMcs8()
Return MCS 8 from VHT MCS values.
static WifiMode GetVhtMcs7()
Return MCS 7 from VHT MCS values.
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
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1480
static const Ptr< const PhyEntity > GetStaticPhyEntity(WifiModulationClass modulation)
Get the implemented PHY entity corresponding to the modulation class.
Definition: wifi-phy.cc:695
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
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