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 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18#include "ns3/boolean.h"
19#include "ns3/constant-position-mobility-model.h"
20#include "ns3/he-phy.h" //includes OFDM PHY
21#include "ns3/interference-helper.h"
22#include "ns3/log.h"
23#include "ns3/mobility-helper.h"
24#include "ns3/multi-model-spectrum-channel.h"
25#include "ns3/nist-error-rate-model.h"
26#include "ns3/ofdm-ppdu.h"
27#include "ns3/pointer.h"
28#include "ns3/spectrum-wifi-helper.h"
29#include "ns3/spectrum-wifi-phy.h"
30#include "ns3/string.h"
31#include "ns3/test.h"
32#include "ns3/wifi-mac-header.h"
33#include "ns3/wifi-net-device.h"
34#include "ns3/wifi-phy-listener.h"
35#include "ns3/wifi-psdu.h"
36#include "ns3/wifi-spectrum-phy-interface.h"
37#include "ns3/wifi-spectrum-signal-parameters.h"
38#include "ns3/wifi-spectrum-value-helper.h"
39#include "ns3/wifi-utils.h"
40
41#include <memory>
42#include <optional>
43#include <tuple>
44#include <vector>
45
46using namespace ns3;
47
48NS_LOG_COMPONENT_DEFINE("SpectrumWifiPhyTest");
49
50static const uint8_t CHANNEL_NUMBER = 36;
51static const uint16_t CHANNEL_WIDTH = 20; // MHz
52static const uint16_t GUARD_WIDTH =
53 CHANNEL_WIDTH; // MHz (expanded to channel width to model spectrum mask)
54
55/**
56 * Extended SpectrumWifiPhy class for the purpose of the tests.
57 */
59{
60 public:
61 using WifiPhy::GetBand;
62};
63
64/**
65 * Extended InterferenceHelper class for the purpose of the tests.
66 */
68{
69 public:
70 /**
71 * \brief Get the type ID.
72 * \return the object TypeId
73 */
75 {
76 static TypeId tid = TypeId("ns3::ExtInterferenceHelper")
78 .SetGroupName("Wifi")
79 .AddConstructor<ExtInterferenceHelper>();
80 return tid;
81 }
82
83 /**
84 * Indicate whether the interference helper is in receiving state
85 *
86 * \return true if the interference helper is in receiving state, false otherwise
87 */
88 bool IsRxing() const
89 {
90 return std::any_of(m_rxing.cbegin(), m_rxing.cend(), [](const auto& rxing) {
91 return rxing.second;
92 });
93 }
94};
95
97
98/**
99 * \ingroup wifi-test
100 * \ingroup tests
101 *
102 * \brief Spectrum Wifi Phy Basic Test
103 */
105{
106 public:
108 /**
109 * Constructor
110 *
111 * \param name reference name
112 */
113 SpectrumWifiPhyBasicTest(std::string name);
114 ~SpectrumWifiPhyBasicTest() override;
115
116 protected:
117 void DoSetup() override;
118 void DoTeardown() override;
120 /**
121 * Make signal function
122 * \param txPowerWatts the transmit power in watts
123 * \param channel the operating channel of the PHY used for the transmission
124 * \returns Ptr<SpectrumSignalParameters>
125 */
126 Ptr<SpectrumSignalParameters> MakeSignal(double txPowerWatts,
127 const WifiPhyOperatingChannel& channel);
128 /**
129 * Send signal function
130 * \param txPowerWatts the transmit power in watts
131 */
132 void SendSignal(double txPowerWatts);
133 /**
134 * Spectrum wifi receive success function
135 * \param psdu the PSDU
136 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
137 * \param txVector the transmit vector
138 * \param statusPerMpdu reception status per MPDU
139 */
141 RxSignalInfo rxSignalInfo,
142 WifiTxVector txVector,
143 std::vector<bool> statusPerMpdu);
144 /**
145 * Spectrum wifi receive failure function
146 * \param psdu the PSDU
147 */
149 uint32_t m_count; ///< count
150
151 private:
152 void DoRun() override;
153
154 uint64_t m_uid; //!< the UID to use for the PPDU
155};
156
158 : SpectrumWifiPhyBasicTest("SpectrumWifiPhy test case receives one packet")
159{
160}
161
163 : TestCase(name),
164 m_count(0),
165 m_uid(0)
166{
167}
168
169// Make a Wi-Fi signal to inject directly to the StartRx() method
172{
174 0,
176 800,
177 1,
178 1,
179 0,
181 false);
182
183 Ptr<Packet> pkt = Create<Packet>(1000);
184 WifiMacHeader hdr;
185
187 hdr.SetQosTid(0);
188
189 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
190 Time txDuration = m_phy->CalculateTxDuration(psdu->GetSize(), txVector, m_phy->GetPhyBand());
191
192 Ptr<WifiPpdu> ppdu = Create<OfdmPpdu>(psdu, txVector, channel, m_uid++);
193
195 channel.GetPrimaryChannelCenterFrequency(CHANNEL_WIDTH),
197 txPowerWatts,
199 Ptr<WifiSpectrumSignalParameters> txParams = Create<WifiSpectrumSignalParameters>();
200 txParams->psd = txPowerSpectrum;
201 txParams->txPhy = nullptr;
202 txParams->duration = txDuration;
203 txParams->ppdu = ppdu;
204
205 return txParams;
206}
207
208// Make a Wi-Fi signal to inject directly to the StartRx() method
209void
211{
212 m_phy->StartRx(MakeSignal(txPowerWatts, m_phy->GetOperatingChannel()), nullptr);
213}
214
215void
217 RxSignalInfo rxSignalInfo,
218 WifiTxVector txVector,
219 std::vector<bool> statusPerMpdu)
220{
221 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
222 m_count++;
223}
224
225void
227{
228 NS_LOG_FUNCTION(this << *psdu);
229 m_count++;
230}
231
233{
234}
235
236// Create necessary objects, and inject signals. Test that the expected
237// number of packet receptions occur.
238void
240{
241 Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
242 Ptr<Node> node = CreateObject<Node>();
243 Ptr<WifiNetDevice> dev = CreateObject<WifiNetDevice>();
244 m_phy = CreateObject<SpectrumWifiPhy>();
245 Ptr<InterferenceHelper> interferenceHelper = CreateObject<InterferenceHelper>();
246 m_phy->SetInterferenceHelper(interferenceHelper);
247 Ptr<ErrorRateModel> error = CreateObject<NistErrorRateModel>();
248 m_phy->SetErrorRateModel(error);
249 m_phy->SetDevice(dev);
250 m_phy->AddChannel(spectrumChannel);
257 dev->SetPhy(m_phy);
258 node->AddDevice(dev);
259}
260
261void
263{
264 m_phy->Dispose();
265 m_phy = nullptr;
266}
267
268// Test that the expected number of packet receptions occur.
269void
271{
272 double txPowerWatts = 0.010;
273 // Send packets spaced 1 second apart; all should be received
277 // Send packets spaced 1 microsecond second apart; none should be received (PHY header reception
278 // failure)
281 this,
282 txPowerWatts);
285 this,
286 txPowerWatts);
289
290 NS_TEST_ASSERT_MSG_EQ(m_count, 3, "Didn't receive right number of packets");
291}
292
293/**
294 * \ingroup wifi-test
295 * \ingroup tests
296 *
297 * \brief Test Phy Listener
298 */
300{
301 public:
302 /**
303 * Create a test PhyListener
304 */
305 TestPhyListener() = default;
306 ~TestPhyListener() override = default;
307
308 void NotifyRxStart(Time duration) override
309 {
310 NS_LOG_FUNCTION(this << duration);
312 }
313
314 void NotifyRxEndOk() override
315 {
316 NS_LOG_FUNCTION(this);
318 }
319
320 void NotifyRxEndError() override
321 {
322 NS_LOG_FUNCTION(this);
324 }
325
326 void NotifyTxStart(Time duration, double txPowerDbm) override
327 {
328 NS_LOG_FUNCTION(this << duration << txPowerDbm);
329 }
330
332 WifiChannelListType channelType,
333 const std::vector<Time>& /*per20MhzDurations*/) override
334 {
335 NS_LOG_FUNCTION(this << duration << channelType);
336 if (duration.IsStrictlyPositive())
337 {
340 {
342 }
343 m_ccaBusyEnd = std::max(m_ccaBusyEnd, Simulator::Now() + duration);
344 }
345 }
346
347 void NotifySwitchingStart(Time duration) override
348 {
349 }
350
351 void NotifySleep() override
352 {
353 }
354
355 void NotifyOff() override
356 {
357 }
358
359 void NotifyWakeup() override
360 {
361 }
362
363 void NotifyOn() override
364 {
365 }
366
367 /**
368 * Reset function
369 */
370 void Reset()
371 {
372 NS_LOG_FUNCTION(this);
373 m_notifyRxStart = 0;
374 m_notifyRxEndOk = 0;
379 }
380
381 uint32_t m_notifyRxStart{0}; ///< notify receive start
382 uint32_t m_notifyRxEndOk{0}; ///< notify receive end OK
383 uint32_t m_notifyRxEndError{0}; ///< notify receive end error
384 uint32_t m_notifyMaybeCcaBusyStart{0}; ///< notify maybe CCA busy start
385 Time m_ccaBusyStart{0}; ///< CCA_BUSY start time
386 Time m_ccaBusyEnd{0}; ///< CCA_BUSY end time
387};
388
389/**
390 * \ingroup wifi-test
391 * \ingroup tests
392 *
393 * \brief Spectrum Wifi Phy Listener Test
394 */
396{
397 public:
400
401 private:
402 void DoSetup() override;
403 void DoRun() override;
404 std::shared_ptr<TestPhyListener> m_listener; ///< listener
405};
406
408 : SpectrumWifiPhyBasicTest("SpectrumWifiPhy test operation of WifiPhyListener")
409{
410}
411
413{
414}
415
416void
418{
420 m_listener = std::make_shared<TestPhyListener>();
422}
423
424void
426{
427 double txPowerWatts = 0.010;
430
431 NS_TEST_ASSERT_MSG_EQ(m_count, 1, "Didn't receive right number of packets");
433 m_listener->m_notifyMaybeCcaBusyStart,
434 2,
435 "Didn't receive NotifyCcaBusyStart (once preamble is detected + prolonged by L-SIG "
436 "reception, then switched to Rx by at the beginning of data)");
437 NS_TEST_ASSERT_MSG_EQ(m_listener->m_notifyRxStart, 1, "Didn't receive NotifyRxStart");
438 NS_TEST_ASSERT_MSG_EQ(m_listener->m_notifyRxEndOk, 1, "Didn't receive NotifyRxEnd");
439
441 m_listener.reset();
442}
443
444/**
445 * \ingroup wifi-test
446 * \ingroup tests
447 *
448 * \brief Spectrum Wifi Phy Filter Test
449 */
451{
452 public:
454 /**
455 * Constructor
456 *
457 * \param name reference name
458 */
459 SpectrumWifiPhyFilterTest(std::string name);
461
462 private:
463 void DoSetup() override;
464 void DoTeardown() override;
465 void DoRun() override;
466
467 /**
468 * Run one function
469 */
470 void RunOne();
471
472 /**
473 * Send PPDU function
474 */
475 void SendPpdu();
476
477 /**
478 * Callback triggered when a packet is received by the PHYs
479 * \param p the received packet
480 * \param rxPowersW the received power per channel band in watts
481 */
483
486
487 uint16_t m_txChannelWidth; ///< TX channel width (MHz)
488 uint16_t m_rxChannelWidth; ///< RX channel width (MHz)
489
490 std::set<WifiSpectrumBandIndices> m_ruBands; ///< spectrum bands associated to all the RUs
491};
492
494 : TestCase("SpectrumWifiPhy test RX filters"),
495 m_txChannelWidth(20),
496 m_rxChannelWidth(20)
497{
498}
499
501 : TestCase(name)
502{
503}
504
505void
507{
509 0,
511 800,
512 1,
513 1,
514 0,
516 false,
517 false);
518 Ptr<Packet> pkt = Create<Packet>(1000);
519 WifiMacHeader hdr;
521 hdr.SetQosTid(0);
522 hdr.SetAddr1(Mac48Address("00:00:00:00:00:01"));
523 hdr.SetSequenceNumber(1);
524 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
525 m_txPhy->Send(WifiConstPsduMap({std::make_pair(SU_STA_ID, psdu)}), txVector);
526}
527
529{
530 m_txPhy = nullptr;
531 m_rxPhy = nullptr;
532}
533
534void
536{
537 for (const auto& pair : rxPowersW)
538 {
539 NS_LOG_INFO("band: (" << pair.first << ") -> powerW=" << pair.second << " ("
540 << WToDbm(pair.second) << " dBm)");
541 }
542
543 size_t numBands = rxPowersW.size();
544 size_t expectedNumBands = std::max(1, (m_rxChannelWidth / 20));
545 expectedNumBands += (m_rxChannelWidth / 40);
546 expectedNumBands += (m_rxChannelWidth / 80);
547 expectedNumBands += (m_rxChannelWidth / 160);
548 expectedNumBands += m_ruBands.size();
549
550 NS_TEST_ASSERT_MSG_EQ(numBands,
551 expectedNumBands,
552 "Total number of bands handled by the receiver is incorrect");
553
554 uint16_t channelWidth = std::min(m_txChannelWidth, m_rxChannelWidth);
555 auto band = m_rxPhy->GetBand(channelWidth, 0);
556 auto it = rxPowersW.find(band);
557 NS_LOG_INFO("powerW total band: " << it->second << " (" << WToDbm(it->second) << " dBm)");
558 int totalRxPower = static_cast<int>(WToDbm(it->second) + 0.5);
559 int expectedTotalRxPower;
561 {
562 // PHY sends at 16 dBm, and since there is no loss, this should be the total power at the
563 // receiver.
564 expectedTotalRxPower = 16;
565 }
566 else
567 {
568 // Only a part of the transmitted power is received
569 expectedTotalRxPower =
570 16 - static_cast<int>(RatioToDb(m_txChannelWidth / m_rxChannelWidth));
571 }
572 NS_TEST_ASSERT_MSG_EQ(totalRxPower,
573 expectedTotalRxPower,
574 "Total received power is not correct");
575
576 if ((m_txChannelWidth <= m_rxChannelWidth) && (channelWidth >= 20))
577 {
578 band = m_rxPhy->GetBand(20, 0); // primary 20 MHz
579 it = rxPowersW.find(band);
580 NS_LOG_INFO("powerW in primary 20 MHz channel: " << it->second << " (" << WToDbm(it->second)
581 << " dBm)");
582 int rxPowerPrimaryChannel20 = static_cast<int>(WToDbm(it->second) + 0.5);
583 int expectedRxPowerPrimaryChannel20 = 16 - static_cast<int>(RatioToDb(channelWidth / 20));
584 NS_TEST_ASSERT_MSG_EQ(rxPowerPrimaryChannel20,
585 expectedRxPowerPrimaryChannel20,
586 "Received power in the primary 20 MHz band is not correct");
587 }
588}
589
590void
592{
593 // WifiHelper::EnableLogComponents();
594 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
595
596 Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
597 Ptr<FriisPropagationLossModel> lossModel = CreateObject<FriisPropagationLossModel>();
598 lossModel->SetFrequency(5.180e9);
599 spectrumChannel->AddPropagationLossModel(lossModel);
601 CreateObject<ConstantSpeedPropagationDelayModel>();
602 spectrumChannel->SetPropagationDelayModel(delayModel);
603
604 Ptr<Node> txNode = CreateObject<Node>();
605 Ptr<WifiNetDevice> txDev = CreateObject<WifiNetDevice>();
606 m_txPhy = CreateObject<ExtSpectrumWifiPhy>();
607 Ptr<InterferenceHelper> txInterferenceHelper = CreateObject<InterferenceHelper>();
608 m_txPhy->SetInterferenceHelper(txInterferenceHelper);
609 Ptr<ErrorRateModel> txErrorModel = CreateObject<NistErrorRateModel>();
610 m_txPhy->SetErrorRateModel(txErrorModel);
611 m_txPhy->SetDevice(txDev);
612 m_txPhy->AddChannel(spectrumChannel);
614 Ptr<ConstantPositionMobilityModel> apMobility = CreateObject<ConstantPositionMobilityModel>();
615 m_txPhy->SetMobility(apMobility);
616 txDev->SetPhy(m_txPhy);
617 txNode->AggregateObject(apMobility);
618 txNode->AddDevice(txDev);
619
620 Ptr<Node> rxNode = CreateObject<Node>();
621 Ptr<WifiNetDevice> rxDev = CreateObject<WifiNetDevice>();
622 m_rxPhy = CreateObject<ExtSpectrumWifiPhy>();
623 Ptr<InterferenceHelper> rxInterferenceHelper = CreateObject<InterferenceHelper>();
624 m_rxPhy->SetInterferenceHelper(rxInterferenceHelper);
625 Ptr<ErrorRateModel> rxErrorModel = CreateObject<NistErrorRateModel>();
626 m_rxPhy->SetErrorRateModel(rxErrorModel);
627 m_rxPhy->AddChannel(spectrumChannel);
629 Ptr<ConstantPositionMobilityModel> sta1Mobility = CreateObject<ConstantPositionMobilityModel>();
630 m_rxPhy->SetMobility(sta1Mobility);
631 rxDev->SetPhy(m_rxPhy);
632 rxNode->AggregateObject(sta1Mobility);
633 rxNode->AddDevice(rxDev);
636}
637
638void
640{
641 m_txPhy->Dispose();
642 m_txPhy = nullptr;
643 m_rxPhy->Dispose();
644 m_rxPhy = nullptr;
645}
646
647void
649{
650 uint16_t txFrequency;
651 switch (m_txChannelWidth)
652 {
653 case 20:
654 default:
655 txFrequency = 5180;
656 break;
657 case 40:
658 txFrequency = 5190;
659 break;
660 case 80:
661 txFrequency = 5210;
662 break;
663 case 160:
664 txFrequency = 5250;
665 break;
666 }
667 auto txChannelNum = std::get<0>(*WifiPhyOperatingChannel::FindFirst(0,
668 txFrequency,
674
675 uint16_t rxFrequency;
676 switch (m_rxChannelWidth)
677 {
678 case 20:
679 default:
680 rxFrequency = 5180;
681 break;
682 case 40:
683 rxFrequency = 5190;
684 break;
685 case 80:
686 rxFrequency = 5210;
687 break;
688 case 160:
689 rxFrequency = 5250;
690 break;
691 }
692 auto rxChannelNum = std::get<0>(*WifiPhyOperatingChannel::FindFirst(0,
693 rxFrequency,
699
700 m_ruBands.clear();
701 for (uint16_t bw = 160; bw >= 20; bw = bw / 2)
702 {
703 for (uint16_t i = 0; i < (m_rxChannelWidth / bw); ++i)
704 {
705 for (unsigned int type = 0; type < 7; type++)
706 {
707 auto ruType = static_cast<HeRu::RuType>(type);
708 for (std::size_t index = 1; index <= HeRu::GetNRus(bw, ruType); index++)
709 {
710 HeRu::SubcarrierGroup subcarrierGroup =
711 HeRu::GetSubcarrierGroup(bw, ruType, index);
712 HeRu::SubcarrierRange subcarrierRange =
713 std::make_pair(subcarrierGroup.front().first,
714 subcarrierGroup.back().second);
715 const auto band =
719 subcarrierRange,
720 i);
721 m_ruBands.insert(band);
722 }
723 }
724 }
725 }
726
728
730}
731
732void
734{
735 m_txChannelWidth = 20;
736 m_rxChannelWidth = 20;
737 RunOne();
738
739 m_txChannelWidth = 40;
740 m_rxChannelWidth = 40;
741 RunOne();
742
743 m_txChannelWidth = 80;
744 m_rxChannelWidth = 80;
745 RunOne();
746
747 m_txChannelWidth = 160;
748 m_rxChannelWidth = 160;
749 RunOne();
750
751 m_txChannelWidth = 20;
752 m_rxChannelWidth = 40;
753 RunOne();
754
755 m_txChannelWidth = 20;
756 m_rxChannelWidth = 80;
757 RunOne();
758
759 m_txChannelWidth = 40;
760 m_rxChannelWidth = 80;
761 RunOne();
762
763 m_txChannelWidth = 20;
764 m_rxChannelWidth = 160;
765 RunOne();
766
767 m_txChannelWidth = 40;
768 m_rxChannelWidth = 160;
769 RunOne();
770
771 m_txChannelWidth = 80;
772 m_rxChannelWidth = 160;
773 RunOne();
774
775 m_txChannelWidth = 40;
776 m_rxChannelWidth = 20;
777 RunOne();
778
779 m_txChannelWidth = 80;
780 m_rxChannelWidth = 20;
781 RunOne();
782
783 m_txChannelWidth = 80;
784 m_rxChannelWidth = 40;
785 RunOne();
786
787 m_txChannelWidth = 160;
788 m_rxChannelWidth = 20;
789 RunOne();
790
791 m_txChannelWidth = 160;
792 m_rxChannelWidth = 40;
793 RunOne();
794
795 m_txChannelWidth = 160;
796 m_rxChannelWidth = 80;
797 RunOne();
798
800}
801
802/**
803 * \ingroup wifi-test
804 * \ingroup tests
805 *
806 * \brief Spectrum Wifi Phy Multiple Spectrum Test
807 *
808 * This test is testing the ability to plug multiple spectrum channels to the spectrum wifi PHY.
809 * It considers 4 TX-RX PHY pairs that are independent from each others and are plugged to different
810 * spectrum channels that are covering different frequency range. Each RX PHY is also attached to
811 * each of the other 3 spectrum channels it can switch to.
812 *
813 * In the first scenario, we consider the default case where each TX-RX PHY pairs are operating on
814 * different frequency ranges and hence using independent spectrum channels. We validate that no
815 * packets is received from other TX PHYs attached to different spectrum channels and we also verify
816 * the amount of connected PHYs to each spectrum channel is exactly 2. The test also makes sure each
817 * PHY has only one active spectrum channel and that the active one is operating at the expected
818 * frequency range.
819 *
820 * In the second scenario, we consecutively switch the channel of all RX PHYs to the one of each TX
821 * PHY. We validate that packets are received by all PHYs and we also verify the amount of connected
822 * PHYs to each spectrum channels is either 5 (1 TX PHY and 4 RX PHYs) or 1 (the TX PHY left alone).
823 */
825{
826 public:
827 /// Enumeration for channel switching scenarios
828 enum class ChannelSwitchScenario : uint8_t
829 {
830 BEFORE_TX = 0, //!< start TX after channel switch is completed
831 BETWEEN_TX_RX //!< perform channel switch during propagation delay (after TX and before RX)
832 };
833
834 /**
835 * Constructor
836 *
837 * \param trackSignalsInactiveInterfaces flag to indicate whether signals coming from inactive
838 * spectrum PHY interfaces shall be tracked during the test
839 * \param chanSwitchScenario the channel switching scenario to consider for the test
840 */
841 SpectrumWifiPhyMultipleInterfacesTest(bool trackSignalsInactiveInterfaces,
842 ChannelSwitchScenario chanSwitchScenario);
843
844 private:
845 void DoSetup() override;
846 void DoTeardown() override;
847 void DoRun() override;
848
849 /**
850 * Switch channel function
851 *
852 * \param phy the PHY to switch
853 * \param band the PHY band to use
854 * \param channelNumber number the channel number to use
855 * \param channelWidth the channel width to use
856 * \param listenerIndex index of the listener for that PHY, if PHY is a RX PHY
857 */
859 WifiPhyBand band,
860 uint8_t channelNumber,
861 uint16_t channelWidth,
862 std::optional<std::size_t> listenerIndex);
863
864 /**
865 * Send PPDU function
866 *
867 * \param phy the PHY to transmit the signal
868 * \param txPowerDbm the power in dBm to transmit the signal (this is also the received power
869 * since we do not have propagation loss to simplify)
870 * \param payloadSize the payload size in bytes
871 */
872 void SendPpdu(Ptr<SpectrumWifiPhy> phy, double txPowerDbm, uint32_t payloadSize);
873
874 /**
875 * Callback triggered when a packet is received by a PHY
876 * \param index the index to identify the RX PHY
877 * \param packet the received packet
878 * \param rxPowersW the received power per channel band in watts
879 */
880 void RxCallback(std::size_t index,
881 Ptr<const Packet> packet,
882 RxPowerWattPerChannelBand rxPowersW);
883
884 /**
885 * Receive success function
886 * \param index index of the RX STA
887 * \param psdu the PSDU
888 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
889 * \param txVector the transmit vector
890 * \param statusPerMpdu reception status per MPDU
891 */
892 void RxSuccess(std::size_t index,
894 RxSignalInfo rxSignalInfo,
895 WifiTxVector txVector,
896 std::vector<bool> statusPerMpdu);
897
898 /**
899 * Receive failure function
900 * \param index index of the RX STA
901 * \param psdu the PSDU
902 */
903 void RxFailure(std::size_t index, Ptr<const WifiPsdu> psdu);
904
905 /**
906 * Schedule now to check the interferences
907 * \param phy the PHY for which the check has to be executed
908 * \param freqRange the frequency range for which the check has to be executed
909 * \param band the band for which the check has to be executed
910 * \param interferencesExpected flag whether interferences are expected to have been tracked
911 */
913 const FrequencyRange& freqRange,
914 const WifiSpectrumBandInfo& band,
915 bool interferencesExpected);
916
917 /**
918 * Check the interferences
919 * \param phy the PHY for which the check has to be executed
920 * \param band the band for which the check has to be executed
921 * \param interferencesExpected flag whether interferences are expected to have been tracked
922 */
924 const WifiSpectrumBandInfo& band,
925 bool interferencesExpected);
926
927 /**
928 * Verify results
929 *
930 * \param index the index to identify the RX PHY to check
931 * \param expectedNumRx the expected number of RX events for that PHY
932 * \param expectedNumRxSuccess the expected amount of successfully received packets
933 * \param expectedRxBytes the expected amount of received bytes
934 * \param expectedFrequencyRangeActiveRfInterface the expected frequency range (in MHz) of the
935 * active RF interface
936 * \param expectedConnectedPhysPerChannel the expected
937 * number of PHYs attached for each spectrum channel
938 */
939 void CheckResults(std::size_t index,
940 uint32_t expectedNumRx,
941 uint32_t expectedNumRxSuccess,
942 uint32_t expectedRxBytes,
943 FrequencyRange expectedFrequencyRangeActiveRfInterface,
944 const std::vector<std::size_t>& expectedConnectedPhysPerChannel);
945
946 /**
947 * Verify CCA indication reported by a given PHY
948 *
949 * \param index the index to identify the RX PHY to check
950 * \param expectedCcaBusyIndication flag to indicate whether a CCA BUSY notification is expected
951 * \param switchingDelay delay between the TX has started and the time RX switched to the TX
952 * channel
953 * \param propagationDelay the propagation delay
954 */
955 void CheckCcaIndication(std::size_t index,
956 bool expectedCcaBusyIndication,
957 Time switchingDelay,
958 Time propagationDelay);
959
960 /**
961 * Verify rxing state of the interference helper
962 *
963 * \param phy the PHY to which the interference helper instance is attached
964 * \param rxingExpected flag whether the interference helper is expected to be in rxing state or
965 * not
966 */
967 void CheckRxingState(Ptr<SpectrumWifiPhy> phy, bool rxingExpected);
968
969 /**
970 * Reset function
971 */
972 void Reset();
973
974 bool
975 m_trackSignalsInactiveInterfaces; //!< flag to indicate whether signals coming from inactive
976 //!< spectrum PHY interfaces are tracked during the test
978 m_chanSwitchScenario; //!< the channel switch scenario to consider for the test
979 std::vector<Ptr<MultiModelSpectrumChannel>> m_spectrumChannels; //!< Spectrum channels
980 std::vector<Ptr<SpectrumWifiPhy>> m_txPhys{}; //!< TX PHYs
981 std::vector<Ptr<SpectrumWifiPhy>> m_rxPhys{}; //!< RX PHYs
982 std::vector<std::shared_ptr<TestPhyListener>> m_listeners{}; //!< listeners
983
984 std::vector<uint32_t> m_counts; //!< count number of packets received by PHYs
985 std::vector<uint32_t>
986 m_countRxSuccess; //!< count number of packets successfully received by PHYs
987 std::vector<uint32_t>
988 m_countRxFailure; //!< count number of packets unsuccessfully received by PHYs
989 std::vector<uint32_t> m_rxBytes; //!< count number of received bytes
990
991 Time m_lastTxStart{0}; //!< hold the time at which the last transmission started
992 Time m_lastTxEnd{0}; //!< hold the time at which the last transmission ended
993};
994
996 bool trackSignalsInactiveInterfaces,
997 ChannelSwitchScenario chanSwitchScenario)
998 : TestCase{"SpectrumWifiPhy test operation with multiple RF interfaces"},
999 m_trackSignalsInactiveInterfaces{trackSignalsInactiveInterfaces},
1000 m_chanSwitchScenario{chanSwitchScenario}
1001{
1002}
1003
1004void
1006 WifiPhyBand band,
1007 uint8_t channelNumber,
1008 uint16_t channelWidth,
1009 std::optional<std::size_t> listenerIndex)
1010{
1011 NS_LOG_FUNCTION(this << phy << band << +channelNumber << channelWidth);
1012 if (listenerIndex)
1013 {
1014 auto& listener = m_listeners.at(*listenerIndex);
1015 listener->m_notifyMaybeCcaBusyStart = 0;
1016 listener->m_ccaBusyStart = Seconds(0);
1017 listener->m_ccaBusyEnd = Seconds(0);
1018 }
1019 phy->SetOperatingChannel(WifiPhy::ChannelTuple{channelNumber, channelWidth, band, 0});
1020 // verify rxing state of interference helper is reset after channel switch
1022 this,
1023 phy,
1024 false);
1025}
1026
1027void
1029 double txPowerDbm,
1030 uint32_t payloadSize)
1031{
1032 NS_LOG_FUNCTION(this << phy << txPowerDbm << payloadSize << phy->GetCurrentFrequencyRange()
1033 << phy->GetChannelWidth() << phy->GetChannelNumber());
1034
1035 WifiTxVector txVector =
1036 WifiTxVector(HePhy::GetHeMcs11(), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, 20, false, false);
1037 Ptr<Packet> pkt = Create<Packet>(payloadSize);
1038 WifiMacHeader hdr;
1040 hdr.SetQosTid(0);
1041 hdr.SetAddr1(Mac48Address("00:00:00:00:00:01"));
1042 hdr.SetSequenceNumber(1);
1043 Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
1044
1047 txVector,
1048 phy->GetPhyBand());
1049 phy->SetTxPowerStart(txPowerDbm);
1050 phy->SetTxPowerEnd(txPowerDbm);
1051 phy->Send(WifiConstPsduMap({std::make_pair(SU_STA_ID, psdu)}), txVector);
1052}
1053
1054void
1056 Ptr<const Packet> packet,
1057 RxPowerWattPerChannelBand /*rxPowersW*/)
1058{
1059 auto phy = m_rxPhys.at(index);
1060 const auto payloadBytes = packet->GetSize() - 30;
1061 NS_LOG_FUNCTION(this << index << payloadBytes << phy->GetCurrentFrequencyRange()
1062 << phy->GetChannelWidth() << phy->GetChannelNumber());
1063 m_counts.at(index)++;
1064 m_rxBytes.at(index) += payloadBytes;
1065}
1066
1067void
1070 RxSignalInfo rxSignalInfo,
1071 WifiTxVector txVector,
1072 std::vector<bool> /*statusPerMpdu*/)
1073{
1074 NS_LOG_FUNCTION(this << index << *psdu << rxSignalInfo << txVector);
1075 m_countRxSuccess.at(index)++;
1076}
1077
1078void
1080{
1081 NS_LOG_FUNCTION(this << index << *psdu);
1082 m_countRxFailure.at(index)++;
1083}
1084
1085void
1087 const FrequencyRange& freqRange,
1088 const WifiSpectrumBandInfo& band,
1089 bool interferencesExpected)
1090{
1091 if ((!m_trackSignalsInactiveInterfaces) && (phy->GetCurrentFrequencyRange() != freqRange))
1092 {
1093 // ignore since no bands for that range exists in interference helper in that case
1094 return;
1095 }
1096 // This is needed to make sure PHY state will be checked as the last event if a state change
1097 // occurred at the exact same time as the check
1099 this,
1100 phy,
1101 band,
1102 interferencesExpected);
1103}
1104
1105void
1107 const WifiSpectrumBandInfo& band,
1108 bool interferencesExpected)
1109{
1110 NS_LOG_FUNCTION(this << phy << band << interferencesExpected);
1111 PointerValue ptr;
1112 phy->GetAttribute("InterferenceHelper", ptr);
1113 auto interferenceHelper = DynamicCast<InterferenceHelper>(ptr.Get<InterferenceHelper>());
1114 NS_ASSERT(interferenceHelper);
1115 const auto energyDuration = interferenceHelper->GetEnergyDuration(0, band);
1116 NS_TEST_ASSERT_MSG_EQ(energyDuration.IsStrictlyPositive(),
1117 interferencesExpected,
1118 "Incorrect interferences detection");
1119}
1120
1121void
1123 std::size_t index,
1124 uint32_t expectedNumRx,
1125 uint32_t expectedNumRxSuccess,
1126 uint32_t expectedRxBytes,
1127 FrequencyRange expectedFrequencyRangeActiveRfInterface,
1128 const std::vector<std::size_t>& expectedConnectedPhysPerChannel)
1129{
1130 NS_LOG_FUNCTION(this << index << expectedNumRx << expectedNumRxSuccess << expectedRxBytes
1131 << expectedFrequencyRangeActiveRfInterface);
1132 const auto phy = m_rxPhys.at(index);
1133 std::size_t numActiveInterfaces = 0;
1134 for (const auto& [freqRange, interface] : phy->GetSpectrumPhyInterfaces())
1135 {
1136 const auto expectedActive = (freqRange == expectedFrequencyRangeActiveRfInterface);
1137 const auto isActive = (interface == phy->GetCurrentInterface());
1138 NS_TEST_ASSERT_MSG_EQ(isActive, expectedActive, "Incorrect active interface");
1139 if (isActive)
1140 {
1141 numActiveInterfaces++;
1142 }
1143 }
1144 NS_TEST_ASSERT_MSG_EQ(numActiveInterfaces, 1, "There should always be one active interface");
1145 NS_ASSERT(expectedConnectedPhysPerChannel.size() == m_spectrumChannels.size());
1146 for (std::size_t i = 0; i < m_spectrumChannels.size(); ++i)
1147 {
1148 NS_TEST_ASSERT_MSG_EQ(m_spectrumChannels.at(i)->GetNDevices(),
1149 expectedConnectedPhysPerChannel.at(i),
1150 "Incorrect number of PHYs attached to the spectrum channel");
1151 }
1152 NS_TEST_ASSERT_MSG_EQ(m_counts.at(index), expectedNumRx, "Unexpected amount of RX events");
1154 expectedNumRxSuccess,
1155 "Unexpected amount of successfully received packets");
1157 0,
1158 "Unexpected amount of unsuccessfully received packets");
1159 NS_TEST_ASSERT_MSG_EQ(m_listeners.at(index)->m_notifyRxStart,
1160 expectedNumRxSuccess,
1161 "Unexpected amount of RX payload start indication");
1162}
1163
1164void
1166 bool expectedCcaBusyIndication,
1167 Time switchingDelay,
1168 Time propagationDelay)
1169{
1170 const auto expectedCcaBusyStart =
1171 expectedCcaBusyIndication ? m_lastTxStart + switchingDelay : Seconds(0);
1172 const auto expectedCcaBusyEnd =
1173 expectedCcaBusyIndication ? m_lastTxEnd + propagationDelay : Seconds(0);
1174 NS_LOG_FUNCTION(this << index << expectedCcaBusyIndication << expectedCcaBusyStart
1175 << expectedCcaBusyEnd);
1176 auto& listener = m_listeners.at(index);
1177 const auto ccaBusyIndication = (listener->m_notifyMaybeCcaBusyStart > 0);
1178 const auto ccaBusyStart = listener->m_ccaBusyStart;
1179 const auto ccaBusyEnd = listener->m_ccaBusyEnd;
1180 NS_TEST_ASSERT_MSG_EQ(ccaBusyIndication,
1181 expectedCcaBusyIndication,
1182 "CCA busy indication check failed");
1183 NS_TEST_ASSERT_MSG_EQ(ccaBusyStart, expectedCcaBusyStart, "CCA busy start mismatch");
1184 NS_TEST_ASSERT_MSG_EQ(ccaBusyEnd, expectedCcaBusyEnd, "CCA busy end mismatch");
1185}
1186
1187void
1189{
1190 NS_LOG_FUNCTION(this << phy << rxingExpected);
1191 PointerValue ptr;
1192 phy->GetAttribute("InterferenceHelper", ptr);
1193 auto interferenceHelper = DynamicCast<ExtInterferenceHelper>(ptr.Get<ExtInterferenceHelper>());
1194 NS_ASSERT(interferenceHelper);
1195 NS_TEST_ASSERT_MSG_EQ(interferenceHelper->IsRxing(), rxingExpected, "Incorrect rxing state");
1196}
1197
1198void
1200{
1201 NS_LOG_FUNCTION(this);
1202 for (auto& count : m_counts)
1203 {
1204 count = 0;
1205 }
1206 for (auto& listener : m_listeners)
1207 {
1208 listener->Reset();
1209 }
1210 // restore all RX PHYs to initial channels
1211 for (std::size_t rxPhyIndex = 0; rxPhyIndex < m_rxPhys.size(); ++rxPhyIndex)
1212 {
1213 auto txPhy = m_txPhys.at(rxPhyIndex);
1214 SwitchChannel(m_rxPhys.at(rxPhyIndex),
1215 txPhy->GetPhyBand(),
1216 txPhy->GetChannelNumber(),
1217 txPhy->GetChannelWidth(),
1218 rxPhyIndex);
1219 }
1220 // reset counters
1221 for (auto& countRxSuccess : m_countRxSuccess)
1222 {
1223 countRxSuccess = 0;
1224 }
1225 for (auto& countRxFailure : m_countRxFailure)
1226 {
1227 countRxFailure = 0;
1228 }
1229 for (auto& rxBytes : m_rxBytes)
1230 {
1231 rxBytes = 0;
1232 }
1233}
1234
1235void
1237{
1238 NS_LOG_FUNCTION(this);
1239
1240 // WifiHelper::EnableLogComponents();
1241 // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
1242
1243 NodeContainer wifiApNode(1);
1244 NodeContainer wifiStaNode(1);
1245
1246 WifiHelper wifi;
1247 wifi.SetStandard(WIFI_STANDARD_80211be);
1248
1249 SpectrumWifiPhyHelper phyHelper(4);
1250 phyHelper.SetInterferenceHelper("ns3::ExtInterferenceHelper");
1252
1253 struct SpectrumPhyInterfaceInfo
1254 {
1255 FrequencyRange range; ///< frequency range covered by the interface
1256 uint8_t number; ///< channel number the interface operates on
1257 WifiPhyBand band; ///< PHY band the interface operates on
1258 std::string bandName; ///< name of the PHY band the interface operates on
1259 };
1260
1261 const FrequencyRange WIFI_SPECTRUM_5_GHZ_LOW{
1265 const FrequencyRange WIFI_SPECTRUM_5_GHZ_HIGH{
1269
1270 const std::vector<SpectrumPhyInterfaceInfo> interfaces{
1271 {WIFI_SPECTRUM_2_4_GHZ, 2, WIFI_PHY_BAND_2_4GHZ, "BAND_2_4GHZ"},
1272 {WIFI_SPECTRUM_5_GHZ_LOW, 42, WIFI_PHY_BAND_5GHZ, "BAND_5GHZ"},
1273 {WIFI_SPECTRUM_5_GHZ_HIGH, 163, WIFI_PHY_BAND_5GHZ, "BAND_5GHZ"},
1274 {WIFI_SPECTRUM_6_GHZ, 215, WIFI_PHY_BAND_6GHZ, "BAND_6GHZ"}};
1275
1276 for (std::size_t i = 0; i < interfaces.size(); ++i)
1277 {
1278 auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
1279 [[maybe_unused]] const auto [channel, frequency, channelWidth, type, band] =
1280 (*WifiPhyOperatingChannel::FindFirst(interfaces.at(i).number,
1281 0,
1282 0,
1284 interfaces.at(i).band));
1285
1286 auto delayModel = CreateObject<ConstantSpeedPropagationDelayModel>();
1287 spectrumChannel->SetPropagationDelayModel(delayModel);
1288 std::ostringstream oss;
1289 oss << "{" << +interfaces.at(i).number << ", 0, " << interfaces.at(i).bandName << ", 0}";
1290 phyHelper.Set(i, "ChannelSettings", StringValue(oss.str()));
1291 phyHelper.AddChannel(spectrumChannel, interfaces.at(i).range);
1292
1293 m_spectrumChannels.emplace_back(spectrumChannel);
1294 }
1295
1296 WifiMacHelper mac;
1297 mac.SetType("ns3::ApWifiMac", "BeaconGeneration", BooleanValue(false));
1298 phyHelper.Set("TrackSignalsFromInactiveInterfaces", BooleanValue(false));
1299 auto apDevice = wifi.Install(phyHelper, mac, wifiApNode.Get(0));
1300
1301 mac.SetType("ns3::StaWifiMac", "ActiveProbing", BooleanValue(false));
1302 phyHelper.Set("TrackSignalsFromInactiveInterfaces",
1304 auto staDevice = wifi.Install(phyHelper, mac, wifiStaNode.Get(0));
1305
1306 MobilityHelper mobility;
1307 auto positionAlloc = CreateObject<ListPositionAllocator>();
1308
1309 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
1310 positionAlloc->Add(Vector(10.0, 0.0, 0.0));
1311 mobility.SetPositionAllocator(positionAlloc);
1312
1313 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
1314 mobility.Install(wifiApNode);
1315 mobility.Install(wifiStaNode);
1316
1317 for (std::size_t i = 0; i < interfaces.size(); ++i)
1318 {
1319 auto txPhy =
1320 DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(apDevice.Get(0))->GetPhy(i));
1322 {
1323 txPhy->SetAttribute("ChannelSwitchDelay", TimeValue(NanoSeconds(1)));
1324 }
1325 m_txPhys.push_back(txPhy);
1326
1327 const auto index = m_rxPhys.size();
1328 auto rxPhy =
1329 DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(staDevice.Get(0))->GetPhy(i));
1331 {
1332 rxPhy->SetAttribute("ChannelSwitchDelay", TimeValue(NanoSeconds(1)));
1333 }
1334 rxPhy->TraceConnectWithoutContext(
1335 "PhyRxBegin",
1337
1338 rxPhy->SetReceiveOkCallback(
1340 rxPhy->SetReceiveErrorCallback(
1342
1343 auto listener = std::make_shared<TestPhyListener>();
1344 rxPhy->RegisterListener(listener);
1345 m_listeners.push_back(std::move(listener));
1346
1347 m_rxPhys.push_back(rxPhy);
1348 m_counts.push_back(0);
1349 m_countRxSuccess.push_back(0);
1350 m_countRxFailure.push_back(0);
1351 m_rxBytes.push_back(0);
1352 }
1353}
1354
1355void
1357{
1358 NS_LOG_FUNCTION(this);
1359 for (auto& phy : m_txPhys)
1360 {
1361 phy->Dispose();
1362 phy = nullptr;
1363 }
1364 for (auto& phy : m_rxPhys)
1365 {
1366 phy->Dispose();
1367 phy = nullptr;
1368 }
1370}
1371
1372void
1374{
1375 NS_LOG_FUNCTION(this);
1376
1377 const auto ccaEdThresholdDbm = -62.0; ///< CCA-ED threshold in dBm
1378 const auto txAfterChannelSwitchDelay =
1380 ? 250
1381 : 0); ///< delay in seconds between channel switch is triggered and a
1382 ///< transmission gets started
1383 const auto checkResultsDelay =
1384 Seconds(0.5); ///< delay in seconds between start of test and moment results are verified
1385 const auto flushResultsDelay =
1386 Seconds(0.9); ///< delay in seconds between start of test and moment results are flushed
1387 const auto txOngoingAfterTxStartedDelay =
1388 MicroSeconds(50); ///< delay in microseconds between a transmission has started and a point
1389 ///< in time the transmission is ongoing
1390 const auto propagationDelay = NanoSeconds(33); // propagation delay for the test scenario
1391
1392 Time delay{0};
1393
1394 // default channels active for all PHYs: each PHY only receives from its associated TX
1395 std::vector<std::size_t> expectedConnectedPhysPerChannel =
1396 m_trackSignalsInactiveInterfaces ? std::vector<std::size_t>{5, 5, 5, 5}
1397 : // all RX PHYs keep all channels active when tracking
1398 // interferences on inactive interfaces
1399 std::vector<std::size_t>{2, 2, 2, 2}; // default channels active for all PHYs: each PHY
1400 // only receives from its associated TX
1401
1402 for (std::size_t i = 0; i < 4; ++i)
1403 {
1404 auto txPpduPhy = m_txPhys.at(i);
1405 delay += Seconds(1);
1406 Simulator::Schedule(delay,
1408 this,
1409 txPpduPhy,
1410 0,
1411 1000);
1412 for (std::size_t j = 0; j < 4; ++j)
1413 {
1414 auto txPhy = m_txPhys.at(j);
1415 auto rxPhy = m_rxPhys.at(j);
1416 const auto& expectedFreqRange = txPhy->GetCurrentFrequencyRange();
1417 Simulator::Schedule(delay + txOngoingAfterTxStartedDelay,
1419 this,
1420 rxPhy,
1421 txPpduPhy->GetCurrentFrequencyRange(),
1422 txPpduPhy->GetBand(txPpduPhy->GetChannelWidth(), 0),
1423 true);
1424 Simulator::Schedule(delay + checkResultsDelay,
1426 this,
1427 j,
1428 (i == j) ? 1 : 0,
1429 (i == j) ? 1 : 0,
1430 (i == j) ? 1000 : 0,
1431 expectedFreqRange,
1432 expectedConnectedPhysPerChannel);
1433 }
1434 Simulator::Schedule(delay + flushResultsDelay,
1436 this);
1437 }
1438
1439 // same channel active for all PHYs: all PHYs receive from TX
1440 for (std::size_t i = 0; i < 4; ++i)
1441 {
1442 delay += Seconds(1);
1443 auto txPpduPhy = m_txPhys.at(i);
1444 Simulator::Schedule(delay + txAfterChannelSwitchDelay,
1446 this,
1447 txPpduPhy,
1448 0,
1449 1000);
1450 const auto& expectedFreqRange = txPpduPhy->GetCurrentFrequencyRange();
1451 for (std::size_t j = 0; j < 4; ++j)
1452 {
1454 {
1455 for (std::size_t k = 0; k < expectedConnectedPhysPerChannel.size(); ++k)
1456 {
1457 expectedConnectedPhysPerChannel.at(k) = (k == i) ? 5 : 1;
1458 }
1459 }
1460 auto rxPhy = m_rxPhys.at(j);
1461 Simulator::Schedule(delay,
1463 this,
1464 rxPhy,
1465 txPpduPhy->GetPhyBand(),
1466 txPpduPhy->GetChannelNumber(),
1467 txPpduPhy->GetChannelWidth(),
1468 j);
1469 Simulator::Schedule(delay + txAfterChannelSwitchDelay + txOngoingAfterTxStartedDelay,
1471 this,
1472 rxPhy,
1473 txPpduPhy->GetCurrentFrequencyRange(),
1474 txPpduPhy->GetBand(txPpduPhy->GetChannelWidth(), 0),
1475 true);
1476 Simulator::Schedule(delay + checkResultsDelay,
1478 this,
1479 j,
1480 1,
1481 1,
1482 1000,
1483 expectedFreqRange,
1484 expectedConnectedPhysPerChannel);
1485 }
1486 Simulator::Schedule(delay + flushResultsDelay,
1488 this);
1489 }
1490
1491 // Switch all PHYs to channel 36: all PHYs switch to the second spectrum channel
1492 // since second spectrum channel is 42 (80 MHz) and hence covers channel 36 (20 MHz)
1493 const auto secondSpectrumChannelIndex = 1;
1494 auto channel36TxPhy = m_txPhys.at(secondSpectrumChannelIndex);
1495 const auto& expectedFreqRange = channel36TxPhy->GetCurrentFrequencyRange();
1496 for (std::size_t i = 0; i < 4; ++i)
1497 {
1498 delay += Seconds(1);
1499 auto txPpduPhy = m_txPhys.at(i);
1500 Simulator::Schedule(delay + txAfterChannelSwitchDelay,
1502 this,
1503 txPpduPhy,
1504 0,
1505 1000);
1506 for (std::size_t j = 0; j < 4; ++j)
1507 {
1509 {
1510 for (std::size_t k = 0; k < expectedConnectedPhysPerChannel.size(); ++k)
1511 {
1512 expectedConnectedPhysPerChannel.at(k) =
1513 (k == secondSpectrumChannelIndex) ? 5 : 1;
1514 }
1515 }
1516 Simulator::Schedule(delay,
1518 this,
1519 m_rxPhys.at(j),
1523 j);
1524 Simulator::Schedule(delay + checkResultsDelay,
1526 this,
1527 j,
1528 (i == secondSpectrumChannelIndex) ? 1 : 0,
1529 (i == secondSpectrumChannelIndex) ? 1 : 0,
1530 (i == secondSpectrumChannelIndex) ? 1000 : 0,
1531 expectedFreqRange,
1532 expectedConnectedPhysPerChannel);
1533 }
1534 Simulator::Schedule(delay + flushResultsDelay,
1536 this);
1537 }
1538
1539 // verify CCA indication when switching to a channel with an ongoing transmission
1540 for (const auto txPowerDbm : {-60.0 /* above CCA-ED */, -70.0 /* below CCA-ED */})
1541 {
1542 for (std::size_t i = 0; i < 4; ++i)
1543 {
1544 for (std::size_t j = 0; j < 4; ++j)
1545 {
1546 auto txPpduPhy = m_txPhys.at(i);
1547 const auto startChannel =
1548 WifiPhyOperatingChannel::FindFirst(txPpduPhy->GetPrimaryChannelNumber(20),
1549 0,
1550 20,
1552 txPpduPhy->GetPhyBand());
1553 for (uint16_t bw = txPpduPhy->GetChannelWidth(); bw >= 20; bw /= 2)
1554 {
1555 [[maybe_unused]] const auto [channel, frequency, channelWidth, type, band] =
1557 0,
1558 bw,
1560 txPpduPhy->GetPhyBand(),
1561 startChannel));
1562 delay += Seconds(1);
1563 Simulator::Schedule(delay,
1565 this,
1566 txPpduPhy,
1567 txPowerDbm,
1568 1000);
1569 Simulator::Schedule(delay + txOngoingAfterTxStartedDelay,
1571 this,
1572 m_rxPhys.at(j),
1573 band,
1574 channel,
1575 channelWidth,
1576 j);
1577 for (std::size_t k = 0; k < 4; ++k)
1578 {
1579 if ((i != j) && (k == i))
1580 {
1581 continue;
1582 }
1583 const auto expectCcaBusyIndication =
1584 (k == i) ? (txPowerDbm >= ccaEdThresholdDbm)
1586 ? ((txPowerDbm >= ccaEdThresholdDbm) ? (j == k) : false)
1587 : false);
1589 delay + checkResultsDelay,
1591 this,
1592 k,
1593 expectCcaBusyIndication,
1594 txOngoingAfterTxStartedDelay,
1595 propagationDelay);
1596 }
1597 Simulator::Schedule(delay + flushResultsDelay,
1599 this);
1600 }
1601 }
1602 }
1603 }
1604
1606 {
1607 /* Reproduce an EMLSR scenario where a PHY is on an initial band and receives a packet.
1608 * Then, the PHY switches to another band where it starts receiving another packet.
1609 * During reception of the PHY header, the PHY switches back to the initial band and starts
1610 * receiving yet another packet. In this case, first and last packets should be successfully
1611 * received (no interference), the second packet reception has been interrupted (before the
1612 * payload reception does start, hence it does not reach the RX state). */
1613 {
1614 // first TX on initial band
1615 auto txPpduPhy = m_txPhys.at(0);
1616 delay += Seconds(1);
1617 Simulator::Schedule(delay,
1619 this,
1620 txPpduPhy,
1621 20,
1622 500);
1623
1624 // switch channel to other band
1625 delay += Seconds(1);
1626 txPpduPhy = m_txPhys.at(1);
1627 Simulator::Schedule(delay,
1629 this,
1630 m_rxPhys.at(0),
1631 txPpduPhy->GetPhyBand(),
1632 txPpduPhy->GetChannelNumber(),
1633 txPpduPhy->GetChannelWidth(),
1634 0);
1635
1636 // TX on other band
1637 delay += Seconds(1);
1638 Simulator::Schedule(delay,
1640 this,
1641 txPpduPhy,
1642 0,
1643 1000);
1644
1645 // switch back to initial band during PHY header reception
1646 txPpduPhy = m_txPhys.at(0);
1647 delay += MicroSeconds(20); // right after legacy PHY header reception
1648 Simulator::Schedule(delay,
1650 this,
1651 m_rxPhys.at(0),
1652 txPpduPhy->GetPhyBand(),
1653 txPpduPhy->GetChannelNumber(),
1654 txPpduPhy->GetChannelWidth(),
1655 0);
1656
1657 // TX once more on the initial band
1658 delay += Seconds(1);
1659 Simulator::Schedule(delay,
1661 this,
1662 txPpduPhy,
1663 0,
1664 1500);
1665
1666 // check results
1668 delay + checkResultsDelay,
1670 this,
1671 0,
1672 3, // 3 RX events
1673 2, // 2 packets should have been successfully received, 1 packet should
1674 // have been interrupted (switch during PHY header reception)
1675 2000, // 500 bytes (firstpacket) and 1500 bytes (third packet)
1676 txPpduPhy->GetCurrentFrequencyRange(),
1677 expectedConnectedPhysPerChannel);
1678
1679 // reset
1680 Simulator::Schedule(delay + flushResultsDelay,
1682 this);
1683 }
1684
1685 /* Reproduce an EMLSR scenario where a PHY is on an initial band and receives a packet
1686 * but switches to another band during preamble detection period. Then, it starts receiving
1687 * two packets which interfere with each other. Afterwards, the PHY goes back to its initial
1688 * band and starts receiving yet another packet. In this case, only the last packet should
1689 * be successfully received (no interference). */
1690 {
1691 // switch channel of PHY index 0 to 5 GHz low band (operating channel of TX PHY index 1)
1692 auto txPpduPhy = m_txPhys.at(1);
1693 delay += Seconds(1);
1694 Simulator::Schedule(delay,
1696 this,
1697 m_rxPhys.at(0),
1698 txPpduPhy->GetPhyBand(),
1699 txPpduPhy->GetChannelNumber(),
1700 txPpduPhy->GetChannelWidth(),
1701 0);
1702
1703 // start transmission on 5 GHz low band
1704 delay += Seconds(1);
1705 Simulator::Schedule(delay,
1707 this,
1708 txPpduPhy,
1709 20,
1710 500);
1711
1712 // switch channel back to previous channel before preamble detection is finished:
1713 // this is needed to verify interference helper rxing state is properly reset
1714 // since ongoing reception is aborted when switching operating channel
1717 this,
1718 m_rxPhys.at(0),
1719 m_txPhys.at(0)->GetPhyBand(),
1720 m_txPhys.at(0)->GetChannelNumber(),
1721 m_txPhys.at(0)->GetChannelWidth(),
1722 0);
1723
1724 delay += Seconds(1);
1725 // we need 2 TX PHYs on the 5 GHz low band to have simultaneous transmissions
1726 // switch operating channel of TX PHY index 2 to the 5 GHz low band
1727 Simulator::Schedule(delay,
1729 this,
1730 m_txPhys.at(2),
1731 txPpduPhy->GetPhyBand(),
1732 txPpduPhy->GetChannelNumber(),
1733 txPpduPhy->GetChannelWidth(),
1734 std::nullopt);
1735
1736 // first transmission on 5 GHz low band with high power
1737 delay += Seconds(1);
1738 Simulator::Schedule(delay,
1740 this,
1741 txPpduPhy,
1742 20,
1743 1000);
1744
1745 // second transmission on 5 GHz low band with high power a bit later:
1746 // first powers get updated updated in the corresponding bands
1747 txPpduPhy = m_txPhys.at(2);
1748 Simulator::Schedule(delay + NanoSeconds(10),
1750 this,
1751 txPpduPhy,
1752 20,
1753 1000);
1754
1755 // restore channel for TX PHY index 2
1756 delay += Seconds(1);
1757 Simulator::Schedule(delay,
1759 this,
1760 m_txPhys.at(2),
1761 m_rxPhys.at(2)->GetPhyBand(),
1762 m_rxPhys.at(2)->GetChannelNumber(),
1763 m_rxPhys.at(2)->GetChannelWidth(),
1764 std::nullopt);
1765
1766 // switch channel of PHY index 0 to 5 GHz low band again
1767 delay += Seconds(1);
1768 txPpduPhy = m_txPhys.at(1);
1769 Simulator::Schedule(delay,
1771 this,
1772 m_rxPhys.at(0),
1773 txPpduPhy->GetPhyBand(),
1774 txPpduPhy->GetChannelNumber(),
1775 txPpduPhy->GetChannelWidth(),
1776 0);
1777
1778 // transmit PPDU on 5 GHz low band (no interference)
1779 delay += Seconds(1);
1780 Simulator::Schedule(delay,
1782 this,
1783 txPpduPhy,
1784 0,
1785 1500);
1786
1787 // check results
1788 Simulator::Schedule(delay + checkResultsDelay,
1790 this,
1791 0,
1792 1, // 1 RX event
1793 1, // last transmitted packet should have been successfully received
1794 1500, // 1500 bytes (payload of last transmitted packet)
1795 txPpduPhy->GetCurrentFrequencyRange(),
1796 expectedConnectedPhysPerChannel);
1797
1798 // reset
1799 Simulator::Schedule(delay + flushResultsDelay,
1801 this);
1802 }
1803 }
1804
1805 delay += Seconds(1);
1806 Simulator::Stop(delay);
1808}
1809
1810/**
1811 * \ingroup wifi-test
1812 * \ingroup tests
1813 *
1814 * \brief Spectrum Wifi Phy Interfaces Helper Test
1815 *
1816 * This test checks the expected interfaces are added to the spectrum PHY instances
1817 * created by the helper.
1818 */
1820{
1821 public:
1824
1825 private:
1826 void DoRun() override;
1827};
1828
1830 : TestCase("Check PHY interfaces added to PHY instances using helper")
1831{
1832}
1833
1834void
1836{
1837 WifiHelper wifiHelper;
1839
1840 SpectrumWifiPhyHelper phyHelper(3);
1841 phyHelper.Set(0, "ChannelSettings", StringValue("{2, 0, BAND_2_4GHZ, 0}"));
1842 phyHelper.Set(1, "ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}"));
1843 phyHelper.Set(2, "ChannelSettings", StringValue("{1, 0, BAND_6GHZ, 0}"));
1844
1845 phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_2_4_GHZ);
1846 phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_5_GHZ);
1847 phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_6_GHZ);
1848
1849 WifiMacHelper macHelper;
1851
1852 /* Default case: all interfaces are added to each link */
1853 auto device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(0));
1854
1855 // Verify each PHY has 3 interfaces
1856 auto phyLink0 =
1857 DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
1858 NS_ASSERT(phyLink0);
1859 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
1860 3,
1861 "Incorrect number of PHY interfaces added to PHY link ID 0");
1862
1863 auto phyLink1 =
1864 DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
1865 NS_ASSERT(phyLink1);
1866 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
1867 3,
1868 "Incorrect number of PHY interfaces added to PHY link ID 1");
1869
1870 auto phyLink2 =
1871 DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
1872 NS_ASSERT(phyLink2);
1873 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
1874 3,
1875 "Incorrect number of PHY interfaces added to PHY link ID 2");
1876
1877 /* each PHY has a single interface */
1881 device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(1));
1882
1883 // Verify each PHY has a single interface
1884 phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
1885 NS_ASSERT(phyLink0);
1886 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
1887 1,
1888 "Incorrect number of PHY interfaces added to PHY link ID 0");
1889 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
1890 1,
1891 "Incorrect PHY interfaces added to PHY link ID 0");
1892
1893 phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
1894 NS_ASSERT(phyLink1);
1895 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
1896 1,
1897 "Incorrect number of PHY interfaces added to PHY link ID 1");
1898 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1899 1,
1900 "Incorrect PHY interfaces added to PHY link ID 1");
1901
1902 phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
1903 NS_ASSERT(phyLink2);
1904 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
1905 1,
1906 "Incorrect number of PHY interfaces added to PHY link ID 2");
1907 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
1908 1,
1909 "Incorrect PHY interfaces added to PHY link ID 2");
1910
1911 /* add yet another interface to PHY 0 */
1913 device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(2));
1914
1915 // Verify each PHY has a single interface except PHY 0 that should have 2 interfaces
1916 phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
1917 NS_ASSERT(phyLink0);
1918 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
1919 2,
1920 "Incorrect number of PHY interfaces added to PHY link ID 0");
1921 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
1922 1,
1923 "Incorrect PHY interfaces added to PHY link ID 0");
1924 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1925 1,
1926 "Incorrect PHY interfaces added to PHY link ID 0");
1927
1928 phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
1929 NS_ASSERT(phyLink1);
1930 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
1931 1,
1932 "Incorrect number of PHY interfaces added to PHY link ID 1");
1933 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1934 1,
1935 "Incorrect PHY interfaces added to PHY link ID 1");
1936
1937 phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
1938 NS_ASSERT(phyLink2);
1939 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
1940 1,
1941 "Incorrect number of PHY interfaces added to PHY link ID 2");
1942 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
1943 1,
1944 "Incorrect PHY interfaces added to PHY link ID 2");
1945
1946 /* reset mapping previously configured to helper: back to default */
1947 phyHelper.ResetPhyToFreqRangeMapping();
1948 device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(3));
1949
1950 // Verify each PHY has 3 interfaces
1951 phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
1952 NS_ASSERT(phyLink0);
1953 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
1954 3,
1955 "Incorrect number of PHY interfaces added to PHY link ID 0");
1956 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
1957 1,
1958 "Incorrect PHY interfaces added to PHY link ID 0");
1959 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1960 1,
1961 "Incorrect PHY interfaces added to PHY link ID 0");
1962 NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
1963 1,
1964 "Incorrect PHY interfaces added to PHY link ID 0");
1965
1966 phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
1967 NS_ASSERT(phyLink1);
1968 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
1969 3,
1970 "Incorrect number of PHY interfaces added to PHY link ID 1");
1971 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
1972 1,
1973 "Incorrect PHY interfaces added to PHY link ID 0");
1974 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1975 1,
1976 "Incorrect PHY interfaces added to PHY link ID 0");
1977 NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
1978 1,
1979 "Incorrect PHY interfaces added to PHY link ID 0");
1980
1981 phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
1982 NS_ASSERT(phyLink2);
1983 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
1984 3,
1985 "Incorrect number of PHY interfaces added to PHY link ID 2");
1986 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
1987 1,
1988 "Incorrect PHY interfaces added to PHY link ID 0");
1989 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1990 1,
1991 "Incorrect PHY interfaces added to PHY link ID 0");
1992 NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
1993 1,
1994 "Incorrect PHY interfaces added to PHY link ID 0");
1995
1997}
1998
1999/**
2000 * \ingroup wifi-test
2001 * \ingroup tests
2002 *
2003 * \brief Spectrum Wifi Phy Test Suite
2004 */
2006{
2007 public:
2009};
2010
2012 : TestSuite("wifi-spectrum-wifi-phy", Type::UNIT)
2013{
2014 AddTestCase(new SpectrumWifiPhyBasicTest, TestCase::Duration::QUICK);
2015 AddTestCase(new SpectrumWifiPhyListenerTest, TestCase::Duration::QUICK);
2016 AddTestCase(new SpectrumWifiPhyFilterTest, TestCase::Duration::QUICK);
2018 false,
2020 TestCase::Duration::QUICK);
2022 true,
2024 TestCase::Duration::QUICK);
2026 true,
2028 TestCase::Duration::QUICK);
2029 AddTestCase(new SpectrumWifiPhyInterfacesHelperTest, TestCase::Duration::QUICK);
2030}
2031
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.
Extended SpectrumWifiPhy class for the purpose of the tests.
Spectrum Wifi Phy Basic Test.
void SpectrumWifiPhyRxSuccess(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > statusPerMpdu)
Spectrum wifi receive success function.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
void DoRun() override
Implementation to actually run this TestCase.
Ptr< SpectrumSignalParameters > MakeSignal(double txPowerWatts, const WifiPhyOperatingChannel &channel)
Make signal function.
void SpectrumWifiPhyRxFailure(Ptr< const WifiPsdu > psdu)
Spectrum wifi receive failure function.
void SendSignal(double txPowerWatts)
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.
uint16_t m_txChannelWidth
TX channel width (MHz)
void DoRun() override
Implementation to actually run this TestCase.
void RunOne()
Run one function.
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.
std::set< WifiSpectrumBandIndices > m_ruBands
spectrum bands associated to all the RUs
Ptr< ExtSpectrumWifiPhy > m_rxPhy
RX PHY.
uint16_t m_rxChannelWidth
RX channel width (MHz)
Ptr< ExtSpectrumWifiPhy > m_txPhy
TX PHY.
Spectrum Wifi Phy Interfaces Helper Test.
~SpectrumWifiPhyInterfacesHelperTest() override=default
void DoRun() override
Implementation to actually run this TestCase.
Spectrum Wifi Phy Listener Test.
void DoRun() override
Implementation to actually run this TestCase.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
std::shared_ptr< TestPhyListener > m_listener
listener
Spectrum Wifi Phy Multiple Spectrum Test.
void 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 SwitchChannel(Ptr< SpectrumWifiPhy > phy, WifiPhyBand band, uint8_t channelNumber, uint16_t channelWidth, std::optional< std::size_t > listenerIndex)
Switch channel function.
bool m_trackSignalsInactiveInterfaces
flag to indicate whether signals coming from inactive spectrum PHY interfaces are tracked during the ...
void RxSuccess(std::size_t index, Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > statusPerMpdu)
Receive success function.
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 SendPpdu(Ptr< SpectrumWifiPhy > phy, double txPowerDbm, uint32_t payloadSize)
Send PPDU function.
void CheckResults(std::size_t index, uint32_t expectedNumRx, uint32_t expectedNumRxSuccess, uint32_t expectedRxBytes, FrequencyRange expectedFrequencyRangeActiveRfInterface, const std::vector< std::size_t > &expectedConnectedPhysPerChannel)
Verify results.
std::vector< Ptr< SpectrumWifiPhy > > m_txPhys
TX PHYs.
std::vector< Ptr< MultiModelSpectrumChannel > > m_spectrumChannels
Spectrum channels.
void CheckInterferences(Ptr< SpectrumWifiPhy > phy, const FrequencyRange &freqRange, const WifiSpectrumBandInfo &band, bool interferencesExpected)
Schedule now to check the interferences.
SpectrumWifiPhyMultipleInterfacesTest(bool trackSignalsInactiveInterfaces, ChannelSwitchScenario chanSwitchScenario)
Constructor.
void CheckCcaIndication(std::size_t index, bool expectedCcaBusyIndication, Time switchingDelay, Time propagationDelay)
Verify CCA indication reported by a given PHY.
void RxCallback(std::size_t index, Ptr< const Packet > packet, RxPowerWattPerChannelBand rxPowersW)
Callback triggered when a packet is received by a PHY.
void CheckRxingState(Ptr< SpectrumWifiPhy > phy, bool rxingExpected)
Verify rxing state of the interference helper.
ChannelSwitchScenario
Enumeration for channel switching scenarios.
@ BETWEEN_TX_RX
perform channel switch during propagation delay (after TX and before RX)
@ BEFORE_TX
start TX after channel switch is completed
std::vector< uint32_t > m_countRxFailure
count number of packets unsuccessfully received by PHYs
Spectrum Wifi Phy Test Suite.
Test Phy Listener.
Time m_ccaBusyEnd
CCA_BUSY end time.
void Reset()
Reset function.
void NotifyWakeup() override
Notify listeners that we woke up.
Time m_ccaBusyStart
CCA_BUSY start time.
void NotifyRxEndOk() override
We have received the last bit of a packet for which NotifyRxStart was invoked first and,...
void NotifyOff() override
Notify listeners that we went to switch off.
TestPhyListener()=default
Create a test PhyListener.
void NotifySleep() override
Notify listeners that we went to sleep.
void NotifySwitchingStart(Time duration) override
uint32_t m_notifyMaybeCcaBusyStart
notify maybe CCA busy start
uint32_t m_notifyRxStart
notify receive start
void NotifyTxStart(Time duration, double txPowerDbm) override
void NotifyCcaBusyStart(Time duration, WifiChannelListType channelType, const std::vector< Time > &) override
void NotifyRxStart(Time duration) override
void NotifyOn() override
Notify listeners that we went to switch on.
uint32_t m_notifyRxEndOk
notify receive end OK
void NotifyRxEndError() override
We have received the last bit of a packet for which NotifyRxStart was invoked first and,...
uint32_t m_notifyRxEndError
notify receive end error
~TestPhyListener() override=default
static WifiMode GetHeMcs11()
Return MCS 11 from HE MCS values.
static WifiMode GetHeMcs0()
Return MCS 0 from HE MCS values.
static WifiSpectrumBandIndices ConvertHeRuSubcarriers(uint16_t bandWidth, uint16_t guardBandwidth, uint32_t subcarrierSpacing, HeRu::SubcarrierRange subcarrierRange, uint8_t bandIndex=0)
Definition: he-phy.cc:1820
static SubcarrierGroup GetSubcarrierGroup(uint16_t bw, RuType ruType, std::size_t phyIndex)
Get the subcarrier group of the RU having the given PHY index among all the RUs of the given type (nu...
Definition: he-ru.cc:591
static std::size_t GetNRus(uint16_t bw, RuType ruType)
Get the number of distinct RUs of the given type (number of tones) available in a HE PPDU of the give...
Definition: he-ru.cc:495
std::vector< SubcarrierRange > SubcarrierGroup
a vector of subcarrier ranges defining a subcarrier group
Definition: he-ru.h:55
std::pair< int16_t, int16_t > SubcarrierRange
(lowest index, highest index) pair defining a subcarrier range
Definition: he-ru.h:52
RuType
The different HE Resource Unit (RU) types.
Definition: he-ru.h:41
handles interference calculations
std::map< FrequencyRange, bool > m_rxing
flag whether it is in receiving state for a given FrequencyRange
an EUI-48 address
Definition: mac48-address.h:46
Helper class used to assign positions and mobility models to nodes.
keep track of a set of node pointers.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:322
void Dispose()
Dispose of this Object.
Definition: object.cc:258
static WifiMode GetOfdmRate6Mbps()
Return a WifiMode for OFDM at 6 Mbps.
AttributeValue implementation for Pointer.
Definition: pointer.h:48
Ptr< T > Get() const
Definition: pointer.h:234
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static void Run()
Run the simulation.
Definition: simulator.cc:178
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:605
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
Make it easy to create and manage PHY objects for the spectrum model.
void ResetPhyToFreqRangeMapping()
Reset mapping of the spectrum PHY interfaces added to the PHY instances.
void AddChannel(const Ptr< SpectrumChannel > channel, const FrequencyRange &freqRange=WHOLE_WIFI_SPECTRUM)
void AddPhyToFreqRangeMapping(uint8_t linkId, const FrequencyRange &freqRange)
Add a given spectrum PHY interface to the PHY instance corresponding of a given link.
802.11 PHY layer model
void SetDevice(const Ptr< WifiNetDevice > device) override
Sets the device this PHY is associated with.
void StartRx(Ptr< SpectrumSignalParameters > rxParams, Ptr< const WifiSpectrumPhyInterface > interface)
Input method for delivering a signal from the spectrum channel and low-level PHY interface to this Sp...
void AddChannel(const Ptr< SpectrumChannel > channel, const FrequencyRange &freqRange=WHOLE_WIFI_SPECTRUM)
Attach a SpectrumChannel to use for a given frequency range.
uint16_t GetGuardBandwidth(uint16_t currentChannelWidth) const override
WifiSpectrumBandInfo GetBand(uint16_t bandWidth, uint8_t bandIndex=0) override
Get the info of a given band.
Hold variables of type string.
Definition: string.h:56
encapsulates test code
Definition: test.h:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:302
A suite of tests to run.
Definition: test.h:1273
Type
Type of test.
Definition: test.h:1280
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition: nstime.h:351
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
helps to create WifiNetDevice objects
Definition: wifi-helper.h:324
virtual void SetStandard(WifiStandard standard)
Definition: wifi-helper.cc:738
virtual NetDeviceContainer Install(const WifiPhyHelper &phy, const WifiMacHelper &mac, NodeContainer::Iterator first, NodeContainer::Iterator last) const
Definition: wifi-helper.cc:756
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.
Definition: wifi-helper.cc:543
void Set(std::string name, const AttributeValue &v)
Definition: wifi-helper.cc:163
void SetInterferenceHelper(std::string type, Args &&... args)
Helper function used to set the interference helper.
Definition: wifi-helper.h:543
@ DLT_IEEE802_11_RADIO
Include Radiotap link layer information.
Definition: wifi-helper.h:178
virtual void SetInterferenceHelper(const Ptr< InterferenceHelper > helper)
Sets the interference helper.
Definition: wifi-phy.cc:662
void Send(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
This function is a wrapper for the Send variant that accepts a WifiConstPsduMap as first argument.
Definition: wifi-phy.cc:1759
void SetErrorRateModel(const Ptr< ErrorRateModel > model)
Sets the error rate model.
Definition: wifi-phy.cc:671
uint32_t GetSubcarrierSpacing() const
Definition: wifi-phy.cc:2322
void SetReceiveErrorCallback(RxErrorCallback callback)
Definition: wifi-phy.cc:473
virtual void ConfigureStandard(WifiStandard standard)
Configure the PHY-level parameters for different Wi-Fi standard.
Definition: wifi-phy.cc:993
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1539
void RegisterListener(const std::shared_ptr< WifiPhyListener > &listener)
Definition: wifi-phy.cc:479
void SetOperatingChannel(const ChannelTuple &channelTuple)
If the standard for this object has not been set yet, store the given channel settings.
Definition: wifi-phy.cc:1130
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1053
std::tuple< uint8_t, uint16_t, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying an operating channel.
Definition: wifi-phy.h:926
virtual WifiSpectrumBandInfo GetBand(uint16_t bandWidth, uint8_t bandIndex=0)=0
Get the info of a given band.
void SetMobility(const Ptr< MobilityModel > mobility)
assign a mobility model to this device
Definition: wifi-phy.cc:637
void SetReceiveOkCallback(RxOkCallback callback)
Definition: wifi-phy.cc:467
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition: wifi-phy.cc:1065
receive notifications about PHY events.
Class that keeps track of all information about the current PHY operating channel.
static ConstIterator FindFirst(uint8_t number, uint16_t frequency, uint16_t width, WifiStandard standard, WifiPhyBand band, ConstIterator start=m_frequencyChannels.begin())
Find the first channel matching the specified parameters.
static Ptr< SpectrumValue > CreateOfdmTxPowerSpectralDensity(uint32_t centerFrequency, uint16_t channelWidth, double txPowerW, uint16_t guardBandwidth, double minInnerBandDbr=-20, double minOuterbandDbr=-28, double lowestPointDbr=-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:66
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:145
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1343
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1355
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
WifiPhyBand
Identifies the PHY band.
Definition: wifi-phy-band.h:33
WifiChannelListType
Enumeration of the possible channel-list parameter elements defined in Table 8-5 of IEEE 802....
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211n
@ WIFI_STANDARD_80211ax
@ WIFI_PREAMBLE_LONG
@ WIFI_PREAMBLE_HE_SU
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
Definition: wifi-phy-band.h:39
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
Definition: wifi-phy-band.h:35
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Definition: wifi-phy-band.h:37
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.
double RatioToDb(double ratio)
Convert from ratio to dB.
Definition: wifi-utils.cc:54
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
double WToDbm(double w)
Convert from Watts to dBm.
Definition: wifi-utils.cc:48
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:700
constexpr FrequencyRange WIFI_SPECTRUM_5_GHZ
Identifier for the frequency range covering the wifi spectrum in the 5 GHz band.
@ WIFI_MAC_QOSDATA
std::map< WifiSpectrumBandInfo, double > RxPowerWattPerChannelBand
A map of the received power (Watts) for each band.
Definition: phy-entity.h:77
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition: wifi-mode.h:35
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 uint16_t GUARD_WIDTH
static const uint16_t CHANNEL_WIDTH
Struct defining a frequency range between minFrequency (MHz) and maxFrequency (MHz).
uint16_t maxFrequency
the maximum frequency in MHz
uint16_t minFrequency
the minimum frequency in MHz
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:69
WifiSpectrumBandInfo structure containing info about a spectrum band.