27 #include "ns3/wifi-phy-operating-channel.h"
28 #include "ns3/wifi-phy.h"
29 #include "ns3/wifi-psdu.h"
30 #include "ns3/wifi-utils.h"
45 return (os <<
"PSD_NON_HE_PORTION");
47 return (os <<
"PSD_HE_PORTION");
50 return (os <<
"INVALID");
70 m_psdus.begin()->second =
nullptr;
86 m_txPsdFlag(PSD_NON_HE_PORTION)
104 uint8_t sigExtension = 0;
111 uint16_t length = ((ceil((
static_cast<double>(ppduDuration.
GetNanoSeconds() - (20 * 1000) -
112 (sigExtension * 1000)) /
134 const uint8_t noMuMimoUsers{0};
147 .m_center26ToneRuIndication =
182 auto heSigHeader = std::get_if<HeSuSigHeader>(&
m_heSig);
183 NS_ASSERT(heSigHeader && (heSigHeader->m_format == 1));
192 auto heSigHeader = std::get_if<HeTbSigHeader>(&
m_heSig);
193 NS_ASSERT(heSigHeader && (heSigHeader->m_format == 0));
199 auto heSigHeader = std::get_if<HeMuSigHeader>(&
m_heSig);
206 heSigHeader->m_contentChannels,
207 heSigHeader->m_sigBCompression,
212 if (heSigHeader->m_center26ToneRuIndication.has_value())
216 if (heSigHeader->m_sigBCompression)
228 bool sigBcompression,
229 uint8_t numMuMimoUsers)
const
231 std::size_t contentChannelIndex = 0;
232 for (
const auto& contentChannel : contentChannels)
234 std::size_t numRusLeft = 0;
235 std::size_t numUsersLeft = 0;
236 std::size_t ruAllocIndex = contentChannelIndex;
237 for (
const auto& userInfo : contentChannel)
243 if (ruAllocIndex >= ruAllocation.size())
254 numRusLeft = ruSpecs.size();
256 if (numUsersLeft == 0)
260 numUsersLeft = numMuMimoUsers;
268 auto ruIndex = (ruSpecs.size() - numRusLeft);
269 auto ruSpec = ruSpecs.at(ruIndex);
270 auto ruType = ruSpec.GetRuType();
274 contentChannel.cbegin(),
275 contentChannel.cend(),
276 [&userInfo](
const auto& item) { return userInfo.staId == item.staId; })))
282 auto primary80 = ruAllocIndex < 4;
283 auto num20MhzSubchannelsInRu = (ruBw < 20) ? 1 : (ruBw / 20);
284 auto numRuAllocsInContentChannel =
std::max(1, num20MhzSubchannelsInRu / 2);
285 auto ruIndexOffset = (ruBw < 20) ? (ruSpecs.size() * ruAllocIndex)
286 : (ruAllocIndex / num20MhzSubchannelsInRu);
294 {{ruType, ruSpec.GetIndex() + ruIndexOffset, primary80},
304 if (numRusLeft == 0 && numUsersLeft == 0)
306 ruAllocIndex += (2 * numRuAllocsInContentChannel);
309 contentChannelIndex++;
314 HePpdu::GetTxDuration()
const
317 const auto& txVector = GetTxVector();
318 const auto length = m_lSig.GetLength();
319 const auto tSymbol =
NanoSeconds(12800 + txVector.GetGuardInterval());
320 const auto preambleDuration = WifiPhy::CalculatePhyPreambleAndHeaderDuration(txVector);
325 const auto calculatedDuration =
326 MicroSeconds(((ceil(
static_cast<double>(length + 3 +
m) / 3)) * 4) + 20 + sigExtension);
327 NS_ASSERT(calculatedDuration > preambleDuration);
329 floor(
static_cast<double>((calculatedDuration - preambleDuration).GetNanoSeconds() -
330 (sigExtension * 1000)) /
331 tSymbol.GetNanoSeconds());
332 return (preambleDuration + (nSymbols * tSymbol) +
MicroSeconds(sigExtension));
342 HePpdu::GetType()
const
374 HePpdu::GetPsdu(uint8_t bssColor, uint16_t staId )
const
384 auto heSigHeader = std::get_if<HeTbSigHeader>(&m_heSig);
387 if ((bssColor == 0) || (heSigHeader->m_bssColor == 0) ||
388 (bssColor == heSigHeader->m_bssColor))
390 return m_psdus.cbegin()->second;
395 auto heSigHeader = std::get_if<HeMuSigHeader>(&m_heSig);
397 if ((bssColor == 0) || (heSigHeader->m_bssColor == 0) ||
398 (bssColor == heSigHeader->m_bssColor))
400 const auto it = m_psdus.find(staId);
401 if (it != m_psdus.cend())
411 HePpdu::GetStaId()
const
414 return m_psdus.begin()->first;
418 HePpdu::GetTxChannelWidth()
const
420 if (
const auto& txVector = GetTxVector();
421 txVector.IsValid() && txVector.IsUlMu() && GetStaId() !=
SU_STA_ID)
424 uint16_t ruWidth = HeRu::GetBandwidth(txVector.GetRu(GetStaId()).GetRuType());
425 uint16_t channelWidth = (flag == PSD_NON_HE_PORTION && ruWidth < 20) ? 20 : ruWidth;
426 NS_LOG_INFO(
"Use channelWidth=" << channelWidth <<
" MHz for HE TB from " << GetStaId()
432 return OfdmPpdu::GetTxChannelWidth();
437 HePpdu::GetTxPsdFlag()
const
450 HePpdu::UpdateTxVectorForUlMu(
const std::optional<WifiTxVector>& trigVector)
const
452 if (trigVector.has_value())
460 if (!m_txVector.has_value())
462 m_txVector = GetTxVector();
467 const auto staId = GetStaId();
468 if (trigVector.has_value() && trigVector->IsUlMu() &&
469 (trigVector->GetHeMuUserInfoMap().count(staId) > 0))
473 m_txVector->SetGuardInterval(trigVector->GetGuardInterval());
474 m_txVector->SetHeMuUserInfo(staId, trigVector->GetHeMuUserInfo(staId));
479 m_txVector->SetHeMuUserInfo(
481 {{HeRu::GetRuType(m_txVector->GetChannelWidth()), 1,
true}, 0, 1});
485 std::pair<std::size_t, std::size_t>
486 HePpdu::GetNumRusPerHeSigBContentChannel(uint16_t channelWidth,
488 bool sigBCompression,
489 uint8_t numMuMimoUsers)
491 std::pair<std::size_t ,
500 if (channelWidth == 20)
502 return {numMuMimoUsers, 0};
504 chSize.first = numMuMimoUsers / 2;
505 chSize.second = numMuMimoUsers / 2;
506 if (numMuMimoUsers != (chSize.first + chSize.second))
513 NS_ASSERT_MSG(!ruAllocation.empty(),
"RU allocation is not set");
515 "RU allocation is not consistent with packet bandwidth");
517 switch (channelWidth)
520 chSize.second += HeRu::GetRuSpecs(ruAllocation[1]).size();
523 chSize.first += HeRu::GetRuSpecs(ruAllocation[0]).size();
526 for (
auto n = 0; n < channelWidth / 20;)
528 chSize.first += HeRu::GetRuSpecs(ruAllocation[n]).size();
529 if (ruAllocation[n] >= 208)
537 for (
auto n = 0; n < channelWidth / 20;)
539 chSize.second += HeRu::GetRuSpecs(ruAllocation[n + 1]).size();
540 if (ruAllocation[n + 1] >= 208)
554 HePpdu::GetHeSigBContentChannels(
const WifiTxVector& txVector, uint8_t p20Index)
559 if (channelWidth > 20)
561 contentChannels.emplace_back();
565 for (
const auto& [ru, staIds] : orderedMap)
567 const auto ruType = ru.GetRuType();
570 for (
auto i = 0; i < ((ruType == HeRu::RU_2x996_TONE) ? 2 : 1); ++i)
572 for (
auto staId : staIds)
576 contentChannels[0].push_back({staId, userInfo.nss, userInfo.mcs});
577 contentChannels[1].push_back({staId, userInfo.nss, userInfo.mcs});
583 std::size_t numRus = (ruType >= HeRu::RU_242_TONE)
585 : HeRu::m_heRuSubcarrierGroups.at({20, ruType}).size();
586 const auto ruIdx = ru.GetIndex();
587 for (
auto staId : staIds)
591 std::size_t ccIndex{0};
592 if (channelWidth < 40)
600 ccIndex = (contentChannels.at(0).size() <= contentChannels.at(1).size()) ? 0 : 1;
604 ccIndex = (((ruIdx - 1) / numRus) % 2 == 0) ? 0 : 1;
606 contentChannels.at(ccIndex).push_back({staId, userInfo.nss, userInfo.mcs});
611 if (!isSigBCompression)
614 auto numNumRusPerHeSigBContentChannel = GetNumRusPerHeSigBContentChannel(
619 std::size_t contentChannelIndex = 1;
620 for (
auto& contentChannel : contentChannels)
622 const auto totalUsersInContentChannel = (contentChannelIndex == 1)
623 ? numNumRusPerHeSigBContentChannel.first
624 : numNumRusPerHeSigBContentChannel.second;
625 NS_ASSERT(contentChannel.size() <= totalUsersInContentChannel);
626 std::size_t unallocatedRus = totalUsersInContentChannel - contentChannel.size();
627 for (std::size_t i = 0; i < unallocatedRus; i++)
631 contentChannelIndex++;
635 return contentChannels;
639 HePpdu::GetSigBFieldSize(uint16_t channelWidth,
641 bool sigBCompression,
642 std::size_t numMuMimoUsers)
645 uint32_t commonFieldSize = 0;
646 if (!sigBCompression)
648 commonFieldSize = 4 + 6 ;
649 if (channelWidth <= 40)
651 commonFieldSize += 8;
656 8 * (channelWidth / 40) + 1 ;
660 auto numRusPerContentChannel = GetNumRusPerHeSigBContentChannel(channelWidth,
664 auto maxNumRusPerContentChannel =
665 std::max(numRusPerContentChannel.first, numRusPerContentChannel.second);
666 auto maxNumUserBlockFields = maxNumRusPerContentChannel /
668 std::size_t userSpecificFieldSize =
669 maxNumUserBlockFields * (2 * 21 + 4 + 6 );
670 if (maxNumRusPerContentChannel % 2 != 0)
672 userSpecificFieldSize += 21 + 4 + 6 ;
675 return commonFieldSize + userSpecificFieldSize;
679 HePpdu::PrintPayload()
const
681 std::ostringstream ss;
685 ss <<
", " << m_txPsdFlag;
689 ss <<
"PSDU=" << m_psdus.at(
SU_STA_ID) <<
" ";
695 HePpdu::GetChannelWidthEncodingFromMhz(uint16_t channelWidth)
697 if (channelWidth == 160)
701 else if (channelWidth == 80)
705 else if (channelWidth == 40)
716 HePpdu::GetChannelWidthMhzFromEncoding(uint8_t bandwidth)
722 else if (bandwidth == 2)
726 else if (bandwidth == 1)
737 HePpdu::GetGuardIntervalAndNltfEncoding(uint16_t gi, uint8_t nltf)
739 if (gi == 800 && nltf == 1)
743 else if (gi == 800 && nltf == 2)
747 else if (gi == 1600 && nltf == 2)
758 HePpdu::GetGuardIntervalFromEncoding(uint8_t giAndNltfSize)
760 if (giAndNltfSize == 3)
765 else if (giAndNltfSize == 2)
776 HePpdu::GetNstsEncodingFromNss(uint8_t nss)
783 HePpdu::GetNssFromNstsEncoding(uint8_t nsts)
789 HePpdu::GetMuMimoUsersEncoding(uint8_t nUsers)
796 HePpdu::GetMuMimoUsersFromEncoding(uint8_t
encoding)
static WifiMode GetHeMcs(uint8_t index)
Return the HE MCS corresponding to the provided index.
std::vector< std::vector< HeSigBUserSpecificField > > HeSigBContentChannels
HE SIG-B Content Channels.
HeSigHeader m_heSig
the HE-SIG PHY header
WifiTxVector DoGetTxVector() const override
Get the TXVECTOR used to send the PPDU.
virtual void SetTxVectorFromPhyHeaders(WifiTxVector &txVector) const
Fill in the TXVECTOR from PHY headers.
static uint16_t GetGuardIntervalFromEncoding(uint8_t giAndNltfSize)
Convert guard interval (in ns) from its encoding in HE-SIG-A.
static uint16_t GetChannelWidthMhzFromEncoding(uint8_t bandwidth)
Convert channel width expressed in MHz from bandwidth field encoding in HE-SIG-A.
TxPsdFlag
The transmit power spectral density flag, namely used to correctly build PSDs for pre-HE and HE porti...
@ PSD_HE_PORTION
HE portion of an HE PPDU.
@ PSD_NON_HE_PORTION
Non-HE portion of an HE PPDU.
virtual bool IsDlMu() const
Return true if the PPDU is a DL MU PPDU.
virtual bool IsUlMu() const
Return true if the PPDU is an UL MU PPDU.
static uint8_t GetNstsEncodingFromNss(uint8_t nss)
Convert number of spatial streams to NSTS field encoding in HE-SIG-A.
void SetHeSigHeader(const WifiTxVector &txVector)
Fill in the HE-SIG header.
static uint8_t GetNssFromNstsEncoding(uint8_t nsts)
Convert number of spatial streams from NSTS field encoding in HE-SIG-A.
void SetPhyHeaders(const WifiTxVector &txVector, Time ppduDuration)
Fill in the PHY headers.
static HeSigBContentChannels GetHeSigBContentChannels(const WifiTxVector &txVector, uint8_t p20Index)
Get the HE SIG-B content channels for a given PPDU IEEE 802.11ax-2021 27.3.11.8.2 HE-SIG-B content ch...
void SetHeMuUserInfos(WifiTxVector &txVector, const RuAllocation &ruAllocation, const HeSigBContentChannels &contentChannels, bool sigBCompression, uint8_t numMuMimoUsers) const
Reconstruct HeMuUserInfoMap from HE-SIG-B header.
static uint8_t GetMuMimoUsersEncoding(uint8_t nUsers)
Convert number of MU-MIMO users to its encoding in HE-SIG-A.
virtual bool IsMu() const
Return true if the PPDU is a MU PPDU.
static uint8_t GetGuardIntervalAndNltfEncoding(uint16_t gi, uint8_t nltf)
Convert guard interval (in ns) and NLTF to its encoding in HE-SIG-A.
void SetLSigHeader(Time ppduDuration)
Fill in the L-SIG header.
HePpdu(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector, const WifiPhyOperatingChannel &channel, Time ppduDuration, uint64_t uid)
Create an SU HE PPDU, storing a PSDU.
static uint8_t GetChannelWidthEncodingFromMhz(uint16_t channelWidth)
Convert channel width expressed in MHz to bandwidth field encoding in HE-SIG-A.
static uint8_t GetMuMimoUsersFromEncoding(uint8_t encoding)
Convert number of MU-MIMO users from its encoding in HE-SIG-A.
static std::vector< RuSpec > GetRuSpecs(uint8_t ruAllocation)
Get the RU specs based on RU_ALLOCATION.
static uint16_t GetBandwidth(RuType ruType)
Get the approximate bandwidth occupied by a RU.
static std::vector< HeRu::RuSpec > GetRusOfType(uint16_t bw, HeRu::RuType ruType)
Get the set of distinct RUs of the given type (number of tones) available in a HE PPDU of the given b...
LSigHeader m_lSig
the L-SIG PHY header
Simulation virtual time values and global simulation resolution.
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
static WifiMode GetVhtMcs(uint8_t index)
Return the VHT MCS corresponding to the provided index.
uint8_t GetMcsValue() const
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.
uint8_t GetPrimaryChannelIndex(uint16_t primaryChannelWidth) const
If the operating channel width is a multiple of 20 MHz, return the index of the primary channel of th...
WifiPhyBand GetPhyBand() const
Return the PHY band of the operating channel.
const WifiPhyOperatingChannel & m_operatingChannel
the operating channel of the PHY
WifiPreamble m_preamble
the PHY preamble
WifiConstPsduMap m_psdus
the PSDUs contained in this PPDU
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetCenter26ToneRuIndication(Center26ToneRuIndication center26ToneRuIndication)
Set CENTER_26_TONE_RU field.
void SetRuAllocation(const RuAllocation &ruAlloc, uint8_t p20Index)
Set RU_ALLOCATION field.
UserInfoMapOrderedByRus GetUserInfoMapOrderedByRus(uint8_t p20Index) const
Get the map of specific user info parameters ordered per increasing frequency RUs.
uint16_t GetGuardInterval() const
bool IsSigBCompression() const
Indicate whether the Common field is present in the HE-SIG-B field.
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
uint8_t GetBssColor() const
Get the BSS color.
const RuAllocation & GetRuAllocation(uint8_t p20Index) const
Get RU_ALLOCATION field.
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
std::optional< Center26ToneRuIndication > GetCenter26ToneRuIndication() const
Get CENTER_26_TONE_RU field This field is present if format is HE_MU and when channel width is set to...
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
RuAllocation m_ruAllocation
RU allocations that are going to be carried in SIG-B common field per Table 27-1 IEEE.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
HeMuUserInfo GetHeMuUserInfo(uint16_t staId) const
Get the HE MU user-specific transmission information for the given STA-ID.
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
uint8_t GetNss(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the number of spatial streams.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
void SetBssColor(uint8_t color)
Set the BSS color.
bool IsAllocated(uint16_t staId) const
Check if STA ID is allocated.
uint16_t GetChannelWidth() const
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
WifiMode GetSigBMode() const
Get MCS used for SIG-B.
void SetNss(uint8_t nss)
Sets the number of Nss.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Time Seconds(double value)
Construct a Time in the indicated unit.
WifiPpduType
The type of PPDU (SU, DL MU, or UL MU)
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
Declaration of ns3::HePpdu class.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
bool IsMu(WifiPreamble preamble)
Return true if a preamble corresponds to a multi-user transmission.
static constexpr uint16_t NO_USER_STA_ID
STA_ID for a RU that is intended for no user (Section 26.11.1 802.11ax-2021)
std::vector< uint8_t > RuAllocation
8 bit RU_ALLOCATION per 20 MHz
bool IsDlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a downlink multi-user transmission.
std::ostream & operator<<(std::ostream &os, const Angles &a)
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
bool IsUlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a uplink multi-user transmission.
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.