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 * 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
46using namespace ns3;
47
48NS_LOG_COMPONENT_DEFINE("WifiPhyMuMimoTest");
49
50constexpr uint32_t DEFAULT_FREQUENCY = 5180; // MHz
51constexpr uint16_t DEFAULT_CHANNEL_WIDTH = 20; // MHz
52
53/**
54 * \ingroup wifi-test
55 * \ingroup tests
56 *
57 * \brief DL MU TX-VECTOR test
58 */
60{
61 public:
63
64 private:
65 void DoRun() override;
66
67 /**
68 * Build a TXVECTOR for DL MU with the given bandwidth and user information.
69 *
70 * \param bw the channel width of the PPDU in MHz
71 * \param userInfos the list of HE MU specific user transmission parameters
72 *
73 * \return the configured MU TXVECTOR
74 */
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
84TestDlMuTxVector::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
99void
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);
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");
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);
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");
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);
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");
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);
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");
179 false,
180 "TX-VECTOR should not indicate all checks are passed");
181}
182
183/**
184 * HE PHY slightly modified so as to return a given
185 * STA-ID in case of DL MU for MuMimoSpectrumWifiPhy.
186 */
187class MuMimoTestHePhy : public HePhy
188{
189 public:
190 /**
191 * Constructor
192 *
193 * \param staId the ID of the STA to which this PHY belongs to
194 */
195 MuMimoTestHePhy(uint16_t staId);
196
197 /**
198 * Return the STA ID that has been assigned to the station this PHY belongs to.
199 * This is typically called for MU PPDUs, in order to pick the correct PSDU.
200 *
201 * \param ppdu the PPDU for which the STA ID is requested
202 * \return the STA ID
203 */
204 uint16_t GetStaId(const Ptr<const WifiPpdu> ppdu) const override;
205
206 /**
207 * Set the global PPDU UID counter.
208 *
209 * \param uid the value to which the global PPDU UID counter should be set
210 */
211 void SetGlobalPpduUid(uint64_t uid);
212
213 private:
214 uint16_t m_staId; ///< ID of the STA to which this PHY belongs to
215}; // class MuMimoTestHePhy
216
218 : HePhy(),
219 m_staId(staId)
220{
221}
222
223uint16_t
225{
226 if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
227 {
228 return m_staId;
229 }
230 return HePhy::GetStaId(ppdu);
231}
232
233void
235{
236 m_globalPpduUid = uid;
237}
238
239/**
240 * SpectrumWifiPhy used for testing MU-MIMO.
241 */
243{
244 public:
245 /**
246 * \brief Get the type ID.
247 * \return the object TypeId
248 */
249 static TypeId GetTypeId();
250 /**
251 * Constructor
252 *
253 * \param staId the ID of the STA to which this PHY belongs to
254 */
255 MuMimoSpectrumWifiPhy(uint16_t staId);
256 ~MuMimoSpectrumWifiPhy() override;
257
258 /**
259 * Set the global PPDU UID counter.
260 *
261 * \param uid the value to which the global PPDU UID counter should be set
262 */
263 void SetPpduUid(uint64_t uid);
264
265 /**
266 * Since we assume trigger frame was previously received from AP, this is used to set its UID
267 *
268 * \param uid the PPDU UID of the trigger frame
269 */
270 void SetTriggerFrameUid(uint64_t uid);
271
272 /**
273 * \return the current event
274 */
276
277 private:
278 void DoInitialize() override;
279 void DoDispose() override;
280
281 Ptr<MuMimoTestHePhy> m_ofdmTestHePhy; ///< Pointer to HE PHY instance used for MU-MIMO test
282}; // class MuMimoSpectrumWifiPhy
283
284TypeId
286{
287 static TypeId tid =
288 TypeId("ns3::MuMimoSpectrumWifiPhy").SetParent<SpectrumWifiPhy>().SetGroupName("Wifi");
289 return tid;
290}
291
294{
295 m_ofdmTestHePhy = Create<MuMimoTestHePhy>(staId);
297}
298
300{
301}
302
303void
305{
306 // Replace HE PHY instance with test instance
309}
310
311void
313{
314 m_ofdmTestHePhy = nullptr;
316}
317
318void
320{
323}
324
325void
327{
329}
330
333{
334 return m_currentEvent;
335}
336
337/**
338 * \ingroup wifi-test
339 * \ingroup tests
340 *
341 * \brief DL MU-MIMO PHY test
342 */
344{
345 public:
347
348 private:
349 void DoSetup() override;
350 void DoTeardown() override;
351 void DoRun() override;
352
353 /**
354 * Receive success function for STA 1
355 * \param psdu the PSDU
356 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
357 * \param txVector the transmit vector
358 * \param statusPerMpdu reception status per MPDU
359 */
361 RxSignalInfo rxSignalInfo,
362 WifiTxVector txVector,
363 std::vector<bool> statusPerMpdu);
364 /**
365 * Receive success function for STA 2
366 * \param psdu the PSDU
367 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
368 * \param txVector the transmit vector
369 * \param statusPerMpdu reception status per MPDU
370 */
372 RxSignalInfo rxSignalInfo,
373 WifiTxVector txVector,
374 std::vector<bool> statusPerMpdu);
375 /**
376 * Receive success function for STA 3
377 * \param psdu the PSDU
378 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
379 * \param txVector the transmit vector
380 * \param statusPerMpdu reception status per MPDU
381 */
383 RxSignalInfo rxSignalInfo,
384 WifiTxVector txVector,
385 std::vector<bool> statusPerMpdu);
386
387 /**
388 * Receive failure function for STA 1
389 * \param psdu the PSDU
390 */
392 /**
393 * Receive failure function for STA 2
394 * \param psdu the PSDU
395 */
397 /**
398 * Receive failure function for STA 3
399 * \param psdu the PSDU
400 */
402
403 /**
404 * Check the results for STA 1
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 CheckResultsSta1(uint32_t expectedRxSuccess,
410 uint32_t expectedRxFailure,
411 uint32_t expectedRxBytes);
412 /**
413 * Check the results for STA 2
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 CheckResultsSta2(uint32_t expectedRxSuccess,
419 uint32_t expectedRxFailure,
420 uint32_t expectedRxBytes);
421 /**
422 * Check the results for STA 3
423 * \param expectedRxSuccess the expected number of RX success
424 * \param expectedRxFailure the expected number of RX failures
425 * \param expectedRxBytes the expected number of RX bytes
426 */
427 void CheckResultsSta3(uint32_t expectedRxSuccess,
428 uint32_t expectedRxFailure,
429 uint32_t expectedRxBytes);
430
431 /**
432 * Reset the results
433 */
434 void ResetResults();
435
436 /**
437 * STA info
438 */
439 struct StaInfo
440 {
441 uint16_t staId; //!< STA ID
442 uint8_t staNss; //!< Number of spatial streams used for the STA
443 };
444
445 /**
446 * Send DL MU-MIMO PPDU function
447 * \param staInfos the STAs infos
448 */
449 void SendMuPpdu(const std::vector<StaInfo>& staInfos);
450
451 /**
452 * Generate interference function
453 * \param interferencePsd the PSD of the interference to be generated
454 * \param duration the duration of the interference
455 */
456 void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
457 /**
458 * Stop interference function
459 */
461
462 /**
463 * Run one function
464 */
465 void RunOne();
466
467 /**
468 * Schedule now to check the PHY state
469 * \param phy the PHY
470 * \param expectedState the expected state of the PHY
471 */
473 /**
474 * Check the PHY state now
475 * \param phy the PHY
476 * \param expectedState the expected state of the PHY
477 */
479
480 uint32_t m_countRxSuccessSta1; ///< count RX success for STA 1
481 uint32_t m_countRxSuccessSta2; ///< count RX success for STA 2
482 uint32_t m_countRxSuccessSta3; ///< count RX success for STA 3
483 uint32_t m_countRxFailureSta1; ///< count RX failure for STA 1
484 uint32_t m_countRxFailureSta2; ///< count RX failure for STA 2
485 uint32_t m_countRxFailureSta3; ///< count RX failure for STA 3
486 uint32_t m_countRxBytesSta1; ///< count RX bytes for STA 1
487 uint32_t m_countRxBytesSta2; ///< count RX bytes for STA 2
488 uint32_t m_countRxBytesSta3; ///< count RX bytes for STA 3
489
494
495 uint8_t m_nss; ///< number of spatial streams per STA
496 uint16_t m_frequency; ///< frequency in MHz
497 uint16_t m_channelWidth; ///< channel width in MHz
498 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
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
519void
521{
531}
532
533void
534TestDlMuMimoPhyTransmission::SendMuPpdu(const std::vector<StaInfo>& staInfos)
535{
536 NS_LOG_FUNCTION(this << staInfos.size());
537 NS_ASSERT(staInfos.size() > 1);
538
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
571
572 NS_ASSERT(txVector.IsDlMuMimo());
573 NS_ASSERT(!txVector.IsDlOfdma());
574
575 m_phyAp->Send(psdus, txVector);
576}
577
578void
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
589void
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
600void
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
611void
613{
614 NS_LOG_FUNCTION(this << *psdu);
616}
617
618void
620{
621 NS_LOG_FUNCTION(this << *psdu);
623}
624
625void
627{
628 NS_LOG_FUNCTION(this << *psdu);
630}
631
632void
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
648void
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
664void
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
680void
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
687}
688
689void
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
705void
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
778void
780{
781 m_phyAp->Dispose();
782 m_phyAp = nullptr;
784 m_phySta1 = nullptr;
786 m_phySta2 = nullptr;
788 m_phySta3 = nullptr;
789}
790
791void
793{
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,
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.
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.
833 this,
834 m_phySta1,
835 WifiPhyState::RX);
838 this,
839 m_phySta2,
840 WifiPhyState::RX);
843 this,
844 m_phySta3,
845 WifiPhyState::CCA_BUSY);
848 this,
849 m_phySta1,
850 WifiPhyState::IDLE);
853 this,
854 m_phySta2,
855 WifiPhyState::IDLE);
858 this,
859 m_phySta3,
860 WifiPhyState::IDLE);
861
862 // One PSDU of 1008 bytes should have been successfully received by STA 1
865 this,
866 1,
867 0,
868 1008);
869 // One PSDU of 1016 bytes should have been successfully received by STA 2
872 this,
873 1,
874 0,
875 1016);
876 // No PSDU should have been received by STA 3
879 this,
880 0,
881 0,
882 0);
883
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.
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.
900 this,
901 m_phySta1,
902 WifiPhyState::RX);
905 this,
906 m_phySta2,
907 WifiPhyState::CCA_BUSY);
910 this,
911 m_phySta3,
912 WifiPhyState::RX);
915 this,
916 m_phySta1,
917 WifiPhyState::IDLE);
920 this,
921 m_phySta2,
922 WifiPhyState::IDLE);
925 this,
926 m_phySta3,
927 WifiPhyState::IDLE);
928
929 // One PSDU of 1008 bytes should have been successfully received by STA 1
932 this,
933 1,
934 0,
935 1008);
936 // No PSDU should have been received by STA 2
939 this,
940 0,
941 0,
942 0);
943 // One PSDU of 1024 bytes should have been successfully received by STA 3
946 this,
947 1,
948 0,
949 1024);
950
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.
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.
967 this,
968 m_phySta1,
969 WifiPhyState::CCA_BUSY);
972 this,
973 m_phySta2,
974 WifiPhyState::RX);
977 this,
978 m_phySta3,
979 WifiPhyState::RX);
982 this,
983 m_phySta1,
984 WifiPhyState::IDLE);
987 this,
988 m_phySta2,
989 WifiPhyState::IDLE);
992 this,
993 m_phySta3,
994 WifiPhyState::IDLE);
995
996 // No PSDU should have been received by STA 1
999 this,
1000 0,
1001 0,
1002 0);
1003 // One PSDU of 1016 bytes should have been successfully received by STA 2
1006 this,
1007 1,
1008 0,
1009 1016);
1010 // One PSDU of 1024 bytes should have been successfully received by STA 3
1013 this,
1014 1,
1015 0,
1016 1024);
1017
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.
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.
1032 this,
1033 m_phySta1,
1034 WifiPhyState::RX);
1037 this,
1038 m_phySta2,
1039 WifiPhyState::RX);
1042 this,
1043 m_phySta3,
1044 WifiPhyState::RX);
1047 this,
1048 m_phySta1,
1049 WifiPhyState::IDLE);
1052 this,
1053 m_phySta2,
1054 WifiPhyState::IDLE);
1057 this,
1058 m_phySta3,
1059 WifiPhyState::IDLE);
1060
1061 // One PSDU of 1008 bytes should have been successfully received by STA 1
1064 this,
1065 1,
1066 0,
1067 1008);
1068 // One PSDU of 1016 bytes should have been successfully received by STA 2
1071 this,
1072 1,
1073 0,
1074 1016);
1075 // One PSDU of 1024 bytes should have been successfully received by STA 3
1078 this,
1079 1,
1080 0,
1081 1024);
1082
1084
1086}
1087
1088void
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
1119}
1120
1121/**
1122 * \ingroup wifi-test
1123 * \ingroup tests
1124 *
1125 * \brief UL MU-MIMO PHY test
1126 */
1128{
1129 public:
1131
1132 private:
1133 void DoSetup() override;
1134 void DoTeardown() override;
1135 void DoRun() override;
1136
1137 /**
1138 * Get TXVECTOR for HE TB PPDU.
1139 * \param txStaId the ID of the TX STA
1140 * \param nss the number of spatial streams used for the transmission
1141 * \param bssColor the BSS color of the TX STA
1142 * \return the TXVECTOR for HE TB PPDU
1143 */
1144 WifiTxVector GetTxVectorForHeTbPpdu(uint16_t txStaId, uint8_t nss, uint8_t bssColor) const;
1145 /**
1146 * Set TRIGVECTOR for HE TB PPDU
1147 *
1148 * \param staIds the IDs of the STAs sollicited for the HE TB transmission
1149 * \param bssColor the BSS color of the TX STA
1150 */
1151 void SetTrigVector(const std::vector<uint16_t>& staIds, uint8_t bssColor);
1152 /**
1153 * Send HE TB PPDU function
1154 * \param txStaId the ID of the TX STA
1155 * \param nss the number of spatial streams used for the transmission
1156 * \param payloadSize the size of the payload in bytes
1157 * \param uid the UID of the trigger frame that is initiating this transmission
1158 * \param bssColor the BSS color of the TX STA
1159 */
1160 void SendHeTbPpdu(uint16_t txStaId,
1161 uint8_t nss,
1162 std::size_t payloadSize,
1163 uint64_t uid,
1164 uint8_t bssColor);
1165
1166 /**
1167 * Send HE SU PPDU function
1168 * \param txStaId the ID of the TX STA
1169 * \param payloadSize the size of the payload in bytes
1170 * \param uid the UID of the trigger frame that is initiating this transmission
1171 * \param bssColor the BSS color of the TX STA
1172 */
1173 void SendHeSuPpdu(uint16_t txStaId, std::size_t payloadSize, uint64_t uid, uint8_t bssColor);
1174
1175 /**
1176 * Set the BSS color
1177 * \param phy the PHY
1178 * \param bssColor the BSS color
1179 */
1180 void SetBssColor(Ptr<WifiPhy> phy, uint8_t bssColor);
1181
1182 /**
1183 * Run one function
1184 */
1185 void RunOne();
1186
1187 /**
1188 * Check the received PSDUs from a given STA
1189 * \param staId the ID of the STA to check
1190 * \param expectedSuccess the expected number of success
1191 * \param expectedFailures the expected number of failures
1192 * \param expectedBytes the expected number of bytes
1193 */
1194 void CheckRxFromSta(uint16_t staId,
1195 uint32_t expectedSuccess,
1196 uint32_t expectedFailures,
1197 uint32_t expectedBytes);
1198
1199 /**
1200 * Verify all events are cleared at end of TX or RX
1201 */
1202 void VerifyEventsCleared();
1203
1204 /**
1205 * Check the PHY state
1206 * \param phy the PHY
1207 * \param expectedState the expected state of the PHY
1208 */
1209 void CheckPhyState(Ptr<MuMimoSpectrumWifiPhy> phy, WifiPhyState expectedState);
1210 /// \copydoc CheckPhyState
1212
1213 /**
1214 * Reset function
1215 */
1216 void Reset();
1217
1218 /**
1219 * Receive success function
1220 * \param psdu the PSDU
1221 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
1222 * \param txVector the transmit vector
1223 * \param statusPerMpdu reception status per MPDU
1224 */
1226 RxSignalInfo rxSignalInfo,
1227 WifiTxVector txVector,
1228 std::vector<bool> statusPerMpdu);
1229
1230 /**
1231 * Receive failure function
1232 * \param psdu the PSDU
1233 */
1234 void RxFailure(Ptr<const WifiPsdu> psdu);
1235
1236 /**
1237 * Schedule test to perform.
1238 * The interference generation should be scheduled apart.
1239 *
1240 * \param delay the reference delay to schedule the events
1241 * \param txStaIds the IDs of the STAs planned to transmit an HE TB PPDU
1242 * \param expectedStateAtEnd the expected state of the PHY at the end of the reception
1243 * \param expectedCountersPerSta the expected counters per STA
1244 */
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
1251 /**
1252 * Log scenario description
1253 *
1254 * \param log the scenario description to add to log
1255 */
1256 void LogScenario(const std::string& log) const;
1257
1259 std::vector<Ptr<MuMimoSpectrumWifiPhy>> m_phyStas; ///< PHYs of STAs
1260
1261 std::vector<uint32_t> m_countRxSuccessFromStas; ///< count RX success from STAs
1262 std::vector<uint32_t> m_countRxFailureFromStas; ///< count RX failure from STAs
1263 std::vector<uint32_t> m_countRxBytesFromStas; ///< count RX bytes from STAs
1264
1265 Time m_delayStart; ///< delay between the start of each HE TB PPDUs
1266 uint16_t m_frequency; ///< frequency in MHz
1267 uint16_t m_channelWidth; ///< channel width in MHz
1268 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
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
1283void
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
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{
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
1348void
1349TestUlMuMimoPhyTransmission::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) =
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
1382void
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
1415void
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
1436void
1438{
1439 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2());
1440 for (std::size_t index = 0; index < m_countRxFailureFromStas.size(); ++index)
1441 {
1442 std::ostringstream addr;
1443 addr << "00:00:00:00:00:0" << index + 1;
1444 if (psdu->GetAddr2() == Mac48Address(addr.str().c_str()))
1445 {
1446 m_countRxFailureFromStas.at(index)++;
1447 break;
1448 }
1449 }
1450}
1451
1452void
1454 uint32_t expectedSuccess,
1455 uint32_t expectedFailures,
1456 uint32_t expectedBytes)
1457{
1458 NS_LOG_FUNCTION(this << staId << expectedSuccess << expectedFailures << expectedBytes);
1460 expectedSuccess,
1461 "The number of successfully received packets from STA "
1462 << staId << " is not correct!");
1464 expectedFailures,
1465 "The number of unsuccessfully received packets from STA "
1466 << staId << " is not correct!");
1468 expectedBytes,
1469 "The number of bytes received from STA " << staId << " is not correct!");
1470}
1471
1472void
1474{
1476 nullptr,
1477 "m_currentEvent for AP was not cleared");
1478 std::size_t sta = 1;
1479 for (auto& phy : m_phyStas)
1480 {
1481 NS_TEST_ASSERT_MSG_EQ(phy->GetCurrentEvent(),
1482 nullptr,
1483 "m_currentEvent for STA " << sta << " was not cleared");
1484 sta++;
1485 }
1486}
1487
1488void
1490 WifiPhyState expectedState)
1491{
1492 // This is needed to make sure PHY state will be checked as the last event if a state change
1493 // occurred at the exact same time as the check
1495}
1496
1497void
1499 WifiPhyState expectedState)
1500{
1501 WifiPhyState currentState;
1502 PointerValue ptr;
1503 phy->GetAttribute("State", ptr);
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
1513void
1515{
1516 for (auto& counter : m_countRxSuccessFromStas)
1517 {
1518 counter = 0;
1519 }
1520 for (auto& counter : m_countRxFailureFromStas)
1521 {
1522 counter = 0;
1523 }
1524 for (auto& counter : m_countRxBytesFromStas)
1525 {
1526 counter = 0;
1527 }
1528 for (auto& phy : m_phyStas)
1529 {
1530 phy->SetPpduUid(0);
1531 phy->SetTriggerFrameUid(0);
1532 }
1533 SetBssColor(m_phyAp, 0);
1534}
1535
1536void
1538{
1539 Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice>(phy->GetDevice());
1540 Ptr<HeConfiguration> heConfiguration = device->GetHeConfiguration();
1541 heConfiguration->SetAttribute("BssColor", UintegerValue(bssColor));
1542}
1543
1544void
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>();
1557 apDev->SetStandard(WIFI_STANDARD_80211ax);
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>();
1580 staDev->SetStandard(WIFI_STANDARD_80211ax);
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
1604void
1606{
1607 for (auto& phy : m_phyStas)
1608 {
1609 phy->Dispose();
1610 phy = nullptr;
1611 }
1612}
1613
1614void
1615TestUlMuMimoPhyTransmission::LogScenario(const std::string& log) const
1616{
1617 NS_LOG_INFO(log);
1618}
1619
1620void
1622 Time delay,
1623 const std::vector<uint16_t>& txStaIds,
1624 WifiPhyState expectedStateAtEnd,
1625 const std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>& expectedCountersPerSta)
1626{
1627 static uint64_t uid = 0;
1628
1629 // AP sends an SU packet preceding HE TB PPDUs
1632 this,
1633 0,
1634 50,
1635 ++uid,
1636 0);
1637
1639
1640 // STAs send MU UL PPDUs addressed to AP
1641 uint16_t payloadSize = 1000;
1642 std::size_t index = 0;
1643 for (auto txStaId : txStaIds)
1644 {
1645 Simulator::Schedule(delay + (index * m_delayStart),
1647 this,
1648 txStaId,
1649 1,
1650 payloadSize,
1651 uid,
1652 0);
1653 payloadSize++;
1654 index++;
1655 }
1656
1657 // Verify it takes m_expectedPpduDuration to transmit the PPDUs
1660 this,
1661 m_phyAp,
1662 WifiPhyState::RX);
1664 (m_delayStart * expectedCountersPerSta.size()),
1666 this,
1667 m_phyAp,
1668 expectedStateAtEnd);
1669
1670 delay += MilliSeconds(100);
1671 // Check reception state from STAs
1672 uint16_t staId = 1;
1673 for (const auto& expectedCounters : expectedCountersPerSta)
1674 {
1675 uint16_t expectedSuccessFromSta = std::get<0>(expectedCounters);
1676 uint16_t expectedFailuresFromSta = std::get<1>(expectedCounters);
1677 uint16_t expectedBytesFromSta = std::get<2>(expectedCounters);
1678 Simulator::Schedule(delay + (m_delayStart * (staId - 1)),
1680 this,
1681 staId,
1682 expectedSuccessFromSta,
1683 expectedFailuresFromSta,
1684 expectedBytesFromSta);
1685 staId++;
1686 }
1687
1688 // Verify events data have been cleared
1690
1691 delay += MilliSeconds(100);
1693}
1694
1695void
1697{
1700 int64_t streamNumber = 0;
1701 m_phyAp->AssignStreams(streamNumber);
1702 for (auto& phy : m_phyStas)
1703 {
1704 phy->AssignStreams(streamNumber);
1705 }
1706
1707 auto channelNum = std::get<0>(*WifiPhyOperatingChannel::FindFirst(0,
1712
1715 for (auto& phy : m_phyStas)
1716 {
1717 phy->SetOperatingChannel(
1719 }
1720
1721 Time delay = Seconds(0.0);
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},
1733 WifiPhyState::IDLE,
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},
1762 WifiPhyState::IDLE,
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
1784 this,
1785 4,
1786 1002,
1787 2,
1788 0);
1789 ScheduleTest(delay,
1790 {1, 2, 3},
1791 WifiPhyState::CCA_BUSY,
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
1803}
1804
1805void
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
1848}
1849
1850/**
1851 * \ingroup wifi-test
1852 * \ingroup tests
1853 *
1854 * \brief wifi PHY MU-MIMO Test Suite
1855 */
1857{
1858 public:
1860};
1861
1863 : TestSuite("wifi-phy-mu-mimo", Type::UNIT)
1864{
1865 AddTestCase(new TestDlMuTxVector, TestCase::Duration::QUICK);
1866 AddTestCase(new TestDlMuMimoPhyTransmission, TestCase::Duration::QUICK);
1867 AddTestCase(new TestUlMuMimoPhyTransmission, TestCase::Duration::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.
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 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.
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
AttributeValue implementation for Boolean.
Definition: boolean.h:37
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
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:575
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:272
RU Specification.
Definition: he-ru.h:66
@ RU_106_TONE
Definition: he-ru.h:44
@ RU_242_TONE
Definition: he-ru.h:45
static RuType GetRuType(uint16_t bandwidth)
Get the RU corresponding to the approximate bandwidth.
Definition: he-ru.cc:792
an EUI-48 address
Definition: mac48-address.h:46
void Dispose()
Dispose of this Object.
Definition: object.cc:258
void SetOwner(Ptr< WifiPhy > wifiPhy)
Set the WifiPhy owning this PHY entity.
Definition: phy-entity.cc:92
static uint64_t m_globalPpduUid
Global counter of the PPDU UID.
Definition: phy-entity.h:1005
AttributeValue implementation for Pointer.
Definition: pointer.h:48
Ptr< T > Get() const
Definition: pointer.h:234
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static void Run()
Run the simulation.
Definition: simulator.cc:178
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:605
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.
encapsulates test code
Definition: test.h:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
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:932
Hold an unsigned integer type.
Definition: uinteger.h:45
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.
void SetNumberOfAntennas(uint8_t antennas)
Definition: wifi-phy.cc:1278
virtual void SetInterferenceHelper(const Ptr< InterferenceHelper > helper)
Sets the interference helper.
Definition: wifi-phy.cc:651
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:1741
void SetErrorRateModel(const Ptr< ErrorRateModel > model)
Sets the error rate model.
Definition: wifi-phy.cc:660
void SetMaxSupportedTxSpatialStreams(uint8_t streams)
Definition: wifi-phy.cc:1296
void SetReceiveErrorCallback(RxErrorCallback callback)
Definition: wifi-phy.cc:462
virtual void ConfigureStandard(WifiStandard standard)
Configure the PHY-level parameters for different Wi-Fi standard.
Definition: wifi-phy.cc:982
std::map< WifiModulationClass, Ptr< PhyEntity > > m_phyEntities
This map holds the supported PHY entities.
Definition: wifi-phy.h:1326
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:1119
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1042
Ptr< Event > m_currentEvent
Hold the current event.
Definition: wifi-phy.h:1301
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
Definition: wifi-phy.cc:733
uint64_t m_previouslyRxPpduUid
UID of the previously received PPDU, reset to UINT64_MAX upon transmission.
Definition: wifi-phy.h:1306
std::tuple< uint8_t, uint16_t, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying an operating channel.
Definition: wifi-phy.h:903
void SetReceiveOkCallback(RxOkCallback callback)
Definition: wifi-phy.cc:456
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:2258
static ConstIterator FindFirst(uint8_t number, uint16_t frequency, uint16_t width, WifiStandard standard, WifiPhyBand band, ConstIterator start=m_frequencyChannels.begin())
Find the first channel 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.
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
#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:145
#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:252
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1343
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1355
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1331
@ 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.
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:706
@ WIFI_MAC_QOSDATA
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition: wifi-mode.h:35
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
constexpr uint32_t DEFAULT_FREQUENCY