wifi: Implement CCA logic when channel bonding is used

This commit is contained in:
Sebastien Deronne
2022-04-24 12:29:45 +02:00
parent 6940bb7170
commit 3177f3d3b5
7 changed files with 178 additions and 6 deletions

View File

@@ -776,6 +776,47 @@ HtPhy::GetMaxPsduSize (void) const
return 65535;
}
PhyEntity::CcaIndication
HtPhy::GetCcaIndication (const Ptr<const WifiPpdu> ppdu)
{
NS_LOG_FUNCTION (this);
if (m_wifiPhy->GetChannelWidth () < 40)
{
return PhyEntity::GetCcaIndication (ppdu);
}
double ccaThresholdDbm = GetCcaThreshold (ppdu, WIFI_CHANLIST_PRIMARY);
Time delayUntilCcaEnd = GetDelayUntilCcaEnd (ccaThresholdDbm, GetPrimaryBand (20));
if (delayUntilCcaEnd.IsStrictlyPositive ())
{
return std::make_pair (delayUntilCcaEnd, WIFI_CHANLIST_PRIMARY); //if Primary is busy, ignore CCA for Secondary
}
if (ppdu != nullptr)
{
const uint16_t primaryWidth = 20;
uint16_t p20MinFreq =
m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelCenterFrequency (primaryWidth) - (primaryWidth / 2);
uint16_t p20MaxFreq =
m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelCenterFrequency (primaryWidth) + (primaryWidth / 2);
if (ppdu->DoesOverlapChannel (p20MinFreq, p20MaxFreq))
{
/*
* PPDU occupies primary 20 MHz channel, hence we skip CCA sensitivity rules
* for signals not occupying the primary 20 MHz channel.
*/
return std::nullopt;
}
}
ccaThresholdDbm = GetCcaThreshold (ppdu, WIFI_CHANLIST_SECONDARY);
delayUntilCcaEnd = GetDelayUntilCcaEnd (ccaThresholdDbm, GetSecondaryBand (20));
if (delayUntilCcaEnd.IsStrictlyPositive ())
{
return std::make_pair (delayUntilCcaEnd, WIFI_CHANLIST_SECONDARY);
}
return std::nullopt;
}
} //namespace ns3
namespace {

View File

@@ -451,6 +451,7 @@ protected:
bool IsConfigSupported (Ptr<const WifiPpdu> ppdu) const override;
Ptr<SpectrumValue> GetTxPowerSpectralDensity (double txPowerW, Ptr<const WifiPpdu> ppdu) const override;
uint32_t GetMaxPsduSize (void) const override;
CcaIndication GetCcaIndication (const Ptr<const WifiPpdu> ppdu) override;
/**
* Build mode list.

View File

@@ -1062,6 +1062,12 @@ PhyEntity::GetCcaThreshold (const Ptr<const WifiPpdu> ppdu, WifiChannelListType
return (ppdu == nullptr) ? m_wifiPhy->GetCcaEdThreshold () : m_wifiPhy->GetCcaSensitivityThreshold ();
}
Time
PhyEntity::GetDelayUntilCcaEnd (double thresholdDbm, WifiSpectrumBand band)
{
return m_wifiPhy->m_interference->GetEnergyDuration (DbmToW (thresholdDbm), band);
}
void
PhyEntity::SwitchMaybeToCcaBusy (const Ptr<const WifiPpdu> ppdu)
{
@@ -1069,15 +1075,31 @@ PhyEntity::SwitchMaybeToCcaBusy (const Ptr<const WifiPpdu> ppdu)
//not going to be able to synchronize on it
//In this model, CCA becomes busy when the aggregation of all signals as
//tracked by the InterferenceHelper class is higher than the CcaBusyThreshold
const auto ccaIndication = GetCcaIndication (ppdu);
if (ccaIndication.has_value ())
{
NS_LOG_DEBUG ("CCA busy for " << ccaIndication.value ().second << " during " << ccaIndication.value ().first.As (Time::S));
m_state->SwitchMaybeToCcaBusy (ccaIndication.value ().first, ccaIndication.value ().second, {});
return;
}
if (ppdu != nullptr)
{
SwitchMaybeToCcaBusy (nullptr);
}
}
PhyEntity::CcaIndication
PhyEntity::GetCcaIndication (const Ptr<const WifiPpdu> ppdu)
{
const uint16_t channelWidth = GetMeasurementChannelWidth (ppdu);
NS_LOG_FUNCTION (this << channelWidth);
double ccaThresholdW = DbmToW (GetCcaThreshold (ppdu, WIFI_CHANLIST_PRIMARY));
const Time delayUntilCcaEnd = m_wifiPhy->m_interference->GetEnergyDuration (ccaThresholdW, GetPrimaryBand (channelWidth));
const double ccaThresholdDbm = GetCcaThreshold (ppdu, WIFI_CHANLIST_PRIMARY);
const Time delayUntilCcaEnd = GetDelayUntilCcaEnd (ccaThresholdDbm, GetPrimaryBand (channelWidth));
if (delayUntilCcaEnd.IsStrictlyPositive ())
{
NS_LOG_DEBUG ("Calling SwitchMaybeToCcaBusy for " << delayUntilCcaEnd.As (Time::S));
m_state->SwitchMaybeToCcaBusy (delayUntilCcaEnd);
return std::make_pair (delayUntilCcaEnd, WIFI_CHANLIST_PRIMARY);
}
return std::nullopt;
}
uint64_t

View File

@@ -27,6 +27,7 @@
#include <map>
#include <tuple>
#include <optional>
#include <utility>
#include "wifi-mpdu-type.h"
#include "wifi-tx-vector.h"
#include "wifi-phy-band.h"
@@ -832,6 +833,15 @@ protected:
*/
virtual uint16_t GetRxChannelWidth (const WifiTxVector& txVector) const;
/**
* Return the delay until CCA busy is ended for a given sensitivity threshold (in dBm) and a given band.
*
* \param thresholdDbm the CCA sensitivity threshold in dBm
* \param band identify the requested band
* \return the delay until CCA busy is ended
*/
Time GetDelayUntilCcaEnd (double thresholdDbm, WifiSpectrumBand band);
/**
* \param currentChannelWidth channel width of the current transmission (MHz)
* \return the width of the guard band (MHz)
@@ -850,6 +860,17 @@ protected:
*/
std::tuple<double, double, double> GetTxMaskRejectionParams (void) const;
using CcaIndication = std::optional<std::pair<Time, WifiChannelListType>>; //!< CCA end time and its corresponding channel list type (can be std::nullopt if IDLE)
/**
* Get CCA end time and its corresponding channel list type when a new signal has been received by the PHY.
*
* \param ppdu the incoming PPDU or nullptr for any signal
* \return CCA end time and its corresponding channel list type when a new signal has been received by the PHY,
* or std::nullopt if all channel list types are IDLE.
*/
virtual CcaIndication GetCcaIndication (const Ptr<const WifiPpdu> ppdu);
Ptr<WifiPhy> m_wifiPhy; //!< Pointer to the owning WifiPhy
Ptr<WifiPhyStateHelper> m_state; //!< Pointer to WifiPhyStateHelper of the WifiPhy (to make it reachable for child classes)

View File

@@ -70,6 +70,9 @@ const VhtPhy::NesExceptionMap VhtPhy::m_exceptionsMap {
{ std::make_tuple (160, 7, 9), 12 } //instead of 10
};
/**
* \brief map a given channel list type to the corresponding scaling factor in dBm
*/
const std::map<WifiChannelListType, double> channelTypeToScalingFactorDbm {
{WIFI_CHANLIST_PRIMARY, 0.0},
{WIFI_CHANLIST_SECONDARY, 0.0},
@@ -77,6 +80,15 @@ const std::map<WifiChannelListType, double> channelTypeToScalingFactorDbm {
{WIFI_CHANLIST_SECONDARY80, 6.0}
};
/**
* \brief map a given secondary channel width to its channel list type
*/
const std::map<uint16_t, WifiChannelListType> secondaryChannels {
{20, WIFI_CHANLIST_SECONDARY},
{40, WIFI_CHANLIST_SECONDARY40},
{80, WIFI_CHANLIST_SECONDARY80}
};
/* *NS_CHECK_STYLE_ON* */
VhtPhy::VhtPhy (bool buildModeList /* = true */)
@@ -576,6 +588,80 @@ VhtPhy::GetCcaThreshold (const Ptr<const WifiPpdu> ppdu, WifiChannelListType cha
}
}
PhyEntity::CcaIndication
VhtPhy::GetCcaIndication (const Ptr<const WifiPpdu> ppdu)
{
NS_LOG_FUNCTION (this);
if (m_wifiPhy->GetChannelWidth () < 80)
{
return HtPhy::GetCcaIndication (ppdu);
}
double ccaThresholdDbm = GetCcaThreshold (ppdu, WIFI_CHANLIST_PRIMARY);
Time delayUntilCcaEnd = GetDelayUntilCcaEnd (ccaThresholdDbm, GetPrimaryBand (20));
if (delayUntilCcaEnd.IsStrictlyPositive ())
{
return std::make_pair (delayUntilCcaEnd, WIFI_CHANLIST_PRIMARY); //if Primary is busy, ignore CCA for Secondary
}
if (ppdu != nullptr)
{
const uint16_t primaryWidth = 20;
uint16_t p20MinFreq =
m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelCenterFrequency (primaryWidth) - (primaryWidth / 2);
uint16_t p20MaxFreq =
m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelCenterFrequency (primaryWidth) + (primaryWidth / 2);
if (ppdu->DoesOverlapChannel (p20MinFreq, p20MaxFreq))
{
/*
* PPDU occupies primary 20 MHz channel, hence we skip CCA sensitivity rules
* for signals not occupying the primary 20 MHz channel.
*/
return std::nullopt;
}
}
std::vector<uint16_t> secondaryWidthsToCheck;
if (ppdu != nullptr)
{
for (const auto& secondaryChannel : secondaryChannels)
{
uint16_t secondaryWidth = secondaryChannel.first;
uint16_t secondaryMinFreq =
m_wifiPhy->GetOperatingChannel ().GetSecondaryChannelCenterFrequency (secondaryWidth) - (secondaryWidth / 2);
uint16_t secondaryMaxFreq =
m_wifiPhy->GetOperatingChannel ().GetSecondaryChannelCenterFrequency (secondaryWidth) + (secondaryWidth / 2);
if ((m_wifiPhy->GetChannelWidth () > secondaryWidth) && ppdu->DoesOverlapChannel (secondaryMinFreq, secondaryMaxFreq))
{
secondaryWidthsToCheck.push_back (secondaryWidth);
}
}
}
else
{
secondaryWidthsToCheck.push_back (20);
secondaryWidthsToCheck.push_back (40);
if (m_wifiPhy->GetChannelWidth () > 80)
{
secondaryWidthsToCheck.push_back (80);
}
}
for (auto secondaryWidth : secondaryWidthsToCheck)
{
auto channelType = secondaryChannels.at (secondaryWidth);
ccaThresholdDbm = GetCcaThreshold (ppdu, channelType);
delayUntilCcaEnd = GetDelayUntilCcaEnd (ccaThresholdDbm, GetSecondaryBand (secondaryWidth));
if (delayUntilCcaEnd.IsStrictlyPositive ())
{
return std::make_pair (delayUntilCcaEnd, channelType);
}
}
return std::nullopt;
}
} //namespace ns3
namespace {

View File

@@ -271,6 +271,7 @@ protected:
PhyFieldRxStatus DoEndReceiveField (WifiPpduField field, Ptr<Event> event) override;
bool IsAllConfigSupported (WifiPpduField field, Ptr<const WifiPpdu> ppdu) const override;
uint32_t GetMaxPsduSize (void) const override;
CcaIndication GetCcaIndication (const Ptr<const WifiPpdu> ppdu) override;
/**
* End receiving the SIG-A, perform VHT-specific actions, and

View File

@@ -2887,7 +2887,7 @@ TestUlOfdmaPhyTransmission::RunOne (void)
Simulator::Schedule (delay + MicroSeconds (50), &TestUlOfdmaPhyTransmission::GenerateInterference, this, interferencePsdRu2, MilliSeconds (100));
ScheduleTest (delay, true,
WifiPhyState::CCA_BUSY, //PHY should move to CCA_BUSY since measurement channel encompasses total channel width
(m_channelWidth >= 40) ? WifiPhyState::IDLE : WifiPhyState::CCA_BUSY, //PHY should move to CCA_BUSY if interference is generated in its primary channel
1, 0, 1000, //One PSDU of 1000 bytes should have been successfully received from STA 1
0, 1, 0); //Reception of the PSDU from STA 2 should have failed (since interference occupies RU 2)
delay += Seconds (1.0);
@@ -2966,7 +2966,7 @@ TestUlOfdmaPhyTransmission::RunOne (void)
bytes = 0;
}
ScheduleTest (delay, true,
WifiPhyState::CCA_BUSY, //PHY should move to CCA_BUSY instead of IDLE due to the interference on measurement channel width
(m_channelWidth >= 40) ? WifiPhyState::IDLE : WifiPhyState::CCA_BUSY, //PHY should move to CCA_BUSY instead of IDLE if HE TB PPDU on primary channel
succ, fail, bytes,
0, 1, 0); //Reception of the PSDU from STA 2 should have failed (since interference from STA 3 on same 20 MHz channel)
delay += Seconds (1.0);