wifi: Use EHT RUs for EHT PPDUs
This commit is contained in:
@@ -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 <algorithm>
|
||||
#include <initializer_list>
|
||||
#include <numeric>
|
||||
|
||||
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<std::size_t>{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<WifiPpdu>
|
||||
EhtPpdu::Copy() const
|
||||
{
|
||||
|
||||
@@ -151,6 +151,12 @@ class EhtPpdu : public HePpdu
|
||||
uint8_t ehtPpduType,
|
||||
std::optional<bool> 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;
|
||||
|
||||
@@ -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<const WifiPpdu> ppdu)
|
||||
}
|
||||
|
||||
std::vector<WifiSpectrumBandIndices>
|
||||
HePhy::ConvertRuSubcarriers(MHz_u bandWidth,
|
||||
MHz_u guardBandwidth,
|
||||
const std::vector<MHz_u>& 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<WifiSpectrumBandIndices> convertedSubcarriers{};
|
||||
guardBandwidth /= centerFrequencies.size();
|
||||
const auto guardBandwidth{info.guardBandwidth / info.centerFrequencies.size()};
|
||||
const auto nGuardBands =
|
||||
static_cast<uint32_t>(((2 * MHzToHz(guardBandwidth)) / subcarrierSpacing) + 0.5);
|
||||
if (bandWidth > (totalWidth / centerFrequencies.size()))
|
||||
static_cast<uint32_t>(((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<size_t>(MHzToHz(bandWidth) / subcarrierSpacing);
|
||||
centerFrequencyIndex += numBandsInBand * bandIndex;
|
||||
const auto numBandsInBand = static_cast<size_t>(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<MHz_u>& 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<WifiSpectrumBandIndices> ConvertRuSubcarriers(
|
||||
MHz_u bandWidth,
|
||||
MHz_u guardBandwidth,
|
||||
const std::vector<MHz_u>& centerFrequencies,
|
||||
MHz_u totalWidth,
|
||||
Hz_u subcarrierSpacing,
|
||||
SubcarrierRange subcarrierRange,
|
||||
uint8_t bandIndex = 0);
|
||||
static std::vector<WifiSpectrumBandIndices> ConvertRuSubcarriers(const RuSubcarriersInfo& info);
|
||||
|
||||
protected:
|
||||
PhyFieldRxStatus ProcessSig(Ptr<Event> event,
|
||||
|
||||
@@ -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> 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<WifiTxVector>& trigVector) con
|
||||
std::pair<std::size_t, std::size_t>
|
||||
HePpdu::GetNumRusPerHeSigBContentChannel(
|
||||
MHz_u channelWidth,
|
||||
WifiModulationClass mc,
|
||||
const RuAllocation& ruAllocation,
|
||||
std::optional<Center26ToneRuIndication> 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<uint16_t>(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> center26ToneRuIndication,
|
||||
bool sigBCompression,
|
||||
@@ -846,6 +854,7 @@ HePpdu::GetSigBFieldSize(MHz_u channelWidth,
|
||||
}
|
||||
|
||||
auto numRusPerContentChannel = GetNumRusPerHeSigBContentChannel(channelWidth,
|
||||
mc,
|
||||
ruAllocation,
|
||||
center26ToneRuIndication,
|
||||
sigBCompression,
|
||||
|
||||
@@ -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<std::size_t, std::size_t> GetNumRusPerHeSigBContentChannel(
|
||||
MHz_u channelWidth,
|
||||
WifiModulationClass mc,
|
||||
const RuAllocation& ruAllocation,
|
||||
std::optional<Center26ToneRuIndication> 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> 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> center26ToneRuIndication,
|
||||
const HeSigBContentChannels& contentChannels,
|
||||
|
||||
@@ -174,13 +174,32 @@ RrMultiUserScheduler::GetTxVectorForUlMu(std::function<bool(const MasterInfo&)>
|
||||
{
|
||||
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<std::size_t>(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<bool(const MasterInfo&)>
|
||||
nCentral26TonesRus = 0;
|
||||
}
|
||||
|
||||
Ptr<HeConfiguration> 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<bool(const MasterInfo&)>
|
||||
{
|
||||
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<bool(const MasterInfo&)>
|
||||
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<std::size_t>(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<std::size_t>(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++)
|
||||
|
||||
@@ -148,45 +148,75 @@ SpectrumWifiPhy::GetRuBands(Ptr<WifiSpectrumPhyInterface> 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<WifiModulationClass> 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<uint32_t>(WifiRu::GetMaxRuType(WIFI_MOD_CLASS_HE));
|
||||
++type)
|
||||
if (bw > GetMaximumChannelWidth(modClass))
|
||||
{
|
||||
auto ruType = static_cast<RuType>(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<uint32_t>(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<RuType>(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});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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<Center26ToneRuIndication>
|
||||
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<RuType> 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;
|
||||
|
||||
@@ -270,7 +270,8 @@ TxDurationTest::CheckMuTxDuration(std::list<uint32_t> 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<YansWifiPhy> phy = CreateObject<YansWifiPhy>();
|
||||
std::list<WifiPhyBand> 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<uint32_t>{1536, 1536},
|
||||
std::list<HeMuUserInfo>{{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<uint32_t>{1536, 1536},
|
||||
std::list<HeMuUserInfo>{{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<uint32_t>{1536, 76},
|
||||
std::list<HeMuUserInfo>{{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<uint32_t>{1536, 1536},
|
||||
std::list<HeMuUserInfo>{{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<uint32_t>{1536, 1536},
|
||||
std::list<HeMuUserInfo>{{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<uint32_t>{1536, 76},
|
||||
std::list<HeMuUserInfo>{{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);
|
||||
}
|
||||
|
||||
@@ -305,22 +305,38 @@ TestMultiUserScheduler::ComputeWifiTxVector()
|
||||
RuType ruType;
|
||||
switch (static_cast<uint16_t>(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());
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user