A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
he-phy.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Orange Labs
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Rediet <getachew.redieteab@orange.com>
7 * Sébastien Deronne <sebastien.deronne@gmail.com> (for logic ported from wifi-phy and
8 * spectrum-wifi-phy)
9 */
10
11#include "he-phy.h"
12
13#include "he-configuration.h"
14#include "obss-pd-algorithm.h"
15
16#include "ns3/ap-wifi-mac.h"
17#include "ns3/assert.h"
18#include "ns3/interference-helper.h"
19#include "ns3/log.h"
20#include "ns3/simulator.h"
21#include "ns3/spectrum-wifi-phy.h"
22#include "ns3/sta-wifi-mac.h"
23#include "ns3/vht-configuration.h"
24#include "ns3/wifi-net-device.h"
25#include "ns3/wifi-psdu.h"
26#include "ns3/wifi-utils.h"
27
28#include <algorithm>
29
30#undef NS_LOG_APPEND_CONTEXT
31#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(m_wifiPhy)
32
33namespace ns3
34{
35
37
38/*******************************************************
39 * HE PHY (P802.11ax/D4.0, clause 27)
40 *******************************************************/
41
42// clang-format off
43
44const PhyEntity::PpduFormats HePhy::m_hePpduFormats { // Ignoring PE (Packet Extension)
46 WIFI_PPDU_FIELD_NON_HT_HEADER, // L-SIG + RL-SIG
47 WIFI_PPDU_FIELD_SIG_A, // HE-SIG-A
48 WIFI_PPDU_FIELD_TRAINING, // HE-STF + HE-LTFs
51 WIFI_PPDU_FIELD_NON_HT_HEADER, // L-SIG + RL-SIG
52 WIFI_PPDU_FIELD_SIG_A, // HE-SIG-A
53 WIFI_PPDU_FIELD_SIG_B, // HE-SIG-B
54 WIFI_PPDU_FIELD_TRAINING, // HE-STF + HE-LTFs
57 WIFI_PPDU_FIELD_NON_HT_HEADER, // L-SIG + RL-SIG
58 WIFI_PPDU_FIELD_SIG_A, // HE-SIG-A
59 WIFI_PPDU_FIELD_TRAINING, // HE-STF + HE-LTFs
62 WIFI_PPDU_FIELD_NON_HT_HEADER, // L-SIG + RL-SIG
63 WIFI_PPDU_FIELD_SIG_A, // HE-SIG-A
64 WIFI_PPDU_FIELD_TRAINING, // HE-STF + HE-LTFs
66};
67
68// clang-format on
69
70HePhy::HePhy(bool buildModeList /* = true */)
71 : VhtPhy(false), // don't add VHT modes to list
72 m_trigVector(std::nullopt),
73 m_trigVectorExpirationTime(std::nullopt),
74 m_currentTxVector(std::nullopt),
75 m_rxHeTbPpdus(0),
76 m_lastPer20MHzDurations()
77{
78 NS_LOG_FUNCTION(this << buildModeList);
82 m_currentMuPpduUid = UINT64_MAX;
83 m_previouslyTxPpduUid = UINT64_MAX;
84 if (buildModeList)
85 {
87 }
88}
89
91{
92 NS_LOG_FUNCTION(this);
93}
94
95void
97{
98 NS_LOG_FUNCTION(this);
99 NS_ASSERT(m_modeList.empty());
101 for (uint8_t index = 0; index <= m_maxSupportedMcsIndexPerSs; ++index)
102 {
103 NS_LOG_LOGIC("Add HeMcs" << +index << " to list");
104 m_modeList.emplace_back(CreateHeMcs(index));
105 }
106}
107
109HePhy::GetSigMode(WifiPpduField field, const WifiTxVector& txVector) const
110{
111 switch (field)
112 {
113 case WIFI_PPDU_FIELD_TRAINING: // consider SIG-A (SIG-B) mode for training for the time being
114 // for SU/ER-SU/TB (MU) (useful for InterferenceHelper)
115 if (txVector.IsDlMu())
116 {
118 // Training comes after SIG-B
119 return GetSigBMode(txVector);
120 }
121 else
122 {
123 // Training comes after SIG-A
124 return GetSigAMode();
125 }
126 default:
127 return VhtPhy::GetSigMode(field, txVector);
128 }
129}
130
133{
134 return GetVhtMcs0(); // same number of data tones as VHT for 20 MHz (i.e. 52)
135}
136
138HePhy::GetSigBMode(const WifiTxVector& txVector) const
139{
140 NS_ABORT_MSG_IF(!IsDlMu(txVector.GetPreambleType()), "SIG-B only available for DL MU");
141 /**
142 * Get smallest HE MCS index among station's allocations and use the
143 * VHT version of the index. This enables to have 800 ns GI, 52 data
144 * tones, and 312.5 kHz spacing while ensuring that MCS will be decoded
145 * by all stations.
146 */
147 uint8_t smallestMcs = 5; // maximum MCS for HE-SIG-B
148 for (auto& info : txVector.GetHeMuUserInfoMap())
149 {
150 smallestMcs = std::min(smallestMcs, info.second.mcs);
151 }
152 switch (smallestMcs)
153 {
154 case 0:
155 return GetVhtMcs0();
156 case 1:
157 return GetVhtMcs1();
158 case 2:
159 return GetVhtMcs2();
160 case 3:
161 return GetVhtMcs3();
162 case 4:
163 return GetVhtMcs4();
164 case 5:
165 default:
166 return GetVhtMcs5();
167 }
168}
169
172{
173 return m_hePpduFormats;
174}
175
176Time
178{
179 return MicroSeconds(8); // L-SIG + RL-SIG
180}
181
182Time
184 uint8_t nDataLtf,
185 uint8_t nExtensionLtf /* = 0 */) const
186{
187 Time ltfDuration = MicroSeconds(8); // TODO extract from TxVector when available
188 Time stfDuration;
189 if (txVector.IsUlMu())
190 {
192 stfDuration = MicroSeconds(8);
193 }
194 else
195 {
196 stfDuration = MicroSeconds(4);
197 }
198 NS_ABORT_MSG_IF(nDataLtf > 8, "Unsupported number of LTFs " << +nDataLtf << " for HE");
199 NS_ABORT_MSG_IF(nExtensionLtf > 0, "No extension LTFs expected for HE");
200 return stfDuration + ltfDuration * nDataLtf; // HE-STF + HE-LTFs
201}
202
203Time
205{
206 return (preamble == WIFI_PREAMBLE_HE_ER_SU)
207 ? MicroSeconds(16)
208 : MicroSeconds(8); // HE-SIG-A (first and second symbol)
209}
210
212HePhy::GetSigBSize(const WifiTxVector& txVector) const
213{
214 if (ns3::IsDlMu(txVector.GetPreambleType()))
215 {
218 txVector.GetChannelWidth(),
219 txVector.GetRuAllocation(
221 txVector.IsSigBCompression(),
222 txVector.IsSigBCompression() ? txVector.GetHeMuUserInfoMap().size() : 0);
223 }
224 return 0;
225}
226
227Time
229{
230 if (const auto sigBSize = GetSigBSize(txVector); sigBSize > 0)
231 {
232 const auto symbolDuration = MicroSeconds(4);
233 // Number of data bits per symbol
234 const auto ndbps =
235 GetSigBMode(txVector).GetDataRate(20) * symbolDuration.GetNanoSeconds() / 1e9;
236 const auto numSymbols = ceil((sigBSize) / ndbps);
237
238 return FemtoSeconds(static_cast<uint64_t>(numSymbols * symbolDuration.GetFemtoSeconds()));
239 }
240 else
241 {
242 // no SIG-B
243 return MicroSeconds(0);
244 }
245}
246
247Time
248HePhy::GetValidPpduDuration(Time ppduDuration, const WifiTxVector& txVector, WifiPhyBand band)
249{
250 const auto tSymbol = GetSymbolDuration(txVector.GetGuardInterval());
251 const auto preambleDuration = WifiPhy::CalculatePhyPreambleAndHeaderDuration(txVector);
252 uint8_t sigExtension = (band == WIFI_PHY_BAND_2_4GHZ ? 6 : 0);
253 uint32_t nSymbols =
254 floor(static_cast<double>((ppduDuration - preambleDuration).GetNanoSeconds() -
255 (sigExtension * 1000)) /
256 tSymbol.GetNanoSeconds());
257 return preambleDuration + (nSymbols * tSymbol) + MicroSeconds(sigExtension);
258}
259
260std::pair<uint16_t, Time>
262 const WifiTxVector& txVector,
263 WifiPhyBand band)
264{
265 NS_ABORT_IF(!txVector.IsUlMu() || (txVector.GetModulationClass() < WIFI_MOD_CLASS_HE));
266 // update ppduDuration so that it is a valid PPDU duration
267 ppduDuration = GetValidPpduDuration(ppduDuration, txVector, band);
268 uint8_t sigExtension = (band == WIFI_PHY_BAND_2_4GHZ ? 6 : 0);
269 uint8_t m = 2; // HE TB PPDU so m is set to 2
270 uint16_t length = ((ceil((static_cast<double>(ppduDuration.GetNanoSeconds() - (20 * 1000) -
271 (sigExtension * 1000)) /
272 1000) /
273 4.0) *
274 3) -
275 3 - m);
276 return {length, ppduDuration};
277}
278
279Time
281 const WifiTxVector& txVector,
282 WifiPhyBand band)
283{
284 NS_ABORT_IF(!txVector.IsUlMu() || (txVector.GetModulationClass() < WIFI_MOD_CLASS_HE));
285 uint8_t sigExtension = (band == WIFI_PHY_BAND_2_4GHZ ? 6 : 0);
286 uint8_t m = 2; // HE TB PPDU so m is set to 2
287 // Equation 27-11 of IEEE P802.11ax/D4.0
288 Time calculatedDuration =
289 MicroSeconds(((ceil(static_cast<double>(length + 3 + m) / 3)) * 4) + 20 + sigExtension);
290 return GetValidPpduDuration(calculatedDuration, txVector, band);
291}
292
293Time
295{
296 Time duration = GetDuration(WIFI_PPDU_FIELD_PREAMBLE, txVector) +
299 return duration;
300}
301
302Time
304{
305 Time duration = GetDuration(WIFI_PPDU_FIELD_PREAMBLE, txVector) +
309 return duration;
310}
311
312uint8_t
313HePhy::GetNumberBccEncoders(const WifiTxVector& /* txVector */) const
314{
315 return 1; // only 1 BCC encoder for HE since higher rates are obtained using LDPC
316}
317
318Time
320{
321 const auto guardInterval = txVector.GetGuardInterval();
322 [[maybe_unused]] const auto gi = guardInterval.GetNanoSeconds();
323 NS_ASSERT(gi == 800 || gi == 1600 || gi == 3200);
324 return GetSymbolDuration(guardInterval);
325}
326
327void
328HePhy::SetTrigVector(const WifiTxVector& trigVector, Time validity)
329{
330 NS_LOG_FUNCTION(this << trigVector << validity);
331 NS_ASSERT_MSG(trigVector.GetGuardInterval().GetNanoSeconds() > 800,
332 "Invalid guard interval " << trigVector.GetGuardInterval());
333 if (auto mac = m_wifiPhy->GetDevice()->GetMac(); mac && mac->GetTypeOfStation() != AP)
334 {
335 return;
336 }
337 m_trigVector = trigVector;
340}
341
343HePhy::BuildPpdu(const WifiConstPsduMap& psdus, const WifiTxVector& txVector, Time ppduDuration)
344{
345 NS_LOG_FUNCTION(this << psdus << txVector << ppduDuration);
346 return Create<HePpdu>(psdus,
347 txVector,
349 ppduDuration,
350 ObtainNextUid(txVector),
352}
353
354void
356 RxPowerWattPerChannelBand& rxPowersW,
357 Time rxDuration)
358{
359 NS_LOG_FUNCTION(this << ppdu << rxDuration);
360 const auto& txVector = ppdu->GetTxVector();
361 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
362 NS_ASSERT(hePpdu);
363 const auto psdFlag = hePpdu->GetTxPsdFlag();
364 if (psdFlag == HePpdu::PSD_HE_PORTION)
365 {
366 NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
367 if (m_currentMuPpduUid == ppdu->GetUid() && GetCurrentEvent())
368 {
369 // AP or STA has already received non-HE portion, switch to HE portion, and schedule
370 // reception of payload (will be canceled for STAs by StartPayload)
371 const auto hePortionStarted = !m_beginMuPayloadRxEvents.empty();
372 NS_LOG_INFO("Switch to HE portion (already started? "
373 << (hePortionStarted ? "Y" : "N") << ") "
374 << "and schedule payload reception in "
376 auto event = CreateInterferenceEvent(ppdu, rxDuration, rxPowersW, !hePortionStarted);
377 uint16_t staId = GetStaId(ppdu);
378 NS_ASSERT(!m_beginMuPayloadRxEvents.contains(staId));
382 this,
383 event);
384 }
385 else
386 {
387 // PHY receives the HE portion while having dropped the preamble
388 NS_LOG_INFO("Consider HE portion of the PPDU as interference since device dropped the "
389 "preamble");
390 CreateInterferenceEvent(ppdu, rxDuration, rxPowersW);
391 // the HE portion of the PPDU will be noise _after_ the completion of the current event
392 ErasePreambleEvent(ppdu, rxDuration);
393 }
394 }
395 else
396 {
398 ppdu,
399 rxPowersW,
400 ppdu->GetTxDuration()); // The actual duration of the PPDU should be used
401 }
402}
403
404void
406{
407 NS_LOG_FUNCTION(this);
408 for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
409 {
410 beginMuPayloadRxEvent.second.Cancel();
411 }
414}
415
416void
418{
419 NS_LOG_FUNCTION(this << reason);
420 if (reason != OBSS_PD_CCA_RESET)
421 {
422 for (auto& endMpduEvent : m_endOfMpduEvents)
423 {
424 endMpduEvent.Cancel();
425 }
426 m_endOfMpduEvents.clear();
427 }
428 else
429 {
431 }
432}
433
434void
436{
437 NS_LOG_FUNCTION(this << *event);
438 if (event->GetPpdu()->GetType() != WIFI_PPDU_TYPE_UL_MU)
439 {
440 NS_ASSERT(event->GetEndTime() == Simulator::Now());
441 }
442 for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
443 {
444 beginMuPayloadRxEvent.second.Cancel();
445 }
447}
448
451{
452 Ptr<Event> event;
453 // We store all incoming preamble events, and a decision is made at the end of the preamble
454 // detection window. If a preamble is received after the preamble detection window, it is stored
455 // anyway because this is needed for HE TB PPDUs in order to properly update the received power
456 // in InterferenceHelper. The map is cleaned anyway at the end of the current reception.
457 const auto& currentPreambleEvents = GetCurrentPreambleEvents();
458 const auto it = currentPreambleEvents.find({ppdu->GetUid(), ppdu->GetPreamble()});
459 if (const auto isResponseToTrigger = (m_previouslyTxPpduUid == ppdu->GetUid());
460 ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU || isResponseToTrigger)
461 {
462 const auto& txVector = ppdu->GetTxVector();
463 const auto rxDuration =
464 (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
466 txVector) // the HE portion of the transmission will be added later on
467 : ppdu->GetTxDuration();
468 if (it != currentPreambleEvents.cend())
469 {
470 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
471 {
472 NS_LOG_DEBUG("Received another HE TB PPDU for UID "
473 << ppdu->GetUid() << " from STA-ID " << ppdu->GetStaId()
474 << " and BSS color " << +txVector.GetBssColor());
475 }
476 else
477 {
478 NS_LOG_DEBUG("Received another response to a trigger frame " << ppdu->GetUid());
479 }
480 event = it->second;
481 HandleRxPpduWithSameContent(event, ppdu, rxPowersW);
482 return nullptr;
483 }
484 else
485 {
486 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
487 {
488 NS_LOG_DEBUG("Received a new HE TB PPDU for UID "
489 << ppdu->GetUid() << " from STA-ID " << ppdu->GetStaId()
490 << " and BSS color " << +txVector.GetBssColor());
491 }
492 else
493 {
494 NS_LOG_DEBUG("Received response to a trigger frame for UID " << ppdu->GetUid());
495 }
496 event = CreateInterferenceEvent(ppdu, rxDuration, rxPowersW);
497 AddPreambleEvent(event);
498 }
499 }
500 else if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
501 {
502 const auto& txVector = ppdu->GetTxVector();
504 txVector); // the HE portion of the transmission will be added later on
505 event = CreateInterferenceEvent(ppdu, rxDuration, rxPowersW);
506 AddPreambleEvent(event);
507 }
508 else
509 {
510 event = VhtPhy::DoGetEvent(ppdu, rxPowersW);
511 }
512 return event;
513}
514
515void
519{
520 VhtPhy::HandleRxPpduWithSameContent(event, ppdu, rxPower);
521
522 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU && GetCurrentEvent() &&
523 (GetCurrentEvent()->GetPpdu()->GetUid() != ppdu->GetUid()))
524 {
525 NS_LOG_DEBUG("Drop packet because already receiving another HE TB PPDU");
527 }
528 else if (const auto isResponseToTrigger = (m_previouslyTxPpduUid == ppdu->GetUid());
529 isResponseToTrigger && GetCurrentEvent() &&
530 (GetCurrentEvent()->GetPpdu()->GetUid() != ppdu->GetUid()))
531 {
532 NS_LOG_DEBUG("Drop packet because already receiving another response to a trigger frame");
534 }
535}
536
539{
540 if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU || ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
541 {
542 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
543 NS_ASSERT(hePpdu);
544 return hePpdu->GetPsdu(GetBssColor(), GetStaId(ppdu));
545 }
547}
548
549uint8_t
551{
552 uint8_t bssColor = 0;
553 if (m_wifiPhy->GetDevice())
554 {
555 Ptr<HeConfiguration> heConfiguration = m_wifiPhy->GetDevice()->GetHeConfiguration();
556 if (heConfiguration)
557 {
558 bssColor = heConfiguration->GetBssColor();
559 }
560 }
561 return bssColor;
562}
563
564uint16_t
566{
567 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
568 {
569 return ppdu->GetStaId();
570 }
571 else if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
572 {
573 auto mac = DynamicCast<StaWifiMac>(m_wifiPhy->GetDevice()->GetMac());
574 if (mac && mac->IsAssociated())
575 {
576 return mac->GetAssociationId();
577 }
578 }
579 return VhtPhy::GetStaId(ppdu);
580}
581
584{
585 NS_LOG_FUNCTION(this << *event << status << field);
586 NS_ASSERT(event->GetPpdu()->GetTxVector().GetPreambleType() >= WIFI_PREAMBLE_HE_SU);
587 switch (field)
588 {
590 return ProcessSigA(event, status);
592 return ProcessSigB(event, status);
593 default:
594 NS_ASSERT_MSG(false, "Invalid PPDU field");
595 }
596 return status;
597}
598
601{
602 NS_LOG_FUNCTION(this << *event << status);
603 // Notify end of SIG-A (in all cases)
604 const auto& txVector = event->GetPpdu()->GetTxVector();
605 HeSigAParameters params{
606 .rssi = WToDbm(GetRxPowerForPpdu(event)),
607 .bssColor = txVector.GetBssColor(),
608 };
609 NotifyEndOfHeSigA(params); // if OBSS_PD CCA_RESET, set power restriction first and wait till
610 // field is processed before switching to IDLE
611
612 if (status.isSuccess)
613 {
614 // Check if PPDU is filtered based on the BSS color
615 uint8_t myBssColor = GetBssColor();
616 uint8_t rxBssColor = txVector.GetBssColor();
617 if (myBssColor != 0 && rxBssColor != 0 && myBssColor != rxBssColor)
618 {
619 NS_LOG_DEBUG("The BSS color of this PPDU ("
620 << +rxBssColor << ") does not match the device's (" << +myBssColor
621 << "). The PPDU is filtered.");
622 return PhyFieldRxStatus(false, FILTERED, DROP);
623 }
624
625 // When SIG-A is decoded, we know the type of frame being received. If we stored a
626 // valid TRIGVECTOR and we are not receiving a TB PPDU, we drop the frame.
627 Ptr<const WifiPpdu> ppdu = event->GetPpdu();
628 if (m_trigVectorExpirationTime.has_value() &&
630 (ppdu->GetType() != WIFI_PPDU_TYPE_UL_MU))
631 {
632 NS_LOG_DEBUG("Expected an HE TB PPDU, receiving a " << txVector.GetPreambleType());
633 return PhyFieldRxStatus(false, FILTERED, DROP);
634 }
635
636 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
637 {
638 NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
639 // check that the stored TRIGVECTOR is still valid
640 if (!m_trigVectorExpirationTime.has_value() ||
642 {
643 NS_LOG_DEBUG("No valid TRIGVECTOR, the PHY was not expecting a TB PPDU");
644 return PhyFieldRxStatus(false, FILTERED, DROP);
645 }
646 // We expected a TB PPDU and we are receiving a TB PPDU. However, despite
647 // the previous check on BSS Color, we may be receiving a TB PPDU from an
648 // OBSS, as BSS Colors are not guaranteed to be different for all APs in
649 // range (an example is when BSS Color is 0). We can detect this situation
650 // by comparing the TRIGVECTOR with the TXVECTOR of the TB PPDU being received
651 NS_ABORT_IF(!m_trigVector.has_value());
652 if (m_trigVector->GetChannelWidth() != txVector.GetChannelWidth())
653 {
654 NS_LOG_DEBUG("Received channel width different than in TRIGVECTOR");
655 return PhyFieldRxStatus(false, FILTERED, DROP);
656 }
657 if (m_trigVector->GetLength() != txVector.GetLength())
658 {
659 NS_LOG_DEBUG("Received UL Length (" << txVector.GetLength()
660 << ") different than in TRIGVECTOR ("
661 << m_trigVector->GetLength() << ")");
662 return PhyFieldRxStatus(false, FILTERED, DROP);
663 }
664 uint16_t staId = ppdu->GetStaId();
665 if (!m_trigVector->GetHeMuUserInfoMap().contains(staId))
666 {
667 NS_LOG_DEBUG("TB PPDU received from un unexpected STA ID");
668 return PhyFieldRxStatus(false, FILTERED, DROP);
669 }
670
671 NS_ASSERT(txVector.GetGuardInterval() == m_trigVector->GetGuardInterval());
672 NS_ASSERT(txVector.GetMode(staId) == m_trigVector->GetMode(staId));
673 NS_ASSERT(txVector.GetNss(staId) == m_trigVector->GetNss(staId));
674 NS_ASSERT(txVector.GetHeMuUserInfo(staId) == m_trigVector->GetHeMuUserInfo(staId));
675
677 ppdu->GetUid(); // to be able to correctly schedule start of MU payload
678 }
679
680 if (ppdu->GetType() != WIFI_PPDU_TYPE_DL_MU &&
681 !GetAddressedPsduInPpdu(ppdu)) // Final decision on STA-ID correspondence of DL MU is
682 // delayed to end of SIG-B
683 {
684 NS_ASSERT(ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU);
686 "No PSDU addressed to that PHY in the received MU PPDU. The PPDU is filtered.");
687 return PhyFieldRxStatus(false, FILTERED, DROP);
688 }
689 }
690 return status;
691}
692
693void
695{
696 m_obssPdAlgorithm = algorithm;
697}
698
701{
702 return m_obssPdAlgorithm;
703}
704
705void
710
711void
719
722{
723 NS_LOG_FUNCTION(this << *event << status);
724 NS_ASSERT(IsDlMu(event->GetPpdu()->GetTxVector().GetPreambleType()));
725 if (status.isSuccess)
726 {
727 // Check if PPDU is filtered only if the SIG-B content is supported (not explicitly stated
728 // but assumed based on behavior for SIG-A)
729 if (!GetAddressedPsduInPpdu(event->GetPpdu()))
730 {
732 "No PSDU addressed to that PHY in the received MU PPDU. The PPDU is filtered.");
733 return PhyFieldRxStatus(false, FILTERED, DROP);
734 }
735 }
737 event->GetPpdu()->GetUid(); // to be able to correctly schedule start of MU payload
738
739 return status;
740}
741
742bool
744{
745 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
746 {
747 return true; // evaluated in ProcessSigA
748 }
749
750 const auto& txVector = ppdu->GetTxVector();
751 const auto staId = GetStaId(ppdu);
752 const auto txMode = txVector.GetMode(staId);
753 auto nss = txVector.GetNssMax();
754 if (txVector.IsDlMu())
755 {
756 NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
757 for (auto info : txVector.GetHeMuUserInfoMap())
758 {
759 if (info.first == staId)
760 {
761 nss = info.second.nss; // no need to look at other PSDUs
762 break;
763 }
764 }
765 }
766
768 {
769 NS_LOG_DEBUG("Packet reception could not be started because not enough RX antennas");
770 return false;
771 }
772 if (!IsModeSupported(txMode))
773 {
774 NS_LOG_DEBUG("Drop packet because it was sent using an unsupported mode ("
775 << txVector.GetMode() << ")");
776 return false;
777 }
778 return true;
779}
780
781Time
783{
784 NS_LOG_FUNCTION(this << *event);
785 const auto ppdu = event->GetPpdu();
786 const auto& txVector = ppdu->GetTxVector();
787
788 if (!txVector.IsMu())
789 {
790 return VhtPhy::DoStartReceivePayload(event);
791 }
792
793 NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
794
795 if (txVector.IsDlMu())
796 {
797 Time payloadDuration =
798 ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(txVector);
799 NotifyPayloadBegin(txVector, payloadDuration);
800 return payloadDuration;
801 }
802
803 // TX duration is determined by the Length field of TXVECTOR
804 Time payloadDuration = ConvertLSigLengthToHeTbPpduDuration(txVector.GetLength(),
805 txVector,
808 // This method is called when we start receiving the first MU payload. To
809 // compute the time to the reception end of the last TB PPDU, we need to add the
810 // offset of the last TB PPDU to the payload duration (same for all TB PPDUs)
811 Time maxOffset{0};
812 for (const auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
813 {
814 maxOffset = Max(maxOffset, Simulator::GetDelayLeft(beginMuPayloadRxEvent.second));
815 }
816 Time timeToEndRx = payloadDuration + maxOffset;
817
818 if (m_wifiPhy->GetDevice()->GetMac()->GetTypeOfStation() != AP)
819 {
820 NS_LOG_DEBUG("Ignore HE TB PPDU payload received by STA but keep state in Rx");
821 NotifyPayloadBegin(txVector, timeToEndRx);
822 m_endRxPayloadEvents.push_back(
823 Simulator::Schedule(timeToEndRx, &HePhy::ResetReceive, this, event));
824 // Cancel all scheduled events for MU payload reception
826 m_beginMuPayloadRxEvents.begin()->second.IsPending());
827 for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
828 {
829 beginMuPayloadRxEvent.second.Cancel();
830 }
832 }
833 else
834 {
835 NS_LOG_DEBUG("Receiving PSDU in HE TB PPDU");
836 const auto staId = GetStaId(ppdu);
837 m_signalNoiseMap.insert({{ppdu->GetUid(), staId}, SignalNoiseDbm()});
838 m_statusPerMpduMap.insert({{ppdu->GetUid(), staId}, std::vector<bool>()});
839 // for HE TB PPDUs, ScheduleEndOfMpdus and EndReceive are scheduled by
840 // StartReceiveMuPayload
842 for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
843 {
844 NS_ASSERT(beginMuPayloadRxEvent.second.IsPending());
845 }
846 }
847
848 return timeToEndRx;
849}
850
851void
853 RxSignalInfo rxSignalInfo,
854 const WifiTxVector& txVector,
855 uint16_t staId,
856 const std::vector<bool>& statusPerMpdu)
857{
858 NS_LOG_FUNCTION(this << *psdu << txVector);
859 if (!IsUlMu(txVector.GetPreambleType()))
860 {
861 m_state->SwitchFromRxEndOk();
862 }
863 else
864 {
866 }
867}
868
869void
871{
872 NS_LOG_FUNCTION(this << *psdu << txVector << snr);
873 if (!txVector.IsUlMu())
874 {
875 m_state->SwitchFromRxEndError();
876 }
877}
878
879void
881{
882 NS_LOG_FUNCTION(this << ppdu);
883 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
884 {
885 for (auto it = m_endRxPayloadEvents.begin(); it != m_endRxPayloadEvents.end();)
886 {
887 if (it->IsExpired())
888 {
889 it = m_endRxPayloadEvents.erase(it);
890 }
891 else
892 {
893 it++;
894 }
895 }
896 if (m_endRxPayloadEvents.empty())
897 {
898 // We've got the last PPDU of the UL-MU transmission.
899 // Indicate a successful reception is terminated if at least one HE TB PPDU
900 // has been successfully received, otherwise indicate a unsuccessful reception is
901 // terminated.
902 if (m_rxHeTbPpdus > 0)
903 {
904 m_state->SwitchFromRxEndOk();
905 }
906 else
907 {
908 m_state->SwitchFromRxEndError();
909 }
910 NotifyInterferenceRxEndAndClear(true); // reset WifiPhy
911 m_rxHeTbPpdus = 0;
912 }
913 }
914 else
915 {
918 }
919 // we are done receiving the payload, we can reset the current MU PPDU UID
920 m_currentMuPpduUid = UINT64_MAX;
921}
922
923void
925{
926 NS_LOG_FUNCTION(this << event);
927 Ptr<const WifiPpdu> ppdu = event->GetPpdu();
928 const RxPowerWattPerChannelBand& rxPowersW = event->GetRxPowerPerBand();
929 // The total RX power corresponds to the maximum over all the bands.
930 // Only perform this computation if the result needs to be logged.
931 auto it = rxPowersW.end();
932 if (g_log.IsEnabled(ns3::LOG_FUNCTION))
933 {
934 it = std::max_element(rxPowersW.cbegin(),
935 rxPowersW.cend(),
936 [](const auto& p1, const auto& p2) { return p1.second < p2.second; });
937 }
938 NS_LOG_FUNCTION(this << *event << it->second);
941 auto itEvent = m_beginMuPayloadRxEvents.find(GetStaId(ppdu));
942 /**
943 * m_beginMuPayloadRxEvents should still be running only for APs, since canceled in
944 * StartReceivePayload for STAs. This is because SpectrumWifiPhy does not have access to the
945 * device type and thus blindly schedules things, letting the parent WifiPhy class take into
946 * account device type.
947 */
948 NS_ASSERT(itEvent != m_beginMuPayloadRxEvents.end() && itEvent->second.IsExpired());
949 m_beginMuPayloadRxEvents.erase(itEvent);
950
951 auto payloadDuration =
952 ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(ppdu->GetTxVector());
953 auto psdu = GetAddressedPsduInPpdu(ppdu);
954 ScheduleEndOfMpdus(event);
955 m_endRxPayloadEvents.push_back(
956 Simulator::Schedule(payloadDuration, &HePhy::EndReceivePayload, this, event));
957 const auto staId = GetStaId(ppdu);
958 m_signalNoiseMap.insert({{ppdu->GetUid(), staId}, SignalNoiseDbm()});
959 m_statusPerMpduMap.insert({{ppdu->GetUid(), staId}, std::vector<bool>()});
960 // Notify the MAC about the start of a new HE TB PPDU, so that it can reschedule the timeout
961 NotifyPayloadBegin(ppdu->GetTxVector(), payloadDuration);
962}
963
964std::pair<MHz_u, WifiSpectrumBandInfo>
965HePhy::GetChannelWidthAndBand(const WifiTxVector& txVector, uint16_t staId) const
966{
967 if (txVector.IsMu())
968 {
969 return {HeRu::GetBandwidth(txVector.GetRu(staId).GetRuType()),
970 GetRuBandForRx(txVector, staId)};
971 }
972 else
973 {
974 return VhtPhy::GetChannelWidthAndBand(txVector, staId);
975 }
976}
977
979HePhy::GetRuBandForTx(const WifiTxVector& txVector, uint16_t staId) const
980{
981 NS_ASSERT(txVector.IsMu());
982 HeRu::RuSpec ru = txVector.GetRu(staId);
983 const auto channelWidth = txVector.GetChannelWidth();
984 NS_ASSERT(channelWidth <= m_wifiPhy->GetChannelWidth());
986 channelWidth,
987 ru.GetRuType(),
989 // for a TX spectrum, the guard bandwidth is a function of the transmission channel width
990 // and the spectrum width equals the transmission channel width (hence bandIndex equals 0)
991 const auto indices = ConvertHeRuSubcarriers(channelWidth,
992 GetGuardBandwidth(channelWidth),
996 {group.front().first, group.back().second},
997 0);
998 WifiSpectrumBandInfo ruBandForTx{};
999 for (const auto& indicesPerSegment : indices)
1000 {
1001 ruBandForTx.indices.emplace_back(indicesPerSegment);
1002 ruBandForTx.frequencies.emplace_back(
1003 m_wifiPhy->ConvertIndicesToFrequencies(indicesPerSegment));
1004 }
1005 return ruBandForTx;
1006}
1007
1009HePhy::GetRuBandForRx(const WifiTxVector& txVector, uint16_t staId) const
1010{
1011 NS_ASSERT(txVector.IsMu());
1012 HeRu::RuSpec ru = txVector.GetRu(staId);
1013 const auto channelWidth = txVector.GetChannelWidth();
1014 NS_ASSERT(channelWidth <= m_wifiPhy->GetChannelWidth());
1016 channelWidth,
1017 ru.GetRuType(),
1019 // for an RX spectrum, the guard bandwidth is a function of the operating channel width
1020 // and the spectrum width equals the operating channel width
1021 const auto indices = ConvertHeRuSubcarriers(
1022 channelWidth,
1027 {group.front().first, group.back().second},
1029 WifiSpectrumBandInfo ruBandForRx{};
1030 for (const auto& indicesPerSegment : indices)
1031 {
1032 ruBandForRx.indices.emplace_back(indicesPerSegment);
1033 ruBandForRx.frequencies.emplace_back(
1034 m_wifiPhy->ConvertIndicesToFrequencies(indicesPerSegment));
1035 }
1036 return ruBandForRx;
1037}
1038
1040HePhy::GetNonOfdmaBand(const WifiTxVector& txVector, uint16_t staId) const
1041{
1042 NS_ASSERT(txVector.IsUlMu() && (txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE));
1043 const auto channelWidth = txVector.GetChannelWidth();
1044 NS_ASSERT(channelWidth <= m_wifiPhy->GetChannelWidth());
1045
1046 HeRu::RuSpec ru = txVector.GetRu(staId);
1047 const auto nonOfdmaWidth = GetNonOfdmaWidth(ru);
1048
1049 // Find the RU that encompasses the non-OFDMA part of the HE TB PPDU for the STA-ID
1050 HeRu::RuSpec nonOfdmaRu =
1051 HeRu::FindOverlappingRu(channelWidth, ru, HeRu::GetRuType(nonOfdmaWidth));
1052
1054 channelWidth,
1055 nonOfdmaRu.GetRuType(),
1056 nonOfdmaRu.GetPhyIndex(channelWidth,
1058 const auto indices = ConvertHeRuSubcarriers(
1059 channelWidth,
1064 {groupPreamble.front().first, groupPreamble.back().second},
1066 WifiSpectrumBandInfo nonOfdmaBand{};
1067 for (const auto& indicesPerSegment : indices)
1068 {
1069 nonOfdmaBand.indices.emplace_back(indicesPerSegment);
1070 nonOfdmaBand.frequencies.emplace_back(
1071 m_wifiPhy->ConvertIndicesToFrequencies(indicesPerSegment));
1072 }
1073 return nonOfdmaBand;
1074}
1075
1076MHz_u
1078{
1079 if (ru.GetRuType() == HeRu::RU_26_TONE && ru.GetIndex() == 19)
1080 {
1081 // the center 26-tone RU in an 80 MHz channel is not fully covered by
1082 // any 20 MHz channel, but only by an 80 MHz channel
1083 return 80;
1084 }
1085 return std::max<MHz_u>(HeRu::GetBandwidth(ru.GetRuType()), 20);
1086}
1087
1088uint64_t
1090{
1091 return m_currentMuPpduUid;
1092}
1093
1094MHz_u
1096{
1097 auto channelWidth = OfdmPhy::GetMeasurementChannelWidth(ppdu);
1098 /**
1099 * The PHY shall not issue a PHY-RXSTART.indication primitive in response to a PPDU that does
1100 * not overlap the primary channel unless the PHY at an AP receives the HE TB PPDU solicited by
1101 * the AP. For the HE TB PPDU solicited by the AP, the PHY shall issue a PHY-RXSTART.indication
1102 * primitive for a PPDU received in the primary or at the secondary 20 MHz channel, the
1103 * secondary 40 MHz channel, or the secondary 80 MHz channel.
1104 */
1105 if (channelWidth >= 40 && ppdu->GetUid() != m_previouslyTxPpduUid)
1106 {
1107 channelWidth = 20;
1108 }
1109 return channelWidth;
1110}
1111
1112dBm_u
1114{
1115 if (!ppdu)
1116 {
1117 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1118 }
1119
1120 if (!m_obssPdAlgorithm)
1121 {
1122 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1123 }
1124
1125 if (channelType == WIFI_CHANLIST_PRIMARY)
1126 {
1127 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1128 }
1129
1130 const auto ppduBw = ppdu->GetTxVector().GetChannelWidth();
1131 auto obssPdLevel = m_obssPdAlgorithm->GetObssPdLevel();
1132 auto bw = ppduBw;
1133 while (bw > 20)
1134 {
1135 obssPdLevel += 3;
1136 bw /= 2;
1137 }
1138
1139 return std::max(VhtPhy::GetCcaThreshold(ppdu, channelType), obssPdLevel);
1140}
1141
1142void
1144{
1145 NS_LOG_FUNCTION(this);
1146 const auto ccaIndication = GetCcaIndication(ppdu);
1147 const auto per20MHzDurations = GetPer20MHzDurations(ppdu);
1148 if (ccaIndication.has_value())
1149 {
1150 NS_LOG_DEBUG("CCA busy for " << ccaIndication.value().second << " during "
1151 << ccaIndication.value().first.As(Time::S));
1152 NotifyCcaBusy(ccaIndication.value().first, ccaIndication.value().second, per20MHzDurations);
1153 return;
1154 }
1155 if (ppdu)
1156 {
1157 SwitchMaybeToCcaBusy(nullptr);
1158 return;
1159 }
1160 if (per20MHzDurations != m_lastPer20MHzDurations)
1161 {
1162 /*
1163 * 8.3.5.12.3: For Clause 27 PHYs, this primitive is generated when (...) the per20bitmap
1164 * parameter changes.
1165 */
1166 NS_LOG_DEBUG("per-20MHz CCA durations changed");
1167 NotifyCcaBusy(Seconds(0), WIFI_CHANLIST_PRIMARY, per20MHzDurations);
1168 }
1169}
1170
1171void
1173{
1174 NS_LOG_FUNCTION(this << duration << channelType);
1175 NS_LOG_DEBUG("CCA busy for " << channelType << " during " << duration.As(Time::S));
1176 const auto per20MHzDurations = GetPer20MHzDurations(ppdu);
1177 NotifyCcaBusy(duration, channelType, per20MHzDurations);
1178}
1179
1180void
1182 WifiChannelListType channelType,
1183 const std::vector<Time>& per20MHzDurations)
1184{
1185 NS_LOG_FUNCTION(this << duration << channelType);
1186 m_state->SwitchMaybeToCcaBusy(duration, channelType, per20MHzDurations);
1187 m_lastPer20MHzDurations = per20MHzDurations;
1188}
1189
1190std::vector<Time>
1192{
1193 NS_LOG_FUNCTION(this);
1194
1195 /**
1196 * 27.3.20.6.5 Per 20 MHz CCA sensitivity:
1197 * If the operating channel width is greater than 20 MHz and the PHY issues a PHY-CCA.indication
1198 * primitive, the PHY shall set the per20bitmap to indicate the busy/idle status of each 20 MHz
1199 * subchannel.
1200 */
1201 if (m_wifiPhy->GetChannelWidth() < 40)
1202 {
1203 return {};
1204 }
1205
1206 std::vector<Time> per20MhzDurations{};
1209 for (auto index : indices)
1210 {
1211 auto band = m_wifiPhy->GetBand(20, index);
1212 /**
1213 * A signal is present on the 20 MHz subchannel at or above a threshold of –62 dBm at the
1214 * receiver's antenna(s). The PHY shall indicate that the 20 MHz subchannel is busy a period
1215 * aCCATime after the signal starts and shall continue to indicate the 20 MHz subchannel is
1216 * busy while the threshold continues to be exceeded.
1217 */
1218 dBm_u ccaThreshold = -62;
1219 auto delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThreshold, band);
1220
1221 if (ppdu)
1222 {
1223 const MHz_u subchannelMinFreq =
1224 m_wifiPhy->GetFrequency() - (m_wifiPhy->GetChannelWidth() / 2) + (index * 20);
1225 const MHz_u subchannelMaxFreq = subchannelMinFreq + 20;
1226 const auto ppduBw = ppdu->GetTxVector().GetChannelWidth();
1227
1228 if (ppduBw <= m_wifiPhy->GetChannelWidth() &&
1229 ppdu->DoesOverlapChannel(subchannelMinFreq, subchannelMaxFreq))
1230 {
1231 std::optional<double> obssPdLevel{std::nullopt};
1233 {
1234 obssPdLevel = m_obssPdAlgorithm->GetObssPdLevel();
1235 }
1236 switch (static_cast<uint16_t>(ppduBw))
1237 {
1238 case 20:
1239 case 22:
1240 /**
1241 * A 20 MHz non-HT, HT_MF, HT_GF, VHT, or HE PPDU at or above max(–72 dBm, OBSS_
1242 * PDlevel) at the receiver's antenna(s) is present on the 20 MHz subchannel.
1243 * The PHY shall indicate that the 20 MHz subchannel is busy with > 90%
1244 * probability within a period aCCAMidTime.
1245 */
1246 ccaThreshold =
1247 obssPdLevel.has_value() ? std::max(-72.0, obssPdLevel.value()) : -72.0;
1248 band = m_wifiPhy->GetBand(20, index);
1249 break;
1250 case 40:
1251 /**
1252 * The 20 MHz subchannel is in a channel on which a 40 MHz non-HT duplicate,
1253 * HT_MF, HT_GF, VHT or HE PPDU at or above max(–72 dBm, OBSS_PDlevel + 3 dB) at
1254 * the receiver's antenna(s) is present. The PHY shall indicate that the 20 MHz
1255 * subchannel is busy with > 90% probability within a period aCCAMidTime.
1256 */
1257 ccaThreshold =
1258 obssPdLevel.has_value() ? std::max(-72.0, obssPdLevel.value() + 3) : -72.0;
1259 band = m_wifiPhy->GetBand(40, std::floor(index / 2));
1260 break;
1261 case 80:
1262 /**
1263 * The 20 MHz subchannel is in a channel on which an 80 MHz non-HT duplicate,
1264 * VHT or HE PPDU at or above max(–69 dBm, OBSS_PDlevel + 6 dB) at the
1265 * receiver's antenna(s) is present. The PHY shall indicate that the 20 MHz
1266 * subchannel is busy with > 90% probability within a period aCCAMidTime.
1267 */
1268 ccaThreshold =
1269 obssPdLevel.has_value() ? std::max(-69.0, obssPdLevel.value() + 6) : -69.0;
1270 band = m_wifiPhy->GetBand(80, std::floor(index / 4));
1271 break;
1272 case 160:
1273 // Not defined in the standard: keep -62 dBm
1274 break;
1275 default:
1276 NS_ASSERT_MSG(false, "Invalid channel width: " << ppduBw);
1277 }
1278 }
1279 const auto ppduCcaDuration = GetDelayUntilCcaEnd(ccaThreshold, band);
1280 delayUntilCcaEnd = std::max(delayUntilCcaEnd, ppduCcaDuration);
1281 }
1282 per20MhzDurations.push_back(delayUntilCcaEnd);
1283 }
1284
1285 return per20MhzDurations;
1286}
1287
1288uint64_t
1290{
1291 NS_LOG_FUNCTION(this << txVector);
1292 uint64_t uid;
1293 if (txVector.IsUlMu() || txVector.IsTriggerResponding())
1294 {
1295 // Use UID of PPDU containing trigger frame to identify resulting HE TB PPDUs, since the
1296 // latter should immediately follow the former
1298 NS_ASSERT(uid != UINT64_MAX);
1299 }
1300 else
1301 {
1302 uid = m_globalPpduUid++;
1303 }
1304 m_previouslyTxPpduUid = uid; // to be able to identify solicited HE TB PPDUs
1305 return uid;
1306}
1307
1308Time
1310{
1311 auto heConfiguration = m_wifiPhy->GetDevice()->GetHeConfiguration();
1312 NS_ASSERT(heConfiguration);
1313 // DoStartReceivePayload(), which is called when we start receiving the Data field,
1314 // computes the max offset among TB PPDUs based on the begin MU payload RX events,
1315 // which are scheduled by StartReceivePreamble() when starting the reception of the
1316 // HE portion. Therefore, the maximum delay cannot exceed the duration of the
1317 // training fields that are between the start of the HE portion and the start
1318 // of the Data field.
1319 auto maxDelay = GetDuration(WIFI_PPDU_FIELD_TRAINING, txVector);
1320 if (heConfiguration->GetMaxTbPpduDelay().IsStrictlyPositive())
1321 {
1322 maxDelay = Min(maxDelay, heConfiguration->GetMaxTbPpduDelay());
1323 }
1324 return maxDelay;
1325}
1326
1329{
1330 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1331 NS_ASSERT(hePpdu);
1332 HePpdu::TxPsdFlag flag = hePpdu->GetTxPsdFlag();
1333 return GetTxPowerSpectralDensity(txPower, ppdu, flag);
1334}
1335
1339 HePpdu::TxPsdFlag flag) const
1340{
1341 const auto& txVector = ppdu->GetTxVector();
1342 const auto& centerFrequencies = ppdu->GetTxCenterFreqs();
1343 auto channelWidth = txVector.GetChannelWidth();
1344 auto printFrequencies = [](const std::vector<MHz_u>& v) {
1345 std::stringstream ss;
1346 for (const auto& centerFrequency : v)
1347 {
1348 ss << centerFrequency << " ";
1349 }
1350 return ss.str();
1351 };
1352 NS_LOG_FUNCTION(this << printFrequencies(centerFrequencies) << channelWidth << txPower
1353 << txVector);
1354 const auto& puncturedSubchannels = txVector.GetInactiveSubchannels();
1355 if (!puncturedSubchannels.empty())
1356 {
1357 const auto p20Index = m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(20);
1358 const auto& indices =
1360 const auto p20IndexInBitmap = p20Index - *(indices.cbegin());
1361 NS_ASSERT(
1362 !puncturedSubchannels.at(p20IndexInBitmap)); // the primary channel cannot be punctured
1363 }
1364 const auto& txMaskRejectionParams = GetTxMaskRejectionParams();
1365 switch (ppdu->GetType())
1366 {
1367 case WIFI_PPDU_TYPE_UL_MU: {
1368 if (flag == HePpdu::PSD_NON_HE_PORTION)
1369 {
1370 // non-HE portion is sent only on the 20 MHz channels covering the RU
1371 const auto staId = GetStaId(ppdu);
1372 const auto ruWidth = HeRu::GetBandwidth(txVector.GetRu(staId).GetRuType());
1373 channelWidth = (ruWidth < 20) ? 20 : ruWidth;
1376 channelWidth,
1377 txPower,
1378 GetGuardBandwidth(channelWidth),
1379 std::get<0>(txMaskRejectionParams),
1380 std::get<1>(txMaskRejectionParams),
1381 std::get<2>(txMaskRejectionParams),
1382 puncturedSubchannels);
1383 }
1384 else
1385 {
1386 const auto band = GetRuBandForTx(txVector, GetStaId(ppdu)).indices;
1388 centerFrequencies,
1389 channelWidth,
1390 txPower,
1391 GetGuardBandwidth(channelWidth),
1392 band);
1393 }
1394 }
1395 case WIFI_PPDU_TYPE_DL_MU: {
1396 if (flag == HePpdu::PSD_NON_HE_PORTION)
1397 {
1399 centerFrequencies,
1400 channelWidth,
1401 txPower,
1402 GetGuardBandwidth(channelWidth),
1403 std::get<0>(txMaskRejectionParams),
1404 std::get<1>(txMaskRejectionParams),
1405 std::get<2>(txMaskRejectionParams),
1406 puncturedSubchannels);
1407 }
1408 else
1409 {
1411 centerFrequencies,
1412 channelWidth,
1413 txPower,
1414 GetGuardBandwidth(channelWidth),
1415 std::get<0>(txMaskRejectionParams),
1416 std::get<1>(txMaskRejectionParams),
1417 std::get<2>(txMaskRejectionParams),
1418 puncturedSubchannels);
1419 }
1420 }
1421 case WIFI_PPDU_TYPE_SU:
1422 default: {
1423 NS_ASSERT(puncturedSubchannels.empty());
1425 centerFrequencies,
1426 channelWidth,
1427 txPower,
1428 GetGuardBandwidth(channelWidth),
1429 std::get<0>(txMaskRejectionParams),
1430 std::get<1>(txMaskRejectionParams),
1431 std::get<2>(txMaskRejectionParams));
1432 }
1433 }
1434}
1435
1436std::vector<MHz_u>
1438{
1439 NS_LOG_FUNCTION(this << ppdu << staId);
1440 const auto& txVector = ppdu->GetTxVector();
1441 NS_ASSERT(txVector.IsUlMu() && (txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE));
1442 auto centerFrequencies = ppdu->GetTxCenterFreqs();
1443 const auto currentWidth = txVector.GetChannelWidth();
1444
1445 HeRu::RuSpec ru = txVector.GetRu(staId);
1446 const auto nonOfdmaWidth = GetNonOfdmaWidth(ru);
1447 if (nonOfdmaWidth != currentWidth)
1448 {
1449 // Obtain the index of the non-OFDMA portion
1450 HeRu::RuSpec nonOfdmaRu =
1451 HeRu::FindOverlappingRu(currentWidth, ru, HeRu::GetRuType(nonOfdmaWidth));
1452
1453 const MHz_u startingFrequency = centerFrequencies.front() - (currentWidth / 2);
1454 centerFrequencies.front() =
1455 startingFrequency +
1456 nonOfdmaWidth * (nonOfdmaRu.GetPhyIndex(
1457 currentWidth,
1459 1) +
1460 nonOfdmaWidth / 2;
1461 }
1462 return centerFrequencies;
1463}
1464
1465void
1467{
1468 NS_LOG_FUNCTION(this << ppdu);
1469 const auto& txVector = ppdu->GetTxVector();
1470 if (auto mac = m_wifiPhy->GetDevice()->GetMac(); mac && (mac->GetTypeOfStation() == AP))
1471 {
1472 m_currentTxVector = txVector;
1473 }
1474 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU || ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
1475 {
1476 dBm_u nonHeTxPower = m_wifiPhy->GetTxPowerForTransmission(ppdu) + m_wifiPhy->GetTxGain();
1477
1478 // temporarily set WifiPpdu flag to PSD_HE_PORTION for correct calculation of TX power for
1479 // the HE portion
1480 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1481 NS_ASSERT(hePpdu);
1482 hePpdu->SetTxPsdFlag(HePpdu::PSD_HE_PORTION);
1484 hePpdu->SetTxPsdFlag(HePpdu::PSD_NON_HE_PORTION);
1485
1486 // non-HE portion
1487 auto nonHePortionDuration = ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU
1490 auto nonHeTxPowerSpectrum =
1492 Transmit(nonHePortionDuration,
1493 ppdu,
1494 nonHeTxPower,
1495 nonHeTxPowerSpectrum,
1496 "non-HE portion transmission");
1497
1498 // HE portion
1499 auto hePortionDuration = ppdu->GetTxDuration() - nonHePortionDuration;
1500 auto heTxPowerSpectrum =
1502 Simulator::Schedule(nonHePortionDuration,
1504 this,
1505 ppdu,
1506 heTxPower,
1507 heTxPowerSpectrum,
1508 hePortionDuration);
1509 }
1510 else
1511 {
1512 VhtPhy::StartTx(ppdu);
1513 }
1514}
1515
1516void
1518 dBm_u txPower,
1519 Ptr<SpectrumValue> txPowerSpectrum,
1520 Time hePortionDuration)
1521{
1522 NS_LOG_FUNCTION(this << ppdu << txPower << hePortionDuration);
1523 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1524 NS_ASSERT(hePpdu);
1525 hePpdu->SetTxPsdFlag(HePpdu::PSD_HE_PORTION);
1526 Transmit(hePortionDuration, ppdu, txPower, txPowerSpectrum, "HE portion transmission");
1527}
1528
1529Time
1531 const WifiTxVector& txVector,
1532 WifiPhyBand band) const
1533{
1534 if (txVector.IsUlMu())
1535 {
1537 return ConvertLSigLengthToHeTbPpduDuration(txVector.GetLength(), txVector, band);
1538 }
1539
1540 Time maxDuration = Seconds(0);
1541 for (auto& staIdPsdu : psduMap)
1542 {
1543 if (txVector.IsDlMu())
1544 {
1546 NS_ABORT_MSG_IF(!txVector.GetHeMuUserInfoMap().contains(staIdPsdu.first),
1547 "STA-ID in psduMap (" << staIdPsdu.first
1548 << ") should be referenced in txVector");
1549 }
1550 Time current = WifiPhy::CalculateTxDuration(staIdPsdu.second->GetSize(),
1551 txVector,
1552 band,
1553 staIdPsdu.first);
1554 if (current > maxDuration)
1555 {
1556 maxDuration = current;
1557 }
1558 }
1559 NS_ASSERT(maxDuration.IsStrictlyPositive());
1560 return maxDuration;
1561}
1562
1563void
1565{
1566 for (uint8_t i = 0; i < 12; ++i)
1567 {
1568 GetHeMcs(i);
1569 }
1570}
1571
1573HePhy::GetHeMcs(uint8_t index)
1574{
1575#define CASE(x) \
1576 case x: \
1577 return GetHeMcs##x();
1578
1579 switch (index)
1580 {
1581 CASE(0)
1582 CASE(1)
1583 CASE(2)
1584 CASE(3)
1585 CASE(4)
1586 CASE(5)
1587 CASE(6)
1588 CASE(7)
1589 CASE(8)
1590 CASE(9)
1591 CASE(10)
1592 CASE(11)
1593 default:
1594 NS_ABORT_MSG("Inexistent index (" << +index << ") requested for HE");
1595 return WifiMode();
1596 }
1597#undef CASE
1598}
1599
1600#define GET_HE_MCS(x) \
1601 WifiMode HePhy::GetHeMcs##x() \
1602 { \
1603 static WifiMode mcs = CreateHeMcs(x); \
1604 return mcs; \
1605 }
1606
1607GET_HE_MCS(0)
1608GET_HE_MCS(1)
1609GET_HE_MCS(2)
1610GET_HE_MCS(3)
1611GET_HE_MCS(4)
1612GET_HE_MCS(5)
1613GET_HE_MCS(6)
1614GET_HE_MCS(7)
1615GET_HE_MCS(8)
1616GET_HE_MCS(9)
1617GET_HE_MCS(10)
1618GET_HE_MCS(11)
1619#undef GET_HE_MCS
1620
1621WifiMode
1623{
1624 NS_ASSERT_MSG(index <= 11, "HeMcs index must be <= 11!");
1625 return WifiModeFactory::CreateWifiMcs("HeMcs" + std::to_string(index),
1626 index,
1628 false,
1635}
1636
1638HePhy::GetCodeRate(uint8_t mcsValue)
1639{
1640 switch (mcsValue)
1641 {
1642 case 10:
1643 return WIFI_CODE_RATE_3_4;
1644 case 11:
1645 return WIFI_CODE_RATE_5_6;
1646 default:
1647 return VhtPhy::GetCodeRate(mcsValue);
1648 }
1649}
1650
1651uint16_t
1653{
1654 switch (mcsValue)
1655 {
1656 case 10:
1657 case 11:
1658 return 1024;
1659 default:
1660 return VhtPhy::GetConstellationSize(mcsValue);
1661 }
1662}
1663
1664uint64_t
1665HePhy::GetPhyRate(uint8_t mcsValue, MHz_u channelWidth, Time guardInterval, uint8_t nss)
1666{
1667 const auto codeRate = GetCodeRate(mcsValue);
1668 const auto dataRate = GetDataRate(mcsValue, channelWidth, guardInterval, nss);
1669 return HtPhy::CalculatePhyRate(codeRate, dataRate);
1670}
1671
1672uint64_t
1673HePhy::GetPhyRateFromTxVector(const WifiTxVector& txVector, uint16_t staId /* = SU_STA_ID */)
1674{
1675 auto bw = txVector.GetChannelWidth();
1676 if (txVector.IsMu())
1677 {
1678 bw = HeRu::GetBandwidth(txVector.GetRu(staId).GetRuType());
1679 }
1680 return HePhy::GetPhyRate(txVector.GetMode(staId).GetMcsValue(),
1681 bw,
1682 txVector.GetGuardInterval(),
1683 txVector.GetNss(staId));
1684}
1685
1686uint64_t
1687HePhy::GetDataRateFromTxVector(const WifiTxVector& txVector, uint16_t staId /* = SU_STA_ID */)
1688{
1689 auto bw = txVector.GetChannelWidth();
1690 if (txVector.IsMu())
1691 {
1692 bw = HeRu::GetBandwidth(txVector.GetRu(staId).GetRuType());
1693 }
1694 return HePhy::GetDataRate(txVector.GetMode(staId).GetMcsValue(),
1695 bw,
1696 txVector.GetGuardInterval(),
1697 txVector.GetNss(staId));
1698}
1699
1700uint64_t
1701HePhy::GetDataRate(uint8_t mcsValue, MHz_u channelWidth, Time guardInterval, uint8_t nss)
1702{
1703 [[maybe_unused]] const auto gi = guardInterval.GetNanoSeconds();
1704 NS_ASSERT((gi == 800) || (gi == 1600) || (gi == 3200));
1705 NS_ASSERT(nss <= 8);
1706 return HtPhy::CalculateDataRate(GetSymbolDuration(guardInterval),
1707 GetUsableSubcarriers(channelWidth),
1708 static_cast<uint16_t>(log2(GetConstellationSize(mcsValue))),
1710 nss);
1711}
1712
1713uint16_t
1715{
1716 switch (static_cast<uint16_t>(channelWidth))
1717 {
1718 case 2: // 26-tone RU
1719 return 24;
1720 case 4: // 52-tone RU
1721 return 48;
1722 case 8: // 106-tone RU
1723 return 102;
1724 case 20:
1725 default:
1726 return 234;
1727 case 40:
1728 return 468;
1729 case 80:
1730 return 980;
1731 case 160:
1732 return 1960;
1733 }
1734}
1735
1736Time
1738{
1739 return NanoSeconds(12800) + guardInterval;
1740}
1741
1742uint64_t
1744{
1745 const auto codeRate = GetCodeRate(mcsValue);
1746 const auto constellationSize = GetConstellationSize(mcsValue);
1747 return CalculateNonHtReferenceRate(codeRate, constellationSize);
1748}
1749
1750uint64_t
1751HePhy::CalculateNonHtReferenceRate(WifiCodeRate codeRate, uint16_t constellationSize)
1752{
1753 uint64_t dataRate;
1754 switch (constellationSize)
1755 {
1756 case 1024:
1757 if (codeRate == WIFI_CODE_RATE_3_4 || codeRate == WIFI_CODE_RATE_5_6)
1758 {
1759 dataRate = 54000000;
1760 }
1761 else
1762 {
1763 NS_FATAL_ERROR("Trying to get reference rate for a MCS with wrong combination of "
1764 "coding rate and modulation");
1765 }
1766 break;
1767 default:
1768 dataRate = VhtPhy::CalculateNonHtReferenceRate(codeRate, constellationSize);
1769 }
1770 return dataRate;
1771}
1772
1773bool
1774HePhy::IsAllowed(const WifiTxVector& /*txVector*/)
1775{
1776 return true;
1777}
1778
1781{
1782 uint16_t staId = SU_STA_ID;
1783
1784 if (IsUlMu(txVector.GetPreambleType()))
1785 {
1786 NS_ASSERT(txVector.GetHeMuUserInfoMap().size() == 1);
1787 staId = txVector.GetHeMuUserInfoMap().begin()->first;
1788 }
1789
1790 return WifiConstPsduMap({{staId, psdu}});
1791}
1792
1795{
1796 return 6500631;
1797}
1798
1799bool
1801{
1802 /*
1803 * The PHY shall not issue a PHY-RXSTART.indication primitive in response to a PPDU
1804 * that does not overlap the primary channel, unless the PHY at an AP receives the
1805 * HE TB PPDU solicited by the AP. For the HE TB PPDU solicited by the AP, the PHY
1806 * shall issue a PHY-RXSTART.indication primitive for a PPDU received in the primary
1807 * or at the secondary 20 MHz channel, the secondary 40 MHz channel, or the secondary
1808 * 80 MHz channel.
1809 */
1810 Ptr<WifiMac> mac = m_wifiPhy->GetDevice() ? m_wifiPhy->GetDevice()->GetMac() : nullptr;
1811 if (ppdu->GetTxVector().IsUlMu() && mac && mac->GetTypeOfStation() == AP)
1812 {
1813 return true;
1814 }
1815 return VhtPhy::CanStartRx(ppdu);
1816}
1817
1820{
1821 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
1822 {
1823 Ptr<const WifiPpdu> rxPpdu;
1824 if ((m_trigVectorExpirationTime.has_value()) &&
1826 {
1827 // We only copy if the AP that is expecting a HE TB PPDU, since the content
1828 // of the TXVECTOR is reconstructed from the TRIGVECTOR, hence the other RX
1829 // PHYs should not have this information.
1830 rxPpdu = ppdu->Copy();
1831 }
1832 else
1833 {
1834 rxPpdu = ppdu;
1835 }
1836 auto hePpdu = DynamicCast<const HePpdu>(rxPpdu);
1837 NS_ASSERT(hePpdu);
1838 hePpdu->UpdateTxVectorForUlMu(m_trigVector);
1839 return rxPpdu;
1840 }
1841 return VhtPhy::GetRxPpduFromTxPpdu(ppdu);
1842}
1843
1844std::vector<WifiSpectrumBandIndices>
1846 MHz_u guardBandwidth,
1847 const std::vector<MHz_u>& centerFrequencies,
1848 MHz_u totalWidth,
1849 Hz_u subcarrierSpacing,
1850 HeRu::SubcarrierRange subcarrierRange,
1851 uint8_t bandIndex)
1852{
1853 NS_ASSERT_MSG(bandWidth <= totalWidth,
1854 "Bandwidth (" << bandWidth << ") cannot exceed total operating channel width ("
1855 << totalWidth << ")");
1856 std::vector<WifiSpectrumBandIndices> convertedSubcarriers{};
1857 guardBandwidth /= centerFrequencies.size();
1858 const auto nGuardBands =
1859 static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / subcarrierSpacing) + 0.5);
1860 if (bandWidth > (totalWidth / centerFrequencies.size()))
1861 {
1862 NS_ASSERT(bandIndex == 0);
1863 bandWidth /= centerFrequencies.size();
1864 }
1865 uint32_t centerFrequencyIndex = 0;
1866 switch (static_cast<uint16_t>(bandWidth))
1867 {
1868 case 20:
1869 centerFrequencyIndex = (nGuardBands / 2) + 6 + 122;
1870 break;
1871 case 40:
1872 centerFrequencyIndex = (nGuardBands / 2) + 12 + 244;
1873 break;
1874 case 80:
1875 centerFrequencyIndex = (nGuardBands / 2) + 12 + 500;
1876 break;
1877 case 160:
1878 centerFrequencyIndex = (nGuardBands / 2) + 12 + 1012;
1879 break;
1880 default:
1881 NS_FATAL_ERROR("ChannelWidth " << bandWidth << " unsupported");
1882 break;
1883 }
1884
1885 const auto numBandsInBand = static_cast<size_t>(bandWidth * 1e6 / subcarrierSpacing);
1886 centerFrequencyIndex += numBandsInBand * bandIndex;
1887 // start and stop subcarriers might be in different frequency segments, hence define a low and a
1888 // high center frequency
1889 auto centerFrequencyIndexLow = centerFrequencyIndex;
1890 auto centerFrequencyIndexHigh = centerFrequencyIndex;
1891 if (centerFrequencies.size() > 1)
1892 {
1893 const auto numBandsBetweenSegments =
1895 totalWidth,
1896 subcarrierSpacing);
1897 if (subcarrierRange.first > 0)
1898 {
1899 centerFrequencyIndexLow += numBandsBetweenSegments;
1900 }
1901 if (subcarrierRange.second > 0)
1902 {
1903 centerFrequencyIndexHigh += numBandsBetweenSegments;
1904 }
1905 }
1906 convertedSubcarriers.emplace_back(centerFrequencyIndexLow + subcarrierRange.first,
1907 centerFrequencyIndexHigh + subcarrierRange.second);
1908 ++bandIndex;
1909 return convertedSubcarriers;
1910}
1911
1912} // namespace ns3
1913
1914namespace
1915{
1916
1917/**
1918 * Constructor class for HE modes
1919 */
1929
1930} // namespace
#define Max(a, b)
#define Min(a, b)
Constructor class for HE modes.
Definition he-phy.cc:1921
bool IsNull() const
Check for null implementation.
Definition callback.h:555
std::optional< WifiTxVector > m_trigVector
the TRIGVECTOR
Definition he-phy.h:561
Time GetLSigDuration(WifiPreamble preamble) const override
Definition he-phy.cc:177
virtual Time CalculateNonHeDurationForHeTb(const WifiTxVector &txVector) const
Definition he-phy.cc:294
static uint64_t GetDataRate(uint8_t mcsValue, MHz_u channelWidth, Time guardInterval, uint8_t nss)
Return the data rate corresponding to the supplied HE MCS index, channel width, guard interval,...
Definition he-phy.cc:1701
static Time ConvertLSigLengthToHeTbPpduDuration(uint16_t length, const WifiTxVector &txVector, WifiPhyBand band)
Definition he-phy.cc:280
static uint64_t GetPhyRate(uint8_t mcsValue, MHz_u channelWidth, Time guardInterval, uint8_t nss)
Return the PHY rate corresponding to the supplied HE MCS index, channel width, guard interval,...
Definition he-phy.cc:1665
uint64_t GetCurrentHeTbPpduUid() const
Definition he-phy.cc:1089
Ptr< Event > DoGetEvent(Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPowersW) override
Get the event corresponding to the incoming PPDU.
Definition he-phy.cc:450
void CancelAllEvents() override
Cancel and clear all running events.
Definition he-phy.cc:405
void SetObssPdAlgorithm(const Ptr< ObssPdAlgorithm > algorithm)
Sets the OBSS-PD algorithm.
Definition he-phy.cc:694
static void InitializeModes()
Initialize all HE modes.
Definition he-phy.cc:1564
void DoAbortCurrentReception(WifiPhyRxfailureReason reason) override
Perform amendment-specific actions before aborting the current reception.
Definition he-phy.cc:417
WifiSpectrumBandInfo GetRuBandForRx(const WifiTxVector &txVector, uint16_t staId) const
Get the band in the RX spectrum associated with the RU used by the PSDU transmitted to/by a given STA...
Definition he-phy.cc:1009
void StartReceiveMuPayload(Ptr< Event > event)
Start receiving the PSDU (i.e.
Definition he-phy.cc:924
virtual PhyFieldRxStatus ProcessSigB(Ptr< Event > event, PhyFieldRxStatus status)
Process SIG-B, perform amendment-specific actions, and provide an updated status of the reception.
Definition he-phy.cc:721
virtual Time CalculateNonHeDurationForHeMu(const WifiTxVector &txVector) const
Definition he-phy.cc:303
std::optional< WifiTxVector > m_currentTxVector
If the STA is an AP STA, this holds the TXVECTOR of the PPDU that has been sent.
Definition he-phy.h:563
Time GetSigBDuration(const WifiTxVector &txVector) const override
Definition he-phy.cc:228
static WifiMode CreateHeMcs(uint8_t index)
Create and return the HE MCS corresponding to the provided index.
Definition he-phy.cc:1622
virtual uint32_t GetSigBSize(const WifiTxVector &txVector) const
Definition he-phy.cc:212
static WifiMode GetHeMcs(uint8_t index)
Return the HE MCS corresponding to the provided index.
Definition he-phy.cc:1573
void BuildModeList() override
Build mode list.
Definition he-phy.cc:96
WifiConstPsduMap GetWifiConstPsduMap(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) const override
Get a WifiConstPsduMap from a PSDU and the TXVECTOR to use to send the PSDU.
Definition he-phy.cc:1780
static uint64_t CalculateNonHtReferenceRate(WifiCodeRate codeRate, uint16_t constellationSize)
Return the rate (in bps) of the non-HT Reference Rate which corresponds to the supplied code rate and...
Definition he-phy.cc:1751
void StartTxHePortion(Ptr< const WifiPpdu > ppdu, dBm_u txPower, Ptr< SpectrumValue > txPowerSpectrum, Time hePortionDuration)
Start the transmission of the HE portion of the MU PPDU.
Definition he-phy.cc:1517
bool CanStartRx(Ptr< const WifiPpdu > ppdu) const override
Determine whether the PHY shall issue a PHY-RXSTART.indication primitive in response to a given PPDU.
Definition he-phy.cc:1800
void SetEndOfHeSigACallback(EndOfHeSigACallback callback)
Set a callback for a end of HE-SIG-A.
Definition he-phy.cc:706
uint64_t m_previouslyTxPpduUid
UID of the previously sent PPDU, used by AP to recognize response HE TB PPDUs.
Definition he-phy.h:552
static WifiCodeRate GetCodeRate(uint8_t mcsValue)
Return the coding rate corresponding to the supplied HE MCS index.
Definition he-phy.cc:1638
void StartTx(Ptr< const WifiPpdu > ppdu) override
This function is called by SpectrumWifiPhy to send the PPDU while performing amendment-specific actio...
Definition he-phy.cc:1466
PhyFieldRxStatus ProcessSig(Ptr< Event > event, PhyFieldRxStatus status, WifiPpduField field) override
Process SIG-A or SIG-B, perform amendment-specific actions, and provide an updated status of the rece...
Definition he-phy.cc:583
EndOfHeSigACallback m_endOfHeSigACallback
end of HE-SIG-A callback
Definition he-phy.h:560
Ptr< const WifiPsdu > GetAddressedPsduInPpdu(Ptr< const WifiPpdu > ppdu) const override
Get the PSDU addressed to that PHY in a PPDU (useful for MU PPDU).
Definition he-phy.cc:538
WifiMode GetSigMode(WifiPpduField field, const WifiTxVector &txVector) const override
Get the WifiMode for the SIG field specified by the PPDU field.
Definition he-phy.cc:109
const PpduFormats & GetPpduFormats() const override
Return the PPDU formats of the PHY.
Definition he-phy.cc:171
uint64_t ObtainNextUid(const WifiTxVector &txVector) override
Obtain the next UID for the PPDU to transmit.
Definition he-phy.cc:1289
Time CalculateTxDuration(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, WifiPhyBand band) const override
Definition he-phy.cc:1530
static uint64_t GetPhyRateFromTxVector(const WifiTxVector &txVector, uint16_t staId=SU_STA_ID)
Return the PHY rate corresponding to the supplied TXVECTOR for the STA-ID.
Definition he-phy.cc:1673
Ptr< ObssPdAlgorithm > m_obssPdAlgorithm
OBSS-PD algorithm.
Definition he-phy.h:636
dBm_u GetCcaThreshold(const Ptr< const WifiPpdu > ppdu, WifiChannelListType channelType) const override
Return the CCA threshold for a given channel type.
Definition he-phy.cc:1113
std::pair< MHz_u, WifiSpectrumBandInfo > GetChannelWidthAndBand(const WifiTxVector &txVector, uint16_t staId) const override
Get the channel width and band to use (will be overloaded by child classes).
Definition he-phy.cc:965
MHz_u GetMeasurementChannelWidth(const Ptr< const WifiPpdu > ppdu) const override
Return the channel width used to measure the RSSI.
Definition he-phy.cc:1095
Ptr< ObssPdAlgorithm > GetObssPdAlgorithm() const
Gets the OBSS-PD algorithm.
Definition he-phy.cc:700
uint8_t GetBssColor() const
Definition he-phy.cc:550
static Time GetValidPpduDuration(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Given a PPDU duration value, the TXVECTOR used to transmit the PPDU and the PHY band,...
Definition he-phy.cc:248
uint8_t GetNumberBccEncoders(const WifiTxVector &txVector) const override
Definition he-phy.cc:313
Time GetMaxDelayPpduSameUid(const WifiTxVector &txVector) override
Obtain the maximum time between two PPDUs with the same UID to consider they are identical and their ...
Definition he-phy.cc:1309
void HandleRxPpduWithSameContent(Ptr< Event > event, Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPower) override
Handle reception of a PPDU that carries the same content of another PPDU.
Definition he-phy.cc:516
static bool IsAllowed(const WifiTxVector &txVector)
Check whether the combination in TXVECTOR is allowed.
Definition he-phy.cc:1774
std::size_t m_rxHeTbPpdus
Number of successfully received HE TB PPDUS.
Definition he-phy.h:635
static std::vector< WifiSpectrumBandIndices > ConvertHeRuSubcarriers(MHz_u bandWidth, MHz_u guardBandwidth, const std::vector< MHz_u > &centerFrequencies, MHz_u totalWidth, Hz_u subcarrierSpacing, HeRu::SubcarrierRange subcarrierRange, uint8_t bandIndex=0)
Definition he-phy.cc:1845
~HePhy() override
Destructor for HE PHY.
Definition he-phy.cc:90
Ptr< WifiPpdu > BuildPpdu(const WifiConstPsduMap &psdus, const WifiTxVector &txVector, Time ppduDuration) override
Build amendment-specific PPDU.
Definition he-phy.cc:343
void NotifyEndOfHeSigA(HeSigAParameters params)
Fire a EndOfHeSigA callback (if connected) once HE-SIG-A field has been received.
Definition he-phy.cc:712
Ptr< SpectrumValue > GetTxPowerSpectralDensity(Watt_u txPower, Ptr< const WifiPpdu > ppdu) const override
Definition he-phy.cc:1328
void RxPayloadSucceeded(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, uint16_t staId, const std::vector< bool > &statusPerMpdu) override
Perform amendment-specific actions when the payload is successfully received.
Definition he-phy.cc:852
uint64_t m_currentMuPpduUid
UID of the HE MU or HE TB PPDU being received.
Definition he-phy.h:554
uint32_t GetMaxPsduSize() const override
Get the maximum PSDU size in bytes.
Definition he-phy.cc:1794
static const PpduFormats m_hePpduFormats
HE PPDU formats.
Definition he-phy.h:633
static uint64_t GetDataRateFromTxVector(const WifiTxVector &txVector, uint16_t staId=SU_STA_ID)
Return the data rate corresponding to the supplied TXVECTOR for the STA-ID.
Definition he-phy.cc:1687
std::map< uint16_t, EventId > m_beginMuPayloadRxEvents
the beginning of the MU payload reception events (indexed by STA-ID)
Definition he-phy.h:557
std::vector< Time > GetPer20MHzDurations(const Ptr< const WifiPpdu > ppdu)
Compute the per-20 MHz CCA durations vector that indicates for how long each 20 MHz subchannel (corre...
Definition he-phy.cc:1191
void RxPayloadFailed(Ptr< const WifiPsdu > psdu, double snr, const WifiTxVector &txVector) override
Perform amendment-specific actions when the payload is unsuccessfuly received.
Definition he-phy.cc:870
Ptr< const WifiPpdu > GetRxPpduFromTxPpdu(Ptr< const WifiPpdu > ppdu) override
The WifiPpdu from the TX PHY is received by each RX PHY attached to the same channel.
Definition he-phy.cc:1819
HePhy(bool buildModeList=true)
Constructor for HE PHY.
Definition he-phy.cc:70
bool IsConfigSupported(Ptr< const WifiPpdu > ppdu) const override
Checks if the signaled configuration (excluding bandwidth) is supported by the PHY.
Definition he-phy.cc:743
uint16_t GetStaId(const Ptr< const WifiPpdu > ppdu) const override
Return the STA ID that has been assigned to the station this PHY belongs to.
Definition he-phy.cc:565
static Time GetSymbolDuration(Time guardInterval)
Definition he-phy.cc:1737
void SetTrigVector(const WifiTxVector &trigVector, Time validity)
Set the TRIGVECTOR and the associated expiration time.
Definition he-phy.cc:328
static std::pair< uint16_t, Time > ConvertHeTbPpduDurationToLSigLength(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Compute the L-SIG length value corresponding to the given HE TB PPDU duration.
Definition he-phy.cc:261
static uint64_t GetNonHtReferenceRate(uint8_t mcsValue)
Calculate the rate in bps of the non-HT Reference Rate corresponding to the supplied HE MCS index.
Definition he-phy.cc:1743
WifiMode GetSigBMode(const WifiTxVector &txVector) const override
Definition he-phy.cc:138
void SwitchMaybeToCcaBusy(const Ptr< const WifiPpdu > ppdu) override
Check if PHY state should move to CCA busy state based on current state of interference tracker.
Definition he-phy.cc:1143
Time DoStartReceivePayload(Ptr< Event > event) override
Start receiving the PSDU (i.e.
Definition he-phy.cc:782
void StartReceivePreamble(Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPowersW, Time rxDuration) override
Start receiving the PHY preamble of a PPDU (i.e.
Definition he-phy.cc:355
virtual PhyFieldRxStatus ProcessSigA(Ptr< Event > event, PhyFieldRxStatus status)
Process SIG-A, perform amendment-specific actions, and provide an updated status of the reception.
Definition he-phy.cc:600
std::optional< Time > m_trigVectorExpirationTime
expiration time of the TRIGVECTOR
Definition he-phy.h:562
void DoEndReceivePayload(Ptr< const WifiPpdu > ppdu) override
Perform amendment-specific actions at the end of the reception of the payload.
Definition he-phy.cc:880
void DoResetReceive(Ptr< Event > event) override
Perform amendment-specific actions before resetting PHY at the end of the PPDU under reception after ...
Definition he-phy.cc:435
WifiMode GetSigAMode() const override
Definition he-phy.cc:132
std::vector< MHz_u > GetCenterFrequenciesForNonHePart(const Ptr< const WifiPpdu > ppdu, uint16_t staId) const
Get the center frequency per segment of the non-HE portion of the current PPDU for the given STA-ID.
Definition he-phy.cc:1437
Time GetSigADuration(WifiPreamble preamble) const override
Definition he-phy.cc:204
WifiSpectrumBandInfo GetNonOfdmaBand(const WifiTxVector &txVector, uint16_t staId) const
Get the band used to transmit the non-OFDMA part of an HE TB PPDU.
Definition he-phy.cc:1040
MHz_u GetNonOfdmaWidth(HeRu::RuSpec ru) const
Get the width of the non-OFDMA portion of an HE TB PPDU.
Definition he-phy.cc:1077
Time GetTrainingDuration(const WifiTxVector &txVector, uint8_t nDataLtf, uint8_t nExtensionLtf=0) const override
Definition he-phy.cc:183
std::vector< Time > m_lastPer20MHzDurations
Hold the last per-20 MHz CCA durations vector.
Definition he-phy.h:637
void NotifyCcaBusy(const Ptr< const WifiPpdu > ppdu, Time duration, WifiChannelListType channelType) override
Notify PHY state helper to switch to CCA busy state,.
Definition he-phy.cc:1172
static uint16_t GetConstellationSize(uint8_t mcsValue)
Return the constellation size corresponding to the supplied HE MCS index.
Definition he-phy.cc:1652
WifiSpectrumBandInfo GetRuBandForTx(const WifiTxVector &txVector, uint16_t staId) const
Get the band in the TX spectrum associated with the RU used by the PSDU transmitted to/by a given STA...
Definition he-phy.cc:979
TxPsdFlag
The transmit power spectral density flag, namely used to correctly build PSDs for pre-HE and HE porti...
Definition he-ppdu.h:104
@ PSD_HE_PORTION
HE portion of an HE PPDU.
Definition he-ppdu.h:106
@ PSD_NON_HE_PORTION
Non-HE portion of an HE PPDU.
Definition he-ppdu.h:105
static uint32_t GetSigBFieldSize(MHz_u channelWidth, const RuAllocation &ruAllocation, bool sigBCompression, std::size_t numMuMimoUsers)
Get variable length HE SIG-B field size.
Definition he-ppdu.cc:629
RU Specification.
Definition he-ru.h:57
std::size_t GetIndex() const
Get the RU index.
Definition he-ru.cc:454
RuType GetRuType() const
Get the RU type.
Definition he-ru.cc:447
std::size_t GetPhyIndex(MHz_u bw, uint8_t p20Index) const
Get the RU PHY index.
Definition he-ru.cc:468
static MHz_u GetBandwidth(RuType ruType)
Get the approximate bandwidth occupied by a RU.
Definition he-ru.cc:756
static RuType GetRuType(MHz_u bandwidth)
Get the RU corresponding to the approximate bandwidth.
Definition he-ru.cc:781
static SubcarrierGroup GetSubcarrierGroup(MHz_u bw, RuType ruType, std::size_t phyIndex)
Get the subcarrier group of the RU having the given PHY index among all the RUs of the given type (nu...
Definition he-ru.cc:580
std::vector< SubcarrierRange > SubcarrierGroup
a vector of subcarrier ranges defining a subcarrier group
Definition he-ru.h:46
static RuSpec FindOverlappingRu(MHz_u bw, RuSpec referenceRu, RuType searchedRuType)
Find the RU allocation of the given RU type overlapping the given reference RU allocation.
Definition he-ru.cc:678
std::pair< int16_t, int16_t > SubcarrierRange
(lowest index, highest index) pair defining a subcarrier range
Definition he-ru.h:43
@ RU_26_TONE
Definition he-ru.h:33
static uint64_t CalculatePhyRate(WifiCodeRate codeRate, uint64_t dataRate)
Return the PHY rate corresponding to the supplied code rate and data rate.
Definition ht-phy.cc:651
uint8_t m_bssMembershipSelector
the BSS membership selector
Definition ht-phy.h:544
uint8_t m_maxMcsIndexPerSs
the maximum MCS index per spatial stream as defined by the standard
Definition ht-phy.h:542
static uint64_t CalculateDataRate(Time symbolDuration, uint16_t usableSubCarriers, uint16_t numberOfBitsPerSubcarrier, double codingRate, uint8_t nss)
Calculates data rate from the supplied parameters.
Definition ht-phy.cc:700
static double GetCodeRatio(WifiCodeRate codeRate)
Convert WifiCodeRate to a ratio, e.g., code ratio of WIFI_CODE_RATE_1_2 is 0.5.
Definition ht-phy.cc:666
uint8_t m_maxSupportedMcsIndexPerSs
the maximum supported MCS index per spatial stream
Definition ht-phy.h:543
static uint16_t GetUsableSubcarriers()
Definition ofdm-phy.cc:624
Ptr< const WifiPpdu > GetRxPpduFromTxPpdu(Ptr< const WifiPpdu > ppdu) override
The WifiPpdu from the TX PHY is received by each RX PHY attached to the same channel.
Definition ofdm-phy.cc:681
MHz_u GetMeasurementChannelWidth(const Ptr< const WifiPpdu > ppdu) const override
Return the channel width used to measure the RSSI.
Definition ofdm-phy.cc:658
void NotifyPayloadBegin(const WifiTxVector &txVector, const Time &payloadDuration)
Fire the trace indicating that the PHY is starting to receive the payload of a PPDU.
virtual void HandleRxPpduWithSameContent(Ptr< Event > event, Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPower)
Handle reception of a PPDU that carries the same content of another PPDU.
MHz_u GetGuardBandwidth(MHz_u currentChannelWidth) const
Ptr< WifiPhyStateHelper > m_state
Pointer to WifiPhyStateHelper of the WifiPhy (to make it reachable for child classes)
Definition phy-entity.h:940
virtual Time DoStartReceivePayload(Ptr< Event > event)
Start receiving the PSDU (i.e.
virtual void StartReceivePreamble(Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPowersW, Time rxDuration)
Start receiving the PHY preamble of a PPDU (i.e.
void Transmit(Time txDuration, Ptr< const WifiPpdu > ppdu, dBm_u txPower, Ptr< SpectrumValue > txPowerSpectrum, const std::string &type)
This function prepares most of the WifiSpectrumSignalParameters parameters and invokes SpectrumWifiPh...
const std::map< std::pair< uint64_t, WifiPreamble >, Ptr< Event > > & GetCurrentPreambleEvents() const
Get the map of current preamble events (stored in WifiPhy).
std::map< UidStaIdPair, SignalNoiseDbm > m_signalNoiseMap
Map of the latest signal power and noise power in dBm (noise power includes the noise figure)
Definition phy-entity.h:961
Watt_u GetRxPowerForPpdu(Ptr< Event > event) const
Obtain the received power for a given band.
Ptr< WifiPhy > m_wifiPhy
Pointer to the owning WifiPhy.
Definition phy-entity.h:939
std::vector< EventId > m_endOfMpduEvents
the end of MPDU events (only used for A-MPDUs)
Definition phy-entity.h:946
virtual void CancelAllEvents()
Cancel and clear all running events.
virtual void DoAbortCurrentReception(WifiPhyRxfailureReason reason)
Perform amendment-specific actions before aborting the current reception.
void EndReceivePayload(Ptr< Event > event)
The last symbol of the PPDU has arrived.
std::map< WifiPreamble, std::vector< WifiPpduField > > PpduFormats
A map of PPDU field elements per preamble type.
Definition phy-entity.h:529
virtual std::pair< MHz_u, WifiSpectrumBandInfo > GetChannelWidthAndBand(const WifiTxVector &txVector, uint16_t staId) const
Get the channel width and band to use (will be overloaded by child classes).
static uint64_t m_globalPpduUid
Global counter of the PPDU UID.
Definition phy-entity.h:964
std::vector< EventId > m_endRxPayloadEvents
the end of receive events (only one unless UL MU reception)
Definition phy-entity.h:950
virtual Ptr< Event > DoGetEvent(Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPowersW)
Get the event corresponding to the incoming PPDU.
Time GetDelayUntilCcaEnd(dBm_u threshold, const WifiSpectrumBandInfo &band)
Return the delay until CCA busy is ended for a given sensitivity threshold and a given band.
Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector) const
void NotifyInterferenceRxEndAndClear(bool reset)
Notify WifiPhy's InterferenceHelper of the end of the reception, clear maps and end of MPDU event,...
std::map< UidStaIdPair, std::vector< bool > > m_statusPerMpduMap
Map of the current reception status per MPDU that is filled in as long as MPDUs are being processed b...
Definition phy-entity.h:958
virtual bool CanStartRx(Ptr< const WifiPpdu > ppdu) const
Determine whether the PHY shall issue a PHY-RXSTART.indication primitive in response to a given PPDU.
virtual void StartTx(Ptr< const WifiPpdu > ppdu)
This function is called by SpectrumWifiPhy to send the PPDU while performing amendment-specific actio...
virtual uint16_t GetStaId(const Ptr< const WifiPpdu > ppdu) const
Return the STA ID that has been assigned to the station this PHY belongs to.
virtual bool IsModeSupported(WifiMode mode) const
Check if the WifiMode is supported.
Definition phy-entity.cc:90
void ResetReceive(Ptr< Event > event)
Reset PHY at the end of the PPDU under reception after it has failed the PHY header.
std::list< WifiMode > m_modeList
the list of supported modes
Definition phy-entity.h:943
Ptr< const Event > GetCurrentEvent() const
Get the pointer to the current event (stored in WifiPhy).
virtual Ptr< const WifiPsdu > GetAddressedPsduInPpdu(Ptr< const WifiPpdu > ppdu) const
Get the PSDU addressed to that PHY in a PPDU (useful for MU PPDU).
void ErasePreambleEvent(Ptr< const WifiPpdu > ppdu, Time rxDuration)
Erase the event corresponding to the PPDU from the list of preamble events, but consider it as noise ...
void AddPreambleEvent(Ptr< Event > event)
Add an entry to the map of current preamble events (stored in WifiPhy).
virtual void DoEndReceivePayload(Ptr< const WifiPpdu > ppdu)
Perform amendment-specific actions at the end of the reception of the payload.
std::tuple< dBr_u, dBr_u, dBr_u > GetTxMaskRejectionParams() const
Ptr< Event > CreateInterferenceEvent(Ptr< const WifiPpdu > ppdu, Time duration, RxPowerWattPerChannelBand &rxPower, bool isStartHePortionRxing=false)
Create an event using WifiPhy's InterferenceHelper class.
@ DROP
drop PPDU and set CCA_BUSY
Definition phy-entity.h:71
void ScheduleEndOfMpdus(Ptr< Event > event)
Schedule end of MPDUs events.
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:206
static uint32_t GetNumBandsBetweenSegments(const std::vector< MHz_u > &centerFrequencies, MHz_u totalWidth, uint32_t subcarrierSpacing)
Determine the number of bands between the two segments if the operating channel is made of non-contig...
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:407
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition nstime.h:340
@ US
microsecond
Definition nstime.h:107
@ S
second
Definition nstime.h:105
@ NS
nanosecond
Definition nstime.h:108
PHY entity for VHT (11ac)
Definition vht-phy.h:38
static WifiMode GetVhtMcs0()
Return MCS 0 from VHT MCS values.
static WifiCodeRate GetCodeRate(uint8_t mcsValue)
Return the coding rate corresponding to the supplied VHT MCS index.
Definition vht-phy.cc:395
Time GetDuration(WifiPpduField field, const WifiTxVector &txVector) const override
Get the duration of the PPDU field (or group of fields) used by this entity for the given transmissio...
Definition vht-phy.cc:165
static WifiMode GetVhtMcs5()
Return MCS 5 from VHT MCS values.
CcaIndication GetCcaIndication(const Ptr< const WifiPpdu > ppdu) override
Get CCA end time and its corresponding channel list type when a new signal has been received by the P...
Definition vht-phy.cc:577
static uint64_t CalculateNonHtReferenceRate(WifiCodeRate codeRate, uint16_t constellationSize)
Return the rate (in bps) of the non-HT Reference Rate which corresponds to the supplied code rate and...
Definition vht-phy.cc:486
static WifiMode GetVhtMcs3()
Return MCS 3 from VHT MCS values.
dBm_u GetCcaThreshold(const Ptr< const WifiPpdu > ppdu, WifiChannelListType channelType) const override
Return the CCA threshold for a given channel type.
Definition vht-phy.cc:537
static WifiMode GetVhtMcs1()
Return MCS 1 from VHT MCS values.
static WifiMode GetVhtMcs4()
Return MCS 4 from VHT MCS values.
static WifiMode GetVhtMcs2()
Return MCS 2 from VHT MCS values.
static uint16_t GetConstellationSize(uint8_t mcsValue)
Return the constellation size corresponding to the supplied VHT MCS index.
Definition vht-phy.cc:409
WifiMode GetSigMode(WifiPpduField field, const WifiTxVector &txVector) const override
Get the WifiMode for the SIG field specified by the PPDU field.
Definition vht-phy.cc:127
static WifiMode CreateWifiMcs(std::string uniqueName, uint8_t mcsValue, WifiModulationClass modClass, bool isMandatory, CodeRateCallback codeRateCallback, ConstellationSizeCallback constellationSizeCallback, PhyRateCallback phyRateCallback, DataRateCallback dataRateCallback, NonHtReferenceRateCallback nonHtReferenceRateCallback, AllowedCallback isAllowedCallback)
Definition wifi-mode.cc:307
represent a single transmission mode
Definition wifi-mode.h:40
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
Definition wifi-mode.cc:111
uint8_t GetMcsValue() const
Definition wifi-mode.cc:152
dB_u GetTxGain() const
Return the transmission gain.
Definition wifi-phy.cc:603
Hz_u GetSubcarrierSpacing() const
Definition wifi-phy.cc:2354
MHz_u GetFrequency() const
Definition wifi-phy.cc:1081
uint8_t GetMaxSupportedRxSpatialStreams() const
Definition wifi-phy.cc:1390
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1572
virtual WifiSpectrumBandFrequencies ConvertIndicesToFrequencies(const WifiSpectrumBandIndices &indices) const =0
This is a helper function to convert start and stop indices to start and stop frequencies.
void NotifyRxPpduDrop(Ptr< const WifiPpdu > ppdu, WifiPhyRxfailureReason reason)
Public method used to fire a PhyRxPpduDrop trace.
Definition wifi-phy.cc:1685
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition wifi-phy.cc:1063
static void AddStaticPhyEntity(WifiModulationClass modulation, Ptr< PhyEntity > phyEntity)
Add the PHY entity to the map of implemented PHY entities for the given modulation class.
Definition wifi-phy.cc:795
MHz_u GetChannelWidth() const
Definition wifi-phy.cc:1093
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition wifi-phy.cc:641
dBm_u GetTxPowerForTransmission(Ptr< const WifiPpdu > ppdu) const
Compute the transmit power for the next transmission.
Definition wifi-phy.cc:2287
uint64_t GetPreviouslyRxPpduUid() const
Definition wifi-phy.cc:1926
Time GetLastRxEndTime() const
Return the end time of the last received packet.
Definition wifi-phy.cc:2194
virtual WifiSpectrumBandInfo GetBand(MHz_u bandWidth, uint8_t bandIndex=0)=0
Get the info of a given band.
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition wifi-phy.cc:1075
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition wifi-phy.cc:1565
std::set< uint8_t > GetAll20MHzChannelIndicesInPrimary(MHz_u width) const
Get the channel indices of all the 20 MHz channels included in the primary channel of the given width...
uint8_t GetPrimaryChannelIndex(MHz_u primaryChannelWidth) const
If the operating channel width is a multiple of 20 MHz, return the index of the primary channel of th...
std::vector< MHz_u > GetFrequencies() const
Return the center frequency per segment.
static Ptr< SpectrumValue > CreateHeMuOfdmTxPowerSpectralDensity(const std::vector< MHz_u > &centerFrequencies, MHz_u channelWidth, Watt_u txPower, MHz_u guardBandwidth, const std::vector< WifiSpectrumBandIndices > &ru)
Create a transmit power spectral density corresponding to the OFDMA part of HE TB PPDUs for a given R...
static Ptr< SpectrumValue > CreateHeOfdmTxPowerSpectralDensity(MHz_u centerFrequency, MHz_u channelWidth, Watt_u txPower, MHz_u guardBandwidth, dBr_u minInnerBand=-20, dBr_u minOuterband=-28, dBr_u lowestPoint=-40, const std::vector< bool > &puncturedSubchannels={})
Create a transmit power spectral density corresponding to OFDM High Efficiency (HE) (802....
static Ptr< SpectrumValue > CreateDuplicated20MhzTxPowerSpectralDensity(const std::vector< MHz_u > &centerFrequencies, MHz_u channelWidth, Watt_u txPower, MHz_u guardBandwidth, dBr_u minInnerBand=-20, dBr_u minOuterband=-28, dBr_u lowestPoint=-40, const std::vector< bool > &puncturedSubchannels={})
Create a transmit power spectral density corresponding to OFDM duplicated over multiple 20 MHz subcha...
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
bool IsTriggerResponding() const
Return true if the Trigger Responding parameter is set to true, false otherwise.
bool IsSigBCompression() const
Indicate whether the Common field is present in the HE-SIG-B field.
const RuAllocation & GetRuAllocation(uint8_t p20Index) const
Get RU_ALLOCATION field.
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.
WifiPreamble GetPreambleType() const
HeRu::RuSpec GetRu(uint16_t staId) const
Get the RU specification for the STA-ID.
uint16_t GetLength() const
Get the LENGTH field of the L-SIG.
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
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.
MHz_u GetChannelWidth() const
Time GetGuardInterval() const
#define CASE(x)
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition abort.h:65
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
auto MakeBoundCallback(R(*fnPtr)(Args...), BArgs &&... bargs)
Make Callbacks with varying number of bound arguments.
Definition callback.h:745
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Time FemtoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1368
WifiPhyRxfailureReason
Enumeration of the possible reception failure reasons.
WifiPreamble
The type of preamble to be used by an IEEE 802.11 transmission.
WifiPhyBand
Identifies the PHY band.
WifiChannelListType
Enumeration of the possible channel-list parameter elements defined in Table 8-5 of IEEE 802....
WifiPpduField
The type of PPDU field (grouped for convenience)
@ AP
Definition wifi-mac.h:59
@ OBSS_PD_CCA_RESET
@ WIFI_PREAMBLE_HE_ER_SU
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PREAMBLE_HE_SU
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_PPDU_TYPE_DL_MU
@ WIFI_PPDU_TYPE_UL_MU
@ WIFI_PPDU_TYPE_SU
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ WIFI_CHANLIST_PRIMARY
@ WIFI_PPDU_FIELD_SIG_B
SIG-B field.
@ WIFI_PPDU_FIELD_TRAINING
STF + LTF fields (excluding those in preamble for HT-GF)
@ WIFI_PPDU_FIELD_NON_HT_HEADER
PHY header field for DSSS or ERP, short PHY header field for HR/DSSS or ERP, field not present for HT...
@ WIFI_PPDU_FIELD_PREAMBLE
SYNC + SFD fields for DSSS or ERP, shortSYNC + shortSFD fields for HR/DSSS or ERP,...
@ WIFI_PPDU_FIELD_DATA
data field
@ WIFI_PPDU_FIELD_SIG_A
SIG-A field.
#define GET_HE_MCS(x)
Definition he-phy.cc:1600
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
#define HE_PHY
This defines the BSS membership value for HE PHY.
Definition he-phy.h:38
class anonymous_namespace{he-phy.cc}::ConstructorHe g_constructor_he
the constructor for HE modes
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
dBm_u WToDbm(Watt_u val)
Convert from Watts to dBm.
Definition wifi-utils.cc:37
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::map< WifiSpectrumBandInfo, Watt_u > RxPowerWattPerChannelBand
A map of the received power for each band.
Definition phy-entity.h:45
double dBm_u
dBm weak type
Definition wifi-units.h:27
Watt_u DbmToW(dBm_u val)
Convert from dBm to Watts.
Definition wifi-utils.cc:31
@ LOG_FUNCTION
Function tracing for non-trivial function calls.
Definition log.h:95
bool IsDlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a downlink multi-user transmission.
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition wifi-mode.h:24
bool IsUlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a uplink multi-user transmission.
WifiCodeRate
These constants define the various convolutional coding rates used for the OFDM transmission modes in...
@ WIFI_CODE_RATE_3_4
3/4 coding rate
@ WIFI_CODE_RATE_5_6
5/6 coding rate
STL namespace.
Parameters for received HE-SIG-A for OBSS_PD based SR.
Definition he-phy.h:44
Status of the reception of the PPDU field.
Definition phy-entity.h:80
bool isSuccess
outcome (true if success) of the reception
Definition phy-entity.h:81
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:72
SignalNoiseDbm structure.
Definition wifi-types.h:58
WifiSpectrumBandInfo structure containing info about a spectrum band.
std::vector< WifiSpectrumBandIndices > indices
the start and stop indices for each segment of the band