fixed Bug 799 - Interference helper is too slow
authorKirill Andreev <andreev@iitp.ru>
Mon, 02 Aug 2010 17:09:16 +0200
changeset 6474 0894b2a245e9
parent 6473 86a4a149eb0f
child 6475 15d607863e1e
fixed Bug 799 - Interference helper is too slow
src/devices/wifi/interference-helper.cc
src/devices/wifi/interference-helper.h
src/devices/wifi/yans-wifi-phy.cc
--- a/src/devices/wifi/interference-helper.cc	Mon Aug 02 13:15:36 2010 +0200
+++ b/src/devices/wifi/interference-helper.cc	Mon Aug 02 17:09:16 2010 +0200
@@ -60,19 +60,6 @@
 {
   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
 {
@@ -123,8 +110,9 @@
  ****************************************************************/
 
 InterferenceHelper::InterferenceHelper ()
-  : m_maxPacketDuration (Seconds(0)),
-    m_errorRateModel (0)  
+  : m_errorRateModel (0),
+    m_firstPower (0.0),
+    m_rxing (false)
 {}
 InterferenceHelper::~InterferenceHelper ()
 {
@@ -145,17 +133,10 @@
      preamble,
      duration,
      rxPowerW);
-
-  m_maxPacketDuration = std::max(duration, m_maxPacketDuration);
   AppendEvent (event);
   return event;
 }
 
-Time 
-InterferenceHelper::GetMaxPacketDuration (void) const
-{
-  return m_maxPacketDuration;
-}
 
 void 
 InterferenceHelper::SetNoiseFigure (double value)
@@ -185,45 +166,23 @@
 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 = m_firstPower;
+  for (NiChanges::const_iterator i = m_niChanges.begin (); i != m_niChanges.end (); i++)
     {
       noiseInterferenceW += i->GetDelta ();
       end = i->GetTime ();
-      if (noiseInterferenceW < energyW) 
-	{
-	  break;
-	}
+      if (end < now)
+        {
+          continue;
+        }
+      if (noiseInterferenceW < energyW)
+	      {
+	        break;
+	      }
     }
-  return end - now;
+  return end > now ? end - now : MicroSeconds (0);
 }
 
 WifiMode 
@@ -412,24 +371,23 @@
 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 now = Simulator::Now ();
+  if (!m_rxing)
     {
-      Time end = Simulator::Now () - GetMaxPacketDuration ();
-      Events::iterator i = m_events.begin ();
-      while (i != m_events.end () &&
-             (*i)->GetEndTime () <= end) 
+      NiChanges::iterator nowIterator = GetPosition (now);
+      for (NiChanges::iterator i = m_niChanges.begin (); i != nowIterator; i++)
         {
-          i++;
+          m_firstPower += i->GetDelta ();
         }
-      EraseEvents (m_events.begin (), i);
-    } 
-  m_events.push_back (event);
+      m_niChanges.erase (m_niChanges.begin (), nowIterator);
+      m_niChanges.insert (m_niChanges.begin (), NiChange (event->GetStartTime (), event->GetRxPowerW ())); 
+    }
+  else
+    {
+      AddNiChangeEvent (NiChange (event->GetStartTime (), event->GetRxPowerW ()));
+    }
+  AddNiChangeEvent(NiChange (event->GetEndTime (), -event->GetRxPowerW ()));
+
 }
 
 
@@ -450,35 +408,18 @@
 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 ()) 
+  double noiseInterference = m_firstPower;
+  NS_ASSERT (m_rxing);
+  for (NiChanges::const_iterator i = m_niChanges.begin () + 1; i != m_niChanges.end (); i++)
     {
-      if (event == (*i)) 
-        {
-          i++;
-          continue;
-        }
-      if ((*i)->Overlaps (event->GetStartTime ())) 
-        {
-          noiseInterference += (*i)->GetRxPowerW ();
-        }
-      else if (event->Overlaps ((*i)->GetStartTime ())) 
+      if ((event->GetEndTime () == i->GetTime ()) && event->GetRxPowerW () == -i->GetDelta ())
         {
-          ni->push_back (NiChange ((*i)->GetStartTime (), (*i)->GetRxPowerW ()));
-        }
-      if (event->Overlaps ((*i)->GetEndTime ())) 
-        {
-          ni->push_back (NiChange ((*i)->GetEndTime (), -(*i)->GetRxPowerW ()));
+          break;
         }
-      i++;
+      ni->push_back (*i);
     }
-  ni->push_back (NiChange (event->GetStartTime (), noiseInterference));
+  ni->insert (ni->begin (), 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;
 }
 
