wifi: Implement per-20 MHz CCA sensitivity
This commit is contained in:
committed by
Sébastien Deronne
parent
8a7783e078
commit
383b537fbc
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 */)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user