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