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/eht-configuration.h"
10#include "ns3/eht-phy.h" //includes all previous PHYs
11#include "ns3/interference-helper.h"
12#include "ns3/log.h"
13#include "ns3/mobility-helper.h"
14#include "ns3/multi-model-spectrum-channel.h"
15#include "ns3/nist-error-rate-model.h"
16#include "ns3/non-communicating-net-device.h"
17#include "ns3/ofdm-ppdu.h"
18#include "ns3/pointer.h"
19#include "ns3/spectrum-wifi-helper.h"
20#include "ns3/spectrum-wifi-phy.h"
21#include "ns3/string.h"
22#include "ns3/test.h"
23#include "ns3/waveform-generator.h"
24#include "ns3/wifi-mac-header.h"
25#include "ns3/wifi-net-device.h"
26#include "ns3/wifi-phy-listener.h"
27#include "ns3/wifi-psdu.h"
28#include "ns3/wifi-spectrum-phy-interface.h"
29#include "ns3/wifi-spectrum-signal-parameters.h"
30#include "ns3/wifi-spectrum-value-helper.h"
31#include "ns3/wifi-utils.h"
32
33#include <memory>
34#include <optional>
35#include <tuple>
36#include <vector>
37
38using namespace ns3;
39
40NS_LOG_COMPONENT_DEFINE("SpectrumWifiPhyTest");
41
42static const uint8_t CHANNEL_NUMBER = 36;
43static const MHz_u CHANNEL_WIDTH{20};
44static const MHz_u GUARD_WIDTH = CHANNEL_WIDTH; // expanded to channel width to model spectrum mask
45
46/**
47 * Extended SpectrumWifiPhy class for the purpose of the tests.
48 */
50{
51 public:
52 using WifiPhy::GetBand;
53};
54
55/**
56 * Extended InterferenceHelper class for the purpose of the tests.
57 */
59{
60 public:
61 /**
62 * @brief Get the type ID.
63 * @return the object TypeId
64 */
66 {
67 static TypeId tid = TypeId("ns3::ExtInterferenceHelper")
69 .SetGroupName("Wifi")
70 .AddConstructor<ExtInterferenceHelper>();
71 return tid;
72 }
73
74 /**
75 * Indicate whether the interference helper is in receiving state
76 *
77 * @return true if the interference helper is in receiving state, false otherwise
78 */
79 bool IsRxing() const
80 {
81 return std::any_of(m_rxing.cbegin(), m_rxing.cend(), [](const auto& rxing) {
82 return rxing.second;
83 });
84 }
85
86 /**
87 * Indicate whether a given band is tracked by the interference helper
88 *
89 * @param startStopFreqs the start and stop frequencies per segment of the band
90 *
91 * @return true if the specified band is tracked by the interference helper, false otherwise
92 */
93 bool IsBandTracked(const std::vector<WifiSpectrumBandFrequencies>& startStopFreqs) const
94 {
95 for (const auto& [band, nis] : m_niChanges)
96 {
97 if (band.frequencies == startStopFreqs)
98 {
99 return true;
100 }
101 }
102 return false;
103 }
104};
105
107
108/**
109 * @ingroup wifi-test
110 * @ingroup tests
111 *
112 * @brief Spectrum Wifi Phy Basic Test
113 */
115{
116 public:
118 /**
119 * Constructor
120 *
121 * @param name reference name
122 */
123 SpectrumWifiPhyBasicTest(std::string name);
124 ~SpectrumWifiPhyBasicTest() override;
125
126 protected:
127 void DoSetup() override;
128 void DoTeardown() override;
130 /**
131 * Make signal function
132 * @param txPower the transmit power
133 * @param channel the operating channel of the PHY used for the transmission
134 * @returns Ptr<SpectrumSignalParameters>
135 */
137 const WifiPhyOperatingChannel& channel);
138 /**
139 * Send signal function
140 * @param txPower the transmit power
141 */
142 void SendSignal(Watt_u txPower);
143 /**
144 * Spectrum wifi receive success function
145 * @param psdu the PSDU
146 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
147 * @param txVector the transmit vector
148 * @param statusPerMpdu reception status per MPDU
149 */
151 RxSignalInfo rxSignalInfo,
152 const WifiTxVector& txVector,
153 const std::vector<bool>& statusPerMpdu);
154 /**
155 * Spectrum wifi receive failure function
156 * @param psdu the PSDU
157 */
159 uint32_t m_count; ///< count
160
161 private:
162 void DoRun() override;
163
164 uint64_t m_uid; //!< the UID to use for the PPDU
165};
166
168 : SpectrumWifiPhyBasicTest("SpectrumWifiPhy test case receives one packet")
169{
170}
171
173 : TestCase(name),
174 m_count(0),
175 m_uid(0)
176{
177}
178
179// Make a Wi-Fi signal to inject directly to the StartRx() method
182{
186 NanoSeconds(800),
187 1,
188 1,
189 0,
191 false};
192
193 auto pkt = Create<Packet>(1000);
194 WifiMacHeader hdr;
195
197 hdr.SetQosTid(0);
198
199 auto psdu = Create<WifiPsdu>(pkt, hdr);
200 const auto txDuration =
201 SpectrumWifiPhy::CalculateTxDuration(psdu->GetSize(), txVector, m_phy->GetPhyBand());
202
203 auto ppdu = Create<OfdmPpdu>(psdu, txVector, channel, m_uid++);
204
206 channel.GetPrimaryChannelCenterFrequency(CHANNEL_WIDTH),
208 txPower,
210 auto txParams = Create<WifiSpectrumSignalParameters>();
211 txParams->psd = txPowerSpectrum;
212 txParams->txPhy = nullptr;
213 txParams->duration = txDuration;
214 txParams->ppdu = ppdu;
215
216 return txParams;
217}
218
219// Make a Wi-Fi signal to inject directly to the StartRx() method
220void
222{
223 m_phy->StartRx(MakeSignal(txPower, m_phy->GetOperatingChannel()), nullptr);
224}
225
226void
228 RxSignalInfo rxSignalInfo,
229 const WifiTxVector& txVector,
230 const std::vector<bool>& statusPerMpdu)
231{
232 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
233 m_count++;
234}
235
236void
242
246
247// Create necessary objects, and inject signals. Test that the expected
248// number of packet receptions occur.
249void
251{
252 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
253 auto node = CreateObject<Node>();
254 auto dev = CreateObject<WifiNetDevice>();
256 auto interferenceHelper = CreateObject<InterferenceHelper>();
257 m_phy->SetInterferenceHelper(interferenceHelper);
259 m_phy->SetErrorRateModel(error);
260 m_phy->SetDevice(dev);
261 m_phy->AddChannel(spectrumChannel);
262 m_phy->SetOperatingChannel(WifiPhy::ChannelTuple{CHANNEL_NUMBER, 0, WIFI_PHY_BAND_5GHZ, 0});
263 m_phy->ConfigureStandard(WIFI_STANDARD_80211n);
264 m_phy->SetReceiveOkCallback(
266 m_phy->SetReceiveErrorCallback(
268 dev->SetPhy(m_phy);
269 node->AddDevice(dev);
270}
271
272void
274{
275 m_phy->Dispose();
276 m_phy = nullptr;
277}
278
279// Test that the expected number of packet receptions occur.
280void
282{
283 Watt_u txPower{0.01};
284 // Send packets spaced 1 second apart; all should be received
288 // Send packets spaced 1 microsecond second apart; none should be received (PHY header reception
289 // failure)
292 this,
293 txPower);
296 this,
297 txPower);
300
301 NS_TEST_ASSERT_MSG_EQ(m_count, 3, "Didn't receive right number of packets");
302}
303
304/**
305 * @ingroup wifi-test
306 * @ingroup tests
307 *
308 * @brief Test Phy Listener
309 */
311{
312 public:
313 /**
314 * Create a test PhyListener
315 */
316 TestPhyListener() = default;
317 ~TestPhyListener() override = default;
318
319 void NotifyRxStart(Time duration) override
320 {
321 NS_LOG_FUNCTION(this << duration);
323 }
324
325 void NotifyRxEndOk() override
326 {
327 NS_LOG_FUNCTION(this);
329 }
330
331 void NotifyRxEndError(const WifiTxVector& txVector) override
332 {
333 NS_LOG_FUNCTION(this << txVector);
335 }
336
337 void NotifyTxStart(Time duration, dBm_u txPower) override
338 {
339 NS_LOG_FUNCTION(this << duration << txPower);
340 }
341
343 WifiChannelListType channelType,
344 const std::vector<Time>& /*per20MhzDurations*/) override
345 {
346 NS_LOG_FUNCTION(this << duration << channelType);
347 if (duration.IsStrictlyPositive())
348 {
350 if (!m_ccaBusyStart.IsStrictlyPositive())
351 {
353 }
354 m_ccaBusyEnd = std::max(m_ccaBusyEnd, Simulator::Now() + duration);
355 }
356 }
357
358 void NotifySwitchingStart(Time duration) override
359 {
360 }
361
362 void NotifySleep() override
363 {
364 }
365
366 void NotifyOff() override
367 {
368 }
369
370 void NotifyWakeup() override
371 {
372 }
373
374 void NotifyOn() override
375 {
376 }
377
378 /**
379 * Reset function
380 */
381 void Reset()
382 {
383 NS_LOG_FUNCTION(this);
384 m_notifyRxStart = 0;
385 m_notifyRxEndOk = 0;
390 }
391
392 uint32_t m_notifyRxStart{0}; ///< notify receive start
393 uint32_t m_notifyRxEndOk{0}; ///< notify receive end OK
394 uint32_t m_notifyRxEndError{0}; ///< notify receive end error
395 uint32_t m_notifyMaybeCcaBusyStart{0}; ///< notify maybe CCA busy start
396 Time m_ccaBusyStart{}; ///< CCA_BUSY start time
397 Time m_ccaBusyEnd{}; ///< CCA_BUSY end time
398};
399
400/**
401 * @ingroup wifi-test
402 * @ingroup tests
403 *
404 * @brief Spectrum Wifi Phy Listener Test
405 */
407{
408 public:
410
411 private:
412 void DoSetup() override;
413 void DoRun() override;
414 std::shared_ptr<TestPhyListener> m_listener; ///< listener
415};
416
418 : SpectrumWifiPhyBasicTest("SpectrumWifiPhy test operation of WifiPhyListener")
419{
420}
421
422void
424{
426 m_listener = std::make_shared<TestPhyListener>();
427 m_phy->RegisterListener(m_listener);
428}
429
430void
432{
433 Watt_u txPower{0.01};
436
437 NS_TEST_ASSERT_MSG_EQ(m_count, 1, "Didn't receive right number of packets");
439 m_listener->m_notifyMaybeCcaBusyStart,
440 2,
441 "Didn't receive NotifyCcaBusyStart (once preamble is detected + prolonged by L-SIG "
442 "reception, then switched to Rx by at the beginning of data)");
443 NS_TEST_ASSERT_MSG_EQ(m_listener->m_notifyRxStart, 1, "Didn't receive NotifyRxStart");
444 NS_TEST_ASSERT_MSG_EQ(m_listener->m_notifyRxEndOk, 1, "Didn't receive NotifyRxEnd");
445
447 m_listener.reset();
448}
449
450/**
451 * @ingroup wifi-test
452 * @ingroup tests
453 *
454 * @brief Spectrum Wifi Phy Filter Test
455 */
457{
458 public:
460 /**
461 * Constructor
462 *
463 * @param name reference name
464 */
465 SpectrumWifiPhyFilterTest(std::string name);
467
468 private:
469 void DoSetup() override;
470 void DoTeardown() override;
471 void DoRun() override;
472
473 /**
474 * Run one function
475 */
476 void RunOne();
477
478 /**
479 * Send PPDU function
480 */
481 void SendPpdu();
482
483 /**
484 * Callback triggered when a packet is received by the PHYs
485 * @param p the received packet
486 * @param rxPowersW the received power per channel band in watts
487 */
489
492
493 MHz_u m_txChannelWidth; ///< TX channel width
494 MHz_u m_rxChannelWidth; ///< RX channel width
495};
496
498 : TestCase("SpectrumWifiPhy test RX filters"),
501{
502}
503
508
509void
511{
515 NanoSeconds(800),
516 1,
517 1,
518 0,
520 false,
521 false};
522 auto pkt = Create<Packet>(1000);
523 WifiMacHeader hdr;
525 hdr.SetQosTid(0);
526 hdr.SetAddr1(Mac48Address("00:00:00:00:00:01"));
527 hdr.SetSequenceNumber(1);
528 auto psdu = Create<WifiPsdu>(pkt, hdr);
529 m_txPhy->Send(WifiConstPsduMap({std::make_pair(SU_STA_ID, psdu)}), txVector);
530}
531
537
538void
540{
541 for (const auto& [band, powerW] : rxPowersW)
542 {
544 "band: (" << band << ") -> powerW=" << powerW
545 << (powerW > 0.0 ? " (" + std::to_string(WToDbm(powerW)) + " dBm)" : ""));
546 }
547
548 size_t numBands = rxPowersW.size();
549 auto expectedNumBands = std::max<std::size_t>(1, m_rxChannelWidth / MHz_u{20});
550 expectedNumBands += (m_rxChannelWidth / MHz_u{40});
551 expectedNumBands += (m_rxChannelWidth / MHz_u{80});
552 expectedNumBands += (m_rxChannelWidth / MHz_u{160});
553 expectedNumBands += (m_rxChannelWidth / MHz_u{320});
554 expectedNumBands += m_rxPhy
555 ->GetRuBands(m_rxPhy->GetCurrentInterface(),
556 m_rxPhy->GetGuardBandwidth(
557 m_rxPhy->GetCurrentInterface()->GetChannelWidth()))
558 .size();
559
560 NS_TEST_ASSERT_MSG_EQ(numBands,
561 expectedNumBands,
562 "Total number of bands handled by the receiver is incorrect");
563
564 MHz_u channelWidth = std::min(m_txChannelWidth, m_rxChannelWidth);
565 auto band = m_rxPhy->GetBand(channelWidth, 0);
566 auto it = rxPowersW.find(band);
567 NS_LOG_INFO("powerW total band: " << it->second << " (" << WToDbm(it->second) << " dBm)");
568 int totalRxPower = static_cast<int>(WToDbm(it->second) + 0.5);
569 int expectedTotalRxPower;
571 {
572 // PHY sends at 16 dBm, and since there is no loss, this should be the total power at the
573 // receiver.
574 expectedTotalRxPower = 16;
575 }
576 else
577 {
578 // Only a part of the transmitted power is received
579 expectedTotalRxPower =
580 16 - static_cast<int>(RatioToDb(m_txChannelWidth / m_rxChannelWidth));
581 }
582 NS_TEST_ASSERT_MSG_EQ(totalRxPower,
583 expectedTotalRxPower,
584 "Total received power is not correct");
585
586 if ((m_txChannelWidth <= m_rxChannelWidth) && (channelWidth >= MHz_u{20}))
587 {
588 band = m_rxPhy->GetBand(MHz_u{20}, 0); // primary 20 MHz
589 it = rxPowersW.find(band);
590 NS_LOG_INFO("powerW in primary 20 MHz channel: " << it->second << " (" << WToDbm(it->second)
591 << " dBm)");
592 const auto rxPowerPrimaryChannel20 = static_cast<int>(WToDbm(it->second) + 0.5);
593 const auto expectedRxPowerPrimaryChannel20 =
594 16 - static_cast<int>(RatioToDb(Count20MHzSubchannels(channelWidth)));
595 NS_TEST_ASSERT_MSG_EQ(rxPowerPrimaryChannel20,
596 expectedRxPowerPrimaryChannel20,
597 "Received power in the primary 20 MHz band is not correct");
598 }
599}
600
601void
603{
604 // WifiHelper::EnableLogComponents();
605 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
606
607 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
609 lossModel->SetFrequency(5.180e9);
610 spectrumChannel->AddPropagationLossModel(lossModel);
612 spectrumChannel->SetPropagationDelayModel(delayModel);
613
614 auto txNode = CreateObject<Node>();
615 auto txDev = CreateObject<WifiNetDevice>();
617 auto txInterferenceHelper = CreateObject<InterferenceHelper>();
618 m_txPhy->SetInterferenceHelper(txInterferenceHelper);
619 auto txErrorModel = CreateObject<NistErrorRateModel>();
620 m_txPhy->SetErrorRateModel(txErrorModel);
621 m_txPhy->SetDevice(txDev);
622 m_txPhy->AddChannel(spectrumChannel);
623 m_txPhy->ConfigureStandard(WIFI_STANDARD_80211be);
624 txDev->SetStandard(WIFI_STANDARD_80211be);
626 m_txPhy->SetMobility(apMobility);
627 txDev->SetPhy(m_txPhy);
628 txNode->AggregateObject(apMobility);
629 txNode->AddDevice(txDev);
630 auto txEhtConfiguration = CreateObject<EhtConfiguration>();
631 txDev->SetEhtConfiguration(txEhtConfiguration);
632
633 auto rxNode = CreateObject<Node>();
634 auto rxDev = CreateObject<WifiNetDevice>();
636 auto rxInterferenceHelper = CreateObject<InterferenceHelper>();
637 m_rxPhy->SetInterferenceHelper(rxInterferenceHelper);
638 auto rxErrorModel = CreateObject<NistErrorRateModel>();
639 m_rxPhy->SetErrorRateModel(rxErrorModel);
640 m_rxPhy->SetDevice(rxDev);
641 m_rxPhy->AddChannel(spectrumChannel);
642 m_rxPhy->ConfigureStandard(WIFI_STANDARD_80211be);
643 rxDev->SetStandard(WIFI_STANDARD_80211be);
645 m_rxPhy->SetMobility(sta1Mobility);
646 rxDev->SetPhy(m_rxPhy);
647 rxNode->AggregateObject(sta1Mobility);
648 rxNode->AddDevice(rxDev);
649 auto rxEhtConfiguration = CreateObject<EhtConfiguration>();
650 rxDev->SetEhtConfiguration(rxEhtConfiguration);
651 m_rxPhy->TraceConnectWithoutContext("PhyRxBegin",
653}
654
655void
657{
658 m_txPhy->Dispose();
659 m_txPhy = nullptr;
660 m_rxPhy->Dispose();
661 m_rxPhy = nullptr;
662}
663
664void
666{
667 MHz_u txFrequency;
668 switch (static_cast<uint16_t>(m_txChannelWidth))
669 {
670 case 20:
671 default:
672 txFrequency = MHz_u{5955};
673 break;
674 case 40:
675 txFrequency = MHz_u{5965};
676 break;
677 case 80:
678 txFrequency = MHz_u{5985};
679 break;
680 case 160:
681 txFrequency = MHz_u{6025};
682 break;
683 case 320:
684 txFrequency = MHz_u{6105};
685 break;
686 }
687 auto txChannelNum = WifiPhyOperatingChannel::FindFirst(0,
688 txFrequency,
692 ->number;
693 m_txPhy->SetOperatingChannel(
695
696 MHz_u rxFrequency;
697 switch (static_cast<uint16_t>(m_rxChannelWidth))
698 {
699 case 20:
700 default:
701 rxFrequency = MHz_u{5955};
702 break;
703 case 40:
704 rxFrequency = MHz_u{5965};
705 break;
706 case 80:
707 rxFrequency = MHz_u{5985};
708 break;
709 case 160:
710 rxFrequency = MHz_u{6025};
711 break;
712 case 320:
713 rxFrequency = MHz_u{6105};
714 break;
715 }
716 auto rxChannelNum = WifiPhyOperatingChannel::FindFirst(0,
717 rxFrequency,
721 ->number;
722 m_rxPhy->SetOperatingChannel(
724
726
728}
729
730void
732{
733 for (const auto txBw : {MHz_u{20}, MHz_u{40}, MHz_u{80}, MHz_u{160}, MHz_u{320}})
734 {
735 for (const auto rxBw : {MHz_u{20}, MHz_u{40}, MHz_u{80}, MHz_u{160}, MHz_u{320}})
736 {
737 m_txChannelWidth = txBw;
738 m_rxChannelWidth = rxBw;
739 RunOne();
740 }
741 }
742
744}
745
746/**
747 * @ingroup wifi-test
748 * @ingroup tests
749 *
750 * @brief Spectrum Wifi Phy Bands Calculations Test
751 *
752 * This test verifies SpectrumWifiPhy::GetBand produces the expected results, for both contiguous
753 * (160 MHz) and non-contiguous (80+80MHz) operating channel
754 */
756{
757 public:
759
760 private:
761 void DoSetup() override;
762 void DoTeardown() override;
763 void DoRun() override;
764
765 /**
766 * Run one function
767 * @param channelNumberPerSegment the channel number for each segment of the operating channel
768 * @param bandWidth the width of the band to test
769 * @param bandIndex the index of the band to test
770 * @param expectedIndices the expected start and stop indices returned by
771 * SpectrumWifiPhy::GetBand \param expectedFrequencies the expected start and stop frequencies
772 * returned by SpectrumWifiPhy::GetBand
773 */
774 void RunOne(const std::vector<uint8_t>& channelNumberPerSegment,
775 MHz_u bandWidth,
776 uint8_t bandIndex,
777 const std::vector<WifiSpectrumBandIndices>& expectedIndices,
778 const std::vector<WifiSpectrumBandFrequencies>& expectedFrequencies);
779
781};
782
784 : TestCase("SpectrumWifiPhy test bands calculations")
785{
786}
787
788void
790{
791 // WifiHelper::EnableLogComponents();
792 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
793
794 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
796 lossModel->SetFrequency(5.180e9);
797 spectrumChannel->AddPropagationLossModel(lossModel);
799 spectrumChannel->SetPropagationDelayModel(delayModel);
800
801 auto node = CreateObject<Node>();
802 auto dev = CreateObject<WifiNetDevice>();
804 auto interferenceHelper = CreateObject<InterferenceHelper>();
805 m_phy->SetInterferenceHelper(interferenceHelper);
806 auto errorModel = CreateObject<NistErrorRateModel>();
807 m_phy->SetErrorRateModel(errorModel);
808 m_phy->SetDevice(dev);
809 m_phy->AddChannel(spectrumChannel);
810 m_phy->ConfigureStandard(WIFI_STANDARD_80211ax);
811 dev->SetPhy(m_phy);
812 node->AddDevice(dev);
813}
814
815void
817{
818 m_phy->Dispose();
819 m_phy = nullptr;
820}
821
822void
824 const std::vector<uint8_t>& channelNumberPerSegment,
825 MHz_u bandWidth,
826 uint8_t bandIndex,
827 const std::vector<WifiSpectrumBandIndices>& expectedIndices,
828 const std::vector<WifiSpectrumBandFrequencies>& expectedFrequencies)
829{
830 WifiPhy::ChannelSegments channelSegments;
831 for (auto channelNumber : channelNumberPerSegment)
832 {
833 const auto& channelInfo = WifiPhyOperatingChannel::FindFirst(channelNumber,
834 MHz_u{0},
835 MHz_u{0},
838 channelSegments.emplace_back(channelInfo->number, channelInfo->width, channelInfo->band, 0);
839 }
840 m_phy->SetOperatingChannel(channelSegments);
841
842 const auto& bandInfo = m_phy->GetBand(bandWidth, bandIndex);
843 NS_ASSERT(expectedIndices.size() == expectedFrequencies.size());
844 NS_ASSERT(expectedIndices.size() == bandInfo.indices.size());
845 NS_ASSERT(expectedFrequencies.size() == bandInfo.frequencies.size());
846 for (std::size_t i = 0; i < expectedIndices.size(); ++i)
847 {
848 NS_ASSERT(bandInfo.indices.at(i).first == expectedIndices.at(i).first);
849 NS_TEST_ASSERT_MSG_EQ(bandInfo.indices.at(i).first,
850 expectedIndices.at(i).first,
851 "Incorrect start indice for segment " << i);
852 NS_TEST_ASSERT_MSG_EQ(bandInfo.indices.at(i).second,
853 expectedIndices.at(i).second,
854 "Incorrect stop indice for segment " << i);
855 NS_TEST_ASSERT_MSG_EQ(bandInfo.frequencies.at(i).first,
856 expectedFrequencies.at(i).first,
857 "Incorrect start frequency for segment " << i);
858 NS_TEST_ASSERT_MSG_EQ(bandInfo.frequencies.at(i).second,
859 expectedFrequencies.at(i).second,
860 "Incorrect stop frequency for segment " << i);
861 }
862}
863
864void
866{
867 const uint32_t indicesPer20MhzBand = 256; // based on 802.11ax carrier spacing
868 const MHz_u channelWidth{160}; // we consider the largest channel width
869 const uint8_t channelNumberContiguous160Mhz =
870 50; // channel number of the first 160 MHz band in 5 GHz band
871 const std::vector<uint8_t> channelNumberPerSegment = {42,
872 106}; // channel numbers used for 80+80MHz
873 // separation between segment at channel number 42 and segment at channel number 106
874 const MHz_u separationWidth{240};
875 for (bool contiguous160Mhz : {true /* 160 MHz */, false /* 80+80MHz */})
876 {
877 const auto guardWidth = contiguous160Mhz ? channelWidth : (channelWidth / 2);
878 uint32_t guardStopIndice = (indicesPer20MhzBand * Count20MHzSubchannels(guardWidth)) - 1;
879 std::vector<WifiSpectrumBandIndices> previousExpectedIndices{};
880 std::vector<WifiSpectrumBandFrequencies> previousExpectedFrequencies{};
881 for (auto bandWidth : {MHz_u{20}, MHz_u{40}, MHz_u{80}, MHz_u{160}})
882 {
883 const uint32_t expectedStartIndice = guardStopIndice + 1;
884 const uint32_t expectedStopIndice =
885 expectedStartIndice + (indicesPer20MhzBand * Count20MHzSubchannels(bandWidth)) - 1;
886 std::vector<WifiSpectrumBandIndices> expectedIndices{
887 {expectedStartIndice, expectedStopIndice}};
888 const Hz_u expectedStartFrequency = MHzToHz(5170);
889 const Hz_u expectedStopFrequency = MHzToHz(5170 + bandWidth);
890 std::vector<WifiSpectrumBandFrequencies> expectedFrequencies{
891 {expectedStartFrequency, expectedStopFrequency}};
892 const std::size_t numBands = (channelWidth / bandWidth);
893 for (std::size_t i = 0; i < numBands; ++i)
894 {
895 if ((bandWidth != channelWidth) && (i >= (numBands / 2)))
896 {
897 // skip DC
898 expectedIndices.at(0).first++;
899 }
900 if ((bandWidth == channelWidth) && !contiguous160Mhz)
901 {
902 // For contiguous 160 MHz, band is made of the two 80 MHz segments (previous run
903 // in the loop)
904 expectedIndices = previousExpectedIndices;
905 expectedFrequencies = previousExpectedFrequencies;
906 }
907 else if ((i == (numBands / 2)) && !contiguous160Mhz)
908 {
909 expectedIndices.at(0).first +=
910 (indicesPer20MhzBand * Count20MHzSubchannels(separationWidth));
911 expectedIndices.at(0).second +=
912 (indicesPer20MhzBand * Count20MHzSubchannels(separationWidth));
913 expectedFrequencies.at(0).first += MHzToHz(separationWidth);
914 expectedFrequencies.at(0).second += MHzToHz(separationWidth);
915 }
916 RunOne(contiguous160Mhz ? std::vector<uint8_t>{channelNumberContiguous160Mhz}
917 : channelNumberPerSegment,
918 bandWidth,
919 i,
920 expectedIndices,
921 expectedFrequencies);
922 if (!contiguous160Mhz && (bandWidth == (channelWidth / 2)))
923 {
924 previousExpectedIndices.emplace_back(expectedIndices.front());
925 previousExpectedFrequencies.emplace_back(expectedFrequencies.front());
926 }
927 expectedIndices.at(0).first = expectedIndices.at(0).second + 1;
928 expectedIndices.at(0).second =
929 expectedIndices.at(0).first +
930 (indicesPer20MhzBand * Count20MHzSubchannels(bandWidth)) - 1;
931 expectedFrequencies.at(0).first += MHzToHz(bandWidth);
932 expectedFrequencies.at(0).second += MHzToHz(bandWidth);
933 }
934 }
935 }
936
938}
939
940/**
941 * @ingroup wifi-test
942 * @ingroup tests
943 *
944 * @brief Test tracked bands in interference helper upon channel switching
945 *
946 * The test is verifying that the correct bands are tracked by the interference helper upon channel
947 * switching. It focuses on 80 and 160 MHz bands while considering 160 MHz operating channels, for
948 * both contiguous and non-contiguous cases.
949 */
951{
952 public:
954
955 private:
956 void DoSetup() override;
957 void DoTeardown() override;
958 void DoRun() override;
959
960 /**
961 * Switch channel function
962 *
963 * @param channelNumberPerSegment the channel number for each segment of the operating channel
964 * to switch to
965 */
966 void SwitchChannel(const std::vector<uint8_t>& channelNumberPerSegment);
967
968 /**
969 * Verify the bands tracked by the interference helper
970 *
971 * @param expectedTrackedBands the bands that are expected to be tracked by the interference
972 * helper
973 * @param expectedUntrackedBands the bands that are expected to be untracked by the
974 * interference helper
975 */
977 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedTrackedBands,
978 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedUntrackedBands);
979
980 /**
981 * Run one function
982 * @param channelNumberPerSegmentBeforeSwitching the channel number for each segment of the
983 * operating channel to switch from \param channelNumberPerSegmentAfterSwitching the channel
984 * number for each segment of the operating channel to switch to \param expectedTrackedBands the
985 * bands that are expected to be tracked by the interference helper \param expectedUntrackedBand
986 * the bands that are expected to be untracked by the interference helper
987 */
988 void RunOne(const std::vector<uint8_t>& channelNumberPerSegmentBeforeSwitching,
989 const std::vector<uint8_t>& channelNumberPerSegmentAfterSwitching,
990 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedTrackedBands,
991 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedUntrackedBand);
992
994};
995
997 : TestCase("SpectrumWifiPhy test channel switching for non-contiguous operating channels")
998{
999}
1000
1001void
1003{
1004 // WifiHelper::EnableLogComponents();
1005 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
1006
1007 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
1008 auto lossModel = CreateObject<FriisPropagationLossModel>();
1009 lossModel->SetFrequency(5.180e9);
1010 spectrumChannel->AddPropagationLossModel(lossModel);
1012 spectrumChannel->SetPropagationDelayModel(delayModel);
1013
1014 auto node = CreateObject<Node>();
1015 auto dev = CreateObject<WifiNetDevice>();
1017 auto interferenceHelper = CreateObject<ExtInterferenceHelper>();
1018 m_phy->SetInterferenceHelper(interferenceHelper);
1019 auto errorModel = CreateObject<NistErrorRateModel>();
1020 m_phy->SetErrorRateModel(errorModel);
1021 m_phy->SetDevice(dev);
1022 m_phy->AddChannel(spectrumChannel);
1023 m_phy->ConfigureStandard(WIFI_STANDARD_80211ax);
1024 dev->SetPhy(m_phy);
1025 node->AddDevice(dev);
1026}
1027
1028void
1030{
1031 m_phy->Dispose();
1032 m_phy = nullptr;
1033}
1034
1035void
1036SpectrumWifiPhyTrackedBandsTest::SwitchChannel(const std::vector<uint8_t>& channelNumberPerSegment)
1037{
1038 NS_LOG_FUNCTION(this);
1039 WifiPhy::ChannelSegments channelSegments;
1040 for (auto channelNumber : channelNumberPerSegment)
1041 {
1042 const auto& channelInfo = WifiPhyOperatingChannel::FindFirst(channelNumber,
1043 MHz_u{0},
1044 MHz_u{0},
1047 channelSegments.emplace_back(channelInfo->number, channelInfo->width, channelInfo->band, 0);
1048 }
1049 m_phy->SetOperatingChannel(channelSegments);
1050}
1051
1052void
1054 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedTrackedBands,
1055 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedUntrackedBands)
1056{
1057 NS_LOG_FUNCTION(this);
1058 PointerValue ptr;
1059 m_phy->GetAttribute("InterferenceHelper", ptr);
1060 auto interferenceHelper = DynamicCast<ExtInterferenceHelper>(ptr.Get<ExtInterferenceHelper>());
1061 NS_ASSERT(interferenceHelper);
1062 auto printBand = [](const std::vector<WifiSpectrumBandFrequencies>& v) {
1063 std::stringstream ss;
1064 for (const auto& [start, stop] : v)
1065 {
1066 ss << "[" << start << "-" << stop << "] ";
1067 }
1068 return ss.str();
1069 };
1070 for (const auto& expectedTrackedBand : expectedTrackedBands)
1071 {
1072 auto bandTracked = interferenceHelper->IsBandTracked(expectedTrackedBand);
1073 NS_TEST_ASSERT_MSG_EQ(bandTracked,
1074 true,
1075 "Band " << printBand(expectedTrackedBand) << " is not tracked");
1076 }
1077 for (const auto& expectedUntrackedBand : expectedUntrackedBands)
1078 {
1079 auto bandTracked = interferenceHelper->IsBandTracked(expectedUntrackedBand);
1080 NS_TEST_ASSERT_MSG_EQ(bandTracked,
1081 false,
1082 "Band " << printBand(expectedUntrackedBand)
1083 << " is unexpectedly tracked");
1084 }
1085}
1086
1087void
1089 const std::vector<uint8_t>& channelNumberPerSegmentBeforeSwitching,
1090 const std::vector<uint8_t>& channelNumberPerSegmentAfterSwitching,
1091 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedTrackedBands,
1092 const std::vector<std::vector<WifiSpectrumBandFrequencies>>& expectedUntrackedBands)
1093{
1094 NS_LOG_FUNCTION(this);
1095
1098 this,
1099 channelNumberPerSegmentBeforeSwitching);
1100
1103 this,
1104 channelNumberPerSegmentAfterSwitching);
1105
1108 this,
1109 expectedTrackedBands,
1110 expectedUntrackedBands);
1111
1113}
1114
1115void
1117{
1118 // switch from 160 MHz to 80+80 MHz
1119 RunOne({50},
1120 {42, 106},
1121 {{{MHzToHz(5170), MHzToHz(5250)}} /* first 80 MHz segment */,
1122 {{MHzToHz(5490), MHzToHz(5570)}} /* second 80 MHz segment */,
1123 {{MHzToHz(5170), MHzToHz(5250)},
1124 {MHzToHz(5490),
1125 MHzToHz(5570)}} /* non-contiguous 160 MHz band made of the two segments */},
1126 {{{MHzToHz(5170), MHzToHz(5330)}} /* full 160 MHz band should have been removed */});
1127
1128 // switch from 80+80 MHz to 160 MHz
1129 RunOne(
1130 {42, 106},
1131 {50},
1132 {{{MHzToHz(5170), MHzToHz(5330)}} /* full 160 MHz band */,
1133 {{MHzToHz(5170), MHzToHz(5250)}} /* first 80 MHz segment is part of the 160 MHz channel*/},
1134 {{{MHzToHz(5490), MHzToHz(5570)}} /* second 80 MHz segment should have been removed */,
1135 {{MHzToHz(5170), MHzToHz(5250)},
1136 {MHzToHz(5490),
1137 MHzToHz(5570)}} /* non-contiguous 160 MHz band should have been removed */});
1138
1139 // switch from 80+80 MHz to 80+80 MHz with segment swap
1140 RunOne({42, 106},
1141 {106, 42},
1142 {{{MHzToHz(5490), MHzToHz(5570)}} /* first 80 MHz segment */,
1143 {{MHzToHz(5490), MHzToHz(5570)}} /* second 80 MHz segment */,
1144 {{MHzToHz(5170), MHzToHz(5250)},
1145 {MHzToHz(5490),
1146 MHzToHz(5570)}} /* non-contiguous 160 MHz band made of the two segments */},
1147 {});
1148
1149 // switch from 80+80 MHz to another 80+80 MHz with one common segment
1150 RunOne({42, 106},
1151 {106, 138},
1152 {{{MHzToHz(5490), MHzToHz(5570)}} /* first 80 MHz segment */,
1153 {{MHzToHz(5650), MHzToHz(5730)}} /* second 80 MHz segment */,
1154 {{MHzToHz(5490), MHzToHz(5570)},
1155 {MHzToHz(5650),
1156 MHzToHz(5730)}} /* non-contiguous 160 MHz band made of the two segments */},
1157 {{{MHzToHz(5170),
1158 MHzToHz(5250)}} /* 80 MHz segment at channel 42 should have been removed */,
1159 {{MHzToHz(5170), MHzToHz(5250)},
1160 {MHzToHz(5490),
1161 MHzToHz(5570)}} /* previous non-contiguous 160 MHz band should have been removed */});
1162
1163 // switch from 80+80 MHz to another 80+80 MHz with no common segment
1164 RunOne({42, 106},
1165 {122, 155},
1166 {{{MHzToHz(5570), MHzToHz(5650)}} /* first 80 MHz segment */,
1167 {{MHzToHz(5735), MHzToHz(5815)}} /* second 80 MHz segment */,
1168 {{MHzToHz(5570), MHzToHz(5650)},
1169 {MHzToHz(5735),
1170 MHzToHz(5815)}} /* non-contiguous 160 MHz band made of the two segments */},
1171 {{{MHzToHz(5170),
1172 MHzToHz(5250)}} /* previous first 80 MHz segment should have been removed */,
1173 {{MHzToHz(5490),
1174 MHzToHz(5570)}} /* previous second 80 MHz segment should have been removed */,
1175 {{MHzToHz(5170), MHzToHz(5250)},
1176 {MHzToHz(5490),
1177 MHzToHz(5570)}} /* previous non-contiguous 160 MHz band should have been removed */});
1178
1180}
1181
1182/**
1183 * @ingroup wifi-test
1184 * @ingroup tests
1185 *
1186 * @brief Test 80+80MHz transmission
1187 *
1188 * The test verifies that two non-contiguous segments are handled by the spectrum PHY
1189 * to transmit 160 MHz PPDUs when the operating channel is configured as 80+80MHz.
1190 *
1191 * The test first considers a contiguous 160 MHz segment and generate interference on the second
1192 * 80 MHz band to verify reception fails in this scenario. Then, a similar interference
1193 * is generated when a 80+80MHz operating channel is configured, where the first frequency segment
1194 * occupies the first 80 MHz band of the previous 160 MHz operating channel. The reception should
1195 * succeed in that scenario, which demonstrates the second 80 MHz band of the operating channel is
1196 * no longer occupying that spectrum portion (the interference is hence is the gap between the two
1197 * frequency segments). Finally, the test also generates interference on each of the frequency
1198 * segments when the operating channel is 80+80MHz, to demonstrate the frequency segments are
1199 * positioned as expected.
1200 */
1202{
1203 public:
1205
1206 private:
1207 void DoSetup() override;
1208 void DoTeardown() override;
1209 void DoRun() override;
1210
1211 /**
1212 * Run one function
1213 * @param channelNumbers the channel number for each segment of the operating channel
1214 * @param interferenceCenterFrequency the center frequency of the interference signal to
1215 * generate
1216 * @param interferenceBandWidth the band width of the interference signal to generate
1217 * @param expectSuccess flag to indicate whether reception is expected to be successful
1218 */
1219 void RunOne(const std::vector<uint8_t>& channelNumbers,
1220 MHz_u interferenceCenterFrequency,
1221 MHz_u interferenceBandWidth,
1222 bool expectSuccess);
1223
1224 /**
1225 * Switch channel function
1226 *
1227 * @param channelNumbers the channel number for each segment of the operating channel
1228 * to switch to
1229 */
1230 void SwitchChannel(const std::vector<uint8_t>& channelNumbers);
1231
1232 /**
1233 * Send 160MHz PPDU function
1234 */
1235 void Send160MhzPpdu();
1236
1237 /**
1238 * Generate interference function
1239 * @param interferencePsd the PSD of the interference to be generated
1240 * @param duration the duration of the interference
1241 */
1242 void GenerateInterference(Ptr<SpectrumValue> interferencePsd, Time duration);
1243
1244 /**
1245 * Stop interference function
1246 */
1247 void StopInterference();
1248
1249 /**
1250 * Receive success function for STA
1251 * @param psdu the PSDU
1252 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
1253 * @param txVector the transmit vector
1254 * @param statusPerMpdu reception status per MPDU
1255 */
1257 RxSignalInfo rxSignalInfo,
1258 const WifiTxVector& txVector,
1259 const std::vector<bool>& statusPerMpdu);
1260
1261 /**
1262 * Receive failure function for STA
1263 * @param psdu the PSDU
1264 */
1266
1267 /**
1268 * Verify results
1269 *
1270 * @param expectSuccess flag to indicate whether reception is expected to be successful
1271 */
1272 void CheckResults(bool expectSuccess);
1273
1277
1278 uint32_t m_countRxSuccessSta; ///< count RX success for STA
1279 uint32_t m_countRxFailureSta; ///< count RX failure for STA
1280};
1281
1283 : TestCase("SpectrumWifiPhy test 80+80MHz transmission"),
1286{
1287}
1288
1289void
1290SpectrumWifiPhy80Plus80Test::SwitchChannel(const std::vector<uint8_t>& channelNumbers)
1291{
1292 NS_LOG_FUNCTION(this);
1293 WifiPhy::ChannelSegments channelSegments;
1294 for (auto channelNumber : channelNumbers)
1295 {
1296 const auto& channelInfo = WifiPhyOperatingChannel::FindFirst(channelNumber,
1297 MHz_u{0},
1298 MHz_u{0},
1301 channelSegments.emplace_back(channelInfo->number, channelInfo->width, channelInfo->band, 0);
1302 }
1303 m_phyAp->SetOperatingChannel(channelSegments);
1304 m_phySta->SetOperatingChannel(channelSegments);
1305}
1306
1307void
1309{
1310 NS_LOG_FUNCTION(this);
1311
1312 WifiTxVector txVector{HePhy::GetHeMcs7(),
1315 NanoSeconds(800),
1316 1,
1317 1,
1318 0,
1319 MHz_u{160},
1320 false,
1321 false,
1322 false};
1323
1324 auto pkt = Create<Packet>(1000);
1325 WifiMacHeader hdr;
1327 auto psdu = Create<WifiPsdu>(pkt, hdr);
1328
1329 m_phyAp->Send(psdu, txVector);
1330}
1331
1332void
1334{
1335 m_phyInterferer->SetTxPowerSpectralDensity(interferencePsd);
1336 m_phyInterferer->SetPeriod(duration);
1337 m_phyInterferer->Start();
1339}
1340
1341void
1346
1347void
1349 RxSignalInfo rxSignalInfo,
1350 const WifiTxVector& txVector,
1351 const std::vector<bool>& /*statusPerMpdu*/)
1352{
1353 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
1355}
1356
1357void
1363
1364void
1366{
1367 NS_LOG_FUNCTION(this << expectSuccess);
1369 expectSuccess,
1370 "Reception should be "
1371 << (expectSuccess ? "successful" : "unsuccessful"));
1372}
1373
1374void
1376{
1377 // WifiHelper::EnableLogComponents();
1378 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
1379
1380 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
1381 auto lossModel = CreateObject<FriisPropagationLossModel>();
1382 spectrumChannel->AddPropagationLossModel(lossModel);
1384 spectrumChannel->SetPropagationDelayModel(delayModel);
1385
1386 auto apNode = CreateObject<Node>();
1387 auto apDev = CreateObject<WifiNetDevice>();
1389 auto apInterferenceHelper = CreateObject<InterferenceHelper>();
1390 m_phyAp->SetInterferenceHelper(apInterferenceHelper);
1391 auto apErrorModel = CreateObject<NistErrorRateModel>();
1392 m_phyAp->SetErrorRateModel(apErrorModel);
1393 m_phyAp->SetDevice(apDev);
1394 m_phyAp->AddChannel(spectrumChannel);
1395 m_phyAp->ConfigureStandard(WIFI_STANDARD_80211ax);
1397 m_phyAp->SetMobility(apMobility);
1398 apDev->SetPhy(m_phyAp);
1399 apNode->AggregateObject(apMobility);
1400 apNode->AddDevice(apDev);
1401
1402 auto staNode = CreateObject<Node>();
1403 auto staDev = CreateObject<WifiNetDevice>();
1405 auto staInterferenceHelper = CreateObject<InterferenceHelper>();
1406 m_phySta->SetInterferenceHelper(staInterferenceHelper);
1407 auto staErrorModel = CreateObject<NistErrorRateModel>();
1408 m_phySta->SetErrorRateModel(staErrorModel);
1409 m_phySta->SetDevice(staDev);
1410 m_phySta->AddChannel(spectrumChannel);
1411 m_phySta->ConfigureStandard(WIFI_STANDARD_80211ax);
1413 m_phySta->SetReceiveErrorCallback(
1416 m_phySta->SetMobility(staMobility);
1417 staDev->SetPhy(m_phySta);
1418 staNode->AggregateObject(staMobility);
1419 staNode->AddDevice(staDev);
1420
1421 auto interfererNode = CreateObject<Node>();
1422 auto interfererDev = CreateObject<NonCommunicatingNetDevice>();
1424 m_phyInterferer->SetDevice(interfererDev);
1425 m_phyInterferer->SetChannel(spectrumChannel);
1426 m_phyInterferer->SetDutyCycle(1);
1427 interfererNode->AddDevice(interfererDev);
1428}
1429
1430void
1432{
1433 m_phyAp->Dispose();
1434 m_phyAp = nullptr;
1435 m_phySta->Dispose();
1436 m_phySta = nullptr;
1437 m_phyInterferer->Dispose();
1438 m_phyInterferer = nullptr;
1439}
1440
1441void
1442SpectrumWifiPhy80Plus80Test::RunOne(const std::vector<uint8_t>& channelNumbers,
1443 MHz_u interferenceCenterFrequency,
1444 MHz_u interferenceBandWidth,
1445 bool expectSuccess)
1446{
1447 // reset counters
1450
1453 this,
1454 channelNumbers);
1455
1456 // create info about interference to generate
1457 BandInfo bandInfo{.fl = MHzToHz(interferenceCenterFrequency - (interferenceBandWidth / 2)),
1458 .fc = MHzToHz(interferenceCenterFrequency),
1459 .fh = MHzToHz(interferenceCenterFrequency + (interferenceBandWidth / 2))};
1460 auto spectrumInterference = Create<SpectrumModel>(Bands{bandInfo});
1461 auto interferencePsd = Create<SpectrumValue>(spectrumInterference);
1462 Watt_u interferencePower{0.1};
1463 *interferencePsd = interferencePower / (interferenceBandWidth * 20e6);
1464
1467 this,
1468 interferencePsd,
1469 MilliSeconds(100));
1470
1472
1475 this,
1476 expectSuccess);
1477
1479}
1480
1481void
1483{
1484 // Test transmission over contiguous 160 MHz (channel 50) and interference generated in
1485 // the second half of the channel width (channel 58, i.e. center frequency 5290 and bandwidth 80
1486 // MHz). The reception should fail because the interference occupies half the channel width used
1487 // for the transmission.
1488 // ┌──────────────────┐
1489 // Interference │ channel 58 │
1490 // │ 5290 MHz, 80 MHz │
1491 // └──────────────────┘
1492 //
1493 // ┌──────────────────────────────────────┐
1494 // Operating Channel │ channel 50 │
1495 // │ 5250 MHz, 160 MHz │
1496 // └──────────────────────────────────────┘
1497 //
1498 RunOne({50}, MHz_u{5290}, MHz_u{80}, false);
1499
1500 // Test transmission over non-contiguous 160 MHz (i.e. 80+80MHz) and same interference as in
1501 // previous run. The reception should succeed because the interference is located between the
1502 // two segments.
1503 // ┌──────────────────┐
1504 // Interference │ channel 58 │
1505 // │ 5290 MHz, 80 MHz │
1506 // └──────────────────┘
1507 //
1508 // ┌──────────────────┐ ┌──────────────────┐
1509 // Operating Channel │ channel 42 │ │ channel 106 │
1510 // │80+80MHz segment 0│ │80+80MHz segment 1│
1511 // └──────────────────┘ └──────────────────┘
1512 //
1513 RunOne({42, 106}, MHz_u{5290}, MHz_u{80}, true);
1514
1515 // Test transmission over non-contiguous 160 MHz (i.e. 80+80MHz) and interference generated on
1516 // the first segment of the channel width (channel 42, i.e. center frequency 5210 and bandwidth
1517 // 80 MHz). The reception should fail because the interference occupies half the channel width
1518 // used for the transmission.
1519 // ┌──────────────────┐
1520 // Interference │ channel 42 │
1521 // │ 5210 MHz, 80 MHz │
1522 // └──────────────────┘
1523 //
1524 // ┌──────────────────┐ ┌──────────────────┐
1525 // Operating Channel │ channel 42 │ │ channel 106 │
1526 // │80+80MHz segment 0│ │80+80MHz segment 1│
1527 // └──────────────────┘ └──────────────────┘
1528 //
1529 RunOne({42, 106}, MHz_u{5210}, MHz_u{80}, false);
1530
1531 // Test transmission over non-contiguous 160 MHz (i.e. 80+80MHz) and interference generated on
1532 // the second segment of the channel width (channel 42, i.e. center frequency 5210 and bandwidth
1533 // 80 MHz). The reception should fail because the interference occupies half the channel width
1534 // used for the transmission.
1535 // ┌──────────────────┐
1536 // Interference │ channel 106 │
1537 // │ 5530 MHz, 80 MHz │
1538 // └──────────────────┘
1539 //
1540 // ┌──────────────────┐ ┌──────────────────┐
1541 // Operating Channel │ channel 42 │ │ channel 106 │
1542 // │80+80MHz segment 0│ │80+80MHz segment 1│
1543 // └──────────────────┘ └──────────────────┘
1544 //
1545 RunOne({42, 106}, MHz_u{5530}, MHz_u{80}, false);
1546
1548}
1549
1550/**
1551 * @ingroup wifi-test
1552 * @ingroup tests
1553 *
1554 * @brief Spectrum Wifi Phy Multiple Spectrum Test
1555 *
1556 * This test is testing the ability to plug multiple spectrum channels to the spectrum wifi PHY.
1557 * It considers 4 TX-RX PHY pairs that are independent from each others and are plugged to different
1558 * spectrum channels that are covering different frequency range. Each RX PHY is also attached to
1559 * each of the other 3 spectrum channels it can switch to.
1560 *
1561 * In the first scenario, we consider the default case where each TX-RX PHY pairs are operating on
1562 * different frequency ranges and hence using independent spectrum channels. We validate that no
1563 * packets is received from other TX PHYs attached to different spectrum channels and we also verify
1564 * the amount of connected PHYs to each spectrum channel is exactly 2. The test also makes sure each
1565 * PHY has only one active spectrum channel and that the active one is operating at the expected
1566 * frequency range.
1567 *
1568 * In the second scenario, we consecutively switch the channel of all RX PHYs to the one of each TX
1569 * PHY. We validate that packets are received by all PHYs and we also verify the amount of connected
1570 * PHYs to each spectrum channels is either 5 (1 TX PHY and 4 RX PHYs) or 1 (the TX PHY left alone).
1571 */
1573{
1574 public:
1575 /// Enumeration for channel switching scenarios
1576 enum class ChannelSwitchScenario : uint8_t
1577 {
1578 BEFORE_TX = 0, //!< start TX after channel switch is completed
1579 BETWEEN_TX_RX //!< perform channel switch during propagation delay (after TX and before RX)
1580 };
1581
1582 /**
1583 * Constructor
1584 *
1585 * @param trackSignalsInactiveInterfaces flag to indicate whether signals coming from inactive
1586 * spectrum PHY interfaces shall be tracked during the test
1587 * @param chanSwitchScenario the channel switching scenario to consider for the test
1588 */
1589 SpectrumWifiPhyMultipleInterfacesTest(bool trackSignalsInactiveInterfaces,
1590 ChannelSwitchScenario chanSwitchScenario);
1591
1592 private:
1593 void DoSetup() override;
1594 void DoTeardown() override;
1595 void DoRun() override;
1596
1597 /**
1598 * Switch channel function
1599 *
1600 * @param phy the PHY to switch
1601 * @param band the PHY band to use
1602 * @param channelNumber number the channel number to use
1603 * @param channelWidth the channel width to use
1604 * @param listenerIndex index of the listener for that PHY, if PHY is a RX PHY
1605 */
1607 WifiPhyBand band,
1608 uint8_t channelNumber,
1609 MHz_u channelWidth,
1610 std::optional<std::size_t> listenerIndex);
1611
1612 /**
1613 * Send PPDU function
1614 *
1615 * @param phy the PHY to transmit the signal
1616 * @param txPower the power to transmit the signal (this is also the received power since we do
1617 * not have propagation loss to simplify) \param payloadSize the payload size in bytes
1618 */
1619 void SendPpdu(Ptr<SpectrumWifiPhy> phy, dBm_u txPower, uint32_t payloadSize);
1620
1621 /**
1622 * Callback triggered when a packet is received by a PHY
1623 * @param index the index to identify the RX PHY
1624 * @param packet the received packet
1625 * @param rxPowersW the received power per channel band in watts
1626 */
1627 void RxCallback(std::size_t index,
1628 Ptr<const Packet> packet,
1629 RxPowerWattPerChannelBand rxPowersW);
1630
1631 /**
1632 * Receive success function
1633 * @param index index of the RX STA
1634 * @param psdu the PSDU
1635 * @param rxSignalInfo the info on the received signal (\see RxSignalInfo)
1636 * @param txVector the transmit vector
1637 * @param statusPerMpdu reception status per MPDU
1638 */
1639 void RxSuccess(std::size_t index,
1641 RxSignalInfo rxSignalInfo,
1642 const WifiTxVector& txVector,
1643 const std::vector<bool>& statusPerMpdu);
1644
1645 /**
1646 * Receive failure function
1647 * @param index index of the RX STA
1648 * @param psdu the PSDU
1649 */
1650 void RxFailure(std::size_t index, Ptr<const WifiPsdu> psdu);
1651
1652 /**
1653 * Schedule now to check the interferences
1654 * @param phy the PHY for which the check has to be executed
1655 * @param freqRange the frequency range for which the check has to be executed
1656 * @param band the band for which the check has to be executed
1657 * @param interferencesExpected flag whether interferences are expected to have been tracked
1658 */
1660 const FrequencyRange& freqRange,
1661 const WifiSpectrumBandInfo& band,
1662 bool interferencesExpected);
1663
1664 /**
1665 * Check the interferences
1666 * @param phy the PHY for which the check has to be executed
1667 * @param band the band for which the check has to be executed
1668 * @param interferencesExpected flag whether interferences are expected to have been tracked
1669 */
1671 const WifiSpectrumBandInfo& band,
1672 bool interferencesExpected);
1673
1674 /**
1675 * Verify results
1676 *
1677 * @param index the index to identify the RX PHY to check
1678 * @param expectedNumRx the expected number of RX events for that PHY
1679 * @param expectedNumRxSuccess the expected amount of successfully received packets
1680 * @param expectedRxBytes the expected amount of received bytes
1681 * @param expectedFrequencyRangeActiveRfInterface the expected frequency range (in MHz) of the
1682 * active RF interface
1683 * @param expectedConnectedPhysPerChannel the expected number of PHYs attached for each spectrum
1684 * channel
1685 */
1686 void CheckResults(std::size_t index,
1687 uint32_t expectedNumRx,
1688 uint32_t expectedNumRxSuccess,
1689 uint32_t expectedRxBytes,
1690 FrequencyRange expectedFrequencyRangeActiveRfInterface,
1691 const std::vector<std::size_t>& expectedConnectedPhysPerChannel);
1692
1693 /**
1694 * Verify CCA indication reported by a given PHY
1695 *
1696 * @param index the index to identify the RX PHY to check
1697 * @param expectedCcaBusyIndication flag to indicate whether a CCA BUSY notification is expected
1698 * @param timeBeforeChannelSwitchStarted delay between the TX has started and the time RX
1699 * switched to the TX channel
1700 * @param propagationDelay the propagation delay
1701 */
1702 void CheckCcaIndication(std::size_t index,
1703 bool expectedCcaBusyIndication,
1704 Time timeBeforeChannelSwitchStarted,
1705 Time propagationDelay);
1706
1707 /**
1708 * Verify rxing state of the interference helper
1709 *
1710 * @param phy the PHY to which the interference helper instance is attached
1711 * @param rxingExpected flag whether the interference helper is expected to be in rxing state or
1712 * not
1713 */
1714 void CheckRxingState(Ptr<SpectrumWifiPhy> phy, bool rxingExpected);
1715
1716 /**
1717 * Reset function
1718 */
1719 void Reset();
1720
1721 bool
1722 m_trackSignalsInactiveInterfaces; //!< flag to indicate whether signals coming from inactive
1723 //!< spectrum PHY interfaces are tracked during the test
1725 m_chanSwitchScenario; //!< the channel switch scenario to consider for the test
1726 std::vector<Ptr<MultiModelSpectrumChannel>> m_spectrumChannels; //!< Spectrum channels
1727 std::vector<Ptr<SpectrumWifiPhy>> m_txPhys{}; //!< TX PHYs
1728 std::vector<Ptr<SpectrumWifiPhy>> m_rxPhys{}; //!< RX PHYs
1729 std::vector<std::shared_ptr<TestPhyListener>> m_listeners{}; //!< listeners
1730
1731 Time m_switchingDelay; //!< The switching delay to consider to the test, this has to be lessen
1732 //!< than the default one to ensure TX is still ongoing when the RX PHYs
1733 //!< switched to the TX channel
1734
1735 std::vector<uint32_t> m_counts; //!< count number of packets received by PHYs
1736 std::vector<uint32_t>
1737 m_countRxSuccess; //!< count number of packets successfully received by PHYs
1738 std::vector<uint32_t>
1739 m_countRxFailure; //!< count number of packets unsuccessfully received by PHYs
1740 std::vector<uint32_t> m_rxBytes; //!< count number of received bytes
1741
1742 Time m_lastTxStart{0}; //!< hold the time at which the last transmission started
1743 Time m_lastTxEnd{0}; //!< hold the time at which the last transmission ended
1744};
1745
1747 bool trackSignalsInactiveInterfaces,
1748 ChannelSwitchScenario chanSwitchScenario)
1749 : TestCase{"SpectrumWifiPhy test operation with multiple RF interfaces"},
1750 m_trackSignalsInactiveInterfaces{trackSignalsInactiveInterfaces},
1751 m_chanSwitchScenario{chanSwitchScenario},
1753 ? NanoSeconds(1)
1754 : MicroSeconds(50)}
1755{
1756}
1757
1758void
1760 WifiPhyBand band,
1761 uint8_t channelNumber,
1762 MHz_u channelWidth,
1763 std::optional<std::size_t> listenerIndex)
1764{
1765 NS_LOG_FUNCTION(this << phy << band << +channelNumber << channelWidth);
1766 if (listenerIndex)
1767 {
1768 auto& listener = m_listeners.at(*listenerIndex);
1769 listener->m_notifyMaybeCcaBusyStart = 0;
1770 listener->m_ccaBusyStart = Seconds(0);
1771 listener->m_ccaBusyEnd = Seconds(0);
1772 }
1773 phy->SetOperatingChannel(WifiPhy::ChannelTuple{channelNumber, channelWidth, band, 0});
1774 // verify rxing state of interference helper is reset after channel switch
1776 this,
1777 phy,
1778 false);
1779}
1780
1781void
1783 dBm_u txPower,
1784 uint32_t payloadSize)
1785{
1786 NS_LOG_FUNCTION(this << phy << txPower << payloadSize << phy->GetCurrentFrequencyRange()
1787 << phy->GetChannelWidth() << phy->GetChannelNumber());
1788
1792 NanoSeconds(800),
1793 1,
1794 1,
1795 0,
1796 MHz_u{20},
1797 false,
1798 false};
1799 Ptr<Packet> pkt = Create<Packet>(payloadSize);
1800 WifiMacHeader hdr;
1802 hdr.SetQosTid(0);
1803 hdr.SetAddr1(Mac48Address("00:00:00:00:00:01"));
1804 hdr.SetSequenceNumber(1);
1805 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1806
1809 txVector,
1810 phy->GetPhyBand());
1811 phy->SetTxPowerStart(txPower);
1812 phy->SetTxPowerEnd(txPower);
1813 phy->Send(WifiConstPsduMap({std::make_pair(SU_STA_ID, psdu)}), txVector);
1814}
1815
1816void
1818 Ptr<const Packet> packet,
1819 RxPowerWattPerChannelBand /*rxPowersW*/)
1820{
1821 auto phy = m_rxPhys.at(index);
1822 const auto payloadBytes = packet->GetSize() - 30;
1823 NS_LOG_FUNCTION(this << index << payloadBytes << phy->GetCurrentFrequencyRange()
1824 << phy->GetChannelWidth() << phy->GetChannelNumber());
1825 m_counts.at(index)++;
1826 m_rxBytes.at(index) += payloadBytes;
1827}
1828
1829void
1832 RxSignalInfo rxSignalInfo,
1833 const WifiTxVector& txVector,
1834 const std::vector<bool>& /*statusPerMpdu*/)
1835{
1836 NS_LOG_FUNCTION(this << index << *psdu << rxSignalInfo << txVector);
1837 m_countRxSuccess.at(index)++;
1838}
1839
1840void
1842{
1843 NS_LOG_FUNCTION(this << index << *psdu);
1844 m_countRxFailure.at(index)++;
1845}
1846
1847void
1849 const FrequencyRange& freqRange,
1850 const WifiSpectrumBandInfo& band,
1851 bool interferencesExpected)
1852{
1853 if ((!m_trackSignalsInactiveInterfaces) && (phy->GetCurrentFrequencyRange() != freqRange))
1854 {
1855 // ignore since no bands for that range exists in interference helper in that case
1856 return;
1857 }
1858 // This is needed to make sure PHY state will be checked as the last event if a state change
1859 // occurred at the exact same time as the check
1861 this,
1862 phy,
1863 band,
1864 interferencesExpected);
1865}
1866
1867void
1869 const WifiSpectrumBandInfo& band,
1870 bool interferencesExpected)
1871{
1872 NS_LOG_FUNCTION(this << phy << band << interferencesExpected);
1873 PointerValue ptr;
1874 phy->GetAttribute("InterferenceHelper", ptr);
1875 auto interferenceHelper = DynamicCast<InterferenceHelper>(ptr.Get<InterferenceHelper>());
1876 NS_ASSERT(interferenceHelper);
1877 const auto energyDuration = interferenceHelper->GetEnergyDuration(Watt_u{0}, band);
1878 NS_TEST_ASSERT_MSG_EQ(energyDuration.IsStrictlyPositive(),
1879 interferencesExpected,
1880 "Incorrect interferences detection");
1881}
1882
1883void
1885 std::size_t index,
1886 uint32_t expectedNumRx,
1887 uint32_t expectedNumRxSuccess,
1888 uint32_t expectedRxBytes,
1889 FrequencyRange expectedFrequencyRangeActiveRfInterface,
1890 const std::vector<std::size_t>& expectedConnectedPhysPerChannel)
1891{
1892 NS_LOG_FUNCTION(this << index << expectedNumRx << expectedNumRxSuccess << expectedRxBytes
1893 << expectedFrequencyRangeActiveRfInterface);
1894 const auto phy = m_rxPhys.at(index);
1895 std::size_t numActiveInterfaces = 0;
1896 for (const auto& [freqRange, interface] : phy->GetSpectrumPhyInterfaces())
1897 {
1898 const auto expectedActive = (freqRange == expectedFrequencyRangeActiveRfInterface);
1899 const auto isActive = (interface == phy->GetCurrentInterface());
1900 NS_TEST_ASSERT_MSG_EQ(isActive, expectedActive, "Incorrect active interface");
1901 if (isActive)
1902 {
1903 numActiveInterfaces++;
1904 }
1905 }
1906 NS_TEST_ASSERT_MSG_EQ(numActiveInterfaces, 1, "There should always be one active interface");
1907 NS_ASSERT(expectedConnectedPhysPerChannel.size() == m_spectrumChannels.size());
1908 for (std::size_t i = 0; i < m_spectrumChannels.size(); ++i)
1909 {
1910 NS_TEST_ASSERT_MSG_EQ(m_spectrumChannels.at(i)->GetNDevices(),
1911 expectedConnectedPhysPerChannel.at(i),
1912 "Incorrect number of PHYs attached to the spectrum channel");
1913 }
1914 NS_TEST_ASSERT_MSG_EQ(m_counts.at(index), expectedNumRx, "Unexpected amount of RX events");
1916 expectedNumRxSuccess,
1917 "Unexpected amount of successfully received packets");
1919 0,
1920 "Unexpected amount of unsuccessfully received packets");
1921 NS_TEST_ASSERT_MSG_EQ(m_listeners.at(index)->m_notifyRxStart,
1922 expectedNumRxSuccess,
1923 "Unexpected amount of RX payload start indication");
1924}
1925
1926void
1928 bool expectedCcaBusyIndication,
1929 Time timeBeforeChannelSwitchStarted,
1930 Time propagationDelay)
1931{
1932 const auto expectedCcaBusyStart =
1933 expectedCcaBusyIndication
1934 ? m_lastTxStart + timeBeforeChannelSwitchStarted + m_switchingDelay
1935 : Seconds(0);
1936 const auto expectedCcaBusyEnd =
1937 expectedCcaBusyIndication ? m_lastTxEnd + propagationDelay : Seconds(0);
1938 NS_LOG_FUNCTION(this << index << expectedCcaBusyIndication << expectedCcaBusyStart
1939 << expectedCcaBusyEnd);
1940 auto& listener = m_listeners.at(index);
1941 const auto ccaBusyIndication = (listener->m_notifyMaybeCcaBusyStart > 0);
1942 const auto ccaBusyStart = listener->m_ccaBusyStart;
1943 const auto ccaBusyEnd = listener->m_ccaBusyEnd;
1944 NS_TEST_ASSERT_MSG_EQ(ccaBusyIndication,
1945 expectedCcaBusyIndication,
1946 "CCA busy indication check failed");
1947 NS_TEST_ASSERT_MSG_EQ(ccaBusyStart, expectedCcaBusyStart, "CCA busy start mismatch");
1948 NS_TEST_ASSERT_MSG_EQ(ccaBusyEnd, expectedCcaBusyEnd, "CCA busy end mismatch");
1949}
1950
1951void
1953{
1954 NS_LOG_FUNCTION(this << phy << rxingExpected);
1955 PointerValue ptr;
1956 phy->GetAttribute("InterferenceHelper", ptr);
1957 auto interferenceHelper = DynamicCast<ExtInterferenceHelper>(ptr.Get<ExtInterferenceHelper>());
1958 NS_ASSERT(interferenceHelper);
1959 NS_TEST_ASSERT_MSG_EQ(interferenceHelper->IsRxing(), rxingExpected, "Incorrect rxing state");
1960}
1961
1962void
1964{
1965 NS_LOG_FUNCTION(this);
1966 for (auto& count : m_counts)
1967 {
1968 count = 0;
1969 }
1970 for (auto& listener : m_listeners)
1971 {
1972 listener->Reset();
1973 }
1974 // restore all RX PHYs to initial channels
1975 for (std::size_t rxPhyIndex = 0; rxPhyIndex < m_rxPhys.size(); ++rxPhyIndex)
1976 {
1977 auto txPhy = m_txPhys.at(rxPhyIndex);
1978 SwitchChannel(m_rxPhys.at(rxPhyIndex),
1979 txPhy->GetPhyBand(),
1980 txPhy->GetChannelNumber(),
1981 txPhy->GetChannelWidth(),
1982 rxPhyIndex);
1983 }
1984 // reset counters
1985 for (auto& countRxSuccess : m_countRxSuccess)
1986 {
1987 countRxSuccess = 0;
1988 }
1989 for (auto& countRxFailure : m_countRxFailure)
1990 {
1991 countRxFailure = 0;
1992 }
1993 for (auto& rxBytes : m_rxBytes)
1994 {
1995 rxBytes = 0;
1996 }
1997}
1998
1999void
2001{
2002 NS_LOG_FUNCTION(this);
2003
2004 // WifiHelper::EnableLogComponents();
2005 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
2006
2007 NodeContainer wifiApNode(1);
2008 NodeContainer wifiStaNode(1);
2009
2010 WifiHelper wifi;
2011 wifi.SetStandard(WIFI_STANDARD_80211be);
2012
2013 SpectrumWifiPhyHelper phyHelper(4);
2014 phyHelper.SetInterferenceHelper("ns3::ExtInterferenceHelper");
2016
2017 struct SpectrumPhyInterfaceInfo
2018 {
2019 FrequencyRange range; ///< frequency range covered by the interface
2020 uint8_t number; ///< channel number the interface operates on
2021 WifiPhyBand band; ///< PHY band the interface operates on
2022 std::string bandName; ///< name of the PHY band the interface operates on
2023 };
2024
2025 const FrequencyRange WIFI_SPECTRUM_5_GHZ_LOW{
2026 WIFI_SPECTRUM_5_GHZ.minFrequency,
2027 WIFI_SPECTRUM_5_GHZ.minFrequency +
2028 ((WIFI_SPECTRUM_5_GHZ.maxFrequency - WIFI_SPECTRUM_5_GHZ.minFrequency) / 2)};
2029 const FrequencyRange WIFI_SPECTRUM_5_GHZ_HIGH{
2030 WIFI_SPECTRUM_5_GHZ.minFrequency +
2031 ((WIFI_SPECTRUM_5_GHZ.maxFrequency - WIFI_SPECTRUM_5_GHZ.minFrequency) / 2),
2032 WIFI_SPECTRUM_5_GHZ.maxFrequency};
2033
2034 const std::vector<SpectrumPhyInterfaceInfo> interfaces{
2035 {WIFI_SPECTRUM_2_4_GHZ, 2, WIFI_PHY_BAND_2_4GHZ, "BAND_2_4GHZ"},
2036 {WIFI_SPECTRUM_5_GHZ_LOW, 42, WIFI_PHY_BAND_5GHZ, "BAND_5GHZ"},
2037 {WIFI_SPECTRUM_5_GHZ_HIGH, 163, WIFI_PHY_BAND_5GHZ, "BAND_5GHZ"},
2038 {WIFI_SPECTRUM_6_GHZ, 215, WIFI_PHY_BAND_6GHZ, "BAND_6GHZ"}};
2039
2040 for (std::size_t i = 0; i < interfaces.size(); ++i)
2041 {
2042 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
2044 spectrumChannel->SetPropagationDelayModel(delayModel);
2045 std::ostringstream oss;
2046 oss << "{" << +interfaces.at(i).number << ", 0, " << interfaces.at(i).bandName << ", 0}";
2047 phyHelper.Set(i, "ChannelSettings", StringValue(oss.str()));
2048 phyHelper.AddChannel(spectrumChannel, interfaces.at(i).range);
2049 m_spectrumChannels.emplace_back(spectrumChannel);
2050 }
2051
2052 WifiMacHelper mac;
2053 mac.SetType("ns3::ApWifiMac", "BeaconGeneration", BooleanValue(false));
2054 phyHelper.Set("TrackSignalsFromInactiveInterfaces", BooleanValue(false));
2055 auto apDevice = wifi.Install(phyHelper, mac, wifiApNode.Get(0));
2056
2057 mac.SetType("ns3::StaWifiMac", "ActiveProbing", BooleanValue(false));
2058 phyHelper.Set("TrackSignalsFromInactiveInterfaces",
2060 auto staDevice = wifi.Install(phyHelper, mac, wifiStaNode.Get(0));
2061
2062 MobilityHelper mobility;
2063 auto positionAlloc = CreateObject<ListPositionAllocator>();
2064
2065 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
2066 positionAlloc->Add(Vector(10.0, 0.0, 0.0));
2067 mobility.SetPositionAllocator(positionAlloc);
2068
2069 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
2070 mobility.Install(wifiApNode);
2071 mobility.Install(wifiStaNode);
2072
2073 for (std::size_t i = 0; i < interfaces.size(); ++i)
2074 {
2075 auto txPhy =
2076 DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(apDevice.Get(0))->GetPhy(i));
2077 txPhy->SetAttribute("ChannelSwitchDelay", TimeValue(m_switchingDelay));
2078 m_txPhys.push_back(txPhy);
2079
2080 const auto index = m_rxPhys.size();
2081 auto rxPhy =
2082 DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(staDevice.Get(0))->GetPhy(i));
2083 rxPhy->SetAttribute("ChannelSwitchDelay", TimeValue(m_switchingDelay));
2084 rxPhy->TraceConnectWithoutContext(
2085 "PhyRxBegin",
2087
2088 rxPhy->SetReceiveOkCallback(
2090 rxPhy->SetReceiveErrorCallback(
2092
2093 auto listener = std::make_shared<TestPhyListener>();
2094 rxPhy->RegisterListener(listener);
2095 m_listeners.push_back(std::move(listener));
2096
2097 m_rxPhys.push_back(rxPhy);
2098 m_counts.push_back(0);
2099 m_countRxSuccess.push_back(0);
2100 m_countRxFailure.push_back(0);
2101 m_rxBytes.push_back(0);
2102 }
2103}
2104
2105void
2107{
2108 NS_LOG_FUNCTION(this);
2109 for (auto& phy : m_txPhys)
2110 {
2111 phy->Dispose();
2112 phy = nullptr;
2113 }
2114 for (auto& phy : m_rxPhys)
2115 {
2116 phy->Dispose();
2117 phy = nullptr;
2118 }
2120}
2121
2122void
2124{
2125 NS_LOG_FUNCTION(this);
2126
2127 const dBm_u ccaEdThreshold{-62.0}; ///< CCA-ED threshold
2128 const auto txAfterChannelSwitchDelay =
2130 ? 250
2131 : 0); ///< delay in seconds between channel switch is triggered and a
2132 ///< transmission gets started
2133 const auto checkResultsDelay =
2134 Seconds(0.5); ///< delay in seconds between start of test and moment results are verified
2135 const auto flushResultsDelay =
2136 Seconds(0.9); ///< delay in seconds between start of test and moment results are flushed
2137 const auto txOngoingAfterTxStartedDelay =
2138 MicroSeconds(50); ///< delay in microseconds between a transmission has started and a point
2139 ///< in time the transmission is ongoing
2140 const auto propagationDelay = NanoSeconds(33); // propagation delay for the test scenario
2141
2142 Time delay{0};
2143
2144 // default channels active for all PHYs: each PHY only receives from its associated TX
2145 std::vector<std::size_t> expectedConnectedPhysPerChannel =
2146 m_trackSignalsInactiveInterfaces ? std::vector<std::size_t>{5, 5, 5, 5}
2147 : // all RX PHYs keep all channels active when tracking
2148 // interferences on inactive interfaces
2149 std::vector<std::size_t>{2, 2, 2, 2}; // default channels active for all PHYs: each PHY
2150 // only receives from its associated TX
2151
2152 for (std::size_t i = 0; i < 4; ++i)
2153 {
2154 auto txPpduPhy = m_txPhys.at(i);
2155 delay += Seconds(1);
2156 Simulator::Schedule(delay,
2158 this,
2159 txPpduPhy,
2160 dBm_u{0},
2161 1000);
2162 for (std::size_t j = 0; j < 4; ++j)
2163 {
2164 auto txPhy = m_txPhys.at(j);
2165 auto rxPhy = m_rxPhys.at(j);
2166 const auto& expectedFreqRange = txPhy->GetCurrentFrequencyRange();
2167 Simulator::Schedule(delay + txOngoingAfterTxStartedDelay,
2169 this,
2170 rxPhy,
2171 txPpduPhy->GetCurrentFrequencyRange(),
2172 txPpduPhy->GetBand(txPpduPhy->GetChannelWidth(), 0),
2173 true);
2174 Simulator::Schedule(delay + checkResultsDelay,
2176 this,
2177 j,
2178 (i == j) ? 1 : 0,
2179 (i == j) ? 1 : 0,
2180 (i == j) ? 1000 : 0,
2181 expectedFreqRange,
2182 expectedConnectedPhysPerChannel);
2183 }
2184 Simulator::Schedule(delay + flushResultsDelay,
2186 this);
2187 }
2188
2189 // same channel active for all PHYs: all PHYs receive from TX
2190 for (std::size_t i = 0; i < 4; ++i)
2191 {
2192 delay += Seconds(1);
2193 auto txPpduPhy = m_txPhys.at(i);
2194 Simulator::Schedule(delay + txAfterChannelSwitchDelay,
2196 this,
2197 txPpduPhy,
2198 dBm_u{0},
2199 1000);
2200 const auto& expectedFreqRange = txPpduPhy->GetCurrentFrequencyRange();
2201 for (std::size_t j = 0; j < 4; ++j)
2202 {
2204 {
2205 for (std::size_t k = 0; k < expectedConnectedPhysPerChannel.size(); ++k)
2206 {
2207 expectedConnectedPhysPerChannel.at(k) = (k == i) ? 5 : 1;
2208 }
2209 }
2210 auto rxPhy = m_rxPhys.at(j);
2211 Simulator::Schedule(delay,
2213 this,
2214 rxPhy,
2215 txPpduPhy->GetPhyBand(),
2216 txPpduPhy->GetChannelNumber(),
2217 txPpduPhy->GetChannelWidth(),
2218 j);
2219 Simulator::Schedule(delay + txAfterChannelSwitchDelay + txOngoingAfterTxStartedDelay,
2221 this,
2222 rxPhy,
2223 txPpduPhy->GetCurrentFrequencyRange(),
2224 txPpduPhy->GetBand(txPpduPhy->GetChannelWidth(), 0),
2225 true);
2226 Simulator::Schedule(delay + checkResultsDelay,
2228 this,
2229 j,
2230 1,
2231 1,
2232 1000,
2233 expectedFreqRange,
2234 expectedConnectedPhysPerChannel);
2235 }
2236 Simulator::Schedule(delay + flushResultsDelay,
2238 this);
2239 }
2240
2241 // Switch all PHYs to channel 36: all PHYs switch to the second spectrum channel
2242 // since second spectrum channel is 42 (80 MHz) and hence covers channel 36 (20 MHz)
2243 const auto secondSpectrumChannelIndex = 1;
2244 auto channel36TxPhy = m_txPhys.at(secondSpectrumChannelIndex);
2245 const auto& expectedFreqRange = channel36TxPhy->GetCurrentFrequencyRange();
2246 for (std::size_t i = 0; i < 4; ++i)
2247 {
2248 delay += Seconds(1);
2249 auto txPpduPhy = m_txPhys.at(i);
2250 Simulator::Schedule(delay + txAfterChannelSwitchDelay,
2252 this,
2253 txPpduPhy,
2254 dBm_u{0},
2255 1000);
2256 for (std::size_t j = 0; j < 4; ++j)
2257 {
2259 {
2260 for (std::size_t k = 0; k < expectedConnectedPhysPerChannel.size(); ++k)
2261 {
2262 expectedConnectedPhysPerChannel.at(k) =
2263 (k == secondSpectrumChannelIndex) ? 5 : 1;
2264 }
2265 }
2266 Simulator::Schedule(delay,
2268 this,
2269 m_rxPhys.at(j),
2273 j);
2274 Simulator::Schedule(delay + checkResultsDelay,
2276 this,
2277 j,
2278 (i == secondSpectrumChannelIndex) ? 1 : 0,
2279 (i == secondSpectrumChannelIndex) ? 1 : 0,
2280 (i == secondSpectrumChannelIndex) ? 1000 : 0,
2281 expectedFreqRange,
2282 expectedConnectedPhysPerChannel);
2283 }
2284 Simulator::Schedule(delay + flushResultsDelay,
2286 this);
2287 }
2288
2289 // verify CCA indication when switching to a channel with an ongoing transmission
2290 for (const auto txPower : {dBm_u{-60} /* above CCA-ED */, dBm_u{-70} /* below CCA-ED */})
2291 {
2292 for (std::size_t i = 0; i < 4; ++i)
2293 {
2294 for (std::size_t j = 0; j < 4; ++j)
2295 {
2296 auto txPpduPhy = m_txPhys.at(i);
2297 const auto startChannel = WifiPhyOperatingChannel::FindFirst(
2298 txPpduPhy->GetPrimaryChannelNumber(MHz_u{20}),
2299 MHz_u{0},
2300 MHz_u{20},
2302 txPpduPhy->GetPhyBand());
2303 for (auto bw = txPpduPhy->GetChannelWidth(); bw >= MHz_u{20}; bw /= 2)
2304 {
2305 if ((j == i) && (bw == m_rxPhys.at(j)->GetChannelWidth()))
2306 {
2307 // this test is not interested in RX PHY staying on the same channel as TX
2308 // PHY
2309 break;
2310 }
2311 const auto& channelInfo =
2313 MHz_u{0},
2314 bw,
2316 txPpduPhy->GetPhyBand(),
2317 startChannel));
2318 delay += Seconds(1);
2319 Simulator::Schedule(delay,
2321 this,
2322 txPpduPhy,
2323 txPower,
2324 1000);
2325 Simulator::Schedule(delay + txOngoingAfterTxStartedDelay,
2327 this,
2328 m_rxPhys.at(j),
2329 channelInfo.band,
2330 channelInfo.number,
2331 channelInfo.width,
2332 j);
2333 for (std::size_t k = 0; k < 4; ++k)
2334 {
2335 if ((i != j) && (k == i))
2336 {
2337 continue;
2338 }
2339 const auto expectCcaBusyIndication =
2340 (k == i) ? (txPower >= ccaEdThreshold)
2342 ? ((txPower >= ccaEdThreshold) ? (j == k) : false)
2343 : false);
2345 delay + checkResultsDelay,
2347 this,
2348 k,
2349 expectCcaBusyIndication,
2350 txOngoingAfterTxStartedDelay,
2351 propagationDelay);
2352 }
2353 Simulator::Schedule(delay + flushResultsDelay,
2355 this);
2356 }
2357 }
2358 }
2359 }
2360
2362 {
2363 /* Reproduce an EMLSR scenario where a PHY is on an initial band and receives a packet.
2364 * Then, the PHY switches to another band where it starts receiving another packet.
2365 * During reception of the PHY header, the PHY switches back to the initial band and starts
2366 * receiving yet another packet. In this case, first and last packets should be successfully
2367 * received (no interference), the second packet reception has been interrupted (before the
2368 * payload reception does start, hence it does not reach the RX state). */
2369 {
2370 // first TX on initial band
2371 auto txPpduPhy = m_txPhys.at(0);
2372 delay += Seconds(1);
2373 Simulator::Schedule(delay,
2375 this,
2376 txPpduPhy,
2377 dBm_u{20},
2378 500);
2379
2380 // switch channel to other band
2381 delay += Seconds(1);
2382 txPpduPhy = m_txPhys.at(1);
2383 Simulator::Schedule(delay,
2385 this,
2386 m_rxPhys.at(0),
2387 txPpduPhy->GetPhyBand(),
2388 txPpduPhy->GetChannelNumber(),
2389 txPpduPhy->GetChannelWidth(),
2390 0);
2391
2392 // TX on other band
2393 delay += Seconds(1);
2394 Simulator::Schedule(delay,
2396 this,
2397 txPpduPhy,
2398 dBm_u{0},
2399 1000);
2400
2401 // switch back to initial band during PHY header reception
2402 txPpduPhy = m_txPhys.at(0);
2403 delay += MicroSeconds(20); // right after legacy PHY header reception
2404 Simulator::Schedule(delay,
2406 this,
2407 m_rxPhys.at(0),
2408 txPpduPhy->GetPhyBand(),
2409 txPpduPhy->GetChannelNumber(),
2410 txPpduPhy->GetChannelWidth(),
2411 0);
2412
2413 // TX once more on the initial band
2414 delay += Seconds(1);
2415 Simulator::Schedule(delay,
2417 this,
2418 txPpduPhy,
2419 dBm_u{0},
2420 1500);
2421
2422 // check results
2424 delay + checkResultsDelay,
2426 this,
2427 0,
2428 3, // 3 RX events
2429 2, // 2 packets should have been successfully received, 1 packet should
2430 // have been interrupted (switch during PHY header reception)
2431 2000, // 500 bytes (firstpacket) and 1500 bytes (third packet)
2432 txPpduPhy->GetCurrentFrequencyRange(),
2433 expectedConnectedPhysPerChannel);
2434
2435 // reset
2436 Simulator::Schedule(delay + flushResultsDelay,
2438 this);
2439 }
2440
2441 /* Reproduce an EMLSR scenario where a PHY is on an initial band and receives a packet
2442 * but switches to another band during preamble detection period. Then, it starts receiving
2443 * two packets which interfere with each other. Afterwards, the PHY goes back to its initial
2444 * band and starts receiving yet another packet. In this case, only the last packet should
2445 * be successfully received (no interference). */
2446 {
2447 // switch channel of PHY index 0 to 5 GHz low band (operating channel of TX PHY index 1)
2448 auto txPpduPhy = m_txPhys.at(1);
2449 delay += Seconds(1);
2450 Simulator::Schedule(delay,
2452 this,
2453 m_rxPhys.at(0),
2454 txPpduPhy->GetPhyBand(),
2455 txPpduPhy->GetChannelNumber(),
2456 txPpduPhy->GetChannelWidth(),
2457 0);
2458
2459 // start transmission on 5 GHz low band
2460 delay += Seconds(1);
2461 Simulator::Schedule(delay,
2463 this,
2464 txPpduPhy,
2465 dBm_u{20},
2466 500);
2467
2468 // switch channel back to previous channel before preamble detection is finished:
2469 // this is needed to verify interference helper rxing state is properly reset
2470 // since ongoing reception is aborted when switching operating channel
2473 this,
2474 m_rxPhys.at(0),
2475 m_txPhys.at(0)->GetPhyBand(),
2476 m_txPhys.at(0)->GetChannelNumber(),
2477 m_txPhys.at(0)->GetChannelWidth(),
2478 0);
2479
2480 delay += Seconds(1);
2481 // we need 2 TX PHYs on the 5 GHz low band to have simultaneous transmissions
2482 // switch operating channel of TX PHY index 2 to the 5 GHz low band
2483 Simulator::Schedule(delay,
2485 this,
2486 m_txPhys.at(2),
2487 txPpduPhy->GetPhyBand(),
2488 txPpduPhy->GetChannelNumber(),
2489 txPpduPhy->GetChannelWidth(),
2490 std::nullopt);
2491
2492 // first transmission on 5 GHz low band with high power
2493 delay += Seconds(1);
2494 Simulator::Schedule(delay,
2496 this,
2497 txPpduPhy,
2498 dBm_u{20},
2499 1000);
2500
2501 // second transmission on 5 GHz low band with high power a bit later:
2502 // first powers get updated updated in the corresponding bands
2503 txPpduPhy = m_txPhys.at(2);
2504 Simulator::Schedule(delay + NanoSeconds(10),
2506 this,
2507 txPpduPhy,
2508 dBm_u{20},
2509 1000);
2510
2511 // restore channel for TX PHY index 2
2512 delay += Seconds(1);
2513 Simulator::Schedule(delay,
2515 this,
2516 m_txPhys.at(2),
2517 m_rxPhys.at(2)->GetPhyBand(),
2518 m_rxPhys.at(2)->GetChannelNumber(),
2519 m_rxPhys.at(2)->GetChannelWidth(),
2520 std::nullopt);
2521
2522 // switch channel of PHY index 0 to 5 GHz low band again
2523 delay += Seconds(1);
2524 txPpduPhy = m_txPhys.at(1);
2525 Simulator::Schedule(delay,
2527 this,
2528 m_rxPhys.at(0),
2529 txPpduPhy->GetPhyBand(),
2530 txPpduPhy->GetChannelNumber(),
2531 txPpduPhy->GetChannelWidth(),
2532 0);
2533
2534 // transmit PPDU on 5 GHz low band (no interference)
2535 delay += Seconds(1);
2536 Simulator::Schedule(delay,
2538 this,
2539 txPpduPhy,
2540 dBm_u{0},
2541 1500);
2542
2543 // check results
2544 Simulator::Schedule(delay + checkResultsDelay,
2546 this,
2547 0,
2548 1, // 1 RX event
2549 1, // last transmitted packet should have been successfully received
2550 1500, // 1500 bytes (payload of last transmitted packet)
2551 txPpduPhy->GetCurrentFrequencyRange(),
2552 expectedConnectedPhysPerChannel);
2553
2554 // reset
2555 Simulator::Schedule(delay + flushResultsDelay,
2557 this);
2558 }
2559 }
2560
2561 delay += Seconds(1);
2562 Simulator::Stop(delay);
2564}
2565
2566/**
2567 * @ingroup wifi-test
2568 * @ingroup tests
2569 *
2570 * @brief Spectrum Wifi Phy Interfaces Helper Test
2571 *
2572 * This test checks the expected interfaces are added to the spectrum PHY instances
2573 * created by the helper.
2574 */
2576{
2577 public:
2580
2581 private:
2582 void DoRun() override;
2583};
2584
2586 : TestCase("Check PHY interfaces added to PHY instances using helper")
2587{
2588}
2589
2590void
2592{
2593 WifiHelper wifiHelper;
2595
2596 SpectrumWifiPhyHelper phyHelper(3);
2597 phyHelper.Set(0, "ChannelSettings", StringValue("{2, 0, BAND_2_4GHZ, 0}"));
2598 phyHelper.Set(1, "ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}"));
2599 phyHelper.Set(2, "ChannelSettings", StringValue("{1, 0, BAND_6GHZ, 0}"));
2600
2604
2605 WifiMacHelper macHelper;
2607
2608 /* Default case: all interfaces are added to each link */
2609 auto device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(0));
2610
2611 // Verify each PHY has 3 interfaces
2612 auto phyLink0 =
2614 NS_ASSERT(phyLink0);
2615 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
2616 3,
2617 "Incorrect number of PHY interfaces added to PHY link ID 0");
2618
2619 auto phyLink1 =
2621 NS_ASSERT(phyLink1);
2622 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
2623 3,
2624 "Incorrect number of PHY interfaces added to PHY link ID 1");
2625
2626 auto phyLink2 =
2628 NS_ASSERT(phyLink2);
2629 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
2630 3,
2631 "Incorrect number of PHY interfaces added to PHY link ID 2");
2632
2633 /* each PHY has a single interface */
2637 device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(1));
2638
2639 // Verify each PHY has a single interface
2640 phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
2641 NS_ASSERT(phyLink0);
2642 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
2643 1,
2644 "Incorrect number of PHY interfaces added to PHY link ID 0");
2645 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
2646 1,
2647 "Incorrect PHY interfaces added to PHY link ID 0");
2648
2649 phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
2650 NS_ASSERT(phyLink1);
2651 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
2652 1,
2653 "Incorrect number of PHY interfaces added to PHY link ID 1");
2654 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2655 1,
2656 "Incorrect PHY interfaces added to PHY link ID 1");
2657
2658 phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
2659 NS_ASSERT(phyLink2);
2660 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
2661 1,
2662 "Incorrect number of PHY interfaces added to PHY link ID 2");
2663 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
2664 1,
2665 "Incorrect PHY interfaces added to PHY link ID 2");
2666
2667 /* add yet another interface to PHY 0 */
2669 device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(2));
2670
2671 // Verify each PHY has a single interface except PHY 0 that should have 2 interfaces
2672 phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
2673 NS_ASSERT(phyLink0);
2674 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
2675 2,
2676 "Incorrect number of PHY interfaces added to PHY link ID 0");
2677 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
2678 1,
2679 "Incorrect PHY interfaces added to PHY link ID 0");
2680 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2681 1,
2682 "Incorrect PHY interfaces added to PHY link ID 0");
2683
2684 phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
2685 NS_ASSERT(phyLink1);
2686 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
2687 1,
2688 "Incorrect number of PHY interfaces added to PHY link ID 1");
2689 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2690 1,
2691 "Incorrect PHY interfaces added to PHY link ID 1");
2692
2693 phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
2694 NS_ASSERT(phyLink2);
2695 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
2696 1,
2697 "Incorrect number of PHY interfaces added to PHY link ID 2");
2698 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
2699 1,
2700 "Incorrect PHY interfaces added to PHY link ID 2");
2701
2702 /* reset mapping previously configured to helper: back to default */
2703 phyHelper.ResetPhyToFreqRangeMapping();
2704 device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(3));
2705
2706 // Verify each PHY has 3 interfaces
2707 phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
2708 NS_ASSERT(phyLink0);
2709 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
2710 3,
2711 "Incorrect number of PHY interfaces added to PHY link ID 0");
2712 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
2713 1,
2714 "Incorrect PHY interfaces added to PHY link ID 0");
2715 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2716 1,
2717 "Incorrect PHY interfaces added to PHY link ID 0");
2718 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
2719 1,
2720 "Incorrect PHY interfaces added to PHY link ID 0");
2721
2722 phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
2723 NS_ASSERT(phyLink1);
2724 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
2725 3,
2726 "Incorrect number of PHY interfaces added to PHY link ID 1");
2727 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
2728 1,
2729 "Incorrect PHY interfaces added to PHY link ID 0");
2730 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2731 1,
2732 "Incorrect PHY interfaces added to PHY link ID 0");
2733 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
2734 1,
2735 "Incorrect PHY interfaces added to PHY link ID 0");
2736
2737 phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
2738 NS_ASSERT(phyLink2);
2739 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
2740 3,
2741 "Incorrect number of PHY interfaces added to PHY link ID 2");
2742 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
2743 1,
2744 "Incorrect PHY interfaces added to PHY link ID 0");
2745 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
2746 1,
2747 "Incorrect PHY interfaces added to PHY link ID 0");
2748 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
2749 1,
2750 "Incorrect PHY interfaces added to PHY link ID 0");
2751
2753}
2754
2755/**
2756 * @ingroup wifi-test
2757 * @ingroup tests
2758 *
2759 * @brief Spectrum Wifi Phy Test Suite
2760 */
2762{
2763 public:
2765};
2766
2790
uint32_t v
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.
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 RxSuccessSta(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function for STA.
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 CheckResults(bool expectSuccess)
Verify results.
void Send160MhzPpdu()
Send 160MHz PPDU function.
Spectrum Wifi Phy Basic Test.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void DoRun() override
Implementation to actually run this TestCase.
void SpectrumWifiPhyRxSuccess(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Spectrum wifi receive success function.
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.
Time m_switchingDelay
The switching delay to consider to the test, this has to be lessen than the default one to ensure TX ...
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.
void RxSuccess(std::size_t index, Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Receive success function.
void CheckCcaIndication(std::size_t index, bool expectedCcaBusyIndication, Time timeBeforeChannelSwitchStarted, Time propagationDelay)
Verify CCA indication reported by a given PHY.
bool m_trackSignalsInactiveInterfaces
flag to indicate whether signals coming from inactive spectrum PHY interfaces are tracked during the ...
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 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)
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.
void NotifyRxEndError(const WifiTxVector &txVector) override
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
uint32_t m_notifyRxEndError
notify receive end error
~TestPhyListener() override=default
AttributeValue implementation for Boolean.
Definition boolean.h:26
static WifiMode GetEhtMcs0()
Return MCS 0 from EHT MCS values.
static WifiMode GetHeMcs11()
Return MCS 11 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.
static WifiMode GetOfdmRate6Mbps()
Return a WifiMode for OFDM at 6 Mbps.
AttributeValue implementation for Pointer.
Definition pointer.h:37
Ptr< T > Get() const
Definition pointer.h:224
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:125
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static void Run()
Run the simulation.
Definition simulator.cc:161
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:614
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:169
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.
Hold variables of type string.
Definition string.h:45
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
@ QUICK
Fast test.
Definition test.h:1057
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
Type
Type of test.
Definition test.h:1271
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
Simulation virtual time values and global simulation resolution.
Definition nstime.h:96
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition nstime.h:342
AttributeValue implementation for Time.
Definition nstime.h:1483
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
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.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1574
std::list< WifiChannelConfig::TupleWithoutUnits > ChannelSegments
segments identifying an operating channel
Definition wifi-phy.h:957
WifiChannelConfig::SegmentWithoutUnits ChannelTuple
kept for backward compatibility, can be deprecated when using strong types
Definition wifi-phy.h:954
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=GetFrequencyChannels().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=dBr_u{-20}, dBr_u minOuterband=dBr_u{-28}, dBr_u lowestPoint=dBr_u{-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
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:690
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#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:267
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
#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:454
#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:133
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1415
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1432
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1398
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_EHT_MU
@ 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::map< WifiSpectrumBandInfo, Watt_u > RxPowerWattPerChannelBand
A map of the received power for each band.
dB_u RatioToDb(double ratio)
Convert from ratio to dB.
Definition wifi-utils.cc:45
static constexpr uint8_t WIFI_MIN_TX_PWR_LEVEL
minimum TX power level value
double Hz_u
Hz weak type.
Definition wifi-units.h:30
std::vector< BandInfo > Bands
Container of BandInfo.
dBm_u WToDbm(Watt_u val)
Convert from Watts to dBm.
Definition wifi-utils.cc:38
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Definition wifi-utils.h:145
double dBm_u
dBm weak type
Definition wifi-units.h:27
constexpr FrequencyRange WIFI_SPECTRUM_5_GHZ
Identifier for the frequency range covering the wifi spectrum in the 5 GHz band.
@ WIFI_MAC_QOSDATA
Hz_u MHzToHz(MHz_u val)
Convert from MHz to Hz.
Definition wifi-utils.h:120
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU).
double Watt_u
Watt weak type.
Definition wifi-units.h:25
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.
Struct defining a frequency range between minFrequency and maxFrequency.
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:84
WifiSpectrumBandInfo structure containing info about a spectrum band.