A Discrete-Event Network Simulator
API
interference-helper.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005,2006 INRIA
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18  * Sébastien Deronne <sebastien.deronne@gmail.com>
19  */
20 
21 #include "interference-helper.h"
22 
23 #include "error-rate-model.h"
25 #include "wifi-phy.h"
26 #include "wifi-psdu.h"
27 #include "wifi-utils.h"
28 
29 #include "ns3/he-ppdu.h"
30 #include "ns3/log.h"
31 #include "ns3/packet.h"
32 #include "ns3/simulator.h"
33 
34 #include <algorithm>
35 #include <numeric>
36 
37 namespace ns3
38 {
39 
40 NS_LOG_COMPONENT_DEFINE("InterferenceHelper");
41 
42 NS_OBJECT_ENSURE_REGISTERED(InterferenceHelper);
43 
44 /****************************************************************
45  * PHY event class
46  ****************************************************************/
47 
49  : m_ppdu(ppdu),
50  m_startTime(Simulator::Now()),
51  m_endTime(m_startTime + duration),
52  m_rxPowerW(std::move(rxPower))
53 {
54 }
55 
58 {
59  return m_ppdu;
60 }
61 
62 Time
64 {
65  return m_startTime;
66 }
67 
68 Time
70 {
71  return m_endTime;
72 }
73 
74 Time
76 {
77  return m_endTime - m_startTime;
78 }
79 
80 double
82 {
83  NS_ASSERT(!m_rxPowerW.empty());
84  // The total RX power corresponds to the maximum over all the bands
85  auto it =
86  std::max_element(m_rxPowerW.cbegin(),
87  m_rxPowerW.cend(),
88  [](const auto& p1, const auto& p2) { return p1.second < p2.second; });
89  return it->second;
90 }
91 
92 double
94 {
95  const auto it = m_rxPowerW.find(band);
96  NS_ASSERT(it != m_rxPowerW.cend());
97  return it->second;
98 }
99 
102 {
103  return m_rxPowerW;
104 }
105 
106 void
108 {
109  NS_ASSERT(rxPower.size() == m_rxPowerW.size());
110  // Update power band per band
111  for (auto& currentRxPowerW : m_rxPowerW)
112  {
113  auto band = currentRxPowerW.first;
114  auto it = rxPower.find(band);
115  if (it != rxPower.end())
116  {
117  currentRxPowerW.second += it->second;
118  }
119  }
120 }
121 
122 void
124 {
125  m_ppdu = ppdu;
126 }
127 
128 std::ostream&
129 operator<<(std::ostream& os, const Event& event)
130 {
131  os << "start=" << event.GetStartTime() << ", end=" << event.GetEndTime()
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 
143  : m_power(power),
144  m_event(event)
145 {
146 }
147 
149 {
150  m_event = nullptr;
151 }
152 
153 double
155 {
156  return m_power;
157 }
158 
159 void
161 {
162  m_power += power;
163 }
164 
167 {
168  return m_event;
169 }
170 
171 /****************************************************************
172  * The actual InterferenceHelper
173  ****************************************************************/
174 
176  : m_errorRateModel(nullptr),
177  m_numRxAntennas(1),
178  m_rxing(false)
179 {
180  NS_LOG_FUNCTION(this);
181 }
182 
184 {
185  NS_LOG_FUNCTION(this);
186 }
187 
188 TypeId
190 {
191  static TypeId tid = TypeId("ns3::InterferenceHelper")
193  .SetGroupName("Wifi")
194  .AddConstructor<InterferenceHelper>();
195  return tid;
196 }
197 
198 void
200 {
201  NS_LOG_FUNCTION(this);
202  for (auto it : m_niChanges)
203  {
204  it.second.clear();
205  }
206  m_niChanges.clear();
207  m_firstPowers.clear();
208  m_errorRateModel = nullptr;
209 }
210 
213  Time duration,
214  RxPowerWattPerChannelBand& rxPowerW,
215  bool isStartHePortionRxing)
216 {
217  Ptr<Event> event = Create<Event>(ppdu, duration, std::move(rxPowerW));
218  AppendEvent(event, isStartHePortionRxing);
219  return event;
220 }
221 
222 void
224 {
225  // Parameters other than duration and rxPowerW are unused for this type
226  // of signal, so we provide dummy versions
227  WifiMacHeader hdr;
229  hdr.SetQosTid(0);
230  Ptr<WifiPpdu> fakePpdu = Create<WifiPpdu>(Create<WifiPsdu>(Create<Packet>(0), hdr),
231  WifiTxVector(),
233  Add(fakePpdu, duration, rxPowerW);
234 }
235 
236 bool
238 {
239  return !m_niChanges.empty();
240 }
241 
242 bool
244 {
245  return (m_niChanges.count(band) > 0);
246 }
247 
248 void
250 {
251  NS_LOG_FUNCTION(this << band);
252  NS_ASSERT(m_niChanges.count(band) == 0);
253  NS_ASSERT(m_firstPowers.count(band) == 0);
254  NiChanges niChanges;
255  auto result = m_niChanges.insert({band, niChanges});
256  NS_ASSERT(result.second);
257  // Always have a zero power noise event in the list
258  AddNiChangeEvent(Time(0), NiChange(0.0, nullptr), result.first);
259  m_firstPowers.insert({band, 0.0});
260 }
261 
262 void
263 InterferenceHelper::UpdateBands(const std::vector<WifiSpectrumBandInfo>& bands,
264  const FrequencyRange& freqRange)
265 {
266  NS_LOG_FUNCTION(this << freqRange);
267  for (auto it = m_niChanges.begin(); it != m_niChanges.end();)
268  {
269  if (!IsBandInFrequencyRange(it->first, freqRange))
270  {
271  it++;
272  continue;
273  }
274  const auto frequencies = it->first.frequencies;
275  const auto found =
276  std::find_if(bands.cbegin(), bands.cend(), [frequencies](const auto& item) {
277  return frequencies == item.frequencies;
278  }) != std::end(bands);
279  if (!found)
280  {
281  // band does not belong to the new bands, erase it
282  m_firstPowers.erase(it->first);
283  it->second.clear();
284  it = m_niChanges.erase(it);
285  }
286  else
287  {
288  it++;
289  }
290  }
291  for (const auto& band : bands)
292  {
293  if (!HasBand(band))
294  {
295  // this is a new band, add it
296  AddBand(band);
297  }
298  }
299 }
300 
301 void
303 {
304  m_noiseFigure = value;
305 }
306 
307 void
309 {
310  m_errorRateModel = rate;
311 }
312 
315 {
316  return m_errorRateModel;
317 }
318 
319 void
321 {
322  m_numRxAntennas = rx;
323 }
324 
325 Time
327 {
328  NS_LOG_FUNCTION(this << energyW << band);
329  Time now = Simulator::Now();
330  auto niIt = m_niChanges.find(band);
331  NS_ABORT_IF(niIt == m_niChanges.end());
332  auto i = GetPreviousPosition(now, niIt);
333  Time end = i->first;
334  for (; i != niIt->second.end(); ++i)
335  {
336  double noiseInterferenceW = i->second.GetPower();
337  end = i->first;
338  if (noiseInterferenceW < energyW)
339  {
340  break;
341  }
342  }
343  return end > now ? end - now : MicroSeconds(0);
344 }
345 
346 void
347 InterferenceHelper::AppendEvent(Ptr<Event> event, bool isStartHePortionRxing)
348 {
349  NS_LOG_FUNCTION(this << event << isStartHePortionRxing);
350  for (const auto& [band, power] : event->GetRxPowerWPerBand())
351  {
352  auto niIt = m_niChanges.find(band);
353  NS_ABORT_IF(niIt == m_niChanges.end());
354  double previousPowerStart = 0;
355  double previousPowerEnd = 0;
356  auto previousPowerPosition = GetPreviousPosition(event->GetStartTime(), niIt);
357  previousPowerStart = previousPowerPosition->second.GetPower();
358  previousPowerEnd = GetPreviousPosition(event->GetEndTime(), niIt)->second.GetPower();
359  if (!m_rxing)
360  {
361  m_firstPowers.find(band)->second = previousPowerStart;
362  // Always leave the first zero power noise event in the list
363  niIt->second.erase(++(niIt->second.begin()), ++previousPowerPosition);
364  }
365  else if (isStartHePortionRxing)
366  {
367  // When the first HE portion is received, we need to set m_firstPowerPerBand
368  // so that it takes into account interferences that arrived between the start of the
369  // HE TB PPDU transmission and the start of HE TB payload.
370  m_firstPowers.find(band)->second = previousPowerStart;
371  }
372  auto first =
373  AddNiChangeEvent(event->GetStartTime(), NiChange(previousPowerStart, event), niIt);
374  auto last = AddNiChangeEvent(event->GetEndTime(), NiChange(previousPowerEnd, event), niIt);
375  for (auto i = first; i != last; ++i)
376  {
377  i->second.AddPower(power);
378  }
379  }
380 }
381 
382 void
384 {
385  NS_LOG_FUNCTION(this << event);
386  // This is called for UL MU events, in order to scale power as long as UL MU PPDUs arrive
387  for (const auto& [band, power] : rxPower)
388  {
389  auto niIt = m_niChanges.find(band);
390  NS_ABORT_IF(niIt == m_niChanges.end());
391  auto first = GetPreviousPosition(event->GetStartTime(), niIt);
392  auto last = GetPreviousPosition(event->GetEndTime(), niIt);
393  for (auto i = first; i != last; ++i)
394  {
395  i->second.AddPower(power);
396  }
397  }
398  event->UpdateRxPowerW(rxPower);
399 }
400 
401 double
403  double noiseInterference,
404  uint16_t channelWidth,
405  uint8_t nss) const
406 {
407  NS_LOG_FUNCTION(this << signal << noiseInterference << channelWidth << +nss);
408  // thermal noise at 290K in J/s = W
409  static const double BOLTZMANN = 1.3803e-23;
410  // Nt is the power of thermal noise in W
411  double Nt = BOLTZMANN * 290 * channelWidth * 1e6;
412  // receiver noise Floor (W) which accounts for thermal noise and non-idealities of the receiver
413  double noiseFloor = m_noiseFigure * Nt;
414  double noise = noiseFloor + noiseInterference;
415  double snr = signal / noise; // linear scale
416  NS_LOG_DEBUG("bandwidth(MHz)=" << channelWidth << ", signal(W)= " << signal << ", noise(W)="
417  << noiseFloor << ", interference(W)=" << noiseInterference
418  << ", snr=" << RatioToDb(snr) << "dB");
419  if (m_errorRateModel->IsAwgn())
420  {
421  double gain = 1;
422  if (m_numRxAntennas > nss)
423  {
424  gain = static_cast<double>(m_numRxAntennas) /
425  nss; // compute gain offered by diversity for AWGN
426  }
427  NS_LOG_DEBUG("SNR improvement thanks to diversity: " << 10 * std::log10(gain) << "dB");
428  snr *= gain;
429  }
430  return snr;
431 }
432 
433 double
435  NiChangesPerBand& nis,
436  const WifiSpectrumBandInfo& band) const
437 {
438  NS_LOG_FUNCTION(this << band);
439  auto firstPower_it = m_firstPowers.find(band);
440  NS_ABORT_IF(firstPower_it == m_firstPowers.end());
441  double noiseInterferenceW = firstPower_it->second;
442  auto niIt = m_niChanges.find(band);
443  NS_ABORT_IF(niIt == m_niChanges.end());
444  auto it = niIt->second.find(event->GetStartTime());
445  double muMimoPowerW = (event->GetPpdu()->GetType() == WIFI_PPDU_TYPE_UL_MU)
446  ? CalculateMuMimoPowerW(event, band)
447  : 0.0;
448  for (; it != niIt->second.end() && it->first < Simulator::Now(); ++it)
449  {
450  if (IsSameMuMimoTransmission(event, it->second.GetEvent()) &&
451  (event != it->second.GetEvent()))
452  {
453  // Do not calculate noiseInterferenceW if events belong to the same MU-MIMO transmission
454  // unless this is the same event
455  continue;
456  }
457  noiseInterferenceW = it->second.GetPower() - event->GetRxPowerW(band) - muMimoPowerW;
458  if (std::abs(noiseInterferenceW) < std::numeric_limits<double>::epsilon())
459  {
460  // fix some possible rounding issues with double values
461  noiseInterferenceW = 0.0;
462  }
463  }
464  it = niIt->second.find(event->GetStartTime());
465  NS_ABORT_IF(it == niIt->second.end());
466  for (; it != niIt->second.end() && it->second.GetEvent() != event; ++it)
467  {
468  ;
469  }
470  NiChanges ni;
471  ni.emplace(event->GetStartTime(), NiChange(0, event));
472  while (++it != niIt->second.end() && it->second.GetEvent() != event)
473  {
474  ni.insert(*it);
475  }
476  ni.emplace(event->GetEndTime(), NiChange(0, event));
477  nis.insert({band, ni});
478  NS_ASSERT_MSG(noiseInterferenceW >= 0.0,
479  "CalculateNoiseInterferenceW returns negative value " << noiseInterferenceW);
480  return noiseInterferenceW;
481 }
482 
483 double
485  const WifiSpectrumBandInfo& band) const
486 {
487  auto niIt = m_niChanges.find(band);
488  NS_ASSERT(niIt != m_niChanges.end());
489  auto it = niIt->second.begin();
490  ++it;
491  double muMimoPowerW = 0.0;
492  for (; it != niIt->second.end() && it->first < Simulator::Now(); ++it)
493  {
494  if (IsSameMuMimoTransmission(event, it->second.GetEvent()))
495  {
496  auto hePpdu = DynamicCast<HePpdu>(it->second.GetEvent()->GetPpdu()->Copy());
497  NS_ASSERT(hePpdu);
498  HePpdu::TxPsdFlag psdFlag = hePpdu->GetTxPsdFlag();
499  if (psdFlag == HePpdu::PSD_HE_PORTION)
500  {
501  const auto staId =
502  event->GetPpdu()->GetTxVector().GetHeMuUserInfoMap().cbegin()->first;
503  const auto otherStaId = it->second.GetEvent()
504  ->GetPpdu()
505  ->GetTxVector()
506  .GetHeMuUserInfoMap()
507  .cbegin()
508  ->first;
509  if (staId == otherStaId)
510  {
511  break;
512  }
513  muMimoPowerW += it->second.GetEvent()->GetRxPowerW(band);
514  }
515  }
516  }
517  return muMimoPowerW;
518 }
519 
520 double
522  Time duration,
523  WifiMode mode,
524  const WifiTxVector& txVector,
525  WifiPpduField field) const
526 {
527  if (duration.IsZero())
528  {
529  return 1.0;
530  }
531  uint64_t rate = mode.GetDataRate(txVector.GetChannelWidth());
532  auto nbits = static_cast<uint64_t>(rate * duration.GetSeconds());
533  double csr =
534  m_errorRateModel->GetChunkSuccessRate(mode, txVector, snir, nbits, m_numRxAntennas, field);
535  return csr;
536 }
537 
538 double
540  Time duration,
541  const WifiTxVector& txVector,
542  uint16_t staId) const
543 {
544  if (duration.IsZero())
545  {
546  return 1.0;
547  }
548  WifiMode mode = txVector.GetMode(staId);
549  uint64_t rate = mode.GetDataRate(txVector, staId);
550  auto nbits = static_cast<uint64_t>(rate * duration.GetSeconds());
551  nbits /= txVector.GetNss(staId); // divide effective number of bits by NSS to achieve same chunk
552  // error rate as SISO for AWGN
553  double csr = m_errorRateModel->GetChunkSuccessRate(mode,
554  txVector,
555  snir,
556  nbits,
559  staId);
560  return csr;
561 }
562 
563 double
565  uint16_t channelWidth,
566  NiChangesPerBand* nis,
567  const WifiSpectrumBandInfo& band,
568  uint16_t staId,
569  std::pair<Time, Time> window) const
570 {
571  NS_LOG_FUNCTION(this << channelWidth << band << staId << window.first << window.second);
572  double psr = 1.0; /* Packet Success Rate */
573  const auto& niIt = nis->find(band)->second;
574  auto j = niIt.cbegin();
575  Time previous = j->first;
576  double muMimoPowerW = 0.0;
577  WifiMode payloadMode = event->GetPpdu()->GetTxVector().GetMode(staId);
578  Time phyPayloadStart = j->first;
579  if (event->GetPpdu()->GetType() != WIFI_PPDU_TYPE_UL_MU &&
580  event->GetPpdu()->GetType() !=
581  WIFI_PPDU_TYPE_DL_MU) // j->first corresponds to the start of the MU payload
582  {
583  phyPayloadStart = j->first + WifiPhy::CalculatePhyPreambleAndHeaderDuration(
584  event->GetPpdu()->GetTxVector());
585  }
586  else
587  {
588  muMimoPowerW = CalculateMuMimoPowerW(event, band);
589  }
590  Time windowStart = phyPayloadStart + window.first;
591  Time windowEnd = phyPayloadStart + window.second;
592  NS_ABORT_IF(m_firstPowers.count(band) == 0);
593  double noiseInterferenceW = m_firstPowers.at(band);
594  double powerW = event->GetRxPowerW(band);
595  while (++j != niIt.cend())
596  {
597  Time current = j->first;
598  NS_LOG_DEBUG("previous= " << previous << ", current=" << current);
599  NS_ASSERT(current >= previous);
600  double snr = CalculateSnr(powerW,
601  noiseInterferenceW,
602  channelWidth,
603  event->GetPpdu()->GetTxVector().GetNss(staId));
604  // Case 1: Both previous and current point to the windowed payload
605  if (previous >= windowStart)
606  {
608  Min(windowEnd, current) - previous,
609  event->GetPpdu()->GetTxVector(),
610  staId);
611  NS_LOG_DEBUG("Both previous and current point to the windowed payload: mode="
612  << payloadMode << ", psr=" << psr);
613  }
614  // Case 2: previous is before windowed payload and current is in the windowed payload
615  else if (current >= windowStart)
616  {
618  Min(windowEnd, current) - windowStart,
619  event->GetPpdu()->GetTxVector(),
620  staId);
621  NS_LOG_DEBUG(
622  "previous is before windowed payload and current is in the windowed payload: mode="
623  << payloadMode << ", psr=" << psr);
624  }
625  noiseInterferenceW = j->second.GetPower() - powerW;
626  if (IsSameMuMimoTransmission(event, j->second.GetEvent()))
627  {
628  muMimoPowerW += j->second.GetEvent()->GetRxPowerW(band);
629  NS_LOG_DEBUG(
630  "PPDU belongs to same MU-MIMO transmission: muMimoPowerW=" << muMimoPowerW);
631  }
632  noiseInterferenceW -= muMimoPowerW;
633  previous = j->first;
634  if (previous > windowEnd)
635  {
636  NS_LOG_DEBUG("Stop: new previous=" << previous
637  << " after time window end=" << windowEnd);
638  break;
639  }
640  }
641  double per = 1 - psr;
642  return per;
643 }
644 
645 double
647  Ptr<const Event> event,
648  NiChangesPerBand* nis,
649  uint16_t channelWidth,
650  const WifiSpectrumBandInfo& band,
651  PhyEntity::PhyHeaderSections phyHeaderSections) const
652 {
653  NS_LOG_FUNCTION(this << band);
654  double psr = 1.0; /* Packet Success Rate */
655  auto niIt = nis->find(band)->second;
656  auto j = niIt.begin();
657 
658  NS_ASSERT(!phyHeaderSections.empty());
659  Time stopLastSection = Seconds(0);
660  for (const auto& section : phyHeaderSections)
661  {
662  stopLastSection = Max(stopLastSection, section.second.first.second);
663  }
664 
665  Time previous = j->first;
666  NS_ABORT_IF(m_firstPowers.count(band) == 0);
667  double noiseInterferenceW = m_firstPowers.at(band);
668  double powerW = event->GetRxPowerW(band);
669  while (++j != niIt.end())
670  {
671  Time current = j->first;
672  NS_LOG_DEBUG("previous= " << previous << ", current=" << current);
673  NS_ASSERT(current >= previous);
674  double snr = CalculateSnr(powerW, noiseInterferenceW, channelWidth, 1);
675  for (const auto& section : phyHeaderSections)
676  {
677  Time start = section.second.first.first;
678  Time stop = section.second.first.second;
679 
680  if (previous <= stop || current >= start)
681  {
682  Time duration = Min(stop, current) - Max(start, previous);
683  if (duration.IsStrictlyPositive())
684  {
685  psr *= CalculateChunkSuccessRate(snr,
686  duration,
687  section.second.second,
688  event->GetPpdu()->GetTxVector(),
689  section.first);
690  NS_LOG_DEBUG("Current NI change in "
691  << section.first << " [" << start << ", " << stop << "] for "
692  << duration.As(Time::NS) << ": mode=" << section.second.second
693  << ", psr=" << psr);
694  }
695  }
696  }
697  noiseInterferenceW = j->second.GetPower() - powerW;
698  previous = j->first;
699  if (previous > stopLastSection)
700  {
701  NS_LOG_DEBUG("Stop: new previous=" << previous << " after stop of last section="
702  << stopLastSection);
703  break;
704  }
705  }
706  return psr;
707 }
708 
709 double
711  NiChangesPerBand* nis,
712  uint16_t channelWidth,
713  const WifiSpectrumBandInfo& band,
714  WifiPpduField header) const
715 {
716  NS_LOG_FUNCTION(this << band << header);
717  auto niIt = nis->find(band)->second;
718  auto phyEntity =
719  WifiPhy::GetStaticPhyEntity(event->GetPpdu()->GetTxVector().GetModulationClass());
720 
722  for (const auto& section :
723  phyEntity->GetPhyHeaderSections(event->GetPpdu()->GetTxVector(), niIt.begin()->first))
724  {
725  if (section.first == header)
726  {
727  sections[header] = section.second;
728  }
729  }
730 
731  double psr = 1.0;
732  if (!sections.empty())
733  {
734  psr = CalculatePhyHeaderSectionPsr(event, nis, channelWidth, band, sections);
735  }
736  return 1 - psr;
737 }
738 
741  uint16_t channelWidth,
742  const WifiSpectrumBandInfo& band,
743  uint16_t staId,
744  std::pair<Time, Time> relativeMpduStartStop) const
745 {
746  NS_LOG_FUNCTION(this << channelWidth << band << staId << relativeMpduStartStop.first
747  << relativeMpduStartStop.second);
748  NiChangesPerBand ni;
749  double noiseInterferenceW = CalculateNoiseInterferenceW(event, ni, band);
750  double snr = CalculateSnr(event->GetRxPowerW(band),
751  noiseInterferenceW,
752  channelWidth,
753  event->GetPpdu()->GetTxVector().GetNss(staId));
754 
755  /* calculate the SNIR at the start of the MPDU (located through windowing) and accumulate
756  * all SNIR changes in the SNIR vector.
757  */
758  double per = CalculatePayloadPer(event, channelWidth, &ni, band, staId, relativeMpduStartStop);
759 
760  return PhyEntity::SnrPer(snr, per);
761 }
762 
763 double
765  uint16_t channelWidth,
766  uint8_t nss,
767  const WifiSpectrumBandInfo& band) const
768 {
769  NiChangesPerBand ni;
770  double noiseInterferenceW = CalculateNoiseInterferenceW(event, ni, band);
771  double snr = CalculateSnr(event->GetRxPowerW(band), noiseInterferenceW, channelWidth, nss);
772  return snr;
773 }
774 
777  uint16_t channelWidth,
778  const WifiSpectrumBandInfo& band,
779  WifiPpduField header) const
780 {
781  NS_LOG_FUNCTION(this << band << header);
782  NiChangesPerBand ni;
783  double noiseInterferenceW = CalculateNoiseInterferenceW(event, ni, band);
784  double snr = CalculateSnr(event->GetRxPowerW(band), noiseInterferenceW, channelWidth, 1);
785 
786  /* calculate the SNIR at the start of the PHY header and accumulate
787  * all SNIR changes in the SNIR vector.
788  */
789  double per = CalculatePhyHeaderPer(event, &ni, channelWidth, band, header);
790 
791  return PhyEntity::SnrPer(snr, per);
792 }
793 
794 InterferenceHelper::NiChanges::iterator
795 InterferenceHelper::GetNextPosition(Time moment, NiChangesPerBand::iterator niIt)
796 {
797  return niIt->second.upper_bound(moment);
798 }
799 
800 InterferenceHelper::NiChanges::iterator
801 InterferenceHelper::GetPreviousPosition(Time moment, NiChangesPerBand::iterator niIt)
802 {
803  auto it = GetNextPosition(moment, niIt);
804  // This is safe since there is always an NiChange at time 0,
805  // before moment.
806  --it;
807  return it;
808 }
809 
810 InterferenceHelper::NiChanges::iterator
811 InterferenceHelper::AddNiChangeEvent(Time moment, NiChange change, NiChangesPerBand::iterator niIt)
812 {
813  return niIt->second.insert(GetNextPosition(moment, niIt), {moment, change});
814 }
815 
816 void
818 {
819  NS_LOG_FUNCTION(this);
820  m_rxing = true;
821 }
822 
823 void
825 {
826  NS_LOG_FUNCTION(this << endTime << freqRange);
827  m_rxing = false;
828  // Update m_firstPowers for frame capture
829  for (auto niIt = m_niChanges.begin(); niIt != m_niChanges.end(); ++niIt)
830  {
831  if (!IsBandInFrequencyRange(niIt->first, freqRange))
832  {
833  continue;
834  }
835  NS_ASSERT(niIt->second.size() > 1);
836  auto it = GetPreviousPosition(endTime, niIt);
837  it--;
838  m_firstPowers.find(niIt->first)->second = it->second.GetPower();
839  }
840 }
841 
842 bool
844  const FrequencyRange& freqRange) const
845 {
846  return ((band.frequencies.second > (freqRange.minFrequency * 1e6)) &&
847  (band.frequencies.first < (freqRange.maxFrequency * 1e6)));
848 }
849 
850 bool
852  Ptr<const Event> otherEvent) const
853 {
854  if ((currentEvent->GetPpdu()->GetType() == WIFI_PPDU_TYPE_UL_MU) &&
855  (otherEvent->GetPpdu()->GetType() == WIFI_PPDU_TYPE_UL_MU) &&
856  (currentEvent->GetPpdu()->GetUid() == otherEvent->GetPpdu()->GetUid()))
857  {
858  const auto currentTxVector = currentEvent->GetPpdu()->GetTxVector();
859  const auto otherTxVector = otherEvent->GetPpdu()->GetTxVector();
860  NS_ASSERT(currentTxVector.GetHeMuUserInfoMap().size() == 1);
861  NS_ASSERT(otherTxVector.GetHeMuUserInfoMap().size() == 1);
862  const auto currentUserInfo = currentTxVector.GetHeMuUserInfoMap().cbegin();
863  const auto otherUserInfo = otherTxVector.GetHeMuUserInfoMap().cbegin();
864  return (currentUserInfo->second.ru == otherUserInfo->second.ru);
865  }
866  return false;
867 }
868 
869 } // namespace ns3
handles interference calculations
Time m_endTime
end time
Time m_startTime
start time
Event(Ptr< const WifiPpdu > ppdu, Time duration, RxPowerWattPerChannelBand &&rxPower)
Create an Event with the given parameters.
Ptr< const WifiPpdu > GetPpdu() const
Return the PPDU.
Ptr< const WifiPpdu > m_ppdu
PPDU.
void UpdateRxPowerW(const RxPowerWattPerChannelBand &rxPower)
Update the received power (W) for all bands, i.e.
Time GetEndTime() const
Return the end time of the signal.
Time GetDuration() const
Return the duration of the signal.
double GetRxPowerW() const
Return the total received power (W).
RxPowerWattPerChannelBand m_rxPowerW
received power in watts per band
const RxPowerWattPerChannelBand & GetRxPowerWPerBand() const
Return the received power (W) for all bands.
Time GetStartTime() const
Return the start time of the signal.
void UpdatePpdu(Ptr< const WifiPpdu > ppdu)
Update the PPDU that initially generated the event.
TxPsdFlag
The transmit power spectral density flag, namely used to correctly build PSDs for pre-HE and HE porti...
Definition: he-ppdu.h:115
@ PSD_HE_PORTION
HE portion of an HE PPDU.
Definition: he-ppdu.h:117
Noise and Interference (thus Ni) event.
void AddPower(double power)
Add a given amount of power.
NiChange(double power, Ptr< Event > event)
Create a NiChange at the given time and the amount of NI change.
double GetPower() const
Return the power.
Ptr< Event > GetEvent() const
Return the event causes the corresponding NI change.
handles interference calculations
void SetNoiseFigure(double value)
Set the noise figure.
double m_noiseFigure
noise figure (linear)
Ptr< ErrorRateModel > GetErrorRateModel() const
Return the error rate model.
void AddForeignSignal(Time duration, RxPowerWattPerChannelBand &rxPower)
Add a non-Wifi signal to interference helper.
bool m_rxing
flag whether it is in receiving state
NiChanges::iterator AddNiChangeEvent(Time moment, NiChange change, NiChangesPerBand::iterator niIt)
Add NiChange to the list at the appropriate position and return the iterator of the new event.
std::map< WifiSpectrumBandInfo, NiChanges > NiChangesPerBand
Map of NiChanges per band.
double CalculateMuMimoPowerW(Ptr< const Event > event, const WifiSpectrumBandInfo &band) const
Calculate power of all other events preceding a given event that belong to the same MU-MIMO transmiss...
uint8_t m_numRxAntennas
the number of RX antennas in the corresponding receiver
bool IsBandInFrequencyRange(const WifiSpectrumBandInfo &band, const FrequencyRange &freqRange) const
Check whether a given band belongs to a given frequency range.
void DoDispose() override
Destructor implementation.
std::multimap< Time, NiChange > NiChanges
typedef for a multimap of NiChange
NiChangesPerBand m_niChanges
NI Changes for each band.
void UpdateBands(const std::vector< WifiSpectrumBandInfo > &bands, const FrequencyRange &freqRange)
Update the frequency bands that belongs to a given frequency range when the spectrum model is changed...
void SetErrorRateModel(const Ptr< ErrorRateModel > rate)
Set the error rate model for this interference helper.
bool HasBands() const
Check whether bands are already tracked by this interference helper.
double CalculatePayloadChunkSuccessRate(double snir, Time duration, const WifiTxVector &txVector, uint16_t staId=SU_STA_ID) const
Calculate the success rate of the payload chunk given the SINR, duration, and TXVECTOR.
Ptr< ErrorRateModel > m_errorRateModel
error rate model
Ptr< Event > Add(Ptr< const WifiPpdu > ppdu, Time duration, RxPowerWattPerChannelBand &rxPower, bool isStartHePortionRxing=false)
Add the PPDU-related signal to interference helper.
void NotifyRxStart()
Notify that RX has started.
NiChanges::iterator GetNextPosition(Time moment, NiChangesPerBand::iterator niIt)
Returns an iterator to the first NiChange that is later than moment.
FirstPowerPerBand m_firstPowers
first power of each band in watts
Time GetEnergyDuration(double energyW, const WifiSpectrumBandInfo &band)
bool IsSameMuMimoTransmission(Ptr< const Event > currentEvent, Ptr< const Event > otherEvent) const
Return whether another event is a MU-MIMO event that belongs to the same transmission and to the same...
double CalculateChunkSuccessRate(double snir, Time duration, WifiMode mode, const WifiTxVector &txVector, WifiPpduField field) const
Calculate the success rate of the chunk given the SINR, duration, and TXVECTOR.
double CalculatePayloadPer(Ptr< const Event > event, uint16_t channelWidth, NiChangesPerBand *nis, const WifiSpectrumBandInfo &band, uint16_t staId, std::pair< Time, Time > window) const
Calculate the error rate of the given PHY payload only in the provided time window (thus enabling per...
bool HasBand(const WifiSpectrumBandInfo &band) const
Check whether a given band is tracked by this interference helper.
void AddBand(const WifiSpectrumBandInfo &band)
Add a frequency band.
double CalculateNoiseInterferenceW(Ptr< Event > event, NiChangesPerBand &nis, const WifiSpectrumBandInfo &band) const
Calculate noise and interference power in W.
double CalculatePhyHeaderPer(Ptr< const Event > event, NiChangesPerBand *nis, uint16_t channelWidth, const WifiSpectrumBandInfo &band, WifiPpduField header) const
Calculate the error rate of the PHY header.
NiChanges::iterator GetPreviousPosition(Time moment, NiChangesPerBand::iterator niIt)
Returns an iterator to the last NiChange that is before than moment.
double CalculateSnr(Ptr< Event > event, uint16_t channelWidth, uint8_t nss, const WifiSpectrumBandInfo &band) const
Calculate the SNIR for the event (starting from now until the event end).
PhyEntity::SnrPer CalculatePhyHeaderSnrPer(Ptr< Event > event, uint16_t channelWidth, const WifiSpectrumBandInfo &band, WifiPpduField header) const
Calculate the SNIR at the start of the PHY header and accumulate all SNIR changes in the SNIR vector.
void AppendEvent(Ptr< Event > event, bool isStartHePortionRxing)
Append the given Event.
static TypeId GetTypeId()
Get the type ID.
void UpdateEvent(Ptr< Event > event, const RxPowerWattPerChannelBand &rxPower)
Update event to scale its received power (W) per band.
void NotifyRxEnd(Time endTime, const FrequencyRange &freqRange)
Notify that RX has ended.
double CalculatePhyHeaderSectionPsr(Ptr< const Event > event, NiChangesPerBand *nis, uint16_t channelWidth, const WifiSpectrumBandInfo &band, PhyEntity::PhyHeaderSections phyHeaderSections) const
Calculate the success rate of the PHY header sections for the provided event.
void SetNumberOfReceiveAntennas(uint8_t rx)
Set the number of RX antennas in the receiver corresponding to this interference helper.
PhyEntity::SnrPer CalculatePayloadSnrPer(Ptr< Event > event, uint16_t channelWidth, const WifiSpectrumBandInfo &band, uint16_t staId, std::pair< Time, Time > relativeMpduStartStop) const
Calculate the SNIR at the start of the payload and accumulate all SNIR changes in the SNIR vector for...
A base class which provides memory management and object aggregation.
Definition: object.h:89
std::map< WifiPpduField, PhyHeaderChunkInfo > PhyHeaderSections
A map of PhyHeaderChunkInfo elements per PPDU field.
Definition: phy-entity.h:326
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Control the scheduling of simulation events.
Definition: simulator.h:68
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:415
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition: nstime.h:351
@ NS
nanosecond
Definition: nstime.h:119
bool IsZero() const
Exactly equivalent to t == 0.
Definition: nstime.h:315
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
Implements the IEEE 802.11 MAC header.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
void SetQosTid(uint8_t tid)
Set the TID for the QoS header.
represent a single transmission mode
Definition: wifi-mode.h:51
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:122
static const Ptr< const PhyEntity > GetStaticPhyEntity(WifiModulationClass modulation)
Get the implemented PHY entity corresponding to the modulation class.
Definition: wifi-phy.cc:702
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1500
Class that keeps track of all information about the current PHY operating channel.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
uint8_t GetNss(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the number of spatial streams.
uint16_t GetChannelWidth() const
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:243
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:229
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:305
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
WifiPpduField
The type of PPDU field (grouped for convenience)
@ WIFI_PPDU_TYPE_DL_MU
@ WIFI_PPDU_TYPE_UL_MU
@ WIFI_PPDU_FIELD_DATA
data field
Definition: first.py:1
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:839
Every class exported by the ns3 library is enclosed in the ns3 namespace.
double RatioToDb(double ratio)
Convert from ratio to dB.
Definition: wifi-utils.cc:52
@ WIFI_MAC_QOSDATA
std::map< WifiSpectrumBandInfo, double > RxPowerWattPerChannelBand
A map of the received power (Watts) for each band.
Definition: phy-entity.h:77
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:159
Struct defining a frequency range between minFrequency (MHz) and maxFrequency (MHz).
uint16_t maxFrequency
the maximum frequency in MHz
uint16_t minFrequency
the minimum frequency in MHz
A struct for both SNR and PER.
Definition: phy-entity.h:147
WifiSpectrumBandInfo structure containing info about a spectrum band.
WifiSpectrumBandFrequencies frequencies
the start and stop frequencies of the band