wifi: Modularize calculation to determine the amount of 20 MHz subchannels covering a given width

This commit is contained in:
Sébastien Deronne
2024-11-11 12:03:53 +01:00
parent 3059da784a
commit 4cf22a3c55
17 changed files with 94 additions and 48 deletions

View File

@@ -383,8 +383,9 @@ ChannelAccessManager::ResizeLastBusyStructs()
m_lastIdle.emplace(WIFI_CHANLIST_PRIMARY, Timespan{now, now});
const auto width = m_phy ? m_phy->GetChannelWidth() : 0;
std::size_t size =
(width > 20 && m_phy->GetStandard() >= WIFI_STANDARD_80211ax) ? width / 20 : 0;
std::size_t size = (width > 20 && m_phy->GetStandard() >= WIFI_STANDARD_80211ax)
? Count20MHzSubchannels(width)
: 0;
m_lastPer20MHzBusyEnd.resize(size, now);
if (!m_phy || !m_phy->GetOperatingChannel().IsOfdm())

View File

@@ -268,7 +268,7 @@ HePpdu::SetHeMuUserInfos(WifiTxVector& txVector,
}
const auto ruBw = HeRu::GetBandwidth(ruType);
auto primary80 = ruAllocIndex < 4;
const uint8_t num20MhzSubchannelsInRu = (ruBw < 20) ? 1 : (ruBw / 20);
const uint8_t num20MhzSubchannelsInRu = (ruBw < 20) ? 1 : Count20MHzSubchannels(ruBw);
auto numRuAllocsInContentChannel = std::max(1, num20MhzSubchannelsInRu / 2);
auto ruIndexOffset = (ruBw < 20) ? (ruSpecs.size() * ruAllocIndex)
: (ruAllocIndex / num20MhzSubchannelsInRu);
@@ -499,8 +499,7 @@ HePpdu::GetNumRusPerHeSigBContentChannel(MHz_u channelWidth,
}
NS_ASSERT_MSG(!ruAllocation.empty(), "RU allocation is not set");
[[maybe_unused]] const std::size_t num20MhzSubchannels = channelWidth / 20;
NS_ASSERT_MSG(ruAllocation.size() == num20MhzSubchannels,
NS_ASSERT_MSG(ruAllocation.size() == Count20MHzSubchannels(channelWidth),
"RU allocation is not consistent with packet bandwidth");
switch (static_cast<uint16_t>(channelWidth))
@@ -512,7 +511,7 @@ HePpdu::GetNumRusPerHeSigBContentChannel(MHz_u channelWidth,
chSize.first += HeRu::GetRuSpecs(ruAllocation[0]).size();
break;
default:
for (auto n = 0; n < channelWidth / 20;)
for (std::size_t n = 0; n < Count20MHzSubchannels(channelWidth);)
{
chSize.first += HeRu::GetRuSpecs(ruAllocation[n]).size();
if (ruAllocation[n] >= 208)
@@ -523,7 +522,7 @@ HePpdu::GetNumRusPerHeSigBContentChannel(MHz_u channelWidth,
}
n += 2;
}
for (auto n = 0; n < channelWidth / 20;)
for (std::size_t n = 0; n < Count20MHzSubchannels(channelWidth);)
{
chSize.second += HeRu::GetRuSpecs(ruAllocation[n + 1]).size();
if (ruAllocation[n + 1] >= 208)

View File

@@ -805,7 +805,7 @@ RrMultiUserScheduler::TrySendingDlMuPpdu()
m_candidates.clear();
std::vector<uint8_t> ruAllocations;
const std::size_t numRuAllocs = m_txParams.m_txVector.GetChannelWidth() / 20;
const auto numRuAllocs = Count20MHzSubchannels(m_txParams.m_txVector.GetChannelWidth());
ruAllocations.resize(numRuAllocs);
NS_ASSERT((m_candidates.size() % numRuAllocs) == 0);

View File

@@ -9,6 +9,7 @@
#include "reduced-neighbor-report.h"
#include "wifi-phy-operating-channel.h"
#include "wifi-utils.h"
#include "ns3/abort.h"
#include "ns3/address-utils.h"
@@ -326,7 +327,7 @@ ReducedNeighborReport::GetOperatingChannel(std::size_t nbrApInfoId) const
MHz_u channelLowestFreq = frequency - width / 2;
MHz_u primaryChannelLowestFreq = primaryChannelCenterFrequency - 10;
channel.SetPrimary20Index((primaryChannelLowestFreq - channelLowestFreq) / 20);
channel.SetPrimary20Index(Count20MHzSubchannels(channelLowestFreq, primaryChannelLowestFreq));
return channel;
}

View File

@@ -587,7 +587,7 @@ SpectrumWifiPhy::StartRx(Ptr<SpectrumSignalParameters> rxParams,
// Current implementation assumes constant RX power over the PPDU duration
// Compare received TX power per MHz to normalized RX sensitivity
const auto ppdu = GetRxPpduFromTxPpdu(wifiRxParams->ppdu);
if (totalRxPower < DbmToW(GetRxSensitivity()) * (ppdu->GetTxChannelWidth() / 20.0))
if (totalRxPower < DbmToW(GetRxSensitivity()) * (ppdu->GetTxChannelWidth() / MHz_u{20}))
{
NS_LOG_INFO(
"Received signal too weak to process: "

View File

@@ -10,6 +10,7 @@
#include "wifi-phy-operating-channel.h"
#include "wifi-phy-common.h"
#include "wifi-utils.h"
#include "ns3/assert.h"
#include "ns3/log.h"
@@ -644,7 +645,8 @@ WifiPhyOperatingChannel::SetPrimary20Index(uint8_t index)
{
NS_LOG_FUNCTION(this << +index);
NS_ABORT_MSG_IF(index > 0 && index >= GetTotalWidth() / 20, "Primary20 index out of range");
NS_ABORT_MSG_IF(index > 0 && index >= Count20MHzSubchannels(GetTotalWidth()),
"Primary20 index out of range");
m_primary20Index = index;
}
@@ -737,7 +739,7 @@ WifiPhyOperatingChannel::GetPrimaryChannel(MHz_u primaryChannelWidth) const
WifiPhyOperatingChannel primaryChannel(primaryChanIt);
const auto primaryIndex = m_primary20Index - (GetPrimaryChannelIndex(primaryChannelWidth) *
(primaryChannelWidth / 20));
Count20MHzSubchannels(primaryChannelWidth));
primaryChannel.SetPrimary20Index(primaryIndex);
return primaryChannel;
@@ -904,7 +906,7 @@ WifiPhyOperatingChannel::Get20MHzIndicesCoveringRu(HeRu::RuSpec ru, MHz_u width)
}
// finally, add the appropriate offset if width is less than the operational channel width
auto offset = GetPrimaryChannelIndex(width) * width / 20;
auto offset = GetPrimaryChannelIndex(width) * Count20MHzSubchannels(width);
if (offset > 0)
{

View File

@@ -12,6 +12,7 @@
#include "wifi-phy.h"
#include "wifi-psdu.h"
#include "wifi-tx-vector.h"
#include "wifi-utils.h"
#include "ns3/log.h"
#include "ns3/packet.h"
@@ -579,7 +580,9 @@ WifiPhyStateHelper::SwitchFromRxAbort(MHz_u operatingWidth)
std::vector<Time> per20MhzDurations;
if (operatingWidth >= 40)
{
std::fill_n(std::back_inserter(per20MhzDurations), (operatingWidth / 20), Seconds(0));
std::fill_n(std::back_inserter(per20MhzDurations),
Count20MHzSubchannels(operatingWidth),
Seconds(0));
}
NotifyListeners(&WifiPhyListener::NotifyCcaBusyStart,
Seconds(0),

View File

@@ -292,7 +292,7 @@ WifiSpectrumValueHelper::CreateDuplicated20MhzTxPowerSpectralDensity(
NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() ==
(nAllocatedBands + nGuardBands + nUnallocatedBands + 1),
"Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
std::size_t num20MhzBands = channelWidth / 20;
auto num20MhzBands = Count20MHzSubchannels(channelWidth);
std::size_t numAllocatedSubcarriersPer20MHz = 52;
NS_ASSERT(puncturedSubchannels.empty() || (puncturedSubchannels.size() == num20MhzBands));
const auto txPowerPerBand = (txPower / numAllocatedSubcarriersPer20MHz) / num20MhzBands;
@@ -396,7 +396,7 @@ WifiSpectrumValueHelper::CreateHtOfdmTxPowerSpectralDensity(
NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() ==
(nAllocatedBands + nGuardBands + nUnallocatedBands + 1),
"Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
std::size_t num20MhzBands = channelWidth / 20;
auto num20MhzBands = Count20MHzSubchannels(channelWidth);
std::size_t numAllocatedSubcarriersPer20MHz = 56;
const auto txPowerPerBand = (txPower / numAllocatedSubcarriersPer20MHz) / num20MhzBands;
NS_LOG_DEBUG("Power per band " << txPowerPerBand << "W");

View File

@@ -10,6 +10,7 @@
#include "wifi-tx-vector.h"
#include "wifi-phy-common.h"
#include "wifi-utils.h"
#include "ns3/abort.h"
#include "ns3/eht-phy.h"
@@ -659,9 +660,8 @@ WifiTxVector::SetInactiveSubchannels(const std::vector<bool>& inactiveSubchannel
NS_ABORT_MSG_IF(
m_channelWidth < 80,
"Preamble puncturing only possible for transmission bandwidth of 80 MHz or larger");
[[maybe_unused]] const std::size_t num20MhzSubchannels = m_channelWidth / 20;
NS_ABORT_MSG_IF(!inactiveSubchannels.empty() &&
inactiveSubchannels.size() != num20MhzSubchannels,
inactiveSubchannels.size() != Count20MHzSubchannels(m_channelWidth),
"The size of the inactive subchannnels bitmap should be equal to the number of "
"20 MHz subchannels");
m_inactiveSubchannels = inactiveSubchannels;
@@ -786,7 +786,7 @@ WifiTxVector::GetUserInfoMapOrderedByRus(uint8_t p20Index) const
RuAllocation
WifiTxVector::DeriveRuAllocation(uint8_t p20Index) const
{
RuAllocation ruAllocations(m_channelWidth / 20, HeRu::EMPTY_242_TONE_RU);
RuAllocation ruAllocations(Count20MHzSubchannels(m_channelWidth), HeRu::EMPTY_242_TONE_RU);
std::vector<HeRu::RuType> ruTypes{};
ruTypes.resize(ruAllocations.size());
const auto& orderedMap = GetUserInfoMapOrderedByRus(p20Index);
@@ -815,11 +815,10 @@ WifiTxVector::DeriveRuAllocation(uint8_t p20Index) const
// the primary 80 MHz
ruIndex += HeRu::GetRusOfType(80, ruType).size();
}
const auto index =
(ruBw < 20) ? ((ruIndex - 1) / rusPerSubchannel.size()) : ((ruIndex - 1) * (ruBw / 20));
const auto numSubchannelsForRu = (ruBw < 20) ? 1 : (ruBw / 20);
[[maybe_unused]] const std::size_t num20MhzSubchannels = m_channelWidth / 20;
NS_ABORT_IF(index >= num20MhzSubchannels);
const auto numSubchannelsForRu = (ruBw < 20) ? 1 : Count20MHzSubchannels(ruBw);
const auto index = (ruBw < 20) ? ((ruIndex - 1) / rusPerSubchannel.size())
: ((ruIndex - 1) * numSubchannelsForRu);
NS_ABORT_IF(index >= Count20MHzSubchannels(m_channelWidth));
auto ruAlloc = HeRu::GetEqualizedRuAllocation(ruType, false);
if (ruAllocations.at(index) != HeRu::EMPTY_242_TONE_RU)
{
@@ -840,7 +839,7 @@ WifiTxVector::DeriveRuAllocation(uint8_t p20Index) const
NS_ASSERT_MSG(false, "unsupported RU combination");
}
}
for (auto i = 0; i < numSubchannelsForRu; ++i)
for (std::size_t i = 0; i < numSubchannelsForRu; ++i)
{
ruTypes.at(index + i) = ruType;
ruAllocations.at(index + i) = ruAlloc;

View File

@@ -124,6 +124,37 @@ HzToMHz(Hz_u val)
return val * 1e-6;
}
/**
* Return the number of 20 MHz subchannels covering the channel width.
*
* @param channelWidth the channel width
* @return the number of 20 MHz subchannels
*/
inline std::size_t
Count20MHzSubchannels(MHz_u channelWidth)
{
NS_ASSERT(static_cast<uint16_t>(channelWidth) % 20 == 0);
return channelWidth / MHz_u{20};
}
/**
* Return the number of 20 MHz subchannels covering the channel width between a lower frequency and
* an upper frequency. This function should only be called when the channel width between the lower
* frequency and the upper frequency is a multiple of 20 MHz.
*
* @param lower the lower frequency
* @param upper the upper frequency
* @return the number of 20 MHz subchannels
*/
inline std::size_t
Count20MHzSubchannels(MHz_u lower, MHz_u upper)
{
NS_ASSERT(upper >= lower);
const auto width = upper - lower;
NS_ASSERT((static_cast<uint16_t>(width) % 20 == 0));
return Count20MHzSubchannels(width);
}
/**
* Return the total Ack size (including FCS trailer).
*

View File

@@ -129,7 +129,7 @@ YansWifiChannel::Receive(Ptr<YansWifiPhy> phy, Ptr<const WifiPpdu> ppdu, dBm_u r
// Current implementation assumes constant RX power over the PPDU duration
// Compare received TX power per MHz to normalized RX sensitivity
const auto txWidth = ppdu->GetTxChannelWidth();
if (totalRxPower < phy->GetRxSensitivity() + RatioToDb(txWidth / 20.0))
if (totalRxPower < phy->GetRxSensitivity() + RatioToDb(txWidth / MHz_u{20}))
{
NS_LOG_INFO("Received signal too weak to process: " << rxPower << " dBm");
return;

View File

@@ -1391,12 +1391,13 @@ LargestIdlePrimaryChannelTest::RunOne(MHz_u chWidth, WifiChannelListType busyCha
// After 1ms, we are notified of CCA_BUSY for 1ms on the given channel
Time ccaBusyStartDelay = MilliSeconds(1);
Time ccaBusyDuration = MilliSeconds(1);
Simulator::Schedule(ccaBusyStartDelay,
&ChannelAccessManager::NotifyCcaBusyStartNow,
m_cam,
ccaBusyDuration,
busyChannel,
std::vector<Time>(chWidth == 20 ? 0 : chWidth / 20, Seconds(0)));
Simulator::Schedule(
ccaBusyStartDelay,
&ChannelAccessManager::NotifyCcaBusyStartNow,
m_cam,
ccaBusyDuration,
busyChannel,
std::vector<Time>(chWidth == 20 ? 0 : Count20MHzSubchannels(chWidth), Seconds(0)));
// During any interval ending within CCA_BUSY period, the idle channel is the
// primary channel contiguous to the busy secondary channel, if the busy channel

View File

@@ -589,7 +589,7 @@ SpectrumWifiPhyFilterTest::RxCallback(Ptr<const Packet> p, RxPowerWattPerChannel
<< " dBm)");
const auto rxPowerPrimaryChannel20 = static_cast<int>(WToDbm(it->second) + 0.5);
const auto expectedRxPowerPrimaryChannel20 =
16 - static_cast<int>(RatioToDb(channelWidth / 20));
16 - static_cast<int>(RatioToDb(Count20MHzSubchannels(channelWidth)));
NS_TEST_ASSERT_MSG_EQ(rxPowerPrimaryChannel20,
expectedRxPowerPrimaryChannel20,
"Received power in the primary 20 MHz band is not correct");
@@ -914,14 +914,14 @@ SpectrumWifiPhyGetBandTest::DoRun()
for (bool contiguous160Mhz : {true /* 160 MHz */, false /* 80+80MHz */})
{
MHz_u guardWidth = contiguous160Mhz ? channelWidth : (channelWidth / 2);
uint32_t guardStopIndice = (indicesPer20MhzBand * (guardWidth / 20)) - 1;
uint32_t guardStopIndice = (indicesPer20MhzBand * Count20MHzSubchannels(guardWidth)) - 1;
std::vector<WifiSpectrumBandIndices> previousExpectedIndices{};
std::vector<WifiSpectrumBandFrequencies> previousExpectedFrequencies{};
for (auto bandWidth : {20, 40, 80, 160})
{
const uint32_t expectedStartIndice = guardStopIndice + 1;
const uint32_t expectedStopIndice =
expectedStartIndice + (indicesPer20MhzBand * (bandWidth / 20)) - 1;
expectedStartIndice + (indicesPer20MhzBand * Count20MHzSubchannels(bandWidth)) - 1;
std::vector<WifiSpectrumBandIndices> expectedIndices{
{expectedStartIndice, expectedStopIndice}};
const Hz_u expectedStartFrequency = MHzToHz(5170);
@@ -945,8 +945,10 @@ SpectrumWifiPhyGetBandTest::DoRun()
}
else if ((i == (numBands / 2)) && !contiguous160Mhz)
{
expectedIndices.at(0).first += (indicesPer20MhzBand * (separationWidth / 20));
expectedIndices.at(0).second += (indicesPer20MhzBand * (separationWidth / 20));
expectedIndices.at(0).first +=
(indicesPer20MhzBand * Count20MHzSubchannels(separationWidth));
expectedIndices.at(0).second +=
(indicesPer20MhzBand * Count20MHzSubchannels(separationWidth));
expectedFrequencies.at(0).first += MHzToHz(separationWidth);
expectedFrequencies.at(0).second += MHzToHz(separationWidth);
}
@@ -963,7 +965,8 @@ SpectrumWifiPhyGetBandTest::DoRun()
}
expectedIndices.at(0).first = expectedIndices.at(0).second + 1;
expectedIndices.at(0).second =
expectedIndices.at(0).first + (indicesPer20MhzBand * (bandWidth / 20)) - 1;
expectedIndices.at(0).first +
(indicesPer20MhzBand * Count20MHzSubchannels(bandWidth)) - 1;
expectedFrequencies.at(0).first += MHzToHz(bandWidth);
expectedFrequencies.at(0).second += MHzToHz(bandWidth);
}

View File

@@ -2655,7 +2655,7 @@ EmlsrUlTxopTest::DoSetup()
while (bw < width)
{
bw *= 2;
number += bw / 20;
number += Count20MHzSubchannels(bw);
}
for (auto mac : std::initializer_list<Ptr<WifiMac>>{m_apMac, m_staMacs[0]})

View File

@@ -468,8 +468,7 @@ TestNonHtDuplicatePhyReception::DoSetup()
0,
m_apStandard,
WIFI_PHY_BAND_5GHZ));
[[maybe_unused]] const std::size_t num20MhzSubchannels = channelInfo.width / 20;
NS_ASSERT(m_per20MhzInterference.size() == num20MhzSubchannels);
NS_ASSERT(m_per20MhzInterference.size() == Count20MHzSubchannels(channelInfo.width));
for (std::size_t i = 0; i < m_per20MhzInterference.size(); ++i)
{
auto interfererNode = CreateObject<Node>();
@@ -588,7 +587,8 @@ TestNonHtDuplicatePhyReception::DoRun()
bool expectSuccess = true;
if (!m_per20MhzInterference.empty())
{
const auto index20MhzSubBand = ((staP20Freq - minApCenterFrequency) / 20);
const auto index20MhzSubBand =
Count20MHzSubchannels(staP20Freq - minApCenterFrequency);
expectSuccess = !m_per20MhzInterference.at(index20MhzSubBand);
}
Simulator::Schedule(Seconds(index + 0.5),

View File

@@ -1735,7 +1735,7 @@ TestDlOfdmaPhyPuncturing::RunOne()
// Send MU PPDU with two PSDUs addressed to STA 1 and STA 2 with preamble puncturing:
// the punctured 20 MHz subchannel is the one that has interference
std::vector<bool> puncturedSubchannels;
const std::size_t num20MhzSubchannels = m_channelWidth / 20;
const auto num20MhzSubchannels = Count20MHzSubchannels(m_channelWidth);
for (std::size_t i = 0; i < num20MhzSubchannels; ++i)
{
if (i == m_indexSubchannel)

View File

@@ -343,7 +343,7 @@ WifiPrimaryChannelsTest::DoSetup()
}
// we create as many BSSes as the number of 20 MHz subchannels
m_nBss = m_channelWidth / 20;
m_nBss = Count20MHzSubchannels(m_channelWidth);
NodeContainer wifiApNodes;
wifiApNodes.Create(m_nBss);
@@ -608,7 +608,9 @@ WifiPrimaryChannelsTest::DoRun()
// To have simultaneous transmissions on adjacent channels, just initialize
// nRounds to 1 and nApsPerRound to m_channelWidth / 20. Of course, the test
// will fail because some stations will not receive some frames due to interfence
for (MHz_u txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
for (MHz_u txChannelWidth = 20,
nRounds = 2,
nApsPerRound = Count20MHzSubchannels(m_channelWidth) / 2;
txChannelWidth <= m_channelWidth;
txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
{
@@ -644,7 +646,9 @@ WifiPrimaryChannelsTest::DoRun()
* channel width, every round is repeated as many times as the number of ways in
* which we can partition the transmission channel width in equal sized RUs.
*/
for (MHz_u txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
for (MHz_u txChannelWidth = 20,
nRounds = 2,
nApsPerRound = Count20MHzSubchannels(m_channelWidth) / 2;
txChannelWidth <= m_channelWidth;
txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
{
@@ -692,7 +696,9 @@ WifiPrimaryChannelsTest::DoRun()
* channel width, every round is repeated as many times as the number of ways in
* which we can partition the transmission channel width in equal sized RUs.
*/
for (MHz_u txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
for (MHz_u txChannelWidth = 20,
nRounds = 2,
nApsPerRound = Count20MHzSubchannels(m_channelWidth) / 2;
txChannelWidth <= m_channelWidth;
txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
{
@@ -830,7 +836,7 @@ WifiPrimaryChannelsTest::SendDlMuPpdu(uint8_t bss,
}
txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
RuAllocation ruAllocations;
const std::size_t numRuAllocs = txChannelWidth / 20;
const auto numRuAllocs = Count20MHzSubchannels(txChannelWidth);
ruAllocations.resize(numRuAllocs);
auto IsOddNum = (nRus / numRuAllocs) % 2 == 1;
auto ruAlloc = HeRu::GetEqualizedRuAllocation(ruType, IsOddNum);