A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
spectrum-wifi-phy.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2005,2006 INRIA
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
7 * Ghada Badawy <gbadawy@gmail.com>
8 * Sébastien Deronne <sebastien.deronne@gmail.com>
9 *
10 * Ported from yans-wifi-phy.cc by several contributors starting
11 * with Nicola Baldo and Dean Armstrong
12 */
13
14#include "spectrum-wifi-phy.h"
15
16#include "interference-helper.h"
17#include "wifi-net-device.h"
18#include "wifi-psdu.h"
21#include "wifi-utils.h"
22
23#include "ns3/boolean.h"
24#include "ns3/double.h"
25#include "ns3/he-phy.h"
26#include "ns3/log.h"
27#include "ns3/node.h"
28#include "ns3/simulator.h"
29#include "ns3/spectrum-channel.h"
30
31#include <algorithm>
32#include <numeric>
33
34#undef NS_LOG_APPEND_CONTEXT
35#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(Ptr(this, false))
36
37namespace ns3
38{
39
40NS_LOG_COMPONENT_DEFINE("SpectrumWifiPhy");
41
42NS_OBJECT_ENSURE_REGISTERED(SpectrumWifiPhy);
43
44TypeId
46{
47 static TypeId tid =
48 TypeId("ns3::SpectrumWifiPhy")
50 .SetGroupName("Wifi")
51 .AddConstructor<SpectrumWifiPhy>()
52 .AddAttribute("DisableWifiReception",
53 "Prevent Wi-Fi frame sync from ever happening",
54 BooleanValue(false),
57 .AddAttribute(
58 "TrackSignalsFromInactiveInterfaces",
59 "Enable or disable tracking signals coming from inactive spectrum PHY interfaces",
60 BooleanValue(true),
63 .AddAttribute(
64 "TxMaskInnerBandMinimumRejection",
65 "Minimum rejection (dBr) for the inner band of the transmit spectrum mask",
66 DoubleValue(-20.0),
69 .AddAttribute(
70 "TxMaskOuterBandMinimumRejection",
71 "Minimum rejection (dBr) for the outer band of the transmit spectrum mask",
72 DoubleValue(-28.0),
75 .AddAttribute(
76 "TxMaskOuterBandMaximumRejection",
77 "Maximum rejection (dBr) for the outer band of the transmit spectrum mask",
78 DoubleValue(-40.0),
81 .AddTraceSource(
82 "SignalArrival",
83 "Trace start of all signal arrivals, including weak and foreign signals",
85 "ns3::SpectrumWifiPhy::SignalArrivalCallback");
86 return tid;
87}
88
90 : m_spectrumPhyInterfaces{},
91 m_currentSpectrumPhyInterface{nullptr},
92 m_frequenciesBeforeSwitch{},
93 m_widthsBeforeSwitch{}
94{
95 NS_LOG_FUNCTION(this);
96}
97
102
103void
113
114void
120
123{
124 NS_LOG_FUNCTION(this << spectrumPhyInterface);
125 WifiSpectrumBands bands{};
126 const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
127 if (channelWidth < MHz_u{20})
128 {
129 bands.push_back(GetBandForInterface(spectrumPhyInterface, channelWidth));
130 }
131 else
132 {
133 for (MHz_u bw = channelWidth; bw >= MHz_u{20}; bw = bw / 2)
134 {
135 for (uint16_t i = 0; i < (channelWidth / bw); ++i)
136 {
137 bands.push_back(GetBandForInterface(spectrumPhyInterface, bw, i));
138 }
139 }
140 }
141 return bands;
142}
143
146 MHz_u guardBandwidth)
147{
148 RuBands ruBands{};
149 const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
150 const auto p20Index = GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20});
151 std::vector<WifiModulationClass> modClasses{WIFI_MOD_CLASS_HE};
153 {
154 modClasses.push_back(WIFI_MOD_CLASS_EHT);
155 }
156 for (const auto modClass : modClasses)
157 {
158 for (MHz_u bw = channelWidth; bw >= MHz_u{20}; bw = bw / 2)
159 {
160 if (bw > GetMaximumChannelWidth(modClass))
161 {
162 continue;
163 }
164 for (uint8_t i = 0; i < (channelWidth / bw); ++i)
165 {
166 for (uint32_t type = 0;
167 type <= static_cast<uint32_t>(WifiRu::GetMaxRuType(modClass));
168 ++type)
169 {
170 const auto ruType = static_cast<RuType>(type);
171 const auto nRus = WifiRu::GetNRus(bw, ruType, modClass);
172 std::size_t undefRus{0};
173 for (std::size_t phyIndex = 1; phyIndex <= nRus + undefRus; ++phyIndex)
174 {
175 const auto group =
176 WifiRu::GetSubcarrierGroup(bw, ruType, phyIndex, modClass);
177 if (group.empty())
178 {
179 ++undefRus;
180 continue;
181 }
182 const auto subcarrierRange =
183 std::make_pair(group.front().first, group.back().second);
184 const auto bandIndices = HePhy::ConvertRuSubcarriers(
185 {bw,
186 guardBandwidth,
187 spectrumPhyInterface->GetCenterFrequencies(),
188 spectrumPhyInterface->GetChannelWidth(),
190 modClass,
191 subcarrierRange,
192 i});
193
195 for (const auto& indicesPerSegment : bandIndices)
196 {
197 band.indices.emplace_back(indicesPerSegment);
198 band.frequencies.emplace_back(
199 ConvertIndicesToFrequenciesForInterface(spectrumPhyInterface,
200 indicesPerSegment));
201 }
203 if (modClass == WIFI_MOD_CLASS_HE)
204 {
205 const auto index = HeRu::GetIndexIn80MHzSegment(bw, ruType, phyIndex);
206 const auto primary80 =
207 HeRu::GetPrimary80MHzFlag(bw, ruType, phyIndex, p20Index);
208 ru = HeRu::RuSpec{ruType, index, primary80};
209 }
210 else
211 {
212 const auto index = EhtRu::GetIndexIn80MHzSegment(bw, ruType, phyIndex);
213 const auto& [primary160, primary80OrLow80] =
214 EhtRu::GetPrimaryFlags(bw, ruType, phyIndex, p20Index);
215 ru = EhtRu::RuSpec{ruType, index, primary160, primary80OrLow80};
216 }
217 NS_ABORT_IF(WifiRu::GetPhyIndex(ru, bw, p20Index) != phyIndex);
218 ruBands.insert({band, ru});
219 }
220 }
221 }
222 }
223 }
224 return ruBands;
225}
226
227void
229{
230 NS_LOG_FUNCTION(this << spectrumPhyInterface);
231 auto&& bands = ComputeBands(spectrumPhyInterface);
232 WifiSpectrumBands allBands{bands};
234 {
235 const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
236 auto&& ruBands = GetRuBands(spectrumPhyInterface, GetGuardBandwidth(channelWidth));
237 for (const auto& bandRuPair : ruBands)
238 {
239 allBands.push_back(bandRuPair.first);
240 }
241 spectrumPhyInterface->SetRuBands(std::move(ruBands));
242 }
243
244 spectrumPhyInterface->SetBands(std::move(bands));
245
246 if (m_interference->HasBands())
247 {
248 m_interference->UpdateBands(allBands, spectrumPhyInterface->GetFrequencyRange());
249 }
250 else
251 {
252 for (const auto& band : allBands)
253 {
254 m_interference->AddBand(band);
255 }
256 }
257}
258
265
266void
268{
269 NS_LOG_FUNCTION(this << channel << freqRange);
270
271 const auto foundOverlappingChannel =
272 std::any_of(m_spectrumPhyInterfaces.cbegin(),
274 [freqRange, channel](const auto& item) {
275 const auto spectrumRange = item.first;
276 const auto noOverlap =
277 ((freqRange.minFrequency >= spectrumRange.maxFrequency) ||
278 (freqRange.maxFrequency <= spectrumRange.minFrequency));
279 return (!noOverlap);
280 });
281 NS_ABORT_MSG_IF(foundOverlappingChannel,
282 "Added a wifi spectrum channel that overlaps with another existing wifi "
283 "spectrum channel");
284
285 auto wifiSpectrumPhyInterface = CreateObject<WifiSpectrumPhyInterface>(freqRange);
286 wifiSpectrumPhyInterface->SetSpectrumWifiPhy(this);
287 wifiSpectrumPhyInterface->SetChannel(channel);
288 if (GetDevice())
289 {
290 wifiSpectrumPhyInterface->SetDevice(GetDevice());
291 }
292 m_spectrumPhyInterfaces.emplace(freqRange, wifiSpectrumPhyInterface);
293}
294
295void
297 const std::vector<MHz_u>& centerFrequencies,
298 MHz_u channelWidth)
299{
300 std::stringstream ss;
301 for (const auto& centerFrequency : centerFrequencies)
302 {
303 ss << centerFrequency << " ";
304 }
305 NS_LOG_FUNCTION(this << spectrumPhyInterface << ss.str() << channelWidth);
306
307 // We have to reset the spectrum model because we changed RF channel. Consequently,
308 // we also have to add the spectrum interface to the spectrum channel again because
309 // MultiModelSpectrumChannel keeps spectrum interfaces in a map indexed by the RX
310 // spectrum model UID (which has changed after channel switching).
311 // Both SingleModelSpectrumChannel and MultiModelSpectrumChannel ensure not to keep
312 // duplicated spectrum interfaces (the latter removes the spectrum interface and adds
313 // it again in the entry associated with the new RX spectrum model UID)
314
315 // Replace existing spectrum model with new one
316 spectrumPhyInterface->SetRxSpectrumModel(centerFrequencies,
317 channelWidth,
319 GetGuardBandwidth(channelWidth));
320
321 spectrumPhyInterface->GetChannel()->AddRx(spectrumPhyInterface);
322
323 UpdateInterferenceHelperBands(spectrumPhyInterface);
324}
325
326void
337
338void
340{
341 NS_LOG_FUNCTION(this);
342 const auto frequenciesAfter = GetOperatingChannel().GetFrequencies();
343 const auto widthsAfter = GetOperatingChannel().GetWidths();
344 if ((m_frequenciesBeforeSwitch == frequenciesAfter) && (m_widthsBeforeSwitch == widthsAfter))
345 {
346 NS_LOG_DEBUG("Same RF channel as before, do nothing");
347 if (IsInitialized())
348 {
349 SwitchMaybeToCcaBusy(nullptr);
350 }
351 return;
352 }
353
354 Ptr<WifiSpectrumPhyInterface> newSpectrumPhyInterface;
355 const auto numSegments = GetOperatingChannel().GetNSegments();
356 NS_ASSERT(numSegments == frequenciesAfter.size() && numSegments == widthsAfter.size());
357 for (std::size_t i = 0; i < numSegments; ++i)
358 {
359 auto interfaceCoveringBand =
360 GetInterfaceCoveringChannelBand(frequenciesAfter.at(i), widthsAfter.at(i));
361 NS_ABORT_MSG_IF(!interfaceCoveringBand,
362 "No spectrum channel covers frequency range ["
363 << frequenciesAfter.at(i) - (widthsAfter.at(i) / 2) << " MHz - "
364 << frequenciesAfter.at(i) + (widthsAfter.at(i) / 2) << " MHz]");
365 if (!newSpectrumPhyInterface)
366 {
367 newSpectrumPhyInterface = interfaceCoveringBand;
368 }
369 else
370 {
371 NS_ABORT_MSG_IF(interfaceCoveringBand != newSpectrumPhyInterface,
372 "All segments are not covered by the same spectrum channel");
373 }
374 }
375 const auto interfaceChanged = (newSpectrumPhyInterface != m_currentSpectrumPhyInterface);
376
377 if (interfaceChanged)
378 {
379 std::stringstream ss;
380 for (std::size_t i = 0; i < frequenciesAfter.size(); ++i)
381 {
382 ss << "(" << frequenciesAfter.at(i) << ", " << widthsAfter.at(i) << ") ";
383 }
384 NS_LOG_DEBUG("Switch to existing RF interface with frequency/width "
385 << (numSegments > 1 ? "pair" : "pairs") << " of " << ss.str());
387 {
389 }
390 }
391
392 m_currentSpectrumPhyInterface = newSpectrumPhyInterface;
393
394 auto reset = true;
395 if (m_currentSpectrumPhyInterface->GetCenterFrequencies() == frequenciesAfter)
396 {
397 // Center frequencies have not changed for that interface, hence we do not need to
398 // reset the spectrum model nor update any band stored in the interference helper
400 {
401 // If we are not tracking signals from inactive interface,
402 // this means the spectrum interface has been disconnected
403 // from the spectrum channel and has to be connected back
405 }
406 reset = false;
407 }
408
409 if (reset)
410 {
412 frequenciesAfter,
413 GetOperatingChannel().GetTotalWidth());
414 }
415
416 if (IsInitialized())
417 {
419 }
420 else
421 {
423 }
424}
425
426void
434
435void
436SpectrumWifiPhy::ConfigureInterface(const std::vector<MHz_u>& frequencies, MHz_u width)
437{
438 std::stringstream ss;
439 for (const auto& centerFrequency : frequencies)
440 {
441 ss << centerFrequency << " ";
442 }
443 NS_LOG_FUNCTION(this << ss.str() << width);
444
446 {
447 NS_LOG_DEBUG("Tracking of signals on inactive interfaces is not enabled");
448 return;
449 }
450
451 Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface;
452 const auto numSegments = frequencies.size();
453 const auto segmentWidth = width / numSegments;
454 for (std::size_t i = 0; i < numSegments; ++i)
455 {
456 auto interfaceCoveringBand =
457 GetInterfaceCoveringChannelBand(frequencies.at(i), segmentWidth);
458 NS_ABORT_MSG_IF(!interfaceCoveringBand,
459 "No spectrum channel covers frequency range ["
460 << frequencies.at(i) - (segmentWidth / 2) << " MHz - "
461 << frequencies.at(i) + (segmentWidth / 2) << " MHz]");
462 if (!spectrumPhyInterface)
463 {
464 spectrumPhyInterface = interfaceCoveringBand;
465 }
466 else
467 {
468 NS_ABORT_MSG_IF(interfaceCoveringBand != spectrumPhyInterface,
469 "All segments are not covered by the same spectrum channel");
470 }
471 }
472
473 NS_ABORT_MSG_IF(spectrumPhyInterface == m_currentSpectrumPhyInterface,
474 "This method should not be called for the current interface");
475
476 if ((frequencies == spectrumPhyInterface->GetCenterFrequencies()) &&
477 (width == spectrumPhyInterface->GetChannelWidth()))
478 {
479 NS_LOG_DEBUG("Same RF channel as before on that interface, do nothing");
480 return;
481 }
482
483 ResetSpectrumModel(spectrumPhyInterface, frequencies, width);
484}
485
486bool
488{
489 return GetLatestPhyEntity()->CanStartRx(ppdu);
490}
491
492void
495{
496 NS_LOG_FUNCTION(this << rxParams << interface);
497 Time rxDuration = rxParams->duration;
498 Ptr<SpectrumValue> receivedSignalPsd = rxParams->psd;
499 if (interface)
500 {
501 NS_ASSERT_MSG(receivedSignalPsd->GetValuesN() ==
502 interface->GetRxSpectrumModel()->GetNumBands(),
503 "Incorrect spectrum conversion or multi model spectrum channel is not used!");
504 }
505 NS_LOG_DEBUG("Received signal with PSD " << *receivedSignalPsd << " and duration "
506 << rxDuration.As(Time::NS));
507 uint32_t senderNodeId = 0;
508 if (rxParams->txPhy)
509 {
510 senderNodeId = rxParams->txPhy->GetDevice()->GetNode()->GetId();
511 }
512 NS_LOG_DEBUG("Received signal from " << senderNodeId << " with unfiltered power "
513 << WToDbm(Integral(*receivedSignalPsd)) << " dBm");
514
515 // Integrate over our receive bandwidth (i.e., all that the receive
516 // spectral mask representing our filtering allows) to find the
517 // total energy apparent to the "demodulator".
518 // This is done per 20 MHz channel band.
519 const auto channelWidth = interface ? interface->GetChannelWidth() : GetChannelWidth();
520 const auto& bands =
521 interface ? interface->GetBands() : m_currentSpectrumPhyInterface->GetBands();
522 Watt_u totalRxPower{0.0};
524
525 const auto rxGainRatio = DbToRatio(GetRxGain());
526
527 std::size_t index = 0;
528 MHz_u prevBw{0};
529 for (const auto& band : bands)
530 {
531 const auto bw =
532 std::accumulate(band.frequencies.cbegin(),
533 band.frequencies.cend(),
534 MHz_u{0},
535 [](MHz_u sum, const auto& startStopFreqs) {
536 return sum + HzToMHz(startStopFreqs.second - startStopFreqs.first);
537 });
538 NS_ASSERT(bw <= channelWidth);
539 index = ((bw != prevBw) ? 0 : (index + 1));
540 auto rxPowerPerBand =
541 WifiSpectrumValueHelper::GetBandPowerW(receivedSignalPsd, band.indices);
542 NS_LOG_DEBUG("Signal power received (watts) before antenna gain for "
543 << bw << " MHz channel band " << index << ": " << band);
544 rxPowerPerBand *= rxGainRatio;
545 rxPowers.insert({band, rxPowerPerBand});
546 NS_LOG_DEBUG("Signal power received after antenna gain for "
547 << bw << " MHz channel band " << index << ": " << rxPowerPerBand << " W"
548 << (rxPowerPerBand > Watt_u{0.0}
549 ? " (" + std::to_string(WToDbm(rxPowerPerBand)) + " dBm)"
550 : ""));
551 if (bw <= MHz_u{20})
552 {
553 totalRxPower += rxPowerPerBand;
554 }
555 prevBw = bw;
556 }
557
559 {
560 const auto& ruBands =
561 interface ? interface->GetRuBands() : m_currentSpectrumPhyInterface->GetRuBands();
562 NS_ASSERT(!ruBands.empty());
563 for (const auto& [band, ru] : ruBands)
564 {
565 auto rxPowerPerBand =
566 WifiSpectrumValueHelper::GetBandPowerW(receivedSignalPsd, band.indices);
567 rxPowerPerBand *= rxGainRatio;
568 rxPowers.insert({band, rxPowerPerBand});
569 }
570 }
571
572 NS_ASSERT_MSG(totalRxPower >= Watt_u{0.0}, "Negative RX power");
573 NS_LOG_DEBUG("Total signal power received after antenna gain: "
574 << totalRxPower << " W"
575 << (totalRxPower > Watt_u{0.0}
576 ? " (" + std::to_string(WToDbm(totalRxPower)) + " dBm)"
577 : ""));
578
581
582 // Log the signal arrival to the trace source
583 if (totalRxPower > Watt_u{0.0})
584 {
585 m_signalCb(rxParams, senderNodeId, WToDbm(totalRxPower), rxDuration);
586 }
587
588 if (m_trackSignalsInactiveInterfaces && interface &&
589 (interface != m_currentSpectrumPhyInterface))
590 {
591 NS_LOG_INFO("Received Wi-Fi signal from a non-active PHY interface "
592 << interface->GetFrequencyRange());
593 m_interference->AddForeignSignal(rxDuration, rxPowers, interface->GetFrequencyRange());
594 return;
595 }
596
597 if (!wifiRxParams)
598 {
599 NS_LOG_INFO("Received non Wi-Fi signal");
600 m_interference->AddForeignSignal(rxDuration,
601 rxPowers,
602 interface ? interface->GetFrequencyRange()
604 SwitchMaybeToCcaBusy(nullptr);
605 return;
606 }
607
608 if (wifiRxParams && m_disableWifiReception)
609 {
610 NS_LOG_INFO("Received Wi-Fi signal but blocked from syncing");
611 NS_ASSERT(interface);
612 m_interference->AddForeignSignal(rxDuration, rxPowers, interface->GetFrequencyRange());
613 SwitchMaybeToCcaBusy(nullptr);
614 return;
615 }
616
617 // Do no further processing if signal is too weak
618 // Current implementation assumes constant RX power over the PPDU duration
619 // Compare received TX power per MHz to normalized RX sensitivity
620 const auto ppdu = GetRxPpduFromTxPpdu(wifiRxParams->ppdu);
621 if (totalRxPower < DbmToW(GetRxSensitivity()) * (ppdu->GetTxChannelWidth() / MHz_u{20}))
622 {
623 NS_LOG_INFO("Received signal too weak to process: "
624 << totalRxPower << " W"
625 << (totalRxPower > Watt_u{0.0}
626 ? " (" + std::to_string(WToDbm(totalRxPower)) + " dBm)"
627 : ""));
628 m_interference->Add(ppdu, rxDuration, rxPowers, GetCurrentFrequencyRange());
629 SwitchMaybeToCcaBusy(nullptr);
630 return;
631 }
632
633 if (wifiRxParams->txPhy)
634 {
635 if (!CanStartRx(ppdu))
636 {
637 NS_LOG_INFO("Cannot start reception of the PPDU, consider it as interference");
638 m_interference->Add(ppdu, rxDuration, rxPowers, GetCurrentFrequencyRange());
640 return;
641 }
642 }
643
644 NS_LOG_INFO("Received Wi-Fi signal");
645 StartReceivePreamble(ppdu, rxPowers, rxDuration);
646}
647
650{
651 return GetPhyEntityForPpdu(ppdu)->GetRxPpduFromTxPpdu(ppdu);
652}
653
656{
657 return m_antenna;
658}
659
660void
662{
663 NS_LOG_FUNCTION(this << a);
664 m_antenna = a;
665}
666
667void
669{
670 NS_LOG_FUNCTION(this << device);
671 WifiPhy::SetDevice(device);
672 for (auto& spectrumPhyInterface : m_spectrumPhyInterfaces)
673 {
674 spectrumPhyInterface.second->SetDevice(device);
675 }
676}
677
678void
680{
681 NS_LOG_FUNCTION(this << ppdu);
682 m_signalTransmissionCb(ppdu, ppdu->GetTxVector());
683 GetPhyEntity(ppdu->GetModulation())->StartTx(ppdu);
684}
685
686void
693
694MHz_u
696{
697 MHz_u guardBandwidth{0};
698 if (currentChannelWidth == MHz_u{22})
699 {
700 // handle case of DSSS transmission
701 guardBandwidth = MHz_u{10};
702 }
703 else
704 {
705 // In order to properly model out of band transmissions for OFDM, the guard
706 // band has been configured so as to expand the modeled spectrum up to the
707 // outermost referenced point in "Transmit spectrum mask" sections' PSDs of
708 // each PHY specification of 802.11-2016 standard. It thus ultimately corresponds
709 // to the currently considered channel bandwidth (which can be different from
710 // supported channel width).
711 guardBandwidth = currentChannelWidth;
712 }
713 return guardBandwidth;
714}
715
717SpectrumWifiPhy::GetNumBandsBetweenSegments(const std::vector<MHz_u>& centerFrequencies,
718 MHz_u totalWidth,
719 Hz_u subcarrierSpacing)
720{
721 const auto numSegments = centerFrequencies.size();
722 NS_ABORT_MSG_IF(numSegments > 2, "Only 2 non-contiguous frequency segments are supported");
723 if (numSegments < 2)
724 {
725 return 0;
726 }
727 const auto lowFrequency = *centerFrequencies.cbegin();
728 const auto highFrequency = *centerFrequencies.crbegin();
729 NS_ASSERT(lowFrequency != highFrequency);
730 // all segments have the same width
731 const auto segmentsWidth = totalWidth / numSegments;
732 const auto widthBetweenSegments = highFrequency - lowFrequency - segmentsWidth;
733 return MHzToHz(widthBetweenSegments) / subcarrierSpacing;
734}
735
738 MHz_u bandWidth,
739 uint8_t bandIndex /* = 0 */)
740{
741 const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
742 NS_ASSERT_MSG(bandWidth <= channelWidth,
743 "Bandwidth (" << bandWidth << ") cannot exceed total operating channel width ("
744 << channelWidth << ")");
745 const auto subcarrierSpacing = GetSubcarrierSpacing();
746 WifiSpectrumBandInfo bandInfo;
747 std::size_t numSegments = 1;
748 if (const auto segmentWidth =
749 (channelWidth / spectrumPhyInterface->GetCenterFrequencies().size());
750 bandWidth > segmentWidth)
751 {
752 NS_ASSERT(bandIndex == 0);
753 numSegments = spectrumPhyInterface->GetCenterFrequencies().size();
754 bandWidth /= spectrumPhyInterface->GetCenterFrequencies().size();
755 }
756 const auto numBandsInBand = static_cast<size_t>(MHzToHz(bandWidth) / subcarrierSpacing);
757 auto numBandsInChannel = static_cast<size_t>(MHzToHz(channelWidth) / subcarrierSpacing);
758 const auto numBands = channelWidth / bandWidth;
759 if (numBandsInBand % 2 == 0)
760 {
761 numBandsInChannel += 1; // symmetry around center frequency
762 }
763 auto rxSpectrumModel = spectrumPhyInterface->GetRxSpectrumModel();
764 size_t totalNumBands = rxSpectrumModel->GetNumBands();
765 NS_ASSERT_MSG((numBandsInChannel % 2 == 1) && (totalNumBands % 2 == 1),
766 "Should have odd number of bands");
767 for (std::size_t segmentIndex = 0; segmentIndex < numSegments; ++segmentIndex)
768 {
769 NS_ASSERT_MSG(bandIndex < numBands, "Band index is out of bound");
770 NS_ASSERT(totalNumBands >= numBandsInChannel);
771 const auto numBandsBetweenSegments =
772 GetNumBandsBetweenSegments(spectrumPhyInterface->GetCenterFrequencies(),
773 channelWidth,
775 auto startIndex = ((totalNumBands - numBandsInChannel - numBandsBetweenSegments) / 2) +
776 (bandIndex * numBandsInBand);
777 if (bandIndex >= (numBands / 2))
778 {
779 startIndex += numBandsBetweenSegments;
780 }
781 auto stopIndex = startIndex + numBandsInBand - 1;
782 auto frequencies =
783 ConvertIndicesToFrequenciesForInterface(spectrumPhyInterface, {startIndex, stopIndex});
784 auto freqRange = spectrumPhyInterface->GetFrequencyRange();
785 NS_ASSERT(frequencies.first >= MHzToHz(freqRange.minFrequency));
786 NS_ASSERT(frequencies.second <= MHzToHz(freqRange.maxFrequency));
787 NS_ASSERT((frequencies.second - frequencies.first) == MHzToHz(bandWidth));
788 if (startIndex >= totalNumBands / 2)
789 {
790 // step past DC
791 startIndex += 1;
792 }
793 bandInfo.indices.emplace_back(startIndex, stopIndex);
794 bandInfo.frequencies.emplace_back(frequencies);
795 ++bandIndex;
796 }
797 return bandInfo;
798}
799
801SpectrumWifiPhy::GetBand(MHz_u bandWidth, uint8_t bandIndex /* = 0 */)
802{
804 return GetBandForInterface(m_currentSpectrumPhyInterface, bandWidth, bandIndex);
805}
806
813
816 Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
817 const WifiSpectrumBandIndices& indices) const
818{
819 NS_ABORT_IF(!spectrumPhyInterface);
820 auto rxSpectrumModel = spectrumPhyInterface->GetRxSpectrumModel();
821 auto startGuardBand = rxSpectrumModel->Begin();
822 auto startChannel = std::next(startGuardBand, indices.first);
823 auto endChannel = std::next(startGuardBand, indices.second + 1);
824 return {Hz_u{startChannel->fc}, Hz_u{endChannel->fc}};
825}
826
827std::tuple<dBr_u, dBr_u, dBr_u>
834
841
842const std::map<FrequencyRange, Ptr<WifiSpectrumPhyInterface>>&
847
850{
851 const auto lowFreq = frequency - (width / 2);
852 const auto highFreq = frequency + (width / 2);
853 const auto it = std::find_if(m_spectrumPhyInterfaces.cbegin(),
855 [lowFreq, highFreq](const auto& item) {
856 return ((lowFreq >= item.first.minFrequency) &&
857 (highFreq <= item.first.maxFrequency));
858 });
859 if (it == std::end(m_spectrumPhyInterfaces))
860 {
861 return nullptr;
862 }
863 return it->second;
864}
865
871
872void
877
878} // namespace ns3
AttributeValue implementation for Boolean.
Definition boolean.h:26
Callback template class.
Definition callback.h:422
void Nullify()
Discard the implementation, set it to null.
Definition callback.h:561
bool IsNull() const
Check for null implementation.
Definition callback.h:555
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
RU Specification.
Definition eht-ru.h:34
static std::pair< bool, bool > GetPrimaryFlags(MHz_u bw, RuType ruType, std::size_t phyIndex, uint8_t p20Index)
Get the primary flags of a given RU transmitted in a PPDU.
Definition eht-ru.cc:912
static std::size_t GetIndexIn80MHzSegment(MHz_u bw, RuType ruType, std::size_t phyIndex)
Get the index of a given RU transmitted in a PPDU within its 80 MHz segment.
Definition eht-ru.cc:945
static std::vector< WifiSpectrumBandIndices > ConvertRuSubcarriers(const RuSubcarriersInfo &info)
This is a helper function to convert RU subcarriers, which are relative to the center frequency subca...
Definition he-phy.cc:1829
RU Specification.
Definition he-ru.h:37
static std::size_t GetIndexIn80MHzSegment(MHz_u bw, RuType ruType, std::size_t phyIndex)
Get the index of a given RU transmitted in a PPDU within its 80 MHz segment.
Definition he-ru.cc:475
static bool GetPrimary80MHzFlag(MHz_u bw, RuType ruType, std::size_t phyIndex, uint8_t p20Index)
Get the primary 80 MHz flag of a given RU transmitted in a PPDU.
Definition he-ru.cc:462
bool IsInitialized() const
Check if the object has been initialized.
Definition object.cc:240
Smart pointer class similar to boost::intrusive_ptr.
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:595
802.11 PHY layer model
std::vector< MHz_u > m_frequenciesBeforeSwitch
center frequency before channel switch
WifiSpectrumBandInfo GetBand(MHz_u bandWidth, uint8_t bandIndex=0) override
Get the info of a given band.
void SetDevice(const Ptr< WifiNetDevice > device) override
Sets the device this PHY is associated with.
void Transmit(Ptr< WifiSpectrumSignalParameters > txParams)
This function is sending the signal to the Spectrum channel after finishing the configuration of the ...
dBr_u m_txMaskInnerBandMinimumRejection
The minimum rejection for the inner band of the transmit spectrum mask.
std::vector< MHz_u > m_widthsBeforeSwitch
channel width before channel switch
WifiSpectrumBands ComputeBands(Ptr< WifiSpectrumPhyInterface > spectrumPhyInterface)
This function computes the bands that belong to a given spectrum PHY interface.
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 DoInitialize() override
Initialize() implementation.
void FinalizeChannelSwitch() override
Method that can be overridden by subclasses to perform operations after the channel is actually switc...
dBr_u m_txMaskOuterBandMinimumRejection
The minimum rejection for the outer band of the transmit spectrum mask.
std::map< FrequencyRange, Ptr< WifiSpectrumPhyInterface > > m_spectrumPhyInterfaces
Spectrum PHY interfaces.
WifiSpectrumBandFrequencies ConvertIndicesToFrequenciesForInterface(Ptr< WifiSpectrumPhyInterface > spectrumPhyInterface, const WifiSpectrumBandIndices &indices) const
This is a helper function to convert start and stop indices to start and stop frequencies.
Ptr< AntennaModel > m_antenna
antenna model
FrequencyRange GetCurrentFrequencyRange() const override
Get the frequency range of the current RF interface.
Ptr< const WifiPpdu > GetRxPpduFromTxPpdu(Ptr< const WifiPpdu > ppdu)
Determine the WifiPpdu to be used by the RX PHY based on the WifiPpdu sent by the TX PHY.
MHz_u GetGuardBandwidth(MHz_u currentChannelWidth) const override
Ptr< WifiSpectrumPhyInterface > GetInterfaceCoveringChannelBand(MHz_u frequency, MHz_u width) const
Get the spectrum PHY interface that covers a band portion of the RF channel.
Ptr< AntennaModel > GetAntenna() const
Get the antenna model used for reception.
std::tuple< dBr_u, dBr_u, dBr_u > GetTxMaskRejectionParams() const override
Ptr< Channel > GetChannel() const override
Return the Channel this WifiPhy is connected to.
void AddChannel(const Ptr< SpectrumChannel > channel, const FrequencyRange &freqRange=WHOLE_WIFI_SPECTRUM)
Attach a SpectrumChannel to use for a given frequency range.
void SetChannelSwitchedCallback(Callback< void > callback)
Ptr< WifiSpectrumPhyInterface > m_currentSpectrumPhyInterface
The current Spectrum PHY interface (held for performance reasons)
Ptr< WifiSpectrumPhyInterface > GetCurrentInterface() const
Get the currently active spectrum PHY interface.
bool m_trackSignalsInactiveInterfaces
flag whether signals coming from inactive spectrum PHY interfaces are tracked
void DoDispose() override
Destructor implementation.
const std::map< FrequencyRange, Ptr< WifiSpectrumPhyInterface > > & GetSpectrumPhyInterfaces() const
Get the map of interfaces attached to this spectrum PHY.
static TypeId GetTypeId()
Get the type ID.
TracedCallback< Ptr< const SpectrumSignalParameters >, uint32_t, double, Time > m_signalCb
Signal callback.
Callback< void > m_channelSwitchedCallback
Callback when channel switched.
void SetAntenna(const Ptr< AntennaModel > antenna)
void ResetSpectrumModel(Ptr< WifiSpectrumPhyInterface > spectrumPhyInterface, const std::vector< MHz_u > &centerFrequencies, MHz_u channelWidth)
Perform run-time spectrum model change.
void ConfigureInterface(const std::vector< MHz_u > &frequencies, MHz_u width)
Configure a non-active spectrum PHY interface to operate on a given frequency (or several frequencies...
bool m_disableWifiReception
forces this PHY to fail to sync on any signal
bool CanStartRx(Ptr< const WifiPpdu > ppdu) const
Determine whether the PHY shall issue a PHY-RXSTART.indication primitive in response to a given PPDU.
void UpdateInterferenceHelperBands(Ptr< WifiSpectrumPhyInterface > spectrumPhyInterface)
This function is called to update the bands handled by the InterferenceHelper.
void StartTx(Ptr< const WifiPpdu > ppdu) override
dBr_u m_txMaskOuterBandMaximumRejection
The maximum rejection for the outer band of the transmit spectrum mask.
void NotifyChannelSwitched()
Notify the spectrum channel has switched.
void DoChannelSwitch() override
Actually switch channel based on the stored channel settings.
static uint32_t GetNumBandsBetweenSegments(const std::vector< MHz_u > &centerFrequencies, MHz_u totalWidth, Hz_u subcarrierSpacing)
Determine the number of bands between the two segments if the operating channel is made of non-contig...
WifiSpectrumBandFrequencies ConvertIndicesToFrequencies(const WifiSpectrumBandIndices &indices) const override
This is a helper function to convert start and stop indices to start and stop frequencies.
RuBands GetRuBands(Ptr< WifiSpectrumPhyInterface > spectrumPhyInterface, MHz_u guardBandwidth)
This function computes the RU bands that belong to a given spectrum PHY interface.
WifiSpectrumBandInfo GetBandForInterface(Ptr< WifiSpectrumPhyInterface > spectrumPhyInterface, MHz_u bandWidth, uint8_t bandIndex=0)
Get the info of a given band that belongs to a given spectrum PHY interface.
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:403
@ NS
nanosecond
Definition nstime.h:108
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
802.11 PHY layer model
Definition wifi-phy.h:55
dBm_u GetRxSensitivity() const
Return the receive sensitivity threshold.
Definition wifi-phy.cc:529
Hz_u GetSubcarrierSpacing() const
Definition wifi-phy.cc:2367
TracedCallback< Ptr< const WifiPpdu >, const WifiTxVector & > m_signalTransmissionCb
Signal Transmission callback.
Definition wifi-phy.h:1384
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
Definition wifi-phy.cc:769
virtual void SetDevice(const Ptr< WifiNetDevice > device)
Sets the device this PHY is associated with.
Definition wifi-phy.cc:650
void StartReceivePreamble(Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPowersW, Time rxDuration)
Start receiving the PHY preamble of a PPDU (i.e.
Definition wifi-phy.cc:1971
MHz_u GetChannelWidth() const
Definition wifi-phy.cc:1087
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition wifi-phy.cc:656
void DoDispose() override
Destructor implementation.
Definition wifi-phy.cc:445
dB_u GetRxGain() const
Return the reception gain.
Definition wifi-phy.cc:631
virtual void DoChannelSwitch()
Actually switch channel based on the stored channel settings.
Definition wifi-phy.cc:1222
void SwitchMaybeToCcaBusy(const Ptr< const WifiPpdu > ppdu=nullptr)
Check if PHY state should move to CCA busy state based on current state of interference tracker.
Definition wifi-phy.cc:2213
Ptr< InterferenceHelper > m_interference
Pointer to a helper responsible for interference computations.
Definition wifi-phy.h:1343
void DoInitialize() override
Initialize() implementation.
Definition wifi-phy.cc:420
WifiStandard GetStandard() const
Get the configured Wi-Fi standard.
Definition wifi-phy.cc:1063
Ptr< PhyEntity > GetPhyEntityForPpdu(const Ptr< const WifiPpdu > ppdu) const
Get the supported PHY entity to use for a received PPDU.
Definition wifi-phy.cc:790
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition wifi-phy.cc:1069
Ptr< PhyEntity > GetLatestPhyEntity() const
Get the latest PHY entity supported by this PHY instance.
Definition wifi-phy.cc:784
bool IsSet() const
Return true if a valid channel has been set, false otherwise.
std::size_t GetNSegments() const
Get the number of frequency segments in the operating channel.
uint8_t GetPrimaryChannelIndex(MHz_u primaryChannelWidth) const
If the operating channel width is a multiple of 20 MHz, return the index of the primary channel of th...
std::vector< MHz_u > GetFrequencies() const
Return the center frequency per segment.
std::vector< MHz_u > GetWidths() const
Return the channel width per segment.
static std::size_t GetNRus(MHz_u bw, RuType ruType, WifiModulationClass mc)
Get the number of distinct RUs of the given type (number of tones) available in a PPDU of the given b...
Definition wifi-ru.cc:132
std::variant< HeRu::RuSpec, EhtRu::RuSpec > RuSpec
variant of the RU specification
Definition wifi-ru.h:27
static SubcarrierGroup GetSubcarrierGroup(MHz_u bw, RuType ruType, std::size_t phyIndex, WifiModulationClass mc)
Get the subcarrier group of the RU having the given PHY index among all the RUs of the given type (nu...
Definition wifi-ru.cc:142
static std::size_t GetPhyIndex(RuSpec ru, MHz_u bw, uint8_t p20Index)
Get the RU PHY index.
Definition wifi-ru.cc:57
static RuType GetMaxRuType(WifiModulationClass mc)
Get the maximum RU type supported by a given modulation class.
Definition wifi-ru.cc:63
static Watt_u GetBandPowerW(Ptr< SpectrumValue > psd, const std::vector< WifiSpectrumBandIndices > &segments)
Calculate the power of the specified band composed of uniformly-sized sub-bands.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeChecker > MakeDoubleChecker()
Definition double.h:82
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition double.h:32
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition abort.h:65
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211ax
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
Every class exported by the ns3 library is enclosed in the ns3 namespace.
double Integral(const SpectrumValue &arg)
RuType
The different Resource Unit (RU) types.
Definition wifi-types.h:99
dBm_u WToDbm(Watt_u val)
Convert from Watts to dBm.
Definition wifi-utils.cc:38
std::vector< WifiSpectrumBandInfo > WifiSpectrumBands
vector of spectrum bands
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::pair< Hz_u, Hz_u > WifiSpectrumBandFrequencies
typedef for a pair of start and stop frequencies to represent a band
std::map< WifiSpectrumBandInfo, Watt_u > RxPowerWattPerChannelBand
A map of the received power for each band.
Definition phy-entity.h:45
MHz_u GetMaximumChannelWidth(WifiModulationClass modulation)
Get the maximum channel width allowed for the given modulation class.
std::map< WifiSpectrumBandInfo, WifiRu::RuSpec > RuBands
Map a spectrum band associated with an RU to the RU specification.
double DbToRatio(dB_u val)
Convert from dB to ratio.
Definition wifi-utils.cc:26
Watt_u DbmToW(dBm_u val)
Convert from dBm to Watts.
Definition wifi-utils.cc:32
Hz_u MHzToHz(MHz_u val)
Convert from MHz to Hz.
Definition wifi-utils.h:113
std::pair< uint32_t, uint32_t > WifiSpectrumBandIndices
typedef for a pair of start and stop sub-band indices
Struct defining a frequency range between minFrequency and maxFrequency.
WifiSpectrumBandInfo structure containing info about a spectrum band.
std::vector< WifiSpectrumBandFrequencies > frequencies
the start and stop frequencies for each segment of the band
std::vector< WifiSpectrumBandIndices > indices
the start and stop indices for each segment of the band