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.GetModulationClass(),
220 txVector.GetRuAllocation(
223 txVector.IsSigBCompression(),
224 txVector.IsSigBCompression() ? txVector.GetHeMuUserInfoMap().size() : 0);
225 }
226 return 0;
227}
228
229Time
231{
232 if (const auto sigBSize = GetSigBSize(txVector); sigBSize > 0)
233 {
234 const auto symbolDuration = MicroSeconds(4);
235 // Number of data bits per symbol
236 const auto ndbps =
237 GetSigBMode(txVector).GetDataRate(MHz_u{20}) * symbolDuration.GetNanoSeconds() / 1e9;
238 const auto numSymbols = ceil((sigBSize) / ndbps);
239
240 return FemtoSeconds(static_cast<uint64_t>(numSymbols * symbolDuration.GetFemtoSeconds()));
241 }
242 else
243 {
244 // no SIG-B
245 return MicroSeconds(0);
246 }
247}
248
249Time
250HePhy::GetValidPpduDuration(Time ppduDuration, const WifiTxVector& txVector, WifiPhyBand band)
251{
252 const auto tSymbol = GetSymbolDuration(txVector.GetGuardInterval());
253 const auto preambleDuration = WifiPhy::CalculatePhyPreambleAndHeaderDuration(txVector);
254 uint8_t sigExtension = (band == WIFI_PHY_BAND_2_4GHZ ? 6 : 0);
255 uint32_t nSymbols =
256 floor(static_cast<double>((ppduDuration - preambleDuration).GetNanoSeconds() -
257 (sigExtension * 1000)) /
258 tSymbol.GetNanoSeconds());
259 return preambleDuration + (nSymbols * tSymbol) + MicroSeconds(sigExtension);
260}
261
262std::pair<uint16_t, Time>
264 const WifiTxVector& txVector,
265 WifiPhyBand band)
266{
267 NS_ABORT_IF(!txVector.IsUlMu() || (txVector.GetModulationClass() < WIFI_MOD_CLASS_HE));
268 // update ppduDuration so that it is a valid PPDU duration
269 ppduDuration = GetValidPpduDuration(ppduDuration, txVector, band);
270 uint8_t sigExtension = (band == WIFI_PHY_BAND_2_4GHZ ? 6 : 0);
271 uint8_t m = 2; // HE TB PPDU so m is set to 2
272 uint16_t length = ((ceil((static_cast<double>(ppduDuration.GetNanoSeconds() - (20 * 1000) -
273 (sigExtension * 1000)) /
274 1000) /
275 4.0) *
276 3) -
277 3 - m);
278 return {length, ppduDuration};
279}
280
281Time
283 const WifiTxVector& txVector,
284 WifiPhyBand band)
285{
286 NS_ABORT_IF(!txVector.IsUlMu() || (txVector.GetModulationClass() < WIFI_MOD_CLASS_HE));
287 uint8_t sigExtension = (band == WIFI_PHY_BAND_2_4GHZ ? 6 : 0);
288 uint8_t m = 2; // HE TB PPDU so m is set to 2
289 // Equation 27-11 of IEEE P802.11ax/D4.0
290 Time calculatedDuration =
291 MicroSeconds(((ceil(static_cast<double>(length + 3 + m) / 3)) * 4) + 20 + sigExtension);
292 return GetValidPpduDuration(calculatedDuration, txVector, band);
293}
294
295Time
297{
298 Time duration = GetDuration(WIFI_PPDU_FIELD_PREAMBLE, txVector) +
301 return duration;
302}
303
304Time
306{
307 Time duration = GetDuration(WIFI_PPDU_FIELD_PREAMBLE, txVector) +
311 return duration;
312}
313
314uint8_t
315HePhy::GetNumberBccEncoders(const WifiTxVector& /* txVector */) const
316{
317 return 1; // only 1 BCC encoder for HE since higher rates are obtained using LDPC
318}
319
320Time
322{
323 const auto guardInterval = txVector.GetGuardInterval();
324 [[maybe_unused]] const auto gi = guardInterval.GetNanoSeconds();
325 NS_ASSERT(gi == 800 || gi == 1600 || gi == 3200);
326 return GetSymbolDuration(guardInterval);
327}
328
329void
330HePhy::SetTrigVector(const WifiTxVector& trigVector, Time validity)
331{
332 NS_LOG_FUNCTION(this << trigVector << validity);
333 NS_ASSERT_MSG(trigVector.GetGuardInterval().GetNanoSeconds() > 800,
334 "Invalid guard interval " << trigVector.GetGuardInterval());
335 if (auto mac = m_wifiPhy->GetDevice()->GetMac(); mac && mac->GetTypeOfStation() != AP)
336 {
337 return;
338 }
339 m_trigVector = trigVector;
342}
343
345HePhy::BuildPpdu(const WifiConstPsduMap& psdus, const WifiTxVector& txVector, Time ppduDuration)
346{
347 NS_LOG_FUNCTION(this << psdus << txVector << ppduDuration);
348 return Create<HePpdu>(psdus,
349 txVector,
351 ppduDuration,
352 ObtainNextUid(txVector),
354}
355
356void
358 RxPowerWattPerChannelBand& rxPowersW,
359 Time rxDuration)
360{
361 NS_LOG_FUNCTION(this << ppdu << rxDuration);
362 const auto& txVector = ppdu->GetTxVector();
363 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
364 NS_ASSERT(hePpdu);
365 const auto psdFlag = hePpdu->GetTxPsdFlag();
366 if (psdFlag == HePpdu::PSD_HE_PORTION)
367 {
368 NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
369 if (m_currentMuPpduUid == ppdu->GetUid() && GetCurrentEvent())
370 {
371 // AP or STA has already received non-HE portion, switch to HE portion, and schedule
372 // reception of payload (will be canceled for STAs by StartPayload)
373 const auto hePortionStarted = !m_beginMuPayloadRxEvents.empty();
374 NS_LOG_INFO("Switch to HE portion (already started? "
375 << (hePortionStarted ? "Y" : "N") << ") "
376 << "and schedule payload reception in "
378 auto event = CreateInterferenceEvent(ppdu, rxDuration, rxPowersW, !hePortionStarted);
379 uint16_t staId = GetStaId(ppdu);
380 NS_ASSERT(!m_beginMuPayloadRxEvents.contains(staId));
384 this,
385 event);
386 }
387 else
388 {
389 // PHY receives the HE portion while having dropped the preamble
390 NS_LOG_INFO("Consider HE portion of the PPDU as interference since device dropped the "
391 "preamble");
392 CreateInterferenceEvent(ppdu, rxDuration, rxPowersW);
393 // the HE portion of the PPDU will be noise _after_ the completion of the current event
394 ErasePreambleEvent(ppdu, rxDuration);
395 }
396 }
397 else
398 {
400 ppdu,
401 rxPowersW,
402 ppdu->GetTxDuration()); // The actual duration of the PPDU should be used
403 }
404}
405
406void
408{
409 NS_LOG_FUNCTION(this);
410 for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
411 {
412 beginMuPayloadRxEvent.second.Cancel();
413 }
416}
417
418void
420{
421 NS_LOG_FUNCTION(this << reason);
422 if (reason != OBSS_PD_CCA_RESET)
423 {
424 for (auto& endMpduEvent : m_endOfMpduEvents)
425 {
426 endMpduEvent.Cancel();
427 }
428 m_endOfMpduEvents.clear();
429 }
430 else
431 {
433 }
434}
435
436void
438{
439 NS_LOG_FUNCTION(this << *event);
440 if (event->GetPpdu()->GetType() != WIFI_PPDU_TYPE_UL_MU)
441 {
442 NS_ASSERT(event->GetEndTime() == Simulator::Now());
443 }
444 for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
445 {
446 beginMuPayloadRxEvent.second.Cancel();
447 }
449}
450
453{
454 Ptr<Event> event;
455 // We store all incoming preamble events, and a decision is made at the end of the preamble
456 // detection window. If a preamble is received after the preamble detection window, it is stored
457 // anyway because this is needed for HE TB PPDUs in order to properly update the received power
458 // in InterferenceHelper. The map is cleaned anyway at the end of the current reception.
459 const auto& currentPreambleEvents = GetCurrentPreambleEvents();
460 const auto it = currentPreambleEvents.find({ppdu->GetUid(), ppdu->GetPreamble()});
461 if (const auto isResponseToTrigger = (m_previouslyTxPpduUid == ppdu->GetUid());
462 ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU || isResponseToTrigger)
463 {
464 const auto& txVector = ppdu->GetTxVector();
465 const auto rxDuration =
466 (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
468 txVector) // the HE portion of the transmission will be added later on
469 : ppdu->GetTxDuration();
470 if (it != currentPreambleEvents.cend())
471 {
472 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
473 {
474 NS_LOG_DEBUG("Received another HE TB PPDU for UID "
475 << ppdu->GetUid() << " from STA-ID " << ppdu->GetStaId()
476 << " and BSS color " << +txVector.GetBssColor());
477 }
478 else
479 {
480 NS_LOG_DEBUG("Received another response to a trigger frame " << ppdu->GetUid());
481 }
482 event = it->second;
483 HandleRxPpduWithSameContent(event, ppdu, rxPowersW);
484 return nullptr;
485 }
486 else
487 {
488 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
489 {
490 NS_LOG_DEBUG("Received a new HE TB PPDU for UID "
491 << ppdu->GetUid() << " from STA-ID " << ppdu->GetStaId()
492 << " and BSS color " << +txVector.GetBssColor());
493 }
494 else
495 {
496 NS_LOG_DEBUG("Received response to a trigger frame for UID " << ppdu->GetUid());
497 }
498 event = CreateInterferenceEvent(ppdu, rxDuration, rxPowersW);
499 AddPreambleEvent(event);
500 }
501 }
502 else if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
503 {
504 const auto& txVector = ppdu->GetTxVector();
506 txVector); // the HE portion of the transmission will be added later on
507 event = CreateInterferenceEvent(ppdu, rxDuration, rxPowersW);
508 AddPreambleEvent(event);
509 }
510 else
511 {
512 event = VhtPhy::DoGetEvent(ppdu, rxPowersW);
513 }
514 return event;
515}
516
517void
521{
522 VhtPhy::HandleRxPpduWithSameContent(event, ppdu, rxPower);
523
524 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU && GetCurrentEvent() &&
525 (GetCurrentEvent()->GetPpdu()->GetUid() != ppdu->GetUid()))
526 {
527 NS_LOG_DEBUG("Drop packet because already receiving another HE TB PPDU");
529 }
530 else if (const auto isResponseToTrigger = (m_previouslyTxPpduUid == ppdu->GetUid());
531 isResponseToTrigger && GetCurrentEvent() &&
532 (GetCurrentEvent()->GetPpdu()->GetUid() != ppdu->GetUid()))
533 {
534 NS_LOG_DEBUG("Drop packet because already receiving another response to a trigger frame");
536 }
537}
538
541{
542 if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU || ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
543 {
544 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
545 NS_ASSERT(hePpdu);
546 return hePpdu->GetPsdu(GetBssColor(), GetStaId(ppdu));
547 }
549}
550
551uint8_t
553{
554 uint8_t bssColor = 0;
555 if (m_wifiPhy->GetDevice())
556 {
557 Ptr<HeConfiguration> heConfiguration = m_wifiPhy->GetDevice()->GetHeConfiguration();
558 if (heConfiguration)
559 {
560 bssColor = heConfiguration->m_bssColor;
561 }
562 }
563 return bssColor;
564}
565
566uint16_t
568{
569 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
570 {
571 return ppdu->GetStaId();
572 }
573 else if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
574 {
575 auto mac = DynamicCast<StaWifiMac>(m_wifiPhy->GetDevice()->GetMac());
576 if (mac && mac->IsAssociated())
577 {
578 return mac->GetAssociationId();
579 }
580 }
581 return VhtPhy::GetStaId(ppdu);
582}
583
586{
587 NS_LOG_FUNCTION(this << *event << status << field);
588 NS_ASSERT(event->GetPpdu()->GetTxVector().GetPreambleType() >= WIFI_PREAMBLE_HE_SU);
589 switch (field)
590 {
592 return ProcessSigA(event, status);
594 return ProcessSigB(event, status);
595 default:
596 NS_ASSERT_MSG(false, "Invalid PPDU field");
597 }
598 return status;
599}
600
603{
604 NS_LOG_FUNCTION(this << *event << status);
605 // Notify end of SIG-A (in all cases)
606 const auto& txVector = event->GetPpdu()->GetTxVector();
607 HeSigAParameters params{
608 .rssi = WToDbm(GetRxPowerForPpdu(event)),
609 .bssColor = txVector.GetBssColor(),
610 };
611 NotifyEndOfHeSigA(params); // if OBSS_PD CCA_RESET, set power restriction first and wait till
612 // field is processed before switching to IDLE
613
614 if (status.isSuccess)
615 {
616 // Check if PPDU is filtered based on the BSS color
617 uint8_t myBssColor = GetBssColor();
618 uint8_t rxBssColor = txVector.GetBssColor();
619 if (myBssColor != 0 && rxBssColor != 0 && myBssColor != rxBssColor)
620 {
621 NS_LOG_DEBUG("The BSS color of this PPDU ("
622 << +rxBssColor << ") does not match the device's (" << +myBssColor
623 << "). The PPDU is filtered.");
624 return PhyFieldRxStatus(false, FILTERED, DROP);
625 }
626
627 // When SIG-A is decoded, we know the type of frame being received. If we stored a
628 // valid TRIGVECTOR and we are not receiving a TB PPDU, we drop the frame.
629 Ptr<const WifiPpdu> ppdu = event->GetPpdu();
630 if (m_trigVectorExpirationTime.has_value() &&
632 (ppdu->GetType() != WIFI_PPDU_TYPE_UL_MU))
633 {
634 NS_LOG_DEBUG("Expected an HE TB PPDU, receiving a " << txVector.GetPreambleType());
635 return PhyFieldRxStatus(false, FILTERED, DROP);
636 }
637
638 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
639 {
640 NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
641 // check that the stored TRIGVECTOR is still valid
642 if (!m_trigVectorExpirationTime.has_value() ||
644 {
645 NS_LOG_DEBUG("No valid TRIGVECTOR, the PHY was not expecting a TB PPDU");
646 return PhyFieldRxStatus(false, FILTERED, DROP);
647 }
648 // We expected a TB PPDU and we are receiving a TB PPDU. However, despite
649 // the previous check on BSS Color, we may be receiving a TB PPDU from an
650 // OBSS, as BSS Colors are not guaranteed to be different for all APs in
651 // range (an example is when BSS Color is 0). We can detect this situation
652 // by comparing the TRIGVECTOR with the TXVECTOR of the TB PPDU being received
653 NS_ABORT_IF(!m_trigVector.has_value());
654 if (m_trigVector->GetChannelWidth() != txVector.GetChannelWidth())
655 {
656 NS_LOG_DEBUG("Received channel width different than in TRIGVECTOR");
657 return PhyFieldRxStatus(false, FILTERED, DROP);
658 }
659 if (m_trigVector->GetLength() != txVector.GetLength())
660 {
661 NS_LOG_DEBUG("Received UL Length (" << txVector.GetLength()
662 << ") different than in TRIGVECTOR ("
663 << m_trigVector->GetLength() << ")");
664 return PhyFieldRxStatus(false, FILTERED, DROP);
665 }
666 uint16_t staId = ppdu->GetStaId();
667 if (!m_trigVector->GetHeMuUserInfoMap().contains(staId))
668 {
669 NS_LOG_DEBUG("TB PPDU received from un unexpected STA ID");
670 return PhyFieldRxStatus(false, FILTERED, DROP);
671 }
672
673 NS_ASSERT(txVector.GetGuardInterval() == m_trigVector->GetGuardInterval());
674 NS_ASSERT(txVector.GetMode(staId) == m_trigVector->GetMode(staId));
675 NS_ASSERT(txVector.GetNss(staId) == m_trigVector->GetNss(staId));
676 NS_ASSERT(txVector.GetHeMuUserInfo(staId) == m_trigVector->GetHeMuUserInfo(staId));
677
679 ppdu->GetUid(); // to be able to correctly schedule start of MU payload
680 }
681
682 if (ppdu->GetType() != WIFI_PPDU_TYPE_DL_MU &&
683 !GetAddressedPsduInPpdu(ppdu)) // Final decision on STA-ID correspondence of DL MU is
684 // delayed to end of SIG-B
685 {
686 NS_ASSERT(ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU);
688 "No PSDU addressed to that PHY in the received MU PPDU. The PPDU is filtered.");
689 return PhyFieldRxStatus(false, FILTERED, DROP);
690 }
691 }
692 return status;
693}
694
695void
697{
698 m_obssPdAlgorithm = algorithm;
699}
700
703{
704 return m_obssPdAlgorithm;
705}
706
707void
712
713void
721
724{
725 NS_LOG_FUNCTION(this << *event << status);
726 NS_ASSERT(IsDlMu(event->GetPpdu()->GetTxVector().GetPreambleType()));
727 if (status.isSuccess)
728 {
729 // Check if PPDU is filtered only if the SIG-B content is supported (not explicitly stated
730 // but assumed based on behavior for SIG-A)
731 if (!GetAddressedPsduInPpdu(event->GetPpdu()))
732 {
734 "No PSDU addressed to that PHY in the received MU PPDU. The PPDU is filtered.");
735 return PhyFieldRxStatus(false, FILTERED, DROP);
736 }
737 }
739 event->GetPpdu()->GetUid(); // to be able to correctly schedule start of MU payload
740
741 return status;
742}
743
744bool
746{
747 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
748 {
749 return true; // evaluated in ProcessSigA
750 }
751
752 const auto& txVector = ppdu->GetTxVector();
753 const auto staId = GetStaId(ppdu);
754 const auto txMode = txVector.GetMode(staId);
755 auto nss = txVector.GetNssMax();
756 if (txVector.IsDlMu())
757 {
758 NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
759 for (auto info : txVector.GetHeMuUserInfoMap())
760 {
761 if (info.first == staId)
762 {
763 nss = info.second.nss; // no need to look at other PSDUs
764 break;
765 }
766 }
767 }
768
770 {
771 NS_LOG_DEBUG("Packet reception could not be started because not enough RX antennas");
772 return false;
773 }
774 if (!IsModeSupported(txMode))
775 {
776 NS_LOG_DEBUG("Drop packet because it was sent using an unsupported mode ("
777 << txVector.GetMode() << ")");
778 return false;
779 }
780 return true;
781}
782
783Time
785{
786 NS_LOG_FUNCTION(this << *event);
787 const auto ppdu = event->GetPpdu();
788 const auto& txVector = ppdu->GetTxVector();
789
790 if (!txVector.IsMu())
791 {
792 return VhtPhy::DoStartReceivePayload(event);
793 }
794
795 NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
796
797 if (txVector.IsDlMu())
798 {
799 Time payloadDuration =
800 ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(txVector);
801 NotifyPayloadBegin(txVector, payloadDuration);
802 return payloadDuration;
803 }
804
805 // TX duration is determined by the Length field of TXVECTOR
806 Time payloadDuration = ConvertLSigLengthToHeTbPpduDuration(txVector.GetLength(),
807 txVector,
810 // This method is called when we start receiving the first MU payload. To
811 // compute the time to the reception end of the last TB PPDU, we need to add the
812 // offset of the last TB PPDU to the payload duration (same for all TB PPDUs)
813 Time maxOffset{0};
814 for (const auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
815 {
816 maxOffset = Max(maxOffset, Simulator::GetDelayLeft(beginMuPayloadRxEvent.second));
817 }
818 Time timeToEndRx = payloadDuration + maxOffset;
819
820 if (m_wifiPhy->GetDevice()->GetMac()->GetTypeOfStation() != AP)
821 {
822 NS_LOG_DEBUG("Ignore HE TB PPDU payload received by STA but keep state in Rx");
823 NotifyPayloadBegin(txVector, timeToEndRx);
824 m_endRxPayloadEvents.push_back(
825 Simulator::Schedule(timeToEndRx, &HePhy::ResetReceive, this, event));
826 // Cancel all scheduled events for MU payload reception
828 m_beginMuPayloadRxEvents.begin()->second.IsPending());
829 for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
830 {
831 beginMuPayloadRxEvent.second.Cancel();
832 }
834 }
835 else
836 {
837 NS_LOG_DEBUG("Receiving PSDU in HE TB PPDU");
838 const auto staId = GetStaId(ppdu);
839 m_signalNoiseMap.insert({{ppdu->GetUid(), staId}, SignalNoiseDbm()});
840 m_statusPerMpduMap.insert({{ppdu->GetUid(), staId}, std::vector<bool>()});
841 // for HE TB PPDUs, ScheduleEndOfMpdus and EndReceive are scheduled by
842 // StartReceiveMuPayload
844 for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
845 {
846 NS_ASSERT(beginMuPayloadRxEvent.second.IsPending());
847 }
848 }
849
850 return timeToEndRx;
851}
852
853void
855 RxSignalInfo rxSignalInfo,
856 const WifiTxVector& txVector,
857 uint16_t staId,
858 const std::vector<bool>& statusPerMpdu)
859{
860 NS_LOG_FUNCTION(this << *psdu << txVector);
861 if (!IsUlMu(txVector.GetPreambleType()))
862 {
863 m_state->SwitchFromRxEndOk();
864 }
865 else
866 {
868 }
869}
870
871void
873{
874 NS_LOG_FUNCTION(this << *psdu << txVector << snr);
875 if (!txVector.IsUlMu())
876 {
877 m_state->SwitchFromRxEndError(txVector);
878 }
879}
880
881void
883{
884 NS_LOG_FUNCTION(this << ppdu);
885 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
886 {
887 for (auto it = m_endRxPayloadEvents.begin(); it != m_endRxPayloadEvents.end();)
888 {
889 if (it->IsExpired())
890 {
891 it = m_endRxPayloadEvents.erase(it);
892 }
893 else
894 {
895 it++;
896 }
897 }
898 if (m_endRxPayloadEvents.empty())
899 {
900 // We've got the last PPDU of the UL-MU transmission.
901 // Indicate a successful reception is terminated if at least one HE TB PPDU
902 // has been successfully received, otherwise indicate a unsuccessful reception is
903 // terminated.
904 if (m_rxHeTbPpdus > 0)
905 {
906 m_state->SwitchFromRxEndOk();
907 }
908 else
909 {
910 m_state->SwitchFromRxEndError(ppdu->GetTxVector());
911 }
912 NotifyInterferenceRxEndAndClear(true); // reset WifiPhy
913 m_rxHeTbPpdus = 0;
914 }
915 }
916 else
917 {
920 }
921 // we are done receiving the payload, we can reset the current MU PPDU UID
922 m_currentMuPpduUid = UINT64_MAX;
923}
924
925void
927{
928 NS_LOG_FUNCTION(this << event);
929 Ptr<const WifiPpdu> ppdu = event->GetPpdu();
930 const RxPowerWattPerChannelBand& rxPowersW = event->GetRxPowerPerBand();
931 // The total RX power corresponds to the maximum over all the bands.
932 // Only perform this computation if the result needs to be logged.
933 auto it = rxPowersW.end();
934 if (g_log.IsEnabled(ns3::LOG_FUNCTION))
935 {
936 it = std::max_element(rxPowersW.cbegin(),
937 rxPowersW.cend(),
938 [](const auto& p1, const auto& p2) { return p1.second < p2.second; });
939 }
940 NS_LOG_FUNCTION(this << *event << it->second);
943 auto itEvent = m_beginMuPayloadRxEvents.find(GetStaId(ppdu));
944 /**
945 * m_beginMuPayloadRxEvents should still be running only for APs, since canceled in
946 * StartReceivePayload for STAs. This is because SpectrumWifiPhy does not have access to the
947 * device type and thus blindly schedules things, letting the parent WifiPhy class take into
948 * account device type.
949 */
950 NS_ASSERT(itEvent != m_beginMuPayloadRxEvents.end() && itEvent->second.IsExpired());
951 m_beginMuPayloadRxEvents.erase(itEvent);
952
953 auto payloadDuration =
954 ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(ppdu->GetTxVector());
955 auto psdu = GetAddressedPsduInPpdu(ppdu);
956 ScheduleEndOfMpdus(event);
957 m_endRxPayloadEvents.push_back(
958 Simulator::Schedule(payloadDuration, &HePhy::EndReceivePayload, this, event));
959 const auto staId = GetStaId(ppdu);
960 m_signalNoiseMap.insert({{ppdu->GetUid(), staId}, SignalNoiseDbm()});
961 m_statusPerMpduMap.insert({{ppdu->GetUid(), staId}, std::vector<bool>()});
962 // Notify the MAC about the start of a new HE TB PPDU, so that it can reschedule the timeout
963 NotifyPayloadBegin(ppdu->GetTxVector(), payloadDuration);
964}
965
966std::pair<MHz_u, WifiSpectrumBandInfo>
967HePhy::GetChannelWidthAndBand(const WifiTxVector& txVector, uint16_t staId) const
968{
969 if (txVector.IsMu())
970 {
971 return {WifiRu::GetBandwidth(WifiRu::GetRuType(txVector.GetRu(staId))),
972 GetRuBandForRx(txVector, staId)};
973 }
974 else
975 {
976 return VhtPhy::GetChannelWidthAndBand(txVector, staId);
977 }
978}
979
981HePhy::GetRuBandForTx(const WifiTxVector& txVector, uint16_t staId) const
982{
983 NS_ASSERT(txVector.IsMu());
984 auto ru = txVector.GetRu(staId);
985 const auto channelWidth = txVector.GetChannelWidth();
986 NS_ASSERT(channelWidth <= m_wifiPhy->GetChannelWidth());
987 const auto mc = txVector.GetModulationClass();
988 const auto group = WifiRu::GetSubcarrierGroup(
989 channelWidth,
992 channelWidth,
994 mc);
995 // for a TX spectrum, the guard bandwidth is a function of the transmission channel width
996 // and the spectrum width equals the transmission channel width (hence bandIndex equals 0)
997 const auto indices = ConvertRuSubcarriers({channelWidth,
998 GetGuardBandwidth(channelWidth),
1002 mc,
1003 {group.front().first, group.back().second},
1004 0});
1005 WifiSpectrumBandInfo ruBandForTx{};
1006 for (const auto& indicesPerSegment : indices)
1007 {
1008 ruBandForTx.indices.emplace_back(indicesPerSegment);
1009 ruBandForTx.frequencies.emplace_back(
1010 m_wifiPhy->ConvertIndicesToFrequencies(indicesPerSegment));
1011 }
1012 return ruBandForTx;
1013}
1014
1016HePhy::GetRuBandForRx(const WifiTxVector& txVector, uint16_t staId) const
1017{
1018 NS_ASSERT(txVector.IsMu());
1019 auto ru = txVector.GetRu(staId);
1020 const auto channelWidth = txVector.GetChannelWidth();
1021 NS_ASSERT(channelWidth <= m_wifiPhy->GetChannelWidth());
1022 const auto mc = txVector.GetModulationClass();
1023 const auto group = WifiRu::GetSubcarrierGroup(
1024 channelWidth,
1027 channelWidth,
1029 mc);
1030 // for an RX spectrum, the guard bandwidth is a function of the operating channel width
1031 // and the spectrum width equals the operating channel width
1032 const auto indices = ConvertRuSubcarriers(
1033 {channelWidth,
1038 mc,
1039 {group.front().first, group.back().second},
1041 WifiSpectrumBandInfo ruBandForRx{};
1042 for (const auto& indicesPerSegment : indices)
1043 {
1044 ruBandForRx.indices.emplace_back(indicesPerSegment);
1045 ruBandForRx.frequencies.emplace_back(
1046 m_wifiPhy->ConvertIndicesToFrequencies(indicesPerSegment));
1047 }
1048 return ruBandForRx;
1049}
1050
1051MHz_u
1053{
1054 const auto ruType = WifiRu::GetRuType(ru);
1055 if (ruType == RuType::RU_26_TONE && WifiRu::GetIndex(ru) == 19)
1056 {
1057 // the center 26-tone RU in an 80 MHz channel is not fully covered by
1058 // any 20 MHz channel, but only by an 80 MHz channel
1059 return MHz_u{80};
1060 }
1061 return std::max(WifiRu::GetBandwidth(ruType), MHz_u{20});
1062}
1063
1064uint64_t
1066{
1067 return m_currentMuPpduUid;
1068}
1069
1070MHz_u
1072{
1073 auto channelWidth = OfdmPhy::GetMeasurementChannelWidth(ppdu);
1074 /**
1075 * The PHY shall not issue a PHY-RXSTART.indication primitive in response to a PPDU that does
1076 * not overlap the primary channel unless the PHY at an AP receives the HE TB PPDU solicited by
1077 * the AP. For the HE TB PPDU solicited by the AP, the PHY shall issue a PHY-RXSTART.indication
1078 * primitive for a PPDU received in the primary or at the secondary 20 MHz channel, the
1079 * secondary 40 MHz channel, or the secondary 80 MHz channel.
1080 */
1081 if (channelWidth >= MHz_u{40} && ppdu->GetUid() != m_previouslyTxPpduUid)
1082 {
1083 channelWidth = MHz_u{20};
1084 }
1085 return channelWidth;
1086}
1087
1088dBm_u
1090{
1091 if (!ppdu)
1092 {
1093 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1094 }
1095
1096 if (!m_obssPdAlgorithm)
1097 {
1098 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1099 }
1100
1101 if (channelType == WIFI_CHANLIST_PRIMARY)
1102 {
1103 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1104 }
1105
1106 const auto ppduBw = ppdu->GetTxVector().GetChannelWidth();
1107 auto obssPdLevel = m_obssPdAlgorithm->GetObssPdLevel();
1108 auto bw = ppduBw;
1109 while (bw > MHz_u{20})
1110 {
1111 obssPdLevel += dB_u{3};
1112 bw /= 2;
1113 }
1114
1115 return std::max(VhtPhy::GetCcaThreshold(ppdu, channelType), obssPdLevel);
1116}
1117
1118void
1120{
1121 NS_LOG_FUNCTION(this);
1122 const auto ccaIndication = GetCcaIndication(ppdu);
1123 const auto per20MHzDurations = GetPer20MHzDurations(ppdu);
1124 if (ccaIndication.has_value())
1125 {
1126 NS_LOG_DEBUG("CCA busy for " << ccaIndication.value().second << " during "
1127 << ccaIndication.value().first.As(Time::S));
1128 NotifyCcaBusy(ccaIndication.value().first, ccaIndication.value().second, per20MHzDurations);
1129 return;
1130 }
1131 if (ppdu)
1132 {
1133 SwitchMaybeToCcaBusy(nullptr);
1134 return;
1135 }
1136 if (per20MHzDurations != m_lastPer20MHzDurations)
1137 {
1138 /*
1139 * 8.3.5.12.3: For Clause 27 PHYs, this primitive is generated when (...) the per20bitmap
1140 * parameter changes.
1141 */
1142 NS_LOG_DEBUG("per-20MHz CCA durations changed");
1143 NotifyCcaBusy(Seconds(0), WIFI_CHANLIST_PRIMARY, per20MHzDurations);
1144 }
1145}
1146
1147void
1149{
1150 NS_LOG_FUNCTION(this << duration << channelType);
1151 NS_LOG_DEBUG("CCA busy for " << channelType << " during " << duration.As(Time::S));
1152 const auto per20MHzDurations = GetPer20MHzDurations(ppdu);
1153 NotifyCcaBusy(duration, channelType, per20MHzDurations);
1154}
1155
1156void
1158 WifiChannelListType channelType,
1159 const std::vector<Time>& per20MHzDurations)
1160{
1161 NS_LOG_FUNCTION(this << duration << channelType);
1162 m_state->SwitchMaybeToCcaBusy(duration, channelType, per20MHzDurations);
1163 m_lastPer20MHzDurations = per20MHzDurations;
1164}
1165
1166std::vector<Time>
1168{
1169 NS_LOG_FUNCTION(this);
1170
1171 /**
1172 * 27.3.20.6.5 Per 20 MHz CCA sensitivity:
1173 * If the operating channel width is greater than 20 MHz and the PHY issues a PHY-CCA.indication
1174 * primitive, the PHY shall set the per20bitmap to indicate the busy/idle status of each 20 MHz
1175 * subchannel.
1176 */
1177 if (m_wifiPhy->GetChannelWidth() < MHz_u{40})
1178 {
1179 return {};
1180 }
1181
1182 std::vector<Time> per20MhzDurations{};
1185 for (auto index : indices)
1186 {
1187 auto band = m_wifiPhy->GetBand(MHz_u{20}, index);
1188 /**
1189 * A signal is present on the 20 MHz subchannel at or above a threshold of –62 dBm at the
1190 * receiver's antenna(s). The PHY shall indicate that the 20 MHz subchannel is busy a period
1191 * aCCATime after the signal starts and shall continue to indicate the 20 MHz subchannel is
1192 * busy while the threshold continues to be exceeded.
1193 */
1194 auto ccaThreshold = m_wifiPhy->GetCcaEdThreshold();
1195 auto delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThreshold, band);
1196
1197 if (ppdu)
1198 {
1199 const auto subchannelMinFreq = m_wifiPhy->GetFrequency() -
1200 (m_wifiPhy->GetChannelWidth() / 2) + (index * MHz_u{20});
1201 const auto subchannelMaxFreq = subchannelMinFreq + MHz_u{20};
1202 const auto ppduBw = ppdu->GetTxVector().GetChannelWidth();
1203
1204 if (ppduBw <= m_wifiPhy->GetChannelWidth() &&
1205 ppdu->DoesOverlapChannel(subchannelMinFreq, subchannelMaxFreq))
1206 {
1207 std::optional<dBm_u> obssPdLevel{std::nullopt};
1209 {
1210 obssPdLevel = m_obssPdAlgorithm->GetObssPdLevel();
1211 }
1212 switch (static_cast<uint16_t>(ppduBw))
1213 {
1214 case 20:
1215 case 22:
1216 /**
1217 * A 20 MHz non-HT, HT_MF, HT_GF, VHT, or HE PPDU at or above max(–72 dBm, OBSS_
1218 * PDlevel) at the receiver's antenna(s) is present on the 20 MHz subchannel.
1219 * The PHY shall indicate that the 20 MHz subchannel is busy with > 90%
1220 * probability within a period aCCAMidTime.
1221 */
1222 ccaThreshold = obssPdLevel.has_value()
1223 ? std::max(dBm_u{-72.0}, obssPdLevel.value())
1224 : dBm_u{-72.0};
1225 band = m_wifiPhy->GetBand(MHz_u{20}, index);
1226 break;
1227 case 40:
1228 /**
1229 * The 20 MHz subchannel is in a channel on which a 40 MHz non-HT duplicate,
1230 * HT_MF, HT_GF, VHT or HE PPDU at or above max(–72 dBm, OBSS_PDlevel + 3 dB) at
1231 * the receiver's antenna(s) is present. The PHY shall indicate that the 20 MHz
1232 * subchannel is busy with > 90% probability within a period aCCAMidTime.
1233 */
1234 ccaThreshold = obssPdLevel.has_value()
1235 ? std::max(dBm_u{-72.0}, obssPdLevel.value() + dB_u{3})
1236 : dBm_u{-72.0};
1237 band = m_wifiPhy->GetBand(MHz_u{40}, std::floor(index / 2));
1238 break;
1239 case 80:
1240 /**
1241 * The 20 MHz subchannel is in a channel on which an 80 MHz non-HT duplicate,
1242 * VHT or HE PPDU at or above max(–69 dBm, OBSS_PDlevel + 6 dB) at the
1243 * receiver's antenna(s) is present. The PHY shall indicate that the 20 MHz
1244 * subchannel is busy with > 90% probability within a period aCCAMidTime.
1245 */
1246 ccaThreshold = obssPdLevel.has_value()
1247 ? std::max(dBm_u{-69.0}, obssPdLevel.value() + dB_u{6})
1248 : dBm_u{-69.0};
1249 band = m_wifiPhy->GetBand(MHz_u{80}, std::floor(index / 4));
1250 break;
1251 case 160:
1252 // Not defined in the standard: keep -62 dBm
1253 break;
1254 default:
1255 NS_ASSERT_MSG(false, "Invalid channel width: " << ppduBw);
1256 }
1257 }
1258 const auto ppduCcaDuration = GetDelayUntilCcaEnd(ccaThreshold, band);
1259 delayUntilCcaEnd = std::max(delayUntilCcaEnd, ppduCcaDuration);
1260 }
1261 per20MhzDurations.push_back(delayUntilCcaEnd);
1262 }
1263
1264 return per20MhzDurations;
1265}
1266
1267uint64_t
1269{
1270 NS_LOG_FUNCTION(this << txVector);
1271 uint64_t uid;
1272 if (txVector.IsUlMu() || txVector.IsTriggerResponding())
1273 {
1274 // Use UID of PPDU containing trigger frame to identify resulting HE TB PPDUs, since the
1275 // latter should immediately follow the former
1277 NS_ASSERT(uid != UINT64_MAX);
1278 }
1279 else
1280 {
1281 uid = m_globalPpduUid++;
1282 }
1283 m_previouslyTxPpduUid = uid; // to be able to identify solicited HE TB PPDUs
1284 return uid;
1285}
1286
1287Time
1289{
1290 auto heConfiguration = m_wifiPhy->GetDevice()->GetHeConfiguration();
1291 NS_ASSERT(heConfiguration);
1292 // DoStartReceivePayload(), which is called when we start receiving the Data field,
1293 // computes the max offset among TB PPDUs based on the begin MU payload RX events,
1294 // which are scheduled by StartReceivePreamble() when starting the reception of the
1295 // HE portion. Therefore, the maximum delay cannot exceed the duration of the
1296 // training fields that are between the start of the HE portion and the start
1297 // of the Data field.
1298 auto maxDelay = GetDuration(WIFI_PPDU_FIELD_TRAINING, txVector);
1299 if (heConfiguration->m_maxTbPpduDelay.IsStrictlyPositive())
1300 {
1301 maxDelay = Min(maxDelay, heConfiguration->m_maxTbPpduDelay);
1302 }
1303 return maxDelay;
1304}
1305
1308{
1309 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1310 NS_ASSERT(hePpdu);
1311 HePpdu::TxPsdFlag flag = hePpdu->GetTxPsdFlag();
1312 return GetTxPowerSpectralDensity(txPower, ppdu, flag);
1313}
1314
1318 HePpdu::TxPsdFlag flag) const
1319{
1320 const auto& txVector = ppdu->GetTxVector();
1321 const auto& centerFrequencies = ppdu->GetTxCenterFreqs();
1322 auto channelWidth = txVector.GetChannelWidth();
1323 auto printFrequencies = [](const std::vector<MHz_u>& v) {
1324 std::stringstream ss;
1325 for (const auto& centerFrequency : v)
1326 {
1327 ss << centerFrequency << " ";
1328 }
1329 return ss.str();
1330 };
1331 NS_LOG_FUNCTION(this << printFrequencies(centerFrequencies) << channelWidth << txPower
1332 << txVector);
1333 const auto& puncturedSubchannels = txVector.GetInactiveSubchannels();
1334 if (!puncturedSubchannels.empty())
1335 {
1336 const auto p20Index = m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20});
1337 const auto& indices =
1339 const auto p20IndexInBitmap = p20Index - *(indices.cbegin());
1340 NS_ASSERT(
1341 !puncturedSubchannels.at(p20IndexInBitmap)); // the primary channel cannot be punctured
1342 }
1343 const auto& txMaskRejectionParams = GetTxMaskRejectionParams();
1344 switch (ppdu->GetType())
1345 {
1346 case WIFI_PPDU_TYPE_UL_MU: {
1347 if (flag == HePpdu::PSD_NON_HE_PORTION)
1348 {
1349 // non-HE portion is sent only on the 20 MHz channels covering the RU
1350 const auto staId = GetStaId(ppdu);
1351 const auto ruWidth = WifiRu::GetBandwidth(WifiRu::GetRuType(txVector.GetRu(staId)));
1352 channelWidth = (ruWidth < MHz_u{20}) ? MHz_u{20} : ruWidth;
1355 channelWidth,
1356 txPower,
1357 GetGuardBandwidth(channelWidth),
1358 std::get<0>(txMaskRejectionParams),
1359 std::get<1>(txMaskRejectionParams),
1360 std::get<2>(txMaskRejectionParams),
1361 puncturedSubchannels);
1362 }
1363 else
1364 {
1365 const auto band = GetRuBandForTx(txVector, GetStaId(ppdu)).indices;
1367 centerFrequencies,
1368 channelWidth,
1369 txPower,
1370 GetGuardBandwidth(channelWidth),
1371 band);
1372 }
1373 }
1374 case WIFI_PPDU_TYPE_DL_MU: {
1375 if (flag == HePpdu::PSD_NON_HE_PORTION)
1376 {
1378 centerFrequencies,
1379 channelWidth,
1380 txPower,
1381 GetGuardBandwidth(channelWidth),
1382 std::get<0>(txMaskRejectionParams),
1383 std::get<1>(txMaskRejectionParams),
1384 std::get<2>(txMaskRejectionParams),
1385 puncturedSubchannels);
1386 }
1387 else
1388 {
1390 centerFrequencies,
1391 channelWidth,
1392 txPower,
1393 GetGuardBandwidth(channelWidth),
1394 std::get<0>(txMaskRejectionParams),
1395 std::get<1>(txMaskRejectionParams),
1396 std::get<2>(txMaskRejectionParams),
1397 puncturedSubchannels);
1398 }
1399 }
1400 case WIFI_PPDU_TYPE_SU:
1401 default: {
1402 NS_ASSERT(puncturedSubchannels.empty());
1404 centerFrequencies,
1405 channelWidth,
1406 txPower,
1407 GetGuardBandwidth(channelWidth),
1408 std::get<0>(txMaskRejectionParams),
1409 std::get<1>(txMaskRejectionParams),
1410 std::get<2>(txMaskRejectionParams));
1411 }
1412 }
1413}
1414
1415std::vector<MHz_u>
1417{
1418 NS_LOG_FUNCTION(this << ppdu << staId);
1419 const auto& txVector = ppdu->GetTxVector();
1420 NS_ASSERT(txVector.IsUlMu() && (txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE));
1421 auto centerFrequencies = ppdu->GetTxCenterFreqs();
1422 const auto currentWidth = txVector.GetChannelWidth();
1423
1424 auto ru = txVector.GetRu(staId);
1425 const auto nonOfdmaWidth = GetNonOfdmaWidth(ru);
1426 if (nonOfdmaWidth != currentWidth)
1427 {
1428 // Obtain the index of the non-OFDMA portion
1429 const auto nonOfdmaRu =
1430 WifiRu::FindOverlappingRu(currentWidth, ru, WifiRu::GetRuType(nonOfdmaWidth));
1431
1432 const MHz_u startingFrequency = centerFrequencies.front() - (currentWidth / 2);
1433 centerFrequencies.front() =
1434 startingFrequency +
1435 nonOfdmaWidth *
1437 nonOfdmaRu,
1438 currentWidth,
1440 1) +
1441 nonOfdmaWidth / 2;
1442 }
1443 return centerFrequencies;
1444}
1445
1446void
1448{
1449 NS_LOG_FUNCTION(this << ppdu);
1450 const auto& txVector = ppdu->GetTxVector();
1451 if (auto mac = m_wifiPhy->GetDevice()->GetMac(); mac && (mac->GetTypeOfStation() == AP))
1452 {
1453 m_currentTxVector = txVector;
1454 }
1455 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU || ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
1456 {
1457 const auto nonHeTxPower =
1459
1460 // temporarily set WifiPpdu flag to PSD_HE_PORTION for correct calculation of TX power for
1461 // the HE portion
1462 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1463 NS_ASSERT(hePpdu);
1464 hePpdu->SetTxPsdFlag(HePpdu::PSD_HE_PORTION);
1465 const auto heTxPower = m_wifiPhy->GetTxPowerForTransmission(ppdu) + m_wifiPhy->GetTxGain();
1466 hePpdu->SetTxPsdFlag(HePpdu::PSD_NON_HE_PORTION);
1467
1468 // non-HE portion
1469 auto nonHePortionDuration = ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU
1472 auto nonHeTxPowerSpectrum =
1474 Transmit(nonHePortionDuration,
1475 ppdu,
1476 nonHeTxPower,
1477 nonHeTxPowerSpectrum,
1478 "non-HE portion transmission");
1479
1480 // HE portion
1481 auto hePortionDuration = ppdu->GetTxDuration() - nonHePortionDuration;
1482 auto heTxPowerSpectrum =
1484 Simulator::Schedule(nonHePortionDuration,
1486 this,
1487 ppdu,
1488 heTxPower,
1489 heTxPowerSpectrum,
1490 hePortionDuration);
1491 }
1492 else
1493 {
1494 VhtPhy::StartTx(ppdu);
1495 }
1496}
1497
1498void
1500 dBm_u txPower,
1501 Ptr<SpectrumValue> txPowerSpectrum,
1502 Time hePortionDuration)
1503{
1504 NS_LOG_FUNCTION(this << ppdu << txPower << hePortionDuration);
1505 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1506 NS_ASSERT(hePpdu);
1507 hePpdu->SetTxPsdFlag(HePpdu::PSD_HE_PORTION);
1508 Transmit(hePortionDuration, ppdu, txPower, txPowerSpectrum, "HE portion transmission");
1509}
1510
1511Time
1513 const WifiTxVector& txVector,
1514 WifiPhyBand band) const
1515{
1516 if (txVector.IsUlMu())
1517 {
1519 return ConvertLSigLengthToHeTbPpduDuration(txVector.GetLength(), txVector, band);
1520 }
1521
1522 Time maxDuration;
1523 for (auto& staIdPsdu : psduMap)
1524 {
1525 if (txVector.IsDlMu())
1526 {
1528 NS_ABORT_MSG_IF(!txVector.GetHeMuUserInfoMap().contains(staIdPsdu.first),
1529 "STA-ID in psduMap (" << staIdPsdu.first
1530 << ") should be referenced in txVector");
1531 }
1532 Time current = WifiPhy::CalculateTxDuration(staIdPsdu.second->GetSize(),
1533 txVector,
1534 band,
1535 staIdPsdu.first);
1536 if (current > maxDuration)
1537 {
1538 maxDuration = current;
1539 }
1540 }
1541 NS_ASSERT(maxDuration.IsStrictlyPositive());
1542 return maxDuration;
1543}
1544
1545void
1547{
1548 for (uint8_t i = 0; i < 12; ++i)
1549 {
1550 GetHeMcs(i);
1551 }
1552}
1553
1555HePhy::GetHeMcs(uint8_t index)
1556{
1557#define CASE(x) \
1558 case x: \
1559 return GetHeMcs##x();
1560
1561 switch (index)
1562 {
1563 CASE(0)
1564 CASE(1)
1565 CASE(2)
1566 CASE(3)
1567 CASE(4)
1568 CASE(5)
1569 CASE(6)
1570 CASE(7)
1571 CASE(8)
1572 CASE(9)
1573 CASE(10)
1574 CASE(11)
1575 default:
1576 NS_ABORT_MSG("Inexistent index (" << +index << ") requested for HE");
1577 return WifiMode();
1578 }
1579#undef CASE
1580}
1581
1582#define GET_HE_MCS(x) \
1583 WifiMode HePhy::GetHeMcs##x() \
1584 { \
1585 static WifiMode mcs = CreateHeMcs(x); \
1586 return mcs; \
1587 }
1588
1589GET_HE_MCS(0)
1590GET_HE_MCS(1)
1591GET_HE_MCS(2)
1592GET_HE_MCS(3)
1593GET_HE_MCS(4)
1594GET_HE_MCS(5)
1595GET_HE_MCS(6)
1596GET_HE_MCS(7)
1597GET_HE_MCS(8)
1598GET_HE_MCS(9)
1599GET_HE_MCS(10)
1600GET_HE_MCS(11)
1601#undef GET_HE_MCS
1602
1603WifiMode
1605{
1606 NS_ASSERT_MSG(index <= 11, "HeMcs index must be <= 11!");
1607 return WifiModeFactory::CreateWifiMcs("HeMcs" + std::to_string(index),
1608 index,
1610 false,
1617}
1618
1620HePhy::GetCodeRate(uint8_t mcsValue)
1621{
1622 switch (mcsValue)
1623 {
1624 case 10:
1625 return WIFI_CODE_RATE_3_4;
1626 case 11:
1627 return WIFI_CODE_RATE_5_6;
1628 default:
1629 return VhtPhy::GetCodeRate(mcsValue);
1630 }
1631}
1632
1633uint16_t
1635{
1636 switch (mcsValue)
1637 {
1638 case 10:
1639 case 11:
1640 return 1024;
1641 default:
1642 return VhtPhy::GetConstellationSize(mcsValue);
1643 }
1644}
1645
1646uint64_t
1647HePhy::GetPhyRate(uint8_t mcsValue, MHz_u channelWidth, Time guardInterval, uint8_t nss)
1648{
1649 const auto codeRate = GetCodeRate(mcsValue);
1650 const auto dataRate = GetDataRate(mcsValue, channelWidth, guardInterval, nss);
1651 return HtPhy::CalculatePhyRate(codeRate, dataRate);
1652}
1653
1654uint64_t
1655HePhy::GetPhyRateFromTxVector(const WifiTxVector& txVector, uint16_t staId /* = SU_STA_ID */)
1656{
1657 auto bw = txVector.GetChannelWidth();
1658 if (txVector.IsMu())
1659 {
1660 bw = WifiRu::GetBandwidth(WifiRu::GetRuType(txVector.GetRu(staId)));
1661 }
1662 return HePhy::GetPhyRate(txVector.GetMode(staId).GetMcsValue(),
1663 bw,
1664 txVector.GetGuardInterval(),
1665 txVector.GetNss(staId));
1666}
1667
1668uint64_t
1669HePhy::GetDataRateFromTxVector(const WifiTxVector& txVector, uint16_t staId /* = SU_STA_ID */)
1670{
1671 auto bw = txVector.GetChannelWidth();
1672 if (txVector.IsMu())
1673 {
1674 bw = WifiRu::GetBandwidth(WifiRu::GetRuType(txVector.GetRu(staId)));
1675 }
1676 return HePhy::GetDataRate(txVector.GetMode(staId).GetMcsValue(),
1677 bw,
1678 txVector.GetGuardInterval(),
1679 txVector.GetNss(staId));
1680}
1681
1682uint64_t
1683HePhy::GetDataRate(uint8_t mcsValue, MHz_u channelWidth, Time guardInterval, uint8_t nss)
1684{
1685 [[maybe_unused]] const auto gi = guardInterval.GetNanoSeconds();
1686 NS_ASSERT((gi == 800) || (gi == 1600) || (gi == 3200));
1687 NS_ASSERT(nss <= 8);
1688 return HtPhy::CalculateDataRate(GetSymbolDuration(guardInterval),
1689 GetUsableSubcarriers(channelWidth),
1690 static_cast<uint16_t>(log2(GetConstellationSize(mcsValue))),
1692 nss);
1693}
1694
1695uint16_t
1697{
1698 switch (static_cast<uint16_t>(channelWidth))
1699 {
1700 case 2: // 26-tone RU
1701 return 24;
1702 case 4: // 52-tone RU
1703 return 48;
1704 case 8: // 106-tone RU
1705 return 102;
1706 case 20:
1707 return 234;
1708 case 40:
1709 return 468;
1710 case 80:
1711 return 980;
1712 case 160:
1713 return 1960;
1714 default:
1715 NS_ASSERT_MSG(false, "Invalid channel width: " << channelWidth);
1716 return 234;
1717 }
1718}
1719
1720Time
1722{
1723 return NanoSeconds(12800) + guardInterval;
1724}
1725
1726uint64_t
1728{
1729 const auto codeRate = GetCodeRate(mcsValue);
1730 const auto constellationSize = GetConstellationSize(mcsValue);
1731 return CalculateNonHtReferenceRate(codeRate, constellationSize);
1732}
1733
1734uint64_t
1735HePhy::CalculateNonHtReferenceRate(WifiCodeRate codeRate, uint16_t constellationSize)
1736{
1737 uint64_t dataRate;
1738 switch (constellationSize)
1739 {
1740 case 1024:
1741 if (codeRate == WIFI_CODE_RATE_3_4 || codeRate == WIFI_CODE_RATE_5_6)
1742 {
1743 dataRate = 54000000;
1744 }
1745 else
1746 {
1747 NS_FATAL_ERROR("Trying to get reference rate for a MCS with wrong combination of "
1748 "coding rate and modulation");
1749 }
1750 break;
1751 default:
1752 dataRate = VhtPhy::CalculateNonHtReferenceRate(codeRate, constellationSize);
1753 }
1754 return dataRate;
1755}
1756
1757bool
1758HePhy::IsAllowed(const WifiTxVector& /*txVector*/)
1759{
1760 return true;
1761}
1762
1765{
1766 uint16_t staId = SU_STA_ID;
1767
1768 if (IsUlMu(txVector.GetPreambleType()))
1769 {
1770 NS_ASSERT(txVector.GetHeMuUserInfoMap().size() == 1);
1771 staId = txVector.GetHeMuUserInfoMap().begin()->first;
1772 }
1773
1774 return WifiConstPsduMap({{staId, psdu}});
1775}
1776
1779{
1780 return 6500631;
1781}
1782
1783bool
1785{
1786 /*
1787 * The PHY shall not issue a PHY-RXSTART.indication primitive in response to a PPDU
1788 * that does not overlap the primary channel, unless the PHY at an AP receives the
1789 * HE TB PPDU solicited by the AP. For the HE TB PPDU solicited by the AP, the PHY
1790 * shall issue a PHY-RXSTART.indication primitive for a PPDU received in the primary
1791 * or at the secondary 20 MHz channel, the secondary 40 MHz channel, or the secondary
1792 * 80 MHz channel.
1793 */
1794 Ptr<WifiMac> mac = m_wifiPhy->GetDevice() ? m_wifiPhy->GetDevice()->GetMac() : nullptr;
1795 if (ppdu->GetTxVector().IsUlMu() && mac && mac->GetTypeOfStation() == AP)
1796 {
1797 return true;
1798 }
1799 return VhtPhy::CanStartRx(ppdu);
1800}
1801
1804{
1805 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
1806 {
1807 Ptr<const WifiPpdu> rxPpdu;
1808 if ((m_trigVectorExpirationTime.has_value()) &&
1810 {
1811 // We only copy if the AP that is expecting a HE TB PPDU, since the content
1812 // of the TXVECTOR is reconstructed from the TRIGVECTOR, hence the other RX
1813 // PHYs should not have this information.
1814 rxPpdu = ppdu->Copy();
1815 }
1816 else
1817 {
1818 rxPpdu = ppdu;
1819 }
1820 auto hePpdu = DynamicCast<const HePpdu>(rxPpdu);
1821 NS_ASSERT(hePpdu);
1822 hePpdu->UpdateTxVectorForUlMu(m_trigVector);
1823 return rxPpdu;
1824 }
1825 return VhtPhy::GetRxPpduFromTxPpdu(ppdu);
1826}
1827
1828std::vector<WifiSpectrumBandIndices>
1830{
1831 NS_ASSERT_MSG(info.bandWidth <= info.totalWidth,
1832 "Bandwidth (" << info.bandWidth
1833 << ") cannot exceed total operating channel width ("
1834 << info.totalWidth << ")");
1835 std::vector<WifiSpectrumBandIndices> convertedSubcarriers{};
1836 const auto guardBandwidth{info.guardBandwidth / info.centerFrequencies.size()};
1837 const auto nGuardBands =
1838 static_cast<uint32_t>(((2 * MHzToHz(guardBandwidth)) / info.subcarrierSpacing) + 0.5);
1839 auto bw{info.bandWidth};
1840 if (bw > (info.totalWidth / info.centerFrequencies.size()))
1841 {
1842 NS_ASSERT(info.bandIndex == 0);
1843 bw /= info.centerFrequencies.size();
1844 }
1845 // Figures 27-5 to 27-7 of IEEE 802.11ax-2021: the number of guard subcarriers is 6 for 20 MHz
1846 // MHz HE PPDUs and 12 for 40/80/160 MHz HE PPDUs
1847 const uint32_t guardSubcarriers = (bw < MHz_u{40}) ? 6 : 12;
1848 const auto refRu = WifiRu::GetRuType(bw);
1849 const auto offset = WifiRu::GetSubcarrierGroup(bw, refRu, 1, info.mc).back().second;
1850 uint32_t centerFrequencyIndex = (nGuardBands / 2) + guardSubcarriers + offset;
1851 const auto numBandsInBand = static_cast<size_t>(MHzToHz(bw) / info.subcarrierSpacing);
1852 centerFrequencyIndex += numBandsInBand * info.bandIndex;
1853 // start and stop subcarriers might be in different frequency segments, hence define a low and a
1854 // high center frequency
1855 auto centerFrequencyIndexLow = centerFrequencyIndex;
1856 auto centerFrequencyIndexHigh = centerFrequencyIndex;
1857 if (info.centerFrequencies.size() > 1)
1858 {
1859 const auto numBandsBetweenSegments =
1861 info.totalWidth,
1862 info.subcarrierSpacing);
1863 if (info.subcarrierRange.first > 0)
1864 {
1865 centerFrequencyIndexLow += numBandsBetweenSegments;
1866 }
1867 if (info.subcarrierRange.second > 0)
1868 {
1869 centerFrequencyIndexHigh += numBandsBetweenSegments;
1870 }
1871 }
1872 convertedSubcarriers.emplace_back(centerFrequencyIndexLow + info.subcarrierRange.first,
1873 centerFrequencyIndexHigh + info.subcarrierRange.second);
1874 return convertedSubcarriers;
1875}
1876
1877} // namespace ns3
1878
1879namespace
1880{
1881
1882/**
1883 * Constructor class for HE modes
1884 */
1894
1895} // namespace
#define Max(a, b)
#define Min(a, b)
Constructor class for HE modes.
Definition he-phy.cc:1886
bool IsNull() const
Check for null implementation.
Definition callback.h:555
std::optional< WifiTxVector > m_trigVector
the TRIGVECTOR
Definition he-phy.h:565
Time GetLSigDuration(WifiPreamble preamble) const override
Definition he-phy.cc:177
virtual Time CalculateNonHeDurationForHeTb(const WifiTxVector &txVector) const
Definition he-phy.cc:296
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:1683
static Time ConvertLSigLengthToHeTbPpduDuration(uint16_t length, const WifiTxVector &txVector, WifiPhyBand band)
Definition he-phy.cc:282
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:1647
uint64_t GetCurrentHeTbPpduUid() const
Definition he-phy.cc:1065
Ptr< Event > DoGetEvent(Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPowersW) override
Get the event corresponding to the incoming PPDU.
Definition he-phy.cc:452
void CancelAllEvents() override
Cancel and clear all running events.
Definition he-phy.cc:407
void SetObssPdAlgorithm(const Ptr< ObssPdAlgorithm > algorithm)
Sets the OBSS-PD algorithm.
Definition he-phy.cc:696
static void InitializeModes()
Initialize all HE modes.
Definition he-phy.cc:1546
void DoAbortCurrentReception(WifiPhyRxfailureReason reason) override
Perform amendment-specific actions before aborting the current reception.
Definition he-phy.cc:419
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:1016
void StartReceiveMuPayload(Ptr< Event > event)
Start receiving the PSDU (i.e.
Definition he-phy.cc:926
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:723
virtual Time CalculateNonHeDurationForHeMu(const WifiTxVector &txVector) const
Definition he-phy.cc:305
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:567
Time GetSigBDuration(const WifiTxVector &txVector) const override
Definition he-phy.cc:230
static WifiMode CreateHeMcs(uint8_t index)
Create and return the HE MCS corresponding to the provided index.
Definition he-phy.cc:1604
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:1555
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:1764
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:1735
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:1499
MHz_u GetNonOfdmaWidth(WifiRu::RuSpec ru) const
Get the width of the non-OFDMA portion of an HE TB PPDU.
Definition he-phy.cc:1052
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:1784
void SetEndOfHeSigACallback(EndOfHeSigACallback callback)
Set a callback for a end of HE-SIG-A.
Definition he-phy.cc:708
uint64_t m_previouslyTxPpduUid
UID of the previously sent PPDU, used by AP to recognize response HE TB PPDUs.
Definition he-phy.h:556
static WifiCodeRate GetCodeRate(uint8_t mcsValue)
Return the coding rate corresponding to the supplied HE MCS index.
Definition he-phy.cc:1620
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:1447
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:585
EndOfHeSigACallback m_endOfHeSigACallback
end of HE-SIG-A callback
Definition he-phy.h:564
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:540
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:1268
Time CalculateTxDuration(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, WifiPhyBand band) const override
Definition he-phy.cc:1512
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:1655
Ptr< ObssPdAlgorithm > m_obssPdAlgorithm
OBSS-PD algorithm.
Definition he-phy.h:628
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:1089
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:967
MHz_u GetMeasurementChannelWidth(const Ptr< const WifiPpdu > ppdu) const override
Return the channel width used to measure the RSSI.
Definition he-phy.cc:1071
Ptr< ObssPdAlgorithm > GetObssPdAlgorithm() const
Gets the OBSS-PD algorithm.
Definition he-phy.cc:702
uint8_t GetBssColor() const
Definition he-phy.cc:552
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:250
uint8_t GetNumberBccEncoders(const WifiTxVector &txVector) const override
Definition he-phy.cc:315
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:1288
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:518
static bool IsAllowed(const WifiTxVector &txVector)
Check whether the combination in TXVECTOR is allowed.
Definition he-phy.cc:1758
std::size_t m_rxHeTbPpdus
Number of successfully received HE TB PPDUS.
Definition he-phy.h:627
~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:345
void NotifyEndOfHeSigA(HeSigAParameters params)
Fire a EndOfHeSigA callback (if connected) once HE-SIG-A field has been received.
Definition he-phy.cc:714
Ptr< SpectrumValue > GetTxPowerSpectralDensity(Watt_u txPower, Ptr< const WifiPpdu > ppdu) const override
Definition he-phy.cc:1307
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:854
uint64_t m_currentMuPpduUid
UID of the HE MU or HE TB PPDU being received.
Definition he-phy.h:558
uint32_t GetMaxPsduSize() const override
Get the maximum PSDU size in bytes.
Definition he-phy.cc:1778
static const PpduFormats m_hePpduFormats
HE PPDU formats.
Definition he-phy.h:625
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:1669
std::map< uint16_t, EventId > m_beginMuPayloadRxEvents
the beginning of the MU payload reception events (indexed by STA-ID)
Definition he-phy.h:561
virtual 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:1167
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:872
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:1803
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:745
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:567
static Time GetSymbolDuration(Time guardInterval)
Definition he-phy.cc:1721
void SetTrigVector(const WifiTxVector &trigVector, Time validity)
Set the TRIGVECTOR and the associated expiration time.
Definition he-phy.cc:330
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:263
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:1727
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:1119
Time DoStartReceivePayload(Ptr< Event > event) override
Start receiving the PSDU (i.e.
Definition he-phy.cc:784
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:357
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:602
std::optional< Time > m_trigVectorExpirationTime
expiration time of the TRIGVECTOR
Definition he-phy.h:566
void DoEndReceivePayload(Ptr< const WifiPpdu > ppdu) override
Perform amendment-specific actions at the end of the reception of the payload.
Definition he-phy.cc:882
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:437
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:1416
Time GetSigADuration(WifiPreamble preamble) const override
Definition he-phy.cc:204
Time GetTrainingDuration(const WifiTxVector &txVector, uint8_t nDataLtf, uint8_t nExtensionLtf=0) const override
Definition he-phy.cc:183
static std::vector< WifiSpectrumBandIndices > ConvertRuSubcarriers(const RuSubcarriersInfo &info)
This is a helper function to convert RU subcarriers, which are relative to the center frequency subca...
Definition he-phy.cc:1829
std::vector< Time > m_lastPer20MHzDurations
Hold the last per-20 MHz CCA durations vector.
Definition he-phy.h:629
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:1148
static uint16_t GetConstellationSize(uint8_t mcsValue)
Return the constellation size corresponding to the supplied HE MCS index.
Definition he-phy.cc:1634
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:981
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, WifiModulationClass mc, const RuAllocation &ruAllocation, std::optional< Center26ToneRuIndication > center26ToneRuIndication, bool sigBCompression, std::size_t numMuMimoUsers)
Get variable length HE SIG-B field size.
Definition he-ppdu.cc:832
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:658
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 ht-phy.cc:889
uint8_t m_bssMembershipSelector
the BSS membership selector
Definition ht-phy.h:570
uint8_t m_maxMcsIndexPerSs
the maximum MCS index per spatial stream as defined by the standard
Definition ht-phy.h:568
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:707
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:673
uint8_t m_maxSupportedMcsIndexPerSs
the maximum supported MCS index per spatial stream
Definition ht-phy.h:569
static uint16_t GetUsableSubcarriers()
Definition ofdm-phy.cc:623
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:680
MHz_u GetMeasurementChannelWidth(const Ptr< const WifiPpdu > ppdu) const override
Return the channel width used to measure the RSSI.
Definition ofdm-phy.cc:657
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:942
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:964
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:941
std::vector< EventId > m_endOfMpduEvents
the end of MPDU events (only used for A-MPDUs)
Definition phy-entity.h:948
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:531
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:967
std::vector< EventId > m_endRxPayloadEvents
the end of receive events (only one unless UL MU reception)
Definition phy-entity.h:953
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:961
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:945
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:561
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, Hz_u 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:403
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:385
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:155
static WifiMode GetVhtMcs5()
Return MCS 5 from VHT MCS values.
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:476
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:527
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:399
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:117
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:305
represent a single transmission mode
Definition wifi-mode.h:38
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
Definition wifi-mode.cc:110
uint8_t GetMcsValue() const
Definition wifi-mode.cc:151
dB_u GetTxGain() const
Return the transmission gain.
Definition wifi-phy.cc:618
Hz_u GetSubcarrierSpacing() const
Definition wifi-phy.cc:2367
MHz_u GetFrequency() const
Definition wifi-phy.cc:1075
uint8_t GetMaxSupportedRxSpatialStreams() const
Definition wifi-phy.cc:1372
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1563
dBm_u GetCcaEdThreshold() const
Return the CCA energy detection threshold.
Definition wifi-phy.cc:542
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:1678
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition wifi-phy.cc:1057
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:810
MHz_u GetChannelWidth() const
Definition wifi-phy.cc:1087
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition wifi-phy.cc:656
dBm_u GetTxPowerForTransmission(Ptr< const WifiPpdu > ppdu) const
Compute the transmit power for the next transmission.
Definition wifi-phy.cc:2300
uint64_t GetPreviouslyRxPpduUid() const
Definition wifi-phy.cc:1940
Time GetLastRxEndTime() const
Return the end time of the last received packet.
Definition wifi-phy.cc:2207
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:1069
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition wifi-phy.cc:1556
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.
std::variant< HeRu::RuSpec, EhtRu::RuSpec > RuSpec
variant of the RU specification
Definition wifi-ru.h:27
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 wifi-ru.cc:226
static MHz_u GetBandwidth(RuType ruType)
Get the approximate bandwidth occupied by a RU.
Definition wifi-ru.cc:78
static RuType GetRuType(RuSpec ru)
Get the type of a given RU.
Definition wifi-ru.cc:45
static SubcarrierGroup GetSubcarrierGroup(MHz_u bw, RuType ruType, std::size_t phyIndex, WifiModulationClass mc)
Get the subcarrier group of the RU having the given PHY index among all the RUs of the given type (nu...
Definition wifi-ru.cc:142
static std::size_t GetPhyIndex(RuSpec ru, MHz_u bw, uint8_t p20Index)
Get the RU PHY index.
Definition wifi-ru.cc:57
static std::size_t GetIndex(RuSpec ru)
Get the index of a given RU.
Definition wifi-ru.cc:51
static Ptr< SpectrumValue > CreateDuplicated20MhzTxPowerSpectralDensity(const std::vector< MHz_u > &centerFrequencies, MHz_u channelWidth, Watt_u txPower, MHz_u guardBandwidth, dBr_u minInnerBand=dBr_u{-20}, dBr_u minOuterband=dBr_u{-28}, dBr_u lowestPoint=dBr_u{-40}, const std::vector< bool > &puncturedSubchannels={})
Create a transmit power spectral density corresponding to OFDM duplicated over multiple 20 MHz subcha...
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=dBr_u{-20}, dBr_u minOuterband=dBr_u{-28}, dBr_u lowestPoint=dBr_u{-40}, const std::vector< bool > &puncturedSubchannels={})
Create a transmit power spectral density corresponding to OFDM High Efficiency (HE/EHT) (802....
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.
std::optional< Center26ToneRuIndication > GetCenter26ToneRuIndication() const
Get CENTER_26_TONE_RU field This field is present if format is HE_MU and when channel width is set to...
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
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
WifiRu::RuSpec GetRu(uint16_t staId) const
Get the RU specification for the STA-ID.
#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:1369
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Time FemtoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1405
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:60
@ 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:1582
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.
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:38
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:32
@ 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.
Hz_u MHzToHz(MHz_u val)
Convert from MHz to Hz.
Definition wifi-utils.h:113
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
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.
structure containing the information about the RU subcarriers to be able to converted to the indices ...
Definition he-phy.h:433
MHz_u bandWidth
width of the band used for the OFDMA transmission.
Definition he-phy.h:434
Hz_u subcarrierSpacing
subcarrier spacing
Definition he-phy.h:439
MHz_u totalWidth
width of the operating channel
Definition he-phy.h:438
const std::vector< MHz_u > & centerFrequencies
center frequency of each segment
Definition he-phy.h:437
uint8_t bandIndex
index (starting at 0) of the band within the operating channel
Definition he-phy.h:442
MHz_u guardBandwidth
width of the guard band
Definition he-phy.h:436
WifiModulationClass mc
modulation class used for the transmission
Definition he-phy.h:440
SubcarrierRange subcarrierRange
subcarrier range of the RU
Definition he-phy.h:441
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:79
SignalNoiseDbm structure.
Definition wifi-types.h:65
WifiSpectrumBandInfo structure containing info about a spectrum band.
std::vector< WifiSpectrumBandIndices > indices
the start and stop indices for each segment of the band