wifi: Implement per-20 MHz CCA sensitivity

This commit is contained in:
Sebastien Deronne
2022-05-01 13:37:29 +02:00
committed by Sébastien Deronne
parent 8a7783e078
commit 383b537fbc
7 changed files with 142 additions and 8 deletions

View File

@@ -1015,6 +1015,100 @@ HePhy::GetCcaThreshold (const Ptr<const WifiPpdu> ppdu, WifiChannelListType chan
return std::max (VhtPhy::GetCcaThreshold (ppdu, channelType), obssPdLevel);
}
void
HePhy::NotifyCcaBusy (const Ptr<const WifiPpdu> ppdu, Time duration, WifiChannelListType channelType)
{
NS_LOG_FUNCTION (this << duration << channelType);
NS_LOG_DEBUG ("CCA busy for " << channelType << " during " << duration.As (Time::S));
m_state->SwitchMaybeToCcaBusy (duration, channelType, GetPer20MHzDurations (ppdu));
}
std::vector<Time>
HePhy::GetPer20MHzDurations (const Ptr<const WifiPpdu> ppdu)
{
NS_LOG_FUNCTION (this);
/**
* 27.3.20.6.5 Per 20 MHz CCA sensitivity:
* If the operating channel width is greater than 20 MHz and the PHY issues a PHY-CCA.indication primitive,
* the PHY shall set the per20bitmap to indicate the busy/idle status of each 20 MHz subchannel.
*/
if (m_wifiPhy->GetChannelWidth () < 40)
{
return {};
}
std::vector<Time> per20MhzDurations {};
const auto indices = m_wifiPhy->GetOperatingChannel ().GetAll20MHzChannelIndicesInPrimary (m_wifiPhy->GetChannelWidth ());
for (auto index : indices)
{
auto band = m_wifiPhy->GetBand (20, index);
/**
* A signal is present on the 20 MHz subchannel at or above a threshold of 62 dBm at the receiver's antenna(s).
* The PHY shall indicate that the 20 MHz subchannel is busy a period aCCATime after the signal starts and shall
* continue to indicate the 20 MHz subchannel is busy while the threshold continues to be exceeded.
*/
double ccaThresholdDbm = -62;
Time delayUntilCcaEnd = GetDelayUntilCcaEnd (ccaThresholdDbm, band);
if (ppdu)
{
const uint16_t subchannelMinFreq = m_wifiPhy->GetFrequency () - (m_wifiPhy->GetChannelWidth () / 2) + (index * 20);
const uint16_t subchannelMaxFreq = subchannelMinFreq + 20;
const uint16_t ppduBw = ppdu->GetTxVector ().GetChannelWidth ();
if (ppduBw <= m_wifiPhy->GetChannelWidth () && ppdu->DoesOverlapChannel (subchannelMinFreq, subchannelMaxFreq))
{
std::optional<double> obssPdLevel {std::nullopt};
if (m_obssPdAlgorithm)
{
obssPdLevel = m_obssPdAlgorithm->GetObssPdLevel ();
}
switch (ppduBw)
{
case 20:
case 22:
/**
* A 20 MHz non-HT, HT_MF, HT_GF, VHT, or HE PPDU at or above max(72 dBm, OBSS_ PDlevel) at the receiver's antenna(s) is present
* on the 20 MHz subchannel. The PHY shall indicate that the 20 MHz subchannel is busy with > 90% probability within a period aCCAMidTime.
*/
ccaThresholdDbm = obssPdLevel.has_value () ? std::max (-72.0, obssPdLevel.value ()) : -72.0;
band = m_wifiPhy->GetBand (20, index);
break;
case 40:
/**
* The 20 MHz subchannel is in a channel on which a 40 MHz non-HT duplicate, HT_MF, HT_GF, VHT or HE PPDU at or above
* max(72 dBm, OBSS_PDlevel + 3 dB) at the receiver's antenna(s) is present. The PHY shall indicate that the 20 MHz
* subchannel is busy with > 90% probability within a period aCCAMidTime.
*/
ccaThresholdDbm = obssPdLevel.has_value () ? std::max (-72.0, obssPdLevel.value () + 3) : -72.0;
band = m_wifiPhy->GetBand (40, std::floor (index / 2));
break;
case 80:
/**
* The 20 MHz subchannel is in a channel on which an 80 MHz non-HT duplicate, VHT or HE PPDU at or above
* max(69 dBm, OBSS_PDlevel + 6 dB) at the receiver's antenna(s) is present. The PHY shall indicate that
* the 20 MHz subchannel is busy with > 90% probability within a period aCCAMidTime.
*/
ccaThresholdDbm = obssPdLevel.has_value () ? std::max (-69.0, obssPdLevel.value () + 6) : -69.0;
band = m_wifiPhy->GetBand (80, std::floor (index / 4));
break;
case 160:
//Not defined in the standard: keep -62 dBm
break;
default:
NS_ASSERT_MSG (false, "Invalid channel width: " << ppduBw);
}
}
Time ppduCcaDuration = GetDelayUntilCcaEnd (ccaThresholdDbm, band);
delayUntilCcaEnd = std::max (delayUntilCcaEnd, ppduCcaDuration);
}
per20MhzDurations.push_back (delayUntilCcaEnd);
}
return per20MhzDurations;
}
uint64_t
HePhy::ObtainNextUid (const WifiTxVector& txVector)
{

View File

@@ -104,6 +104,7 @@ public:
void StartTx (Ptr<const WifiPpdu> ppdu) override;
Time CalculateTxDuration (WifiConstPsduMap psduMap, const WifiTxVector& txVector, WifiPhyBand band) const override;
double GetCcaThreshold (const Ptr<const WifiPpdu> ppdu, WifiChannelListType channelType) const override;
void NotifyCcaBusy (const Ptr<const WifiPpdu> ppdu, Time duration, WifiChannelListType channelType) override;
/**
* \return the BSS color of this PHY.
@@ -478,6 +479,18 @@ private:
uint8_t GetNumberBccEncoders (const WifiTxVector& txVector) const override;
Time GetSymbolDuration (const WifiTxVector& txVector) const override;
/**
* Compute the per-20 MHz CCA durations vector that indicates
* for how long each 20 MHz subchannel (corresponding to the
* index of the element in the vector) is busy and where a zero duration
* indicates that the subchannel is idle. The vector is non-empty if the
* operational channel width is larger than 20 MHz.
*
* \param ppdu the incoming PPDU or nullptr for any signal
* \return the per-20 MHz CCA durations vector
*/
std::vector<Time> GetPer20MHzDurations (const Ptr<const WifiPpdu> ppdu);
/**
* Create and return the HE MCS corresponding to
* the provided index.

View File

@@ -275,7 +275,7 @@ PhyEntity::StartReceiveField (WifiPpduField field, Ptr<Event> event)
NS_ABORT_MSG_IF (!supported, "Unknown field " << field << " for this PHY entity"); //TODO see what to do if not supported
Time duration = GetDuration (field, event->GetTxVector ());
m_wifiPhy->m_endPhyRxEvent = Simulator::Schedule (duration, &PhyEntity::EndReceiveField, this, field, event);
m_state->SwitchMaybeToCcaBusy (duration); //keep in CCA busy state up to reception of Data (will then switch to RX)
m_wifiPhy->NotifyCcaBusy (event->GetPpdu (), duration); //keep in CCA busy state up to reception of Data (will then switch to RX)
}
void
@@ -311,7 +311,7 @@ PhyEntity::EndReceiveField (WifiPpduField field, Ptr<Event> event)
m_wifiPhy->m_phyRxPayloadBeginTrace (txVector, NanoSeconds (0)); //this callback (equivalent to PHY-RXSTART primitive) is also triggered for filtered PPDUs
}
m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (ppdu), status.reason);
m_state->SwitchMaybeToCcaBusy (GetRemainingDurationAfterField (ppdu, field)); //keep in CCA busy state till the end
m_wifiPhy->NotifyCcaBusy (ppdu, GetRemainingDurationAfterField (ppdu, field));
//no break
case IGNORE:
//Keep in Rx state and reset at end
@@ -896,7 +896,7 @@ PhyEntity::EndPreambleDetectionPeriod (Ptr<Event> event)
//Continue receiving preamble
Time durationTillEnd = GetDuration (WIFI_PPDU_FIELD_PREAMBLE, event->GetTxVector ()) - m_wifiPhy->GetPreambleDetectionDuration ();
m_state->SwitchMaybeToCcaBusy (durationTillEnd); //will be prolonged by next field
m_wifiPhy->NotifyCcaBusy (event->GetPpdu (), durationTillEnd); //will be prolonged by next field
m_wifiPhy->m_endPhyRxEvent = Simulator::Schedule (durationTillEnd, &PhyEntity::EndReceiveField, this, WIFI_PPDU_FIELD_PREAMBLE, event);
}
else
@@ -1102,6 +1102,14 @@ PhyEntity::GetCcaIndication (const Ptr<const WifiPpdu> ppdu)
return std::nullopt;
}
void
PhyEntity::NotifyCcaBusy (const Ptr<const WifiPpdu> /*ppdu*/, Time duration, WifiChannelListType channelType)
{
NS_LOG_FUNCTION (this << duration << channelType);
NS_LOG_DEBUG ("CCA busy for " << channelType << " during " << duration.As (Time::S));
m_state->SwitchMaybeToCcaBusy (duration, channelType, {});
}
uint64_t
PhyEntity::ObtainNextUid (const WifiTxVector& /* txVector */)
{

View File

@@ -433,7 +433,14 @@ public:
* \param ppdu the incoming PPDU or nullptr for any signal
*/
virtual void SwitchMaybeToCcaBusy (const Ptr<const WifiPpdu> ppdu);
/**
* Notify PHY state helper to switch to CCA busy state,
*
* \param ppdu the incoming PPDU or nullptr for any signal
* \param duration the duration of the CCA state
* \param channelType the channel type for which the CCA busy state is reported.
*/
virtual void NotifyCcaBusy (const Ptr<const WifiPpdu> ppdu, Time duration, WifiChannelListType channelType);
/**
* This function is called by SpectrumWifiPhy to send
* the PPDU while performing amendment-specific actions.

View File

@@ -223,7 +223,6 @@ public:
void SwitchFromRxEndError (void);
/**
* Switch to CCA busy.
* TODO: remove default values
*
* \param duration the duration of the CCA state
* \param channelType the channel type for which the CCA busy state is reported.
@@ -232,9 +231,8 @@ public:
* indicates that the subchannel is idle. The vector is non-empty if the PHY supports 802.11ax
* or later and if the operational channel width is larger than 20 MHz.
*/
void SwitchMaybeToCcaBusy (Time duration,
WifiChannelListType channelType = WIFI_CHANLIST_PRIMARY,
const std::vector<Time>& per20MhzDurations = std::vector<Time>{});
void SwitchMaybeToCcaBusy (Time duration, WifiChannelListType channelType,
const std::vector<Time>& per20MhzDurations);
/**
* Switch to sleep mode.
*/

View File

@@ -1902,6 +1902,13 @@ WifiPhy::SwitchMaybeToCcaBusy (const Ptr<const WifiPpdu> ppdu)
GetPhyEntity (m_standard)->SwitchMaybeToCcaBusy (ppdu);
}
void
WifiPhy::NotifyCcaBusy (const Ptr<const WifiPpdu> ppdu, Time duration)
{
NS_LOG_FUNCTION (this << duration);
GetPhyEntity (m_standard)->NotifyCcaBusy (ppdu, duration, WIFI_CHANLIST_PRIMARY);
}
void
WifiPhy::AbortCurrentReception (WifiPhyRxfailureReason reason)
{

View File

@@ -1104,6 +1104,13 @@ protected:
* \param ppdu the incoming PPDU or nullptr for any signal
*/
void SwitchMaybeToCcaBusy (const Ptr<const WifiPpdu> ppdu);
/**
* Notify PHY state helper to switch to CCA busy state,
*
* \param ppdu the incoming PPDU or nullptr for any signal
* \param duration the duration of the CCA state
*/
void NotifyCcaBusy (const Ptr<const WifiPpdu> ppdu, Time duration);
/**
* Add the PHY entity to the map of supported PHY entities for the