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