diff --git a/src/wifi/model/eht/eht-ppdu.cc b/src/wifi/model/eht/eht-ppdu.cc index 1bd8dec09..fe5bbc998 100644 --- a/src/wifi/model/eht/eht-ppdu.cc +++ b/src/wifi/model/eht/eht-ppdu.cc @@ -13,8 +13,10 @@ #include "ns3/log.h" #include "ns3/wifi-phy-operating-channel.h" #include "ns3/wifi-psdu.h" +#include "ns3/wifi-utils.h" #include +#include #include namespace ns3 @@ -187,6 +189,7 @@ EhtPpdu::SetTxVectorFromPhyHeaders(WifiTxVector& txVector) const [](uint8_t prev, const auto& cc) { return prev + cc.size(); }) : 0; SetHeMuUserInfos(txVector, + WIFI_MOD_CLASS_EHT, ruAllocation.value(), std::nullopt, ehtPhyHeader->m_contentChannels, @@ -203,7 +206,7 @@ EhtPpdu::SetTxVectorFromPhyHeaders(WifiTxVector& txVector) const } else { - const auto fullBwRu{HeRu::RuSpec(WifiRu::GetRuType(bw), 1, true)}; + const auto fullBwRu{EhtRu::RuSpec(WifiRu::GetRuType(bw), 1, true, true)}; txVector.SetHeMuUserInfo(ehtPhyHeader->m_contentChannels.front().front().staId, {fullBwRu, ehtPhyHeader->m_contentChannels.front().front().mcs, @@ -232,6 +235,7 @@ EhtPpdu::GetNumRusPerEhtSigBContentChannel(MHz_u channelWidth, return {1, 0}; } return HePpdu::GetNumRusPerHeSigBContentChannel(channelWidth, + WIFI_MOD_CLASS_EHT, ruAllocation, std::nullopt, compression, @@ -388,6 +392,26 @@ EhtPpdu::GetPsdu(uint8_t bssColor, uint16_t staId /* = SU_STA_ID */) const return nullptr; } +WifiRu::RuSpec +EhtPpdu::GetRuSpec(std::size_t ruAllocIndex, MHz_u bw, RuType ruType, std::size_t phyIndex) const +{ + if (ruType == RuType::RU_26_TONE) + { + for (const auto undefinedRu : std::initializer_list{19, 56, 93, 130}) + { + if (phyIndex >= undefinedRu) + { + ++phyIndex; + } + } + } + const auto p20Index = m_operatingChannel.GetPrimaryChannelIndex(MHz_u{20}); + const auto& [primary160, primary80OrLow80] = + EhtRu::GetPrimaryFlags(bw, ruType, phyIndex, p20Index); + const auto index = EhtRu::GetIndexIn80MHzSegment(bw, ruType, phyIndex); + return EhtRu::RuSpec{ruType, index, primary160, primary80OrLow80}; +} + Ptr EhtPpdu::Copy() const { diff --git a/src/wifi/model/eht/eht-ppdu.h b/src/wifi/model/eht/eht-ppdu.h index 402f42bd5..9def61a16 100644 --- a/src/wifi/model/eht/eht-ppdu.h +++ b/src/wifi/model/eht/eht-ppdu.h @@ -151,6 +151,12 @@ class EhtPpdu : public HePpdu uint8_t ehtPpduType, std::optional isLow80MHz); + protected: + WifiRu::RuSpec GetRuSpec(std::size_t ruAllocIndex, + MHz_u bw, + RuType ruType, + std::size_t phyIndex) const override; + private: bool IsDlMu() const override; bool IsUlMu() const override; diff --git a/src/wifi/model/he/he-phy.cc b/src/wifi/model/he/he-phy.cc index 1212a72be..c2ad01ec5 100644 --- a/src/wifi/model/he/he-phy.cc +++ b/src/wifi/model/he/he-phy.cc @@ -216,6 +216,7 @@ HePhy::GetSigBSize(const WifiTxVector& txVector) const NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE); return HePpdu::GetSigBFieldSize( txVector.GetChannelWidth(), + txVector.GetModulationClass(), txVector.GetRuAllocation( m_wifiPhy ? m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20}) : 0), txVector.GetCenter26ToneRuIndication(), @@ -983,22 +984,24 @@ HePhy::GetRuBandForTx(const WifiTxVector& txVector, uint16_t staId) const auto ru = txVector.GetRu(staId); const auto channelWidth = txVector.GetChannelWidth(); NS_ASSERT(channelWidth <= m_wifiPhy->GetChannelWidth()); + const auto mc = txVector.GetModulationClass(); const auto group = WifiRu::GetSubcarrierGroup( channelWidth, WifiRu::GetRuType(ru), WifiRu::GetPhyIndex(ru, channelWidth, m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20})), - WIFI_MOD_CLASS_HE); + mc); // for a TX spectrum, the guard bandwidth is a function of the transmission channel width // and the spectrum width equals the transmission channel width (hence bandIndex equals 0) - const auto indices = ConvertRuSubcarriers(channelWidth, - GetGuardBandwidth(channelWidth), - m_wifiPhy->GetOperatingChannel().GetFrequencies(), - m_wifiPhy->GetChannelWidth(), - m_wifiPhy->GetSubcarrierSpacing(), - {group.front().first, group.back().second}, - 0); + const auto indices = ConvertRuSubcarriers({channelWidth, + GetGuardBandwidth(channelWidth), + m_wifiPhy->GetOperatingChannel().GetFrequencies(), + m_wifiPhy->GetChannelWidth(), + m_wifiPhy->GetSubcarrierSpacing(), + mc, + {group.front().first, group.back().second}, + 0}); WifiSpectrumBandInfo ruBandForTx{}; for (const auto& indicesPerSegment : indices) { @@ -1016,23 +1019,25 @@ HePhy::GetRuBandForRx(const WifiTxVector& txVector, uint16_t staId) const auto ru = txVector.GetRu(staId); const auto channelWidth = txVector.GetChannelWidth(); NS_ASSERT(channelWidth <= m_wifiPhy->GetChannelWidth()); + const auto mc = txVector.GetModulationClass(); const auto group = WifiRu::GetSubcarrierGroup( channelWidth, WifiRu::GetRuType(ru), WifiRu::GetPhyIndex(ru, channelWidth, m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20})), - WIFI_MOD_CLASS_HE); + mc); // for an RX spectrum, the guard bandwidth is a function of the operating channel width // and the spectrum width equals the operating channel width - const auto indices = - ConvertRuSubcarriers(channelWidth, - GetGuardBandwidth(m_wifiPhy->GetChannelWidth()), - m_wifiPhy->GetOperatingChannel().GetFrequencies(), - m_wifiPhy->GetChannelWidth(), - m_wifiPhy->GetSubcarrierSpacing(), - {group.front().first, group.back().second}, - m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(channelWidth)); + const auto indices = ConvertRuSubcarriers( + {channelWidth, + GetGuardBandwidth(m_wifiPhy->GetChannelWidth()), + m_wifiPhy->GetOperatingChannel().GetFrequencies(), + m_wifiPhy->GetChannelWidth(), + m_wifiPhy->GetSubcarrierSpacing(), + mc, + {group.front().first, group.back().second}, + m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(channelWidth)}); WifiSpectrumBandInfo ruBandForRx{}; for (const auto& indicesPerSegment : indices) { @@ -1821,56 +1826,51 @@ HePhy::GetRxPpduFromTxPpdu(Ptr ppdu) } std::vector -HePhy::ConvertRuSubcarriers(MHz_u bandWidth, - MHz_u guardBandwidth, - const std::vector& centerFrequencies, - MHz_u totalWidth, - Hz_u subcarrierSpacing, - SubcarrierRange subcarrierRange, - uint8_t bandIndex) +HePhy::ConvertRuSubcarriers(const RuSubcarriersInfo& info) { - NS_ASSERT_MSG(bandWidth <= totalWidth, - "Bandwidth (" << bandWidth << ") cannot exceed total operating channel width (" - << totalWidth << ")"); + NS_ASSERT_MSG(info.bandWidth <= info.totalWidth, + "Bandwidth (" << info.bandWidth + << ") cannot exceed total operating channel width (" + << info.totalWidth << ")"); std::vector convertedSubcarriers{}; - guardBandwidth /= centerFrequencies.size(); + const auto guardBandwidth{info.guardBandwidth / info.centerFrequencies.size()}; const auto nGuardBands = - static_cast(((2 * MHzToHz(guardBandwidth)) / subcarrierSpacing) + 0.5); - if (bandWidth > (totalWidth / centerFrequencies.size())) + static_cast(((2 * MHzToHz(guardBandwidth)) / info.subcarrierSpacing) + 0.5); + auto bw{info.bandWidth}; + if (bw > (info.totalWidth / info.centerFrequencies.size())) { - NS_ASSERT(bandIndex == 0); - bandWidth /= centerFrequencies.size(); + NS_ASSERT(info.bandIndex == 0); + bw /= info.centerFrequencies.size(); } // Figures 27-5 to 27-7 of IEEE 802.11ax-2021: the number of guard subcarriers is 6 for 20 MHz // MHz HE PPDUs and 12 for 40/80/160 MHz HE PPDUs - const uint32_t guardSubcarriers = (bandWidth < MHz_u{40}) ? 6 : 12; - const auto refRu = WifiRu::GetRuType(bandWidth); - const auto mc{WIFI_MOD_CLASS_HE}; - const auto offset = WifiRu::GetSubcarrierGroup(bandWidth, refRu, 1, mc).back().second; + const uint32_t guardSubcarriers = (bw < MHz_u{40}) ? 6 : 12; + const auto refRu = WifiRu::GetRuType(bw); + const auto offset = WifiRu::GetSubcarrierGroup(bw, refRu, 1, info.mc).back().second; uint32_t centerFrequencyIndex = (nGuardBands / 2) + guardSubcarriers + offset; - const auto numBandsInBand = static_cast(MHzToHz(bandWidth) / subcarrierSpacing); - centerFrequencyIndex += numBandsInBand * bandIndex; + const auto numBandsInBand = static_cast(MHzToHz(bw) / info.subcarrierSpacing); + centerFrequencyIndex += numBandsInBand * info.bandIndex; // start and stop subcarriers might be in different frequency segments, hence define a low and a // high center frequency auto centerFrequencyIndexLow = centerFrequencyIndex; auto centerFrequencyIndexHigh = centerFrequencyIndex; - if (centerFrequencies.size() > 1) + if (info.centerFrequencies.size() > 1) { const auto numBandsBetweenSegments = - SpectrumWifiPhy::GetNumBandsBetweenSegments(centerFrequencies, - totalWidth, - subcarrierSpacing); - if (subcarrierRange.first > 0) + SpectrumWifiPhy::GetNumBandsBetweenSegments(info.centerFrequencies, + info.totalWidth, + info.subcarrierSpacing); + if (info.subcarrierRange.first > 0) { centerFrequencyIndexLow += numBandsBetweenSegments; } - if (subcarrierRange.second > 0) + if (info.subcarrierRange.second > 0) { centerFrequencyIndexHigh += numBandsBetweenSegments; } } - convertedSubcarriers.emplace_back(centerFrequencyIndexLow + subcarrierRange.first, - centerFrequencyIndexHigh + subcarrierRange.second); + convertedSubcarriers.emplace_back(centerFrequencyIndexLow + info.subcarrierRange.first, + centerFrequencyIndexHigh + info.subcarrierRange.second); return convertedSubcarriers; } diff --git a/src/wifi/model/he/he-phy.h b/src/wifi/model/he/he-phy.h index bc7a09f69..92b6bcbf1 100644 --- a/src/wifi/model/he/he-phy.h +++ b/src/wifi/model/he/he-phy.h @@ -427,29 +427,30 @@ class HePhy : public VhtPhy */ static Time GetSymbolDuration(Time guardInterval); + /// structure containing the information about the RU subcarriers to be able to converted to the + /// indices used by the Spectrum model + struct RuSubcarriersInfo + { + MHz_u bandWidth; ///< width of the band used for the OFDMA transmission. Must be a multiple + ///< of 20 MHz + MHz_u guardBandwidth; ///< width of the guard band + const std::vector& centerFrequencies; ///< center frequency of each segment + MHz_u totalWidth; ///< width of the operating channel + Hz_u subcarrierSpacing; ///< subcarrier spacing + WifiModulationClass mc; ///< modulation class used for the transmission + SubcarrierRange subcarrierRange; ///< subcarrier range of the RU + uint8_t bandIndex{0}; ///< index (starting at 0) of the band within the operating channel + }; + /** - * @param bandWidth the width of the band used for the OFDMA transmission. Must be a multiple of - * 20 MHz - * @param guardBandwidth width of the guard band - * @param centerFrequencies the center frequency of each segment - * @param totalWidth the width of the operating channel - * @param subcarrierSpacing the subcarrier spacing - * @param subcarrierRange the subcarrier range of the RU - * @param bandIndex the index (starting at 0) of the band within the operating channel - * @return the converted subcarriers - * * This is a helper function to convert RU subcarriers, which are relative to the center - * frequency subcarrier, to the indexes used by the Spectrum model. The size of the returned + * frequency subcarrier, to the indices used by the Spectrum model. The size of the returned * vector corresponds to the number of segments covered by the RU. + * + * @param info the information about the RU subcarrier to convert + * @return the indices used by the Spectrum model for the provided RU subcarrier */ - static std::vector ConvertRuSubcarriers( - MHz_u bandWidth, - MHz_u guardBandwidth, - const std::vector& centerFrequencies, - MHz_u totalWidth, - Hz_u subcarrierSpacing, - SubcarrierRange subcarrierRange, - uint8_t bandIndex = 0); + static std::vector ConvertRuSubcarriers(const RuSubcarriersInfo& info); protected: PhyFieldRxStatus ProcessSig(Ptr event, diff --git a/src/wifi/model/he/he-ppdu.cc b/src/wifi/model/he/he-ppdu.cc index 828de17a2..14b0a582b 100644 --- a/src/wifi/model/he/he-ppdu.cc +++ b/src/wifi/model/he/he-ppdu.cc @@ -202,6 +202,7 @@ HePpdu::SetTxVectorFromPhyHeaders(WifiTxVector& txVector) const txVector.SetGuardInterval(GetGuardIntervalFromEncoding(heSigHeader->m_giLtfSize)); txVector.SetBssColor(heSigHeader->m_bssColor); SetHeMuUserInfos(txVector, + WIFI_MOD_CLASS_HE, heSigHeader->m_ruAllocation, heSigHeader->m_center26ToneRuIndication, heSigHeader->m_contentChannels, @@ -248,6 +249,7 @@ HePpdu::GetRuSpec(std::size_t ruAllocIndex, MHz_u bw, RuType ruType, std::size_t void HePpdu::SetHeMuUserInfos(WifiTxVector& txVector, + WifiModulationClass mc, const RuAllocation& ruAllocation, std::optional center26ToneRuIndication, const HeSigBContentChannels& contentChannels, @@ -304,7 +306,6 @@ HePpdu::SetHeMuUserInfos(WifiTxVector& txVector, } } NS_ASSERT(ruAllocIndex < ruAllocation.size()); - const auto mc{WIFI_MOD_CLASS_HE}; auto ruSpecs = WifiRu::GetRuSpecs(ruAllocation.at(ruAllocIndex), mc); while (ruSpecs.empty() && (ruAllocIndex < ruAllocation.size())) { @@ -550,6 +551,7 @@ HePpdu::UpdateTxVectorForUlMu(const std::optional& trigVector) con std::pair HePpdu::GetNumRusPerHeSigBContentChannel( MHz_u channelWidth, + WifiModulationClass mc, const RuAllocation& ruAllocation, std::optional center26ToneRuIndication, bool sigBCompression, @@ -581,7 +583,6 @@ HePpdu::GetNumRusPerHeSigBContentChannel( NS_ASSERT_MSG(ruAllocation.size() == Count20MHzSubchannels(channelWidth), "RU allocation is not consistent with packet bandwidth"); - const auto mc{WIFI_MOD_CLASS_HE}; switch (static_cast(channelWidth)) { case 40: @@ -717,7 +718,7 @@ HePpdu::GetHeSigBContentChannels(const WifiTxVector& txVector, uint8_t p20Index) continue; } - const auto mc{WIFI_MOD_CLASS_HE}; + const auto mc = txVector.GetModulationClass(); const auto numRus = WifiRu::GetNRus(MHz_u{20}, ruType, mc); while (prevRuIndex < ruIndex - 1) { @@ -775,6 +776,11 @@ HePpdu::GetHeSigBContentChannels(const WifiTxVector& txVector, uint8_t p20Index) { // "ignore" the center 26-tone RUs in 80 MHz channels ruIdx--; + if (ruIdx > 37) + { + NS_ASSERT(!WifiRu::IsHe(ru)); + ruIdx -= (ruIdx - 19) / 37; + } } ccIndex = (((ruIdx - 1) / numRus) % 2 == 0) ? 0 : 1; } @@ -798,6 +804,7 @@ HePpdu::GetHeSigBContentChannels(const WifiTxVector& txVector, uint8_t p20Index) // Add unassigned RUs auto numNumRusPerHeSigBContentChannel = GetNumRusPerHeSigBContentChannel( channelWidth, + txVector.GetModulationClass(), txVector.GetRuAllocation(p20Index), txVector.GetCenter26ToneRuIndication(), isSigBCompression, @@ -823,6 +830,7 @@ HePpdu::GetHeSigBContentChannels(const WifiTxVector& txVector, uint8_t p20Index) uint32_t HePpdu::GetSigBFieldSize(MHz_u channelWidth, + WifiModulationClass mc, const RuAllocation& ruAllocation, std::optional center26ToneRuIndication, bool sigBCompression, @@ -846,6 +854,7 @@ HePpdu::GetSigBFieldSize(MHz_u channelWidth, } auto numRusPerContentChannel = GetNumRusPerHeSigBContentChannel(channelWidth, + mc, ruAllocation, center26ToneRuIndication, sigBCompression, diff --git a/src/wifi/model/he/he-ppdu.h b/src/wifi/model/he/he-ppdu.h index eb0dc729e..f2c1213a8 100644 --- a/src/wifi/model/he/he-ppdu.h +++ b/src/wifi/model/he/he-ppdu.h @@ -189,6 +189,7 @@ class HePpdu : public OfdmPpdu * See section 27.3.10.8.3 of IEEE 802.11ax draft 4.0. * * @param channelWidth the channel width occupied by the PPDU + * @param mc the modulation class used for the transmission of the PPDU * @param ruAllocation 8 bit RU_ALLOCATION per 20 MHz * @param center26ToneRuIndication the center 26 tone RU indication * @param sigBCompression flag whether SIG-B compression is used by the PPDU @@ -197,6 +198,7 @@ class HePpdu : public OfdmPpdu */ static std::pair GetNumRusPerHeSigBContentChannel( MHz_u channelWidth, + WifiModulationClass mc, const RuAllocation& ruAllocation, std::optional center26ToneRuIndication, bool sigBCompression, @@ -216,6 +218,7 @@ class HePpdu : public OfdmPpdu /** * Get variable length HE SIG-B field size * @param channelWidth the channel width occupied by the PPDU + * @param mc the modulation class used for the transmission of the PPDU * @param ruAllocation 8 bit RU_ALLOCATION per 20 MHz * @param center26ToneRuIndication the center 26 tone RU indication * @param sigBCompression flag whether SIG-B compression is used by the PPDU @@ -224,6 +227,7 @@ class HePpdu : public OfdmPpdu */ static uint32_t GetSigBFieldSize( MHz_u channelWidth, + WifiModulationClass mc, const RuAllocation& ruAllocation, std::optional center26ToneRuIndication, bool sigBCompression, @@ -248,6 +252,7 @@ class HePpdu : public OfdmPpdu * Reconstruct HeMuUserInfoMap from HE-SIG-B header. * * @param txVector the TXVECTOR to set its HeMuUserInfoMap + * @param mc the modulation class used for the transmission of the PPDU * @param ruAllocation the RU_ALLOCATION per 20 MHz * @param center26ToneRuIndication the center 26 tone RU indication * @param contentChannels the HE-SIG-B content channels @@ -255,6 +260,7 @@ class HePpdu : public OfdmPpdu * @param numMuMimoUsers the number of MU-MIMO users addressed by the PPDU */ void SetHeMuUserInfos(WifiTxVector& txVector, + WifiModulationClass mc, const RuAllocation& ruAllocation, std::optional center26ToneRuIndication, const HeSigBContentChannels& contentChannels, diff --git a/src/wifi/model/he/rr-multi-user-scheduler.cc b/src/wifi/model/he/rr-multi-user-scheduler.cc index f965def99..e8fbbc75c 100644 --- a/src/wifi/model/he/rr-multi-user-scheduler.cc +++ b/src/wifi/model/he/rr-multi-user-scheduler.cc @@ -174,13 +174,32 @@ RrMultiUserScheduler::GetTxVectorForUlMu(std::function { NS_LOG_FUNCTION(this); + auto heConfiguration = m_apMac->GetHeConfiguration(); + NS_ASSERT(heConfiguration); + + WifiTxVector txVector; + txVector.SetChannelWidth(m_allowedWidth); + txVector.SetGuardInterval(heConfiguration->GetGuardInterval()); + txVector.SetBssColor(heConfiguration->m_bssColor); + txVector.SetPreambleType(WIFI_PREAMBLE_HE_TB); + + const auto firstCandidate = + std::find_if(m_staListUl.begin(), m_staListUl.end(), canBeSolicited); + if (firstCandidate == m_staListUl.cend()) + { + NS_LOG_DEBUG("No candidate"); + return txVector; + } + // determine RUs to allocate to stations + const auto isEht = + (m_apMac->GetEhtSupported() && m_apMac->GetEhtSupported(firstCandidate->address)); auto count = std::min(m_nStations, m_staListUl.size()); std::size_t nCentral26TonesRus; WifiRu::GetEqualSizedRusForStations(m_allowedWidth, count, nCentral26TonesRus, - WIFI_MOD_CLASS_HE); + isEht ? WIFI_MOD_CLASS_EHT : WIFI_MOD_CLASS_HE); NS_ASSERT(count >= 1); if (!m_useCentral26TonesRus) @@ -188,17 +207,15 @@ RrMultiUserScheduler::GetTxVectorForUlMu(std::function nCentral26TonesRus = 0; } - Ptr heConfiguration = m_apMac->GetHeConfiguration(); - NS_ASSERT(heConfiguration); - - WifiTxVector txVector; - txVector.SetPreambleType(WIFI_PREAMBLE_HE_TB); - txVector.SetChannelWidth(m_allowedWidth); - txVector.SetGuardInterval(heConfiguration->GetGuardInterval()); - txVector.SetBssColor(heConfiguration->m_bssColor); + if (isEht) + { + txVector.SetPreambleType(WIFI_PREAMBLE_EHT_TB); + txVector.SetEhtPpduType(0); + } + // TODO otherwise make sure the TX width does not exceed 160 MHz // iterate over the associated stations until an enough number of stations is identified - auto staIt = m_staListUl.begin(); + auto staIt = firstCandidate; m_candidates.clear(); while (staIt != m_staListUl.end() && @@ -207,51 +224,15 @@ RrMultiUserScheduler::GetTxVectorForUlMu(std::function { NS_LOG_DEBUG("Next candidate STA (MAC=" << staIt->address << ", AID=" << staIt->aid << ")"); - if (!canBeSolicited(*staIt)) - { - NS_LOG_DEBUG("Skipping station based on provided function object"); - staIt++; - continue; - } - if (txVector.GetPreambleType() == WIFI_PREAMBLE_EHT_TB && !m_apMac->GetEhtSupported(staIt->address)) { NS_LOG_DEBUG( "Skipping non-EHT STA because this Trigger Frame is only soliciting EHT STAs"); - staIt++; + staIt = std::find_if(++staIt, m_staListUl.end(), canBeSolicited); continue; } - uint8_t tid = 0; - while (tid < 8) - { - // check that a BA agreement is established with the receiver for the - // considered TID, since ack sequences for UL MU require block ack - if (m_apMac->GetBaAgreementEstablishedAsRecipient(staIt->address, tid)) - { - break; - } - ++tid; - } - if (tid == 8) - { - NS_LOG_DEBUG("No Block Ack agreement established with " << staIt->address); - staIt++; - continue; - } - - // if the first candidate STA is an EHT STA, we switch to soliciting EHT TB PPDUs - if (txVector.GetHeMuUserInfoMap().empty()) - { - if (m_apMac->GetEhtSupported() && m_apMac->GetEhtSupported(staIt->address)) - { - txVector.SetPreambleType(WIFI_PREAMBLE_EHT_TB); - txVector.SetEhtPpduType(0); - } - // TODO otherwise, make sure the TX width does not exceed 160 MHz - } - // prepare the MAC header of a frame that would be sent to the candidate station, // just for the purpose of retrieving the TXVECTOR used to transmit to that station WifiMacHeader hdr(WIFI_MAC_QOSDATA); @@ -267,8 +248,8 @@ RrMultiUserScheduler::GetTxVectorForUlMu(std::function suTxVector.GetNss()}); m_candidates.emplace_back(staIt, nullptr); - // move to the next station in the list - staIt++; + // move to the next candidate station in the list + staIt = std::find_if(++staIt, m_staListUl.end(), canBeSolicited); } if (txVector.GetHeMuUserInfoMap().empty()) @@ -287,7 +268,26 @@ RrMultiUserScheduler::CanSolicitStaInBsrpTf(const MasterInfo& info) const // check if station has setup the current link if (!m_apMac->GetStaList(m_linkId).contains(info.aid)) { - NS_LOG_INFO("STA with AID " << info.aid << " has not setup link " << +m_linkId); + NS_LOG_INFO("STA with AID " << info.aid << " has not setup link " << +m_linkId + << ": skipping station"); + return false; + } + + uint8_t tid = 0; + while (tid < 8) + { + // check that a BA agreement is established with the receiver for the + // considered TID, since ack sequences for UL MU require block ack + if (m_apMac->GetBaAgreementEstablishedAsRecipient(info.address, tid)) + { + break; + } + ++tid; + } + if (tid == 8) + { + NS_LOG_DEBUG("No Block Ack agreement established with " << info.address + << ": skipping station"); return false; } @@ -312,7 +312,8 @@ RrMultiUserScheduler::CanSolicitStaInBsrpTf(const MasterInfo& info) const if (!mapped) { - NS_LOG_DEBUG("MLD " << *mldAddr << " has not mapped any TID on link " << +m_linkId); + NS_LOG_DEBUG("MLD " << *mldAddr << " has not mapped any TID on link " << +m_linkId + << ": skipping station"); return false; } @@ -327,7 +328,7 @@ RrMultiUserScheduler::CanSolicitStaInBsrpTf(const MasterInfo& info) const m_linkId, WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY))) { - NS_LOG_INFO("EMLSR client " << *mldAddr << " is using another link"); + NS_LOG_INFO("EMLSR client " << *mldAddr << " is using another link: skipping station"); return false; } @@ -752,17 +753,7 @@ RrMultiUserScheduler::TrySendingDlMuPpdu() std::size_t count = std::min(static_cast(m_nStations), m_staListDl[primaryAc].size()); - std::size_t nCentral26TonesRus; - const auto ruType = WifiRu::GetEqualSizedRusForStations(m_allowedWidth, - count, - nCentral26TonesRus, - WIFI_MOD_CLASS_HE); - NS_ASSERT(count >= 1); - - if (!m_useCentral26TonesRus) - { - nCentral26TonesRus = 0; - } + std::size_t nCentral26TonesRus{0}; uint8_t currTid = wifiAcList.at(primaryAc).GetHighTid(); @@ -814,6 +805,7 @@ RrMultiUserScheduler::TrySendingDlMuPpdu() ruAllocations.resize(numRuAllocs); NS_ASSERT((m_candidates.size() % numRuAllocs) == 0); + RuType ruType{RuType::RU_TYPE_MAX}; while (staIt != m_staListDl[primaryAc].end() && m_candidates.size() < std::min(static_cast(m_nStations), count + nCentral26TonesRus)) @@ -828,8 +820,6 @@ RrMultiUserScheduler::TrySendingDlMuPpdu() continue; } - RuType currRuType = (m_candidates.size() < count ? ruType : RuType::RU_26_TONE); - // check if the AP has at least one frame to be sent to the current station for (uint8_t tid : tids) { @@ -857,17 +847,37 @@ RrMultiUserScheduler::TrySendingDlMuPpdu() WifiTxVector txVectorCopy = m_txParams.m_txVector; // the first candidate STA determines the preamble type for the DL MU PPDU - if (m_candidates.empty() && - suTxVector.GetPreambleType() == WIFI_PREAMBLE_EHT_MU) + if (m_candidates.empty()) { - m_txParams.m_txVector.SetPreambleType(WIFI_PREAMBLE_EHT_MU); - m_txParams.m_txVector.SetEhtPpduType(0); // indicates DL OFDMA transmission + WifiModulationClass mc = WIFI_MOD_CLASS_HE; + if (suTxVector.GetPreambleType() == WIFI_PREAMBLE_EHT_MU) + { + m_txParams.m_txVector.SetPreambleType(WIFI_PREAMBLE_EHT_MU); + m_txParams.m_txVector.SetEhtPpduType( + 0); // indicates DL OFDMA transmission + mc = WIFI_MOD_CLASS_EHT; + } + ruType = WifiRu::GetEqualSizedRusForStations(m_allowedWidth, + count, + nCentral26TonesRus, + mc); + NS_ASSERT(count >= 1); + if (!m_useCentral26TonesRus) + { + nCentral26TonesRus = 0; + } } - m_txParams.m_txVector.SetHeMuUserInfo(staIt->aid, - {HeRu::RuSpec{currRuType, 1, true}, - suTxVector.GetMode().GetMcsValue(), - suTxVector.GetNss()}); + NS_ASSERT(ruType != RuType::RU_TYPE_MAX); + const auto currRuType = + (m_candidates.size() < count ? ruType : RuType::RU_26_TONE); + const auto ru = + (m_txParams.m_txVector.GetPreambleType() == WIFI_PREAMBLE_EHT_MU) + ? WifiRu::RuSpec(EhtRu::RuSpec{currRuType, 1, true, true}) + : WifiRu::RuSpec(HeRu::RuSpec{currRuType, 1, true}); + m_txParams.m_txVector.SetHeMuUserInfo( + staIt->aid, + {ru, suTxVector.GetMode().GetMcsValue(), suTxVector.GetNss()}); if (!GetHeFem(m_linkId)->TryAddMpdu(mpdu, m_txParams, actualAvailableTime)) { @@ -923,7 +933,7 @@ RrMultiUserScheduler::FinalizeTxVector(WifiTxVector& txVector) const auto ruType = WifiRu::GetEqualSizedRusForStations(m_allowedWidth, nRusAssigned, nCentral26TonesRus, - WIFI_MOD_CLASS_HE); + txVector.GetModulationClass()); NS_LOG_DEBUG(nRusAssigned << " stations are being assigned a " << ruType << " RU"); @@ -941,11 +951,11 @@ RrMultiUserScheduler::FinalizeTxVector(WifiTxVector& txVector) WifiTxVector::HeMuUserInfoMap heMuUserInfoMap; std::swap(heMuUserInfoMap, txVector.GetHeMuUserInfoMap()); + const auto mc = IsEht(txVector.GetPreambleType()) ? WIFI_MOD_CLASS_EHT : WIFI_MOD_CLASS_HE; auto candidateIt = m_candidates.begin(); // iterator over the list of candidate receivers - auto ruSet = WifiRu::GetRusOfType(m_allowedWidth, ruType, WIFI_MOD_CLASS_HE); + auto ruSet = WifiRu::GetRusOfType(m_allowedWidth, ruType, mc); auto ruSetIt = ruSet.begin(); - auto central26TonesRus = - WifiRu::GetCentral26TonesRus(m_allowedWidth, ruType, WIFI_MOD_CLASS_HE); + auto central26TonesRus = WifiRu::GetCentral26TonesRus(m_allowedWidth, ruType, mc); auto central26TonesRusIt = central26TonesRus.begin(); for (std::size_t i = 0; i < nRusAssigned + nCentral26TonesRus; i++) diff --git a/src/wifi/model/spectrum-wifi-phy.cc b/src/wifi/model/spectrum-wifi-phy.cc index 4fc531444..b65350eb5 100644 --- a/src/wifi/model/spectrum-wifi-phy.cc +++ b/src/wifi/model/spectrum-wifi-phy.cc @@ -148,45 +148,75 @@ SpectrumWifiPhy::GetRuBands(Ptr spectrumPhyInterface, RuBands ruBands{}; const auto channelWidth = spectrumPhyInterface->GetChannelWidth(); const auto p20Index = GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20}); - for (auto bw = channelWidth; bw >= MHz_u{20}; bw = bw / 2) + std::vector modClasses{WIFI_MOD_CLASS_HE}; + if (GetStandard() >= WIFI_STANDARD_80211be) { - for (uint32_t i = 0; i < (channelWidth / bw); ++i) + modClasses.push_back(WIFI_MOD_CLASS_EHT); + } + for (const auto modClass : modClasses) + { + for (MHz_u bw = channelWidth; bw >= MHz_u{20}; bw = bw / 2) { - for (uint32_t type = 0; - type <= static_cast(WifiRu::GetMaxRuType(WIFI_MOD_CLASS_HE)); - ++type) + if (bw > GetMaximumChannelWidth(modClass)) { - auto ruType = static_cast(type); - std::size_t nRus = WifiRu::GetNRus(bw, ruType, WIFI_MOD_CLASS_HE); - for (std::size_t phyIndex = 1; phyIndex <= nRus; phyIndex++) + continue; + } + for (uint8_t i = 0; i < (channelWidth / bw); ++i) + { + for (uint32_t type = 0; + type <= static_cast(WifiRu::GetMaxRuType(modClass)); + ++type) { - const auto group = - WifiRu::GetSubcarrierGroup(bw, ruType, phyIndex, WIFI_MOD_CLASS_HE); - SubcarrierRange subcarrierRange = - std::make_pair(group.front().first, group.back().second); - const auto bandIndices = - HePhy::ConvertRuSubcarriers(bw, - guardBandwidth, - spectrumPhyInterface->GetCenterFrequencies(), - spectrumPhyInterface->GetChannelWidth(), - GetSubcarrierSpacing(), - subcarrierRange, - i); - - WifiSpectrumBandInfo band{}; - for (const auto& indicesPerSegment : bandIndices) + const auto ruType = static_cast(type); + const auto nRus = WifiRu::GetNRus(bw, ruType, modClass); + std::size_t undefRus{0}; + for (std::size_t phyIndex = 1; phyIndex <= nRus + undefRus; ++phyIndex) { - band.indices.emplace_back(indicesPerSegment); - band.frequencies.emplace_back( - ConvertIndicesToFrequenciesForInterface(spectrumPhyInterface, - indicesPerSegment)); + const auto group = + WifiRu::GetSubcarrierGroup(bw, ruType, phyIndex, modClass); + if (group.empty()) + { + ++undefRus; + continue; + } + const auto subcarrierRange = + std::make_pair(group.front().first, group.back().second); + const auto bandIndices = HePhy::ConvertRuSubcarriers( + {bw, + guardBandwidth, + spectrumPhyInterface->GetCenterFrequencies(), + spectrumPhyInterface->GetChannelWidth(), + GetSubcarrierSpacing(), + modClass, + subcarrierRange, + i}); + + WifiSpectrumBandInfo band{}; + for (const auto& indicesPerSegment : bandIndices) + { + band.indices.emplace_back(indicesPerSegment); + band.frequencies.emplace_back( + ConvertIndicesToFrequenciesForInterface(spectrumPhyInterface, + indicesPerSegment)); + } + WifiRu::RuSpec ru; + if (modClass == WIFI_MOD_CLASS_HE) + { + const auto index = HeRu::GetIndexIn80MHzSegment(bw, ruType, phyIndex); + const auto primary80 = + HeRu::GetPrimary80MHzFlag(bw, ruType, phyIndex, p20Index); + ru = HeRu::RuSpec{ruType, index, primary80}; + } + else + { + const auto index = EhtRu::GetIndexIn80MHzSegment(bw, ruType, phyIndex); + const auto& [primary160, primary80OrLow80] = + EhtRu::GetPrimaryFlags(bw, ruType, phyIndex, p20Index); + ru = EhtRu::RuSpec{ruType, index, primary160, primary80OrLow80}; + } + NS_ABORT_IF(WifiRu::GetPhyIndex(ru, bw, p20Index) != phyIndex); + ruBands.insert({band, ru}); } - const auto index = HeRu::GetIndexIn80MHzSegment(bw, ruType, phyIndex); - const auto primary80 = - HeRu::GetPrimary80MHzFlag(bw, ruType, phyIndex, p20Index); - const auto ru = HeRu::RuSpec{ruType, index, primary80}; - NS_ABORT_IF(WifiRu::GetPhyIndex(ru, bw, p20Index) != phyIndex); - ruBands.insert({band, ru}); } } } diff --git a/src/wifi/model/wifi-constants.h b/src/wifi/model/wifi-constants.h index a8b84ebbd..71cccbe26 100644 --- a/src/wifi/model/wifi-constants.h +++ b/src/wifi/model/wifi-constants.h @@ -116,6 +116,9 @@ static constexpr uint16_t MAX_AID{2007}; /// STA_ID for a RU that is intended for no user (Section 26.11.1 802.11ax-2021) static constexpr uint16_t NO_USER_STA_ID{2046}; +/// Unassigned 242-tone RU identifier for EHT (Table Table 36-34 IEEE 802.11be D7.0) +static constexpr uint8_t UNASSIGNED_242_TONE_EHT_RU{27}; + /// The maximum value for the association ID updated since 802.11be (Sec. 9.4.1.8 of 802.11be D7.0) static constexpr uint16_t EHT_MAX_AID{2006}; diff --git a/src/wifi/model/wifi-tx-vector.cc b/src/wifi/model/wifi-tx-vector.cc index 5ec96e702..a01149d4a 100644 --- a/src/wifi/model/wifi-tx-vector.cc +++ b/src/wifi/model/wifi-tx-vector.cc @@ -691,6 +691,7 @@ WifiTxVector::GetInactiveSubchannels() const void WifiTxVector::SetCenter26ToneRuIndication(Center26ToneRuIndication center26ToneRuIndication) { + NS_ASSERT(GetModulationClass() == WIFI_MOD_CLASS_HE); if (IsDlMu()) { NS_ASSERT(center26ToneRuIndication == DeriveCenter26ToneRuIndication()); @@ -701,7 +702,7 @@ WifiTxVector::SetCenter26ToneRuIndication(Center26ToneRuIndication center26ToneR std::optional WifiTxVector::GetCenter26ToneRuIndication() const { - if (!IsDlMu() || (m_channelWidth < MHz_u{80})) + if ((GetModulationClass() != WIFI_MOD_CLASS_HE) || !IsDlMu() || (m_channelWidth < MHz_u{80})) { return std::nullopt; } @@ -801,7 +802,10 @@ WifiTxVector::GetUserInfoMapOrderedByRus(uint8_t p20Index) const RuAllocation WifiTxVector::DeriveRuAllocation(uint8_t p20Index) const { - RuAllocation ruAllocations(Count20MHzSubchannels(m_channelWidth), EMPTY_242_TONE_HE_RU); + const auto mc = GetModulationClass(); + const auto emptyRu = + (mc == WIFI_MOD_CLASS_HE) ? EMPTY_242_TONE_HE_RU : UNASSIGNED_242_TONE_EHT_RU; + RuAllocation ruAllocations(Count20MHzSubchannels(m_channelWidth), emptyRu); std::vector ruTypes{}; ruTypes.resize(ruAllocations.size()); const auto& orderedMap = GetUserInfoMapOrderedByRus(p20Index); @@ -817,8 +821,6 @@ WifiTxVector::DeriveRuAllocation(uint8_t p20Index) const continue; } const auto ruBw = WifiRu::GetBandwidth(ruType); - NS_ASSERT_MSG(WifiRu::IsHe(ru), "EHT RUs should not be used yet"); - const auto mc{WIFI_MOD_CLASS_HE}; const auto rusPerSubchannel = WifiRu::GetRusOfType(ruBw > MHz_u{20} ? ruBw : MHz_u{20}, ruType, mc); if ((m_channelWidth >= MHz_u{80}) && (ruIndex > 19)) @@ -835,7 +837,7 @@ WifiTxVector::DeriveRuAllocation(uint8_t p20Index) const : ((ruIndex - 1) * numSubchannelsForRu); NS_ABORT_IF(index >= Count20MHzSubchannels(m_channelWidth)); auto ruAlloc = WifiRu::GetEqualizedRuAllocation(ruType, false, true, mc); - if (ruAllocations.at(index) != EMPTY_242_TONE_HE_RU) + if (ruAllocations.at(index) != emptyRu) { if (ruType == ruTypes.at(index)) { @@ -873,7 +875,7 @@ WifiTxVector::DeriveRuAllocation(uint8_t p20Index) const } for (std::size_t i = 0; i < numSubchannelsForRu; ++i) { - auto ruAllocNoUsers = HeRu::GetEqualizedRuAllocation(ruType, false, false); + auto ruAllocNoUsers = WifiRu::GetEqualizedRuAllocation(ruType, false, false, mc); ruTypes.at(index + i) = ruType; ruAllocations.at(index + i) = (IsSigBCompression() || ((index + i) % 2) == ccIndex) ? ruAlloc : ruAllocNoUsers; diff --git a/src/wifi/test/tx-duration-test.cc b/src/wifi/test/tx-duration-test.cc index 9fab5d64d..37bf57ab6 100644 --- a/src/wifi/test/tx-duration-test.cc +++ b/src/wifi/test/tx-duration-test.cc @@ -270,7 +270,8 @@ TxDurationTest::CheckMuTxDuration(std::list sizes, staIds.push_back(staId++); } txVector.SetSigBMode(VhtPhy::GetVhtMcs0()); - txVector.SetRuAllocation({192, 192}, 0); + const uint16_t ruAllocPer20 = IsEht(preamble) ? 64 : 192; + txVector.SetRuAllocation({ruAllocPer20, ruAllocPer20}, 0); Ptr phy = CreateObject(); std::list testedBands; @@ -1950,31 +1951,32 @@ TxDurationTest::DoRun() NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11be SU duration failed"); // 802.11be MU durations - retval = retval && - CheckMuTxDuration( - std::list{1536, 1536}, - std::list{{HeRu::RuSpec{RuType::RU_242_TONE, 1, true}, 0, 1}, - {HeRu::RuSpec{RuType::RU_242_TONE, 2, true}, 0, 1}}, - MHz_u{40}, - NanoSeconds(800), - WIFI_PREAMBLE_EHT_MU, - NanoSeconds(1493600)) // equivalent to 802.11ax MU - && CheckMuTxDuration( - std::list{1536, 1536}, - std::list{{HeRu::RuSpec{RuType::RU_242_TONE, 1, true}, 1, 1}, - {HeRu::RuSpec{RuType::RU_242_TONE, 2, true}, 0, 1}}, - MHz_u{40}, - NanoSeconds(800), - WIFI_PREAMBLE_EHT_MU, - NanoSeconds(1493600)) // shouldn't change if first PSDU is shorter - && CheckMuTxDuration( - std::list{1536, 76}, - std::list{{HeRu::RuSpec{RuType::RU_242_TONE, 1, true}, 0, 1}, - {HeRu::RuSpec{RuType::RU_242_TONE, 2, true}, 0, 1}}, - MHz_u{40}, - NanoSeconds(800), - WIFI_PREAMBLE_EHT_MU, - NanoSeconds(1493600)); + retval = + retval && + CheckMuTxDuration( + std::list{1536, 1536}, + std::list{{EhtRu::RuSpec{RuType::RU_242_TONE, 1, true, true}, 0, 1}, + {EhtRu::RuSpec{RuType::RU_242_TONE, 2, true, true}, 0, 1}}, + MHz_u{40}, + NanoSeconds(800), + WIFI_PREAMBLE_EHT_MU, + NanoSeconds(1493600)) // equivalent to 802.11ax MU + && CheckMuTxDuration( + std::list{1536, 1536}, + std::list{{EhtRu::RuSpec{RuType::RU_242_TONE, 1, true, true}, 1, 1}, + {EhtRu::RuSpec{RuType::RU_242_TONE, 2, true, true}, 0, 1}}, + MHz_u{40}, + NanoSeconds(800), + WIFI_PREAMBLE_EHT_MU, + NanoSeconds(1493600)) // shouldn't change if first PSDU is shorter + && CheckMuTxDuration( + std::list{1536, 76}, + std::list{{EhtRu::RuSpec{RuType::RU_242_TONE, 1, true, true}, 0, 1}, + {EhtRu::RuSpec{RuType::RU_242_TONE, 2, true, true}, 0, 1}}, + MHz_u{40}, + NanoSeconds(800), + WIFI_PREAMBLE_EHT_MU, + NanoSeconds(1493600)); NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11be MU duration failed"); @@ -2116,6 +2118,7 @@ HeSigBDurationTest::DoRun() // Verify number of users for content channels 1 and 2 const auto& numUsersPerCc = HePpdu::GetNumRusPerHeSigBContentChannel( txVector.GetChannelWidth(), + txVector.GetModulationClass(), txVector.GetRuAllocation(m_p20Index), txVector.GetCenter26ToneRuIndication(), txVector.IsSigBCompression(), @@ -2485,8 +2488,10 @@ PhyHeaderSectionsTest::DoRun() txVector.SetNss(2); // EHT-LTF duration assumed to be always 8 us for the time being (see note // in HePhy::GetTrainingDuration) txVector.SetMode(EhtPhy::GetEhtMcs9()); - userInfoMap = {{1, {HeRu::RuSpec{RuType::RU_106_TONE, 1, true}, 4, 2}}, - {2, {HeRu::RuSpec{RuType::RU_106_TONE, 1, true}, 9, 1}}}; + userInfoMap = {{1, {EhtRu::RuSpec{RuType::RU_52_TONE, 1, true, true}, 4, 2}}, + {2, {EhtRu::RuSpec{RuType::RU_52_TONE, 2, true, true}, 9, 1}}, + {3, {EhtRu::RuSpec{RuType::RU_52_TONE, 3, true, true}, 4, 2}}, + {4, {EhtRu::RuSpec{RuType::RU_52_TONE, 4, true, true}, 9, 1}}}; WifiMode uSigMode = EhtPhy::GetVhtMcs0(); WifiMode ehtSigMode = EhtPhy::GetVhtMcs4(); // because of first user info map @@ -2505,7 +2510,7 @@ PhyHeaderSectionsTest::DoRun() // -> EHT MU format txVector.SetPreambleType(WIFI_PREAMBLE_EHT_MU); txVector.SetEhtPpduType(0); // EHT MU transmission - txVector.SetRuAllocation({96}, 0); + txVector.SetRuAllocation({24}, 0); sections[WIFI_PPDU_FIELD_U_SIG] = {{ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(32)}, uSigMode}; sections[WIFI_PPDU_FIELD_EHT_SIG] = { @@ -2517,7 +2522,7 @@ PhyHeaderSectionsTest::DoRun() ehtSigMode}; CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections); txVector.SetChannelWidth(MHz_u{160}); // shouldn't have any impact - txVector.SetRuAllocation({96, 113, 113, 113, 113, 113, 113, 113}, 0); + txVector.SetRuAllocation({24, 27, 27, 27, 27, 27, 27, 27}, 0); CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections); } diff --git a/src/wifi/test/wifi-mac-ofdma-test.cc b/src/wifi/test/wifi-mac-ofdma-test.cc index 095c35133..ecaffeee8 100644 --- a/src/wifi/test/wifi-mac-ofdma-test.cc +++ b/src/wifi/test/wifi-mac-ofdma-test.cc @@ -305,22 +305,38 @@ TestMultiUserScheduler::ComputeWifiTxVector() RuType ruType; switch (static_cast(bw)) { - case 20: + case 20: { ruType = RuType::RU_52_TONE; - m_txVector.SetRuAllocation({112}, 0); + const uint16_t ruAllocPer20 = IsEht(m_txVector.GetPreambleType()) ? 24 : 112; + m_txVector.SetRuAllocation({ruAllocPer20}, 0); break; - case 40: + } + case 40: { ruType = RuType::RU_106_TONE; - m_txVector.SetRuAllocation({96, 96}, 0); + const uint16_t ruAllocPer20 = IsEht(m_txVector.GetPreambleType()) ? 48 : 96; + m_txVector.SetRuAllocation({ruAllocPer20, ruAllocPer20}, 0); break; - case 80: + } + case 80: { ruType = RuType::RU_242_TONE; - m_txVector.SetRuAllocation({192, 192, 192, 192}, 0); + const uint16_t ruAllocPer20 = IsEht(m_txVector.GetPreambleType()) ? 64 : 112; + m_txVector.SetRuAllocation({ruAllocPer20, ruAllocPer20, ruAllocPer20, ruAllocPer20}, 0); break; - case 160: + } + case 160: { ruType = RuType::RU_484_TONE; - m_txVector.SetRuAllocation({200, 200, 200, 200, 200, 200, 200, 200}, 0); + const uint16_t ruAllocPer20 = IsEht(m_txVector.GetPreambleType()) ? 72 : 200; + m_txVector.SetRuAllocation({ruAllocPer20, + ruAllocPer20, + ruAllocPer20, + ruAllocPer20, + ruAllocPer20, + ruAllocPer20, + ruAllocPer20, + ruAllocPer20}, + 0); break; + } default: NS_ABORT_MSG("Unsupported channel width"); } @@ -330,12 +346,20 @@ TestMultiUserScheduler::ComputeWifiTxVector() for (auto& sta : staList) { auto index{ruIndex}; - if ((bw == MHz_u{160}) && (ruIndex == 3)) + if (!IsEht(m_txVector.GetPreambleType()) && (bw == MHz_u{160}) && (ruIndex >= 3)) { - index = HeRu::GetIndexIn80MHzSegment(bw, ruType, ruIndex); - primary80 = HeRu::GetPrimary80MHzFlag(bw, ruType, ruIndex, 0); + index = ruIndex - 2; + primary80 = false; } - m_txVector.SetHeMuUserInfo(sta.first, {HeRu::RuSpec{ruType, index, primary80}, 11, 1}); + if (IsEht(m_txVector.GetPreambleType()) && (bw > MHz_u{80})) + { + index = EhtRu::GetIndexIn80MHzSegment(bw, ruType, ruIndex); + primary80 = EhtRu::GetPrimaryFlags(bw, ruType, ruIndex, 0).second; + } + const auto ru = IsEht(m_txVector.GetPreambleType()) + ? WifiRu::RuSpec(EhtRu::RuSpec{ruType, index, true, primary80}) + : WifiRu::RuSpec(HeRu::RuSpec{ruType, index, primary80}); + m_txVector.SetHeMuUserInfo(sta.first, {ru, 11, 1}); ruIndex++; } m_txVector.SetSigBMode(VhtPhy::GetVhtMcs5()); diff --git a/src/wifi/test/wifi-phy-ofdma-test.cc b/src/wifi/test/wifi-phy-ofdma-test.cc index 32dfd3117..4c56fde66 100644 --- a/src/wifi/test/wifi-phy-ofdma-test.cc +++ b/src/wifi/test/wifi-phy-ofdma-test.cc @@ -148,14 +148,15 @@ OfdmaTestHePhy::GetNonOfdmaBand(const WifiTxVector& txVector, uint16_t staId) co WifiRu::GetPhyIndex(nonOfdmaRu, channelWidth, m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20}))); - const auto indices = - ConvertRuSubcarriers(channelWidth, - GetGuardBandwidth(m_wifiPhy->GetChannelWidth()), - m_wifiPhy->GetOperatingChannel().GetFrequencies(), - m_wifiPhy->GetChannelWidth(), - m_wifiPhy->GetSubcarrierSpacing(), - {groupPreamble.front().first, groupPreamble.back().second}, - m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(channelWidth)); + const auto indices = ConvertRuSubcarriers( + {channelWidth, + GetGuardBandwidth(m_wifiPhy->GetChannelWidth()), + m_wifiPhy->GetOperatingChannel().GetFrequencies(), + m_wifiPhy->GetChannelWidth(), + m_wifiPhy->GetSubcarrierSpacing(), + txVector.GetModulationClass(), + {groupPreamble.front().first, groupPreamble.back().second}, + m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(channelWidth)}); WifiSpectrumBandInfo nonOfdmaBand{}; for (const auto& indicesPerSegment : indices) {