A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-phy-operating-channel.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2021
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Stefano Avallone <stavallo@unina.it>
7 * Sébastien Deronne <sebastien.deronne@gmail.com>
8 */
9
11
12#include "wifi-phy-common.h"
13#include "wifi-utils.h"
14
15#include "ns3/assert.h"
16#include "ns3/log.h"
17
18#include <algorithm>
19#include <numeric>
20#include <sstream>
21
22namespace ns3
23{
24
25NS_LOG_COMPONENT_DEFINE("WifiPhyOperatingChannel");
26
27const std::set<FrequencyChannelInfo> WifiPhyOperatingChannel::m_frequencyChannels = {{
28 // 2.4 GHz channels
29 // 802.11b uses width of 22, while OFDM modes use width of 20
56 // Only defined for 802.11b
58 // 40 MHz channels
68
69 // Now the 5 GHz channels used for 802.11a/n/ac/ax/be
70 // 20 MHz channels
100 // 40 MHz channels
115 // 80 MHz channels
123 // 160 MHz channels
127
128 // 802.11p 10 MHz channels at the 5.855-5.925 band
136
137 // 802.11p 5 MHz channels at the 5.855-5.925 band (for simplification, we consider the same
138 // center frequencies as the 10 MHz channels)
146
147 // Now the 6 GHz channels for 802.11ax/be
148 // 20 MHz channels
208 // 40 MHz channels
238 // 80 MHz channels
253 // 160 MHz channels
261 // 320 MHz-1 channels
265 // 320 MHz-2 channels
269}};
270
271std::ostream&
272operator<<(std::ostream& os, const FrequencyChannelInfo& info)
273{
274 os << "{" << +info.number << " " << info.frequency << " " << info.width << " " << info.band
275 << "}";
276 return os;
277}
278
279const std::set<FrequencyChannelInfo>&
284
285bool
287 const ConstIterator& second) const
288{
289 return first->frequency < second->frequency;
290}
291
296
301
303 : m_channelIts(channelIts),
305{
306 NS_LOG_FUNCTION(this);
307 NS_ASSERT_MSG(channelIts.size() <= 2,
308 "Operating channel does not support more than 2 segments");
309}
310
315
316bool
318{
319 return !m_channelIts.empty();
320}
321
322void
323WifiPhyOperatingChannel::Set(const std::vector<FrequencyChannelInfo>& segments,
324 WifiStandard standard)
325{
326 std::stringstream ss;
327 for (const auto& segment : segments)
328 {
329 ss << segment;
330 }
331 NS_LOG_FUNCTION(this << ss.str() << standard);
332
333 NS_ASSERT_MSG(!segments.empty(), "At least one frequency segment has to be provided");
334
335 ConstIteratorSet channelIts{};
336 for (const auto& segment : segments)
337 {
338 if (const auto channelIt =
339 FindFirst(segment.number, segment.frequency, segment.width, standard, segment.band);
340 channelIt != m_frequencyChannels.cend() &&
341 FindFirst(segment.number,
342 segment.frequency,
343 segment.width,
344 standard,
345 segment.band,
346 std::next(channelIt)) == m_frequencyChannels.cend())
347 {
348 // a unique channel matches the specified criteria
349 channelIts.insert(channelIt);
350 }
351 }
352
353 if (channelIts.size() != segments.size())
354 {
355 // if a unique channel was not found, throw an exception (mainly for unit testing this code)
356 throw std::runtime_error(
357 "WifiPhyOperatingChannel: No unique channel found given the specified criteria");
358 }
359
360 auto it = channelIts.begin();
361 for (std::size_t segment = 0; segment < (channelIts.size() - 1); ++segment)
362 {
363 const auto freq = (*it)->frequency;
364 const auto width = (*it)->width;
365 const auto band = (*it)->band;
366 const auto maxFreq = freq + (width / 2);
367 ++it;
368 const auto nextFreq = (*it)->frequency;
369 const auto nextWidth = (*it)->width;
370 const auto nextBand = (*it)->band;
371 const auto nextMinFreq = nextFreq - (nextWidth / 2);
372 if (maxFreq >= nextMinFreq)
373 {
374 throw std::runtime_error(
375 "WifiPhyOperatingChannel is invalid: segments cannot be adjacent nor overlap");
376 }
377 if (band != nextBand)
378 {
379 throw std::runtime_error("WifiPhyOperatingChannel is invalid: all segments shall "
380 "belong to the same band");
381 }
382 }
383
384 if ((channelIts.size() > 2) ||
385 ((channelIts.size() == 2) &&
386 !std::all_of(channelIts.cbegin(), channelIts.cend(), [](const auto& channel) {
387 return channel->width == MHz_u{80};
388 })))
389 {
390 throw std::runtime_error("WifiPhyOperatingChannel is invalid: only 80+80MHz is "
391 "expected as non-contiguous channel");
392 }
393
394 m_channelIts = channelIts;
395 m_primary20Index = 0;
396}
397
398void
400{
401 NS_LOG_FUNCTION(this << width << standard << band);
402 Set({{GetDefaultChannelNumber(width, standard, band), MHz_u{0}, width, band}}, standard);
403}
404
405uint8_t
407 MHz_u width,
408 WifiStandard standard,
409 WifiPhyBand band,
410 std::optional<uint8_t> previousChannelNumber /* = std::nullopt */)
411{
412 auto start = m_frequencyChannels.begin();
413 auto prevSegmentChannelIt = m_frequencyChannels.end();
414 if (previousChannelNumber)
415 {
416 prevSegmentChannelIt =
417 FindFirst(*previousChannelNumber, MHz_u{0}, width, standard, band, start);
418 if (prevSegmentChannelIt != m_frequencyChannels.end())
419 {
420 start = std::next(prevSegmentChannelIt);
421 }
422 }
423 auto channelIt = FindFirst(0, MHz_u{0}, width, standard, band, start);
424 if (prevSegmentChannelIt != m_frequencyChannels.end() && channelIt != m_frequencyChannels.end())
425 {
426 const auto prevFreq = prevSegmentChannelIt->frequency;
427 const auto prevWidth = prevSegmentChannelIt->width;
428 const auto prevMaxFreq = prevFreq + (prevWidth / 2);
429 const auto nextFreq = channelIt->frequency;
430 const auto nextWidth = channelIt->width;
431 const auto nextMinFreq = nextFreq - (nextWidth / 2);
432 if (prevMaxFreq <= nextMinFreq)
433 {
434 // segments are contiguous to each others, find next segment to make sure they are
435 // not contiguous
436 channelIt = FindFirst(0, MHz_u{0}, width, standard, band, std::next(channelIt));
437 }
438 }
439 if (channelIt != m_frequencyChannels.end())
440 {
441 // a channel matches the specified criteria
442 return channelIt->number;
443 }
444
445 // if a default channel was not found, throw an exception (mainly for unit testing this code)
446 throw std::runtime_error("WifiPhyOperatingChannel: No default channel found of the given width "
447 "and for the given PHY standard and band");
448}
449
452 MHz_u frequency,
453 MHz_u width,
454 WifiStandard standard,
455 WifiPhyBand band,
456 ConstIterator start)
457{
458 // lambda used to match channels against the specified criteria
459 auto predicate = [&](const FrequencyChannelInfo& channel) {
460 if (number != 0 && channel.number != number)
461 {
462 return false;
463 }
464 if (frequency != MHz_u{0} && channel.frequency != frequency)
465 {
466 return false;
467 }
468 if (width != MHz_u{0} && channel.width != width)
469 {
470 return false;
471 }
472 if (standard != WIFI_STANDARD_UNSPECIFIED &&
473 channel.type != GetFrequencyChannelType(standard))
474 {
475 return false;
476 }
477 if (band != WIFI_PHY_BAND_UNSPECIFIED && channel.band != band)
478 {
479 return false;
480 }
481 return true;
482 };
483
484 // Do not search for a channel matching the specified criteria if the given PHY band
485 // is not allowed for the given standard (if any) or the given channel width is not
486 // allowed for the given standard (if any)
487 if (const auto standardIt = wifiStandards.find(standard);
488 standardIt != wifiStandards.cend() &&
489 (std::find(standardIt->second.cbegin(), standardIt->second.cend(), band) ==
490 standardIt->second.cend() ||
492 {
493 return m_frequencyChannels.cend();
494 }
495
496 return std::find_if(start, m_frequencyChannels.cend(), predicate);
497}
498
499uint8_t
500WifiPhyOperatingChannel::GetNumber(std::size_t segment /* = 0 */) const
501{
502 NS_ASSERT(IsSet());
503 return (*std::next(m_channelIts.begin(), segment))->number;
504}
505
506MHz_u
507WifiPhyOperatingChannel::GetFrequency(std::size_t segment /* = 0 */) const
508{
509 NS_ASSERT(IsSet());
510 return (*std::next(m_channelIts.begin(), segment))->frequency;
511}
512
513MHz_u
514WifiPhyOperatingChannel::GetWidth(std::size_t /* segment = 0 */) const
515{
516 NS_ASSERT(IsSet());
517 // Current specs only allow all segments to be the same width
518 return (*m_channelIts.cbegin())->width;
519}
520
523{
524 NS_ASSERT(IsSet());
525 // Current specs only allow all segments to be the same band
526 return (*m_channelIts.cbegin())->band;
527}
528
529bool
531{
532 NS_ASSERT(IsSet());
533 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::OFDM);
534}
535
536bool
538{
539 NS_ASSERT(IsSet());
540 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::DSSS);
541}
542
543bool
545{
546 NS_ASSERT(IsSet());
547 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::CH_80211P);
548}
549
550std::vector<uint8_t>
552{
553 NS_ASSERT(IsSet());
554 std::vector<uint8_t> channelNumbers{};
555 std::transform(m_channelIts.cbegin(),
556 m_channelIts.cend(),
557 std::back_inserter(channelNumbers),
558 [](const auto& channel) { return channel->number; });
559 return channelNumbers;
560}
561
562std::vector<MHz_u>
564{
565 NS_ASSERT(IsSet());
566 std::vector<MHz_u> centerFrequencies{};
567 std::transform(m_channelIts.cbegin(),
568 m_channelIts.cend(),
569 std::back_inserter(centerFrequencies),
570 [](const auto& channel) { return channel->frequency; });
571 return centerFrequencies;
572}
573
574std::vector<MHz_u>
576{
577 NS_ASSERT(IsSet());
578 std::vector<MHz_u> channelWidths{};
579 std::transform(m_channelIts.cbegin(),
580 m_channelIts.cend(),
581 std::back_inserter(channelWidths),
582 [](const auto& channel) { return channel->width; });
583 return channelWidths;
584}
585
586MHz_u
588{
589 NS_ASSERT(IsSet());
590 return std::accumulate(m_channelIts.cbegin(),
591 m_channelIts.cend(),
592 MHz_u{0},
593 [](MHz_u sum, const auto& channel) { return sum + channel->width; });
594}
595
598{
599 NS_ASSERT(IsSet());
600 switch (static_cast<uint16_t>(GetTotalWidth()))
601 {
602 case 20:
604 case 22:
606 case 5:
608 case 10:
610 case 40:
612 case 80:
614 case 160:
617 case 320:
619 case 2160:
621 case 0:
622 default:
624 }
625}
626
627uint8_t
629{
630 if (static_cast<uint16_t>(primaryChannelWidth) % 20 != 0)
631 {
632 NS_LOG_DEBUG("The operating channel width is not a multiple of 20 MHz; return 0");
633 return 0;
634 }
635
636 NS_ASSERT(primaryChannelWidth <= GetTotalWidth());
637
638 // the index of primary40 is half the index of primary20; the index of
639 // primary80 is half the index of primary40, ...
640 MHz_u width{20};
641 uint8_t index = m_primary20Index;
642
643 while (width < primaryChannelWidth)
644 {
645 index /= 2;
646 width *= 2;
647 }
648 return index;
649}
650
651uint8_t
653{
654 const uint8_t primaryIndex = GetPrimaryChannelIndex(secondaryChannelWidth);
655 const uint8_t secondaryIndex =
656 (primaryIndex % 2 == 0) ? (primaryIndex + 1) : (primaryIndex - 1);
657 return secondaryIndex;
658}
659
660void
662{
663 NS_LOG_FUNCTION(this << +index);
664
665 NS_ABORT_MSG_IF(index > 0 && index >= Count20MHzSubchannels(GetTotalWidth()),
666 "Primary20 index out of range");
667 m_primary20Index = index;
668}
669
670uint8_t
672{
673 if (m_channelIts.size() < 2)
674 {
675 return 0;
676 }
677 // Note: this function assumes no more than 2 segments are used
678 const auto numIndices = GetTotalWidth() / primaryChannelWidth;
679 const auto primaryIndex = GetPrimaryChannelIndex(primaryChannelWidth);
680 return (primaryIndex >= (numIndices / 2)) ? 1 : 0;
681}
682
683uint8_t
685{
686 NS_ABORT_MSG_IF(primaryChannelWidth > GetWidth(),
687 "Primary channel width cannot be larger than the width of a frequency segment");
688 if (m_channelIts.size() < 2)
689 {
690 return 0;
691 }
692 // Note: this function assumes no more than 2 segments are used
693 const auto numIndices = GetTotalWidth() / primaryChannelWidth;
694 const auto secondaryIndex = GetSecondaryChannelIndex(primaryChannelWidth);
695 return (secondaryIndex >= (numIndices / 2)) ? 1 : 0;
696}
697
698MHz_u
700{
701 const auto segmentIndex = GetPrimarySegmentIndex(primaryChannelWidth);
702 // we assume here that all segments have the same width
703 const auto segmentWidth = GetWidth(segmentIndex);
704 // segmentOffset has to be an (unsigned) integer to ensure correct calculation
705 const uint8_t segmentOffset = (segmentIndex * (segmentWidth / primaryChannelWidth));
706 return GetFrequency(segmentIndex) - segmentWidth / 2. +
707 (GetPrimaryChannelIndex(primaryChannelWidth) - segmentOffset + 0.5) *
708 primaryChannelWidth;
709}
710
711MHz_u
713{
714 const auto segmentIndex = GetSecondarySegmentIndex(secondaryChannelWidth);
715 // we assume here that all segments have the same width
716 const auto segmentWidth = GetWidth(segmentIndex);
717 // segmentOffset has to be an (unsigned) integer to ensure correct calculation
718 const uint8_t segmentOffset = (segmentIndex * (segmentWidth / secondaryChannelWidth));
719 return GetFrequency(segmentIndex) - segmentWidth / 2. +
720 (GetSecondaryChannelIndex(secondaryChannelWidth) - segmentOffset + 0.5) *
721 secondaryChannelWidth;
722}
723
724uint8_t
726 WifiStandard standard) const
727{
728 NS_ABORT_MSG_IF(primaryChannelWidth > GetWidth(),
729 "Primary channel width cannot be larger than the width of a frequency segment");
730 auto frequency = GetPrimaryChannelCenterFrequency(primaryChannelWidth);
731 NS_ASSERT_MSG(IsSet(), "No channel set");
732 auto primaryChanIt = FindFirst(0, frequency, primaryChannelWidth, standard, GetPhyBand());
733 NS_ASSERT_MSG(primaryChanIt != m_frequencyChannels.end(), "Primary channel number not found");
734 return primaryChanIt->number;
735}
736
739{
740 NS_ASSERT_MSG(IsSet(), "No channel set");
741 NS_ASSERT_MSG(primaryChannelWidth <= GetTotalWidth(),
742 "Requested primary channel width ("
743 << primaryChannelWidth << " MHz) exceeds total width (" << GetTotalWidth()
744 << " MHz)");
745
746 if (primaryChannelWidth == GetTotalWidth())
747 {
748 return *this;
749 }
750
751 const auto frequency = GetPrimaryChannelCenterFrequency(primaryChannelWidth);
752 auto primaryChanIt =
753 FindFirst(0, frequency, primaryChannelWidth, WIFI_STANDARD_UNSPECIFIED, GetPhyBand());
754 NS_ABORT_MSG_IF(primaryChanIt == m_frequencyChannels.end(), "Primary channel number not found");
755
756 WifiPhyOperatingChannel primaryChannel(primaryChanIt);
757
758 const auto primaryIndex = m_primary20Index - (GetPrimaryChannelIndex(primaryChannelWidth) *
759 Count20MHzSubchannels(primaryChannelWidth));
760 primaryChannel.SetPrimary20Index(primaryIndex);
761
762 return primaryChannel;
763}
764
765std::set<uint8_t>
767{
768 if (width > GetTotalWidth())
769 {
770 // a primary channel of the given width does not exist
771 return {};
772 }
773
774 MHz_u currWidth{20};
775 std::set<uint8_t> indices;
776 indices.insert(m_primary20Index);
777
778 while (currWidth < width)
779 {
780 indices.merge(GetAll20MHzChannelIndicesInSecondary(indices));
781 currWidth *= 2;
782 }
783
784 return indices;
785}
786
787std::set<uint8_t>
792
793std::set<uint8_t>
795 const std::set<uint8_t>& primaryIndices) const
796{
797 if (primaryIndices.empty() || GetTotalWidth() == MHz_u{20})
798 {
799 return {};
800 }
801
802 uint8_t size = 1;
803 MHz_u primaryWidth{20};
804
805 // find the width of the primary channel corresponding to the size of the given set
806 while (size != primaryIndices.size())
807 {
808 size <<= 1;
809 primaryWidth *= 2;
810
811 if (primaryWidth >= GetTotalWidth())
812 {
813 // the width of the primary channel resulting from the given indices
814 // exceeds the width of the operating channel
815 return {};
816 }
817 }
818
819 std::set<uint8_t> secondaryIndices;
820 for (const auto& index : primaryIndices)
821 {
822 secondaryIndices.insert(index ^ size);
823 }
824
825 return secondaryIndices;
826}
827
828std::set<uint8_t>
830{
831 const auto ruType = WifiRu::GetRuType(ru);
832
833 NS_ASSERT_MSG(WifiRu::GetBandwidth(ruType) <= width,
834 "No RU of type " << ruType << " is contained in a " << width << " MHz channel");
835 NS_ASSERT_MSG(width <= GetTotalWidth(),
836 "The given width (" << width << " MHz) exceeds the operational width ("
837 << GetTotalWidth() << ")");
838
839 // handle first the special case of center 26-tone RUs
840 if (const auto ruIndex = WifiRu::GetIndex(ru); ruType == RuType::RU_26_TONE && ruIndex == 19)
841 {
842 NS_ASSERT_MSG(WifiRu::IsHe(ru), "Center 26-tone RUs can only be used with HE");
843 NS_ASSERT_MSG(width >= MHz_u{80},
844 "26-tone RU with index 19 is only present in channels of at least 80 MHz");
845 // the center 26-tone RU in an 80 MHz channel is not fully covered by
846 // any 20 MHz channel, but by the two central 20 MHz channels in the 80 MHz channel
847 auto indices = std::get<HeRu::RuSpec>(ru).GetPrimary80MHz()
850 indices.erase(indices.begin());
851 indices.erase(std::prev(indices.end()));
852 return indices;
853 }
854
855 auto ruPhyIndex = WifiRu::GetPhyIndex(ru, width, m_primary20Index);
856 if (ruType == RuType::RU_26_TONE && ruPhyIndex > 19)
857 {
858 // "ignore" the center 26-tone RUs in 80 MHz channels
859 ruPhyIndex--;
860 if (ruPhyIndex > 37)
861 {
862 ruPhyIndex -= (ruPhyIndex - 19) / 37;
863 }
864 }
865
866 uint8_t n20MHzChannels; // number of 20 MHz channels in the channel covering the RU
867
868 switch (ruType)
869 {
874 n20MHzChannels = 1;
875 break;
877 n20MHzChannels = 2;
878 break;
880 n20MHzChannels = 4;
881 break;
883 n20MHzChannels = 8;
884 break;
886 n20MHzChannels = 16;
887 break;
888 default:
889 NS_ABORT_MSG("Unhandled RU type: " << ruType);
890 }
891
892 auto nRusInCoveringChannel =
893 WifiRu::GetNRus(n20MHzChannels * MHz_u{20},
894 ruType,
896 // compute the index (starting at 0) of the covering channel within the given width
897 std::size_t indexOfCoveringChannelInGivenWidth = (ruPhyIndex - 1) / nRusInCoveringChannel;
898
899 // expand the index of the covering channel in the indices of its constituent
900 // 20 MHz channels (within the given width)
901 NS_ASSERT(indexOfCoveringChannelInGivenWidth < 16); // max number of 20 MHz channels
902 std::set<uint8_t> indices({static_cast<uint8_t>(indexOfCoveringChannelInGivenWidth)});
903
904 while (n20MHzChannels > 1)
905 {
906 std::set<uint8_t> updatedIndices;
907 for (const auto& idx : indices)
908 {
909 updatedIndices.insert(idx * 2);
910 updatedIndices.insert(idx * 2 + 1);
911 }
912 indices.swap(updatedIndices);
913 n20MHzChannels /= 2;
914 }
915
916 // finally, add the appropriate offset if width is less than the operational channel width
917 auto offset = GetPrimaryChannelIndex(width) * Count20MHzSubchannels(width);
918
919 if (offset > 0)
920 {
921 std::set<uint8_t> updatedIndices;
922 for (const auto& idx : indices)
923 {
924 updatedIndices.insert(idx + offset);
925 }
926 indices.swap(updatedIndices);
927 }
928
929 return indices;
930}
931
932std::size_t
934{
935 return m_channelIts.size();
936}
937
938bool
943
944bool
946{
947 return !(*this == other);
948}
949
950std::ostream&
951operator<<(std::ostream& os, const WifiPhyOperatingChannel& channel)
952{
953 if (channel.IsSet())
954 {
955 const auto numSegments = channel.GetNSegments();
956 for (std::size_t segmentId = 0; segmentId < numSegments; ++segmentId)
957 {
958 if (numSegments > 1)
959 {
960 os << "segment " << segmentId << " ";
961 }
962 os << "channel " << +channel.GetNumber() << " frequency " << channel.GetFrequency()
963 << " width " << channel.GetWidth() << " band " << channel.GetPhyBand();
964 if ((segmentId == 0) && (static_cast<uint16_t>(channel.GetTotalWidth()) % 20 == 0))
965 {
966 os << " primary20 " << +channel.GetPrimaryChannelIndex(MHz_u{20});
967 }
968 if (segmentId < numSegments - 1)
969 {
970 os << " ";
971 }
972 }
973 }
974 else
975 {
976 os << "channel not set";
977 }
978 return os;
979}
980
981} // namespace ns3
Class that keeps track of all information about the current PHY operating channel.
MHz_u GetTotalWidth() const
Return the width of the whole 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.
uint8_t GetNumber(std::size_t segment=0) const
Return the channel number for a given frequency segment.
bool operator==(const WifiPhyOperatingChannel &other) const
Check if the given WifiPhyOperatingChannel is equivalent.
WifiPhyOperatingChannel()
Create an uninitialized PHY operating channel.
WifiChannelWidthType GetWidthType() const
Return the width type of the operating channel.
MHz_u GetSecondaryChannelCenterFrequency(MHz_u secondaryChannelWidth) const
Get the center frequency of the secondary channel of the given width.
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.
static const std::set< FrequencyChannelInfo > & GetFrequencyChannels()
Return a reference to the set of all available frequency channels.
bool operator!=(const WifiPhyOperatingChannel &other) const
Check if the given WifiPhyOperatingChannel is different.
std::set< uint8_t > GetAll20MHzChannelIndicesInSecondary(MHz_u width) const
Get the channel indices of all the 20 MHz channels included in the secondary channel of the given wid...
bool IsDsss() const
Return whether the operating channel is a DSSS channel.
void SetPrimary20Index(uint8_t index)
Set the index of the primary 20 MHz channel (0 indicates the 20 MHz subchannel with the lowest center...
static uint8_t GetDefaultChannelNumber(MHz_u width, WifiStandard standard, WifiPhyBand band, std::optional< uint8_t > previousChannelNumber=std::nullopt)
Get the default channel number for a given segment of the given width and for the given standard and ...
uint8_t GetSecondarySegmentIndex(MHz_u secondaryChannelWidth) const
Get the index of the segment that contains a given secondary channel.
std::set< uint8_t > GetAll20MHzChannelIndicesInPrimary(MHz_u width) const
Get the channel indices of all the 20 MHz channels included in the primary channel of the given width...
uint8_t GetSecondaryChannelIndex(MHz_u secondaryChannelWidth) const
If the operating channel width is made of a multiple of 20 MHz, return the index of the secondary cha...
std::size_t GetNSegments() const
Get the number of frequency segments in the operating channel.
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...
void SetDefault(MHz_u width, WifiStandard standard, WifiPhyBand band)
Set the default channel of the given width and for the given standard and band.
ConstIteratorSet m_channelIts
const iterators pointing to the configured frequency channel
MHz_u GetWidth(std::size_t segment=0) const
Return the channel width for a given frequency segment.
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...
bool Is80211p() const
Return whether the operating channel is an 802.11p channel.
MHz_u GetPrimaryChannelCenterFrequency(MHz_u primaryChannelWidth) const
Get the center frequency of the primary channel of the given width.
std::vector< uint8_t > GetNumbers() const
Return the channel number per segment.
std::vector< MHz_u > GetFrequencies() const
Return the center frequency per segment.
bool IsOfdm() const
Return whether the operating channel is an OFDM channel.
MHz_u GetFrequency(std::size_t segment=0) const
Return the center frequency for a given frequency segment.
static ConstIterator FindFirst(uint8_t number, MHz_u frequency, MHz_u width, WifiStandard standard, WifiPhyBand band, ConstIterator start=GetFrequencyChannels().begin())
Find the first frequency segment matching the specified parameters.
uint8_t m_primary20Index
index of the primary20 channel (0 indicates the 20 MHz subchannel with the lowest center frequency)
std::vector< MHz_u > GetWidths() const
Return the channel width per segment.
uint8_t GetPrimarySegmentIndex(MHz_u primaryChannelWidth) const
Get the index of the segment that contains a given primary channel.
WifiPhyBand GetPhyBand() const
Return the PHY band of the operating channel.
WifiPhyOperatingChannel GetPrimaryChannel(MHz_u primaryChannelWidth) const
Get a WifiPhyOperatingChannel object corresponding to the primary channel of the given width.
uint8_t GetPrimaryChannelNumber(MHz_u primaryChannelWidth, WifiStandard standard) const
Get channel number of the primary channel.
std::set< uint8_t > Get20MHzIndicesCoveringRu(WifiRu::RuSpec ru, MHz_u width) const
Get the channel indices of the minimum subset of 20 MHz channels containing the given RU.
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 bool IsHe(RuSpec ru)
Get whether a given RU variant is a HE RU.
Definition wifi-ru.cc:248
static MHz_u GetBandwidth(RuType ruType)
Get the approximate bandwidth occupied by a RU.
Definition wifi-ru.cc:78
static RuType GetRuType(RuSpec ru)
Get the type of a given RU.
Definition wifi-ru.cc:45
static std::size_t GetPhyIndex(RuSpec ru, MHz_u bw, uint8_t p20Index)
Get the RU PHY index.
Definition wifi-ru.cc:57
static std::size_t GetIndex(RuSpec ru)
Get the index of a given RU.
Definition wifi-ru.cc:51
#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
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#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_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.
Definition wifi-types.h:28
@ 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)
Definition first.py:1
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
double MHz_u
MHz weak type.
Definition wifi-units.h:31
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Definition wifi-utils.h:138
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.
uint8_t number
the channel number
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: