15#include "ns3/assert.h"
297 : m_channelIts(channelIts),
302 "Operating channel does not support more than 2 segments");
320 std::stringstream ss;
321 for (
const auto& segment : segments)
327 NS_ASSERT_MSG(!segments.empty(),
"At least one frequency segment has to be provided");
330 for (
const auto& segment : segments)
332 if (
const auto channelIt =
333 FindFirst(segment.number, segment.frequency, segment.width, standard, segment.band);
343 channelIts.insert(channelIt);
347 if (channelIts.size() != segments.size())
350 throw std::runtime_error(
351 "WifiPhyOperatingChannel: No unique channel found given the specified criteria");
354 auto it = channelIts.begin();
355 for (std::size_t segment = 0; segment < (channelIts.size() - 1); ++segment)
357 const auto freq = (*it)->frequency;
358 const auto width = (*it)->width;
359 const auto band = (*it)->band;
360 const auto maxFreq = freq + (width / 2);
362 const auto nextFreq = (*it)->frequency;
363 const auto nextWidth = (*it)->width;
364 const auto nextBand = (*it)->band;
365 const auto nextMinFreq = nextFreq - (nextWidth / 2);
366 if (maxFreq >= nextMinFreq)
368 throw std::runtime_error(
369 "WifiPhyOperatingChannel is invalid: segments cannot be adjacent nor overlap");
371 if (band != nextBand)
373 throw std::runtime_error(
"WifiPhyOperatingChannel is invalid: all segments shall "
374 "belong to the same band");
378 if ((channelIts.size() > 2) ||
379 ((channelIts.size() == 2) &&
380 !std::all_of(channelIts.cbegin(), channelIts.cend(), [](
const auto& channel) {
381 return channel->width == MHz_u{80};
384 throw std::runtime_error(
"WifiPhyOperatingChannel is invalid: only 80+80MHz is "
385 "expected as non-contiguous channel");
388 m_channelIts = channelIts;
389 m_primary20Index = 0;
396 Set({{GetDefaultChannelNumber(width, standard, band),
MHz_u{0}, width, band}}, standard);
400WifiPhyOperatingChannel::GetDefaultChannelNumber(
404 std::optional<uint8_t> previousChannelNumber )
406 auto start = m_frequencyChannels.begin();
407 auto prevSegmentChannelIt = m_frequencyChannels.end();
408 if (previousChannelNumber)
410 prevSegmentChannelIt =
411 FindFirst(*previousChannelNumber,
MHz_u{0}, width, standard, band, start);
412 if (prevSegmentChannelIt != m_frequencyChannels.end())
414 start = std::next(prevSegmentChannelIt);
417 auto channelIt = FindFirst(0,
MHz_u{0}, width, standard, band, start);
418 if (prevSegmentChannelIt != m_frequencyChannels.end() && channelIt != m_frequencyChannels.end())
420 const auto prevFreq = prevSegmentChannelIt->frequency;
421 const auto prevWidth = prevSegmentChannelIt->width;
422 const auto prevMaxFreq = prevFreq + (prevWidth / 2);
423 const auto nextFreq = channelIt->frequency;
424 const auto nextWidth = channelIt->width;
425 const auto nextMinFreq = nextFreq - (nextWidth / 2);
426 if (prevMaxFreq <= nextMinFreq)
430 channelIt = FindFirst(0,
MHz_u{0}, width, standard, band, std::next(channelIt));
433 if (channelIt != m_frequencyChannels.end())
436 return channelIt->number;
440 throw std::runtime_error(
"WifiPhyOperatingChannel: No default channel found of the given width "
441 "and for the given PHY standard and band");
445WifiPhyOperatingChannel::FindFirst(uint8_t number,
454 if (number != 0 && channel.number != number)
458 if (frequency !=
MHz_u{0} && channel.frequency != frequency)
462 if (width !=
MHz_u{0} && channel.width != width)
483 (std::find(standardIt->second.cbegin(), standardIt->second.cend(), band) ==
484 standardIt->second.cend() ||
487 return m_frequencyChannels.cend();
490 return std::find_if(start, m_frequencyChannels.cend(), predicate);
494WifiPhyOperatingChannel::GetNumber(std::size_t segment )
const
497 return (*std::next(m_channelIts.begin(), segment))->number;
501WifiPhyOperatingChannel::GetFrequency(std::size_t segment )
const
504 return (*std::next(m_channelIts.begin(), segment))->frequency;
508WifiPhyOperatingChannel::GetWidth(std::size_t )
const
512 return (*m_channelIts.cbegin())->width;
516WifiPhyOperatingChannel::GetPhyBand()
const
520 return (*m_channelIts.cbegin())->band;
524WifiPhyOperatingChannel::IsOfdm()
const
527 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::OFDM);
531WifiPhyOperatingChannel::IsDsss()
const
534 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::DSSS);
538WifiPhyOperatingChannel::Is80211p()
const
541 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::CH_80211P);
545WifiPhyOperatingChannel::GetNumbers()
const
548 std::vector<uint8_t> channelNumbers{};
549 std::transform(m_channelIts.cbegin(),
551 std::back_inserter(channelNumbers),
552 [](
const auto& channel) { return channel->number; });
553 return channelNumbers;
557WifiPhyOperatingChannel::GetFrequencies()
const
560 std::vector<MHz_u> centerFrequencies{};
561 std::transform(m_channelIts.cbegin(),
563 std::back_inserter(centerFrequencies),
564 [](
const auto& channel) { return channel->frequency; });
565 return centerFrequencies;
569WifiPhyOperatingChannel::GetWidths()
const
572 std::vector<MHz_u> channelWidths{};
573 std::transform(m_channelIts.cbegin(),
575 std::back_inserter(channelWidths),
576 [](
const auto& channel) { return channel->width; });
577 return channelWidths;
581WifiPhyOperatingChannel::GetTotalWidth()
const
584 return std::accumulate(m_channelIts.cbegin(),
587 [](
MHz_u sum,
const auto& channel) { return sum + channel->width; });
591WifiPhyOperatingChannel::GetWidthType()
const
594 switch (
static_cast<uint16_t
>(GetTotalWidth()))
597 return WifiChannelWidthType::CW_20MHZ;
599 return WifiChannelWidthType::CW_22MHZ;
601 return WifiChannelWidthType::CW_5MHZ;
603 return WifiChannelWidthType::CW_10MHZ;
605 return WifiChannelWidthType::CW_40MHZ;
607 return WifiChannelWidthType::CW_80MHZ;
609 return (m_channelIts.size() == 2) ? WifiChannelWidthType::CW_80_PLUS_80MHZ
610 : WifiChannelWidthType::CW_160MHZ;
612 return WifiChannelWidthType::CW_320MHZ;
614 return WifiChannelWidthType::CW_2160MHZ;
617 return WifiChannelWidthType::UNKNOWN;
622WifiPhyOperatingChannel::GetPrimaryChannelIndex(
MHz_u primaryChannelWidth)
const
624 if (
static_cast<uint16_t
>(primaryChannelWidth) % 20 != 0)
626 NS_LOG_DEBUG(
"The operating channel width is not a multiple of 20 MHz; return 0");
630 NS_ASSERT(primaryChannelWidth <= GetTotalWidth());
635 uint8_t index = m_primary20Index;
637 while (width < primaryChannelWidth)
646WifiPhyOperatingChannel::GetSecondaryChannelIndex(
MHz_u secondaryChannelWidth)
const
648 const uint8_t primaryIndex = GetPrimaryChannelIndex(secondaryChannelWidth);
649 const uint8_t secondaryIndex =
650 (primaryIndex % 2 == 0) ? (primaryIndex + 1) : (primaryIndex - 1);
651 return secondaryIndex;
655WifiPhyOperatingChannel::SetPrimary20Index(uint8_t index)
660 "Primary20 index out of range");
661 m_primary20Index = index;
665WifiPhyOperatingChannel::GetPrimarySegmentIndex(
MHz_u primaryChannelWidth)
const
667 if (m_channelIts.size() < 2)
672 const auto numIndices = GetTotalWidth() / primaryChannelWidth;
673 const auto primaryIndex = GetPrimaryChannelIndex(primaryChannelWidth);
674 return (primaryIndex >= (numIndices / 2)) ? 1 : 0;
678WifiPhyOperatingChannel::GetSecondarySegmentIndex(
MHz_u primaryChannelWidth)
const
681 "Primary channel width cannot be larger than the width of a frequency segment");
682 if (m_channelIts.size() < 2)
687 const auto numIndices = GetTotalWidth() / primaryChannelWidth;
688 const auto secondaryIndex = GetSecondaryChannelIndex(primaryChannelWidth);
689 return (secondaryIndex >= (numIndices / 2)) ? 1 : 0;
693WifiPhyOperatingChannel::GetPrimaryChannelCenterFrequency(
MHz_u primaryChannelWidth)
const
695 const auto segmentIndex = GetPrimarySegmentIndex(primaryChannelWidth);
697 const auto segmentWidth = GetWidth(segmentIndex);
699 const uint8_t segmentOffset = (segmentIndex * (segmentWidth / primaryChannelWidth));
700 return GetFrequency(segmentIndex) - segmentWidth / 2. +
701 (GetPrimaryChannelIndex(primaryChannelWidth) - segmentOffset + 0.5) *
706WifiPhyOperatingChannel::GetSecondaryChannelCenterFrequency(
MHz_u secondaryChannelWidth)
const
708 const auto segmentIndex = GetSecondarySegmentIndex(secondaryChannelWidth);
710 const auto segmentWidth = GetWidth(segmentIndex);
712 const uint8_t segmentOffset = (segmentIndex * (segmentWidth / secondaryChannelWidth));
713 return GetFrequency(segmentIndex) - segmentWidth / 2. +
714 (GetSecondaryChannelIndex(secondaryChannelWidth) - segmentOffset + 0.5) *
715 secondaryChannelWidth;
719WifiPhyOperatingChannel::GetPrimaryChannelNumber(
MHz_u primaryChannelWidth,
723 "Primary channel width cannot be larger than the width of a frequency segment");
724 auto frequency = GetPrimaryChannelCenterFrequency(primaryChannelWidth);
726 auto primaryChanIt = FindFirst(0, frequency, primaryChannelWidth, standard, GetPhyBand());
727 NS_ASSERT_MSG(primaryChanIt != m_frequencyChannels.end(),
"Primary channel number not found");
728 return primaryChanIt->number;
732WifiPhyOperatingChannel::GetPrimaryChannel(
MHz_u primaryChannelWidth)
const
736 "Requested primary channel width ("
737 << primaryChannelWidth <<
" MHz) exceeds total width (" << GetTotalWidth()
740 if (primaryChannelWidth == GetTotalWidth())
745 const auto frequency = GetPrimaryChannelCenterFrequency(primaryChannelWidth);
748 NS_ABORT_MSG_IF(primaryChanIt == m_frequencyChannels.end(),
"Primary channel number not found");
752 const auto primaryIndex = m_primary20Index - (GetPrimaryChannelIndex(primaryChannelWidth) *
756 return primaryChannel;
760WifiPhyOperatingChannel::GetAll20MHzChannelIndicesInPrimary(
MHz_u width)
const
762 if (width > GetTotalWidth())
769 std::set<uint8_t> indices;
770 indices.insert(m_primary20Index);
772 while (currWidth < width)
774 indices.merge(GetAll20MHzChannelIndicesInSecondary(indices));
782WifiPhyOperatingChannel::GetAll20MHzChannelIndicesInSecondary(
MHz_u width)
const
784 return GetAll20MHzChannelIndicesInSecondary(GetAll20MHzChannelIndicesInPrimary(width));
788WifiPhyOperatingChannel::GetAll20MHzChannelIndicesInSecondary(
789 const std::set<uint8_t>& primaryIndices)
const
791 if (primaryIndices.empty() || GetTotalWidth() ==
MHz_u{20})
797 MHz_u primaryWidth{20};
800 while (size != primaryIndices.size())
805 if (primaryWidth >= GetTotalWidth())
813 std::set<uint8_t> secondaryIndices;
814 for (
const auto& index : primaryIndices)
816 secondaryIndices.insert(index ^ size);
819 return secondaryIndices;
825 const auto ruType = WifiRu::GetRuType(ru);
828 "No RU of type " << ruType <<
" is contained in a " << width <<
" MHz channel");
830 "The given width (" << width <<
" MHz) exceeds the operational width ("
831 << GetTotalWidth() <<
")");
834 if (
const auto ruIndex = WifiRu::GetIndex(ru); ruType == RuType::RU_26_TONE && ruIndex == 19)
836 NS_ASSERT_MSG(WifiRu::IsHe(ru),
"Center 26-tone RUs can only be used with HE");
838 "26-tone RU with index 19 is only present in channels of at least 80 MHz");
841 auto indices = std::get<HeRu::RuSpec>(ru).GetPrimary80MHz()
842 ? GetAll20MHzChannelIndicesInPrimary(
MHz_u{80})
843 : GetAll20MHzChannelIndicesInSecondary(
MHz_u{80});
844 indices.erase(indices.begin());
845 indices.erase(std::prev(indices.end()));
849 auto ruPhyIndex = WifiRu::GetPhyIndex(ru, width, m_primary20Index);
850 if (ruType == RuType::RU_26_TONE && ruPhyIndex > 19)
856 ruPhyIndex -= (ruPhyIndex - 19) / 37;
860 uint8_t n20MHzChannels;
864 case RuType::RU_26_TONE:
865 case RuType::RU_52_TONE:
866 case RuType::RU_106_TONE:
867 case RuType::RU_242_TONE:
870 case RuType::RU_484_TONE:
873 case RuType::RU_996_TONE:
876 case RuType::RU_2x996_TONE:
879 case RuType::RU_4x996_TONE:
886 auto nRusInCoveringChannel =
887 WifiRu::GetNRus(n20MHzChannels *
MHz_u{20},
891 std::size_t indexOfCoveringChannelInGivenWidth = (ruPhyIndex - 1) / nRusInCoveringChannel;
895 NS_ASSERT(indexOfCoveringChannelInGivenWidth < 16);
896 std::set<uint8_t> indices({
static_cast<uint8_t
>(indexOfCoveringChannelInGivenWidth)});
898 while (n20MHzChannels > 1)
900 std::set<uint8_t> updatedIndices;
901 for (
const auto& idx : indices)
903 updatedIndices.insert(idx * 2);
904 updatedIndices.insert(idx * 2 + 1);
906 indices.swap(updatedIndices);
915 std::set<uint8_t> updatedIndices;
916 for (
const auto& idx : indices)
918 updatedIndices.insert(idx + offset);
920 indices.swap(updatedIndices);
927WifiPhyOperatingChannel::GetNSegments()
const
929 return m_channelIts.size();
941 return !(*
this == other);
949 const auto numSegments = channel.GetNSegments();
950 for (std::size_t segmentId = 0; segmentId < numSegments; ++segmentId)
954 os <<
"segment " << segmentId <<
" ";
956 os <<
"channel " << +channel.GetNumber() <<
" frequency " << channel.GetFrequency()
957 <<
" width " << channel.GetWidth() <<
" band " << channel.GetPhyBand();
958 if ((segmentId == 0) && (
static_cast<uint16_t
>(channel.GetTotalWidth()) % 20 == 0))
960 os <<
" primary20 " << +channel.GetPrimaryChannelIndex(
MHz_u{20});
962 if (segmentId < numSegments - 1)
970 os <<
"channel not set";
Class that keeps track of all information about the current PHY operating channel.
bool IsSet() const
Return true if a valid channel has been set, false otherwise.
std::set< ConstIterator, Compare > ConstIteratorSet
Typedef for a set of const iterator pointing to the segments of a channel.
WifiPhyOperatingChannel()
Create an uninitialized PHY operating channel.
static const std::set< FrequencyChannelInfo > m_frequencyChannels
Available frequency channels.
std::set< FrequencyChannelInfo >::const_iterator ConstIterator
Typedef for a const iterator pointing to a channel in the set of available channels.
void SetPrimary20Index(uint8_t index)
Set the index of the primary 20 MHz channel (0 indicates the 20 MHz subchannel with the lowest center...
void Set(const std::vector< FrequencyChannelInfo > &segments, WifiStandard standard)
Set the channel according to the specified parameters if a unique frequency channel matches the speci...
ConstIteratorSet m_channelIts
const iterators pointing to the configured frequency channel
static ConstIterator FindFirst(uint8_t number, MHz_u frequency, MHz_u width, WifiStandard standard, WifiPhyBand band, ConstIterator start=m_frequencyChannels.begin())
Find the first frequency segment matching the specified parameters.
virtual ~WifiPhyOperatingChannel()
std::variant< HeRu::RuSpec, EhtRu::RuSpec > RuSpec
variant of the RU specification
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
WifiStandard
Identifies the IEEE 802.11 specifications that a Wifi device can be configured to use.
WifiPhyBand
Identifies the PHY band.
WifiChannelWidthType
Enumeration of the possible channel widths.
@ WIFI_STANDARD_UNSPECIFIED
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
@ WIFI_PHY_BAND_UNSPECIFIED
Unspecified.
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
@ 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.
std::ostream & operator<<(std::ostream &os, const Angles &a)
double MHz_u
MHz weak type.
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
MHz_u GetMaximumChannelWidth(WifiModulationClass modulation)
Get the maximum channel width allowed for the given modulation class.
WifiModulationClass GetModulationClassForStandard(WifiStandard standard)
Return the modulation class corresponding to a given standard.
const std::map< WifiStandard, std::list< WifiPhyBand > > wifiStandards
map a given standard configured by the user to the allowed PHY bands
FrequencyChannelType GetFrequencyChannelType(WifiStandard standard)
Get the type of the frequency channel for the given standard.
std::ostream & operator<<(std::ostream &os, const PairObject &obj)
Stream insertion operator.
A structure containing the information about a frequency channel.
WifiPhyBand band
the PHY band
uint8_t number
the channel number
MHz_u width
the channel width
MHz_u frequency
the center frequency
bool operator()(const ConstIterator &a, const ConstIterator &b) const
Functional operator for sorting the frequency segments.
Declaration of the following enums: