wifi: Extend InterferenceHelper to track interferences for multiple spectrum PHY interfaces
This commit is contained in:
committed by
Sebastien Deronne
parent
1635f0a57e
commit
d666ad494e
@@ -209,7 +209,20 @@ void
|
||||
InterferenceHelper::DoDispose()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
RemoveBands();
|
||||
for (auto [range, niChangesPerBand] : m_niChanges)
|
||||
{
|
||||
for (auto it : niChangesPerBand)
|
||||
{
|
||||
it.second.clear();
|
||||
}
|
||||
niChangesPerBand.clear();
|
||||
}
|
||||
m_niChanges.clear();
|
||||
for (auto it : m_firstPowers)
|
||||
{
|
||||
it.second.clear();
|
||||
}
|
||||
m_firstPowers.clear();
|
||||
m_errorRateModel = nullptr;
|
||||
}
|
||||
|
||||
@@ -218,15 +231,18 @@ InterferenceHelper::Add(Ptr<const WifiPpdu> ppdu,
|
||||
const WifiTxVector& txVector,
|
||||
Time duration,
|
||||
RxPowerWattPerChannelBand& rxPowerW,
|
||||
const FrequencyRange& range,
|
||||
bool isStartOfdmaRxing)
|
||||
{
|
||||
Ptr<Event> event = Create<Event>(ppdu, txVector, duration, std::move(rxPowerW));
|
||||
AppendEvent(event, isStartOfdmaRxing);
|
||||
AppendEvent(event, range, isStartOfdmaRxing);
|
||||
return event;
|
||||
}
|
||||
|
||||
void
|
||||
InterferenceHelper::AddForeignSignal(Time duration, RxPowerWattPerChannelBand& rxPowerW)
|
||||
InterferenceHelper::AddForeignSignal(Time duration,
|
||||
RxPowerWattPerChannelBand& rxPowerW,
|
||||
const FrequencyRange& range)
|
||||
{
|
||||
// Parameters other than duration and rxPowerW are unused for this type
|
||||
// of signal, so we provide dummy versions
|
||||
@@ -236,32 +252,40 @@ InterferenceHelper::AddForeignSignal(Time duration, RxPowerWattPerChannelBand& r
|
||||
Ptr<WifiPpdu> fakePpdu = Create<WifiPpdu>(Create<WifiPsdu>(Create<Packet>(0), hdr),
|
||||
WifiTxVector(),
|
||||
WifiPhyOperatingChannel());
|
||||
Add(fakePpdu, WifiTxVector(), duration, rxPowerW);
|
||||
Add(fakePpdu, WifiTxVector(), duration, rxPowerW, range);
|
||||
}
|
||||
|
||||
void
|
||||
InterferenceHelper::RemoveBands()
|
||||
InterferenceHelper::RemoveBands(FrequencyRange range)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for (auto it : m_niChanges)
|
||||
NS_LOG_FUNCTION(this << range);
|
||||
if ((m_niChanges.count(range) == 0) && (m_firstPowers.count(range) == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto niChangesPerBand = m_niChanges.at(range);
|
||||
for (auto it : niChangesPerBand)
|
||||
{
|
||||
it.second.clear();
|
||||
}
|
||||
m_niChanges.clear();
|
||||
m_firstPowers.clear();
|
||||
niChangesPerBand.clear();
|
||||
m_niChanges.erase(range);
|
||||
m_firstPowers.at(range).clear();
|
||||
m_firstPowers.erase(range);
|
||||
}
|
||||
|
||||
void
|
||||
InterferenceHelper::AddBand(WifiSpectrumBand band)
|
||||
InterferenceHelper::AddBand(WifiSpectrumBand band, const FrequencyRange& range)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << band.first << band.second);
|
||||
NS_ASSERT(m_niChanges.find(band) == m_niChanges.end());
|
||||
NS_LOG_FUNCTION(this << band.first << band.second << range);
|
||||
NS_ASSERT(m_niChanges.count(range) == 0 || m_niChanges.at(range).count(band) == 0);
|
||||
NS_ASSERT(m_firstPowers.count(range) == 0 || m_firstPowers.at(range).count(band) == 0);
|
||||
NiChanges niChanges;
|
||||
auto result = m_niChanges.insert({band, niChanges});
|
||||
auto result = m_niChanges[range].insert({band, niChanges});
|
||||
NS_ASSERT(result.second);
|
||||
// Always have a zero power noise event in the list
|
||||
AddNiChangeEvent(Time(0), NiChange(0.0, nullptr), result.first);
|
||||
m_firstPowers.insert({band, 0.0});
|
||||
m_firstPowers[range].insert({band, 0.0});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -289,11 +313,15 @@ InterferenceHelper::SetNumberOfReceiveAntennas(uint8_t rx)
|
||||
}
|
||||
|
||||
Time
|
||||
InterferenceHelper::GetEnergyDuration(double energyW, WifiSpectrumBand band)
|
||||
InterferenceHelper::GetEnergyDuration(double energyW,
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << energyW << band.first << band.second << range);
|
||||
Time now = Simulator::Now();
|
||||
auto niIt = m_niChanges.find(band);
|
||||
NS_ASSERT(niIt != m_niChanges.end());
|
||||
NS_ABORT_IF(m_niChanges.count(range) == 0);
|
||||
auto niIt = m_niChanges.at(range).find(band);
|
||||
NS_ABORT_IF(niIt == m_niChanges.at(range).end());
|
||||
auto i = GetPreviousPosition(now, niIt);
|
||||
Time end = i->first;
|
||||
for (; i != niIt->second.end(); ++i)
|
||||
@@ -309,14 +337,18 @@ InterferenceHelper::GetEnergyDuration(double energyW, WifiSpectrumBand band)
|
||||
}
|
||||
|
||||
void
|
||||
InterferenceHelper::AppendEvent(Ptr<Event> event, bool isStartOfdmaRxing)
|
||||
InterferenceHelper::AppendEvent(Ptr<Event> event,
|
||||
const FrequencyRange& range,
|
||||
bool isStartOfdmaRxing)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << event << isStartOfdmaRxing);
|
||||
NS_LOG_FUNCTION(this << event << range << isStartOfdmaRxing);
|
||||
NS_ABORT_IF(m_niChanges.count(range) == 0);
|
||||
NS_ABORT_IF(m_firstPowers.count(range) == 0);
|
||||
for (const auto& it : event->GetRxPowerWPerBand())
|
||||
{
|
||||
WifiSpectrumBand band = it.first;
|
||||
auto niIt = m_niChanges.find(band);
|
||||
NS_ASSERT(niIt != m_niChanges.end());
|
||||
auto niIt = m_niChanges.at(range).find(band);
|
||||
NS_ABORT_IF(niIt == m_niChanges.at(range).end());
|
||||
double previousPowerStart = 0;
|
||||
double previousPowerEnd = 0;
|
||||
auto previousPowerPosition = GetPreviousPosition(event->GetStartTime(), niIt);
|
||||
@@ -324,7 +356,7 @@ InterferenceHelper::AppendEvent(Ptr<Event> event, bool isStartOfdmaRxing)
|
||||
previousPowerEnd = GetPreviousPosition(event->GetEndTime(), niIt)->second.GetPower();
|
||||
if (!m_rxing)
|
||||
{
|
||||
m_firstPowers.find(band)->second = previousPowerStart;
|
||||
m_firstPowers.at(range).find(band)->second = previousPowerStart;
|
||||
// Always leave the first zero power noise event in the list
|
||||
niIt->second.erase(++(niIt->second.begin()), ++previousPowerPosition);
|
||||
}
|
||||
@@ -333,7 +365,7 @@ InterferenceHelper::AppendEvent(Ptr<Event> event, bool isStartOfdmaRxing)
|
||||
// When the first UL-OFDMA payload is received, we need to set m_firstPowers
|
||||
// so that it takes into account interferences that arrived between the start of the
|
||||
// UL MU transmission and the start of UL-OFDMA payload.
|
||||
m_firstPowers.find(band)->second = previousPowerStart;
|
||||
m_firstPowers.at(range).find(band)->second = previousPowerStart;
|
||||
}
|
||||
auto first =
|
||||
AddNiChangeEvent(event->GetStartTime(), NiChange(previousPowerStart, event), niIt);
|
||||
@@ -346,15 +378,18 @@ InterferenceHelper::AppendEvent(Ptr<Event> event, bool isStartOfdmaRxing)
|
||||
}
|
||||
|
||||
void
|
||||
InterferenceHelper::UpdateEvent(Ptr<Event> event, const RxPowerWattPerChannelBand& rxPower)
|
||||
InterferenceHelper::UpdateEvent(Ptr<Event> event,
|
||||
const RxPowerWattPerChannelBand& rxPower,
|
||||
const FrequencyRange& range)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << event);
|
||||
NS_LOG_FUNCTION(this << event << range);
|
||||
NS_ABORT_IF(m_niChanges.count(range) == 0);
|
||||
// This is called for UL MU events, in order to scale power as long as UL MU PPDUs arrive
|
||||
for (const auto& it : rxPower)
|
||||
{
|
||||
WifiSpectrumBand band = it.first;
|
||||
auto niIt = m_niChanges.find(band);
|
||||
NS_ASSERT(niIt != m_niChanges.end());
|
||||
auto niIt = m_niChanges.at(range).find(band);
|
||||
NS_ABORT_IF(niIt == m_niChanges.at(range).end());
|
||||
auto first = GetPreviousPosition(event->GetStartTime(), niIt);
|
||||
auto last = GetPreviousPosition(event->GetEndTime(), niIt);
|
||||
for (auto i = first; i != last; ++i)
|
||||
@@ -400,21 +435,24 @@ InterferenceHelper::CalculateSnr(double signal,
|
||||
double
|
||||
InterferenceHelper::CalculateNoiseInterferenceW(Ptr<Event> event,
|
||||
NiChangesPerBand* nis,
|
||||
WifiSpectrumBand band) const
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << band.first << band.second);
|
||||
auto firstPower_it = m_firstPowers.find(band);
|
||||
NS_ASSERT(firstPower_it != m_firstPowers.end());
|
||||
NS_LOG_FUNCTION(this << band.first << band.second << range);
|
||||
NS_ABORT_IF(m_firstPowers.count(range) == 0);
|
||||
auto firstPower_it = m_firstPowers.at(range).find(band);
|
||||
NS_ABORT_IF(firstPower_it == m_firstPowers.at(range).end());
|
||||
double noiseInterferenceW = firstPower_it->second;
|
||||
auto niIt = m_niChanges.find(band);
|
||||
NS_ASSERT(niIt != m_niChanges.end());
|
||||
NS_ABORT_IF(m_niChanges.count(range) == 0);
|
||||
auto niIt = m_niChanges.at(range).find(band);
|
||||
NS_ABORT_IF(niIt == m_niChanges.at(range).end());
|
||||
auto it = niIt->second.find(event->GetStartTime());
|
||||
for (; it != niIt->second.end() && it->first < Simulator::Now(); ++it)
|
||||
{
|
||||
noiseInterferenceW = it->second.GetPower() - event->GetRxPowerW(band);
|
||||
}
|
||||
it = niIt->second.find(event->GetStartTime());
|
||||
NS_ASSERT(it != niIt->second.end());
|
||||
NS_ABORT_IF(it == niIt->second.end());
|
||||
for (; it != niIt->second.end() && it->second.GetEvent() != event; ++it)
|
||||
{
|
||||
;
|
||||
@@ -480,6 +518,7 @@ InterferenceHelper::CalculatePayloadPer(Ptr<const Event> event,
|
||||
uint16_t channelWidth,
|
||||
NiChangesPerBand* nis,
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range,
|
||||
uint16_t staId,
|
||||
std::pair<Time, Time> window) const
|
||||
{
|
||||
@@ -500,7 +539,9 @@ InterferenceHelper::CalculatePayloadPer(Ptr<const Event> event,
|
||||
}
|
||||
Time windowStart = phyPayloadStart + window.first;
|
||||
Time windowEnd = phyPayloadStart + window.second;
|
||||
double noiseInterferenceW = m_firstPowers.find(band)->second;
|
||||
NS_ABORT_IF(m_firstPowers.count(range) == 0);
|
||||
NS_ABORT_IF(m_firstPowers.at(range).count(band) == 0);
|
||||
double noiseInterferenceW = m_firstPowers.at(range).at(band);
|
||||
double powerW = event->GetRxPowerW(band);
|
||||
while (++j != niIt.cend())
|
||||
{
|
||||
@@ -551,9 +592,10 @@ InterferenceHelper::CalculatePhyHeaderSectionPsr(
|
||||
NiChangesPerBand* nis,
|
||||
uint16_t channelWidth,
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range,
|
||||
PhyEntity::PhyHeaderSections phyHeaderSections) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << band.first << band.second);
|
||||
NS_LOG_FUNCTION(this << band.first << band.second << range);
|
||||
double psr = 1.0; /* Packet Success Rate */
|
||||
auto niIt = nis->find(band)->second;
|
||||
auto j = niIt.begin();
|
||||
@@ -566,7 +608,9 @@ InterferenceHelper::CalculatePhyHeaderSectionPsr(
|
||||
}
|
||||
|
||||
Time previous = j->first;
|
||||
double noiseInterferenceW = m_firstPowers.find(band)->second;
|
||||
NS_ABORT_IF(m_firstPowers.count(range) == 0);
|
||||
NS_ABORT_IF(m_firstPowers.at(range).count(band) == 0);
|
||||
double noiseInterferenceW = m_firstPowers.at(range).at(band);
|
||||
double powerW = event->GetRxPowerW(band);
|
||||
while (++j != niIt.end())
|
||||
{
|
||||
@@ -613,9 +657,10 @@ InterferenceHelper::CalculatePhyHeaderPer(Ptr<const Event> event,
|
||||
NiChangesPerBand* nis,
|
||||
uint16_t channelWidth,
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range,
|
||||
WifiPpduField header) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << band.first << band.second << header);
|
||||
NS_LOG_FUNCTION(this << band.first << band.second << range << header);
|
||||
auto niIt = nis->find(band)->second;
|
||||
auto phyEntity = WifiPhy::GetStaticPhyEntity(event->GetTxVector().GetModulationClass());
|
||||
|
||||
@@ -632,7 +677,7 @@ InterferenceHelper::CalculatePhyHeaderPer(Ptr<const Event> event,
|
||||
double psr = 1.0;
|
||||
if (!sections.empty())
|
||||
{
|
||||
psr = CalculatePhyHeaderSectionPsr(event, nis, channelWidth, band, sections);
|
||||
psr = CalculatePhyHeaderSectionPsr(event, nis, channelWidth, band, range, sections);
|
||||
}
|
||||
return 1 - psr;
|
||||
}
|
||||
@@ -641,13 +686,14 @@ struct PhyEntity::SnrPer
|
||||
InterferenceHelper::CalculatePayloadSnrPer(Ptr<Event> event,
|
||||
uint16_t channelWidth,
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range,
|
||||
uint16_t staId,
|
||||
std::pair<Time, Time> relativeMpduStartStop) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << channelWidth << band.first << band.second << staId
|
||||
NS_LOG_FUNCTION(this << channelWidth << band.first << band.second << range << staId
|
||||
<< relativeMpduStartStop.first << relativeMpduStartStop.second);
|
||||
NiChangesPerBand ni;
|
||||
double noiseInterferenceW = CalculateNoiseInterferenceW(event, &ni, band);
|
||||
double noiseInterferenceW = CalculateNoiseInterferenceW(event, &ni, band, range);
|
||||
double snr = CalculateSnr(event->GetRxPowerW(band),
|
||||
noiseInterferenceW,
|
||||
channelWidth,
|
||||
@@ -656,7 +702,8 @@ InterferenceHelper::CalculatePayloadSnrPer(Ptr<Event> event,
|
||||
/* calculate the SNIR at the start of the MPDU (located through windowing) and accumulate
|
||||
* all SNIR changes in the SNIR vector.
|
||||
*/
|
||||
double per = CalculatePayloadPer(event, channelWidth, &ni, band, staId, relativeMpduStartStop);
|
||||
double per =
|
||||
CalculatePayloadPer(event, channelWidth, &ni, band, range, staId, relativeMpduStartStop);
|
||||
|
||||
return PhyEntity::SnrPer(snr, per);
|
||||
}
|
||||
@@ -665,10 +712,11 @@ double
|
||||
InterferenceHelper::CalculateSnr(Ptr<Event> event,
|
||||
uint16_t channelWidth,
|
||||
uint8_t nss,
|
||||
WifiSpectrumBand band) const
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range) const
|
||||
{
|
||||
NiChangesPerBand ni;
|
||||
double noiseInterferenceW = CalculateNoiseInterferenceW(event, &ni, band);
|
||||
double noiseInterferenceW = CalculateNoiseInterferenceW(event, &ni, band, range);
|
||||
double snr = CalculateSnr(event->GetRxPowerW(band), noiseInterferenceW, channelWidth, nss);
|
||||
return snr;
|
||||
}
|
||||
@@ -677,30 +725,34 @@ struct PhyEntity::SnrPer
|
||||
InterferenceHelper::CalculatePhyHeaderSnrPer(Ptr<Event> event,
|
||||
uint16_t channelWidth,
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range,
|
||||
WifiPpduField header) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << band.first << band.second << header);
|
||||
NiChangesPerBand ni;
|
||||
double noiseInterferenceW = CalculateNoiseInterferenceW(event, &ni, band);
|
||||
double noiseInterferenceW = CalculateNoiseInterferenceW(event, &ni, band, range);
|
||||
double snr = CalculateSnr(event->GetRxPowerW(band), noiseInterferenceW, channelWidth, 1);
|
||||
|
||||
/* calculate the SNIR at the start of the PHY header and accumulate
|
||||
* all SNIR changes in the SNIR vector.
|
||||
*/
|
||||
double per = CalculatePhyHeaderPer(event, &ni, channelWidth, band, header);
|
||||
double per = CalculatePhyHeaderPer(event, &ni, channelWidth, band, range, header);
|
||||
|
||||
return PhyEntity::SnrPer(snr, per);
|
||||
}
|
||||
|
||||
void
|
||||
InterferenceHelper::EraseEvents()
|
||||
InterferenceHelper::EraseEvents(const FrequencyRange& range)
|
||||
{
|
||||
for (auto niIt = m_niChanges.begin(); niIt != m_niChanges.end(); ++niIt)
|
||||
NS_LOG_FUNCTION(this << range);
|
||||
NS_ABORT_IF(m_niChanges.count(range) == 0);
|
||||
NS_ABORT_IF(m_firstPowers.count(range) == 0);
|
||||
for (auto niIt = m_niChanges.at(range).begin(); niIt != m_niChanges.at(range).end(); ++niIt)
|
||||
{
|
||||
niIt->second.clear();
|
||||
// Always have a zero power noise event in the list
|
||||
AddNiChangeEvent(Time(0), NiChange(0.0, nullptr), niIt);
|
||||
m_firstPowers.at(niIt->first) = 0.0;
|
||||
m_firstPowers.at(range).at(niIt->first) = 0.0;
|
||||
}
|
||||
m_rxing = false;
|
||||
}
|
||||
@@ -735,17 +787,19 @@ InterferenceHelper::NotifyRxStart()
|
||||
}
|
||||
|
||||
void
|
||||
InterferenceHelper::NotifyRxEnd(Time endTime)
|
||||
InterferenceHelper::NotifyRxEnd(Time endTime, const FrequencyRange& range)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << endTime);
|
||||
NS_LOG_FUNCTION(this << endTime << range);
|
||||
NS_ABORT_IF(m_niChanges.count(range) == 0);
|
||||
NS_ABORT_IF(m_firstPowers.count(range) == 0);
|
||||
m_rxing = false;
|
||||
// Update m_firstPowers for frame capture
|
||||
for (auto niIt = m_niChanges.begin(); niIt != m_niChanges.end(); ++niIt)
|
||||
for (auto niIt = m_niChanges.at(range).begin(); niIt != m_niChanges.at(range).end(); ++niIt)
|
||||
{
|
||||
NS_ASSERT(niIt->second.size() > 1);
|
||||
auto it = GetPreviousPosition(endTime, niIt);
|
||||
it--;
|
||||
m_firstPowers.find(niIt->first)->second = it->second.GetPower();
|
||||
m_firstPowers.at(range).find(niIt->first)->second = it->second.GetPower();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,14 +147,17 @@ class InterferenceHelper : public Object
|
||||
/**
|
||||
* Add a frequency band.
|
||||
*
|
||||
* \param band the band to be created
|
||||
* \param band the band to be added
|
||||
* \param range the frequency range the band to add belongs to
|
||||
*/
|
||||
void AddBand(WifiSpectrumBand band);
|
||||
void AddBand(WifiSpectrumBand band, const FrequencyRange& range);
|
||||
|
||||
/**
|
||||
* Remove the frequency bands.
|
||||
* Remove the frequency bands for a given frequency range.
|
||||
*
|
||||
* \param range the frequency range the bands to remove belong to
|
||||
*/
|
||||
void RemoveBands();
|
||||
void RemoveBands(FrequencyRange range);
|
||||
|
||||
/**
|
||||
* Set the noise figure.
|
||||
@@ -186,12 +189,13 @@ class InterferenceHelper : public Object
|
||||
/**
|
||||
* \param energyW the minimum energy (W) requested
|
||||
* \param band identify the requested band
|
||||
* \param range the frequency range the requested band belongs to
|
||||
*
|
||||
* \returns the expected amount of time the observed
|
||||
* energy on the medium for a given band will
|
||||
* be higher than the requested threshold.
|
||||
*/
|
||||
Time GetEnergyDuration(double energyW, WifiSpectrumBand band);
|
||||
Time GetEnergyDuration(double energyW, WifiSpectrumBand band, const FrequencyRange& range);
|
||||
|
||||
/**
|
||||
* Add the PPDU-related signal to interference helper.
|
||||
@@ -200,6 +204,7 @@ class InterferenceHelper : public Object
|
||||
* \param txVector the TXVECTOR
|
||||
* \param duration the PPDU duration
|
||||
* \param rxPower received power per band (W)
|
||||
* \param range the frequency range in which the signal has been detected
|
||||
* \param isStartOfdmaRxing flag whether the event corresponds to the start of the OFDMA payload
|
||||
* reception (only used for UL-OFDMA) //TODO simplify this once WifiPpdu is subclassed by adding
|
||||
* an attribute
|
||||
@@ -210,14 +215,18 @@ class InterferenceHelper : public Object
|
||||
const WifiTxVector& txVector,
|
||||
Time duration,
|
||||
RxPowerWattPerChannelBand& rxPower,
|
||||
const FrequencyRange& range,
|
||||
bool isStartOfdmaRxing = false);
|
||||
|
||||
/**
|
||||
* Add a non-Wifi signal to interference helper.
|
||||
* \param duration the duration of the signal
|
||||
* \param rxPower received power per band (W)
|
||||
* \param range the frequency range in which the non-wifi signal has been detected
|
||||
*/
|
||||
void AddForeignSignal(Time duration, RxPowerWattPerChannelBand& rxPower);
|
||||
void AddForeignSignal(Time duration,
|
||||
RxPowerWattPerChannelBand& rxPower,
|
||||
const FrequencyRange& range);
|
||||
/**
|
||||
* Calculate the SNIR at the start of the payload and accumulate
|
||||
* all SNIR changes in the SNIR vector for each MPDU of an A-MPDU.
|
||||
@@ -228,6 +237,7 @@ class InterferenceHelper : public Object
|
||||
* \param event the event corresponding to the first time the corresponding PPDU arrives
|
||||
* \param channelWidth the channel width used to transmit the PSDU (in MHz)
|
||||
* \param band identify the band used by the PSDU
|
||||
* \param range the frequency range the band belongs to
|
||||
* \param staId the station ID of the PSDU (only used for MU)
|
||||
* \param relativeMpduStartStop the time window (pair of start and end times) of PHY payload to
|
||||
* focus on
|
||||
@@ -238,6 +248,7 @@ class InterferenceHelper : public Object
|
||||
Ptr<Event> event,
|
||||
uint16_t channelWidth,
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range,
|
||||
uint16_t staId,
|
||||
std::pair<Time, Time> relativeMpduStartStop) const;
|
||||
/**
|
||||
@@ -247,13 +258,15 @@ class InterferenceHelper : public Object
|
||||
* \param channelWidth the channel width (in MHz)
|
||||
* \param nss the number of spatial streams
|
||||
* \param band identify the band used by the PSDU
|
||||
* \param range the frequency range the band belongs to
|
||||
*
|
||||
* \return the SNR for the PPDU in linear scale
|
||||
*/
|
||||
double CalculateSnr(Ptr<Event> event,
|
||||
uint16_t channelWidth,
|
||||
uint8_t nss,
|
||||
WifiSpectrumBand band) const;
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range) const;
|
||||
/**
|
||||
* Calculate the SNIR at the start of the PHY header and accumulate
|
||||
* all SNIR changes in the SNIR vector.
|
||||
@@ -261,6 +274,7 @@ class InterferenceHelper : public Object
|
||||
* \param event the event corresponding to the first time the corresponding PPDU arrives
|
||||
* \param channelWidth the channel width (in MHz) for header measurement
|
||||
* \param band identify the band used by the PSDU
|
||||
* \param range the frequency range the band belongs to
|
||||
* \param header the PHY header to consider
|
||||
*
|
||||
* \return struct of SNR and PER
|
||||
@@ -268,6 +282,7 @@ class InterferenceHelper : public Object
|
||||
struct PhyEntity::SnrPer CalculatePhyHeaderSnrPer(Ptr<Event> event,
|
||||
uint16_t channelWidth,
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range,
|
||||
WifiPpduField header) const;
|
||||
|
||||
/**
|
||||
@@ -278,20 +293,25 @@ class InterferenceHelper : public Object
|
||||
* Notify that RX has ended.
|
||||
*
|
||||
* \param endTime the end time of the signal
|
||||
* \param range the frequency range in which the signal event has been detected
|
||||
*/
|
||||
void NotifyRxEnd(Time endTime);
|
||||
void NotifyRxEnd(Time endTime, const FrequencyRange& range);
|
||||
/**
|
||||
* Erase all events.
|
||||
* Erase all events that belong to a given frequency range.
|
||||
* \param range the frequency range
|
||||
*/
|
||||
void EraseEvents();
|
||||
void EraseEvents(const FrequencyRange& range);
|
||||
|
||||
/**
|
||||
* Update event to scale its received power (W) per band.
|
||||
*
|
||||
* \param event the event to be updated
|
||||
* \param rxPower the received power (W) per band to be added to the current event
|
||||
* \param range the frequency range in which the signal event has been detected
|
||||
*/
|
||||
void UpdateEvent(Ptr<Event> event, const RxPowerWattPerChannelBand& rxPower);
|
||||
void UpdateEvent(Ptr<Event> event,
|
||||
const RxPowerWattPerChannelBand& rxPower,
|
||||
const FrequencyRange& range);
|
||||
|
||||
protected:
|
||||
void DoDispose() override;
|
||||
@@ -393,19 +413,30 @@ class InterferenceHelper : public Object
|
||||
*/
|
||||
using NiChangesPerBand = std::map<WifiSpectrumBand, NiChanges>;
|
||||
|
||||
/**
|
||||
* Map of NiChanges per band and per range
|
||||
*/
|
||||
using NiChangesPerBandPerRange = std::map<FrequencyRange, NiChangesPerBand>;
|
||||
|
||||
/**
|
||||
* Map of first power per band
|
||||
*/
|
||||
using FirstPowerPerBand = std::map<WifiSpectrumBand, double>;
|
||||
|
||||
/**
|
||||
* Map of first power per band and per range
|
||||
*/
|
||||
using FirstPowerPerBandPerRange = std::map<FrequencyRange, FirstPowerPerBand>;
|
||||
|
||||
/**
|
||||
* Append the given Event.
|
||||
*
|
||||
* \param event the event to be appended
|
||||
* \param range the frequency range in which the signal event has been detected
|
||||
* \param isStartOfdmaRxing flag whether event corresponds to the start of the OFDMA payload
|
||||
* reception (only used for UL-OFDMA)
|
||||
*/
|
||||
void AppendEvent(Ptr<Event> event, bool isStartOfdmaRxing);
|
||||
void AppendEvent(Ptr<Event> event, const FrequencyRange& range, bool isStartOfdmaRxing);
|
||||
|
||||
/**
|
||||
* Calculate noise and interference power in W.
|
||||
@@ -413,12 +444,14 @@ class InterferenceHelper : public Object
|
||||
* \param event the event
|
||||
* \param nis the NiChanges
|
||||
* \param band the band
|
||||
* \param range the frequency range
|
||||
*
|
||||
* \return noise and interference power
|
||||
*/
|
||||
double CalculateNoiseInterferenceW(Ptr<Event> event,
|
||||
NiChangesPerBand* nis,
|
||||
WifiSpectrumBand band) const;
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range) const;
|
||||
/**
|
||||
* Calculate the error rate of the given PHY payload only in the provided time
|
||||
* window (thus enabling per MPDU PER information). The PHY payload can be divided into
|
||||
@@ -428,6 +461,7 @@ class InterferenceHelper : public Object
|
||||
* \param channelWidth the channel width used to transmit the PSDU (in MHz)
|
||||
* \param nis the NiChanges
|
||||
* \param band identify the band used by the PSDU
|
||||
* \param range the frequency range the band belongs to
|
||||
* \param staId the station ID of the PSDU (only used for MU)
|
||||
* \param window time window (pair of start and end times) of PHY payload to focus on
|
||||
*
|
||||
@@ -437,6 +471,7 @@ class InterferenceHelper : public Object
|
||||
uint16_t channelWidth,
|
||||
NiChangesPerBand* nis,
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range,
|
||||
uint16_t staId,
|
||||
std::pair<Time, Time> window) const;
|
||||
/**
|
||||
@@ -447,6 +482,7 @@ class InterferenceHelper : public Object
|
||||
* \param nis the NiChanges
|
||||
* \param channelWidth the channel width (in MHz) for header measurement
|
||||
* \param band the band
|
||||
* \param range the frequency range
|
||||
* \param header the PHY header to consider
|
||||
*
|
||||
* \return the error rate of the HT PHY header
|
||||
@@ -455,6 +491,7 @@ class InterferenceHelper : public Object
|
||||
NiChangesPerBand* nis,
|
||||
uint16_t channelWidth,
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range,
|
||||
WifiPpduField header) const;
|
||||
/**
|
||||
* Calculate the success rate of the PHY header sections for the provided event.
|
||||
@@ -463,6 +500,7 @@ class InterferenceHelper : public Object
|
||||
* \param nis the NiChanges
|
||||
* \param channelWidth the channel width (in MHz) for header measurement
|
||||
* \param band the band
|
||||
* \param range the frequency range
|
||||
* \param phyHeaderSections the map of PHY header sections (\see PhyEntity::PhyHeaderSections)
|
||||
*
|
||||
* \return the success rate of the PHY header sections
|
||||
@@ -471,14 +509,15 @@ class InterferenceHelper : public Object
|
||||
NiChangesPerBand* nis,
|
||||
uint16_t channelWidth,
|
||||
WifiSpectrumBand band,
|
||||
const FrequencyRange& range,
|
||||
PhyEntity::PhyHeaderSections phyHeaderSections) const;
|
||||
|
||||
double m_noiseFigure; //!< noise figure (linear)
|
||||
Ptr<ErrorRateModel> m_errorRateModel; //!< error rate model
|
||||
uint8_t m_numRxAntennas; //!< the number of RX antennas in the corresponding receiver
|
||||
NiChangesPerBand m_niChanges; //!< NI Changes for each band in each range
|
||||
FirstPowerPerBand m_firstPowers; //!< first power of each band in watts
|
||||
bool m_rxing; //!< flag whether it is in receiving state
|
||||
uint8_t m_numRxAntennas; //!< the number of RX antennas in the corresponding receiver
|
||||
NiChangesPerBandPerRange m_niChanges; //!< NI Changes for each band in each range
|
||||
FirstPowerPerBandPerRange m_firstPowers; //!< first power of each band in watts
|
||||
bool m_rxing; //!< flag whether it is in receiving state
|
||||
|
||||
/**
|
||||
* Returns an iterator to the first NiChange that is later than moment
|
||||
|
||||
@@ -273,6 +273,7 @@ PhyEntity::GetPhyHeaderSnrPer(WifiPpduField field, Ptr<Event> event) const
|
||||
event,
|
||||
measurementChannelWidth,
|
||||
GetPrimaryBand(measurementChannelWidth),
|
||||
WHOLE_WIFI_SPECTRUM,
|
||||
field);
|
||||
}
|
||||
|
||||
@@ -713,7 +714,8 @@ PhyEntity::EndReceivePayload(Ptr<Event> event)
|
||||
double snr = m_wifiPhy->m_interference->CalculateSnr(event,
|
||||
channelWidthAndBand.first,
|
||||
txVector.GetNss(staId),
|
||||
channelWidthAndBand.second);
|
||||
channelWidthAndBand.second,
|
||||
WHOLE_WIFI_SPECTRUM);
|
||||
|
||||
Ptr<const WifiPsdu> psdu = GetAddressedPsduInPpdu(ppdu);
|
||||
m_wifiPhy->NotifyRxEnd(psdu);
|
||||
@@ -794,6 +796,7 @@ PhyEntity::GetReceptionStatus(Ptr<const WifiPsdu> psdu,
|
||||
event,
|
||||
channelWidthAndBand.first,
|
||||
channelWidthAndBand.second,
|
||||
WHOLE_WIFI_SPECTRUM,
|
||||
staId,
|
||||
std::make_pair(relativeMpduStart, relativeMpduStart + mpduDuration));
|
||||
|
||||
@@ -869,19 +872,20 @@ PhyEntity::CreateInterferenceEvent(Ptr<const WifiPpdu> ppdu,
|
||||
RxPowerWattPerChannelBand& rxPower,
|
||||
bool isStartOfdmaRxing /* = false */)
|
||||
{
|
||||
return m_wifiPhy->m_interference->Add(ppdu, txVector, duration, rxPower, isStartOfdmaRxing);
|
||||
return m_wifiPhy->m_interference
|
||||
->Add(ppdu, txVector, duration, rxPower, WHOLE_WIFI_SPECTRUM, isStartOfdmaRxing);
|
||||
}
|
||||
|
||||
void
|
||||
PhyEntity::UpdateInterferenceEvent(Ptr<Event> event, const RxPowerWattPerChannelBand& rxPower)
|
||||
{
|
||||
m_wifiPhy->m_interference->UpdateEvent(event, rxPower);
|
||||
m_wifiPhy->m_interference->UpdateEvent(event, rxPower, WHOLE_WIFI_SPECTRUM);
|
||||
}
|
||||
|
||||
void
|
||||
PhyEntity::NotifyInterferenceRxEndAndClear(bool reset)
|
||||
{
|
||||
m_wifiPhy->m_interference->NotifyRxEnd(Simulator::Now());
|
||||
m_wifiPhy->m_interference->NotifyRxEnd(Simulator::Now(), WHOLE_WIFI_SPECTRUM);
|
||||
m_signalNoiseMap.clear();
|
||||
m_statusPerMpduMap.clear();
|
||||
for (const auto& endOfMpduEvent : m_endOfMpduEvents)
|
||||
@@ -957,7 +961,7 @@ PhyEntity::EndPreambleDetectionPeriod(Ptr<Event> event)
|
||||
m_wifiPhy->m_currentPreambleEvents.erase(it);
|
||||
// This is needed to cleanup the m_firstPowerPerBand so that the first power corresponds to
|
||||
// the power at the start of the PPDU
|
||||
m_wifiPhy->m_interference->NotifyRxEnd(maxEvent->GetStartTime());
|
||||
m_wifiPhy->m_interference->NotifyRxEnd(maxEvent->GetStartTime(), WHOLE_WIFI_SPECTRUM);
|
||||
// Make sure InterferenceHelper keeps recording events
|
||||
m_wifiPhy->m_interference->NotifyRxStart();
|
||||
return;
|
||||
@@ -968,7 +972,8 @@ PhyEntity::EndPreambleDetectionPeriod(Ptr<Event> event)
|
||||
double snr = m_wifiPhy->m_interference->CalculateSnr(m_wifiPhy->m_currentEvent,
|
||||
measurementChannelWidth,
|
||||
1,
|
||||
measurementBand);
|
||||
measurementBand,
|
||||
WHOLE_WIFI_SPECTRUM);
|
||||
NS_LOG_DEBUG("SNR(dB)=" << RatioToDb(snr) << " at end of preamble detection period");
|
||||
|
||||
if ((!m_wifiPhy->m_preambleDetectionModel && maxRxPowerW > 0.0) ||
|
||||
@@ -999,7 +1004,8 @@ PhyEntity::EndPreambleDetectionPeriod(Ptr<Event> event)
|
||||
// This is needed to cleanup the m_firstPowerPerBand so that the first power
|
||||
// corresponds to the power at the start of the PPDU
|
||||
m_wifiPhy->m_interference->NotifyRxEnd(
|
||||
m_wifiPhy->m_currentEvent->GetStartTime());
|
||||
m_wifiPhy->m_currentEvent->GetStartTime(),
|
||||
WHOLE_WIFI_SPECTRUM);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1043,7 +1049,7 @@ PhyEntity::EndPreambleDetectionPeriod(Ptr<Event> event)
|
||||
if (m_wifiPhy->m_currentPreambleEvents.empty())
|
||||
{
|
||||
// Do not erase events if there are still pending preamble events to be processed
|
||||
m_wifiPhy->m_interference->NotifyRxEnd(Simulator::Now());
|
||||
m_wifiPhy->m_interference->NotifyRxEnd(Simulator::Now(), WHOLE_WIFI_SPECTRUM);
|
||||
}
|
||||
m_wifiPhy->m_currentEvent = nullptr;
|
||||
// Cancel preamble reception
|
||||
@@ -1136,7 +1142,7 @@ PhyEntity::ResetReceive(Ptr<Event> event)
|
||||
NS_LOG_FUNCTION(this << *event);
|
||||
DoResetReceive(event);
|
||||
NS_ASSERT(!m_wifiPhy->IsStateRx());
|
||||
m_wifiPhy->m_interference->NotifyRxEnd(Simulator::Now());
|
||||
m_wifiPhy->m_interference->NotifyRxEnd(Simulator::Now(), WHOLE_WIFI_SPECTRUM);
|
||||
NS_ASSERT(m_endRxPayloadEvents.size() == 1 && m_endRxPayloadEvents.front().IsExpired());
|
||||
m_endRxPayloadEvents.clear();
|
||||
m_wifiPhy->m_currentEvent = nullptr;
|
||||
@@ -1204,7 +1210,9 @@ PhyEntity::GetCcaThreshold(const Ptr<const WifiPpdu> ppdu,
|
||||
Time
|
||||
PhyEntity::GetDelayUntilCcaEnd(double thresholdDbm, WifiSpectrumBand band)
|
||||
{
|
||||
return m_wifiPhy->m_interference->GetEnergyDuration(DbmToW(thresholdDbm), band);
|
||||
return m_wifiPhy->m_interference->GetEnergyDuration(DbmToW(thresholdDbm),
|
||||
band,
|
||||
WHOLE_WIFI_SPECTRUM);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -827,7 +827,13 @@ class PhyEntity : public SimpleRefCount<PhyEntity>
|
||||
* Create an event using WifiPhy's InterferenceHelper class.
|
||||
* Wrapper used by child classes.
|
||||
*
|
||||
* \copydoc InterferenceHelper::Add
|
||||
* \param ppdu the PPDU
|
||||
* \param txVector the TXVECTOR
|
||||
* \param duration the PPDU duration
|
||||
* \param rxPower received power per band (W)
|
||||
* \param isStartOfdmaRxing flag whether the event corresponds to the start of the OFDMA payload
|
||||
* reception (only used for UL-OFDMA)
|
||||
* \return the created event
|
||||
*/
|
||||
Ptr<Event> CreateInterferenceEvent(Ptr<const WifiPpdu> ppdu,
|
||||
const WifiTxVector& txVector,
|
||||
@@ -838,7 +844,8 @@ class PhyEntity : public SimpleRefCount<PhyEntity>
|
||||
* Update an event in WifiPhy's InterferenceHelper class.
|
||||
* Wrapper used by child classes.
|
||||
*
|
||||
* \copydoc InterferenceHelper::UpdateEvent
|
||||
* \param event the event to be updated
|
||||
* \param rxPower the received power (W) per band to be added to the current event
|
||||
*/
|
||||
void UpdateInterferenceEvent(Ptr<Event> event, const RxPowerWattPerChannelBand& rxPower);
|
||||
/**
|
||||
|
||||
@@ -119,11 +119,11 @@ SpectrumWifiPhy::UpdateInterferenceHelperBands()
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT(!m_spectrumPhyInterfaces.empty());
|
||||
uint16_t channelWidth = GetChannelWidth();
|
||||
m_interference->RemoveBands();
|
||||
m_interference->RemoveBands(WHOLE_WIFI_SPECTRUM);
|
||||
if (channelWidth < 20)
|
||||
{
|
||||
WifiSpectrumBand band = GetBand(channelWidth);
|
||||
m_interference->AddBand(band);
|
||||
m_interference->AddBand(band, WHOLE_WIFI_SPECTRUM);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -131,7 +131,7 @@ SpectrumWifiPhy::UpdateInterferenceHelperBands()
|
||||
{
|
||||
for (uint32_t i = 0; i < (channelWidth / bw); ++i)
|
||||
{
|
||||
m_interference->AddBand(GetBand(bw, i));
|
||||
m_interference->AddBand(GetBand(bw, i), WHOLE_WIFI_SPECTRUM);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,7 +183,7 @@ SpectrumWifiPhy::UpdateInterferenceHelperBands()
|
||||
}
|
||||
for (const auto& bandRuPair : m_ruBands[channelWidth])
|
||||
{
|
||||
m_interference->AddBand(bandRuPair.first);
|
||||
m_interference->AddBand(bandRuPair.first, WHOLE_WIFI_SPECTRUM);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -394,14 +394,14 @@ SpectrumWifiPhy::StartRx(Ptr<SpectrumSignalParameters> rxParams)
|
||||
if (!wifiRxParams)
|
||||
{
|
||||
NS_LOG_INFO("Received non Wi-Fi signal");
|
||||
m_interference->AddForeignSignal(rxDuration, rxPowerW);
|
||||
m_interference->AddForeignSignal(rxDuration, rxPowerW, WHOLE_WIFI_SPECTRUM);
|
||||
SwitchMaybeToCcaBusy(nullptr);
|
||||
return;
|
||||
}
|
||||
if (wifiRxParams && m_disableWifiReception)
|
||||
{
|
||||
NS_LOG_INFO("Received Wi-Fi signal but blocked from syncing");
|
||||
m_interference->AddForeignSignal(rxDuration, rxPowerW);
|
||||
m_interference->AddForeignSignal(rxDuration, rxPowerW, WHOLE_WIFI_SPECTRUM);
|
||||
SwitchMaybeToCcaBusy(nullptr);
|
||||
return;
|
||||
}
|
||||
@@ -414,7 +414,7 @@ SpectrumWifiPhy::StartRx(Ptr<SpectrumSignalParameters> rxParams)
|
||||
if (totalRxPowerW < DbmToW(GetRxSensitivity()) * (txWidth / 20.0))
|
||||
{
|
||||
NS_LOG_INFO("Received signal too weak to process: " << WToDbm(totalRxPowerW) << " dBm");
|
||||
m_interference->Add(ppdu, txVector, rxDuration, rxPowerW);
|
||||
m_interference->Add(ppdu, txVector, rxDuration, rxPowerW, WHOLE_WIFI_SPECTRUM);
|
||||
SwitchMaybeToCcaBusy(nullptr);
|
||||
return;
|
||||
}
|
||||
@@ -424,7 +424,7 @@ SpectrumWifiPhy::StartRx(Ptr<SpectrumSignalParameters> rxParams)
|
||||
if (!CanStartRx(ppdu, txWidth))
|
||||
{
|
||||
NS_LOG_INFO("Cannot start reception of the PPDU, consider it as interference");
|
||||
m_interference->Add(ppdu, txVector, rxDuration, rxPowerW);
|
||||
m_interference->Add(ppdu, txVector, rxDuration, rxPowerW, WHOLE_WIFI_SPECTRUM);
|
||||
SwitchMaybeToCcaBusy(ppdu);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1222,7 +1222,7 @@ WifiPhy::DoChannelSwitch()
|
||||
{
|
||||
// notify channel switching
|
||||
m_state->SwitchToChannelSwitching(GetChannelSwitchDelay());
|
||||
m_interference->EraseEvents();
|
||||
m_interference->EraseEvents(WHOLE_WIFI_SPECTRUM);
|
||||
/*
|
||||
* Needed here to be able to correctly sensed the medium for the first
|
||||
* time after the switching. The actual switching is not performed until
|
||||
@@ -1834,7 +1834,7 @@ WifiPhy::StartReceivePreamble(Ptr<const WifiPpdu> ppdu,
|
||||
// TODO find a fallback PHY for receiving the PPDU (e.g. 11a for 11ax due to preamble
|
||||
// structure)
|
||||
NS_LOG_DEBUG("Unsupported modulation received (" << modulation << "), consider as noise");
|
||||
m_interference->Add(ppdu, ppdu->GetTxVector(), rxDuration, rxPowersW);
|
||||
m_interference->Add(ppdu, ppdu->GetTxVector(), rxDuration, rxPowersW, WHOLE_WIFI_SPECTRUM);
|
||||
SwitchMaybeToCcaBusy(nullptr);
|
||||
}
|
||||
}
|
||||
@@ -2087,7 +2087,7 @@ WifiPhy::AbortCurrentReception(WifiPhyRxfailureReason reason)
|
||||
{
|
||||
m_endPhyRxEvent.Cancel();
|
||||
}
|
||||
m_interference->NotifyRxEnd(Simulator::Now());
|
||||
m_interference->NotifyRxEnd(Simulator::Now(), WHOLE_WIFI_SPECTRUM);
|
||||
if (!m_currentEvent)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -56,7 +56,7 @@ YansWifiPhy::SetInterferenceHelper(const Ptr<InterferenceHelper> helper)
|
||||
WifiSpectrumBand band;
|
||||
band.first = 0;
|
||||
band.second = 0;
|
||||
m_interference->AddBand(band);
|
||||
m_interference->AddBand(band, WHOLE_WIFI_SPECTRUM);
|
||||
}
|
||||
|
||||
YansWifiPhy::~YansWifiPhy()
|
||||
|
||||
@@ -279,7 +279,7 @@ OfdmaSpectrumWifiPhy::GetCurrentEvent()
|
||||
Time
|
||||
OfdmaSpectrumWifiPhy::GetEnergyDuration(double energyW, WifiSpectrumBand band)
|
||||
{
|
||||
return m_interference->GetEnergyDuration(energyW, band);
|
||||
return m_interference->GetEnergyDuration(energyW, band, WHOLE_WIFI_SPECTRUM);
|
||||
}
|
||||
|
||||
Ptr<const HePhy>
|
||||
|
||||
Reference in New Issue
Block a user