A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-phy-mu-mimo-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 DERONNE SOFTWARE ENGINEERING
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
7 */
8
9#include "ns3/ap-wifi-mac.h"
10#include "ns3/boolean.h"
11#include "ns3/double.h"
12#include "ns3/he-configuration.h"
13#include "ns3/he-phy.h"
14#include "ns3/interference-helper.h"
15#include "ns3/log.h"
16#include "ns3/multi-model-spectrum-channel.h"
17#include "ns3/nist-error-rate-model.h"
18#include "ns3/node.h"
19#include "ns3/pointer.h"
20#include "ns3/rng-seed-manager.h"
21#include "ns3/simulator.h"
22#include "ns3/spectrum-wifi-helper.h"
23#include "ns3/spectrum-wifi-phy.h"
24#include "ns3/string.h"
25#include "ns3/test.h"
26#include "ns3/txop.h"
27#include "ns3/uinteger.h"
28#include "ns3/wifi-mac-header.h"
29#include "ns3/wifi-net-device.h"
30#include "ns3/wifi-psdu.h"
31#include "ns3/wifi-spectrum-value-helper.h"
32#include "ns3/wifi-utils.h"
33
34#include <list>
35#include <tuple>
36
37using namespace ns3;
38
39NS_LOG_COMPONENT_DEFINE("WifiPhyMuMimoTest");
40
41constexpr MHz_u DEFAULT_FREQUENCY = 5180;
43
44/**
45 * @ingroup wifi-test
46 * @ingroup tests
47 *
48 * @brief DL MU TX-VECTOR test
49 */
51{
52 public:
54
55 private:
56 void DoRun() override;
57
58 /**
59 * Build a TXVECTOR for DL MU with the given bandwidth and user information.
60 *
61 * @param bw the channel width of the PPDU
62 * @param userInfos the list of HE MU specific user transmission parameters
63 *
64 * @return the configured MU TXVECTOR
65 */
66 static WifiTxVector BuildTxVector(MHz_u bw, const std::list<HeMuUserInfo>& userInfos);
67};
68
70 : TestCase("Check for valid combinations of MU TX-VECTOR")
71{
72}
73
75TestDlMuTxVector::BuildTxVector(MHz_u bw, const std::list<HeMuUserInfo>& userInfos)
76{
77 WifiTxVector txVector;
79 txVector.SetChannelWidth(bw);
80 std::list<uint16_t> staIds;
81 uint16_t staId = 1;
82 for (const auto& userInfo : userInfos)
83 {
84 txVector.SetHeMuUserInfo(staId, userInfo);
85 staIds.push_back(staId++);
86 }
87 return txVector;
88}
89
90void
92{
93 // Verify TxVector is OFDMA
94 std::list<HeMuUserInfo> userInfos;
95 userInfos.push_back({{HeRu::RU_106_TONE, 1, true}, 11, 1});
96 userInfos.push_back({{HeRu::RU_106_TONE, 2, true}, 10, 2});
97 WifiTxVector txVector = BuildTxVector(MHz_u{20}, userInfos);
99 true,
100 "TX-VECTOR should indicate an OFDMA transmission");
102 false,
103 "TX-VECTOR should not indicate a MU-MIMO transmission");
105 false,
106 "TX-VECTOR should not indicate a SIG-B compression");
108 true,
109 "TX-VECTOR should indicate all checks are passed");
110 userInfos.clear();
111
112 // Verify TxVector is a full BW MU-MIMO
113 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 1});
114 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 2});
115 txVector = BuildTxVector(MHz_u{20}, userInfos);
117 false,
118 "TX-VECTOR should indicate a MU-MIMO transmission");
120 true,
121 "TX-VECTOR should not indicate an OFDMA transmission");
123 true,
124 "TX-VECTOR should indicate a SIG-B compression");
126 true,
127 "TX-VECTOR should indicate all checks are passed");
128 userInfos.clear();
129
130 // Verify TxVector is not valid if there are more than 8 STAs using the same RU
131 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 1});
132 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 1});
133 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 9, 1});
134 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 8, 1});
135 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 7, 1});
136 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 6, 1});
137 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 5, 1});
138 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 4, 1});
139 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 3, 1});
140 txVector = BuildTxVector(MHz_u{20}, userInfos);
142 false,
143 "TX-VECTOR should indicate a MU-MIMO transmission");
145 true,
146 "TX-VECTOR should not indicate an OFDMA transmission");
148 true,
149 "TX-VECTOR should indicate a SIG-B compression");
151 false,
152 "TX-VECTOR should not indicate all checks are passed");
153
154 // Verify TxVector is not valid if the total number of antennas in a full BW MU-MIMO is above 8
155 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 2});
156 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 2});
157 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 9, 3});
158 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 8, 3});
159 txVector = BuildTxVector(MHz_u{20}, userInfos);
161 false,
162 "TX-VECTOR should indicate a MU-MIMO transmission");
164 true,
165 "TX-VECTOR should not indicate an OFDMA transmission");
167 true,
168 "TX-VECTOR should indicate a SIG-B compression");
170 false,
171 "TX-VECTOR should not indicate all checks are passed");
172}
173
174/**
175 * HE PHY slightly modified so as to return a given
176 * STA-ID in case of DL MU for MuMimoSpectrumWifiPhy.
177 */
178class MuMimoTestHePhy : public HePhy
179{
180 public:
181 /**
182 * Constructor
183 *
184 * @param staId the ID of the STA to which this PHY belongs to
185 */
186 MuMimoTestHePhy(uint16_t staId);
187
188 /**
189 * Return the STA ID that has been assigned to the station this PHY belongs to.
190 * This is typically called for MU PPDUs, in order to pick the correct PSDU.
191 *
192 * @param ppdu the PPDU for which the STA ID is requested
193 * @return the STA ID
194 */
195 uint16_t GetStaId(const Ptr<const WifiPpdu> ppdu) const override;
196
197 /**
198 * Set the global PPDU UID counter.
199 *
200 * @param uid the value to which the global PPDU UID counter should be set
201 */
202 void SetGlobalPpduUid(uint64_t uid);
203
204 private:
205 uint16_t m_staId; ///< ID of the STA to which this PHY belongs to
206
207 // end of class MuMimoTestHePhy
208};
209
211 : HePhy(),
212 m_staId(staId)
213{
214}
215
216uint16_t
218{
219 if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
220 {
221 return m_staId;
222 }
223 return HePhy::GetStaId(ppdu);
224}
225
226void
228{
229 m_globalPpduUid = uid;
230}
231
232/**
233 * SpectrumWifiPhy used for testing MU-MIMO.
234 */
236{
237 public:
238 /**
239 * @brief Get the type ID.
240 * @return the object TypeId
241 */
242 static TypeId GetTypeId();
243 /**
244 * Constructor
245 *
246 * @param staId the ID of the STA to which this PHY belongs to
247 */
248 MuMimoSpectrumWifiPhy(uint16_t staId);
249 ~MuMimoSpectrumWifiPhy() override;
250
251 /**
252 * Set the global PPDU UID counter.
253 *
254 * @param uid the value to which the global PPDU UID counter should be set
255 */
256 void SetPpduUid(uint64_t uid);
257
258 /**
259 * Since we assume trigger frame was previously received from AP, this is used to set its UID
260 *
261 * @param uid the PPDU UID of the trigger frame
262 */
263 void SetTriggerFrameUid(uint64_t uid);
264
265 /**
266 * @return the current event
267 */
269
270 private:
271 void DoInitialize() override;
272 void DoDispose() override;
273
274 Ptr<MuMimoTestHePhy> m_ofdmTestHePhy; ///< Pointer to HE PHY instance used for MU-MIMO test
275
276 // end of class MuMimoSpectrumWifiPhy
277};
278
279TypeId
281{
282 static TypeId tid =
283 TypeId("ns3::MuMimoSpectrumWifiPhy").SetParent<SpectrumWifiPhy>().SetGroupName("Wifi");
284 return tid;
285}
286
293
297
298void
300{
301 // Replace HE PHY instance with test instance
304}
305
306void
312
313void
319
320void
325
331
332/**
333 * @ingroup wifi-test
334 * @ingroup tests
335 *
336 * @brief DL MU-MIMO PHY test
337 */
339{
340 public:
342
343 private:
344 void DoSetup() override;
345 void DoTeardown() override;
346 void DoRun() override;
347
348 /**
349 * Receive success function for STA 1
350 * @param psdu the PSDU
351 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
352 * @param txVector the transmit vector
353 * @param statusPerMpdu reception status per MPDU
354 */
356 RxSignalInfo rxSignalInfo,
357 const WifiTxVector& txVector,
358 const std::vector<bool>& statusPerMpdu);
359 /**
360 * Receive success function for STA 2
361 * @param psdu the PSDU
362 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
363 * @param txVector the transmit vector
364 * @param statusPerMpdu reception status per MPDU
365 */
367 RxSignalInfo rxSignalInfo,
368 const WifiTxVector& txVector,
369 const std::vector<bool>& statusPerMpdu);
370 /**
371 * Receive success function for STA 3
372 * @param psdu the PSDU
373 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
374 * @param txVector the transmit vector
375 * @param statusPerMpdu reception status per MPDU
376 */
378 RxSignalInfo rxSignalInfo,
379 const WifiTxVector& txVector,
380 const std::vector<bool>& statusPerMpdu);
381
382 /**
383 * Receive failure function for STA 1
384 * @param psdu the PSDU
385 */
387 /**
388 * Receive failure function for STA 2
389 * @param psdu the PSDU
390 */
392 /**
393 * Receive failure function for STA 3
394 * @param psdu the PSDU
395 */
397
398 /**
399 * Check the results for STA 1
400 * @param expectedRxSuccess the expected number of RX success
401 * @param expectedRxFailure the expected number of RX failures
402 * @param expectedRxBytes the expected number of RX bytes
403 */
404 void CheckResultsSta1(uint32_t expectedRxSuccess,
405 uint32_t expectedRxFailure,
406 uint32_t expectedRxBytes);
407 /**
408 * Check the results for STA 2
409 * @param expectedRxSuccess the expected number of RX success
410 * @param expectedRxFailure the expected number of RX failures
411 * @param expectedRxBytes the expected number of RX bytes
412 */
413 void CheckResultsSta2(uint32_t expectedRxSuccess,
414 uint32_t expectedRxFailure,
415 uint32_t expectedRxBytes);
416 /**
417 * Check the results for STA 3
418 * @param expectedRxSuccess the expected number of RX success
419 * @param expectedRxFailure the expected number of RX failures
420 * @param expectedRxBytes the expected number of RX bytes
421 */
422 void CheckResultsSta3(uint32_t expectedRxSuccess,
423 uint32_t expectedRxFailure,
424 uint32_t expectedRxBytes);
425
426 /**
427 * Reset the results
428 */
429 void ResetResults();
430
431 /**
432 * STA info
433 */
434 struct StaInfo
435 {
436 uint16_t staId; //!< STA ID
437 uint8_t staNss; //!< Number of spatial streams used for the STA
438 };
439
440 /**
441 * Send DL MU-MIMO PPDU function
442 * @param staInfos the STAs infos
443 */
444 void SendMuPpdu(const std::vector<StaInfo>& staInfos);
445
446 /**
447 * Generate interference function
448 * @param interferencePsd the PSD of the interference to be generated
449 * @param duration the duration of the interference
450 */
451 void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
452 /**
453 * Stop interference function
454 */
456
457 /**
458 * Run one function
459 */
460 void RunOne();
461
462 /**
463 * Schedule now to check the PHY state
464 * @param phy the PHY
465 * @param expectedState the expected state of the PHY
466 */
468 /**
469 * Check the PHY state now
470 * @param phy the PHY
471 * @param expectedState the expected state of the PHY
472 */
474
475 uint32_t m_countRxSuccessSta1; ///< count RX success for STA 1
476 uint32_t m_countRxSuccessSta2; ///< count RX success for STA 2
477 uint32_t m_countRxSuccessSta3; ///< count RX success for STA 3
478 uint32_t m_countRxFailureSta1; ///< count RX failure for STA 1
479 uint32_t m_countRxFailureSta2; ///< count RX failure for STA 2
480 uint32_t m_countRxFailureSta3; ///< count RX failure for STA 3
481 uint32_t m_countRxBytesSta1; ///< count RX bytes for STA 1
482 uint32_t m_countRxBytesSta2; ///< count RX bytes for STA 2
483 uint32_t m_countRxBytesSta3; ///< count RX bytes for STA 3
484
489
490 uint8_t m_nss; ///< number of spatial streams per STA
491 MHz_u m_frequency; ///< frequency
492 MHz_u m_channelWidth; ///< channel width
493 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
494};
495
497 : TestCase("DL MU-MIMO PHY test"),
498 m_countRxSuccessSta1{0},
499 m_countRxSuccessSta2{0},
500 m_countRxSuccessSta3{0},
501 m_countRxFailureSta1{0},
502 m_countRxFailureSta2{0},
503 m_countRxFailureSta3{0},
504 m_countRxBytesSta1{0},
505 m_countRxBytesSta2{0},
506 m_countRxBytesSta3{0},
507 m_nss{1},
508 m_frequency{DEFAULT_FREQUENCY},
509 m_channelWidth{DEFAULT_CHANNEL_WIDTH},
510 m_expectedPpduDuration{NanoSeconds(306400)}
511{
512}
513
514void
527
528void
529TestDlMuMimoPhyTransmission::SendMuPpdu(const std::vector<StaInfo>& staInfos)
530{
531 NS_LOG_FUNCTION(this << staInfos.size());
532 NS_ASSERT(staInfos.size() > 1);
533
535 0,
537 NanoSeconds(800),
538 1,
539 1,
540 0,
542 false,
543 false);
544
545 WifiConstPsduMap psdus;
546 HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
547 for (const auto& staInfo : staInfos)
548 {
549 txVector.SetRu(ru, staInfo.staId);
550 txVector.SetMode(HePhy::GetHeMcs7(), staInfo.staId);
551 txVector.SetNss(staInfo.staNss, staInfo.staId);
552
553 Ptr<Packet> pkt = Create<Packet>(1000 + (8 * staInfo.staId));
554 WifiMacHeader hdr;
556 hdr.SetQosTid(0);
557 std::ostringstream addr;
558 addr << "00:00:00:00:00:0" << staInfo.staId;
559 hdr.SetAddr1(Mac48Address(addr.str().c_str()));
560 hdr.SetSequenceNumber(1 + staInfo.staId);
561 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
562 psdus.insert(std::make_pair(staInfo.staId, psdu));
563 }
564
566
567 NS_ASSERT(txVector.IsDlMuMimo());
568 NS_ASSERT(!txVector.IsDlOfdma());
569
570 m_phyAp->Send(psdus, txVector);
571}
572
573void
575 RxSignalInfo rxSignalInfo,
576 const WifiTxVector& txVector,
577 const std::vector<bool>& /*statusPerMpdu*/)
578{
579 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
581 m_countRxBytesSta1 += (psdu->GetSize() - 30);
582}
583
584void
586 RxSignalInfo rxSignalInfo,
587 const WifiTxVector& txVector,
588 const std::vector<bool>& /*statusPerMpdu*/)
589{
590 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
592 m_countRxBytesSta2 += (psdu->GetSize() - 30);
593}
594
595void
597 RxSignalInfo rxSignalInfo,
598 const WifiTxVector& txVector,
599 const std::vector<bool>& /*statusPerMpdu*/)
600{
601 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
603 m_countRxBytesSta3 += (psdu->GetSize() - 30);
604}
605
606void
612
613void
619
620void
626
627void
629 uint32_t expectedRxFailure,
630 uint32_t expectedRxBytes)
631{
633 expectedRxSuccess,
634 "The number of successfully received packets by STA 1 is not correct!");
636 expectedRxFailure,
637 "The number of unsuccessfully received packets by STA 1 is not correct!");
639 expectedRxBytes,
640 "The number of bytes received by STA 1 is not correct!");
641}
642
643void
645 uint32_t expectedRxFailure,
646 uint32_t expectedRxBytes)
647{
649 expectedRxSuccess,
650 "The number of successfully received packets by STA 2 is not correct!");
652 expectedRxFailure,
653 "The number of unsuccessfully received packets by STA 2 is not correct!");
655 expectedRxBytes,
656 "The number of bytes received by STA 2 is not correct!");
657}
658
659void
661 uint32_t expectedRxFailure,
662 uint32_t expectedRxBytes)
663{
665 expectedRxSuccess,
666 "The number of successfully received packets by STA 3 is not correct!");
668 expectedRxFailure,
669 "The number of unsuccessfully received packets by STA 3 is not correct!");
671 expectedRxBytes,
672 "The number of bytes received by STA 3 is not correct!");
673}
674
675void
677 WifiPhyState expectedState)
678{
679 // This is needed to make sure PHY state will be checked as the last event if a state change
680 // occurred at the exact same time as the check
682}
683
684void
686 WifiPhyState expectedState)
687{
688 WifiPhyState currentState;
689 PointerValue ptr;
690 phy->GetAttribute("State", ptr);
692 currentState = state->GetState();
693 NS_LOG_FUNCTION(this << currentState << expectedState);
694 NS_TEST_ASSERT_MSG_EQ(currentState,
695 expectedState,
696 "PHY State " << currentState << " does not match expected state "
697 << expectedState << " at " << Simulator::Now());
698}
699
700void
702{
706 spectrumChannel->SetPropagationDelayModel(delayModel);
707
708 Ptr<Node> apNode = CreateObject<Node>();
712 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
714 m_phyAp->SetErrorRateModel(apErrorModel);
715 m_phyAp->SetDevice(apDev);
716 m_phyAp->AddChannel(spectrumChannel);
717 m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
718 apDev->SetPhy(m_phyAp);
719 apNode->AddDevice(apDev);
720
721 Ptr<Node> sta1Node = CreateObject<Node>();
725 m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
727 m_phySta1->SetErrorRateModel(sta1ErrorModel);
728 m_phySta1->SetDevice(sta1Dev);
729 m_phySta1->AddChannel(spectrumChannel);
735 sta1Dev->SetPhy(m_phySta1);
736 sta1Node->AddDevice(sta1Dev);
737
738 Ptr<Node> sta2Node = CreateObject<Node>();
742 m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
744 m_phySta2->SetErrorRateModel(sta2ErrorModel);
745 m_phySta2->SetDevice(sta2Dev);
746 m_phySta2->AddChannel(spectrumChannel);
752 sta2Dev->SetPhy(m_phySta2);
753 sta2Node->AddDevice(sta2Dev);
754
755 Ptr<Node> sta3Node = CreateObject<Node>();
759 m_phySta3->SetInterferenceHelper(sta3InterferenceHelper);
761 m_phySta3->SetErrorRateModel(sta3ErrorModel);
762 m_phySta3->SetDevice(sta3Dev);
763 m_phySta3->AddChannel(spectrumChannel);
769 sta3Dev->SetPhy(m_phySta3);
770 sta3Node->AddDevice(sta3Dev);
771}
772
773void
775{
776 m_phyAp->Dispose();
777 m_phyAp = nullptr;
779 m_phySta1 = nullptr;
781 m_phySta2 = nullptr;
783 m_phySta3 = nullptr;
784}
785
786void
788{
791 int64_t streamNumber = 0;
792 m_phyAp->AssignStreams(streamNumber);
793 m_phySta1->AssignStreams(streamNumber);
794 m_phySta2->AssignStreams(streamNumber);
795
796 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
801 ->number;
802
803 m_phyAp->SetOperatingChannel(
811
812 m_phyAp->SetNumberOfAntennas(8);
813 m_phyAp->SetMaxSupportedTxSpatialStreams(8);
814
815 //----------------------------------------------------------------------------------------------------
816 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2:
817 // STA 1 and STA 2 should receive their PSDUs, whereas STA 3 should not receive any PSDU
818 // but should keep its PHY busy during all PPDU duration.
821 this,
822 std::vector<StaInfo>{{1, m_nss}, {2, m_nss}});
823
824 // Since it takes m_expectedPpduDuration to transmit the PPDU,
825 // all 3 PHYs should be back to IDLE at the same time,
826 // even the PHY that has no PSDU addressed to it.
829 this,
830 m_phySta1,
831 WifiPhyState::RX);
834 this,
835 m_phySta2,
836 WifiPhyState::RX);
839 this,
840 m_phySta3,
841 WifiPhyState::CCA_BUSY);
844 this,
845 m_phySta1,
846 WifiPhyState::IDLE);
849 this,
850 m_phySta2,
851 WifiPhyState::IDLE);
854 this,
855 m_phySta3,
856 WifiPhyState::IDLE);
857
858 // One PSDU of 1008 bytes should have been successfully received by STA 1
861 this,
862 1,
863 0,
864 1008);
865 // One PSDU of 1016 bytes should have been successfully received by STA 2
868 this,
869 1,
870 0,
871 1016);
872 // No PSDU should have been received by STA 3
875 this,
876 0,
877 0,
878 0);
879
881
882 //----------------------------------------------------------------------------------------------------
883 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 3:
884 // STA 1 and STA 3 should receive their PSDUs, whereas STA 2 should not receive any PSDU
885 // but should keep its PHY busy during all PPDU duration.
888 this,
889 std::vector<StaInfo>{{1, m_nss}, {3, m_nss}});
890
891 // Since it takes m_expectedPpduDuration to transmit the PPDU,
892 // all 3 PHYs should be back to IDLE at the same time,
893 // even the PHY that has no PSDU addressed to it.
896 this,
897 m_phySta1,
898 WifiPhyState::RX);
901 this,
902 m_phySta2,
903 WifiPhyState::CCA_BUSY);
906 this,
907 m_phySta3,
908 WifiPhyState::RX);
911 this,
912 m_phySta1,
913 WifiPhyState::IDLE);
916 this,
917 m_phySta2,
918 WifiPhyState::IDLE);
921 this,
922 m_phySta3,
923 WifiPhyState::IDLE);
924
925 // One PSDU of 1008 bytes should have been successfully received by STA 1
928 this,
929 1,
930 0,
931 1008);
932 // No PSDU should have been received by STA 2
935 this,
936 0,
937 0,
938 0);
939 // One PSDU of 1024 bytes should have been successfully received by STA 3
942 this,
943 1,
944 0,
945 1024);
946
948
949 //----------------------------------------------------------------------------------------------------
950 // Send MU PPDU with two PSDUs addressed to STA 2 and STA 3:
951 // STA 2 and STA 3 should receive their PSDUs, whereas STA 1 should not receive any PSDU
952 // but should keep its PHY busy during all PPDU duration.
955 this,
956 std::vector<StaInfo>{{2, m_nss}, {3, m_nss}});
957
958 // Since it takes m_expectedPpduDuration to transmit the PPDU,
959 // all 3 PHYs should be back to IDLE at the same time,
960 // even the PHY that has no PSDU addressed to it.
963 this,
964 m_phySta1,
965 WifiPhyState::CCA_BUSY);
968 this,
969 m_phySta2,
970 WifiPhyState::RX);
973 this,
974 m_phySta3,
975 WifiPhyState::RX);
978 this,
979 m_phySta1,
980 WifiPhyState::IDLE);
983 this,
984 m_phySta2,
985 WifiPhyState::IDLE);
988 this,
989 m_phySta3,
990 WifiPhyState::IDLE);
991
992 // No PSDU should have been received by STA 1
995 this,
996 0,
997 0,
998 0);
999 // One PSDU of 1016 bytes should have been successfully received by STA 2
1002 this,
1003 1,
1004 0,
1005 1016);
1006 // One PSDU of 1024 bytes should have been successfully received by STA 3
1009 this,
1010 1,
1011 0,
1012 1024);
1013
1015
1016 //----------------------------------------------------------------------------------------------------
1017 // Send MU PPDU with three PSDUs addressed to STA 1, STA 2 and STA 3:
1018 // All STAs should receive their PSDUs.
1021 this,
1022 std::vector<StaInfo>{{1, m_nss}, {2, m_nss}, {3, m_nss}});
1023
1024 // Since it takes m_expectedPpduDuration to transmit the PPDU,
1025 // all 3 PHYs should be back to IDLE at the same time.
1028 this,
1029 m_phySta1,
1030 WifiPhyState::RX);
1033 this,
1034 m_phySta2,
1035 WifiPhyState::RX);
1038 this,
1039 m_phySta3,
1040 WifiPhyState::RX);
1043 this,
1044 m_phySta1,
1045 WifiPhyState::IDLE);
1048 this,
1049 m_phySta2,
1050 WifiPhyState::IDLE);
1053 this,
1054 m_phySta3,
1055 WifiPhyState::IDLE);
1056
1057 // One PSDU of 1008 bytes should have been successfully received by STA 1
1060 this,
1061 1,
1062 0,
1063 1008);
1064 // One PSDU of 1016 bytes should have been successfully received by STA 2
1067 this,
1068 1,
1069 0,
1070 1016);
1071 // One PSDU of 1024 bytes should have been successfully received by STA 3
1074 this,
1075 1,
1076 0,
1077 1024);
1078
1080
1082}
1083
1084void
1086{
1087 std::vector<uint8_t> nssToTest{1, 2};
1088 for (auto nss : nssToTest)
1089 {
1090 m_nss = nss;
1091 m_frequency = MHz_u{5180};
1092 m_channelWidth = MHz_u{20};
1093 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(110400) : NanoSeconds(156800);
1094 RunOne();
1095
1096 m_frequency = MHz_u{5190};
1097 m_channelWidth = MHz_u{40};
1098 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(83200) : NanoSeconds(102400);
1099 RunOne();
1100
1101 m_frequency = MHz_u{5210};
1102 m_channelWidth = MHz_u{80};
1103 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(75200);
1104 RunOne();
1105
1106 m_frequency = MHz_u{5250};
1107 m_channelWidth = MHz_u{160};
1108 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(61600);
1109 RunOne();
1110 }
1111 // FIXME: test also different nss over STAs once RX durations when receiving different PPDUs
1112 // with different nss over STAs are fixed
1113
1115}
1116
1117/**
1118 * @ingroup wifi-test
1119 * @ingroup tests
1120 *
1121 * @brief UL MU-MIMO PHY test
1122 */
1124{
1125 public:
1127
1128 private:
1129 void DoSetup() override;
1130 void DoTeardown() override;
1131 void DoRun() override;
1132
1133 /**
1134 * Get TXVECTOR for HE TB PPDU.
1135 * @param txStaId the ID of the TX STA
1136 * @param nss the number of spatial streams used for the transmission
1137 * @param bssColor the BSS color of the TX STA
1138 * @return the TXVECTOR for HE TB PPDU
1139 */
1140 WifiTxVector GetTxVectorForHeTbPpdu(uint16_t txStaId, uint8_t nss, uint8_t bssColor) const;
1141 /**
1142 * Set TRIGVECTOR for HE TB PPDU
1143 *
1144 * @param staIds the IDs of the STAs sollicited for the HE TB transmission
1145 * @param bssColor the BSS color of the TX STA
1146 */
1147 void SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor);
1148 /**
1149 * Send HE TB PPDU function
1150 * @param txStaId the ID of the TX STA
1151 * @param nss the number of spatial streams used for the transmission
1152 * @param payloadSize the size of the payload in bytes
1153 * @param uid the UID of the trigger frame that is initiating this transmission
1154 * @param bssColor the BSS color of the TX STA
1155 */
1156 void SendHeTbPpdu(uint16_t txStaId,
1157 uint8_t nss,
1158 std::size_t payloadSize,
1159 uint64_t uid,
1160 uint8_t bssColor);
1161
1162 /**
1163 * Send HE SU PPDU function
1164 * @param txStaId the ID of the TX STA
1165 * @param payloadSize the size of the payload in bytes
1166 * @param uid the UID of the trigger frame that is initiating this transmission
1167 * @param bssColor the BSS color of the TX STA
1168 */
1169 void SendHeSuPpdu(uint16_t txStaId, std::size_t payloadSize, uint64_t uid, uint8_t bssColor);
1170
1171 /**
1172 * Set the BSS color
1173 * @param phy the PHY
1174 * @param bssColor the BSS color
1175 */
1176 void SetBssColor(Ptr<WifiPhy> phy, uint8_t bssColor);
1177
1178 /**
1179 * Run one function
1180 */
1181 void RunOne();
1182
1183 /**
1184 * Check the received PSDUs from a given STA
1185 * @param staId the ID of the STA to check
1186 * @param expectedSuccess the expected number of success
1187 * @param expectedFailures the expected number of failures
1188 * @param expectedBytes the expected number of bytes
1189 */
1190 void CheckRxFromSta(uint16_t staId,
1191 uint32_t expectedSuccess,
1192 uint32_t expectedFailures,
1193 uint32_t expectedBytes);
1194
1195 /**
1196 * Verify all events are cleared at end of TX or RX
1197 */
1198 void VerifyEventsCleared();
1199
1200 /**
1201 * Check the PHY state
1202 * @param phy the PHY
1203 * @param expectedState the expected state of the PHY
1204 */
1205 void CheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy, WifiPhyState expectedState);
1206 /// @copydoc CheckPhyState
1208
1209 /**
1210 * Reset function
1211 */
1212 void Reset();
1213
1214 /**
1215 * Receive success function
1216 * @param psdu the PSDU
1217 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
1218 * @param txVector the transmit vector
1219 * @param statusPerMpdu reception status per MPDU
1220 */
1222 RxSignalInfo rxSignalInfo,
1223 const WifiTxVector& txVector,
1224 const std::vector<bool>& statusPerMpdu);
1225
1226 /**
1227 * Receive failure function
1228 * @param psdu the PSDU
1229 */
1230 void RxFailure(Ptr<const WifiPsdu> psdu);
1231
1232 /**
1233 * Schedule test to perform.
1234 * The interference generation should be scheduled apart.
1235 *
1236 * @param delay the reference delay to schedule the events
1237 * @param txStaIds the IDs of the STAs planned to transmit an HE TB PPDU
1238 * @param expectedStateAtEnd the expected state of the PHY at the end of the reception
1239 * @param expectedCountersPerSta the expected counters per STA
1240 */
1241 void ScheduleTest(
1242 Time delay,
1243 const std::vector<uint16_t>& txStaIds,
1244 WifiPhyState expectedStateAtEnd,
1245 const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta);
1246
1247 /**
1248 * Log scenario description
1249 *
1250 * @param log the scenario description to add to log
1251 */
1252 void LogScenario(const std::string& log) const;
1253
1255 std::vector<Ptr<MuMimoSpectrumWifiPhy>> m_phyStas; ///< PHYs of STAs
1256
1257 std::vector<uint32_t> m_countRxSuccessFromStas; ///< count RX success from STAs
1258 std::vector<uint32_t> m_countRxFailureFromStas; ///< count RX failure from STAs
1259 std::vector<uint32_t> m_countRxBytesFromStas; ///< count RX bytes from STAs
1260
1261 Time m_delayStart; ///< delay between the start of each HE TB PPDUs
1262 MHz_u m_frequency; ///< frequency
1263 MHz_u m_channelWidth; ///< channel width
1264 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
1265};
1266
1268 : TestCase("UL MU-MIMO PHY test"),
1269 m_countRxSuccessFromStas{},
1270 m_countRxFailureFromStas{},
1271 m_countRxBytesFromStas{},
1272 m_delayStart{Seconds(0)},
1273 m_frequency{DEFAULT_FREQUENCY},
1274 m_channelWidth{DEFAULT_CHANNEL_WIDTH},
1275 m_expectedPpduDuration{NanoSeconds(271200)}
1276{
1277}
1278
1279void
1281 std::size_t payloadSize,
1282 uint64_t uid,
1283 uint8_t bssColor)
1284{
1285 NS_LOG_FUNCTION(this << txStaId << payloadSize << uid << +bssColor);
1286 WifiConstPsduMap psdus;
1287
1289 0,
1291 NanoSeconds(800),
1292 1,
1293 1,
1294 0,
1296 false,
1297 false,
1298 false,
1299 bssColor);
1300
1301 Ptr<Packet> pkt = Create<Packet>(payloadSize);
1302 WifiMacHeader hdr;
1304 hdr.SetQosTid(0);
1305 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
1306 std::ostringstream addr;
1307 addr << "00:00:00:00:00:0" << txStaId;
1308 hdr.SetAddr2(Mac48Address(addr.str().c_str()));
1309 hdr.SetSequenceNumber(1);
1310 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1311 psdus.insert(std::make_pair(SU_STA_ID, psdu));
1312
1313 Ptr<MuMimoSpectrumWifiPhy> phy = (txStaId == 0) ? m_phyAp : m_phyStas.at(txStaId - 1);
1314 phy->SetPpduUid(uid);
1315 phy->Send(psdus, txVector);
1316}
1317
1320 uint8_t nss,
1321 uint8_t bssColor) const
1322{
1324 0,
1326 NanoSeconds(1600),
1327 1,
1328 nss,
1329 0,
1331 false,
1332 false,
1333 false,
1334 bssColor);
1335
1336 HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
1337 txVector.SetRu(ru, txStaId);
1338 txVector.SetMode(HePhy::GetHeMcs7(), txStaId);
1339 txVector.SetNss(nss, txStaId);
1340
1341 return txVector;
1342}
1343
1344void
1345TestUlMuMimoPhyTransmission::SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor)
1346{
1347 WifiTxVector txVector(HePhy::GetHeMcs7(),
1348 0,
1350 NanoSeconds(1600),
1351 1,
1352 1,
1353 0,
1355 false,
1356 false,
1357 false,
1358 bssColor);
1359
1360 HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
1361 for (auto staId : staIds)
1362 {
1363 txVector.SetRu(ru, staId);
1364 txVector.SetMode(HePhy::GetHeMcs7(), staId);
1365 txVector.SetNss(1, staId);
1366 }
1367
1368 uint16_t length;
1369 std::tie(length, m_expectedPpduDuration) =
1371 txVector,
1372 m_phyAp->GetPhyBand());
1373 txVector.SetLength(length);
1375 hePhyAp->SetTrigVector(txVector, m_expectedPpduDuration);
1376}
1377
1378void
1380 uint8_t nss,
1381 std::size_t payloadSize,
1382 uint64_t uid,
1383 uint8_t bssColor)
1384{
1385 NS_LOG_FUNCTION(this << txStaId << +nss << payloadSize << uid << +bssColor);
1386 WifiConstPsduMap psdus;
1387
1388 WifiTxVector txVector = GetTxVectorForHeTbPpdu(txStaId, nss, bssColor);
1389 Ptr<Packet> pkt = Create<Packet>(payloadSize);
1390 WifiMacHeader hdr;
1392 hdr.SetQosTid(0);
1393 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
1394 std::ostringstream addr;
1395 addr << "00:00:00:00:00:0" << txStaId;
1396 hdr.SetAddr2(Mac48Address(addr.str().c_str()));
1397 hdr.SetSequenceNumber(1);
1398 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1399 psdus.insert(std::make_pair(txStaId, psdu));
1400
1401 Ptr<MuMimoSpectrumWifiPhy> phy = m_phyStas.at(txStaId - 1);
1402 Time txDuration = MuMimoSpectrumWifiPhy::CalculateTxDuration(psdu->GetSize(),
1403 txVector,
1404 phy->GetPhyBand(),
1405 txStaId);
1406 txVector.SetLength(
1407 HePhy::ConvertHeTbPpduDurationToLSigLength(txDuration, txVector, phy->GetPhyBand()).first);
1408
1409 phy->SetPpduUid(uid);
1410 phy->Send(psdus, txVector);
1411}
1412
1413void
1415 RxSignalInfo rxSignalInfo,
1416 const WifiTxVector& txVector,
1417 const std::vector<bool>& /*statusPerMpdu*/)
1418{
1419 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2() << RatioToDb(rxSignalInfo.snr) << txVector);
1420 NS_TEST_ASSERT_MSG_EQ((RatioToDb(rxSignalInfo.snr) > dB_u{0.0}), true, "Incorrect SNR value");
1421 for (std::size_t index = 0; index < m_countRxSuccessFromStas.size(); ++index)
1422 {
1423 std::ostringstream addr;
1424 addr << "00:00:00:00:00:0" << index + 1;
1425 if (psdu->GetAddr2() == Mac48Address(addr.str().c_str()))
1426 {
1427 m_countRxSuccessFromStas.at(index)++;
1428 m_countRxBytesFromStas.at(index) += (psdu->GetSize() - 30);
1429 break;
1430 }
1431 }
1432}
1433
1434void
1436{
1437 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2());
1438 for (std::size_t index = 0; index < m_countRxFailureFromStas.size(); ++index)
1439 {
1440 std::ostringstream addr;
1441 addr << "00:00:00:00:00:0" << index + 1;
1442 if (psdu->GetAddr2() == Mac48Address(addr.str().c_str()))
1443 {
1444 m_countRxFailureFromStas.at(index)++;
1445 break;
1446 }
1447 }
1448}
1449
1450void
1452 uint32_t expectedSuccess,
1453 uint32_t expectedFailures,
1454 uint32_t expectedBytes)
1455{
1456 NS_LOG_FUNCTION(this << staId << expectedSuccess << expectedFailures << expectedBytes);
1458 expectedSuccess,
1459 "The number of successfully received packets from STA "
1460 << staId << " is not correct!");
1462 expectedFailures,
1463 "The number of unsuccessfully received packets from STA "
1464 << staId << " is not correct!");
1466 expectedBytes,
1467 "The number of bytes received from STA " << staId << " is not correct!");
1468}
1469
1470void
1472{
1474 nullptr,
1475 "m_currentEvent for AP was not cleared");
1476 std::size_t sta = 1;
1477 for (auto& phy : m_phyStas)
1478 {
1479 NS_TEST_ASSERT_MSG_EQ(phy->GetCurrentEvent(),
1480 nullptr,
1481 "m_currentEvent for STA " << sta << " was not cleared");
1482 sta++;
1483 }
1484}
1485
1486void
1488 WifiPhyState expectedState)
1489{
1490 // This is needed to make sure PHY state will be checked as the last event if a state change
1491 // occurred at the exact same time as the check
1493}
1494
1495void
1497 WifiPhyState expectedState)
1498{
1499 WifiPhyState currentState;
1500 PointerValue ptr;
1501 phy->GetAttribute("State", ptr);
1503 currentState = state->GetState();
1504 NS_LOG_FUNCTION(this << currentState << expectedState);
1505 NS_TEST_ASSERT_MSG_EQ(currentState,
1506 expectedState,
1507 "PHY State " << currentState << " does not match expected state "
1508 << expectedState << " at " << Simulator::Now());
1509}
1510
1511void
1513{
1514 for (auto& counter : m_countRxSuccessFromStas)
1515 {
1516 counter = 0;
1517 }
1518 for (auto& counter : m_countRxFailureFromStas)
1519 {
1520 counter = 0;
1521 }
1522 for (auto& counter : m_countRxBytesFromStas)
1523 {
1524 counter = 0;
1525 }
1526 for (auto& phy : m_phyStas)
1527 {
1528 phy->SetPpduUid(0);
1529 phy->SetTriggerFrameUid(0);
1530 }
1531 SetBssColor(m_phyAp, 0);
1532}
1533
1534void
1536{
1537 Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice>(phy->GetDevice());
1538 Ptr<HeConfiguration> heConfiguration = device->GetHeConfiguration();
1539 heConfiguration->SetAttribute("BssColor", UintegerValue(bssColor));
1540}
1541
1542void
1544{
1545 // WifiHelper::EnableLogComponents();
1546 // LogComponentEnable("WifiPhyMuMimoTest", LOG_LEVEL_ALL);
1547
1551 spectrumChannel->SetPropagationDelayModel(delayModel);
1552
1553 Ptr<Node> apNode = CreateObject<Node>();
1555 apDev->SetStandard(WIFI_STANDARD_80211ax);
1557 "Txop",
1558 PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
1559 apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
1560 apDev->SetMac(apMac);
1563 apDev->SetHeConfiguration(heConfiguration);
1565 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
1567 m_phyAp->SetErrorRateModel(apErrorModel);
1568 m_phyAp->SetDevice(apDev);
1569 m_phyAp->AddChannel(spectrumChannel);
1573 apDev->SetPhy(m_phyAp);
1574 apNode->AddDevice(apDev);
1575
1576 for (std::size_t i = 1; i <= 4; ++i)
1577 {
1578 Ptr<Node> staNode = CreateObject<Node>();
1580 staDev->SetStandard(WIFI_STANDARD_80211ax);
1582 staDev->SetHeConfiguration(CreateObject<HeConfiguration>());
1584 phy->SetInterferenceHelper(staInterferenceHelper);
1586 phy->SetErrorRateModel(staErrorModel);
1587 phy->SetDevice(staDev);
1588 phy->AddChannel(spectrumChannel);
1589 phy->ConfigureStandard(WIFI_STANDARD_80211ax);
1590 phy->SetAttribute("TxGain", DoubleValue(1.0));
1591 phy->SetAttribute("TxPowerStart", DoubleValue(16.0));
1592 phy->SetAttribute("TxPowerEnd", DoubleValue(16.0));
1593 phy->SetAttribute("PowerDensityLimit", DoubleValue(100.0)); // no impact by default
1594 phy->SetAttribute("RxGain", DoubleValue(2.0));
1595 staDev->SetPhy(phy);
1596 staNode->AddDevice(staDev);
1597 m_phyStas.push_back(phy);
1598 m_countRxSuccessFromStas.push_back(0);
1599 m_countRxFailureFromStas.push_back(0);
1600 m_countRxBytesFromStas.push_back(0);
1601 }
1602}
1603
1604void
1606{
1607 for (auto& phy : m_phyStas)
1608 {
1609 phy->Dispose();
1610 phy = nullptr;
1611 }
1612}
1613
1614void
1615TestUlMuMimoPhyTransmission::LogScenario(const std::string& log) const
1616{
1617 NS_LOG_INFO(log);
1618}
1619
1620void
1622 Time delay,
1623 const std::vector<uint16_t>& txStaIds,
1624 WifiPhyState expectedStateAtEnd,
1625 const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta)
1626{
1627 static uint64_t uid = 0;
1628
1629 // AP sends an SU packet preceding HE TB PPDUs
1632 this,
1633 0,
1634 50,
1635 ++uid,
1636 0);
1637
1639
1640 // STAs send MU UL PPDUs addressed to AP
1641 uint16_t payloadSize = 1000;
1642 std::size_t index = 0;
1643 for (auto txStaId : txStaIds)
1644 {
1645 Simulator::Schedule(delay + (index * m_delayStart),
1647 this,
1648 txStaId,
1649 1,
1650 payloadSize,
1651 uid,
1652 0);
1653 payloadSize++;
1654 index++;
1655 }
1656
1657 // Verify it takes m_expectedPpduDuration to transmit the PPDUs
1660 this,
1661 m_phyAp,
1662 WifiPhyState::RX);
1664 (m_delayStart * expectedCountersPerSta.size()),
1666 this,
1667 m_phyAp,
1668 expectedStateAtEnd);
1669
1670 delay += MilliSeconds(100);
1671 // Check reception state from STAs
1672 uint16_t staId = 1;
1673 for (const auto& expectedCounters : expectedCountersPerSta)
1674 {
1675 uint16_t expectedSuccessFromSta = std::get<0>(expectedCounters);
1676 uint16_t expectedFailuresFromSta = std::get<1>(expectedCounters);
1677 uint16_t expectedBytesFromSta = std::get<2>(expectedCounters);
1678 Simulator::Schedule(delay + (m_delayStart * (staId - 1)),
1680 this,
1681 staId,
1682 expectedSuccessFromSta,
1683 expectedFailuresFromSta,
1684 expectedBytesFromSta);
1685 staId++;
1686 }
1687
1688 // Verify events data have been cleared
1690
1691 delay += MilliSeconds(100);
1693}
1694
1695void
1697{
1700 int64_t streamNumber = 0;
1701 m_phyAp->AssignStreams(streamNumber);
1702 for (auto& phy : m_phyStas)
1703 {
1704 phy->AssignStreams(streamNumber);
1705 }
1706
1707 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
1712 ->number;
1713
1716 for (auto& phy : m_phyStas)
1717 {
1718 phy->SetOperatingChannel(
1720 }
1721
1722 Time delay;
1724 delay += Seconds(1);
1725
1726 //---------------------------------------------------------------------------
1727 // Verify that all HE TB PPDUs using full BW MU-MIMO have been corrected received
1728 Simulator::Schedule(delay,
1730 this,
1731 "Reception of HE TB PPDUs using full BW MU-MIMO");
1732 ScheduleTest(delay,
1733 {1, 2, 3},
1734 WifiPhyState::IDLE,
1735 {
1736 std::make_tuple(1, 0, 1000), // One PSDU of 1000 bytes should have been
1737 // successfully received from STA 1
1738 std::make_tuple(1, 0, 1001), // One PSDU of 1001 bytes should have been
1739 // successfully received from STA 2
1740 std::make_tuple(1, 0, 1002) // One PSDU of 1002 bytes should have been
1741 // successfully received from STA 3
1742 });
1743 delay += Seconds(1);
1744
1745 //---------------------------------------------------------------------------
1746 // Send an HE SU PPDU during 400 ns window and verify that all HE TB PPDUs using full BW MU-MIMO
1747 // have been impacted
1748 Simulator::Schedule(delay,
1750 this,
1751 "Reception of HE TB PPDUs HE TB PPDUs using full BW MU-MIMO with an HE SU "
1752 "PPDU arriving during the 400 ns window");
1753 // One HE SU arrives at AP during the 400ns window
1754 Simulator::Schedule(delay + NanoSeconds(150),
1756 this,
1757 4,
1758 1002,
1759 2,
1760 0);
1761 ScheduleTest(delay,
1762 {1, 2, 3},
1763 WifiPhyState::IDLE,
1764 {
1765 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
1766 // failed (since interference from STA 4)
1767 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
1768 // failed (since interference from STA 4)
1769 std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
1770 // (since interference from STA 4)
1771 });
1772 delay += Seconds(1);
1773
1774 //---------------------------------------------------------------------------
1775 // Send an HE SU PPDU during HE portion reception and verify that all HE TB PPDUs have been
1776 // impacted
1777 Simulator::Schedule(delay,
1779 this,
1780 "Reception of HE TB PPDUs using full BW MU-MIMO with an HE SU PPDU "
1781 "arriving during the HE portion");
1782 // One HE SU arrives at AP during the HE portion
1785 this,
1786 4,
1787 1002,
1788 2,
1789 0);
1790 ScheduleTest(delay,
1791 {1, 2, 3},
1792 WifiPhyState::CCA_BUSY,
1793 {
1794 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
1795 // failed (since interference from STA 4)
1796 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
1797 // failed (since interference from STA 4)
1798 std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
1799 // (since interference from STA 4)
1800 });
1801 delay += Seconds(1);
1802
1804}
1805
1806void
1808{
1809 std::vector<Time> startDelays{NanoSeconds(0), NanoSeconds(100)};
1810
1811 for (const auto& delayStart : startDelays)
1812 {
1813 m_delayStart = delayStart;
1814
1815 m_frequency = MHz_u{5180};
1816 m_channelWidth = MHz_u{20};
1818 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1819 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1820 << m_delayStart);
1821 RunOne();
1822
1823 m_frequency = MHz_u{5190};
1824 m_channelWidth = MHz_u{40};
1826 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1827 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1828 << m_delayStart);
1829 RunOne();
1830
1831 m_frequency = MHz_u{5210};
1832 m_channelWidth = MHz_u{80};
1834 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1835 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1836 << m_delayStart);
1837 RunOne();
1838
1839 m_frequency = MHz_u{5250};
1840 m_channelWidth = MHz_u{160};
1842 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1843 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1844 << m_delayStart);
1845 RunOne();
1846 }
1847
1849}
1850
1851/**
1852 * @ingroup wifi-test
1853 * @ingroup tests
1854 *
1855 * @brief wifi PHY MU-MIMO Test Suite
1856 */
1858{
1859 public:
1861};
1862
1864 : TestSuite("wifi-phy-mu-mimo", Type::UNIT)
1865{
1866 AddTestCase(new TestDlMuTxVector, TestCase::Duration::QUICK);
1867 AddTestCase(new TestDlMuMimoPhyTransmission, TestCase::Duration::QUICK);
1868 AddTestCase(new TestUlMuMimoPhyTransmission, TestCase::Duration::QUICK);
1869}
1870
SpectrumWifiPhy used for testing MU-MIMO.
void SetTriggerFrameUid(uint64_t uid)
Since we assume trigger frame was previously received from AP, this is used to set its UID.
MuMimoSpectrumWifiPhy(uint16_t staId)
Constructor.
void DoInitialize() override
Initialize() implementation.
static TypeId GetTypeId()
Get the type ID.
void SetPpduUid(uint64_t uid)
Set the global PPDU UID counter.
void DoDispose() override
Destructor implementation.
Ptr< MuMimoTestHePhy > m_ofdmTestHePhy
Pointer to HE PHY instance used for MU-MIMO test.
HE PHY slightly modified so as to return a given STA-ID in case of DL MU for MuMimoSpectrumWifiPhy.
MuMimoTestHePhy(uint16_t staId)
Constructor.
void SetGlobalPpduUid(uint64_t uid)
Set the global PPDU UID counter.
uint16_t m_staId
ID of the STA to which this PHY belongs to.
uint16_t GetStaId(const Ptr< const WifiPpdu > ppdu) const override
Return the STA ID that has been assigned to the station this PHY belongs to.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
Time m_expectedPpduDuration
expected duration to send MU PPDU
void RxFailureSta2(Ptr< const WifiPsdu > psdu)
Receive failure function for STA 2.
void RxFailureSta1(Ptr< const WifiPsdu > psdu)
Receive failure function for STA 1.
Ptr< SpectrumWifiPhy > m_phyAp
PHY of AP.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void RxSuccessSta1(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function for STA 1.
Ptr< MuMimoSpectrumWifiPhy > m_phySta1
PHY of STA 1.
uint32_t m_countRxFailureSta3
count RX failure for STA 3
uint32_t m_countRxFailureSta1
count RX failure for STA 1
void GenerateInterference(Ptr< SpectrumValue > interferencePsd, Time duration)
Generate interference function.
void CheckPhyState(Ptr< MuMimoSpectrumWifiPhy > phy, WifiPhyState expectedState)
Schedule now to check the PHY state.
uint32_t m_countRxSuccessSta2
count RX success for STA 2
void RxSuccessSta3(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function for STA 3.
void CheckResultsSta3(uint32_t expectedRxSuccess, uint32_t expectedRxFailure, uint32_t expectedRxBytes)
Check the results for STA 3.
void ResetResults()
Reset the results.
uint8_t m_nss
number of spatial streams per STA
Ptr< MuMimoSpectrumWifiPhy > m_phySta3
PHY of STA 3.
void RxFailureSta3(Ptr< const WifiPsdu > psdu)
Receive failure function for STA 3.
uint32_t m_countRxBytesSta2
count RX bytes for STA 2
uint32_t m_countRxSuccessSta3
count RX success for STA 3
void SendMuPpdu(const std::vector< StaInfo > &staInfos)
Send DL MU-MIMO PPDU function.
void DoCheckPhyState(Ptr< MuMimoSpectrumWifiPhy > phy, WifiPhyState expectedState)
Check the PHY state now.
uint32_t m_countRxBytesSta1
count RX bytes for STA 1
uint32_t m_countRxFailureSta2
count RX failure for STA 2
void CheckResultsSta1(uint32_t expectedRxSuccess, uint32_t expectedRxFailure, uint32_t expectedRxBytes)
Check the results for STA 1.
Ptr< MuMimoSpectrumWifiPhy > m_phySta2
PHY of STA 2.
void DoRun() override
Implementation to actually run this TestCase.
void StopInterference()
Stop interference function.
void RxSuccessSta2(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function for STA 2.
uint32_t m_countRxBytesSta3
count RX bytes for STA 3
void CheckResultsSta2(uint32_t expectedRxSuccess, uint32_t expectedRxFailure, uint32_t expectedRxBytes)
Check the results for STA 2.
uint32_t m_countRxSuccessSta1
count RX success for STA 1
DL MU TX-VECTOR test.
static WifiTxVector BuildTxVector(MHz_u bw, const std::list< HeMuUserInfo > &userInfos)
Build a TXVECTOR for DL MU with the given bandwidth and user information.
void DoRun() override
Implementation to actually run this TestCase.
void RxFailure(Ptr< const WifiPsdu > psdu)
Receive failure function.
void VerifyEventsCleared()
Verify all events are cleared at end of TX or RX.
void DoRun() override
Implementation to actually run this TestCase.
void LogScenario(const std::string &log) const
Log scenario description.
std::vector< uint32_t > m_countRxFailureFromStas
count RX failure from STAs
void SendHeSuPpdu(uint16_t txStaId, std::size_t payloadSize, uint64_t uid, uint8_t bssColor)
Send HE SU PPDU function.
void SendHeTbPpdu(uint16_t txStaId, uint8_t nss, std::size_t payloadSize, uint64_t uid, uint8_t bssColor)
Send HE TB PPDU function.
std::vector< uint32_t > m_countRxSuccessFromStas
count RX success from STAs
void DoSetup() override
Implementation to do any local setup required for this TestCase.
std::vector< uint32_t > m_countRxBytesFromStas
count RX bytes from STAs
void CheckRxFromSta(uint16_t staId, uint32_t expectedSuccess, uint32_t expectedFailures, uint32_t expectedBytes)
Check the received PSDUs from a given STA.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
void DoCheckPhyState(Ptr< MuMimoSpectrumWifiPhy > phy, WifiPhyState expectedState)
Check the PHY state.
void SetBssColor(Ptr< WifiPhy > phy, uint8_t bssColor)
Set the BSS color.
void ScheduleTest(Time delay, const std::vector< uint16_t > &txStaIds, WifiPhyState expectedStateAtEnd, const std::vector< std::tuple< uint32_t, uint32_t, uint32_t > > &expectedCountersPerSta)
Schedule test to perform.
void CheckPhyState(Ptr< MuMimoSpectrumWifiPhy > phy, WifiPhyState expectedState)
Check the PHY state.
void RxSuccess(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function.
Time m_expectedPpduDuration
expected duration to send MU PPDU
Ptr< MuMimoSpectrumWifiPhy > m_phyAp
PHY of AP.
void SetTrigVector(const std::vector< uint16_t > &staIds, uint8_t bssColor)
Set TRIGVECTOR for HE TB PPDU.
std::vector< Ptr< MuMimoSpectrumWifiPhy > > m_phyStas
PHYs of STAs.
Time m_delayStart
delay between the start of each HE TB PPDUs
WifiTxVector GetTxVectorForHeTbPpdu(uint16_t txStaId, uint8_t nss, uint8_t bssColor) const
Get TXVECTOR for HE TB PPDU.
wifi PHY MU-MIMO Test Suite
AttributeValue implementation for Boolean.
Definition boolean.h:26
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
PHY entity for HE (11ax)
Definition he-phy.h:58
static WifiMode GetHeMcs7()
Return MCS 7 from HE MCS values.
uint16_t GetStaId(const Ptr< const WifiPpdu > ppdu) const override
Return the STA ID that has been assigned to the station this PHY belongs to.
Definition he-phy.cc:565
static std::pair< uint16_t, Time > ConvertHeTbPpduDurationToLSigLength(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Compute the L-SIG length value corresponding to the given HE TB PPDU duration.
Definition he-phy.cc:261
RU Specification.
Definition he-ru.h:57
static RuType GetRuType(MHz_u bandwidth)
Get the RU corresponding to the approximate bandwidth.
Definition he-ru.cc:781
@ RU_106_TONE
Definition he-ru.h:35
@ RU_242_TONE
Definition he-ru.h:36
an EUI-48 address
void Dispose()
Dispose of this Object.
Definition object.cc:247
void SetOwner(Ptr< WifiPhy > wifiPhy)
Set the WifiPhy owning this PHY entity.
Definition phy-entity.cc:82
static uint64_t m_globalPpduUid
Global counter of the PPDU UID.
Definition phy-entity.h:974
AttributeValue implementation for Pointer.
Ptr< T > Get() const
Definition pointer.h:223
Smart pointer class similar to boost::intrusive_ptr.
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:561
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:595
802.11 PHY layer model
void SetDevice(const Ptr< WifiNetDevice > device) override
Sets the device this PHY is associated with.
void DoInitialize() override
Initialize() implementation.
void AddChannel(const Ptr< SpectrumChannel > channel, const FrequencyRange &freqRange=WHOLE_WIFI_SPECTRUM)
Attach a SpectrumChannel to use for a given frequency range.
void DoDispose() override
Destructor implementation.
Hold variables of type string.
Definition string.h:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
static WifiMode GetVhtMcs5()
Return MCS 5 from VHT MCS values.
Implements the IEEE 802.11 MAC header.
void SetSequenceNumber(uint16_t seq)
Set the sequence number of the header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
void SetQosTid(uint8_t tid)
Set the TID for the QoS header.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
virtual void SetInterferenceHelper(const Ptr< InterferenceHelper > helper)
Sets the interference helper.
Definition wifi-phy.cc:678
void SetErrorRateModel(const Ptr< ErrorRateModel > model)
Sets the error rate model.
Definition wifi-phy.cc:687
std::tuple< uint8_t, MHz_u, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying a segment of an operating channel.
Definition wifi-phy.h:940
void SetReceiveErrorCallback(RxErrorCallback callback)
Definition wifi-phy.cc:484
virtual void ConfigureStandard(WifiStandard standard)
Configure the PHY-level parameters for different Wi-Fi standard.
Definition wifi-phy.cc:1009
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1587
std::map< WifiModulationClass, Ptr< PhyEntity > > m_phyEntities
This map holds the supported PHY entities.
Definition wifi-phy.h:1384
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition wifi-phy.cc:1069
Ptr< Event > m_currentEvent
Hold the current event.
Definition wifi-phy.h:1359
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
Definition wifi-phy.cc:760
uint64_t m_previouslyRxPpduUid
UID of the previously received PPDU, reset to UINT64_MAX upon transmission.
Definition wifi-phy.h:1364
void SetOperatingChannel(const WifiPhyOperatingChannel &channel)
If the standard for this object has not been set yet, store the channel settings corresponding to the...
Definition wifi-phy.cc:1135
void SetReceiveOkCallback(RxOkCallback callback)
Definition wifi-phy.cc:478
virtual int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
Definition wifi-phy.cc:2363
static ConstIterator FindFirst(uint8_t number, MHz_u frequency, MHz_u width, WifiStandard standard, WifiPhyBand band, ConstIterator start=m_frequencyChannels.begin())
Find the first frequency segment matching the specified parameters.
This objects implements the PHY state machine of the Wifi device.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
bool IsSigBCompression() const
Indicate whether the Common field is present in the HE-SIG-B field.
bool IsValid(WifiPhyBand band=WIFI_PHY_BAND_UNSPECIFIED) const
The standard disallows certain combinations of WifiMode, number of spatial streams,...
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
void SetRu(HeRu::RuSpec ru, uint16_t staId)
Set the RU specification for the STA-ID.
bool IsDlOfdma() const
Return true if this TX vector is used for a downlink multi-user transmission using OFDMA.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
bool IsDlMuMimo() const
Return true if this TX vector is used for a downlink multi-user transmission using MU-MIMO.
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:55
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > CreateObjectWithAttributes(Args... args)
Allocate an Object on the heap and initialize with a set of attributes.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#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:241
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
@ WIFI_STANDARD_80211ax
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PREAMBLE_HE_SU
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
@ WIFI_PPDU_TYPE_DL_MU
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
Every class exported by the ns3 library is enclosed in the ns3 namespace.
WifiPhyState
The state of the PHY layer.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
dB_u RatioToDb(double ratio)
Convert from ratio to dB.
Definition wifi-utils.cc:46
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
@ WIFI_MAC_QOSDATA
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition wifi-mode.h:24
uint8_t staNss
Number of spatial streams used for the STA.
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:72
double snr
SNR in linear scale.
Definition wifi-types.h:73
constexpr MHz_u DEFAULT_CHANNEL_WIDTH
constexpr MHz_u DEFAULT_FREQUENCY
static WifiPhyMuMimoTestSuite WifiPhyMuMimoTestSuite
the test suite