@@ -605,21 +546,28 @@
 void
 InterferenceHelper::EraseEvents (void) 
 {  
-  for (Events::iterator i = m_events.begin (); i != m_events.end (); ++i)
-    {
-      *i = 0;
-    }
-  m_events.clear ();
+  m_niChanges.clear ();
+  m_firstPower = 0.0;
 }
+InterferenceHelper::NiChanges::iterator
+InterferenceHelper::GetPosition (Time moment)
+{
+  return std::upper_bound (m_niChanges.begin (), m_niChanges.end (), NiChange (moment, 0));
 
+}
 void
-InterferenceHelper::EraseEvents (Events::iterator start, Events::iterator end) 
-{  
-  for (Events::iterator i = start; i != end; ++i)
-    {
-      *i = 0;
-    }
-  m_events.erase (start, end);
+InterferenceHelper::AddNiChangeEvent (NiChange change)
+{
+  m_niChanges.insert (GetPosition (change.GetTime ()), change);
 }
-
+void
+InterferenceHelper::NotifyRxStart ()
+{
+  m_rxing = true;
+}
+void
+InterferenceHelper::NotifyRxEnd ()
+{
+  m_rxing = false;
+}
 } // namespace ns3
--- a/src/devices/wifi/interference-helper.h	Mon Aug 02 13:15:36 2010 +0200
+++ b/src/devices/wifi/interference-helper.h	Mon Aug 02 17:09:16 2010 +0200
@@ -47,7 +47,6 @@
     Time GetDuration (void) const;
     Time GetStartTime (void) const;
     Time GetEndTime (void) const;
-    bool Overlaps (Time time) const;
     double GetRxPowerW (void) const;
     uint32_t GetSize (void) const;
     WifiMode GetPayloadMode (void) const;
@@ -95,6 +94,8 @@
 				      Time duration, double rxPower);
 
   struct InterferenceHelper::SnrPer CalculateSnrPer (Ptr<InterferenceHelper::Event> event);
+  void NotifyRxStart ();
+  void NotifyRxEnd ();
   void EraseEvents (void); 
 private:
   class NiChange {
@@ -110,8 +111,6 @@
   typedef std::vector <NiChange> NiChanges;
   typedef std::list<Ptr<Event> > Events;
 
-  void EraseEvents (Events::iterator start, Events::iterator end); 
-
   InterferenceHelper (const InterferenceHelper &o);
   InterferenceHelper &operator = (const InterferenceHelper &o);
   void AppendEvent (Ptr<Event> event);
@@ -119,12 +118,16 @@
   double CalculateSnr (double signal, double noiseInterference, WifiMode mode) const;
   double CalculateChunkSuccessRate (double snir, Time delay, WifiMode mode) const;
   double CalculatePer (Ptr<const Event> event, NiChanges *ni) const;
-  Time GetMaxPacketDuration (void) const;
 
-  Time m_maxPacketDuration;
   double m_noiseFigure; /**< noise figure (linear) */
-  Events m_events;
   Ptr<ErrorRateModel> m_errorRateModel;
+  ///Experimental: needed for energy duration calculation
+  NiChanges m_niChanges;
+  double m_firstPower;
+  bool m_rxing;
+  /// Returns an iterator to the first nichange, which is later than moment
+  NiChanges::iterator GetPosition (Time moment);
+  void AddNiChangeEvent (NiChange change);
 };
 
 } // namespace ns3
--- a/src/devices/wifi/yans-wifi-phy.cc	Mon Aug 02 13:15:36 2010 +0200
+++ b/src/devices/wifi/yans-wifi-phy.cc	Mon Aug 02 17:09:16 2010 +0200
@@ -459,6 +459,7 @@
         m_state->SwitchToRx (rxDuration);
         NS_ASSERT (m_endRxEvent.IsExpired ());
         NotifyRxBegin (packet);
+        m_interference.NotifyRxStart();
         m_endRxEvent = Simulator::Schedule (rxDuration, &YansWifiPhy::EndReceive, this, 
                                             packet,
                                             event);
@@ -504,6 +505,7 @@
   if (m_state->IsStateRx ())
     {
       m_endRxEvent.Cancel ();
+      m_interference.NotifyRxEnd ();
     }
   NotifyTxBegin (packet);
   uint32_t dataRate500KbpsUnits = txMode.GetDataRate () / 500000;   
@@ -754,6 +756,7 @@
 
   struct InterferenceHelper::SnrPer snrPer;
   snrPer = m_interference.CalculateSnrPer (event);
+  m_interference.NotifyRxEnd();
 
   NS_LOG_DEBUG ("mode="<<(event->GetPayloadMode ().GetDataRate ())<<
                 ", snr="<<snrPer.snr<<", per="<<snrPer.per<<", size="<<packet->GetSize ());