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::RuSpec{RuType::RU_106_TONE, 1, true}, 11, 1});
96 userInfos.push_back({HeRu::RuSpec{RuType::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 auto ru = HeRu::RuSpec{RuType::RU_242_TONE, 1, true};
114 userInfos.push_back({ru, 11, 1});
115 userInfos.push_back({ru, 10, 2});
116 txVector = BuildTxVector(MHz_u{20}, userInfos);
118 false,
119 "TX-VECTOR should indicate a MU-MIMO transmission");
121 true,
122 "TX-VECTOR should not indicate an OFDMA transmission");
124 true,
125 "TX-VECTOR should indicate a SIG-B compression");
127 true,
128 "TX-VECTOR should indicate all checks are passed");
129 userInfos.clear();
130
131 // Verify TxVector is not valid if there are more than 8 STAs using the same RU
132 ru = HeRu::RuSpec{RuType::RU_242_TONE, 1, true};
133 userInfos.push_back({ru, 11, 1});
134 userInfos.push_back({ru, 10, 1});
135 userInfos.push_back({ru, 9, 1});
136 userInfos.push_back({ru, 8, 1});
137 userInfos.push_back({ru, 7, 1});
138 userInfos.push_back({ru, 6, 1});
139 userInfos.push_back({ru, 5, 1});
140 userInfos.push_back({ru, 4, 1});
141 userInfos.push_back({ru, 3, 1});
142 txVector = BuildTxVector(MHz_u{20}, userInfos);
144 false,
145 "TX-VECTOR should indicate a MU-MIMO transmission");
147 true,
148 "TX-VECTOR should not indicate an OFDMA transmission");
150 true,
151 "TX-VECTOR should indicate a SIG-B compression");
153 false,
154 "TX-VECTOR should not indicate all checks are passed");
155
156 // Verify TxVector is not valid if the total number of antennas in a full BW MU-MIMO is above 8
157 userInfos.push_back({ru, 11, 2});
158 userInfos.push_back({ru, 10, 2});
159 userInfos.push_back({ru, 9, 3});
160 userInfos.push_back({ru, 8, 3});
161 txVector = BuildTxVector(MHz_u{20}, userInfos);
163 false,
164 "TX-VECTOR should indicate a MU-MIMO transmission");
166 true,
167 "TX-VECTOR should not indicate an OFDMA transmission");
169 true,
170 "TX-VECTOR should indicate a SIG-B compression");
172 false,
173 "TX-VECTOR should not indicate all checks are passed");
174}
175
176/**
177 * HE PHY slightly modified so as to return a given
178 * STA-ID in case of DL MU for MuMimoSpectrumWifiPhy.
179 */
180class MuMimoTestHePhy : public HePhy
181{
182 public:
183 /**
184 * Constructor
185 *
186 * @param staId the ID of the STA to which this PHY belongs to
187 */
188 MuMimoTestHePhy(uint16_t staId);
189
190 /**
191 * Return the STA ID that has been assigned to the station this PHY belongs to.
192 * This is typically called for MU PPDUs, in order to pick the correct PSDU.
193 *
194 * @param ppdu the PPDU for which the STA ID is requested
195 * @return the STA ID
196 */
197 uint16_t GetStaId(const Ptr<const WifiPpdu> ppdu) const override;
198
199 /**
200 * Set the global PPDU UID counter.
201 *
202 * @param uid the value to which the global PPDU UID counter should be set
203 */
204 void SetGlobalPpduUid(uint64_t uid);
205
206 private:
207 uint16_t m_staId; ///< ID of the STA to which this PHY belongs to
208
209 // end of class MuMimoTestHePhy
210};
211
213 : HePhy(),
214 m_staId(staId)
215{
216}
217
218uint16_t
220{
221 if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
222 {
223 return m_staId;
224 }
225 return HePhy::GetStaId(ppdu);
226}
227
228void
230{
231 m_globalPpduUid = uid;
232}
233
234/**
235 * SpectrumWifiPhy used for testing MU-MIMO.
236 */
238{
239 public:
240 /**
241 * @brief Get the type ID.
242 * @return the object TypeId
243 */
244 static TypeId GetTypeId();
245 /**
246 * Constructor
247 *
248 * @param staId the ID of the STA to which this PHY belongs to
249 */
250 MuMimoSpectrumWifiPhy(uint16_t staId);
251 ~MuMimoSpectrumWifiPhy() override;
252
253 /**
254 * Set the global PPDU UID counter.
255 *
256 * @param uid the value to which the global PPDU UID counter should be set
257 */
258 void SetPpduUid(uint64_t uid);
259
260 /**
261 * Since we assume trigger frame was previously received from AP, this is used to set its UID
262 *
263 * @param uid the PPDU UID of the trigger frame
264 */
265 void SetTriggerFrameUid(uint64_t uid);
266
267 /**
268 * @return the current event
269 */
271
272 private:
273 void DoInitialize() override;
274 void DoDispose() override;
275
276 std::shared_ptr<MuMimoTestHePhy>
277 m_ofdmTestHePhy; ///< Pointer to HE PHY instance used for MU-MIMO test
278
279 // end of class MuMimoSpectrumWifiPhy
280};
281
282TypeId
284{
285 static TypeId tid =
286 TypeId("ns3::MuMimoSpectrumWifiPhy").SetParent<SpectrumWifiPhy>().SetGroupName("Wifi");
287 return tid;
288}
289
292{
293 m_ofdmTestHePhy = std::make_shared<MuMimoTestHePhy>(staId);
294 m_ofdmTestHePhy->SetOwner(this);
295}
296
300
301void
303{
304 // Replace HE PHY instance with test instance
307}
308
309void
315
316void
318{
319 m_ofdmTestHePhy->SetGlobalPpduUid(uid);
321}
322
323void
328
334
335/**
336 * @ingroup wifi-test
337 * @ingroup tests
338 *
339 * @brief DL MU-MIMO PHY test
340 */
342{
343 public:
345
346 private:
347 void DoSetup() override;
348 void DoTeardown() override;
349 void DoRun() override;
350
351 /**
352 * Receive success function for STA 1
353 * @param psdu the PSDU
354 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
355 * @param txVector the transmit vector
356 * @param statusPerMpdu reception status per MPDU
357 */
359 RxSignalInfo rxSignalInfo,
360 const WifiTxVector& txVector,
361 const std::vector<bool>& statusPerMpdu);
362 /**
363 * Receive success function for STA 2
364 * @param psdu the PSDU
365 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
366 * @param txVector the transmit vector
367 * @param statusPerMpdu reception status per MPDU
368 */
370 RxSignalInfo rxSignalInfo,
371 const WifiTxVector& txVector,
372 const std::vector<bool>& statusPerMpdu);
373 /**
374 * Receive success function for STA 3
375 * @param psdu the PSDU
376 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
377 * @param txVector the transmit vector
378 * @param statusPerMpdu reception status per MPDU
379 */
381 RxSignalInfo rxSignalInfo,
382 const WifiTxVector& txVector,
383 const std::vector<bool>& statusPerMpdu);
384
385 /**
386 * Receive failure function for STA 1
387 * @param psdu the PSDU
388 */
390 /**
391 * Receive failure function for STA 2
392 * @param psdu the PSDU
393 */
395 /**
396 * Receive failure function for STA 3
397 * @param psdu the PSDU
398 */
400
401 /**
402 * Check the results for STA 1
403 * @param expectedRxSuccess the expected number of RX success
404 * @param expectedRxFailure the expected number of RX failures
405 * @param expectedRxBytes the expected number of RX bytes
406 */
407 void CheckResultsSta1(uint32_t expectedRxSuccess,
408 uint32_t expectedRxFailure,
409 uint32_t expectedRxBytes);
410 /**
411 * Check the results for STA 2
412 * @param expectedRxSuccess the expected number of RX success
413 * @param expectedRxFailure the expected number of RX failures
414 * @param expectedRxBytes the expected number of RX bytes
415 */
416 void CheckResultsSta2(uint32_t expectedRxSuccess,
417 uint32_t expectedRxFailure,
418 uint32_t expectedRxBytes);
419 /**
420 * Check the results for STA 3
421 * @param expectedRxSuccess the expected number of RX success
422 * @param expectedRxFailure the expected number of RX failures
423 * @param expectedRxBytes the expected number of RX bytes
424 */
425 void CheckResultsSta3(uint32_t expectedRxSuccess,
426 uint32_t expectedRxFailure,
427 uint32_t expectedRxBytes);
428
429 /**
430 * Reset the results
431 */
432 void ResetResults();
433
434 /**
435 * STA info
436 */
437 struct StaInfo
438 {
439 uint16_t staId; //!< STA ID
440 uint8_t staNss; //!< Number of spatial streams used for the STA
441 };
442
443 /**
444 * Send DL MU-MIMO PPDU function
445 * @param staInfos the STAs infos
446 */
447 void SendMuPpdu(const std::vector<StaInfo>& staInfos);
448
449 /**
450 * Generate interference function
451 * @param interferencePsd the PSD of the interference to be generated
452 * @param duration the duration of the interference
453 */
454 void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
455 /**
456 * Stop interference function
457 */
459
460 /**
461 * Run one function
462 */
463 void RunOne();
464
465 /**
466 * Schedule now to check the PHY state
467 * @param phy the PHY
468 * @param expectedState the expected state of the PHY
469 */
471 /**
472 * Check the PHY state now
473 * @param phy the PHY
474 * @param expectedState the expected state of the PHY
475 */
477
478 uint32_t m_countRxSuccessSta1; ///< count RX success for STA 1
479 uint32_t m_countRxSuccessSta2; ///< count RX success for STA 2
480 uint32_t m_countRxSuccessSta3; ///< count RX success for STA 3
481 uint32_t m_countRxFailureSta1; ///< count RX failure for STA 1
482 uint32_t m_countRxFailureSta2; ///< count RX failure for STA 2
483 uint32_t m_countRxFailureSta3; ///< count RX failure for STA 3
484 uint32_t m_countRxBytesSta1; ///< count RX bytes for STA 1
485 uint32_t m_countRxBytesSta2; ///< count RX bytes for STA 2
486 uint32_t m_countRxBytesSta3; ///< count RX bytes for STA 3
487
492
493 uint8_t m_nss; ///< number of spatial streams per STA
494 MHz_u m_frequency; ///< frequency
495 MHz_u m_channelWidth; ///< channel width
496 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
497};
498
516
517void
530
531void
532TestDlMuMimoPhyTransmission::SendMuPpdu(const std::vector<StaInfo>& staInfos)
533{
534 NS_LOG_FUNCTION(this << staInfos.size());
535 NS_ASSERT(staInfos.size() > 1);
536
538 0,
540 NanoSeconds(800),
541 1,
542 1,
543 0,
545 false,
546 false);
547
548 WifiConstPsduMap psdus;
549 HeRu::RuSpec ru(WifiRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
550 for (const auto& staInfo : staInfos)
551 {
552 txVector.SetRu(ru, staInfo.staId);
553 txVector.SetMode(HePhy::GetHeMcs7(), staInfo.staId);
554 txVector.SetNss(staInfo.staNss, staInfo.staId);
555
556 Ptr<Packet> pkt = Create<Packet>(1000 + (8 * staInfo.staId));
557 WifiMacHeader hdr;
559 hdr.SetQosTid(0);
560 std::ostringstream addr;
561 addr << "00:00:00:00:00:0" << staInfo.staId;
562 hdr.SetAddr1(Mac48Address(addr.str().c_str()));
563 hdr.SetSequenceNumber(1 + staInfo.staId);
564 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
565 psdus.insert(std::make_pair(staInfo.staId, psdu));
566 }
567
569
570 NS_ASSERT(txVector.IsDlMuMimo());
571 NS_ASSERT(!txVector.IsDlOfdma());
572
573 m_phyAp->Send(psdus, txVector);
574}
575
576void
578 RxSignalInfo rxSignalInfo,
579 const WifiTxVector& txVector,
580 const std::vector<bool>& /*statusPerMpdu*/)
581{
582 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
584 m_countRxBytesSta1 += (psdu->GetSize() - 30);
585}
586
587void
589 RxSignalInfo rxSignalInfo,
590 const WifiTxVector& txVector,
591 const std::vector<bool>& /*statusPerMpdu*/)
592{
593 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
595 m_countRxBytesSta2 += (psdu->GetSize() - 30);
596}
597
598void
600 RxSignalInfo rxSignalInfo,
601 const WifiTxVector& txVector,
602 const std::vector<bool>& /*statusPerMpdu*/)
603{
604 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
606 m_countRxBytesSta3 += (psdu->GetSize() - 30);
607}
608
609void
615
616void
622
623void
629
630void
632 uint32_t expectedRxFailure,
633 uint32_t expectedRxBytes)
634{
636 expectedRxSuccess,
637 "The number of successfully received packets by STA 1 is not correct!");
639 expectedRxFailure,
640 "The number of unsuccessfully received packets by STA 1 is not correct!");
642 expectedRxBytes,
643 "The number of bytes received by STA 1 is not correct!");
644}
645
646void
648 uint32_t expectedRxFailure,
649 uint32_t expectedRxBytes)
650{
652 expectedRxSuccess,
653 "The number of successfully received packets by STA 2 is not correct!");
655 expectedRxFailure,
656 "The number of unsuccessfully received packets by STA 2 is not correct!");
658 expectedRxBytes,
659 "The number of bytes received by STA 2 is not correct!");
660}
661
662void
664 uint32_t expectedRxFailure,
665 uint32_t expectedRxBytes)
666{
668 expectedRxSuccess,
669 "The number of successfully received packets by STA 3 is not correct!");
671 expectedRxFailure,
672 "The number of unsuccessfully received packets by STA 3 is not correct!");
674 expectedRxBytes,
675 "The number of bytes received by STA 3 is not correct!");
676}
677
678void
680 WifiPhyState expectedState)
681{
682 // This is needed to make sure PHY state will be checked as the last event if a state change
683 // occurred at the exact same time as the check
685}
686
687void
689 WifiPhyState expectedState)
690{
691 WifiPhyState currentState;
692 PointerValue ptr;
693 phy->GetAttribute("State", ptr);
695 currentState = state->GetState();
696 NS_LOG_FUNCTION(this << currentState << expectedState);
697 NS_TEST_ASSERT_MSG_EQ(currentState,
698 expectedState,
699 "PHY State " << currentState << " does not match expected state "
700 << expectedState << " at " << Simulator::Now());
701}
702
703void
705{
709 spectrumChannel->SetPropagationDelayModel(delayModel);
710
711 Ptr<Node> apNode = CreateObject<Node>();
715 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
717 m_phyAp->SetErrorRateModel(apErrorModel);
718 m_phyAp->SetDevice(apDev);
719 m_phyAp->AddChannel(spectrumChannel);
720 m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
721 apDev->SetPhy(m_phyAp);
722 apNode->AddDevice(apDev);
723
724 Ptr<Node> sta1Node = CreateObject<Node>();
728 m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
730 m_phySta1->SetErrorRateModel(sta1ErrorModel);
731 m_phySta1->SetDevice(sta1Dev);
732 m_phySta1->AddChannel(spectrumChannel);
733 m_phySta1->ConfigureStandard(WIFI_STANDARD_80211ax);
734 m_phySta1->SetReceiveOkCallback(
736 m_phySta1->SetReceiveErrorCallback(
738 sta1Dev->SetPhy(m_phySta1);
739 sta1Node->AddDevice(sta1Dev);
740
741 Ptr<Node> sta2Node = CreateObject<Node>();
745 m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
747 m_phySta2->SetErrorRateModel(sta2ErrorModel);
748 m_phySta2->SetDevice(sta2Dev);
749 m_phySta2->AddChannel(spectrumChannel);
750 m_phySta2->ConfigureStandard(WIFI_STANDARD_80211ax);
751 m_phySta2->SetReceiveOkCallback(
753 m_phySta2->SetReceiveErrorCallback(
755 sta2Dev->SetPhy(m_phySta2);
756 sta2Node->AddDevice(sta2Dev);
757
758 Ptr<Node> sta3Node = CreateObject<Node>();
762 m_phySta3->SetInterferenceHelper(sta3InterferenceHelper);
764 m_phySta3->SetErrorRateModel(sta3ErrorModel);
765 m_phySta3->SetDevice(sta3Dev);
766 m_phySta3->AddChannel(spectrumChannel);
767 m_phySta3->ConfigureStandard(WIFI_STANDARD_80211ax);
768 m_phySta3->SetReceiveOkCallback(
770 m_phySta3->SetReceiveErrorCallback(
772 sta3Dev->SetPhy(m_phySta3);
773 sta3Node->AddDevice(sta3Dev);
774}
775
776void
778{
779 m_phyAp->Dispose();
780 m_phyAp = nullptr;
781 m_phySta1->Dispose();
782 m_phySta1 = nullptr;
783 m_phySta2->Dispose();
784 m_phySta2 = nullptr;
785 m_phySta3->Dispose();
786 m_phySta3 = nullptr;
787}
788
789void
791{
794 int64_t streamNumber = 0;
795 m_phyAp->AssignStreams(streamNumber);
796 m_phySta1->AssignStreams(streamNumber);
797 m_phySta2->AssignStreams(streamNumber);
798
799 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
804 ->number;
805
806 m_phyAp->SetOperatingChannel(
808 m_phySta1->SetOperatingChannel(
810 m_phySta2->SetOperatingChannel(
812 m_phySta3->SetOperatingChannel(
814
815 m_phyAp->SetNumberOfAntennas(8);
816 m_phyAp->SetMaxSupportedTxSpatialStreams(8);
817
818 //----------------------------------------------------------------------------------------------------
819 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2:
820 // STA 1 and STA 2 should receive their PSDUs, whereas STA 3 should not receive any PSDU
821 // but should keep its PHY busy during all PPDU duration.
824 this,
825 std::vector<StaInfo>{{1, m_nss}, {2, m_nss}});
826
827 // Since it takes m_expectedPpduDuration to transmit the PPDU,
828 // all 3 PHYs should be back to IDLE at the same time,
829 // even the PHY that has no PSDU addressed to it.
832 this,
833 m_phySta1,
837 this,
838 m_phySta2,
842 this,
843 m_phySta3,
847 this,
848 m_phySta1,
852 this,
853 m_phySta2,
857 this,
858 m_phySta3,
860
861 // One PSDU of 1008 bytes should have been successfully received by STA 1
864 this,
865 1,
866 0,
867 1008);
868 // One PSDU of 1016 bytes should have been successfully received by STA 2
871 this,
872 1,
873 0,
874 1016);
875 // No PSDU should have been received by STA 3
878 this,
879 0,
880 0,
881 0);
882
884
885 //----------------------------------------------------------------------------------------------------
886 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 3:
887 // STA 1 and STA 3 should receive their PSDUs, whereas STA 2 should not receive any PSDU
888 // but should keep its PHY busy during all PPDU duration.
891 this,
892 std::vector<StaInfo>{{1, m_nss}, {3, m_nss}});
893
894 // Since it takes m_expectedPpduDuration to transmit the PPDU,
895 // all 3 PHYs should be back to IDLE at the same time,
896 // even the PHY that has no PSDU addressed to it.
899 this,
900 m_phySta1,
904 this,
905 m_phySta2,
909 this,
910 m_phySta3,
914 this,
915 m_phySta1,
919 this,
920 m_phySta2,
924 this,
925 m_phySta3,
927
928 // One PSDU of 1008 bytes should have been successfully received by STA 1
931 this,
932 1,
933 0,
934 1008);
935 // No PSDU should have been received by STA 2
938 this,
939 0,
940 0,
941 0);
942 // One PSDU of 1024 bytes should have been successfully received by STA 3
945 this,
946 1,
947 0,
948 1024);
949
951
952 //----------------------------------------------------------------------------------------------------
953 // Send MU PPDU with two PSDUs addressed to STA 2 and STA 3:
954 // STA 2 and STA 3 should receive their PSDUs, whereas STA 1 should not receive any PSDU
955 // but should keep its PHY busy during all PPDU duration.
958 this,
959 std::vector<StaInfo>{{2, m_nss}, {3, m_nss}});
960
961 // Since it takes m_expectedPpduDuration to transmit the PPDU,
962 // all 3 PHYs should be back to IDLE at the same time,
963 // even the PHY that has no PSDU addressed to it.
966 this,
967 m_phySta1,
971 this,
972 m_phySta2,
976 this,
977 m_phySta3,
981 this,
982 m_phySta1,
986 this,
987 m_phySta2,
991 this,
992 m_phySta3,
994
995 // No PSDU should have been received by STA 1
998 this,
999 0,
1000 0,
1001 0);
1002 // One PSDU of 1016 bytes should have been successfully received by STA 2
1005 this,
1006 1,
1007 0,
1008 1016);
1009 // One PSDU of 1024 bytes should have been successfully received by STA 3
1012 this,
1013 1,
1014 0,
1015 1024);
1016
1018
1019 //----------------------------------------------------------------------------------------------------
1020 // Send MU PPDU with three PSDUs addressed to STA 1, STA 2 and STA 3:
1021 // All STAs should receive their PSDUs.
1024 this,
1025 std::vector<StaInfo>{{1, m_nss}, {2, m_nss}, {3, m_nss}});
1026
1027 // Since it takes m_expectedPpduDuration to transmit the PPDU,
1028 // all 3 PHYs should be back to IDLE at the same time.
1031 this,
1032 m_phySta1,
1036 this,
1037 m_phySta2,
1041 this,
1042 m_phySta3,
1046 this,
1047 m_phySta1,
1051 this,
1052 m_phySta2,
1056 this,
1057 m_phySta3,
1059
1060 // One PSDU of 1008 bytes should have been successfully received by STA 1
1063 this,
1064 1,
1065 0,
1066 1008);
1067 // One PSDU of 1016 bytes should have been successfully received by STA 2
1070 this,
1071 1,
1072 0,
1073 1016);
1074 // One PSDU of 1024 bytes should have been successfully received by STA 3
1077 this,
1078 1,
1079 0,
1080 1024);
1081
1083
1085}
1086
1087void
1089{
1090 std::vector<uint8_t> nssToTest{1, 2};
1091 for (auto nss : nssToTest)
1092 {
1093 m_nss = nss;
1094 m_frequency = MHz_u{5180};
1095 m_channelWidth = MHz_u{20};
1096 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(110400) : NanoSeconds(156800);
1097 RunOne();
1098
1099 m_frequency = MHz_u{5190};
1100 m_channelWidth = MHz_u{40};
1101 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(83200) : NanoSeconds(102400);
1102 RunOne();
1103
1104 m_frequency = MHz_u{5210};
1105 m_channelWidth = MHz_u{80};
1106 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(75200);
1107 RunOne();
1108
1109 m_frequency = MHz_u{5250};
1110 m_channelWidth = MHz_u{160};
1111 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(61600);
1112 RunOne();
1113 }
1114 // FIXME: test also different nss over STAs once RX durations when receiving different PPDUs
1115 // with different nss over STAs are fixed
1116
1118}
1119
1120/**
1121 * @ingroup wifi-test
1122 * @ingroup tests
1123 *
1124 * @brief UL MU-MIMO PHY test
1125 */
1127{
1128 public:
1130
1131 private:
1132 void DoSetup() override;
1133 void DoTeardown() override;
1134 void DoRun() override;
1135
1136 /**
1137 * Get TXVECTOR for HE TB PPDU.
1138 * @param txStaId the ID of the TX STA
1139 * @param nss the number of spatial streams used for the transmission
1140 * @param bssColor the BSS color of the TX STA
1141 * @return the TXVECTOR for HE TB PPDU
1142 */
1143 WifiTxVector GetTxVectorForHeTbPpdu(uint16_t txStaId, uint8_t nss, uint8_t bssColor) const;
1144 /**
1145 * Set TRIGVECTOR for HE TB PPDU
1146 *
1147 * @param staIds the IDs of the STAs sollicited for the HE TB transmission
1148 * @param bssColor the BSS color of the TX STA
1149 */
1150 void SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor);
1151 /**
1152 * Send HE TB PPDU function
1153 * @param txStaId the ID of the TX STA
1154 * @param nss the number of spatial streams used for the transmission
1155 * @param payloadSize the size of the payload in bytes
1156 * @param uid the UID of the trigger frame that is initiating this transmission
1157 * @param bssColor the BSS color of the TX STA
1158 */
1159 void SendHeTbPpdu(uint16_t txStaId,
1160 uint8_t nss,
1161 std::size_t payloadSize,
1162 uint64_t uid,
1163 uint8_t bssColor);
1164
1165 /**
1166 * Send HE SU PPDU function
1167 * @param txStaId the ID of the TX STA
1168 * @param payloadSize the size of the payload in bytes
1169 * @param uid the UID of the trigger frame that is initiating this transmission
1170 * @param bssColor the BSS color of the TX STA
1171 */
1172 void SendHeSuPpdu(uint16_t txStaId, std::size_t payloadSize, uint64_t uid, uint8_t bssColor);
1173
1174 /**
1175 * Set the BSS color
1176 * @param phy the PHY
1177 * @param bssColor the BSS color
1178 */
1179 void SetBssColor(Ptr<WifiPhy> phy, uint8_t bssColor);
1180
1181 /**
1182 * Run one function
1183 */
1184 void RunOne();
1185
1186 /**
1187 * Check the received PSDUs from a given STA
1188 * @param staId the ID of the STA to check
1189 * @param expectedSuccess the expected number of success
1190 * @param expectedFailures the expected number of failures
1191 * @param expectedBytes the expected number of bytes
1192 */
1193 void CheckRxFromSta(uint16_t staId,
1194 uint32_t expectedSuccess,
1195 uint32_t expectedFailures,
1196 uint32_t expectedBytes);
1197
1198 /**
1199 * Verify all events are cleared at end of TX or RX
1200 */
1201 void VerifyEventsCleared();
1202
1203 /**
1204 * Check the PHY state
1205 * @param phy the PHY
1206 * @param expectedState the expected state of the PHY
1207 */
1208 void CheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy, WifiPhyState expectedState);
1209 /// @copydoc CheckPhyState
1211
1212 /**
1213 * Reset function
1214 */
1215 void Reset();
1216
1217 /**
1218 * Receive success function
1219 * @param psdu the PSDU
1220 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
1221 * @param txVector the transmit vector
1222 * @param statusPerMpdu reception status per MPDU
1223 */
1225 RxSignalInfo rxSignalInfo,
1226 const WifiTxVector& txVector,
1227 const std::vector<bool>& statusPerMpdu);
1228
1229 /**
1230 * Receive failure function
1231 * @param psdu the PSDU
1232 */
1233 void RxFailure(Ptr<const WifiPsdu> psdu);
1234
1235 /**
1236 * Schedule test to perform.
1237 * The interference generation should be scheduled apart.
1238 *
1239 * @param delay the reference delay to schedule the events
1240 * @param txStaIds the IDs of the STAs planned to transmit an HE TB PPDU
1241 * @param expectedStateAtEnd the expected state of the PHY at the end of the reception
1242 * @param expectedCountersPerSta the expected counters per STA
1243 */
1244 void ScheduleTest(
1245 Time delay,
1246 const std::vector<uint16_t>& txStaIds,
1247 WifiPhyState expectedStateAtEnd,
1248 const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta);
1249
1250 /**
1251 * Log scenario description
1252 *
1253 * @param log the scenario description to add to log
1254 */
1255 void LogScenario(const std::string& log) const;
1256
1258 std::vector<Ptr<MuMimoSpectrumWifiPhy>> m_phyStas; ///< PHYs of STAs
1259
1260 std::vector<uint32_t> m_countRxSuccessFromStas; ///< count RX success from STAs
1261 std::vector<uint32_t> m_countRxFailureFromStas; ///< count RX failure from STAs
1262 std::vector<uint32_t> m_countRxBytesFromStas; ///< count RX bytes from STAs
1263
1264 Time m_delayStart; ///< delay between the start of each HE TB PPDUs
1265 MHz_u m_frequency; ///< frequency
1266 MHz_u m_channelWidth; ///< channel width
1267 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
1268};
1269
1281
1282void
1284 std::size_t payloadSize,
1285 uint64_t uid,
1286 uint8_t bssColor)
1287{
1288 NS_LOG_FUNCTION(this << txStaId << payloadSize << uid << +bssColor);
1289 WifiConstPsduMap psdus;
1290
1292 0,
1294 NanoSeconds(800),
1295 1,
1296 1,
1297 0,
1299 false,
1300 false,
1301 false,
1302 bssColor);
1303
1304 Ptr<Packet> pkt = Create<Packet>(payloadSize);
1305 WifiMacHeader hdr;
1307 hdr.SetQosTid(0);
1308 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
1309 std::ostringstream addr;
1310 addr << "00:00:00:00:00:0" << txStaId;
1311 hdr.SetAddr2(Mac48Address(addr.str().c_str()));
1312 hdr.SetSequenceNumber(1);
1313 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1314 psdus.insert(std::make_pair(SU_STA_ID, psdu));
1315
1316 Ptr<MuMimoSpectrumWifiPhy> phy = (txStaId == 0) ? m_phyAp : m_phyStas.at(txStaId - 1);
1317 phy->SetPpduUid(uid);
1318 phy->Send(psdus, txVector);
1319}
1320
1323 uint8_t nss,
1324 uint8_t bssColor) const
1325{
1327 0,
1329 NanoSeconds(1600),
1330 1,
1331 nss,
1332 0,
1334 false,
1335 false,
1336 false,
1337 bssColor);
1338
1339 HeRu::RuSpec ru(WifiRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
1340 txVector.SetRu(ru, txStaId);
1341 txVector.SetMode(HePhy::GetHeMcs7(), txStaId);
1342 txVector.SetNss(nss, txStaId);
1343
1344 return txVector;
1345}
1346
1347void
1348TestUlMuMimoPhyTransmission::SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor)
1349{
1350 WifiTxVector txVector(HePhy::GetHeMcs7(),
1351 0,
1353 NanoSeconds(1600),
1354 1,
1355 1,
1356 0,
1358 false,
1359 false,
1360 false,
1361 bssColor);
1362
1363 HeRu::RuSpec ru(WifiRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
1364 for (auto staId : staIds)
1365 {
1366 txVector.SetRu(ru, staId);
1367 txVector.SetMode(HePhy::GetHeMcs7(), staId);
1368 txVector.SetNss(1, staId);
1369 }
1370
1371 uint16_t length;
1372 std::tie(length, m_expectedPpduDuration) =
1374 txVector,
1375 m_phyAp->GetPhyBand());
1376 txVector.SetLength(length);
1377 auto hePhyAp = std::dynamic_pointer_cast<HePhy>(m_phyAp->GetPhyEntity(WIFI_MOD_CLASS_HE));
1378 hePhyAp->SetTrigVector(txVector, m_expectedPpduDuration);
1379}
1380
1381void
1383 uint8_t nss,
1384 std::size_t payloadSize,
1385 uint64_t uid,
1386 uint8_t bssColor)
1387{
1388 NS_LOG_FUNCTION(this << txStaId << +nss << payloadSize << uid << +bssColor);
1389 WifiConstPsduMap psdus;
1390
1391 WifiTxVector txVector = GetTxVectorForHeTbPpdu(txStaId, nss, bssColor);
1392 Ptr<Packet> pkt = Create<Packet>(payloadSize);
1393 WifiMacHeader hdr;
1395 hdr.SetQosTid(0);
1396 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
1397 std::ostringstream addr;
1398 addr << "00:00:00:00:00:0" << txStaId;
1399 hdr.SetAddr2(Mac48Address(addr.str().c_str()));
1400 hdr.SetSequenceNumber(1);
1401 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1402 psdus.insert(std::make_pair(txStaId, psdu));
1403
1404 Ptr<MuMimoSpectrumWifiPhy> phy = m_phyStas.at(txStaId - 1);
1405 Time txDuration = MuMimoSpectrumWifiPhy::CalculateTxDuration(psdu->GetSize(),
1406 txVector,
1407 phy->GetPhyBand(),
1408 txStaId);
1409 txVector.SetLength(
1410 HePhy::ConvertHeTbPpduDurationToLSigLength(txDuration, txVector, phy->GetPhyBand()).first);
1411
1412 phy->SetPpduUid(uid);
1413 phy->Send(psdus, txVector);
1414}
1415
1416void
1418 RxSignalInfo rxSignalInfo,
1419 const WifiTxVector& txVector,
1420 const std::vector<bool>& /*statusPerMpdu*/)
1421{
1422 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2() << RatioToDb(rxSignalInfo.snr) << txVector);
1423 NS_TEST_ASSERT_MSG_EQ((RatioToDb(rxSignalInfo.snr) > dB_u{0.0}), true, "Incorrect SNR value");
1424 for (std::size_t index = 0; index < m_countRxSuccessFromStas.size(); ++index)
1425 {
1426 std::ostringstream addr;
1427 addr << "00:00:00:00:00:0" << index + 1;
1428 if (psdu->GetAddr2() == Mac48Address(addr.str().c_str()))
1429 {
1430 m_countRxSuccessFromStas.at(index)++;
1431 m_countRxBytesFromStas.at(index) += (psdu->GetSize() - 30);
1432 break;
1433 }
1434 }
1435}
1436
1437void
1439{
1440 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2());
1441 for (std::size_t index = 0; index < m_countRxFailureFromStas.size(); ++index)
1442 {
1443 std::ostringstream addr;
1444 addr << "00:00:00:00:00:0" << index + 1;
1445 if (psdu->GetAddr2() == Mac48Address(addr.str().c_str()))
1446 {
1447 m_countRxFailureFromStas.at(index)++;
1448 break;
1449 }
1450 }
1451}
1452
1453void
1455 uint32_t expectedSuccess,
1456 uint32_t expectedFailures,
1457 uint32_t expectedBytes)
1458{
1459 NS_LOG_FUNCTION(this << staId << expectedSuccess << expectedFailures << expectedBytes);
1461 expectedSuccess,
1462 "The number of successfully received packets from STA "
1463 << staId << " is not correct!");
1465 expectedFailures,
1466 "The number of unsuccessfully received packets from STA "
1467 << staId << " is not correct!");
1469 expectedBytes,
1470 "The number of bytes received from STA " << staId << " is not correct!");
1471}
1472
1473void
1475{
1476 NS_TEST_ASSERT_MSG_EQ(m_phyAp->GetCurrentEvent(),
1477 nullptr,
1478 "m_currentEvent for AP was not cleared");
1479 std::size_t sta = 1;
1480 for (auto& phy : m_phyStas)
1481 {
1482 NS_TEST_ASSERT_MSG_EQ(phy->GetCurrentEvent(),
1483 nullptr,
1484 "m_currentEvent for STA " << sta << " was not cleared");
1485 sta++;
1486 }
1487}
1488
1489void
1491 WifiPhyState expectedState)
1492{
1493 // This is needed to make sure PHY state will be checked as the last event if a state change
1494 // occurred at the exact same time as the check
1496}
1497
1498void
1500 WifiPhyState expectedState)
1501{
1502 WifiPhyState currentState;
1503 PointerValue ptr;
1504 phy->GetAttribute("State", ptr);
1506 currentState = state->GetState();
1507 NS_LOG_FUNCTION(this << currentState << expectedState);
1508 NS_TEST_ASSERT_MSG_EQ(currentState,
1509 expectedState,
1510 "PHY State " << currentState << " does not match expected state "
1511 << expectedState << " at " << Simulator::Now());
1512}
1513
1514void
1516{
1517 for (auto& counter : m_countRxSuccessFromStas)
1518 {
1519 counter = 0;
1520 }
1521 for (auto& counter : m_countRxFailureFromStas)
1522 {
1523 counter = 0;
1524 }
1525 for (auto& counter : m_countRxBytesFromStas)
1526 {
1527 counter = 0;
1528 }
1529 for (auto& phy : m_phyStas)
1530 {
1531 phy->SetPpduUid(0);
1532 phy->SetTriggerFrameUid(0);
1533 }
1534 SetBssColor(m_phyAp, 0);
1535}
1536
1537void
1539{
1540 Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice>(phy->GetDevice());
1541 Ptr<HeConfiguration> heConfiguration = device->GetHeConfiguration();
1542 heConfiguration->m_bssColor = bssColor;
1543}
1544
1545void
1547{
1548 // WifiHelper::EnableLogComponents();
1549 // LogComponentEnable("WifiPhyMuMimoTest", LOG_LEVEL_ALL);
1550
1554 spectrumChannel->SetPropagationDelayModel(delayModel);
1555
1556 Ptr<Node> apNode = CreateObject<Node>();
1558 apDev->SetStandard(WIFI_STANDARD_80211ax);
1560 "Txop",
1561 PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
1562 apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
1563 apDev->SetMac(apMac);
1566 apDev->SetHeConfiguration(heConfiguration);
1568 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
1570 m_phyAp->SetErrorRateModel(apErrorModel);
1571 m_phyAp->SetDevice(apDev);
1572 m_phyAp->AddChannel(spectrumChannel);
1573 m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
1574 m_phyAp->SetReceiveOkCallback(MakeCallback(&TestUlMuMimoPhyTransmission::RxSuccess, this));
1575 m_phyAp->SetReceiveErrorCallback(MakeCallback(&TestUlMuMimoPhyTransmission::RxFailure, this));
1576 apDev->SetPhy(m_phyAp);
1577 apNode->AddDevice(apDev);
1578
1579 for (std::size_t i = 1; i <= 4; ++i)
1580 {
1581 Ptr<Node> staNode = CreateObject<Node>();
1583 staDev->SetStandard(WIFI_STANDARD_80211ax);
1585 staDev->SetHeConfiguration(CreateObject<HeConfiguration>());
1587 phy->SetInterferenceHelper(staInterferenceHelper);
1589 phy->SetErrorRateModel(staErrorModel);
1590 phy->SetDevice(staDev);
1591 phy->AddChannel(spectrumChannel);
1592 phy->ConfigureStandard(WIFI_STANDARD_80211ax);
1593 phy->SetAttribute("TxGain", DoubleValue(1.0));
1594 phy->SetAttribute("TxPowerStart", DoubleValue(16.0));
1595 phy->SetAttribute("TxPowerEnd", DoubleValue(16.0));
1596 phy->SetAttribute("PowerDensityLimit", DoubleValue(100.0)); // no impact by default
1597 phy->SetAttribute("RxGain", DoubleValue(2.0));
1598 staDev->SetPhy(phy);
1599 staNode->AddDevice(staDev);
1600 m_phyStas.push_back(phy);
1601 m_countRxSuccessFromStas.push_back(0);
1602 m_countRxFailureFromStas.push_back(0);
1603 m_countRxBytesFromStas.push_back(0);
1604 }
1605}
1606
1607void
1609{
1610 for (auto& phy : m_phyStas)
1611 {
1612 phy->Dispose();
1613 phy = nullptr;
1614 }
1615}
1616
1617void
1618TestUlMuMimoPhyTransmission::LogScenario(const std::string& log) const
1619{
1620 NS_LOG_INFO(log);
1621}
1622
1623void
1625 Time delay,
1626 const std::vector<uint16_t>& txStaIds,
1627 WifiPhyState expectedStateAtEnd,
1628 const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta)
1629{
1630 static uint64_t uid = 0;
1631
1632 // AP sends an SU packet preceding HE TB PPDUs
1635 this,
1636 0,
1637 50,
1638 ++uid,
1639 0);
1640
1642
1643 // STAs send MU UL PPDUs addressed to AP
1644 uint16_t payloadSize = 1000;
1645 std::size_t index = 0;
1646 for (auto txStaId : txStaIds)
1647 {
1648 Simulator::Schedule(delay + (index * m_delayStart),
1650 this,
1651 txStaId,
1652 1,
1653 payloadSize,
1654 uid,
1655 0);
1656 payloadSize++;
1657 index++;
1658 }
1659
1660 // Verify it takes m_expectedPpduDuration to transmit the PPDUs
1663 this,
1664 m_phyAp,
1667 (m_delayStart * expectedCountersPerSta.size()),
1669 this,
1670 m_phyAp,
1671 expectedStateAtEnd);
1672
1673 delay += MilliSeconds(100);
1674 // Check reception state from STAs
1675 uint16_t staId = 1;
1676 for (const auto& expectedCounters : expectedCountersPerSta)
1677 {
1678 uint16_t expectedSuccessFromSta = std::get<0>(expectedCounters);
1679 uint16_t expectedFailuresFromSta = std::get<1>(expectedCounters);
1680 uint16_t expectedBytesFromSta = std::get<2>(expectedCounters);
1681 Simulator::Schedule(delay + (m_delayStart * (staId - 1)),
1683 this,
1684 staId,
1685 expectedSuccessFromSta,
1686 expectedFailuresFromSta,
1687 expectedBytesFromSta);
1688 staId++;
1689 }
1690
1691 // Verify events data have been cleared
1693
1694 delay += MilliSeconds(100);
1696}
1697
1698void
1700{
1703 int64_t streamNumber = 0;
1704 m_phyAp->AssignStreams(streamNumber);
1705 for (auto& phy : m_phyStas)
1706 {
1707 phy->AssignStreams(streamNumber);
1708 }
1709
1710 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
1715 ->number;
1716
1717 m_phyAp->SetOperatingChannel(
1719 for (auto& phy : m_phyStas)
1720 {
1721 phy->SetOperatingChannel(
1723 }
1724
1725 Time delay;
1727 delay += Seconds(1);
1728
1729 //---------------------------------------------------------------------------
1730 // Verify that all HE TB PPDUs using full BW MU-MIMO have been corrected received
1731 Simulator::Schedule(delay,
1733 this,
1734 "Reception of HE TB PPDUs using full BW MU-MIMO");
1735 ScheduleTest(delay,
1736 {1, 2, 3},
1738 {
1739 std::make_tuple(1, 0, 1000), // One PSDU of 1000 bytes should have been
1740 // successfully received from STA 1
1741 std::make_tuple(1, 0, 1001), // One PSDU of 1001 bytes should have been
1742 // successfully received from STA 2
1743 std::make_tuple(1, 0, 1002) // One PSDU of 1002 bytes should have been
1744 // successfully received from STA 3
1745 });
1746 delay += Seconds(1);
1747
1748 //---------------------------------------------------------------------------
1749 // Send an HE SU PPDU during 400 ns window and verify that all HE TB PPDUs using full BW MU-MIMO
1750 // have been impacted
1751 Simulator::Schedule(delay,
1753 this,
1754 "Reception of HE TB PPDUs HE TB PPDUs using full BW MU-MIMO with an HE SU "
1755 "PPDU arriving during the 400 ns window");
1756 // One HE SU arrives at AP during the 400ns window
1757 Simulator::Schedule(delay + NanoSeconds(150),
1759 this,
1760 4,
1761 1002,
1762 2,
1763 0);
1764 ScheduleTest(delay,
1765 {1, 2, 3},
1767 {
1768 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
1769 // failed (since interference from STA 4)
1770 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
1771 // failed (since interference from STA 4)
1772 std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
1773 // (since interference from STA 4)
1774 });
1775 delay += Seconds(1);
1776
1777 //---------------------------------------------------------------------------
1778 // Send an HE SU PPDU during HE portion reception and verify that all HE TB PPDUs have been
1779 // impacted
1780 Simulator::Schedule(delay,
1782 this,
1783 "Reception of HE TB PPDUs using full BW MU-MIMO with an HE SU PPDU "
1784 "arriving during the HE portion");
1785 // One HE SU arrives at AP during the HE portion
1788 this,
1789 4,
1790 1002,
1791 2,
1792 0);
1793 ScheduleTest(delay,
1794 {1, 2, 3},
1796 {
1797 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
1798 // failed (since interference from STA 4)
1799 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
1800 // failed (since interference from STA 4)
1801 std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
1802 // (since interference from STA 4)
1803 });
1804 delay += Seconds(1);
1805
1807}
1808
1809void
1811{
1812 std::vector<Time> startDelays{NanoSeconds(0), NanoSeconds(100)};
1813
1814 for (const auto& delayStart : startDelays)
1815 {
1816 m_delayStart = delayStart;
1817
1818 m_frequency = MHz_u{5180};
1819 m_channelWidth = MHz_u{20};
1821 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1822 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1823 << m_delayStart);
1824 RunOne();
1825
1826 m_frequency = MHz_u{5190};
1827 m_channelWidth = MHz_u{40};
1829 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1830 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1831 << m_delayStart);
1832 RunOne();
1833
1834 m_frequency = MHz_u{5210};
1835 m_channelWidth = MHz_u{80};
1837 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1838 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1839 << m_delayStart);
1840 RunOne();
1841
1842 m_frequency = MHz_u{5250};
1843 m_channelWidth = MHz_u{160};
1845 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1846 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1847 << m_delayStart);
1848 RunOne();
1849 }
1850
1852}
1853
1854/**
1855 * @ingroup wifi-test
1856 * @ingroup tests
1857 *
1858 * @brief wifi PHY MU-MIMO Test Suite
1859 */
1861{
1862 public:
1864};
1865
1873
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.
std::shared_ptr< MuMimoTestHePhy > m_ofdmTestHePhy
Pointer to HE PHY instance used for MU-MIMO test.
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
static WifiMode GetHeMcs7()
Return MCS 7 from HE MCS values.
HePhy(bool buildModeList=true)
Constructor for HE PHY.
Definition he-phy.cc:70
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:567
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:263
RU Specification.
Definition he-ru.h:37
an EUI-48 address
static uint64_t m_globalPpduUid
Global counter of the PPDU UID.
Definition phy-entity.h:932
AttributeValue implementation for Pointer.
Definition pointer.h:37
Ptr< T > Get() const
Definition pointer.h:223
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:67
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
void DoInitialize() override
Initialize() implementation.
void DoDispose() override
Destructor implementation.
Hold variables of type string.
Definition string.h:45
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
@ QUICK
Fast test.
Definition test.h:1055
TestCase(const TestCase &)=delete
Type
Type of test.
Definition test.h:1274
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:490
static constexpr auto UNIT
Definition test.h:1291
Simulation virtual time values and global simulation resolution.
Definition nstime.h:96
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
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.
std::map< WifiModulationClass, std::shared_ptr< PhyEntity > > m_phyEntities
This map holds the supported PHY entities.
Definition wifi-phy.h:1390
std::tuple< uint8_t, MHz_u, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying a segment of an operating channel.
Definition wifi-phy.h:944
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1564
Ptr< Event > m_currentEvent
Hold the current event.
Definition wifi-phy.h:1365
uint64_t m_previouslyRxPpduUid
UID of the previously received PPDU, reset to UINT64_MAX upon transmission.
Definition wifi-phy.h:1370
static ConstIterator FindFirst(uint8_t number, MHz_u frequency, MHz_u width, WifiStandard standard, WifiPhyBand band, ConstIterator start=GetFrequencyChannels().begin())
Find the first frequency segment matching the specified parameters.
This objects implements the PHY state machine of the Wifi device.
static RuType GetRuType(RuSpec ru)
Get the type of a given RU.
Definition wifi-ru.cc:45
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 SetRu(WifiRu::RuSpec ru, uint16_t staId)
Set the RU specification for the STA-ID.
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
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:439
#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:1393
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1405
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
@ 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.
@ IDLE
The PHY layer is IDLE.
@ CCA_BUSY
The PHY layer has sense the medium busy through the CCA mechanism.
@ RX
The PHY layer is receiving a packet.
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:45
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:585
@ 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)
double dB_u
dB weak type
Definition wifi-units.h:28
uint8_t staNss
Number of spatial streams used for the STA.
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:79
double snr
SNR in linear scale.
Definition wifi-types.h:80
constexpr MHz_u DEFAULT_FREQUENCY
constexpr MHz_u DEFAULT_CHANNEL_WIDTH
constexpr MHz_u DEFAULT_FREQUENCY