src/devices/wifi/interference-helper.cc
changeset 3905 99c9346b5d71
child 3906 01acc159ffb1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/wifi/interference-helper.cc	Sat Jun 14 10:52:10 2008 -0700
@@ -0,0 +1,441 @@
+#include "interference-helper.h"
+#include "wifi-phy.h"
+#include "error-rate-model.h"
+#include "ns3/simulator.h"
+#include "ns3/log.h"
+
+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 = Create<ErrorRateModel> ();
+}
+
+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