A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
spectrum-wifi-phy-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015 University of Washington
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include "ns3/boolean.h"
8#include "ns3/constant-position-mobility-model.h"
9#include "ns3/he-phy.h" //includes OFDM PHY
10#include "ns3/interference-helper.h"
11#include "ns3/log.h"
12#include "ns3/mobility-helper.h"
13#include "ns3/multi-model-spectrum-channel.h"
14#include "ns3/nist-error-rate-model.h"
15#include "ns3/non-communicating-net-device.h"
16#include "ns3/ofdm-ppdu.h"
17#include "ns3/pointer.h"
18#include "ns3/spectrum-wifi-helper.h"
19#include "ns3/spectrum-wifi-phy.h"
20#include "ns3/string.h"
21#include "ns3/test.h"
22#include "ns3/waveform-generator.h"
23#include "ns3/wifi-mac-header.h"
24#include "ns3/wifi-net-device.h"
25#include "ns3/wifi-phy-listener.h"
26#include "ns3/wifi-psdu.h"
27#include "ns3/wifi-spectrum-phy-interface.h"
28#include "ns3/wifi-spectrum-signal-parameters.h"
29#include "ns3/wifi-spectrum-value-helper.h"
30#include "ns3/wifi-utils.h"
31
32#include <memory>
33#include <optional>
34#include <tuple>
35#include <vector>
36
37using namespace ns3;
38
39NS_LOG_COMPONENT_DEFINE("SpectrumWifiPhyTest");
40
41static const uint8_t CHANNEL_NUMBER = 36;
42static const MHz_u CHANNEL_WIDTH = 20;
43static const MHz_u GUARD_WIDTH = CHANNEL_WIDTH; // expanded to channel width to model spectrum mask
44
45/**
46 * Extended SpectrumWifiPhy class for the purpose of the tests.
47 */
49{
50 public:
51 using WifiPhy::GetBand;
52};
53
54/**
55 * Extended InterferenceHelper class for the purpose of the tests.
56 */
58{
59 public:
60 /**
61 * \brief Get the type ID.
62 * \return the object TypeId
63 */
65 {
66 static TypeId tid = TypeId("ns3::ExtInterferenceHelper")
68 .SetGroupName("Wifi")
69 .AddConstructor<ExtInterferenceHelper>();
70 return tid;
71 }
72
73 /**
74 * Indicate whether the interference helper is in receiving state
75 *
76 * \return true if the interference helper is in receiving state, false otherwise
77 */
78 bool IsRxing() const
79 {
80 return std::any_of(m_rxing.cbegin(), m_rxing.cend(), [](const auto& rxing) {
81 return rxing.second;
82 });
83 }
84
85 /**
86 * Indicate whether a given band is tracked by the interference helper
87 *
88 * \param startStopFreqs the start and stop frequencies per segment of the band
89 *
90 * \return true if the specified band is tracked by the interference helper, false otherwise
91 */
92 bool IsBandTracked(const std::vector<WifiSpectrumBandFrequencies>& startStopFreqs) const
93 {
94 for (const auto& [band, nis] : m_niChanges)
95 {
96 if (band.frequencies == startStopFreqs)
97 {
98 return true;
99 }
100 }
101 return false;
102 }
103};
104
106
107/**
108 * \ingroup wifi-test
109 * \ingroup tests
110 *
111 * \brief Spectrum Wifi Phy Basic Test
112 */
114{
115 public:
117 /**
118 * Constructor
119 *
120 * \param name reference name
121 */
122 SpectrumWifiPhyBasicTest(std::string name);
123 ~SpectrumWifiPhyBasicTest() override;
124
125 protected:
126 void DoSetup() override;
127 void DoTeardown() override;
129 /**
130 * Make signal function
131 * \param txPower the transmit power
132 * \param channel the operating channel of the PHY used for the transmission
133 * \returns Ptr<SpectrumSignalParameters>
134 */
136 const WifiPhyOperatingChannel& channel);
137 /**
138 * Send signal function
139 * \param txPower the transmit power
140 */
141 void SendSignal(Watt_u txPower);
142 /**
143 * Spectrum wifi receive success function
144 * \param psdu the PSDU
145 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
146 * \param txVector the transmit vector
147 * \param statusPerMpdu reception status per MPDU
148 */
150 RxSignalInfo rxSignalInfo,
151 WifiTxVector txVector,
152 std::vector<bool> statusPerMpdu);
153 /**
154 * Spectrum wifi receive failure function
155 * \param psdu the PSDU
156 */
158 uint32_t m_count; ///< count
159
160 private:
161 void DoRun() override;
162
163 uint64_t m_uid; //!< the UID to use for the PPDU
164};
165
167 : SpectrumWifiPhyBasicTest("SpectrumWifiPhy test case receives one packet")
168{
169}
170
172 : TestCase(name),
173 m_count(0),
174 m_uid(0)
175{
176}
177
178// Make a Wi-Fi signal to inject directly to the StartRx() method
181{
183 0,
185 NanoSeconds(800),
186 1,
187 1,
188 0,
190 false};
191
192 auto pkt = Create<Packet>(1000);
193 WifiMacHeader hdr;
194
196 hdr.SetQosTid(0);
197
198 auto psdu = Create<WifiPsdu>(pkt, hdr);
199 const auto txDuration =
200 m_phy->CalculateTxDuration(psdu->GetSize(), txVector, m_phy->GetPhyBand());
201
202 auto ppdu = Create<OfdmPpdu>(psdu, txVector, channel, m_uid++);
203
205 channel.GetPrimaryChannelCenterFrequency(CHANNEL_WIDTH),
207 txPower,
209 auto txParams = Create<WifiSpectrumSignalParameters>();
210 txParams->psd = txPowerSpectrum;
211 txParams->txPhy = nullptr;
212 txParams->duration = txDuration;
213 txParams->ppdu = ppdu;
214
215 return txParams;
216}
217
218// Make a Wi-Fi signal to inject directly to the StartRx() method
219void
221{
222 m_phy->StartRx(MakeSignal(txPower, m_phy->GetOperatingChannel()), nullptr);
223}
224
225void
227 RxSignalInfo rxSignalInfo,
228 WifiTxVector txVector,
229 std::vector<bool> statusPerMpdu)
230{
231 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
232 m_count++;
233}
234
235void
241
245
246// Create necessary objects, and inject signals. Test that the expected
247// number of packet receptions occur.
248void
250{
251 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
252 auto node = CreateObject<Node>();
253 auto dev = CreateObject<WifiNetDevice>();
255 auto interferenceHelper = CreateObject<InterferenceHelper>();
256 m_phy->SetInterferenceHelper(interferenceHelper);
258 m_phy->SetErrorRateModel(error);
259 m_phy->SetDevice(dev);
260 m_phy->AddChannel(spectrumChannel);
261 m_phy->SetOperatingChannel(WifiPhy::ChannelTuple{CHANNEL_NUMBER, 0, WIFI_PHY_BAND_5GHZ, 0});
262 m_phy->ConfigureStandard(WIFI_STANDARD_80211n);
263 m_phy->SetReceiveOkCallback(
265 m_phy->SetReceiveErrorCallback(
267 dev->SetPhy(m_phy);
268 node->AddDevice(dev);
269}
270
271void
273{
274 m_phy->Dispose();
275 m_phy = nullptr;
276}
277
278// Test that the expected number of packet receptions occur.
279void
281{
282 Watt_u txPower{0.01};
283 // Send packets spaced 1 second apart; all should be received
287 // Send packets spaced 1 microsecond second apart; none should be received (PHY header reception
288 // failure)
291 this,
292 txPower);
295 this,
296 txPower);
299
300 NS_TEST_ASSERT_MSG_EQ(m_count, 3, "Didn't receive right number of packets");
301}
302
303/**
304 * \ingroup wifi-test
305 * \ingroup tests
306 *
307 * \brief Test Phy Listener
308 */
310{
311 public:
312 /**
313 * Create a test PhyListener
314 */
315 TestPhyListener() = default;
316 ~TestPhyListener() override = default;
317
318 void NotifyRxStart(Time duration) override
319 {
320 NS_LOG_FUNCTION(this << duration);
322 }
323
324 void NotifyRxEndOk() override
325 {
326 NS_LOG_FUNCTION(this);
328 }
329
330 void NotifyRxEndError() override
331 {
332 NS_LOG_FUNCTION(this);
334 }
335
336 void NotifyTxStart(Time duration, dBm_u txPower) override
337 {
338 NS_LOG_FUNCTION(this << duration << txPower);
339 }
340
342 WifiChannelListType channelType,
343 const std::vector<Time>& /*per20MhzDurations*/) override
344 {
345 NS_LOG_FUNCTION(this << duration << channelType);
346 if (duration.IsStrictlyPositive())
347 {
350 {
352 }
353 m_ccaBusyEnd = std::max(m_ccaBusyEnd, Simulator::Now() + duration);
354 }
355 }
356
357 void NotifySwitchingStart(Time duration) override
358 {
359 }
360
361 void NotifySleep() override
362 {
363 }
364
365 void NotifyOff() override
366 {
367 }
368
369 void NotifyWakeup() override
370 {
371 }
372
373 void NotifyOn() override
374 {
375 }
376
377 /**
378 * Reset function
379 */
380 void Reset()
381 {
382 NS_LOG_FUNCTION(this);
383 m_notifyRxStart = 0;
384 m_notifyRxEndOk = 0;
389 }
390
391 uint32_t m_notifyRxStart{0}; ///< notify receive start
392 uint32_t m_notifyRxEndOk{0}; ///< notify receive end OK
393 uint32_t m_notifyRxEndError{0}; ///< notify receive end error
394 uint32_t m_notifyMaybeCcaBusyStart{0}; ///< notify maybe CCA busy start
395 Time m_ccaBusyStart{}; ///< CCA_BUSY start time
396 Time m_ccaBusyEnd{}; ///< CCA_BUSY end time
397};
398
399/**
400 * \ingroup wifi-test
401 * \ingroup tests
402 *
403 * \brief Spectrum Wifi Phy Listener Test
404 */
406{
407 public:
409
410 private:
411 void DoSetup() override;
412 void DoRun() override;
413 std::shared_ptr<TestPhyListener> m_listener; ///< listener
414};
415
417 : SpectrumWifiPhyBasicTest("SpectrumWifiPhy test operation of WifiPhyListener")
418{
419}
420
421void
423{
425 m_listener = std::make_shared<TestPhyListener>();
426 m_phy->RegisterListener(m_listener);
427}
428
429void
431{
432 Watt_u txPower{0.01};
435
436 NS_TEST_ASSERT_MSG_EQ(m_count, 1, "Didn't receive right number of packets");
439 2,
440 "Didn't receive NotifyCcaBusyStart (once preamble is detected + prolonged by L-SIG "
441 "reception, then switched to Rx by at the beginning of data)");
442 NS_TEST_ASSERT_MSG_EQ(m_listener->m_notifyRxStart, 1, "Didn't receive NotifyRxStart");
443 NS_TEST_ASSERT_MSG_EQ(m_listener->m_notifyRxEndOk, 1, "Didn't receive NotifyRxEnd");
444
446 m_listener.reset();
447}
448
449/**
450 * \ingroup wifi-test
451 * \ingroup tests
452 *
453 * \brief Spectrum Wifi Phy Filter Test
454 */
456{
457 public:
459 /**
460 * Constructor
461 *
462 * \param name reference name
463 */
464 SpectrumWifiPhyFilterTest(std::string name);
466
467 private:
468 void DoSetup() override;
469 void DoTeardown() override;
470 void DoRun() override;
471
472 /**
473 * Run one function
474 */
475 void RunOne();
476
477 /**
478 * Send PPDU function
479 */
480 void SendPpdu();
481
482 /**
483 * Callback triggered when a packet is received by the PHYs
484 * \param p the received packet
485 * \param rxPowersW the received power per channel band in watts
486 */
488
491
492 MHz_u m_txChannelWidth; ///< TX channel width
493 MHz_u m_rxChannelWidth; ///< RX channel width
494};
495
497 : TestCase("SpectrumWifiPhy test RX filters"),
498 m_txChannelWidth(20),
499 m_rxChannelWidth(20)
500{
501}
502
507
508void
510{
512 0,
514 NanoSeconds(800),
515 1,
516 1,
517 0,
519 false,
520 false};
521 auto pkt = Create<Packet>(1000);
522 WifiMacHeader hdr;
524 hdr.SetQosTid(0);
525 hdr.SetAddr1(Mac48Address("00:00:00:00:00:01"));
526 hdr.SetSequenceNumber(1);
527 auto psdu = Create<WifiPsdu>(pkt, hdr);
528 m_txPhy->Send(WifiConstPsduMap({std::make_pair(SU_STA_ID, psdu)}), txVector);
529}
530
536
537void
539{
540 for (const auto& [band, powerW] : rxPowersW)
541 {
543 "band: (" << band << ") -> powerW=" << powerW
544 << (powerW > 0.0 ? " (" + std::to_string(WToDbm(powerW)) + " dBm)" : ""));
545 }
546
547 size_t numBands = rxPowersW.size();
548 auto expectedNumBands = std::max<std::size_t>(1, m_rxChannelWidth / 20);
549 expectedNumBands += (m_rxChannelWidth / 40);
550 expectedNumBands += (m_rxChannelWidth / 80);
551 expectedNumBands += (m_rxChannelWidth / 160);
552 expectedNumBands += m_rxPhy
555 m_rxPhy->GetCurrentInterface()->GetChannelWidth()))
556 .size();
557
558 NS_TEST_ASSERT_MSG_EQ(numBands,
559 expectedNumBands,
560 "Total number of bands handled by the receiver is incorrect");
561
562 MHz_u channelWidth = std::min(m_txChannelWidth, m_rxChannelWidth);
563 auto band = m_rxPhy->GetBand(channelWidth, 0);
564 auto it = rxPowersW.find(band);
565 NS_LOG_INFO("powerW total band: " << it->second << " (" << WToDbm(it->second) << " dBm)");
566 int totalRxPower = static_cast<int>(WToDbm(it->second) + 0.5);
567 int expectedTotalRxPower;
569 {
570 // PHY sends at 16 dBm, and since there is no loss, this should be the total power at the
571 // receiver.
572 expectedTotalRxPower = 16;
573 }
574 else
575 {
576 // Only a part of the transmitted power is received
577 expectedTotalRxPower =
578 16 - static_cast<int>(RatioToDb(m_txChannelWidth / m_rxChannelWidth));
579 }
580 NS_TEST_ASSERT_MSG_EQ(totalRxPower,
581 expectedTotalRxPower,
582 "Total received power is not correct");
583
584 if ((m_txChannelWidth <= m_rxChannelWidth) && (channelWidth >= 20))
585 {
586 band = m_rxPhy->GetBand(20, 0); // primary 20 MHz
587 it = rxPowersW.find(band);
588 NS_LOG_INFO("powerW in primary 20 MHz channel: " << it->second << " (" << WToDbm(it->second)
589 << " dBm)");
590 const auto rxPowerPrimaryChannel20 = static_cast<int>(WToDbm(it->second) + 0.5);
591 const auto expectedRxPowerPrimaryChannel20 =
592 16 - static_cast<int>(RatioToDb(channelWidth / 20));
593 NS_TEST_ASSERT_MSG_EQ(rxPowerPrimaryChannel20,
594 expectedRxPowerPrimaryChannel20,
595 "Received power in the primary 20 MHz band is not correct");
596 }
597}
598
599void
601{
602 // WifiHelper::EnableLogComponents();
603 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
604
605 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
607 lossModel->SetFrequency(5.180e9);
608 spectrumChannel->AddPropagationLossModel(lossModel);
610 spectrumChannel->SetPropagationDelayModel(delayModel);
611
612 auto txNode = CreateObject<Node>();
613 auto txDev = CreateObject<WifiNetDevice>();
615 auto txInterferenceHelper = CreateObject<InterferenceHelper>();
616 m_txPhy->SetInterferenceHelper(txInterferenceHelper);
617 auto txErrorModel = CreateObject<NistErrorRateModel>();
618 m_txPhy->SetErrorRateModel(txErrorModel);
619 m_txPhy->SetDevice(txDev);
620 m_txPhy->AddChannel(spectrumChannel);
623 m_txPhy->SetMobility(apMobility);
624 txDev->SetPhy(m_txPhy);
625 txNode->AggregateObject(apMobility);
626 txNode->AddDevice(txDev);
627
628 auto rxNode = CreateObject<Node>();
629 auto rxDev = CreateObject<WifiNetDevice>();
631 auto rxInterferenceHelper = CreateObject<InterferenceHelper>();
632 m_rxPhy->SetInterferenceHelper(rxInterferenceHelper);
633 auto rxErrorModel = CreateObject<NistErrorRateModel>();
634 m_rxPhy->SetErrorRateModel(rxErrorModel);
635 m_rxPhy->AddChannel(spectrumChannel);
638 m_rxPhy->SetMobility(sta1Mobility);
639 rxDev->SetPhy(m_rxPhy);
640 rxNode->AggregateObject(sta1Mobility);
641 rxNode->AddDevice(rxDev);
644}
645
646void
648{
649 m_txPhy->Dispose();
650 m_txPhy = nullptr;
651 m_rxPhy->Dispose();
652 m_rxPhy = nullptr;
653}
654
655void
657{
658 MHz_u txFrequency;
659 switch (static_cast<uint16_t>(m_txChannelWidth))
660 {
661 case 20:
662 default:
663 txFrequency = 5180;
664 break;
665 case 40:
666 txFrequency = 5190;
667 break;
668 case 80:
669 txFrequency = 5210;
670 break;
671 case 160:
672 txFrequency = 5250;
673 break;
674 }
675 auto txChannelNum = WifiPhyOperatingChannel::FindFirst(0,
676 txFrequency,
680 ->number;
683
684 MHz_u rxFrequency;
685 switch (static_cast<uint16_t>(m_rxChannelWidth))
686 {
687 case 20:
688 default:
689 rxFrequency = 5180;
690 break;
691 case 40:
692 rxFrequency = 5190;
693 break;
694 case 80:
695 rxFrequency = 5210;
696 break;
697 case 160:
698 rxFrequency = 5250;
699 break;
700 }
701 auto rxChannelNum = WifiPhyOperatingChannel::FindFirst(0,
702 rxFrequency,
706 ->number;
709
711
713}
714
715void
717{
718 m_txChannelWidth = 20;
719 m_rxChannelWidth = 20;
720 RunOne();
721
722 m_txChannelWidth = 40;
723 m_rxChannelWidth = 40;
724 RunOne();
725
726 m_txChannelWidth = 80;
727 m_rxChannelWidth = 80;
728 RunOne();
729
730 m_txChannelWidth = 160;
731 m_rxChannelWidth = 160;
732 RunOne();
733
734 m_txChannelWidth = 20;
735 m_rxChannelWidth = 40;
736 RunOne();
737
738 m_txChannelWidth = 20;
739 m_rxChannelWidth = 80;
740 RunOne();
741
742 m_txChannelWidth = 40;
743 m_rxChannelWidth = 80;
744 RunOne();
745
746 m_txChannelWidth = 20;
747 m_rxChannelWidth = 160;
748 RunOne();
749
750 m_txChannelWidth = 40;
751 m_rxChannelWidth = 160;
752 RunOne();
753
754 m_txChannelWidth = 80;
755 m_rxChannelWidth = 160;
756 RunOne();
757
758 m_txChannelWidth = 40;
759 m_rxChannelWidth = 20;
760 RunOne();
761
762 m_txChannelWidth = 80;
763 m_rxChannelWidth = 20;
764 RunOne();
765
766 m_txChannelWidth = 80;
767 m_rxChannelWidth = 40;
768 RunOne();
769
770 m_txChannelWidth = 160;
771 m_rxChannelWidth = 20;
772 RunOne();
773
774 m_txChannelWidth = 160;
775 m_rxChannelWidth = 40;
776 RunOne();
777
778 m_txChannelWidth = 160;
779 m_rxChannelWidth = 80;
780 RunOne();
781
783}
784
785/**
786 * \ingroup wifi-test
787 * \ingroup tests
788 *
789 * \brief Spectrum Wifi Phy Bands Calculations Test
790 *
791 * This test verifies SpectrumWifiPhy::GetBand produces the expected results, for both contiguous
792 * (160 MHz) and non-contiguous (80+80MHz) operating channel
793 */
795{
796 public:
798
799 private:
800 void DoSetup() override;
801 void DoTeardown() override;
802 void DoRun() override;
803
804 /**
805 * Run one function
806 * \param channelNumberPerSegment the channel number for each segment of the operating channel
807 * \param bandWidth the width of the band to test
808 * \param bandIndex the index of the band to test
809 * \param expectedIndices the expected start and stop indices returned by
810 * SpectrumWifiPhy::GetBand \param expectedFrequencies the expected start and stop frequencies
811 * returned by SpectrumWifiPhy::GetBand
812 */
813 void RunOne(const std::vector<uint8_t>& channelNumberPerSegment,
814 MHz_u bandWidth,
815 uint8_t bandIndex,
816 const std::vector<WifiSpectrumBandIndices>& expectedIndices,
817 const std::vector<WifiSpectrumBandFrequencies>& expectedFrequencies);
818
820};
821
823 : TestCase("SpectrumWifiPhy test bands calculations")
824{
825}
826
827void
829{
830 // WifiHelper::EnableLogComponents();
831 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
832
833 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
835 lossModel->SetFrequency(5.180e9);
836 spectrumChannel->AddPropagationLossModel(lossModel);
838 spectrumChannel->SetPropagationDelayModel(delayModel);
839
840 auto node = CreateObject<Node>();
841 auto dev = CreateObject<WifiNetDevice>();
843 auto interferenceHelper = CreateObject<InterferenceHelper>();
844 m_phy->SetInterferenceHelper(interferenceHelper);
845 auto errorModel = CreateObject<NistErrorRateModel>();
846 m_phy->SetErrorRateModel(errorModel);
847 m_phy->SetDevice(dev);
848 m_phy->AddChannel(spectrumChannel);
849 m_phy->ConfigureStandard(WIFI_STANDARD_80211ax);
850 dev->SetPhy(m_phy);
851 node->AddDevice(dev);
852}
853
854void
856{
857 m_phy->Dispose();
858 m_phy = nullptr;
859}
860
861void
863 const std::vector<uint8_t>& channelNumberPerSegment,
864 MHz_u bandWidth,
865 uint8_t bandIndex,
866 const std::vector<WifiSpectrumBandIndices>& expectedIndices,
867 const std::vector<WifiSpectrumBandFrequencies>& expectedFrequencies)
868{
869 WifiPhy::ChannelSegments channelSegments;
870 for (auto channelNumber : channelNumberPerSegment)
871 {
872 const auto& channelInfo = WifiPhyOperatingChannel::FindFirst(channelNumber,
873 0,
874 0,
877 channelSegments.emplace_back(channelInfo->number, channelInfo->width, channelInfo->band, 0);
878 }
879 m_phy->SetOperatingChannel(channelSegments);
880
881 const auto& bandInfo = m_phy->GetBand(bandWidth, bandIndex);
882 NS_ASSERT(expectedIndices.size() == expectedFrequencies.size());
883 NS_ASSERT(expectedIndices.size() == bandInfo.indices.size());
884 NS_ASSERT(expectedFrequencies.size() == bandInfo.frequencies.size());
885 for (std::size_t i = 0; i < expectedIndices.size(); ++i)
886 {
887 NS_ASSERT(bandInfo.indices.at(i).first == expectedIndices.at(i).first);
888 NS_TEST_ASSERT_MSG_EQ(bandInfo.indices.at(i).first,
889 expectedIndices.at(i).first,
890 "Incorrect start indice for segment " << i);
891 NS_TEST_ASSERT_MSG_EQ(bandInfo.indices.at(i).second,
892 expectedIndices.at(i).second,
893 "Incorrect stop indice for segment " << i);
894 NS_TEST_ASSERT_MSG_EQ(bandInfo.frequencies.at(i).first,
895 expectedFrequencies.at(i).first,
896 "Incorrect start frequency for segment " << i);
897 NS_TEST_ASSERT_MSG_EQ(bandInfo.frequencies.at(i).second,
898 expectedFrequencies.at(i).second,
899 "Incorrect stop frequency for segment " << i);
900 }
901}
902
903void
905{
906 const uint32_t indicesPer20MhzBand = 256; // based on 802.11ax carrier spacing
907 const MHz_u channelWidth = 160; // we consider the largest channel width
908 const uint8_t channelNumberContiguous160Mhz =
909 50; // channel number of the first 160 MHz band in 5 GHz band
910 const std::vector<uint8_t> channelNumberPerSegment = {42,
911 106}; // channel numbers used for 80+80MHz
912 // separation between segment at channel number 42 and segment at channel number 106
913 const MHz_u separationWidth = 240;
914 for (bool contiguous160Mhz : {true /* 160 MHz */, false /* 80+80MHz */})
915 {
916 MHz_u guardWidth = contiguous160Mhz ? channelWidth : (channelWidth / 2);
917 uint32_t guardStopIndice = (indicesPer20MhzBand * (guardWidth / 20)) - 1;
918 std::vector<WifiSpectrumBandIndices> previousExpectedIndices{};
919 std::vector<WifiSpectrumBandFrequencies> previousExpectedFrequencies{};
920 for (auto bandWidth : {20, 40, 80, 160})
921 {
922 const uint32_t expectedStartIndice = guardStopIndice + 1;
923 const uint32_t expectedStopIndice =
924 expectedStartIndice + (indicesPer20MhzBand * (bandWidth / 20)) - 1;
925 std::vector<WifiSpectrumBandIndices> expectedIndices{
926 {expectedStartIndice, expectedStopIndice}};
927 const Hz_u expectedStartFrequency = 5170 * 1e6;
928 const Hz_u expectedStopFrequency = (5170 + bandWidth) * 1e6;
929 std::vector<WifiSpectrumBandFrequencies> expectedFrequencies{
930 {expectedStartFrequency, expectedStopFrequency}};
931 const std::size_t numBands = (channelWidth / bandWidth);
932 for (std::size_t i = 0; i < numBands; ++i)
933 {
934 if ((bandWidth != channelWidth) && (i >= (numBands / 2)))
935 {
936 // skip DC
937 expectedIndices.at(0).first++;
938 }
939 if ((bandWidth == channelWidth) && !contiguous160Mhz)
940 {
941 // For contiguous 160 MHz, band is made of the two 80 MHz segments (previous run
942 // in the loop)
943 expectedIndices = previousExpectedIndices;
944 expectedFrequencies = previousExpectedFrequencies;
945 }
946 else if ((i == (numBands / 2)) && !contiguous160Mhz)
947 {
948 expectedIndices.at(0).first += (indicesPer20MhzBand * (separationWidth / 20));
949 expectedIndices.at(0).second += (indicesPer20MhzBand * (separationWidth / 20));
950 expectedFrequencies.at(0).first += (separationWidth * 1e6);
951 expectedFrequencies.at(0).second += (separationWidth * 1e6);
952 }
953 RunOne(contiguous160Mhz ? std::vector<uint8_t>{channelNumberContiguous160Mhz}
954 : channelNumberPerSegment,
955 bandWidth,
956 i,
957 expectedIndices,
958 expectedFrequencies);
959 if (!contiguous160Mhz && (bandWidth == (channelWidth / 2)))
960 {
961 previousExpectedIndices.emplace_back(expectedIndices.front());
962 previousExpectedFrequencies.emplace_back(expectedFrequencies.front());
963 }
964 expectedIndices.at(0).first = expectedIndices.at(0).second + 1;
965 expectedIndices.at(0).second =
966 expectedIndices.at(0).first + (indicesPer20MhzBand * (bandWidth / 20)) - 1;
967 expectedFrequencies.at(0).first += (bandWidth * 1e6);
968 expectedFrequencies.at(0).second += (bandWidth * 1e6);
969 }
970 }
971 }
972
974}
975
976/**
977 * \ingroup wifi-test
978 * \ingroup tests
979 *
980 * \brief Test tracked bands in interference helper upon channel switching
981 *
982 * The test is verifying that the correct bands are tracked by the interference helper upon channel
983 * switching. It focuses on 80 and 160 MHz bands while considering 160 MHz operating channels, for
984 * both contiguous and non-contiguous cases.
985 */
987{
988 public:
990
991 private:
992 void DoSetup() override;
993 void DoTeardown() override;
994 void DoRun() override;
995
996 /**
997 * Switch channel function
998 *
999 * \param channelNumberPerSegment the channel number for each segment of the operating channel
1000 * to switch to
1001 */
1002 void SwitchChannel(const std::vector<uint8_t>& channelNumberPerSegment);
1003
1004 /**
1005 * Verify the bands tracked by the interference helper
1006 *
1007 * \param expectedTrackedBands the bands that are expected to be tracked by the interference
1008 * helper
1009 * \param expectedUntrackedBands the bands that are expected to be untracked by the
1010 * interference helper
1011 */
1012 void VerifyTrackedBands(
1013 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedTrackedBands,
1014 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedUntrackedBands);
1015
1016 /**
1017 * Run one function
1018 * \param channelNumberPerSegmentBeforeSwitching the channel number for each segment of the
1019 * operating channel to switch from \param channelNumberPerSegmentAfterSwitching the channel
1020 * number for each segment of the operating channel to switch to \param expectedTrackedBands the
1021 * bands that are expected to be tracked by the interference helper \param expectedUntrackedBand
1022 * the bands that are expected to be untracked by the interference helper
1023 */
1024 void RunOne(const std::vector<uint8_t>& channelNumberPerSegmentBeforeSwitching,
1025 const std::vector<uint8_t>& channelNumberPerSegmentAfterSwitching,
1026 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedTrackedBands,
1027 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedUntrackedBand);
1028
1030};
1031
1033 : TestCase("SpectrumWifiPhy test channel switching for non-contiguous operating channels")
1034{
1035}
1036
1037void
1039{
1040 // WifiHelper::EnableLogComponents();
1041 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
1042
1043 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
1044 auto lossModel = CreateObject<FriisPropagationLossModel>();
1045 lossModel->SetFrequency(5.180e9);
1046 spectrumChannel->AddPropagationLossModel(lossModel);
1048 spectrumChannel->SetPropagationDelayModel(delayModel);
1049
1050 auto node = CreateObject<Node>();
1051 auto dev = CreateObject<WifiNetDevice>();
1053 auto interferenceHelper = CreateObject<ExtInterferenceHelper>();
1054 m_phy->SetInterferenceHelper(interferenceHelper);
1055 auto errorModel = CreateObject<NistErrorRateModel>();
1056 m_phy->SetErrorRateModel(errorModel);
1057 m_phy->SetDevice(dev);
1058 m_phy->AddChannel(spectrumChannel);
1060 dev->SetPhy(m_phy);
1061 node->AddDevice(dev);
1062}
1063
1064void
1070
1071void
1072SpectrumWifiPhyTrackedBandsTest::SwitchChannel(const std::vector<uint8_t>& channelNumberPerSegment)
1073{
1074 NS_LOG_FUNCTION(this);
1075 WifiPhy::ChannelSegments channelSegments;
1076 for (auto channelNumber : channelNumberPerSegment)
1077 {
1078 const auto& channelInfo = WifiPhyOperatingChannel::FindFirst(channelNumber,
1079 0,
1080 0,
1083 channelSegments.emplace_back(channelInfo->number, channelInfo->width, channelInfo->band, 0);
1084 }
1085 m_phy->SetOperatingChannel(channelSegments);
1086}
1087
1088void
1090 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedTrackedBands,
1091 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedUntrackedBands)
1092{
1093 NS_LOG_FUNCTION(this);
1094 PointerValue ptr;
1095 m_phy->GetAttribute("InterferenceHelper", ptr);
1096 auto interferenceHelper = DynamicCast<ExtInterferenceHelper>(ptr.Get<ExtInterferenceHelper>());
1097 NS_ASSERT(interferenceHelper);
1098 auto printBand = [](const std::vector<WifiSpectrumBandFrequencies>& v) {
1099 std::stringstream ss;
1100 for (const auto& [start, stop] : v)
1101 {
1102 ss << "[" << start << "-" << stop << "] ";
1103 }
1104 return ss.str();
1105 };
1106 for (const auto& expectedTrackedBand : expectedTrackedBands)
1107 {
1108 auto bandTracked = interferenceHelper->IsBandTracked(expectedTrackedBand);
1109 NS_TEST_ASSERT_MSG_EQ(bandTracked,
1110 true,
1111 "Band " << printBand(expectedTrackedBand) << " is not tracked");
1112 }
1113 for (const auto& expectedUntrackedBand : expectedUntrackedBands)
1114 {
1115 auto bandTracked = interferenceHelper->IsBandTracked(expectedUntrackedBand);
1116 NS_TEST_ASSERT_MSG_EQ(bandTracked,
1117 false,
1118 "Band " << printBand(expectedUntrackedBand)
1119 << " is unexpectedly tracked");
1120 }
1121}
1122
1123void
1125 const std::vector<uint8_t>& channelNumberPerSegmentBeforeSwitching,
1126 const std::vector<uint8_t>& channelNumberPerSegmentAfterSwitching,
1127 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedTrackedBands,
1128 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedUntrackedBands)
1129{
1130 NS_LOG_FUNCTION(this);
1131
1134 this,
1135 channelNumberPerSegmentBeforeSwitching);
1136
1139 this,
1140 channelNumberPerSegmentAfterSwitching);
1141
1144 this,
1145 expectedTrackedBands,
1146 expectedUntrackedBands);
1147
1149}
1150
1151void
1153{
1154 // switch from 160 MHz to 80+80 MHz
1155 RunOne({50},
1156 {42, 106},
1157 {{{5170 * 1e6, 5250 * 1e6}} /* first 80 MHz segment */,
1158 {{5490 * 1e6, 5570 * 1e6}} /* second 80 MHz segment */,
1159 {{5170 * 1e6, 5250 * 1e6},
1160 {5490 * 1e6, 5570 * 1e6}} /* non-contiguous 160 MHz band made of the two segments */},
1161 {{{5170 * 1e6, 5330 * 1e6}} /* full 160 MHz band should have been removed */});
1162
1163 // switch from 80+80 MHz to 160 MHz
1164 RunOne({42, 106},
1165 {50},
1166 {{{5170 * 1e6, 5330 * 1e6}} /* full 160 MHz band */,
1167 {{5170 * 1e6, 5250 * 1e6}} /* first 80 MHz segment is part of the 160 MHz channel*/},
1168 {{{5490 * 1e6, 5570 * 1e6}} /* second 80 MHz segment should have been removed */,
1169 {{5170 * 1e6, 5250 * 1e6},
1170 {5490 * 1e6, 5570 * 1e6}} /* non-contiguous 160 MHz band should have been removed */});
1171
1172 // switch from 80+80 MHz to 80+80 MHz with segment swap
1173 RunOne({42, 106},
1174 {106, 42},
1175 {{{5490 * 1e6, 5570 * 1e6}} /* first 80 MHz segment */,
1176 {{5490 * 1e6, 5570 * 1e6}} /* second 80 MHz segment */,
1177 {{5170 * 1e6, 5250 * 1e6},
1178 {5490 * 1e6, 5570 * 1e6}} /* non-contiguous 160 MHz band made of the two segments */},
1179 {});
1180
1181 // switch from 80+80 MHz to another 80+80 MHz with one common segment
1182 RunOne({42, 106},
1183 {106, 138},
1184 {{{5490 * 1e6, 5570 * 1e6}} /* first 80 MHz segment */,
1185 {{5650 * 1e6, 5730 * 1e6}} /* second 80 MHz segment */,
1186 {{5490 * 1e6, 5570 * 1e6},
1187 {5650 * 1e6, 5730 * 1e6}} /* non-contiguous 160 MHz band made of the two segments */},
1188 {{{5170 * 1e6, 5250 * 1e6}} /* 80 MHz segment at channel 42 should have been removed */,
1189 {{5170 * 1e6, 5250 * 1e6},
1190 {5490 * 1e6,
1191 5570 * 1e6}} /* previous non-contiguous 160 MHz band should have been removed */});
1192
1193 // switch from 80+80 MHz to another 80+80 MHz with no common segment
1194 RunOne(
1195 {42, 106},
1196 {122, 155},
1197 {{{5570 * 1e6, 5650 * 1e6}} /* first 80 MHz segment */,
1198 {{5735 * 1e6, 5815 * 1e6}} /* second 80 MHz segment */,
1199 {{5570 * 1e6, 5650 * 1e6},
1200 {5735 * 1e6, 5815 * 1e6}} /* non-contiguous 160 MHz band made of the two segments */},
1201 {{{5170 * 1e6, 5250 * 1e6}} /* previous first 80 MHz segment should have been removed */,
1202 {{5490 * 1e6, 5570 * 1e6}} /* previous second 80 MHz segment should have been removed */,
1203 {{5170 * 1e6, 5250 * 1e6},
1204 {5490 * 1e6,
1205 5570 * 1e6}} /* previous non-contiguous 160 MHz band should have been removed */});
1206
1208}
1209
1210/**
1211 * \ingroup wifi-test
1212 * \ingroup tests
1213 *
1214 * \brief Test 80+80MHz transmission
1215 *
1216 * The test verifies that two non-contiguous segments are handled by the spectrum PHY
1217 * to transmit 160 MHz PPDUs when the operating channel is configured as 80+80MHz.
1218 *
1219 * The test first considers a contiguous 160 MHz segment and generate interference on the second
1220 * 80 MHz band to verify reception fails in this scenario. Then, a similar interference
1221 * is generated when a 80+80MHz operating channel is configured, where the first frequency segment
1222 * occupies the first 80 MHz band of the previous 160 MHz operating channel. The reception should
1223 * succeed in that scenario, which demonstrates the second 80 MHz band of the operating channel is
1224 * no longer occupying that spectrum portion (the interference is hence is the gap between the two
1225 * frequency segments). Finally, the test also generates interference on each of the frequency
1226 * segments when the operating channel is 80+80MHz, to demonstrate the frequency segments are
1227 * positioned as expected.
1228 */
1230{
1231 public:
1233
1234 private:
1235 void DoSetup() override;
1236 void DoTeardown() override;
1237 void DoRun() override;
1238
1239 /**
1240 * Run one function
1241 * \param channelNumbers the channel number for each segment of the operating channel
1242 * \param interferenceCenterFrequency the center frequency of the interference signal to
1243 * generate
1244 * \param interferenceBandWidth the band width of the interference signal to generate
1245 * \param expectSuccess flag to indicate whether reception is expected to be successful
1246 */
1247 void RunOne(const std::vector<uint8_t>& channelNumbers,
1248 MHz_u interferenceCenterFrequency,
1249 MHz_u interferenceBandWidth,
1250 bool expectSuccess);
1251
1252 /**
1253 * Switch channel function
1254 *
1255 * \param channelNumbers the channel number for each segment of the operating channel
1256 * to switch to
1257 */
1258 void SwitchChannel(const std::vector<uint8_t>& channelNumbers);
1259
1260 /**
1261 * Send 160MHz PPDU function
1262 */
1263 void Send160MhzPpdu();
1264
1265 /**
1266 * Generate interference function
1267 * \param interferencePsd the PSD of the interference to be generated
1268 * \param duration the duration of the interference
1269 */
1270 void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
1271
1272 /**
1273 * Stop interference function
1274 */
1275 void StopInterference();
1276
1277 /**
1278 * Receive success function for STA
1279 * \param psdu the PSDU
1280 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
1281 * \param txVector the transmit vector
1282 * \param statusPerMpdu reception status per MPDU
1283 */
1285 RxSignalInfo rxSignalInfo,
1286 WifiTxVector txVector,
1287 std::vector<bool> statusPerMpdu);
1288
1289 /**
1290 * Receive failure function for STA
1291 * \param psdu the PSDU
1292 */
1294
1295 /**
1296 * Verify results
1297 *
1298 * \param expectSuccess flag to indicate whether reception is expected to be successful
1299 */
1300 void CheckResults(bool expectSuccess);
1301
1305
1306 uint32_t m_countRxSuccessSta; ///< count RX success for STA
1307 uint32_t m_countRxFailureSta; ///< count RX failure for STA
1308};
1309
1311 : TestCase("SpectrumWifiPhy test 80+80MHz transmission"),
1312 m_countRxSuccessSta(0),
1313 m_countRxFailureSta(0)
1314{
1315}
1316
1317void
1318SpectrumWifiPhy80Plus80Test::SwitchChannel(const std::vector<uint8_t>& channelNumbers)
1319{
1320 NS_LOG_FUNCTION(this);
1321 WifiPhy::ChannelSegments channelSegments;
1322 for (auto channelNumber : channelNumbers)
1323 {
1324 const auto& channelInfo = WifiPhyOperatingChannel::FindFirst(channelNumber,
1325 0,
1326 0,
1329 channelSegments.emplace_back(channelInfo->number, channelInfo->width, channelInfo->band, 0);
1330 }
1331 m_phyAp->SetOperatingChannel(channelSegments);
1332 m_phySta->SetOperatingChannel(channelSegments);
1333}
1334
1335void
1337{
1338 NS_LOG_FUNCTION(this);
1339
1340 WifiTxVector txVector{HePhy::GetHeMcs7(),
1341 0,
1343 NanoSeconds(800),
1344 1,
1345 1,
1346 0,
1347 160,
1348 false,
1349 false,
1350 false};
1351
1352 auto pkt = Create<Packet>(1000);
1353 WifiMacHeader hdr;
1355 auto psdu = Create<WifiPsdu>(pkt, hdr);
1356
1357 m_phyAp->Send(psdu, txVector);
1358}
1359
1360void
1362{
1363 m_phyInterferer->SetTxPowerSpectralDensity(interferencePsd);
1364 m_phyInterferer->SetPeriod(duration);
1365 m_phyInterferer->Start();
1367}
1368
1369void
1374
1375void
1377 RxSignalInfo rxSignalInfo,
1378 WifiTxVector txVector,
1379 std::vector<bool> /*statusPerMpdu*/)
1380{
1381 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
1383}
1384
1385void
1391
1392void
1394{
1395 NS_LOG_FUNCTION(this << expectSuccess);
1397 expectSuccess,
1398 "Reception should be "
1399 << (expectSuccess ? "successful" : "unsuccessful"));
1400}
1401
1402void
1404{
1405 // WifiHelper::EnableLogComponents();
1406 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
1407
1408 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
1409 auto lossModel = CreateObject<FriisPropagationLossModel>();
1410 spectrumChannel->AddPropagationLossModel(lossModel);
1412 spectrumChannel->SetPropagationDelayModel(delayModel);
1413
1414 auto apNode = CreateObject<Node>();
1415 auto apDev = CreateObject<WifiNetDevice>();
1417 auto apInterferenceHelper = CreateObject<InterferenceHelper>();
1418 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
1419 auto apErrorModel = CreateObject<NistErrorRateModel>();
1420 m_phyAp->SetErrorRateModel(apErrorModel);
1421 m_phyAp->SetDevice(apDev);
1422 m_phyAp->AddChannel(spectrumChannel);
1423 m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
1425 m_phyAp->SetMobility(apMobility);
1426 apDev->SetPhy(m_phyAp);
1427 apNode->AggregateObject(apMobility);
1428 apNode->AddDevice(apDev);
1429
1430 auto staNode = CreateObject<Node>();
1431 auto staDev = CreateObject<WifiNetDevice>();
1433 auto staInterferenceHelper = CreateObject<InterferenceHelper>();
1434 m_phySta->SetInterferenceHelper(staInterferenceHelper);
1435 auto staErrorModel = CreateObject<NistErrorRateModel>();
1436 m_phySta->SetErrorRateModel(staErrorModel);
1437 m_phySta->SetDevice(staDev);
1438 m_phySta->AddChannel(spectrumChannel);
1439 m_phySta->ConfigureStandard(WIFI_STANDARD_80211ax);
1441 m_phySta->SetReceiveErrorCallback(
1444 m_phySta->SetMobility(staMobility);
1445 staDev->SetPhy(m_phySta);
1446 staNode->AggregateObject(staMobility);
1447 staNode->AddDevice(staDev);
1448
1449 auto interfererNode = CreateObject<Node>();
1450 auto interfererDev = CreateObject<NonCommunicatingNetDevice>();
1452 m_phyInterferer->SetDevice(interfererDev);
1453 m_phyInterferer->SetChannel(spectrumChannel);
1454 m_phyInterferer->SetDutyCycle(1);
1455 interfererNode->AddDevice(interfererDev);
1456}
1457
1458void
1460{
1461 m_phyAp->Dispose();
1462 m_phyAp = nullptr;
1463 m_phySta->Dispose();
1464 m_phySta = nullptr;
1465 m_phyInterferer->Dispose();
1466 m_phyInterferer = nullptr;
1467}
1468
1469void
1470SpectrumWifiPhy80Plus80Test::RunOne(const std::vector<uint8_t>& channelNumbers,
1471 MHz_u interferenceCenterFrequency,
1472 MHz_u interferenceBandWidth,
1473 bool expectSuccess)
1474{
1475 // reset counters
1478
1481 this,
1482 channelNumbers);
1483
1484 // create info about interference to generate
1485 BandInfo bandInfo{.fl = (interferenceCenterFrequency - (interferenceBandWidth / 2)) * 1e6,
1486 .fc = interferenceCenterFrequency * 1e6,
1487 .fh = (interferenceCenterFrequency + (interferenceBandWidth / 2)) * 1e6};
1488 auto spectrumInterference = Create<SpectrumModel>(Bands{bandInfo});
1489 auto interferencePsd = Create<SpectrumValue>(spectrumInterference);
1490 Watt_u interferencePower{0.1};
1491 *interferencePsd = interferencePower / (interferenceBandWidth * 20e6);
1492
1495 this,
1496 interferencePsd,
1497 MilliSeconds(100));
1498
1500
1503 this,
1504 expectSuccess);
1505
1507}
1508
1509void
1511{
1512 // Test transmission over contiguous 160 MHz (channel 50) and interference generated in
1513 // the second half of the channel width (channel 58, i.e. center frequency 5290 and bandwidth 80
1514 // MHz). The reception should fail because the interference occupies half the channel width used
1515 // for the transmission.
1516 // ┌──────────────────┐
1517 // Interference │ channel 58 │
1518 // │ 5290 MHz, 80 MHz │
1519 // └──────────────────┘
1520 //
1521 // ┌──────────────────────────────────────┐
1522 // Operating Channel │ channel 50 │
1523 // │ 5250 MHz, 160 MHz │
1524 // └──────────────────────────────────────┘
1525 //
1526 RunOne({50}, 5290, 80, false);
1527
1528 // Test transmission over non-contiguous 160 MHz (i.e. 80+80MHz) and same interference as in
1529 // previous run. The reception should succeed because the interference is located between the
1530 // two segments.
1531 // ┌──────────────────┐
1532 // Interference │ channel 58 │
1533 // │ 5290 MHz, 80 MHz │
1534 // └──────────────────┘
1535 //
1536 // ┌──────────────────┐ ┌──────────────────┐
1537 // Operating Channel │ channel 42 │ │ channel 106 │
1538 // │80+80MHz segment 0│ │80+80MHz segment 1│
1539 // └──────────────────┘ └──────────────────┘
1540 //
1541 RunOne({42, 106}, 5290, 80, true);
1542
1543 // Test transmission over non-contiguous 160 MHz (i.e. 80+80MHz) and interference generated on
1544 // the first segment of the channel width (channel 42, i.e. center frequency 5210 and bandwidth
1545 // 80 MHz). The reception should fail because the interference occupies half the channel width
1546 // used for the transmission.
1547 // ┌──────────────────┐
1548 // Interference │ channel 42 │
1549 // │ 5210 MHz, 80 MHz │
1550 // └──────────────────┘
1551 //
1552 // ┌──────────────────┐ ┌──────────────────┐
1553 // Operating Channel │ channel 42 │ │ channel 106 │
1554 // │80+80MHz segment 0│ │80+80MHz segment 1│
1555 // └──────────────────┘ └──────────────────┘
1556 //
1557 RunOne({42, 106}, 5210, 80, false);
1558
1559 // Test transmission over non-contiguous 160 MHz (i.e. 80+80MHz) and interference generated on
1560 // the second segment of the channel width (channel 42, i.e. center frequency 5210 and bandwidth
1561 // 80 MHz). The reception should fail because the interference occupies half the channel width
1562 // used for the transmission.
1563 // ┌──────────────────┐
1564 // Interference │ channel 106 │
1565 // │ 5530 MHz, 80 MHz │
1566 // └──────────────────┘
1567 //
1568 // ┌──────────────────┐ ┌──────────────────┐
1569 // Operating Channel │ channel 42 │ │ channel 106 │
1570 // │80+80MHz segment 0│ │80+80MHz segment 1│
1571 // └──────────────────┘ └──────────────────┘
1572 //
1573 RunOne({42, 106}, 5530, 80, false);
1574
1576}
1577
1578/**
1579 * \ingroup wifi-test
1580 * \ingroup tests
1581 *
1582 * \brief Spectrum Wifi Phy Multiple Spectrum Test
1583 *
1584 * This test is testing the ability to plug multiple spectrum channels to the spectrum wifi PHY.
1585 * It considers 4 TX-RX PHY pairs that are independent from each others and are plugged to different
1586 * spectrum channels that are covering different frequency range. Each RX PHY is also attached to
1587 * each of the other 3 spectrum channels it can switch to.
1588 *
1589 * In the first scenario, we consider the default case where each TX-RX PHY pairs are operating on
1590 * different frequency ranges and hence using independent spectrum channels. We validate that no
1591 * packets is received from other TX PHYs attached to different spectrum channels and we also verify
1592 * the amount of connected PHYs to each spectrum channel is exactly 2. The test also makes sure each
1593 * PHY has only one active spectrum channel and that the active one is operating at the expected
1594 * frequency range.
1595 *
1596 * In the second scenario, we consecutively switch the channel of all RX PHYs to the one of each TX
1597 * PHY. We validate that packets are received by all PHYs and we also verify the amount of connected
1598 * PHYs to each spectrum channels is either 5 (1 TX PHY and 4 RX PHYs) or 1 (the TX PHY left alone).
1599 */
1601{
1602 public:
1603 /// Enumeration for channel switching scenarios
1604 enum class ChannelSwitchScenario : uint8_t
1605 {
1606 BEFORE_TX = 0, //!< start TX after channel switch is completed
1607 BETWEEN_TX_RX //!< perform channel switch during propagation delay (after TX and before RX)
1608 };
1609
1610 /**
1611 * Constructor
1612 *
1613 * \param trackSignalsInactiveInterfaces flag to indicate whether signals coming from inactive
1614 * spectrum PHY interfaces shall be tracked during the test
1615 * \param chanSwitchScenario the channel switching scenario to consider for the test
1616 */
1617 SpectrumWifiPhyMultipleInterfacesTest(bool trackSignalsInactiveInterfaces,
1618 ChannelSwitchScenario chanSwitchScenario);
1619
1620 private:
1621 void DoSetup() override;
1622 void DoTeardown() override;
1623 void DoRun() override;
1624
1625 /**
1626 * Switch channel function
1627 *
1628 * \param phy the PHY to switch
1629 * \param band the PHY band to use
1630 * \param channelNumber number the channel number to use
1631 * \param channelWidth the channel width to use
1632 * \param listenerIndex index of the listener for that PHY, if PHY is a RX PHY
1633 */
1635 WifiPhyBand band,
1636 uint8_t channelNumber,
1637 MHz_u channelWidth,
1638 std::optional<std::size_t> listenerIndex);
1639
1640 /**
1641 * Send PPDU function
1642 *
1643 * \param phy the PHY to transmit the signal
1644 * \param txPower the power to transmit the signal (this is also the received power since we do
1645 * not have propagation loss to simplify) \param payloadSize the payload size in bytes
1646 */
1647 void SendPpdu(Ptr<SpectrumWifiPhy> phy, dBm_u txPower, uint32_t payloadSize);
1648
1649 /**
1650 * Callback triggered when a packet is received by a PHY
1651 * \param index the index to identify the RX PHY
1652 * \param packet the received packet
1653 * \param rxPowersW the received power per channel band in watts
1654 */
1655 void RxCallback(std::size_t index,
1656 Ptr<const Packet> packet,
1657 RxPowerWattPerChannelBand rxPowersW);
1658
1659 /**
1660 * Receive success function
1661 * \param index index of the RX STA
1662 * \param psdu the PSDU
1663 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
1664 * \param txVector the transmit vector
1665 * \param statusPerMpdu reception status per MPDU
1666 */
1667 void RxSuccess(std::size_t index,
1669 RxSignalInfo rxSignalInfo,
1670 WifiTxVector txVector,
1671 std::vector<bool> statusPerMpdu);
1672
1673 /**
1674 * Receive failure function
1675 * \param index index of the RX STA
1676 * \param psdu the PSDU
1677 */
1678 void RxFailure(std::size_t index, Ptr<const WifiPsdu> psdu);
1679
1680 /**
1681 * Schedule now to check the interferences
1682 * \param phy the PHY for which the check has to be executed
1683 * \param freqRange the frequency range for which the check has to be executed
1684 * \param band the band for which the check has to be executed
1685 * \param interferencesExpected flag whether interferences are expected to have been tracked
1686 */
1688 const FrequencyRange& freqRange,
1689 const WifiSpectrumBandInfo& band,
1690 bool interferencesExpected);
1691
1692 /**
1693 * Check the interferences
1694 * \param phy the PHY for which the check has to be executed
1695 * \param band the band for which the check has to be executed
1696 * \param interferencesExpected flag whether interferences are expected to have been tracked
1697 */
1699 const WifiSpectrumBandInfo& band,
1700 bool interferencesExpected);
1701
1702 /**
1703 * Verify results
1704 *
1705 * \param index the index to identify the RX PHY to check
1706 * \param expectedNumRx the expected number of RX events for that PHY
1707 * \param expectedNumRxSuccess the expected amount of successfully received packets
1708 * \param expectedRxBytes the expected amount of received bytes
1709 * \param expectedFrequencyRangeActiveRfInterface the expected frequency range (in MHz) of the
1710 * active RF interface
1711 * \param expectedConnectedPhysPerChannel the expected number of PHYs attached for each spectrum
1712 * channel
1713 */
1714 void CheckResults(std::size_t index,
1715 uint32_t expectedNumRx,
1716 uint32_t expectedNumRxSuccess,
1717 uint32_t expectedRxBytes,
1718 FrequencyRange expectedFrequencyRangeActiveRfInterface,
1719 const std::vector<std::size_t>& expectedConnectedPhysPerChannel);
1720
1721 /**
1722 * Verify CCA indication reported by a given PHY
1723 *
1724 * \param index the index to identify the RX PHY to check
1725 * \param expectedCcaBusyIndication flag to indicate whether a CCA BUSY notification is expected
1726 * \param switchingDelay delay between the TX has started and the time RX switched to the TX
1727 * channel
1728 * \param propagationDelay the propagation delay
1729 */
1730 void CheckCcaIndication(std::size_t index,
1731 bool expectedCcaBusyIndication,
1732 Time switchingDelay,
1733 Time propagationDelay);
1734
1735 /**
1736 * Verify rxing state of the interference helper
1737 *
1738 * \param phy the PHY to which the interference helper instance is attached
1739 * \param rxingExpected flag whether the interference helper is expected to be in rxing state or
1740 * not
1741 */
1742 void CheckRxingState(Ptr<SpectrumWifiPhy> phy, bool rxingExpected);
1743
1744 /**
1745 * Reset function
1746 */
1747 void Reset();
1748
1749 bool
1750 m_trackSignalsInactiveInterfaces; //!< flag to indicate whether signals coming from inactive
1751 //!< spectrum PHY interfaces are tracked during the test
1753 m_chanSwitchScenario; //!< the channel switch scenario to consider for the test
1754 std::vector<Ptr<MultiModelSpectrumChannel>> m_spectrumChannels; //!< Spectrum channels
1755 std::vector<Ptr<SpectrumWifiPhy>> m_txPhys{}; //!< TX PHYs
1756 std::vector<Ptr<SpectrumWifiPhy>> m_rxPhys{}; //!< RX PHYs
1757 std::vector<std::shared_ptr<TestPhyListener>> m_listeners{}; //!< listeners
1758
1759 std::vector<uint32_t> m_counts; //!< count number of packets received by PHYs
1760 std::vector<uint32_t>
1761 m_countRxSuccess; //!< count number of packets successfully received by PHYs
1762 std::vector<uint32_t>
1763 m_countRxFailure; //!< count number of packets unsuccessfully received by PHYs
1764 std::vector<uint32_t> m_rxBytes; //!< count number of received bytes
1765
1766 Time m_lastTxStart{0}; //!< hold the time at which the last transmission started
1767 Time m_lastTxEnd{0}; //!< hold the time at which the last transmission ended
1768};
1769
1771 bool trackSignalsInactiveInterfaces,
1772 ChannelSwitchScenario chanSwitchScenario)
1773 : TestCase{"SpectrumWifiPhy test operation with multiple RF interfaces"},
1774 m_trackSignalsInactiveInterfaces{trackSignalsInactiveInterfaces},
1775 m_chanSwitchScenario{chanSwitchScenario}
1776{
1777}
1778
1779void
1781 WifiPhyBand band,
1782 uint8_t channelNumber,
1783 MHz_u channelWidth,
1784 std::optional<std::size_t> listenerIndex)
1785{
1786 NS_LOG_FUNCTION(this << phy << band << +channelNumber << channelWidth);
1787 if (listenerIndex)
1788 {
1789 auto& listener = m_listeners.at(*listenerIndex);
1790 listener->m_notifyMaybeCcaBusyStart = 0;
1791 listener->m_ccaBusyStart = Seconds(0);
1792 listener->m_ccaBusyEnd = Seconds(0);
1793 }
1794 phy->SetOperatingChannel(WifiPhy::ChannelTuple{channelNumber, channelWidth, band, 0});
1795 // verify rxing state of interference helper is reset after channel switch
1797 this,
1798 phy,
1799 false);
1800}
1801
1802void
1804 dBm_u txPower,
1805 uint32_t payloadSize)
1806{
1807 NS_LOG_FUNCTION(this << phy << txPower << payloadSize << phy->GetCurrentFrequencyRange()
1808 << phy->GetChannelWidth() << phy->GetChannelNumber());
1809
1811 0,
1813 NanoSeconds(800),
1814 1,
1815 1,
1816 0,
1817 20,
1818 false,
1819 false};
1820 Ptr<Packet> pkt = Create<Packet>(payloadSize);
1821 WifiMacHeader hdr;
1823 hdr.SetQosTid(0);
1824 hdr.SetAddr1(Mac48Address("00:00:00:00:00:01"));
1825 hdr.SetSequenceNumber(1);
1826 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1827
1830 txVector,
1831 phy->GetPhyBand());
1832 phy->SetTxPowerStart(txPower);
1833 phy->SetTxPowerEnd(txPower);
1834 phy->Send(WifiConstPsduMap({std::make_pair(SU_STA_ID, psdu)}), txVector);
1835}
1836
1837void
1839 Ptr<const Packet> packet,
1840 RxPowerWattPerChannelBand /*rxPowersW*/)
1841{
1842 auto phy = m_rxPhys.at(index);
1843 const auto payloadBytes = packet->GetSize() - 30;
1844 NS_LOG_FUNCTION(this << index << payloadBytes << phy->GetCurrentFrequencyRange()
1845 << phy->GetChannelWidth() << phy->GetChannelNumber());
1846 m_counts.at(index)++;
1847 m_rxBytes.at(index) += payloadBytes;
1848}
1849
1850void
1853 RxSignalInfo rxSignalInfo,
1854 WifiTxVector txVector,
1855 std::vector<bool> /*statusPerMpdu*/)
1856{
1857 NS_LOG_FUNCTION(this << index << *psdu << rxSignalInfo << txVector);
1858 m_countRxSuccess.at(index)++;
1859}
1860
1861void
1863{
1864 NS_LOG_FUNCTION(this << index << *psdu);
1865 m_countRxFailure.at(index)++;
1866}
1867
1868void
1870 const FrequencyRange& freqRange,
1871 const WifiSpectrumBandInfo& band,
1872 bool interferencesExpected)
1873{
1874 if ((!m_trackSignalsInactiveInterfaces) && (phy->GetCurrentFrequencyRange() != freqRange))
1875 {
1876 // ignore since no bands for that range exists in interference helper in that case
1877 return;
1878 }
1879 // This is needed to make sure PHY state will be checked as the last event if a state change
1880 // occurred at the exact same time as the check
1882 this,
1883 phy,
1884 band,
1885 interferencesExpected);
1886}
1887
1888void
1890 const WifiSpectrumBandInfo& band,
1891 bool interferencesExpected)
1892{
1893 NS_LOG_FUNCTION(this << phy << band << interferencesExpected);
1894 PointerValue ptr;
1895 phy->GetAttribute("InterferenceHelper", ptr);
1896 auto interferenceHelper = DynamicCast<InterferenceHelper>(ptr.Get<InterferenceHelper>());
1897 NS_ASSERT(interferenceHelper);
1898 const auto energyDuration = interferenceHelper->GetEnergyDuration(0, band);
1899 NS_TEST_ASSERT_MSG_EQ(energyDuration.IsStrictlyPositive(),
1900 interferencesExpected,
1901 "Incorrect interferences detection");
1902}
1903
1904void
1906 std::size_t index,
1907 uint32_t expectedNumRx,
1908 uint32_t expectedNumRxSuccess,
1909 uint32_t expectedRxBytes,
1910 FrequencyRange expectedFrequencyRangeActiveRfInterface,
1911 const std::vector<std::size_t>& expectedConnectedPhysPerChannel)
1912{
1913 NS_LOG_FUNCTION(this << index << expectedNumRx << expectedNumRxSuccess << expectedRxBytes
1914 << expectedFrequencyRangeActiveRfInterface);
1915 const auto phy = m_rxPhys.at(index);
1916 std::size_t numActiveInterfaces = 0;
1917 for (const auto& [freqRange, interface] : phy->GetSpectrumPhyInterfaces())
1918 {
1919 const auto expectedActive = (freqRange == expectedFrequencyRangeActiveRfInterface);
1920 const auto isActive = (interface == phy->GetCurrentInterface());
1921 NS_TEST_ASSERT_MSG_EQ(isActive, expectedActive, "Incorrect active interface");
1922 if (isActive)
1923 {
1924 numActiveInterfaces++;
1925 }
1926 }
1927 NS_TEST_ASSERT_MSG_EQ(numActiveInterfaces, 1, "There should always be one active interface");
1928 NS_ASSERT(expectedConnectedPhysPerChannel.size() == m_spectrumChannels.size());
1929 for (std::size_t i = 0; i < m_spectrumChannels.size(); ++i)
1930 {
1931 NS_TEST_ASSERT_MSG_EQ(m_spectrumChannels.at(i)->GetNDevices(),
1932 expectedConnectedPhysPerChannel.at(i),
1933 "Incorrect number of PHYs attached to the spectrum channel");
1934 }
1935 NS_TEST_ASSERT_MSG_EQ(m_counts.at(index), expectedNumRx, "Unexpected amount of RX events");
1937 expectedNumRxSuccess,
1938 "Unexpected amount of successfully received packets");
1940 0,
1941 "Unexpected amount of unsuccessfully received packets");
1942 NS_TEST_ASSERT_MSG_EQ(m_listeners.at(index)->m_notifyRxStart,
1943 expectedNumRxSuccess,
1944 "Unexpected amount of RX payload start indication");
1945}
1946
1947void
1949 bool expectedCcaBusyIndication,
1950 Time switchingDelay,
1951 Time propagationDelay)
1952{
1953 const auto expectedCcaBusyStart =
1954 expectedCcaBusyIndication ? m_lastTxStart + switchingDelay : Seconds(0);
1955 const auto expectedCcaBusyEnd =
1956 expectedCcaBusyIndication ? m_lastTxEnd + propagationDelay : Seconds(0);
1957 NS_LOG_FUNCTION(this << index << expectedCcaBusyIndication << expectedCcaBusyStart
1958 << expectedCcaBusyEnd);
1959 auto& listener = m_listeners.at(index);
1960 const auto ccaBusyIndication = (listener->m_notifyMaybeCcaBusyStart > 0);
1961 const auto ccaBusyStart = listener->m_ccaBusyStart;
1962 const auto ccaBusyEnd = listener->m_ccaBusyEnd;
1963 NS_TEST_ASSERT_MSG_EQ(ccaBusyIndication,
1964 expectedCcaBusyIndication,
1965 "CCA busy indication check failed");
1966 NS_TEST_ASSERT_MSG_EQ(ccaBusyStart, expectedCcaBusyStart, "CCA busy start mismatch");
1967 NS_TEST_ASSERT_MSG_EQ(ccaBusyEnd, expectedCcaBusyEnd, "CCA busy end mismatch");
1968}
1969
1970void
1972{
1973 NS_LOG_FUNCTION(this << phy << rxingExpected);
1974 PointerValue ptr;
1975 phy->GetAttribute("InterferenceHelper", ptr);
1976 auto interferenceHelper = DynamicCast<ExtInterferenceHelper>(ptr.Get<ExtInterferenceHelper>());
1977 NS_ASSERT(interferenceHelper);
1978 NS_TEST_ASSERT_MSG_EQ(interferenceHelper->IsRxing(), rxingExpected, "Incorrect rxing state");
1979}
1980
1981void
1983{
1984 NS_LOG_FUNCTION(this);
1985 for (auto& count : m_counts)
1986 {
1987 count = 0;
1988 }
1989 for (auto& listener : m_listeners)
1990 {
1991 listener->Reset();
1992 }
1993 // restore all RX PHYs to initial channels
1994 for (std::size_t rxPhyIndex = 0; rxPhyIndex < m_rxPhys.size(); ++rxPhyIndex)
1995 {
1996 auto txPhy = m_txPhys.at(rxPhyIndex);
1997 SwitchChannel(m_rxPhys.at(rxPhyIndex),
1998 txPhy->GetPhyBand(),
1999 txPhy->GetChannelNumber(),
2000 txPhy->GetChannelWidth(),
2001 rxPhyIndex);
2002 }
2003 // reset counters
2004 for (auto& countRxSuccess : m_countRxSuccess)
2005 {
2006 countRxSuccess = 0;
2007 }
2008 for (auto& countRxFailure : m_countRxFailure)
2009 {
2010 countRxFailure = 0;
2011 }
2012 for (auto& rxBytes : m_rxBytes)
2013 {
2014 rxBytes = 0;
2015 }
2016}
2017
2018void
2020{
2021 NS_LOG_FUNCTION(this);
2022
2023 // WifiHelper::EnableLogComponents();
2024 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
2025
2026 NodeContainer wifiApNode(1);
2027 NodeContainer wifiStaNode(1);
2028
2029 WifiHelper wifi;
2030 wifi.SetStandard(WIFI_STANDARD_80211be);
2031
2032 SpectrumWifiPhyHelper phyHelper(4);
2033 phyHelper.SetInterferenceHelper("ns3::ExtInterferenceHelper");
2035
2036 struct SpectrumPhyInterfaceInfo
2037 {
2038 FrequencyRange range; ///< frequency range covered by the interface
2039 uint8_t number; ///< channel number the interface operates on
2040 WifiPhyBand band; ///< PHY band the interface operates on
2041 std::string bandName; ///< name of the PHY band the interface operates on
2042 };
2043
2044 const FrequencyRange WIFI_SPECTRUM_5_GHZ_LOW{
2048 const FrequencyRange WIFI_SPECTRUM_5_GHZ_HIGH{
2052
2053 const std::vector<SpectrumPhyInterfaceInfo> interfaces{
2054 {WIFI_SPECTRUM_2_4_GHZ, 2, WIFI_PHY_BAND_2_4GHZ, "BAND_2_4GHZ"},
2055 {WIFI_SPECTRUM_5_GHZ_LOW, 42, WIFI_PHY_BAND_5GHZ, "BAND_5GHZ"},
2056 {WIFI_SPECTRUM_5_GHZ_HIGH, 163, WIFI_PHY_BAND_5GHZ, "BAND_5GHZ"},
2057 {WIFI_SPECTRUM_6_GHZ, 215, WIFI_PHY_BAND_6GHZ, "BAND_6GHZ"}};
2058
2059 for (std::size_t i = 0; i < interfaces.size(); ++i)
2060 {
2061 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
2063 spectrumChannel->SetPropagationDelayModel(delayModel);
2064 std::ostringstream oss;
2065 oss << "{" << +interfaces.at(i).number << ", 0, " << interfaces.at(i).bandName << ", 0}";
2066 phyHelper.Set(i, "ChannelSettings", StringValue(oss.str()));
2067 phyHelper.AddChannel(spectrumChannel, interfaces.at(i).range);
2068 m_spectrumChannels.emplace_back(spectrumChannel);
2069 }
2070
2071 WifiMacHelper mac;
2072 mac.SetType("ns3::ApWifiMac", "BeaconGeneration", BooleanValue(false));
2073 phyHelper.Set("TrackSignalsFromInactiveInterfaces", BooleanValue(false));
2074 auto apDevice = wifi.Install(phyHelper, mac, wifiApNode.Get(0));
2075
2076 mac.SetType("ns3::StaWifiMac", "ActiveProbing", BooleanValue(false));
2077 phyHelper.Set("TrackSignalsFromInactiveInterfaces",
2079 auto staDevice = wifi.Install(phyHelper, mac, wifiStaNode.Get(0));
2080
2081 MobilityHelper mobility;
2082 auto positionAlloc = CreateObject<ListPositionAllocator>();
2083
2084 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
2085 positionAlloc->Add(Vector(10.0, 0.0, 0.0));
2086 mobility.SetPositionAllocator(positionAlloc);
2087
2088 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
2089 mobility.Install(wifiApNode);
2090 mobility.Install(wifiStaNode);
2091
2092 for (std::size_t i = 0; i < interfaces.size(); ++i)
2093 {
2094 auto txPhy =
2095 DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(apDevice.Get(0))->GetPhy(i));
2097 {
2098 txPhy->SetAttribute("ChannelSwitchDelay", TimeValue(NanoSeconds(1)));
2099 }
2100 m_txPhys.push_back(txPhy);
2101
2102 const auto index = m_rxPhys.size();
2103 auto rxPhy =
2104 DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(staDevice.Get(0))->GetPhy(i));
2106 {
2107 rxPhy->SetAttribute("ChannelSwitchDelay", TimeValue(NanoSeconds(1)));
2108 }
2109 rxPhy->TraceConnectWithoutContext(
2110 "PhyRxBegin",
2112
2113 rxPhy->SetReceiveOkCallback(
2115 rxPhy->SetReceiveErrorCallback(
2117
2118 auto listener = std::make_shared<TestPhyListener>();
2119 rxPhy->RegisterListener(listener);
2120 m_listeners.push_back(std::move(listener));
2121
2122 m_rxPhys.push_back(rxPhy);
2123 m_counts.push_back(0);
2124 m_countRxSuccess.push_back(0);
2125 m_countRxFailure.push_back(0);
2126 m_rxBytes.push_back(0);
2127 }
2128}
2129
2130void
2132{
2133 NS_LOG_FUNCTION(this);
2134 for (auto& phy : m_txPhys)
2135 {
2136 phy->Dispose();
2137 phy = nullptr;
2138 }
2139 for (auto& phy : m_rxPhys)
2140 {
2141 phy->Dispose();
2142 phy = nullptr;
2143 }
2145}
2146
2147void
2149{
2150 NS_LOG_FUNCTION(this);
2151
2152 const dBm_u ccaEdThreshold = -62.0; ///< CCA-ED threshold
2153 const auto txAfterChannelSwitchDelay =
2155 ? 250
2156 : 0); ///< delay in seconds between channel switch is triggered and a
2157 ///< transmission gets started
2158 const auto checkResultsDelay =
2159 Seconds(0.5); ///< delay in seconds between start of test and moment results are verified
2160 const auto flushResultsDelay =
2161 Seconds(0.9); ///< delay in seconds between start of test and moment results are flushed
2162 const auto txOngoingAfterTxStartedDelay =
2163 MicroSeconds(50); ///< delay in microseconds between a transmission has started and a point
2164 ///< in time the transmission is ongoing
2165 const auto propagationDelay = NanoSeconds(33); // propagation delay for the test scenario
2166
2167 Time delay{0};
2168
2169 // default channels active for all PHYs: each PHY only receives from its associated TX
2170 std::vector<std::size_t> expectedConnectedPhysPerChannel =
2171 m_trackSignalsInactiveInterfaces ? std::vector<std::size_t>{5, 5, 5, 5}
2172 : // all RX PHYs keep all channels active when tracking
2173 // interferences on inactive interfaces
2174 std::vector<std::size_t>{2, 2, 2, 2}; // default channels active for all PHYs: each PHY
2175 // only receives from its associated TX
2176
2177 for (std::size_t i = 0; i < 4; ++i)
2178 {
2179 auto txPpduPhy = m_txPhys.at(i);
2180 delay += Seconds(1);
2181 Simulator::Schedule(delay,
2183 this,
2184 txPpduPhy,
2185 0,
2186 1000);
2187 for (std::size_t j = 0; j < 4; ++j)
2188 {
2189 auto txPhy = m_txPhys.at(j);
2190 auto rxPhy = m_rxPhys.at(j);
2191 const auto& expectedFreqRange = txPhy->GetCurrentFrequencyRange();
2192 Simulator::Schedule(delay + txOngoingAfterTxStartedDelay,
2194 this,
2195 rxPhy,
2196 txPpduPhy->GetCurrentFrequencyRange(),
2197 txPpduPhy->GetBand(txPpduPhy->GetChannelWidth(), 0),
2198 true);
2199 Simulator::Schedule(delay + checkResultsDelay,
2201 this,
2202 j,
2203 (i == j) ? 1 : 0,
2204 (i == j) ? 1 : 0,
2205 (i == j) ? 1000 : 0,
2206 expectedFreqRange,
2207 expectedConnectedPhysPerChannel);
2208 }
2209 Simulator::Schedule(delay + flushResultsDelay,
2211 this);
2212 }
2213
2214 // same channel active for all PHYs: all PHYs receive from TX
2215 for (std::size_t i = 0; i < 4; ++i)
2216 {
2217 delay += Seconds(1);
2218 auto txPpduPhy = m_txPhys.at(i);
2219 Simulator::Schedule(delay + txAfterChannelSwitchDelay,
2221 this,
2222 txPpduPhy,
2223 0,
2224 1000);
2225 const auto& expectedFreqRange = txPpduPhy->GetCurrentFrequencyRange();
2226 for (std::size_t j = 0; j < 4; ++j)
2227 {
2229 {
2230 for (std::size_t k = 0; k < expectedConnectedPhysPerChannel.size(); ++k)
2231 {
2232 expectedConnectedPhysPerChannel.at(k) = (k == i) ? 5 : 1;
2233 }
2234 }
2235 auto rxPhy = m_rxPhys.at(j);
2236 Simulator::Schedule(delay,
2238 this,
2239 rxPhy,
2240 txPpduPhy->GetPhyBand(),
2241 txPpduPhy->GetChannelNumber(),
2242 txPpduPhy->GetChannelWidth(),
2243 j);
2244 Simulator::Schedule(delay + txAfterChannelSwitchDelay + txOngoingAfterTxStartedDelay,
2246 this,
2247 rxPhy,
2248 txPpduPhy->GetCurrentFrequencyRange(),
2249 txPpduPhy->GetBand(txPpduPhy->GetChannelWidth(), 0),
2250 true);
2251 Simulator::Schedule(delay + checkResultsDelay,
2253 this,
2254 j,
2255 1,
2256 1,
2257 1000,
2258 expectedFreqRange,
2259 expectedConnectedPhysPerChannel);
2260 }
2261 Simulator::Schedule(delay + flushResultsDelay,
2263 this);
2264 }
2265
2266 // Switch all PHYs to channel 36: all PHYs switch to the second spectrum channel
2267 // since second spectrum channel is 42 (80 MHz) and hence covers channel 36 (20 MHz)
2268 const auto secondSpectrumChannelIndex = 1;
2269 auto channel36TxPhy = m_txPhys.at(secondSpectrumChannelIndex);
2270 const auto& expectedFreqRange = channel36TxPhy->GetCurrentFrequencyRange();
2271 for (std::size_t i = 0; i < 4; ++i)
2272 {
2273 delay += Seconds(1);
2274 auto txPpduPhy = m_txPhys.at(i);
2275 Simulator::Schedule(delay + txAfterChannelSwitchDelay,
2277 this,
2278 txPpduPhy,
2279 0,
2280 1000);
2281 for (std::size_t j = 0; j < 4; ++j)
2282 {
2284 {
2285 for (std::size_t k = 0; k < expectedConnectedPhysPerChannel.size(); ++k)
2286 {
2287 expectedConnectedPhysPerChannel.at(k) =
2288 (k == secondSpectrumChannelIndex) ? 5 : 1;
2289 }
2290 }
2291 Simulator::Schedule(delay,
2293 this,
2294 m_rxPhys.at(j),
2298 j);
2299 Simulator::Schedule(delay + checkResultsDelay,
2301 this,
2302 j,
2303 (i == secondSpectrumChannelIndex) ? 1 : 0,
2304 (i == secondSpectrumChannelIndex) ? 1 : 0,
2305 (i == secondSpectrumChannelIndex) ? 1000 : 0,
2306 expectedFreqRange,
2307 expectedConnectedPhysPerChannel);
2308 }
2309 Simulator::Schedule(delay + flushResultsDelay,
2311 this);
2312 }
2313
2314 // verify CCA indication when switching to a channel with an ongoing transmission
2315 for (const dBm_u txPower : {-60.0 /* above CCA-ED */, -70.0 /* below CCA-ED */})
2316 {
2317 for (std::size_t i = 0; i < 4; ++i)
2318 {
2319 for (std::size_t j = 0; j < 4; ++j)
2320 {
2321 auto txPpduPhy = m_txPhys.at(i);
2322 const auto startChannel =
2323 WifiPhyOperatingChannel::FindFirst(txPpduPhy->GetPrimaryChannelNumber(20),
2324 0,
2325 20,
2327 txPpduPhy->GetPhyBand());
2328 for (auto bw = txPpduPhy->GetChannelWidth(); bw >= 20; bw /= 2)
2329 {
2330 const auto& channelInfo =
2332 0,
2333 bw,
2335 txPpduPhy->GetPhyBand(),
2336 startChannel));
2337 delay += Seconds(1);
2338 Simulator::Schedule(delay,
2340 this,
2341 txPpduPhy,
2342 txPower,
2343 1000);
2344 Simulator::Schedule(delay + txOngoingAfterTxStartedDelay,
2346 this,
2347 m_rxPhys.at(j),
2348 channelInfo.band,
2349 channelInfo.number,
2350 channelInfo.width,
2351 j);
2352 for (std::size_t k = 0; k < 4; ++k)
2353 {
2354 if ((i != j) && (k == i))
2355 {
2356 continue;
2357 }
2358 const auto expectCcaBusyIndication =
2359 (k == i) ? (txPower >= ccaEdThreshold)
2361 ? ((txPower >= ccaEdThreshold) ? (j == k) : false)
2362 : false);
2364 delay + checkResultsDelay,
2366 this,
2367 k,
2368 expectCcaBusyIndication,
2369 txOngoingAfterTxStartedDelay,
2370 propagationDelay);
2371 }
2372 Simulator::Schedule(delay + flushResultsDelay,
2374 this);
2375 }
2376 }
2377 }
2378 }
2379
2381 {
2382 /* Reproduce an EMLSR scenario where a PHY is on an initial band and receives a packet.
2383 * Then, the PHY switches to another band where it starts receiving another packet.
2384 * During reception of the PHY header, the PHY switches back to the initial band and starts
2385 * receiving yet another packet. In this case, first and last packets should be successfully
2386 * received (no interference), the second packet reception has been interrupted (before the
2387 * payload reception does start, hence it does not reach the RX state). */
2388 {
2389 // first TX on initial band
2390 auto txPpduPhy = m_txPhys.at(0);
2391 delay += Seconds(1);
2392 Simulator::Schedule(delay,
2394 this,
2395 txPpduPhy,
2396 20,
2397 500);
2398
2399 // switch channel to other band
2400 delay += Seconds(1);
2401 txPpduPhy = m_txPhys.at(1);
2402 Simulator::Schedule(delay,
2404 this,
2405 m_rxPhys.at(0),
2406 txPpduPhy->GetPhyBand(),
2407 txPpduPhy->GetChannelNumber(),
2408 txPpduPhy->GetChannelWidth(),
2409 0);
2410
2411 // TX on other band
2412 delay += Seconds(1);
2413 Simulator::Schedule(delay,
2415 this,
2416 txPpduPhy,
2417 0,
2418 1000);
2419
2420 // switch back to initial band during PHY header reception
2421 txPpduPhy = m_txPhys.at(0);
2422 delay += MicroSeconds(20); // right after legacy PHY header reception
2423 Simulator::Schedule(delay,
2425 this,
2426 m_rxPhys.at(0),
2427 txPpduPhy->GetPhyBand(),
2428 txPpduPhy->GetChannelNumber(),
2429 txPpduPhy->GetChannelWidth(),
2430 0);
2431
2432 // TX once more on the initial band
2433 delay += Seconds(1);
2434 Simulator::Schedule(delay,
2436 this,
2437 txPpduPhy,
2438 0,
2439 1500);
2440
2441 // check results
2443 delay + checkResultsDelay,
2445 this,
2446 0,
2447 3, // 3 RX events
2448 2, // 2 packets should have been successfully received, 1 packet should
2449 // have been interrupted (switch during PHY header reception)
2450 2000, // 500 bytes (firstpacket) and 1500 bytes (third packet)
2451 txPpduPhy->GetCurrentFrequencyRange(),
2452 expectedConnectedPhysPerChannel);
2453
2454 // reset
2455 Simulator::Schedule(delay + flushResultsDelay,
2457 this);
2458 }
2459
2460 /* Reproduce an EMLSR scenario where a PHY is on an initial band and receives a packet
2461 * but switches to another band during preamble detection period. Then, it starts receiving
2462 * two packets which interfere with each other. Afterwards, the PHY goes back to its initial
2463 * band and starts receiving yet another packet. In this case, only the last packet should
2464 * be successfully received (no interference). */
2465 {
2466 // switch channel of PHY index 0 to 5 GHz low band (operating channel of TX PHY index 1)
2467 auto txPpduPhy = m_txPhys.at(1);
2468 delay += Seconds(1);
2469 Simulator::Schedule(delay,
2471 this,
2472 m_rxPhys.at(0),
2473 txPpduPhy->GetPhyBand(),
2474 txPpduPhy->GetChannelNumber(),
2475 txPpduPhy->GetChannelWidth(),
2476 0);
2477
2478 // start transmission on 5 GHz low band
2479 delay += Seconds(1);
2480 Simulator::Schedule(delay,
2482 this,
2483 txPpduPhy,
2484 20,
2485 500);
2486
2487 // switch channel back to previous channel before preamble detection is finished:
2488 // this is needed to verify interference helper rxing state is properly reset
2489 // since ongoing reception is aborted when switching operating channel
2492 this,
2493 m_rxPhys.at(0),
2494 m_txPhys.at(0)->GetPhyBand(),
2495 m_txPhys.at(0)->GetChannelNumber(),
2496 m_txPhys.at(0)->GetChannelWidth(),
2497 0);
2498
2499 delay += Seconds(1);
2500 // we need 2 TX PHYs on the 5 GHz low band to have simultaneous transmissions
2501 // switch operating channel of TX PHY index 2 to the 5 GHz low band
2502 Simulator::Schedule(delay,
2504 this,
2505 m_txPhys.at(2),
2506 txPpduPhy->GetPhyBand(),
2507 txPpduPhy->GetChannelNumber(),
2508 txPpduPhy->GetChannelWidth(),
2509 std::nullopt);
2510
2511 // first transmission on 5 GHz low band with high power
2512 delay += Seconds(1);
2513 Simulator::Schedule(delay,
2515 this,
2516 txPpduPhy,
2517 20,
2518 1000);
2519
2520 // second transmission on 5 GHz low band with high power a bit later:
2521 // first powers get updated updated in the corresponding bands
2522 txPpduPhy = m_txPhys.at(2);
2523 Simulator::Schedule(delay + NanoSeconds(10),
2525 this,
2526 txPpduPhy,
2527 20,
2528 1000);
2529
2530 // restore channel for TX PHY index 2
2531 delay += Seconds(1);
2532 Simulator::Schedule(delay,
2534 this,
2535 m_txPhys.at(2),
2536 m_rxPhys.at(2)->GetPhyBand(),
2537 m_rxPhys.at(2)->GetChannelNumber(),
2538 m_rxPhys.at(2)->GetChannelWidth(),
2539 std::nullopt);
2540
2541 // switch channel of PHY index 0 to 5 GHz low band again
2542 delay += Seconds(1);
2543 txPpduPhy = m_txPhys.at(1);
2544 Simulator::Schedule(delay,
2546 this,
2547 m_rxPhys.at(0),
2548 txPpduPhy->GetPhyBand(),
2549 txPpduPhy->GetChannelNumber(),
2550 txPpduPhy->GetChannelWidth(),
2551 0);
2552
2553 // transmit PPDU on 5 GHz low band (no interference)
2554 delay += Seconds(1);
2555 Simulator::Schedule(delay,
2557 this,
2558 txPpduPhy,
2559 0,
2560 1500);
2561
2562 // check results
2563 Simulator::Schedule(delay + checkResultsDelay,
2565 this,
2566 0,
2567 1, // 1 RX event
2568 1, // last transmitted packet should have been successfully received
2569 1500, // 1500 bytes (payload of last transmitted packet)
2570 txPpduPhy->GetCurrentFrequencyRange(),
2571 expectedConnectedPhysPerChannel);
2572
2573 // reset
2574 Simulator::Schedule(delay + flushResultsDelay,
2576 this);
2577 }
2578 }
2579
2580 delay += Seconds(1);
2581 Simulator::Stop(delay);
2583}
2584
2585/**
2586 * \ingroup wifi-test
2587 * \ingroup tests
2588 *
2589 * \brief Spectrum Wifi Phy Interfaces Helper Test
2590 *
2591 * This test checks the expected interfaces are added to the spectrum PHY instances
2592 * created by the helper.
2593 */
2595{
2596 public:
2599
2600 private:
2601 void DoRun() override;
2602};
2603
2605 : TestCase("Check PHY interfaces added to PHY instances using helper")
2606{
2607}
2608
2609void
2611{
2612 WifiHelper wifiHelper;
2614
2615 SpectrumWifiPhyHelper phyHelper(3);
2616 phyHelper.Set(0, "ChannelSettings", StringValue("{2, 0, BAND_2_4GHZ, 0}"));
2617 phyHelper.Set(1, "ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}"));
2618 phyHelper.Set(2, "ChannelSettings", StringValue("{1, 0, BAND_6GHZ, 0}"));
2619
2623
2624 WifiMacHelper macHelper;
2626
2627 /* Default case: all interfaces are added to each link */
2628 auto device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(0));
2629
2630 // Verify each PHY has 3 interfaces
2631 auto phyLink0 =
2633 NS_ASSERT(phyLink0);
2634 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
2635 3,
2636 "Incorrect number of PHY interfaces added to PHY link ID 0");
2637
2638 auto phyLink1 =
2640 NS_ASSERT(phyLink1);
2641 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
2642 3,
2643 "Incorrect number of PHY interfaces added to PHY link ID 1");
2644
2645 auto phyLink2 =
2647 NS_ASSERT(phyLink2);
2648 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
2649 3,
2650 "Incorrect number of PHY interfaces added to PHY link ID 2");
2651
2652 /* each PHY has a single interface */
2656 device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(1));
2657
2658 // Verify each PHY has a single interface
2659 phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
2660 NS_ASSERT(phyLink0);
2661 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
2662 1,
2663 "Incorrect number of PHY interfaces added to PHY link ID 0");
2664 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
2665 1,
2666 "Incorrect PHY interfaces added to PHY link ID 0");
2667
2668 phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
2669 NS_ASSERT(phyLink1);
2670 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
2671 1,
2672 "Incorrect number of PHY interfaces added to PHY link ID 1");
2673 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2674 1,
2675 "Incorrect PHY interfaces added to PHY link ID 1");
2676
2677 phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
2678 NS_ASSERT(phyLink2);
2679 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
2680 1,
2681 "Incorrect number of PHY interfaces added to PHY link ID 2");
2682 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
2683 1,
2684 "Incorrect PHY interfaces added to PHY link ID 2");
2685
2686 /* add yet another interface to PHY 0 */
2688 device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(2));
2689
2690 // Verify each PHY has a single interface except PHY 0 that should have 2 interfaces
2691 phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
2692 NS_ASSERT(phyLink0);
2693 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
2694 2,
2695 "Incorrect number of PHY interfaces added to PHY link ID 0");
2696 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
2697 1,
2698 "Incorrect PHY interfaces added to PHY link ID 0");
2699 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2700 1,
2701 "Incorrect PHY interfaces added to PHY link ID 0");
2702
2703 phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
2704 NS_ASSERT(phyLink1);
2705 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
2706 1,
2707 "Incorrect number of PHY interfaces added to PHY link ID 1");
2708 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2709 1,
2710 "Incorrect PHY interfaces added to PHY link ID 1");
2711
2712 phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
2713 NS_ASSERT(phyLink2);
2714 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
2715 1,
2716 "Incorrect number of PHY interfaces added to PHY link ID 2");
2717 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
2718 1,
2719 "Incorrect PHY interfaces added to PHY link ID 2");
2720
2721 /* reset mapping previously configured to helper: back to default */
2722 phyHelper.ResetPhyToFreqRangeMapping();
2723 device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(3));
2724
2725 // Verify each PHY has 3 interfaces
2726 phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
2727 NS_ASSERT(phyLink0);
2728 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
2729 3,
2730 "Incorrect number of PHY interfaces added to PHY link ID 0");
2731 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
2732 1,
2733 "Incorrect PHY interfaces added to PHY link ID 0");
2734 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2735 1,
2736 "Incorrect PHY interfaces added to PHY link ID 0");
2737 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
2738 1,
2739 "Incorrect PHY interfaces added to PHY link ID 0");
2740
2741 phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
2742 NS_ASSERT(phyLink1);
2743 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
2744 3,
2745 "Incorrect number of PHY interfaces added to PHY link ID 1");
2746 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
2747 1,
2748 "Incorrect PHY interfaces added to PHY link ID 0");
2749 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2750 1,
2751 "Incorrect PHY interfaces added to PHY link ID 0");
2752 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
2753 1,
2754 "Incorrect PHY interfaces added to PHY link ID 0");
2755
2756 phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
2757 NS_ASSERT(phyLink2);
2758 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
2759 3,
2760 "Incorrect number of PHY interfaces added to PHY link ID 2");
2761 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
2762 1,
2763 "Incorrect PHY interfaces added to PHY link ID 0");
2764 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2765 1,
2766 "Incorrect PHY interfaces added to PHY link ID 0");
2767 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
2768 1,
2769 "Incorrect PHY interfaces added to PHY link ID 0");
2770
2772}
2773
2774/**
2775 * \ingroup wifi-test
2776 * \ingroup tests
2777 *
2778 * \brief Spectrum Wifi Phy Test Suite
2779 */
2781{
2782 public:
2784};
2785
2787 : TestSuite("wifi-spectrum-phy", Type::UNIT)
2788{
2789 AddTestCase(new SpectrumWifiPhyBasicTest, TestCase::Duration::QUICK);
2790 AddTestCase(new SpectrumWifiPhyListenerTest, TestCase::Duration::QUICK);
2791 AddTestCase(new SpectrumWifiPhyFilterTest, TestCase::Duration::QUICK);
2792 AddTestCase(new SpectrumWifiPhyGetBandTest, TestCase::Duration::QUICK);
2793 AddTestCase(new SpectrumWifiPhyTrackedBandsTest, TestCase::Duration::QUICK);
2794 AddTestCase(new SpectrumWifiPhy80Plus80Test, TestCase::Duration::QUICK);
2796 false,
2798 TestCase::Duration::QUICK);
2800 true,
2802 TestCase::Duration::QUICK);
2804 true,
2806 TestCase::Duration::QUICK);
2807 AddTestCase(new SpectrumWifiPhyInterfacesHelperTest, TestCase::Duration::QUICK);
2808}
2809
Extended InterferenceHelper class for the purpose of the tests.
static TypeId GetTypeId()
Get the type ID.
bool IsRxing() const
Indicate whether the interference helper is in receiving state.
bool IsBandTracked(const std::vector< WifiSpectrumBandFrequencies > &startStopFreqs) const
Indicate whether a given band is tracked by the interference helper.
Extended SpectrumWifiPhy class for the purpose of the tests.
virtual WifiSpectrumBandInfo GetBand(MHz_u bandWidth, uint8_t bandIndex=0)=0
Get the info of a given band.
Test 80+80MHz transmission.
void StopInterference()
Stop interference function.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
Ptr< SpectrumWifiPhy > m_phyAp
PHY of AP.
void RunOne(const std::vector< uint8_t > &channelNumbers, MHz_u interferenceCenterFrequency, MHz_u interferenceBandWidth, bool expectSuccess)
Run one function.
uint32_t m_countRxSuccessSta
count RX success for STA
void DoRun() override
Implementation to actually run this TestCase.
Ptr< WaveformGenerator > m_phyInterferer
PHY of interferer.
void SwitchChannel(const std::vector< uint8_t > &channelNumbers)
Switch channel function.
Ptr< SpectrumWifiPhy > m_phySta
PHY of STA.
void RxFailureSta(Ptr< const WifiPsdu > psdu)
Receive failure function for STA.
uint32_t m_countRxFailureSta
count RX failure for STA
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
void GenerateInterference(Ptr< SpectrumValue > interferencePsd, Time duration)
Generate interference function.
void RxSuccessSta(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > statusPerMpdu)
Receive success function for STA.
void CheckResults(bool expectSuccess)
Verify results.
void Send160MhzPpdu()
Send 160MHz PPDU function.
Spectrum Wifi Phy Basic Test.
void SpectrumWifiPhyRxSuccess(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > statusPerMpdu)
Spectrum wifi receive success function.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void DoRun() override
Implementation to actually run this TestCase.
void SpectrumWifiPhyRxFailure(Ptr< const WifiPsdu > psdu)
Spectrum wifi receive failure function.
Ptr< SpectrumSignalParameters > MakeSignal(Watt_u txPower, const WifiPhyOperatingChannel &channel)
Make signal function.
void SendSignal(Watt_u txPower)
Send signal function.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
uint64_t m_uid
the UID to use for the PPDU
Ptr< SpectrumWifiPhy > m_phy
Phy.
Spectrum Wifi Phy Filter Test.
void RxCallback(Ptr< const Packet > p, RxPowerWattPerChannelBand rxPowersW)
Callback triggered when a packet is received by the PHYs.
void DoRun() override
Implementation to actually run this TestCase.
void SendPpdu()
Send PPDU function.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
Ptr< ExtSpectrumWifiPhy > m_rxPhy
RX PHY.
MHz_u m_rxChannelWidth
RX channel width.
Ptr< ExtSpectrumWifiPhy > m_txPhy
TX PHY.
MHz_u m_txChannelWidth
TX channel width.
Spectrum Wifi Phy Bands Calculations Test.
void RunOne(const std::vector< uint8_t > &channelNumberPerSegment, MHz_u bandWidth, uint8_t bandIndex, const std::vector< WifiSpectrumBandIndices > &expectedIndices, const std::vector< WifiSpectrumBandFrequencies > &expectedFrequencies)
Run one function.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
Ptr< SpectrumWifiPhy > m_phy
PHY.
void DoRun() override
Implementation to actually run this TestCase.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
Spectrum Wifi Phy Interfaces Helper Test.
~SpectrumWifiPhyInterfacesHelperTest() override=default
void DoRun() override
Implementation to actually run this TestCase.
Spectrum Wifi Phy Listener Test.
void DoRun() override
Implementation to actually run this TestCase.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
std::shared_ptr< TestPhyListener > m_listener
listener
Spectrum Wifi Phy Multiple Spectrum Test.
void SendPpdu(Ptr< SpectrumWifiPhy > phy, dBm_u txPower, uint32_t payloadSize)
Send PPDU function.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
std::vector< uint32_t > m_rxBytes
count number of received bytes
std::vector< Ptr< SpectrumWifiPhy > > m_rxPhys
RX PHYs.
std::vector< uint32_t > m_countRxSuccess
count number of packets successfully received by PHYs
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
ChannelSwitchScenario m_chanSwitchScenario
the channel switch scenario to consider for the test
void DoRun() override
Implementation to actually run this TestCase.
void DoCheckInterferences(Ptr< SpectrumWifiPhy > phy, const WifiSpectrumBandInfo &band, bool interferencesExpected)
Check the interferences.
bool m_trackSignalsInactiveInterfaces
flag to indicate whether signals coming from inactive spectrum PHY interfaces are tracked during the ...
void RxSuccess(std::size_t index, Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > statusPerMpdu)
Receive success function.
void SwitchChannel(Ptr< SpectrumWifiPhy > phy, WifiPhyBand band, uint8_t channelNumber, MHz_u channelWidth, std::optional< std::size_t > listenerIndex)
Switch channel function.
std::vector< std::shared_ptr< TestPhyListener > > m_listeners
listeners
Time m_lastTxEnd
hold the time at which the last transmission ended
void RxFailure(std::size_t index, Ptr< const WifiPsdu > psdu)
Receive failure function.
Time m_lastTxStart
hold the time at which the last transmission started
std::vector< uint32_t > m_counts
count number of packets received by PHYs
void CheckResults(std::size_t index, uint32_t expectedNumRx, uint32_t expectedNumRxSuccess, uint32_t expectedRxBytes, FrequencyRange expectedFrequencyRangeActiveRfInterface, const std::vector< std::size_t > &expectedConnectedPhysPerChannel)
Verify results.
std::vector< Ptr< SpectrumWifiPhy > > m_txPhys
TX PHYs.
std::vector< Ptr< MultiModelSpectrumChannel > > m_spectrumChannels
Spectrum channels.
void CheckInterferences(Ptr< SpectrumWifiPhy > phy, const FrequencyRange &freqRange, const WifiSpectrumBandInfo &band, bool interferencesExpected)
Schedule now to check the interferences.
SpectrumWifiPhyMultipleInterfacesTest(bool trackSignalsInactiveInterfaces, ChannelSwitchScenario chanSwitchScenario)
Constructor.
void CheckCcaIndication(std::size_t index, bool expectedCcaBusyIndication, Time switchingDelay, Time propagationDelay)
Verify CCA indication reported by a given PHY.
void RxCallback(std::size_t index, Ptr< const Packet > packet, RxPowerWattPerChannelBand rxPowersW)
Callback triggered when a packet is received by a PHY.
void CheckRxingState(Ptr< SpectrumWifiPhy > phy, bool rxingExpected)
Verify rxing state of the interference helper.
ChannelSwitchScenario
Enumeration for channel switching scenarios.
@ BETWEEN_TX_RX
perform channel switch during propagation delay (after TX and before RX)
@ BEFORE_TX
start TX after channel switch is completed
std::vector< uint32_t > m_countRxFailure
count number of packets unsuccessfully received by PHYs
Spectrum Wifi Phy Test Suite.
Test tracked bands in interference helper upon channel switching.
void DoRun() override
Implementation to actually run this TestCase.
void RunOne(const std::vector< uint8_t > &channelNumberPerSegmentBeforeSwitching, const std::vector< uint8_t > &channelNumberPerSegmentAfterSwitching, const std::vector< std::vector< WifiSpectrumBandFrequencies > > &expectedTrackedBands, const std::vector< std::vector< WifiSpectrumBandFrequencies > > &expectedUntrackedBand)
Run one function.
void VerifyTrackedBands(const std::vector< std::vector< WifiSpectrumBandFrequencies > > &expectedTrackedBands, const std::vector< std::vector< WifiSpectrumBandFrequencies > > &expectedUntrackedBands)
Verify the bands tracked by the interference helper.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void SwitchChannel(const std::vector< uint8_t > &channelNumberPerSegment)
Switch channel function.
Ptr< ExtSpectrumWifiPhy > m_phy
PHY.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
Time m_ccaBusyEnd
CCA_BUSY end time.
void NotifyTxStart(Time duration, dBm_u txPower) override
void Reset()
Reset function.
void NotifyWakeup() override
Notify listeners that we woke up.
Time m_ccaBusyStart
CCA_BUSY start time.
void NotifyRxEndOk() override
We have received the last bit of a packet for which NotifyRxStart was invoked first and,...
void NotifyOff() override
Notify listeners that we went to switch off.
TestPhyListener()=default
Create a test PhyListener.
void NotifySleep() override
Notify listeners that we went to sleep.
void NotifySwitchingStart(Time duration) override
uint32_t m_notifyMaybeCcaBusyStart
notify maybe CCA busy start
uint32_t m_notifyRxStart
notify receive start
void NotifyCcaBusyStart(Time duration, WifiChannelListType channelType, const std::vector< Time > &) override
void NotifyRxStart(Time duration) override
void NotifyOn() override
Notify listeners that we went to switch on.
uint32_t m_notifyRxEndOk
notify receive end OK
void NotifyRxEndError() override
We have received the last bit of a packet for which NotifyRxStart was invoked first and,...
uint32_t m_notifyRxEndError
notify receive end error
~TestPhyListener() override=default
static WifiMode GetHeMcs11()
Return MCS 11 from HE MCS values.
static WifiMode GetHeMcs0()
Return MCS 0 from HE MCS values.
static WifiMode GetHeMcs7()
Return MCS 7 from HE MCS values.
handles interference calculations
std::map< FrequencyRange, bool > m_rxing
flag whether it is in receiving state for a given FrequencyRange
NiChangesPerBand m_niChanges
NI Changes for each band.
an EUI-48 address
Helper class used to assign positions and mobility models to nodes.
keep track of a set of node pointers.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
void GetAttribute(std::string name, AttributeValue &value, bool permissive=false) const
Get the value of an attribute, raising fatal errors if unsuccessful.
void Dispose()
Dispose of this Object.
Definition object.cc:247
static WifiMode GetOfdmRate6Mbps()
Return a WifiMode for OFDM at 6 Mbps.
AttributeValue implementation for Pointer.
Ptr< T > Get() const
Definition pointer.h:223
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:594
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 ResetPhyToFreqRangeMapping()
Reset mapping of the spectrum PHY interfaces added to the PHY instances.
void AddChannel(const Ptr< SpectrumChannel > channel, const FrequencyRange &freqRange=WHOLE_WIFI_SPECTRUM)
void AddPhyToFreqRangeMapping(uint8_t linkId, const FrequencyRange &freqRange)
Add a given spectrum PHY interface to the PHY instance corresponding of a given link.
802.11 PHY layer model
void SetDevice(const Ptr< WifiNetDevice > device) override
Sets the device this PHY is associated with.
HeRuBands GetHeRuBands(Ptr< WifiSpectrumPhyInterface > spectrumPhyInterface, MHz_u guardBandwidth)
This function computes the RU bands that belong to a given spectrum PHY interface.
MHz_u GetGuardBandwidth(MHz_u currentChannelWidth) const override
void AddChannel(const Ptr< SpectrumChannel > channel, const FrequencyRange &freqRange=WHOLE_WIFI_SPECTRUM)
Attach a SpectrumChannel to use for a given frequency range.
Ptr< WifiSpectrumPhyInterface > GetCurrentInterface() const
Get the currently active spectrum PHY interface.
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
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition nstime.h:340
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
helps to create WifiNetDevice objects
virtual void SetStandard(WifiStandard standard)
virtual NetDeviceContainer Install(const WifiPhyHelper &phy, const WifiMacHelper &mac, NodeContainer::Iterator first, NodeContainer::Iterator last) const
Implements the IEEE 802.11 MAC header.
void SetSequenceNumber(uint16_t seq)
Set the sequence number of the header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
void SetQosTid(uint8_t tid)
Set the TID for the QoS header.
create MAC layers for a ns3::WifiNetDevice.
void SetPcapDataLinkType(SupportedPcapDataLinkTypes dlt)
Set the data link type of PCAP traces to be used.
void Set(std::string name, const AttributeValue &v)
void SetInterferenceHelper(std::string type, Args &&... args)
Helper function used to set the interference helper.
@ DLT_IEEE802_11_RADIO
Include Radiotap link layer information.
virtual void SetInterferenceHelper(const Ptr< InterferenceHelper > helper)
Sets the interference helper.
Definition wifi-phy.cc:672
void Send(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
This function is a wrapper for the Send variant that accepts a WifiConstPsduMap as first argument.
Definition wifi-phy.cc:1792
void SetErrorRateModel(const Ptr< ErrorRateModel > model)
Sets the error rate model.
Definition wifi-phy.cc:681
std::tuple< uint8_t, MHz_u, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying a segment of an operating channel.
Definition wifi-phy.h:919
virtual void ConfigureStandard(WifiStandard standard)
Configure the PHY-level parameters for different Wi-Fi standard.
Definition wifi-phy.cc:1003
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1572
std::vector< ChannelTuple > ChannelSegments
segments identifying an operating channel
Definition wifi-phy.h:925
void SetOperatingChannel(const WifiPhyOperatingChannel &channel)
If the standard for this object has not been set yet, store the channel settings corresponding to the...
Definition wifi-phy.cc:1129
void SetMobility(const Ptr< MobilityModel > mobility)
assign a mobility model to this device
Definition wifi-phy.cc:647
virtual WifiSpectrumBandInfo GetBand(MHz_u bandWidth, uint8_t bandIndex=0)=0
Get the info of a given band.
receive notifications about PHY events.
Class that keeps track of all information about the current PHY operating channel.
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.
static Ptr< SpectrumValue > CreateOfdmTxPowerSpectralDensity(MHz_u centerFrequency, MHz_u channelWidth, Watt_u txPower, MHz_u guardBandwidth, dBr_u minInnerBand=-20, dBr_u minOuterband=-28, dBr_u lowestPoint=-40)
Create a transmit power spectral density corresponding to OFDM (802.11a/g).
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_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
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
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
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
WifiPhyBand
Identifies the PHY band.
WifiChannelListType
Enumeration of the possible channel-list parameter elements defined in Table 8-5 of IEEE 802....
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211n
@ WIFI_STANDARD_80211ax
@ WIFI_PREAMBLE_LONG
@ WIFI_PREAMBLE_HE_SU
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
NodeContainer nodes
Every class exported by the ns3 library is enclosed in the ns3 namespace.
constexpr FrequencyRange WIFI_SPECTRUM_6_GHZ
Identifier for the frequency range covering the wifi spectrum in the 6 GHz band.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
dB_u RatioToDb(double ratio)
Convert from ratio to dB.
Definition wifi-utils.cc:44
std::vector< BandInfo > Bands
Container of BandInfo.
dBm_u WToDbm(Watt_u val)
Convert from Watts to dBm.
Definition wifi-utils.cc:37
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::map< WifiSpectrumBandInfo, Watt_u > RxPowerWattPerChannelBand
A map of the received power for each band.
Definition phy-entity.h:45
constexpr FrequencyRange WIFI_SPECTRUM_5_GHZ
Identifier for the frequency range covering the wifi spectrum in the 5 GHz band.
@ WIFI_MAC_QOSDATA
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition wifi-mode.h:24
constexpr FrequencyRange WIFI_SPECTRUM_2_4_GHZ
Identifier for the frequency range covering the wifi spectrum in the 2.4 GHz band.
static const uint8_t CHANNEL_NUMBER
static SpectrumWifiPhyTestSuite spectrumWifiPhyTestSuite
the test suite
static const MHz_u GUARD_WIDTH
static const MHz_u CHANNEL_WIDTH
The building block of a SpectrumModel.
double fl
lower limit of subband
Struct defining a frequency range between minFrequency and maxFrequency.
MHz_u minFrequency
the minimum frequency
MHz_u maxFrequency
the maximum frequency
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:72
WifiSpectrumBandInfo structure containing info about a spectrum band.