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: