1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2005,2006 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  *          Sébastien Deronne <sebastien.deronne@gmail.com>
20  */
21 
22 #include <numeric>
23 #include <algorithm>
24 #include "ns3/simulator.h"
25 #include "ns3/log.h"
26 #include "ns3/packet.h"
27 #include "interference-helper.h"
28 #include "wifi-phy.h"
29 #include "error-rate-model.h"
30 #include "wifi-utils.h"
31 #include "wifi-psdu.h"
32 
33 namespace ns3 {
34 
35 NS_LOG_COMPONENT_DEFINE ("InterferenceHelper");
36 
37 /****************************************************************
38  *       PHY event class
39  ****************************************************************/
40 
Event(Ptr<const WifiPpdu> ppdu,const WifiTxVector & txVector,Time duration,RxPowerWattPerChannelBand && rxPower)41 Event::Event (Ptr<const WifiPpdu> ppdu, const WifiTxVector& txVector, Time duration, RxPowerWattPerChannelBand&& rxPower)
42   : m_ppdu (ppdu),
43     m_txVector (txVector),
44     m_startTime (Simulator::Now ()),
45     m_endTime (m_startTime + duration),
46     m_rxPowerW (std::move (rxPower))
47 {
48 }
49 
~Event()50 Event::~Event ()
51 {
52   m_ppdu = 0;
53   m_rxPowerW.clear ();
54 }
55 
56 Ptr<const WifiPpdu>
GetPpdu(void) const57 Event::GetPpdu (void) const
58 {
59   return m_ppdu;
60 }
61 
62 Time
GetStartTime(void) const63 Event::GetStartTime (void) const
64 {
65   return m_startTime;
66 }
67 
68 Time
GetEndTime(void) const69 Event::GetEndTime (void) const
70 {
71   return m_endTime;
72 }
73 
74 Time
GetDuration(void) const75 Event::GetDuration (void) const
76 {
77   return m_endTime - m_startTime;
78 }
79 
80 double
GetRxPowerW(void) const81 Event::GetRxPowerW (void) const
82 {
83   NS_ASSERT (m_rxPowerW.size () > 0);
84   //The total RX power corresponds to the maximum over all the bands
85   auto it = std::max_element (m_rxPowerW.begin (), m_rxPowerW.end (),
86     [] (const std::pair<WifiSpectrumBand, double>& p1, const std::pair<WifiSpectrumBand, double>& p2) {
87       return p1.second < p2.second;
88     });
89   return it->second;
90 }
91 
92 double
GetRxPowerW(WifiSpectrumBand band) const93 Event::GetRxPowerW (WifiSpectrumBand band) const
94 {
95   auto it = m_rxPowerW.find (band);
96   NS_ASSERT (it != m_rxPowerW.end ());
97   return it->second;
98 }
99 
100 const RxPowerWattPerChannelBand&
GetRxPowerWPerBand(void) const101 Event::GetRxPowerWPerBand (void) const
102 {
103   return m_rxPowerW;
104 }
105 
106 const WifiTxVector&
GetTxVector(void) const107 Event::GetTxVector (void) const
108 {
109   return m_txVector;
110 }
111 
112 void
UpdateRxPowerW(const RxPowerWattPerChannelBand & rxPower)113 Event::UpdateRxPowerW (const RxPowerWattPerChannelBand& rxPower)
114 {
115   NS_ASSERT (rxPower.size () == m_rxPowerW.size ());
116   //Update power band per band
117   for (auto & currentRxPowerW : m_rxPowerW)
118     {
119       auto band = currentRxPowerW.first;
120       auto it = rxPower.find (band);
121       if (it != rxPower.end ())
122         {
123           currentRxPowerW.second += it->second;
124         }
125     }
126 }
127 
operator <<(std::ostream & os,const Event & event)128 std::ostream & operator << (std::ostream &os, const Event &event)
129 {
130   os << "start=" << event.GetStartTime () << ", end=" << event.GetEndTime ()
131      << ", TXVECTOR=" << event.GetTxVector ()
132      << ", power=" << event.GetRxPowerW () << "W"
133      << ", PPDU=" << event.GetPpdu ();
134   return os;
135 }
136 
137 /****************************************************************
138  *       Class which records SNIR change events for a
139  *       short period of time.
140  ****************************************************************/
141 
NiChange(double power,Ptr<Event> event)142 InterferenceHelper::NiChange::NiChange (double power, Ptr<Event> event)
143   : m_power (power),
144     m_event (event)
145 {
146 }
147 
~NiChange()148 InterferenceHelper::NiChange::~NiChange ()
149 {
150   m_event = 0;
151 }
152 
153 double
GetPower(void) const154 InterferenceHelper::NiChange::GetPower (void) const
155 {
156   return m_power;
157 }
158 
159 void
AddPower(double power)160 InterferenceHelper::NiChange::AddPower (double power)
161 {
162   m_power += power;
163 }
164 
165 Ptr<Event>
GetEvent(void) const166 InterferenceHelper::NiChange::GetEvent (void) const
167 {
168   return m_event;
169 }
170 
171 
172 /****************************************************************
173  *       The actual InterferenceHelper
174  ****************************************************************/
175 
InterferenceHelper()176 InterferenceHelper::InterferenceHelper ()
177   : m_errorRateModel (0),
178     m_numRxAntennas (1),
179     m_rxing (false)
180 {
181 }
182 
~InterferenceHelper()183 InterferenceHelper::~InterferenceHelper ()
184 {
185   RemoveBands ();
186   m_errorRateModel = 0;
187 }
188 
189 Ptr<Event>
Add(Ptr<const WifiPpdu> ppdu,const WifiTxVector & txVector,Time duration,RxPowerWattPerChannelBand & rxPowerW,bool isStartOfdmaRxing)190 InterferenceHelper::Add (Ptr<const WifiPpdu> ppdu, const WifiTxVector& txVector, Time duration, RxPowerWattPerChannelBand& rxPowerW, bool isStartOfdmaRxing)
191 {
192   Ptr<Event> event = Create<Event> (ppdu, txVector, duration, std::move (rxPowerW));
193   AppendEvent (event, isStartOfdmaRxing);
194   return event;
195 }
196 
197 void
AddForeignSignal(Time duration,RxPowerWattPerChannelBand & rxPowerW)198 InterferenceHelper::AddForeignSignal (Time duration, RxPowerWattPerChannelBand& rxPowerW)
199 {
200   // Parameters other than duration and rxPowerW are unused for this type
201   // of signal, so we provide dummy versions
202   WifiMacHeader hdr;
203   hdr.SetType (WIFI_MAC_QOSDATA);
204   hdr.SetQosTid (0);
205   Ptr<WifiPpdu> fakePpdu = Create<WifiPpdu> (Create<WifiPsdu> (Create<Packet> (0), hdr),
206                                              WifiTxVector ());
207   Add (fakePpdu, WifiTxVector (), duration, rxPowerW);
208 }
209 
210 void
RemoveBands(void)211 InterferenceHelper::RemoveBands(void)
212 {
213   NS_LOG_FUNCTION (this);
214   for (auto it : m_niChangesPerBand)
215     {
216       it.second.clear ();
217     }
218   m_niChangesPerBand.clear();
219   m_firstPowerPerBand.clear();
220 }
221 
222 void
AddBand(WifiSpectrumBand band)223 InterferenceHelper::AddBand (WifiSpectrumBand band)
224 {
225   NS_LOG_FUNCTION (this << band.first << band.second);
226   NS_ASSERT (m_niChangesPerBand.find (band) == m_niChangesPerBand.end ());
227   NiChanges niChanges;
228   auto result = m_niChangesPerBand.insert ({band, niChanges});
229   NS_ASSERT (result.second);
230   // Always have a zero power noise event in the list
231   AddNiChangeEvent (Time (0), NiChange (0.0, 0), result.first);
232   m_firstPowerPerBand.insert ({band, 0.0});
233 }
234 
235 void
SetNoiseFigure(double value)236 InterferenceHelper::SetNoiseFigure (double value)
237 {
238   m_noiseFigure = value;
239 }
240 
241 void
SetErrorRateModel(const Ptr<ErrorRateModel> rate)242 InterferenceHelper::SetErrorRateModel (const Ptr<ErrorRateModel> rate)
243 {
244   m_errorRateModel = rate;
245 }
246 
247 Ptr<ErrorRateModel>
GetErrorRateModel(void) const248 InterferenceHelper::GetErrorRateModel (void) const
249 {
250   return m_errorRateModel;
251 }
252 
253 void
SetNumberOfReceiveAntennas(uint8_t rx)254 InterferenceHelper::SetNumberOfReceiveAntennas (uint8_t rx)
255 {
256   m_numRxAntennas = rx;
257 }
258 
259 Time
GetEnergyDuration(double energyW,WifiSpectrumBand band)260 InterferenceHelper::GetEnergyDuration (double energyW, WifiSpectrumBand band)
261 {
262   Time now = Simulator::Now ();
263   auto niIt = m_niChangesPerBand.find (band);
264   NS_ASSERT (niIt != m_niChangesPerBand.end ());
265   auto i = GetPreviousPosition (now, niIt);
266   Time end = i->first;
267   for (; i != niIt->second.end (); ++i)
268     {
269       double noiseInterferenceW = i->second.GetPower ();
270       end = i->first;
271       if (noiseInterferenceW < energyW)
272         {
273           break;
274         }
275     }
276   return end > now ? end - now : MicroSeconds (0);
277 }
278 
279 void
AppendEvent(Ptr<Event> event,bool isStartOfdmaRxing)280 InterferenceHelper::AppendEvent (Ptr<Event> event, bool isStartOfdmaRxing)
281 {
282   NS_LOG_FUNCTION (this << event << isStartOfdmaRxing);
283   for (auto const& it : event->GetRxPowerWPerBand ())
284     {
285       WifiSpectrumBand band = it.first;
286       auto niIt = m_niChangesPerBand.find (band);
287       NS_ASSERT (niIt != m_niChangesPerBand.end ());
288       double previousPowerStart = 0;
289       double previousPowerEnd = 0;
290       auto previousPowerPosition = GetPreviousPosition (event->GetStartTime (), niIt);
291       previousPowerStart = previousPowerPosition->second.GetPower ();
292       previousPowerEnd = GetPreviousPosition (event->GetEndTime (), niIt)->second.GetPower ();
293       if (!m_rxing)
294         {
295           m_firstPowerPerBand.find (band)->second = previousPowerStart;
296           // Always leave the first zero power noise event in the list
297           niIt->second.erase (++(niIt->second.begin ()), ++previousPowerPosition);
298         }
299       else if (isStartOfdmaRxing)
300         {
301           //When the first UL-OFDMA payload is received, we need to set m_firstPowerPerBand
302           //so that it takes into account interferences that arrived between the start of the
303           //UL MU transmission and the start of UL-OFDMA payload.
304           m_firstPowerPerBand.find (band)->second = previousPowerStart;
305         }
306       auto first = AddNiChangeEvent (event->GetStartTime (), NiChange (previousPowerStart, event), niIt);
307       auto last = AddNiChangeEvent (event->GetEndTime (), NiChange (previousPowerEnd, event), niIt);
308       for (auto i = first; i != last; ++i)
309         {
310           i->second.AddPower (it.second);
311         }
312     }
313 }
314 
315 void
UpdateEvent(Ptr<Event> event,const RxPowerWattPerChannelBand & rxPower)316 InterferenceHelper::UpdateEvent (Ptr<Event> event, const RxPowerWattPerChannelBand& rxPower)
317 {
318   NS_LOG_FUNCTION (this << event);
319   //This is called for UL MU events, in order to scale power as long as UL MU PPDUs arrive
320   for (auto const& it : rxPower)
321     {
322       WifiSpectrumBand band = it.first;
323       auto niIt = m_niChangesPerBand.find (band);
324       NS_ASSERT (niIt != m_niChangesPerBand.end ());
325       auto first = GetPreviousPosition (event->GetStartTime (), niIt);
326       auto last = GetPreviousPosition (event->GetEndTime (), niIt);
327       for (auto i = first; i != last; ++i)
328         {
329           i->second.AddPower (it.second);
330         }
331     }
332     event->UpdateRxPowerW (rxPower);
333 }
334 
335 double
CalculateSnr(double signal,double noiseInterference,uint16_t channelWidth,uint8_t nss) const336 InterferenceHelper::CalculateSnr (double signal, double noiseInterference, uint16_t channelWidth, uint8_t nss) const
337 {
338   NS_LOG_FUNCTION (this << signal << noiseInterference << channelWidth << +nss);
339   //thermal noise at 290K in J/s = W
340   static const double BOLTZMANN = 1.3803e-23;
341   //Nt is the power of thermal noise in W
342   double Nt = BOLTZMANN * 290 * channelWidth * 1e6;
343   //receiver noise Floor (W) which accounts for thermal noise and non-idealities of the receiver
344   double noiseFloor = m_noiseFigure * Nt;
345   double noise = noiseFloor + noiseInterference;
346   double snr = signal / noise; //linear scale
347   NS_LOG_DEBUG ("bandwidth(MHz)=" << channelWidth << ", signal(W)= " << signal << ", noise(W)=" << noiseFloor << ", interference(W)=" << noiseInterference << ", snr=" << RatioToDb(snr) << "dB");
348   if (m_errorRateModel->IsAwgn ())
349     {
350       double gain = 1;
351       if (m_numRxAntennas > nss)
352         {
353           gain = static_cast<double> (m_numRxAntennas) / nss; //compute gain offered by diversity for AWGN
354         }
355       NS_LOG_DEBUG ("SNR improvement thanks to diversity: " << 10 * std::log10 (gain) << "dB");
356       snr *= gain;
357     }
358   return snr;
359 }
360 
361 double
CalculateNoiseInterferenceW(Ptr<Event> event,NiChangesPerBand * nis,WifiSpectrumBand band) const362 InterferenceHelper::CalculateNoiseInterferenceW (Ptr<Event> event, NiChangesPerBand *nis, WifiSpectrumBand band) const
363 {
364   NS_LOG_FUNCTION (this << band.first << band.second);
365   auto firstPower_it = m_firstPowerPerBand.find (band);
366   NS_ASSERT (firstPower_it != m_firstPowerPerBand.end ());
367   double noiseInterferenceW = firstPower_it->second;
368   auto niIt = m_niChangesPerBand.find (band);
369   NS_ASSERT (niIt != m_niChangesPerBand.end ());
370   auto it = niIt->second.find (event->GetStartTime ());
371   for (; it != niIt->second.end () && it->first < Simulator::Now (); ++it)
372     {
373       noiseInterferenceW = it->second.GetPower () - event->GetRxPowerW (band);
374     }
375   it = niIt->second.find (event->GetStartTime ());
376   NS_ASSERT (it != niIt->second.end ());
377   for (; it != niIt->second.end () && it->second.GetEvent () != event; ++it);
378   NiChanges ni;
379   ni.emplace (event->GetStartTime (), NiChange (0, event));
380   while (++it != niIt->second.end () && it->second.GetEvent () != event)
381     {
382       ni.insert (*it);
383     }
384   ni.emplace (event->GetEndTime (), NiChange (0, event));
385   nis->insert ({band, ni});
386   NS_ASSERT_MSG (noiseInterferenceW >= 0, "CalculateNoiseInterferenceW returns negative value " << noiseInterferenceW);
387   return noiseInterferenceW;
388 }
389 
390 double
CalculateChunkSuccessRate(double snir,Time duration,WifiMode mode,const WifiTxVector & txVector,WifiPpduField field) const391 InterferenceHelper::CalculateChunkSuccessRate (double snir, Time duration, WifiMode mode, const WifiTxVector& txVector, WifiPpduField field) const
392 {
393   if (duration.IsZero ())
394     {
395       return 1.0;
396     }
397   uint64_t rate = mode.GetDataRate (txVector.GetChannelWidth ());
398   uint64_t nbits = static_cast<uint64_t> (rate * duration.GetSeconds ());
399   double csr = m_errorRateModel->GetChunkSuccessRate (mode, txVector, snir, nbits, m_numRxAntennas, field);
400   return csr;
401 }
402 
403 double
CalculatePayloadChunkSuccessRate(double snir,Time duration,const WifiTxVector & txVector,uint16_t staId) const404 InterferenceHelper::CalculatePayloadChunkSuccessRate (double snir, Time duration, const WifiTxVector& txVector, uint16_t staId) const
405 {
406   if (duration.IsZero ())
407     {
408       return 1.0;
409     }
410   WifiMode mode = txVector.GetMode (staId);
411   uint64_t rate = mode.GetDataRate (txVector, staId);
412   uint64_t nbits = static_cast<uint64_t> (rate * duration.GetSeconds ());
413   nbits /= txVector.GetNss (staId); //divide effective number of bits by NSS to achieve same chunk error rate as SISO for AWGN
414   double csr = m_errorRateModel->GetChunkSuccessRate (mode, txVector, snir, nbits, m_numRxAntennas, WIFI_PPDU_FIELD_DATA, staId);
415   return csr;
416 }
417 
418 double
CalculatePayloadPer(Ptr<const Event> event,uint16_t channelWidth,NiChangesPerBand * nis,WifiSpectrumBand band,uint16_t staId,std::pair<Time,Time> window) const419 InterferenceHelper::CalculatePayloadPer (Ptr<const Event> event, uint16_t channelWidth,
420                                          NiChangesPerBand *nis, WifiSpectrumBand band,
421                                          uint16_t staId, std::pair<Time, Time> window) const
422 {
423   NS_LOG_FUNCTION (this << channelWidth << band.first << band.second << staId << window.first << window.second);
424   double psr = 1.0; /* Packet Success Rate */
425   auto niIt = nis->find (band)->second;
426   auto j = niIt.begin ();
427   Time previous = j->first;
428   WifiMode payloadMode = event->GetTxVector ().GetMode (staId);
429   Time phyPayloadStart = j->first;
430   if (event->GetPpdu ()->GetType () != WIFI_PPDU_TYPE_UL_MU) //j->first corresponds to the start of the UL-OFDMA payload
431     {
432       phyPayloadStart = j->first + WifiPhy::CalculatePhyPreambleAndHeaderDuration (event->GetTxVector ());
433     }
434   Time windowStart = phyPayloadStart + window.first;
435   Time windowEnd = phyPayloadStart + window.second;
436   double noiseInterferenceW = m_firstPowerPerBand.find (band)->second;
437   double powerW = event->GetRxPowerW (band);
438   while (++j != niIt.end ())
439     {
440       Time current = j->first;
441       NS_LOG_DEBUG ("previous= " << previous << ", current=" << current);
442       NS_ASSERT (current >= previous);
443       double snr = CalculateSnr (powerW, noiseInterferenceW, channelWidth, event->GetTxVector ().GetNss (staId));
444       //Case 1: Both previous and current point to the windowed payload
445       if (previous >= windowStart)
446         {
447           psr *= CalculatePayloadChunkSuccessRate (snr, Min (windowEnd, current) - previous, event->GetTxVector (), staId);
448           NS_LOG_DEBUG ("Both previous and current point to the windowed payload: mode=" << payloadMode << ", psr=" << psr);
449         }
450       //Case 2: previous is before windowed payload and current is in the windowed payload
451       else if (current >= windowStart)
452         {
453           psr *= CalculatePayloadChunkSuccessRate (snr, Min (windowEnd, current) - windowStart, event->GetTxVector (), staId);
454           NS_LOG_DEBUG ("previous is before windowed payload and current is in the windowed payload: mode=" << payloadMode << ", psr=" << psr);
455         }
456       noiseInterferenceW = j->second.GetPower () - powerW;
457       previous = j->first;
458       if (previous > windowEnd)
459         {
460           NS_LOG_DEBUG ("Stop: new previous=" << previous << " after time window end=" << windowEnd);
461           break;
462         }
463     }
464   double per = 1 - psr;
465   return per;
466 }
467 
468 double
CalculatePhyHeaderSectionPsr(Ptr<const Event> event,NiChangesPerBand * nis,uint16_t channelWidth,WifiSpectrumBand band,PhyEntity::PhyHeaderSections phyHeaderSections) const469 InterferenceHelper::CalculatePhyHeaderSectionPsr (Ptr<const Event> event, NiChangesPerBand *nis,
470                                                   uint16_t channelWidth, WifiSpectrumBand band,
471                                                   PhyEntity::PhyHeaderSections phyHeaderSections) const
472 {
473   NS_LOG_FUNCTION (this << band.first << band.second);
474   double psr = 1.0; /* Packet Success Rate */
475   auto niIt = nis->find (band)->second;
476   auto j = niIt.begin ();
477 
478   NS_ASSERT (!phyHeaderSections.empty ());
479   Time stopLastSection = Seconds (0);
480   for (const auto & section : phyHeaderSections)
481     {
482       stopLastSection = Max (stopLastSection, section.second.first.second);
483     }
484 
485   Time previous = j->first;
486   double noiseInterferenceW = m_firstPowerPerBand.find (band)->second;
487   double powerW = event->GetRxPowerW (band);
488   while (++j != niIt.end ())
489     {
490       Time current = j->first;
491       NS_LOG_DEBUG ("previous= " << previous << ", current=" << current);
492       NS_ASSERT (current >= previous);
493       double snr = CalculateSnr (powerW, noiseInterferenceW, channelWidth, 1);
494       for (const auto & section : phyHeaderSections)
495         {
496           Time start = section.second.first.first;
497           Time stop = section.second.first.second;
498 
499           if (previous <= stop || current >= start)
500             {
501               Time duration = Min (stop, current) - Max (start, previous);
502               if (duration.IsStrictlyPositive ())
503                 {
504                   psr *= CalculateChunkSuccessRate (snr, duration, section.second.second, event->GetTxVector (), section.first);
505                   NS_LOG_DEBUG ("Current NI change in " << section.first << " [" << start << ", " << stop << "] for "
506                                 << duration.As (Time::NS) << ": mode=" << section.second.second << ", psr=" << psr);
507                 }
508             }
509         }
510       noiseInterferenceW = j->second.GetPower () - powerW;
511       previous = j->first;
512       if (previous > stopLastSection)
513         {
514           NS_LOG_DEBUG ("Stop: new previous=" << previous << " after stop of last section=" << stopLastSection);
515           break;
516         }
517     }
518   return psr;
519 }
520 
521 double
CalculatePhyHeaderPer(Ptr<const Event> event,NiChangesPerBand * nis,uint16_t channelWidth,WifiSpectrumBand band,WifiPpduField header) const522 InterferenceHelper::CalculatePhyHeaderPer (Ptr<const Event> event, NiChangesPerBand *nis,
523                                            uint16_t channelWidth, WifiSpectrumBand band,
524                                            WifiPpduField header) const
525 {
526   NS_LOG_FUNCTION (this << band.first << band.second << header);
527   auto niIt = nis->find (band)->second;
528   auto phyEntity = WifiPhy::GetStaticPhyEntity (event->GetTxVector ().GetModulationClass ());
529 
530   PhyEntity::PhyHeaderSections sections;
531   for (const auto & section : phyEntity->GetPhyHeaderSections (event->GetTxVector (), niIt.begin ()->first))
532     {
533       if (section.first == header)
534         {
535           sections[header] = section.second;
536         }
537     }
538 
539   double psr = 1.0;
540   if (!sections.empty () > 0)
541     {
542       psr = CalculatePhyHeaderSectionPsr (event, nis, channelWidth, band, sections);
543     }
544   return 1 - psr;
545 }
546 
547 struct PhyEntity::SnrPer
CalculatePayloadSnrPer(Ptr<Event> event,uint16_t channelWidth,WifiSpectrumBand band,uint16_t staId,std::pair<Time,Time> relativeMpduStartStop) const548 InterferenceHelper::CalculatePayloadSnrPer (Ptr<Event> event, uint16_t channelWidth, WifiSpectrumBand band,
549                                             uint16_t staId, std::pair<Time, Time> relativeMpduStartStop) const
550 {
551   NS_LOG_FUNCTION (this << channelWidth << band.first << band.second << staId << relativeMpduStartStop.first << relativeMpduStartStop.second);
552   NiChangesPerBand ni;
553   double noiseInterferenceW = CalculateNoiseInterferenceW (event, &ni, band);
554   double snr = CalculateSnr (event->GetRxPowerW (band),
555                              noiseInterferenceW,
556                              channelWidth,
557                              event->GetTxVector ().GetNss (staId));
558 
559   /* calculate the SNIR at the start of the MPDU (located through windowing) and accumulate
560    * all SNIR changes in the SNIR vector.
561    */
562   double per = CalculatePayloadPer (event, channelWidth, &ni, band, staId, relativeMpduStartStop);
563 
564   return PhyEntity::SnrPer (snr, per);
565 }
566 
567 double
CalculateSnr(Ptr<Event> event,uint16_t channelWidth,uint8_t nss,WifiSpectrumBand band) const568 InterferenceHelper::CalculateSnr (Ptr<Event> event, uint16_t channelWidth, uint8_t nss, WifiSpectrumBand band) const
569 {
570   NiChangesPerBand ni;
571   double noiseInterferenceW = CalculateNoiseInterferenceW (event, &ni, band);
572   double snr = CalculateSnr (event->GetRxPowerW (band),
573                              noiseInterferenceW,
574                              channelWidth,
575                              nss);
576   return snr;
577 }
578 
579 struct PhyEntity::SnrPer
CalculatePhyHeaderSnrPer(Ptr<Event> event,uint16_t channelWidth,WifiSpectrumBand band,WifiPpduField header) const580 InterferenceHelper::CalculatePhyHeaderSnrPer (Ptr<Event> event, uint16_t channelWidth, WifiSpectrumBand band,
581                                               WifiPpduField header) const
582 {
583   NS_LOG_FUNCTION (this << band.first << band.second << header);
584   NiChangesPerBand ni;
585   double noiseInterferenceW = CalculateNoiseInterferenceW (event, &ni, band);
586   double snr = CalculateSnr (event->GetRxPowerW (band),
587                              noiseInterferenceW,
588                              channelWidth,
589                              1);
590 
591   /* calculate the SNIR at the start of the PHY header and accumulate
592    * all SNIR changes in the SNIR vector.
593    */
594   double per = CalculatePhyHeaderPer (event, &ni, channelWidth, band, header);
595 
596   return PhyEntity::SnrPer (snr, per);
597 }
598 
599 void
EraseEvents(void)600 InterferenceHelper::EraseEvents (void)
601 {
602   for (auto niIt = m_niChangesPerBand.begin(); niIt != m_niChangesPerBand.end(); ++niIt)
603     {
604       niIt->second.clear ();
605       // Always have a zero power noise event in the list
606       AddNiChangeEvent (Time (0), NiChange (0.0, 0), niIt);
607       m_firstPowerPerBand.at (niIt->first) = 0.0;
608     }
609   m_rxing = false;
610 }
611 
612 InterferenceHelper::NiChanges::iterator
GetNextPosition(Time moment,NiChangesPerBand::iterator niIt)613 InterferenceHelper::GetNextPosition (Time moment, NiChangesPerBand::iterator niIt)
614 {
615   return niIt->second.upper_bound (moment);
616 }
617 
618 InterferenceHelper::NiChanges::iterator
GetPreviousPosition(Time moment,NiChangesPerBand::iterator niIt)619 InterferenceHelper::GetPreviousPosition (Time moment, NiChangesPerBand::iterator niIt)
620 {
621   auto it = GetNextPosition (moment, niIt);
622   // This is safe since there is always an NiChange at time 0,
623   // before moment.
624   --it;
625   return it;
626 }
627 
628 InterferenceHelper::NiChanges::iterator
AddNiChangeEvent(Time moment,NiChange change,NiChangesPerBand::iterator niIt)629 InterferenceHelper::AddNiChangeEvent (Time moment, NiChange change, NiChangesPerBand::iterator niIt)
630 {
631   return niIt->second.insert (GetNextPosition (moment, niIt), std::make_pair (moment, change));
632 }
633 
634 void
NotifyRxStart()635 InterferenceHelper::NotifyRxStart ()
636 {
637   NS_LOG_FUNCTION (this);
638   m_rxing = true;
639 }
640 
641 void
NotifyRxEnd(Time endTime)642 InterferenceHelper::NotifyRxEnd (Time endTime)
643 {
644   NS_LOG_FUNCTION (this << endTime);
645   m_rxing = false;
646   //Update m_firstPowerPerBand for frame capture
647   for (auto niIt = m_niChangesPerBand.begin(); niIt != m_niChangesPerBand.end(); ++niIt)
648     {
649       NS_ASSERT (niIt->second.size () > 1);
650       auto it = GetPreviousPosition (endTime, niIt);
651       it--;
652       m_firstPowerPerBand.find (niIt->first)->second = it->second.GetPower ();
653     }
654 }
655 
656 } //namespace ns3
657