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 Ptr<MuMimoTestHePhy> m_ofdmTestHePhy; ///< Pointer to HE PHY instance used for MU-MIMO test
277
278 // end of class MuMimoSpectrumWifiPhy
279};
280
281TypeId
283{
284 static TypeId tid =
285 TypeId("ns3::MuMimoSpectrumWifiPhy").SetParent<SpectrumWifiPhy>().SetGroupName("Wifi");
286 return tid;
287}
288
295
299
300void
302{
303 // Replace HE PHY instance with test instance
306}
307
308void
314
315void
321
322void
327
333
334/**
335 * @ingroup wifi-test
336 * @ingroup tests
337 *
338 * @brief DL MU-MIMO PHY test
339 */
341{
342 public:
344
345 private:
346 void DoSetup() override;
347 void DoTeardown() override;
348 void DoRun() override;
349
350 /**
351 * Receive success function for STA 1
352 * @param psdu the PSDU
353 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
354 * @param txVector the transmit vector
355 * @param statusPerMpdu reception status per MPDU
356 */
358 RxSignalInfo rxSignalInfo,
359 const WifiTxVector& txVector,
360 const std::vector<bool>& statusPerMpdu);
361 /**
362 * Receive success function for STA 2
363 * @param psdu the PSDU
364 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
365 * @param txVector the transmit vector
366 * @param statusPerMpdu reception status per MPDU
367 */
369 RxSignalInfo rxSignalInfo,
370 const WifiTxVector& txVector,
371 const std::vector<bool>& statusPerMpdu);
372 /**
373 * Receive success function for STA 3
374 * @param psdu the PSDU
375 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
376 * @param txVector the transmit vector
377 * @param statusPerMpdu reception status per MPDU
378 */
380 RxSignalInfo rxSignalInfo,
381 const WifiTxVector& txVector,
382 const std::vector<bool>& statusPerMpdu);
383
384 /**
385 * Receive failure function for STA 1
386 * @param psdu the PSDU
387 */
389 /**
390 * Receive failure function for STA 2
391 * @param psdu the PSDU
392 */
394 /**
395 * Receive failure function for STA 3
396 * @param psdu the PSDU
397 */
399
400 /**
401 * Check the results for STA 1
402 * @param expectedRxSuccess the expected number of RX success
403 * @param expectedRxFailure the expected number of RX failures
404 * @param expectedRxBytes the expected number of RX bytes
405 */
406 void CheckResultsSta1(uint32_t expectedRxSuccess,
407 uint32_t expectedRxFailure,
408 uint32_t expectedRxBytes);
409 /**
410 * Check the results for STA 2
411 * @param expectedRxSuccess the expected number of RX success
412 * @param expectedRxFailure the expected number of RX failures
413 * @param expectedRxBytes the expected number of RX bytes
414 */
415 void CheckResultsSta2(uint32_t expectedRxSuccess,
416 uint32_t expectedRxFailure,
417 uint32_t expectedRxBytes);
418 /**
419 * Check the results for STA 3
420 * @param expectedRxSuccess the expected number of RX success
421 * @param expectedRxFailure the expected number of RX failures
422 * @param expectedRxBytes the expected number of RX bytes
423 */
424 void CheckResultsSta3(uint32_t expectedRxSuccess,
425 uint32_t expectedRxFailure,
426 uint32_t expectedRxBytes);
427
428 /**
429 * Reset the results
430 */
431 void ResetResults();
432
433 /**
434 * STA info
435 */
436 struct StaInfo
437 {
438 uint16_t staId; //!< STA ID
439 uint8_t staNss; //!< Number of spatial streams used for the STA
440 };
441
442 /**
443 * Send DL MU-MIMO PPDU function
444 * @param staInfos the STAs infos
445 */
446 void SendMuPpdu(const std::vector<StaInfo>& staInfos);
447
448 /**
449 * Generate interference function
450 * @param interferencePsd the PSD of the interference to be generated
451 * @param duration the duration of the interference
452 */
453 void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
454 /**
455 * Stop interference function
456 */
458
459 /**
460 * Run one function
461 */
462 void RunOne();
463
464 /**
465 * Schedule now to check the PHY state
466 * @param phy the PHY
467 * @param expectedState the expected state of the PHY
468 */
470 /**
471 * Check the PHY state now
472 * @param phy the PHY
473 * @param expectedState the expected state of the PHY
474 */
476
477 uint32_t m_countRxSuccessSta1; ///< count RX success for STA 1
478 uint32_t m_countRxSuccessSta2; ///< count RX success for STA 2
479 uint32_t m_countRxSuccessSta3; ///< count RX success for STA 3
480 uint32_t m_countRxFailureSta1; ///< count RX failure for STA 1
481 uint32_t m_countRxFailureSta2; ///< count RX failure for STA 2
482 uint32_t m_countRxFailureSta3; ///< count RX failure for STA 3
483 uint32_t m_countRxBytesSta1; ///< count RX bytes for STA 1
484 uint32_t m_countRxBytesSta2; ///< count RX bytes for STA 2
485 uint32_t m_countRxBytesSta3; ///< count RX bytes for STA 3
486
491
492 uint8_t m_nss; ///< number of spatial streams per STA
493 MHz_u m_frequency; ///< frequency
494 MHz_u m_channelWidth; ///< channel width
495 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
496};
497
499 : TestCase("DL MU-MIMO PHY test"),
500 m_countRxSuccessSta1{0},
501 m_countRxSuccessSta2{0},
502 m_countRxSuccessSta3{0},
503 m_countRxFailureSta1{0},
504 m_countRxFailureSta2{0},
505 m_countRxFailureSta3{0},
506 m_countRxBytesSta1{0},
507 m_countRxBytesSta2{0},
508 m_countRxBytesSta3{0},
509 m_nss{1},
510 m_frequency{DEFAULT_FREQUENCY},
511 m_channelWidth{DEFAULT_CHANNEL_WIDTH},
512 m_expectedPpduDuration{NanoSeconds(306400)}
513{
514}
515
516void
529
530void
531TestDlMuMimoPhyTransmission::SendMuPpdu(const std::vector<StaInfo>& staInfos)
532{
533 NS_LOG_FUNCTION(this << staInfos.size());
534 NS_ASSERT(staInfos.size() > 1);
535
537 0,
539 NanoSeconds(800),
540 1,
541 1,
542 0,
544 false,
545 false);
546
547 WifiConstPsduMap psdus;
548 HeRu::RuSpec ru(WifiRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
549 for (const auto& staInfo : staInfos)
550 {
551 txVector.SetRu(ru, staInfo.staId);
552 txVector.SetMode(HePhy::GetHeMcs7(), staInfo.staId);
553 txVector.SetNss(staInfo.staNss, staInfo.staId);
554
555 Ptr<Packet> pkt = Create<Packet>(1000 + (8 * staInfo.staId));
556 WifiMacHeader hdr;
558 hdr.SetQosTid(0);
559 std::ostringstream addr;
560 addr << "00:00:00:00:00:0" << staInfo.staId;
561 hdr.SetAddr1(Mac48Address(addr.str().c_str()));
562 hdr.SetSequenceNumber(1 + staInfo.staId);
563 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
564 psdus.insert(std::make_pair(staInfo.staId, psdu));
565 }
566
568
569 NS_ASSERT(txVector.IsDlMuMimo());
570 NS_ASSERT(!txVector.IsDlOfdma());
571
572 m_phyAp->Send(psdus, txVector);
573}
574
575void
577 RxSignalInfo rxSignalInfo,
578 const WifiTxVector& txVector,
579 const std::vector<bool>& /*statusPerMpdu*/)
580{
581 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
583 m_countRxBytesSta1 += (psdu->GetSize() - 30);
584}
585
586void
588 RxSignalInfo rxSignalInfo,
589 const WifiTxVector& txVector,
590 const std::vector<bool>& /*statusPerMpdu*/)
591{
592 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
594 m_countRxBytesSta2 += (psdu->GetSize() - 30);
595}
596
597void
599 RxSignalInfo rxSignalInfo,
600 const WifiTxVector& txVector,
601 const std::vector<bool>& /*statusPerMpdu*/)
602{
603 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
605 m_countRxBytesSta3 += (psdu->GetSize() - 30);
606}
607
608void
614
615void
621
622void
628
629void
631 uint32_t expectedRxFailure,
632 uint32_t expectedRxBytes)
633{
635 expectedRxSuccess,
636 "The number of successfully received packets by STA 1 is not correct!");
638 expectedRxFailure,
639 "The number of unsuccessfully received packets by STA 1 is not correct!");
641 expectedRxBytes,
642 "The number of bytes received by STA 1 is not correct!");
643}
644
645void
647 uint32_t expectedRxFailure,
648 uint32_t expectedRxBytes)
649{
651 expectedRxSuccess,
652 "The number of successfully received packets by STA 2 is not correct!");
654 expectedRxFailure,
655 "The number of unsuccessfully received packets by STA 2 is not correct!");
657 expectedRxBytes,
658 "The number of bytes received by STA 2 is not correct!");
659}
660
661void
663 uint32_t expectedRxFailure,
664 uint32_t expectedRxBytes)
665{
667 expectedRxSuccess,
668 "The number of successfully received packets by STA 3 is not correct!");
670 expectedRxFailure,
671 "The number of unsuccessfully received packets by STA 3 is not correct!");
673 expectedRxBytes,
674 "The number of bytes received by STA 3 is not correct!");
675}
676
677void
679 WifiPhyState expectedState)
680{
681 // This is needed to make sure PHY state will be checked as the last event if a state change
682 // occurred at the exact same time as the check
684}
685
686void
688 WifiPhyState expectedState)
689{
690 WifiPhyState currentState;
691 PointerValue ptr;
692 phy->GetAttribute("State", ptr);
694 currentState = state->GetState();
695 NS_LOG_FUNCTION(this << currentState << expectedState);
696 NS_TEST_ASSERT_MSG_EQ(currentState,
697 expectedState,
698 "PHY State " << currentState << " does not match expected state "
699 << expectedState << " at " << Simulator::Now());
700}
701
702void
704{
708 spectrumChannel->SetPropagationDelayModel(delayModel);
709
710 Ptr<Node> apNode = CreateObject<Node>();
714 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
716 m_phyAp->SetErrorRateModel(apErrorModel);
717 m_phyAp->SetDevice(apDev);
718 m_phyAp->AddChannel(spectrumChannel);
719 m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
720 apDev->SetPhy(m_phyAp);
721 apNode->AddDevice(apDev);
722
723 Ptr<Node> sta1Node = CreateObject<Node>();
727 m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
729 m_phySta1->SetErrorRateModel(sta1ErrorModel);
730 m_phySta1->SetDevice(sta1Dev);
731 m_phySta1->AddChannel(spectrumChannel);
737 sta1Dev->SetPhy(m_phySta1);
738 sta1Node->AddDevice(sta1Dev);
739
740 Ptr<Node> sta2Node = CreateObject<Node>();
744 m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
746 m_phySta2->SetErrorRateModel(sta2ErrorModel);
747 m_phySta2->SetDevice(sta2Dev);
748 m_phySta2->AddChannel(spectrumChannel);
754 sta2Dev->SetPhy(m_phySta2);
755 sta2Node->AddDevice(sta2Dev);
756
757 Ptr<Node> sta3Node = CreateObject<Node>();
761 m_phySta3->SetInterferenceHelper(sta3InterferenceHelper);
763 m_phySta3->SetErrorRateModel(sta3ErrorModel);
764 m_phySta3->SetDevice(sta3Dev);
765 m_phySta3->AddChannel(spectrumChannel);
771 sta3Dev->SetPhy(m_phySta3);
772 sta3Node->AddDevice(sta3Dev);
773}
774
775void
777{
778 m_phyAp->Dispose();
779 m_phyAp = nullptr;
781 m_phySta1 = nullptr;
783 m_phySta2 = nullptr;
785 m_phySta3 = nullptr;
786}
787
788void
790{
793 int64_t streamNumber = 0;
794 m_phyAp->AssignStreams(streamNumber);
795 m_phySta1->AssignStreams(streamNumber);
796 m_phySta2->AssignStreams(streamNumber);
797
798 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
803 ->number;
804
805 m_phyAp->SetOperatingChannel(
813
814 m_phyAp->SetNumberOfAntennas(8);
815 m_phyAp->SetMaxSupportedTxSpatialStreams(8);
816
817 //----------------------------------------------------------------------------------------------------
818 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2:
819 // STA 1 and STA 2 should receive their PSDUs, whereas STA 3 should not receive any PSDU
820 // but should keep its PHY busy during all PPDU duration.
823 this,
824 std::vector<StaInfo>{{1, m_nss}, {2, m_nss}});
825
826 // Since it takes m_expectedPpduDuration to transmit the PPDU,
827 // all 3 PHYs should be back to IDLE at the same time,
828 // even the PHY that has no PSDU addressed to it.
831 this,
832 m_phySta1,
833 WifiPhyState::RX);
836 this,
837 m_phySta2,
838 WifiPhyState::RX);
841 this,
842 m_phySta3,
843 WifiPhyState::CCA_BUSY);
846 this,
847 m_phySta1,
848 WifiPhyState::IDLE);
851 this,
852 m_phySta2,
853 WifiPhyState::IDLE);
856 this,
857 m_phySta3,
858 WifiPhyState::IDLE);
859
860 // One PSDU of 1008 bytes should have been successfully received by STA 1
863 this,
864 1,
865 0,
866 1008);
867 // One PSDU of 1016 bytes should have been successfully received by STA 2
870 this,
871 1,
872 0,
873 1016);
874 // No PSDU should have been received by STA 3
877 this,
878 0,
879 0,
880 0);
881
883
884 //----------------------------------------------------------------------------------------------------
885 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 3:
886 // STA 1 and STA 3 should receive their PSDUs, whereas STA 2 should not receive any PSDU
887 // but should keep its PHY busy during all PPDU duration.
890 this,
891 std::vector<StaInfo>{{1, m_nss}, {3, m_nss}});
892
893 // Since it takes m_expectedPpduDuration to transmit the PPDU,
894 // all 3 PHYs should be back to IDLE at the same time,
895 // even the PHY that has no PSDU addressed to it.
898 this,
899 m_phySta1,
900 WifiPhyState::RX);
903 this,
904 m_phySta2,
905 WifiPhyState::CCA_BUSY);
908 this,
909 m_phySta3,
910 WifiPhyState::RX);
913 this,
914 m_phySta1,
915 WifiPhyState::IDLE);
918 this,
919 m_phySta2,
920 WifiPhyState::IDLE);
923 this,
924 m_phySta3,
925 WifiPhyState::IDLE);
926
927 // One PSDU of 1008 bytes should have been successfully received by STA 1
930 this,
931 1,
932 0,
933 1008);
934 // No PSDU should have been received by STA 2
937 this,
938 0,
939 0,
940 0);
941 // One PSDU of 1024 bytes should have been successfully received by STA 3
944 this,
945 1,
946 0,
947 1024);
948
950
951 //----------------------------------------------------------------------------------------------------
952 // Send MU PPDU with two PSDUs addressed to STA 2 and STA 3:
953 // STA 2 and STA 3 should receive their PSDUs, whereas STA 1 should not receive any PSDU
954 // but should keep its PHY busy during all PPDU duration.
957 this,
958 std::vector<StaInfo>{{2, m_nss}, {3, m_nss}});
959
960 // Since it takes m_expectedPpduDuration to transmit the PPDU,
961 // all 3 PHYs should be back to IDLE at the same time,
962 // even the PHY that has no PSDU addressed to it.
965 this,
966 m_phySta1,
967 WifiPhyState::CCA_BUSY);
970 this,
971 m_phySta2,
972 WifiPhyState::RX);
975 this,
976 m_phySta3,
977 WifiPhyState::RX);
980 this,
981 m_phySta1,
982 WifiPhyState::IDLE);
985 this,
986 m_phySta2,
987 WifiPhyState::IDLE);
990 this,
991 m_phySta3,
992 WifiPhyState::IDLE);
993
994 // No PSDU should have been received by STA 1
997 this,
998 0,
999 0,
1000 0);
1001 // One PSDU of 1016 bytes should have been successfully received by STA 2
1004 this,
1005 1,
1006 0,
1007 1016);
1008 // One PSDU of 1024 bytes should have been successfully received by STA 3
1011 this,
1012 1,
1013 0,
1014 1024);
1015
1017
1018 //----------------------------------------------------------------------------------------------------
1019 // Send MU PPDU with three PSDUs addressed to STA 1, STA 2 and STA 3:
1020 // All STAs should receive their PSDUs.
1023 this,
1024 std::vector<StaInfo>{{1, m_nss}, {2, m_nss}, {3, m_nss}});
1025
1026 // Since it takes m_expectedPpduDuration to transmit the PPDU,
1027 // all 3 PHYs should be back to IDLE at the same time.
1030 this,
1031 m_phySta1,
1032 WifiPhyState::RX);
1035 this,
1036 m_phySta2,
1037 WifiPhyState::RX);
1040 this,
1041 m_phySta3,
1042 WifiPhyState::RX);
1045 this,
1046 m_phySta1,
1047 WifiPhyState::IDLE);
1050 this,
1051 m_phySta2,
1052 WifiPhyState::IDLE);
1055 this,
1056 m_phySta3,
1057 WifiPhyState::IDLE);
1058
1059 // One PSDU of 1008 bytes should have been successfully received by STA 1
1062 this,
1063 1,
1064 0,
1065 1008);
1066 // One PSDU of 1016 bytes should have been successfully received by STA 2
1069 this,
1070 1,
1071 0,
1072 1016);
1073 // One PSDU of 1024 bytes should have been successfully received by STA 3
1076 this,
1077 1,
1078 0,
1079 1024);
1080
1082
1084}
1085
1086void
1088{
1089 std::vector<uint8_t> nssToTest{1, 2};
1090 for (auto nss : nssToTest)
1091 {
1092 m_nss = nss;
1093 m_frequency = MHz_u{5180};
1094 m_channelWidth = MHz_u{20};
1095 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(110400) : NanoSeconds(156800);
1096 RunOne();
1097
1098 m_frequency = MHz_u{5190};
1099 m_channelWidth = MHz_u{40};
1100 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(83200) : NanoSeconds(102400);
1101 RunOne();
1102
1103 m_frequency = MHz_u{5210};
1104 m_channelWidth = MHz_u{80};
1105 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(75200);
1106 RunOne();
1107
1108 m_frequency = MHz_u{5250};
1109 m_channelWidth = MHz_u{160};
1110 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(61600);
1111 RunOne();
1112 }
1113 // FIXME: test also different nss over STAs once RX durations when receiving different PPDUs
1114 // with different nss over STAs are fixed
1115
1117}
1118
1119/**
1120 * @ingroup wifi-test
1121 * @ingroup tests
1122 *
1123 * @brief UL MU-MIMO PHY test
1124 */
1126{
1127 public:
1129
1130 private:
1131 void DoSetup() override;
1132 void DoTeardown() override;
1133 void DoRun() override;
1134
1135 /**
1136 * Get TXVECTOR for HE TB PPDU.
1137 * @param txStaId the ID of the TX STA
1138 * @param nss the number of spatial streams used for the transmission
1139 * @param bssColor the BSS color of the TX STA
1140 * @return the TXVECTOR for HE TB PPDU
1141 */
1142 WifiTxVector GetTxVectorForHeTbPpdu(uint16_t txStaId, uint8_t nss, uint8_t bssColor) const;
1143 /**
1144 * Set TRIGVECTOR for HE TB PPDU
1145 *
1146 * @param staIds the IDs of the STAs sollicited for the HE TB transmission
1147 * @param bssColor the BSS color of the TX STA
1148 */
1149 void SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor);
1150 /**
1151 * Send HE TB PPDU function
1152 * @param txStaId the ID of the TX STA
1153 * @param nss the number of spatial streams used for the transmission
1154 * @param payloadSize the size of the payload in bytes
1155 * @param uid the UID of the trigger frame that is initiating this transmission
1156 * @param bssColor the BSS color of the TX STA
1157 */
1158 void SendHeTbPpdu(uint16_t txStaId,
1159 uint8_t nss,
1160 std::size_t payloadSize,
1161 uint64_t uid,
1162 uint8_t bssColor);
1163
1164 /**
1165 * Send HE SU PPDU function
1166 * @param txStaId the ID of the TX STA
1167 * @param payloadSize the size of the payload in bytes
1168 * @param uid the UID of the trigger frame that is initiating this transmission
1169 * @param bssColor the BSS color of the TX STA
1170 */
1171 void SendHeSuPpdu(uint16_t txStaId, std::size_t payloadSize, uint64_t uid, uint8_t bssColor);
1172
1173 /**
1174 * Set the BSS color
1175 * @param phy the PHY
1176 * @param bssColor the BSS color
1177 */
1178 void SetBssColor(Ptr<WifiPhy> phy, uint8_t bssColor);
1179
1180 /**
1181 * Run one function
1182 */
1183 void RunOne();
1184
1185 /**
1186 * Check the received PSDUs from a given STA
1187 * @param staId the ID of the STA to check
1188 * @param expectedSuccess the expected number of success
1189 * @param expectedFailures the expected number of failures
1190 * @param expectedBytes the expected number of bytes
1191 */
1192 void CheckRxFromSta(uint16_t staId,
1193 uint32_t expectedSuccess,
1194 uint32_t expectedFailures,
1195 uint32_t expectedBytes);
1196
1197 /**
1198 * Verify all events are cleared at end of TX or RX
1199 */
1200 void VerifyEventsCleared();
1201
1202 /**
1203 * Check the PHY state
1204 * @param phy the PHY
1205 * @param expectedState the expected state of the PHY
1206 */
1207 void CheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy, WifiPhyState expectedState);
1208 /// @copydoc CheckPhyState
1210
1211 /**
1212 * Reset function
1213 */
1214 void Reset();
1215
1216 /**
1217 * Receive success function
1218 * @param psdu the PSDU
1219 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
1220 * @param txVector the transmit vector
1221 * @param statusPerMpdu reception status per MPDU
1222 */
1224 RxSignalInfo rxSignalInfo,
1225 const WifiTxVector& txVector,
1226 const std::vector<bool>& statusPerMpdu);
1227
1228 /**
1229 * Receive failure function
1230 * @param psdu the PSDU
1231 */
1232 void RxFailure(Ptr<const WifiPsdu> psdu);
1233
1234 /**
1235 * Schedule test to perform.
1236 * The interference generation should be scheduled apart.
1237 *
1238 * @param delay the reference delay to schedule the events
1239 * @param txStaIds the IDs of the STAs planned to transmit an HE TB PPDU
1240 * @param expectedStateAtEnd the expected state of the PHY at the end of the reception
1241 * @param expectedCountersPerSta the expected counters per STA
1242 */
1243 void ScheduleTest(
1244 Time delay,
1245 const std::vector<uint16_t>& txStaIds,
1246 WifiPhyState expectedStateAtEnd,
1247 const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta);
1248
1249 /**
1250 * Log scenario description
1251 *
1252 * @param log the scenario description to add to log
1253 */
1254 void LogScenario(const std::string& log) const;
1255
1257 std::vector<Ptr<MuMimoSpectrumWifiPhy>> m_phyStas; ///< PHYs of STAs
1258
1259 std::vector<uint32_t> m_countRxSuccessFromStas; ///< count RX success from STAs
1260 std::vector<uint32_t> m_countRxFailureFromStas; ///< count RX failure from STAs
1261 std::vector<uint32_t> m_countRxBytesFromStas; ///< count RX bytes from STAs
1262
1263 Time m_delayStart; ///< delay between the start of each HE TB PPDUs
1264 MHz_u m_frequency; ///< frequency
1265 MHz_u m_channelWidth; ///< channel width
1266 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
1267};
1268
1270 : TestCase("UL MU-MIMO PHY test"),
1271 m_countRxSuccessFromStas{},
1272 m_countRxFailureFromStas{},
1273 m_countRxBytesFromStas{},
1274 m_delayStart{Seconds(0)},
1275 m_frequency{DEFAULT_FREQUENCY},
1276 m_channelWidth{DEFAULT_CHANNEL_WIDTH},
1277 m_expectedPpduDuration{NanoSeconds(271200)}
1278{
1279}
1280
1281void
1283 std::size_t payloadSize,
1284 uint64_t uid,
1285 uint8_t bssColor)
1286{
1287 NS_LOG_FUNCTION(this << txStaId << payloadSize << uid << +bssColor);
1288 WifiConstPsduMap psdus;
1289
1291 0,
1293 NanoSeconds(800),
1294 1,
1295 1,
1296 0,
1298 false,
1299 false,
1300 false,
1301 bssColor);
1302
1303 Ptr<Packet> pkt = Create<Packet>(payloadSize);
1304 WifiMacHeader hdr;
1306 hdr.SetQosTid(0);
1307 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
1308 std::ostringstream addr;
1309 addr << "00:00:00:00:00:0" << txStaId;
1310 hdr.SetAddr2(Mac48Address(addr.str().c_str()));
1311 hdr.SetSequenceNumber(1);
1312 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1313 psdus.insert(std::make_pair(SU_STA_ID, psdu));
1314
1315 Ptr<MuMimoSpectrumWifiPhy> phy = (txStaId == 0) ? m_phyAp : m_phyStas.at(txStaId - 1);
1316 phy->SetPpduUid(uid);
1317 phy->Send(psdus, txVector);
1318}
1319
1322 uint8_t nss,
1323 uint8_t bssColor) const
1324{
1326 0,
1328 NanoSeconds(1600),
1329 1,
1330 nss,
1331 0,
1333 false,
1334 false,
1335 false,
1336 bssColor);
1337
1338 HeRu::RuSpec ru(WifiRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
1339 txVector.SetRu(ru, txStaId);
1340 txVector.SetMode(HePhy::GetHeMcs7(), txStaId);
1341 txVector.SetNss(nss, txStaId);
1342
1343 return txVector;
1344}
1345
1346void
1347TestUlMuMimoPhyTransmission::SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor)
1348{
1349 WifiTxVector txVector(HePhy::GetHeMcs7(),
1350 0,
1352 NanoSeconds(1600),
1353 1,
1354 1,
1355 0,
1357 false,
1358 false,
1359 false,
1360 bssColor);
1361
1362 HeRu::RuSpec ru(WifiRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
1363 for (auto staId : staIds)
1364 {
1365 txVector.SetRu(ru, staId);
1366 txVector.SetMode(HePhy::GetHeMcs7(), staId);
1367 txVector.SetNss(1, staId);
1368 }
1369
1370 uint16_t length;
1371 std::tie(length, m_expectedPpduDuration) =
1373 txVector,
1374 m_phyAp->GetPhyBand());
1375 txVector.SetLength(length);
1377 hePhyAp->SetTrigVector(txVector, m_expectedPpduDuration);
1378}
1379
1380void
1382 uint8_t nss,
1383 std::size_t payloadSize,
1384 uint64_t uid,
1385 uint8_t bssColor)
1386{
1387 NS_LOG_FUNCTION(this << txStaId << +nss << payloadSize << uid << +bssColor);
1388 WifiConstPsduMap psdus;
1389
1390 WifiTxVector txVector = GetTxVectorForHeTbPpdu(txStaId, nss, bssColor);
1391 Ptr<Packet> pkt = Create<Packet>(payloadSize);
1392 WifiMacHeader hdr;
1394 hdr.SetQosTid(0);
1395 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
1396 std::ostringstream addr;
1397 addr << "00:00:00:00:00:0" << txStaId;
1398 hdr.SetAddr2(Mac48Address(addr.str().c_str()));
1399 hdr.SetSequenceNumber(1);
1400 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1401 psdus.insert(std::make_pair(txStaId, psdu));
1402
1403 Ptr<MuMimoSpectrumWifiPhy> phy = m_phyStas.at(txStaId - 1);
1404 Time txDuration = MuMimoSpectrumWifiPhy::CalculateTxDuration(psdu->GetSize(),
1405 txVector,
1406 phy->GetPhyBand(),
1407 txStaId);
1408 txVector.SetLength(
1409 HePhy::ConvertHeTbPpduDurationToLSigLength(txDuration, txVector, phy->GetPhyBand()).first);
1410
1411 phy->SetPpduUid(uid);
1412 phy->Send(psdus, txVector);
1413}
1414
1415void
1417 RxSignalInfo rxSignalInfo,
1418 const WifiTxVector& txVector,
1419 const std::vector<bool>& /*statusPerMpdu*/)
1420{
1421 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2() << RatioToDb(rxSignalInfo.snr) << txVector);
1422 NS_TEST_ASSERT_MSG_EQ((RatioToDb(rxSignalInfo.snr) > dB_u{0.0}), true, "Incorrect SNR value");
1423 for (std::size_t index = 0; index < m_countRxSuccessFromStas.size(); ++index)
1424 {
1425 std::ostringstream addr;
1426 addr << "00:00:00:00:00:0" << index + 1;
1427 if (psdu->GetAddr2() == Mac48Address(addr.str().c_str()))
1428 {
1429 m_countRxSuccessFromStas.at(index)++;
1430 m_countRxBytesFromStas.at(index) += (psdu->GetSize() - 30);
1431 break;
1432 }
1433 }
1434}
1435
1436void
1438{
1439 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2());
1440 for (std::size_t index = 0; index < m_countRxFailureFromStas.size(); ++index)
1441 {
1442 std::ostringstream addr;
1443 addr << "00:00:00:00:00:0" << index + 1;
1444 if (psdu->GetAddr2() == Mac48Address(addr.str().c_str()))
1445 {
1446 m_countRxFailureFromStas.at(index)++;
1447 break;
1448 }
1449 }
1450}
1451
1452void
1454 uint32_t expectedSuccess,
1455 uint32_t expectedFailures,
1456 uint32_t expectedBytes)
1457{
1458 NS_LOG_FUNCTION(this << staId << expectedSuccess << expectedFailures << expectedBytes);
1460 expectedSuccess,
1461 "The number of successfully received packets from STA "
1462 << staId << " is not correct!");
1464 expectedFailures,
1465 "The number of unsuccessfully received packets from STA "
1466 << staId << " is not correct!");
1468 expectedBytes,
1469 "The number of bytes received from STA " << staId << " is not correct!");
1470}
1471
1472void
1474{
1476 nullptr,
1477 "m_currentEvent for AP was not cleared");
1478 std::size_t sta = 1;
1479 for (auto& phy : m_phyStas)
1480 {
1481 NS_TEST_ASSERT_MSG_EQ(phy->GetCurrentEvent(),
1482 nullptr,
1483 "m_currentEvent for STA " << sta << " was not cleared");
1484 sta++;
1485 }
1486}
1487
1488void
1490 WifiPhyState expectedState)
1491{
1492 // This is needed to make sure PHY state will be checked as the last event if a state change
1493 // occurred at the exact same time as the check
1495}
1496
1497void
1499 WifiPhyState expectedState)
1500{
1501 WifiPhyState currentState;
1502 PointerValue ptr;
1503 phy->GetAttribute("State", ptr);
1505 currentState = state->GetState();
1506 NS_LOG_FUNCTION(this << currentState << expectedState);
1507 NS_TEST_ASSERT_MSG_EQ(currentState,
1508 expectedState,
1509 "PHY State " << currentState << " does not match expected state "
1510 << expectedState << " at " << Simulator::Now());
1511}
1512
1513void
1515{
1516 for (auto& counter : m_countRxSuccessFromStas)
1517 {
1518 counter = 0;
1519 }
1520 for (auto& counter : m_countRxFailureFromStas)
1521 {
1522 counter = 0;
1523 }
1524 for (auto& counter : m_countRxBytesFromStas)
1525 {
1526 counter = 0;
1527 }
1528 for (auto& phy : m_phyStas)
1529 {
1530 phy->SetPpduUid(0);
1531 phy->SetTriggerFrameUid(0);
1532 }
1533 SetBssColor(m_phyAp, 0);
1534}
1535
1536void
1538{
1539 Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice>(phy->GetDevice());
1540 Ptr<HeConfiguration> heConfiguration = device->GetHeConfiguration();
1541 heConfiguration->m_bssColor = bssColor;
1542}
1543
1544void
1546{
1547 // WifiHelper::EnableLogComponents();
1548 // LogComponentEnable("WifiPhyMuMimoTest", LOG_LEVEL_ALL);
1549
1553 spectrumChannel->SetPropagationDelayModel(delayModel);
1554
1555 Ptr<Node> apNode = CreateObject<Node>();
1557 apDev->SetStandard(WIFI_STANDARD_80211ax);
1559 "Txop",
1560 PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
1561 apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
1562 apDev->SetMac(apMac);
1565 apDev->SetHeConfiguration(heConfiguration);
1567 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
1569 m_phyAp->SetErrorRateModel(apErrorModel);
1570 m_phyAp->SetDevice(apDev);
1571 m_phyAp->AddChannel(spectrumChannel);
1575 apDev->SetPhy(m_phyAp);
1576 apNode->AddDevice(apDev);
1577
1578 for (std::size_t i = 1; i <= 4; ++i)
1579 {
1580 Ptr<Node> staNode = CreateObject<Node>();
1582 staDev->SetStandard(WIFI_STANDARD_80211ax);
1584 staDev->SetHeConfiguration(CreateObject<HeConfiguration>());
1586 phy->SetInterferenceHelper(staInterferenceHelper);
1588 phy->SetErrorRateModel(staErrorModel);
1589 phy->SetDevice(staDev);
1590 phy->AddChannel(spectrumChannel);
1591 phy->ConfigureStandard(WIFI_STANDARD_80211ax);
1592 phy->SetAttribute("TxGain", DoubleValue(1.0));
1593 phy->SetAttribute("TxPowerStart", DoubleValue(16.0));
1594 phy->SetAttribute("TxPowerEnd", DoubleValue(16.0));
1595 phy->SetAttribute("PowerDensityLimit", DoubleValue(100.0)); // no impact by default
1596 phy->SetAttribute("RxGain", DoubleValue(2.0));
1597 staDev->SetPhy(phy);
1598 staNode->AddDevice(staDev);
1599 m_phyStas.push_back(phy);
1600 m_countRxSuccessFromStas.push_back(0);
1601 m_countRxFailureFromStas.push_back(0);
1602 m_countRxBytesFromStas.push_back(0);
1603 }
1604}
1605
1606void
1608{
1609 for (auto& phy : m_phyStas)
1610 {
1611 phy->Dispose();
1612 phy = nullptr;
1613 }
1614}
1615
1616void
1617TestUlMuMimoPhyTransmission::LogScenario(const std::string& log) const
1618{
1619 NS_LOG_INFO(log);
1620}
1621
1622void
1624 Time delay,
1625 const std::vector<uint16_t>& txStaIds,
1626 WifiPhyState expectedStateAtEnd,
1627 const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta)
1628{
1629 static uint64_t uid = 0;
1630
1631 // AP sends an SU packet preceding HE TB PPDUs
1634 this,
1635 0,
1636 50,
1637 ++uid,
1638 0);
1639
1641
1642 // STAs send MU UL PPDUs addressed to AP
1643 uint16_t payloadSize = 1000;
1644 std::size_t index = 0;
1645 for (auto txStaId : txStaIds)
1646 {
1647 Simulator::Schedule(delay + (index * m_delayStart),
1649 this,
1650 txStaId,
1651 1,
1652 payloadSize,
1653 uid,
1654 0);
1655 payloadSize++;
1656 index++;
1657 }
1658
1659 // Verify it takes m_expectedPpduDuration to transmit the PPDUs
1662 this,
1663 m_phyAp,
1664 WifiPhyState::RX);
1666 (m_delayStart * expectedCountersPerSta.size()),
1668 this,
1669 m_phyAp,
1670 expectedStateAtEnd);
1671
1672 delay += MilliSeconds(100);
1673 // Check reception state from STAs
1674 uint16_t staId = 1;
1675 for (const auto& expectedCounters : expectedCountersPerSta)
1676 {
1677 uint16_t expectedSuccessFromSta = std::get<0>(expectedCounters);
1678 uint16_t expectedFailuresFromSta = std::get<1>(expectedCounters);
1679 uint16_t expectedBytesFromSta = std::get<2>(expectedCounters);
1680 Simulator::Schedule(delay + (m_delayStart * (staId - 1)),
1682 this,
1683 staId,
1684 expectedSuccessFromSta,
1685 expectedFailuresFromSta,
1686 expectedBytesFromSta);
1687 staId++;
1688 }
1689
1690 // Verify events data have been cleared
1692
1693 delay += MilliSeconds(100);
1695}
1696
1697void
1699{
1702 int64_t streamNumber = 0;
1703 m_phyAp->AssignStreams(streamNumber);
1704 for (auto& phy : m_phyStas)
1705 {
1706 phy->AssignStreams(streamNumber);
1707 }
1708
1709 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
1714 ->number;
1715
1718 for (auto& phy : m_phyStas)
1719 {
1720 phy->SetOperatingChannel(
1722 }
1723
1724 Time delay;
1726 delay += Seconds(1);
1727
1728 //---------------------------------------------------------------------------
1729 // Verify that all HE TB PPDUs using full BW MU-MIMO have been corrected received
1730 Simulator::Schedule(delay,
1732 this,
1733 "Reception of HE TB PPDUs using full BW MU-MIMO");
1734 ScheduleTest(delay,
1735 {1, 2, 3},
1736 WifiPhyState::IDLE,
1737 {
1738 std::make_tuple(1, 0, 1000), // One PSDU of 1000 bytes should have been
1739 // successfully received from STA 1
1740 std::make_tuple(1, 0, 1001), // One PSDU of 1001 bytes should have been
1741 // successfully received from STA 2
1742 std::make_tuple(1, 0, 1002) // One PSDU of 1002 bytes should have been
1743 // successfully received from STA 3
1744 });
1745 delay += Seconds(1);
1746
1747 //---------------------------------------------------------------------------
1748 // Send an HE SU PPDU during 400 ns window and verify that all HE TB PPDUs using full BW MU-MIMO
1749 // have been impacted
1750 Simulator::Schedule(delay,
1752 this,
1753 "Reception of HE TB PPDUs HE TB PPDUs using full BW MU-MIMO with an HE SU "
1754 "PPDU arriving during the 400 ns window");
1755 // One HE SU arrives at AP during the 400ns window
1756 Simulator::Schedule(delay + NanoSeconds(150),
1758 this,
1759 4,
1760 1002,
1761 2,
1762 0);
1763 ScheduleTest(delay,
1764 {1, 2, 3},
1765 WifiPhyState::IDLE,
1766 {
1767 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
1768 // failed (since interference from STA 4)
1769 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
1770 // failed (since interference from STA 4)
1771 std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
1772 // (since interference from STA 4)
1773 });
1774 delay += Seconds(1);
1775
1776 //---------------------------------------------------------------------------
1777 // Send an HE SU PPDU during HE portion reception and verify that all HE TB PPDUs have been
1778 // impacted
1779 Simulator::Schedule(delay,
1781 this,
1782 "Reception of HE TB PPDUs using full BW MU-MIMO with an HE SU PPDU "
1783 "arriving during the HE portion");
1784 // One HE SU arrives at AP during the HE portion
1787 this,
1788 4,
1789 1002,
1790 2,
1791 0);
1792 ScheduleTest(delay,
1793 {1, 2, 3},
1794 WifiPhyState::CCA_BUSY,
1795 {
1796 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
1797 // failed (since interference from STA 4)
1798 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
1799 // failed (since interference from STA 4)
1800 std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
1801 // (since interference from STA 4)
1802 });
1803 delay += Seconds(1);
1804
1806}
1807
1808void
1810{
1811 std::vector<Time> startDelays{NanoSeconds(0), NanoSeconds(100)};
1812
1813 for (const auto& delayStart : startDelays)
1814 {
1815 m_delayStart = delayStart;
1816
1817 m_frequency = MHz_u{5180};
1818 m_channelWidth = MHz_u{20};
1820 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1821 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1822 << m_delayStart);
1823 RunOne();
1824
1825 m_frequency = MHz_u{5190};
1826 m_channelWidth = MHz_u{40};
1828 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1829 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1830 << m_delayStart);
1831 RunOne();
1832
1833 m_frequency = MHz_u{5210};
1834 m_channelWidth = MHz_u{80};
1836 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1837 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1838 << m_delayStart);
1839 RunOne();
1840
1841 m_frequency = MHz_u{5250};
1842 m_channelWidth = MHz_u{160};
1844 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1845 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1846 << m_delayStart);
1847 RunOne();
1848 }
1849
1851}
1852
1853/**
1854 * @ingroup wifi-test
1855 * @ingroup tests
1856 *
1857 * @brief wifi PHY MU-MIMO Test Suite
1858 */
1860{
1861 public:
1863};
1864
1866 : TestSuite("wifi-phy-mu-mimo", Type::UNIT)
1867{
1868 AddTestCase(new TestDlMuTxVector, TestCase::Duration::QUICK);
1869 AddTestCase(new TestDlMuMimoPhyTransmission, TestCase::Duration::QUICK);
1870 AddTestCase(new TestUlMuMimoPhyTransmission, TestCase::Duration::QUICK);
1871}
1872
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:566
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:262
RU Specification.
Definition he-ru.h:37
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
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:679
void SetErrorRateModel(const Ptr< ErrorRateModel > model)
Sets the error rate model.
Definition wifi-phy.cc:688
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:485
virtual void ConfigureStandard(WifiStandard standard)
Configure the PHY-level parameters for different Wi-Fi standard.
Definition wifi-phy.cc:1010
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1588
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:1070
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:761
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:1136
void SetReceiveOkCallback(RxOkCallback callback)
Definition wifi-phy.cc:479
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:2364
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.
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: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:78
double snr
SNR in linear scale.
Definition wifi-types.h:79
constexpr MHz_u DEFAULT_CHANNEL_WIDTH
constexpr MHz_u DEFAULT_FREQUENCY
static WifiPhyMuMimoTestSuite WifiPhyMuMimoTestSuite
the test suite