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
279bool
281 const ConstIterator& second) const
282{
283 return first->frequency < second->frequency;
284}
285
290
295
297 : m_channelIts(channelIts),
299{
300 NS_LOG_FUNCTION(this);
301 NS_ASSERT_MSG(channelIts.size() <= 2,
302 "Operating channel does not support more than 2 segments");
303}
304
309
310bool
312{
313 return !m_channelIts.empty();
314}
315
316void
317WifiPhyOperatingChannel::Set(const std::vector<FrequencyChannelInfo>& segments,
318 WifiStandard standard)
319{
320 std::stringstream ss;
321 for (const auto& segment : segments)
322 {
323 ss << segment;
324 }
325 NS_LOG_FUNCTION(this << ss.str() << standard);
326
327 NS_ASSERT_MSG(!segments.empty(), "At least one frequency segment has to be provided");
328
329 ConstIteratorSet channelIts{};
330 for (const auto& segment : segments)
331 {
332 if (const auto channelIt =
333 FindFirst(segment.number, segment.frequency, segment.width, standard, segment.band);
334 channelIt != m_frequencyChannels.cend() &&
335 FindFirst(segment.number,
336 segment.frequency,
337 segment.width,
338 standard,
339 segment.band,
340 std::next(channelIt)) == m_frequencyChannels.cend())
341 {
342 // a unique channel matches the specified criteria
343 channelIts.insert(channelIt);
344 }
345 }
346
347 if (channelIts.size() != segments.size())
348 {
349 // if a unique channel was not found, throw an exception (mainly for unit testing this code)
350 throw std::runtime_error(
351 "WifiPhyOperatingChannel: No unique channel found given the specified criteria");
352 }
353
354 auto it = channelIts.begin();
355 for (std::size_t segment = 0; segment < (channelIts.size() - 1); ++segment)
356 {
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);
361 ++it;
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)
367 {
368 throw std::runtime_error(
369 "WifiPhyOperatingChannel is invalid: segments cannot be adjacent nor overlap");
370 }
371 if (band != nextBand)
372 {
373 throw std::runtime_error("WifiPhyOperatingChannel is invalid: all segments shall "
374 "belong to the same band");
375 }
376 }
377
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};
382 })))
383 {
384 throw std::runtime_error("WifiPhyOperatingChannel is invalid: only 80+80MHz is "
385 "expected as non-contiguous channel");
386 }
387
388 m_channelIts = channelIts;
389 m_primary20Index = 0;
390}
391
392void
394{
395 NS_LOG_FUNCTION(this << width << standard << band);
396 Set({{GetDefaultChannelNumber(width, standard, band), MHz_u{0}, width, band}}, standard);
397}
398
399uint8_t
401 MHz_u width,
402 WifiStandard standard,
403 WifiPhyBand band,
404 std::optional<uint8_t> previousChannelNumber /* = std::nullopt */)
405{
406 auto start = m_frequencyChannels.begin();
407 auto prevSegmentChannelIt = m_frequencyChannels.end();
408 if (previousChannelNumber)
409 {
410 prevSegmentChannelIt =
411 FindFirst(*previousChannelNumber, MHz_u{0}, width, standard, band, start);
412 if (prevSegmentChannelIt != m_frequencyChannels.end())
413 {
414 start = std::next(prevSegmentChannelIt);
415 }
416 }
417 auto channelIt = FindFirst(0, MHz_u{0}, width, standard, band, start);
418 if (prevSegmentChannelIt != m_frequencyChannels.end() && channelIt != m_frequencyChannels.end())
419 {
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)
427 {
428 // segments are contiguous to each others, find next segment to make sure they are
429 // not contiguous
430 channelIt = FindFirst(0, MHz_u{0}, width, standard, band, std::next(channelIt));
431 }
432 }
433 if (channelIt != m_frequencyChannels.end())
434 {
435 // a channel matches the specified criteria
436 return channelIt->number;
437 }
438
439 // if a default channel was not found, throw an exception (mainly for unit testing this code)
440 throw std::runtime_error("WifiPhyOperatingChannel: No default channel found of the given width "
441 "and for the given PHY standard and band");
442}
443
446 MHz_u frequency,
447 MHz_u width,
448 WifiStandard standard,
449 WifiPhyBand band,
450 ConstIterator start)
451{
452 // lambda used to match channels against the specified criteria
453 auto predicate = [&](const FrequencyChannelInfo& channel) {
454 if (number != 0 && channel.number != number)
455 {
456 return false;
457 }
458 if (frequency != MHz_u{0} && channel.frequency != frequency)
459 {
460 return false;
461 }
462 if (width != MHz_u{0} && channel.width != width)
463 {
464 return false;
465 }
466 if (standard != WIFI_STANDARD_UNSPECIFIED &&
467 channel.type != GetFrequencyChannelType(standard))
468 {
469 return false;
470 }
471 if (band != WIFI_PHY_BAND_UNSPECIFIED && channel.band != band)
472 {
473 return false;
474 }
475 return true;
476 };
477
478 // Do not search for a channel matching the specified criteria if the given PHY band
479 // is not allowed for the given standard (if any) or the given channel width is not
480 // allowed for the given standard (if any)
481 if (const auto standardIt = wifiStandards.find(standard);
482 standardIt != wifiStandards.cend() &&
483 (std::find(standardIt->second.cbegin(), standardIt->second.cend(), band) ==
484 standardIt->second.cend() ||
486 {
487 return m_frequencyChannels.cend();
488 }
489
490 return std::find_if(start, m_frequencyChannels.cend(), predicate);
491}
492
493uint8_t
494WifiPhyOperatingChannel::GetNumber(std::size_t segment /* = 0 */) const
495{
496 NS_ASSERT(IsSet());
497 return (*std::next(m_channelIts.begin(), segment))->number;
498}
499
500MHz_u
501WifiPhyOperatingChannel::GetFrequency(std::size_t segment /* = 0 */) const
502{
503 NS_ASSERT(IsSet());
504 return (*std::next(m_channelIts.begin(), segment))->frequency;
505}
506
507MHz_u
508WifiPhyOperatingChannel::GetWidth(std::size_t /* segment = 0 */) const
509{
510 NS_ASSERT(IsSet());
511 // Current specs only allow all segments to be the same width
512 return (*m_channelIts.cbegin())->width;
513}
514
517{
518 NS_ASSERT(IsSet());
519 // Current specs only allow all segments to be the same band
520 return (*m_channelIts.cbegin())->band;
521}
522
523bool
525{
526 NS_ASSERT(IsSet());
527 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::OFDM);
528}
529
530bool
532{
533 NS_ASSERT(IsSet());
534 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::DSSS);
535}
536
537bool
539{
540 NS_ASSERT(IsSet());
541 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::CH_80211P);
542}
543
544std::vector<uint8_t>
546{
547 NS_ASSERT(IsSet());
548 std::vector<uint8_t> channelNumbers{};
549 std::transform(m_channelIts.cbegin(),
550 m_channelIts.cend(),
551 std::back_inserter(channelNumbers),
552 [](const auto& channel) { return channel->number; });
553 return channelNumbers;
554}
555
556std::vector<MHz_u>
558{
559 NS_ASSERT(IsSet());
560 std::vector<MHz_u> centerFrequencies{};
561 std::transform(m_channelIts.cbegin(),
562 m_channelIts.cend(),
563 std::back_inserter(centerFrequencies),
564 [](const auto& channel) { return channel->frequency; });
565 return centerFrequencies;
566}
567
568std::vector<MHz_u>
570{
571 NS_ASSERT(IsSet());
572 std::vector<MHz_u> channelWidths{};
573 std::transform(m_channelIts.cbegin(),
574 m_channelIts.cend(),
575 std::back_inserter(channelWidths),
576 [](const auto& channel) { return channel->width; });
577 return channelWidths;
578}
579
580MHz_u
582{
583 NS_ASSERT(IsSet());
584 return std::accumulate(m_channelIts.cbegin(),
585 m_channelIts.cend(),
586 MHz_u{0},
587 [](MHz_u sum, const auto& channel) { return sum + channel->width; });
588}
589
592{
593 NS_ASSERT(IsSet());
594 switch (static_cast<uint16_t>(GetTotalWidth()))
595 {
596 case 20:
598 case 22:
600 case 5:
602 case 10:
604 case 40:
606 case 80:
608 case 160:
611 case 320:
613 case 2160:
615 case 0:
616 default:
618 }
619}
620
621uint8_t
623{
624 if (static_cast<uint16_t>(primaryChannelWidth) % 20 != 0)
625 {
626 NS_LOG_DEBUG("The operating channel width is not a multiple of 20 MHz; return 0");
627 return 0;
628 }
629
630 NS_ASSERT(primaryChannelWidth <= GetTotalWidth());
631
632 // the index of primary40 is half the index of primary20; the index of
633 // primary80 is half the index of primary40, ...
634 MHz_u width{20};
635 uint8_t index = m_primary20Index;
636
637 while (width < primaryChannelWidth)
638 {
639 index /= 2;
640 width *= 2;
641 }
642 return index;
643}
644
645uint8_t
647{
648 const uint8_t primaryIndex = GetPrimaryChannelIndex(secondaryChannelWidth);
649 const uint8_t secondaryIndex =
650 (primaryIndex % 2 == 0) ? (primaryIndex + 1) : (primaryIndex - 1);
651 return secondaryIndex;
652}
653
654void
656{
657 NS_LOG_FUNCTION(this << +index);
658
659 NS_ABORT_MSG_IF(index > 0 && index >= Count20MHzSubchannels(GetTotalWidth()),
660 "Primary20 index out of range");
661 m_primary20Index = index;
662}
663
664uint8_t
666{
667 if (m_channelIts.size() < 2)
668 {
669 return 0;
670 }
671 // Note: this function assumes no more than 2 segments are used
672 const auto numIndices = GetTotalWidth() / primaryChannelWidth;
673 const auto primaryIndex = GetPrimaryChannelIndex(primaryChannelWidth);
674 return (primaryIndex >= (numIndices / 2)) ? 1 : 0;
675}
676
677uint8_t
679{
680 NS_ABORT_MSG_IF(primaryChannelWidth > GetWidth(),
681 "Primary channel width cannot be larger than the width of a frequency segment");
682 if (m_channelIts.size() < 2)
683 {
684 return 0;
685 }
686 // Note: this function assumes no more than 2 segments are used
687 const auto numIndices = GetTotalWidth() / primaryChannelWidth;
688 const auto secondaryIndex = GetSecondaryChannelIndex(primaryChannelWidth);
689 return (secondaryIndex >= (numIndices / 2)) ? 1 : 0;
690}
691
692MHz_u
694{
695 const auto segmentIndex = GetPrimarySegmentIndex(primaryChannelWidth);
696 // we assume here that all segments have the same width
697 const auto segmentWidth = GetWidth(segmentIndex);
698 // segmentOffset has to be an (unsigned) integer to ensure correct calculation
699 const uint8_t segmentOffset = (segmentIndex * (segmentWidth / primaryChannelWidth));
700 return GetFrequency(segmentIndex) - segmentWidth / 2. +
701 (GetPrimaryChannelIndex(primaryChannelWidth) - segmentOffset + 0.5) *
702 primaryChannelWidth;
703}
704
705MHz_u
707{
708 const auto segmentIndex = GetSecondarySegmentIndex(secondaryChannelWidth);
709 // we assume here that all segments have the same width
710 const auto segmentWidth = GetWidth(segmentIndex);
711 // segmentOffset has to be an (unsigned) integer to ensure correct calculation
712 const uint8_t segmentOffset = (segmentIndex * (segmentWidth / secondaryChannelWidth));
713 return GetFrequency(segmentIndex) - segmentWidth / 2. +
714 (GetSecondaryChannelIndex(secondaryChannelWidth) - segmentOffset + 0.5) *
715 secondaryChannelWidth;
716}
717
718uint8_t
720 WifiStandard standard) const
721{
722 NS_ABORT_MSG_IF(primaryChannelWidth > GetWidth(),
723 "Primary channel width cannot be larger than the width of a frequency segment");
724 auto frequency = GetPrimaryChannelCenterFrequency(primaryChannelWidth);
725 NS_ASSERT_MSG(IsSet(), "No channel set");
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;
729}
730
733{
734 NS_ASSERT_MSG(IsSet(), "No channel set");
735 NS_ASSERT_MSG(primaryChannelWidth <= GetTotalWidth(),
736 "Requested primary channel width ("
737 << primaryChannelWidth << " MHz) exceeds total width (" << GetTotalWidth()
738 << " MHz)");
739
740 if (primaryChannelWidth == GetTotalWidth())
741 {
742 return *this;
743 }
744
745 const auto frequency = GetPrimaryChannelCenterFrequency(primaryChannelWidth);
746 auto primaryChanIt =
747 FindFirst(0, frequency, primaryChannelWidth, WIFI_STANDARD_UNSPECIFIED, GetPhyBand());
748 NS_ABORT_MSG_IF(primaryChanIt == m_frequencyChannels.end(), "Primary channel number not found");
749
750 WifiPhyOperatingChannel primaryChannel(primaryChanIt);
751
752 const auto primaryIndex = m_primary20Index - (GetPrimaryChannelIndex(primaryChannelWidth) *
753 Count20MHzSubchannels(primaryChannelWidth));
754 primaryChannel.SetPrimary20Index(primaryIndex);
755
756 return primaryChannel;
757}
758
759std::set<uint8_t>
761{
762 if (width > GetTotalWidth())
763 {
764 // a primary channel of the given width does not exist
765 return {};
766 }
767
768 MHz_u currWidth{20};
769 std::set<uint8_t> indices;
770 indices.insert(m_primary20Index);
771
772 while (currWidth < width)
773 {
774 indices.merge(GetAll20MHzChannelIndicesInSecondary(indices));
775 currWidth *= 2;
776 }
777
778 return indices;
779}
780
781std::set<uint8_t>
786
787std::set<uint8_t>
789 const std::set<uint8_t>& primaryIndices) const
790{
791 if (primaryIndices.empty() || GetTotalWidth() == MHz_u{20})
792 {
793 return {};
794 }
795
796 uint8_t size = 1;
797 MHz_u primaryWidth{20};
798
799 // find the width of the primary channel corresponding to the size of the given set
800 while (size != primaryIndices.size())
801 {
802 size <<= 1;
803 primaryWidth *= 2;
804
805 if (primaryWidth >= GetTotalWidth())
806 {
807 // the width of the primary channel resulting from the given indices
808 // exceeds the width of the operating channel
809 return {};
810 }
811 }
812
813 std::set<uint8_t> secondaryIndices;
814 for (const auto& index : primaryIndices)
815 {
816 secondaryIndices.insert(index ^ size);
817 }
818
819 return secondaryIndices;
820}
821
822std::set<uint8_t>
824{
825 const auto ruType = WifiRu::GetRuType(ru);
826
827 NS_ASSERT_MSG(WifiRu::GetBandwidth(ruType) <= width,
828 "No RU of type " << ruType << " is contained in a " << width << " MHz channel");
829 NS_ASSERT_MSG(width <= GetTotalWidth(),
830 "The given width (" << width << " MHz) exceeds the operational width ("
831 << GetTotalWidth() << ")");
832
833 // handle first the special case of center 26-tone RUs
834 if (const auto ruIndex = WifiRu::GetIndex(ru); ruType == RuType::RU_26_TONE && ruIndex == 19)
835 {
836 NS_ASSERT_MSG(WifiRu::IsHe(ru), "Center 26-tone RUs can only be used with HE");
837 NS_ASSERT_MSG(width >= MHz_u{80},
838 "26-tone RU with index 19 is only present in channels of at least 80 MHz");
839 // the center 26-tone RU in an 80 MHz channel is not fully covered by
840 // any 20 MHz channel, but by the two central 20 MHz channels in the 80 MHz channel
841 auto indices = std::get<HeRu::RuSpec>(ru).GetPrimary80MHz()
844 indices.erase(indices.begin());
845 indices.erase(std::prev(indices.end()));
846 return indices;
847 }
848
849 auto ruPhyIndex = WifiRu::GetPhyIndex(ru, width, m_primary20Index);
850 if (ruType == RuType::RU_26_TONE && ruPhyIndex > 19)
851 {
852 // "ignore" the center 26-tone RUs in 80 MHz channels
853 ruPhyIndex--;
854 if (ruPhyIndex > 37)
855 {
856 ruPhyIndex -= (ruPhyIndex - 19) / 37;
857 }
858 }
859
860 uint8_t n20MHzChannels; // number of 20 MHz channels in the channel covering the RU
861
862 switch (ruType)
863 {
868 n20MHzChannels = 1;
869 break;
871 n20MHzChannels = 2;
872 break;
874 n20MHzChannels = 4;
875 break;
877 n20MHzChannels = 8;
878 break;
880 n20MHzChannels = 16;
881 break;
882 default:
883 NS_ABORT_MSG("Unhandled RU type: " << ruType);
884 }
885
886 auto nRusInCoveringChannel =
887 WifiRu::GetNRus(n20MHzChannels * MHz_u{20},
888 ruType,
890 // compute the index (starting at 0) of the covering channel within the given width
891 std::size_t indexOfCoveringChannelInGivenWidth = (ruPhyIndex - 1) / nRusInCoveringChannel;
892
893 // expand the index of the covering channel in the indices of its constituent
894 // 20 MHz channels (within the given width)
895 NS_ASSERT(indexOfCoveringChannelInGivenWidth < 16); // max number of 20 MHz channels
896 std::set<uint8_t> indices({static_cast<uint8_t>(indexOfCoveringChannelInGivenWidth)});
897
898 while (n20MHzChannels > 1)
899 {
900 std::set<uint8_t> updatedIndices;
901 for (const auto& idx : indices)
902 {
903 updatedIndices.insert(idx * 2);
904 updatedIndices.insert(idx * 2 + 1);
905 }
906 indices.swap(updatedIndices);
907 n20MHzChannels /= 2;
908 }
909
910 // finally, add the appropriate offset if width is less than the operational channel width
911 auto offset = GetPrimaryChannelIndex(width) * Count20MHzSubchannels(width);
912
913 if (offset > 0)
914 {
915 std::set<uint8_t> updatedIndices;
916 for (const auto& idx : indices)
917 {
918 updatedIndices.insert(idx + offset);
919 }
920 indices.swap(updatedIndices);
921 }
922
923 return indices;
924}
925
926std::size_t
928{
929 return m_channelIts.size();
930}
931
932bool
937
938bool
940{
941 return !(*this == other);
942}
943
944std::ostream&
945operator<<(std::ostream& os, const WifiPhyOperatingChannel& channel)
946{
947 if (channel.IsSet())
948 {
949 const auto numSegments = channel.GetNSegments();
950 for (std::size_t segmentId = 0; segmentId < numSegments; ++segmentId)
951 {
952 if (numSegments > 1)
953 {
954 os << "segment " << segmentId << " ";
955 }
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))
959 {
960 os << " primary20 " << +channel.GetPrimaryChannelIndex(MHz_u{20});
961 }
962 if (segmentId < numSegments - 1)
963 {
964 os << " ";
965 }
966 }
967 }
968 else
969 {
970 os << "channel not set";
971 }
972 return os;
973}
974
975} // 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.
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=m_frequencyChannels.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: