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