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