A Discrete-Event Network Simulator
API
wifi-phy-mu-mimo-test.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2022 DERONNE SOFTWARE ENGINEERING
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
18  */
19 
20 #include "ns3/ap-wifi-mac.h"
21 #include "ns3/boolean.h"
22 #include "ns3/double.h"
23 #include "ns3/he-configuration.h"
24 #include "ns3/he-phy.h"
25 #include "ns3/interference-helper.h"
26 #include "ns3/log.h"
27 #include "ns3/multi-model-spectrum-channel.h"
28 #include "ns3/nist-error-rate-model.h"
29 #include "ns3/node.h"
30 #include "ns3/pointer.h"
31 #include "ns3/rng-seed-manager.h"
32 #include "ns3/simulator.h"
33 #include "ns3/spectrum-wifi-helper.h"
34 #include "ns3/spectrum-wifi-phy.h"
35 #include "ns3/test.h"
36 #include "ns3/uinteger.h"
37 #include "ns3/wifi-mac-header.h"
38 #include "ns3/wifi-net-device.h"
39 #include "ns3/wifi-psdu.h"
40 #include "ns3/wifi-spectrum-value-helper.h"
41 #include "ns3/wifi-utils.h"
42 
43 #include <list>
44 #include <tuple>
45 
46 using namespace ns3;
47 
48 NS_LOG_COMPONENT_DEFINE("WifiPhyMuMimoTest");
49 
50 constexpr uint32_t DEFAULT_FREQUENCY = 5180; // MHz
51 constexpr uint16_t DEFAULT_CHANNEL_WIDTH = 20; // MHz
52 
59 class TestDlMuTxVector : public TestCase
60 {
61  public:
63 
64  private:
65  void DoRun() override;
66 
75  static WifiTxVector BuildTxVector(uint16_t bw, const std::list<HeMuUserInfo>& userInfos);
76 };
77 
79  : TestCase("Check for valid combinations of MU TX-VECTOR")
80 {
81 }
82 
84 TestDlMuTxVector::BuildTxVector(uint16_t bw, const std::list<HeMuUserInfo>& userInfos)
85 {
86  WifiTxVector txVector;
88  txVector.SetChannelWidth(bw);
89  std::list<uint16_t> staIds;
90  uint16_t staId = 1;
91  for (const auto& userInfo : userInfos)
92  {
93  txVector.SetHeMuUserInfo(staId, userInfo);
94  staIds.push_back(staId++);
95  }
96  return txVector;
97 }
98 
99 void
101 {
102  // Verify TxVector is OFDMA
103  std::list<HeMuUserInfo> userInfos;
104  userInfos.push_back({{HeRu::RU_106_TONE, 1, true}, 11, 1});
105  userInfos.push_back({{HeRu::RU_106_TONE, 2, true}, 10, 2});
106  WifiTxVector txVector = BuildTxVector(20, userInfos);
107  NS_TEST_EXPECT_MSG_EQ(txVector.IsDlOfdma(),
108  true,
109  "TX-VECTOR should indicate an OFDMA transmission");
111  false,
112  "TX-VECTOR should not indicate a MU-MIMO transmission");
114  false,
115  "TX-VECTOR should not indicate a SIG-B compression");
116  NS_TEST_EXPECT_MSG_EQ(txVector.IsValid(),
117  true,
118  "TX-VECTOR should indicate all checks are passed");
119  userInfos.clear();
120 
121  // Verify TxVector is a full BW MU-MIMO
122  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 1});
123  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 2});
124  txVector = BuildTxVector(20, userInfos);
125  NS_TEST_EXPECT_MSG_EQ(txVector.IsDlOfdma(),
126  false,
127  "TX-VECTOR should indicate a MU-MIMO transmission");
129  true,
130  "TX-VECTOR should not indicate an OFDMA transmission");
132  true,
133  "TX-VECTOR should indicate a SIG-B compression");
134  NS_TEST_EXPECT_MSG_EQ(txVector.IsValid(),
135  true,
136  "TX-VECTOR should indicate all checks are passed");
137  userInfos.clear();
138 
139  // Verify TxVector is not valid if there are more than 8 STAs using the same RU
140  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 1});
141  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 1});
142  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 9, 1});
143  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 8, 1});
144  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 7, 1});
145  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 6, 1});
146  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 5, 1});
147  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 4, 1});
148  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 3, 1});
149  txVector = BuildTxVector(20, userInfos);
150  NS_TEST_EXPECT_MSG_EQ(txVector.IsDlOfdma(),
151  false,
152  "TX-VECTOR should indicate a MU-MIMO transmission");
154  true,
155  "TX-VECTOR should not indicate an OFDMA transmission");
157  true,
158  "TX-VECTOR should indicate a SIG-B compression");
159  NS_TEST_EXPECT_MSG_EQ(txVector.IsValid(),
160  false,
161  "TX-VECTOR should not indicate all checks are passed");
162 
163  // Verify TxVector is not valid if the total number of antennas in a full BW MU-MIMO is above 8
164  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 11, 2});
165  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 10, 2});
166  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 9, 3});
167  userInfos.push_back({{HeRu::RU_242_TONE, 1, true}, 8, 3});
168  txVector = BuildTxVector(20, userInfos);
169  NS_TEST_EXPECT_MSG_EQ(txVector.IsDlOfdma(),
170  false,
171  "TX-VECTOR should indicate a MU-MIMO transmission");
173  true,
174  "TX-VECTOR should not indicate an OFDMA transmission");
176  true,
177  "TX-VECTOR should indicate a SIG-B compression");
178  NS_TEST_EXPECT_MSG_EQ(txVector.IsValid(),
179  false,
180  "TX-VECTOR should not indicate all checks are passed");
181 }
182 
187 class MuMimoTestHePhy : public HePhy
188 {
189  public:
195  MuMimoTestHePhy(uint16_t staId);
196 
204  uint16_t GetStaId(const Ptr<const WifiPpdu> ppdu) const override;
205 
211  void SetGlobalPpduUid(uint64_t uid);
212 
213  private:
214  uint16_t m_staId;
215 }; // class MuMimoTestHePhy
216 
218  : HePhy(),
219  m_staId(staId)
220 {
221 }
222 
223 uint16_t
225 {
226  if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
227  {
228  return m_staId;
229  }
230  return HePhy::GetStaId(ppdu);
231 }
232 
233 void
235 {
236  m_globalPpduUid = uid;
237 }
238 
243 {
244  public:
249  static TypeId GetTypeId();
255  MuMimoSpectrumWifiPhy(uint16_t staId);
256  ~MuMimoSpectrumWifiPhy() override;
257 
263  void SetPpduUid(uint64_t uid);
264 
270  void SetTriggerFrameUid(uint64_t uid);
271 
276 
277  private:
278  void DoInitialize() override;
279  void DoDispose() override;
280 
282 }; // class MuMimoSpectrumWifiPhy
283 
284 TypeId
286 {
287  static TypeId tid =
288  TypeId("ns3::MuMimoSpectrumWifiPhy").SetParent<SpectrumWifiPhy>().SetGroupName("Wifi");
289  return tid;
290 }
291 
293  : SpectrumWifiPhy()
294 {
295  m_ofdmTestHePhy = Create<MuMimoTestHePhy>(staId);
296  m_ofdmTestHePhy->SetOwner(this);
297 }
298 
300 {
301 }
302 
303 void
305 {
306  // Replace HE PHY instance with test instance
308  SpectrumWifiPhy::DoInitialize();
309 }
310 
311 void
313 {
314  m_ofdmTestHePhy = nullptr;
315  SpectrumWifiPhy::DoDispose();
316 }
317 
318 void
320 {
322  m_previouslyRxPpduUid = uid;
323 }
324 
325 void
327 {
328  m_previouslyRxPpduUid = uid;
329 }
330 
333 {
334  return m_currentEvent;
335 }
336 
344 {
345  public:
347 
348  private:
349  void DoSetup() override;
350  void DoTeardown() override;
351  void DoRun() override;
352 
361  RxSignalInfo rxSignalInfo,
362  WifiTxVector txVector,
363  std::vector<bool> statusPerMpdu);
372  RxSignalInfo rxSignalInfo,
373  WifiTxVector txVector,
374  std::vector<bool> statusPerMpdu);
383  RxSignalInfo rxSignalInfo,
384  WifiTxVector txVector,
385  std::vector<bool> statusPerMpdu);
386 
402 
409  void CheckResultsSta1(uint32_t expectedRxSuccess,
410  uint32_t expectedRxFailure,
411  uint32_t expectedRxBytes);
418  void CheckResultsSta2(uint32_t expectedRxSuccess,
419  uint32_t expectedRxFailure,
420  uint32_t expectedRxBytes);
427  void CheckResultsSta3(uint32_t expectedRxSuccess,
428  uint32_t expectedRxFailure,
429  uint32_t expectedRxBytes);
430 
434  void ResetResults();
435 
439  struct StaInfo
440  {
441  uint16_t staId;
442  uint8_t staNss;
443  };
444 
449  void SendMuPpdu(const std::vector<StaInfo>& staInfos);
450 
456  void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
461 
465  void RunOne();
466 
479 
489 
494 
495  uint8_t m_nss;
496  uint16_t m_frequency;
497  uint16_t m_channelWidth;
499 };
500 
502  : TestCase("DL MU-MIMO PHY test"),
503  m_countRxSuccessSta1{0},
504  m_countRxSuccessSta2{0},
505  m_countRxSuccessSta3{0},
506  m_countRxFailureSta1{0},
507  m_countRxFailureSta2{0},
508  m_countRxFailureSta3{0},
509  m_countRxBytesSta1{0},
510  m_countRxBytesSta2{0},
511  m_countRxBytesSta3{0},
512  m_nss{1},
513  m_frequency{DEFAULT_FREQUENCY},
514  m_channelWidth{DEFAULT_CHANNEL_WIDTH},
515  m_expectedPpduDuration{NanoSeconds(306400)}
516 {
517 }
518 
519 void
521 {
528  m_countRxBytesSta1 = 0;
529  m_countRxBytesSta2 = 0;
530  m_countRxBytesSta3 = 0;
531 }
532 
533 void
534 TestDlMuMimoPhyTransmission::SendMuPpdu(const std::vector<StaInfo>& staInfos)
535 {
536  NS_LOG_FUNCTION(this << staInfos.size());
537  NS_ASSERT(staInfos.size() > 1);
538 
539  WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs7(),
540  0,
542  800,
543  1,
544  1,
545  0,
547  false,
548  false);
549 
550  WifiConstPsduMap psdus;
551  HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
552  for (const auto& staInfo : staInfos)
553  {
554  txVector.SetRu(ru, staInfo.staId);
555  txVector.SetMode(HePhy::GetHeMcs7(), staInfo.staId);
556  txVector.SetNss(staInfo.staNss, staInfo.staId);
557 
558  Ptr<Packet> pkt = Create<Packet>(1000 + (8 * staInfo.staId));
559  WifiMacHeader hdr;
561  hdr.SetQosTid(0);
562  std::ostringstream addr;
563  addr << "00:00:00:00:00:0" << staInfo.staId;
564  hdr.SetAddr1(Mac48Address(addr.str().c_str()));
565  hdr.SetSequenceNumber(1 + staInfo.staId);
566  Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
567  psdus.insert(std::make_pair(staInfo.staId, psdu));
568  }
569 
570  txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
571 
572  NS_ASSERT(txVector.IsDlMuMimo());
573  NS_ASSERT(!txVector.IsDlOfdma());
574 
575  m_phyAp->Send(psdus, txVector);
576 }
577 
578 void
580  RxSignalInfo rxSignalInfo,
581  WifiTxVector txVector,
582  std::vector<bool> /*statusPerMpdu*/)
583 {
584  NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
586  m_countRxBytesSta1 += (psdu->GetSize() - 30);
587 }
588 
589 void
591  RxSignalInfo rxSignalInfo,
592  WifiTxVector txVector,
593  std::vector<bool> /*statusPerMpdu*/)
594 {
595  NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
597  m_countRxBytesSta2 += (psdu->GetSize() - 30);
598 }
599 
600 void
602  RxSignalInfo rxSignalInfo,
603  WifiTxVector txVector,
604  std::vector<bool> /*statusPerMpdu*/)
605 {
606  NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
608  m_countRxBytesSta3 += (psdu->GetSize() - 30);
609 }
610 
611 void
613 {
614  NS_LOG_FUNCTION(this << *psdu);
616 }
617 
618 void
620 {
621  NS_LOG_FUNCTION(this << *psdu);
623 }
624 
625 void
627 {
628  NS_LOG_FUNCTION(this << *psdu);
630 }
631 
632 void
634  uint32_t expectedRxFailure,
635  uint32_t expectedRxBytes)
636 {
638  expectedRxSuccess,
639  "The number of successfully received packets by STA 1 is not correct!");
641  expectedRxFailure,
642  "The number of unsuccessfully received packets by STA 1 is not correct!");
644  expectedRxBytes,
645  "The number of bytes received by STA 1 is not correct!");
646 }
647 
648 void
650  uint32_t expectedRxFailure,
651  uint32_t expectedRxBytes)
652 {
654  expectedRxSuccess,
655  "The number of successfully received packets by STA 2 is not correct!");
657  expectedRxFailure,
658  "The number of unsuccessfully received packets by STA 2 is not correct!");
660  expectedRxBytes,
661  "The number of bytes received by STA 2 is not correct!");
662 }
663 
664 void
666  uint32_t expectedRxFailure,
667  uint32_t expectedRxBytes)
668 {
670  expectedRxSuccess,
671  "The number of successfully received packets by STA 3 is not correct!");
673  expectedRxFailure,
674  "The number of unsuccessfully received packets by STA 3 is not correct!");
676  expectedRxBytes,
677  "The number of bytes received by STA 3 is not correct!");
678 }
679 
680 void
682  WifiPhyState expectedState)
683 {
684  // This is needed to make sure PHY state will be checked as the last event if a state change
685  // occurred at the exact same time as the check
686  Simulator::ScheduleNow(&TestDlMuMimoPhyTransmission::DoCheckPhyState, this, phy, expectedState);
687 }
688 
689 void
691  WifiPhyState expectedState)
692 {
693  WifiPhyState currentState;
694  PointerValue ptr;
695  phy->GetAttribute("State", ptr);
696  Ptr<WifiPhyStateHelper> state = DynamicCast<WifiPhyStateHelper>(ptr.Get<WifiPhyStateHelper>());
697  currentState = state->GetState();
698  NS_LOG_FUNCTION(this << currentState << expectedState);
699  NS_TEST_ASSERT_MSG_EQ(currentState,
700  expectedState,
701  "PHY State " << currentState << " does not match expected state "
702  << expectedState << " at " << Simulator::Now());
703 }
704 
705 void
707 {
708  Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
710  CreateObject<ConstantSpeedPropagationDelayModel>();
711  spectrumChannel->SetPropagationDelayModel(delayModel);
712 
713  Ptr<Node> apNode = CreateObject<Node>();
714  Ptr<WifiNetDevice> apDev = CreateObject<WifiNetDevice>();
715  m_phyAp = CreateObject<SpectrumWifiPhy>();
716  Ptr<InterferenceHelper> apInterferenceHelper = CreateObject<InterferenceHelper>();
717  m_phyAp->SetInterferenceHelper(apInterferenceHelper);
718  Ptr<ErrorRateModel> apErrorModel = CreateObject<NistErrorRateModel>();
719  m_phyAp->SetErrorRateModel(apErrorModel);
720  m_phyAp->SetDevice(apDev);
721  m_phyAp->AddChannel(spectrumChannel);
723  apDev->SetPhy(m_phyAp);
724  apNode->AddDevice(apDev);
725 
726  Ptr<Node> sta1Node = CreateObject<Node>();
727  Ptr<WifiNetDevice> sta1Dev = CreateObject<WifiNetDevice>();
728  m_phySta1 = CreateObject<MuMimoSpectrumWifiPhy>(1);
729  Ptr<InterferenceHelper> sta1InterferenceHelper = CreateObject<InterferenceHelper>();
730  m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
731  Ptr<ErrorRateModel> sta1ErrorModel = CreateObject<NistErrorRateModel>();
732  m_phySta1->SetErrorRateModel(sta1ErrorModel);
733  m_phySta1->SetDevice(sta1Dev);
734  m_phySta1->AddChannel(spectrumChannel);
740  sta1Dev->SetPhy(m_phySta1);
741  sta1Node->AddDevice(sta1Dev);
742 
743  Ptr<Node> sta2Node = CreateObject<Node>();
744  Ptr<WifiNetDevice> sta2Dev = CreateObject<WifiNetDevice>();
745  m_phySta2 = CreateObject<MuMimoSpectrumWifiPhy>(2);
746  Ptr<InterferenceHelper> sta2InterferenceHelper = CreateObject<InterferenceHelper>();
747  m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
748  Ptr<ErrorRateModel> sta2ErrorModel = CreateObject<NistErrorRateModel>();
749  m_phySta2->SetErrorRateModel(sta2ErrorModel);
750  m_phySta2->SetDevice(sta2Dev);
751  m_phySta2->AddChannel(spectrumChannel);
757  sta2Dev->SetPhy(m_phySta2);
758  sta2Node->AddDevice(sta2Dev);
759 
760  Ptr<Node> sta3Node = CreateObject<Node>();
761  Ptr<WifiNetDevice> sta3Dev = CreateObject<WifiNetDevice>();
762  m_phySta3 = CreateObject<MuMimoSpectrumWifiPhy>(3);
763  Ptr<InterferenceHelper> sta3InterferenceHelper = CreateObject<InterferenceHelper>();
764  m_phySta3->SetInterferenceHelper(sta3InterferenceHelper);
765  Ptr<ErrorRateModel> sta3ErrorModel = CreateObject<NistErrorRateModel>();
766  m_phySta3->SetErrorRateModel(sta3ErrorModel);
767  m_phySta3->SetDevice(sta3Dev);
768  m_phySta3->AddChannel(spectrumChannel);
774  sta3Dev->SetPhy(m_phySta3);
775  sta3Node->AddDevice(sta3Dev);
776 }
777 
778 void
780 {
781  m_phyAp->Dispose();
782  m_phyAp = nullptr;
783  m_phySta1->Dispose();
784  m_phySta1 = nullptr;
785  m_phySta2->Dispose();
786  m_phySta2 = nullptr;
787  m_phySta3->Dispose();
788  m_phySta3 = nullptr;
789 }
790 
791 void
793 {
794  RngSeedManager::SetSeed(1);
795  RngSeedManager::SetRun(1);
796  int64_t streamNumber = 0;
797  m_phyAp->AssignStreams(streamNumber);
798  m_phySta1->AssignStreams(streamNumber);
799  m_phySta2->AssignStreams(streamNumber);
800 
801  auto channelNum = std::get<0>(*WifiPhyOperatingChannel::FindFirst(0,
802  m_frequency,
806 
815 
818 
819  //----------------------------------------------------------------------------------------------------
820  // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2:
821  // STA 1 and STA 2 should receive their PSDUs, whereas STA 3 should not receive any PSDU
822  // but should keep its PHY busy during all PPDU duration.
823  Simulator::Schedule(Seconds(1.0),
825  this,
826  std::vector<StaInfo>{{1, m_nss}, {2, m_nss}});
827 
828  // Since it takes m_expectedPpduDuration to transmit the PPDU,
829  // all 3 PHYs should be back to IDLE at the same time,
830  // even the PHY that has no PSDU addressed to it.
831  Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration - NanoSeconds(1),
833  this,
834  m_phySta1,
836  Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration - NanoSeconds(1),
838  this,
839  m_phySta2,
841  Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration - NanoSeconds(1),
843  this,
844  m_phySta3,
846  Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration,
848  this,
849  m_phySta1,
851  Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration,
853  this,
854  m_phySta2,
856  Simulator::Schedule(Seconds(1.0) + m_expectedPpduDuration,
858  this,
859  m_phySta3,
861 
862  // One PSDU of 1008 bytes should have been successfully received by STA 1
863  Simulator::Schedule(Seconds(1.1),
865  this,
866  1,
867  0,
868  1008);
869  // One PSDU of 1016 bytes should have been successfully received by STA 2
870  Simulator::Schedule(Seconds(1.1),
872  this,
873  1,
874  0,
875  1016);
876  // No PSDU should have been received by STA 3
877  Simulator::Schedule(Seconds(1.1),
879  this,
880  0,
881  0,
882  0);
883 
884  Simulator::Schedule(Seconds(1.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
885 
886  //----------------------------------------------------------------------------------------------------
887  // Send MU PPDU with two PSDUs addressed to STA 1 and STA 3:
888  // STA 1 and STA 3 should receive their PSDUs, whereas STA 2 should not receive any PSDU
889  // but should keep its PHY busy during all PPDU duration.
890  Simulator::Schedule(Seconds(2.0),
892  this,
893  std::vector<StaInfo>{{1, m_nss}, {3, m_nss}});
894 
895  // Since it takes m_expectedPpduDuration to transmit the PPDU,
896  // all 3 PHYs should be back to IDLE at the same time,
897  // even the PHY that has no PSDU addressed to it.
898  Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration - NanoSeconds(1),
900  this,
901  m_phySta1,
903  Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration - NanoSeconds(1),
905  this,
906  m_phySta2,
908  Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration - NanoSeconds(1),
910  this,
911  m_phySta3,
913  Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration,
915  this,
916  m_phySta1,
918  Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration,
920  this,
921  m_phySta2,
923  Simulator::Schedule(Seconds(2.0) + m_expectedPpduDuration,
925  this,
926  m_phySta3,
928 
929  // One PSDU of 1008 bytes should have been successfully received by STA 1
930  Simulator::Schedule(Seconds(2.1),
932  this,
933  1,
934  0,
935  1008);
936  // No PSDU should have been received by STA 2
937  Simulator::Schedule(Seconds(2.1),
939  this,
940  0,
941  0,
942  0);
943  // One PSDU of 1024 bytes should have been successfully received by STA 3
944  Simulator::Schedule(Seconds(2.1),
946  this,
947  1,
948  0,
949  1024);
950 
951  Simulator::Schedule(Seconds(2.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
952 
953  //----------------------------------------------------------------------------------------------------
954  // Send MU PPDU with two PSDUs addressed to STA 2 and STA 3:
955  // STA 2 and STA 3 should receive their PSDUs, whereas STA 1 should not receive any PSDU
956  // but should keep its PHY busy during all PPDU duration.
957  Simulator::Schedule(Seconds(3.0),
959  this,
960  std::vector<StaInfo>{{2, m_nss}, {3, m_nss}});
961 
962  // Since it takes m_expectedPpduDuration to transmit the PPDU,
963  // all 3 PHYs should be back to IDLE at the same time,
964  // even the PHY that has no PSDU addressed to it.
965  Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration - NanoSeconds(1),
967  this,
968  m_phySta1,
970  Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration - NanoSeconds(1),
972  this,
973  m_phySta2,
975  Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration - NanoSeconds(1),
977  this,
978  m_phySta3,
980  Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration,
982  this,
983  m_phySta1,
985  Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration,
987  this,
988  m_phySta2,
990  Simulator::Schedule(Seconds(3.0) + m_expectedPpduDuration,
992  this,
993  m_phySta3,
995 
996  // No PSDU should have been received by STA 1
997  Simulator::Schedule(Seconds(3.1),
999  this,
1000  0,
1001  0,
1002  0);
1003  // One PSDU of 1016 bytes should have been successfully received by STA 2
1004  Simulator::Schedule(Seconds(3.1),
1006  this,
1007  1,
1008  0,
1009  1016);
1010  // One PSDU of 1024 bytes should have been successfully received by STA 3
1011  Simulator::Schedule(Seconds(3.1),
1013  this,
1014  1,
1015  0,
1016  1024);
1017 
1018  Simulator::Schedule(Seconds(3.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
1019 
1020  //----------------------------------------------------------------------------------------------------
1021  // Send MU PPDU with three PSDUs addressed to STA 1, STA 2 and STA 3:
1022  // All STAs should receive their PSDUs.
1023  Simulator::Schedule(Seconds(4.0),
1025  this,
1026  std::vector<StaInfo>{{1, m_nss}, {2, m_nss}, {3, m_nss}});
1027 
1028  // Since it takes m_expectedPpduDuration to transmit the PPDU,
1029  // all 3 PHYs should be back to IDLE at the same time.
1030  Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration - NanoSeconds(1),
1032  this,
1033  m_phySta1,
1035  Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration - NanoSeconds(1),
1037  this,
1038  m_phySta2,
1040  Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration - NanoSeconds(1),
1042  this,
1043  m_phySta3,
1045  Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration,
1047  this,
1048  m_phySta1,
1050  Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration,
1052  this,
1053  m_phySta2,
1055  Simulator::Schedule(Seconds(4.0) + m_expectedPpduDuration,
1057  this,
1058  m_phySta3,
1060 
1061  // One PSDU of 1008 bytes should have been successfully received by STA 1
1062  Simulator::Schedule(Seconds(4.1),
1064  this,
1065  1,
1066  0,
1067  1008);
1068  // One PSDU of 1016 bytes should have been successfully received by STA 2
1069  Simulator::Schedule(Seconds(4.1),
1071  this,
1072  1,
1073  0,
1074  1016);
1075  // One PSDU of 1024 bytes should have been successfully received by STA 3
1076  Simulator::Schedule(Seconds(4.1),
1078  this,
1079  1,
1080  0,
1081  1024);
1082 
1083  Simulator::Schedule(Seconds(4.5), &TestDlMuMimoPhyTransmission::ResetResults, this);
1084 
1085  Simulator::Run();
1086 }
1087 
1088 void
1090 {
1091  std::vector<uint8_t> nssToTest{1, 2};
1092  for (auto nss : nssToTest)
1093  {
1094  m_nss = nss;
1095  m_frequency = 5180;
1096  m_channelWidth = 20;
1097  m_expectedPpduDuration = (nss > 1) ? NanoSeconds(110400) : NanoSeconds(156800);
1098  RunOne();
1099 
1100  m_frequency = 5190;
1101  m_channelWidth = 40;
1102  m_expectedPpduDuration = (nss > 1) ? NanoSeconds(83200) : NanoSeconds(102400);
1103  RunOne();
1104 
1105  m_frequency = 5210;
1106  m_channelWidth = 80;
1107  m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(75200);
1108  RunOne();
1109 
1110  m_frequency = 5250;
1111  m_channelWidth = 160;
1112  m_expectedPpduDuration = (nss > 1) ? NanoSeconds(69600) : NanoSeconds(61600);
1113  RunOne();
1114  }
1115  // FIXME: test also different nss over STAs once RX durations when receiving different PPDUs
1116  // with different nss over STAs are fixed
1117 
1118  Simulator::Destroy();
1119 }
1120 
1128 {
1129  public:
1131 
1132  private:
1133  void DoSetup() override;
1134  void DoTeardown() override;
1135  void DoRun() override;
1136 
1144  WifiTxVector GetTxVectorForHeTbPpdu(uint16_t txStaId, uint8_t nss, uint8_t bssColor) const;
1151  void SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor);
1160  void SendHeTbPpdu(uint16_t txStaId,
1161  uint8_t nss,
1162  std::size_t payloadSize,
1163  uint64_t uid,
1164  uint8_t bssColor);
1165 
1173  void SendHeSuPpdu(uint16_t txStaId, std::size_t payloadSize, uint64_t uid, uint8_t bssColor);
1174 
1180  void SetBssColor(Ptr<WifiPhy> phy, uint8_t bssColor);
1181 
1185  void RunOne();
1186 
1194  void CheckRxFromSta(uint16_t staId,
1195  uint32_t expectedSuccess,
1196  uint32_t expectedFailures,
1197  uint32_t expectedBytes);
1198 
1202  void VerifyEventsCleared();
1203 
1212 
1216  void Reset();
1217 
1225  void RxSuccess(Ptr<const WifiPsdu> psdu,
1226  RxSignalInfo rxSignalInfo,
1227  WifiTxVector txVector,
1228  std::vector<bool> statusPerMpdu);
1229 
1234  void RxFailure(Ptr<const WifiPsdu> psdu);
1235 
1245  void ScheduleTest(
1246  Time delay,
1247  const std::vector<uint16_t>& txStaIds,
1248  WifiPhyState expectedStateAtEnd,
1249  const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta);
1250 
1256  void LogScenario(const std::string& log) const;
1257 
1259  std::vector<Ptr<MuMimoSpectrumWifiPhy>> m_phyStas;
1260 
1261  std::vector<uint32_t> m_countRxSuccessFromStas;
1262  std::vector<uint32_t> m_countRxFailureFromStas;
1263  std::vector<uint32_t> m_countRxBytesFromStas;
1264 
1266  uint16_t m_frequency;
1267  uint16_t m_channelWidth;
1269 };
1270 
1272  : TestCase("UL MU-MIMO PHY test"),
1273  m_countRxSuccessFromStas{},
1274  m_countRxFailureFromStas{},
1275  m_countRxBytesFromStas{},
1276  m_delayStart{Seconds(0)},
1277  m_frequency{DEFAULT_FREQUENCY},
1278  m_channelWidth{DEFAULT_CHANNEL_WIDTH},
1279  m_expectedPpduDuration{NanoSeconds(271200)}
1280 {
1281 }
1282 
1283 void
1285  std::size_t payloadSize,
1286  uint64_t uid,
1287  uint8_t bssColor)
1288 {
1289  NS_LOG_FUNCTION(this << txStaId << payloadSize << uid << +bssColor);
1290  WifiConstPsduMap psdus;
1291 
1292  WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs7(),
1293  0,
1295  800,
1296  1,
1297  1,
1298  0,
1300  false,
1301  false,
1302  false,
1303  bssColor);
1304 
1305  Ptr<Packet> pkt = Create<Packet>(payloadSize);
1306  WifiMacHeader hdr;
1308  hdr.SetQosTid(0);
1309  hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
1310  std::ostringstream addr;
1311  addr << "00:00:00:00:00:0" << txStaId;
1312  hdr.SetAddr2(Mac48Address(addr.str().c_str()));
1313  hdr.SetSequenceNumber(1);
1314  Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1315  psdus.insert(std::make_pair(SU_STA_ID, psdu));
1316 
1317  Ptr<MuMimoSpectrumWifiPhy> phy = (txStaId == 0) ? m_phyAp : m_phyStas.at(txStaId - 1);
1318  phy->SetPpduUid(uid);
1319  phy->Send(psdus, txVector);
1320 }
1321 
1324  uint8_t nss,
1325  uint8_t bssColor) const
1326 {
1327  WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs7(),
1328  0,
1330  1600,
1331  1,
1332  nss,
1333  0,
1335  false,
1336  false,
1337  false,
1338  bssColor);
1339 
1340  HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
1341  txVector.SetRu(ru, txStaId);
1342  txVector.SetMode(HePhy::GetHeMcs7(), txStaId);
1343  txVector.SetNss(nss, txStaId);
1344 
1345  return txVector;
1346 }
1347 
1348 void
1349 TestUlMuMimoPhyTransmission::SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor)
1350 {
1351  WifiTxVector txVector(HePhy::GetHeMcs7(),
1352  0,
1354  1600,
1355  1,
1356  1,
1357  0,
1359  false,
1360  false,
1361  false,
1362  bssColor);
1363 
1364  HeRu::RuSpec ru(HeRu::GetRuType(m_channelWidth), 1, true); // full BW MU-MIMO
1365  for (auto staId : staIds)
1366  {
1367  txVector.SetRu(ru, staId);
1368  txVector.SetMode(HePhy::GetHeMcs7(), staId);
1369  txVector.SetNss(1, staId);
1370  }
1371 
1372  uint16_t length;
1373  std::tie(length, m_expectedPpduDuration) =
1374  HePhy::ConvertHeTbPpduDurationToLSigLength(m_expectedPpduDuration,
1375  txVector,
1376  m_phyAp->GetPhyBand());
1377  txVector.SetLength(length);
1378  auto hePhyAp = DynamicCast<HePhy>(m_phyAp->GetPhyEntity(WIFI_MOD_CLASS_HE));
1379  hePhyAp->SetTrigVector(txVector, m_expectedPpduDuration);
1380 }
1381 
1382 void
1384  uint8_t nss,
1385  std::size_t payloadSize,
1386  uint64_t uid,
1387  uint8_t bssColor)
1388 {
1389  NS_LOG_FUNCTION(this << txStaId << +nss << payloadSize << uid << +bssColor);
1390  WifiConstPsduMap psdus;
1391 
1392  WifiTxVector txVector = GetTxVectorForHeTbPpdu(txStaId, nss, bssColor);
1393  Ptr<Packet> pkt = Create<Packet>(payloadSize);
1394  WifiMacHeader hdr;
1396  hdr.SetQosTid(0);
1397  hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
1398  std::ostringstream addr;
1399  addr << "00:00:00:00:00:0" << txStaId;
1400  hdr.SetAddr2(Mac48Address(addr.str().c_str()));
1401  hdr.SetSequenceNumber(1);
1402  Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1403  psdus.insert(std::make_pair(txStaId, psdu));
1404 
1405  Ptr<MuMimoSpectrumWifiPhy> phy = m_phyStas.at(txStaId - 1);
1406  Time txDuration =
1407  phy->CalculateTxDuration(psdu->GetSize(), txVector, phy->GetPhyBand(), txStaId);
1408  txVector.SetLength(
1409  HePhy::ConvertHeTbPpduDurationToLSigLength(txDuration, txVector, phy->GetPhyBand()).first);
1410 
1411  phy->SetPpduUid(uid);
1412  phy->Send(psdus, txVector);
1413 }
1414 
1415 void
1417  RxSignalInfo rxSignalInfo,
1418  WifiTxVector txVector,
1419  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) > 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 
1436 void
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 
1452 void
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 
1472 void
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 
1488 void
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
1494  Simulator::ScheduleNow(&TestUlMuMimoPhyTransmission::DoCheckPhyState, this, phy, expectedState);
1495 }
1496 
1497 void
1499  WifiPhyState expectedState)
1500 {
1501  WifiPhyState currentState;
1502  PointerValue ptr;
1503  phy->GetAttribute("State", ptr);
1504  Ptr<WifiPhyStateHelper> state = DynamicCast<WifiPhyStateHelper>(ptr.Get<WifiPhyStateHelper>());
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 
1513 void
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 
1536 void
1538 {
1539  Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice>(phy->GetDevice());
1540  Ptr<HeConfiguration> heConfiguration = device->GetHeConfiguration();
1541  heConfiguration->SetAttribute("BssColor", UintegerValue(bssColor));
1542 }
1543 
1544 void
1546 {
1547  // WifiHelper::EnableLogComponents();
1548  // LogComponentEnable("WifiPhyMuMimoTest", LOG_LEVEL_ALL);
1549 
1550  Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
1552  CreateObject<ConstantSpeedPropagationDelayModel>();
1553  spectrumChannel->SetPropagationDelayModel(delayModel);
1554 
1555  Ptr<Node> apNode = CreateObject<Node>();
1556  Ptr<WifiNetDevice> apDev = CreateObject<WifiNetDevice>();
1558  Ptr<ApWifiMac> apMac = CreateObject<ApWifiMac>();
1559  apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
1560  apDev->SetMac(apMac);
1561  m_phyAp = CreateObject<MuMimoSpectrumWifiPhy>(0);
1562  Ptr<HeConfiguration> heConfiguration = CreateObject<HeConfiguration>();
1563  apDev->SetHeConfiguration(heConfiguration);
1564  Ptr<InterferenceHelper> apInterferenceHelper = CreateObject<InterferenceHelper>();
1565  m_phyAp->SetInterferenceHelper(apInterferenceHelper);
1566  Ptr<ErrorRateModel> apErrorModel = CreateObject<NistErrorRateModel>();
1567  m_phyAp->SetErrorRateModel(apErrorModel);
1568  m_phyAp->SetDevice(apDev);
1569  m_phyAp->AddChannel(spectrumChannel);
1573  apDev->SetPhy(m_phyAp);
1574  apNode->AddDevice(apDev);
1575 
1576  for (std::size_t i = 1; i <= 4; ++i)
1577  {
1578  Ptr<Node> staNode = CreateObject<Node>();
1579  Ptr<WifiNetDevice> staDev = CreateObject<WifiNetDevice>();
1581  Ptr<MuMimoSpectrumWifiPhy> phy = CreateObject<MuMimoSpectrumWifiPhy>(i);
1582  staDev->SetHeConfiguration(CreateObject<HeConfiguration>());
1583  Ptr<InterferenceHelper> staInterferenceHelper = CreateObject<InterferenceHelper>();
1584  phy->SetInterferenceHelper(staInterferenceHelper);
1585  Ptr<ErrorRateModel> staErrorModel = CreateObject<NistErrorRateModel>();
1586  phy->SetErrorRateModel(staErrorModel);
1587  phy->SetDevice(staDev);
1588  phy->AddChannel(spectrumChannel);
1589  phy->ConfigureStandard(WIFI_STANDARD_80211ax);
1590  phy->SetAttribute("TxGain", DoubleValue(1.0));
1591  phy->SetAttribute("TxPowerStart", DoubleValue(16.0));
1592  phy->SetAttribute("TxPowerEnd", DoubleValue(16.0));
1593  phy->SetAttribute("PowerDensityLimit", DoubleValue(100.0)); // no impact by default
1594  phy->SetAttribute("RxGain", DoubleValue(2.0));
1595  staDev->SetPhy(phy);
1596  staNode->AddDevice(staDev);
1597  m_phyStas.push_back(phy);
1598  m_countRxSuccessFromStas.push_back(0);
1599  m_countRxFailureFromStas.push_back(0);
1600  m_countRxBytesFromStas.push_back(0);
1601  }
1602 }
1603 
1604 void
1606 {
1607  for (auto& phy : m_phyStas)
1608  {
1609  phy->Dispose();
1610  phy = nullptr;
1611  }
1612 }
1613 
1614 void
1615 TestUlMuMimoPhyTransmission::LogScenario(const std::string& log) const
1616 {
1617  NS_LOG_INFO(log);
1618 }
1619 
1620 void
1622  Time delay,
1623  const std::vector<uint16_t>& txStaIds,
1624  WifiPhyState expectedStateAtEnd,
1625  const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta)
1626 {
1627  static uint64_t uid = 0;
1628 
1629  // AP sends an SU packet preceding HE TB PPDUs
1630  Simulator::Schedule(delay - MilliSeconds(10),
1632  this,
1633  0,
1634  50,
1635  ++uid,
1636  0);
1637 
1638  Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::SetTrigVector, this, txStaIds, 0);
1639 
1640  // STAs send MU UL PPDUs addressed to AP
1641  uint16_t payloadSize = 1000;
1642  std::size_t index = 0;
1643  for (auto txStaId : txStaIds)
1644  {
1645  Simulator::Schedule(delay + (index * m_delayStart),
1647  this,
1648  txStaId,
1649  1,
1650  payloadSize,
1651  uid,
1652  0);
1653  payloadSize++;
1654  index++;
1655  }
1656 
1657  // Verify it takes m_expectedPpduDuration to transmit the PPDUs
1658  Simulator::Schedule(delay + m_expectedPpduDuration - NanoSeconds(1),
1660  this,
1661  m_phyAp,
1663  Simulator::Schedule(delay + m_expectedPpduDuration +
1664  (m_delayStart * expectedCountersPerSta.size()),
1666  this,
1667  m_phyAp,
1668  expectedStateAtEnd);
1669 
1670  delay += MilliSeconds(100);
1671  // Check reception state from STAs
1672  uint16_t staId = 1;
1673  for (const auto& expectedCounters : expectedCountersPerSta)
1674  {
1675  uint16_t expectedSuccessFromSta = std::get<0>(expectedCounters);
1676  uint16_t expectedFailuresFromSta = std::get<1>(expectedCounters);
1677  uint16_t expectedBytesFromSta = std::get<2>(expectedCounters);
1678  Simulator::Schedule(delay + (m_delayStart * (staId - 1)),
1680  this,
1681  staId,
1682  expectedSuccessFromSta,
1683  expectedFailuresFromSta,
1684  expectedBytesFromSta);
1685  staId++;
1686  }
1687 
1688  // Verify events data have been cleared
1689  Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::VerifyEventsCleared, this);
1690 
1691  delay += MilliSeconds(100);
1692  Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::Reset, this);
1693 }
1694 
1695 void
1697 {
1698  RngSeedManager::SetSeed(1);
1699  RngSeedManager::SetRun(1);
1700  int64_t streamNumber = 0;
1701  m_phyAp->AssignStreams(streamNumber);
1702  for (auto& phy : m_phyStas)
1703  {
1704  phy->AssignStreams(streamNumber);
1705  }
1706 
1707  auto channelNum = std::get<0>(*WifiPhyOperatingChannel::FindFirst(0,
1708  m_frequency,
1712 
1715  for (auto& phy : m_phyStas)
1716  {
1717  phy->SetOperatingChannel(
1719  }
1720 
1721  Time delay = Seconds(0.0);
1722  Simulator::Schedule(delay, &TestUlMuMimoPhyTransmission::Reset, this);
1723  delay += Seconds(1.0);
1724 
1725  //---------------------------------------------------------------------------
1726  // Verify that all HE TB PPDUs using full BW MU-MIMO have been corrected received
1727  Simulator::Schedule(delay,
1729  this,
1730  "Reception of HE TB PPDUs using full BW MU-MIMO");
1731  ScheduleTest(delay,
1732  {1, 2, 3},
1734  {
1735  std::make_tuple(1, 0, 1000), // One PSDU of 1000 bytes should have been
1736  // successfully received from STA 1
1737  std::make_tuple(1, 0, 1001), // One PSDU of 1001 bytes should have been
1738  // successfully received from STA 2
1739  std::make_tuple(1, 0, 1002) // One PSDU of 1002 bytes should have been
1740  // successfully received from STA 3
1741  });
1742  delay += Seconds(1.0);
1743 
1744  //---------------------------------------------------------------------------
1745  // Send an HE SU PPDU during 400 ns window and verify that all HE TB PPDUs using full BW MU-MIMO
1746  // have been impacted
1747  Simulator::Schedule(delay,
1749  this,
1750  "Reception of HE TB PPDUs HE TB PPDUs using full BW MU-MIMO with an HE SU "
1751  "PPDU arriving during the 400 ns window");
1752  // One HE SU arrives at AP during the 400ns window
1753  Simulator::Schedule(delay + NanoSeconds(150),
1755  this,
1756  4,
1757  1002,
1758  2,
1759  0);
1760  ScheduleTest(delay,
1761  {1, 2, 3},
1763  {
1764  std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
1765  // failed (since interference from STA 4)
1766  std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
1767  // failed (since interference from STA 4)
1768  std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
1769  // (since interference from STA 4)
1770  });
1771  delay += Seconds(1.0);
1772 
1773  //---------------------------------------------------------------------------
1774  // Send an HE SU PPDU during HE portion reception and verify that all HE TB PPDUs have been
1775  // impacted
1776  Simulator::Schedule(delay,
1778  this,
1779  "Reception of HE TB PPDUs using full BW MU-MIMO with an HE SU PPDU "
1780  "arriving during the HE portion");
1781  // One HE SU arrives at AP during the HE portion
1782  Simulator::Schedule(delay + MicroSeconds(40),
1784  this,
1785  4,
1786  1002,
1787  2,
1788  0);
1789  ScheduleTest(delay,
1790  {1, 2, 3},
1792  {
1793  std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 1 should have
1794  // failed (since interference from STA 4)
1795  std::make_tuple(0, 1, 0), // Reception of the PSDU from STA 2 should have
1796  // failed (since interference from STA 4)
1797  std::make_tuple(0, 1, 0) // Reception of the PSDU from STA 3 should have failed
1798  // (since interference from STA 4)
1799  });
1800  delay += Seconds(1.0);
1801 
1802  Simulator::Run();
1803 }
1804 
1805 void
1807 {
1808  std::vector<Time> startDelays{NanoSeconds(0), NanoSeconds(100)};
1809 
1810  for (const auto& delayStart : startDelays)
1811  {
1812  m_delayStart = delayStart;
1813 
1814  m_frequency = 5180;
1815  m_channelWidth = 20;
1817  NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1818  << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1819  << m_delayStart);
1820  RunOne();
1821 
1822  m_frequency = 5190;
1823  m_channelWidth = 40;
1825  NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1826  << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1827  << m_delayStart);
1828  RunOne();
1829 
1830  m_frequency = 5210;
1831  m_channelWidth = 80;
1833  NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1834  << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1835  << m_delayStart);
1836  RunOne();
1837 
1838  m_frequency = 5250;
1839  m_channelWidth = 160;
1841  NS_LOG_DEBUG("Run UL MU-MIMO PHY transmission test for "
1842  << m_channelWidth << " MHz with delay between each HE TB PPDUs of "
1843  << m_delayStart);
1844  RunOne();
1845  }
1846 
1847  Simulator::Destroy();
1848 }
1849 
1857 {
1858  public:
1860 };
1861 
1863  : TestSuite("wifi-phy-mu-mimo", UNIT)
1864 {
1865  AddTestCase(new TestDlMuTxVector, TestCase::QUICK);
1866  AddTestCase(new TestDlMuMimoPhyTransmission, TestCase::QUICK);
1867  AddTestCase(new TestUlMuMimoPhyTransmission, TestCase::QUICK);
1868 }
1869 
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.
uint16_t m_frequency
frequency in MHz
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
uint16_t m_channelWidth
channel width in MHz
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
void RunOne()
Run one function.
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.
void DoRun() override
Implementation to actually run this TestCase.
static WifiTxVector BuildTxVector(uint16_t bw, const std::list< HeMuUserInfo > &userInfos)
Build a TXVECTOR for DL MU with the given bandwidth and user information.
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.
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.
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.
uint16_t m_channelWidth
channel width in MHz
void DoCheckPhyState(Ptr< MuMimoSpectrumWifiPhy > phy, WifiPhyState expectedState)
Check the PHY state.
void SetBssColor(Ptr< WifiPhy > phy, uint8_t bssColor)
Set the BSS color.
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.
uint16_t m_frequency
frequency in MHz
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:42
PHY entity for HE (11ax)
Definition: he-phy.h:68
RU Specification.
Definition: he-ru.h:66
an EUI-48 address
Definition: mac48-address.h:46
uint32_t AddDevice(Ptr< NetDevice > device)
Associate a NetDevice to this node.
Definition: node.cc:138
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:204
void Dispose()
Dispose of this Object.
Definition: object.cc:219
void SetOwner(Ptr< WifiPhy > wifiPhy)
Set the WifiPhy owning this PHY entity.
Definition: phy-entity.cc:89
static uint64_t m_globalPpduUid
Global counter of the PPDU UID.
Definition: phy-entity.h:1005
Hold objects of type Ptr<T>.
Definition: pointer.h:37
Ptr< T > Get() const
Definition: pointer.h:202
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
802.11 PHY layer model
void SetDevice(const Ptr< WifiNetDevice > device) override
Sets the device this PHY is associated with.
void AddChannel(const Ptr< SpectrumChannel > channel, const FrequencyRange &freqRange=WHOLE_WIFI_SPECTRUM)
Attach a SpectrumChannel to use for a given frequency range.
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
Hold an unsigned integer type.
Definition: uinteger.h:45
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.
void SetMac(const Ptr< WifiMac > mac)
void SetHeConfiguration(Ptr< HeConfiguration > heConfiguration)
Ptr< HeConfiguration > GetHeConfiguration() const
void SetStandard(WifiStandard standard)
Set the Wifi standard.
void SetPhy(const Ptr< WifiPhy > phy)
void SetNumberOfAntennas(uint8_t antennas)
Definition: wifi-phy.cc:1257
virtual void SetInterferenceHelper(const Ptr< InterferenceHelper > helper)
Sets the interference helper.
Definition: wifi-phy.cc:631
void Send(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
This function is a wrapper for the Send variant that accepts a WifiConstPsduMap as first argument.
Definition: wifi-phy.cc:1720
void SetErrorRateModel(const Ptr< ErrorRateModel > model)
Sets the error rate model.
Definition: wifi-phy.cc:639
void SetMaxSupportedTxSpatialStreams(uint8_t streams)
Definition: wifi-phy.cc:1275
void SetReceiveErrorCallback(RxErrorCallback callback)
Definition: wifi-phy.cc:455
virtual void ConfigureStandard(WifiStandard standard)
Configure the PHY-level parameters for different Wi-Fi standard.
Definition: wifi-phy.cc:961
std::map< WifiModulationClass, Ptr< PhyEntity > > m_phyEntities
This map holds the supported PHY entities.
Definition: wifi-phy.h:1298
void SetOperatingChannel(const ChannelTuple &channelTuple)
If the standard for this object has not been set yet, store the given channel settings.
Definition: wifi-phy.cc:1098
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1021
Ptr< Event > m_currentEvent
Hold the current event.
Definition: wifi-phy.h:1273
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
Definition: wifi-phy.cc:711
uint64_t m_previouslyRxPpduUid
UID of the previously received PPDU, reset to UINT64_MAX upon transmission.
Definition: wifi-phy.h:1278
std::tuple< uint8_t, uint16_t, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying an operating channel.
Definition: wifi-phy.h:891
void SetReceiveOkCallback(RxOkCallback callback)
Definition: wifi-phy.cc:449
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:2227
This objects implements the PHY state machine of the Wifi device.
Mac48Address GetAddr2() const
Get the Transmitter Address (TA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:128
uint32_t GetSize() const
Return the size of the PSDU in bytes.
Definition: wifi-psdu.cc:273
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.
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
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(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:66
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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:275
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:305
#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:144
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:251
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
@ WIFI_STANDARD_80211ax
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PREAMBLE_HE_SU
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Definition: wifi-phy-band.h:37
@ 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.
double RatioToDb(double ratio)
Convert from ratio to dB.
Definition: wifi-utils.cc:52
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
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:704
@ WIFI_MAC_QOSDATA
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition: wifi-mode.h:35
phy
Definition: third.py:89
uint8_t staNss
Number of spatial streams used for the STA.
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:69
double snr
SNR in linear scale.
Definition: phy-entity.h:70
constexpr uint16_t DEFAULT_CHANNEL_WIDTH
static WifiPhyMuMimoTestSuite WifiPhyMuMimoTestSuite
the test suite
constexpr uint32_t DEFAULT_FREQUENCY
WifiPhyState
The state of the PHY layer.
@ CCA_BUSY
The PHY layer has sense the medium busy through the CCA mechanism.
@ RX
The PHY layer is receiving a packet.
@ IDLE
The PHY layer is IDLE.