A Discrete-Event Network Simulator
API
he-phy.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Orange Labs
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Authors: Rediet <getachew.redieteab@orange.com>
18 * Sébastien Deronne <sebastien.deronne@gmail.com> (for logic ported from wifi-phy and
19 * spectrum-wifi-phy)
20 */
21
22#include "he-phy.h"
23
24#include "he-configuration.h"
25#include "obss-pd-algorithm.h"
26
27#include "ns3/ap-wifi-mac.h"
28#include "ns3/assert.h"
29#include "ns3/interference-helper.h"
30#include "ns3/log.h"
31#include "ns3/simulator.h"
32#include "ns3/sta-wifi-mac.h"
33#include "ns3/vht-configuration.h"
34#include "ns3/wifi-net-device.h"
35#include "ns3/wifi-phy.h"
36#include "ns3/wifi-psdu.h"
37#include "ns3/wifi-utils.h"
38
39#include <algorithm>
40
41namespace ns3
42{
43
45
46/*******************************************************
47 * HE PHY (P802.11ax/D4.0, clause 27)
48 *******************************************************/
49
50// clang-format off
51
52const PhyEntity::PpduFormats HePhy::m_hePpduFormats { // Ignoring PE (Packet Extension)
54 WIFI_PPDU_FIELD_NON_HT_HEADER, // L-SIG + RL-SIG
55 WIFI_PPDU_FIELD_SIG_A, // HE-SIG-A
56 WIFI_PPDU_FIELD_TRAINING, // HE-STF + HE-LTFs
59 WIFI_PPDU_FIELD_NON_HT_HEADER, // L-SIG + RL-SIG
60 WIFI_PPDU_FIELD_SIG_A, // HE-SIG-A
61 WIFI_PPDU_FIELD_SIG_B, // HE-SIG-B
62 WIFI_PPDU_FIELD_TRAINING, // HE-STF + HE-LTFs
65 WIFI_PPDU_FIELD_NON_HT_HEADER, // L-SIG + RL-SIG
66 WIFI_PPDU_FIELD_SIG_A, // HE-SIG-A
67 WIFI_PPDU_FIELD_TRAINING, // HE-STF + HE-LTFs
70 WIFI_PPDU_FIELD_NON_HT_HEADER, // L-SIG + RL-SIG
71 WIFI_PPDU_FIELD_SIG_A, // HE-SIG-A
72 WIFI_PPDU_FIELD_TRAINING, // HE-STF + HE-LTFs
74};
75
76// clang-format on
77
78HePhy::HePhy(bool buildModeList /* = true */)
79 : VhtPhy(false), // don't add VHT modes to list
80 m_trigVector(std::nullopt),
81 m_trigVectorExpirationTime(std::nullopt),
82 m_currentTxVector(std::nullopt),
83 m_rxHeTbPpdus(0),
84 m_lastPer20MHzDurations()
85{
86 NS_LOG_FUNCTION(this << buildModeList);
90 m_currentMuPpduUid = UINT64_MAX;
91 m_previouslyTxPpduUid = UINT64_MAX;
92 if (buildModeList)
93 {
95 }
96}
97
99{
100 NS_LOG_FUNCTION(this);
101}
102
103void
105{
106 NS_LOG_FUNCTION(this);
107 NS_ASSERT(m_modeList.empty());
109 for (uint8_t index = 0; index <= m_maxSupportedMcsIndexPerSs; ++index)
110 {
111 NS_LOG_LOGIC("Add HeMcs" << +index << " to list");
112 m_modeList.emplace_back(CreateHeMcs(index));
113 }
114}
115
117HePhy::GetSigMode(WifiPpduField field, const WifiTxVector& txVector) const
118{
119 switch (field)
120 {
121 case WIFI_PPDU_FIELD_TRAINING: // consider SIG-A (SIG-B) mode for training for the time being
122 // for SU/ER-SU/TB (MU) (useful for InterferenceHelper)
123 if (txVector.IsDlMu())
124 {
126 // Training comes after SIG-B
127 return GetSigBMode(txVector);
128 }
129 else
130 {
131 // Training comes after SIG-A
132 return GetSigAMode();
133 }
134 default:
135 return VhtPhy::GetSigMode(field, txVector);
136 }
137}
138
141{
142 return GetVhtMcs0(); // same number of data tones as VHT for 20 MHz (i.e. 52)
143}
144
146HePhy::GetSigBMode(const WifiTxVector& txVector) const
147{
148 NS_ABORT_MSG_IF(!IsDlMu(txVector.GetPreambleType()), "SIG-B only available for DL MU");
155 uint8_t smallestMcs = 5; // maximum MCS for HE-SIG-B
156 for (auto& info : txVector.GetHeMuUserInfoMap())
157 {
158 smallestMcs = std::min(smallestMcs, info.second.mcs);
159 }
160 switch (smallestMcs)
161 {
162 case 0:
163 return GetVhtMcs0();
164 case 1:
165 return GetVhtMcs1();
166 case 2:
167 return GetVhtMcs2();
168 case 3:
169 return GetVhtMcs3();
170 case 4:
171 return GetVhtMcs4();
172 case 5:
173 default:
174 return GetVhtMcs5();
175 }
176}
177
180{
181 return m_hePpduFormats;
182}
183
184Time
186{
187 return MicroSeconds(8); // L-SIG + RL-SIG
188}
189
190Time
192 uint8_t nDataLtf,
193 uint8_t nExtensionLtf /* = 0 */) const
194{
195 Time ltfDuration = MicroSeconds(8); // TODO extract from TxVector when available
196 Time stfDuration;
197 if (txVector.IsUlMu())
198 {
200 stfDuration = MicroSeconds(8);
201 }
202 else
203 {
204 stfDuration = MicroSeconds(4);
205 }
206 NS_ABORT_MSG_IF(nDataLtf > 8, "Unsupported number of LTFs " << +nDataLtf << " for HE");
207 NS_ABORT_MSG_IF(nExtensionLtf > 0, "No extension LTFs expected for HE");
208 return stfDuration + ltfDuration * nDataLtf; // HE-STF + HE-LTFs
209}
210
211Time
213{
214 return (preamble == WIFI_PREAMBLE_HE_ER_SU)
215 ? MicroSeconds(16)
216 : MicroSeconds(8); // HE-SIG-A (first and second symbol)
217}
218
219Time
221{
222 if (ns3::IsDlMu(txVector.GetPreambleType())) // See section 27.3.11.8 of IEEE 802.11ax-2021
223 {
225
226 auto sigBSize = GetSigBFieldSize(txVector);
227 auto symbolDuration = MicroSeconds(4);
228 // Number of data bits per symbol
229 auto ndbps =
230 GetSigBMode(txVector).GetDataRate(20, 800, 1) * symbolDuration.GetNanoSeconds() / 1e9;
231 auto numSymbols = ceil((sigBSize) / ndbps);
232
233 return FemtoSeconds(static_cast<uint64_t>(numSymbols * symbolDuration.GetFemtoSeconds()));
234 }
235 else
236 {
237 // no SIG-B
238 return MicroSeconds(0);
239 }
240}
241
242Time
243HePhy::GetValidPpduDuration(Time ppduDuration, const WifiTxVector& txVector, WifiPhyBand band)
244{
245 Time tSymbol = NanoSeconds(12800 + txVector.GetGuardInterval());
246 Time preambleDuration = WifiPhy::CalculatePhyPreambleAndHeaderDuration(txVector);
247 uint8_t sigExtension = (band == WIFI_PHY_BAND_2_4GHZ ? 6 : 0);
248 uint32_t nSymbols =
249 floor(static_cast<double>((ppduDuration - preambleDuration).GetNanoSeconds() -
250 (sigExtension * 1000)) /
251 tSymbol.GetNanoSeconds());
252 return preambleDuration + (nSymbols * tSymbol) + MicroSeconds(sigExtension);
253}
254
255std::pair<uint16_t, Time>
257 const WifiTxVector& txVector,
258 WifiPhyBand band)
259{
260 NS_ABORT_IF(!txVector.IsUlMu() || (txVector.GetModulationClass() < WIFI_MOD_CLASS_HE));
261 // update ppduDuration so that it is a valid PPDU duration
262 ppduDuration = GetValidPpduDuration(ppduDuration, txVector, band);
263 uint8_t sigExtension = (band == WIFI_PHY_BAND_2_4GHZ ? 6 : 0);
264 uint8_t m = 2; // HE TB PPDU so m is set to 2
265 uint16_t length = ((ceil((static_cast<double>(ppduDuration.GetNanoSeconds() - (20 * 1000) -
266 (sigExtension * 1000)) /
267 1000) /
268 4.0) *
269 3) -
270 3 - m);
271 return {length, ppduDuration};
272}
273
274Time
276 const WifiTxVector& txVector,
277 WifiPhyBand band)
278{
279 NS_ABORT_IF(!txVector.IsUlMu() || (txVector.GetModulationClass() < WIFI_MOD_CLASS_HE));
280 uint8_t sigExtension = (band == WIFI_PHY_BAND_2_4GHZ ? 6 : 0);
281 uint8_t m = 2; // HE TB PPDU so m is set to 2
282 // Equation 27-11 of IEEE P802.11ax/D4.0
283 Time calculatedDuration =
284 MicroSeconds(((ceil(static_cast<double>(length + 3 + m) / 3)) * 4) + 20 + sigExtension);
285 return GetValidPpduDuration(calculatedDuration, txVector, band);
286}
287
288Time
290{
291 Time duration = GetDuration(WIFI_PPDU_FIELD_PREAMBLE, txVector) +
294 return duration;
295}
296
297Time
299{
300 Time duration = GetDuration(WIFI_PPDU_FIELD_PREAMBLE, txVector) +
304 return duration;
305}
306
307uint8_t
308HePhy::GetNumberBccEncoders(const WifiTxVector& /* txVector */) const
309{
310 return 1; // only 1 BCC encoder for HE since higher rates are obtained using LDPC
311}
312
313Time
315{
316 uint16_t gi = txVector.GetGuardInterval();
317 NS_ASSERT(gi == 800 || gi == 1600 || gi == 3200);
318 return GetSymbolDuration(NanoSeconds(gi));
319}
320
321void
322HePhy::SetTrigVector(const WifiTxVector& trigVector, Time validity)
323{
324 NS_LOG_FUNCTION(this << trigVector << validity);
325 NS_ASSERT_MSG(trigVector.GetGuardInterval() > 800,
326 "Invalid guard interval " << trigVector.GetGuardInterval());
327 if (auto mac = m_wifiPhy->GetDevice()->GetMac(); mac && mac->GetTypeOfStation() != AP)
328 {
329 return;
330 }
331 m_trigVector = trigVector;
334}
335
337HePhy::BuildPpdu(const WifiConstPsduMap& psdus, const WifiTxVector& txVector, Time ppduDuration)
338{
339 NS_LOG_FUNCTION(this << psdus << txVector << ppduDuration);
340 return Create<HePpdu>(psdus,
341 txVector,
343 txVector.GetChannelWidth()),
344 ppduDuration,
346 ObtainNextUid(txVector),
348}
349
350void
352 RxPowerWattPerChannelBand& rxPowersW,
353 Time rxDuration)
354{
355 NS_LOG_FUNCTION(this << ppdu << rxDuration);
356 const auto& txVector = ppdu->GetTxVector();
357 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
358 NS_ASSERT(hePpdu);
359 const auto psdFlag = hePpdu->GetTxPsdFlag();
360 if (psdFlag == HePpdu::PSD_HE_PORTION)
361 {
362 NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
363 if (m_currentMuPpduUid == ppdu->GetUid() && GetCurrentEvent())
364 {
365 // AP or STA has already received non-OFDMA part, switch to OFDMA part, and schedule
366 // reception of payload (will be canceled for STAs by StartPayload)
367 bool ofdmaStarted = !m_beginOfdmaPayloadRxEvents.empty();
368 NS_LOG_INFO("Switch to OFDMA part (already started? "
369 << (ofdmaStarted ? "Y" : "N") << ") "
370 << "and schedule OFDMA payload reception in "
372 Ptr<Event> event =
373 CreateInterferenceEvent(ppdu, txVector, rxDuration, rxPowersW, !ofdmaStarted);
374 uint16_t staId = GetStaId(ppdu);
379 this,
380 event);
381 }
382 else
383 {
384 // PHY receives the OFDMA payload while having dropped the preamble
385 NS_LOG_INFO("Consider OFDMA part of the PPDU as interference since device dropped the "
386 "preamble");
387 CreateInterferenceEvent(ppdu, txVector, rxDuration, rxPowersW);
388 // the OFDMA part of the PPDU will be noise _after_ the completion of the current event
389 ErasePreambleEvent(ppdu, rxDuration);
390 }
391 }
392 else
393 {
395 ppdu,
396 rxPowersW,
397 ppdu->GetTxDuration()); // The actual duration of the PPDU should be used
398 }
399}
400
401void
403{
404 NS_LOG_FUNCTION(this);
405 for (auto& beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
406 {
407 beginOfdmaPayloadRxEvent.second.Cancel();
408 }
411}
412
413void
415{
416 NS_LOG_FUNCTION(this << reason);
417 if (reason != OBSS_PD_CCA_RESET)
418 {
419 for (auto& endMpduEvent : m_endOfMpduEvents)
420 {
421 endMpduEvent.Cancel();
422 }
423 m_endOfMpduEvents.clear();
424 }
425 else
426 {
428 }
429}
430
431void
433{
434 NS_LOG_FUNCTION(this << *event);
435 if (event->GetPpdu()->GetType() != WIFI_PPDU_TYPE_UL_MU)
436 {
437 NS_ASSERT(event->GetEndTime() == Simulator::Now());
438 }
439 for (auto& beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
440 {
441 beginOfdmaPayloadRxEvent.second.Cancel();
442 }
444}
445
448{
449 Ptr<Event> event;
450 // We store all incoming preamble events, and a decision is made at the end of the preamble
451 // detection window. If a preamble is received after the preamble detection window, it is stored
452 // anyway because this is needed for HE TB PPDUs in order to properly update the received power
453 // in InterferenceHelper. The map is cleaned anyway at the end of the current reception.
454 auto uidPreamblePair = std::make_pair(ppdu->GetUid(), ppdu->GetPreamble());
455 const auto& currentPreambleEvents = GetCurrentPreambleEvents();
456 auto it = currentPreambleEvents.find(uidPreamblePair);
457 bool isResponseToTrigger = (m_previouslyTxPpduUid == ppdu->GetUid());
458 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU || isResponseToTrigger)
459 {
460 const auto& txVector = ppdu->GetTxVector();
461 Time rxDuration;
462 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
463 {
465 txVector); // the OFDMA part of the transmission will be added later on
466 }
467 else
468 {
469 rxDuration = ppdu->GetTxDuration();
470 }
471 if (it != currentPreambleEvents.end())
472 {
473 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
474 {
475 NS_LOG_DEBUG("Received another HE TB PPDU for UID "
476 << ppdu->GetUid() << " from STA-ID " << ppdu->GetStaId()
477 << " and BSS color " << +txVector.GetBssColor());
478 }
479 else
480 {
481 NS_LOG_DEBUG("Received another response to a trigger frame " << ppdu->GetUid());
482 }
483 event = it->second;
484
485 auto heConfiguration = m_wifiPhy->GetDevice()->GetHeConfiguration();
486 NS_ASSERT(heConfiguration);
487 // DoStartReceivePayload(), which is called when we start receiving the Data field,
488 // computes the max offset among TB PPDUs based on the begin OFDMA payload RX events,
489 // which are scheduled by StartReceivePreamble() when starting the reception of the
490 // OFDMA portion. Therefore, the maximum delay cannot exceed the duration of the
491 // training fields that are between the start of the OFDMA portion and the start
492 // of the Data field.
493 Time maxDelay = GetDuration(WIFI_PPDU_FIELD_TRAINING, txVector);
494 if (heConfiguration->GetMaxTbPpduDelay().IsStrictlyPositive())
495 {
496 maxDelay = Min(maxDelay, heConfiguration->GetMaxTbPpduDelay());
497 }
498
499 if (Simulator::Now() - event->GetStartTime() > maxDelay)
500 {
501 // This HE TB PPDU arrived too late to be decoded properly. The HE TB PPDU
502 // is dropped and added as interference
503 event = CreateInterferenceEvent(ppdu, txVector, rxDuration, rxPowersW);
504 NS_LOG_DEBUG("Drop HE TB PPDU that arrived too late");
506 }
507 else
508 {
509 // Update received power of the event associated to that UL MU transmission
510 UpdateInterferenceEvent(event, rxPowersW);
511 }
512
513 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU && GetCurrentEvent() &&
514 (GetCurrentEvent()->GetPpdu()->GetUid() != ppdu->GetUid()))
515 {
516 NS_LOG_DEBUG("Drop packet because already receiving another HE TB PPDU");
518 }
519 else if (isResponseToTrigger && GetCurrentEvent() &&
520 (GetCurrentEvent()->GetPpdu()->GetUid() != ppdu->GetUid()))
521 {
523 "Drop packet because already receiving another response to a trigger frame");
525 }
526 return nullptr;
527 }
528 else
529 {
530 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
531 {
532 NS_LOG_DEBUG("Received a new HE TB PPDU for UID "
533 << ppdu->GetUid() << " from STA-ID " << ppdu->GetStaId()
534 << " and BSS color " << +txVector.GetBssColor());
535 }
536 else
537 {
538 NS_LOG_DEBUG("Received response to a trigger frame for UID " << ppdu->GetUid());
539 }
540 event = CreateInterferenceEvent(ppdu, txVector, rxDuration, rxPowersW);
541 AddPreambleEvent(event);
542 }
543 }
544 else if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
545 {
546 const auto& txVector = ppdu->GetTxVector();
548 txVector); // the OFDMA part of the transmission will be added later on
549 event = CreateInterferenceEvent(ppdu, ppdu->GetTxVector(), rxDuration, rxPowersW);
550 AddPreambleEvent(event);
551 }
552 else
553 {
554 if (it == currentPreambleEvents.end())
555 {
556 event = PhyEntity::DoGetEvent(ppdu, rxPowersW);
557 }
558 else
559 {
561 "Update received power of the event associated to these UL transmissions with UID "
562 << ppdu->GetUid());
563 event = it->second;
564 UpdateInterferenceEvent(event, rxPowersW);
565 return nullptr;
566 }
567 }
568 return event;
569}
570
573{
574 if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU || ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
575 {
576 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
577 NS_ASSERT(hePpdu);
578 return hePpdu->GetPsdu(GetBssColor(), GetStaId(ppdu));
579 }
581}
582
583uint8_t
585{
586 uint8_t bssColor = 0;
587 if (m_wifiPhy->GetDevice())
588 {
590 if (heConfiguration)
591 {
592 bssColor = heConfiguration->GetBssColor();
593 }
594 }
595 return bssColor;
596}
597
598uint16_t
600{
601 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
602 {
603 return ppdu->GetStaId();
604 }
605 else if (ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
606 {
607 auto mac = DynamicCast<StaWifiMac>(m_wifiPhy->GetDevice()->GetMac());
608 if (mac && mac->IsAssociated())
609 {
610 return mac->GetAssociationId();
611 }
612 }
613 return PhyEntity::GetStaId(ppdu);
614}
615
618{
619 NS_LOG_FUNCTION(this << *event << status << field);
620 NS_ASSERT(event->GetTxVector().GetPreambleType() >= WIFI_PREAMBLE_HE_SU);
621 switch (field)
622 {
624 return ProcessSigA(event, status);
626 return ProcessSigB(event, status);
627 default:
628 NS_ASSERT_MSG(false, "Invalid PPDU field");
629 }
630 return status;
631}
632
635{
636 NS_LOG_FUNCTION(this << *event << status);
637 // Notify end of SIG-A (in all cases)
638 WifiTxVector txVector = event->GetTxVector();
640 params.rssiW = GetRxPowerWForPpdu(event);
641 params.bssColor = txVector.GetBssColor();
642 NotifyEndOfHeSigA(params); // if OBSS_PD CCA_RESET, set power restriction first and wait till
643 // field is processed before switching to IDLE
644
645 if (status.isSuccess)
646 {
647 // Check if PPDU is filtered based on the BSS color
648 uint8_t myBssColor = GetBssColor();
649 uint8_t rxBssColor = txVector.GetBssColor();
650 if (myBssColor != 0 && rxBssColor != 0 && myBssColor != rxBssColor)
651 {
652 NS_LOG_DEBUG("The BSS color of this PPDU ("
653 << +rxBssColor << ") does not match the device's (" << +myBssColor
654 << "). The PPDU is filtered.");
655 return PhyFieldRxStatus(false, FILTERED, DROP);
656 }
657
658 // When SIG-A is decoded, we know the type of frame being received. If we stored a
659 // valid TRIGVECTOR and we are not receiving a TB PPDU, we drop the frame.
660 Ptr<const WifiPpdu> ppdu = event->GetPpdu();
661 if (m_trigVectorExpirationTime.has_value() &&
663 (ppdu->GetType() != WIFI_PPDU_TYPE_UL_MU))
664 {
665 NS_LOG_DEBUG("Expected an HE TB PPDU, receiving a " << txVector.GetPreambleType());
666 return PhyFieldRxStatus(false, FILTERED, DROP);
667 }
668
669 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
670 {
672 // check that the stored TRIGVECTOR is still valid
673 if (!m_trigVectorExpirationTime.has_value() ||
675 {
676 NS_LOG_DEBUG("No valid TRIGVECTOR, the PHY was not expecting a TB PPDU");
677 return PhyFieldRxStatus(false, FILTERED, DROP);
678 }
679 // We expected a TB PPDU and we are receiving a TB PPDU. However, despite
680 // the previous check on BSS Color, we may be receiving a TB PPDU from an
681 // OBSS, as BSS Colors are not guaranteed to be different for all APs in
682 // range (an example is when BSS Color is 0). We can detect this situation
683 // by comparing the TRIGVECTOR with the TXVECTOR of the TB PPDU being received
684 NS_ABORT_IF(!m_trigVector.has_value());
685 if (m_trigVector->GetChannelWidth() != txVector.GetChannelWidth())
686 {
687 NS_LOG_DEBUG("Received channel width different than in TRIGVECTOR");
688 return PhyFieldRxStatus(false, FILTERED, DROP);
689 }
690 if (m_trigVector->GetLength() != txVector.GetLength())
691 {
692 NS_LOG_DEBUG("Received UL Length (" << txVector.GetLength()
693 << ") different than in TRIGVECTOR ("
694 << m_trigVector->GetLength() << ")");
695 return PhyFieldRxStatus(false, FILTERED, DROP);
696 }
697 uint16_t staId = ppdu->GetStaId();
698 if (m_trigVector->GetHeMuUserInfoMap().find(staId) ==
699 m_trigVector->GetHeMuUserInfoMap().end())
700 {
701 NS_LOG_DEBUG("TB PPDU received from un unexpected STA ID");
702 return PhyFieldRxStatus(false, FILTERED, DROP);
703 }
704
705 NS_ASSERT(txVector.GetGuardInterval() == m_trigVector->GetGuardInterval());
706 NS_ASSERT(txVector.GetMode(staId) == m_trigVector->GetMode(staId));
707 NS_ASSERT(txVector.GetNss(staId) == m_trigVector->GetNss(staId));
708 NS_ASSERT(txVector.GetHeMuUserInfo(staId) == m_trigVector->GetHeMuUserInfo(staId));
709
711 ppdu->GetUid(); // to be able to correctly schedule start of OFDMA payload
712 }
713
714 if (ppdu->GetType() != WIFI_PPDU_TYPE_DL_MU &&
715 !GetAddressedPsduInPpdu(ppdu)) // Final decision on STA-ID correspondence of DL MU is
716 // delayed to end of SIG-B
717 {
718 NS_ASSERT(ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU);
720 "No PSDU addressed to that PHY in the received MU PPDU. The PPDU is filtered.");
721 return PhyFieldRxStatus(false, FILTERED, DROP);
722 }
723 }
724 return status;
725}
726
727void
729{
730 m_obssPdAlgorithm = algorithm;
731}
732
733void
735{
736 m_endOfHeSigACallback = callback;
737}
738
739void
741{
743 {
745 }
746}
747
750{
751 NS_LOG_FUNCTION(this << *event << status);
752 NS_ASSERT(IsDlMu(event->GetTxVector().GetPreambleType()));
753 if (status.isSuccess)
754 {
755 // Check if PPDU is filtered only if the SIG-B content is supported (not explicitly stated
756 // but assumed based on behavior for SIG-A)
757 if (!GetAddressedPsduInPpdu(event->GetPpdu()))
758 {
760 "No PSDU addressed to that PHY in the received MU PPDU. The PPDU is filtered.");
761 return PhyFieldRxStatus(false, FILTERED, DROP);
762 }
763 }
764 if (event->GetTxVector().IsDlMu())
765 {
766 // When including a Trigger Frame, a DL MU PPDU solicits a TB PPDU.
767 // NOTE that the 'if' condition above is not needed for HE because SIG-B is only
768 // included in HE MU PPDUs, but it is necessary for EHT to avoid that a non-AP
769 // STA receiving a Trigger Frame sent as an EHT SU transmission (which carries
770 // the EHT-SIG field) stores the PPDU UID and uses it later to schedule the
771 // reception of the OFDMA payload of the TB PPDU (see HePhy::StartReceivePreamble())
772 // despite it lacks the TRIGVECTOR.
774 event->GetPpdu()->GetUid(); // to be able to correctly schedule start of OFDMA payload
775 }
776 return status;
777}
778
779bool
781{
782 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
783 {
784 return true; // evaluated in ProcessSigA
785 }
786
787 const WifiTxVector& txVector = ppdu->GetTxVector();
788 uint16_t staId = GetStaId(ppdu);
789 WifiMode txMode = txVector.GetMode(staId);
790 uint8_t nss = txVector.GetNssMax();
791 if (txVector.IsDlMu())
792 {
794 for (auto info : txVector.GetHeMuUserInfoMap())
795 {
796 if (info.first == staId)
797 {
798 nss = info.second.nss; // no need to look at other PSDUs
799 break;
800 }
801 }
802 }
803
805 {
806 NS_LOG_DEBUG("Packet reception could not be started because not enough RX antennas");
807 return false;
808 }
809 if (!IsModeSupported(txMode))
810 {
811 NS_LOG_DEBUG("Drop packet because it was sent using an unsupported mode ("
812 << txVector.GetMode() << ")");
813 return false;
814 }
815 return true;
816}
817
818Time
820{
821 NS_LOG_FUNCTION(this << *event);
822 const auto& txVector = event->GetTxVector();
823
824 if (!txVector.IsMu())
825 {
827 }
828
829 NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
830 Ptr<const WifiPpdu> ppdu = event->GetPpdu();
831
832 if (txVector.IsDlMu())
833 {
834 Time payloadDuration =
835 ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(txVector);
836 NotifyPayloadBegin(txVector, payloadDuration);
837 return payloadDuration;
838 }
839
840 // TX duration is determined by the Length field of TXVECTOR
841 Time payloadDuration = ConvertLSigLengthToHeTbPpduDuration(txVector.GetLength(),
842 txVector,
845 // This method is called when we start receiving the first OFDMA payload. To
846 // compute the time to the reception end of the last TB PPDU, we need to add the
847 // offset of the last TB PPDU to the payload duration (same for all TB PPDUs)
848 Time maxOffset{0};
849 for (const auto& beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
850 {
851 maxOffset = Max(maxOffset, Simulator::GetDelayLeft(beginOfdmaPayloadRxEvent.second));
852 }
853 Time timeToEndRx = payloadDuration + maxOffset;
854
856 {
857 NS_LOG_DEBUG("Ignore HE TB PPDU payload received by STA but keep state in Rx");
858 NotifyPayloadBegin(txVector, timeToEndRx);
859 m_endRxPayloadEvents.push_back(
860 Simulator::Schedule(timeToEndRx, &PhyEntity::ResetReceive, this, event));
861 // Cancel all scheduled events for OFDMA payload reception
863 m_beginOfdmaPayloadRxEvents.begin()->second.IsRunning());
864 for (auto& beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
865 {
866 beginOfdmaPayloadRxEvent.second.Cancel();
867 }
869 }
870 else
871 {
872 NS_LOG_DEBUG("Receiving PSDU in HE TB PPDU");
873 uint16_t staId = GetStaId(ppdu);
874 m_signalNoiseMap.insert({std::make_pair(ppdu->GetUid(), staId), SignalNoiseDbm()});
875 m_statusPerMpduMap.insert({std::make_pair(ppdu->GetUid(), staId), std::vector<bool>()});
876 // for HE TB PPDUs, ScheduleEndOfMpdus and EndReceive are scheduled by
877 // StartReceiveOfdmaPayload
879 for (auto& beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
880 {
881 NS_ASSERT(beginOfdmaPayloadRxEvent.second.IsRunning());
882 }
883 }
884
885 return timeToEndRx;
886}
887
888void
890 RxSignalInfo rxSignalInfo,
891 const WifiTxVector& txVector,
892 uint16_t staId,
893 const std::vector<bool>& statusPerMpdu)
894{
895 NS_LOG_FUNCTION(this << *psdu << txVector);
896 m_state->NotifyRxPsduSucceeded(psdu, rxSignalInfo, txVector, staId, statusPerMpdu);
897 if (!IsUlMu(txVector.GetPreambleType()))
898 {
899 m_state->SwitchFromRxEndOk();
900 }
901 else
902 {
904 }
905}
906
907void
909{
910 NS_LOG_FUNCTION(this << *psdu << txVector << snr);
911 m_state->NotifyRxPsduFailed(psdu, snr);
912 if (!txVector.IsUlMu())
913 {
914 m_state->SwitchFromRxEndError();
915 }
916}
917
918void
920{
921 NS_LOG_FUNCTION(this << ppdu);
922 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
923 {
924 for (auto it = m_endRxPayloadEvents.begin(); it != m_endRxPayloadEvents.end();)
925 {
926 if (it->IsExpired())
927 {
928 it = m_endRxPayloadEvents.erase(it);
929 }
930 else
931 {
932 it++;
933 }
934 }
935 if (m_endRxPayloadEvents.empty())
936 {
937 // We've got the last PPDU of the UL-OFDMA transmission.
938 // Indicate a successful reception is terminated if at least one HE TB PPDU
939 // has been successfully received, otherwise indicate a unsuccessful reception is
940 // terminated.
941 if (m_rxHeTbPpdus > 0)
942 {
943 m_state->SwitchFromRxEndOk();
944 }
945 else
946 {
947 m_state->SwitchFromRxEndError();
948 }
949 NotifyInterferenceRxEndAndClear(true); // reset WifiPhy
950 m_rxHeTbPpdus = 0;
951 }
952 }
953 else
954 {
957 }
958}
959
960void
962{
963 NS_LOG_FUNCTION(this << event);
964 Ptr<const WifiPpdu> ppdu = event->GetPpdu();
965 const RxPowerWattPerChannelBand& rxPowersW = event->GetRxPowerWPerBand();
966 // The total RX power corresponds to the maximum over all the bands.
967 // Only perform this computation if the result needs to be logged.
968 auto it = rxPowersW.end();
969 if (g_log.IsEnabled(ns3::LOG_FUNCTION))
970 {
971 it = std::max_element(
972 rxPowersW.begin(),
973 rxPowersW.end(),
974 [](const std::pair<WifiSpectrumBand, double>& p1,
975 const std::pair<WifiSpectrumBand, double>& p2) { return p1.second < p2.second; });
976 }
977 NS_LOG_FUNCTION(this << *event << it->second);
980 auto itEvent = m_beginOfdmaPayloadRxEvents.find(GetStaId(ppdu));
987 NS_ASSERT(itEvent != m_beginOfdmaPayloadRxEvents.end() && itEvent->second.IsExpired());
988 m_beginOfdmaPayloadRxEvents.erase(itEvent);
989
990 Time payloadDuration =
991 ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(ppdu->GetTxVector());
993 ScheduleEndOfMpdus(event);
994 m_endRxPayloadEvents.push_back(
995 Simulator::Schedule(payloadDuration, &PhyEntity::EndReceivePayload, this, event));
996 uint16_t staId = GetStaId(ppdu);
997 m_signalNoiseMap.insert({std::make_pair(ppdu->GetUid(), staId), SignalNoiseDbm()});
998 m_statusPerMpduMap.insert({std::make_pair(ppdu->GetUid(), staId), std::vector<bool>()});
999 // Notify the MAC about the start of a new HE TB PPDU, so that it can reschedule the timeout
1000 NotifyPayloadBegin(ppdu->GetTxVector(), payloadDuration);
1001}
1002
1003std::pair<uint16_t, WifiSpectrumBand>
1004HePhy::GetChannelWidthAndBand(const WifiTxVector& txVector, uint16_t staId) const
1005{
1006 if (txVector.IsMu())
1007 {
1008 return std::make_pair(HeRu::GetBandwidth(txVector.GetRu(staId).GetRuType()),
1009 GetRuBandForRx(txVector, staId));
1010 }
1011 else
1012 {
1013 return PhyEntity::GetChannelWidthAndBand(txVector, staId);
1014 }
1015}
1016
1018HePhy::GetRuBandForTx(const WifiTxVector& txVector, uint16_t staId) const
1019{
1020 NS_ASSERT(txVector.IsMu());
1021 WifiSpectrumBand band;
1022 HeRu::RuSpec ru = txVector.GetRu(staId);
1023 uint16_t channelWidth = txVector.GetChannelWidth();
1024 NS_ASSERT(channelWidth <= m_wifiPhy->GetChannelWidth());
1026 channelWidth,
1027 ru.GetRuType(),
1029 HeRu::SubcarrierRange range = std::make_pair(group.front().first, group.back().second);
1030 // for a TX spectrum, the guard bandwidth is a function of the transmission channel width
1031 // and the spectrum width equals the transmission channel width (hence bandIndex equals 0)
1032 band =
1033 m_wifiPhy->ConvertHeRuSubcarriers(channelWidth, GetGuardBandwidth(channelWidth), range, 0);
1034 return band;
1035}
1036
1038HePhy::GetRuBandForRx(const WifiTxVector& txVector, uint16_t staId) const
1039{
1040 NS_ASSERT(txVector.IsMu());
1041 WifiSpectrumBand band;
1042 HeRu::RuSpec ru = txVector.GetRu(staId);
1043 uint16_t channelWidth = txVector.GetChannelWidth();
1044 NS_ASSERT(channelWidth <= m_wifiPhy->GetChannelWidth());
1046 channelWidth,
1047 ru.GetRuType(),
1049 HeRu::SubcarrierRange range = std::make_pair(group.front().first, group.back().second);
1050 // for an RX spectrum, the guard bandwidth is a function of the operating channel width
1051 // and the spectrum width equals the operating channel width
1053 channelWidth,
1055 range,
1057 return band;
1058}
1059
1061HePhy::GetNonOfdmaBand(const WifiTxVector& txVector, uint16_t staId) const
1062{
1063 NS_ASSERT(txVector.IsUlMu() && (txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE));
1064 uint16_t channelWidth = txVector.GetChannelWidth();
1065 NS_ASSERT(channelWidth <= m_wifiPhy->GetChannelWidth());
1066
1067 HeRu::RuSpec ru = txVector.GetRu(staId);
1068 uint16_t nonOfdmaWidth = GetNonOfdmaWidth(ru);
1069
1070 // Find the RU that encompasses the non-OFDMA part of the HE TB PPDU for the STA-ID
1071 HeRu::RuSpec nonOfdmaRu =
1072 HeRu::FindOverlappingRu(channelWidth, ru, HeRu::GetRuType(nonOfdmaWidth));
1073
1075 channelWidth,
1076 nonOfdmaRu.GetRuType(),
1077 nonOfdmaRu.GetPhyIndex(channelWidth,
1079 HeRu::SubcarrierRange range =
1080 std::make_pair(groupPreamble.front().first, groupPreamble.back().second);
1082 channelWidth,
1084 range,
1086}
1087
1088uint16_t
1090{
1091 if (ru.GetRuType() == HeRu::RU_26_TONE && ru.GetIndex() == 19)
1092 {
1093 // the center 26-tone RU in an 80 MHz channel is not fully covered by
1094 // any 20 MHz channel, but only by an 80 MHz channel
1095 return 80;
1096 }
1097 return std::max<uint16_t>(HeRu::GetBandwidth(ru.GetRuType()), 20);
1098}
1099
1100uint64_t
1102{
1103 return m_currentMuPpduUid;
1104}
1105
1106uint16_t
1108{
1109 uint16_t channelWidth = OfdmPhy::GetMeasurementChannelWidth(ppdu);
1117 if (channelWidth >= 40 && ppdu->GetUid() != m_previouslyTxPpduUid)
1118 {
1119 channelWidth = 20;
1120 }
1121 return channelWidth;
1122}
1123
1124double
1126{
1127 if (!ppdu)
1128 {
1129 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1130 }
1131
1132 if (!m_obssPdAlgorithm)
1133 {
1134 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1135 }
1136
1137 if (channelType == WIFI_CHANLIST_PRIMARY)
1138 {
1139 return VhtPhy::GetCcaThreshold(ppdu, channelType);
1140 }
1141
1142 const uint16_t ppduBw = ppdu->GetTxVector().GetChannelWidth();
1143 double obssPdLevel = m_obssPdAlgorithm->GetObssPdLevel();
1144 uint16_t bw = ppduBw;
1145 while (bw > 20)
1146 {
1147 obssPdLevel += 3;
1148 bw /= 2;
1149 }
1150
1151 return std::max(VhtPhy::GetCcaThreshold(ppdu, channelType), obssPdLevel);
1152}
1153
1154void
1156{
1157 NS_LOG_FUNCTION(this);
1158 const auto ccaIndication = GetCcaIndication(ppdu);
1159 const auto per20MHzDurations = GetPer20MHzDurations(ppdu);
1160 if (ccaIndication.has_value())
1161 {
1162 NS_LOG_DEBUG("CCA busy for " << ccaIndication.value().second << " during "
1163 << ccaIndication.value().first.As(Time::S));
1164 NotifyCcaBusy(ccaIndication.value().first, ccaIndication.value().second, per20MHzDurations);
1165 return;
1166 }
1167 if (ppdu)
1168 {
1169 SwitchMaybeToCcaBusy(nullptr);
1170 return;
1171 }
1172 if (per20MHzDurations != m_lastPer20MHzDurations)
1173 {
1174 /*
1175 * 8.3.5.12.3: For Clause 27 PHYs, this primitive is generated when (...) the per20bitmap
1176 * parameter changes.
1177 */
1178 NS_LOG_DEBUG("per-20MHz CCA durations changed");
1179 NotifyCcaBusy(Seconds(0), WIFI_CHANLIST_PRIMARY, per20MHzDurations);
1180 }
1181}
1182
1183void
1185{
1186 NS_LOG_FUNCTION(this << duration << channelType);
1187 NS_LOG_DEBUG("CCA busy for " << channelType << " during " << duration.As(Time::S));
1188 const auto per20MHzDurations = GetPer20MHzDurations(ppdu);
1189 NotifyCcaBusy(duration, channelType, per20MHzDurations);
1190}
1191
1192void
1194 WifiChannelListType channelType,
1195 const std::vector<Time>& per20MHzDurations)
1196{
1197 NS_LOG_FUNCTION(this << duration << channelType);
1198 m_state->SwitchMaybeToCcaBusy(duration, channelType, per20MHzDurations);
1199 m_lastPer20MHzDurations = per20MHzDurations;
1200}
1201
1202std::vector<Time>
1204{
1205 NS_LOG_FUNCTION(this);
1206
1213 if (m_wifiPhy->GetChannelWidth() < 40)
1214 {
1215 return {};
1216 }
1217
1218 std::vector<Time> per20MhzDurations{};
1221 for (auto index : indices)
1222 {
1223 auto band = m_wifiPhy->GetBand(20, index);
1230 double ccaThresholdDbm = -62;
1231 Time delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThresholdDbm, band);
1232
1233 if (ppdu)
1234 {
1235 const uint16_t subchannelMinFreq =
1236 m_wifiPhy->GetFrequency() - (m_wifiPhy->GetChannelWidth() / 2) + (index * 20);
1237 const uint16_t subchannelMaxFreq = subchannelMinFreq + 20;
1238 const uint16_t ppduBw = ppdu->GetTxVector().GetChannelWidth();
1239
1240 if (ppduBw <= m_wifiPhy->GetChannelWidth() &&
1241 ppdu->DoesOverlapChannel(subchannelMinFreq, subchannelMaxFreq))
1242 {
1243 std::optional<double> obssPdLevel{std::nullopt};
1245 {
1246 obssPdLevel = m_obssPdAlgorithm->GetObssPdLevel();
1247 }
1248 switch (ppduBw)
1249 {
1250 case 20:
1251 case 22:
1258 ccaThresholdDbm =
1259 obssPdLevel.has_value() ? std::max(-72.0, obssPdLevel.value()) : -72.0;
1260 band = m_wifiPhy->GetBand(20, index);
1261 break;
1262 case 40:
1269 ccaThresholdDbm =
1270 obssPdLevel.has_value() ? std::max(-72.0, obssPdLevel.value() + 3) : -72.0;
1271 band = m_wifiPhy->GetBand(40, std::floor(index / 2));
1272 break;
1273 case 80:
1280 ccaThresholdDbm =
1281 obssPdLevel.has_value() ? std::max(-69.0, obssPdLevel.value() + 6) : -69.0;
1282 band = m_wifiPhy->GetBand(80, std::floor(index / 4));
1283 break;
1284 case 160:
1285 // Not defined in the standard: keep -62 dBm
1286 break;
1287 default:
1288 NS_ASSERT_MSG(false, "Invalid channel width: " << ppduBw);
1289 }
1290 }
1291 Time ppduCcaDuration = GetDelayUntilCcaEnd(ccaThresholdDbm, band);
1292 delayUntilCcaEnd = std::max(delayUntilCcaEnd, ppduCcaDuration);
1293 }
1294 per20MhzDurations.push_back(delayUntilCcaEnd);
1295 }
1296
1297 return per20MhzDurations;
1298}
1299
1300uint64_t
1302{
1303 NS_LOG_FUNCTION(this << txVector);
1304 uint64_t uid;
1305 if (txVector.IsUlMu() || txVector.IsTriggerResponding())
1306 {
1307 // Use UID of PPDU containing trigger frame to identify resulting HE TB PPDUs, since the
1308 // latter should immediately follow the former
1310 NS_ASSERT(uid != UINT64_MAX);
1311 }
1312 else
1313 {
1314 uid = m_globalPpduUid++;
1315 }
1316 m_previouslyTxPpduUid = uid; // to be able to identify solicited HE TB PPDUs
1317 return uid;
1318}
1319
1322{
1323 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1324 NS_ASSERT(hePpdu);
1325 HePpdu::TxPsdFlag flag = hePpdu->GetTxPsdFlag();
1326 return GetTxPowerSpectralDensity(txPowerW, ppdu, flag);
1327}
1328
1332 HePpdu::TxPsdFlag flag) const
1333{
1334 const auto& txVector = ppdu->GetTxVector();
1335 uint16_t centerFrequency = GetCenterFrequencyForChannelWidth(txVector);
1336 uint16_t channelWidth = txVector.GetChannelWidth();
1337 NS_LOG_FUNCTION(this << centerFrequency << channelWidth << txPowerW << txVector);
1338 const auto& puncturedSubchannels = txVector.GetInactiveSubchannels();
1339 if (!puncturedSubchannels.empty())
1340 {
1341 const auto p20Index = m_wifiPhy->GetOperatingChannel().GetPrimaryChannelIndex(20);
1342 const auto& indices =
1344 const auto p20IndexInBitmap = p20Index - *(indices.cbegin());
1345 NS_ASSERT(
1346 !puncturedSubchannels.at(p20IndexInBitmap)); // the primary channel cannot be punctured
1347 }
1348 const auto& txMaskRejectionParams = GetTxMaskRejectionParams();
1349 switch (ppdu->GetType())
1350 {
1351 case WIFI_PPDU_TYPE_UL_MU: {
1352 if (flag == HePpdu::PSD_NON_HE_PORTION)
1353 {
1354 // non-OFDMA portion is sent only on the 20 MHz channels covering the RU
1355 const uint16_t staId = GetStaId(ppdu);
1356 centerFrequency = GetCenterFrequencyForNonOfdmaPart(txVector, staId);
1357 const uint16_t ruWidth = HeRu::GetBandwidth(txVector.GetRu(staId).GetRuType());
1358 channelWidth = (ruWidth < 20) ? 20 : ruWidth;
1360 centerFrequency,
1361 channelWidth,
1362 txPowerW,
1363 GetGuardBandwidth(channelWidth),
1364 std::get<0>(txMaskRejectionParams),
1365 std::get<1>(txMaskRejectionParams),
1366 std::get<2>(txMaskRejectionParams),
1367 puncturedSubchannels);
1368 }
1369 else
1370 {
1371 const auto band = GetRuBandForTx(txVector, GetStaId(ppdu));
1373 centerFrequency,
1374 channelWidth,
1375 txPowerW,
1376 GetGuardBandwidth(channelWidth),
1377 band);
1378 }
1379 }
1380 case WIFI_PPDU_TYPE_DL_MU: {
1381 if (flag == HePpdu::PSD_NON_HE_PORTION)
1382 {
1384 centerFrequency,
1385 channelWidth,
1386 txPowerW,
1387 GetGuardBandwidth(channelWidth),
1388 std::get<0>(txMaskRejectionParams),
1389 std::get<1>(txMaskRejectionParams),
1390 std::get<2>(txMaskRejectionParams),
1391 puncturedSubchannels);
1392 }
1393 else
1394 {
1396 centerFrequency,
1397 channelWidth,
1398 txPowerW,
1399 GetGuardBandwidth(channelWidth),
1400 std::get<0>(txMaskRejectionParams),
1401 std::get<1>(txMaskRejectionParams),
1402 std::get<2>(txMaskRejectionParams),
1403 puncturedSubchannels);
1404 }
1405 }
1406 case WIFI_PPDU_TYPE_SU:
1407 default: {
1408 NS_ASSERT(puncturedSubchannels.empty());
1410 centerFrequency,
1411 channelWidth,
1412 txPowerW,
1413 GetGuardBandwidth(channelWidth),
1414 std::get<0>(txMaskRejectionParams),
1415 std::get<1>(txMaskRejectionParams),
1416 std::get<2>(txMaskRejectionParams));
1417 }
1418 }
1419}
1420
1421uint16_t
1422HePhy::GetCenterFrequencyForNonOfdmaPart(const WifiTxVector& txVector, uint16_t staId) const
1423{
1424 NS_LOG_FUNCTION(this << txVector << staId);
1425 NS_ASSERT(txVector.IsUlMu() && (txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE));
1426 uint16_t centerFrequency = GetCenterFrequencyForChannelWidth(txVector);
1427 uint16_t currentWidth = txVector.GetChannelWidth();
1428
1429 HeRu::RuSpec ru = txVector.GetRu(staId);
1430 uint16_t nonOfdmaWidth = GetNonOfdmaWidth(ru);
1431 if (nonOfdmaWidth != currentWidth)
1432 {
1433 // Obtain the index of the non-OFDMA portion
1434 HeRu::RuSpec nonOfdmaRu =
1435 HeRu::FindOverlappingRu(currentWidth, ru, HeRu::GetRuType(nonOfdmaWidth));
1436
1437 uint16_t startingFrequency = centerFrequency - (currentWidth / 2);
1438 centerFrequency =
1439 startingFrequency +
1440 nonOfdmaWidth * (nonOfdmaRu.GetPhyIndex(
1441 currentWidth,
1443 1) +
1444 nonOfdmaWidth / 2;
1445 }
1446 return centerFrequency;
1447}
1448
1449void
1451{
1452 NS_LOG_FUNCTION(this << ppdu);
1453 const auto& txVector = ppdu->GetTxVector();
1454 if (auto mac = m_wifiPhy->GetDevice()->GetMac(); mac && (mac->GetTypeOfStation() == AP))
1455 {
1456 m_currentTxVector = txVector;
1457 }
1458 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU || ppdu->GetType() == WIFI_PPDU_TYPE_DL_MU)
1459 {
1460 auto nonOfdmaTxPowerDbm =
1462
1463 // temporarily set WifiPpdu flag to PSD_HE_PORTION for correct calculation of the OFDMA TX
1464 // power
1465 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1466 NS_ASSERT(hePpdu);
1467 hePpdu->SetTxPsdFlag(HePpdu::PSD_HE_PORTION);
1468 auto ofdmaTxPowerDbm = m_wifiPhy->GetTxPowerForTransmission(ppdu) + m_wifiPhy->GetTxGain();
1469 hePpdu->SetTxPsdFlag(HePpdu::PSD_NON_HE_PORTION);
1470
1471 // non-OFDMA part
1472 auto nonOfdmaDuration = ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU
1475 auto nonOfdmaTxPowerSpectrum =
1477 Transmit(nonOfdmaDuration,
1478 ppdu,
1479 nonOfdmaTxPowerDbm,
1480 nonOfdmaTxPowerSpectrum,
1481 "non-OFDMA transmission");
1482
1483 // OFDMA part
1484 auto ofdmaDuration = ppdu->GetTxDuration() - nonOfdmaDuration;
1485 auto ofdmaTxPowerSpectrum =
1487 Simulator::Schedule(nonOfdmaDuration,
1489 this,
1490 ppdu,
1491 ofdmaTxPowerDbm,
1492 ofdmaTxPowerSpectrum,
1493 ofdmaDuration);
1494 }
1495 else
1496 {
1497 PhyEntity::StartTx(ppdu);
1498 }
1499}
1500
1501void
1503 double txPowerDbm,
1504 Ptr<SpectrumValue> txPowerSpectrum,
1505 Time ofdmaDuration)
1506{
1507 NS_LOG_FUNCTION(this << ppdu << txPowerDbm << ofdmaDuration);
1508 auto hePpdu = DynamicCast<const HePpdu>(ppdu);
1509 NS_ASSERT(hePpdu);
1510 hePpdu->SetTxPsdFlag(HePpdu::PSD_HE_PORTION);
1511 Transmit(ofdmaDuration, ppdu, txPowerDbm, txPowerSpectrum, "OFDMA transmission");
1512}
1513
1514Time
1516 const WifiTxVector& txVector,
1517 WifiPhyBand band) const
1518{
1519 if (txVector.IsUlMu())
1520 {
1522 return ConvertLSigLengthToHeTbPpduDuration(txVector.GetLength(), txVector, band);
1523 }
1524
1525 Time maxDuration = Seconds(0);
1526 for (auto& staIdPsdu : psduMap)
1527 {
1528 if (txVector.IsDlMu())
1529 {
1531 WifiTxVector::HeMuUserInfoMap userInfoMap = txVector.GetHeMuUserInfoMap();
1532 NS_ABORT_MSG_IF(userInfoMap.find(staIdPsdu.first) == userInfoMap.end(),
1533 "STA-ID in psduMap (" << staIdPsdu.first
1534 << ") should be referenced in txVector");
1535 }
1536 Time current = WifiPhy::CalculateTxDuration(staIdPsdu.second->GetSize(),
1537 txVector,
1538 band,
1539 staIdPsdu.first);
1540 if (current > maxDuration)
1541 {
1542 maxDuration = current;
1543 }
1544 }
1545 NS_ASSERT(maxDuration.IsStrictlyPositive());
1546 return maxDuration;
1547}
1548
1549void
1551{
1552 for (uint8_t i = 0; i < 12; ++i)
1553 {
1554 GetHeMcs(i);
1555 }
1556}
1557
1559HePhy::GetHeMcs(uint8_t index)
1560{
1561#define CASE(x) \
1562 case x: \
1563 return GetHeMcs##x();
1564
1565 switch (index)
1566 {
1567 CASE(0)
1568 CASE(1)
1569 CASE(2)
1570 CASE(3)
1571 CASE(4)
1572 CASE(5)
1573 CASE(6)
1574 CASE(7)
1575 CASE(8)
1576 CASE(9)
1577 CASE(10)
1578 CASE(11)
1579 default:
1580 NS_ABORT_MSG("Inexistent index (" << +index << ") requested for HE");
1581 return WifiMode();
1582 }
1583#undef CASE
1584}
1585
1586#define GET_HE_MCS(x) \
1587 WifiMode HePhy::GetHeMcs##x() \
1588 { \
1589 static WifiMode mcs = CreateHeMcs(x); \
1590 return mcs; \
1591 };
1592
1593GET_HE_MCS(0)
1594GET_HE_MCS(1)
1595GET_HE_MCS(2)
1596GET_HE_MCS(3)
1597GET_HE_MCS(4)
1598GET_HE_MCS(5)
1599GET_HE_MCS(6)
1600GET_HE_MCS(7)
1601GET_HE_MCS(8)
1602GET_HE_MCS(9)
1603GET_HE_MCS(10)
1604GET_HE_MCS(11)
1605#undef GET_HE_MCS
1606
1607WifiMode
1609{
1610 NS_ASSERT_MSG(index <= 11, "HeMcs index must be <= 11!");
1611 return WifiModeFactory::CreateWifiMcs("HeMcs" + std::to_string(index),
1612 index,
1614 false,
1621}
1622
1624HePhy::GetCodeRate(uint8_t mcsValue)
1625{
1626 switch (mcsValue)
1627 {
1628 case 10:
1629 return WIFI_CODE_RATE_3_4;
1630 case 11:
1631 return WIFI_CODE_RATE_5_6;
1632 default:
1633 return VhtPhy::GetCodeRate(mcsValue);
1634 }
1635}
1636
1637uint16_t
1639{
1640 switch (mcsValue)
1641 {
1642 case 10:
1643 case 11:
1644 return 1024;
1645 default:
1646 return VhtPhy::GetConstellationSize(mcsValue);
1647 }
1648}
1649
1650uint64_t
1651HePhy::GetPhyRate(uint8_t mcsValue, uint16_t channelWidth, uint16_t guardInterval, uint8_t nss)
1652{
1653 WifiCodeRate codeRate = GetCodeRate(mcsValue);
1654 uint64_t dataRate = GetDataRate(mcsValue, channelWidth, guardInterval, nss);
1655 return HtPhy::CalculatePhyRate(codeRate, dataRate);
1656}
1657
1658uint64_t
1659HePhy::GetPhyRateFromTxVector(const WifiTxVector& txVector, uint16_t staId /* = SU_STA_ID */)
1660{
1661 uint16_t bw = txVector.GetChannelWidth();
1662 if (txVector.IsMu())
1663 {
1664 bw = HeRu::GetBandwidth(txVector.GetRu(staId).GetRuType());
1665 }
1666 return HePhy::GetPhyRate(txVector.GetMode(staId).GetMcsValue(),
1667 bw,
1668 txVector.GetGuardInterval(),
1669 txVector.GetNss(staId));
1670}
1671
1672uint64_t
1673HePhy::GetDataRateFromTxVector(const WifiTxVector& txVector, uint16_t staId /* = SU_STA_ID */)
1674{
1675 uint16_t bw = txVector.GetChannelWidth();
1676 if (txVector.IsMu())
1677 {
1678 bw = HeRu::GetBandwidth(txVector.GetRu(staId).GetRuType());
1679 }
1680 return HePhy::GetDataRate(txVector.GetMode(staId).GetMcsValue(),
1681 bw,
1682 txVector.GetGuardInterval(),
1683 txVector.GetNss(staId));
1684}
1685
1686uint64_t
1687HePhy::GetDataRate(uint8_t mcsValue, uint16_t channelWidth, uint16_t guardInterval, uint8_t nss)
1688{
1689 NS_ASSERT(guardInterval == 800 || guardInterval == 1600 || guardInterval == 3200);
1690 NS_ASSERT(nss <= 8);
1692 GetUsableSubcarriers(channelWidth),
1693 static_cast<uint16_t>(log2(GetConstellationSize(mcsValue))),
1695 nss);
1696}
1697
1698uint16_t
1699HePhy::GetUsableSubcarriers(uint16_t channelWidth)
1700{
1701 switch (channelWidth)
1702 {
1703 case 2: // 26-tone RU
1704 return 24;
1705 case 4: // 52-tone RU
1706 return 48;
1707 case 8: // 106-tone RU
1708 return 102;
1709 case 20:
1710 default:
1711 return 234;
1712 case 40:
1713 return 468;
1714 case 80:
1715 return 980;
1716 case 160:
1717 return 1960;
1718 }
1719}
1720
1721Time
1723{
1724 return NanoSeconds(12800) + guardInterval;
1725}
1726
1727uint64_t
1729{
1730 WifiCodeRate codeRate = GetCodeRate(mcsValue);
1731 uint16_t constellationSize = GetConstellationSize(mcsValue);
1732 return CalculateNonHtReferenceRate(codeRate, constellationSize);
1733}
1734
1735uint64_t
1736HePhy::CalculateNonHtReferenceRate(WifiCodeRate codeRate, uint16_t constellationSize)
1737{
1738 uint64_t dataRate;
1739 switch (constellationSize)
1740 {
1741 case 1024:
1742 if (codeRate == WIFI_CODE_RATE_3_4 || codeRate == WIFI_CODE_RATE_5_6)
1743 {
1744 dataRate = 54000000;
1745 }
1746 else
1747 {
1748 NS_FATAL_ERROR("Trying to get reference rate for a MCS with wrong combination of "
1749 "coding rate and modulation");
1750 }
1751 break;
1752 default:
1753 dataRate = VhtPhy::CalculateNonHtReferenceRate(codeRate, constellationSize);
1754 }
1755 return dataRate;
1756}
1757
1758bool
1759HePhy::IsAllowed(const WifiTxVector& /*txVector*/)
1760{
1761 return true;
1762}
1763
1766{
1767 uint16_t staId = SU_STA_ID;
1768
1769 if (IsUlMu(txVector.GetPreambleType()))
1770 {
1771 NS_ASSERT(txVector.GetHeMuUserInfoMap().size() == 1);
1772 staId = txVector.GetHeMuUserInfoMap().begin()->first;
1773 }
1774
1775 return WifiConstPsduMap({std::make_pair(staId, psdu)});
1776}
1777
1780{
1781 return 6500631;
1782}
1783
1786{
1789
1790 // Compute the number of bits used by common field.
1791 // Assume that compression bit in HE-SIG-A is not set (i.e. not
1792 // full band MU-MIMO); the field is present.
1793 auto bw = txVector.GetChannelWidth();
1794 auto commonFieldSize = 4 /* CRC */ + 6 /* tail */;
1795 if (bw <= 40)
1796 {
1797 commonFieldSize += 8; // only one allocation subfield
1798 }
1799 else
1800 {
1801 commonFieldSize += 8 * (bw / 40) /* one allocation field per 40 MHz */ + 1 /* center RU */;
1802 }
1803
1804 auto numStaPerContentChannel = txVector.GetNumRusPerHeSigBContentChannel();
1805 auto maxNumStaPerContentChannel =
1806 std::max(numStaPerContentChannel.first, numStaPerContentChannel.second);
1807 auto maxNumUserBlockFields = maxNumStaPerContentChannel /
1808 2; // handle last user block with single user, if any, further down
1809 std::size_t userSpecificFieldSize =
1810 maxNumUserBlockFields * (2 * 21 /* user fields (2 users) */ + 4 /* tail */ + 6 /* CRC */);
1811 if (maxNumStaPerContentChannel % 2 != 0)
1812 {
1813 userSpecificFieldSize += 21 /* last user field */ + 4 /* CRC */ + 6 /* tail */;
1814 }
1815
1816 return commonFieldSize + userSpecificFieldSize;
1817}
1818
1819bool
1820HePhy::CanStartRx(Ptr<const WifiPpdu> ppdu, uint16_t txChannelWidth) const
1821{
1822 /*
1823 * The PHY shall not issue a PHY-RXSTART.indication primitive in response to a PPDU
1824 * that does not overlap the primary channel, unless the PHY at an AP receives the
1825 * HE TB PPDU solicited by the AP. For the HE TB PPDU solicited by the AP, the PHY
1826 * shall issue a PHY-RXSTART.indication primitive for a PPDU received in the primary
1827 * or at the secondary 20 MHz channel, the secondary 40 MHz channel, or the secondary
1828 * 80 MHz channel.
1829 */
1831 if (ppdu->GetTxVector().IsUlMu() && mac && mac->GetTypeOfStation() == AP)
1832 {
1833 return true;
1834 }
1835 return PhyEntity::CanStartRx(ppdu, txChannelWidth);
1836}
1837
1840{
1841 if (ppdu->GetType() == WIFI_PPDU_TYPE_UL_MU)
1842 {
1843 Ptr<const WifiPpdu> rxPpdu;
1844 if ((m_trigVectorExpirationTime.has_value()) &&
1846 {
1847 // We only copy if the AP that is expecting a HE TB PPDU, since the content
1848 // of the TXVECTOR is reconstructed from the TRIGVECTOR, hence the other RX
1849 // PHYs should not have this information.
1850 rxPpdu = ppdu->Copy();
1851 }
1852 else
1853 {
1854 rxPpdu = ppdu;
1855 }
1856 auto hePpdu = DynamicCast<const HePpdu>(rxPpdu);
1857 NS_ASSERT(hePpdu);
1858 hePpdu->UpdateTxVectorForUlMu(m_trigVector);
1859 return rxPpdu;
1860 }
1861 else if (auto txVector = ppdu->GetTxVector();
1862 m_currentTxVector.has_value() &&
1863 (m_previouslyTxPpduUid == ppdu->GetUid()) && // response to a trigger frame
1864 (txVector.GetModulationClass() < WIFI_MOD_CLASS_HT)) // PPDU is a non-HT (duplicate)
1865 {
1866 auto triggerChannelWidth = m_currentTxVector->GetChannelWidth();
1867 if (txVector.GetChannelWidth() != triggerChannelWidth)
1868 {
1869 txVector.SetChannelWidth(triggerChannelWidth);
1870 ppdu->UpdateTxVector(txVector);
1871 }
1872 }
1873 return PhyEntity::GetRxPpduFromTxPpdu(ppdu);
1874}
1875
1876} // namespace ns3
1877
1878namespace
1879{
1880
1885{
1886 public:
1888 {
1890 ns3::WifiPhy::AddStaticPhyEntity(ns3::WIFI_MOD_CLASS_HE, ns3::Create<ns3::HePhy>());
1891 }
1893
1894} // namespace
#define min(a, b)
Definition: 80211b.c:42
#define max(a, b)
Definition: 80211b.c:43
Constructor class for HE modes.
Definition: he-phy.cc:1885
bool IsNull() const
Check for null implementation.
Definition: callback.h:572
std::optional< WifiTxVector > m_trigVector
the TRIGVECTOR
Definition: he-phy.h:527
Time GetLSigDuration(WifiPreamble preamble) const override
Definition: he-phy.cc:185
static Time ConvertLSigLengthToHeTbPpduDuration(uint16_t length, const WifiTxVector &txVector, WifiPhyBand band)
Definition: he-phy.cc:275
void StartReceiveOfdmaPayload(Ptr< Event > event)
Start receiving the PSDU (i.e.
Definition: he-phy.cc:961
uint64_t GetCurrentHeTbPpduUid() const
Definition: he-phy.cc:1101
Ptr< Event > DoGetEvent(Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPowersW) override
Get the event corresponding to the incoming PPDU.
Definition: he-phy.cc:447
void CancelAllEvents() override
Cancel and clear all running events.
Definition: he-phy.cc:402
WifiSpectrumBand 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:1061
void SetObssPdAlgorithm(const Ptr< ObssPdAlgorithm > algorithm)
Sets the OBSS-PD algorithm.
Definition: he-phy.cc:728
static void InitializeModes()
Initialize all HE modes.
Definition: he-phy.cc:1550
static uint32_t GetSigBFieldSize(const WifiTxVector &txVector)
Get variable length HE SIG-B field size based on TX Vector.
Definition: he-phy.cc:1785
void DoAbortCurrentReception(WifiPhyRxfailureReason reason) override
Perform amendment-specific actions before aborting the current reception.
Definition: he-phy.cc:414
Time CalculateTxDuration(WifiConstPsduMap psduMap, const WifiTxVector &txVector, WifiPhyBand band) const override
Definition: he-phy.cc:1515
std::pair< uint16_t, WifiSpectrumBand > 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:1004
void StartTxOfdma(Ptr< const WifiPpdu > ppdu, double txPowerDbm, Ptr< SpectrumValue > txPowerSpectrum, Time ofdmaDuration)
Start the transmission of the OFDMA part of the MU PPDU.
Definition: he-phy.cc:1502
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:749
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:529
Time GetSigBDuration(const WifiTxVector &txVector) const override
Definition: he-phy.cc:220
static WifiMode CreateHeMcs(uint8_t index)
Create and return the HE MCS corresponding to the provided index.
Definition: he-phy.cc:1608
static WifiMode GetHeMcs(uint8_t index)
Return the HE MCS corresponding to the provided index.
Definition: he-phy.cc:1559
void BuildModeList() override
Build mode list.
Definition: he-phy.cc:104
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:1765
uint16_t GetNonOfdmaWidth(HeRu::RuSpec ru) const
Get the width in MHz of the non-OFDMA portion of an HE TB PPDU.
Definition: he-phy.cc:1089
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:1736
std::map< uint16_t, EventId > m_beginOfdmaPayloadRxEvents
the beginning of the OFDMA payload reception events (indexed by STA-ID)
Definition: he-phy.h:523
void SetEndOfHeSigACallback(EndOfHeSigACallback callback)
Set a callback for a end of HE-SIG-A.
Definition: he-phy.cc:734
uint64_t m_previouslyTxPpduUid
UID of the previously sent PPDU, used by AP to recognize response HE TB PPDUs.
Definition: he-phy.h:518
static WifiCodeRate GetCodeRate(uint8_t mcsValue)
Return the coding rate corresponding to the supplied HE MCS index.
Definition: he-phy.cc:1624
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:1450
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:617
WifiSpectrumBand 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:1038
EndOfHeSigACallback m_endOfHeSigACallback
end of HE-SIG-A callback
Definition: he-phy.h:526
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:572
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:117
const PpduFormats & GetPpduFormats() const override
Return the PPDU formats of the PHY.
Definition: he-phy.cc:179
uint64_t ObtainNextUid(const WifiTxVector &txVector) override
Obtain the next UID for the PPDU to transmit.
Definition: he-phy.cc:1301
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:1659
Ptr< ObssPdAlgorithm > m_obssPdAlgorithm
OBSS-PD algorithm.
Definition: he-phy.h:612
bool CanStartRx(Ptr< const WifiPpdu > ppdu, uint16_t txChannelWidth) const override
Determine whether the PHY shall issue a PHY-RXSTART.indication primitive in response to a given PPDU.
Definition: he-phy.cc:1820
uint16_t GetCenterFrequencyForNonOfdmaPart(const WifiTxVector &txVector, uint16_t staId) const
Get the center frequency of the non-OFDMA part of the current TxVector for the given STA-ID.
Definition: he-phy.cc:1422
virtual Time CalculateNonOfdmaDurationForHeTb(const WifiTxVector &txVector) const
Definition: he-phy.cc:289
uint8_t GetBssColor() const
Definition: he-phy.cc:584
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:243
uint8_t GetNumberBccEncoders(const WifiTxVector &txVector) const override
Definition: he-phy.cc:308
static bool IsAllowed(const WifiTxVector &txVector)
Check whether the combination in TXVECTOR is allowed.
Definition: he-phy.cc:1759
std::size_t m_rxHeTbPpdus
Number of successfully received HE TB PPDUS.
Definition: he-phy.h:611
~HePhy() override
Destructor for HE PHY.
Definition: he-phy.cc:98
Ptr< WifiPpdu > BuildPpdu(const WifiConstPsduMap &psdus, const WifiTxVector &txVector, Time ppduDuration) override
Build amendment-specific PPDU.
Definition: he-phy.cc:337
void NotifyEndOfHeSigA(HeSigAParameters params)
Fire a EndOfHeSigA callback (if connected) once HE-SIG-A field has been received.
Definition: he-phy.cc:740
static uint64_t GetDataRate(uint8_t mcsValue, uint16_t channelWidth, uint16_t guardInterval, uint8_t nss)
Return the data rate corresponding to the supplied HE MCS index, channel width, guard interval,...
Definition: he-phy.cc:1687
virtual Time CalculateNonOfdmaDurationForHeMu(const WifiTxVector &txVector) const
Definition: he-phy.cc:298
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:889
static uint64_t GetPhyRate(uint8_t mcsValue, uint16_t channelWidth, uint16_t guardInterval, uint8_t nss)
Return the PHY rate corresponding to the supplied HE MCS index, channel width, guard interval,...
Definition: he-phy.cc:1651
uint64_t m_currentMuPpduUid
UID of the HE MU or HE TB PPDU being received.
Definition: he-phy.h:520
uint32_t GetMaxPsduSize() const override
Get the maximum PSDU size in bytes.
Definition: he-phy.cc:1779
static const PpduFormats m_hePpduFormats
HE PPDU formats.
Definition: he-phy.h:609
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:1673
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:1203
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:908
double GetCcaThreshold(const Ptr< const WifiPpdu > ppdu, WifiChannelListType channelType) const override
Return the CCA threshold in dBm for a given channel type.
Definition: he-phy.cc:1125
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:1839
HePhy(bool buildModeList=true)
Constructor for HE PHY.
Definition: he-phy.cc:78
bool IsConfigSupported(Ptr< const WifiPpdu > ppdu) const override
Checks if the signaled configuration (excluding bandwidth) is supported by the PHY.
Definition: he-phy.cc:780
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:599
static Time GetSymbolDuration(Time guardInterval)
Definition: he-phy.cc:1722
void SetTrigVector(const WifiTxVector &trigVector, Time validity)
Set the TRIGVECTOR and the associated expiration time.
Definition: he-phy.cc:322
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:256
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:1728
WifiSpectrumBand 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:1018
WifiMode GetSigBMode(const WifiTxVector &txVector) const override
Definition: he-phy.cc:146
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:1155
Time DoStartReceivePayload(Ptr< Event > event) override
Start receiving the PSDU (i.e.
Definition: he-phy.cc:819
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:351
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:634
std::optional< Time > m_trigVectorExpirationTime
expiration time of the TRIGVECTOR
Definition: he-phy.h:528
void DoEndReceivePayload(Ptr< const WifiPpdu > ppdu) override
Perform amendment-specific actions at the end of the reception of the payload.
Definition: he-phy.cc:919
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:432
WifiMode GetSigAMode() const override
Definition: he-phy.cc:140
Time GetSigADuration(WifiPreamble preamble) const override
Definition: he-phy.cc:212
Time GetTrainingDuration(const WifiTxVector &txVector, uint8_t nDataLtf, uint8_t nExtensionLtf=0) const override
Definition: he-phy.cc:191
std::vector< Time > m_lastPer20MHzDurations
Hold the last per-20 MHz CCA durations vector.
Definition: he-phy.h:613
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:1184
Ptr< SpectrumValue > GetTxPowerSpectralDensity(double txPowerW, Ptr< const WifiPpdu > ppdu) const override
Definition: he-phy.cc:1321
uint16_t GetMeasurementChannelWidth(const Ptr< const WifiPpdu > ppdu) const override
Return the channel width used to measure the RSSI.
Definition: he-phy.cc:1107
static uint16_t GetConstellationSize(uint8_t mcsValue)
Return the constellation size corresponding to the supplied HE MCS index.
Definition: he-phy.cc:1638
TxPsdFlag
The transmit power spectral density flag, namely used to correctly build PSDs for pre-HE and HE porti...
Definition: he-ppdu.h:156
@ PSD_HE_PORTION
HE portion of an HE PPDU.
Definition: he-ppdu.h:158
@ PSD_NON_HE_PORTION
Non-HE portion of an HE PPDU.
Definition: he-ppdu.h:157
RU Specification.
Definition: he-ru.h:66
std::size_t GetIndex() const
Get the RU index.
Definition: he-ru.cc:442
RuType GetRuType() const
Get the RU type.
Definition: he-ru.cc:435
std::size_t GetPhyIndex(uint16_t bw, uint8_t p20Index) const
Get the RU PHY index.
Definition: he-ru.cc:456
static RuSpec FindOverlappingRu(uint16_t bw, RuSpec referenceRu, RuType searchedRuType)
Find the RU allocation of the given RU type overlapping the given reference RU allocation.
Definition: he-ru.cc:666
static uint16_t GetBandwidth(RuType ruType)
Get the approximate bandwidth occupied by a RU.
Definition: he-ru.cc:744
static SubcarrierGroup GetSubcarrierGroup(uint16_t 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:568
std::vector< SubcarrierRange > SubcarrierGroup
a vector of subcarrier ranges defining a subcarrier group
Definition: he-ru.h:55
std::pair< int16_t, int16_t > SubcarrierRange
(lowest index, highest index) pair defining a subcarrier range
Definition: he-ru.h:52
@ RU_26_TONE
Definition: he-ru.h:42
static RuType GetRuType(uint16_t bandwidth)
Get the RU corresponding to the approximate bandwidth.
Definition: he-ru.cc:769
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:659
uint8_t m_bssMembershipSelector
the BSS membership selector
Definition: ht-phy.h:558
uint8_t m_maxMcsIndexPerSs
the maximum MCS index per spatial stream as defined by the standard
Definition: ht-phy.h:556
static uint64_t CalculateDataRate(Time symbolDuration, uint16_t usableSubCarriers, uint16_t numberOfBitsPerSubcarrier, double codingRate, uint8_t nss)
Calculates data rate from the supplied parameters.
Definition: ht-phy.cc:707
static double GetCodeRatio(WifiCodeRate codeRate)
Convert WifiCodeRate to a ratio, e.g., code ratio of WIFI_CODE_RATE_1_2 is 0.5.
Definition: ht-phy.cc:674
uint8_t m_maxSupportedMcsIndexPerSs
the maximum supported MCS index per spatial stream
Definition: ht-phy.h:557
double GetObssPdLevel() const
static uint16_t GetUsableSubcarriers()
Definition: ofdm-phy.cc:633
uint16_t GetMeasurementChannelWidth(const Ptr< const WifiPpdu > ppdu) const override
Return the channel width used to measure the RSSI.
Definition: ofdm-phy.cc:667
void NotifyPayloadBegin(const WifiTxVector &txVector, const Time &payloadDuration)
Fire the trace indicating that the PHY is starting to receive the payload of a PPDU.
Definition: phy-entity.cc:1276
Ptr< WifiPhyStateHelper > m_state
Pointer to WifiPhyStateHelper of the WifiPhy (to make it reachable for child classes)
Definition: phy-entity.h:964
std::tuple< double, double, double > GetTxMaskRejectionParams() const
Definition: phy-entity.cc:1324
virtual Time DoStartReceivePayload(Ptr< Event > event)
Start receiving the PSDU (i.e.
Definition: phy-entity.cc:584
virtual bool CanStartRx(Ptr< const WifiPpdu > ppdu, uint16_t txChannelWidth) const
Determine whether the PHY shall issue a PHY-RXSTART.indication primitive in response to a given PPDU.
Definition: phy-entity.cc:1340
virtual void StartReceivePreamble(Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPowersW, Time rxDuration)
Start receiving the PHY preamble of a PPDU (i.e.
Definition: phy-entity.cc:399
Ptr< Event > CreateInterferenceEvent(Ptr< const WifiPpdu > ppdu, const WifiTxVector &txVector, Time duration, RxPowerWattPerChannelBand &rxPower, bool isStartOfdmaRxing=false)
Create an event using WifiPhy's InterferenceHelper class.
Definition: phy-entity.cc:867
const std::map< std::pair< uint64_t, WifiPreamble >, Ptr< Event > > & GetCurrentPreambleEvents() const
Get the map of current preamble events (stored in WifiPhy).
Definition: phy-entity.cc:837
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:984
Ptr< WifiPhy > m_wifiPhy
Pointer to the owning WifiPhy.
Definition: phy-entity.h:963
void Transmit(Time txDuration, Ptr< const WifiPpdu > ppdu, double txPowerDbm, Ptr< SpectrumValue > txPowerSpectrum, const std::string &type)
This function prepares most of the WifiSpectrumSignalParameters parameters and invokes SpectrumWifiPh...
Definition: phy-entity.cc:1292
std::vector< EventId > m_endOfMpduEvents
the end of MPDU events (only used for A-MPDUs)
Definition: phy-entity.h:970
virtual std::pair< uint16_t, WifiSpectrumBand > GetChannelWidthAndBand(const WifiTxVector &txVector, uint16_t staId) const
Get the channel width and band to use (will be overloaded by child classes).
Definition: phy-entity.cc:830
virtual void CancelAllEvents()
Cancel and clear all running events.
Definition: phy-entity.cc:1069
virtual void DoAbortCurrentReception(WifiPhyRxfailureReason reason)
Perform amendment-specific actions before aborting the current reception.
Definition: phy-entity.cc:1121
void EndReceivePayload(Ptr< Event > event)
The last symbol of the PPDU has arrived.
Definition: phy-entity.cc:705
std::map< WifiPreamble, std::vector< WifiPpduField > > PpduFormats
A map of PPDU field elements per preamble type.
Definition: phy-entity.h:556
static uint64_t m_globalPpduUid
Global counter of the PPDU UID.
Definition: phy-entity.h:987
std::vector< EventId > m_endRxPayloadEvents
the end of receive events (only one unless UL MU reception)
Definition: phy-entity.h:973
virtual Ptr< Event > DoGetEvent(Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPowersW)
Get the event corresponding to the incoming PPDU.
Definition: phy-entity.cc:852
double GetRxPowerWForPpdu(Ptr< Event > event) const
Obtain the received power (W) for a given band.
Definition: phy-entity.cc:1162
Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector) const
Definition: phy-entity.cc:200
void NotifyInterferenceRxEndAndClear(bool reset)
Notify WifiPhy's InterferenceHelper of the end of the reception, clear maps and end of MPDU event,...
Definition: phy-entity.cc:883
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:981
virtual void StartTx(Ptr< const WifiPpdu > ppdu)
This function is called by SpectrumWifiPhy to send the PPDU while performing amendment-specific actio...
Definition: phy-entity.cc:1282
Time GetDelayUntilCcaEnd(double thresholdDbm, WifiSpectrumBand band)
Return the delay until CCA busy is ended for a given sensitivity threshold (in dBm) and a given band.
Definition: phy-entity.cc:1206
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.
Definition: phy-entity.cc:568
uint16_t GetGuardBandwidth(uint16_t currentChannelWidth) const
Definition: phy-entity.cc:1318
virtual bool IsModeSupported(WifiMode mode) const
Check if the WifiMode is supported.
Definition: phy-entity.cc:97
void ResetReceive(Ptr< Event > event)
Reset PHY at the end of the PPDU under reception after it has failed the PHY header.
Definition: phy-entity.cc:1135
std::list< WifiMode > m_modeList
the list of supported modes
Definition: phy-entity.h:967
Ptr< const Event > GetCurrentEvent() const
Get the pointer to the current event (stored in WifiPhy).
Definition: phy-entity.cc:1168
virtual Ptr< const WifiPsdu > GetAddressedPsduInPpdu(Ptr< const WifiPpdu > ppdu) const
Get the PSDU addressed to that PHY in a PPDU (useful for MU PPDU).
Definition: phy-entity.cc:217
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 ...
Definition: phy-entity.cc:546
virtual Ptr< const WifiPpdu > GetRxPpduFromTxPpdu(Ptr< const WifiPpdu > ppdu)
The WifiPpdu from the TX PHY is received by each RX PHY attached to the same channel.
Definition: phy-entity.cc:1364
void AddPreambleEvent(Ptr< Event > event)
Add an entry to the map of current preamble events (stored in WifiPhy).
Definition: phy-entity.cc:843
virtual void DoEndReceivePayload(Ptr< const WifiPpdu > ppdu)
Perform amendment-specific actions at the end of the reception of the payload.
Definition: phy-entity.cc:774
uint16_t GetCenterFrequencyForChannelWidth(const WifiTxVector &txVector) const
Get the center frequency of the channel corresponding the current TxVector rather than that of the su...
Definition: phy-entity.cc:1267
@ DROP
drop PPDU and set CCA_BUSY
Definition: phy-entity.h:104
void UpdateInterferenceEvent(Ptr< Event > event, const RxPowerWattPerChannelBand &rxPower)
Update an event in WifiPhy's InterferenceHelper class.
Definition: phy-entity.cc:877
void ScheduleEndOfMpdus(Ptr< Event > event)
Schedule end of MPDUs events.
Definition: phy-entity.cc:606
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:417
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:417
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition: nstime.h:350
@ US
microsecond
Definition: nstime.h:118
@ S
second
Definition: nstime.h:116
@ NS
nanosecond
Definition: nstime.h:119
PHY entity for VHT (11ac)
Definition: vht-phy.h:49
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:405
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:173
double GetCcaThreshold(const Ptr< const WifiPpdu > ppdu, WifiChannelListType channelType) const override
Return the CCA threshold in dBm for a given channel type.
Definition: vht-phy.cc:546
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:586
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:495
static WifiMode GetVhtMcs3()
Return MCS 3 from VHT MCS values.
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:419
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:135
TypeOfStation GetTypeOfStation() const
Return the type of station.
Definition: wifi-mac.cc:418
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:318
represent a single transmission mode
Definition: wifi-mode.h:50
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:122
uint8_t GetMcsValue() const
Definition: wifi-mode.cc:163
Ptr< WifiMac > GetMac() const
Ptr< HeConfiguration > GetHeConfiguration() const
uint16_t GetChannelWidth() const
Definition: wifi-phy.cc:1026
double GetTxGain() const
Return the transmission gain (dB).
Definition: wifi-phy.cc:568
void NotifyRxDrop(Ptr< const WifiPsdu > psdu, WifiPhyRxfailureReason reason)
Public method used to fire a PhyRxDrop trace.
Definition: wifi-phy.cc:1581
uint16_t GetFrequency() const
Definition: wifi-phy.cc:1014
uint8_t GetMaxSupportedRxSpatialStreams() const
Definition: wifi-phy.cc:1295
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1480
virtual WifiSpectrumBand ConvertHeRuSubcarriers(uint16_t bandWidth, uint16_t guardBandwidth, HeRu::SubcarrierRange range, uint8_t bandIndex=0) const
Definition: wifi-phy.cc:1839
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:996
virtual WifiSpectrumBand GetBand(uint16_t bandWidth, uint8_t bandIndex=0)
Get the start band index and the stop band index for a given band.
Definition: wifi-phy.cc:2175
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:745
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition: wifi-phy.cc:606
double GetTxPowerForTransmission(Ptr< const WifiPpdu > ppdu) const
Compute the transmit power for the next transmission.
Definition: wifi-phy.cc:2132
uint64_t GetPreviouslyRxPpduUid() const
Definition: wifi-phy.cc:1798
Time GetLastRxEndTime() const
Return the end time of the last received packet.
Definition: wifi-phy.cc:2052
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition: wifi-phy.cc:1008
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1473
uint8_t GetPrimaryChannelIndex(uint16_t primaryChannelWidth) const
If the operating channel width is a multiple of 20 MHz, return the index of the primary channel of th...
std::set< uint8_t > GetAll20MHzChannelIndicesInPrimary(uint16_t width) const
Get the channel indices of all the 20 MHz channels included in the primary channel of the given width...
uint16_t GetPrimaryChannelCenterFrequency(uint16_t primaryChannelWidth) const
Get the center frequency of the primary channel of the given width.
static Ptr< SpectrumValue > CreateDuplicated20MhzTxPowerSpectralDensity(uint32_t centerFrequency, uint16_t channelWidth, double txPowerW, uint16_t guardBandwidth, double minInnerBandDbr=-20, double minOuterbandDbr=-28, double lowestPointDbr=-40, const std::vector< bool > &puncturedSubchannels=std::vector< bool >{})
Create a transmit power spectral density corresponding to OFDM duplicated over multiple 20 MHz subcha...
static Ptr< SpectrumValue > CreateHeMuOfdmTxPowerSpectralDensity(uint32_t centerFrequency, uint16_t channelWidth, double txPowerW, uint16_t guardBandwidth, WifiSpectrumBand ru)
Create a transmit power spectral density corresponding to the OFDMA part of HE TB PPDUs for a given R...
static Ptr< SpectrumValue > CreateHeOfdmTxPowerSpectralDensity(uint32_t centerFrequency, uint16_t channelWidth, double txPowerW, uint16_t guardBandwidth, double minInnerBandDbr=-20, double minOuterbandDbr=-28, double lowestPointDbr=-40, const std::vector< bool > &puncturedSubchannels=std::vector< bool >{})
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.
uint16_t GetGuardInterval() const
uint8_t GetBssColor() const
Get the BSS color.
std::map< uint16_t, HeMuUserInfo > HeMuUserInfoMap
map of HE MU specific user info parameters indexed by STA-ID
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
HeMuUserInfo GetHeMuUserInfo(uint16_t staId) const
Get the HE MU user-specific transmission information for the given STA-ID.
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.
bool IsDlMu() const
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.
uint8_t GetNssMax() const
bool IsUlMu() const
std::pair< std::size_t, std::size_t > GetNumRusPerHeSigBContentChannel() const
Get the number of RUs per HE-SIG-B content channel.
uint16_t GetChannelWidth() const
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#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:86
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:243
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:229
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#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:275
auto MakeBoundCallback(R(*fnPtr)(Args...), BArgs &&... bargs)
Make Callbacks with varying number of bound arguments.
Definition: callback.h:768
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1360
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1372
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time FemtoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1396
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.
Definition: wifi-phy-band.h:33
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)
@ OBSS_PD_CCA_RESET
@ HE_TB_PPDU_TOO_LATE
@ 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.
Definition: wifi-phy-band.h:35
@ WIFI_PPDU_TYPE_DL_MU
@ WIFI_PPDU_TYPE_UL_MU
@ WIFI_PPDU_TYPE_SU
@ WIFI_MOD_CLASS_HT
HT (Clause 19)
@ 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:1586
#define CASE(x)
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:48
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.
const uint16_t WIFI_CODE_RATE_3_4
3/4 coding rate
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
@ AP
Definition: wifi-mac.h:63
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:707
std::pair< uint32_t, uint32_t > WifiSpectrumBand
typedef for a pair of start and stop sub-band indexes
double DbmToW(double dBm)
Convert from dBm to Watts.
Definition: wifi-utils.cc:40
std::map< WifiSpectrumBand, double > RxPowerWattPerChannelBand
A map of the received power (Watts) for each band.
Definition: phy-entity.h:78
uint16_t WifiCodeRate
These constants define the various convolutional coding rates used for the OFDM transmission modes in...
const uint16_t WIFI_CODE_RATE_5_6
5/6 coding rate
@ LOG_FUNCTION
Function tracing.
Definition: log.h:109
bool IsDlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a downlink multi-user transmission.
bool IsUlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a uplink multi-user transmission.
STL namespace.
mac
Definition: third.py:85
params
Fit Fluctuating Two Ray model to the 3GPP TR 38.901 using the Anderson-Darling goodness-of-fit ##.
Parameters for received HE-SIG-A for OBSS_PD based SR.
Definition: he-phy.h:54
Status of the reception of the PPDU field.
Definition: phy-entity.h:113
bool isSuccess
outcome (true if success) of the reception
Definition: phy-entity.h:114
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:70
SignalNoiseDbm structure.
Definition: phy-entity.h:56
#define SU_STA_ID
Definition: wifi-mode.h:34