A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
37namespace ns3
38{
39
40NS_LOG_COMPONENT_DEFINE("InterferenceHelper");
41
42NS_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
57{
58 m_ppdu = nullptr;
59 m_rxPowerW.clear();
60}
61
64{
65 return m_ppdu;
66}
67
68Time
70{
71 return m_startTime;
72}
73
74Time
76{
77 return m_endTime;
78}
79
80Time
82{
83 return m_endTime - m_startTime;
84}
85
86double
88{
89 NS_ASSERT(!m_rxPowerW.empty());
90 // The total RX power corresponds to the maximum over all the bands
91 auto it =
92 std::max_element(m_rxPowerW.cbegin(),
93 m_rxPowerW.cend(),
94 [](const auto& p1, const auto& p2) { return p1.second < p2.second; });
95 return it->second;
96}
97
98double
100{
101 const auto it = m_rxPowerW.find(band);
102 NS_ASSERT(it != m_rxPowerW.cend());
103 return it->second;
104}
105
108{
109 return m_rxPowerW;
110}
111
112void
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
128void
130{
131 m_ppdu = ppdu;
132}
133
134std::ostream&
135operator<<(std::ostream& os, const Event& event)
136{
137 os << "start=" << event.GetStartTime() << ", end=" << event.GetEndTime()
138 << ", power=" << event.GetRxPowerW() << "W"
139 << ", PPDU=" << event.GetPpdu();
140 return os;
141}
142
143/****************************************************************
144 * Class which records SNIR change events for a
145 * short period of time.
146 ****************************************************************/
147
149 : m_power(power),
150 m_event(event)
151{
152}
153
155{
156 m_event = nullptr;
157}
158
159double
161{
162 return m_power;
163}
164
165void
167{
168 m_power += power;
169}
170
173{
174 return m_event;
175}
176
177/****************************************************************
178 * The actual InterferenceHelper
179 ****************************************************************/
180
182 : m_errorRateModel(nullptr),
184 m_rxing(false)
185{
186 NS_LOG_FUNCTION(this);
187}
188
190{
191 NS_LOG_FUNCTION(this);
192}
193
194TypeId
196{
197 static TypeId tid = TypeId("ns3::InterferenceHelper")
199 .SetGroupName("Wifi")
200 .AddConstructor<InterferenceHelper>();
201 return tid;
202}
203
204void
206{
207 NS_LOG_FUNCTION(this);
208 for (auto it : m_niChanges)
209 {
210 it.second.clear();
211 }
212 m_niChanges.clear();
213 m_firstPowers.clear();
214 m_errorRateModel = nullptr;
215}
216
219 Time duration,
221 bool isStartHePortionRxing)
222{
223 Ptr<Event> event = Create<Event>(ppdu, duration, std::move(rxPowerW));
224 AppendEvent(event, isStartHePortionRxing);
225 return event;
226}
227
228void
230{
231 // Parameters other than duration and rxPowerW are unused for this type
232 // of signal, so we provide dummy versions
233 WifiMacHeader hdr;
235 hdr.SetQosTid(0);
236 Ptr<WifiPpdu> fakePpdu = Create<WifiPpdu>(Create<WifiPsdu>(Create<Packet>(0), hdr),
237 WifiTxVector(),
239 Add(fakePpdu, duration, rxPowerW);
240}
241
242bool
244{
245 return !m_niChanges.empty();
246}
247
248bool
250{
251 return (m_niChanges.count(band) > 0);
252}
253
254void
256{
257 NS_LOG_FUNCTION(this << band);
258 NS_ASSERT(m_niChanges.count(band) == 0);
259 NS_ASSERT(m_firstPowers.count(band) == 0);
260 NiChanges niChanges;
261 auto result = m_niChanges.insert({band, niChanges});
262 NS_ASSERT(result.second);
263 // Always have a zero power noise event in the list
264 AddNiChangeEvent(Time(0), NiChange(0.0, nullptr), result.first);
265 m_firstPowers.insert({band, 0.0});
266}
267
268void
269InterferenceHelper::UpdateBands(const std::vector<WifiSpectrumBandInfo>& bands,
270 const FrequencyRange& freqRange)
271{
272 NS_LOG_FUNCTION(this << freqRange);
273 for (auto it = m_niChanges.begin(); it != m_niChanges.end();)
274 {
275 if (!IsBandInFrequencyRange(it->first, freqRange))
276 {
277 it++;
278 continue;
279 }
280 const auto frequencies = it->first.frequencies;
281 const auto found =
282 std::find_if(bands.cbegin(), bands.cend(), [frequencies](const auto& item) {
283 return frequencies == item.frequencies;
284 }) != std::end(bands);
285 if (!found)
286 {
287 // band does not belong to the new bands, erase it
288 m_firstPowers.erase(it->first);
289 it->second.clear();
290 it = m_niChanges.erase(it);
291 }
292 else
293 {
294 it++;
295 }
296 }
297 for (const auto& band : bands)
298 {
299 if (!HasBand(band))
300 {
301 // this is a new band, add it
302 AddBand(band);
303 }
304 }
305}
306
307void
309{
310 m_noiseFigure = value;
311}
312
313void
315{
316 m_errorRateModel = rate;
317}
318
321{
322 return m_errorRateModel;
323}
324
325void
327{
328 m_numRxAntennas = rx;
329}
330
331Time
333{
334 NS_LOG_FUNCTION(this << energyW << band);
335 Time now = Simulator::Now();
336 auto niIt = m_niChanges.find(band);
337 NS_ABORT_IF(niIt == m_niChanges.end());
338 auto i = GetPreviousPosition(now, niIt);
339 Time end = i->first;
340 for (; i != niIt->second.end(); ++i)
341 {
342 double noiseInterferenceW = i->second.GetPower();
343 end = i->first;
344 if (noiseInterferenceW < energyW)
345 {
346 break;
347 }
348 }
349 return end > now ? end - now : MicroSeconds(0);
350}
351
352void
353InterferenceHelper::AppendEvent(Ptr<Event> event, bool isStartHePortionRxing)
354{
355 NS_LOG_FUNCTION(this << event << isStartHePortionRxing);
356 for (const auto& [band, power] : event->GetRxPowerWPerBand())
357 {
358 auto niIt = m_niChanges.find(band);
359 NS_ABORT_IF(niIt == m_niChanges.end());
360 double previousPowerStart = 0;
361 double previousPowerEnd = 0;
362 auto previousPowerPosition = GetPreviousPosition(event->GetStartTime(), niIt);
363 previousPowerStart = previousPowerPosition->second.GetPower();
364 previousPowerEnd = GetPreviousPosition(event->GetEndTime(), niIt)->second.GetPower();
365 if (!m_rxing)
366 {
367 m_firstPowers.find(band)->second = previousPowerStart;
368 // Always leave the first zero power noise event in the list
369 niIt->second.erase(++(niIt->second.begin()), ++previousPowerPosition);
370 }
371 else if (isStartHePortionRxing)
372 {
373 // When the first HE portion is received, we need to set m_firstPowerPerBand
374 // so that it takes into account interferences that arrived between the start of the
375 // HE TB PPDU transmission and the start of HE TB payload.
376 m_firstPowers.find(band)->second = previousPowerStart;
377 }
378 auto first =
379 AddNiChangeEvent(event->GetStartTime(), NiChange(previousPowerStart, event), niIt);
380 auto last = AddNiChangeEvent(event->GetEndTime(), NiChange(previousPowerEnd, event), niIt);
381 for (auto i = first; i != last; ++i)
382 {
383 i->second.AddPower(power);
384 }
385 }
386}
387
388void
390{
391 NS_LOG_FUNCTION(this << event);
392 // This is called for UL MU events, in order to scale power as long as UL MU PPDUs arrive
393 for (const auto& [band, power] : rxPower)
394 {
395 auto niIt = m_niChanges.find(band);
396 NS_ABORT_IF(niIt == m_niChanges.end());
397 auto first = GetPreviousPosition(event->GetStartTime(), niIt);
398 auto last = GetPreviousPosition(event->GetEndTime(), niIt);
399 for (auto i = first; i != last; ++i)
400 {
401 i->second.AddPower(power);
402 }
403 }
404 event->UpdateRxPowerW(rxPower);
405}
406
407double
409 double noiseInterference,
410 uint16_t channelWidth,
411 uint8_t nss) const
412{
413 NS_LOG_FUNCTION(this << signal << noiseInterference << channelWidth << +nss);
414 // thermal noise at 290K in J/s = W
415 static const double BOLTZMANN = 1.3803e-23;
416 // Nt is the power of thermal noise in W
417 double Nt = BOLTZMANN * 290 * channelWidth * 1e6;
418 // receiver noise Floor (W) which accounts for thermal noise and non-idealities of the receiver
419 double noiseFloor = m_noiseFigure * Nt;
420 double noise = noiseFloor + noiseInterference;
421 double snr = signal / noise; // linear scale
422 NS_LOG_DEBUG("bandwidth(MHz)=" << channelWidth << ", signal(W)= " << signal << ", noise(W)="
423 << noiseFloor << ", interference(W)=" << noiseInterference
424 << ", snr=" << RatioToDb(snr) << "dB");
425 if (m_errorRateModel->IsAwgn())
426 {
427 double gain = 1;
428 if (m_numRxAntennas > nss)
429 {
430 gain = static_cast<double>(m_numRxAntennas) /
431 nss; // compute gain offered by diversity for AWGN
432 }
433 NS_LOG_DEBUG("SNR improvement thanks to diversity: " << 10 * std::log10(gain) << "dB");
434 snr *= gain;
435 }
436 return snr;
437}
438
439double
441 NiChangesPerBand& nis,
442 const WifiSpectrumBandInfo& band) const
443{
444 NS_LOG_FUNCTION(this << band);
445 auto firstPower_it = m_firstPowers.find(band);
446 NS_ABORT_IF(firstPower_it == m_firstPowers.end());
447 double noiseInterferenceW = firstPower_it->second;
448 auto niIt = m_niChanges.find(band);
449 NS_ABORT_IF(niIt == m_niChanges.end());
450 auto it = niIt->second.find(event->GetStartTime());
451 double muMimoPowerW = (event->GetPpdu()->GetType() == WIFI_PPDU_TYPE_UL_MU)
452 ? CalculateMuMimoPowerW(event, band)
453 : 0.0;
454 for (; it != niIt->second.end() && it->first < Simulator::Now(); ++it)
455 {
456 if (IsSameMuMimoTransmission(event, it->second.GetEvent()) &&
457 (event != it->second.GetEvent()))
458 {
459 // Do not calculate noiseInterferenceW if events belong to the same MU-MIMO transmission
460 // unless this is the same event
461 continue;
462 }
463 noiseInterferenceW = it->second.GetPower() - event->GetRxPowerW(band) - muMimoPowerW;
464 if (std::abs(noiseInterferenceW) < std::numeric_limits<double>::epsilon())
465 {
466 // fix some possible rounding issues with double values
467 noiseInterferenceW = 0.0;
468 }
469 }
470 it = niIt->second.find(event->GetStartTime());
471 NS_ABORT_IF(it == niIt->second.end());
472 for (; it != niIt->second.end() && it->second.GetEvent() != event; ++it)
473 {
474 ;
475 }
476 NiChanges ni;
477 ni.emplace(event->GetStartTime(), NiChange(0, event));
478 while (++it != niIt->second.end() && it->second.GetEvent() != event)
479 {
480 ni.insert(*it);
481 }
482 ni.emplace(event->GetEndTime(), NiChange(0, event));
483 nis.insert({band, ni});
484 NS_ASSERT_MSG(noiseInterferenceW >= 0.0,
485 "CalculateNoiseInterferenceW returns negative value " << noiseInterferenceW);
486 return noiseInterferenceW;
487}
488
489double
491 const WifiSpectrumBandInfo& band) const
492{
493 auto niIt = m_niChanges.find(band);
494 NS_ASSERT(niIt != m_niChanges.end());
495 auto it = niIt->second.begin();
496 ++it;
497 double muMimoPowerW = 0.0;
498 for (; it != niIt->second.end() && it->first < Simulator::Now(); ++it)
499 {
500 if (IsSameMuMimoTransmission(event, it->second.GetEvent()))
501 {
502 auto hePpdu = DynamicCast<HePpdu>(it->second.GetEvent()->GetPpdu()->Copy());
503 NS_ASSERT(hePpdu);
504 HePpdu::TxPsdFlag psdFlag = hePpdu->GetTxPsdFlag();
505 if (psdFlag == HePpdu::PSD_HE_PORTION)
506 {
507 const auto staId =
508 event->GetPpdu()->GetTxVector().GetHeMuUserInfoMap().cbegin()->first;
509 const auto otherStaId = it->second.GetEvent()
510 ->GetPpdu()
511 ->GetTxVector()
512 .GetHeMuUserInfoMap()
513 .cbegin()
514 ->first;
515 if (staId == otherStaId)
516 {
517 break;
518 }
519 muMimoPowerW += it->second.GetEvent()->GetRxPowerW(band);
520 }
521 }
522 }
523 return muMimoPowerW;
524}
525
526double
528 Time duration,
529 WifiMode mode,
530 const WifiTxVector& txVector,
531 WifiPpduField field) const
532{
533 if (duration.IsZero())
534 {
535 return 1.0;
536 }
537 uint64_t rate = mode.GetDataRate(txVector.GetChannelWidth());
538 auto nbits = static_cast<uint64_t>(rate * duration.GetSeconds());
539 double csr =
540 m_errorRateModel->GetChunkSuccessRate(mode, txVector, snir, nbits, m_numRxAntennas, field);
541 return csr;
542}
543
544double
546 Time duration,
547 const WifiTxVector& txVector,
548 uint16_t staId) const
549{
550 if (duration.IsZero())
551 {
552 return 1.0;
553 }
554 WifiMode mode = txVector.GetMode(staId);
555 uint64_t rate = mode.GetDataRate(txVector, staId);
556 auto nbits = static_cast<uint64_t>(rate * duration.GetSeconds());
557 nbits /= txVector.GetNss(staId); // divide effective number of bits by NSS to achieve same chunk
558 // error rate as SISO for AWGN
559 double csr = m_errorRateModel->GetChunkSuccessRate(mode,
560 txVector,
561 snir,
562 nbits,
565 staId);
566 return csr;
567}
568
569double
571 uint16_t channelWidth,
572 NiChangesPerBand* nis,
573 const WifiSpectrumBandInfo& band,
574 uint16_t staId,
575 std::pair<Time, Time> window) const
576{
577 NS_LOG_FUNCTION(this << channelWidth << band << staId << window.first << window.second);
578 double psr = 1.0; /* Packet Success Rate */
579 const auto& niIt = nis->find(band)->second;
580 auto j = niIt.cbegin();
581 Time previous = j->first;
582 double muMimoPowerW = 0.0;
583 WifiMode payloadMode = event->GetPpdu()->GetTxVector().GetMode(staId);
584 Time phyPayloadStart = j->first;
585 if (event->GetPpdu()->GetType() != WIFI_PPDU_TYPE_UL_MU &&
586 event->GetPpdu()->GetType() !=
587 WIFI_PPDU_TYPE_DL_MU) // j->first corresponds to the start of the MU payload
588 {
589 phyPayloadStart = j->first + WifiPhy::CalculatePhyPreambleAndHeaderDuration(
590 event->GetPpdu()->GetTxVector());
591 }
592 else
593 {
594 muMimoPowerW = CalculateMuMimoPowerW(event, band);
595 }
596 Time windowStart = phyPayloadStart + window.first;
597 Time windowEnd = phyPayloadStart + window.second;
598 NS_ABORT_IF(m_firstPowers.count(band) == 0);
599 double noiseInterferenceW = m_firstPowers.at(band);
600 double powerW = event->GetRxPowerW(band);
601 while (++j != niIt.cend())
602 {
603 Time current = j->first;
604 NS_LOG_DEBUG("previous= " << previous << ", current=" << current);
605 NS_ASSERT(current >= previous);
606 double snr = CalculateSnr(powerW,
607 noiseInterferenceW,
608 channelWidth,
609 event->GetPpdu()->GetTxVector().GetNss(staId));
610 // Case 1: Both previous and current point to the windowed payload
611 if (previous >= windowStart)
612 {
614 Min(windowEnd, current) - previous,
615 event->GetPpdu()->GetTxVector(),
616 staId);
617 NS_LOG_DEBUG("Both previous and current point to the windowed payload: mode="
618 << payloadMode << ", psr=" << psr);
619 }
620 // Case 2: previous is before windowed payload and current is in the windowed payload
621 else if (current >= windowStart)
622 {
624 Min(windowEnd, current) - windowStart,
625 event->GetPpdu()->GetTxVector(),
626 staId);
628 "previous is before windowed payload and current is in the windowed payload: mode="
629 << payloadMode << ", psr=" << psr);
630 }
631 noiseInterferenceW = j->second.GetPower() - powerW;
632 if (IsSameMuMimoTransmission(event, j->second.GetEvent()))
633 {
634 muMimoPowerW += j->second.GetEvent()->GetRxPowerW(band);
636 "PPDU belongs to same MU-MIMO transmission: muMimoPowerW=" << muMimoPowerW);
637 }
638 noiseInterferenceW -= muMimoPowerW;
639 previous = j->first;
640 if (previous > windowEnd)
641 {
642 NS_LOG_DEBUG("Stop: new previous=" << previous
643 << " after time window end=" << windowEnd);
644 break;
645 }
646 }
647 double per = 1 - psr;
648 return per;
649}
650
651double
653 Ptr<const Event> event,
654 NiChangesPerBand* nis,
655 uint16_t channelWidth,
656 const WifiSpectrumBandInfo& band,
657 PhyEntity::PhyHeaderSections phyHeaderSections) const
658{
659 NS_LOG_FUNCTION(this << band);
660 double psr = 1.0; /* Packet Success Rate */
661 auto niIt = nis->find(band)->second;
662 auto j = niIt.begin();
663
664 NS_ASSERT(!phyHeaderSections.empty());
665 Time stopLastSection = Seconds(0);
666 for (const auto& section : phyHeaderSections)
667 {
668 stopLastSection = Max(stopLastSection, section.second.first.second);
669 }
670
671 Time previous = j->first;
672 NS_ABORT_IF(m_firstPowers.count(band) == 0);
673 double noiseInterferenceW = m_firstPowers.at(band);
674 double powerW = event->GetRxPowerW(band);
675 while (++j != niIt.end())
676 {
677 Time current = j->first;
678 NS_LOG_DEBUG("previous= " << previous << ", current=" << current);
679 NS_ASSERT(current >= previous);
680 double snr = CalculateSnr(powerW, noiseInterferenceW, channelWidth, 1);
681 for (const auto& section : phyHeaderSections)
682 {
683 Time start = section.second.first.first;
684 Time stop = section.second.first.second;
685
686 if (previous <= stop || current >= start)
687 {
688 Time duration = Min(stop, current) - Max(start, previous);
689 if (duration.IsStrictlyPositive())
690 {
691 psr *= CalculateChunkSuccessRate(snr,
692 duration,
693 section.second.second,
694 event->GetPpdu()->GetTxVector(),
695 section.first);
696 NS_LOG_DEBUG("Current NI change in "
697 << section.first << " [" << start << ", " << stop << "] for "
698 << duration.As(Time::NS) << ": mode=" << section.second.second
699 << ", psr=" << psr);
700 }
701 }
702 }
703 noiseInterferenceW = j->second.GetPower() - powerW;
704 previous = j->first;
705 if (previous > stopLastSection)
706 {
707 NS_LOG_DEBUG("Stop: new previous=" << previous << " after stop of last section="
708 << stopLastSection);
709 break;
710 }
711 }
712 return psr;
713}
714
715double
717 NiChangesPerBand* nis,
718 uint16_t channelWidth,
719 const WifiSpectrumBandInfo& band,
720 WifiPpduField header) const
721{
722 NS_LOG_FUNCTION(this << band << header);
723 auto niIt = nis->find(band)->second;
724 auto phyEntity =
725 WifiPhy::GetStaticPhyEntity(event->GetPpdu()->GetTxVector().GetModulationClass());
726
728 for (const auto& section :
729 phyEntity->GetPhyHeaderSections(event->GetPpdu()->GetTxVector(), niIt.begin()->first))
730 {
731 if (section.first == header)
732 {
733 sections[header] = section.second;
734 }
735 }
736
737 double psr = 1.0;
738 if (!sections.empty())
739 {
740 psr = CalculatePhyHeaderSectionPsr(event, nis, channelWidth, band, sections);
741 }
742 return 1 - psr;
743}
744
747 uint16_t channelWidth,
748 const WifiSpectrumBandInfo& band,
749 uint16_t staId,
750 std::pair<Time, Time> relativeMpduStartStop) const
751{
752 NS_LOG_FUNCTION(this << channelWidth << band << staId << relativeMpduStartStop.first
753 << relativeMpduStartStop.second);
755 double noiseInterferenceW = CalculateNoiseInterferenceW(event, ni, band);
756 double snr = CalculateSnr(event->GetRxPowerW(band),
757 noiseInterferenceW,
758 channelWidth,
759 event->GetPpdu()->GetTxVector().GetNss(staId));
760
761 /* calculate the SNIR at the start of the MPDU (located through windowing) and accumulate
762 * all SNIR changes in the SNIR vector.
763 */
764 double per = CalculatePayloadPer(event, channelWidth, &ni, band, staId, relativeMpduStartStop);
765
766 return PhyEntity::SnrPer(snr, per);
767}
768
769double
771 uint16_t channelWidth,
772 uint8_t nss,
773 const WifiSpectrumBandInfo& band) const
774{
776 double noiseInterferenceW = CalculateNoiseInterferenceW(event, ni, band);
777 double snr = CalculateSnr(event->GetRxPowerW(band), noiseInterferenceW, channelWidth, nss);
778 return snr;
779}
780
783 uint16_t channelWidth,
784 const WifiSpectrumBandInfo& band,
785 WifiPpduField header) const
786{
787 NS_LOG_FUNCTION(this << band << header);
789 double noiseInterferenceW = CalculateNoiseInterferenceW(event, ni, band);
790 double snr = CalculateSnr(event->GetRxPowerW(band), noiseInterferenceW, channelWidth, 1);
791
792 /* calculate the SNIR at the start of the PHY header and accumulate
793 * all SNIR changes in the SNIR vector.
794 */
795 double per = CalculatePhyHeaderPer(event, &ni, channelWidth, band, header);
796
797 return PhyEntity::SnrPer(snr, per);
798}
799
800InterferenceHelper::NiChanges::iterator
801InterferenceHelper::GetNextPosition(Time moment, NiChangesPerBand::iterator niIt)
802{
803 return niIt->second.upper_bound(moment);
804}
805
806InterferenceHelper::NiChanges::iterator
807InterferenceHelper::GetPreviousPosition(Time moment, NiChangesPerBand::iterator niIt)
808{
809 auto it = GetNextPosition(moment, niIt);
810 // This is safe since there is always an NiChange at time 0,
811 // before moment.
812 --it;
813 return it;
814}
815
816InterferenceHelper::NiChanges::iterator
817InterferenceHelper::AddNiChangeEvent(Time moment, NiChange change, NiChangesPerBand::iterator niIt)
818{
819 return niIt->second.insert(GetNextPosition(moment, niIt), std::make_pair(moment, change));
820}
821
822void
824{
825 NS_LOG_FUNCTION(this);
826 m_rxing = true;
827}
828
829void
831{
832 NS_LOG_FUNCTION(this << endTime << freqRange);
833 m_rxing = false;
834 // Update m_firstPowers for frame capture
835 for (auto niIt = m_niChanges.begin(); niIt != m_niChanges.end(); ++niIt)
836 {
837 if (!IsBandInFrequencyRange(niIt->first, freqRange))
838 {
839 continue;
840 }
841 NS_ASSERT(niIt->second.size() > 1);
842 auto it = GetPreviousPosition(endTime, niIt);
843 it--;
844 m_firstPowers.find(niIt->first)->second = it->second.GetPower();
845 }
846}
847
848bool
850 const FrequencyRange& freqRange) const
851{
852 return ((band.frequencies.second > (freqRange.minFrequency * 1e6)) &&
853 (band.frequencies.first < (freqRange.maxFrequency * 1e6)));
854}
855
856bool
858 Ptr<const Event> otherEvent) const
859{
860 if ((currentEvent->GetPpdu()->GetType() == WIFI_PPDU_TYPE_UL_MU) &&
861 (otherEvent->GetPpdu()->GetType() == WIFI_PPDU_TYPE_UL_MU) &&
862 (currentEvent->GetPpdu()->GetUid() == otherEvent->GetPpdu()->GetUid()))
863 {
864 const auto currentTxVector = currentEvent->GetPpdu()->GetTxVector();
865 const auto otherTxVector = otherEvent->GetPpdu()->GetTxVector();
866 NS_ASSERT(currentTxVector.GetHeMuUserInfoMap().size() == 1);
867 NS_ASSERT(otherTxVector.GetHeMuUserInfoMap().size() == 1);
868 const auto currentUserInfo = currentTxVector.GetHeMuUserInfoMap().cbegin();
869 const auto otherUserInfo = otherTxVector.GetHeMuUserInfoMap().cbegin();
870 return (currentUserInfo->second.ru == otherUserInfo->second.ru);
871 }
872 return false;
873}
874
875} // namespace ns3
#define Max(a, b)
#define Min(a, b)
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:78
Control the scheduling of simulation events.
Definition: simulator.h:68
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
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:402
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition: nstime.h:350
@ NS
nanosecond
Definition: nstime.h:119
bool IsZero() const
Exactly equivalent to t == 0.
Definition: nstime.h:314
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:930
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:704
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1489
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
#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:296
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1349
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1325
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
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
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:159
@ WIFI_MAC_QOSDATA
std::map< WifiSpectrumBandInfo, double > RxPowerWattPerChannelBand
A map of the received power (Watts) for each band.
Definition: phy-entity.h:77
STL namespace.
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