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