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),
74 m_currentTxVector(std::nullopt),
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(
221 m_wifiPhy ? m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20}) : 0),
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,
350 m_wifiPhy->GetOperatingChannel(),
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");
528 m_wifiPhy->NotifyRxPpduDrop(ppdu, RXING);
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");
535 m_wifiPhy->NotifyRxPpduDrop(ppdu, RXING);
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
715{
716 if (!m_endOfHeSigACallback.IsNull())
717 {
718 m_endOfHeSigACallback(params);
719 }
720}
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
769 if (nss > m_wifiPhy->GetMaxSupportedRxSpatialStreams())
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,
808 m_wifiPhy->GetPhyBand()) -
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 {
918 NS_ASSERT(m_wifiPhy->GetLastRxEndTime() == Simulator::Now());
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,
993 m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20})),
994 mc);
995 NS_ABORT_MSG_IF(group.empty(), "No subcarrier group found");
996 // for a TX spectrum, the guard bandwidth is a function of the transmission channel width
997 // and the spectrum width equals the transmission channel width (hence bandIndex equals 0)
998 const auto indices = ConvertRuSubcarriers({channelWidth,
999 GetGuardBandwidth(channelWidth),
1000 m_wifiPhy->GetOperatingChannel().GetFrequencies(),
1001 m_wifiPhy->GetChannelWidth(),
1002 m_wifiPhy->GetSubcarrierSpacing(),
1003 mc,
1004 {group.front().first, group.back().second},
1005 0});
1006 WifiSpectrumBandInfo ruBandForTx{};
1007 for (const auto& indicesPerSegment : indices)
1008 {
1009 ruBandForTx.indices.emplace_back(indicesPerSegment);
1010 ruBandForTx.frequencies.emplace_back(
1011 m_wifiPhy->ConvertIndicesToFrequencies(indicesPerSegment));
1012 }
1013 return ruBandForTx;
1014}
1015
1017HePhy::GetRuBandForRx(const WifiTxVector& txVector, uint16_t staId) const
1018{
1019 NS_ASSERT(txVector.IsMu());
1020 auto ru = txVector.GetRu(staId);
1021 const auto channelWidth = txVector.GetChannelWidth();
1022 NS_ASSERT(channelWidth <= m_wifiPhy->GetChannelWidth());
1023 const auto mc = txVector.GetModulationClass();
1024 const auto group = WifiRu::GetSubcarrierGroup(
1025 channelWidth,
1028 channelWidth,
1029 m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20})),
1030 mc);
1031 NS_ABORT_MSG_IF(group.empty(), "No subcarrier group found");
1032 // for an RX spectrum, the guard bandwidth is a function of the operating channel width
1033 // and the spectrum width equals the operating channel width
1034 const auto indices = ConvertRuSubcarriers(
1035 {channelWidth,
1036 GetGuardBandwidth(m_wifiPhy->GetChannelWidth()),
1037 m_wifiPhy->GetOperatingChannel().GetFrequencies(),
1038 m_wifiPhy->GetChannelWidth(),
1039 m_wifiPhy->GetSubcarrierSpacing(),
1040 mc,
1041 {group.front().first, group.back().second},
1042 m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(channelWidth)});
1043 WifiSpectrumBandInfo ruBandForRx{};
1044 for (const auto& indicesPerSegment : indices)
1045 {
1046 ruBandForRx.indices.emplace_back(indicesPerSegment);
1047 ruBandForRx.frequencies.emplace_back(
1048 m_wifiPhy->ConvertIndicesToFrequencies(indicesPerSegment));
1049 }
1050 return ruBandForRx;
1051}
1052
1053MHz_u
1055{
1056 const auto ruType = WifiRu::GetRuType(ru);
1057 if (ruType == RuType::RU_26_TONE && WifiRu::GetIndex(ru) == 19)
1058 {
1059 // the center 26-tone RU in an 80 MHz channel is not fully covered by
1060 // any 20 MHz channel, but only by an 80 MHz channel
1061 return MHz_u{80};
1062 }
1063 return std::max(WifiRu::GetBandwidth(ruType), MHz_u{20});
1064}
1065
1066uint64_t
1068{
1069 return m_currentMuPpduUid;
1070}
1071
1072MHz_u
1074{
1075 auto channelWidth = OfdmPhy::GetMeasurementChannelWidth(ppdu);
1076 /**
1077 * The PHY shall not issue a PHY-RXSTART.indication primitive in response to a PPDU that does
1078 * not overlap the primary channel unless the PHY at an AP receives the HE TB PPDU solicited by
1079 * the AP. For the HE TB PPDU solicited by the AP, the PHY shall issue a PHY-RXSTART.indication
1080 * primitive for a PPDU received in the primary or at the secondary 20 MHz channel, the
1081 * secondary 40 MHz channel, or the secondary 80 MHz channel.
1082 */
1083 if (channelWidth >= MHz_u{40} && ppdu->GetUid() != m_previouslyTxPpduUid)
1084 {
1085 channelWidth = MHz_u{20};
1086 }
1087 return channelWidth;
1088}
1089
1090dBm_u
1092{
1093 if (!ppdu)
1094 {
1095 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1096 }
1097
1098 if (!m_obssPdAlgorithm)
1099 {
1100 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1101 }
1102
1103 if (channelType == WIFI_CHANLIST_PRIMARY)
1104 {
1105 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1106 }
1107
1108 const auto ppduBw = ppdu->GetTxVector().GetChannelWidth();
1109 auto obssPdLevel = m_obssPdAlgorithm->GetObssPdLevel();
1110 auto bw = ppduBw;
1111 while (bw > MHz_u{20})
1112 {
1113 obssPdLevel += dB_u{3};
1114 bw /= 2;
1115 }
1116
1117 return std::max(VhtPhy::GetCcaThreshold(ppdu, channelType), obssPdLevel);
1118}
1119
1120void
1122{
1123 NS_LOG_FUNCTION(this);
1124 const auto ccaIndication = GetCcaIndication(ppdu);
1125 const auto per20MHzDurations = GetPer20MHzDurations(ppdu);
1126 if (ccaIndication.has_value())
1127 {
1128 NS_LOG_DEBUG("CCA busy for " << ccaIndication.value().second << " during "
1129 << ccaIndication.value().first.As(Time::S));
1130 NotifyCcaBusy(ccaIndication.value().first, ccaIndication.value().second, per20MHzDurations);
1131 return;
1132 }
1133 if (ppdu)
1134 {
1135 SwitchMaybeToCcaBusy(nullptr);
1136 return;
1137 }
1138 if (per20MHzDurations != m_lastPer20MHzDurations)
1139 {
1140 /*
1141 * 8.3.5.12.3: For Clause 27 PHYs, this primitive is generated when (...) the per20bitmap
1142 * parameter changes.
1143 */
1144 NS_LOG_DEBUG("per-20MHz CCA durations changed");
1145 NotifyCcaBusy(Seconds(0), WIFI_CHANLIST_PRIMARY, per20MHzDurations);
1146 }
1147}
1148
1149void
1151{
1152 NS_LOG_FUNCTION(this << duration << channelType);
1153 NS_LOG_DEBUG("CCA busy for " << channelType << " during " << duration.As(Time::S));
1154 const auto per20MHzDurations = GetPer20MHzDurations(ppdu);
1155 NotifyCcaBusy(duration, channelType, per20MHzDurations);
1156}
1157
1158void
1160 WifiChannelListType channelType,
1161 const std::vector<Time>& per20MHzDurations)
1162{
1163 NS_LOG_FUNCTION(this << duration << channelType);
1164 m_state->SwitchMaybeToCcaBusy(duration, channelType, per20MHzDurations);
1165 m_lastPer20MHzDurations = per20MHzDurations;
1166}
1167
1168std::vector<Time>
1170{
1171 NS_LOG_FUNCTION(this);
1172
1173 /**
1174 * 27.3.20.6.5 Per 20 MHz CCA sensitivity:
1175 * If the operating channel width is greater than 20 MHz and the PHY issues a PHY-CCA.indication
1176 * primitive, the PHY shall set the per20bitmap to indicate the busy/idle status of each 20 MHz
1177 * subchannel.
1178 */
1179 if (m_wifiPhy->GetChannelWidth() < MHz_u{40})
1180 {
1181 return {};
1182 }
1183
1184 std::vector<Time> per20MhzDurations{};
1185 const auto indices = m_wifiPhy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(
1186 m_wifiPhy->GetChannelWidth());
1187 for (auto index : indices)
1188 {
1189 auto band = m_wifiPhy->GetBand(MHz_u{20}, index);
1190 /**
1191 * A signal is present on the 20 MHz subchannel at or above a threshold of –62 dBm at the
1192 * receiver's antenna(s). The PHY shall indicate that the 20 MHz subchannel is busy a period
1193 * aCCATime after the signal starts and shall continue to indicate the 20 MHz subchannel is
1194 * busy while the threshold continues to be exceeded.
1195 */
1196 auto ccaThreshold = m_wifiPhy->GetCcaEdThreshold();
1197 auto delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThreshold, band);
1198
1199 if (ppdu)
1200 {
1201 const auto subchannelMinFreq = m_wifiPhy->GetFrequency() -
1202 (m_wifiPhy->GetChannelWidth() / 2) + (index * MHz_u{20});
1203 const auto subchannelMaxFreq = subchannelMinFreq + MHz_u{20};
1204 const auto ppduBw = ppdu->GetTxVector().GetChannelWidth();
1205
1206 if (ppduBw <= m_wifiPhy->GetChannelWidth() &&
1207 ppdu->DoesOverlapChannel(subchannelMinFreq, subchannelMaxFreq))
1208 {
1209 std::optional<dBm_u> obssPdLevel{std::nullopt};
1211 {
1212 obssPdLevel = m_obssPdAlgorithm->GetObssPdLevel();
1213 }
1214 switch (static_cast<uint16_t>(ppduBw))
1215 {
1216 case 20:
1217 case 22:
1218 /**
1219 * A 20 MHz non-HT, HT_MF, HT_GF, VHT, or HE PPDU at or above max(–72 dBm, OBSS_
1220 * PDlevel) at the receiver's antenna(s) is present on the 20 MHz subchannel.
1221 * The PHY shall indicate that the 20 MHz subchannel is busy with > 90%
1222 * probability within a period aCCAMidTime.
1223 */
1224 ccaThreshold = obssPdLevel.has_value()
1225 ? std::max(dBm_u{-72.0}, obssPdLevel.value())
1226 : dBm_u{-72.0};
1227 band = m_wifiPhy->GetBand(MHz_u{20}, index);
1228 break;
1229 case 40:
1230 /**
1231 * The 20 MHz subchannel is in a channel on which a 40 MHz non-HT duplicate,
1232 * HT_MF, HT_GF, VHT or HE PPDU at or above max(–72 dBm, OBSS_PDlevel + 3 dB) at
1233 * the receiver's antenna(s) is present. The PHY shall indicate that the 20 MHz
1234 * subchannel is busy with > 90% probability within a period aCCAMidTime.
1235 */
1236 ccaThreshold = obssPdLevel.has_value()
1237 ? std::max(dBm_u{-72.0}, obssPdLevel.value() + dB_u{3})
1238 : dBm_u{-72.0};
1239 band = m_wifiPhy->GetBand(MHz_u{40}, std::floor(index / 2));
1240 break;
1241 case 80:
1242 /**
1243 * The 20 MHz subchannel is in a channel on which an 80 MHz non-HT duplicate,
1244 * VHT or HE PPDU at or above max(–69 dBm, OBSS_PDlevel + 6 dB) at the
1245 * receiver's antenna(s) is present. The PHY shall indicate that the 20 MHz
1246 * subchannel is busy with > 90% probability within a period aCCAMidTime.
1247 */
1248 ccaThreshold = obssPdLevel.has_value()
1249 ? std::max(dBm_u{-69.0}, obssPdLevel.value() + dB_u{6})
1250 : dBm_u{-69.0};
1251 band = m_wifiPhy->GetBand(MHz_u{80}, std::floor(index / 4));
1252 break;
1253 case 160:
1254 // Not defined in the standard: keep -62 dBm
1255 break;
1256 default:
1257 NS_ASSERT_MSG(false, "Invalid channel width: " << ppduBw);
1258 }
1259 }
1260 const auto ppduCcaDuration = GetDelayUntilCcaEnd(ccaThreshold, band);
1261 delayUntilCcaEnd = std::max(delayUntilCcaEnd, ppduCcaDuration);
1262 }
1263 per20MhzDurations.push_back(delayUntilCcaEnd);
1264 }
1265
1266 return per20MhzDurations;
1267}
1268
1269uint64_t
1271{
1272 NS_LOG_FUNCTION(this << txVector);
1273 uint64_t uid;
1274 if (txVector.IsUlMu() || txVector.IsTriggerResponding())
1275 {
1276 // Use UID of PPDU containing trigger frame to identify resulting HE TB PPDUs, since the
1277 // latter should immediately follow the former
1278 uid = m_wifiPhy->GetPreviouslyRxPpduUid();
1279 NS_ASSERT(uid != UINT64_MAX);
1280 }
1281 else
1282 {
1283 uid = m_globalPpduUid++;
1284 }
1285 m_previouslyTxPpduUid = uid; // to be able to identify solicited HE TB PPDUs
1286 return uid;
1287}
1288
1289Time
1291{
1292 auto heConfiguration = m_wifiPhy->GetDevice()->GetHeConfiguration();
1293 NS_ASSERT(heConfiguration);
1294 // DoStartReceivePayload(), which is called when we start receiving the Data field,
1295 // computes the max offset among TB PPDUs based on the begin MU payload RX events,
1296 // which are scheduled by StartReceivePreamble() when starting the reception of the
1297 // HE portion. Therefore, the maximum delay cannot exceed the duration of the
1298 // training fields that are between the start of the HE portion and the start
1299 // of the Data field.
1300 auto maxDelay = GetDuration(WIFI_PPDU_FIELD_TRAINING, txVector);
1301 if (heConfiguration->m_maxTbPpduDelay.IsStrictlyPositive())
1302 {
1303 maxDelay = Min(maxDelay, heConfiguration->m_maxTbPpduDelay);
1304 }
1305 return maxDelay;
1306}
1307
1310{
1311 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1312 NS_ASSERT(hePpdu);
1313 HePpdu::TxPsdFlag flag = hePpdu->GetTxPsdFlag();
1314 return GetTxPowerSpectralDensity(txPower, ppdu, flag);
1315}
1316
1320 HePpdu::TxPsdFlag flag) const
1321{
1322 const auto& txVector = ppdu->GetTxVector();
1323 const auto& centerFrequencies = ppdu->GetTxCenterFreqs();
1324 auto channelWidth = txVector.GetChannelWidth();
1325 auto printFrequencies = [](const std::vector<MHz_u>& v) {
1326 std::stringstream ss;
1327 for (const auto& centerFrequency : v)
1328 {
1329 ss << centerFrequency << " ";
1330 }
1331 return ss.str();
1332 };
1333 NS_LOG_FUNCTION(this << printFrequencies(centerFrequencies) << channelWidth << txPower
1334 << txVector);
1335 const auto& puncturedSubchannels = txVector.GetInactiveSubchannels();
1336 if (!puncturedSubchannels.empty())
1337 {
1338 const auto p20Index = m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20});
1339 const auto& indices =
1340 m_wifiPhy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(channelWidth);
1341 const auto p20IndexInBitmap = p20Index - *(indices.cbegin());
1342 NS_ASSERT(
1343 !puncturedSubchannels.at(p20IndexInBitmap)); // the primary channel cannot be punctured
1344 }
1345 const auto& txMaskRejectionParams = GetTxMaskRejectionParams();
1346 switch (ppdu->GetType())
1347 {
1348 case WIFI_PPDU_TYPE_UL_MU: {
1349 if (flag == HePpdu::PSD_NON_HE_PORTION)
1350 {
1351 // non-HE portion is sent only on the 20 MHz channels covering the RU
1352 const auto staId = GetStaId(ppdu);
1353 const auto ruWidth = WifiRu::GetBandwidth(WifiRu::GetRuType(txVector.GetRu(staId)));
1354 channelWidth = (ruWidth < MHz_u{20}) ? MHz_u{20} : ruWidth;
1357 channelWidth,
1358 txPower,
1359 GetGuardBandwidth(channelWidth),
1360 std::get<0>(txMaskRejectionParams),
1361 std::get<1>(txMaskRejectionParams),
1362 std::get<2>(txMaskRejectionParams),
1363 puncturedSubchannels);
1364 }
1365 else
1366 {
1367 const auto band = GetRuBandForTx(txVector, GetStaId(ppdu)).indices;
1369 centerFrequencies,
1370 channelWidth,
1371 txPower,
1372 GetGuardBandwidth(channelWidth),
1373 band);
1374 }
1375 }
1376 case WIFI_PPDU_TYPE_DL_MU: {
1377 if (flag == HePpdu::PSD_NON_HE_PORTION)
1378 {
1380 centerFrequencies,
1381 channelWidth,
1382 txPower,
1383 GetGuardBandwidth(channelWidth),
1384 std::get<0>(txMaskRejectionParams),
1385 std::get<1>(txMaskRejectionParams),
1386 std::get<2>(txMaskRejectionParams),
1387 puncturedSubchannels);
1388 }
1389 else
1390 {
1392 centerFrequencies,
1393 channelWidth,
1394 txPower,
1395 GetGuardBandwidth(channelWidth),
1396 std::get<0>(txMaskRejectionParams),
1397 std::get<1>(txMaskRejectionParams),
1398 std::get<2>(txMaskRejectionParams),
1399 puncturedSubchannels);
1400 }
1401 }
1402 case WIFI_PPDU_TYPE_SU:
1403 default: {
1404 NS_ASSERT(puncturedSubchannels.empty());
1406 centerFrequencies,
1407 channelWidth,
1408 txPower,
1409 GetGuardBandwidth(channelWidth),
1410 std::get<0>(txMaskRejectionParams),
1411 std::get<1>(txMaskRejectionParams),
1412 std::get<2>(txMaskRejectionParams));
1413 }
1414 }
1415}
1416
1417std::vector<MHz_u>
1419{
1420 NS_LOG_FUNCTION(this << ppdu << staId);
1421 const auto& txVector = ppdu->GetTxVector();
1422 NS_ASSERT(txVector.IsUlMu() && (txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE));
1423 auto centerFrequencies = ppdu->GetTxCenterFreqs();
1424 const auto currentWidth = txVector.GetChannelWidth();
1425
1426 auto ru = txVector.GetRu(staId);
1427 const auto nonOfdmaWidth = GetNonOfdmaWidth(ru);
1428 if (nonOfdmaWidth != currentWidth)
1429 {
1430 // Obtain the index of the non-OFDMA portion
1431 const auto nonOfdmaRu =
1432 WifiRu::FindOverlappingRu(currentWidth, ru, WifiRu::GetRuType(nonOfdmaWidth));
1433
1434 const MHz_u startingFrequency = centerFrequencies.front() - (currentWidth / 2);
1435 centerFrequencies.front() =
1436 startingFrequency +
1437 nonOfdmaWidth *
1439 nonOfdmaRu,
1440 currentWidth,
1441 m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(MHz_u{20})) -
1442 1) +
1443 nonOfdmaWidth / 2;
1444 }
1445 return centerFrequencies;
1446}
1447
1448void
1450{
1451 NS_LOG_FUNCTION(this << ppdu);
1452 const auto& txVector = ppdu->GetTxVector();
1453 if (auto mac = m_wifiPhy->GetDevice()->GetMac(); mac && (mac->GetTypeOfStation() == AP))
1454 {
1455 m_currentTxVector = txVector;
1456 }
1457 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU || ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
1458 {
1459 const auto nonHeTxPower =
1460 m_wifiPhy->GetTxPowerForTransmission(ppdu) + m_wifiPhy->GetTxGain();
1461
1462 // temporarily set WifiPpdu flag to PSD_HE_PORTION for correct calculation of TX power for
1463 // the HE portion
1464 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1465 NS_ASSERT(hePpdu);
1466 hePpdu->SetTxPsdFlag(HePpdu::PSD_HE_PORTION);
1467 const auto heTxPower = m_wifiPhy->GetTxPowerForTransmission(ppdu) + m_wifiPhy->GetTxGain();
1468 hePpdu->SetTxPsdFlag(HePpdu::PSD_NON_HE_PORTION);
1469
1470 // non-HE portion
1471 auto nonHePortionDuration = ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU
1474 auto nonHeTxPowerSpectrum =
1476 Transmit(nonHePortionDuration,
1477 ppdu,
1478 nonHeTxPower,
1479 nonHeTxPowerSpectrum,
1480 "non-HE portion transmission");
1481
1482 // HE portion
1483 auto hePortionDuration = ppdu->GetTxDuration() - nonHePortionDuration;
1484 auto heTxPowerSpectrum =
1486 Simulator::Schedule(nonHePortionDuration,
1488 this,
1489 ppdu,
1490 heTxPower,
1491 heTxPowerSpectrum,
1492 hePortionDuration);
1493 }
1494 else
1495 {
1496 VhtPhy::StartTx(ppdu);
1497 }
1498}
1499
1500void
1502 dBm_u txPower,
1503 Ptr<SpectrumValue> txPowerSpectrum,
1504 Time hePortionDuration)
1505{
1506 NS_LOG_FUNCTION(this << ppdu << txPower << hePortionDuration);
1507 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1508 NS_ASSERT(hePpdu);
1509 hePpdu->SetTxPsdFlag(HePpdu::PSD_HE_PORTION);
1510 Transmit(hePortionDuration, ppdu, txPower, txPowerSpectrum, "HE portion transmission");
1511}
1512
1513Time
1515 const WifiTxVector& txVector,
1516 WifiPhyBand band) const
1517{
1518 if (txVector.IsUlMu())
1519 {
1521 return ConvertLSigLengthToHeTbPpduDuration(txVector.GetLength(), txVector, band);
1522 }
1523
1524 Time maxDuration;
1525 for (auto& staIdPsdu : psduMap)
1526 {
1527 if (txVector.IsDlMu())
1528 {
1530 NS_ABORT_MSG_IF(!txVector.GetHeMuUserInfoMap().contains(staIdPsdu.first),
1531 "STA-ID in psduMap (" << staIdPsdu.first
1532 << ") should be referenced in txVector");
1533 }
1534 Time current = WifiPhy::CalculateTxDuration(staIdPsdu.second->GetSize(),
1535 txVector,
1536 band,
1537 staIdPsdu.first);
1538 if (current > maxDuration)
1539 {
1540 maxDuration = current;
1541 }
1542 }
1543 NS_ASSERT(maxDuration.IsStrictlyPositive());
1544 return maxDuration;
1545}
1546
1547void
1549{
1550 for (uint8_t i = 0; i < 12; ++i)
1551 {
1552 GetHeMcs(i);
1553 }
1554}
1555
1557HePhy::GetHeMcs(uint8_t index)
1558{
1559#define CASE(x) \
1560 case x: \
1561 return GetHeMcs##x();
1562
1563 switch (index)
1564 {
1565 CASE(0)
1566 CASE(1)
1567 CASE(2)
1568 CASE(3)
1569 CASE(4)
1570 CASE(5)
1571 CASE(6)
1572 CASE(7)
1573 CASE(8)
1574 CASE(9)
1575 CASE(10)
1576 CASE(11)
1577 default:
1578 NS_ABORT_MSG("Inexistent index (" << +index << ") requested for HE");
1579 return WifiMode();
1580 }
1581#undef CASE
1582}
1583
1584#define GET_HE_MCS(x) \
1585 WifiMode HePhy::GetHeMcs##x() \
1586 { \
1587 static WifiMode mcs = CreateHeMcs(x); \
1588 return mcs; \
1589 }
1590
1591GET_HE_MCS(0)
1592GET_HE_MCS(1)
1593GET_HE_MCS(2)
1594GET_HE_MCS(3)
1595GET_HE_MCS(4)
1596GET_HE_MCS(5)
1597GET_HE_MCS(6)
1598GET_HE_MCS(7)
1599GET_HE_MCS(8)
1600GET_HE_MCS(9)
1601GET_HE_MCS(10)
1602GET_HE_MCS(11)
1603#undef GET_HE_MCS
1604
1605WifiMode
1607{
1608 NS_ASSERT_MSG(index <= 11, "HeMcs index must be <= 11!");
1609 return WifiModeFactory::CreateWifiMcs("HeMcs" + std::to_string(index),
1610 index,
1612 false,
1619}
1620
1622HePhy::GetCodeRate(uint8_t mcsValue)
1623{
1624 switch (mcsValue)
1625 {
1626 case 10:
1627 return WIFI_CODE_RATE_3_4;
1628 case 11:
1629 return WIFI_CODE_RATE_5_6;
1630 default:
1631 return VhtPhy::GetCodeRate(mcsValue);
1632 }
1633}
1634
1635uint16_t
1637{
1638 switch (mcsValue)
1639 {
1640 case 10:
1641 case 11:
1642 return 1024;
1643 default:
1644 return VhtPhy::GetConstellationSize(mcsValue);
1645 }
1646}
1647
1648uint64_t
1649HePhy::GetPhyRate(uint8_t mcsValue, MHz_u channelWidth, Time guardInterval, uint8_t nss)
1650{
1651 const auto codeRate = GetCodeRate(mcsValue);
1652 const auto dataRate = GetDataRate(mcsValue, channelWidth, guardInterval, nss);
1653 return HtPhy::CalculatePhyRate(codeRate, dataRate);
1654}
1655
1656uint64_t
1657HePhy::GetPhyRateFromTxVector(const WifiTxVector& txVector, uint16_t staId /* = SU_STA_ID */)
1658{
1659 auto bw = txVector.GetChannelWidth();
1660 if (txVector.IsMu())
1661 {
1662 bw = WifiRu::GetBandwidth(WifiRu::GetRuType(txVector.GetRu(staId)));
1663 }
1664 return HePhy::GetPhyRate(txVector.GetMode(staId).GetMcsValue(),
1665 bw,
1666 txVector.GetGuardInterval(),
1667 txVector.GetNss(staId));
1668}
1669
1670uint64_t
1671HePhy::GetDataRateFromTxVector(const WifiTxVector& txVector, uint16_t staId /* = SU_STA_ID */)
1672{
1673 auto bw = txVector.GetChannelWidth();
1674 if (txVector.IsMu())
1675 {
1676 bw = WifiRu::GetBandwidth(WifiRu::GetRuType(txVector.GetRu(staId)));
1677 }
1678 return HePhy::GetDataRate(txVector.GetMode(staId).GetMcsValue(),
1679 bw,
1680 txVector.GetGuardInterval(),
1681 txVector.GetNss(staId));
1682}
1683
1684uint64_t
1685HePhy::GetDataRate(uint8_t mcsValue, MHz_u channelWidth, Time guardInterval, uint8_t nss)
1686{
1687 [[maybe_unused]] const auto gi = guardInterval.GetNanoSeconds();
1688 NS_ASSERT((gi == 800) || (gi == 1600) || (gi == 3200));
1689 NS_ASSERT(nss <= 8);
1690 return HtPhy::CalculateDataRate(GetSymbolDuration(guardInterval),
1691 GetUsableSubcarriers(channelWidth),
1692 static_cast<uint16_t>(log2(GetConstellationSize(mcsValue))),
1694 nss);
1695}
1696
1697uint16_t
1699{
1700 switch (static_cast<uint16_t>(channelWidth))
1701 {
1702 case 2: // 26-tone RU
1703 return 24;
1704 case 4: // 52-tone RU
1705 return 48;
1706 case 8: // 106-tone RU
1707 return 102;
1708 case 20:
1709 return 234;
1710 case 40:
1711 return 468;
1712 case 80:
1713 return 980;
1714 case 160:
1715 return 1960;
1716 default:
1717 NS_ASSERT_MSG(false, "Invalid channel width: " << channelWidth);
1718 return 234;
1719 }
1720}
1721
1722Time
1724{
1725 return NanoSeconds(12800) + guardInterval;
1726}
1727
1728uint64_t
1730{
1731 const auto codeRate = GetCodeRate(mcsValue);
1732 const auto constellationSize = GetConstellationSize(mcsValue);
1733 return CalculateNonHtReferenceRate(codeRate, constellationSize);
1734}
1735
1736uint64_t
1737HePhy::CalculateNonHtReferenceRate(WifiCodeRate codeRate, uint16_t constellationSize)
1738{
1739 uint64_t dataRate;
1740 switch (constellationSize)
1741 {
1742 case 1024:
1743 if (codeRate == WIFI_CODE_RATE_3_4 || codeRate == WIFI_CODE_RATE_5_6)
1744 {
1745 dataRate = 54000000;
1746 }
1747 else
1748 {
1749 NS_FATAL_ERROR("Trying to get reference rate for a MCS with wrong combination of "
1750 "coding rate and modulation");
1751 }
1752 break;
1753 default:
1754 dataRate = VhtPhy::CalculateNonHtReferenceRate(codeRate, constellationSize);
1755 }
1756 return dataRate;
1757}
1758
1759bool
1760HePhy::IsAllowed(const WifiTxVector& /*txVector*/)
1761{
1762 return true;
1763}
1764
1767{
1768 uint16_t staId = SU_STA_ID;
1769
1770 if (IsUlMu(txVector.GetPreambleType()))
1771 {
1772 NS_ASSERT(txVector.GetHeMuUserInfoMap().size() == 1);
1773 staId = txVector.GetHeMuUserInfoMap().begin()->first;
1774 }
1775
1776 return WifiConstPsduMap({{staId, psdu}});
1777}
1778
1781{
1782 return 6500631;
1783}
1784
1785bool
1787{
1788 /*
1789 * The PHY shall not issue a PHY-RXSTART.indication primitive in response to a PPDU
1790 * that does not overlap the primary channel, unless the PHY at an AP receives the
1791 * HE TB PPDU solicited by the AP. For the HE TB PPDU solicited by the AP, the PHY
1792 * shall issue a PHY-RXSTART.indication primitive for a PPDU received in the primary
1793 * or at the secondary 20 MHz channel, the secondary 40 MHz channel, or the secondary
1794 * 80 MHz channel.
1795 */
1796 Ptr<WifiMac> mac = m_wifiPhy->GetDevice() ? m_wifiPhy->GetDevice()->GetMac() : nullptr;
1797 if (ppdu->GetTxVector().IsUlMu() && mac && mac->GetTypeOfStation() == AP)
1798 {
1799 return true;
1800 }
1801 return VhtPhy::CanStartRx(ppdu);
1802}
1803
1806{
1807 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
1808 {
1809 Ptr<const WifiPpdu> rxPpdu;
1810 if ((m_trigVectorExpirationTime.has_value()) &&
1812 {
1813 // We only copy if the AP that is expecting a HE TB PPDU, since the content
1814 // of the TXVECTOR is reconstructed from the TRIGVECTOR, hence the other RX
1815 // PHYs should not have this information.
1816 rxPpdu = ppdu->Copy();
1817 }
1818 else
1819 {
1820 rxPpdu = ppdu;
1821 }
1822 auto hePpdu = DynamicCast<const HePpdu>(rxPpdu);
1823 NS_ASSERT(hePpdu);
1824 hePpdu->UpdateTxVectorForUlMu(m_trigVector);
1825 return rxPpdu;
1826 }
1827 return VhtPhy::GetRxPpduFromTxPpdu(ppdu);
1828}
1829
1830std::vector<WifiSpectrumBandIndices>
1832{
1833 NS_ASSERT_MSG(info.bandWidth <= info.totalWidth,
1834 "Bandwidth (" << info.bandWidth
1835 << ") cannot exceed total operating channel width ("
1836 << info.totalWidth << ")");
1837 std::vector<WifiSpectrumBandIndices> convertedSubcarriers{};
1838 const auto guardBandwidth{info.guardBandwidth / info.centerFrequencies.size()};
1839 const auto nGuardBands =
1840 static_cast<uint32_t>(((2 * MHzToHz(guardBandwidth)) / info.subcarrierSpacing) + 0.5);
1841 auto bw{info.bandWidth};
1842 if (bw > (info.totalWidth / info.centerFrequencies.size()))
1843 {
1844 NS_ASSERT(info.bandIndex == 0);
1845 bw /= info.centerFrequencies.size();
1846 }
1847 // Figures 27-5 to 27-7 of IEEE 802.11ax-2021: the number of guard subcarriers is 6 for 20 MHz
1848 // MHz HE PPDUs and 12 for 40/80/160 MHz HE PPDUs
1849 const uint32_t guardSubcarriers = (bw < MHz_u{40}) ? 6 : 12;
1850 const auto refRu = WifiRu::GetRuType(bw);
1851 const auto offset = WifiRu::GetSubcarrierGroup(bw, refRu, 1, info.mc).back().second;
1852 uint32_t centerFrequencyIndex = (nGuardBands / 2) + guardSubcarriers + offset;
1853 const auto numBandsInBand = static_cast<size_t>(MHzToHz(bw) / info.subcarrierSpacing);
1854 centerFrequencyIndex += numBandsInBand * info.bandIndex;
1855 // start and stop subcarriers might be in different frequency segments, hence define a low and a
1856 // high center frequency
1857 auto centerFrequencyIndexLow = centerFrequencyIndex;
1858 auto centerFrequencyIndexHigh = centerFrequencyIndex;
1859 if (info.centerFrequencies.size() > 1)
1860 {
1861 const auto numBandsBetweenSegments =
1863 info.totalWidth,
1864 info.subcarrierSpacing);
1865 if (info.subcarrierRange.first > 0)
1866 {
1867 centerFrequencyIndexLow += numBandsBetweenSegments;
1868 }
1869 if (info.subcarrierRange.second > 0)
1870 {
1871 centerFrequencyIndexHigh += numBandsBetweenSegments;
1872 }
1873 }
1874 convertedSubcarriers.emplace_back(centerFrequencyIndexLow + info.subcarrierRange.first,
1875 centerFrequencyIndexHigh + info.subcarrierRange.second);
1876 return convertedSubcarriers;
1877}
1878
1879} // namespace ns3
1880
1881namespace
1882{
1883
1884/**
1885 * Constructor class for HE modes
1886 */
1888{
1889 public:
1891 {
1893 ns3::WifiPhy::AddStaticPhyEntity(ns3::WIFI_MOD_CLASS_HE, std::make_shared<ns3::HePhy>());
1894 }
1895} g_constructor_he; ///< the constructor for HE modes
1896
1897} // namespace
#define Max(a, b)
#define Min(a, b)
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:1685
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:1649
uint64_t GetCurrentHeTbPpduUid() const
Definition he-phy.cc:1067
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:1548
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:1017
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:1606
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:1557
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:1766
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:1737
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:1501
MHz_u GetNonOfdmaWidth(WifiRu::RuSpec ru) const
Get the width of the non-OFDMA portion of an HE TB PPDU.
Definition he-phy.cc:1054
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:1786
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:1622
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:1449
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:1270
Time CalculateTxDuration(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, WifiPhyBand band) const override
Definition he-phy.cc:1514
Callback< void, HeSigAParameters > EndOfHeSigACallback
Callback upon end of HE-SIG-A.
Definition he-phy.h:65
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:1657
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:1091
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:1073
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:1290
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:1760
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:1309
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:1780
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:1671
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:1169
void RxPayloadFailed(Ptr< const WifiPsdu > psdu, double snr, const WifiTxVector &txVector) override
Perform amendment-specific actions when the payload is unsuccessfully 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:1805
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:1723
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:1729
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:1121
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:1418
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:1831
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:1150
static uint16_t GetConstellationSize(uint8_t mcsValue)
Return the constellation size corresponding to the supplied HE MCS index.
Definition he-phy.cc:1636
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:657
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:888
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:706
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:672
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:907
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:929
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:906
std::vector< EventId > m_endOfMpduEvents
the end of MPDU events (only used for A-MPDUs)
Definition phy-entity.h:913
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:496
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:932
std::vector< EventId > m_endRxPayloadEvents
the end of receive events (only one unless UL MU reception)
Definition phy-entity.h:918
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:926
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:93
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:910
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:74
void ScheduleEndOfMpdus(Ptr< Event > event)
Schedule end of MPDUs events.
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:67
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:96
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:409
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:409
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition nstime.h:342
@ US
microsecond
Definition nstime.h:109
@ S
second
Definition nstime.h:107
@ NS
nanosecond
Definition nstime.h:110
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
VhtPhy(bool buildModeList=true)
Constructor for VHT PHY.
Definition vht-phy.cc:79
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
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1568
static void AddStaticPhyEntity(WifiModulationClass modulation, std::shared_ptr< PhyEntity > phyEntity)
Add the PHY entity to the map of implemented PHY entities for the given modulation class.
Definition wifi-phy.cc:810
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition wifi-phy.cc:1561
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:439
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1393
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1405
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time FemtoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1429
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:1584
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::map< WifiSpectrumBandInfo, Watt_u > RxPowerWattPerChannelBand
A map of the received power for each band.
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:585
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:120
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)
double Watt_u
Watt weak type.
Definition wifi-units.h:25
bool IsUlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a uplink multi-user transmission.
double dB_u
dB weak type
Definition wifi-units.h:28
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:83
bool isSuccess
outcome (true if success) of the reception
Definition phy-entity.h:84
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:84
SignalNoiseDbm structure.
Definition wifi-types.h:70
WifiSpectrumBandInfo structure containing info about a spectrum band.
std::vector< WifiSpectrumBandIndices > indices
the start and stop indices for each segment of the band