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