A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-phy-mu-mimo-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 DERONNE SOFTWARE ENGINEERING
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
7 */
8
9#include "ns3/ap-wifi-mac.h"
10#include "ns3/boolean.h"
11#include "ns3/double.h"
12#include "ns3/he-configuration.h"
13#include "ns3/he-phy.h"
14#include "ns3/interference-helper.h"
15#include "ns3/log.h"
16#include "ns3/multi-model-spectrum-channel.h"
17#include "ns3/nist-error-rate-model.h"
18#include "ns3/node.h"
19#include "ns3/pointer.h"
20#include "ns3/rng-seed-manager.h"
21#include "ns3/simulator.h"
22#include "ns3/spectrum-wifi-helper.h"
23#include "ns3/spectrum-wifi-phy.h"
24#include "ns3/string.h"
25#include "ns3/test.h"
26#include "ns3/txop.h"
27#include "ns3/uinteger.h"
28#include "ns3/wifi-mac-header.h"
29#include "ns3/wifi-net-device.h"
30#include "ns3/wifi-psdu.h"
31#include "ns3/wifi-spectrum-value-helper.h"
32#include "ns3/wifi-utils.h"
33
34#include <list>
35#include <tuple>
36
37using namespace ns3;
38
39NS_LOG_COMPONENT_DEFINE("WifiPhyMuMimoTest");
40
41constexpr MHz_u DEFAULT_FREQUENCY = 5180;
43
44/**
45 * \ingroup wifi-test
46 * \ingroup tests
47 *
48 * \brief DL MU TX-VECTOR test
49 */
51{
52 public:
54
55 private:
56 void DoRun() override;
57
58 /**
59 * Build a TXVECTOR for DL MU with the given bandwidth and user information.
60 *
61 * \param bw the channel width of the PPDU
62 * \param userInfos the list of HE MU specific user transmission parameters
63 *
64 * \return the configured MU TXVECTOR
65 */
66 static WifiTxVector BuildTxVector(MHz_u bw, const std::list<HeMuUserInfo>& userInfos);
67};
68
70 : TestCase("Check for valid combinations of MU TX-VECTOR")
71{
72}
73
75TestDlMuTxVector::BuildTxVector(MHz_u bw, const std::list<HeMuUserInfo>& userInfos)
76{
77 WifiTxVector txVector;
79 txVector.SetChannelWidth(bw);
80 std::list<uint16_t> staIds;
81 uint16_t staId = 1;
82 for (const auto& userInfo : userInfos)
83 {
84 txVector.SetHeMuUserInfo(staId, userInfo);
85 staIds.push_back(staId++);
86 }
87 return txVector;
88}
89
90void
92{
93 // Verify TxVector is OFDMA
94 std::list<HeMuUserInfo> userInfos;
95 userInfos.push_back({{HeRu::RU_106_TONE, 1, true}, 11, 1});
96 userInfos.push_back({{HeRu::RU_106_TONE, 2, true}, 10, 2});
97 WifiTxVector txVector = BuildTxVector(20, userInfos);
99 true,
100 "TX-VECTOR should indicate an OFDMA transmission");
102 false,
103 "TX-VECTOR should not indicate a MU-MIMO transmission");
105 false,
106 "TX-VECTOR should not indicate a SIG-B compression");
108 true,
109 "TX-VECTOR should indicate all checks are passed");
110 userInfos.clear();
111
112 // Verify TxVector is a full BW MU-MIMO
113 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 1});
114 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 2});
115 txVector = BuildTxVector(20, userInfos);
117 false,
118 "TX-VECTOR should indicate a MU-MIMO transmission");
120 true,
121 "TX-VECTOR should not indicate an OFDMA transmission");
123 true,
124 "TX-VECTOR should indicate a SIG-B compression");
126 true,
127 "TX-VECTOR should indicate all checks are passed");
128 userInfos.clear();
129
130 // Verify TxVector is not valid if there are more than 8 STAs using the same RU
131 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 1});
132 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 1});
133 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 9, 1});
134 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 8, 1});
135 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 7, 1});
136 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 6, 1});
137 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 5, 1});
138 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 4, 1});
139 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 3, 1});
140 txVector = BuildTxVector(20, userInfos);
142 false,
143 "TX-VECTOR should indicate a MU-MIMO transmission");
145 true,
146 "TX-VECTOR should not indicate an OFDMA transmission");
148 true,
149 "TX-VECTOR should indicate a SIG-B compression");
151 false,
152 "TX-VECTOR should not indicate all checks are passed");
153
154 // Verify TxVector is not valid if the total number of antennas in a full BW MU-MIMO is above 8
155 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 2});
156 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 2});
157 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 9, 3});
158 userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 8, 3});
159 txVector = BuildTxVector(20, userInfos);
161 false,
162 "TX-VECTOR should indicate a MU-MIMO transmission");
164 true,
165 "TX-VECTOR should not indicate an OFDMA transmission");
167 true,
168 "TX-VECTOR should indicate a SIG-B compression");
170 false,
171 "TX-VECTOR should not indicate all checks are passed");
172}
173
174/**
175 * HE PHY slightly modified so as to return a given
176 * STA-ID in case of DL MU for MuMimoSpectrumWifiPhy.
177 */
178class MuMimoTestHePhy : public HePhy
179{
180 public:
181 /**
182 * Constructor
183 *
184 * \param staId the ID of the STA to which this PHY belongs to
185 */
186 MuMimoTestHePhy(uint16_t staId);
187
188 /**
189 * Return the STA ID that has been assigned to the station this PHY belongs to.
190 * This is typically called for MU PPDUs, in order to pick the correct PSDU.
191 *
192 * \param ppdu the PPDU for which the STA ID is requested
193 * \return the STA ID
194 */
195 uint16_t GetStaId(const Ptr<const WifiPpdu> ppdu) const override;
196
197 /**
198 * Set the global PPDU UID counter.
199 *
200 * \param uid the value to which the global PPDU UID counter should be set
201 */
202 void SetGlobalPpduUid(uint64_t uid);
203
204 private:
205 uint16_t m_staId; ///< ID of the STA to which this PHY belongs to
206}; // class MuMimoTestHePhy
207
209 : HePhy(),
210 m_staId(staId)
211{
212}
213
214uint16_t
216{
217 if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
218 {
219 return m_staId;
220 }
221 return HePhy::GetStaId(ppdu);
222}
223
224void
226{
227 m_globalPpduUid = uid;
228}
229
230/**
231 * SpectrumWifiPhy used for testing MU-MIMO.
232 */
234{
235 public:
236 /**
237 * \brief Get the type ID.
238 * \return the object TypeId
239 */
240 static TypeId GetTypeId();
241 /**
242 * Constructor
243 *
244 * \param staId the ID of the STA to which this PHY belongs to
245 */
246 MuMimoSpectrumWifiPhy(uint16_t staId);
247 ~MuMimoSpectrumWifiPhy() override;
248
249 /**
250 * Set the global PPDU UID counter.
251 *
252 * \param uid the value to which the global PPDU UID counter should be set
253 */
254 void SetPpduUid(uint64_t uid);
255
256 /**
257 * Since we assume trigger frame was previously received from AP, this is used to set its UID
258 *
259 * \param uid the PPDU UID of the trigger frame
260 */
261 void SetTriggerFrameUid(uint64_t uid);
262
263 /**
264 * \return the current event
265 */
267
268 private:
269 void DoInitialize() override;
270 void DoDispose() override;
271
272 Ptr<MuMimoTestHePhy> m_ofdmTestHePhy; ///< Pointer to HE PHY instance used for MU-MIMO test
273}; // class MuMimoSpectrumWifiPhy
274
275TypeId
277{
278 static TypeId tid =
279 TypeId("ns3::MuMimoSpectrumWifiPhy").SetParent<SpectrumWifiPhy>().SetGroupName("Wifi");
280 return tid;
281}
282
289
293
294void
296{
297 // Replace HE PHY instance with test instance
300}
301
302void
308
309void
315
316void
321
327
328/**
329 * \ingroup wifi-test
330 * \ingroup tests
331 *
332 * \brief DL MU-MIMO PHY test
333 */
335{
336 public:
338
339 private:
340 void DoSetup() override;
341 void DoTeardown() override;
342 void DoRun() override;
343
344 /**
345 * Receive success function for STA 1
346 * \param psdu the PSDU
347 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
348 * \param txVector the transmit vector
349 * \param statusPerMpdu reception status per MPDU
350 */
352 RxSignalInfo rxSignalInfo,
353 WifiTxVector txVector,
354 std::vector<bool> statusPerMpdu);
355 /**
356 * Receive success function for STA 2
357 * \param psdu the PSDU
358 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
359 * \param txVector the transmit vector
360 * \param statusPerMpdu reception status per MPDU
361 */
363 RxSignalInfo rxSignalInfo,
364 WifiTxVector txVector,
365 std::vector<bool> statusPerMpdu);
366 /**
367 * Receive success function for STA 3
368 * \param psdu the PSDU
369 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
370 * \param txVector the transmit vector
371 * \param statusPerMpdu reception status per MPDU
372 */
374 RxSignalInfo rxSignalInfo,
375 WifiTxVector txVector,
376 std::vector<bool> statusPerMpdu);
377
378 /**
379 * Receive failure function for STA 1
380 * \param psdu the PSDU
381 */
383 /**
384 * Receive failure function for STA 2
385 * \param psdu the PSDU
386 */
388 /**
389 * Receive failure function for STA 3
390 * \param psdu the PSDU
391 */
393
394 /**
395 * Check the results for STA 1
396 * \param expectedRxSuccess the expected number of RX success
397 * \param expectedRxFailure the expected number of RX failures
398 * \param expectedRxBytes the expected number of RX bytes
399 */
400 void CheckResultsSta1(uint32_t expectedRxSuccess,
401 uint32_t expectedRxFailure,
402 uint32_t expectedRxBytes);
403 /**
404 * Check the results for STA 2
405 * \param expectedRxSuccess the expected number of RX success
406 * \param expectedRxFailure the expected number of RX failures
407 * \param expectedRxBytes the expected number of RX bytes
408 */
409 void CheckResultsSta2(uint32_t expectedRxSuccess,
410 uint32_t expectedRxFailure,
411 uint32_t expectedRxBytes);
412 /**
413 * Check the results for STA 3
414 * \param expectedRxSuccess the expected number of RX success
415 * \param expectedRxFailure the expected number of RX failures
416 * \param expectedRxBytes the expected number of RX bytes
417 */
418 void CheckResultsSta3(uint32_t expectedRxSuccess,
419 uint32_t expectedRxFailure,
420 uint32_t expectedRxBytes);
421
422 /**
423 * Reset the results
424 */
425 void ResetResults();
426
427 /**
428 * STA info
429 */
430 struct StaInfo
431 {
432 uint16_t staId; //!< STA ID
433 uint8_t staNss; //!< Number of spatial streams used for the STA
434 };
435
436 /**
437 * Send DL MU-MIMO PPDU function
438 * \param staInfos the STAs infos
439 */
440 void SendMuPpdu(const std::vector<StaInfo>& staInfos);
441
442 /**
443 * Generate interference function
444 * \param interferencePsd the PSD of the interference to be generated
445 * \param duration the duration of the interference
446 */
447 void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
448 /**
449 * Stop interference function
450 */
452
453 /**
454 * Run one function
455 */
456 void RunOne();
457
458 /**
459 * Schedule now to check the PHY state
460 * \param phy the PHY
461 * \param expectedState the expected state of the PHY
462 */
464 /**
465 * Check the PHY state now
466 * \param phy the PHY
467 * \param expectedState the expected state of the PHY
468 */
470
471 uint32_t m_countRxSuccessSta1; ///< count RX success for STA 1
472 uint32_t m_countRxSuccessSta2; ///< count RX success for STA 2
473 uint32_t m_countRxSuccessSta3; ///< count RX success for STA 3
474 uint32_t m_countRxFailureSta1; ///< count RX failure for STA 1
475 uint32_t m_countRxFailureSta2; ///< count RX failure for STA 2
476 uint32_t m_countRxFailureSta3; ///< count RX failure for STA 3
477 uint32_t m_countRxBytesSta1; ///< count RX bytes for STA 1
478 uint32_t m_countRxBytesSta2; ///< count RX bytes for STA 2
479 uint32_t m_countRxBytesSta3; ///< count RX bytes for STA 3
480
485
486 uint8_t m_nss; ///< number of spatial streams per STA
487 MHz_u m_frequency; ///< frequency
488 MHz_u m_channelWidth; ///< channel width
489 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
490};
491
493 : TestCase("DL MU-MIMO PHY test"),
494 m_countRxSuccessSta1{0},
495 m_countRxSuccessSta2{0},
496 m_countRxSuccessSta3{0},
497 m_countRxFailureSta1{0},
498 m_countRxFailureSta2{0},
499 m_countRxFailureSta3{0},
500 m_countRxBytesSta1{0},
501 m_countRxBytesSta2{0},
502 m_countRxBytesSta3{0},
503 m_nss{1},
504 m_frequency{DEFAULT_FREQUENCY},
505 m_channelWidth{DEFAULT_CHANNEL_WIDTH},
506 m_expectedPpduDuration{NanoSeconds(306400)}
507{
508}
509
510void
523
524void
525TestDlMuMimoPhyTransmission::SendMuPpdu(const std::vector<StaInfo>& staInfos)
526{
527 NS_LOG_FUNCTION(this << staInfos.size());
528 NS_ASSERT(staInfos.size() > 1);
529
531 0,
533 NanoSeconds(800),
534 1,
535 1,
536 0,
538 false,
539 false);
540
541 WifiConstPsduMap psdus;
542 HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
543 for (const auto& staInfo : staInfos)
544 {
545 txVector.SetRu(ru, staInfo.staId);
546 txVector.SetMode(HePhy::GetHeMcs7(), staInfo.staId);
547 txVector.SetNss(staInfo.staNss, staInfo.staId);
548
549 Ptr<Packet> pkt = Create<Packet>(1000 + (8 * staInfo.staId));
550 WifiMacHeader hdr;
552 hdr.SetQosTid(0);
553 std::ostringstream addr;
554 addr << "00:00:00:00:00:0" << staInfo.staId;
555 hdr.SetAddr1(Mac48Address(addr.str().c_str()));
556 hdr.SetSequenceNumber(1 + staInfo.staId);
557 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
558 psdus.insert(std::make_pair(staInfo.staId, psdu));
559 }
560
562
563 NS_ASSERT(txVector.IsDlMuMimo());
564 NS_ASSERT(!txVector.IsDlOfdma());
565
566 m_phyAp->Send(psdus, txVector);
567}
568
569void
571 RxSignalInfo rxSignalInfo,
572 WifiTxVector txVector,
573 std::vector<bool> /*statusPerMpdu*/)
574{
575 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
577 m_countRxBytesSta1 += (psdu->GetSize() - 30);
578}
579
580void
582 RxSignalInfo rxSignalInfo,
583 WifiTxVector txVector,
584 std::vector<bool> /*statusPerMpdu*/)
585{
586 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
588 m_countRxBytesSta2 += (psdu->GetSize() - 30);
589}
590
591void
593 RxSignalInfo rxSignalInfo,
594 WifiTxVector txVector,
595 std::vector<bool> /*statusPerMpdu*/)
596{
597 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
599 m_countRxBytesSta3 += (psdu->GetSize() - 30);
600}
601
602void
608
609void
615
616void
622
623void
625 uint32_t expectedRxFailure,
626 uint32_t expectedRxBytes)
627{
629 expectedRxSuccess,
630 "The number of successfully received packets by STA 1 is not correct!");
632 expectedRxFailure,
633 "The number of unsuccessfully received packets by STA 1 is not correct!");
635 expectedRxBytes,
636 "The number of bytes received by STA 1 is not correct!");
637}
638
639void
641 uint32_t expectedRxFailure,
642 uint32_t expectedRxBytes)
643{
645 expectedRxSuccess,
646 "The number of successfully received packets by STA 2 is not correct!");
648 expectedRxFailure,
649 "The number of unsuccessfully received packets by STA 2 is not correct!");
651 expectedRxBytes,
652 "The number of bytes received by STA 2 is not correct!");
653}
654
655void
657 uint32_t expectedRxFailure,
658 uint32_t expectedRxBytes)
659{
661 expectedRxSuccess,
662 "The number of successfully received packets by STA 3 is not correct!");
664 expectedRxFailure,
665 "The number of unsuccessfully received packets by STA 3 is not correct!");
667 expectedRxBytes,
668 "The number of bytes received by STA 3 is not correct!");
669}
670
671void
673 WifiPhyState expectedState)
674{
675 // This is needed to make sure PHY state will be checked as the last event if a state change
676 // occurred at the exact same time as the check
678}
679
680void
682 WifiPhyState expectedState)
683{
684 WifiPhyState currentState;
685 PointerValue ptr;
686 phy->GetAttribute("State", ptr);
688 currentState = state->GetState();
689 NS_LOG_FUNCTION(this << currentState << expectedState);
690 NS_TEST_ASSERT_MSG_EQ(currentState,
691 expectedState,
692 "PHY State " << currentState << " does not match expected state "
693 << expectedState << " at " << Simulator::Now());
694}
695
696void
698{
702 spectrumChannel->SetPropagationDelayModel(delayModel);
703
704 Ptr<Node> apNode = CreateObject<Node>();
708 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
710 m_phyAp->SetErrorRateModel(apErrorModel);
711 m_phyAp->SetDevice(apDev);
712 m_phyAp->AddChannel(spectrumChannel);
713 m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
714 apDev->SetPhy(m_phyAp);
715 apNode->AddDevice(apDev);
716
717 Ptr<Node> sta1Node = CreateObject<Node>();
721 m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
723 m_phySta1->SetErrorRateModel(sta1ErrorModel);
724 m_phySta1->SetDevice(sta1Dev);
725 m_phySta1->AddChannel(spectrumChannel);
731 sta1Dev->SetPhy(m_phySta1);
732 sta1Node->AddDevice(sta1Dev);
733
734 Ptr<Node> sta2Node = CreateObject<Node>();
738 m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
740 m_phySta2->SetErrorRateModel(sta2ErrorModel);
741 m_phySta2->SetDevice(sta2Dev);
742 m_phySta2->AddChannel(spectrumChannel);
748 sta2Dev->SetPhy(m_phySta2);
749 sta2Node->AddDevice(sta2Dev);
750
751 Ptr<Node> sta3Node = CreateObject<Node>();
755 m_phySta3->SetInterferenceHelper(sta3InterferenceHelper);
757 m_phySta3->SetErrorRateModel(sta3ErrorModel);
758 m_phySta3->SetDevice(sta3Dev);
759 m_phySta3->AddChannel(spectrumChannel);
765 sta3Dev->SetPhy(m_phySta3);
766 sta3Node->AddDevice(sta3Dev);
767}
768
769void
771{
772 m_phyAp->Dispose();
773 m_phyAp = nullptr;
775 m_phySta1 = nullptr;
777 m_phySta2 = nullptr;
779 m_phySta3 = nullptr;
780}
781
782void
784{
787 int64_t streamNumber = 0;
788 m_phyAp->AssignStreams(streamNumber);
789 m_phySta1->AssignStreams(streamNumber);
790 m_phySta2->AssignStreams(streamNumber);
791
792 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
797 ->number;
798
799 m_phyAp->SetOperatingChannel(
807
808 m_phyAp->SetNumberOfAntennas(8);
809 m_phyAp->SetMaxSupportedTxSpatialStreams(8);
810
811 //----------------------------------------------------------------------------------------------------
812 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2:
813 // STA 1 and STA 2 should receive their PSDUs, whereas STA 3 should not receive any PSDU
814 // but should keep its PHY busy during all PPDU duration.
817 this,
818 std::vector<StaInfo>{{1, m_nss}, {2, m_nss}});
819
820 // Since it takes m_expectedPpduDuration to transmit the PPDU,
821 // all 3 PHYs should be back to IDLE at the same time,
822 // even the PHY that has no PSDU addressed to it.
825 this,
826 m_phySta1,
827 WifiPhyState::RX);
830 this,
831 m_phySta2,
832 WifiPhyState::RX);
835 this,
836 m_phySta3,
837 WifiPhyState::CCA_BUSY);
840 this,
841 m_phySta1,
842 WifiPhyState::IDLE);
845 this,
846 m_phySta2,
847 WifiPhyState::IDLE);
850 this,
851 m_phySta3,
852 WifiPhyState::IDLE);
853
854 // One PSDU of 1008 bytes should have been successfully received by STA 1
857 this,
858 1,
859 0,
860 1008);
861 // One PSDU of 1016 bytes should have been successfully received by STA 2
864 this,
865 1,
866 0,
867 1016);
868 // No PSDU should have been received by STA 3
871 this,
872 0,
873 0,
874 0);
875
877
878 //----------------------------------------------------------------------------------------------------
879 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 3:
880 // STA 1 and STA 3 should receive their PSDUs, whereas STA 2 should not receive any PSDU
881 // but should keep its PHY busy during all PPDU duration.
884 this,
885 std::vector<StaInfo>{{1, m_nss}, {3, m_nss}});
886
887 // Since it takes m_expectedPpduDuration to transmit the PPDU,
888 // all 3 PHYs should be back to IDLE at the same time,
889 // even the PHY that has no PSDU addressed to it.
892 this,
893 m_phySta1,
894 WifiPhyState::RX);
897 this,
898 m_phySta2,
899 WifiPhyState::CCA_BUSY);
902 this,
903 m_phySta3,
904 WifiPhyState::RX);
907 this,
908 m_phySta1,
909 WifiPhyState::IDLE);
912 this,
913 m_phySta2,
914 WifiPhyState::IDLE);
917 this,
918 m_phySta3,
919 WifiPhyState::IDLE);
920
921 // One PSDU of 1008 bytes should have been successfully received by STA 1
924 this,
925 1,
926 0,
927 1008);
928 // No PSDU should have been received by STA 2
931 this,
932 0,
933 0,
934 0);
935 // One PSDU of 1024 bytes should have been successfully received by STA 3
938 this,
939 1,
940 0,
941 1024);
942
944
945 //----------------------------------------------------------------------------------------------------
946 // Send MU PPDU with two PSDUs addressed to STA 2 and STA 3:
947 // STA 2 and STA 3 should receive their PSDUs, whereas STA 1 should not receive any PSDU
948 // but should keep its PHY busy during all PPDU duration.
951 this,
952 std::vector<StaInfo>{{2, m_nss}, {3, m_nss}});
953
954 // Since it takes m_expectedPpduDuration to transmit the PPDU,
955 // all 3 PHYs should be back to IDLE at the same time,
956 // even the PHY that has no PSDU addressed to it.
959 this,
960 m_phySta1,
961 WifiPhyState::CCA_BUSY);
964 this,
965 m_phySta2,
966 WifiPhyState::RX);
969 this,
970 m_phySta3,
971 WifiPhyState::RX);
974 this,
975 m_phySta1,
976 WifiPhyState::IDLE);
979 this,
980 m_phySta2,
981 WifiPhyState::IDLE);
984 this,
985 m_phySta3,
986 WifiPhyState::IDLE);
987
988 // No PSDU should have been received by STA 1
991 this,
992 0,
993 0,
994 0);
995 // One PSDU of 1016 bytes should have been successfully received by STA 2
998 this,
999 1,
1000 0,
1001 1016);
1002 // One PSDU of 1024 bytes should have been successfully received by STA 3
1005 this,
1006 1,
1007 0,
1008 1024);
1009
1011
1012 //----------------------------------------------------------------------------------------------------
1013 // Send MU PPDU with three PSDUs addressed to STA 1, STA 2 and STA 3:
1014 // All STAs should receive their PSDUs.
1017 this,
1018 std::vector<StaInfo>{{1, m_nss}, {2, m_nss}, {3, m_nss}});
1019
1020 // Since it takes m_expectedPpduDuration to transmit the PPDU,
1021 // all 3 PHYs should be back to IDLE at the same time.
1024 this,
1025 m_phySta1,
1026 WifiPhyState::RX);
1029 this,
1030 m_phySta2,
1031 WifiPhyState::RX);
1034 this,
1035 m_phySta3,
1036 WifiPhyState::RX);
1039 this,
1040 m_phySta1,
1041 WifiPhyState::IDLE);
1044 this,
1045 m_phySta2,
1046 WifiPhyState::IDLE);
1049 this,
1050 m_phySta3,
1051 WifiPhyState::IDLE);
1052
1053 // One PSDU of 1008 bytes should have been successfully received by STA 1
1056 this,
1057 1,
1058 0,
1059 1008);
1060 // One PSDU of 1016 bytes should have been successfully received by STA 2
1063 this,
1064 1,
1065 0,
1066 1016);
1067 // One PSDU of 1024 bytes should have been successfully received by STA 3
1070 this,
1071 1,
1072 0,
1073 1024);
1074
1076
1078}
1079
1080void
1082{
1083 std::vector<uint8_t> nssToTest{1, 2};
1084 for (auto nss : nssToTest)
1085 {
1086 m_nss = nss;
1087 m_frequency = 5180;
1088 m_channelWidth = 20;
1089 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(110400) : NanoSeconds(156800);
1090 RunOne();
1091
1092 m_frequency = 5190;
1093 m_channelWidth = 40;
1094 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(83200) : NanoSeconds(102400);
1095 RunOne();
1096
1097 m_frequency = 5210;
1098 m_channelWidth = 80;
1099 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(75200);
1100 RunOne();
1101
1102 m_frequency = 5250;
1103 m_channelWidth = 160;
1104 m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(61600);
1105 RunOne();
1106 }
1107 // FIXME: test also different nss over STAs once RX durations when receiving different PPDUs
1108 // with different nss over STAs are fixed
1109
1111}
1112
1113/**
1114 * \ingroup wifi-test
1115 * \ingroup tests
1116 *
1117 * \brief UL MU-MIMO PHY test
1118 */
1120{
1121 public:
1123
1124 private:
1125 void DoSetup() override;
1126 void DoTeardown() override;
1127 void DoRun() override;
1128
1129 /**
1130 * Get TXVECTOR for HE TB PPDU.
1131 * \param txStaId the ID of the TX STA
1132 * \param nss the number of spatial streams used for the transmission
1133 * \param bssColor the BSS color of the TX STA
1134 * \return the TXVECTOR for HE TB PPDU
1135 */
1136 WifiTxVector GetTxVectorForHeTbPpdu(uint16_t txStaId, uint8_t nss, uint8_t bssColor) const;
1137 /**
1138 * Set TRIGVECTOR for HE TB PPDU
1139 *
1140 * \param staIds the IDs of the STAs sollicited for the HE TB transmission
1141 * \param bssColor the BSS color of the TX STA
1142 */
1143 void SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor);
1144 /**
1145 * Send HE TB PPDU function
1146 * \param txStaId the ID of the TX STA
1147 * \param nss the number of spatial streams used for the transmission
1148 * \param payloadSize the size of the payload in bytes
1149 * \param uid the UID of the trigger frame that is initiating this transmission
1150 * \param bssColor the BSS color of the TX STA
1151 */
1152 void SendHeTbPpdu(uint16_t txStaId,
1153 uint8_t nss,
1154 std::size_t payloadSize,
1155 uint64_t uid,
1156 uint8_t bssColor);
1157
1158 /**
1159 * Send HE SU PPDU function
1160 * \param txStaId the ID of the TX STA
1161 * \param payloadSize the size of the payload in bytes
1162 * \param uid the UID of the trigger frame that is initiating this transmission
1163 * \param bssColor the BSS color of the TX STA
1164 */
1165 void SendHeSuPpdu(uint16_t txStaId, std::size_t payloadSize, uint64_t uid, uint8_t bssColor);
1166
1167 /**
1168 * Set the BSS color
1169 * \param phy the PHY
1170 * \param bssColor the BSS color
1171 */
1172 void SetBssColor(Ptr<WifiPhy> phy, uint8_t bssColor);
1173
1174 /**
1175 * Run one function
1176 */
1177 void RunOne();
1178
1179 /**
1180 * Check the received PSDUs from a given STA
1181 * \param staId the ID of the STA to check
1182 * \param expectedSuccess the expected number of success
1183 * \param expectedFailures the expected number of failures
1184 * \param expectedBytes the expected number of bytes
1185 */
1186 void CheckRxFromSta(uint16_t staId,
1187 uint32_t expectedSuccess,
1188 uint32_t expectedFailures,
1189 uint32_t expectedBytes);
1190
1191 /**
1192 * Verify all events are cleared at end of TX or RX
1193 */
1194 void VerifyEventsCleared();
1195
1196 /**
1197 * Check the PHY state
1198 * \param phy the PHY
1199 * \param expectedState the expected state of the PHY
1200 */
1201 void CheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy, WifiPhyState expectedState);
1202 /// \copydoc CheckPhyState
1204
1205 /**
1206 * Reset function
1207 */
1208 void Reset();
1209
1210 /**
1211 * Receive success function
1212 * \param psdu the PSDU
1213 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
1214 * \param txVector the transmit vector
1215 * \param statusPerMpdu reception status per MPDU
1216 */
1218 RxSignalInfo rxSignalInfo,
1219 WifiTxVector txVector,
1220 std::vector<bool> statusPerMpdu);
1221
1222 /**
1223 * Receive failure function
1224 * \param psdu the PSDU
1225 */
1226 void RxFailure(Ptr<const WifiPsdu> psdu);
1227
1228 /**
1229 * Schedule test to perform.
1230 * The interference generation should be scheduled apart.
1231 *
1232 * \param delay the reference delay to schedule the events
1233 * \param txStaIds the IDs of the STAs planned to transmit an HE TB PPDU
1234 * \param expectedStateAtEnd the expected state of the PHY at the end of the reception
1235 * \param expectedCountersPerSta the expected counters per STA
1236 */
1237 void ScheduleTest(
1238 Time delay,
1239 const std::vector<uint16_t>& txStaIds,
1240 WifiPhyState expectedStateAtEnd,
1241 const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta);
1242
1243 /**
1244 * Log scenario description
1245 *
1246 * \param log the scenario description to add to log
1247 */
1248 void LogScenario(const std::string& log) const;
1249
1251 std::vector<Ptr<MuMimoSpectrumWifiPhy>> m_phyStas; ///< PHYs of STAs
1252
1253 std::vector<uint32_t> m_countRxSuccessFromStas; ///< count RX success from STAs
1254 std::vector<uint32_t> m_countRxFailureFromStas; ///< count RX failure from STAs
1255 std::vector<uint32_t> m_countRxBytesFromStas; ///< count RX bytes from STAs
1256
1257 Time m_delayStart; ///< delay between the start of each HE TB PPDUs
1258 MHz_u m_frequency; ///< frequency
1259 MHz_u m_channelWidth; ///< channel width
1260 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
1261};
1262
1264 : TestCase("UL MU-MIMO PHY test"),
1265 m_countRxSuccessFromStas{},
1266 m_countRxFailureFromStas{},
1267 m_countRxBytesFromStas{},
1268 m_delayStart{Seconds(0)},
1269 m_frequency{DEFAULT_FREQUENCY},
1270 m_channelWidth{DEFAULT_CHANNEL_WIDTH},
1271 m_expectedPpduDuration{NanoSeconds(271200)}
1272{
1273}
1274
1275void
1277 std::size_t payloadSize,
1278 uint64_t uid,
1279 uint8_t bssColor)
1280{
1281 NS_LOG_FUNCTION(this << txStaId << payloadSize << uid << +bssColor);
1282 WifiConstPsduMap psdus;
1283
1285 0,
1287 NanoSeconds(800),
1288 1,
1289 1,
1290 0,
1292 false,
1293 false,
1294 false,
1295 bssColor);
1296
1297 Ptr<Packet> pkt = Create<Packet>(payloadSize);
1298 WifiMacHeader hdr;
1300 hdr.SetQosTid(0);
1301 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
1302 std::ostringstream addr;
1303 addr << "00:00:00:00:00:0" << txStaId;
1304 hdr.SetAddr2(Mac48Address(addr.str().c_str()));
1305 hdr.SetSequenceNumber(1);
1306 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1307 psdus.insert(std::make_pair(SU_STA_ID, psdu));
1308
1309 Ptr<MuMimoSpectrumWifiPhy> phy = (txStaId == 0) ? m_phyAp : m_phyStas.at(txStaId - 1);
1310 phy->SetPpduUid(uid);
1311 phy->Send(psdus, txVector);
1312}
1313
1316 uint8_t nss,
1317 uint8_t bssColor) const
1318{
1320 0,
1322 NanoSeconds(1600),
1323 1,
1324 nss,
1325 0,
1327 false,
1328 false,
1329 false,
1330 bssColor);
1331
1332 HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
1333 txVector.SetRu(ru, txStaId);
1334 txVector.SetMode(HePhy::GetHeMcs7(), txStaId);
1335 txVector.SetNss(nss, txStaId);
1336
1337 return txVector;
1338}
1339
1340void
1341TestUlMuMimoPhyTransmission::SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor)
1342{
1343 WifiTxVector txVector(HePhy::GetHeMcs7(),
1344 0,
1346 NanoSeconds(1600),
1347 1,
1348 1,
1349 0,
1351 false,
1352 false,
1353 false,
1354 bssColor);
1355
1356 HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
1357 for (auto staId : staIds)
1358 {
1359 txVector.SetRu(ru, staId);
1360 txVector.SetMode(HePhy::GetHeMcs7(), staId);
1361 txVector.SetNss(1, staId);
1362 }
1363
1364 uint16_t length;
1365 std::tie(length, m_expectedPpduDuration) =
1367 txVector,
1368 m_phyAp->GetPhyBand());
1369 txVector.SetLength(length);
1371 hePhyAp->SetTrigVector(txVector, m_expectedPpduDuration);
1372}
1373
1374void
1376 uint8_t nss,
1377 std::size_t payloadSize,
1378 uint64_t uid,
1379 uint8_t bssColor)
1380{
1381 NS_LOG_FUNCTION(this << txStaId << +nss << payloadSize << uid << +bssColor);
1382 WifiConstPsduMap psdus;
1383
1384 WifiTxVector txVector = GetTxVectorForHeTbPpdu(txStaId, nss, bssColor);
1385 Ptr<Packet> pkt = Create<Packet>(payloadSize);
1386 WifiMacHeader hdr;
1388 hdr.SetQosTid(0);
1389 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
1390 std::ostringstream addr;
1391 addr << "00:00:00:00:00:0" << txStaId;
1392 hdr.SetAddr2(Mac48Address(addr.str().c_str()));
1393 hdr.SetSequenceNumber(1);
1394 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1395 psdus.insert(std::make_pair(txStaId, psdu));
1396
1397 Ptr<MuMimoSpectrumWifiPhy> phy = m_phyStas.at(txStaId - 1);
1398 Time txDuration =
1399 phy->CalculateTxDuration(psdu->GetSize(), txVector, phy->GetPhyBand(), txStaId);
1400 txVector.SetLength(
1401 HePhy::ConvertHeTbPpduDurationToLSigLength(txDuration, txVector, phy->GetPhyBand()).first);
1402
1403 phy->SetPpduUid(uid);
1404 phy->Send(psdus, txVector);
1405}
1406
1407void
1409 RxSignalInfo rxSignalInfo,
1410 WifiTxVector txVector,
1411 std::vector<bool> /*statusPerMpdu*/)
1412{
1413 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2() << RatioToDb(rxSignalInfo.snr) << txVector);
1414 NS_TEST_ASSERT_MSG_EQ((RatioToDb(rxSignalInfo.snr) > dB_u{0.0}), true, "Incorrect SNR value");
1415 for (std::size_t index = 0; index < m_countRxSuccessFromStas.size(); ++index)
1416 {
1417 std::ostringstream addr;
1418 addr << "00:00:00:00:00:0" << index + 1;
1419 if (psdu->GetAddr2() == Mac48Address(addr.str().c_str()))
1420 {
1421 m_countRxSuccessFromStas.at(index)++;
1422 m_countRxBytesFromStas.at(index) += (psdu->GetSize() - 30);
1423 break;
1424 }
1425 }
1426}
1427
1428void
1430{
1431 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2());
1432 for (std::size_t index = 0; index < m_countRxFailureFromStas.size(); ++index)
1433 {
1434 std::ostringstream addr;
1435 addr << "00:00:00:00:00:0" << index + 1;
1436 if (psdu->GetAddr2() == Mac48Address(addr.str().c_str()))
1437 {
1438 m_countRxFailureFromStas.at(index)++;
1439 break;
1440 }
1441 }
1442}
1443
1444void
1446 uint32_t expectedSuccess,
1447 uint32_t expectedFailures,
1448 uint32_t expectedBytes)
1449{
1450 NS_LOG_FUNCTION(this << staId << expectedSuccess << expectedFailures << expectedBytes);
1452 expectedSuccess,
1453 "The number of successfully received packets from STA "
1454 << staId << " is not correct!");
1456 expectedFailures,
1457 "The number of unsuccessfully received packets from STA "
1458 << staId << " is not correct!");
1460 expectedBytes,
1461 "The number of bytes received from STA " << staId << " is not correct!");
1462}
1463
1464void
1466{
1468 nullptr,
1469 "m_currentEvent for AP was not cleared");
1470 std::size_t sta = 1;
1471 for (auto& phy : m_phyStas)
1472 {
1473 NS_TEST_ASSERT_MSG_EQ(phy->GetCurrentEvent(),
1474 nullptr,
1475 "m_currentEvent for STA " << sta << " was not cleared");
1476 sta++;
1477 }
1478}
1479
1480void
1482 WifiPhyState expectedState)
1483{
1484 // This is needed to make sure PHY state will be checked as the last event if a state change
1485 // occurred at the exact same time as the check
1487}
1488
1489void
1491 WifiPhyState expectedState)
1492{
1493 WifiPhyState currentState;
1494 PointerValue ptr;
1495 phy->GetAttribute("State", ptr);
1497 currentState = state->GetState();
1498 NS_LOG_FUNCTION(this << currentState << expectedState);
1499 NS_TEST_ASSERT_MSG_EQ(currentState,
1500 expectedState,
1501 "PHY State " << currentState << " does not match expected state "
1502 << expectedState << " at " << Simulator::Now());
1503}
1504
1505void
1507{
1508 for (auto& counter : m_countRxSuccessFromStas)
1509 {
1510 counter = 0;
1511 }
1512 for (auto& counter : m_countRxFailureFromStas)
1513 {
1514 counter = 0;
1515 }
1516 for (auto& counter : m_countRxBytesFromStas)
1517 {
1518 counter = 0;
1519 }
1520 for (auto& phy : m_phyStas)
1521 {
1522 phy->SetPpduUid(0);
1523 phy->SetTriggerFrameUid(0);
1524 }
1525 SetBssColor(m_phyAp, 0);
1526}
1527
1528void
1530{
1531 Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice>(phy->GetDevice());
1532 Ptr<HeConfiguration> heConfiguration = device->GetHeConfiguration();
1533 heConfiguration->SetAttribute("BssColor", UintegerValue(bssColor));
1534}
1535
1536void
1538{
1539 // WifiHelper::EnableLogComponents();
1540 // LogComponentEnable("WifiPhyMuMimoTest", LOG_LEVEL_ALL);
1541
1545 spectrumChannel->SetPropagationDelayModel(delayModel);
1546
1547 Ptr<Node> apNode = CreateObject<Node>();
1549 apDev->SetStandard(WIFI_STANDARD_80211ax);
1551 "Txop",
1552 PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
1553 apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
1554 apDev->SetMac(apMac);
1557 apDev->SetHeConfiguration(heConfiguration);
1559 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
1561 m_phyAp->SetErrorRateModel(apErrorModel);
1562 m_phyAp->SetDevice(apDev);
1563 m_phyAp->AddChannel(spectrumChannel);
1567 apDev->SetPhy(m_phyAp);
1568 apNode->AddDevice(apDev);
1569
1570 for (std::size_t i = 1; i <= 4; ++i)
1571 {
1572 Ptr<Node> staNode = CreateObject<Node>();
1574 staDev->SetStandard(WIFI_STANDARD_80211ax);
1576 staDev->SetHeConfiguration(CreateObject<HeConfiguration>());
1578 phy->SetInterferenceHelper(staInterferenceHelper);
1580 phy->SetErrorRateModel(staErrorModel);
1581 phy->SetDevice(staDev);
1582 phy->AddChannel(spectrumChannel);
1583 phy->ConfigureStandard(WIFI_STANDARD_80211ax);
1584 phy->SetAttribute("TxGain", DoubleValue(1.0));
1585 phy->SetAttribute("TxPowerStart", DoubleValue(16.0));
1586 phy->SetAttribute("TxPowerEnd", DoubleValue(16.0));
1587 phy->SetAttribute("PowerDensityLimit", DoubleValue(100.0)); // no impact by default
1588 phy->SetAttribute("RxGain", DoubleValue(2.0));
1589 staDev->SetPhy(phy);
1590 staNode->AddDevice(staDev);
1591 m_phyStas.push_back(phy);
1592 m_countRxSuccessFromStas.push_back(0);
1593 m_countRxFailureFromStas.push_back(0);
1594 m_countRxBytesFromStas.push_back(0);
1595 }
1596}
1597
1598void
1600{
1601 for (auto& phy : m_phyStas)
1602 {
1603 phy->Dispose();
1604 phy = nullptr;
1605 }
1606}
1607
1608void
1609TestUlMuMimoPhyTransmission::LogScenario(const std::string& log) const
1610{
1611 NS_LOG_INFO(log);
1612}
1613
1614void
1616 Time delay,
1617 const std::vector<uint16_t>& txStaIds,
1618 WifiPhyState expectedStateAtEnd,
1619 const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta)
1620{
1621 static uint64_t uid = 0;
1622
1623 // AP sends an SU packet preceding HE TB PPDUs
1626 this,
1627 0,
1628 50,
1629 ++uid,
1630 0);
1631
1633
1634 // STAs send MU UL PPDUs addressed to AP
1635 uint16_t payloadSize = 1000;
1636 std::size_t index = 0;
1637 for (auto txStaId : txStaIds)
1638 {
1639 Simulator::Schedule(delay + (index * m_delayStart),
1641 this,
1642 txStaId,
1643 1,
1644 payloadSize,
1645 uid,
1646 0);
1647 payloadSize++;
1648 index++;
1649 }
1650
1651 // Verify it takes m_expectedPpduDuration to transmit the PPDUs
1654 this,
1655 m_phyAp,
1656 WifiPhyState::RX);
1658 (m_delayStart * expectedCountersPerSta.size()),
1660 this,
1661 m_phyAp,
1662 expectedStateAtEnd);
1663
1664 delay += MilliSeconds(100);
1665 // Check reception state from STAs
1666 uint16_t staId = 1;
1667 for (const auto& expectedCounters : expectedCountersPerSta)
1668 {
1669 uint16_t expectedSuccessFromSta = std::get<0>(expectedCounters);
1670 uint16_t expectedFailuresFromSta = std::get<1>(expectedCounters);
1671 uint16_t expectedBytesFromSta = std::get<2>(expectedCounters);
1672 Simulator::Schedule(delay + (m_delayStart * (staId - 1)),
1674 this,
1675 staId,
1676 expectedSuccessFromSta,
1677 expectedFailuresFromSta,
1678 expectedBytesFromSta);
1679 staId++;
1680 }
1681
1682 // Verify events data have been cleared
1684
1685 delay += MilliSeconds(100);
1687}
1688
1689void
1691{
1694 int64_t streamNumber = 0;
1695 m_phyAp->AssignStreams(streamNumber);
1696 for (auto& phy : m_phyStas)
1697 {
1698 phy->AssignStreams(streamNumber);
1699 }
1700
1701 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
1706 ->number;
1707
1710 for (auto& phy : m_phyStas)
1711 {
1712 phy->SetOperatingChannel(
1714 }
1715
1716 Time delay = Seconds(0.0);
1718 delay += Seconds(1.0);
1719
1720 //---------------------------------------------------------------------------
1721 // Verify that all HE TB PPDUs using full BW MU-MIMO have been corrected received
1722 Simulator::Schedule(delay,
1724 this,
1725 "Reception of HE TB PPDUs using full BW MU-MIMO");
1726 ScheduleTest(delay,
1727 {1, 2, 3},
1728 WifiPhyState::IDLE,
1729 {
1730 std::make_tuple(1, 0, 1000), // One PSDU of 1000 bytes should have been
1731 // successfully received from STA 1
1732 std::make_tuple(1, 0, 1001), // One PSDU of 1001 bytes should have been
1733 // successfully received from STA 2
1734 std::make_tuple(1, 0, 1002) // One PSDU of 1002 bytes should have been
1735 // successfully received from STA 3
1736 });
1737 delay += Seconds(1.0);
1738
1739 //---------------------------------------------------------------------------
1740 // Send an HE SU PPDU during 400 ns window and verify that all HE TB PPDUs using full BW MU-MIMO
1741 // have been impacted
1742 Simulator::Schedule(delay,
1744 this,
1745 "Reception of HE TB PPDUs HE TB PPDUs using full BW MU-MIMO with an HE SU "
1746 "PPDU arriving during the 400 ns window");
1747 // One HE SU arrives at AP during the 400ns window
1748 Simulator::Schedule(delay + NanoSeconds(150),
1750 this,
1751 4,
1752 1002,
1753 2,
1754 0);
1755 ScheduleTest(delay,
1756 {1, 2, 3},
1757 WifiPhyState::IDLE,
1758 {
1759 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
1760 // failed (since interference from STA 4)
1761 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
1762 // failed (since interference from STA 4)
1763 std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
1764 // (since interference from STA 4)
1765 });
1766 delay += Seconds(1.0);
1767
1768 //---------------------------------------------------------------------------
1769 // Send an HE SU PPDU during HE portion reception and verify that all HE TB PPDUs have been
1770 // impacted
1771 Simulator::Schedule(delay,
1773 this,
1774 "Reception of HE TB PPDUs using full BW MU-MIMO with an HE SU PPDU "
1775 "arriving during the HE portion");
1776 // One HE SU arrives at AP during the HE portion
1779 this,
1780 4,
1781 1002,
1782 2,
1783 0);
1784 ScheduleTest(delay,
1785 {1, 2, 3},
1786 WifiPhyState::CCA_BUSY,
1787 {
1788 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
1789 // failed (since interference from STA 4)
1790 std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
1791 // failed (since interference from STA 4)
1792 std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
1793 // (since interference from STA 4)
1794 });
1795 delay += Seconds(1.0);
1796
1798}
1799
1800void
1802{
1803 std::vector<Time> startDelays{NanoSeconds(0), NanoSeconds(100)};
1804
1805 for (const auto& delayStart : startDelays)
1806 {
1807 m_delayStart = delayStart;
1808
1809 m_frequency = 5180;
1810 m_channelWidth = 20;
1812 NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1813 << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1814 << m_delayStart);
1815 RunOne();
1816
1817 m_frequency = 5190;
1818 m_channelWidth = 40;
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 = 5210;
1826 m_channelWidth = 80;
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 = 5250;
1834 m_channelWidth = 160;
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
1843}
1844
1845/**
1846 * \ingroup wifi-test
1847 * \ingroup tests
1848 *
1849 * \brief wifi PHY MU-MIMO Test Suite
1850 */
1852{
1853 public:
1855};
1856
1858 : TestSuite("wifi-phy-mu-mimo", Type::UNIT)
1859{
1860 AddTestCase(new TestDlMuTxVector, TestCase::Duration::QUICK);
1861 AddTestCase(new TestDlMuMimoPhyTransmission, TestCase::Duration::QUICK);
1862 AddTestCase(new TestUlMuMimoPhyTransmission, TestCase::Duration::QUICK);
1863}
1864
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.
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 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
void RxSuccessSta3(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > statusPerMpdu)
Receive success function for STA 3.
Ptr< MuMimoSpectrumWifiPhy > m_phySta3
PHY of STA 3.
void RxSuccessSta2(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > statusPerMpdu)
Receive success function for STA 2.
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 RxSuccessSta1(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > statusPerMpdu)
Receive success function for STA 1.
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.
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.
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.
void RxSuccess(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > statusPerMpdu)
Receive success function.
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
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
PHY entity for HE (11ax)
Definition he-phy.h:58
static WifiMode GetHeMcs7()
Return MCS 7 from HE MCS values.
uint16_t GetStaId(const Ptr< const WifiPpdu > ppdu) const override
Return the STA ID that has been assigned to the station this PHY belongs to.
Definition he-phy.cc:565
static std::pair< uint16_t, Time > ConvertHeTbPpduDurationToLSigLength(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Compute the L-SIG length value corresponding to the given HE TB PPDU duration.
Definition he-phy.cc:261
RU Specification.
Definition he-ru.h:57
static RuType GetRuType(MHz_u bandwidth)
Get the RU corresponding to the approximate bandwidth.
Definition he-ru.cc:781
@ RU_106_TONE
Definition he-ru.h:35
@ RU_242_TONE
Definition he-ru.h:36
an EUI-48 address
void Dispose()
Dispose of this Object.
Definition object.cc:247
void SetOwner(Ptr< WifiPhy > wifiPhy)
Set the WifiPhy owning this PHY entity.
Definition phy-entity.cc:82
static uint64_t m_globalPpduUid
Global counter of the PPDU UID.
Definition phy-entity.h:964
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:560
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:594
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:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
static WifiMode GetVhtMcs5()
Return MCS 5 from VHT MCS values.
Implements the IEEE 802.11 MAC header.
void SetSequenceNumber(uint16_t seq)
Set the sequence number of the header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
void SetQosTid(uint8_t tid)
Set the TID for the QoS header.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
virtual void SetInterferenceHelper(const Ptr< InterferenceHelper > helper)
Sets the interference helper.
Definition wifi-phy.cc:672
void SetErrorRateModel(const Ptr< ErrorRateModel > model)
Sets the error rate model.
Definition wifi-phy.cc:681
std::tuple< uint8_t, MHz_u, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying a segment of an operating channel.
Definition wifi-phy.h:919
void SetReceiveErrorCallback(RxErrorCallback callback)
Definition wifi-phy.cc:478
virtual void ConfigureStandard(WifiStandard standard)
Configure the PHY-level parameters for different Wi-Fi standard.
Definition wifi-phy.cc:1003
std::map< WifiModulationClass, Ptr< PhyEntity > > m_phyEntities
This map holds the supported PHY entities.
Definition wifi-phy.h:1360
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition wifi-phy.cc:1063
Ptr< Event > m_currentEvent
Hold the current event.
Definition wifi-phy.h:1335
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
Definition wifi-phy.cc:754
uint64_t m_previouslyRxPpduUid
UID of the previously received PPDU, reset to UINT64_MAX upon transmission.
Definition wifi-phy.h:1340
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:1129
void SetReceiveOkCallback(RxOkCallback callback)
Definition wifi-phy.cc:472
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:2330
static ConstIterator FindFirst(uint8_t number, MHz_u frequency, MHz_u width, WifiStandard standard, WifiPhyBand band, ConstIterator start=m_frequencyChannels.begin())
Find the first frequency segment matching the specified parameters.
This objects implements the PHY state machine of the Wifi device.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
bool IsSigBCompression() const
Indicate whether the Common field is present in the HE-SIG-B field.
bool IsValid(WifiPhyBand band=WIFI_PHY_BAND_UNSPECIFIED) const
The standard disallows certain combinations of WifiMode, number of spatial streams,...
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
void SetRu(HeRu::RuSpec ru, uint16_t staId)
Set the RU specification for the STA-ID.
bool IsDlOfdma() const
Return true if this TX vector is used for a downlink multi-user transmission using OFDMA.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
bool IsDlMuMimo() const
Return true if this TX vector is used for a downlink multi-user transmission using MU-MIMO.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetNss(uint8_t nss)
Sets the number of Nss.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > CreateObjectWithAttributes(Args... args)
Allocate an Object on the heap and initialize with a set of attributes.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition test.h:241
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
@ 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.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
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:44
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
@ WIFI_MAC_QOSDATA
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition wifi-mode.h:24
uint8_t staNss
Number of spatial streams used for the STA.
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:72
double snr
SNR in linear scale.
Definition wifi-types.h:73
constexpr MHz_u DEFAULT_CHANNEL_WIDTH
constexpr MHz_u DEFAULT_FREQUENCY
static WifiPhyMuMimoTestSuite WifiPhyMuMimoTestSuite
the test suite