A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-phy-ofdma-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 University of Washington
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
7 */
8
9#include "ns3/ap-wifi-mac.h"
10#include "ns3/boolean.h"
11#include "ns3/constant-position-mobility-model.h"
12#include "ns3/ctrl-headers.h"
13#include "ns3/demangle.h"
14#include "ns3/double.h"
15#include "ns3/eht-configuration.h"
16#include "ns3/eht-phy.h"
17#include "ns3/he-configuration.h"
18#include "ns3/he-ppdu.h"
19#include "ns3/interference-helper.h"
20#include "ns3/log.h"
21#include "ns3/mobility-helper.h"
22#include "ns3/multi-model-spectrum-channel.h"
23#include "ns3/nist-error-rate-model.h"
24#include "ns3/node.h"
25#include "ns3/non-communicating-net-device.h"
26#include "ns3/pointer.h"
27#include "ns3/rng-seed-manager.h"
28#include "ns3/simulator.h"
29#include "ns3/spectrum-wifi-helper.h"
30#include "ns3/spectrum-wifi-phy.h"
31#include "ns3/sta-wifi-mac.h"
32#include "ns3/string.h"
33#include "ns3/test.h"
34#include "ns3/threshold-preamble-detection-model.h"
35#include "ns3/txop.h"
36#include "ns3/waveform-generator.h"
37#include "ns3/wifi-mac-header.h"
38#include "ns3/wifi-net-device.h"
39#include "ns3/wifi-phy-listener.h"
40#include "ns3/wifi-psdu.h"
41#include "ns3/wifi-spectrum-phy-interface.h"
42#include "ns3/wifi-spectrum-signal-parameters.h"
43#include "ns3/wifi-spectrum-value-helper.h"
44#include "ns3/wifi-utils.h"
45
46#include <algorithm>
47#include <iterator>
48#include <memory>
49
50using namespace ns3;
51
52NS_LOG_COMPONENT_DEFINE("WifiPhyOfdmaTest");
53
54static const uint8_t DEFAULT_CHANNEL_NUMBER = 36;
55static const MHz_u DEFAULT_FREQUENCY{5180};
59 DEFAULT_CHANNEL_WIDTH; // expanded to channel width to model spectrum mask
60
61/**
62 * PHY entity slightly modified so as to return a given
63 * STA-ID in case of DL MU for OfdmaSpectrumWifiPhy.
64 */
65template <typename PhyEntityType>
67{
68 public:
69 /**
70 * Constructor
71 *
72 * @param staId the ID of the STA to which this PHY belongs to
73 */
74 OfdmaTestPhy(uint16_t staId);
75
76 /**
77 * Return the STA ID that has been assigned to the station this PHY belongs to.
78 * This is typically called for MU PPDUs, in order to pick the correct PSDU.
79 *
80 * @param ppdu the PPDU for which the STA ID is requested
81 * @return the STA ID
82 */
83 uint16_t GetStaId(const Ptr<const WifiPpdu> ppdu) const override;
84
85 /**
86 * Set the global PPDU UID counter.
87 *
88 * @param uid the value to which the global PPDU UID counter should be set
89 */
90 void SetGlobalPpduUid(uint64_t uid);
91
92 /**
93 * Get the band used to transmit the non-OFDMA part of an HE TB PPDU.
94 *
95 * @param txVector the TXVECTOR used for the transmission
96 * @param staId the STA-ID of the station taking part of the UL MU
97 *
98 * @return the spectrum band used to transmit the non-OFDMA part of an HE TB PPDU
99 */
100 WifiSpectrumBandInfo GetNonOfdmaBand(const WifiTxVector& txVector, uint16_t staId) const;
101
102 private:
103 uint16_t m_staId; ///< ID of the STA to which this PHY belongs to
104
105 // end of class OfdmaTestPhy
106};
107
108template <typename PhyEntityType>
110 : PhyEntityType(),
111 m_staId(staId)
112{
113}
114
115template <typename PhyEntityType>
116uint16_t
118{
119 NS_LOG_FUNCTION(this << ppdu);
120 if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
121 {
122 return m_staId;
123 }
124 return PhyEntityType::GetStaId(ppdu);
125}
126
127template <typename PhyEntityType>
128void
130{
131 PhyEntityType::m_globalPpduUid = uid;
132}
133
134template <typename PhyEntityType>
136OfdmaTestPhy<PhyEntityType>::GetNonOfdmaBand(const WifiTxVector& txVector, uint16_t staId) const
137{
138 const auto mc = txVector.GetModulationClass();
139 NS_ASSERT(txVector.IsUlMu() && (mc >= WIFI_MOD_CLASS_HE));
140 const auto channelWidth = txVector.GetChannelWidth();
141 NS_ASSERT(channelWidth <= PhyEntityType::m_wifiPhy->GetChannelWidth());
142
143 auto ru = txVector.GetRu(staId);
144 const auto nonOfdmaWidth = PhyEntityType::GetNonOfdmaWidth(ru);
145
146 // Find the RU that encompasses the non-OFDMA part of the HE TB PPDU for the STA-ID
147 auto nonOfdmaRu = WifiRu::FindOverlappingRu(channelWidth, ru, WifiRu::GetRuType(nonOfdmaWidth));
148
149 const auto groupPreamble = WifiRu::GetSubcarrierGroup(
150 channelWidth,
151 WifiRu::GetRuType(nonOfdmaRu),
153 nonOfdmaRu,
154 channelWidth,
155 PhyEntityType::m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20})),
156 mc);
157 const auto indices = PhyEntityType::ConvertRuSubcarriers(
158 {channelWidth,
159 PhyEntityType::GetGuardBandwidth(PhyEntityType::m_wifiPhy->GetChannelWidth()),
160 PhyEntityType::m_wifiPhy->GetOperatingChannel().GetFrequencies(),
161 PhyEntityType::m_wifiPhy->GetChannelWidth(),
162 PhyEntityType::m_wifiPhy->GetSubcarrierSpacing(),
163 mc,
164 {groupPreamble.front().first, groupPreamble.back().second},
165 PhyEntityType::m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(channelWidth)});
166 WifiSpectrumBandInfo nonOfdmaBand{};
167 for (const auto& indicesPerSegment : indices)
168 {
169 nonOfdmaBand.indices.emplace_back(indicesPerSegment);
170 nonOfdmaBand.frequencies.emplace_back(
171 PhyEntityType::m_wifiPhy->ConvertIndicesToFrequencies(indicesPerSegment));
172 }
173 return nonOfdmaBand;
174}
175
176/**
177 * SpectrumWifiPhy used for testing OFDMA.
178 */
179template <typename LatestPhyEntityType>
181{
182 public:
183 /**
184 * @brief Get the type ID.
185 * @return the object TypeId
186 */
188 /**
189 * Constructor
190 *
191 * @param staId the ID of the STA to which this PHY belongs to
192 */
193 OfdmaSpectrumWifiPhy(uint16_t staId);
194
195 void DoInitialize() override;
196 void DoDispose() override;
197
198 using WifiPhy::Reset;
199 void StartTx(Ptr<const WifiPpdu> ppdu) override;
200
201 /**
202 * TracedCallback signature for UID of transmitted PPDU.
203 *
204 * @param uid the UID of the transmitted PPDU
205 */
206 typedef void (*TxPpduUidCallback)(uint64_t uid);
207
208 /**
209 * Set the global PPDU UID counter.
210 *
211 * @param uid the value to which the global PPDU UID counter should be set
212 */
213 void SetPpduUid(uint64_t uid);
214
215 /**
216 * Since we assume trigger frame was previously received from AP, this is used to set its UID
217 *
218 * @param uid the PPDU UID of the trigger frame
219 */
220 void SetTriggerFrameUid(uint64_t uid);
221
222 /**
223 * @return the current preamble events map
224 */
225 std::map<std::pair<uint64_t, WifiPreamble>, Ptr<Event>>& GetCurrentPreambleEvents();
226 /**
227 * @return the current event
228 */
230
231 /**
232 * Wrapper to InterferenceHelper method.
233 *
234 * @param energy the minimum energy requested
235 * @param band identify the requested band
236 *
237 * @returns the expected amount of time the observed
238 * energy on the medium for a given band will
239 * be higher than the requested threshold.
240 */
242
243 /**
244 * @return a const pointer to the latest PHY entity instance
245 */
247
248 private:
249 /// Pointer to latest PHY entity instance used for OFDMA test
251
252 /// Callback providing UID of the PPDU that is about to be transmitted
254
255 // end of class OfdmaSpectrumWifiPhy
256};
257
258template <typename LatestPhyEntityType>
259TypeId
261{
262 static TypeId tid =
263 TypeId(std::string("ns3::OfdmaSpectrumWifiPhy") +
264 Demangle(typeid(LatestPhyEntityType).name()))
266 .SetGroupName("Wifi")
267 .AddTraceSource("TxPpduUid",
268 "UID of the PPDU to be transmitted",
271 "ns3::OfdmaSpectrumWifiPhy<LatestPhyEntityType>::TxPpduUidCallback");
272 return tid;
273}
274
275template <typename LatestPhyEntityType>
282
283template <typename LatestPhyEntityType>
284void
286{
287 const auto modClass = GetModulationClassForStandard(GetStandard());
288 // Replace PHY instance with test instance
289 m_phyEntities[modClass] = m_ofdmaTestPhy;
291}
292
293template <typename LatestPhyEntityType>
294void
300
301template <typename LatestPhyEntityType>
302void
304{
305 m_ofdmaTestPhy->SetGlobalPpduUid(uid);
306 m_previouslyRxPpduUid = uid;
307}
308
309template <typename LatestPhyEntityType>
310void
312{
313 m_previouslyRxPpduUid = uid;
314}
315
316template <typename LatestPhyEntityType>
317void
319{
320 m_phyTxPpduUidTrace(ppdu->GetUid());
322}
323
324template <typename LatestPhyEntityType>
325std::map<std::pair<uint64_t, WifiPreamble>, Ptr<Event>>&
327{
328 return m_currentPreambleEvents;
329}
330
331template <typename LatestPhyEntityType>
337
338template <typename LatestPhyEntityType>
339Time
342{
343 return m_interference->GetEnergyDuration(energy, band);
344}
345
346template <typename LatestPhyEntityType>
349{
350 return DynamicCast<LatestPhyEntityType>(m_ofdmaTestPhy /*GetLatestPhyEntity()*/);
351}
352
353/**
354 * @ingroup wifi-test
355 * @ingroup tests
356 *
357 * @brief DL-OFDMA PHY test
358 */
359template <typename LatestPhyEntityType>
361{
362 public:
363 /**
364 * Constructor
365 */
367
368 private:
369 void DoSetup() override;
370 void DoTeardown() override;
371 void DoRun() override;
372
373 /**
374 * Receive success function for STA 1
375 * @param psdu the PSDU
376 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
377 * @param txVector the transmit vector
378 * @param statusPerMpdu reception status per MPDU
379 */
381 RxSignalInfo rxSignalInfo,
382 const WifiTxVector& txVector,
383 const std::vector<bool>& statusPerMpdu);
384 /**
385 * Receive success function for STA 2
386 * @param psdu the PSDU
387 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
388 * @param txVector the transmit vector
389 * @param statusPerMpdu reception status per MPDU
390 */
392 RxSignalInfo rxSignalInfo,
393 const WifiTxVector& txVector,
394 const std::vector<bool>& statusPerMpdu);
395 /**
396 * Receive success function for STA 3
397 * @param psdu the PSDU
398 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
399 * @param txVector the transmit vector
400 * @param statusPerMpdu reception status per MPDU
401 */
403 RxSignalInfo rxSignalInfo,
404 const WifiTxVector& txVector,
405 const std::vector<bool>& statusPerMpdu);
406
407 /**
408 * Receive failure function for STA 1
409 * @param psdu the PSDU
410 */
412 /**
413 * Receive failure function for STA 2
414 * @param psdu the PSDU
415 */
417 /**
418 * Receive failure function for STA 3
419 * @param psdu the PSDU
420 */
422
423 /**
424 * Check the results for STA 1
425 * @param expectedRxSuccess the expected number of RX success
426 * @param expectedRxFailure the expected number of RX failures
427 * @param expectedRxBytes the expected number of RX bytes
428 */
429 void CheckResultsSta1(uint32_t expectedRxSuccess,
430 uint32_t expectedRxFailure,
431 uint32_t expectedRxBytes);
432 /**
433 * Check the results for STA 2
434 * @param expectedRxSuccess the expected number of RX success
435 * @param expectedRxFailure the expected number of RX failures
436 * @param expectedRxBytes the expected number of RX bytes
437 */
438 void CheckResultsSta2(uint32_t expectedRxSuccess,
439 uint32_t expectedRxFailure,
440 uint32_t expectedRxBytes);
441 /**
442 * Check the results for STA 3
443 * @param expectedRxSuccess the expected number of RX success
444 * @param expectedRxFailure the expected number of RX failures
445 * @param expectedRxBytes the expected number of RX bytes
446 */
447 void CheckResultsSta3(uint32_t expectedRxSuccess,
448 uint32_t expectedRxFailure,
449 uint32_t expectedRxBytes);
450
451 /**
452 * Reset the results
453 */
454 void ResetResults();
455
456 /**
457 * Send MU-PPDU function
458 * @param rxStaId1 the ID of the recipient STA for the first PSDU
459 * @param rxStaId2 the ID of the recipient STA for the second PSDU
460 */
461 void SendMuPpdu(uint16_t rxStaId1, uint16_t rxStaId2);
462
463 /**
464 * Generate interference function
465 * @param interferencePsd the PSD of the interference to be generated
466 * @param duration the duration of the interference
467 */
468 void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
469 /**
470 * Stop interference function
471 */
472 void StopInterference();
473
474 /**
475 * Run one function
476 */
477 void RunOne();
478
479 /**
480 * Schedule now to check the PHY state
481 * @param phy the PHY
482 * @param expectedState the expected state of the PHY
483 */
485 WifiPhyState expectedState);
486 /**
487 * Check the PHY state now
488 * @param phy the PHY
489 * @param expectedState the expected state of the PHY
490 */
492 WifiPhyState expectedState);
493
494 WifiModulationClass m_modClass; ///< the modulation class to consider for the test
495
496 uint32_t m_countRxSuccessSta1{0}; ///< count RX success for STA 1
497 uint32_t m_countRxSuccessSta2{0}; ///< count RX success for STA 2
498 uint32_t m_countRxSuccessSta3{0}; ///< count RX success for STA 3
499 uint32_t m_countRxFailureSta1{0}; ///< count RX failure for STA 1
500 uint32_t m_countRxFailureSta2{0}; ///< count RX failure for STA 2
501 uint32_t m_countRxFailureSta3{0}; ///< count RX failure for STA 3
502 uint32_t m_countRxBytesSta1{0}; ///< count RX bytes for STA 1
503 uint32_t m_countRxBytesSta2{0}; ///< count RX bytes for STA 2
504 uint32_t m_countRxBytesSta3{0}; ///< count RX bytes for STA 3
505
511
514 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
515};
516
517template <typename LatestPhyEntityType>
519 : TestCase{std::string("DL-OFDMA PHY test for ") +
520 ((Demangle(typeid(LatestPhyEntityType).name()).find("He") != std::string::npos)
521 ? "HE"
522 : "EHT")},
523 m_modClass{(Demangle(typeid(LatestPhyEntityType).name()).find("He") != std::string::npos)
526 m_expectedPpduDuration{NanoSeconds(306400)}
527{
528}
529
530template <typename LatestPhyEntityType>
531void
533{
534 m_countRxSuccessSta1 = 0;
535 m_countRxSuccessSta2 = 0;
536 m_countRxSuccessSta3 = 0;
537 m_countRxFailureSta1 = 0;
538 m_countRxFailureSta2 = 0;
539 m_countRxFailureSta3 = 0;
540 m_countRxBytesSta1 = 0;
541 m_countRxBytesSta2 = 0;
542 m_countRxBytesSta3 = 0;
543}
544
545template <typename LatestPhyEntityType>
546void
548{
549 NS_LOG_FUNCTION(this << rxStaId1 << rxStaId2);
550 WifiConstPsduMap psdus;
551 WifiTxVector txVector{
553 0,
555 NanoSeconds(800),
556 1,
557 1,
558 0,
559 m_channelWidth,
560 false,
561 false};
562 if (m_modClass == WIFI_MOD_CLASS_EHT)
563 {
564 txVector.SetEhtPpduType(0);
565 }
566 auto ruType{RuType::RU_TYPE_MAX};
567 if (m_channelWidth == MHz_u{20})
568 {
569 ruType = RuType::RU_106_TONE;
570 const uint16_t ruAllocPer20 = (m_modClass == WIFI_MOD_CLASS_HE) ? 96 : 48;
571 txVector.SetRuAllocation({ruAllocPer20}, 0);
572 }
573 else if (m_channelWidth == MHz_u{40})
574 {
575 ruType = RuType::RU_242_TONE;
576 const uint16_t ruAllocPer20 = (m_modClass == WIFI_MOD_CLASS_HE) ? 192 : 64;
577 txVector.SetRuAllocation({ruAllocPer20, ruAllocPer20}, 0);
578 }
579 else if (m_channelWidth == MHz_u{80})
580 {
581 ruType = RuType::RU_484_TONE;
582 const uint16_t ruAllocUser = (m_modClass == WIFI_MOD_CLASS_HE) ? 200 : 72;
583 const uint16_t ruAllocNoUser = (m_modClass == WIFI_MOD_CLASS_HE) ? 114 : 29;
584 txVector.SetRuAllocation({ruAllocUser, ruAllocNoUser, ruAllocNoUser, ruAllocUser}, 0);
585 }
586 else if (m_channelWidth == MHz_u{160})
587 {
588 ruType = RuType::RU_996_TONE;
589 const uint16_t ruAllocUser = (m_modClass == WIFI_MOD_CLASS_HE) ? 208 : 80;
590 const uint16_t ruAllocNoUser = (m_modClass == WIFI_MOD_CLASS_HE) ? 115 : 30;
591 txVector.SetRuAllocation({ruAllocUser,
592 ruAllocNoUser,
593 ruAllocUser,
594 ruAllocNoUser,
595 ruAllocNoUser,
596 ruAllocUser,
597 ruAllocNoUser,
598 ruAllocUser},
599 0);
600 }
601 else if (m_channelWidth == MHz_u{320})
602 {
603 NS_ASSERT(m_modClass >= WIFI_MOD_CLASS_EHT);
604 ruType = RuType::RU_2x996_TONE;
605 txVector.SetRuAllocation({88, 30, 88, 30, 88, 30, 88, 30, 30, 88, 30, 88, 30, 88, 30, 88},
606 0);
607 }
608 else
609 {
610 NS_ASSERT_MSG(false, "Unsupported channel width: " << m_channelWidth);
611 }
612
613 txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
614
615 const auto ru1 = (m_modClass == WIFI_MOD_CLASS_HE)
616 ? WifiRu::RuSpec(HeRu::RuSpec{ruType, 1, true})
617 : WifiRu::RuSpec(EhtRu::RuSpec{ruType, 1, true, true});
618 txVector.SetRu(ru1, rxStaId1);
619 txVector.SetMode((m_modClass == WIFI_MOD_CLASS_HE) ? HePhy::GetHeMcs7() : EhtPhy::GetEhtMcs7(),
620 rxStaId1);
621 txVector.SetNss(1, rxStaId1);
622
623 std::size_t ru2Index = (m_channelWidth > MHz_u{80}) ? 1 : 2;
624 const auto ru2 =
625 (m_modClass == WIFI_MOD_CLASS_HE)
626 ? WifiRu::RuSpec(HeRu::RuSpec{ruType, ru2Index, m_channelWidth != MHz_u{160}})
627 : WifiRu::RuSpec(EhtRu::RuSpec{ruType, ru2Index, m_channelWidth != MHz_u{320}, true});
628 txVector.SetRu(ru2, rxStaId2);
629 txVector.SetMode((m_modClass == WIFI_MOD_CLASS_HE) ? HePhy::GetHeMcs9() : EhtPhy::GetEhtMcs9(),
630 rxStaId2);
631 txVector.SetNss(1, rxStaId2);
632
633 Ptr<Packet> pkt1 = Create<Packet>(1000);
634 WifiMacHeader hdr1;
636 hdr1.SetQosTid(0);
637 hdr1.SetAddr1(Mac48Address("00:00:00:00:00:01"));
638 hdr1.SetSequenceNumber(1);
639 Ptr<WifiPsdu> psdu1 = Create<WifiPsdu>(pkt1, hdr1);
640 psdus.insert(std::make_pair(rxStaId1, psdu1));
641
642 Ptr<Packet> pkt2 = Create<Packet>(1500);
643 WifiMacHeader hdr2;
645 hdr2.SetQosTid(0);
646 hdr2.SetAddr1(Mac48Address("00:00:00:00:00:02"));
647 hdr2.SetSequenceNumber(2);
648 Ptr<WifiPsdu> psdu2 = Create<WifiPsdu>(pkt2, hdr2);
649 psdus.insert(std::make_pair(rxStaId2, psdu2));
650
651 m_phyAp->Send(psdus, txVector);
652}
653
654template <typename LatestPhyEntityType>
655void
657 Ptr<SpectrumValue> interferencePsd,
658 Time duration)
659{
660 m_phyInterferer->SetTxPowerSpectralDensity(interferencePsd);
661 m_phyInterferer->SetPeriod(duration);
662 m_phyInterferer->Start();
663 Simulator::Schedule(duration,
665 this);
666}
667
668template <typename LatestPhyEntityType>
669void
674
675template <typename LatestPhyEntityType>
676void
679 RxSignalInfo rxSignalInfo,
680 const WifiTxVector& txVector,
681 const std::vector<bool>& /*statusPerMpdu*/)
682{
683 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
684 m_countRxSuccessSta1++;
685 m_countRxBytesSta1 += (psdu->GetSize() - 30);
686}
687
688template <typename LatestPhyEntityType>
689void
692 RxSignalInfo rxSignalInfo,
693 const WifiTxVector& txVector,
694 const std::vector<bool>& /*statusPerMpdu*/)
695{
696 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
697 m_countRxSuccessSta2++;
698 m_countRxBytesSta2 += (psdu->GetSize() - 30);
699}
700
701template <typename LatestPhyEntityType>
702void
705 RxSignalInfo rxSignalInfo,
706 const WifiTxVector& txVector,
707 const std::vector<bool>& /*statusPerMpdu*/)
708{
709 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
710 m_countRxSuccessSta3++;
711 m_countRxBytesSta3 += (psdu->GetSize() - 30);
712}
713
714template <typename LatestPhyEntityType>
715void
717{
718 NS_LOG_FUNCTION(this << *psdu);
719 m_countRxFailureSta1++;
720}
721
722template <typename LatestPhyEntityType>
723void
725{
726 NS_LOG_FUNCTION(this << *psdu);
727 m_countRxFailureSta2++;
728}
729
730template <typename LatestPhyEntityType>
731void
733{
734 NS_LOG_FUNCTION(this << *psdu);
735 m_countRxFailureSta3++;
736}
737
738template <typename LatestPhyEntityType>
739void
741 uint32_t expectedRxFailure,
742 uint32_t expectedRxBytes)
743{
744 NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessSta1,
745 expectedRxSuccess,
746 "The number of successfully received packets by STA 1 is not correct!");
747 NS_TEST_ASSERT_MSG_EQ(m_countRxFailureSta1,
748 expectedRxFailure,
749 "The number of unsuccessfully received packets by STA 1 is not correct!");
750 NS_TEST_ASSERT_MSG_EQ(m_countRxBytesSta1,
751 expectedRxBytes,
752 "The number of bytes received by STA 1 is not correct!");
753}
754
755template <typename LatestPhyEntityType>
756void
758 uint32_t expectedRxFailure,
759 uint32_t expectedRxBytes)
760{
761 NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessSta2,
762 expectedRxSuccess,
763 "The number of successfully received packets by STA 2 is not correct!");
764 NS_TEST_ASSERT_MSG_EQ(m_countRxFailureSta2,
765 expectedRxFailure,
766 "The number of unsuccessfully received packets by STA 2 is not correct!");
767 NS_TEST_ASSERT_MSG_EQ(m_countRxBytesSta2,
768 expectedRxBytes,
769 "The number of bytes received by STA 2 is not correct!");
770}
771
772template <typename LatestPhyEntityType>
773void
775 uint32_t expectedRxFailure,
776 uint32_t expectedRxBytes)
777{
778 NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessSta3,
779 expectedRxSuccess,
780 "The number of successfully received packets by STA 3 is not correct!");
781 NS_TEST_ASSERT_MSG_EQ(m_countRxFailureSta3,
782 expectedRxFailure,
783 "The number of unsuccessfully received packets by STA 3 is not correct!");
784 NS_TEST_ASSERT_MSG_EQ(m_countRxBytesSta3,
785 expectedRxBytes,
786 "The number of bytes received by STA 3 is not correct!");
787}
788
789template <typename LatestPhyEntityType>
790void
793 WifiPhyState expectedState)
794{
795 // This is needed to make sure PHY state will be checked as the last event if a state change
796 // occurred at the exact same time as the check
798 this,
799 phy,
800 expectedState);
801}
802
803template <typename LatestPhyEntityType>
804void
807 WifiPhyState expectedState)
808{
809 WifiPhyState currentState;
810 PointerValue ptr;
811 phy->GetAttribute("State", ptr);
813 currentState = state->GetState();
814 NS_LOG_FUNCTION(this << currentState);
815 NS_TEST_ASSERT_MSG_EQ(currentState,
816 expectedState,
817 "PHY State " << currentState << " does not match expected state "
818 << expectedState << " at " << Simulator::Now());
819}
820
821template <typename LatestPhyEntityType>
822void
824{
825 const auto standard =
827
830 lossModel->SetFrequency(MHzToHz(m_frequency));
831 spectrumChannel->AddPropagationLossModel(lossModel);
834 spectrumChannel->SetPropagationDelayModel(delayModel);
835
836 Ptr<Node> apNode = CreateObject<Node>();
840 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
842 m_phyAp->SetErrorRateModel(apErrorModel);
843 m_phyAp->SetDevice(apDev);
844 m_phyAp->AddChannel(spectrumChannel);
845 m_phyAp->ConfigureStandard(standard);
847 m_phyAp->SetMobility(apMobility);
848 apDev->SetPhy(m_phyAp);
849 apNode->AggregateObject(apMobility);
850 apNode->AddDevice(apDev);
851 apDev->SetStandard(standard);
852 if (m_modClass >= WIFI_MOD_CLASS_EHT)
853 {
854 apDev->SetEhtConfiguration(CreateObject<EhtConfiguration>());
855 }
856
857 Ptr<Node> sta1Node = CreateObject<Node>();
861 m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
863 m_phySta1->SetErrorRateModel(sta1ErrorModel);
864 m_phySta1->SetDevice(sta1Dev);
865 m_phySta1->AddChannel(spectrumChannel);
866 m_phySta1->ConfigureStandard(standard);
867 m_phySta1->SetReceiveOkCallback(
869 m_phySta1->SetReceiveErrorCallback(
872 m_phySta1->SetMobility(sta1Mobility);
873 sta1Dev->SetPhy(m_phySta1);
874 sta1Node->AggregateObject(sta1Mobility);
875 sta1Node->AddDevice(sta1Dev);
876 sta1Dev->SetStandard(standard);
877 if (m_modClass >= WIFI_MOD_CLASS_EHT)
878 {
879 sta1Dev->SetEhtConfiguration(CreateObject<EhtConfiguration>());
880 }
881
882 Ptr<Node> sta2Node = CreateObject<Node>();
886 m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
888 m_phySta2->SetErrorRateModel(sta2ErrorModel);
889 m_phySta2->SetDevice(sta2Dev);
890 m_phySta2->AddChannel(spectrumChannel);
891 m_phySta2->ConfigureStandard(standard);
892 m_phySta2->SetReceiveOkCallback(
894 m_phySta2->SetReceiveErrorCallback(
897 m_phySta2->SetMobility(sta2Mobility);
898 sta2Dev->SetPhy(m_phySta2);
899 sta2Node->AggregateObject(sta2Mobility);
900 sta2Node->AddDevice(sta2Dev);
901 sta2Dev->SetStandard(standard);
902 if (m_modClass >= WIFI_MOD_CLASS_EHT)
903 {
904 sta2Dev->SetEhtConfiguration(CreateObject<EhtConfiguration>());
905 }
906
907 Ptr<Node> sta3Node = CreateObject<Node>();
911 m_phySta3->SetInterferenceHelper(sta3InterferenceHelper);
913 m_phySta3->SetErrorRateModel(sta3ErrorModel);
914 m_phySta3->SetDevice(sta3Dev);
915 m_phySta3->AddChannel(spectrumChannel);
916 m_phySta3->ConfigureStandard(standard);
917 sta3Dev->SetEhtConfiguration(CreateObject<EhtConfiguration>());
918 m_phySta3->SetReceiveOkCallback(
920 m_phySta3->SetReceiveErrorCallback(
923 m_phySta3->SetMobility(sta3Mobility);
924 sta3Dev->SetPhy(m_phySta3);
925 sta3Node->AggregateObject(sta3Mobility);
926 sta3Node->AddDevice(sta3Dev);
927 sta3Dev->SetStandard(standard);
928 if (m_modClass >= WIFI_MOD_CLASS_EHT)
929 {
930 sta3Dev->SetEhtConfiguration(CreateObject<EhtConfiguration>());
931 }
932
933 Ptr<Node> interfererNode = CreateObject<Node>();
935 m_phyInterferer = CreateObject<WaveformGenerator>();
936 m_phyInterferer->SetDevice(interfererDev);
937 m_phyInterferer->SetChannel(spectrumChannel);
938 m_phyInterferer->SetDutyCycle(1);
939 interfererNode->AddDevice(interfererDev);
940}
941
942template <typename LatestPhyEntityType>
943void
945{
946 m_phyAp->Dispose();
947 m_phyAp = nullptr;
948 m_phySta1->Dispose();
949 m_phySta1 = nullptr;
950 m_phySta2->Dispose();
951 m_phySta2 = nullptr;
952 m_phySta3->Dispose();
953 m_phySta3 = nullptr;
954 m_phyInterferer->Dispose();
955 m_phyInterferer = nullptr;
956}
957
958template <typename LatestPhyEntityType>
959void
961{
964 int64_t streamNumber = 0;
965 m_phyAp->AssignStreams(streamNumber);
966 m_phySta1->AssignStreams(streamNumber);
967 m_phySta2->AssignStreams(streamNumber);
968 m_phySta3->AssignStreams(streamNumber);
969
970 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
971 m_frequency,
972 m_channelWidth,
975 ->number;
976
977 const auto operatingChannel{
978 WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_6GHZ, 0}};
979 m_phyAp->SetOperatingChannel(operatingChannel);
980 m_phySta1->SetOperatingChannel(operatingChannel);
981 m_phySta2->SetOperatingChannel(operatingChannel);
982 m_phySta3->SetOperatingChannel(operatingChannel);
983
986 this);
987
988 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2:
989 // Each STA should receive its PSDU.
992 this,
993 1,
994 2);
995
996 // Since it takes m_expectedPpduDuration to transmit the PPDU,
997 // all 3 PHYs should be back to IDLE at the same time,
998 // even the PHY that has no PSDU addressed to it.
999 Simulator::Schedule(Seconds(1) + m_expectedPpduDuration - NanoSeconds(1),
1001 this,
1002 m_phySta1,
1003 WifiPhyState::RX);
1004
1005 Simulator::Schedule(Seconds(1) + m_expectedPpduDuration - NanoSeconds(1),
1007 this,
1008 m_phySta2,
1009 WifiPhyState::RX);
1010 Simulator::Schedule(Seconds(1) + m_expectedPpduDuration - NanoSeconds(1),
1012 this,
1013 m_phySta3,
1014 WifiPhyState::CCA_BUSY);
1015 Simulator::Schedule(Seconds(1) + m_expectedPpduDuration,
1017 this,
1018 m_phySta1,
1019 WifiPhyState::IDLE);
1020 Simulator::Schedule(Seconds(1) + m_expectedPpduDuration,
1022 this,
1023 m_phySta2,
1024 WifiPhyState::IDLE);
1025 Simulator::Schedule(Seconds(1) + m_expectedPpduDuration,
1027 this,
1028 m_phySta3,
1029 WifiPhyState::IDLE);
1030
1031 // One PSDU of 1000 bytes should have been successfully received by STA 1
1034 this,
1035 1,
1036 0,
1037 1000);
1038 // One PSDU of 1500 bytes should have been successfully received by STA 2
1041 this,
1042 1,
1043 0,
1044 1500);
1045 // No PSDU should have been received by STA 3
1048 this,
1049 0,
1050 0,
1051 0);
1052
1055 this);
1056
1057 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 3:
1058 // STA 1 should receive its PSDU, whereas STA 2 should not receive any PSDU
1059 // but should keep its PHY busy during all PPDU duration.
1062 this,
1063 1,
1064 3);
1065
1066 // Since it takes m_expectedPpduDuration to transmit the PPDU,
1067 // all 3 PHYs should be back to IDLE at the same time,
1068 // even the PHY that has no PSDU addressed to it.
1069 Simulator::Schedule(Seconds(2) + m_expectedPpduDuration - NanoSeconds(1),
1071 this,
1072 m_phySta1,
1073 WifiPhyState::RX);
1074 Simulator::Schedule(Seconds(2) + m_expectedPpduDuration - NanoSeconds(1),
1076 this,
1077 m_phySta2,
1078 WifiPhyState::CCA_BUSY);
1079 Simulator::Schedule(Seconds(2) + m_expectedPpduDuration - NanoSeconds(1),
1081 this,
1082 m_phySta3,
1083 WifiPhyState::RX);
1084 Simulator::Schedule(Seconds(2) + m_expectedPpduDuration,
1086 this,
1087 m_phySta1,
1088 WifiPhyState::IDLE);
1089 Simulator::Schedule(Seconds(2) + m_expectedPpduDuration,
1091 this,
1092 m_phySta2,
1093 WifiPhyState::IDLE);
1094 Simulator::Schedule(Seconds(2) + m_expectedPpduDuration,
1096 this,
1097 m_phySta3,
1098 WifiPhyState::IDLE);
1099
1100 // One PSDU of 1000 bytes should have been successfully received by STA 1
1103 this,
1104 1,
1105 0,
1106 1000);
1107 // No PSDU should have been received by STA 2
1110 this,
1111 0,
1112 0,
1113 0);
1114 // One PSDU of 1500 bytes should have been successfully received by STA 3
1117 this,
1118 1,
1119 0,
1120 1500);
1121
1124 this);
1125
1126 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2:
1129 this,
1130 1,
1131 2);
1132
1133 // A strong non-wifi interference is generated on RU 1 during PSDU reception
1134 BandInfo bandInfo;
1135 bandInfo.fc = MHzToHz(m_frequency - (m_channelWidth / 4));
1136 bandInfo.fl = bandInfo.fc - MHzToHz(m_channelWidth / 4);
1137 bandInfo.fh = bandInfo.fc + MHzToHz(m_channelWidth / 4);
1138 Bands bands;
1139 bands.push_back(bandInfo);
1140
1141 auto SpectrumInterferenceRu1 = Create<SpectrumModel>(bands);
1142 auto interferencePsdRu1 = Create<SpectrumValue>(SpectrumInterferenceRu1);
1143 Watt_u interferencePower{0.1};
1144 *interferencePsdRu1 = interferencePower / (MHzToHz(m_channelWidth / 2) * 20);
1145
1148 this,
1149 interferencePsdRu1,
1150 MilliSeconds(100));
1151
1152 // Since it takes m_expectedPpduDuration to transmit the PPDU,
1153 // both PHYs should be back to CCA_BUSY (due to the interference) at the same time,
1154 // even the PHY that has no PSDU addressed to it.
1155 Simulator::Schedule(Seconds(3) + m_expectedPpduDuration - NanoSeconds(1),
1157 this,
1158 m_phySta1,
1159 WifiPhyState::RX);
1160 Simulator::Schedule(Seconds(3) + m_expectedPpduDuration - NanoSeconds(1),
1162 this,
1163 m_phySta2,
1164 WifiPhyState::RX);
1165 Simulator::Schedule(Seconds(3) + m_expectedPpduDuration - NanoSeconds(1),
1167 this,
1168 m_phySta3,
1169 WifiPhyState::CCA_BUSY);
1170 Simulator::Schedule(Seconds(3) + m_expectedPpduDuration,
1172 this,
1173 m_phySta1,
1174 WifiPhyState::CCA_BUSY);
1175 Simulator::Schedule(Seconds(3) + m_expectedPpduDuration,
1177 this,
1178 m_phySta2,
1179 WifiPhyState::CCA_BUSY);
1180 Simulator::Schedule(Seconds(3) + m_expectedPpduDuration,
1182 this,
1183 m_phySta3,
1184 WifiPhyState::CCA_BUSY);
1185
1186 // One PSDU of 1000 bytes should have been unsuccessfully received by STA 1 (since interference
1187 // occupies RU 1)
1190 this,
1191 0,
1192 1,
1193 0);
1194 // One PSDU of 1500 bytes should have been successfully received by STA 2
1197 this,
1198 1,
1199 0,
1200 1500);
1201 // No PSDU should have been received by STA3
1204 this,
1205 0,
1206 0,
1207 0);
1208
1211 this);
1212
1213 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2:
1216 this,
1217 1,
1218 2);
1219
1220 // A strong non-wifi interference is generated on RU 2 during PSDU reception
1221 bandInfo.fc = MHzToHz(m_frequency + (m_channelWidth / 4));
1222 bandInfo.fl = bandInfo.fc - MHzToHz(m_channelWidth / 4);
1223 bandInfo.fh = bandInfo.fc + MHzToHz(m_channelWidth / 4);
1224 bands.clear();
1225 bands.push_back(bandInfo);
1226
1227 Ptr<SpectrumModel> SpectrumInterferenceRu2 = Create<SpectrumModel>(bands);
1228 Ptr<SpectrumValue> interferencePsdRu2 = Create<SpectrumValue>(SpectrumInterferenceRu2);
1229 *interferencePsdRu2 = interferencePower / (MHzToHz(m_channelWidth / 2) * 20);
1230
1233 this,
1234 interferencePsdRu2,
1235 MilliSeconds(100));
1236
1237 // Since it takes m_expectedPpduDuration to transmit the PPDU,
1238 // both PHYs should be back to IDLE (or CCA_BUSY if interference on the primary 20 MHz) at the
1239 // same time, even the PHY that has no PSDU addressed to it.
1240 Simulator::Schedule(Seconds(4) + m_expectedPpduDuration - NanoSeconds(1),
1242 this,
1243 m_phySta1,
1244 WifiPhyState::RX);
1245 Simulator::Schedule(Seconds(4) + m_expectedPpduDuration - NanoSeconds(1),
1247 this,
1248 m_phySta2,
1249 WifiPhyState::RX);
1250 Simulator::Schedule(Seconds(4) + m_expectedPpduDuration - NanoSeconds(1),
1252 this,
1253 m_phySta3,
1254 WifiPhyState::CCA_BUSY);
1255 Simulator::Schedule(Seconds(4) + m_expectedPpduDuration,
1257 this,
1258 m_phySta1,
1259 (m_channelWidth >= MHz_u{40}) ? WifiPhyState::IDLE
1260 : WifiPhyState::CCA_BUSY);
1261 Simulator::Schedule(Seconds(4) + m_expectedPpduDuration,
1263 this,
1264 m_phySta2,
1265 (m_channelWidth >= MHz_u{40}) ? WifiPhyState::IDLE
1266 : WifiPhyState::CCA_BUSY);
1267 Simulator::Schedule(Seconds(4) + m_expectedPpduDuration,
1269 this,
1270 m_phySta3,
1271 (m_channelWidth >= MHz_u{40}) ? WifiPhyState::IDLE
1272 : WifiPhyState::CCA_BUSY);
1273
1274 // One PSDU of 1000 bytes should have been successfully received by STA 1
1277 this,
1278 1,
1279 0,
1280 1000);
1281 // One PSDU of 1500 bytes should have been unsuccessfully received by STA 2 (since interference
1282 // occupies RU 2)
1285 this,
1286 0,
1287 1,
1288 0);
1289 // No PSDU should have been received by STA3
1292 this,
1293 0,
1294 0,
1295 0);
1296
1299 this);
1300
1301 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2:
1304 this,
1305 1,
1306 2);
1307
1308 // A strong non-wifi interference is generated on the full band during PSDU reception
1309 bandInfo.fc = MHzToHz(m_frequency);
1310 bandInfo.fl = bandInfo.fc - MHzToHz(m_channelWidth / 2);
1311 bandInfo.fh = bandInfo.fc + MHzToHz(m_channelWidth / 2);
1312 bands.clear();
1313 bands.push_back(bandInfo);
1314
1315 Ptr<SpectrumModel> SpectrumInterferenceAll = Create<SpectrumModel>(bands);
1316 Ptr<SpectrumValue> interferencePsdAll = Create<SpectrumValue>(SpectrumInterferenceAll);
1317 *interferencePsdAll = interferencePower / (MHzToHz(m_channelWidth) * 20);
1318
1321 this,
1322 interferencePsdAll,
1323 MilliSeconds(100));
1324
1325 // Since it takes m_expectedPpduDuration to transmit the PPDU,
1326 // both PHYs should be back to CCA_BUSY (due to the interference) at the same time,
1327 // even the PHY that has no PSDU addressed to it.
1328 Simulator::Schedule(Seconds(5) + m_expectedPpduDuration - NanoSeconds(1),
1330 this,
1331 m_phySta1,
1332 WifiPhyState::RX);
1333 Simulator::Schedule(Seconds(5) + m_expectedPpduDuration - NanoSeconds(1),
1335 this,
1336 m_phySta2,
1337 WifiPhyState::RX);
1338 Simulator::Schedule(Seconds(5) + m_expectedPpduDuration - NanoSeconds(1),
1340 this,
1341 m_phySta3,
1342 WifiPhyState::CCA_BUSY);
1343 Simulator::Schedule(Seconds(5) + m_expectedPpduDuration,
1345 this,
1346 m_phySta1,
1347 WifiPhyState::CCA_BUSY);
1348 Simulator::Schedule(Seconds(5) + m_expectedPpduDuration,
1350 this,
1351 m_phySta2,
1352 WifiPhyState::CCA_BUSY);
1353 Simulator::Schedule(Seconds(5) + m_expectedPpduDuration,
1355 this,
1356 m_phySta3,
1357 WifiPhyState::CCA_BUSY);
1358
1359 // One PSDU of 1000 bytes should have been unsuccessfully received by STA 1 (since interference
1360 // occupies RU 1)
1363 this,
1364 0,
1365 1,
1366 0);
1367 // One PSDU of 1500 bytes should have been unsuccessfully received by STA 2 (since interference
1368 // occupies RU 2)
1371 this,
1372 0,
1373 1,
1374 0);
1375 // No PSDU should have been received by STA3
1378 this,
1379 0,
1380 0,
1381 0);
1382
1385 this);
1386
1388}
1389
1390template <typename LatestPhyEntityType>
1391void
1393{
1394 m_frequency = MHz_u{5955};
1395 m_channelWidth = MHz_u{20};
1396 m_expectedPpduDuration = NanoSeconds(306400);
1397 RunOne();
1398
1399 m_frequency = MHz_u{5965};
1400 m_channelWidth = MHz_u{40};
1401 m_expectedPpduDuration = NanoSeconds(156800);
1402 RunOne();
1403
1404 m_frequency = MHz_u{5985};
1405 m_channelWidth = MHz_u{80};
1406 m_expectedPpduDuration = NanoSeconds(102400);
1407 RunOne();
1408
1409 m_frequency = MHz_u{6025};
1410 m_channelWidth = MHz_u{160};
1411 m_expectedPpduDuration = NanoSeconds(75200);
1412 RunOne();
1413
1414 if (m_modClass >= WIFI_MOD_CLASS_EHT)
1415 {
1416 m_frequency = MHz_u{6105};
1417 m_channelWidth = MHz_u{320};
1418 m_expectedPpduDuration = NanoSeconds(61600);
1419 RunOne();
1420 }
1421
1423}
1424
1425/**
1426 * @ingroup wifi-test
1427 * @ingroup tests
1428 *
1429 * @brief DL-OFDMA PHY puncturing test
1430 */
1432{
1433 public:
1435
1436 private:
1437 void DoSetup() override;
1438 void DoTeardown() override;
1439 void DoRun() override;
1440
1441 /**
1442 * Receive success function for STA 1
1443 * @param psdu the PSDU
1444 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
1445 * @param txVector the transmit vector
1446 * @param statusPerMpdu reception status per MPDU
1447 */
1449 RxSignalInfo rxSignalInfo,
1450 const WifiTxVector& txVector,
1451 const std::vector<bool>& statusPerMpdu);
1452
1453 /**
1454 * Receive success function for STA 2
1455 * @param psdu the PSDU
1456 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
1457 * @param txVector the transmit vector
1458 * @param statusPerMpdu reception status per MPDU
1459 */
1461 RxSignalInfo rxSignalInfo,
1462 const WifiTxVector& txVector,
1463 const std::vector<bool>& statusPerMpdu);
1464
1465 /**
1466 * Receive failure function for STA 1
1467 * @param psdu the PSDU
1468 */
1470
1471 /**
1472 * Receive failure function for STA 2
1473 * @param psdu the PSDU
1474 */
1476
1477 /**
1478 * Check the results for STA 1
1479 * @param expectedRxSuccess the expected number of RX success
1480 * @param expectedRxFailure the expected number of RX failures
1481 * @param expectedRxBytes the expected number of RX bytes
1482 */
1483 void CheckResultsSta1(uint32_t expectedRxSuccess,
1484 uint32_t expectedRxFailure,
1485 uint32_t expectedRxBytes);
1486
1487 /**
1488 * Check the results for STA 2
1489 * @param expectedRxSuccess the expected number of RX success
1490 * @param expectedRxFailure the expected number of RX failures
1491 * @param expectedRxBytes the expected number of RX bytes
1492 */
1493 void CheckResultsSta2(uint32_t expectedRxSuccess,
1494 uint32_t expectedRxFailure,
1495 uint32_t expectedRxBytes);
1496
1497 /**
1498 * Reset the results
1499 */
1500 void ResetResults();
1501
1502 /**
1503 * Send MU-PPDU function
1504 * @param rxStaId1 the ID of the recipient STA for the first PSDU
1505 * @param rxStaId2 the ID of the recipient STA for the second PSDU
1506 * @param puncturedSubchannels indicates for each subchannel whether it is punctured or not. if
1507 * empty, preamble puncturing is not used.
1508 */
1509 void SendMuPpdu(uint16_t rxStaId1,
1510 uint16_t rxStaId2,
1511 const std::vector<bool>& puncturedSubchannels);
1512
1513 /**
1514 * Generate interference function
1515 * @param interferencePsd the PSD of the interference to be generated
1516 * @param duration the duration of the interference
1517 */
1518 void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
1519
1520 /**
1521 * Stop interference function
1522 */
1523 void StopInterference();
1524
1525 /**
1526 * Run one function
1527 */
1528 void RunOne();
1529
1530 /**
1531 * Schedule now to check the PHY state
1532 * @param phy the PHY
1533 * @param expectedState the expected state of the PHY
1534 */
1536
1537 /**
1538 * Check the PHY state now
1539 * @param phy the PHY
1540 * @param expectedState the expected state of the PHY
1541 */
1543
1544 uint32_t m_countRxSuccessSta1; ///< count RX success for STA 1
1545 uint32_t m_countRxSuccessSta2; ///< count RX success for STA 2
1546 uint32_t m_countRxFailureSta1; ///< count RX failure for STA 1
1547 uint32_t m_countRxFailureSta2; ///< count RX failure for STA 2
1548 uint32_t m_countRxBytesSta1; ///< count RX bytes for STA 1
1549 uint32_t m_countRxBytesSta2; ///< count RX bytes for STA 2
1550
1555
1556 MHz_u m_frequency; ///< frequency
1557 MHz_u m_channelWidth; ///< channel width
1558
1559 uint8_t m_indexSubchannel; ///< Index of the subchannel (starting from 0) that should contain an
1560 ///< interference and be punctured during the test run
1561
1562 Time m_expectedPpduDuration20Mhz; ///< expected duration to send MU PPDU on 20 MHz RU
1563 Time m_expectedPpduDuration40Mhz; ///< expected duration to send MU PPDU on 40 MHz RU
1564};
1565
1567 : TestCase("DL-OFDMA PHY puncturing test"),
1568 m_countRxSuccessSta1(0),
1569 m_countRxSuccessSta2(0),
1570 m_countRxFailureSta1(0),
1571 m_countRxFailureSta2(0),
1572 m_countRxBytesSta1(0),
1573 m_countRxBytesSta2(0),
1574 m_frequency(MHz_u{5210}),
1575 m_channelWidth(MHz_u{80}),
1576 m_indexSubchannel(0),
1577 m_expectedPpduDuration20Mhz(NanoSeconds(156800)),
1578 m_expectedPpduDuration40Mhz(NanoSeconds(102400))
1579{
1580}
1581
1582void
1592
1593void
1595 uint16_t rxStaId2,
1596 const std::vector<bool>& puncturedSubchannels)
1597{
1598 NS_LOG_FUNCTION(this << rxStaId1 << rxStaId2);
1599 WifiConstPsduMap psdus;
1600 WifiTxVector txVector{HePhy::GetHeMcs7(),
1601 0,
1603 NanoSeconds(800),
1604 1,
1605 1,
1606 0,
1608 false,
1609 false};
1610
1611 RuType ruType = puncturedSubchannels.empty()
1612 ? RuType::RU_484_TONE
1613 : (puncturedSubchannels.at(1) ? RuType::RU_242_TONE : RuType::RU_484_TONE);
1614 HeRu::RuSpec ru1(ruType, 1, true);
1615 txVector.SetRu(ru1, rxStaId1);
1616 txVector.SetMode(HePhy::GetHeMcs7(), rxStaId1);
1617 txVector.SetNss(1, rxStaId1);
1618
1619 ruType = puncturedSubchannels.empty()
1620 ? RuType::RU_484_TONE
1621 : (puncturedSubchannels.at(1) ? RuType::RU_484_TONE : RuType::RU_242_TONE);
1622 HeRu::RuSpec ru2(ruType,
1623 ruType == RuType::RU_484_TONE ? 2 : (puncturedSubchannels.at(3) ? 3 : 4),
1624 true);
1625 txVector.SetRu(ru2, rxStaId2);
1626 txVector.SetMode(HePhy::GetHeMcs9(), rxStaId2);
1627 txVector.SetNss(1, rxStaId2);
1628
1629 RuAllocation ruAlloc;
1630 if (puncturedSubchannels.empty())
1631 {
1632 ruAlloc.push_back(200);
1633 ruAlloc.push_back(114);
1634 ruAlloc.push_back(114);
1635 ruAlloc.push_back(200);
1636 }
1637 else
1638 {
1639 ruAlloc.push_back(puncturedSubchannels.at(1) ? 192 : 200);
1640 ruAlloc.push_back(puncturedSubchannels.at(1) ? 113 : 114);
1641 ruAlloc.push_back(puncturedSubchannels.at(2) ? 113
1642 : (puncturedSubchannels.at(3) ? 192 : 114));
1643 ruAlloc.push_back(puncturedSubchannels.at(2) ? 192
1644 : (puncturedSubchannels.at(3) ? 113 : 200));
1645 }
1646
1647 txVector.SetRuAllocation(ruAlloc, 0);
1648 txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
1649
1650 Ptr<Packet> pkt1 = Create<Packet>(1000);
1651 WifiMacHeader hdr1;
1653 hdr1.SetQosTid(0);
1654 hdr1.SetAddr1(Mac48Address("00:00:00:00:00:01"));
1655 hdr1.SetSequenceNumber(1);
1656 Ptr<WifiPsdu> psdu1 = Create<WifiPsdu>(pkt1, hdr1);
1657 psdus.insert(std::make_pair(rxStaId1, psdu1));
1658
1659 Ptr<Packet> pkt2 = Create<Packet>(1500);
1660 WifiMacHeader hdr2;
1662 hdr2.SetQosTid(0);
1663 hdr2.SetAddr1(Mac48Address("00:00:00:00:00:02"));
1664 hdr2.SetSequenceNumber(2);
1665 Ptr<WifiPsdu> psdu2 = Create<WifiPsdu>(pkt2, hdr2);
1666 psdus.insert(std::make_pair(rxStaId2, psdu2));
1667
1668 if (!puncturedSubchannels.empty())
1669 {
1670 txVector.SetInactiveSubchannels(puncturedSubchannels);
1671 }
1672
1673 m_phyAp->Send(psdus, txVector);
1674}
1675
1676void
1678{
1679 NS_LOG_FUNCTION(this << duration);
1680 m_phyInterferer->SetTxPowerSpectralDensity(interferencePsd);
1681 m_phyInterferer->SetPeriod(duration);
1682 m_phyInterferer->Start();
1684}
1685
1686void
1692
1693void
1695 RxSignalInfo rxSignalInfo,
1696 const WifiTxVector& txVector,
1697 const std::vector<bool>& /*statusPerMpdu*/)
1698{
1699 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
1701 m_countRxBytesSta1 += (psdu->GetSize() - 30);
1702}
1703
1704void
1706 RxSignalInfo rxSignalInfo,
1707 const WifiTxVector& txVector,
1708 const std::vector<bool>& /*statusPerMpdu*/)
1709{
1710 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
1712 m_countRxBytesSta2 += (psdu->GetSize() - 30);
1713}
1714
1715void
1721
1722void
1728
1729void
1731 uint32_t expectedRxFailure,
1732 uint32_t expectedRxBytes)
1733{
1735 expectedRxSuccess,
1736 "The number of successfully received packets by STA 1 is not correct!");
1738 expectedRxFailure,
1739 "The number of unsuccessfully received packets by STA 1 is not correct!");
1741 expectedRxBytes,
1742 "The number of bytes received by STA 1 is not correct!");
1743}
1744
1745void
1747 uint32_t expectedRxFailure,
1748 uint32_t expectedRxBytes)
1749{
1751 expectedRxSuccess,
1752 "The number of successfully received packets by STA 2 is not correct!");
1754 expectedRxFailure,
1755 "The number of unsuccessfully received packets by STA 2 is not correct!");
1757 expectedRxBytes,
1758 "The number of bytes received by STA 2 is not correct!");
1759}
1760
1761void
1763 WifiPhyState expectedState)
1764{
1765 // This is needed to make sure PHY state will be checked as the last event if a state change
1766 // occurred at the exact same time as the check
1768}
1769
1770void
1772 WifiPhyState expectedState)
1773{
1774 WifiPhyState currentState;
1775 PointerValue ptr;
1776 phy->GetAttribute("State", ptr);
1778 currentState = state->GetState();
1779 NS_LOG_FUNCTION(this << currentState);
1780 NS_TEST_ASSERT_MSG_EQ(currentState,
1781 expectedState,
1782 "PHY State " << currentState << " does not match expected state "
1783 << expectedState << " at " << Simulator::Now());
1784}
1785
1786void
1788{
1791 lossModel->SetFrequency(MHzToHz(m_frequency));
1792 spectrumChannel->AddPropagationLossModel(lossModel);
1795 spectrumChannel->SetPropagationDelayModel(delayModel);
1796
1797 Ptr<Node> apNode = CreateObject<Node>();
1801 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
1803 m_phyAp->SetErrorRateModel(apErrorModel);
1804 m_phyAp->SetDevice(apDev);
1805 m_phyAp->AddChannel(spectrumChannel);
1806 m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
1808 m_phyAp->SetMobility(apMobility);
1809 apDev->SetPhy(m_phyAp);
1810 apNode->AggregateObject(apMobility);
1811 apNode->AddDevice(apDev);
1812 apDev->SetStandard(WIFI_STANDARD_80211ax);
1813
1814 Ptr<Node> sta1Node = CreateObject<Node>();
1818 m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
1820 m_phySta1->SetErrorRateModel(sta1ErrorModel);
1821 m_phySta1->SetDevice(sta1Dev);
1822 m_phySta1->AddChannel(spectrumChannel);
1823 m_phySta1->ConfigureStandard(WIFI_STANDARD_80211ax);
1824 m_phySta1->SetReceiveOkCallback(MakeCallback(&TestDlOfdmaPhyPuncturing::RxSuccessSta1, this));
1825 m_phySta1->SetReceiveErrorCallback(
1828 m_phySta1->SetMobility(sta1Mobility);
1829 sta1Dev->SetPhy(m_phySta1);
1830 sta1Node->AggregateObject(sta1Mobility);
1831 sta1Node->AddDevice(sta1Dev);
1832 sta1Dev->SetStandard(WIFI_STANDARD_80211ax);
1833
1834 Ptr<Node> sta2Node = CreateObject<Node>();
1838 m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
1840 m_phySta2->SetErrorRateModel(sta2ErrorModel);
1841 m_phySta2->SetDevice(sta2Dev);
1842 m_phySta2->AddChannel(spectrumChannel);
1843 m_phySta2->ConfigureStandard(WIFI_STANDARD_80211ax);
1844 m_phySta2->SetReceiveOkCallback(MakeCallback(&TestDlOfdmaPhyPuncturing::RxSuccessSta2, this));
1845 m_phySta2->SetReceiveErrorCallback(
1848 m_phySta2->SetMobility(sta2Mobility);
1849 sta2Dev->SetPhy(m_phySta2);
1850 sta2Node->AggregateObject(sta2Mobility);
1851 sta2Node->AddDevice(sta2Dev);
1852 sta2Dev->SetStandard(WIFI_STANDARD_80211ax);
1853
1854 Ptr<Node> interfererNode = CreateObject<Node>();
1857 m_phyInterferer->SetDevice(interfererDev);
1858 m_phyInterferer->SetChannel(spectrumChannel);
1859 m_phyInterferer->SetDutyCycle(1);
1860 interfererNode->AddDevice(interfererDev);
1861}
1862
1863void
1865{
1866 m_phyAp->Dispose();
1867 m_phyAp = nullptr;
1868 m_phySta1->Dispose();
1869 m_phySta1 = nullptr;
1870 m_phySta2->Dispose();
1871 m_phySta2 = nullptr;
1872 m_phyInterferer->Dispose();
1873 m_phyInterferer = nullptr;
1874}
1875
1876void
1878{
1881 int64_t streamNumber = 0;
1882 m_phyAp->AssignStreams(streamNumber);
1883 m_phySta1->AssignStreams(streamNumber);
1884 m_phySta2->AssignStreams(streamNumber);
1885
1886 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
1891 ->number;
1892
1893 m_phyAp->SetOperatingChannel(
1895 m_phySta1->SetOperatingChannel(
1897 m_phySta2->SetOperatingChannel(
1899
1900 // A strong non-wifi interference is generated on selected 20 MHz subchannel for the whole
1901 // duration of the test run
1902 BandInfo bandInfo;
1903 bandInfo.fc = MHzToHz(m_frequency - (m_channelWidth / 2) + 10 + (m_indexSubchannel * 20));
1904 // Occupy half of the RU to make sure we do not have some power allocated to the subcarriers on
1905 // the border of another RU
1906 bandInfo.fl = bandInfo.fc - MHzToHz(5);
1907 bandInfo.fh = bandInfo.fc + MHzToHz(5);
1908 Bands bands;
1909 bands.push_back(bandInfo);
1910
1911 auto spectrumInterference = Create<SpectrumModel>(bands);
1912 auto interferencePsd = Create<SpectrumValue>(spectrumInterference);
1913 Watt_u interferencePower{0.1};
1914 *interferencePsd = interferencePower / 10e6;
1915
1918 this,
1919 interferencePsd,
1920 Seconds(3));
1921
1922 //---------------------------------------------------------------------------
1923 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2 without preamble puncturing:
1926 this,
1927 1,
1928 2,
1929 std::vector<bool>{});
1930
1931 // Since it takes m_expectedPpduDuration to transmit the PPDU,
1932 // both PHYs should be back to IDLE at the same time.
1935 this,
1936 m_phySta1,
1937 WifiPhyState::RX);
1940 this,
1941 m_phySta2,
1942 WifiPhyState::RX);
1945 this,
1946 m_phySta1,
1947 WifiPhyState::IDLE);
1950 this,
1951 m_phySta2,
1952 WifiPhyState::IDLE);
1953
1954 if (m_indexSubchannel < 2) // interference in RU 1
1955 {
1956 // One PSDU of 1000 bytes should have been unsuccessfully received by STA 1
1959 this,
1960 0,
1961 1,
1962 0);
1963 // One PSDU of 1500 bytes should have been successfully received by STA 2
1966 this,
1967 1,
1968 0,
1969 1500);
1970 }
1971 else // interference in RU 2
1972 {
1973 // One PSDU of 1000 bytes should have been successfully received by STA 1
1976 this,
1977 1,
1978 0,
1979 1000);
1980 // One PSDU of 1500 bytes should have been unsuccessfully received by STA 2
1983 this,
1984 0,
1985 1,
1986 0);
1987 }
1988
1990
1991 //---------------------------------------------------------------------------
1992 // Send MU PPDU with two PSDUs addressed to STA 1 and STA 2 with preamble puncturing:
1993 // the punctured 20 MHz subchannel is the one that has interference
1994 std::vector<bool> puncturedSubchannels;
1995 const auto num20MhzSubchannels = Count20MHzSubchannels(m_channelWidth);
1996 for (std::size_t i = 0; i < num20MhzSubchannels; ++i)
1997 {
1998 if (i == m_indexSubchannel)
1999 {
2000 puncturedSubchannels.push_back(true);
2001 }
2002 else
2003 {
2004 puncturedSubchannels.push_back(false);
2005 }
2006 }
2009 this,
2010 1,
2011 2,
2012 puncturedSubchannels);
2013
2014 // Since it takes m_expectedPpduDuration to transmit the PPDU,
2015 // both PHYs should be back to IDLE at the same time.
2018 this,
2019 m_phySta1,
2020 WifiPhyState::RX);
2023 this,
2024 m_phySta2,
2025 WifiPhyState::RX);
2028 this,
2029 m_phySta1,
2030 WifiPhyState::IDLE);
2033 this,
2034 m_phySta2,
2035 WifiPhyState::IDLE);
2036
2037 // One PSDU of 1000 bytes should have been successfully received by STA 1
2040 this,
2041 1,
2042 0,
2043 1000);
2044 // One PSDU of 1500 bytes should have been successfully received by STA 2
2047 this,
2048 1,
2049 0,
2050 1500);
2051
2053
2055}
2056
2057void
2059{
2060 // test all 20 MHz subchannels in the 80 MHz operation channel except the primary one which
2061 // cannot be punctured
2062 for (auto index : {1, 2, 3})
2063 {
2064 m_indexSubchannel = index;
2065 RunOne();
2066 }
2068}
2069
2070/**
2071 * @ingroup wifi-test
2072 * @ingroup tests
2073 *
2074 * @brief UL-OFDMA PPDU UID attribution test
2075 */
2077{
2078 public:
2080 ~TestUlOfdmaPpduUid() override;
2081
2082 private:
2083 void DoSetup() override;
2084 void DoTeardown() override;
2085 void DoRun() override;
2086
2087 /**
2088 * Transmitted PPDU information function for AP
2089 * @param uid the UID of the transmitted PPDU
2090 */
2091 void TxPpduAp(uint64_t uid);
2092 /**
2093 * Transmitted PPDU information function for STA 1
2094 * @param uid the UID of the transmitted PPDU
2095 */
2096 void TxPpduSta1(uint64_t uid);
2097 /**
2098 * Transmitted PPDU information function for STA 2
2099 * @param uid the UID of the transmitted PPDU
2100 */
2101 void TxPpduSta2(uint64_t uid);
2102 /**
2103 * Reset the global PPDU UID counter in WifiPhy
2104 */
2105 void ResetPpduUid();
2106
2107 /**
2108 * Send MU-PPDU toward both STAs.
2109 */
2110 void SendMuPpdu();
2111 /**
2112 * Send TB-PPDU from both STAs.
2113 */
2114 void SendTbPpdu();
2115 /**
2116 * Send SU-PPDU function
2117 * @param txStaId the ID of the sending STA
2118 */
2119 void SendSuPpdu(uint16_t txStaId);
2120
2121 /**
2122 * Check the UID of the transmitted PPDU
2123 * @param staId the STA-ID of the PHY (0 for AP)
2124 * @param expectedUid the expected UID
2125 */
2126 void CheckUid(uint16_t staId, uint64_t expectedUid);
2127
2131
2132 uint64_t m_ppduUidAp; ///< UID of PPDU transmitted by AP
2133 uint64_t m_ppduUidSta1; ///< UID of PPDU transmitted by STA1
2134 uint64_t m_ppduUidSta2; ///< UID of PPDU transmitted by STA2
2135};
2136
2138 : TestCase("UL-OFDMA PPDU UID attribution test"),
2139 m_ppduUidAp(UINT64_MAX),
2140 m_ppduUidSta1(UINT64_MAX),
2141 m_ppduUidSta2(UINT64_MAX)
2142{
2143}
2144
2148
2149void
2151{
2154 lossModel->SetFrequency(DEFAULT_FREQUENCY);
2155 spectrumChannel->AddPropagationLossModel(lossModel);
2158 spectrumChannel->SetPropagationDelayModel(delayModel);
2159
2160 Ptr<Node> apNode = CreateObject<Node>();
2164 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
2166 m_phyAp->SetErrorRateModel(apErrorModel);
2167 m_phyAp->AddChannel(spectrumChannel);
2168 m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
2169 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
2174 ->number;
2175 m_phyAp->SetOperatingChannel(
2177 m_phyAp->SetDevice(apDev);
2178 m_phyAp->TraceConnectWithoutContext("TxPpduUid",
2181 m_phyAp->SetMobility(apMobility);
2182 apDev->SetPhy(m_phyAp);
2183 apNode->AggregateObject(apMobility);
2184 apNode->AddDevice(apDev);
2185 apDev->SetStandard(WIFI_STANDARD_80211ax);
2186 apDev->SetHeConfiguration(CreateObject<HeConfiguration>());
2187
2188 Ptr<Node> sta1Node = CreateObject<Node>();
2192 m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
2194 m_phySta1->SetErrorRateModel(sta1ErrorModel);
2195 m_phySta1->AddChannel(spectrumChannel);
2196 m_phySta1->ConfigureStandard(WIFI_STANDARD_80211ax);
2197 m_phySta1->SetOperatingChannel(
2199 m_phySta1->SetDevice(sta1Dev);
2200 m_phySta1->TraceConnectWithoutContext("TxPpduUid",
2203 m_phySta1->SetMobility(sta1Mobility);
2204 sta1Dev->SetPhy(m_phySta1);
2205 sta1Node->AggregateObject(sta1Mobility);
2206 sta1Node->AddDevice(sta1Dev);
2207
2208 Ptr<Node> sta2Node = CreateObject<Node>();
2212 m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
2214 m_phySta2->SetErrorRateModel(sta2ErrorModel);
2215 m_phySta2->AddChannel(spectrumChannel);
2216 m_phySta2->ConfigureStandard(WIFI_STANDARD_80211ax);
2217 m_phySta2->SetOperatingChannel(
2219 m_phySta2->SetDevice(sta2Dev);
2220 m_phySta2->TraceConnectWithoutContext("TxPpduUid",
2223 m_phySta2->SetMobility(sta2Mobility);
2224 sta2Dev->SetPhy(m_phySta2);
2225 sta2Node->AggregateObject(sta2Mobility);
2226 sta2Node->AddDevice(sta2Dev);
2227}
2228
2229void
2231{
2232 m_phyAp->Dispose();
2233 m_phyAp = nullptr;
2234 m_phySta1->Dispose();
2235 m_phySta1 = nullptr;
2236 m_phySta2->Dispose();
2237 m_phySta2 = nullptr;
2238}
2239
2240void
2241TestUlOfdmaPpduUid::CheckUid(uint16_t staId, uint64_t expectedUid)
2242{
2243 uint64_t uid;
2244 std::string device;
2245 switch (staId)
2246 {
2247 case 0:
2248 uid = m_ppduUidAp;
2249 device = "AP";
2250 break;
2251 case 1:
2252 uid = m_ppduUidSta1;
2253 device = "STA1";
2254 break;
2255 case 2:
2256 uid = m_ppduUidSta2;
2257 device = "STA2";
2258 break;
2259 default:
2260 NS_ABORT_MSG("Unexpected STA-ID");
2261 }
2263 expectedUid,
2264 "UID " << uid << " does not match expected one " << expectedUid << " for "
2265 << device << " at " << Simulator::Now());
2266}
2267
2268void
2270{
2271 NS_LOG_FUNCTION(this << uid);
2272 m_ppduUidAp = uid;
2273}
2274
2275void
2277{
2278 NS_LOG_FUNCTION(this << uid);
2279 m_ppduUidSta1 = uid;
2280}
2281
2282void
2284{
2285 NS_LOG_FUNCTION(this << uid);
2286 m_ppduUidSta2 = uid;
2287}
2288
2289void
2291{
2292 NS_LOG_FUNCTION(this);
2293 m_phyAp->SetPpduUid(0); // one is enough since it's a global attribute
2294}
2295
2296void
2298{
2299 WifiConstPsduMap psdus;
2300 WifiTxVector txVector{HePhy::GetHeMcs7(),
2301 0,
2303 NanoSeconds(800),
2304 1,
2305 1,
2306 0,
2308 false,
2309 false};
2310
2311 uint16_t rxStaId1 = 1;
2312 HeRu::RuSpec ru1(RuType::RU_106_TONE, 1, true);
2313 txVector.SetRu(ru1, rxStaId1);
2314 txVector.SetMode(HePhy::GetHeMcs7(), rxStaId1);
2315 txVector.SetNss(1, rxStaId1);
2316
2317 uint16_t rxStaId2 = 2;
2318 HeRu::RuSpec ru2(RuType::RU_106_TONE, 2, true);
2319 txVector.SetRu(ru2, rxStaId2);
2320 txVector.SetMode(HePhy::GetHeMcs9(), rxStaId2);
2321 txVector.SetNss(1, rxStaId2);
2322 txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
2323 txVector.SetRuAllocation({96}, 0);
2324
2325 Ptr<Packet> pkt1 = Create<Packet>(1000);
2326 WifiMacHeader hdr1;
2328 hdr1.SetQosTid(0);
2329 hdr1.SetAddr1(Mac48Address("00:00:00:00:00:01"));
2330 hdr1.SetSequenceNumber(1);
2331 Ptr<WifiPsdu> psdu1 = Create<WifiPsdu>(pkt1, hdr1);
2332 psdus.insert(std::make_pair(rxStaId1, psdu1));
2333
2334 Ptr<Packet> pkt2 = Create<Packet>(1500);
2335 WifiMacHeader hdr2;
2337 hdr2.SetQosTid(0);
2338 hdr2.SetAddr1(Mac48Address("00:00:00:00:00:02"));
2339 hdr2.SetSequenceNumber(2);
2340 Ptr<WifiPsdu> psdu2 = Create<WifiPsdu>(pkt2, hdr2);
2341 psdus.insert(std::make_pair(rxStaId2, psdu2));
2342
2343 m_phyAp->Send(psdus, txVector);
2344}
2345
2346void
2348{
2349 WifiConstPsduMap psdus1;
2350 WifiConstPsduMap psdus2;
2351
2352 WifiTxVector txVector1{HePhy::GetHeMcs7(),
2353 0,
2355 NanoSeconds(1600),
2356 1,
2357 1,
2358 0,
2360 false,
2361 false};
2362 WifiTxVector txVector2{txVector1};
2363 WifiTxVector trigVector{txVector2};
2364
2365 uint16_t rxStaId1 = 1;
2366 HeRu::RuSpec ru1(RuType::RU_106_TONE, 1, false);
2367 txVector1.SetRu(ru1, rxStaId1);
2368 txVector1.SetMode(HePhy::GetHeMcs7(), rxStaId1);
2369 txVector1.SetNss(1, rxStaId1);
2370 trigVector.SetRu(ru1, rxStaId1);
2371 trigVector.SetMode(HePhy::GetHeMcs7(), rxStaId1);
2372 trigVector.SetNss(1, rxStaId1);
2373
2374 auto pkt1 = Create<Packet>(1000);
2375 WifiMacHeader hdr1;
2377 hdr1.SetQosTid(0);
2378 hdr1.SetAddr1(Mac48Address("00:00:00:00:00:00"));
2379 hdr1.SetSequenceNumber(1);
2380 auto psdu1 = Create<WifiPsdu>(pkt1, hdr1);
2381 psdus1.insert(std::make_pair(rxStaId1, psdu1));
2382
2383 uint16_t rxStaId2 = 2;
2384 HeRu::RuSpec ru2(RuType::RU_106_TONE, 2, false);
2385 txVector2.SetRu(ru2, rxStaId2);
2386 txVector2.SetMode(HePhy::GetHeMcs9(), rxStaId2);
2387 txVector2.SetNss(1, rxStaId2);
2388 trigVector.SetRu(ru2, rxStaId2);
2389 trigVector.SetMode(HePhy::GetHeMcs9(), rxStaId2);
2390 trigVector.SetNss(1, rxStaId2);
2391
2392 auto pkt2 = Create<Packet>(1500);
2393 WifiMacHeader hdr2;
2395 hdr2.SetQosTid(0);
2396 hdr2.SetAddr1(Mac48Address("00:00:00:00:00:00"));
2397 hdr2.SetSequenceNumber(2);
2398 auto psdu2 = Create<WifiPsdu>(pkt2, hdr2);
2399 psdus2.insert(std::make_pair(rxStaId2, psdu2));
2400
2401 const auto txDuration1 =
2403 txVector1,
2404 m_phySta1->GetPhyBand(),
2405 rxStaId1);
2406 const auto txDuration2 =
2408 txVector2,
2409 m_phySta1->GetPhyBand(),
2410 rxStaId2);
2411 const auto txDuration = std::max(txDuration1, txDuration2);
2412
2413 txVector1.SetLength(
2414 HePhy::ConvertHeTbPpduDurationToLSigLength(txDuration, txVector1, m_phySta1->GetPhyBand())
2415 .first);
2416 txVector2.SetLength(
2417 HePhy::ConvertHeTbPpduDurationToLSigLength(txDuration, txVector2, m_phySta2->GetPhyBand())
2418 .first);
2419
2420 auto phyAp = m_phyAp->GetPhyEntity();
2421 phyAp->SetTrigVector(trigVector, txDuration);
2422
2423 m_phySta1->Send(psdus1, txVector1);
2424 m_phySta2->Send(psdus2, txVector2);
2425}
2426
2427void
2429{
2430 WifiConstPsduMap psdus;
2431 WifiTxVector txVector{HePhy::GetHeMcs7(),
2432 0,
2434 NanoSeconds(800),
2435 1,
2436 1,
2437 0,
2439 false,
2440 false};
2441
2442 auto pkt = Create<Packet>(1000);
2443 WifiMacHeader hdr;
2445 hdr.SetQosTid(0);
2447 hdr.SetSequenceNumber(1);
2448 auto psdu = Create<WifiPsdu>(pkt, hdr);
2449 psdus.insert(std::make_pair(SU_STA_ID, psdu));
2450
2451 switch (txStaId)
2452 {
2453 case 0:
2454 m_phyAp->Send(psdus, txVector);
2455 break;
2456 case 1:
2457 m_phySta1->Send(psdus, txVector);
2458 break;
2459 case 2:
2460 m_phySta2->Send(psdus, txVector);
2461 break;
2462 default:
2463 NS_ABORT_MSG("Unexpected STA-ID");
2464 }
2465}
2466
2467void
2469{
2472 int64_t streamNumber = 0;
2473 m_phyAp->AssignStreams(streamNumber);
2474 m_phySta1->AssignStreams(streamNumber);
2475 m_phySta2->AssignStreams(streamNumber);
2476
2477 // Reset PPDU UID so as not to be dependent on previously executed test cases,
2478 // since global attribute will be changed).
2479 ResetPpduUid();
2480
2481 // Send HE MU PPDU with two PSDUs addressed to STA 1 and STA 2.
2482 // PPDU UID should be equal to 0 (the first counter value).
2485
2486 // Send HE SU PPDU from AP.
2487 // PPDU UID should be incremented since this is a new PPDU.
2490
2491 // Send HE TB PPDU from STAs to AP.
2492 // PPDU UID should NOT be incremented since HE TB PPDUs reuse the UID of the immediately
2493 // preceding correctly received PPDU (which normally contains the trigger frame).
2497
2498 // Send HE SU PPDU from STA1.
2499 // PPDU UID should be incremented since this is a new PPDU.
2502
2505}
2506
2507/**
2508 * @ingroup wifi-test
2509 * @ingroup tests
2510 *
2511 * @brief UL-OFDMA multiple RX events test
2512 */
2514{
2515 public:
2517 ~TestMultipleHeTbPreambles() override;
2518
2519 private:
2520 void DoSetup() override;
2521 void DoTeardown() override;
2522 void DoRun() override;
2523
2524 /**
2525 * Receive HE TB PPDU function.
2526 *
2527 * @param uid the UID used to identify a set of HE TB PPDUs belonging to the same UL-MU
2528 * transmission
2529 * @param staId the STA ID
2530 * @param txPower the TX power
2531 * @param payloadSize the size of the payload in bytes
2532 */
2533 void RxHeTbPpdu(uint64_t uid, uint16_t staId, Watt_u txPower, size_t payloadSize);
2534
2535 /**
2536 * Receive OFDMA part of HE TB PPDU function.
2537 * Immediately schedules DoRxHeTbPpduOfdmaPart.
2538 *
2539 * @param rxParamsOfdma the spectrum signal parameters to send for OFDMA part
2540 */
2542 /**
2543 * Receive OFDMA part of HE TB PPDU function.
2544 * Actual reception call.
2545 *
2546 * @param rxParamsOfdma the spectrum signal parameters to send for OFDMA part
2547 */
2549
2550 /**
2551 * RX dropped function
2552 * @param p the packet
2553 * @param reason the reason
2554 */
2556
2557 /**
2558 * Reset function
2559 */
2560 void Reset();
2561
2562 /**
2563 * Check the received HE TB preambles
2564 * @param nEvents the number of events created by the PHY
2565 * @param uids the vector of expected UIDs
2566 */
2567 void CheckHeTbPreambles(size_t nEvents, std::vector<uint64_t> uids);
2568
2569 /**
2570 * Check the number of bytes dropped
2571 * @param expectedBytesDropped the expected number of bytes dropped
2572 */
2573 void CheckBytesDropped(size_t expectedBytesDropped);
2574
2576
2577 uint64_t m_totalBytesDropped; ///< total number of dropped bytes
2579};
2580
2582 : TestCase("UL-OFDMA multiple RX events test"),
2583 m_totalBytesDropped(0),
2584 m_trigVector(HePhy::GetHeMcs7(),
2585 0,
2587 NanoSeconds(1600),
2588 1,
2589 1,
2590 0,
2592 false,
2593 false)
2594{
2595}
2596
2600
2601void
2603{
2604 NS_LOG_FUNCTION(this);
2606 // We have to reset PHY here since we do not trigger OFDMA payload RX event in this test
2607 m_phy->Reset();
2609}
2610
2611void
2613{
2614 NS_LOG_FUNCTION(this << p << reason);
2615 m_totalBytesDropped += (p->GetSize() - 30);
2616}
2617
2618void
2619TestMultipleHeTbPreambles::CheckHeTbPreambles(size_t nEvents, std::vector<uint64_t> uids)
2620{
2621 auto events = m_phy->GetCurrentPreambleEvents();
2622 NS_TEST_ASSERT_MSG_EQ(events.size(), nEvents, "The number of UL MU events is not correct!");
2623 for (const auto& uid : uids)
2624 {
2625 auto pair = std::make_pair(uid, WIFI_PREAMBLE_HE_TB);
2626 auto it = events.find(pair);
2627 bool found = (it != events.end());
2629 true,
2630 "HE TB PPDU with UID " << uid << " has not been received!");
2631 }
2632}
2633
2634void
2636{
2638 expectedBytesDropped,
2639 "The number of dropped bytes is not correct!");
2640}
2641
2642void
2644 uint16_t staId,
2645 Watt_u txPower,
2646 size_t payloadSize)
2647{
2648 WifiConstPsduMap psdus;
2649 WifiTxVector txVector{HePhy::GetHeMcs7(),
2650 0,
2652 NanoSeconds(1600),
2653 1,
2654 1,
2655 0,
2657 false,
2658 false};
2659
2660 HeRu::RuSpec ru(RuType::RU_106_TONE, staId, false);
2661 txVector.SetRu(ru, staId);
2662 txVector.SetMode(HePhy::GetHeMcs7(), staId);
2663 txVector.SetNss(1, staId);
2664
2665 m_trigVector.SetHeMuUserInfo(staId, {ru, 7, 1});
2666
2667 auto pkt = Create<Packet>(payloadSize);
2668 WifiMacHeader hdr;
2670 hdr.SetQosTid(0);
2671 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
2672 hdr.SetSequenceNumber(1);
2673 auto psdu = Create<WifiPsdu>(pkt, hdr);
2674 psdus.insert(std::make_pair(staId, psdu));
2675
2676 auto ppduDuration = OfdmaSpectrumWifiPhy<HePhy>::CalculateTxDuration(psdu->GetSize(),
2677 txVector,
2678 m_phy->GetPhyBand(),
2679 staId);
2680 auto ppdu = Create<HePpdu>(psdus,
2681 txVector,
2682 m_phy->GetOperatingChannel(),
2683 ppduDuration,
2684 uid,
2686
2687 // Send non-OFDMA part
2688 const auto nonOfdmaDuration = m_phy->GetPhyEntity()->CalculateNonHeDurationForHeTb(txVector);
2689 const auto centerFrequency =
2690 m_phy->GetPhyEntity()->GetCenterFrequenciesForNonHePart(ppdu, staId).front();
2691 auto ruWidth = WifiRu::GetBandwidth(WifiRu::GetRuType(txVector.GetRu(staId)));
2692 auto channelWidth = ruWidth < MHz_u{20} ? MHz_u{20} : ruWidth;
2694 centerFrequency,
2695 channelWidth,
2696 txPower,
2697 m_phy->GetGuardBandwidth(channelWidth));
2698 auto rxParams = Create<WifiSpectrumSignalParameters>();
2699 rxParams->psd = rxPsd;
2700 rxParams->txPhy = nullptr;
2701 rxParams->duration = nonOfdmaDuration;
2702 rxParams->ppdu = ppdu;
2703
2704 uint16_t length;
2705 std::tie(length, ppduDuration) =
2706 HePhy::ConvertHeTbPpduDurationToLSigLength(ppduDuration, txVector, m_phy->GetPhyBand());
2707 txVector.SetLength(length);
2708 m_trigVector.SetLength(length);
2709 auto hePhy = DynamicCast<HePhy>(m_phy->GetLatestPhyEntity());
2710 hePhy->SetTrigVector(m_trigVector, ppduDuration);
2711 ppdu->ResetTxVector();
2712 m_phy->StartRx(rxParams, nullptr);
2713
2714 // Schedule OFDMA part
2715 auto ppduOfdma = DynamicCast<HePpdu>(ppdu->Copy()); // since flag will be modified
2716 ppduOfdma->SetTxPsdFlag(HePpdu::PSD_HE_PORTION);
2717 const auto band = m_phy->GetPhyEntity()->GetRuBandForRx(txVector, staId);
2718 auto rxPsdOfdma =
2721 txPower,
2723 band.indices);
2724 auto rxParamsOfdma = Create<WifiSpectrumSignalParameters>();
2725 rxParamsOfdma->psd = rxPsd;
2726 rxParamsOfdma->txPhy = nullptr;
2727 rxParamsOfdma->duration = ppduDuration - nonOfdmaDuration;
2728 rxParamsOfdma->ppdu = ppduOfdma;
2729 Simulator::Schedule(nonOfdmaDuration,
2731 this,
2732 rxParamsOfdma);
2733}
2734
2735void
2740
2741void
2743{
2744 // This is needed to make sure the OFDMA part is started as the last event since HE-SIG-A should
2745 // end at the exact same time as the start For normal WifiNetDevices, this the reception of the
2746 // OFDMA part is scheduled after end of HE-SIG-A decoding.
2747 m_phy->StartRx(rxParamsOfdma, nullptr);
2748}
2749
2750void
2752{
2756 dev->SetStandard(WIFI_STANDARD_80211ax);
2761 "Txop",
2762 PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
2763 mac->SetAttribute("BeaconGeneration", BooleanValue(false));
2764 dev->SetMac(mac);
2765 m_phy->SetInterferenceHelper(interferenceHelper);
2766 m_phy->SetErrorRateModel(error);
2767 m_phy->AddChannel(spectrumChannel);
2768 m_phy->ConfigureStandard(WIFI_STANDARD_80211ax);
2772 0});
2773 m_phy->TraceConnectWithoutContext("PhyRxDrop",
2775 m_phy->SetDevice(dev);
2776 Ptr<ThresholdPreambleDetectionModel> preambleDetectionModel =
2778 preambleDetectionModel->SetAttribute("Threshold", DoubleValue(4));
2779 preambleDetectionModel->SetAttribute("MinimumRssi", DoubleValue(-82));
2780 m_phy->SetPreambleDetectionModel(preambleDetectionModel);
2782 heConfiguration->m_maxTbPpduDelay = NanoSeconds(400);
2783 dev->SetHeConfiguration(heConfiguration);
2784 dev->SetPhy(m_phy);
2785 node->AddDevice(dev);
2786}
2787
2788void
2790{
2791 m_phy->Dispose();
2792 m_phy = nullptr;
2793}
2794
2795void
2797{
2800 int64_t streamNumber = 0;
2801 m_phy->AssignStreams(streamNumber);
2802
2803 Watt_u txPower{0.01};
2804
2805 {
2806 // Verify a single UL MU transmission with two stations belonging to the same BSS
2807 std::vector<uint64_t> uids{0};
2810 this,
2811 uids[0],
2812 1,
2813 txPower,
2814 1001);
2817 this,
2818 uids[0],
2819 2,
2820 txPower,
2821 1002);
2822 // Check that we received a single UL MU transmission with the corresponding UID
2825 this,
2826 1,
2827 uids);
2829 }
2830
2831 {
2832 // Verify the correct reception of 2 UL MU transmissions with two stations per BSS, where
2833 // the second transmission arrives during the preamble detection window and with half the
2834 // power of the first transmission.
2835 std::vector<uint64_t> uids{1, 2};
2838 this,
2839 uids[0],
2840 1,
2841 txPower,
2842 1001);
2845 this,
2846 uids[0],
2847 2,
2848 txPower,
2849 1002);
2852 this,
2853 uids[1],
2854 1,
2855 txPower / 2,
2856 1003);
2859 this,
2860 uids[1],
2861 2,
2862 txPower / 2,
2863 1004);
2864 // Check that we received the correct reception of 2 UL MU transmissions with the
2865 // corresponding UIDs
2868 this,
2869 2,
2870 uids);
2872 // TODO: verify PPDUs from second UL MU transmission are dropped
2873 }
2874
2875 {
2876 // Verify the correct reception of 2 UL MU transmissions with two stations per BSS, where
2877 // the second transmission arrives during the preamble detection window and with twice the
2878 // power of the first transmission.
2879 std::vector<uint64_t> uids{3, 4};
2882 this,
2883 uids[0],
2884 1,
2885 txPower / 2,
2886 1001);
2889 this,
2890 uids[0],
2891 2,
2892 txPower / 2,
2893 1002);
2896 this,
2897 uids[1],
2898 1,
2899 txPower,
2900 1003);
2903 this,
2904 uids[1],
2905 2,
2906 txPower,
2907 1004);
2908 // Check that we received the correct reception of 2 UL MU transmissions with the
2909 // corresponding UIDs
2912 this,
2913 2,
2914 uids);
2916 // TODO: verify PPDUs from first UL MU transmission are dropped
2917 }
2918
2919 {
2920 // Verify the correct reception of 2 UL MU transmissions with two stations per BSS, where
2921 // the second transmission arrives during PHY header reception and with the same power as
2922 // the first transmission.
2923 std::vector<uint64_t> uids{5, 6};
2926 this,
2927 uids[0],
2928 1,
2929 txPower,
2930 1001);
2933 this,
2934 uids[0],
2935 2,
2936 txPower,
2937 1002);
2940 this,
2941 uids[1],
2942 1,
2943 txPower,
2944 1003);
2947 this,
2948 uids[1],
2949 2,
2950 txPower,
2951 1004);
2952 // Check that we received the correct reception of the first UL MU transmission with the
2953 // corresponding UID (second one dropped)
2956 this,
2957 1,
2958 std::vector<uint64_t>{uids[0]});
2959 // The packets of the second UL MU transmission should have been dropped
2962 this,
2963 1003 + 1004);
2965 }
2966
2967 {
2968 // Verify the correct reception of one UL MU transmission out of 2 with two stations per
2969 // BSS, where the second transmission arrives during payload reception and with the same
2970 // power as the first transmission.
2971 std::vector<uint64_t> uids{7, 8};
2974 this,
2975 uids[0],
2976 1,
2977 txPower,
2978 1001);
2981 this,
2982 uids[0],
2983 2,
2984 txPower,
2985 1002);
2988 this,
2989 uids[1],
2990 1,
2991 txPower,
2992 1003);
2995 this,
2996 uids[1],
2997 2,
2998 txPower,
2999 1004);
3000 // Check that we received the correct reception of the first UL MU transmission with the
3001 // corresponding UID (second one dropped)
3004 this,
3005 1,
3006 std::vector<uint64_t>{uids[0]});
3007 // The packets of the second UL MU transmission should have been dropped
3010 this,
3011 1003 + 1004);
3013 }
3014
3015 {
3016 // Verify the correct reception of a single UL MU transmission with two stations belonging
3017 // to the same BSS, and the second PPDU arrives 500ns after the first PPDU, i.e. it exceeds
3018 // the configured delay spread of 400ns
3019 std::vector<uint64_t> uids{9};
3022 this,
3023 uids[0],
3024 1,
3025 txPower,
3026 1001);
3029 this,
3030 uids[0],
3031 2,
3032 txPower,
3033 1002);
3034 // Check that we received a single UL MU transmission with the corresponding UID
3037 this,
3038 1,
3039 uids);
3040 // The first packet of 1001 bytes should be dropped because preamble is not detected after
3041 // 4us (because the PPDU that arrived at 500ns is interfering): the second HE TB PPDU is
3042 // acting as interference since it arrived after the maximum allowed 400ns. Obviously, that
3043 // second packet of 1002 bytes is dropped as well.
3046 this,
3047 1001 + 1002);
3049 }
3050
3053}
3054
3055/**
3056 * @ingroup wifi-test
3057 * @ingroup tests
3058 *
3059 * @brief PHY listener for OFDMA tests
3060 */
3062{
3063 public:
3065
3066 void NotifyRxStart(Time duration) override
3067 {
3068 NS_LOG_FUNCTION(this << duration);
3071 m_lastRxSuccess = false;
3072 }
3073
3074 void NotifyRxEndOk() override
3075 {
3076 NS_LOG_FUNCTION(this);
3078 ++m_notifyRxEnd;
3079 m_lastRxSuccess = true;
3080 }
3081
3082 void NotifyRxEndError(const WifiTxVector& txVector) override
3083 {
3084 NS_LOG_FUNCTION(this << txVector);
3086 ++m_notifyRxEnd;
3087 m_lastRxSuccess = false;
3088 }
3089
3090 void NotifyTxStart(Time duration, dBm_u txPower) override
3091 {
3092 NS_LOG_FUNCTION(this << duration << txPower);
3093 }
3094
3096 WifiChannelListType channelType,
3097 const std::vector<Time>& /*per20MhzDurations*/) override
3098 {
3099 NS_LOG_FUNCTION(this << duration << channelType);
3100 }
3101
3102 void NotifySwitchingStart(Time duration) override
3103 {
3104 }
3105
3106 void NotifySleep() override
3107 {
3108 }
3109
3110 void NotifyOff() override
3111 {
3112 }
3113
3114 void NotifyWakeup() override
3115 {
3116 }
3117
3118 void NotifyOn() override
3119 {
3120 }
3121
3122 /**
3123 * Reset function.
3124 */
3125 void Reset()
3126 {
3127 m_notifyRxStart = 0;
3128 m_notifyRxEnd = 0;
3130 m_lastRxEnd = Seconds(0);
3131 m_lastRxSuccess = false;
3132 }
3133
3134 /**
3135 * Return the number of RX start notifications that has been received since the last reset.
3136 * @return the number of RX start notifications that has been received
3137 */
3139 {
3140 return m_notifyRxStart;
3141 }
3142
3143 /**
3144 * Return the number of RX end notifications that has been received since the last reset.
3145 * @return the number of RX end notifications that has been received
3146 */
3148 {
3149 return m_notifyRxEnd;
3150 }
3151
3152 /**
3153 * Return the time at which the last RX start notification has been received.
3154 * @return the time at which the last RX start notification has been received
3155 */
3157 {
3158 return m_lastRxStart;
3159 }
3160
3161 /**
3162 * Return the time at which the last RX end notification has been received.
3163 * @return the time at which the last RX end notification has been received
3164 */
3166 {
3167 return m_lastRxEnd;
3168 }
3169
3170 /**
3171 * Return whether last RX has been successful.
3172 * @return true if last RX has been successful, false otherwise
3173 */
3174 bool IsLastRxSuccess() const
3175 {
3176 return m_lastRxSuccess;
3177 }
3178
3179 private:
3180 uint32_t m_notifyRxStart{0}; ///< count number of RX start notifications
3181 uint32_t m_notifyRxEnd{0}; ///< count number of RX end notifications
3182 Time m_lastRxStart{Seconds(0)}; ///< last time a RX start notification has been received
3183 Time m_lastRxEnd{Seconds(0)}; ///< last time a RX end notification has been received
3184 bool m_lastRxSuccess{false}; ///< flag whether last RX has been successful
3185};
3186
3187/**
3188 * @ingroup wifi-test
3189 * @ingroup tests
3190 *
3191 * @brief UL-OFDMA PHY test
3192 */
3193template <typename LatestPhyEntityType>
3195{
3196 public:
3197 /**
3198 * Erroneous info included in a TRIGVECTOR
3199 */
3207
3209
3210 private:
3211 void DoSetup() override;
3212 void DoTeardown() override;
3213 void DoRun() override;
3214
3215 /**
3216 * Get TXVECTOR for HE PPDU.
3217 * @param txStaId the ID of the TX STA
3218 * @param index the RU index used for the transmission
3219 * @param bssColor the BSS color of the TX STA
3220 * @return the TXVECTOR for HE TB PPDU
3221 */
3222 WifiTxVector GetTxVectorForTbPpdu(uint16_t txStaId, std::size_t index, uint8_t bssColor) const;
3223 /**
3224 * Set TRIGVECTOR for HE TB PPDU
3225 *
3226 * @param bssColor the BSS color of the TX STA
3227 * @param error the erroneous info (if any) in the TRIGVECTOR to set
3228 */
3229 void SetTrigVector(uint8_t bssColor, TrigVectorInfo error);
3230 /**
3231 * Send HE TB PPDU function
3232 * @param txStaId the ID of the TX STA
3233 * @param index the RU index used for the transmission
3234 * @param payloadSize the size of the payload in bytes
3235 * @param uid the UID of the trigger frame that is initiating this transmission
3236 * @param bssColor the BSS color of the TX STA
3237 * @param incrementUid whether UID shall be incremented
3238 */
3239 void SendTbPpdu(uint16_t txStaId,
3240 std::size_t index,
3241 std::size_t payloadSize,
3242 uint64_t uid,
3243 uint8_t bssColor,
3244 bool incrementUid);
3245
3246 /**
3247 * Send HE SU PPDU function
3248 * @param txStaId the ID of the TX STA
3249 * @param payloadSize the size of the payload in bytes
3250 * @param uid the UID of the trigger frame that is initiating this transmission
3251 * @param bssColor the BSS color of the TX STA
3252 */
3253 void SendSuPpdu(uint16_t txStaId, std::size_t payloadSize, uint64_t uid, uint8_t bssColor);
3254
3255 /**
3256 * Set the BSS color
3257 * @param phy the PHY
3258 * @param bssColor the BSS color
3259 */
3260 void SetBssColor(Ptr<WifiPhy> phy, uint8_t bssColor);
3261
3262 /**
3263 * Set the PSD limit
3264 * @param phy the PHY
3265 * @param psdLimit the PSD limit
3266 */
3267 void SetPsdLimit(Ptr<WifiPhy> phy, dBm_per_MHz_u psdLimit);
3268
3269 /**
3270 * Generate interference function
3271 * @param interferencePsd the PSD of the interference to be generated
3272 * @param duration the duration of the interference
3273 */
3274 void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
3275 /**
3276 * Stop interference function
3277 */
3278 void StopInterference();
3279
3280 /**
3281 * Run one function
3282 */
3283 void RunOne();
3284
3285 /**
3286 * Check the received PSDUs from STA1
3287 * @param expectedSuccess the expected number of success
3288 * @param expectedFailures the expected number of failures
3289 * @param expectedBytes the expected number of bytes
3290 */
3291 void CheckRxFromSta1(uint32_t expectedSuccess,
3292 uint32_t expectedFailures,
3293 uint32_t expectedBytes);
3294
3295 /**
3296 * Check the received PSDUs from STA2
3297 * @param expectedSuccess the expected number of success
3298 * @param expectedFailures the expected number of failures
3299 * @param expectedBytes the expected number of bytes
3300 */
3301 void CheckRxFromSta2(uint32_t expectedSuccess,
3302 uint32_t expectedFailures,
3303 uint32_t expectedBytes);
3304
3305 /**
3306 * Check the received power for the non-OFDMA of the HE TB PPDUs over the given band
3307 * @param phy the PHY
3308 * @param band the indices of the band over which the power is measured
3309 * @param expectedRxPower the expected received power
3310 */
3313 Watt_u expectedRxPower);
3314 /**
3315 * Check the received power for the OFDMA part of the HE TB PPDUs over the given band
3316 * @param phy the PHY
3317 * @param band the indices of the band over which the power is measured
3318 * @param expectedRxPower the expected received power
3319 */
3322 Watt_u expectedRxPower);
3323
3324 /**
3325 * Verify all events are cleared at end of TX or RX
3326 */
3327 void VerifyEventsCleared();
3328
3329 /**
3330 * Check the PHY state
3331 * @param phy the PHY
3332 * @param expectedState the expected state of the PHY
3333 */
3335 WifiPhyState expectedState);
3336 /// @copydoc CheckPhyState
3338 WifiPhyState expectedState);
3339
3340 /**
3341 * Check the the number of RX start notifications at the AP as well as the last time a RX start
3342 * has been notified
3343 * @param expectedNotifications the expected number of RX start notifications at the AP
3344 * @param expectedLastNotification the expected time of the last RX start notification at the AP
3345 */
3346 void CheckApRxStart(uint32_t expectedNotifications, Time expectedLastNotification);
3347 /**
3348 * Check the the number of RX end notifications at the AP as well as the last time a RX end has
3349 * been notified
3350 * @param expectedNotifications the expected number of RX end notifications at the AP
3351 * @param expectedLastNotification the expected time of the last RX end notification at the AP
3352 * @param expectedSuccess true if the last RX notification indicates a success, false otherwise
3353 */
3354 void CheckApRxEnd(uint32_t expectedNotifications,
3355 Time expectedLastNotification,
3356 bool expectedSuccess);
3357
3358 /**
3359 * Reset function
3360 */
3361 void Reset();
3362
3363 /**
3364 * Receive success function
3365 * @param psdu the PSDU
3366 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
3367 * @param txVector the transmit vector
3368 * @param statusPerMpdu reception status per MPDU
3369 */
3371 RxSignalInfo rxSignalInfo,
3372 const WifiTxVector& txVector,
3373 const std::vector<bool>& statusPerMpdu);
3374
3375 /**
3376 * Receive failure function
3377 * @param psdu the PSDU
3378 */
3379 void RxFailure(Ptr<const WifiPsdu> psdu);
3380
3381 /**
3382 * Schedule test to perform.
3383 * The interference generation should be scheduled apart.
3384 *
3385 * @param delay the reference delay to schedule the events
3386 * @param solicited flag indicating if HE TB PPDUs were solicited by the AP
3387 * @param expectedStateAtEnd the expected state of the PHY at the end of the reception
3388 * @param expectedSuccessFromSta1 the expected number of success from STA 1
3389 * @param expectedFailuresFromSta1 the expected number of failures from STA 1
3390 * @param expectedBytesFromSta1 the expected number of bytes from STA 1
3391 * @param expectedSuccessFromSta2 the expected number of success from STA 2
3392 * @param expectedFailuresFromSta2 the expected number of failures from STA 2
3393 * @param expectedBytesFromSta2 the expected number of bytes from STA 2
3394 * @param scheduleTxSta1 flag indicating to schedule a HE TB PPDU from STA 1
3395 * @param ulTimeDifference delay between HE TB PPDU from STA 1 and HE TB PPDU from STA 2
3396 * are received
3397 * @param expectedStateBeforeEnd the expected state of the PHY before the end of the
3398 * transmission
3399 * @param error the erroneous info (if any) in the TRIGVECTOR to set
3400 */
3401 void ScheduleTest(Time delay,
3402 bool solicited,
3403 WifiPhyState expectedStateAtEnd,
3404 uint32_t expectedSuccessFromSta1,
3405 uint32_t expectedFailuresFromSta1,
3406 uint32_t expectedBytesFromSta1,
3407 uint32_t expectedSuccessFromSta2,
3408 uint32_t expectedFailuresFromSta2,
3409 uint32_t expectedBytesFromSta2,
3410 bool scheduleTxSta1 = true,
3411 Time ulTimeDifference = Seconds(0),
3412 WifiPhyState expectedStateBeforeEnd = WifiPhyState::RX,
3413 TrigVectorInfo error = NONE);
3414
3415 /**
3416 * Schedule power measurement related checks.
3417 *
3418 * @param delay the reference delay used to schedule the events
3419 * @param rxPowerNonOfdmaRu1 the received power on the non-OFDMA part of RU1
3420 * @param rxPowerNonOfdmaRu2 the received power on the non-OFDMA part of RU2
3421 * @param rxPowerOfdmaRu1 the received power on RU1
3422 * @param rxPowerOfdmaRu2 the received power on RU2
3423 */
3425 Watt_u rxPowerNonOfdmaRu1,
3426 Watt_u rxPowerNonOfdmaRu2,
3427 Watt_u rxPowerOfdmaRu1,
3428 Watt_u rxPowerOfdmaRu2);
3429 /**
3430 * Log scenario description
3431 *
3432 * @param log the scenario description to add to log
3433 */
3434 void LogScenario(std::string log) const;
3435
3436 WifiModulationClass m_modClass; ///< the modulation class to consider for the test
3437
3442
3443 std::shared_ptr<OfdmaTestPhyListener>
3444 m_apPhyStateListener; ///< listener for AP PHY state transitions
3445
3447
3448 uint32_t m_countRxSuccessFromSta1{0}; ///< count RX success from STA 1
3449 uint32_t m_countRxSuccessFromSta2{0}; ///< count RX success from STA 2
3450 uint32_t m_countRxFailureFromSta1{0}; ///< count RX failure from STA 1
3451 uint32_t m_countRxFailureFromSta2{0}; ///< count RX failure from STA 2
3452 uint32_t m_countRxBytesFromSta1{0}; ///< count RX bytes from STA 1
3453 uint32_t m_countRxBytesFromSta2{0}; ///< count RX bytes from STA 2
3454
3457 Time m_expectedPpduDuration; ///< expected duration to send MU PPDU
3458};
3459
3460template <typename LatestPhyEntityType>
3462 : TestCase{std::string("UL-OFDMA PHY test for ") +
3463 ((Demangle(typeid(LatestPhyEntityType).name()).find("He") != std::string::npos)
3464 ? "HE"
3465 : "EHT")},
3466 m_modClass{(Demangle(typeid(LatestPhyEntityType).name()).find("He") != std::string::npos)
3469 m_expectedPpduDuration{NanoSeconds(271200)}
3470{
3471}
3472
3473template <typename LatestPhyEntityType>
3474void
3476 std::size_t payloadSize,
3477 uint64_t uid,
3478 uint8_t bssColor)
3479{
3480 NS_LOG_FUNCTION(this << txStaId << payloadSize << uid << +bssColor);
3481 WifiConstPsduMap psdus;
3482
3483 WifiTxVector txVector{
3485 0,
3487 NanoSeconds(800),
3488 1,
3489 1,
3490 0,
3491 m_channelWidth,
3492 false,
3493 false,
3494 false,
3495 bssColor};
3496
3497 auto pkt = Create<Packet>(payloadSize);
3498 WifiMacHeader hdr;
3500 hdr.SetQosTid(0);
3501 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
3502 std::ostringstream addr;
3503 addr << "00:00:00:00:00:0" << txStaId;
3504 hdr.SetAddr2(Mac48Address(addr.str().c_str()));
3505 hdr.SetSequenceNumber(1);
3506 auto psdu = Create<WifiPsdu>(pkt, hdr);
3507 psdus.insert(std::make_pair(SU_STA_ID, psdu));
3508
3510 if (txStaId == 1)
3511 {
3512 phy = m_phySta1;
3513 }
3514 else if (txStaId == 2)
3515 {
3516 phy = m_phySta2;
3517 }
3518 else if (txStaId == 3)
3519 {
3520 phy = m_phySta3;
3521 }
3522 else if (txStaId == 0)
3523 {
3524 phy = m_phyAp;
3525 }
3526 phy->SetPpduUid(uid);
3527 phy->Send(psdus, txVector);
3528}
3529
3530template <typename LatestPhyEntityType>
3533 std::size_t index,
3534 uint8_t bssColor) const
3535{
3536 WifiTxVector txVector{
3538 0,
3540 NanoSeconds(1600),
3541 1,
3542 1,
3543 0,
3544 m_channelWidth,
3545 false,
3546 false,
3547 false,
3548 bssColor};
3549 if (m_modClass == WIFI_MOD_CLASS_EHT)
3550 {
3551 txVector.SetEhtPpduType(0);
3552 }
3553 auto ruType{RuType::RU_TYPE_MAX};
3554 if (m_channelWidth == MHz_u{20})
3555 {
3556 ruType = RuType::RU_106_TONE;
3557 }
3558 else if (m_channelWidth == MHz_u{40})
3559 {
3560 ruType = RuType::RU_242_TONE;
3561 }
3562 else if (m_channelWidth == MHz_u{80})
3563 {
3564 ruType = RuType::RU_484_TONE;
3565 }
3566 else if (m_channelWidth == MHz_u{160})
3567 {
3568 ruType = RuType::RU_996_TONE;
3569 }
3570 else if (m_channelWidth == MHz_u{320})
3571 {
3572 ruType = RuType::RU_2x996_TONE;
3573 }
3574 else
3575 {
3576 NS_ASSERT_MSG(false, "Unsupported channel width: " << m_channelWidth);
3577 }
3578
3579 auto primary80MHzOrLow80MHz{true};
3580 auto primary160MHz{true};
3581 if (m_channelWidth > MHz_u{80})
3582 {
3583 if (m_modClass == WIFI_MOD_CLASS_HE)
3584 {
3585 primary80MHzOrLow80MHz = HeRu::GetPrimary80MHzFlag(m_channelWidth, ruType, index, 0);
3586 index = HeRu::GetIndexIn80MHzSegment(m_channelWidth, ruType, index);
3587 }
3588 else
3589 {
3590 const auto& [p160, p80OrLow80] =
3591 EhtRu::GetPrimaryFlags(m_channelWidth, ruType, index, 0);
3592 primary160MHz = p160;
3593 primary80MHzOrLow80MHz = p80OrLow80;
3594 index = EhtRu::GetIndexIn80MHzSegment(m_channelWidth, ruType, index);
3595 }
3596 }
3597 const auto ru =
3598 (m_modClass == WIFI_MOD_CLASS_HE)
3599 ? WifiRu::RuSpec(HeRu::RuSpec{ruType, index, primary80MHzOrLow80MHz})
3600 : WifiRu::RuSpec(EhtRu::RuSpec{ruType, index, primary160MHz, primary80MHzOrLow80MHz});
3601 txVector.SetRu(ru, txStaId);
3602 txVector.SetMode((m_modClass == WIFI_MOD_CLASS_HE) ? HePhy::GetHeMcs7() : EhtPhy::GetEhtMcs7(),
3603 txStaId);
3604 txVector.SetNss(1, txStaId);
3605 return txVector;
3606}
3607
3608template <typename LatestPhyEntityType>
3609void
3611 TrigVectorInfo error)
3612{
3613 auto channelWidth = m_channelWidth;
3614 if (error == CHANNEL_WIDTH)
3615 {
3616 channelWidth =
3617 (channelWidth >= GetMaximumChannelWidth(m_modClass) ? MHz_u{20} : channelWidth * 2);
3618 }
3619
3620 WifiTxVector txVector(
3622 0,
3624 NanoSeconds(1600),
3625 1,
3626 1,
3627 0,
3628 channelWidth,
3629 false,
3630 false,
3631 false,
3632 bssColor);
3633
3634 RuType ruType = RuType::RU_106_TONE;
3635 if (channelWidth == MHz_u{20})
3636 {
3637 ruType = RuType::RU_106_TONE;
3638 }
3639 else if (channelWidth == MHz_u{40})
3640 {
3641 ruType = RuType::RU_242_TONE;
3642 }
3643 else if (channelWidth == MHz_u{80})
3644 {
3645 ruType = RuType::RU_484_TONE;
3646 }
3647 else if (channelWidth == MHz_u{160})
3648 {
3649 ruType = RuType::RU_996_TONE;
3650 }
3651 else if (channelWidth == MHz_u{320})
3652 {
3653 ruType = RuType::RU_2x996_TONE;
3654 }
3655 else
3656 {
3657 NS_ASSERT_MSG(false, "Unsupported channel width: " << channelWidth);
3658 }
3659
3660 uint16_t aid1 = (error == AID ? 3 : 1);
3661 uint16_t aid2 = (error == AID ? 4 : 2);
3662
3663 const auto ru1 = (m_modClass == WIFI_MOD_CLASS_HE)
3664 ? WifiRu::RuSpec(HeRu::RuSpec{ruType, 1, true})
3665 : WifiRu::RuSpec(EhtRu::RuSpec{ruType, 1, true, true});
3666 txVector.SetRu(ru1, aid1);
3667 txVector.SetMode((m_modClass == WIFI_MOD_CLASS_HE) ? HePhy::GetHeMcs7() : EhtPhy::GetEhtMcs7(),
3668 aid1);
3669 txVector.SetNss(1, aid1);
3670
3671 const auto ru2 = (m_modClass == WIFI_MOD_CLASS_HE)
3673 (channelWidth == MHz_u{160} ? 1ULL : 2ULL),
3674 (channelWidth != MHz_u{160})})
3676 (channelWidth == MHz_u{320} ? 1ULL : 2ULL),
3677 (channelWidth != MHz_u{320}),
3678 true});
3679 txVector.SetRu(ru2, aid2);
3680 txVector.SetMode((m_modClass == WIFI_MOD_CLASS_HE) ? HePhy::GetHeMcs7() : EhtPhy::GetEhtMcs7(),
3681 aid2);
3682 txVector.SetNss(1, aid2);
3683
3684 uint16_t length;
3685 std::tie(length, m_expectedPpduDuration) =
3686 HePhy::ConvertHeTbPpduDurationToLSigLength(m_expectedPpduDuration,
3687 txVector,
3688 m_phyAp->GetPhyBand());
3689 if (error == UL_LENGTH)
3690 {
3691 ++length;
3692 }
3693 txVector.SetLength(length);
3694 auto phyAp = m_phyAp->GetPhyEntity();
3695 phyAp->SetTrigVector(txVector, m_expectedPpduDuration);
3696}
3697
3698template <typename LatestPhyEntityType>
3699void
3701 std::size_t index,
3702 std::size_t payloadSize,
3703 uint64_t uid,
3704 uint8_t bssColor,
3705 bool incrementUid)
3706{
3707 NS_LOG_FUNCTION(this << txStaId << index << payloadSize << uid << +bssColor << (incrementUid));
3708 WifiConstPsduMap psdus;
3709
3710 if (incrementUid)
3711 {
3712 ++uid;
3713 }
3714
3715 auto txVector = GetTxVectorForTbPpdu(txStaId, index, bssColor);
3716 Ptr<Packet> pkt = Create<Packet>(payloadSize);
3717 WifiMacHeader hdr;
3719 hdr.SetQosTid(0);
3720 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
3721 std::ostringstream addr;
3722 addr << "00:00:00:00:00:0" << txStaId;
3723 hdr.SetAddr2(Mac48Address(addr.str().c_str()));
3724 hdr.SetSequenceNumber(1);
3725 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
3726 psdus.insert(std::make_pair(txStaId, psdu));
3727
3729 if (txStaId == 1)
3730 {
3731 phy = m_phySta1;
3732 }
3733 else if (txStaId == 2)
3734 {
3735 phy = m_phySta2;
3736 }
3737 else if (txStaId == 3)
3738 {
3739 phy = m_phySta3;
3740 }
3741
3742 Time txDuration =
3744 txVector,
3745 phy->GetPhyBand(),
3746 txStaId);
3747 txVector.SetLength(
3748 HePhy::ConvertHeTbPpduDurationToLSigLength(txDuration, txVector, phy->GetPhyBand()).first);
3749
3750 phy->SetPpduUid(uid);
3751 phy->Send(psdus, txVector);
3752}
3753
3754template <typename LatestPhyEntityType>
3755void
3757 Ptr<SpectrumValue> interferencePsd,
3758 Time duration)
3759{
3760 NS_LOG_FUNCTION(this << duration);
3761 m_phyInterferer->SetTxPowerSpectralDensity(interferencePsd);
3762 m_phyInterferer->SetPeriod(duration);
3763 m_phyInterferer->Start();
3764 Simulator::Schedule(duration,
3766 this);
3767}
3768
3769template <typename LatestPhyEntityType>
3770void
3775
3776template <typename LatestPhyEntityType>
3777void
3780 RxSignalInfo rxSignalInfo,
3781 const WifiTxVector& txVector,
3782 const std::vector<bool>& /*statusPerMpdu*/)
3783{
3784 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2() << rxSignalInfo << txVector);
3785 if (psdu->GetAddr2() == Mac48Address("00:00:00:00:00:01"))
3786 {
3787 m_countRxSuccessFromSta1++;
3788 m_countRxBytesFromSta1 += (psdu->GetSize() - 30);
3789 }
3790 else if (psdu->GetAddr2() == Mac48Address("00:00:00:00:00:02"))
3791 {
3792 m_countRxSuccessFromSta2++;
3793 m_countRxBytesFromSta2 += (psdu->GetSize() - 30);
3794 }
3795}
3796
3797template <typename LatestPhyEntityType>
3798void
3800{
3801 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2());
3802 if (psdu->GetAddr2() == Mac48Address("00:00:00:00:00:01"))
3803 {
3804 m_countRxFailureFromSta1++;
3805 }
3806 else if (psdu->GetAddr2() == Mac48Address("00:00:00:00:00:02"))
3807 {
3808 m_countRxFailureFromSta2++;
3809 }
3810}
3811
3812template <typename LatestPhyEntityType>
3813void
3815 uint32_t expectedFailures,
3816 uint32_t expectedBytes)
3817{
3818 NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessFromSta1,
3819 expectedSuccess,
3820 "The number of successfully received packets from STA 1 is not correct!");
3822 m_countRxFailureFromSta1,
3823 expectedFailures,
3824 "The number of unsuccessfully received packets from STA 1 is not correct!");
3825 NS_TEST_ASSERT_MSG_EQ(m_countRxBytesFromSta1,
3826 expectedBytes,
3827 "The number of bytes received from STA 1 is not correct!");
3828}
3829
3830template <typename LatestPhyEntityType>
3831void
3833 uint32_t expectedFailures,
3834 uint32_t expectedBytes)
3835{
3836 NS_TEST_ASSERT_MSG_EQ(m_countRxSuccessFromSta2,
3837 expectedSuccess,
3838 "The number of successfully received packets from STA 2 is not correct!");
3840 m_countRxFailureFromSta2,
3841 expectedFailures,
3842 "The number of unsuccessfully received packets from STA 2 is not correct!");
3843 NS_TEST_ASSERT_MSG_EQ(m_countRxBytesFromSta2,
3844 expectedBytes,
3845 "The number of bytes received from STA 2 is not correct!");
3846}
3847
3848template <typename LatestPhyEntityType>
3849void
3853 Watt_u expectedRxPower)
3854{
3855 auto event = phy->GetCurrentEvent();
3856 NS_ASSERT(event);
3857 auto rxPower = event->GetRxPower(band);
3858 NS_LOG_FUNCTION(this << band << expectedRxPower << rxPower);
3859 // Since there is out of band emission due to spectrum mask, the tolerance cannot be very low
3861 expectedRxPower,
3862 Watt_u{5e-3},
3863 "RX power " << rxPower << " over (" << band
3864 << ") does not match expected power " << expectedRxPower
3865 << " at " << Simulator::Now());
3866}
3867
3868template <typename LatestPhyEntityType>
3869void
3873 Watt_u expectedRxPower)
3874{
3875 /**
3876 * The current event cannot be used since it points to the preamble part of the HE TB PPDU.
3877 * We will have to check if the expected power is indeed the max power returning a positive
3878 * duration when calling GetEnergyDuration.
3879 */
3880 NS_LOG_FUNCTION(this << band << expectedRxPower);
3881 Watt_u step{5e-3};
3882 if (expectedRxPower > Watt_u{0.0})
3883 {
3885 phy->GetEnergyDuration(expectedRxPower - step, band).IsStrictlyPositive(),
3886 true,
3887 "At least " << expectedRxPower << " W expected for OFDMA part over (" << band << ") at "
3888 << Simulator::Now());
3890 phy->GetEnergyDuration(expectedRxPower + step, band).IsStrictlyPositive(),
3891 false,
3892 "At most " << expectedRxPower << " W expected for OFDMA part over (" << band << ") at "
3893 << Simulator::Now());
3894 }
3895 else
3896 {
3898 phy->GetEnergyDuration(expectedRxPower + step, band).IsStrictlyPositive(),
3899 false,
3900 "At most " << expectedRxPower << " W expected for OFDMA part over (" << band << ") at "
3901 << Simulator::Now());
3902 }
3903}
3904
3905template <typename LatestPhyEntityType>
3906void
3908{
3909 NS_TEST_ASSERT_MSG_EQ(m_phyAp->GetCurrentEvent(),
3910 nullptr,
3911 "m_currentEvent for AP was not cleared");
3912 NS_TEST_ASSERT_MSG_EQ(m_phySta1->GetCurrentEvent(),
3913 nullptr,
3914 "m_currentEvent for STA 1 was not cleared");
3915 NS_TEST_ASSERT_MSG_EQ(m_phySta2->GetCurrentEvent(),
3916 nullptr,
3917 "m_currentEvent for STA 2 was not cleared");
3918}
3919
3920template <typename LatestPhyEntityType>
3921void
3924 WifiPhyState expectedState)
3925{
3926 // This is needed to make sure PHY state will be checked as the last event if a state change
3927 // occurred at the exact same time as the check
3929 this,
3930 phy,
3931 expectedState);
3932}
3933
3934template <typename LatestPhyEntityType>
3935void
3938 WifiPhyState expectedState)
3939{
3940 WifiPhyState currentState;
3941 PointerValue ptr;
3942 phy->GetAttribute("State", ptr);
3944 currentState = state->GetState();
3945 NS_LOG_FUNCTION(this << currentState);
3946 NS_TEST_ASSERT_MSG_EQ(currentState,
3947 expectedState,
3948 "PHY State " << currentState << " does not match expected state "
3949 << expectedState << " at " << Simulator::Now());
3950}
3951
3952template <typename LatestPhyEntityType>
3953void
3955 Time expectedLastNotification)
3956{
3957 NS_TEST_ASSERT_MSG_EQ(m_apPhyStateListener->GetNumRxStartNotifications(),
3958 expectedNotifications,
3959 "Number of RX start notifications "
3960 << m_apPhyStateListener->GetNumRxStartNotifications()
3961 << " does not match expected count " << expectedNotifications
3962 << " for AP at " << Simulator::Now());
3963 NS_TEST_ASSERT_MSG_EQ(m_apPhyStateListener->GetLastRxStartNotification(),
3964 expectedLastNotification,
3965 "Last time RX start notification has been received "
3966 << m_apPhyStateListener->GetLastRxStartNotification()
3967 << " does not match expected time " << expectedLastNotification
3968 << " for AP at " << Simulator::Now());
3969}
3970
3971template <typename LatestPhyEntityType>
3972void
3974 Time expectedLastNotification,
3975 bool expectedSuccess)
3976{
3977 NS_TEST_ASSERT_MSG_EQ(m_apPhyStateListener->GetNumRxEndNotifications(),
3978 expectedNotifications,
3979 "Number of RX end notifications "
3980 << m_apPhyStateListener->GetNumRxEndNotifications()
3981 << " does not match expected count " << expectedNotifications
3982 << " for AP at " << Simulator::Now());
3983 NS_TEST_ASSERT_MSG_EQ(m_apPhyStateListener->GetLastRxEndNotification(),
3984 expectedLastNotification,
3985 "Last time RX end notification has been received "
3986 << m_apPhyStateListener->GetLastRxEndNotification()
3987 << " does not match expected time " << expectedLastNotification
3988 << " for AP at " << Simulator::Now());
3989 NS_TEST_ASSERT_MSG_EQ(m_apPhyStateListener->IsLastRxSuccess(),
3990 expectedSuccess,
3991 "Last time RX end notification indicated a "
3992 << (m_apPhyStateListener->IsLastRxSuccess() ? "success" : "failure")
3993 << " but expected a " << (expectedSuccess ? "success" : "failure")
3994 << " for AP at " << Simulator::Now());
3995}
3996
3997template <typename LatestPhyEntityType>
3998void
4000{
4001 m_countRxSuccessFromSta1 = 0;
4002 m_countRxSuccessFromSta2 = 0;
4003 m_countRxFailureFromSta1 = 0;
4004 m_countRxFailureFromSta2 = 0;
4005 m_countRxBytesFromSta1 = 0;
4006 m_countRxBytesFromSta2 = 0;
4007 m_phySta1->SetPpduUid(0);
4008 m_phySta1->SetTriggerFrameUid(0);
4009 m_phySta2->SetTriggerFrameUid(0);
4010 SetBssColor(m_phyAp, 0);
4011 m_apPhyStateListener->Reset();
4012}
4013
4014template <typename LatestPhyEntityType>
4015void
4017{
4018 Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice>(phy->GetDevice());
4019 Ptr<HeConfiguration> heConfiguration = device->GetHeConfiguration();
4020 heConfiguration->m_bssColor = bssColor;
4021}
4022
4023template <typename LatestPhyEntityType>
4024void
4026 dBm_per_MHz_u psdLimit)
4027{
4028 NS_LOG_FUNCTION(this << phy << psdLimit);
4029 phy->SetAttribute("PowerDensityLimit", DoubleValue(psdLimit));
4030}
4031
4032template <typename LatestPhyEntityType>
4033void
4035{
4036 const auto standard =
4038
4041 lossModel->SetFrequency(m_frequency);
4042 spectrumChannel->AddPropagationLossModel(lossModel);
4045 spectrumChannel->SetPropagationDelayModel(delayModel);
4046
4047 Ptr<ThresholdPreambleDetectionModel> preambleDetectionModel =
4049 preambleDetectionModel->SetAttribute(
4050 "MinimumRssi",
4052 -8)); // to ensure that transmission in neighboring channel is ignored (16 dBm baseline)
4053 preambleDetectionModel->SetAttribute("Threshold", DoubleValue(-100)); // no limit on SNR
4054
4055 Ptr<Node> apNode = CreateObject<Node>();
4057 apDev->SetStandard(standard);
4059 "Txop",
4060 PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
4061 apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
4062 apDev->SetMac(apMac);
4065 apDev->SetHeConfiguration(heConfiguration);
4066 if (m_modClass >= WIFI_MOD_CLASS_EHT)
4067 {
4068 apDev->SetEhtConfiguration(CreateObject<EhtConfiguration>());
4069 }
4071 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
4073 m_phyAp->SetErrorRateModel(apErrorModel);
4074 m_phyAp->SetDevice(apDev);
4075 m_phyAp->AddChannel(spectrumChannel);
4076 m_phyAp->ConfigureStandard(standard);
4077 m_phyAp->SetReceiveOkCallback(
4079 m_phyAp->SetReceiveErrorCallback(
4081 m_phyAp->SetPreambleDetectionModel(preambleDetectionModel);
4083 m_phyAp->SetMobility(apMobility);
4084 m_apPhyStateListener = std::make_unique<OfdmaTestPhyListener>();
4085 m_phyAp->RegisterListener(m_apPhyStateListener);
4086 apDev->SetPhy(m_phyAp);
4087 apMac->SetWifiPhys({m_phyAp});
4088 apNode->AggregateObject(apMobility);
4089 apNode->AddDevice(apDev);
4090
4091 Ptr<Node> sta1Node = CreateObject<Node>();
4093 sta1Dev->SetStandard(standard);
4094 sta1Dev->SetHeConfiguration(CreateObject<HeConfiguration>());
4095 if (m_modClass >= WIFI_MOD_CLASS_EHT)
4096 {
4097 sta1Dev->SetEhtConfiguration(CreateObject<EhtConfiguration>());
4098 }
4101 m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
4103 m_phySta1->SetErrorRateModel(sta1ErrorModel);
4104 m_phySta1->SetDevice(sta1Dev);
4105 m_phySta1->AddChannel(spectrumChannel);
4106 m_phySta1->ConfigureStandard(standard);
4107 m_phySta1->SetPreambleDetectionModel(preambleDetectionModel);
4109 m_phySta1->SetMobility(sta1Mobility);
4110 sta1Dev->SetPhy(m_phySta1);
4111 sta1Node->AggregateObject(sta1Mobility);
4112 sta1Node->AddDevice(sta1Dev);
4113
4114 Ptr<Node> sta2Node = CreateObject<Node>();
4116 sta2Dev->SetStandard(standard);
4117 sta2Dev->SetHeConfiguration(CreateObject<HeConfiguration>());
4118 if (m_modClass >= WIFI_MOD_CLASS_EHT)
4119 {
4120 sta2Dev->SetEhtConfiguration(CreateObject<EhtConfiguration>());
4121 }
4124 m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
4126 m_phySta2->SetErrorRateModel(sta2ErrorModel);
4127 m_phySta2->SetDevice(sta2Dev);
4128 m_phySta2->AddChannel(spectrumChannel);
4129 m_phySta2->ConfigureStandard(standard);
4130 m_phySta2->SetPreambleDetectionModel(preambleDetectionModel);
4132 m_phySta2->SetMobility(sta2Mobility);
4133 sta2Dev->SetPhy(m_phySta2);
4134 sta2Node->AggregateObject(sta2Mobility);
4135 sta2Node->AddDevice(sta2Dev);
4136
4137 Ptr<Node> sta3Node = CreateObject<Node>();
4139 sta3Dev->SetStandard(standard);
4140 sta3Dev->SetHeConfiguration(CreateObject<HeConfiguration>());
4141 if (m_modClass >= WIFI_MOD_CLASS_EHT)
4142 {
4143 sta3Dev->SetEhtConfiguration(CreateObject<EhtConfiguration>());
4144 }
4147 m_phySta3->SetInterferenceHelper(sta3InterferenceHelper);
4149 m_phySta3->SetErrorRateModel(sta3ErrorModel);
4150 m_phySta3->SetDevice(sta3Dev);
4151 m_phySta3->AddChannel(spectrumChannel);
4152 m_phySta3->ConfigureStandard(standard);
4153 m_phySta3->SetPreambleDetectionModel(preambleDetectionModel);
4155 m_phySta3->SetMobility(sta3Mobility);
4156 sta3Dev->SetPhy(m_phySta3);
4157 sta3Node->AggregateObject(sta3Mobility);
4158 sta3Node->AddDevice(sta3Dev);
4159
4160 Ptr<Node> interfererNode = CreateObject<Node>();
4162 m_phyInterferer = CreateObject<WaveformGenerator>();
4163 m_phyInterferer->SetDevice(interfererDev);
4164 m_phyInterferer->SetChannel(spectrumChannel);
4165 m_phyInterferer->SetDutyCycle(1);
4166 interfererNode->AddDevice(interfererDev);
4167
4168 // Configure power attributes of all wifi devices
4169 std::list<Ptr<WifiPhy>> phys{m_phyAp, m_phySta1, m_phySta2, m_phySta3};
4170 for (auto& phy : phys)
4171 {
4172 phy->SetAttribute("TxGain", DoubleValue(1.0));
4173 phy->SetAttribute("TxPowerStart", DoubleValue(16.0));
4174 phy->SetAttribute("TxPowerEnd", DoubleValue(16.0));
4175 phy->SetAttribute("PowerDensityLimit", DoubleValue(100.0)); // no impact by default
4176 phy->SetAttribute("RxGain", DoubleValue(2.0));
4177 // test assumes no rejection power for simplicity
4178 phy->SetAttribute("TxMaskInnerBandMinimumRejection", DoubleValue(-100.0));
4179 phy->SetAttribute("TxMaskOuterBandMinimumRejection", DoubleValue(-100.0));
4180 phy->SetAttribute("TxMaskOuterBandMaximumRejection", DoubleValue(-100.0));
4181 }
4182}
4183
4184template <typename LatestPhyEntityType>
4185void
4187{
4188 m_phyAp->Dispose();
4189 m_phyAp = nullptr;
4190 m_phySta1->Dispose();
4191 m_phySta1 = nullptr;
4192 m_phySta2->Dispose();
4193 m_phySta2 = nullptr;
4194 m_phySta3->Dispose();
4195 m_phySta3 = nullptr;
4196 m_phyInterferer->Dispose();
4197 m_phyInterferer = nullptr;
4198}
4199
4200template <typename LatestPhyEntityType>
4201void
4206
4207template <typename LatestPhyEntityType>
4208void
4210 bool solicited,
4211 WifiPhyState expectedStateAtEnd,
4212 uint32_t expectedSuccessFromSta1,
4213 uint32_t expectedFailuresFromSta1,
4214 uint32_t expectedBytesFromSta1,
4215 uint32_t expectedSuccessFromSta2,
4216 uint32_t expectedFailuresFromSta2,
4217 uint32_t expectedBytesFromSta2,
4218 bool scheduleTxSta1,
4219 Time ulTimeDifference,
4220 WifiPhyState expectedStateBeforeEnd,
4221 TrigVectorInfo error)
4222{
4223 static uint64_t uid = 0;
4224
4225 // AP sends an SU packet preceding HE TB PPDUs
4228 this,
4229 0,
4230 50,
4231 ++uid,
4232 0);
4233 if (!solicited)
4234 {
4235 // UID of TB PPDUs will be different than the one of the preceding frame
4236 ++uid;
4237 }
4238 else
4239 {
4240 Simulator::Schedule(delay,
4242 this,
4243 0,
4244 error);
4245 }
4246 // STA1 and STA2 send MU UL PPDUs addressed to AP
4249 m_apPhyStateListener.get());
4250 if (scheduleTxSta1)
4251 {
4252 Simulator::Schedule(delay,
4254 this,
4255 1,
4256 1,
4257 1000,
4258 uid,
4259 0,
4260 false);
4261 }
4262 Simulator::Schedule(delay + ulTimeDifference,
4264 this,
4265 2,
4266 2,
4267 1001,
4268 uid,
4269 0,
4270 false);
4271
4272 // Verify it takes m_expectedPpduDuration to transmit the PPDUs
4273 Simulator::Schedule(delay + m_expectedPpduDuration - NanoSeconds(1),
4275 this,
4276 m_phyAp,
4277 expectedStateBeforeEnd);
4278 Simulator::Schedule(delay + m_expectedPpduDuration + ulTimeDifference,
4280 this,
4281 m_phyAp,
4282 expectedStateAtEnd);
4283 // TODO: add checks on TX stop for STAs
4284
4285 if (expectedSuccessFromSta1 + expectedFailuresFromSta1 + expectedSuccessFromSta2 +
4286 expectedFailuresFromSta2 >
4287 0)
4288 {
4289 // RxEndOk if at least one HE TB PPDU has been successfully received, RxEndError otherwise
4290 const bool isSuccess = (expectedSuccessFromSta1 > 0) || (expectedSuccessFromSta2 > 0);
4291 // The expected time at which the reception is started corresponds to the time at which the
4292 // test is started, plus the time to transmit the PHY preamble and the PHY headers.
4293 const Time expectedPayloadStart = delay + MicroSeconds(48);
4294 // The expected time at which the reception is terminated corresponds to the time at which
4295 // the test is started, plus the time to transmit the PPDU, plus the delay between the first
4296 // received HE TB PPDU and the last received HE TB PPDU.
4297 const Time expectedPayloadEnd = delay + m_expectedPpduDuration + ulTimeDifference;
4298 // At the end of the transmission, verify that a single RX start notification shall have
4299 // been notified when the reception of the first HE RB PPDU starts.
4300 Simulator::Schedule(expectedPayloadEnd,
4302 this,
4303 1,
4304 Simulator::Now() + expectedPayloadStart);
4305 // After the reception (hence we add 1ns to expectedPayloadEnd), a single RX end
4306 // notification shall have been notified when the reception of the last HE RB PPDU ends
4307 Simulator::Schedule(expectedPayloadEnd + NanoSeconds(1),
4309 this,
4310 1,
4311 Simulator::Now() + expectedPayloadEnd,
4312 isSuccess);
4313 }
4314
4315 delay += MilliSeconds(100);
4316 // Check reception state from STA 1
4317 Simulator::Schedule(delay,
4319 this,
4320 expectedSuccessFromSta1,
4321 expectedFailuresFromSta1,
4322 expectedBytesFromSta1);
4323 // Check reception state from STA 2
4324 Simulator::Schedule(delay,
4326 this,
4327 expectedSuccessFromSta2,
4328 expectedFailuresFromSta2,
4329 expectedBytesFromSta2);
4330 // Verify events data have been cleared
4331 Simulator::Schedule(delay,
4333 this);
4334
4335 delay += MilliSeconds(100);
4337}
4338
4339template <typename LatestPhyEntityType>
4340void
4342 Time delay,
4343 Watt_u rxPowerNonOfdmaRu1,
4344 Watt_u rxPowerNonOfdmaRu2,
4345 Watt_u rxPowerOfdmaRu1,
4346 Watt_u rxPowerOfdmaRu2)
4347{
4348 const auto detectionDuration = WifiPhy::GetPreambleDetectionDuration();
4349 const auto txVectorSta1 = GetTxVectorForTbPpdu(1, 1, 0);
4350 const auto txVectorSta2 = GetTxVectorForTbPpdu(2, 2, 0);
4351 const auto phyEntity = DynamicCast<OfdmaTestPhy<LatestPhyEntityType>>(m_phyAp->GetPhyEntity());
4352 const auto nonOfdmaDuration = phyEntity->CalculateNonHeDurationForHeTb(txVectorSta2);
4353 NS_ASSERT(nonOfdmaDuration == phyEntity->CalculateNonHeDurationForHeTb(txVectorSta1));
4354
4355 std::vector<Watt_u> rxPowerNonOfdma{rxPowerNonOfdmaRu1, rxPowerNonOfdmaRu2};
4356 std::vector<WifiSpectrumBandInfo> nonOfdmaBand{phyEntity->GetNonOfdmaBand(txVectorSta1, 1),
4357 phyEntity->GetNonOfdmaBand(txVectorSta2, 2)};
4358 std::vector<Watt_u> rxPowerOfdma{rxPowerOfdmaRu1, rxPowerOfdmaRu2};
4359 std::vector<WifiSpectrumBandInfo> ofdmaBand{phyEntity->GetRuBandForRx(txVectorSta1, 1),
4360 phyEntity->GetRuBandForRx(txVectorSta2, 2)};
4361
4362 for (uint8_t i = 0; i < 2; ++i)
4363 {
4364 /**
4365 * Perform checks at AP
4366 */
4367 // Check received power on non-OFDMA portion
4369 delay + detectionDuration +
4370 NanoSeconds(1), // just after beginning of portion (once event is stored)
4372 this,
4373 m_phyAp,
4374 nonOfdmaBand[i],
4375 rxPowerNonOfdma[i]);
4376 Simulator::Schedule(delay + nonOfdmaDuration - NanoSeconds(1), // just before end of portion
4378 this,
4379 m_phyAp,
4380 nonOfdmaBand[i],
4381 rxPowerNonOfdma[i]);
4382 // Check received power on OFDMA portion
4383 Simulator::Schedule(delay + nonOfdmaDuration +
4384 NanoSeconds(1), // just after beginning of portion
4386 this,
4387 m_phyAp,
4388 ofdmaBand[i],
4389 rxPowerOfdma[i]);
4390 Simulator::Schedule(delay + m_expectedPpduDuration -
4391 NanoSeconds(1), // just before end of portion
4393 this,
4394 m_phyAp,
4395 ofdmaBand[i],
4396 rxPowerOfdma[i]);
4397
4398 /**
4399 * Perform checks for non-transmitting STA (STA 3).
4400 * Cannot use CheckNonOfdmaRxPower method since current event may be reset if
4401 * preamble not detected (e.g. not on primary).
4402 */
4403 // Check received power on non-OFDMA portion
4405 delay + detectionDuration +
4406 NanoSeconds(1), // just after beginning of portion (once event is stored)
4408 this,
4409 m_phySta3,
4410 nonOfdmaBand[i],
4411 rxPowerNonOfdma[i]);
4412 Simulator::Schedule(delay + nonOfdmaDuration - NanoSeconds(1), // just before end of portion
4414 this,
4415 m_phySta3,
4416 nonOfdmaBand[i],
4417 rxPowerNonOfdma[i]);
4418 // Check received power on OFDMA portion
4419 Simulator::Schedule(delay + nonOfdmaDuration +
4420 NanoSeconds(1), // just after beginning of portion
4422 this,
4423 m_phySta3,
4424 ofdmaBand[i],
4425 rxPowerOfdma[i]);
4426 Simulator::Schedule(delay + m_expectedPpduDuration -
4427 NanoSeconds(1), // just before end of portion
4429 this,
4430 m_phySta3,
4431 ofdmaBand[i],
4432 rxPowerOfdma[i]);
4433 }
4434
4435 if (rxPowerOfdmaRu1 != Watt_u{0.0})
4436 {
4437 /**
4438 * Perform checks for transmitting STA (STA 2) to ensure it has correctly logged
4439 * power received from other transmitting STA (STA 1).
4440 * Cannot use CheckNonOfdmaRxPower method since current event not set.
4441 */
4442 const auto rxPowerNonOfdmaSta1Only =
4443 (m_channelWidth >= MHz_u{40})
4444 ? rxPowerNonOfdma[0]
4445 : rxPowerNonOfdma[0] / 2; // both STAs transmit over the same 20 MHz channel
4446 // Check received power on non-OFDMA portion
4448 delay + detectionDuration +
4449 NanoSeconds(1), // just after beginning of portion (once event is stored)
4451 this,
4452 m_phySta2,
4453 nonOfdmaBand[0],
4454 rxPowerNonOfdmaSta1Only);
4455 Simulator::Schedule(delay + nonOfdmaDuration - NanoSeconds(1), // just before end of portion
4457 this,
4458 m_phySta2,
4459 nonOfdmaBand[0],
4460 rxPowerNonOfdmaSta1Only);
4461 // Check received power on OFDMA portion
4462 Simulator::Schedule(delay + nonOfdmaDuration +
4463 NanoSeconds(1), // just after beginning of portion
4465 this,
4466 m_phySta2,
4467 ofdmaBand[0],
4468 rxPowerOfdma[0]);
4469 Simulator::Schedule(delay + m_expectedPpduDuration -
4470 NanoSeconds(1), // just before end of portion
4472 this,
4473 m_phySta2,
4474 ofdmaBand[0],
4475 rxPowerOfdma[0]);
4476 }
4477}
4478
4479template <typename LatestPhyEntityType>
4480void
4482{
4483 NS_LOG_DEBUG("Run UL OFDMA PHY transmission test for " << m_channelWidth << " MHz");
4484
4487 int64_t streamNumber = 0;
4488 m_phyAp->AssignStreams(streamNumber);
4489 m_phySta1->AssignStreams(streamNumber);
4490 m_phySta2->AssignStreams(streamNumber);
4491 m_phySta3->AssignStreams(streamNumber);
4492
4493 const auto standard =
4495 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
4496 m_frequency,
4497 m_channelWidth,
4498 standard,
4500 ->number;
4501
4502 const auto operatingChannel{
4503 WifiPhy::ChannelTuple{channelNum, m_channelWidth, WIFI_PHY_BAND_6GHZ, 0}};
4504 m_phyAp->SetOperatingChannel(operatingChannel);
4505 m_phySta1->SetOperatingChannel(operatingChannel);
4506 m_phySta2->SetOperatingChannel(operatingChannel);
4507 m_phySta3->SetOperatingChannel(operatingChannel);
4508
4509 Time delay;
4511 delay += Seconds(1);
4512
4513 /**
4514 * In all the following tests, 2 HE TB PPDUs of the same UL MU transmission
4515 * are sent on RU 1 for STA 1 and RU 2 for STA 2.
4516 * The difference between solicited and unsolicited lies in that their PPDU
4517 * ID correspond to the one of the immediately preceding HE SU PPDU (thus
4518 * mimicking trigger frame reception).
4519 */
4520
4521 //---------------------------------------------------------------------------
4522 // Verify that both solicited HE TB PPDUs have been corrected received
4523 Simulator::Schedule(delay,
4525 this,
4526 "Reception of solicited HE TB PPDUs");
4527 ScheduleTest(delay,
4528 true,
4529 WifiPhyState::IDLE,
4530 1,
4531 0,
4532 1000, // One PSDU of 1000 bytes should have been successfully received from STA 1
4533 1,
4534 0,
4535 1001); // One PSDU of 1001 bytes should have been successfully received from STA 2
4536 delay += Seconds(1);
4537
4538 //---------------------------------------------------------------------------
4539 // Verify that two solicited HE TB PPDUs with delay (< 400ns) between the two signals have been
4540 // corrected received
4542 delay,
4544 this,
4545 "Reception of solicited HE TB PPDUs with delay (< 400ns) between the two signals");
4546 ScheduleTest(delay,
4547 true,
4548 WifiPhyState::IDLE,
4549 1,
4550 0,
4551 1000, // One PSDU of 1000 bytes should have been successfully received from STA 1
4552 1,
4553 0,
4554 1001, // One PSDU of 1001 bytes should have been successfully received from STA 2
4555 true,
4556 NanoSeconds(100));
4557 delay += Seconds(1);
4558
4559 //---------------------------------------------------------------------------
4560 // Verify that no unsolicited HE TB PPDU is received
4561 Simulator::Schedule(delay,
4563 this,
4564 "Dropping of unsolicited HE TB PPDUs");
4565 ScheduleTest(delay,
4566 false,
4567 WifiPhyState::IDLE,
4568 0,
4569 0,
4570 0, // PSDU from STA 1 is not received (no TRIGVECTOR)
4571 0,
4572 0,
4573 0, // PSDU from STA 2 is not received (no TRIGVECTOR)
4574 true,
4575 Seconds(0),
4576 WifiPhyState::CCA_BUSY);
4577 delay += Seconds(1);
4578
4579 //---------------------------------------------------------------------------
4580 // Verify that HE TB PPDUs with channel width differing from TRIGVECTOR are discarded
4581 Simulator::Schedule(delay,
4583 this,
4584 "Dropping of HE TB PPDUs with channel width differing from TRIGVECTOR");
4585 ScheduleTest(delay,
4586 true,
4587 WifiPhyState::IDLE,
4588 0,
4589 0,
4590 0, // PSDU from STA 1 is not received (no TRIGVECTOR)
4591 0,
4592 0,
4593 0, // PSDU from STA 2 is not received (no TRIGVECTOR)
4594 true,
4595 Seconds(0),
4596 WifiPhyState::CCA_BUSY,
4598 delay += Seconds(1);
4599
4600 //---------------------------------------------------------------------------
4601 // Verify that HE TB PPDUs with UL Length differing from TRIGVECTOR are discarded
4602 Simulator::Schedule(delay,
4604 this,
4605 "Dropping of HE TB PPDUs with UL Length differing from TRIGVECTOR");
4606 ScheduleTest(delay,
4607 true,
4608 WifiPhyState::IDLE,
4609 0,
4610 0,
4611 0, // PSDU from STA 1 is not received (no TRIGVECTOR)
4612 0,
4613 0,
4614 0, // PSDU from STA 2 is not received (no TRIGVECTOR)
4615 true,
4616 Seconds(0),
4617 WifiPhyState::CCA_BUSY,
4618 UL_LENGTH);
4619 delay += Seconds(1);
4620
4621 //---------------------------------------------------------------------------
4622 // Verify that HE TB PPDUs with AIDs differing from TRIGVECTOR are discarded
4623 Simulator::Schedule(delay,
4625 this,
4626 "Dropping of HE TB PPDUs with AIDs differing from TRIGVECTOR");
4627 ScheduleTest(delay,
4628 true,
4629 WifiPhyState::IDLE,
4630 0,
4631 0,
4632 0, // PSDU from STA 1 is not received (no TRIGVECTOR)
4633 0,
4634 0,
4635 0, // PSDU from STA 2 is not received (no TRIGVECTOR)
4636 true,
4637 Seconds(0),
4638 WifiPhyState::CCA_BUSY,
4639 AID);
4640 delay += Seconds(1);
4641
4642 //---------------------------------------------------------------------------
4643 // Generate an interference on RU 1 and verify that only STA 1's solicited HE TB PPDU has been
4644 // impacted
4646 delay,
4648 this,
4649 "Reception of solicited HE TB PPDUs with interference on RU 1 during PSDU reception");
4650 // A strong non-wifi interference is generated on RU 1 during PSDU reception
4651 BandInfo bandInfo;
4652 bandInfo.fc = MHzToHz(m_frequency - (m_channelWidth / 4));
4653 bandInfo.fl = bandInfo.fc - MHzToHz(m_channelWidth / 4);
4654 bandInfo.fh = bandInfo.fc + MHzToHz(m_channelWidth / 4);
4655 Bands bands;
4656 bands.push_back(bandInfo);
4657
4658 Ptr<SpectrumModel> SpectrumInterferenceRu1 = Create<SpectrumModel>(bands);
4659 Ptr<SpectrumValue> interferencePsdRu1 = Create<SpectrumValue>(SpectrumInterferenceRu1);
4660 Watt_u interferencePower{0.1};
4661 *interferencePsdRu1 = interferencePower / (MHzToHz(m_channelWidth / 2) * 20);
4662
4665 this,
4666 interferencePsdRu1,
4667 MilliSeconds(100));
4668 ScheduleTest(
4669 delay,
4670 true,
4671 WifiPhyState::CCA_BUSY, // PHY should move to CCA_BUSY instead of IDLE due to the
4672 // interference
4673 0,
4674 1,
4675 0, // Reception of the PSDU from STA 1 should have failed (since interference occupies RU 1)
4676 1,
4677 0,
4678 1001); // One PSDU of 1001 bytes should have been successfully received from STA 2
4679 delay += Seconds(1);
4680
4681 //---------------------------------------------------------------------------
4682 // Generate an interference on RU 2 and verify that only STA 2's solicited HE TB PPDU has been
4683 // impacted
4685 delay,
4687 this,
4688 "Reception of solicited HE TB PPDUs with interference on RU 2 during PSDU reception");
4689 // A strong non-wifi interference is generated on RU 2 during PSDU reception
4690 bandInfo.fc = MHzToHz(m_frequency + (m_channelWidth / 4));
4691 bandInfo.fl = bandInfo.fc - MHzToHz(m_channelWidth / 4);
4692 bandInfo.fh = bandInfo.fc + MHzToHz(m_channelWidth / 4);
4693 bands.clear();
4694 bands.push_back(bandInfo);
4695
4696 Ptr<SpectrumModel> SpectrumInterferenceRu2 = Create<SpectrumModel>(bands);
4697 Ptr<SpectrumValue> interferencePsdRu2 = Create<SpectrumValue>(SpectrumInterferenceRu2);
4698 *interferencePsdRu2 = interferencePower / (MHzToHz(m_channelWidth / 2) * 20);
4699
4702 this,
4703 interferencePsdRu2,
4704 MilliSeconds(100));
4705 ScheduleTest(delay,
4706 true,
4707 (m_channelWidth >= MHz_u{40})
4708 ? WifiPhyState::IDLE
4709 : WifiPhyState::CCA_BUSY, // PHY should move to CCA_BUSY if interference is
4710 // generated in its primary channel
4711 1,
4712 0,
4713 1000, // One PSDU of 1000 bytes should have been successfully received from STA 1
4714 0,
4715 1,
4716 0); // Reception of the PSDU from STA 2 should have failed (since interference
4717 // occupies RU 2)
4718 delay += Seconds(1);
4719
4720 //---------------------------------------------------------------------------
4721 // Generate an interference on the full band and verify that both solicited HE TB PPDUs have
4722 // been impacted
4723 Simulator::Schedule(delay,
4725 this,
4726 "Reception of solicited HE TB PPDUs with interference on the full band "
4727 "during PSDU reception");
4728 // A strong non-wifi interference is generated on the full band during PSDU reception
4729 bandInfo.fc = MHzToHz(m_frequency);
4730 bandInfo.fl = bandInfo.fc - MHzToHz(m_channelWidth / 2);
4731 bandInfo.fh = bandInfo.fc + MHzToHz(m_channelWidth / 2);
4732 bands.clear();
4733 bands.push_back(bandInfo);
4734
4735 Ptr<SpectrumModel> SpectrumInterferenceAll = Create<SpectrumModel>(bands);
4736 Ptr<SpectrumValue> interferencePsdAll = Create<SpectrumValue>(SpectrumInterferenceAll);
4737 *interferencePsdAll = interferencePower / (MHzToHz(m_channelWidth) * 20);
4738
4741 this,
4742 interferencePsdAll,
4743 MilliSeconds(100));
4744 ScheduleTest(
4745 delay,
4746 true,
4747 WifiPhyState::CCA_BUSY, // PHY should move to CCA_BUSY instead of IDLE due to the
4748 // interference
4749 0,
4750 1,
4751 0, // Reception of the PSDU from STA 1 should have failed (since interference occupies RU 1)
4752 0,
4753 1,
4754 0); // Reception of the PSDU from STA 2 should have failed (since interference occupies RU
4755 // 2)
4756 delay += Seconds(1);
4757
4758 //---------------------------------------------------------------------------
4759 // Send another HE TB PPDU (of another UL MU transmission) on RU 1 and verify that both
4760 // solicited HE TB PPDUs have been impacted if they are on the same
4761 // 20 MHz channel. Only STA 1's solicited HE TB PPDU is impacted otherwise.
4762 Simulator::Schedule(delay,
4764 this,
4765 "Reception of solicited HE TB PPDUs with another HE TB PPDU arriving on RU "
4766 "1 during PSDU reception");
4767 // Another HE TB PPDU arrives at AP on the same RU as STA 1 during PSDU reception
4770 this,
4771 3,
4772 1,
4773 1002,
4774 1,
4775 0,
4776 false);
4777 // Expected figures from STA 2
4778 uint32_t succ;
4779 uint32_t fail;
4780 uint32_t bytes;
4781 if (m_channelWidth > MHz_u{20})
4782 {
4783 // One PSDU of 1001 bytes should have been successfully received from STA 2 (since
4784 // interference from STA 3 on distinct 20 MHz channel)
4785 succ = 1;
4786 fail = 0;
4787 bytes = 1001;
4788 }
4789 else
4790 {
4791 // Reception of the PSDU from STA 2 should have failed (since interference from STA 3 on
4792 // same 20 MHz channel)
4793 succ = 0;
4794 fail = 1;
4795 bytes = 0;
4796 }
4797 ScheduleTest(delay,
4798 true,
4799 WifiPhyState::CCA_BUSY, // PHY should move to CCA_BUSY instead of IDLE due to the
4800 // interference on measurement channel width
4801 0,
4802 1,
4803 0, // Reception of the PSDU from STA 1 should have failed (since interference from
4804 // STA 3 on same 20 MHz channel)
4805 succ,
4806 fail,
4807 bytes);
4808 delay += Seconds(1);
4809
4810 //---------------------------------------------------------------------------
4811 // Send another HE TB PPDU (of another UL MU transmission) on RU 2 and verify that both
4812 // solicited HE TB PPDUs have been impacted if they are on the same
4813 // 20 MHz channel. Only STA 2's solicited HE TB PPDU is impacted otherwise.
4814 Simulator::Schedule(delay,
4816 this,
4817 "Reception of solicited HE TB PPDUs with another HE TB PPDU arriving on RU "
4818 "2 during PSDU reception");
4819 // Another HE TB PPDU arrives at AP on the same RU as STA 2 during PSDU reception
4822 this,
4823 3,
4824 2,
4825 1002,
4826 1,
4827 0,
4828 false);
4829 // Expected figures from STA 1
4830 if (m_channelWidth > MHz_u{20})
4831 {
4832 // One PSDU of 1000 bytes should have been successfully received from STA 1 (since
4833 // interference from STA 3 on distinct 20 MHz channel)
4834 succ = 1;
4835 fail = 0;
4836 bytes = 1000;
4837 }
4838 else
4839 {
4840 // Reception of the PSDU from STA 1 should have failed (since interference from STA 3 on
4841 // same 20 MHz channel)
4842 succ = 0;
4843 fail = 1;
4844 bytes = 0;
4845 }
4846 ScheduleTest(delay,
4847 true,
4848 (m_channelWidth >= MHz_u{40})
4849 ? WifiPhyState::IDLE
4850 : WifiPhyState::CCA_BUSY, // PHY should move to CCA_BUSY instead of IDLE if HE
4851 // TB PPDU on primary channel
4852 succ,
4853 fail,
4854 bytes,
4855 0,
4856 1,
4857 0); // Reception of the PSDU from STA 2 should have failed (since interference from
4858 // STA 3 on same 20 MHz channel)
4859 delay += Seconds(1);
4860
4861 //---------------------------------------------------------------------------
4862 // Send an HE SU PPDU during 400 ns window and verify that both solicited HE TB PPDUs have been
4863 // impacted
4865 delay,
4867 this,
4868 "Reception of solicited HE TB PPDUs with an HE SU PPDU arriving during the 400 ns window");
4869 // One HE SU arrives at AP during the 400ns window
4870 Simulator::Schedule(delay + NanoSeconds(300),
4872 this,
4873 3,
4874 1002,
4875 1,
4876 0);
4877 ScheduleTest(
4878 delay,
4879 true,
4880 WifiPhyState::IDLE,
4881 0,
4882 1,
4883 0, // Reception of the PSDU from STA 1 should have failed (since interference from STA 3)
4884 0,
4885 1,
4886 0); // Reception of the PSDU from STA 2 should have failed (since interference from STA 3)
4887 delay += Seconds(1);
4888
4889 //---------------------------------------------------------------------------
4890 // Only send a solicited HE TB PPDU from STA 2 on RU 2 and verify that it has been correctly
4891 // received
4892 Simulator::Schedule(delay,
4894 this,
4895 "Reception of solicited HE TB PPDU only on RU 2");
4896 // Check that STA3 will correctly set its state to CCA_BUSY if in measurement channel or IDLE
4897 // otherwise
4898 Simulator::Schedule(delay + m_expectedPpduDuration - NanoSeconds(1),
4900 this,
4901 m_phySta3,
4902 (m_channelWidth >= MHz_u{40})
4903 ? WifiPhyState::IDLE
4904 : WifiPhyState::CCA_BUSY); // PHY should move to CCA_BUSY instead of
4905 // IDLE if HE TB PPDU on primary channel
4906 ScheduleTest(delay,
4907 true,
4908 WifiPhyState::IDLE,
4909 0,
4910 0,
4911 0, // No transmission scheduled for STA 1
4912 1,
4913 0,
4914 1001, // One PSDU of 1001 bytes should have been successfully received from STA 2
4915 false,
4916 Seconds(0),
4917 WifiPhyState::RX); // Measurement channel is total channel width
4918 delay += Seconds(1);
4919
4920 //---------------------------------------------------------------------------
4921 // Measure the power of a solicited HE TB PPDU from STA 2 on RU 2
4922 Simulator::Schedule(delay,
4924 this,
4925 "Measure power for reception of HE TB PPDU only on RU 2");
4926 auto rxPower = DbmToW(
4927 dBm_u{19}); // 16+1 dBm at STAs and +2 at AP (no loss since all devices are colocated)
4928 SchedulePowerMeasurementChecks(delay,
4929 (m_channelWidth >= MHz_u{40}) ? Watt_u{0.0} : rxPower,
4930 rxPower, // power detected on RU1 only if same 20 MHz as RU 2
4931 Watt_u{0.0},
4932 rxPower);
4933 ScheduleTest(delay,
4934 true,
4935 WifiPhyState::IDLE,
4936 0,
4937 0,
4938 0, // No transmission scheduled for STA 1
4939 1,
4940 0,
4941 1001, // One PSDU of 1001 bytes should have been successfully received from STA 2
4942 false,
4943 Seconds(0),
4944 WifiPhyState::RX); // Measurement channel is total channel width
4945 delay += Seconds(1);
4946
4947 //---------------------------------------------------------------------------
4948 // Measure the power of a solicited HE TB PPDU from STA 2 on RU 2 with power spectrum density
4949 // limitation enforced
4951 delay,
4953 this,
4954 "Measure power for reception of HE TB PPDU only on RU 2 with PSD limitation");
4955 // Configure PSD limitation at 3 dBm/MHz -> 3+13.0103=16.0103 dBm max for 20 MHz,
4956 // 3+9.0309=12.0309 dBm max for 106-tone RU, no impact for 40 MHz and above
4957 Simulator::Schedule(delay - NanoSeconds(1), // just before sending HE TB
4959 this,
4960 m_phySta2,
4961 dBm_per_MHz_u{3});
4962
4963 rxPower = (m_channelWidth > MHz_u{40})
4964 ? DbmToW(dBm_u{19})
4965 : DbmToW(dBm_u{18.0103}); // 15.0103+1 dBm at STA 2 and +2 at AP for non-OFDMA
4966 // transmitted only on one 20 MHz channel
4967 auto rxPowerOfdma = rxPower;
4968 if (m_channelWidth <= MHz_u{40})
4969 {
4970 rxPowerOfdma =
4971 (m_channelWidth == MHz_u{20})
4972 ? DbmToW(dBm_u{14.0309}) // 11.0309+1 dBm at STA and +2 at AP if 106-tone RU
4973 : DbmToW(dBm_u{18.0103}); // 15.0103+1 dBm at STA 2 and +2 at AP if 242-tone RU
4974 }
4975 SchedulePowerMeasurementChecks(delay,
4976 (m_channelWidth >= MHz_u{40}) ? Watt_u{0.0} : rxPower,
4977 rxPower, // power detected on RU1 only if same 20 MHz as RU 2
4978 Watt_u{0.0},
4979 rxPowerOfdma);
4980
4981 // Reset PSD limitation once HE TB has been sent
4982 Simulator::Schedule(delay + m_expectedPpduDuration,
4984 this,
4985 m_phySta2,
4986 dBm_per_MHz_u{100});
4987 ScheduleTest(delay,
4988 true,
4989 WifiPhyState::IDLE,
4990 0,
4991 0,
4992 0, // No transmission scheduled for STA 1
4993 1,
4994 0,
4995 1001, // One PSDU of 1001 bytes should have been successfully received from STA 2
4996 false,
4997 Seconds(0),
4998 WifiPhyState::RX); // Measurement channel is total channel width
4999 delay += Seconds(1);
5000
5001 //---------------------------------------------------------------------------
5002 // Measure the power of 2 solicited HE TB PPDU from both STAs
5003 Simulator::Schedule(delay,
5005 this,
5006 "Measure power for reception of HE TB PPDU on both RUs");
5007 rxPower = DbmToW(
5008 dBm_u{19}); // 16+1 dBm at STAs and +2 at AP (no loss since all devices are colocated)
5009 const auto rxPowerNonOfdma =
5010 (m_channelWidth >= MHz_u{40})
5011 ? rxPower
5012 : rxPower * 2; // both STAs transmit over the same 20 MHz channel
5013 SchedulePowerMeasurementChecks(delay, rxPowerNonOfdma, rxPowerNonOfdma, rxPower, rxPower);
5014 ScheduleTest(delay,
5015 true,
5016 WifiPhyState::IDLE,
5017 1,
5018 0,
5019 1000, // One PSDU of 1000 bytes should have been successfully received from STA 1
5020 1,
5021 0,
5022 1001); // One PSDU of 1001 bytes should have been successfully received from STA 2
5023 delay += Seconds(1);
5024
5025 //---------------------------------------------------------------------------
5026 // Verify that an HE TB PPDU from another BSS has been correctly received (no UL MU transmission
5027 // ongoing)
5028 Simulator::Schedule(delay,
5030 this,
5031 "Reception of an HE TB PPDU from another BSS");
5032 // One HE TB from another BSS (BSS color 2) arrives at AP (BSS color 1)
5033 Simulator::Schedule(delay,
5035 this,
5036 m_phyAp,
5037 1);
5038 Simulator::Schedule(delay + MilliSeconds(100),
5040 this,
5041 3,
5042 1,
5043 1002,
5044 1,
5045 2,
5046 false);
5047
5048 // Verify events data have been cleared
5049 Simulator::Schedule(delay + MilliSeconds(200),
5051 this);
5052
5053 Simulator::Schedule(delay + MilliSeconds(500),
5055 this);
5056 delay += Seconds(1);
5057
5058 //---------------------------------------------------------------------------
5059 // Verify that two solicited HE TB PPDUs with delay (< 400ns) between the two signals have been
5060 // corrected received
5062 delay,
5064 this,
5065 "Reception of solicited HE TB PPDUs with delay (< 400ns) between the two signals and "
5066 "reception of an HE TB PPDU from another BSS between the ends of the two HE TB PPDUs");
5067 Simulator::Schedule(delay,
5069 this,
5070 m_phyAp,
5071 1);
5072 Simulator::Schedule(delay + m_expectedPpduDuration + NanoSeconds(100),
5074 this,
5075 3,
5076 1,
5077 1002,
5078 1,
5079 2,
5080 true);
5081 ScheduleTest(delay,
5082 true,
5083 WifiPhyState::CCA_BUSY,
5084 1,
5085 0,
5086 1000, // One PSDU of 1000 bytes should have been successfully received from STA 1
5087 1,
5088 0,
5089 1001, // One PSDU of 1001 bytes should have been successfully received from STA 2
5090 true,
5091 NanoSeconds(200));
5092 delay += Seconds(1);
5093
5095}
5096
5097template <typename LatestPhyEntityType>
5098void
5100{
5101 m_frequency = MHz_u{5955};
5102 m_channelWidth = MHz_u{20};
5103 m_expectedPpduDuration = NanoSeconds(292800);
5104 RunOne();
5105
5106 m_frequency = MHz_u{5965};
5107 m_channelWidth = MHz_u{40};
5108 m_expectedPpduDuration = NanoSeconds(163200);
5109 RunOne();
5110
5111 m_frequency = MHz_u{5985};
5112 m_channelWidth = MHz_u{80};
5113 m_expectedPpduDuration = NanoSeconds(105600);
5114 RunOne();
5115
5116 m_frequency = MHz_u{6025};
5117 m_channelWidth = MHz_u{160};
5118 m_expectedPpduDuration = NanoSeconds(76800);
5119 RunOne();
5120
5121 if (m_modClass >= WIFI_MOD_CLASS_EHT)
5122 {
5123 m_frequency = MHz_u{6105};
5124 m_channelWidth = MHz_u{320};
5125 m_expectedPpduDuration = NanoSeconds(62400);
5126 RunOne();
5127 }
5128
5130}
5131
5132/**
5133 * @ingroup wifi-test
5134 * @ingroup tests
5135 *
5136 * @brief PHY padding exclusion test
5137 */
5139{
5140 public:
5142 ~TestPhyPaddingExclusion() override;
5143
5144 private:
5145 void DoSetup() override;
5146 void DoTeardown() override;
5147 void DoRun() override;
5148
5149 /**
5150 * Send HE TB PPDU function
5151 * @param txStaId the ID of the TX STA
5152 * @param index the RU index used for the transmission
5153 * @param payloadSize the size of the payload in bytes
5154 * @param txDuration the duration of the PPDU
5155 */
5156 void SendTbPpdu(uint16_t txStaId, std::size_t index, std::size_t payloadSize, Time txDuration);
5157 /**
5158 * Set TRIGVECTOR for HE TB PPDU
5159 *
5160 * @param ppduDuration the duration of the HE TB PPDU
5161 */
5162 void SetTrigVector(Time ppduDuration);
5163
5164 /**
5165 * Generate interference function
5166 * @param interferencePsd the PSD of the interference to be generated
5167 * @param duration the duration of the interference
5168 */
5169 void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
5170 /**
5171 * Stop interference function
5172 */
5173 void StopInterference();
5174
5175 /**
5176 * Run one function
5177 */
5178 void RunOne();
5179
5180 /**
5181 * Check the received PSDUs from STA1
5182 * @param expectedSuccess the expected number of success
5183 * @param expectedFailures the expected number of failures
5184 * @param expectedBytes the expected number of bytes
5185 */
5186 void CheckRxFromSta1(uint32_t expectedSuccess,
5187 uint32_t expectedFailures,
5188 uint32_t expectedBytes);
5189
5190 /**
5191 * Check the received PSDUs from STA2
5192 * @param expectedSuccess the expected number of success
5193 * @param expectedFailures the expected number of failures
5194 * @param expectedBytes the expected number of bytes
5195 */
5196 void CheckRxFromSta2(uint32_t expectedSuccess,
5197 uint32_t expectedFailures,
5198 uint32_t expectedBytes);
5199
5200 /**
5201 * Verify all events are cleared at end of TX or RX
5202 */
5203 void VerifyEventsCleared();
5204
5205 /**
5206 * Check the PHY state
5207 * @param phy the PHY
5208 * @param expectedState the expected state of the PHY
5209 */
5211 /// @copydoc CheckPhyState
5213
5214 /**
5215 * Reset function
5216 */
5217 void Reset();
5218
5219 /**
5220 * Receive success function
5221 * @param psdu the PSDU
5222 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
5223 * @param txVector the transmit vector
5224 * @param statusPerMpdu reception status per MPDU
5225 */
5227 RxSignalInfo rxSignalInfo,
5228 const WifiTxVector& txVector,
5229 const std::vector<bool>& statusPerMpdu);
5230
5231 /**
5232 * Receive failure function
5233 * @param psdu the PSDU
5234 */
5235 void RxFailure(Ptr<const WifiPsdu> psdu);
5236
5240
5242
5243 uint32_t m_countRxSuccessFromSta1; ///< count RX success from STA 1
5244 uint32_t m_countRxSuccessFromSta2; ///< count RX success from STA 2
5245 uint32_t m_countRxFailureFromSta1; ///< count RX failure from STA 1
5246 uint32_t m_countRxFailureFromSta2; ///< count RX failure from STA 2
5247 uint32_t m_countRxBytesFromSta1; ///< count RX bytes from STA 1
5248 uint32_t m_countRxBytesFromSta2; ///< count RX bytes from STA 2
5249};
5250
5252 : TestCase("PHY padding exclusion test"),
5253 m_countRxSuccessFromSta1(0),
5254 m_countRxSuccessFromSta2(0),
5255 m_countRxFailureFromSta1(0),
5256 m_countRxFailureFromSta2(0),
5257 m_countRxBytesFromSta1(0),
5258 m_countRxBytesFromSta2(0)
5259{
5260}
5261
5262void
5264 std::size_t index,
5265 std::size_t payloadSize,
5266 Time txDuration)
5267{
5268 WifiConstPsduMap psdus;
5269
5270 WifiTxVector txVector{HePhy::GetHeMcs7(),
5271 0,
5273 NanoSeconds(1600),
5274 1,
5275 1,
5276 0,
5278 false,
5279 false,
5280 true};
5281
5282 HeRu::RuSpec ru(RuType::RU_106_TONE, index, false);
5283 txVector.SetRu(ru, txStaId);
5284 txVector.SetMode(HePhy::GetHeMcs7(), txStaId);
5285 txVector.SetNss(1, txStaId);
5286
5287 auto pkt = Create<Packet>(payloadSize);
5288 WifiMacHeader hdr;
5290 hdr.SetQosTid(0);
5291 hdr.SetAddr1(Mac48Address("00:00:00:00:00:00"));
5292 std::ostringstream addr;
5293 addr << "00:00:00:00:00:0" << txStaId;
5294 hdr.SetAddr2(Mac48Address(addr.str().c_str()));
5295 hdr.SetSequenceNumber(1);
5296 auto psdu = Create<WifiPsdu>(pkt, hdr);
5297 psdus.insert(std::make_pair(txStaId, psdu));
5298
5300 if (txStaId == 1)
5301 {
5302 phy = m_phySta1;
5303 }
5304 else if (txStaId == 2)
5305 {
5306 phy = m_phySta2;
5307 }
5308
5309 txVector.SetLength(
5310 HePhy::ConvertHeTbPpduDurationToLSigLength(txDuration, txVector, phy->GetPhyBand()).first);
5311
5312 phy->SetPpduUid(0);
5313 phy->Send(psdus, txVector);
5314}
5315
5316void
5318{
5319 m_phyInterferer->SetTxPowerSpectralDensity(interferencePsd);
5320 m_phyInterferer->SetPeriod(duration);
5321 m_phyInterferer->Start();
5323}
5324
5325void
5330
5334
5335void
5337 RxSignalInfo rxSignalInfo,
5338 const WifiTxVector& txVector,
5339 const std::vector<bool>& /*statusPerMpdu*/)
5340{
5341 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2() << rxSignalInfo << txVector);
5342 if (psdu->GetAddr2() == Mac48Address("00:00:00:00:00:01"))
5343 {
5345 m_countRxBytesFromSta1 += (psdu->GetSize() - 30);
5346 }
5347 else if (psdu->GetAddr2() == Mac48Address("00:00:00:00:00:02"))
5348 {
5350 m_countRxBytesFromSta2 += (psdu->GetSize() - 30);
5351 }
5352}
5353
5354void
5356{
5357 NS_LOG_FUNCTION(this << *psdu << psdu->GetAddr2());
5358 if (psdu->GetAddr2() == Mac48Address("00:00:00:00:00:01"))
5359 {
5361 }
5362 else if (psdu->GetAddr2() == Mac48Address("00:00:00:00:00:02"))
5363 {
5365 }
5366}
5367
5368void
5370 uint32_t expectedFailures,
5371 uint32_t expectedBytes)
5372{
5374 expectedSuccess,
5375 "The number of successfully received packets from STA 1 is not correct!");
5378 expectedFailures,
5379 "The number of unsuccessfully received packets from STA 1 is not correct!");
5381 expectedBytes,
5382 "The number of bytes received from STA 1 is not correct!");
5383}
5384
5385void
5387 uint32_t expectedFailures,
5388 uint32_t expectedBytes)
5389{
5391 expectedSuccess,
5392 "The number of successfully received packets from STA 2 is not correct!");
5395 expectedFailures,
5396 "The number of unsuccessfully received packets from STA 2 is not correct!");
5398 expectedBytes,
5399 "The number of bytes received from STA 2 is not correct!");
5400}
5401
5402void
5404{
5405 NS_TEST_ASSERT_MSG_EQ(m_phyAp->GetCurrentEvent(),
5406 nullptr,
5407 "m_currentEvent for AP was not cleared");
5408 NS_TEST_ASSERT_MSG_EQ(m_phySta1->GetCurrentEvent(),
5409 nullptr,
5410 "m_currentEvent for STA 1 was not cleared");
5411 NS_TEST_ASSERT_MSG_EQ(m_phySta2->GetCurrentEvent(),
5412 nullptr,
5413 "m_currentEvent for STA 2 was not cleared");
5414}
5415
5416void
5418 WifiPhyState expectedState)
5419{
5420 // This is needed to make sure PHY state will be checked as the last event if a state change
5421 // occurred at the exact same time as the check
5423}
5424
5425void
5427 WifiPhyState expectedState)
5428{
5429 WifiPhyState currentState = phy->GetState()->GetState();
5430 NS_LOG_FUNCTION(this << currentState);
5431 NS_TEST_ASSERT_MSG_EQ(currentState,
5432 expectedState,
5433 "PHY State " << currentState << " does not match expected state "
5434 << expectedState << " at " << Simulator::Now());
5435}
5436
5437void
5439{
5446 m_phySta1->SetPpduUid(0);
5447 m_phySta1->SetTriggerFrameUid(0);
5448 m_phySta2->SetTriggerFrameUid(0);
5449}
5450
5451void
5453{
5456 int64_t streamNumber = 0;
5457
5460 lossModel->SetFrequency(MHzToHz(DEFAULT_FREQUENCY));
5461 spectrumChannel->AddPropagationLossModel(lossModel);
5464 spectrumChannel->SetPropagationDelayModel(delayModel);
5465
5466 Ptr<Node> apNode = CreateObject<Node>();
5469 "Txop",
5470 PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
5471 apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
5472 apDev->SetMac(apMac);
5475 apDev->SetHeConfiguration(heConfiguration);
5477 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
5479 m_phyAp->SetErrorRateModel(apErrorModel);
5480 m_phyAp->SetDevice(apDev);
5481 m_phyAp->AddChannel(spectrumChannel);
5482 m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
5483 m_phyAp->AssignStreams(streamNumber);
5484 auto channelNum = WifiPhyOperatingChannel::FindFirst(0,
5489 ->number;
5490
5491 m_phyAp->SetOperatingChannel(
5493 m_phyAp->SetReceiveOkCallback(MakeCallback(&TestPhyPaddingExclusion::RxSuccess, this));
5494 m_phyAp->SetReceiveErrorCallback(MakeCallback(&TestPhyPaddingExclusion::RxFailure, this));
5496 m_phyAp->SetMobility(apMobility);
5497 apDev->SetPhy(m_phyAp);
5498 apDev->SetStandard(WIFI_STANDARD_80211ax);
5499 apDev->SetHeConfiguration(CreateObject<HeConfiguration>());
5500 apMac->SetWifiPhys({m_phyAp});
5501 apNode->AggregateObject(apMobility);
5502 apNode->AddDevice(apDev);
5503
5504 Ptr<Node> sta1Node = CreateObject<Node>();
5508 m_phySta1->SetInterferenceHelper(sta1InterferenceHelper);
5510 m_phySta1->SetErrorRateModel(sta1ErrorModel);
5511 m_phySta1->SetDevice(sta1Dev);
5512 m_phySta1->AddChannel(spectrumChannel);
5513 m_phySta1->ConfigureStandard(WIFI_STANDARD_80211ax);
5514 m_phySta1->AssignStreams(streamNumber);
5515 m_phySta1->SetOperatingChannel(
5518 m_phySta1->SetMobility(sta1Mobility);
5519 sta1Dev->SetPhy(m_phySta1);
5520 sta1Dev->SetStandard(WIFI_STANDARD_80211ax);
5521 sta1Dev->SetHeConfiguration(CreateObject<HeConfiguration>());
5522 sta1Node->AggregateObject(sta1Mobility);
5523 sta1Node->AddDevice(sta1Dev);
5524
5525 Ptr<Node> sta2Node = CreateObject<Node>();
5529 m_phySta2->SetInterferenceHelper(sta2InterferenceHelper);
5531 m_phySta2->SetErrorRateModel(sta2ErrorModel);
5532 m_phySta2->SetDevice(sta2Dev);
5533 m_phySta2->AddChannel(spectrumChannel);
5534 m_phySta2->ConfigureStandard(WIFI_STANDARD_80211ax);
5535 m_phySta2->AssignStreams(streamNumber);
5536 m_phySta2->SetOperatingChannel(
5539 m_phySta2->SetMobility(sta2Mobility);
5540 sta2Dev->SetPhy(m_phySta2);
5541 sta2Dev->SetStandard(WIFI_STANDARD_80211ax);
5542 sta2Dev->SetHeConfiguration(CreateObject<HeConfiguration>());
5543 sta2Node->AggregateObject(sta2Mobility);
5544 sta2Node->AddDevice(sta2Dev);
5545
5546 Ptr<Node> interfererNode = CreateObject<Node>();
5549 m_phyInterferer->SetDevice(interfererDev);
5550 m_phyInterferer->SetChannel(spectrumChannel);
5551 m_phyInterferer->SetDutyCycle(1);
5552 interfererNode->AddDevice(interfererDev);
5553}
5554
5555void
5557{
5558 m_phyAp->Dispose();
5559 m_phyAp = nullptr;
5560 m_phySta1->Dispose();
5561 m_phySta1 = nullptr;
5562 m_phySta2->Dispose();
5563 m_phySta2 = nullptr;
5564 m_phyInterferer->Dispose();
5565 m_phyInterferer = nullptr;
5566}
5567
5568void
5570{
5571 WifiTxVector trigVector{HePhy::GetHeMcs7(),
5572 0,
5574 NanoSeconds(1600),
5575 1,
5576 1,
5577 0,
5579 false,
5580 false,
5581 true};
5582 trigVector.SetRu(HeRu::RuSpec(RuType::RU_106_TONE, 1, false), 1);
5583 trigVector.SetMode(HePhy::GetHeMcs7(), 1);
5584 trigVector.SetNss(1, 1);
5585 trigVector.SetRu(HeRu::RuSpec(RuType::RU_106_TONE, 2, false), 2);
5586 trigVector.SetMode(HePhy::GetHeMcs7(), 2);
5587 trigVector.SetNss(1, 2);
5588 uint16_t length;
5589 std::tie(length, ppduDuration) =
5590 HePhy::ConvertHeTbPpduDurationToLSigLength(ppduDuration, trigVector, m_phyAp->GetPhyBand());
5591 trigVector.SetLength(length);
5592 auto hePhyAp = DynamicCast<HePhy>(m_phyAp->GetLatestPhyEntity());
5593 hePhyAp->SetTrigVector(trigVector, ppduDuration);
5594}
5595
5596void
5598{
5599 Time expectedPpduDuration = NanoSeconds(292800);
5600 Time ppduWithPaddingDuration =
5601 expectedPpduDuration + 10 * NanoSeconds(12800 + 1600 /* GI */); // add 10 extra OFDM symbols
5602
5604
5605 // STA1 and STA2 send MU UL PPDUs addressed to AP:
5608 this,
5609 1,
5610 1,
5611 1000,
5612 ppduWithPaddingDuration);
5615 this,
5616 2,
5617 2,
5618 1001,
5619 ppduWithPaddingDuration);
5620
5621 // Set TRIGVECTOR on AP
5624 this,
5625 ppduWithPaddingDuration);
5626
5627 // Verify it takes expectedPpduDuration + padding to transmit the PPDUs
5628 Simulator::Schedule(Seconds(1) + ppduWithPaddingDuration - NanoSeconds(1),
5630 this,
5631 m_phyAp,
5632 WifiPhyState::RX);
5633 Simulator::Schedule(Seconds(1) + ppduWithPaddingDuration,
5635 this,
5636 m_phyAp,
5637 WifiPhyState::IDLE);
5638
5639 // One PSDU of 1000 bytes should have been successfully received from STA 1
5641 // One PSDU of 1001 bytes should have been successfully received from STA 2
5643 // Verify events data have been cleared
5645
5647
5648 // STA1 and STA2 send MU UL PPDUs addressed to AP:
5651 this,
5652 1,
5653 1,
5654 1000,
5655 ppduWithPaddingDuration);
5658 this,
5659 2,
5660 2,
5661 1001,
5662 ppduWithPaddingDuration);
5663
5664 // Set TRIGVECTOR on AP
5667 this,
5668 ppduWithPaddingDuration);
5669
5670 // A strong non-wifi interference is generated on RU 1 during padding reception
5671 BandInfo bandInfo;
5673 bandInfo.fl = bandInfo.fc - MHzToHz(DEFAULT_CHANNEL_WIDTH / 4);
5674 bandInfo.fh = bandInfo.fc + MHzToHz(DEFAULT_CHANNEL_WIDTH / 4);
5675 Bands bands;
5676 bands.push_back(bandInfo);
5677
5678 Ptr<SpectrumModel> SpectrumInterferenceRu1 = Create<SpectrumModel>(bands);
5679 Ptr<SpectrumValue> interferencePsdRu1 = Create<SpectrumValue>(SpectrumInterferenceRu1);
5680 Watt_u interferencePower{0.1};
5681 *interferencePsdRu1 = interferencePower / (MHzToHz(DEFAULT_CHANNEL_WIDTH / 2) * 20);
5682
5683 Simulator::Schedule(Seconds(2) + MicroSeconds(50) + expectedPpduDuration,
5685 this,
5686 interferencePsdRu1,
5687 MilliSeconds(100));
5688
5689 // Verify it takes expectedPpduDuration + padding to transmit the PPDUs (PHY should move to
5690 // CCA_BUSY instead of IDLE due to the interference)
5691 Simulator::Schedule(Seconds(2) + ppduWithPaddingDuration - NanoSeconds(1),
5693 this,
5694 m_phyAp,
5695 WifiPhyState::RX);
5696 Simulator::Schedule(Seconds(2) + ppduWithPaddingDuration,
5698 this,
5699 m_phyAp,
5700 WifiPhyState::CCA_BUSY);
5701
5702 // One PSDU of 1000 bytes should have been successfully received from STA 1 (since interference
5703 // occupies RU 1 after payload, during PHY padding)
5705 // One PSDU of 1001 bytes should have been successfully received from STA 2
5707 // Verify events data have been cleared
5709
5711
5713
5715}
5716
5717/**
5718 * @ingroup wifi-test
5719 * @ingroup tests
5720 *
5721 * @brief UL-OFDMA power control test
5722 */
5724{
5725 public:
5727 ~TestUlOfdmaPowerControl() override;
5728
5729 private:
5730 void DoSetup() override;
5731 void DoTeardown() override;
5732 void DoRun() override;
5733
5734 /**
5735 * Send a MU BAR through the AP to the STAs listed in the provided vector.
5736 *
5737 * @param staIds the vector of STA-IDs of STAs to address the MU-BAR to
5738 */
5739 void SendMuBar(std::vector<uint16_t> staIds);
5740
5741 /**
5742 * Send a QoS Data packet to the destination station in order
5743 * to set up a block Ack session (so that the MU-BAR may have a reply).
5744 *
5745 * @param destination the address of the destination station
5746 */
5747 void SetupBa(Address destination);
5748
5749 /**
5750 * Run one simulation with an optional BA session set up phase.
5751 *
5752 * @param setupBa true if BA session should be set up (i.e. upon first run),
5753 * false otherwise
5754 */
5755 void RunOne(bool setupBa);
5756
5757 /**
5758 * Replace the AP's callback on its PHY's ReceiveOkCallback
5759 * by the ReceiveOkCallbackAtAp method.
5760 */
5762
5763 /**
5764 * Receive OK callback function at AP.
5765 * This method will be plugged into the AP PHY's ReceiveOkCallback once the
5766 * block Ack session has been set up. This is done in the Reset function.
5767 * @param psdu the PSDU
5768 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
5769 * @param txVector the TXVECTOR used for the packet
5770 * @param statusPerMpdu reception status per MPDU
5771 */
5773 RxSignalInfo rxSignalInfo,
5774 const WifiTxVector& txVector,
5775 const std::vector<bool>& statusPerMpdu);
5776
5777 uint8_t m_bssColor; ///< BSS color
5778
5779 Ptr<WifiNetDevice> m_apDev; ///< network device of AP
5780 Ptr<WifiNetDevice> m_sta1Dev; ///< network device of STA 1
5781 Ptr<WifiNetDevice> m_sta2Dev; ///< network device of STA 2
5782
5784
5785 dBm_u m_txPowerAp; ///< transmit power of AP
5786 dBm_u m_txPowerStart; ///< minimum transmission power for STAs
5787 dBm_u m_txPowerEnd; ///< maximum transmission power for STAs
5788 uint8_t m_txPowerLevels; ///< number of transmission power levels for STAs
5789
5790 dBm_u m_requestedRssiSta1; ///< requested RSSI from STA 1 at AP for HE TB PPDUs
5791 dBm_u m_requestedRssiSta2; ///< requested RSSI from STA 2 at AP for HE TB PPDUs
5792
5793 dBm_u m_rssiSta1; ///< expected RSSI from STA 1 at AP for HE TB PPDUs
5794 dBm_u m_rssiSta2; ///< expected RSSI from STA 2 at AP for HE TB PPDUs
5795
5796 dB_u m_tol; ///< tolerance between received and expected RSSIs
5797};
5798
5800 : TestCase("UL-OFDMA power control test"),
5801 m_bssColor(1),
5802 m_txPowerAp(dBm_u{0}),
5803 m_txPowerStart(dBm_u{0}),
5804 m_txPowerEnd(dBm_u{0}),
5805 m_txPowerLevels(0),
5806 m_requestedRssiSta1(dBm_u{0}),
5807 m_requestedRssiSta2(dBm_u{0}),
5808 m_rssiSta1(dBm_u{0}),
5809 m_rssiSta2(dBm_u{0}),
5810 m_tol(dB_u{0.1})
5811{
5812}
5813
5815{
5816 m_phyAp = nullptr;
5817 m_apDev = nullptr;
5818 m_sta1Dev = nullptr;
5819 m_sta2Dev = nullptr;
5820}
5821
5822void
5824{
5825 // Only one packet is sufficient to set up BA since AP and STAs are HE capable
5826 Ptr<Packet> pkt = Create<Packet>(100); // 100 dummy bytes of data
5827 m_apDev->Send(pkt, destination, 0);
5828}
5829
5830void
5831TestUlOfdmaPowerControl::SendMuBar(std::vector<uint16_t> staIds)
5832{
5833 NS_ASSERT(!staIds.empty() && staIds.size() <= 2);
5834
5835 // Build MU-BAR trigger frame
5836 CtrlTriggerHeader muBar;
5837 muBar.SetType(TriggerFrameType::MU_BAR_TRIGGER);
5838 muBar.SetMoreTF(true);
5839 muBar.SetCsRequired(true);
5841 muBar.SetGiAndLtfType(NanoSeconds(1600), 2);
5842 muBar.SetApTxPower(static_cast<int8_t>(m_txPowerAp));
5843 muBar.SetUlSpatialReuse(60500);
5844
5845 RuType ru = (staIds.size() == 1) ? RuType::RU_242_TONE : RuType::RU_106_TONE;
5846 std::size_t index = 1;
5847 int8_t ulTargetRssi = -40; // will be overwritten
5848 for (const auto& staId : staIds)
5849 {
5851 ui.SetAid12(staId);
5852 ui.SetRuAllocation(HeRu::RuSpec{ru, index, true});
5853 ui.SetUlFecCodingType(true);
5854 ui.SetUlMcs(7);
5855 ui.SetUlDcm(false);
5856 ui.SetSsAllocation(1, 1);
5857 if (staId == 1)
5858 {
5859 ulTargetRssi = m_requestedRssiSta1;
5860 }
5861 else if (staId == 2)
5862 {
5863 ulTargetRssi = m_requestedRssiSta2;
5864 }
5865 else
5866 {
5867 NS_ABORT_MSG("Unknown STA-ID (" << staId << ")");
5868 }
5869 ui.SetUlTargetRssi(ulTargetRssi);
5870
5873 bar.SetTidInfo(0);
5874 bar.SetStartingSequence(4095);
5876
5877 ++index;
5878 }
5879
5880 WifiTxVector tbTxVector{muBar.GetHeTbTxVector(staIds.front())};
5882 tbTxVector,
5884 .first);
5885
5886 WifiConstPsduMap psdus;
5887 WifiTxVector txVector{HePhy::GetHeMcs7(),
5888 0,
5890 NanoSeconds(800),
5891 1,
5892 1,
5893 0,
5895 false,
5896 false,
5897 false,
5898 m_bssColor};
5899
5900 auto bar = Create<Packet>();
5901 bar->AddHeader(muBar);
5902
5903 auto receiver = Mac48Address::GetBroadcast();
5904 if (staIds.size() == 1)
5905 {
5906 const auto aidSta1 = DynamicCast<StaWifiMac>(m_sta1Dev->GetMac())->GetAssociationId();
5907 if (staIds.front() == aidSta1)
5908 {
5909 receiver = Mac48Address::ConvertFrom(m_sta1Dev->GetAddress());
5910 }
5911 else
5912 {
5913 NS_ASSERT(staIds.front() ==
5914 DynamicCast<StaWifiMac>(m_sta2Dev->GetMac())->GetAssociationId());
5915 receiver = Mac48Address::ConvertFrom(m_sta2Dev->GetAddress());
5916 }
5917 }
5918
5919 WifiMacHeader hdr;
5921 hdr.SetAddr1(receiver);
5922 hdr.SetAddr2(Mac48Address::ConvertFrom(m_apDev->GetAddress()));
5923 hdr.SetAddr3(Mac48Address::ConvertFrom(m_apDev->GetAddress()));
5924 hdr.SetDsNotTo();
5925 hdr.SetDsFrom();
5926 hdr.SetNoRetry();
5927 hdr.SetNoMoreFragments();
5928 auto psdu = Create<WifiPsdu>(bar, hdr);
5929
5930 auto nav = m_apDev->GetPhy()->GetSifs();
5931 const auto staId = staIds.front(); // either will do
5932 nav += SpectrumWifiPhy::CalculateTxDuration(GetBlockAckSize(BlockAckType::COMPRESSED),
5933 tbTxVector,
5935 staId);
5936 psdu->SetDuration(nav);
5937 psdus.insert(std::make_pair(SU_STA_ID, psdu));
5938
5939 m_phyAp->Send(psdus, txVector);
5940}
5941
5942void
5944 RxSignalInfo rxSignalInfo,
5945 const WifiTxVector& txVector,
5946 const std::vector<bool>& /*statusPerMpdu*/)
5947{
5948 NS_TEST_ASSERT_MSG_EQ(txVector.GetPreambleType(), WIFI_PREAMBLE_HE_TB, "HE TB PPDU expected");
5949 const auto rssi = rxSignalInfo.rssi;
5950 NS_ASSERT(psdu->GetNMpdus() == 1);
5951 const auto& hdr = psdu->GetHeader(0);
5952 NS_TEST_ASSERT_MSG_EQ(hdr.GetType(), WIFI_MAC_CTL_BACKRESP, "Block ACK expected");
5953 if (hdr.GetAddr2() == m_sta1Dev->GetAddress())
5954 {
5956 rssi,
5957 m_rssiSta1,
5958 m_tol,
5959 "The obtained RSSI from STA 1 at AP is different from the expected one ("
5960 << rssi << " vs " << m_rssiSta1 << ", with tolerance of " << m_tol << ")");
5961 }
5962 else if (psdu->GetAddr2() == m_sta2Dev->GetAddress())
5963 {
5965 rssi,
5966 m_rssiSta2,
5967 m_tol,
5968 "The obtained RSSI from STA 2 at AP is different from the expected one ("
5969 << rssi << " vs " << m_rssiSta2 << ", with tolerance of " << m_tol << ")");
5970 }
5971 else
5972 {
5973 NS_ABORT_MSG("The receiver address is unknown");
5974 }
5975}
5976
5977void
5979{
5980 // Now that BA session has been established we can plug our method
5981 m_phyAp->SetReceiveOkCallback(
5983}
5984
5985void
5987{
5988 auto apNode = CreateObject<Node>();
5989 NodeContainer staNodes;
5990 staNodes.Create(2);
5991
5992 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
5994 spectrumChannel->AddPropagationLossModel(lossModel);
5996 spectrumChannel->SetPropagationDelayModel(delayModel);
5997
5998 SpectrumWifiPhyHelper spectrumPhy;
5999 spectrumPhy.SetChannel(spectrumChannel);
6000 spectrumPhy.SetErrorRateModel("ns3::NistErrorRateModel");
6001 spectrumPhy.Set("ChannelSettings", StringValue("{0, 0, BAND_5GHZ, 0}"));
6002
6003 WifiHelper wifi;
6004 wifi.SetStandard(WIFI_STANDARD_80211ax);
6005 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
6006 "DataMode",
6007 StringValue("HeMcs7"),
6008 "ControlMode",
6009 StringValue("HeMcs7"));
6010
6011 WifiMacHelper mac;
6012 mac.SetType("ns3::StaWifiMac");
6013 auto staDevs = wifi.Install(spectrumPhy, mac, staNodes);
6014 WifiHelper::AssignStreams(staDevs, 0);
6015 m_sta1Dev = DynamicCast<WifiNetDevice>(staDevs.Get(0));
6017 m_sta2Dev = DynamicCast<WifiNetDevice>(staDevs.Get(1));
6019
6020 // Set the beacon interval long enough so that associated STAs may not consider link lost when
6021 // beacon generation is disabled during the actual tests. Having such a long interval also
6022 // avoids bloating logs with beacons during the set up phase.
6023 mac.SetType("ns3::ApWifiMac",
6024 "BeaconGeneration",
6025 BooleanValue(true),
6026 "BeaconInterval",
6027 TimeValue(MicroSeconds(1024 * 600)));
6028 m_apDev = DynamicCast<WifiNetDevice>(wifi.Install(spectrumPhy, mac, apNode).Get(0));
6030 m_apDev->GetHeConfiguration()->m_bssColor = m_bssColor;
6033 // ReceiveOkCallback of AP will be set to corresponding test's method once BA sessions have been
6034 // set up for both STAs
6035
6036 MobilityHelper mobility;
6037 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
6038 auto positionAlloc = CreateObject<ListPositionAllocator>();
6039 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
6040 positionAlloc->Add(Vector(1.0, 0.0, 0.0)); // put close enough in order to use MCS
6041 positionAlloc->Add(
6042 Vector(2.0, 0.0, 0.0)); // STA 2 is a bit further away, but still in range of MCS
6043 mobility.SetPositionAllocator(positionAlloc);
6044
6045 mobility.Install(apNode);
6046 mobility.Install(staNodes);
6047
6048 lossModel->SetDefaultLoss(50.0);
6049 lossModel->SetLoss(apNode->GetObject<MobilityModel>(),
6050 staNodes.Get(1)->GetObject<MobilityModel>(),
6051 56.0,
6052 true); //+6 dB between AP <-> STA 2 compared to AP <-> STA 1
6053}
6054
6055void
6057{
6058 m_phyAp->Dispose();
6059 m_phyAp = nullptr;
6060 m_apDev->Dispose();
6061 m_apDev = nullptr;
6062 m_sta1Dev->Dispose();
6063 m_sta1Dev = nullptr;
6064 m_sta2Dev->Dispose();
6065 m_sta2Dev = nullptr;
6066}
6067
6068void
6070{
6073 int64_t streamNumber = 0;
6074
6075 auto phySta1 = m_sta1Dev->GetPhy();
6076 auto phySta2 = m_sta2Dev->GetPhy();
6077
6078 m_phyAp->AssignStreams(streamNumber);
6079 phySta1->AssignStreams(streamNumber);
6080 phySta2->AssignStreams(streamNumber);
6081
6082 m_phyAp->SetAttribute("TxPowerStart", DoubleValue(m_txPowerAp));
6083 m_phyAp->SetAttribute("TxPowerEnd", DoubleValue(m_txPowerAp));
6084 m_phyAp->SetAttribute("TxPowerLevels", UintegerValue(1));
6085
6086 phySta1->SetAttribute("TxPowerStart", DoubleValue(m_txPowerStart));
6087 phySta1->SetAttribute("TxPowerEnd", DoubleValue(m_txPowerEnd));
6088 phySta1->SetAttribute("TxPowerLevels", UintegerValue(m_txPowerLevels));
6089
6090 phySta2->SetAttribute("TxPowerStart", DoubleValue(m_txPowerStart));
6091 phySta2->SetAttribute("TxPowerEnd", DoubleValue(m_txPowerEnd));
6092 phySta2->SetAttribute("TxPowerLevels", UintegerValue(m_txPowerLevels));
6093
6094 Time relativeStart{};
6095 if (setupBa)
6096 {
6097 // Set up BA for each station once the association phase has ended
6098 // so that a BA session is established when the MU-BAR is received.
6101 this,
6102 m_sta1Dev->GetAddress());
6105 this,
6106 m_sta2Dev->GetAddress());
6107 relativeStart = MilliSeconds(1000);
6108 }
6109 else
6110 {
6111 auto apMac = DynamicCast<ApWifiMac>(m_apDev->GetMac());
6112 NS_ASSERT(apMac);
6113 apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
6114 }
6115
6116 Simulator::Schedule(relativeStart,
6118 this);
6119
6120 {
6121 // Verify that the RSSI from STA 1 is consistent with what was requested
6122 std::vector<uint16_t> staIds{1};
6123 Simulator::Schedule(relativeStart, &TestUlOfdmaPowerControl::SendMuBar, this, staIds);
6124 }
6125
6126 {
6127 // Verify that the RSSI from STA 2 is consistent with what was requested
6128 std::vector<uint16_t> staIds{2};
6129 Simulator::Schedule(relativeStart + MilliSeconds(20),
6131 this,
6132 staIds);
6133 }
6134
6135 {
6136 // Verify that the RSSI from STA 1 and 2 is consistent with what was requested
6137 std::vector<uint16_t> staIds{1, 2};
6138 Simulator::Schedule(relativeStart + MilliSeconds(40),
6140 this,
6141 staIds);
6142 }
6143
6144 Simulator::Stop(relativeStart + MilliSeconds(100));
6146}
6147
6148void
6150{
6151 // Power configurations
6152 m_txPowerAp = dBm_u{20}; // so as to have -30 and -36 dBm at STA 1 and STA 2 resp., since path
6153 // loss = 50 dB for AP <-> STA 1 and 56 dB for AP <-> STA 2
6154 m_txPowerStart = dBm_u{15};
6155
6156 // Requested UL RSSIs: should correspond to 20 dBm transmit power at STAs
6159
6160 // Test single power level
6161 {
6162 // STA power configurations: 15 dBm only
6163 m_txPowerEnd = dBm_u{15};
6164 m_txPowerLevels = 1;
6165
6166 // Expected UL RSSIs, considering that the provided power is 5 dB less than requested,
6167 // regardless of the estimated path loss.
6168 m_rssiSta1 = dBm_u{-35}; // 15 dBm - 50 dB
6169 m_rssiSta2 = dBm_u{-41}; // 15 dBm - 56 dB
6170
6171 RunOne(true);
6172 }
6173
6174 // Test 2 dBm granularity
6175 {
6176 // STA power configurations: [15:2:25] dBm
6177 m_txPowerEnd = dBm_u{25};
6178 m_txPowerLevels = 6;
6179
6180 // Expected UL RSSIs, considering that the provided power (21 dBm) is 1 dB more than
6181 // requested
6182 m_rssiSta1 = dBm_u{-29}; // 21 dBm - 50 dB
6183 m_rssiSta2 = dBm_u{-35}; // 21 dBm - 50 dB
6184
6185 RunOne(false);
6186 }
6187
6188 // Test 1 dBm granularity
6189 {
6190 // STA power configurations: [15:1:25] dBm
6191 m_txPowerEnd = dBm_u{25};
6192 m_txPowerLevels = 11;
6193
6194 // Expected UL RSSIs, considering that we can correctly tune the transmit power
6195 m_rssiSta1 = dBm_u{-30}; // 20 dBm - 50 dB
6196 m_rssiSta2 = dBm_u{-36}; // 20 dBm - 56 dB
6197
6198 RunOne(false);
6199 }
6200
6201 // Ask for different power levels (3 dB difference between HE_TB_PPDUs)
6202 {
6203 // STA power configurations: [15:1:25] dBm
6204 m_txPowerEnd = dBm_u{25};
6205 m_txPowerLevels = 11;
6206
6207 // Requested UL RSSIs
6209 dBm_u{-28}; // 2 dB higher than previously -> Tx power = 22 dBm at STA 1
6210 m_requestedRssiSta2 = dBm_u{-37}; // 1 dB less than previously -> Tx power = 19 dBm at STA 2
6211
6212 // Expected UL RSSIs, considering that we can correctly tune the transmit power
6213 m_rssiSta1 = dBm_u{-28}; // 22 dBm - 50 dB
6214 m_rssiSta2 = dBm_u{-37}; // 19 dBm - 56 dB
6215
6216 RunOne(false);
6217 }
6218
6220}
6221
6222/**
6223 * @ingroup wifi-test
6224 * @ingroup tests
6225 *
6226 * @brief wifi PHY OFDMA Test Suite
6227 */
6229{
6230 public:
6232};
6233
6235 : TestSuite("wifi-phy-ofdma", Type::UNIT)
6236{
6237 AddTestCase(new TestDlOfdmaPhyTransmission<HePhy>(), TestCase::Duration::QUICK);
6238 AddTestCase(new TestDlOfdmaPhyTransmission<EhtPhy>(), TestCase::Duration::QUICK);
6239 AddTestCase(new TestDlOfdmaPhyPuncturing, TestCase::Duration::QUICK);
6240 AddTestCase(new TestUlOfdmaPpduUid, TestCase::Duration::QUICK);
6241 AddTestCase(new TestMultipleHeTbPreambles, TestCase::Duration::QUICK);
6242 AddTestCase(new TestUlOfdmaPhyTransmission<HePhy>(), TestCase::Duration::QUICK);
6243 AddTestCase(new TestUlOfdmaPhyTransmission<EhtPhy>(), TestCase::Duration::QUICK);
6244 AddTestCase(new TestPhyPaddingExclusion, TestCase::Duration::QUICK);
6245 AddTestCase(new TestUlOfdmaPowerControl, TestCase::Duration::QUICK);
6246}
6247
SpectrumWifiPhy used for testing OFDMA.
void SetTriggerFrameUid(uint64_t uid)
Since we assume trigger frame was previously received from AP, this is used to set its UID.
TracedCallback< uint64_t > m_phyTxPpduUidTrace
Callback providing UID of the PPDU that is about to be transmitted.
Ptr< LatestPhyEntityType > GetPhyEntity() const
static TypeId GetTypeId()
Get the type ID.
Ptr< OfdmaTestPhy< LatestPhyEntityType > > m_ofdmaTestPhy
Pointer to latest PHY entity instance used for OFDMA test.
std::map< std::pair< uint64_t, WifiPreamble >, Ptr< Event > > & GetCurrentPreambleEvents()
void DoDispose() override
Destructor implementation.
Time GetEnergyDuration(Watt_u energy, WifiSpectrumBandInfo band)
Wrapper to InterferenceHelper method.
void SetPpduUid(uint64_t uid)
Set the global PPDU UID counter.
void(* TxPpduUidCallback)(uint64_t uid)
TracedCallback signature for UID of transmitted PPDU.
void DoInitialize() override
Initialize() implementation.
OfdmaSpectrumWifiPhy(uint16_t staId)
Constructor.
void StartTx(Ptr< const WifiPpdu > ppdu) override
PHY entity slightly modified so as to return a given STA-ID in case of DL MU for OfdmaSpectrumWifiPhy...
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.
WifiSpectrumBandInfo GetNonOfdmaBand(const WifiTxVector &txVector, uint16_t staId) const
Get the band used to transmit the non-OFDMA part of an HE TB PPDU.
OfdmaTestPhy(uint16_t staId)
Constructor.
PHY listener for OFDMA tests.
OfdmaTestPhyListener()=default
bool m_lastRxSuccess
flag whether last RX has been successful
void NotifyRxStart(Time duration) override
Time GetLastRxStartNotification() const
Return the time at which the last RX start notification has been received.
void NotifySwitchingStart(Time duration) override
void NotifyWakeup() override
Notify listeners that we woke up.
uint32_t m_notifyRxStart
count number of RX start notifications
void Reset()
Reset function.
Time m_lastRxEnd
last time a RX end notification has been received
Time m_lastRxStart
last time a RX start notification has been received
Time GetLastRxEndNotification() const
Return the time at which the last RX end notification has been received.
void NotifyCcaBusyStart(Time duration, WifiChannelListType channelType, const std::vector< Time > &) override
uint32_t m_notifyRxEnd
count number of RX end notifications
bool IsLastRxSuccess() const
Return whether last RX has been successful.
void NotifySleep() override
Notify listeners that we went to sleep.
uint32_t GetNumRxEndNotifications() const
Return the number of RX end notifications that has been received since the last reset.
void NotifyRxEndOk() override
We have received the last bit of a packet for which NotifyRxStart was invoked first and,...
void NotifyTxStart(Time duration, dBm_u txPower) override
uint32_t GetNumRxStartNotifications() const
Return the number of RX start notifications that has been received since the last reset.
void NotifyRxEndError(const WifiTxVector &txVector) override
void NotifyOff() override
Notify listeners that we went to switch off.
void NotifyOn() override
Notify listeners that we went to switch on.
DL-OFDMA PHY puncturing test.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
uint32_t m_countRxBytesSta1
count RX bytes for STA 1
uint32_t m_countRxBytesSta2
count RX bytes for STA 2
Ptr< SpectrumWifiPhy > m_phyAp
PHY of AP.
void DoRun() override
Implementation to actually run this TestCase.
Time m_expectedPpduDuration20Mhz
expected duration to send MU PPDU on 20 MHz RU
void CheckResultsSta1(uint32_t expectedRxSuccess, uint32_t expectedRxFailure, uint32_t expectedRxBytes)
Check the results for STA 1.
void ResetResults()
Reset the results.
uint32_t m_countRxSuccessSta2
count RX success for STA 2
void RunOne()
Run one function.
void DoCheckPhyState(Ptr< OfdmaSpectrumWifiPhy< HePhy > > phy, WifiPhyState expectedState)
Check the PHY state now.
void RxFailureSta1(Ptr< const WifiPsdu > psdu)
Receive failure function for STA 1.
uint32_t m_countRxFailureSta2
count RX failure for STA 2
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void SendMuPpdu(uint16_t rxStaId1, uint16_t rxStaId2, const std::vector< bool > &puncturedSubchannels)
Send MU-PPDU function.
uint32_t m_countRxFailureSta1
count RX failure for STA 1
void RxSuccessSta2(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function for STA 2.
Time m_expectedPpduDuration40Mhz
expected duration to send MU PPDU on 40 MHz RU
void CheckResultsSta2(uint32_t expectedRxSuccess, uint32_t expectedRxFailure, uint32_t expectedRxBytes)
Check the results for STA 2.
Ptr< OfdmaSpectrumWifiPhy< HePhy > > m_phySta2
PHY of STA 2.
void RxFailureSta2(Ptr< const WifiPsdu > psdu)
Receive failure function for STA 2.
Ptr< WaveformGenerator > m_phyInterferer
PHY of interferer.
Ptr< OfdmaSpectrumWifiPhy< HePhy > > m_phySta1
PHY of STA 1.
void StopInterference()
Stop interference function.
void RxSuccessSta1(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function for STA 1.
uint8_t m_indexSubchannel
Index of the subchannel (starting from 0) that should contain an interference and be punctured during...
uint32_t m_countRxSuccessSta1
count RX success for STA 1
void CheckPhyState(Ptr< OfdmaSpectrumWifiPhy< HePhy > > phy, WifiPhyState expectedState)
Schedule now to check the PHY state.
void GenerateInterference(Ptr< SpectrumValue > interferencePsd, Time duration)
Generate interference function.
Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > m_phySta1
PHY of STA 1.
uint32_t m_countRxSuccessSta3
count RX success for STA 3
uint32_t m_countRxBytesSta3
count RX bytes for STA 3
void DoRun() override
Implementation to actually run this TestCase.
Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > m_phySta3
PHY of STA 3.
void StopInterference()
Stop interference function.
void CheckResultsSta1(uint32_t expectedRxSuccess, uint32_t expectedRxFailure, uint32_t expectedRxBytes)
Check the results for STA 1.
void RxFailureSta3(Ptr< const WifiPsdu > psdu)
Receive failure function for STA 3.
Ptr< SpectrumWifiPhy > m_phyAp
PHY of AP.
void RxFailureSta2(Ptr< const WifiPsdu > psdu)
Receive failure function for STA 2.
void RunOne()
Run one function.
uint32_t m_countRxFailureSta3
count RX failure for STA 3
uint32_t m_countRxBytesSta2
count RX bytes for STA 2
void ResetResults()
Reset the results.
Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > m_phySta2
PHY of STA 2.
void RxSuccessSta3(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function for STA 3.
void CheckPhyState(Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > phy, WifiPhyState expectedState)
Schedule now to check the PHY state.
uint32_t m_countRxBytesSta1
count RX bytes for STA 1
void CheckResultsSta2(uint32_t expectedRxSuccess, uint32_t expectedRxFailure, uint32_t expectedRxBytes)
Check the results for STA 2.
void RxSuccessSta1(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function for STA 1.
Time m_expectedPpduDuration
expected duration to send MU PPDU
void RxFailureSta1(Ptr< const WifiPsdu > psdu)
Receive failure function for STA 1.
void GenerateInterference(Ptr< SpectrumValue > interferencePsd, Time duration)
Generate interference function.
void CheckResultsSta3(uint32_t expectedRxSuccess, uint32_t expectedRxFailure, uint32_t expectedRxBytes)
Check the results for STA 3.
uint32_t m_countRxFailureSta1
count RX failure for STA 1
void DoCheckPhyState(Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > phy, WifiPhyState expectedState)
Check the PHY state now.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
uint32_t m_countRxSuccessSta2
count RX success for STA 2
Ptr< WaveformGenerator > m_phyInterferer
PHY of interferer.
WifiModulationClass m_modClass
the modulation class to consider for the test
uint32_t m_countRxFailureSta2
count RX failure for STA 2
void RxSuccessSta2(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function for STA 2.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void SendMuPpdu(uint16_t rxStaId1, uint16_t rxStaId2)
Send MU-PPDU function.
uint32_t m_countRxSuccessSta1
count RX success for STA 1
UL-OFDMA multiple RX events test.
WifiTxVector m_trigVector
TRIGVECTOR.
void RxHeTbPpdu(uint64_t uid, uint16_t staId, Watt_u txPower, size_t payloadSize)
Receive HE TB PPDU function.
Ptr< OfdmaSpectrumWifiPhy< HePhy > > m_phy
Phy.
void RxHeTbPpduOfdmaPart(Ptr< WifiSpectrumSignalParameters > rxParamsOfdma)
Receive OFDMA part of HE TB PPDU function.
void CheckHeTbPreambles(size_t nEvents, std::vector< uint64_t > uids)
Check the received HE TB preambles.
uint64_t m_totalBytesDropped
total number of dropped bytes
void CheckBytesDropped(size_t expectedBytesDropped)
Check the number of bytes dropped.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
void DoRun() override
Implementation to actually run this TestCase.
void RxDropped(Ptr< const Packet > p, WifiPhyRxfailureReason reason)
RX dropped function.
void DoRxHeTbPpduOfdmaPart(Ptr< WifiSpectrumSignalParameters > rxParamsOfdma)
Receive OFDMA part of HE TB PPDU function.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
PHY padding exclusion test.
void DoCheckPhyState(Ptr< OfdmaSpectrumWifiPhy< HePhy > > phy, WifiPhyState expectedState)
Check the PHY state.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void CheckRxFromSta1(uint32_t expectedSuccess, uint32_t expectedFailures, uint32_t expectedBytes)
Check the received PSDUs from STA1.
void VerifyEventsCleared()
Verify all events are cleared at end of TX or RX.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
void GenerateInterference(Ptr< SpectrumValue > interferencePsd, Time duration)
Generate interference function.
Ptr< WaveformGenerator > m_phyInterferer
PHY of interferer.
uint32_t m_countRxSuccessFromSta2
count RX success from STA 2
void DoRun() override
Implementation to actually run this TestCase.
void SendTbPpdu(uint16_t txStaId, std::size_t index, std::size_t payloadSize, Time txDuration)
Send HE TB PPDU function.
Ptr< OfdmaSpectrumWifiPhy< HePhy > > m_phySta1
PHY of STA 1.
void RxFailure(Ptr< const WifiPsdu > psdu)
Receive failure function.
Ptr< OfdmaSpectrumWifiPhy< HePhy > > m_phySta2
PHY of STA 2.
uint32_t m_countRxBytesFromSta1
count RX bytes from STA 1
void RxSuccess(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function.
void SetTrigVector(Time ppduDuration)
Set TRIGVECTOR for HE TB PPDU.
void Reset()
Reset function.
uint32_t m_countRxFailureFromSta1
count RX failure from STA 1
uint32_t m_countRxSuccessFromSta1
count RX success from STA 1
void StopInterference()
Stop interference function.
Ptr< OfdmaSpectrumWifiPhy< HePhy > > m_phyAp
PHY of AP.
void RunOne()
Run one function.
void CheckRxFromSta2(uint32_t expectedSuccess, uint32_t expectedFailures, uint32_t expectedBytes)
Check the received PSDUs from STA2.
uint32_t m_countRxFailureFromSta2
count RX failure from STA 2
uint32_t m_countRxBytesFromSta2
count RX bytes from STA 2
void CheckPhyState(Ptr< OfdmaSpectrumWifiPhy< HePhy > > phy, WifiPhyState expectedState)
Check the PHY state.
void SetPsdLimit(Ptr< WifiPhy > phy, dBm_per_MHz_u psdLimit)
Set the PSD limit.
void StopInterference()
Stop interference function.
Time m_expectedPpduDuration
expected duration to send MU PPDU
Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > m_phySta2
PHY of STA 2.
void RxSuccess(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function.
void RunOne()
Run one function.
void DoCheckPhyState(Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > phy, WifiPhyState expectedState)
Check the PHY state.
void CheckApRxEnd(uint32_t expectedNotifications, Time expectedLastNotification, bool expectedSuccess)
Check the the number of RX end notifications at the AP as well as the last time a RX end has been not...
uint32_t m_countRxSuccessFromSta1
count RX success from STA 1
uint32_t m_countRxFailureFromSta2
count RX failure from STA 2
uint32_t m_countRxSuccessFromSta2
count RX success from STA 2
uint32_t m_countRxBytesFromSta1
count RX bytes from STA 1
WifiTxVector GetTxVectorForTbPpdu(uint16_t txStaId, std::size_t index, uint8_t bssColor) const
Get TXVECTOR for HE PPDU.
Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > m_phySta3
PHY of STA 3.
Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > m_phySta1
PHY of STA 1.
void SchedulePowerMeasurementChecks(Time delay, Watt_u rxPowerNonOfdmaRu1, Watt_u rxPowerNonOfdmaRu2, Watt_u rxPowerOfdmaRu1, Watt_u rxPowerOfdmaRu2)
Schedule power measurement related checks.
void SendTbPpdu(uint16_t txStaId, std::size_t index, std::size_t payloadSize, uint64_t uid, uint8_t bssColor, bool incrementUid)
Send HE TB PPDU function.
void CheckPhyState(Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > phy, WifiPhyState expectedState)
Check the PHY state.
TrigVectorInfo
Erroneous info included in a TRIGVECTOR.
void CheckNonOfdmaRxPower(Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > phy, WifiSpectrumBandInfo band, Watt_u expectedRxPower)
Check the received power for the non-OFDMA of the HE TB PPDUs over the given band.
void CheckOfdmaRxPower(Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > phy, WifiSpectrumBandInfo band, Watt_u expectedRxPower)
Check the received power for the OFDMA part of the HE TB PPDUs over the given band.
WifiModulationClass m_modClass
the modulation class to consider for the test
void CheckRxFromSta1(uint32_t expectedSuccess, uint32_t expectedFailures, uint32_t expectedBytes)
Check the received PSDUs from STA1.
uint32_t m_countRxFailureFromSta1
count RX failure from STA 1
void RxFailure(Ptr< const WifiPsdu > psdu)
Receive failure function.
void CheckApRxStart(uint32_t expectedNotifications, Time expectedLastNotification)
Check the the number of RX start notifications at the AP as well as the last time a RX start has been...
void DoRun() override
Implementation to actually run this TestCase.
void LogScenario(std::string log) const
Log scenario description.
void ScheduleTest(Time delay, bool solicited, WifiPhyState expectedStateAtEnd, uint32_t expectedSuccessFromSta1, uint32_t expectedFailuresFromSta1, uint32_t expectedBytesFromSta1, uint32_t expectedSuccessFromSta2, uint32_t expectedFailuresFromSta2, uint32_t expectedBytesFromSta2, bool scheduleTxSta1=true, Time ulTimeDifference=Seconds(0), WifiPhyState expectedStateBeforeEnd=WifiPhyState::RX, TrigVectorInfo error=NONE)
Schedule test to perform.
void CheckRxFromSta2(uint32_t expectedSuccess, uint32_t expectedFailures, uint32_t expectedBytes)
Check the received PSDUs from STA2.
Ptr< OfdmaSpectrumWifiPhy< LatestPhyEntityType > > m_phyAp
PHY of AP.
void VerifyEventsCleared()
Verify all events are cleared at end of TX or RX.
void SendSuPpdu(uint16_t txStaId, std::size_t payloadSize, uint64_t uid, uint8_t bssColor)
Send HE SU PPDU function.
std::shared_ptr< OfdmaTestPhyListener > m_apPhyStateListener
listener for AP PHY state transitions
void GenerateInterference(Ptr< SpectrumValue > interferencePsd, Time duration)
Generate interference function.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
uint32_t m_countRxBytesFromSta2
count RX bytes from STA 2
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
void SetBssColor(Ptr< WifiPhy > phy, uint8_t bssColor)
Set the BSS color.
Ptr< WaveformGenerator > m_phyInterferer
PHY of interferer.
void SetTrigVector(uint8_t bssColor, TrigVectorInfo error)
Set TRIGVECTOR for HE TB PPDU.
UL-OFDMA power control test.
dBm_u m_requestedRssiSta2
requested RSSI from STA 2 at AP for HE TB PPDUs
void DoRun() override
Implementation to actually run this TestCase.
Ptr< WifiNetDevice > m_sta2Dev
network device of STA 2
dBm_u m_rssiSta2
expected RSSI from STA 2 at AP for HE TB PPDUs
dBm_u m_txPowerEnd
maximum transmission power for STAs
dBm_u m_txPowerStart
minimum transmission power for STAs
void SetupBa(Address destination)
Send a QoS Data packet to the destination station in order to set up a block Ack session (so that the...
Ptr< WifiNetDevice > m_sta1Dev
network device of STA 1
dBm_u m_rssiSta1
expected RSSI from STA 1 at AP for HE TB PPDUs
Ptr< WifiNetDevice > m_apDev
network device of AP
dBm_u m_requestedRssiSta1
requested RSSI from STA 1 at AP for HE TB PPDUs
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
void ReplaceReceiveOkCallbackOfAp()
Replace the AP's callback on its PHY's ReceiveOkCallback by the ReceiveOkCallbackAtAp method.
dBm_u m_txPowerAp
transmit power of AP
uint8_t m_txPowerLevels
number of transmission power levels for STAs
dB_u m_tol
tolerance between received and expected RSSIs
void RunOne(bool setupBa)
Run one simulation with an optional BA session set up phase.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
Ptr< SpectrumWifiPhy > m_phyAp
PHY of AP.
void ReceiveOkCallbackAtAp(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive OK callback function at AP.
void SendMuBar(std::vector< uint16_t > staIds)
Send a MU BAR through the AP to the STAs listed in the provided vector.
UL-OFDMA PPDU UID attribution test.
void TxPpduSta1(uint64_t uid)
Transmitted PPDU information function for STA 1.
Ptr< OfdmaSpectrumWifiPhy< HePhy > > m_phyAp
PHY of AP.
void ResetPpduUid()
Reset the global PPDU UID counter in WifiPhy.
void CheckUid(uint16_t staId, uint64_t expectedUid)
Check the UID of the transmitted PPDU.
void TxPpduAp(uint64_t uid)
Transmitted PPDU information function for AP.
void TxPpduSta2(uint64_t uid)
Transmitted PPDU information function for STA 2.
Ptr< OfdmaSpectrumWifiPhy< HePhy > > m_phySta1
PHY of STA 1.
uint64_t m_ppduUidAp
UID of PPDU transmitted by AP.
uint64_t m_ppduUidSta1
UID of PPDU transmitted by STA1.
uint64_t m_ppduUidSta2
UID of PPDU transmitted by STA2.
void DoRun() override
Implementation to actually run this TestCase.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
Ptr< OfdmaSpectrumWifiPhy< HePhy > > m_phySta2
PHY of STA 2.
void SendMuPpdu()
Send MU-PPDU toward both STAs.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void SendTbPpdu()
Send TB-PPDU from both STAs.
void SendSuPpdu(uint16_t txStaId)
Send SU-PPDU function.
wifi PHY OFDMA Test Suite
a polymophic address class
Definition address.h:90
AttributeValue implementation for Boolean.
Definition boolean.h:26
Headers for BlockAckRequest.
void SetType(BlockAckReqType type)
Set the BlockAckRequest type.
void SetStartingSequence(uint16_t seq)
Set the starting sequence number from the given raw sequence control field.
void SetTidInfo(uint8_t tid)
Set Traffic ID (TID).
Headers for Trigger frames.
CtrlTriggerUserInfoField & AddUserInfoField()
Append a new User Info field to this Trigger frame and return a non-const reference to it.
void SetApTxPower(int8_t power)
Set the AP TX Power subfield of the Common Info field.
WifiTxVector GetHeTbTxVector(uint16_t staId) const
Get the TX vector that the station with the given STA-ID will use to send the HE TB PPDU solicited by...
void SetType(TriggerFrameType type)
Set the Trigger frame type.
void SetCsRequired(bool cs)
Set the CS Required subfield of the Common Info field.
void SetUlSpatialReuse(uint16_t sr)
Set the UL Spatial Reuse subfield of the Common Info field.
void SetGiAndLtfType(Time guardInterval, uint8_t ltfType)
Set the GI And LTF Type subfield of the Common Info field.
void SetUlLength(uint16_t len)
Set the UL Length subfield of the Common Info field.
void SetMoreTF(bool more)
Set the More TF subfield of the Common Info field.
void SetUlBandwidth(MHz_u bw)
Set the bandwidth of the solicited HE/EHT TB PPDU.
User Info field of Trigger frames.
void SetAid12(uint16_t aid)
Set the AID12 subfield, which carries the 12 LSBs of the AID of the station for which this User Info ...
void SetUlFecCodingType(bool ldpc)
Set the UL FEC Coding Type subfield, which indicates whether BCC or LDPC is used.
void SetUlMcs(uint8_t mcs)
Set the UL MCS subfield, which indicates the MCS of the solicited HE TB PPDU.
void SetMuBarTriggerDepUserInfo(const CtrlBAckRequestHeader &bar)
Set the Trigger Dependent User Info subfield for the MU-BAR variant of Trigger frames,...
void SetUlDcm(bool dcm)
Set the UL DCM subfield, which indicates whether or not DCM is used.
void SetSsAllocation(uint8_t startingSs, uint8_t nSs)
Set the SS Allocation subfield, which is present when the AID12 subfield is neither 0 nor 2045.
void SetUlTargetRssi(int8_t dBm)
Set the UL Target RSSI subfield to indicate the expected receive signal power in dBm.
void SetRuAllocation(WifiRu::RuSpec ru)
Set the RU Allocation subfield according to the specified RU.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
static WifiMode GetEhtMcs7()
Return MCS 7 from EHT MCS values.
static WifiMode GetEhtMcs9()
Return MCS 9 from EHT MCS values.
RU Specification.
Definition eht-ru.h:34
static std::pair< bool, bool > GetPrimaryFlags(MHz_u bw, RuType ruType, std::size_t phyIndex, uint8_t p20Index)
Get the primary flags of a given RU transmitted in a PPDU.
Definition eht-ru.cc:912
static std::size_t GetIndexIn80MHzSegment(MHz_u bw, RuType ruType, std::size_t phyIndex)
Get the index of a given RU transmitted in a PPDU within its 80 MHz segment.
Definition eht-ru.cc:945
PHY entity for HE (11ax)
Definition he-phy.h:58
static WifiMode GetHeMcs9()
Return MCS 9 from HE MCS values.
static WifiMode GetHeMcs7()
Return MCS 7 from HE MCS values.
static std::pair< uint16_t, Time > ConvertHeTbPpduDurationToLSigLength(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Compute the L-SIG length value corresponding to the given HE TB PPDU duration.
Definition he-phy.cc:263
@ PSD_HE_PORTION
HE portion of an HE PPDU.
Definition he-ppdu.h:106
@ PSD_NON_HE_PORTION
Non-HE portion of an HE PPDU.
Definition he-ppdu.h:105
RU Specification.
Definition he-ru.h:37
static std::size_t GetIndexIn80MHzSegment(MHz_u bw, RuType ruType, std::size_t phyIndex)
Get the index of a given RU transmitted in a PPDU within its 80 MHz segment.
Definition he-ru.cc:475
static bool GetPrimary80MHzFlag(MHz_u bw, RuType ruType, std::size_t phyIndex, uint8_t p20Index)
Get the primary 80 MHz flag of a given RU transmitted in a PPDU.
Definition he-ru.cc:462
an EUI-48 address
static Mac48Address ConvertFrom(const Address &address)
static Mac48Address GetBroadcast()
Helper class used to assign positions and mobility models to nodes.
Keep track of the current position and velocity of an object.
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:511
AttributeValue implementation for Pointer.
Ptr< T > Get() const
Definition pointer.h:223
Smart pointer class similar to boost::intrusive_ptr.
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:561
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:595
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Make it easy to create and manage PHY objects for the spectrum model.
void SetChannel(const Ptr< SpectrumChannel > channel)
802.11 PHY layer model
void DoInitialize() override
Initialize() implementation.
void DoDispose() override
Destructor implementation.
void StartTx(Ptr< const WifiPpdu > ppdu) override
Hold variables of type string.
Definition string.h:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
AttributeValue implementation for Time.
Definition nstime.h:1432
Forward calls to a chain of Callback.
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
static WifiMode GetVhtMcs5()
Return MCS 5 from VHT MCS values.
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
Implements the IEEE 802.11 MAC header.
void SetNoMoreFragments()
Un-set the More Fragment bit in the Frame Control Field.
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 SetDsFrom()
Set the From DS bit in the Frame Control field.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
void SetDsNotTo()
Un-set the To DS bit in the Frame Control field.
void SetNoRetry()
Un-set the Retry bit in the Frame Control field.
create MAC layers for a ns3::WifiNetDevice.
void Set(std::string name, const AttributeValue &v)
void SetErrorRateModel(std::string type, Args &&... args)
Helper function used to set the error rate model.
std::tuple< uint8_t, MHz_u, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying a segment of an operating channel.
Definition wifi-phy.h:937
static Time GetPreambleDetectionDuration()
Definition wifi-phy.cc:1504
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1563
void Reset()
Reset data upon end of TX or RX.
Definition wifi-phy.cc:1953
receive notifications about PHY events.
static ConstIterator FindFirst(uint8_t number, MHz_u frequency, MHz_u width, WifiStandard standard, WifiPhyBand band, ConstIterator start=m_frequencyChannels.begin())
Find the first frequency segment matching the specified parameters.
This objects implements the PHY state machine of the Wifi device.
std::variant< HeRu::RuSpec, EhtRu::RuSpec > RuSpec
variant of the RU specification
Definition wifi-ru.h:27
static RuSpec FindOverlappingRu(MHz_u bw, RuSpec referenceRu, RuType searchedRuType)
Find the RU allocation of the given RU type overlapping the given reference RU allocation.
Definition wifi-ru.cc:226
static MHz_u GetBandwidth(RuType ruType)
Get the approximate bandwidth occupied by a RU.
Definition wifi-ru.cc:78
static RuType GetRuType(RuSpec ru)
Get the type of a given RU.
Definition wifi-ru.cc:45
static SubcarrierGroup GetSubcarrierGroup(MHz_u bw, RuType ruType, std::size_t phyIndex, WifiModulationClass mc)
Get the subcarrier group of the RU having the given PHY index among all the RUs of the given type (nu...
Definition wifi-ru.cc:142
static std::size_t GetPhyIndex(RuSpec ru, MHz_u bw, uint8_t p20Index)
Get the RU PHY index.
Definition wifi-ru.cc:57
static Ptr< SpectrumValue > CreateHeMuOfdmTxPowerSpectralDensity(const std::vector< MHz_u > &centerFrequencies, MHz_u channelWidth, Watt_u txPower, MHz_u guardBandwidth, const std::vector< WifiSpectrumBandIndices > &ru)
Create a transmit power spectral density corresponding to the OFDMA part of HE TB PPDUs for a given R...
static Ptr< SpectrumValue > CreateHeOfdmTxPowerSpectralDensity(MHz_u centerFrequency, MHz_u channelWidth, Watt_u txPower, MHz_u guardBandwidth, dBr_u minInnerBand=dBr_u{-20}, dBr_u minOuterband=dBr_u{-28}, dBr_u lowestPoint=dBr_u{-40}, const std::vector< bool > &puncturedSubchannels={})
Create a transmit power spectral density corresponding to OFDM High Efficiency (HE/EHT) (802....
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
void SetRu(WifiRu::RuSpec ru, uint16_t staId)
Set the RU specification for the STA-ID.
WifiPreamble GetPreambleType() const
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
MHz_u GetChannelWidth() const
WifiRu::RuSpec GetRu(uint16_t staId) const
Get the RU specification for the STA-ID.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetNss(uint8_t nss)
Sets the number of Nss.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > CreateObjectWithAttributes(Args... args)
Allocate an Object on the heap and initialize with a set of attributes.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#define NS_TEST_ASSERT_MSG_EQ_TOL(actual, limit, tol, msg)
Test that actual and expected (limit) values are equal to plus or minus some tolerance and report and...
Definition test.h:327
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiPhyRxfailureReason
Enumeration of the possible reception failure reasons.
WifiPhyBand
Identifies the PHY band.
WifiModulationClass
This enumeration defines the modulation classes per (Table 10-6 "Modulation classes"; IEEE 802....
WifiChannelListType
Enumeration of the possible channel-list parameter elements defined in Table 8-5 of IEEE 802....
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211ax
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PREAMBLE_HE_SU
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
@ WIFI_PPDU_TYPE_DL_MU
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
Definition first.py:1
Every class exported by the ns3 library is enclosed in the ns3 namespace.
WifiPhyState
The state of the PHY layer.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
std::string Demangle(const std::string &mangled)
Definition demangle.cc:69
std::vector< BandInfo > Bands
Container of BandInfo.
RuType
The different Resource Unit (RU) types.
Definition wifi-types.h:99
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Definition wifi-utils.h:138
MHz_u GetMaximumChannelWidth(WifiModulationClass modulation)
Get the maximum channel width allowed for the given modulation class.
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_CTL_BACKRESP
@ WIFI_MAC_QOSDATA
Watt_u DbmToW(dBm_u val)
Convert from dBm to Watts.
Definition wifi-utils.cc:32
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
Definition wifi-utils.cc:59
WifiModulationClass GetModulationClassForStandard(WifiStandard standard)
Return the modulation class corresponding to a given standard.
Hz_u MHzToHz(MHz_u val)
Convert from MHz to Hz.
Definition wifi-utils.h:113
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
std::vector< uint16_t > RuAllocation
9 bits RU_ALLOCATION per 20 MHz
STL namespace.
static const MHz_u CHANNEL_WIDTH
The building block of a SpectrumModel.
double fc
center frequency
double fl
lower limit of subband
double fh
upper limit of subband
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:79
dBm_u rssi
RSSI.
Definition wifi-types.h:81
WifiSpectrumBandInfo structure containing info about a spectrum band.
std::vector< WifiSpectrumBandIndices > indices
the start and stop indices for each segment of the band
static const MHz_u DEFAULT_FREQUENCY
static WifiPhyOfdmaTestSuite wifiPhyOfdmaTestSuite
the test suite
static const uint8_t DEFAULT_CHANNEL_NUMBER
static const WifiPhyBand DEFAULT_WIFI_BAND
static const MHz_u DEFAULT_CHANNEL_WIDTH
static const MHz_u DEFAULT_GUARD_WIDTH