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),
298 m_primary20Index(0)
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
393WifiPhyOperatingChannel::SetDefault(MHz_u width, WifiStandard standard, WifiPhyBand band)
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
400WifiPhyOperatingChannel::GetDefaultChannelNumber(
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
445WifiPhyOperatingChannel::FindFirst(uint8_t number,
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
516WifiPhyOperatingChannel::GetPhyBand() const
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
524WifiPhyOperatingChannel::IsOfdm() const
525{
526 NS_ASSERT(IsSet());
527 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::OFDM);
528}
529
530bool
531WifiPhyOperatingChannel::IsDsss() const
532{
533 NS_ASSERT(IsSet());
534 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::DSSS);
535}
536
537bool
538WifiPhyOperatingChannel::Is80211p() const
539{
540 NS_ASSERT(IsSet());
541 return ((*m_channelIts.cbegin())->type == FrequencyChannelType::CH_80211P);
542}
543
544std::vector<uint8_t>
545WifiPhyOperatingChannel::GetNumbers() const
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>
557WifiPhyOperatingChannel::GetFrequencies() const
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>
569WifiPhyOperatingChannel::GetWidths() const
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
581WifiPhyOperatingChannel::GetTotalWidth() const
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
591WifiPhyOperatingChannel::GetWidthType() const
592{
593 NS_ASSERT(IsSet());
594 switch (static_cast<uint16_t>(GetTotalWidth()))
595 {
596 case 20:
597 return WifiChannelWidthType::CW_20MHZ;
598 case 22:
599 return WifiChannelWidthType::CW_22MHZ;
600 case 5:
601 return WifiChannelWidthType::CW_5MHZ;
602 case 10:
603 return WifiChannelWidthType::CW_10MHZ;
604 case 40:
605 return WifiChannelWidthType::CW_40MHZ;
606 case 80:
607 return WifiChannelWidthType::CW_80MHZ;
608 case 160:
609 return (m_channelIts.size() == 2) ? WifiChannelWidthType::CW_80_PLUS_80MHZ
610 : WifiChannelWidthType::CW_160MHZ;
611 case 320:
612 return WifiChannelWidthType::CW_320MHZ;
613 case 2160:
614 return WifiChannelWidthType::CW_2160MHZ;
615 case 0:
616 default:
617 return WifiChannelWidthType::UNKNOWN;
618 }
619}
620
621uint8_t
622WifiPhyOperatingChannel::GetPrimaryChannelIndex(MHz_u primaryChannelWidth) const
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
646WifiPhyOperatingChannel::GetSecondaryChannelIndex(MHz_u secondaryChannelWidth) const
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
655WifiPhyOperatingChannel::SetPrimary20Index(uint8_t index)
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
665WifiPhyOperatingChannel::GetPrimarySegmentIndex(MHz_u primaryChannelWidth) const
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
678WifiPhyOperatingChannel::GetSecondarySegmentIndex(MHz_u primaryChannelWidth) const
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
693WifiPhyOperatingChannel::GetPrimaryChannelCenterFrequency(MHz_u primaryChannelWidth) const
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
706WifiPhyOperatingChannel::GetSecondaryChannelCenterFrequency(MHz_u secondaryChannelWidth) const
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
719WifiPhyOperatingChannel::GetPrimaryChannelNumber(MHz_u primaryChannelWidth,
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
732WifiPhyOperatingChannel::GetPrimaryChannel(MHz_u primaryChannelWidth) const
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>
760WifiPhyOperatingChannel::GetAll20MHzChannelIndicesInPrimary(MHz_u width) const
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>
782WifiPhyOperatingChannel::GetAll20MHzChannelIndicesInSecondary(MHz_u width) const
783{
784 return GetAll20MHzChannelIndicesInSecondary(GetAll20MHzChannelIndicesInPrimary(width));
785}
786
787std::set<uint8_t>
788WifiPhyOperatingChannel::GetAll20MHzChannelIndicesInSecondary(
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>
823WifiPhyOperatingChannel::Get20MHzIndicesCoveringRu(WifiRu::RuSpec ru, MHz_u width) const
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()
842 ? GetAll20MHzChannelIndicesInPrimary(MHz_u{80})
843 : GetAll20MHzChannelIndicesInSecondary(MHz_u{80});
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 {
864 case RuType::RU_26_TONE:
865 case RuType::RU_52_TONE:
866 case RuType::RU_106_TONE:
867 case RuType::RU_242_TONE:
868 n20MHzChannels = 1;
869 break;
870 case RuType::RU_484_TONE:
871 n20MHzChannels = 2;
872 break;
873 case RuType::RU_996_TONE:
874 n20MHzChannels = 4;
875 break;
876 case RuType::RU_2x996_TONE:
877 n20MHzChannels = 8;
878 break;
879 case RuType::RU_4x996_TONE:
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,
889 WifiRu::IsHe(ru) ? WIFI_MOD_CLASS_HE : WIFI_MOD_CLASS_EHT);
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
927WifiPhyOperatingChannel::GetNSegments() const
928{
929 return m_channelIts.size();
930}
931
932bool
933WifiPhyOperatingChannel::operator==(const WifiPhyOperatingChannel& other) const
934{
935 return m_channelIts == other.m_channelIts;
936}
937
938bool
939WifiPhyOperatingChannel::operator!=(const WifiPhyOperatingChannel& other) const
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.
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.
std::variant< HeRu::RuSpec, EhtRu::RuSpec > RuSpec
variant of the RU specification
Definition wifi-ru.h:27
#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: