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