15#include "ns3/assert.h"
289 : m_channelIts(channelIts),
294 "Operating channel does not support more than 2 segments");
312 std::stringstream ss;
313 for (
const auto& segment : segments)
319 NS_ASSERT_MSG(!segments.empty(),
"At least one frequency segment has to be provided");
322 for (
const auto& segment : segments)
324 if (
const auto channelIt =
325 FindFirst(segment.number, segment.frequency, segment.width, standard, segment.band);
335 channelIts.insert(channelIt);
339 if (channelIts.size() != segments.size())
342 throw std::runtime_error(
343 "WifiPhyOperatingChannel: No unique channel found given the specified criteria");
346 auto it = channelIts.begin();
347 for (std::size_t segment = 0; segment < (channelIts.size() - 1); ++segment)
349 const auto freq = (*it)->frequency;
350 const auto width = (*it)->width;
351 const auto band = (*it)->band;
352 const auto maxFreq = freq + (width / 2);
354 const auto nextFreq = (*it)->frequency;
355 const auto nextWidth = (*it)->width;
356 const auto nextBand = (*it)->band;
357 const auto nextMinFreq = nextFreq - (nextWidth / 2);
358 if (maxFreq >= nextMinFreq)
360 throw std::runtime_error(
361 "WifiPhyOperatingChannel is invalid: segments cannot be adjacent nor overlap");
363 if (band != nextBand)
365 throw std::runtime_error(
"WifiPhyOperatingChannel is invalid: all segments shall "
366 "belong to the same band");
370 if ((channelIts.size() > 2) ||
371 ((channelIts.size() == 2) &&
372 !std::all_of(channelIts.cbegin(), channelIts.cend(), [](
const auto& channel) {
373 return channel->width == MHz_u{80};
376 throw std::runtime_error(
"WifiPhyOperatingChannel is invalid: only 80+80MHz is "
377 "expected as non-contiguous channel");
380 m_channelIts = channelIts;
381 m_primary20Index = 0;
388 Set({{GetDefaultChannelNumber(width, standard, band),
MHz_u{0}, width, band}}, standard);
392WifiPhyOperatingChannel::GetDefaultChannelNumber(
396 std::optional<uint8_t> previousChannelNumber )
398 auto start = m_frequencyChannels.begin();
399 auto prevSegmentChannelIt = m_frequencyChannels.end();
400 if (previousChannelNumber)
402 prevSegmentChannelIt =
403 FindFirst(*previousChannelNumber,
MHz_u{0}, width, standard, band, start);
404 if (prevSegmentChannelIt != m_frequencyChannels.end())
406 start = std::next(prevSegmentChannelIt);
409 auto channelIt = FindFirst(0,
MHz_u{0}, width, standard, band, start);
410 if (prevSegmentChannelIt != m_frequencyChannels.end() && channelIt != m_frequencyChannels.end())
412 const auto prevFreq = prevSegmentChannelIt->frequency;
413 const auto prevWidth = prevSegmentChannelIt->width;
414 const auto prevMaxFreq = prevFreq + (prevWidth / 2);
415 const auto nextFreq = channelIt->frequency;
416 const auto nextWidth = channelIt->width;
417 const auto nextMinFreq = nextFreq - (nextWidth / 2);
418 if (prevMaxFreq <= nextMinFreq)
422 channelIt = FindFirst(0,
MHz_u{0}, width, standard, band, std::next(channelIt));
425 if (channelIt != m_frequencyChannels.end())
428 return channelIt->number;
432 throw std::runtime_error(
"WifiPhyOperatingChannel: No default channel found of the given width "
433 "and for the given PHY standard and band");
437WifiPhyOperatingChannel::FindFirst(uint8_t number,
446 if (number != 0 && channel.number != number)
450 if (frequency !=
MHz_u{0} && channel.frequency != frequency)
454 if (width !=
MHz_u{0} && channel.width != width)
475 (std::find(standardIt->second.cbegin(), standardIt->second.cend(), band) ==
476 standardIt->second.cend() ||
479 return m_frequencyChannels.cend();
482 return std::find_if(start, m_frequencyChannels.cend(), predicate);
486WifiPhyOperatingChannel::GetNumber(std::size_t segment )
const
489 return (*std::next(m_channelIts.begin(), segment))->number;
493WifiPhyOperatingChannel::GetFrequency(std::size_t segment )
const
496 return (*std::next(m_channelIts.begin(), segment))->frequency;
500WifiPhyOperatingChannel::GetWidth(std::size_t )
const
504 return (*m_channelIts.cbegin())->width;
508WifiPhyOperatingChannel::GetPhyBand()
const
512 return (*m_channelIts.cbegin())->band;
516WifiPhyOperatingChannel::IsOfdm()
const
519 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::OFDM);
523WifiPhyOperatingChannel::IsDsss()
const
526 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::DSSS);
530WifiPhyOperatingChannel::Is80211p()
const
533 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::CH_80211P);
537WifiPhyOperatingChannel::GetNumbers()
const
540 std::vector<uint8_t> channelNumbers{};
541 std::transform(m_channelIts.cbegin(),
543 std::back_inserter(channelNumbers),
544 [](
const auto& channel) { return channel->number; });
545 return channelNumbers;
549WifiPhyOperatingChannel::GetFrequencies()
const
552 std::vector<MHz_u> centerFrequencies{};
553 std::transform(m_channelIts.cbegin(),
555 std::back_inserter(centerFrequencies),
556 [](
const auto& channel) { return channel->frequency; });
557 return centerFrequencies;
561WifiPhyOperatingChannel::GetWidths()
const
564 std::vector<MHz_u> channelWidths{};
565 std::transform(m_channelIts.cbegin(),
567 std::back_inserter(channelWidths),
568 [](
const auto& channel) { return channel->width; });
569 return channelWidths;
573WifiPhyOperatingChannel::GetTotalWidth()
const
576 return std::accumulate(m_channelIts.cbegin(),
579 [](
MHz_u sum,
const auto& channel) { return sum + channel->width; });
583WifiPhyOperatingChannel::GetWidthType()
const
586 switch (
static_cast<uint16_t
>(GetTotalWidth()))
589 return WifiChannelWidthType::CW_20MHZ;
591 return WifiChannelWidthType::CW_22MHZ;
593 return WifiChannelWidthType::CW_5MHZ;
595 return WifiChannelWidthType::CW_10MHZ;
597 return WifiChannelWidthType::CW_40MHZ;
599 return WifiChannelWidthType::CW_80MHZ;
601 return (m_channelIts.size() == 2) ? WifiChannelWidthType::CW_80_PLUS_80MHZ
602 : WifiChannelWidthType::CW_160MHZ;
604 return WifiChannelWidthType::CW_2160MHZ;
607 return WifiChannelWidthType::UNKNOWN;
612WifiPhyOperatingChannel::GetPrimaryChannelIndex(
MHz_u primaryChannelWidth)
const
614 if (
static_cast<uint16_t
>(primaryChannelWidth) % 20 != 0)
616 NS_LOG_DEBUG(
"The operating channel width is not a multiple of 20 MHz; return 0");
620 NS_ASSERT(primaryChannelWidth <= GetTotalWidth());
625 uint8_t index = m_primary20Index;
627 while (width < primaryChannelWidth)
636WifiPhyOperatingChannel::GetSecondaryChannelIndex(
MHz_u secondaryChannelWidth)
const
638 const uint8_t primaryIndex = GetPrimaryChannelIndex(secondaryChannelWidth);
639 const uint8_t secondaryIndex =
640 (primaryIndex % 2 == 0) ? (primaryIndex + 1) : (primaryIndex - 1);
641 return secondaryIndex;
645WifiPhyOperatingChannel::SetPrimary20Index(uint8_t index)
650 "Primary20 index out of range");
651 m_primary20Index = index;
655WifiPhyOperatingChannel::GetPrimarySegmentIndex(
MHz_u primaryChannelWidth)
const
657 if (m_channelIts.size() < 2)
662 const auto numIndices = GetTotalWidth() / primaryChannelWidth;
663 const auto primaryIndex = GetPrimaryChannelIndex(primaryChannelWidth);
664 return (primaryIndex >= (numIndices / 2)) ? 1 : 0;
668WifiPhyOperatingChannel::GetSecondarySegmentIndex(
MHz_u primaryChannelWidth)
const
671 "Primary channel width cannot be larger than the width of a frequency segment");
672 if (m_channelIts.size() < 2)
677 const auto numIndices = GetTotalWidth() / primaryChannelWidth;
678 const auto secondaryIndex = GetSecondaryChannelIndex(primaryChannelWidth);
679 return (secondaryIndex >= (numIndices / 2)) ? 1 : 0;
683WifiPhyOperatingChannel::GetPrimaryChannelCenterFrequency(
MHz_u primaryChannelWidth)
const
685 const auto segmentIndex = GetPrimarySegmentIndex(primaryChannelWidth);
687 const auto segmentWidth = GetWidth(segmentIndex);
689 const uint8_t segmentOffset = (segmentIndex * (segmentWidth / primaryChannelWidth));
690 return GetFrequency(segmentIndex) - segmentWidth / 2. +
691 (GetPrimaryChannelIndex(primaryChannelWidth) - segmentOffset + 0.5) *
696WifiPhyOperatingChannel::GetSecondaryChannelCenterFrequency(
MHz_u secondaryChannelWidth)
const
698 const auto segmentIndex = GetSecondarySegmentIndex(secondaryChannelWidth);
700 const auto segmentWidth = GetWidth(segmentIndex);
702 const uint8_t segmentOffset = (segmentIndex * (segmentWidth / secondaryChannelWidth));
703 return GetFrequency(segmentIndex) - segmentWidth / 2. +
704 (GetSecondaryChannelIndex(secondaryChannelWidth) - segmentOffset + 0.5) *
705 secondaryChannelWidth;
709WifiPhyOperatingChannel::GetPrimaryChannelNumber(
MHz_u primaryChannelWidth,
713 "Primary channel width cannot be larger than the width of a frequency segment");
714 auto frequency = GetPrimaryChannelCenterFrequency(primaryChannelWidth);
716 auto primaryChanIt = FindFirst(0, frequency, primaryChannelWidth, standard, GetPhyBand());
717 NS_ASSERT_MSG(primaryChanIt != m_frequencyChannels.end(),
"Primary channel number not found");
718 return primaryChanIt->number;
722WifiPhyOperatingChannel::GetPrimaryChannel(
MHz_u primaryChannelWidth)
const
726 "Requested primary channel width ("
727 << primaryChannelWidth <<
" MHz) exceeds total width (" << GetTotalWidth()
730 if (primaryChannelWidth == GetTotalWidth())
735 const auto frequency = GetPrimaryChannelCenterFrequency(primaryChannelWidth);
738 NS_ABORT_MSG_IF(primaryChanIt == m_frequencyChannels.end(),
"Primary channel number not found");
742 const auto primaryIndex = m_primary20Index - (GetPrimaryChannelIndex(primaryChannelWidth) *
746 return primaryChannel;
750WifiPhyOperatingChannel::GetAll20MHzChannelIndicesInPrimary(
MHz_u width)
const
752 if (width > GetTotalWidth())
759 std::set<uint8_t> indices;
760 indices.insert(m_primary20Index);
762 while (currWidth < width)
764 indices.merge(GetAll20MHzChannelIndicesInSecondary(indices));
772WifiPhyOperatingChannel::GetAll20MHzChannelIndicesInSecondary(
MHz_u width)
const
774 return GetAll20MHzChannelIndicesInSecondary(GetAll20MHzChannelIndicesInPrimary(width));
778WifiPhyOperatingChannel::GetAll20MHzChannelIndicesInSecondary(
779 const std::set<uint8_t>& primaryIndices)
const
781 if (primaryIndices.empty() || GetTotalWidth() ==
MHz_u{20})
787 MHz_u primaryWidth{20};
790 while (size != primaryIndices.size())
795 if (primaryWidth >= GetTotalWidth())
803 std::set<uint8_t> secondaryIndices;
804 for (
const auto& index : primaryIndices)
806 secondaryIndices.insert(index ^ size);
809 return secondaryIndices;
815 const auto ruType = WifiRu::GetRuType(ru);
818 "No RU of type " << ruType <<
" is contained in a " << width <<
" MHz channel");
820 "The given width (" << width <<
" MHz) exceeds the operational width ("
821 << GetTotalWidth() <<
")");
824 if (
const auto ruIndex = WifiRu::GetIndex(ru); ruType == RuType::RU_26_TONE && ruIndex == 19)
826 NS_ASSERT_MSG(WifiRu::IsHe(ru),
"Center 26-tone RUs can only be used with HE");
828 "26-tone RU with index 19 is only present in channels of at least 80 MHz");
831 auto indices = std::get<HeRu::RuSpec>(ru).GetPrimary80MHz()
832 ? GetAll20MHzChannelIndicesInPrimary(
MHz_u{80})
833 : GetAll20MHzChannelIndicesInSecondary(
MHz_u{80});
834 indices.erase(indices.begin());
835 indices.erase(std::prev(indices.end()));
839 auto ruPhyIndex = WifiRu::GetPhyIndex(ru, width, m_primary20Index);
840 if (ruType == RuType::RU_26_TONE && ruPhyIndex > 19)
846 ruPhyIndex -= (ruPhyIndex - 19) / 37;
850 uint8_t n20MHzChannels;
854 case RuType::RU_26_TONE:
855 case RuType::RU_52_TONE:
856 case RuType::RU_106_TONE:
857 case RuType::RU_242_TONE:
860 case RuType::RU_484_TONE:
863 case RuType::RU_996_TONE:
866 case RuType::RU_2x996_TONE:
869 case RuType::RU_4x996_TONE:
876 auto nRusInCoveringChannel =
877 WifiRu::GetNRus(n20MHzChannels *
MHz_u{20},
881 std::size_t indexOfCoveringChannelInGivenWidth = (ruPhyIndex - 1) / nRusInCoveringChannel;
885 NS_ASSERT(indexOfCoveringChannelInGivenWidth < 16);
886 std::set<uint8_t> indices({
static_cast<uint8_t
>(indexOfCoveringChannelInGivenWidth)});
888 while (n20MHzChannels > 1)
890 std::set<uint8_t> updatedIndices;
891 for (
const auto& idx : indices)
893 updatedIndices.insert(idx * 2);
894 updatedIndices.insert(idx * 2 + 1);
896 indices.swap(updatedIndices);
905 std::set<uint8_t> updatedIndices;
906 for (
const auto& idx : indices)
908 updatedIndices.insert(idx + offset);
910 indices.swap(updatedIndices);
917WifiPhyOperatingChannel::GetNSegments()
const
919 return m_channelIts.size();
931 return !(*
this == other);
939 const auto numSegments = channel.GetNSegments();
940 for (std::size_t segmentId = 0; segmentId < numSegments; ++segmentId)
944 os <<
"segment " << segmentId <<
" ";
946 os <<
"channel " << +channel.GetNumber() <<
" frequency " << channel.GetFrequency()
947 <<
" width " << channel.GetWidth() <<
" band " << channel.GetPhyBand();
948 if ((segmentId == 0) && (
static_cast<uint16_t
>(channel.GetTotalWidth()) % 20 == 0))
950 os <<
" primary20 " << +channel.GetPrimaryChannelIndex(
MHz_u{20});
952 if (segmentId < numSegments - 1)
960 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: