A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
he-ppdu.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 * Author: Rediet <getachew.redieteab@orange.com>
18 * Muhammad Iqbal Rochman <muhiqbalcr@uchicago.edu>
19 * Sébastien Deronne <sebastien.deronne@gmail.com> (HeSigHeader)
20 */
21
22#include "he-ppdu.h"
23
24#include "he-phy.h"
25
26#include "ns3/log.h"
27#include "ns3/wifi-phy-operating-channel.h"
28#include "ns3/wifi-phy.h"
29#include "ns3/wifi-psdu.h"
30#include "ns3/wifi-utils.h"
31
32namespace ns3
33{
34
36
37std::ostream&
38operator<<(std::ostream& os, const HePpdu::TxPsdFlag& flag)
39{
40 switch (flag)
41 {
43 return (os << "PSD_NON_HE_PORTION");
45 return (os << "PSD_HE_PORTION");
46 default:
47 NS_FATAL_ERROR("Invalid PSD flag");
48 return (os << "INVALID");
49 }
50}
51
53 const WifiTxVector& txVector,
54 const WifiPhyOperatingChannel& channel,
55 Time ppduDuration,
56 uint64_t uid,
57 TxPsdFlag flag)
58 : OfdmPpdu(psdus.begin()->second,
59 txVector,
60 channel,
61 uid,
62 false), // don't instantiate LSigHeader of OfdmPpdu
63 m_txPsdFlag(flag)
64{
65 NS_LOG_FUNCTION(this << psdus << txVector << channel << ppduDuration << uid << flag);
66
67 // overwrite with map (since only first element used by OfdmPpdu)
68 m_psdus.begin()->second = nullptr;
69 m_psdus.clear();
70 m_psdus = psdus;
71 SetPhyHeaders(txVector, ppduDuration);
72}
73
75 const WifiTxVector& txVector,
76 const WifiPhyOperatingChannel& channel,
77 Time ppduDuration,
78 uint64_t uid)
79 : OfdmPpdu(psdu,
80 txVector,
81 channel,
82 uid,
83 false), // don't instantiate LSigHeader of OfdmPpdu
84 m_txPsdFlag(PSD_NON_HE_PORTION)
85{
86 NS_LOG_FUNCTION(this << psdu << txVector << channel << ppduDuration << uid);
87 NS_ASSERT(!IsMu());
88 SetPhyHeaders(txVector, ppduDuration);
89}
90
91void
92HePpdu::SetPhyHeaders(const WifiTxVector& txVector, Time ppduDuration)
93{
94 NS_LOG_FUNCTION(this << txVector << ppduDuration);
95 SetLSigHeader(ppduDuration);
96 SetHeSigHeader(txVector);
97}
98
99void
101{
102 uint8_t sigExtension = 0;
105 {
106 sigExtension = 6;
107 }
108 uint8_t m = IsDlMu() ? 1 : 2;
109 uint16_t length = ((ceil((static_cast<double>(ppduDuration.GetNanoSeconds() - (20 * 1000) -
110 (sigExtension * 1000)) /
111 1000) /
112 4.0) *
113 3) -
114 3 - m);
115 m_lSig.SetLength(length);
116}
117
118void
120{
121 const auto bssColor = txVector.GetBssColor();
122 NS_ASSERT(bssColor < 64);
124 {
126 .m_bssColor = bssColor,
127 .m_bandwidth = GetChannelWidthEncodingFromMhz(txVector.GetChannelWidth())});
128 }
129 else if (ns3::IsDlMu(m_preamble))
130 {
131 const auto p20Index = m_operatingChannel.GetPrimaryChannelIndex(20);
133 .m_bssColor = bssColor,
134 .m_bandwidth = GetChannelWidthEncodingFromMhz(txVector.GetChannelWidth()),
135 .m_sigBMcs = txVector.GetSigBMode().GetMcsValue(),
136 .m_giLtfSize = GetGuardIntervalAndNltfEncoding(txVector.GetGuardInterval(),
137 2 /*NLTF currently unused*/),
138 .m_ruAllocation = txVector.GetRuAllocation(p20Index),
139 .m_contentChannels = GetHeSigBContentChannels(txVector, p20Index),
140 .m_center26ToneRuIndication =
141 (txVector.GetChannelWidth() >= 80)
142 ? std::optional{txVector.GetCenter26ToneRuIndication()}
143 : std::nullopt});
144 }
145 else
146 {
147 const auto mcs = txVector.GetMode().GetMcsValue();
148 NS_ASSERT(mcs <= 11);
150 .m_bssColor = bssColor,
151 .m_mcs = mcs,
152 .m_bandwidth = GetChannelWidthEncodingFromMhz(txVector.GetChannelWidth()),
153 .m_giLtfSize = GetGuardIntervalAndNltfEncoding(txVector.GetGuardInterval(),
154 2 /*NLTF currently unused*/),
155 .m_nsts = GetNstsEncodingFromNss(txVector.GetNss())});
156 }
157}
158
161{
162 WifiTxVector txVector;
163 txVector.SetPreambleType(m_preamble);
165 return txVector;
166}
167
168void
170{
171 txVector.SetLength(m_lSig.GetLength());
172 txVector.SetAggregation(m_psdus.size() > 1 || m_psdus.begin()->second->IsAggregate());
173 if (!IsMu())
174 {
175 auto heSigHeader = std::get_if<HeSuSigHeader>(&m_heSig);
176 NS_ASSERT(heSigHeader && (heSigHeader->m_format == 1));
177 txVector.SetMode(HePhy::GetHeMcs(heSigHeader->m_mcs));
178 txVector.SetNss(GetNssFromNstsEncoding(heSigHeader->m_nsts));
179 txVector.SetChannelWidth(GetChannelWidthMhzFromEncoding(heSigHeader->m_bandwidth));
180 txVector.SetGuardInterval(GetGuardIntervalFromEncoding(heSigHeader->m_giLtfSize));
181 txVector.SetBssColor(heSigHeader->m_bssColor);
182 }
183 else if (IsUlMu())
184 {
185 auto heSigHeader = std::get_if<HeTbSigHeader>(&m_heSig);
186 NS_ASSERT(heSigHeader && (heSigHeader->m_format == 0));
187 txVector.SetChannelWidth(GetChannelWidthMhzFromEncoding(heSigHeader->m_bandwidth));
188 txVector.SetBssColor(heSigHeader->m_bssColor);
189 }
190 else if (IsDlMu())
191 {
192 auto heSigHeader = std::get_if<HeMuSigHeader>(&m_heSig);
193 NS_ASSERT(heSigHeader);
194 txVector.SetChannelWidth(GetChannelWidthMhzFromEncoding(heSigHeader->m_bandwidth));
195 txVector.SetGuardInterval(GetGuardIntervalFromEncoding(heSigHeader->m_giLtfSize));
196 txVector.SetBssColor(heSigHeader->m_bssColor);
197 SetHeMuUserInfos(txVector, heSigHeader->m_ruAllocation, heSigHeader->m_contentChannels);
198 txVector.SetSigBMode(HePhy::GetVhtMcs(heSigHeader->m_sigBMcs));
199 const auto p20Index = m_operatingChannel.GetPrimaryChannelIndex(20);
200 txVector.SetRuAllocation(heSigHeader->m_ruAllocation, p20Index);
201 if (heSigHeader->m_center26ToneRuIndication.has_value())
202 {
203 txVector.SetCenter26ToneRuIndication(heSigHeader->m_center26ToneRuIndication.value());
204 }
205 }
206}
207
208void
210 const RuAllocation& ruAllocation,
211 const HeSigBContentChannels& contentChannels) const
212{
213 auto contentChannelIndex = 0;
214 for (const auto& contentChannel : contentChannels)
215 {
216 auto numRusLeft = 0;
217 auto ruAllocIndex = contentChannelIndex;
218 for (const auto& userInfo : contentChannel)
219 {
220 if (userInfo.staId == NO_USER_STA_ID)
221 {
222 continue;
223 }
224 auto ruSpecs = HeRu::GetRuSpecs(ruAllocation.at(ruAllocIndex));
225 if (ruSpecs.empty())
226 {
227 continue;
228 }
229 if (numRusLeft == 0)
230 {
231 numRusLeft = ruSpecs.size();
232 }
233 auto ruIndex = (ruSpecs.size() - numRusLeft);
234 auto ruSpec = ruSpecs.at(ruIndex);
235 auto ruType = ruSpec.GetRuType();
236 if ((ruAllocation.size() == 8) && (ruType == HeRu::RU_996_TONE) &&
237 (std::all_of(
238 contentChannel.cbegin(),
239 contentChannel.cend(),
240 [&userInfo](const auto& item) { return userInfo.staId == item.staId; })))
241 {
242 NS_ASSERT(txVector.GetChannelWidth() == 160);
243 ruType = HeRu::RU_2x996_TONE;
244 }
245 const auto ruBw = HeRu::GetBandwidth(ruType);
246 auto primary80 = ruAllocIndex < 4;
247 auto num20MhzSubchannelsInRu = (ruBw < 20) ? 1 : (ruBw / 20);
248 auto numRuAllocsInContentChannel = std::max(1, num20MhzSubchannelsInRu / 2);
249 auto ruIndexOffset = (ruBw < 20) ? (ruSpecs.size() * ruAllocIndex)
250 : (ruAllocIndex / num20MhzSubchannelsInRu);
251 if (!primary80)
252 {
253 ruIndexOffset -= HeRu::GetRusOfType(80, ruType).size();
254 }
255 if (!txVector.IsAllocated(userInfo.staId))
256 {
257 txVector.SetHeMuUserInfo(userInfo.staId,
258 {{ruType, ruSpec.GetIndex() + ruIndexOffset, primary80},
259 userInfo.mcs,
260 userInfo.nss});
261 }
262 if (ruType == HeRu::RU_2x996_TONE)
263 {
264 return;
265 }
266 numRusLeft--;
267 if (numRusLeft == 0)
268 {
269 ruAllocIndex += (2 * numRuAllocsInContentChannel);
270 }
271 }
272 contentChannelIndex++;
273 }
274}
275
276Time
277HePpdu::GetTxDuration() const
278{
279 Time ppduDuration = Seconds(0);
280 const WifiTxVector& txVector = GetTxVector();
281 const auto length = m_lSig.GetLength();
282 const auto tSymbol = NanoSeconds(12800 + txVector.GetGuardInterval());
283 const auto preambleDuration = WifiPhy::CalculatePhyPreambleAndHeaderDuration(txVector);
284 NS_ASSERT(m_operatingChannel.IsSet());
285 uint8_t sigExtension = (m_operatingChannel.GetPhyBand() == WIFI_PHY_BAND_2_4GHZ) ? 6 : 0;
286 uint8_t m = IsDlMu() ? 1 : 2;
287 // Equation 27-11 of IEEE P802.11ax/D4.0
288 const auto calculatedDuration =
289 MicroSeconds(((ceil(static_cast<double>(length + 3 + m) / 3)) * 4) + 20 + sigExtension);
290 NS_ASSERT(calculatedDuration > preambleDuration);
291 uint32_t nSymbols =
292 floor(static_cast<double>((calculatedDuration - preambleDuration).GetNanoSeconds() -
293 (sigExtension * 1000)) /
294 tSymbol.GetNanoSeconds());
295 return (preambleDuration + (nSymbols * tSymbol) + MicroSeconds(sigExtension));
296}
297
299HePpdu::Copy() const
300{
301 return Ptr<WifiPpdu>(new HePpdu(*this), false);
302}
303
305HePpdu::GetType() const
306{
307 switch (m_preamble)
308 {
313 default:
314 return WIFI_PPDU_TYPE_SU;
315 }
316}
317
318bool
319HePpdu::IsMu() const
320{
321 return (IsDlMu() || IsUlMu());
322}
323
324bool
325HePpdu::IsDlMu() const
326{
327 return (m_preamble == WIFI_PREAMBLE_HE_MU);
328}
329
330bool
331HePpdu::IsUlMu() const
332{
333 return (m_preamble == WIFI_PREAMBLE_HE_TB);
334}
335
337HePpdu::GetPsdu(uint8_t bssColor, uint16_t staId /* = SU_STA_ID */) const
338{
339 if (!IsMu())
340 {
341 NS_ASSERT(m_psdus.size() == 1);
342 return m_psdus.at(SU_STA_ID);
343 }
344
345 if (IsUlMu())
346 {
347 auto heSigHeader = std::get_if<HeTbSigHeader>(&m_heSig);
348 NS_ASSERT(heSigHeader);
349 NS_ASSERT(m_psdus.size() == 1);
350 if ((bssColor == 0) || (heSigHeader->m_bssColor == 0) ||
351 (bssColor == heSigHeader->m_bssColor))
352 {
353 return m_psdus.cbegin()->second;
354 }
355 }
356 else
357 {
358 auto heSigHeader = std::get_if<HeMuSigHeader>(&m_heSig);
359 NS_ASSERT(heSigHeader);
360 if ((bssColor == 0) || (heSigHeader->m_bssColor == 0) ||
361 (bssColor == heSigHeader->m_bssColor))
362 {
363 const auto it = m_psdus.find(staId);
364 if (it != m_psdus.cend())
365 {
366 return it->second;
367 }
368 }
369 }
370 return nullptr;
371}
372
373uint16_t
374HePpdu::GetStaId() const
375{
376 NS_ASSERT(IsUlMu());
377 return m_psdus.begin()->first;
378}
379
380uint16_t
381HePpdu::GetTransmissionChannelWidth() const
382{
383 const WifiTxVector& txVector = GetTxVector();
384 if (txVector.IsUlMu() && GetStaId() != SU_STA_ID)
385 {
386 TxPsdFlag flag = GetTxPsdFlag();
387 uint16_t ruWidth = HeRu::GetBandwidth(txVector.GetRu(GetStaId()).GetRuType());
388 uint16_t channelWidth = (flag == PSD_NON_HE_PORTION && ruWidth < 20) ? 20 : ruWidth;
389 NS_LOG_INFO("Use channelWidth=" << channelWidth << " MHz for HE TB from " << GetStaId()
390 << " for " << flag);
391 return channelWidth;
392 }
393 else
394 {
395 return OfdmPpdu::GetTransmissionChannelWidth();
396 }
397}
398
400HePpdu::GetTxPsdFlag() const
401{
402 return m_txPsdFlag;
403}
404
405void
406HePpdu::SetTxPsdFlag(TxPsdFlag flag) const
407{
408 NS_LOG_FUNCTION(this << flag);
409 m_txPsdFlag = flag;
410}
411
412void
413HePpdu::UpdateTxVectorForUlMu(const std::optional<WifiTxVector>& trigVector) const
414{
415 if (trigVector.has_value())
416 {
417 NS_LOG_FUNCTION(this << trigVector.value());
418 }
419 else
420 {
421 NS_LOG_FUNCTION(this);
422 }
423 if (!m_txVector.has_value())
424 {
425 m_txVector = GetTxVector();
426 }
427 NS_ASSERT(GetModulation() >= WIFI_MOD_CLASS_HE);
428 NS_ASSERT(GetType() == WIFI_PPDU_TYPE_UL_MU);
429 // HE TB PPDU reception needs information from the TRIGVECTOR to be able to receive the PPDU
430 const auto staId = GetStaId();
431 if (trigVector.has_value() && trigVector->IsUlMu() &&
432 (trigVector->GetHeMuUserInfoMap().count(staId) > 0))
433 {
434 // These information are not carried in HE-SIG-A for a HE TB PPDU,
435 // but they are carried in the Trigger frame soliciting the HE TB PPDU
436 m_txVector->SetGuardInterval(trigVector->GetGuardInterval());
437 m_txVector->SetHeMuUserInfo(staId, trigVector->GetHeMuUserInfo(staId));
438 }
439 else
440 {
441 // Set dummy user info, PPDU will be dropped later after decoding PHY headers.
442 m_txVector->SetHeMuUserInfo(
443 staId,
444 {{HeRu::GetRuType(m_txVector->GetChannelWidth()), 1, true}, 0, 1});
445 }
446}
447
448std::pair<std::size_t, std::size_t>
449HePpdu::GetNumRusPerHeSigBContentChannel(uint16_t channelWidth, const RuAllocation& ruAllocation)
450{
451 // MU-MIMO is not handled for now, i.e. one station per RU
452 NS_ASSERT_MSG(!ruAllocation.empty(), "RU allocation is not set");
453 NS_ASSERT_MSG(ruAllocation.size() == channelWidth / 20,
454 "RU allocation is not consistent with packet bandwidth");
455
456 std::pair<std::size_t /* number of RUs in content channel 1 */,
457 std::size_t /* number of RUs in content channel 2 */>
458 chSize{0, 0};
459
460 switch (channelWidth)
461 {
462 case 40:
463 chSize.second += HeRu::GetRuSpecs(ruAllocation[1]).size();
464 [[fallthrough]];
465 case 20:
466 chSize.first += HeRu::GetRuSpecs(ruAllocation[0]).size();
467 break;
468 default:
469 for (auto n = 0; n < channelWidth / 20;)
470 {
471 chSize.first += HeRu::GetRuSpecs(ruAllocation[n]).size();
472 if (ruAllocation[n] >= 208)
473 {
474 // 996 tone RU occupies 80 MHz
475 n += 4;
476 continue;
477 }
478 n += 2;
479 }
480 for (auto n = 0; n < channelWidth / 20;)
481 {
482 chSize.second += HeRu::GetRuSpecs(ruAllocation[n + 1]).size();
483 if (ruAllocation[n + 1] >= 208)
484 {
485 // 996 tone RU occupies 80 MHz
486 n += 4;
487 continue;
488 }
489 n += 2;
490 }
491 break;
492 }
493 return chSize;
494}
495
497HePpdu::GetHeSigBContentChannels(const WifiTxVector& txVector, uint8_t p20Index)
498{
499 HeSigBContentChannels contentChannels{{}};
500
501 const auto channelWidth = txVector.GetChannelWidth();
502 if (channelWidth > 20)
503 {
504 contentChannels.emplace_back();
505 }
506
507 const auto& orderedMap = txVector.GetUserInfoMapOrderedByRus(p20Index);
508 for (const auto& [ru, staId] : orderedMap)
509 {
510 auto ruType = ru.GetRuType();
511 auto ruIdx = ru.GetIndex();
512 const auto& userInfo = txVector.GetHeMuUserInfo(staId);
513 NS_ASSERT(ru == userInfo.ru);
514
515 if (ruType > HeRu::RU_242_TONE)
516 {
517 for (auto i = 0; i < ((ruType == HeRu::RU_2x996_TONE) ? 2 : 1); ++i)
518 {
519 contentChannels[0].push_back({staId, userInfo.nss, userInfo.mcs});
520 contentChannels[1].push_back({staId, userInfo.nss, userInfo.mcs});
521 }
522 continue;
523 }
524
525 std::size_t numRus = (ruType >= HeRu::RU_242_TONE)
526 ? 1
527 : HeRu::m_heRuSubcarrierGroups.at({20, ruType}).size();
528 if (((ruIdx - 1) / numRus) % 2 == 0)
529 {
530 contentChannels.at(0).push_back({staId, userInfo.nss, userInfo.mcs});
531 }
532 else
533 {
534 contentChannels.at(1).push_back({staId, userInfo.nss, userInfo.mcs});
535 }
536 }
537
538 // Add unassigned RUs
539 auto numNumRusPerHeSigBContentChannel =
540 GetNumRusPerHeSigBContentChannel(channelWidth, txVector.GetRuAllocation(p20Index));
541 std::size_t contentChannelIndex = 1;
542 for (auto& contentChannel : contentChannels)
543 {
544 const auto totalUsersInContentChannel = (contentChannelIndex == 1)
545 ? numNumRusPerHeSigBContentChannel.first
546 : numNumRusPerHeSigBContentChannel.second;
547 NS_ASSERT(contentChannel.size() <= totalUsersInContentChannel);
548 std::size_t unallocatedRus = totalUsersInContentChannel - contentChannel.size();
549 for (std::size_t i = 0; i < unallocatedRus; i++)
550 {
551 contentChannel.push_back({NO_USER_STA_ID, 0, 0});
552 }
553 contentChannelIndex++;
554 }
555
556 return contentChannels;
557}
558
560HePpdu::GetSigBFieldSize(uint16_t channelWidth, const RuAllocation& ruAllocation)
561{
562 // Compute the number of bits used by common field.
563 // Assume that compression bit in HE-SIG-A is not set (i.e. not
564 // full band MU-MIMO); the field is present.
565 auto commonFieldSize = 4 /* CRC */ + 6 /* tail */;
566 if (channelWidth <= 40)
567 {
568 commonFieldSize += 8; // only one allocation subfield
569 }
570 else
571 {
572 commonFieldSize +=
573 8 * (channelWidth / 40) /* one allocation field per 40 MHz */ + 1 /* center RU */;
574 }
575
576 auto numRusPerContentChannel = GetNumRusPerHeSigBContentChannel(channelWidth, ruAllocation);
577 auto maxNumRusPerContentChannel =
578 std::max(numRusPerContentChannel.first, numRusPerContentChannel.second);
579 auto maxNumUserBlockFields = maxNumRusPerContentChannel /
580 2; // handle last user block with single user, if any, further down
581 std::size_t userSpecificFieldSize =
582 maxNumUserBlockFields * (2 * 21 /* user fields (2 users) */ + 4 /* tail */ + 6 /* CRC */);
583 if (maxNumRusPerContentChannel % 2 != 0)
584 {
585 userSpecificFieldSize += 21 /* last user field */ + 4 /* CRC */ + 6 /* tail */;
586 }
587
588 return commonFieldSize + userSpecificFieldSize;
589}
590
591std::string
592HePpdu::PrintPayload() const
593{
594 std::ostringstream ss;
595 if (IsMu())
596 {
597 ss << m_psdus;
598 ss << ", " << m_txPsdFlag;
599 }
600 else
601 {
602 ss << "PSDU=" << m_psdus.at(SU_STA_ID) << " ";
603 }
604 return ss.str();
605}
606
607uint8_t
608HePpdu::GetChannelWidthEncodingFromMhz(uint16_t channelWidth)
609{
610 if (channelWidth == 160)
611 {
612 return 3;
613 }
614 else if (channelWidth == 80)
615 {
616 return 2;
617 }
618 else if (channelWidth == 40)
619 {
620 return 1;
621 }
622 else
623 {
624 return 0;
625 }
626}
627
628uint16_t
629HePpdu::GetChannelWidthMhzFromEncoding(uint8_t bandwidth)
630{
631 if (bandwidth == 3)
632 {
633 return 160;
634 }
635 else if (bandwidth == 2)
636 {
637 return 80;
638 }
639 else if (bandwidth == 1)
640 {
641 return 40;
642 }
643 else
644 {
645 return 20;
646 }
647}
648
649uint8_t
650HePpdu::GetGuardIntervalAndNltfEncoding(uint16_t gi, uint8_t nltf)
651{
652 if (gi == 800 && nltf == 1)
653 {
654 return 0;
655 }
656 else if (gi == 800 && nltf == 2)
657 {
658 return 1;
659 }
660 else if (gi == 1600 && nltf == 2)
661 {
662 return 2;
663 }
664 else
665 {
666 return 3;
667 }
668}
669
670uint16_t
671HePpdu::GetGuardIntervalFromEncoding(uint8_t giAndNltfSize)
672{
673 if (giAndNltfSize == 3)
674 {
675 // we currently do not consider DCM nor STBC fields
676 return 3200;
677 }
678 else if (giAndNltfSize == 2)
679 {
680 return 1600;
681 }
682 else
683 {
684 return 800;
685 }
686}
687
688uint8_t
689HePpdu::GetNstsEncodingFromNss(uint8_t nss)
690{
691 NS_ASSERT(nss <= 8);
692 return nss - 1;
693}
694
695uint8_t
696HePpdu::GetNssFromNstsEncoding(uint8_t nsts)
697{
698 return nsts + 1;
699}
700
701} // namespace ns3
static WifiMode GetHeMcs(uint8_t index)
Return the HE MCS corresponding to the provided index.
Definition: he-phy.cc:1562
HE PPDU (11ax)
Definition: he-ppdu.h:50
std::vector< std::vector< HeSigBUserSpecificField > > HeSigBContentChannels
HE SIG-B Content Channels.
Definition: he-ppdu.h:61
HeSigHeader m_heSig
the HE-SIG PHY header
Definition: he-ppdu.h:336
WifiTxVector DoGetTxVector() const override
Get the TXVECTOR used to send the PPDU.
Definition: he-ppdu.cc:160
virtual void SetTxVectorFromPhyHeaders(WifiTxVector &txVector) const
Fill in the TXVECTOR from PHY headers.
Definition: he-ppdu.cc:169
static uint16_t GetGuardIntervalFromEncoding(uint8_t giAndNltfSize)
Convert guard interval (in ns) from its encoding in HE-SIG-A.
Definition: he-ppdu.cc:671
static uint16_t GetChannelWidthMhzFromEncoding(uint8_t bandwidth)
Convert channel width expressed in MHz from bandwidth field encoding in HE-SIG-A.
Definition: he-ppdu.cc:629
TxPsdFlag
The transmit power spectral density flag, namely used to correctly build PSDs for pre-HE and HE porti...
Definition: he-ppdu.h:113
@ PSD_HE_PORTION
HE portion of an HE PPDU.
Definition: he-ppdu.h:115
@ PSD_NON_HE_PORTION
Non-HE portion of an HE PPDU.
Definition: he-ppdu.h:114
virtual bool IsDlMu() const
Return true if the PPDU is a DL MU PPDU.
Definition: he-ppdu.cc:325
virtual bool IsUlMu() const
Return true if the PPDU is an UL MU PPDU.
Definition: he-ppdu.cc:331
void SetHeMuUserInfos(WifiTxVector &txVector, const RuAllocation &ruAllocation, const HeSigBContentChannels &contentChannels) const
Reconstruct HeMuUserInfoMap from HE-SIG-B header.
Definition: he-ppdu.cc:209
static uint8_t GetNstsEncodingFromNss(uint8_t nss)
Convert number of spatial streams to NSTS field encoding in HE-SIG-A.
Definition: he-ppdu.cc:689
void SetHeSigHeader(const WifiTxVector &txVector)
Fill in the HE-SIG header.
Definition: he-ppdu.cc:119
static uint8_t GetNssFromNstsEncoding(uint8_t nsts)
Convert number of spatial streams from NSTS field encoding in HE-SIG-A.
Definition: he-ppdu.cc:696
void SetPhyHeaders(const WifiTxVector &txVector, Time ppduDuration)
Fill in the PHY headers.
Definition: he-ppdu.cc:92
static HeSigBContentChannels GetHeSigBContentChannels(const WifiTxVector &txVector, uint8_t p20Index)
Get the HE SIG-B content channels for a given PPDU IEEE 802.11ax-2021 27.3.11.8.2 HE-SIG-B content ch...
Definition: he-ppdu.cc:497
virtual bool IsMu() const
Return true if the PPDU is a MU PPDU.
Definition: he-ppdu.cc:319
static uint8_t GetGuardIntervalAndNltfEncoding(uint16_t gi, uint8_t nltf)
Convert guard interval (in ns) and NLTF to its encoding in HE-SIG-A.
Definition: he-ppdu.cc:650
void SetLSigHeader(Time ppduDuration)
Fill in the L-SIG header.
Definition: he-ppdu.cc:100
HePpdu(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector, const WifiPhyOperatingChannel &channel, Time ppduDuration, uint64_t uid)
Create an SU HE PPDU, storing a PSDU.
Definition: he-ppdu.cc:74
static uint8_t GetChannelWidthEncodingFromMhz(uint16_t channelWidth)
Convert channel width expressed in MHz to bandwidth field encoding in HE-SIG-A.
Definition: he-ppdu.cc:608
static std::vector< RuSpec > GetRuSpecs(uint8_t ruAllocation)
Get the RU specs based on RU_ALLOCATION.
Definition: he-ru.cc:392
static uint16_t GetBandwidth(RuType ruType)
Get the approximate bandwidth occupied by a RU.
Definition: he-ru.cc:762
static std::vector< HeRu::RuSpec > GetRusOfType(uint16_t bw, HeRu::RuType ruType)
Get the set of distinct RUs of the given type (number of tones) available in a HE PPDU of the given b...
Definition: he-ru.cc:510
@ RU_996_TONE
Definition: he-ru.h:47
@ RU_2x996_TONE
Definition: he-ru.h:48
uint16_t GetLength() const
Return the LENGTH field of L-SIG (in bytes).
Definition: ofdm-ppdu.cc:210
void SetLength(uint16_t length)
Fill the LENGTH field of L-SIG (in bytes).
Definition: ofdm-ppdu.cc:203
OFDM PPDU (11a)
Definition: ofdm-ppdu.h:47
LSigHeader m_lSig
the L-SIG PHY header
Definition: ofdm-ppdu.h:110
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
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
static WifiMode GetVhtMcs(uint8_t index)
Return the VHT MCS corresponding to the provided index.
Definition: vht-phy.cc:342
uint8_t GetMcsValue() const
Definition: wifi-mode.cc:163
Class that keeps track of all information about the current PHY operating channel.
bool IsSet() const
Return true if a valid channel has been set, false otherwise.
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...
WifiPhyBand GetPhyBand() const
Return the PHY band of the operating channel.
const WifiPhyOperatingChannel & m_operatingChannel
the operating channel of the PHY
Definition: wifi-ppdu.h:210
WifiPreamble m_preamble
the PHY preamble
Definition: wifi-ppdu.h:202
WifiConstPsduMap m_psdus
the PSDUs contained in this PPDU
Definition: wifi-ppdu.h:204
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetCenter26ToneRuIndication(Center26ToneRuIndication center26ToneRuIndication)
Set CENTER_26_TONE_RU field.
void SetRuAllocation(const RuAllocation &ruAlloc, uint8_t p20Index)
Set RU_ALLOCATION field.
UserInfoMapOrderedByRus GetUserInfoMapOrderedByRus(uint8_t p20Index) const
Get the map of specific user info parameters ordered per increasing frequency RUs.
uint16_t GetGuardInterval() const
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
uint8_t GetBssColor() const
Get the BSS color.
const RuAllocation & GetRuAllocation(uint8_t p20Index) const
Get RU_ALLOCATION field.
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
std::optional< Center26ToneRuIndication > GetCenter26ToneRuIndication() const
Get CENTER_26_TONE_RU field This field is present if format is HE_MU and when channel width is set to...
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.
RuAllocation m_ruAllocation
RU allocations that are going to be carried in SIG-B common field per Table 27-1 IEEE.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
HeMuUserInfo GetHeMuUserInfo(uint16_t staId) const
Get the HE MU user-specific transmission information for the given STA-ID.
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
HeRu::RuSpec GetRu(uint16_t staId) const
Get the RU specification for the STA-ID.
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.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
bool IsUlMu() const
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
void SetBssColor(uint8_t color)
Set the BSS color.
bool IsAllocated(uint16_t staId) const
Check if STA ID is allocated.
uint16_t GetChannelWidth() const
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
WifiMode GetSigBMode() const
Get MCS used for SIG-B.
void SetNss(uint8_t nss)
Sets the number of Nss.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#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_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#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
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
WifiPpduType
The type of PPDU (SU, DL MU, or UL MU)
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_HE_MU
@ 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)
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
Declaration of ns3::HePpdu class.
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.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:129
bool IsMu(WifiPreamble preamble)
Return true if a preamble corresponds to a multi-user transmission.
static constexpr uint16_t NO_USER_STA_ID
STA_ID for a RU that is intended for no user (Section 26.11.1 802.11ax-2021)
std::vector< uint8_t > RuAllocation
8 bit RU_ALLOCATION per 20 MHz
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.
Definition: second.py:1
HE-SIG PHY header for HE MU PPDUs (HE-SIG-A1/A2/B)
Definition: he-ppdu.h:90
uint8_t m_bssColor
BSS color field.
Definition: he-ppdu.h:92
HE-SIG PHY header for HE SU PPDUs (HE-SIG-A1/A2)
Definition: he-ppdu.h:67
uint8_t m_bssColor
BSS color field.
Definition: he-ppdu.h:69
HE-SIG PHY header for HE TB PPDUs (HE-SIG-A1/A2)
Definition: he-ppdu.h:80
uint8_t m_bssColor
BSS color field.
Definition: he-ppdu.h:82