A Discrete-Event Network Simulator
API
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/multi-model-spectrum-channel.h"
24 #include "ns3/nist-error-rate-model.h"
25 #include "ns3/ofdm-ppdu.h"
26 #include "ns3/pointer.h"
27 #include "ns3/spectrum-wifi-helper.h"
28 #include "ns3/spectrum-wifi-phy.h"
29 #include "ns3/string.h"
30 #include "ns3/test.h"
31 #include "ns3/wifi-mac-header.h"
32 #include "ns3/wifi-net-device.h"
33 #include "ns3/wifi-phy-listener.h"
34 #include "ns3/wifi-psdu.h"
35 #include "ns3/wifi-spectrum-phy-interface.h"
36 #include "ns3/wifi-spectrum-signal-parameters.h"
37 #include "ns3/wifi-spectrum-value-helper.h"
38 #include "ns3/wifi-utils.h"
39 
40 #include <memory>
41 #include <tuple>
42 #include <vector>
43 
44 using namespace ns3;
45 
46 NS_LOG_COMPONENT_DEFINE("SpectrumWifiPhyTest");
47 
48 static const uint8_t CHANNEL_NUMBER = 36;
49 static const uint16_t CHANNEL_WIDTH = 20; // MHz
50 static const uint16_t GUARD_WIDTH =
51  CHANNEL_WIDTH; // MHz (expanded to channel width to model spectrum mask)
52 
57 {
58  public:
60  using WifiPhy::GetBand;
61 };
62 
70 {
71  public:
78  SpectrumWifiPhyBasicTest(std::string name);
79  ~SpectrumWifiPhyBasicTest() override;
80 
81  protected:
82  void DoSetup() override;
83  void DoTeardown() override;
91  Ptr<SpectrumSignalParameters> MakeSignal(double txPowerWatts,
97  void SendSignal(double txPowerWatts);
105  void SpectrumWifiPhyRxSuccess(Ptr<const WifiPsdu> psdu,
106  RxSignalInfo rxSignalInfo,
107  WifiTxVector txVector,
108  std::vector<bool> statusPerMpdu);
113  void SpectrumWifiPhyRxFailure(Ptr<const WifiPsdu> psdu);
114  uint32_t m_count;
115 
116  private:
117  void DoRun() override;
118 
119  uint64_t m_uid;
120 };
121 
123  : SpectrumWifiPhyBasicTest("SpectrumWifiPhy test case receives one packet")
124 {
125 }
126 
128  : TestCase(name),
129  m_count(0),
130  m_uid(0)
131 {
132 }
133 
134 // Make a Wi-Fi signal to inject directly to the StartRx() method
137 {
138  WifiTxVector txVector = WifiTxVector(OfdmPhy::GetOfdmRate6Mbps(),
139  0,
141  800,
142  1,
143  1,
144  0,
146  false);
147 
148  Ptr<Packet> pkt = Create<Packet>(1000);
149  WifiMacHeader hdr;
150 
152  hdr.SetQosTid(0);
153 
154  Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
155  Time txDuration = m_phy->CalculateTxDuration(psdu->GetSize(), txVector, m_phy->GetPhyBand());
156 
157  Ptr<WifiPpdu> ppdu = Create<OfdmPpdu>(psdu, txVector, channel, m_uid++);
158 
159  Ptr<SpectrumValue> txPowerSpectrum = WifiSpectrumValueHelper::CreateOfdmTxPowerSpectralDensity(
160  channel.GetPrimaryChannelCenterFrequency(CHANNEL_WIDTH),
162  txPowerWatts,
163  GUARD_WIDTH);
164  Ptr<WifiSpectrumSignalParameters> txParams = Create<WifiSpectrumSignalParameters>();
165  txParams->psd = txPowerSpectrum;
166  txParams->txPhy = nullptr;
167  txParams->duration = txDuration;
168  txParams->ppdu = ppdu;
169 
170  return txParams;
171 }
172 
173 // Make a Wi-Fi signal to inject directly to the StartRx() method
174 void
176 {
177  m_phy->StartRx(MakeSignal(txPowerWatts, m_phy->GetOperatingChannel()), nullptr);
178 }
179 
180 void
182  RxSignalInfo rxSignalInfo,
183  WifiTxVector txVector,
184  std::vector<bool> statusPerMpdu)
185 {
186  NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
187  m_count++;
188 }
189 
190 void
192 {
193  NS_LOG_FUNCTION(this << *psdu);
194  m_count++;
195 }
196 
198 {
199 }
200 
201 // Create necessary objects, and inject signals. Test that the expected
202 // number of packet receptions occur.
203 void
205 {
206  Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
207  Ptr<Node> node = CreateObject<Node>();
208  Ptr<WifiNetDevice> dev = CreateObject<WifiNetDevice>();
209  m_phy = CreateObject<SpectrumWifiPhy>();
210  Ptr<InterferenceHelper> interferenceHelper = CreateObject<InterferenceHelper>();
211  m_phy->SetInterferenceHelper(interferenceHelper);
212  Ptr<ErrorRateModel> error = CreateObject<NistErrorRateModel>();
213  m_phy->SetErrorRateModel(error);
214  m_phy->SetDevice(dev);
215  m_phy->AddChannel(spectrumChannel);
222  dev->SetPhy(m_phy);
223  node->AddDevice(dev);
224 }
225 
226 void
228 {
229  m_phy->Dispose();
230  m_phy = nullptr;
231 }
232 
233 // Test that the expected number of packet receptions occur.
234 void
236 {
237  double txPowerWatts = 0.010;
238  // Send packets spaced 1 second apart; all should be received
239  Simulator::Schedule(Seconds(1), &SpectrumWifiPhyBasicTest::SendSignal, this, txPowerWatts);
240  Simulator::Schedule(Seconds(2), &SpectrumWifiPhyBasicTest::SendSignal, this, txPowerWatts);
241  Simulator::Schedule(Seconds(3), &SpectrumWifiPhyBasicTest::SendSignal, this, txPowerWatts);
242  // Send packets spaced 1 microsecond second apart; none should be received (PHY header reception
243  // failure)
244  Simulator::Schedule(MicroSeconds(4000000),
246  this,
247  txPowerWatts);
248  Simulator::Schedule(MicroSeconds(4000001),
250  this,
251  txPowerWatts);
252  Simulator::Run();
253  Simulator::Destroy();
254 
255  NS_TEST_ASSERT_MSG_EQ(m_count, 3, "Didn't receive right number of packets");
256 }
257 
265 {
266  public:
270  TestPhyListener() = default;
271  ~TestPhyListener() override = default;
272 
273  void NotifyRxStart(Time duration) override
274  {
275  NS_LOG_FUNCTION(this << duration);
276  ++m_notifyRxStart;
277  }
278 
279  void NotifyRxEndOk() override
280  {
281  NS_LOG_FUNCTION(this);
282  ++m_notifyRxEndOk;
283  }
284 
285  void NotifyRxEndError() override
286  {
287  NS_LOG_FUNCTION(this);
289  }
290 
291  void NotifyTxStart(Time duration, double txPowerDbm) override
292  {
293  NS_LOG_FUNCTION(this << duration << txPowerDbm);
294  }
295 
296  void NotifyCcaBusyStart(Time duration,
297  WifiChannelListType channelType,
298  const std::vector<Time>& /*per20MhzDurations*/) override
299  {
300  NS_LOG_FUNCTION(this << duration << channelType);
301  if (duration.IsStrictlyPositive())
302  {
305  {
307  }
309  }
310  }
311 
312  void NotifySwitchingStart(Time duration) override
313  {
314  }
315 
316  void NotifySleep() override
317  {
318  }
319 
320  void NotifyOff() override
321  {
322  }
323 
324  void NotifyWakeup() override
325  {
326  }
327 
328  void NotifyOn() override
329  {
330  }
331 
335  void Reset()
336  {
337  NS_LOG_FUNCTION(this);
338  m_notifyRxStart = 0;
339  m_notifyRxEndOk = 0;
340  m_notifyRxEndError = 0;
342  m_ccaBusyStart = Seconds(0);
343  m_ccaBusyEnd = Seconds(0);
344  }
345 
346  uint32_t m_notifyRxStart{0};
347  uint32_t m_notifyRxEndOk{0};
348  uint32_t m_notifyRxEndError{0};
352 };
353 
361 {
362  public:
364  ~SpectrumWifiPhyListenerTest() override;
365 
366  private:
367  void DoSetup() override;
368  void DoRun() override;
369  std::shared_ptr<TestPhyListener> m_listener;
370 };
371 
373  : SpectrumWifiPhyBasicTest("SpectrumWifiPhy test operation of WifiPhyListener")
374 {
375 }
376 
378 {
379 }
380 
381 void
383 {
385  m_listener = std::make_shared<TestPhyListener>();
387 }
388 
389 void
391 {
392  double txPowerWatts = 0.010;
393  Simulator::Schedule(Seconds(1), &SpectrumWifiPhyListenerTest::SendSignal, this, txPowerWatts);
394  Simulator::Run();
395 
396  NS_TEST_ASSERT_MSG_EQ(m_count, 1, "Didn't receive right number of packets");
398  m_listener->m_notifyMaybeCcaBusyStart,
399  2,
400  "Didn't receive NotifyCcaBusyStart (once preamble is detected + prolonged by L-SIG "
401  "reception, then switched to Rx by at the beginning of data)");
402  NS_TEST_ASSERT_MSG_EQ(m_listener->m_notifyRxStart, 1, "Didn't receive NotifyRxStart");
403  NS_TEST_ASSERT_MSG_EQ(m_listener->m_notifyRxEndOk, 1, "Didn't receive NotifyRxEnd");
404 
405  Simulator::Destroy();
406  m_listener.reset();
407 }
408 
416 {
417  public:
424  SpectrumWifiPhyFilterTest(std::string name);
425  ~SpectrumWifiPhyFilterTest() override;
426 
427  private:
428  void DoSetup() override;
429  void DoTeardown() override;
430  void DoRun() override;
431 
435  void RunOne();
436 
440  void SendPpdu();
441 
448 
451 
452  uint16_t m_txChannelWidth;
453  uint16_t m_rxChannelWidth;
454 
455  std::set<WifiSpectrumBandIndices> m_ruBands;
456 };
457 
459  : TestCase("SpectrumWifiPhy test RX filters"),
460  m_txChannelWidth(20),
461  m_rxChannelWidth(20)
462 {
463 }
464 
466  : TestCase(name)
467 {
468 }
469 
470 void
472 {
473  WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs0(),
474  0,
476  800,
477  1,
478  1,
479  0,
481  false,
482  false);
483  Ptr<Packet> pkt = Create<Packet>(1000);
484  WifiMacHeader hdr;
486  hdr.SetQosTid(0);
487  hdr.SetAddr1(Mac48Address("00:00:00:00:00:01"));
488  hdr.SetSequenceNumber(1);
489  Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
490  m_txPhy->Send(WifiConstPsduMap({std::make_pair(SU_STA_ID, psdu)}), txVector);
491 }
492 
494 {
495  m_txPhy = nullptr;
496  m_rxPhy = nullptr;
497 }
498 
499 void
501 {
502  for (const auto& pair : rxPowersW)
503  {
504  NS_LOG_INFO("band: (" << pair.first << ") -> powerW=" << pair.second << " ("
505  << WToDbm(pair.second) << " dBm)");
506  }
507 
508  size_t numBands = rxPowersW.size();
509  size_t expectedNumBands = std::max(1, (m_rxChannelWidth / 20));
510  expectedNumBands += (m_rxChannelWidth / 40);
511  expectedNumBands += (m_rxChannelWidth / 80);
512  expectedNumBands += (m_rxChannelWidth / 160);
513  expectedNumBands += m_ruBands.size();
514 
515  NS_TEST_ASSERT_MSG_EQ(numBands,
516  expectedNumBands,
517  "Total number of bands handled by the receiver is incorrect");
518 
519  uint16_t channelWidth = std::min(m_txChannelWidth, m_rxChannelWidth);
520  auto band = m_rxPhy->GetBand(channelWidth, 0);
521  auto it = rxPowersW.find(band);
522  NS_LOG_INFO("powerW total band: " << it->second << " (" << WToDbm(it->second) << " dBm)");
523  int totalRxPower = static_cast<int>(WToDbm(it->second) + 0.5);
524  int expectedTotalRxPower;
526  {
527  // PHY sends at 16 dBm, and since there is no loss, this should be the total power at the
528  // receiver.
529  expectedTotalRxPower = 16;
530  }
531  else
532  {
533  // Only a part of the transmitted power is received
534  expectedTotalRxPower =
535  16 - static_cast<int>(RatioToDb(m_txChannelWidth / m_rxChannelWidth));
536  }
537  NS_TEST_ASSERT_MSG_EQ(totalRxPower,
538  expectedTotalRxPower,
539  "Total received power is not correct");
540 
541  if ((m_txChannelWidth <= m_rxChannelWidth) && (channelWidth >= 20))
542  {
543  band = m_rxPhy->GetBand(20, 0); // primary 20 MHz
544  it = rxPowersW.find(band);
545  NS_LOG_INFO("powerW in primary 20 MHz channel: " << it->second << " (" << WToDbm(it->second)
546  << " dBm)");
547  int rxPowerPrimaryChannel20 = static_cast<int>(WToDbm(it->second) + 0.5);
548  int expectedRxPowerPrimaryChannel20 = 16 - static_cast<int>(RatioToDb(channelWidth / 20));
549  NS_TEST_ASSERT_MSG_EQ(rxPowerPrimaryChannel20,
550  expectedRxPowerPrimaryChannel20,
551  "Received power in the primary 20 MHz band is not correct");
552  }
553 }
554 
555 void
557 {
558  // WifiHelper::EnableLogComponents();
559  // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
560 
561  Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
562  Ptr<FriisPropagationLossModel> lossModel = CreateObject<FriisPropagationLossModel>();
563  lossModel->SetFrequency(5.180e9);
564  spectrumChannel->AddPropagationLossModel(lossModel);
566  CreateObject<ConstantSpeedPropagationDelayModel>();
567  spectrumChannel->SetPropagationDelayModel(delayModel);
568 
569  Ptr<Node> txNode = CreateObject<Node>();
570  Ptr<WifiNetDevice> txDev = CreateObject<WifiNetDevice>();
571  m_txPhy = CreateObject<ExtSpectrumWifiPhy>();
572  Ptr<InterferenceHelper> txInterferenceHelper = CreateObject<InterferenceHelper>();
573  m_txPhy->SetInterferenceHelper(txInterferenceHelper);
574  Ptr<ErrorRateModel> txErrorModel = CreateObject<NistErrorRateModel>();
575  m_txPhy->SetErrorRateModel(txErrorModel);
576  m_txPhy->SetDevice(txDev);
577  m_txPhy->AddChannel(spectrumChannel);
579  Ptr<ConstantPositionMobilityModel> apMobility = CreateObject<ConstantPositionMobilityModel>();
580  m_txPhy->SetMobility(apMobility);
581  txDev->SetPhy(m_txPhy);
582  txNode->AggregateObject(apMobility);
583  txNode->AddDevice(txDev);
584 
585  Ptr<Node> rxNode = CreateObject<Node>();
586  Ptr<WifiNetDevice> rxDev = CreateObject<WifiNetDevice>();
587  m_rxPhy = CreateObject<ExtSpectrumWifiPhy>();
588  Ptr<InterferenceHelper> rxInterferenceHelper = CreateObject<InterferenceHelper>();
589  m_rxPhy->SetInterferenceHelper(rxInterferenceHelper);
590  Ptr<ErrorRateModel> rxErrorModel = CreateObject<NistErrorRateModel>();
591  m_rxPhy->SetErrorRateModel(rxErrorModel);
592  m_rxPhy->AddChannel(spectrumChannel);
594  Ptr<ConstantPositionMobilityModel> sta1Mobility = CreateObject<ConstantPositionMobilityModel>();
595  m_rxPhy->SetMobility(sta1Mobility);
596  rxDev->SetPhy(m_rxPhy);
597  rxNode->AggregateObject(sta1Mobility);
598  rxNode->AddDevice(rxDev);
599  m_rxPhy->TraceConnectWithoutContext("PhyRxBegin",
601 }
602 
603 void
605 {
606  m_txPhy->Dispose();
607  m_txPhy = nullptr;
608  m_rxPhy->Dispose();
609  m_rxPhy = nullptr;
610 }
611 
612 void
614 {
615  uint16_t txFrequency;
616  switch (m_txChannelWidth)
617  {
618  case 20:
619  default:
620  txFrequency = 5180;
621  break;
622  case 40:
623  txFrequency = 5190;
624  break;
625  case 80:
626  txFrequency = 5210;
627  break;
628  case 160:
629  txFrequency = 5250;
630  break;
631  }
632  auto txChannelNum = std::get<0>(*WifiPhyOperatingChannel::FindFirst(0,
633  txFrequency,
639 
640  uint16_t rxFrequency;
641  switch (m_rxChannelWidth)
642  {
643  case 20:
644  default:
645  rxFrequency = 5180;
646  break;
647  case 40:
648  rxFrequency = 5190;
649  break;
650  case 80:
651  rxFrequency = 5210;
652  break;
653  case 160:
654  rxFrequency = 5250;
655  break;
656  }
657  auto rxChannelNum = std::get<0>(*WifiPhyOperatingChannel::FindFirst(0,
658  rxFrequency,
664 
665  m_ruBands.clear();
666  for (uint16_t bw = 160; bw >= 20; bw = bw / 2)
667  {
668  for (uint16_t i = 0; i < (m_rxChannelWidth / bw); ++i)
669  {
670  for (unsigned int type = 0; type < 7; type++)
671  {
672  auto ruType = static_cast<HeRu::RuType>(type);
673  for (std::size_t index = 1; index <= HeRu::GetNRus(bw, ruType); index++)
674  {
675  HeRu::SubcarrierGroup subcarrierGroup =
676  HeRu::GetSubcarrierGroup(bw, ruType, index);
677  HeRu::SubcarrierRange subcarrierRange =
678  std::make_pair(subcarrierGroup.front().first,
679  subcarrierGroup.back().second);
680  const auto band =
681  HePhy::ConvertHeRuSubcarriers(bw,
684  subcarrierRange,
685  i);
686  m_ruBands.insert(band);
687  }
688  }
689  }
690  }
691 
692  Simulator::Schedule(Seconds(1), &SpectrumWifiPhyFilterTest::SendPpdu, this);
693 
694  Simulator::Run();
695 }
696 
697 void
699 {
700  m_txChannelWidth = 20;
701  m_rxChannelWidth = 20;
702  RunOne();
703 
704  m_txChannelWidth = 40;
705  m_rxChannelWidth = 40;
706  RunOne();
707 
708  m_txChannelWidth = 80;
709  m_rxChannelWidth = 80;
710  RunOne();
711 
712  m_txChannelWidth = 160;
713  m_rxChannelWidth = 160;
714  RunOne();
715 
716  m_txChannelWidth = 20;
717  m_rxChannelWidth = 40;
718  RunOne();
719 
720  m_txChannelWidth = 20;
721  m_rxChannelWidth = 80;
722  RunOne();
723 
724  m_txChannelWidth = 40;
725  m_rxChannelWidth = 80;
726  RunOne();
727 
728  m_txChannelWidth = 20;
729  m_rxChannelWidth = 160;
730  RunOne();
731 
732  m_txChannelWidth = 40;
733  m_rxChannelWidth = 160;
734  RunOne();
735 
736  m_txChannelWidth = 80;
737  m_rxChannelWidth = 160;
738  RunOne();
739 
740  m_txChannelWidth = 40;
741  m_rxChannelWidth = 20;
742  RunOne();
743 
744  m_txChannelWidth = 80;
745  m_rxChannelWidth = 20;
746  RunOne();
747 
748  m_txChannelWidth = 80;
749  m_rxChannelWidth = 40;
750  RunOne();
751 
752  m_txChannelWidth = 160;
753  m_rxChannelWidth = 20;
754  RunOne();
755 
756  m_txChannelWidth = 160;
757  m_rxChannelWidth = 40;
758  RunOne();
759 
760  m_txChannelWidth = 160;
761  m_rxChannelWidth = 80;
762  RunOne();
763 
764  Simulator::Destroy();
765 }
766 
790 {
791  public:
798  SpectrumWifiPhyMultipleInterfacesTest(bool trackSignalsInactiveInterfaces);
799 
800  private:
801  void DoSetup() override;
802  void DoTeardown() override;
803  void DoRun() override;
804 
813  void SwitchChannel(std::size_t index,
814  WifiPhyBand band,
815  uint8_t channelNumber,
816  uint16_t channelWidth);
817 
825  void SendPpdu(Ptr<SpectrumWifiPhy> phy, double txPowerDbm);
826 
833  void RxCallback(std::size_t index,
834  Ptr<const Packet> packet,
835  RxPowerWattPerChannelBand rxPowersW);
836 
845  const FrequencyRange& freqRange,
846  const WifiSpectrumBandInfo& band,
847  bool interferencesExpected);
848 
856  const WifiSpectrumBandInfo& band,
857  bool interferencesExpected);
858 
869  void CheckResults(std::size_t index,
870  uint32_t expectedNumRx,
871  FrequencyRange expectedFrequencyRangeActiveRfInterface,
872  const std::vector<std::size_t>& expectedConnectedPhysPerChannel);
873 
882  void CheckCcaIndication(std::size_t index, bool expectedCcaBusyIndication, Time switchingDelay);
883 
887  void Reset();
888 
889  bool
892 
893  std::vector<Ptr<MultiModelSpectrumChannel>> m_spectrumChannels;
894  std::vector<Ptr<SpectrumWifiPhy>> m_txPhys{};
895  std::vector<Ptr<SpectrumWifiPhy>> m_rxPhys{};
896  std::vector<std::shared_ptr<TestPhyListener>> m_listeners{};
897 
898  std::vector<uint32_t> m_counts{0};
899 
902 };
903 
905  bool trackSignalsInactiveInterfaces)
906  : TestCase{"SpectrumWifiPhy test operation with multiple RF interfaces"},
907  m_trackSignalsInactiveInterfaces{trackSignalsInactiveInterfaces}
908 {
909 }
910 
911 void
913  WifiPhyBand band,
914  uint8_t channelNumber,
915  uint16_t channelWidth)
916 {
917  NS_LOG_FUNCTION(this << index << band << +channelNumber << channelWidth);
918  auto& listener = m_listeners.at(index);
919  listener->m_notifyMaybeCcaBusyStart = 0;
920  listener->m_ccaBusyStart = Seconds(0);
921  listener->m_ccaBusyEnd = Seconds(0);
922  auto phy = m_rxPhys.at(index);
923  phy->SetOperatingChannel(WifiPhy::ChannelTuple{channelNumber, channelWidth, band, 0});
924 }
925 
926 void
928 {
929  NS_LOG_FUNCTION(this << phy << txPowerDbm << phy->GetCurrentFrequencyRange()
930  << phy->GetChannelWidth() << phy->GetChannelNumber());
931 
932  WifiTxVector txVector =
933  WifiTxVector(HePhy::GetHeMcs0(), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, 20, false, false);
934  Ptr<Packet> pkt = Create<Packet>(1000);
935  WifiMacHeader hdr;
937  hdr.SetQosTid(0);
938  hdr.SetAddr1(Mac48Address("00:00:00:00:00:01"));
939  hdr.SetSequenceNumber(1);
940  Ptr<WifiPsdu> psdu = Create<WifiPsdu>(pkt, hdr);
941 
943  m_lastTxEnd = m_lastTxStart + WifiPhy::CalculateTxDuration({std::make_pair(SU_STA_ID, psdu)},
944  txVector,
945  phy->GetPhyBand());
946  phy->SetTxPowerStart(txPowerDbm);
947  phy->SetTxPowerEnd(txPowerDbm);
948  phy->Send(WifiConstPsduMap({std::make_pair(SU_STA_ID, psdu)}), txVector);
949 }
950 
951 void
953  Ptr<const Packet> /*packet*/,
954  RxPowerWattPerChannelBand /*rxPowersW*/)
955 {
956  auto phy = m_rxPhys.at(index);
957  NS_LOG_FUNCTION(this << index << phy->GetCurrentFrequencyRange() << phy->GetChannelWidth()
958  << phy->GetChannelNumber());
959  m_counts.at(index)++;
960 }
961 
962 void
964  const FrequencyRange& freqRange,
965  const WifiSpectrumBandInfo& band,
966  bool interferencesExpected)
967 {
968  if ((!m_trackSignalsInactiveInterfaces) && (phy->GetCurrentFrequencyRange() != freqRange))
969  {
970  // ignore since no bands for that range exists in interference helper in that case
971  return;
972  }
973  // This is needed to make sure PHY state will be checked as the last event if a state change
974  // occurred at the exact same time as the check
976  this,
977  phy,
978  band,
979  interferencesExpected);
980 }
981 
982 void
984  const WifiSpectrumBandInfo& band,
985  bool interferencesExpected)
986 {
987  NS_LOG_FUNCTION(this << phy << band << interferencesExpected);
988  PointerValue ptr;
989  phy->GetAttribute("InterferenceHelper", ptr);
990  auto interferenceHelper = DynamicCast<InterferenceHelper>(ptr.Get<InterferenceHelper>());
991  NS_ASSERT(interferenceHelper);
992  const auto energyDuration = interferenceHelper->GetEnergyDuration(0, band);
993  NS_TEST_ASSERT_MSG_EQ(energyDuration.IsStrictlyPositive(),
994  interferencesExpected,
995  "Incorrect interferences detection");
996 }
997 
998 void
1000  std::size_t index,
1001  uint32_t expectedNumRx,
1002  FrequencyRange expectedFrequencyRangeActiveRfInterface,
1003  const std::vector<std::size_t>& expectedConnectedPhysPerChannel)
1004 {
1005  NS_LOG_FUNCTION(this << index << expectedNumRx << expectedFrequencyRangeActiveRfInterface);
1006  const auto phy = m_rxPhys.at(index);
1007  std::size_t numActiveInterfaces = 0;
1008  for (const auto& [freqRange, interface] : phy->GetSpectrumPhyInterfaces())
1009  {
1010  const auto expectedActive = (freqRange == expectedFrequencyRangeActiveRfInterface);
1011  const auto isActive = (interface == phy->GetCurrentInterface());
1012  NS_TEST_ASSERT_MSG_EQ(isActive, expectedActive, "Incorrect active interface");
1013  if (isActive)
1014  {
1015  numActiveInterfaces++;
1016  }
1017  }
1018  NS_TEST_ASSERT_MSG_EQ(numActiveInterfaces, 1, "There should always be one active interface");
1019  NS_ASSERT(expectedConnectedPhysPerChannel.size() == m_spectrumChannels.size());
1020  for (std::size_t i = 0; i < m_spectrumChannels.size(); ++i)
1021  {
1022  NS_TEST_ASSERT_MSG_EQ(m_spectrumChannels.at(i)->GetNDevices(),
1023  expectedConnectedPhysPerChannel.at(i),
1024  "Incorrect number of PHYs attached to the spectrum channel");
1025  }
1026  NS_TEST_ASSERT_MSG_EQ(m_counts.at(index),
1027  expectedNumRx,
1028  "Didn't receive right number of packets");
1029  NS_TEST_ASSERT_MSG_EQ(m_listeners.at(index)->m_notifyRxStart,
1030  expectedNumRx,
1031  "Didn't receive NotifyRxStart");
1032 }
1033 
1034 void
1036  bool expectedCcaBusyIndication,
1037  Time switchingDelay)
1038 {
1039  const auto expectedCcaBusyStart =
1040  expectedCcaBusyIndication ? m_lastTxStart + switchingDelay : Seconds(0);
1041  const auto expectedCcaBusyEnd = expectedCcaBusyIndication ? m_lastTxEnd : Seconds(0);
1042  NS_LOG_FUNCTION(this << index << expectedCcaBusyIndication << expectedCcaBusyStart
1043  << expectedCcaBusyEnd);
1044  auto& listener = m_listeners.at(index);
1045  const auto ccaBusyIndication = (listener->m_notifyMaybeCcaBusyStart > 0);
1046  const auto ccaBusyStart = listener->m_ccaBusyStart;
1047  const auto ccaBusyEnd = listener->m_ccaBusyEnd;
1048  NS_TEST_ASSERT_MSG_EQ(ccaBusyIndication,
1049  expectedCcaBusyIndication,
1050  "CCA busy indication check failed");
1051  NS_TEST_ASSERT_MSG_EQ(ccaBusyStart, expectedCcaBusyStart, "CCA busy start mismatch");
1052  NS_TEST_ASSERT_MSG_EQ(ccaBusyEnd, expectedCcaBusyEnd, "CCA busy end mismatch");
1053 }
1054 
1055 void
1057 {
1058  NS_LOG_FUNCTION(this);
1059  for (auto& count : m_counts)
1060  {
1061  count = 0;
1062  }
1063  for (auto& listener : m_listeners)
1064  {
1065  listener->Reset();
1066  }
1067  // restore all RX PHYs to initial channels
1068  for (std::size_t rxPhyIndex = 0; rxPhyIndex < m_rxPhys.size(); ++rxPhyIndex)
1069  {
1070  auto txPhy = m_txPhys.at(rxPhyIndex);
1071  SwitchChannel(rxPhyIndex,
1072  txPhy->GetPhyBand(),
1073  txPhy->GetChannelNumber(),
1074  txPhy->GetChannelWidth());
1075  }
1076 }
1077 
1078 void
1080 {
1081  NS_LOG_FUNCTION(this);
1082 
1083  // WifiHelper::EnableLogComponents();
1084  // LogComponentEnable("SpectrumWifiPhyTest", LOG_LEVEL_ALL);
1085 
1087  NodeContainer wifiStaNode(1);
1088 
1089  WifiHelper wifi;
1090  wifi.SetStandard(WIFI_STANDARD_80211be);
1091 
1092  SpectrumWifiPhyHelper phyHelper(4);
1093  phyHelper.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
1094 
1095  struct SpectrumPhyInterfaceInfo
1096  {
1097  FrequencyRange range;
1098  uint8_t number;
1099  WifiPhyBand band;
1100  std::string bandName;
1101  };
1102 
1103  const FrequencyRange WIFI_SPECTRUM_5_GHZ_LOW{
1107  const FrequencyRange WIFI_SPECTRUM_5_GHZ_HIGH{
1111 
1112  const std::vector<SpectrumPhyInterfaceInfo> interfaces{
1113  {WIFI_SPECTRUM_2_4_GHZ, 2, WIFI_PHY_BAND_2_4GHZ, "BAND_2_4GHZ"},
1114  {WIFI_SPECTRUM_5_GHZ_LOW, 42, WIFI_PHY_BAND_5GHZ, "BAND_5GHZ"},
1115  {WIFI_SPECTRUM_5_GHZ_HIGH, 163, WIFI_PHY_BAND_5GHZ, "BAND_5GHZ"},
1116  {WIFI_SPECTRUM_6_GHZ, 215, WIFI_PHY_BAND_6GHZ, "BAND_6GHZ"}};
1117 
1118  for (std::size_t i = 0; i < interfaces.size(); ++i)
1119  {
1120  auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
1121  [[maybe_unused]] const auto [channel, frequency, channelWidth, type, band] =
1122  (*WifiPhyOperatingChannel::FindFirst(interfaces.at(i).number,
1123  0,
1124  0,
1126  interfaces.at(i).band));
1127 
1128  std::ostringstream oss;
1129  oss << "{" << +interfaces.at(i).number << ", 0, " << interfaces.at(i).bandName << ", 0}";
1130  phyHelper.Set(i, "ChannelSettings", StringValue(oss.str()));
1131  phyHelper.AddChannel(spectrumChannel, interfaces.at(i).range);
1132 
1133  m_spectrumChannels.emplace_back(spectrumChannel);
1134  }
1135 
1137  mac.SetType("ns3::ApWifiMac", "BeaconGeneration", BooleanValue(false));
1138  phyHelper.Set("TrackSignalsFromInactiveInterfaces", BooleanValue(false));
1139  auto apDevice = wifi.Install(phyHelper, mac, wifiApNode.Get(0));
1140 
1141  mac.SetType("ns3::StaWifiMac", "ActiveProbing", BooleanValue(false));
1142  phyHelper.Set("TrackSignalsFromInactiveInterfaces",
1144  auto staDevice = wifi.Install(phyHelper, mac, wifiStaNode.Get(0));
1145 
1146  for (std::size_t i = 0; i < interfaces.size(); ++i)
1147  {
1148  auto txPhy =
1149  DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(apDevice.Get(0))->GetPhy(i));
1150  m_txPhys.push_back(txPhy);
1151 
1152  const auto index = m_rxPhys.size();
1153  auto rxPhy =
1154  DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(staDevice.Get(0))->GetPhy(i));
1155  rxPhy->TraceConnectWithoutContext(
1156  "PhyRxBegin",
1158 
1159  auto listener = std::make_shared<TestPhyListener>();
1160  rxPhy->RegisterListener(listener);
1161  m_listeners.push_back(std::move(listener));
1162 
1163  m_rxPhys.push_back(rxPhy);
1164  m_counts.push_back(0);
1165  }
1166 }
1167 
1168 void
1170 {
1171  NS_LOG_FUNCTION(this);
1172  for (auto& phy : m_txPhys)
1173  {
1174  phy->Dispose();
1175  phy = nullptr;
1176  }
1177  for (auto& phy : m_rxPhys)
1178  {
1179  phy->Dispose();
1180  phy = nullptr;
1181  }
1182  Simulator::Destroy();
1183 }
1184 
1185 void
1187 {
1188  NS_LOG_FUNCTION(this);
1189 
1190  const auto ccaEdThresholdDbm = -62.0;
1191  const auto txAfterChannelSwitchDelay =
1192  Seconds(0.25);
1194  const auto checkResultsDelay =
1195  Seconds(0.5);
1196  const auto flushResultsDelay =
1197  Seconds(0.9);
1198  const auto txOngoingAfterTxStartedDelay =
1199  MicroSeconds(50);
1201 
1202  Time delay{0};
1203 
1204  // default channels active for all PHYs: each PHY only receives from its associated TX
1205  std::vector<std::size_t> expectedConnectedPhysPerChannel =
1206  m_trackSignalsInactiveInterfaces ? std::vector<std::size_t>{5, 5, 5, 5}
1207  : // all RX PHYs keep all channels active when tracking
1208  // interferences on inactive interfaces
1209  std::vector<std::size_t>{2, 2, 2, 2}; // default channels active for all PHYs: each PHY
1210  // only receives from its associated TX
1211  for (std::size_t i = 0; i < 4; ++i)
1212  {
1213  auto txPpduPhy = m_txPhys.at(i);
1214  delay += Seconds(1);
1215  Simulator::Schedule(delay,
1217  this,
1218  txPpduPhy,
1219  0);
1220  for (std::size_t j = 0; j < 4; ++j)
1221  {
1222  auto txPhy = m_txPhys.at(j);
1223  auto rxPhy = m_rxPhys.at(j);
1224  const auto& expectedFreqRange = txPhy->GetCurrentFrequencyRange();
1225  Simulator::Schedule(delay + txOngoingAfterTxStartedDelay,
1227  this,
1228  rxPhy,
1229  txPpduPhy->GetCurrentFrequencyRange(),
1230  txPpduPhy->GetBand(txPpduPhy->GetChannelWidth(), 0),
1231  true);
1232  Simulator::Schedule(delay + checkResultsDelay,
1234  this,
1235  j,
1236  (i == j) ? 1 : 0,
1237  expectedFreqRange,
1238  expectedConnectedPhysPerChannel);
1239  }
1240  Simulator::Schedule(delay + flushResultsDelay,
1242  this);
1243  }
1244 
1245  // same channel active for all PHYs: all PHYs receive from TX
1246  for (std::size_t i = 0; i < 4; ++i)
1247  {
1248  delay += Seconds(1);
1249  auto txPpduPhy = m_txPhys.at(i);
1250  Simulator::Schedule(delay + txAfterChannelSwitchDelay,
1252  this,
1253  txPpduPhy,
1254  0);
1255  const auto& expectedFreqRange = txPpduPhy->GetCurrentFrequencyRange();
1256  for (std::size_t j = 0; j < 4; ++j)
1257  {
1259  {
1260  for (std::size_t k = 0; k < expectedConnectedPhysPerChannel.size(); ++k)
1261  {
1262  expectedConnectedPhysPerChannel.at(k) = (k == i) ? 5 : 1;
1263  }
1264  }
1265  auto rxPhy = m_rxPhys.at(j);
1266  Simulator::Schedule(delay,
1268  this,
1269  j,
1270  txPpduPhy->GetPhyBand(),
1271  txPpduPhy->GetChannelNumber(),
1272  txPpduPhy->GetChannelWidth());
1273  Simulator::Schedule(delay + txAfterChannelSwitchDelay + txOngoingAfterTxStartedDelay,
1275  this,
1276  rxPhy,
1277  txPpduPhy->GetCurrentFrequencyRange(),
1278  txPpduPhy->GetBand(txPpduPhy->GetChannelWidth(), 0),
1279  true);
1280  Simulator::Schedule(delay + checkResultsDelay,
1282  this,
1283  j,
1284  1,
1285  expectedFreqRange,
1286  expectedConnectedPhysPerChannel);
1287  }
1288  Simulator::Schedule(delay + flushResultsDelay,
1290  this);
1291  }
1292 
1293  // Switch all PHYs to channel 36: all PHYs switch to the second spectrum channel
1294  // since second spectrum channel is 42 (80 MHz) and hence covers channel 36 (20 MHz)
1295  const auto secondSpectrumChannelIndex = 1;
1296  auto channel36TxPhy = m_txPhys.at(secondSpectrumChannelIndex);
1297  const auto& expectedFreqRange = channel36TxPhy->GetCurrentFrequencyRange();
1298  for (std::size_t i = 0; i < 4; ++i)
1299  {
1300  delay += Seconds(1);
1301  auto txPpduPhy = m_txPhys.at(i);
1302  Simulator::Schedule(delay + txAfterChannelSwitchDelay,
1304  this,
1305  txPpduPhy,
1306  0);
1307  for (std::size_t j = 0; j < 4; ++j)
1308  {
1310  {
1311  for (std::size_t k = 0; k < expectedConnectedPhysPerChannel.size(); ++k)
1312  {
1313  expectedConnectedPhysPerChannel.at(k) =
1314  (k == secondSpectrumChannelIndex) ? 5 : 1;
1315  }
1316  }
1317  Simulator::Schedule(delay,
1319  this,
1320  j,
1323  CHANNEL_WIDTH);
1324  Simulator::Schedule(delay + checkResultsDelay,
1326  this,
1327  j,
1328  (i == secondSpectrumChannelIndex) ? 1 : 0,
1329  expectedFreqRange,
1330  expectedConnectedPhysPerChannel);
1331  }
1332  Simulator::Schedule(delay + flushResultsDelay,
1334  this);
1335  }
1336 
1337  // verify CCA indication when switching to a channel with an ongoing transmission
1338  for (const auto txPowerDbm : {-60.0 /* above CCA-ED */, -70.0 /* below CCA-ED */})
1339  {
1340  for (std::size_t i = 0; i < 4; ++i)
1341  {
1342  for (std::size_t j = 0; j < 4; ++j)
1343  {
1344  auto txPpduPhy = m_txPhys.at(i);
1345  const auto startChannel =
1346  WifiPhyOperatingChannel::FindFirst(txPpduPhy->GetPrimaryChannelNumber(20),
1347  0,
1348  20,
1350  txPpduPhy->GetPhyBand());
1351  for (uint16_t bw = txPpduPhy->GetChannelWidth(); bw >= 20; bw /= 2)
1352  {
1353  [[maybe_unused]] const auto [channel, frequency, channelWidth, type, band] =
1354  (*WifiPhyOperatingChannel::FindFirst(0,
1355  0,
1356  bw,
1358  txPpduPhy->GetPhyBand(),
1359  startChannel));
1360  delay += Seconds(1);
1361  Simulator::Schedule(delay,
1363  this,
1364  txPpduPhy,
1365  txPowerDbm);
1366  Simulator::Schedule(delay + txOngoingAfterTxStartedDelay,
1368  this,
1369  j,
1370  band,
1371  channel,
1372  channelWidth);
1373  for (std::size_t k = 0; k < 4; ++k)
1374  {
1375  if ((i != j) && (k == i))
1376  {
1377  continue;
1378  }
1379  const auto expectCcaBusyIndication =
1380  (k == i) ? (txPowerDbm >= ccaEdThresholdDbm)
1382  ? ((txPowerDbm >= ccaEdThresholdDbm) ? (j == k) : false)
1383  : false);
1384  Simulator::Schedule(
1385  delay + checkResultsDelay,
1387  this,
1388  k,
1389  expectCcaBusyIndication,
1390  txOngoingAfterTxStartedDelay);
1391  }
1392  Simulator::Schedule(delay + flushResultsDelay,
1394  this);
1395  }
1396  }
1397  }
1398  }
1399 
1400  Simulator::Stop(Seconds(30));
1401  Simulator::Run();
1402 }
1403 
1414 {
1415  public:
1418 
1419  private:
1420  void DoRun() override;
1421 };
1422 
1424  : TestCase("Check PHY interfaces added to PHY instances using helper")
1425 {
1426 }
1427 
1428 void
1430 {
1431  WifiHelper wifiHelper;
1432  wifiHelper.SetStandard(WIFI_STANDARD_80211be);
1433 
1434  SpectrumWifiPhyHelper phyHelper(3);
1435  phyHelper.Set(0, "ChannelSettings", StringValue("{2, 0, BAND_2_4GHZ, 0}"));
1436  phyHelper.Set(1, "ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}"));
1437  phyHelper.Set(2, "ChannelSettings", StringValue("{1, 0, BAND_6GHZ, 0}"));
1438 
1439  phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_2_4_GHZ);
1440  phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_5_GHZ);
1441  phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_6_GHZ);
1442 
1443  WifiMacHelper macHelper;
1444  NodeContainer nodes(4);
1445 
1446  /* Default case: all interfaces are added to each link */
1447  auto device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(0));
1448 
1449  // Verify each PHY has 3 interfaces
1450  auto phyLink0 =
1451  DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
1452  NS_ASSERT(phyLink0);
1453  NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
1454  3,
1455  "Incorrect number of PHY interfaces added to PHY link ID 0");
1456 
1457  auto phyLink1 =
1458  DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
1459  NS_ASSERT(phyLink1);
1460  NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
1461  3,
1462  "Incorrect number of PHY interfaces added to PHY link ID 1");
1463 
1464  auto phyLink2 =
1465  DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
1466  NS_ASSERT(phyLink2);
1467  NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
1468  3,
1469  "Incorrect number of PHY interfaces added to PHY link ID 2");
1470 
1471  /* each PHY has a single interface */
1475  device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(1));
1476 
1477  // Verify each PHY has a single interface
1478  phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
1479  NS_ASSERT(phyLink0);
1480  NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
1481  1,
1482  "Incorrect number of PHY interfaces added to PHY link ID 0");
1483  NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
1484  1,
1485  "Incorrect PHY interfaces added to PHY link ID 0");
1486 
1487  phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
1488  NS_ASSERT(phyLink1);
1489  NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
1490  1,
1491  "Incorrect number of PHY interfaces added to PHY link ID 1");
1492  NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1493  1,
1494  "Incorrect PHY interfaces added to PHY link ID 1");
1495 
1496  phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
1497  NS_ASSERT(phyLink2);
1498  NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
1499  1,
1500  "Incorrect number of PHY interfaces added to PHY link ID 2");
1501  NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
1502  1,
1503  "Incorrect PHY interfaces added to PHY link ID 2");
1504 
1505  /* add yet another interface to PHY 0 */
1507  device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(2));
1508 
1509  // Verify each PHY has a single interface except PHY 0 that should have 2 interfaces
1510  phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
1511  NS_ASSERT(phyLink0);
1512  NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
1513  2,
1514  "Incorrect number of PHY interfaces added to PHY link ID 0");
1515  NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
1516  1,
1517  "Incorrect PHY interfaces added to PHY link ID 0");
1518  NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1519  1,
1520  "Incorrect PHY interfaces added to PHY link ID 0");
1521 
1522  phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
1523  NS_ASSERT(phyLink1);
1524  NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
1525  1,
1526  "Incorrect number of PHY interfaces added to PHY link ID 1");
1527  NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1528  1,
1529  "Incorrect PHY interfaces added to PHY link ID 1");
1530 
1531  phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
1532  NS_ASSERT(phyLink2);
1533  NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
1534  1,
1535  "Incorrect number of PHY interfaces added to PHY link ID 2");
1536  NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
1537  1,
1538  "Incorrect PHY interfaces added to PHY link ID 2");
1539 
1540  /* reset mapping previously configured to helper: back to default */
1541  phyHelper.ResetPhyToFreqRangeMapping();
1542  device = wifiHelper.Install(phyHelper, macHelper, nodes.Get(3));
1543 
1544  // Verify each PHY has 3 interfaces
1545  phyLink0 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(0));
1546  NS_ASSERT(phyLink0);
1547  NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().size(),
1548  3,
1549  "Incorrect number of PHY interfaces added to PHY link ID 0");
1550  NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
1551  1,
1552  "Incorrect PHY interfaces added to PHY link ID 0");
1553  NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1554  1,
1555  "Incorrect PHY interfaces added to PHY link ID 0");
1556  NS_TEST_ASSERT_MSG_EQ(phyLink0->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
1557  1,
1558  "Incorrect PHY interfaces added to PHY link ID 0");
1559 
1560  phyLink1 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(1));
1561  NS_ASSERT(phyLink1);
1562  NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().size(),
1563  3,
1564  "Incorrect number of PHY interfaces added to PHY link ID 1");
1565  NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
1566  1,
1567  "Incorrect PHY interfaces added to PHY link ID 0");
1568  NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1569  1,
1570  "Incorrect PHY interfaces added to PHY link ID 0");
1571  NS_TEST_ASSERT_MSG_EQ(phyLink1->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
1572  1,
1573  "Incorrect PHY interfaces added to PHY link ID 0");
1574 
1575  phyLink2 = DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(device.Get(0))->GetPhy(2));
1576  NS_ASSERT(phyLink2);
1577  NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().size(),
1578  3,
1579  "Incorrect number of PHY interfaces added to PHY link ID 2");
1580  NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_2_4_GHZ),
1581  1,
1582  "Incorrect PHY interfaces added to PHY link ID 0");
1583  NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_5_GHZ),
1584  1,
1585  "Incorrect PHY interfaces added to PHY link ID 0");
1586  NS_TEST_ASSERT_MSG_EQ(phyLink2->GetSpectrumPhyInterfaces().count(WIFI_SPECTRUM_6_GHZ),
1587  1,
1588  "Incorrect PHY interfaces added to PHY link ID 0");
1589 
1590  Simulator::Destroy();
1591 }
1592 
1600 {
1601  public:
1603 };
1604 
1606  : TestSuite("wifi-spectrum-wifi-phy", UNIT)
1607 {
1608  AddTestCase(new SpectrumWifiPhyBasicTest, TestCase::QUICK);
1609  AddTestCase(new SpectrumWifiPhyListenerTest, TestCase::QUICK);
1610  AddTestCase(new SpectrumWifiPhyFilterTest, TestCase::QUICK);
1611  AddTestCase(new SpectrumWifiPhyMultipleInterfacesTest(false), TestCase::QUICK);
1612  AddTestCase(new SpectrumWifiPhyMultipleInterfacesTest(true), TestCase::QUICK);
1613  AddTestCase(new SpectrumWifiPhyInterfacesHelperTest, TestCase::QUICK);
1614 }
1615 
#define min(a, b)
Definition: 80211b.c:41
#define max(a, b)
Definition: 80211b.c:42
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.
void CheckCcaIndication(std::size_t index, bool expectedCcaBusyIndication, Time switchingDelay)
Verify CCA indication reported by a given PHY.
std::vector< Ptr< SpectrumWifiPhy > > m_rxPhys
RX PHYs.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
void DoRun() override
Implementation to actually run this TestCase.
void DoCheckInterferences(Ptr< SpectrumWifiPhy > phy, const WifiSpectrumBandInfo &band, bool interferencesExpected)
Check the interferences.
SpectrumWifiPhyMultipleInterfacesTest(bool trackSignalsInactiveInterfaces)
Constructor.
bool m_trackSignalsInactiveInterfaces
flag to indicate whether signals coming from inactive spectrum PHY interfaces are tracked during the ...
std::vector< std::shared_ptr< TestPhyListener > > m_listeners
listeners
Time m_lastTxEnd
hold the time at which the last transmission ended
void CheckResults(std::size_t index, uint32_t expectedNumRx, FrequencyRange expectedFrequencyRangeActiveRfInterface, const std::vector< std::size_t > &expectedConnectedPhysPerChannel)
Verify results.
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 SwitchChannel(std::size_t index, WifiPhyBand band, uint8_t channelNumber, uint16_t channelWidth)
Switch channel function.
std::vector< Ptr< SpectrumWifiPhy > > m_txPhys
TX PHYs.
void SendPpdu(Ptr< SpectrumWifiPhy > phy, double txPowerDbm)
Send PPDU function.
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.
void RxCallback(std::size_t index, Ptr< const Packet > packet, RxPowerWattPerChannelBand rxPowersW)
Callback triggered when a packet is received by a PHY.
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
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
an EUI-48 address
Definition: mac48-address.h:46
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.
uint32_t AddDevice(Ptr< NetDevice > device)
Associate a NetDevice to this node.
Definition: node.cc:138
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:315
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition: object.cc:259
void Dispose()
Dispose of this Object.
Definition: object.cc:219
Hold objects of type Ptr<T>.
Definition: pointer.h:37
Ptr< T > Get() const
Definition: pointer.h:202
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:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition: nstime.h:351
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 SetPhy(const Ptr< WifiPhy > phy)
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
virtual void SetInterferenceHelper(const Ptr< InterferenceHelper > helper)
Sets the interference helper.
Definition: wifi-phy.cc:631
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:1720
void SetErrorRateModel(const Ptr< ErrorRateModel > model)
Sets the error rate model.
Definition: wifi-phy.cc:639
uint32_t GetSubcarrierSpacing() const
Definition: wifi-phy.cc:2251
void SetReceiveErrorCallback(RxErrorCallback callback)
Definition: wifi-phy.cc:455
virtual void ConfigureStandard(WifiStandard standard)
Configure the PHY-level parameters for different Wi-Fi standard.
Definition: wifi-phy.cc:961
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1507
void RegisterListener(const std::shared_ptr< WifiPhyListener > &listener)
Definition: wifi-phy.cc:461
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:1098
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1021
std::tuple< uint8_t, uint16_t, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying an operating channel.
Definition: wifi-phy.h:891
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:619
void SetReceiveOkCallback(RxOkCallback callback)
Definition: wifi-phy.cc:449
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition: wifi-phy.cc:1033
receive notifications about PHY events.
Class that keeps track of all information about the current PHY operating channel.
uint32_t GetSize() const
Return the size of the PSDU in bytes.
Definition: wifi-psdu.cc:273
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
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:305
#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:144
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
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
interfaces
Definition: first.py:50
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:52
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:46
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:704
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.
channel
Definition: third.py:88
mac
Definition: third.py:92
wifi
Definition: third.py:95
wifiApNode
Definition: third.py:86
phy
Definition: third.py:89
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.