#include "interference-helper.h"
#include "wifi-phy.h"
#include "error-rate-model.h"
#include "ns3/simulator.h"
#include "ns3/log.h"
#include <algorithm>
NS_LOG_COMPONENT_DEFINE ("InterferenceHelper");
namespace ns3 {
/****************************************************************
* Phy event class
****************************************************************/
InterferenceHelper::Event::Event (uint32_t size, WifiMode payloadMode,
enum WifiPreamble preamble,
Time duration, double rxPower)
: m_size (size),
m_payloadMode (payloadMode),
m_preamble (preamble),
m_startTime (Simulator::Now ()),
m_endTime (m_startTime + duration),
m_rxPowerW (rxPower)
{}
InterferenceHelper::Event::~Event ()
{}
Time
InterferenceHelper::Event::GetDuration (void) const
{
return m_endTime - m_startTime;
}
Time
InterferenceHelper::Event::GetStartTime (void) const
{
return m_startTime;
}
Time
InterferenceHelper::Event::GetEndTime (void) const
{
return m_endTime;
}
bool
InterferenceHelper::Event::Overlaps (Time time) const
{
if (m_startTime <= time &&
m_endTime >= time)
{
return true;
}
else
{
return false;
}
}
double
InterferenceHelper::Event::GetRxPowerW (void) const
{
return m_rxPowerW;
}
uint32_t
InterferenceHelper::Event::GetSize (void) const
{
return m_size;
}
WifiMode
InterferenceHelper::Event::GetPayloadMode (void) const
{
return m_payloadMode;
}
enum WifiPreamble
InterferenceHelper::Event::GetPreambleType (void) const
{
return m_preamble;
}
/****************************************************************
* Class which records SNIR change events for a
* short period of time.
****************************************************************/
InterferenceHelper::NiChange::NiChange (Time time, double delta)
: m_time (time), m_delta (delta)
{}
Time
InterferenceHelper::NiChange::GetTime (void) const
{
return m_time;
}
double
InterferenceHelper::NiChange::GetDelta (void) const
{
return m_delta;
}
bool
InterferenceHelper::NiChange::operator < (InterferenceHelper::NiChange const &o) const
{
return (m_time < o.m_time)?true:false;
}
/****************************************************************
* The actual InterferenceHelper
****************************************************************/
InterferenceHelper::InterferenceHelper ()
: m_80211a (false),
m_errorRateModel (0)
{}
InterferenceHelper::~InterferenceHelper ()
{
m_errorRateModel = 0;
}
Ptr<InterferenceHelper::Event>
InterferenceHelper::Add (uint32_t size, WifiMode payloadMode,
enum WifiPreamble preamble,
Time duration, double rxPowerW)
{
Ptr<InterferenceHelper::Event> event;
event = Create<InterferenceHelper::Event>
(size,
payloadMode,
preamble,
duration,
rxPowerW);
AppendEvent (event);
return event;
}
Time
InterferenceHelper::GetMaxPacketDuration (void) const
{
return m_maxPacketDuration;
}
void
InterferenceHelper::SetNoiseFloorW (double noiseFloor)
{
m_noiseFloorW = noiseFloor;
}
double
InterferenceHelper::GetNoiseFloorW (void) const
{
return m_noiseFloorW;
}
void
InterferenceHelper::SetErrorRateModel (Ptr<ErrorRateModel> rate)
{
m_errorRateModel = rate;
}
Ptr<ErrorRateModel>
InterferenceHelper::GetErrorRateModel (void) const
{
return m_errorRateModel;
}
Time
InterferenceHelper::GetEnergyDuration (double energyW)
{
Time now = Simulator::Now ();
// first, we iterate over all events and, each event
// which contributes energy to the channel now is
// appended to the noise interference array.
Events::const_iterator i = m_events.begin ();
double noiseInterferenceW = 0.0;
NiChanges ni;
while (i != m_events.end ())
{
Ptr<Event> ev = *i;
NS_ASSERT (ev->GetStartTime () <= now);
if (ev->GetEndTime () > now)
{
ni.push_back (NiChange (ev->GetEndTime (), -ev->GetRxPowerW ()));
noiseInterferenceW += ev->GetRxPowerW ();
}
i++;
}
if (noiseInterferenceW < energyW)
{
return MicroSeconds (0);
}
/* quicksort vector of NI changes by time.
*/
std::sort (ni.begin (), ni.end (), std::less<NiChange> ());
// Now, we iterate the piecewise linear noise function
Time end = now;
for (NiChanges::const_iterator i = ni.begin (); i != ni.end (); i++)
{
noiseInterferenceW += i->GetDelta ();
end = i->GetTime ();
if (noiseInterferenceW < energyW)
{
break;
}
}
return end - now;
}
Time
InterferenceHelper::CalculateTxDuration (uint32_t size, WifiMode payloadMode, WifiPreamble preamble) const
{
NS_ASSERT (m_80211a);
uint64_t delay = 0;
delay += m_plcpLongPreambleDelayUs;
// symbol duration is 4us
delay += 4;
delay += lrint (ceil ((size * 8.0 + 16.0 + 6.0) / payloadMode.GetDataRate () / 4e-6) * 4);
return MicroSeconds (delay);
}
void
InterferenceHelper::Configure80211aParameters (void)
{
NS_LOG_FUNCTION (this);
m_80211a = true;
m_plcpLongPreambleDelayUs = 16;
m_plcpShortPreambleDelayUs = 16;
m_longPlcpHeaderMode = WifiPhy::g_6mba;
m_shortPlcpHeaderMode = WifiPhy::g_6mba;
m_plcpHeaderLength = 4 + 1 + 12 + 1 + 6;
/* 4095 bytes at a 6Mb/s rate with a 1/2 coding rate. */
m_maxPacketDuration = CalculateTxDuration (4095, WifiPhy::g_6mba, WIFI_PREAMBLE_LONG);
}
void
InterferenceHelper::AppendEvent (Ptr<InterferenceHelper::Event> event)
{
/* attempt to remove the events which are
* not useful anymore.
* i.e.: all events which end _before_
* now - m_maxPacketDuration
*/
if (Simulator::Now () > GetMaxPacketDuration ())
{
Time end = Simulator::Now () - GetMaxPacketDuration ();
Events::iterator i = m_events.begin ();
while (i != m_events.end () &&
(*i)->GetEndTime () <= end)
{
i++;
}
m_events.erase (m_events.begin (), i);
}
m_events.push_back (event);
}
double
InterferenceHelper::CalculateSnr (double signal, double noiseInterference, WifiMode mode) const
{
// thermal noise at 290K in J/s = W
static const double BOLTZMANN = 1.3803e-23;
double Nt = BOLTZMANN * 290.0 * mode.GetBandwidth ();
// receiver noise Floor (W)
double noiseFloor = m_noiseFloorW * Nt;
double noise = noiseFloor + noiseInterference;
double snr = signal / noise;
return snr;
}
double
InterferenceHelper::CalculateNoiseInterferenceW (Ptr<InterferenceHelper::Event> event, NiChanges *ni) const
{
Events::const_iterator i = m_events.begin ();
double noiseInterference = 0.0;
while (i != m_events.end ())
{
if (event == (*i))
{
i++;
continue;
}
if (event->Overlaps ((*i)->GetStartTime ()))
{
ni->push_back (NiChange ((*i)->GetStartTime (), (*i)->GetRxPowerW ()));
}
if (event->Overlaps ((*i)->GetEndTime ()))
{
ni->push_back (NiChange ((*i)->GetEndTime (), -(*i)->GetRxPowerW ()));
}
if ((*i)->Overlaps (event->GetStartTime ()))
{
noiseInterference += (*i)->GetRxPowerW ();
}
i++;
}
ni->push_back (NiChange (event->GetStartTime (), noiseInterference));
ni->push_back (NiChange (event->GetEndTime (), 0));
/* quicksort vector of NI changes by time. */
std::sort (ni->begin (), ni->end (), std::less<NiChange> ());
return noiseInterference;
}
double
InterferenceHelper::CalculateChunkSuccessRate (double snir, Time duration, WifiMode mode) const
{
if (duration == NanoSeconds (0)) {
return 1.0;
}
uint32_t rate = mode.GetPhyRate ();
uint64_t nbits = (uint64_t)(rate * duration.GetSeconds ());
double csr = m_errorRateModel->GetChunkSuccessRate (mode, snir, (uint32_t)nbits);
return csr;
}
double
InterferenceHelper::CalculatePer (Ptr<const InterferenceHelper::Event> event, NiChanges *ni) const
{
double psr = 1.0; /* Packet Success Rate */
NiChanges::iterator j = ni->begin ();
Time previous = (*j).GetTime ();
uint64_t plcpPreambleDelayUs;
WifiMode payloadMode = event->GetPayloadMode ();
WifiMode headerMode;
switch (event->GetPreambleType ()) {
case WIFI_PREAMBLE_LONG:
plcpPreambleDelayUs = m_plcpLongPreambleDelayUs;
headerMode = m_longPlcpHeaderMode;
break;
case WIFI_PREAMBLE_SHORT:
plcpPreambleDelayUs = m_plcpShortPreambleDelayUs;
headerMode = m_shortPlcpHeaderMode;
break;
default:
NS_ASSERT (false);
// only to quiet compiler. Really stupid.
plcpPreambleDelayUs = 0;
headerMode = m_shortPlcpHeaderMode;
break;
}
Time plcpHeaderStart = (*j).GetTime () + MicroSeconds (plcpPreambleDelayUs);
Time plcpPayloadStart = plcpHeaderStart +
Seconds ((m_plcpHeaderLength + 0.0) / headerMode.GetDataRate ());
double noiseInterferenceW = (*j).GetDelta ();
double powerW = event->GetRxPowerW ();
j++;
while (ni->end () != j)
{
Time current = (*j).GetTime ();
NS_ASSERT (current >= previous);
if (previous >= plcpPayloadStart)
{
psr *= CalculateChunkSuccessRate (CalculateSnr (powerW,
noiseInterferenceW,
payloadMode),
current - previous,
payloadMode);
}
else if (previous >= plcpHeaderStart)
{
if (current >= plcpPayloadStart)
{
psr *= CalculateChunkSuccessRate (CalculateSnr (powerW,
noiseInterferenceW,
headerMode),
plcpPayloadStart - previous,
headerMode);
psr *= CalculateChunkSuccessRate (CalculateSnr (powerW,
noiseInterferenceW,
payloadMode),
current - plcpPayloadStart,
payloadMode);
}
else
{
NS_ASSERT (current >= plcpHeaderStart);
psr *= CalculateChunkSuccessRate (CalculateSnr (powerW,
noiseInterferenceW,
headerMode),
current - previous,
headerMode);
}
}
else
{
if (current >= plcpPayloadStart)
{
psr *= CalculateChunkSuccessRate (CalculateSnr (powerW,
noiseInterferenceW,
headerMode),
plcpPayloadStart - plcpHeaderStart,
headerMode);
psr *= CalculateChunkSuccessRate (CalculateSnr (powerW,
noiseInterferenceW,
payloadMode),
current - plcpPayloadStart,
payloadMode);
}
else if (current >= plcpHeaderStart)
{
psr *= CalculateChunkSuccessRate (CalculateSnr (powerW,
noiseInterferenceW,
headerMode),
current - plcpHeaderStart,
headerMode);
}
}
noiseInterferenceW += (*j).GetDelta ();
previous = (*j).GetTime ();
j++;
}
double per = 1 - psr;
return per;
}
struct InterferenceHelper::SnrPer
InterferenceHelper::CalculateSnrPer (Ptr<InterferenceHelper::Event> event)
{
NiChanges ni;
double noiseInterferenceW = CalculateNoiseInterferenceW (event, &ni);
double snr = CalculateSnr (event->GetRxPowerW (),
noiseInterferenceW,
event->GetPayloadMode ());
/* calculate the SNIR at the start of the packet and accumulate
* all SNIR changes in the snir vector.
*/
double per = CalculatePer (event, &ni);
struct SnrPer snrPer;
snrPer.snr = snr;
snrPer.per = per;
return snrPer;
}
} // namespace ns3