717 lines
26 KiB
C++
717 lines
26 KiB
C++
/*
|
|
* Copyright (c) 2005,2006 INRIA
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation;
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
|
* Ghada Badawy <gbadawy@gmail.com>
|
|
* Sébastien Deronne <sebastien.deronne@gmail.com>
|
|
*
|
|
* Ported from yans-wifi-phy.cc by several contributors starting
|
|
* with Nicola Baldo and Dean Armstrong
|
|
*/
|
|
|
|
#include "spectrum-wifi-phy.h"
|
|
|
|
#include "interference-helper.h"
|
|
#include "wifi-net-device.h"
|
|
#include "wifi-psdu.h"
|
|
#include "wifi-spectrum-phy-interface.h"
|
|
#include "wifi-spectrum-signal-parameters.h"
|
|
#include "wifi-utils.h"
|
|
|
|
#include "ns3/boolean.h"
|
|
#include "ns3/double.h"
|
|
#include "ns3/he-phy.h"
|
|
#include "ns3/log.h"
|
|
#include "ns3/node.h"
|
|
#include "ns3/simulator.h"
|
|
#include "ns3/spectrum-channel.h"
|
|
|
|
#include <algorithm>
|
|
|
|
namespace ns3
|
|
{
|
|
|
|
NS_LOG_COMPONENT_DEFINE("SpectrumWifiPhy");
|
|
|
|
NS_OBJECT_ENSURE_REGISTERED(SpectrumWifiPhy);
|
|
|
|
TypeId
|
|
SpectrumWifiPhy::GetTypeId()
|
|
{
|
|
static TypeId tid =
|
|
TypeId("ns3::SpectrumWifiPhy")
|
|
.SetParent<WifiPhy>()
|
|
.SetGroupName("Wifi")
|
|
.AddConstructor<SpectrumWifiPhy>()
|
|
.AddAttribute("DisableWifiReception",
|
|
"Prevent Wi-Fi frame sync from ever happening",
|
|
BooleanValue(false),
|
|
MakeBooleanAccessor(&SpectrumWifiPhy::m_disableWifiReception),
|
|
MakeBooleanChecker())
|
|
.AddAttribute(
|
|
"TrackSignalsFromInactiveInterfaces",
|
|
"Enable or disable tracking signals coming from inactive spectrum PHY interfaces",
|
|
BooleanValue(true),
|
|
MakeBooleanAccessor(&SpectrumWifiPhy::m_trackSignalsInactiveInterfaces),
|
|
MakeBooleanChecker())
|
|
.AddAttribute(
|
|
"TxMaskInnerBandMinimumRejection",
|
|
"Minimum rejection (dBr) for the inner band of the transmit spectrum mask",
|
|
DoubleValue(-20.0),
|
|
MakeDoubleAccessor(&SpectrumWifiPhy::m_txMaskInnerBandMinimumRejection),
|
|
MakeDoubleChecker<double>())
|
|
.AddAttribute(
|
|
"TxMaskOuterBandMinimumRejection",
|
|
"Minimum rejection (dBr) for the outer band of the transmit spectrum mask",
|
|
DoubleValue(-28.0),
|
|
MakeDoubleAccessor(&SpectrumWifiPhy::m_txMaskOuterBandMinimumRejection),
|
|
MakeDoubleChecker<double>())
|
|
.AddAttribute(
|
|
"TxMaskOuterBandMaximumRejection",
|
|
"Maximum rejection (dBr) for the outer band of the transmit spectrum mask",
|
|
DoubleValue(-40.0),
|
|
MakeDoubleAccessor(&SpectrumWifiPhy::m_txMaskOuterBandMaximumRejection),
|
|
MakeDoubleChecker<double>())
|
|
.AddTraceSource("SignalArrival",
|
|
"Signal arrival",
|
|
MakeTraceSourceAccessor(&SpectrumWifiPhy::m_signalCb),
|
|
"ns3::SpectrumWifiPhy::SignalArrivalCallback");
|
|
return tid;
|
|
}
|
|
|
|
SpectrumWifiPhy::SpectrumWifiPhy()
|
|
: m_spectrumPhyInterfaces{},
|
|
m_currentSpectrumPhyInterface{nullptr}
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
}
|
|
|
|
SpectrumWifiPhy::~SpectrumWifiPhy()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::DoDispose()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
m_spectrumPhyInterfaces.clear();
|
|
m_currentSpectrumPhyInterface = nullptr;
|
|
m_antenna = nullptr;
|
|
m_channelSwitchedCallback.Nullify();
|
|
WifiPhy::DoDispose();
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::DoInitialize()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
WifiPhy::DoInitialize();
|
|
}
|
|
|
|
WifiSpectrumBands
|
|
SpectrumWifiPhy::ComputeBands(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface)
|
|
{
|
|
NS_LOG_FUNCTION(this << spectrumPhyInterface);
|
|
WifiSpectrumBands bands{};
|
|
const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
|
|
if (channelWidth < 20)
|
|
{
|
|
bands.push_back(GetBandForInterface(spectrumPhyInterface, channelWidth));
|
|
}
|
|
else
|
|
{
|
|
for (uint16_t bw = 160; bw >= 20; bw = bw / 2)
|
|
{
|
|
for (uint32_t i = 0; i < (channelWidth / bw); ++i)
|
|
{
|
|
bands.push_back(GetBandForInterface(spectrumPhyInterface, bw, i));
|
|
}
|
|
}
|
|
}
|
|
return bands;
|
|
}
|
|
|
|
HeRuBands
|
|
SpectrumWifiPhy::GetHeRuBands(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
|
|
uint16_t guardBandwidth)
|
|
{
|
|
HeRuBands heRuBands{};
|
|
const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
|
|
for (uint16_t bw = 160; bw >= 20; bw = bw / 2)
|
|
{
|
|
for (uint32_t i = 0; i < (channelWidth / bw); ++i)
|
|
{
|
|
for (uint32_t type = 0; type < 7; type++)
|
|
{
|
|
auto ruType = static_cast<HeRu::RuType>(type);
|
|
std::size_t nRus = HeRu::GetNRus(bw, ruType);
|
|
for (std::size_t phyIndex = 1; phyIndex <= nRus; phyIndex++)
|
|
{
|
|
HeRu::SubcarrierGroup group = HeRu::GetSubcarrierGroup(bw, ruType, phyIndex);
|
|
HeRu::SubcarrierRange subcarrierRange =
|
|
std::make_pair(group.front().first, group.back().second);
|
|
const auto bandIndices = HePhy::ConvertHeRuSubcarriers(bw,
|
|
guardBandwidth,
|
|
GetSubcarrierSpacing(),
|
|
subcarrierRange,
|
|
i);
|
|
const auto bandFrequencies =
|
|
ConvertIndicesToFrequenciesForInterface(spectrumPhyInterface, bandIndices);
|
|
WifiSpectrumBandInfo band = {bandIndices, bandFrequencies};
|
|
std::size_t index =
|
|
(bw == 160 && phyIndex > nRus / 2 ? phyIndex - nRus / 2 : phyIndex);
|
|
const auto p20Index = GetOperatingChannel().GetPrimaryChannelIndex(20);
|
|
bool primary80IsLower80 = (p20Index < bw / 40);
|
|
bool primary80 = (bw < 160 || ruType == HeRu::RU_2x996_TONE ||
|
|
(primary80IsLower80 && phyIndex <= nRus / 2) ||
|
|
(!primary80IsLower80 && phyIndex > nRus / 2));
|
|
HeRu::RuSpec ru(ruType, index, primary80);
|
|
NS_ABORT_IF(ru.GetPhyIndex(bw, p20Index) != phyIndex);
|
|
heRuBands.insert({band, ru});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return heRuBands;
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::UpdateInterferenceHelperBands(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface)
|
|
{
|
|
NS_LOG_FUNCTION(this << spectrumPhyInterface);
|
|
auto&& bands = ComputeBands(spectrumPhyInterface);
|
|
WifiSpectrumBands allBands{bands};
|
|
if (GetStandard() >= WIFI_STANDARD_80211ax)
|
|
{
|
|
const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
|
|
auto&& heRuBands = GetHeRuBands(spectrumPhyInterface, GetGuardBandwidth(channelWidth));
|
|
for (const auto& bandRuPair : heRuBands)
|
|
{
|
|
allBands.push_back(bandRuPair.first);
|
|
}
|
|
spectrumPhyInterface->SetHeRuBands(std::move(heRuBands));
|
|
}
|
|
|
|
spectrumPhyInterface->SetBands(std::move(bands));
|
|
|
|
if (m_interference->HasBands())
|
|
{
|
|
m_interference->UpdateBands(allBands, spectrumPhyInterface->GetFrequencyRange());
|
|
}
|
|
else
|
|
{
|
|
for (const auto& band : allBands)
|
|
{
|
|
m_interference->AddBand(band);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ptr<Channel>
|
|
SpectrumWifiPhy::GetChannel() const
|
|
{
|
|
NS_ABORT_IF(!m_currentSpectrumPhyInterface);
|
|
return m_currentSpectrumPhyInterface->GetChannel();
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::AddChannel(const Ptr<SpectrumChannel> channel, const FrequencyRange& freqRange)
|
|
{
|
|
NS_LOG_FUNCTION(this << channel << freqRange);
|
|
|
|
const auto foundOverlappingChannel =
|
|
std::any_of(m_spectrumPhyInterfaces.cbegin(),
|
|
m_spectrumPhyInterfaces.cend(),
|
|
[freqRange, channel](const auto& item) {
|
|
const auto spectrumRange = item.first;
|
|
const auto noOverlap =
|
|
((freqRange.minFrequency >= spectrumRange.maxFrequency) ||
|
|
(freqRange.maxFrequency <= spectrumRange.minFrequency));
|
|
return (!noOverlap);
|
|
});
|
|
NS_ABORT_MSG_IF(foundOverlappingChannel,
|
|
"Added a wifi spectrum channel that overlaps with another existing wifi "
|
|
"spectrum channel");
|
|
|
|
auto wifiSpectrumPhyInterface = CreateObject<WifiSpectrumPhyInterface>(freqRange);
|
|
wifiSpectrumPhyInterface->SetSpectrumWifiPhy(this);
|
|
wifiSpectrumPhyInterface->SetChannel(channel);
|
|
if (GetDevice())
|
|
{
|
|
wifiSpectrumPhyInterface->SetDevice(GetDevice());
|
|
}
|
|
m_spectrumPhyInterfaces.emplace(freqRange, wifiSpectrumPhyInterface);
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::ResetSpectrumModel(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
|
|
uint16_t centerFrequency,
|
|
uint16_t channelWidth)
|
|
{
|
|
NS_LOG_FUNCTION(this << spectrumPhyInterface << centerFrequency << channelWidth);
|
|
|
|
// We have to reset the spectrum model because we changed RF channel. Consequently,
|
|
// we also have to add the spectrum interface to the spectrum channel again because
|
|
// MultiModelSpectrumChannel keeps spectrum interfaces in a map indexed by the RX
|
|
// spectrum model UID (which has changed after channel switching).
|
|
// Both SingleModelSpectrumChannel and MultiModelSpectrumChannel ensure not to keep
|
|
// duplicated spectrum interfaces (the latter removes the spectrum interface and adds
|
|
// it again in the entry associated with the new RX spectrum model UID)
|
|
|
|
// Replace existing spectrum model with new one
|
|
spectrumPhyInterface->SetRxSpectrumModel(centerFrequency,
|
|
channelWidth,
|
|
GetSubcarrierSpacing(),
|
|
GetGuardBandwidth(channelWidth));
|
|
|
|
spectrumPhyInterface->GetChannel()->AddRx(spectrumPhyInterface);
|
|
|
|
UpdateInterferenceHelperBands(spectrumPhyInterface);
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::DoChannelSwitch()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
const auto frequencyBefore = GetOperatingChannel().IsSet() ? GetFrequency() : 0;
|
|
const auto widthBefore = GetOperatingChannel().IsSet() ? GetChannelWidth() : 0;
|
|
WifiPhy::DoChannelSwitch();
|
|
const auto frequencyAfter = GetFrequency();
|
|
const auto widthAfter = GetChannelWidth();
|
|
if ((frequencyBefore == frequencyAfter) && (widthBefore == widthAfter))
|
|
{
|
|
NS_LOG_DEBUG("Same RF channel as before, do nothing");
|
|
if (IsInitialized())
|
|
{
|
|
SwitchMaybeToCcaBusy(nullptr);
|
|
}
|
|
return;
|
|
}
|
|
|
|
auto newSpectrumPhyInterface = GetInterfaceCoveringChannelBand(frequencyAfter, widthAfter);
|
|
const auto interfaceChanged = (newSpectrumPhyInterface != m_currentSpectrumPhyInterface);
|
|
|
|
NS_ABORT_MSG_IF(!newSpectrumPhyInterface,
|
|
"No spectrum channel covers frequency range ["
|
|
<< frequencyAfter - (widthAfter / 2) << " MHz - "
|
|
<< frequencyAfter + (widthAfter / 2) << " MHz]");
|
|
|
|
if (interfaceChanged)
|
|
{
|
|
NS_LOG_DEBUG("Switch to existing RF interface with frequency/width pair of ("
|
|
<< frequencyAfter << ", " << widthAfter << ")");
|
|
if (m_currentSpectrumPhyInterface && !m_trackSignalsInactiveInterfaces)
|
|
{
|
|
m_currentSpectrumPhyInterface->GetChannel()->RemoveRx(m_currentSpectrumPhyInterface);
|
|
}
|
|
}
|
|
|
|
m_currentSpectrumPhyInterface = newSpectrumPhyInterface;
|
|
|
|
auto reset = true;
|
|
if (m_currentSpectrumPhyInterface->GetCenterFrequency() == frequencyAfter)
|
|
{
|
|
// Center frequency has not changed for that interface, hence we do not need to
|
|
// reset the spectrum model nor update any band stored in the interference helper
|
|
if (!m_trackSignalsInactiveInterfaces)
|
|
{
|
|
// If we are not tracking signals from inactive interface,
|
|
// this means the spectrum interface has been disconnected
|
|
// from the spectrum channel and has to be connected back
|
|
m_currentSpectrumPhyInterface->GetChannel()->AddRx(m_currentSpectrumPhyInterface);
|
|
}
|
|
reset = false;
|
|
}
|
|
|
|
if (reset)
|
|
{
|
|
ResetSpectrumModel(m_currentSpectrumPhyInterface, frequencyAfter, widthAfter);
|
|
}
|
|
|
|
if (IsInitialized())
|
|
{
|
|
SwitchMaybeToCcaBusy(nullptr);
|
|
}
|
|
|
|
Simulator::ScheduleNow(&SpectrumWifiPhy::NotifyChannelSwitched, this);
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::NotifyChannelSwitched()
|
|
{
|
|
if (!m_channelSwitchedCallback.IsNull())
|
|
{
|
|
m_channelSwitchedCallback();
|
|
}
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::ConfigureInterface(uint16_t frequency, uint16_t width)
|
|
{
|
|
NS_LOG_FUNCTION(this << frequency << width);
|
|
|
|
if (!m_trackSignalsInactiveInterfaces)
|
|
{
|
|
NS_LOG_DEBUG("Tracking of signals on inactive interfaces is not enabled");
|
|
return;
|
|
}
|
|
|
|
auto spectrumPhyInterface = GetInterfaceCoveringChannelBand(frequency, width);
|
|
|
|
NS_ABORT_MSG_IF(!spectrumPhyInterface,
|
|
"No spectrum channel covers frequency range ["
|
|
<< frequency - (width / 2) << " MHz - " << frequency + (width / 2)
|
|
<< " MHz]");
|
|
|
|
NS_ABORT_MSG_IF(spectrumPhyInterface == m_currentSpectrumPhyInterface,
|
|
"This method should not be called for the current interface");
|
|
|
|
if ((frequency == spectrumPhyInterface->GetCenterFrequency()) &&
|
|
(width == spectrumPhyInterface->GetChannelWidth()))
|
|
{
|
|
NS_LOG_DEBUG("Same RF channel as before on that interface, do nothing");
|
|
return;
|
|
}
|
|
|
|
ResetSpectrumModel(spectrumPhyInterface, frequency, width);
|
|
}
|
|
|
|
bool
|
|
SpectrumWifiPhy::CanStartRx(Ptr<const WifiPpdu> ppdu) const
|
|
{
|
|
return GetLatestPhyEntity()->CanStartRx(ppdu);
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::StartRx(Ptr<SpectrumSignalParameters> rxParams,
|
|
Ptr<const WifiSpectrumPhyInterface> interface)
|
|
{
|
|
NS_LOG_FUNCTION(this << rxParams << interface);
|
|
Time rxDuration = rxParams->duration;
|
|
Ptr<SpectrumValue> receivedSignalPsd = rxParams->psd;
|
|
NS_LOG_DEBUG("Received signal with PSD " << *receivedSignalPsd << " and duration "
|
|
<< rxDuration.As(Time::NS));
|
|
uint32_t senderNodeId = 0;
|
|
if (rxParams->txPhy)
|
|
{
|
|
senderNodeId = rxParams->txPhy->GetDevice()->GetNode()->GetId();
|
|
}
|
|
NS_LOG_DEBUG("Received signal from " << senderNodeId << " with unfiltered power "
|
|
<< WToDbm(Integral(*receivedSignalPsd)) << " dBm");
|
|
|
|
// Integrate over our receive bandwidth (i.e., all that the receive
|
|
// spectral mask representing our filtering allows) to find the
|
|
// total energy apparent to the "demodulator".
|
|
// This is done per 20 MHz channel band.
|
|
const auto channelWidth = interface ? interface->GetChannelWidth() : GetChannelWidth();
|
|
const auto& bands =
|
|
interface ? interface->GetBands() : m_currentSpectrumPhyInterface->GetBands();
|
|
double totalRxPowerW = 0;
|
|
RxPowerWattPerChannelBand rxPowerW;
|
|
|
|
const auto rxGainRatio = DbToRatio(GetRxGain());
|
|
|
|
std::size_t index = 0;
|
|
uint16_t prevBw = 0;
|
|
for (const auto& band : bands)
|
|
{
|
|
uint16_t bw = (band.frequencies.second - band.frequencies.first) / 1e6;
|
|
NS_ASSERT(bw <= channelWidth);
|
|
index = ((bw != prevBw) ? 0 : (index + 1));
|
|
double rxPowerPerBandW =
|
|
WifiSpectrumValueHelper::GetBandPowerW(receivedSignalPsd, band.indices);
|
|
NS_LOG_DEBUG("Signal power received (watts) before antenna gain for "
|
|
<< bw << " MHz channel band " << index << ": " << band);
|
|
rxPowerPerBandW *= rxGainRatio;
|
|
rxPowerW.insert({band, rxPowerPerBandW});
|
|
NS_LOG_DEBUG("Signal power received after antenna gain for "
|
|
<< bw << " MHz channel band " << index << ": " << rxPowerPerBandW << " W ("
|
|
<< WToDbm(rxPowerPerBandW) << " dBm)");
|
|
if (bw <= 20)
|
|
{
|
|
totalRxPowerW += rxPowerPerBandW;
|
|
}
|
|
prevBw = bw;
|
|
}
|
|
|
|
if (GetStandard() >= WIFI_STANDARD_80211ax)
|
|
{
|
|
const auto& heRuBands =
|
|
interface ? interface->GetHeRuBands() : m_currentSpectrumPhyInterface->GetHeRuBands();
|
|
NS_ASSERT(!heRuBands.empty());
|
|
for (const auto& [band, ru] : heRuBands)
|
|
{
|
|
double rxPowerPerBandW =
|
|
WifiSpectrumValueHelper::GetBandPowerW(receivedSignalPsd, band.indices);
|
|
NS_LOG_DEBUG("Signal power received (watts) before antenna gain for RU with type "
|
|
<< ru.GetRuType() << " and index " << ru.GetIndex() << " -> ("
|
|
<< band.indices.first << "; " << band.indices.second
|
|
<< "): " << rxPowerPerBandW);
|
|
rxPowerPerBandW *= rxGainRatio;
|
|
NS_LOG_DEBUG("Signal power received after antenna gain for RU with type "
|
|
<< ru.GetRuType() << " and index " << ru.GetIndex() << " -> ("
|
|
<< band.indices.first << "; " << band.indices.second << "): "
|
|
<< rxPowerPerBandW << " W (" << WToDbm(rxPowerPerBandW) << " dBm)");
|
|
rxPowerW.insert({band, rxPowerPerBandW});
|
|
}
|
|
}
|
|
|
|
NS_LOG_DEBUG("Total signal power received after antenna gain: "
|
|
<< totalRxPowerW << " W (" << WToDbm(totalRxPowerW) << " dBm)");
|
|
|
|
Ptr<WifiSpectrumSignalParameters> wifiRxParams =
|
|
DynamicCast<WifiSpectrumSignalParameters>(rxParams);
|
|
|
|
// Log the signal arrival to the trace source
|
|
m_signalCb(bool(wifiRxParams), senderNodeId, WToDbm(totalRxPowerW), rxDuration);
|
|
|
|
if (!wifiRxParams)
|
|
{
|
|
NS_LOG_INFO("Received non Wi-Fi signal");
|
|
m_interference->AddForeignSignal(rxDuration, rxPowerW);
|
|
SwitchMaybeToCcaBusy(nullptr);
|
|
return;
|
|
}
|
|
|
|
if (wifiRxParams && m_disableWifiReception)
|
|
{
|
|
NS_LOG_INFO("Received Wi-Fi signal but blocked from syncing");
|
|
m_interference->AddForeignSignal(rxDuration, rxPowerW);
|
|
SwitchMaybeToCcaBusy(nullptr);
|
|
return;
|
|
}
|
|
|
|
if (m_trackSignalsInactiveInterfaces && interface &&
|
|
(interface != m_currentSpectrumPhyInterface))
|
|
{
|
|
NS_LOG_INFO("Received Wi-Fi signal from a non-active PHY interface");
|
|
m_interference->AddForeignSignal(rxDuration, rxPowerW);
|
|
SwitchMaybeToCcaBusy(nullptr);
|
|
return;
|
|
}
|
|
|
|
// Do no further processing if signal is too weak
|
|
// 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 (totalRxPowerW < DbmToW(GetRxSensitivity()) * (ppdu->GetTxChannelWidth() / 20.0))
|
|
{
|
|
NS_LOG_INFO("Received signal too weak to process: " << WToDbm(totalRxPowerW) << " dBm");
|
|
m_interference->Add(ppdu, rxDuration, rxPowerW);
|
|
SwitchMaybeToCcaBusy(nullptr);
|
|
return;
|
|
}
|
|
|
|
if (wifiRxParams->txPhy)
|
|
{
|
|
if (!CanStartRx(ppdu))
|
|
{
|
|
NS_LOG_INFO("Cannot start reception of the PPDU, consider it as interference");
|
|
m_interference->Add(ppdu, rxDuration, rxPowerW);
|
|
SwitchMaybeToCcaBusy(ppdu);
|
|
return;
|
|
}
|
|
}
|
|
|
|
NS_LOG_INFO("Received Wi-Fi signal");
|
|
StartReceivePreamble(ppdu, rxPowerW, rxDuration);
|
|
}
|
|
|
|
Ptr<const WifiPpdu>
|
|
SpectrumWifiPhy::GetRxPpduFromTxPpdu(Ptr<const WifiPpdu> ppdu)
|
|
{
|
|
return GetPhyEntityForPpdu(ppdu)->GetRxPpduFromTxPpdu(ppdu);
|
|
}
|
|
|
|
Ptr<AntennaModel>
|
|
SpectrumWifiPhy::GetAntenna() const
|
|
{
|
|
return m_antenna;
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::SetAntenna(const Ptr<AntennaModel> a)
|
|
{
|
|
NS_LOG_FUNCTION(this << a);
|
|
m_antenna = a;
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::SetDevice(const Ptr<WifiNetDevice> device)
|
|
{
|
|
NS_LOG_FUNCTION(this << device);
|
|
WifiPhy::SetDevice(device);
|
|
for (auto& spectrumPhyInterface : m_spectrumPhyInterfaces)
|
|
{
|
|
spectrumPhyInterface.second->SetDevice(device);
|
|
}
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::StartTx(Ptr<const WifiPpdu> ppdu)
|
|
{
|
|
NS_LOG_FUNCTION(this << ppdu);
|
|
GetPhyEntity(ppdu->GetModulation())->StartTx(ppdu);
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::Transmit(Ptr<WifiSpectrumSignalParameters> txParams)
|
|
{
|
|
NS_LOG_FUNCTION(this << txParams);
|
|
NS_ABORT_IF(!m_currentSpectrumPhyInterface);
|
|
m_currentSpectrumPhyInterface->StartTx(txParams);
|
|
}
|
|
|
|
uint16_t
|
|
SpectrumWifiPhy::GetGuardBandwidth(uint16_t currentChannelWidth) const
|
|
{
|
|
uint16_t guardBandwidth = 0;
|
|
if (currentChannelWidth == 22)
|
|
{
|
|
// handle case of DSSS transmission
|
|
guardBandwidth = 10;
|
|
}
|
|
else
|
|
{
|
|
// In order to properly model out of band transmissions for OFDM, the guard
|
|
// band has been configured so as to expand the modeled spectrum up to the
|
|
// outermost referenced point in "Transmit spectrum mask" sections' PSDs of
|
|
// each PHY specification of 802.11-2016 standard. It thus ultimately corresponds
|
|
// to the currently considered channel bandwidth (which can be different from
|
|
// supported channel width).
|
|
guardBandwidth = currentChannelWidth;
|
|
}
|
|
return guardBandwidth;
|
|
}
|
|
|
|
WifiSpectrumBandInfo
|
|
SpectrumWifiPhy::GetBandForInterface(Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
|
|
uint16_t bandWidth,
|
|
uint8_t bandIndex /* = 0 */)
|
|
{
|
|
const auto subcarrierSpacing = GetSubcarrierSpacing();
|
|
const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
|
|
const auto numBandsInBand = static_cast<size_t>(bandWidth * 1e6 / subcarrierSpacing);
|
|
auto numBandsInChannel = static_cast<size_t>(channelWidth * 1e6 / subcarrierSpacing);
|
|
if (numBandsInBand % 2 == 0)
|
|
{
|
|
numBandsInChannel += 1; // symmetry around center frequency
|
|
}
|
|
auto rxSpectrumModel = spectrumPhyInterface->GetRxSpectrumModel();
|
|
size_t totalNumBands = rxSpectrumModel->GetNumBands();
|
|
NS_ASSERT_MSG((numBandsInChannel % 2 == 1) && (totalNumBands % 2 == 1),
|
|
"Should have odd number of bands");
|
|
NS_ASSERT_MSG((bandIndex * bandWidth) < channelWidth, "Band index is out of bound");
|
|
NS_ASSERT(totalNumBands >= numBandsInChannel);
|
|
auto startIndex = ((totalNumBands - numBandsInChannel) / 2) + (bandIndex * numBandsInBand);
|
|
auto stopIndex = startIndex + numBandsInBand - 1;
|
|
auto frequencies =
|
|
ConvertIndicesToFrequenciesForInterface(spectrumPhyInterface, {startIndex, stopIndex});
|
|
auto freqRange = spectrumPhyInterface->GetFrequencyRange();
|
|
NS_ASSERT(frequencies.first >= (freqRange.minFrequency * 1e6));
|
|
NS_ASSERT(frequencies.second <= (freqRange.maxFrequency * 1e6));
|
|
NS_ASSERT((frequencies.second - frequencies.first) == (bandWidth * 1e6));
|
|
if (startIndex >= totalNumBands / 2)
|
|
{
|
|
// step past DC
|
|
startIndex += 1;
|
|
}
|
|
return {{startIndex, stopIndex}, frequencies};
|
|
}
|
|
|
|
WifiSpectrumBandInfo
|
|
SpectrumWifiPhy::GetBand(uint16_t bandWidth, uint8_t bandIndex /* = 0 */)
|
|
{
|
|
NS_ABORT_IF(!m_currentSpectrumPhyInterface);
|
|
return GetBandForInterface(m_currentSpectrumPhyInterface, bandWidth, bandIndex);
|
|
}
|
|
|
|
WifiSpectrumBandFrequencies
|
|
SpectrumWifiPhy::ConvertIndicesToFrequencies(const WifiSpectrumBandIndices& indices) const
|
|
{
|
|
NS_ABORT_IF(!m_currentSpectrumPhyInterface);
|
|
return ConvertIndicesToFrequenciesForInterface(m_currentSpectrumPhyInterface, indices);
|
|
}
|
|
|
|
WifiSpectrumBandFrequencies
|
|
SpectrumWifiPhy::ConvertIndicesToFrequenciesForInterface(
|
|
Ptr<WifiSpectrumPhyInterface> spectrumPhyInterface,
|
|
const WifiSpectrumBandIndices& indices) const
|
|
{
|
|
NS_ABORT_IF(!spectrumPhyInterface);
|
|
auto rxSpectrumModel = spectrumPhyInterface->GetRxSpectrumModel();
|
|
auto startGuardBand = rxSpectrumModel->Begin();
|
|
auto startChannel = std::next(startGuardBand, indices.first);
|
|
auto endChannel = std::next(startGuardBand, indices.second + 1);
|
|
auto lowFreq = static_cast<uint64_t>(startChannel->fc);
|
|
auto highFreq = static_cast<uint64_t>(endChannel->fc);
|
|
return {lowFreq, highFreq};
|
|
}
|
|
|
|
std::tuple<double, double, double>
|
|
SpectrumWifiPhy::GetTxMaskRejectionParams() const
|
|
{
|
|
return std::make_tuple(m_txMaskInnerBandMinimumRejection,
|
|
m_txMaskOuterBandMinimumRejection,
|
|
m_txMaskOuterBandMaximumRejection);
|
|
}
|
|
|
|
FrequencyRange
|
|
SpectrumWifiPhy::GetCurrentFrequencyRange() const
|
|
{
|
|
NS_ABORT_IF(!m_currentSpectrumPhyInterface);
|
|
return m_currentSpectrumPhyInterface->GetFrequencyRange();
|
|
}
|
|
|
|
const std::map<FrequencyRange, Ptr<WifiSpectrumPhyInterface>>&
|
|
SpectrumWifiPhy::GetSpectrumPhyInterfaces() const
|
|
{
|
|
return m_spectrumPhyInterfaces;
|
|
}
|
|
|
|
Ptr<WifiSpectrumPhyInterface>
|
|
SpectrumWifiPhy::GetInterfaceCoveringChannelBand(uint16_t frequency, uint16_t width) const
|
|
{
|
|
const auto lowFreq = frequency - (width / 2);
|
|
const auto highFreq = frequency + (width / 2);
|
|
const auto it = std::find_if(m_spectrumPhyInterfaces.cbegin(),
|
|
m_spectrumPhyInterfaces.cend(),
|
|
[lowFreq, highFreq](const auto& item) {
|
|
return ((lowFreq >= item.first.minFrequency) &&
|
|
(highFreq <= item.first.maxFrequency));
|
|
});
|
|
if (it == std::end(m_spectrumPhyInterfaces))
|
|
{
|
|
return nullptr;
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
Ptr<WifiSpectrumPhyInterface>
|
|
SpectrumWifiPhy::GetCurrentInterface() const
|
|
{
|
|
return m_currentSpectrumPhyInterface;
|
|
}
|
|
|
|
void
|
|
SpectrumWifiPhy::SetChannelSwitchedCallback(Callback<void> callback)
|
|
{
|
|
m_channelSwitchedCallback = callback;
|
|
}
|
|
|
|
} // namespace ns3
|