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