A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
eht-ppdu.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2021 DERONNE SOFTWARE ENGINEERING
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
7 */
8
9#include "eht-ppdu.h"
10
11#include "eht-phy.h"
12
13#include "ns3/log.h"
14#include "ns3/wifi-phy-operating-channel.h"
15#include "ns3/wifi-psdu.h"
16
17#include <algorithm>
18#include <numeric>
19
20namespace ns3
21{
22
24
26 const WifiTxVector& txVector,
27 const WifiPhyOperatingChannel& channel,
28 Time ppduDuration,
29 uint64_t uid,
30 TxPsdFlag flag)
31 : HePpdu(psdus, txVector, channel, ppduDuration, uid, flag)
32{
33 NS_LOG_FUNCTION(this << psdus << txVector << channel << ppduDuration << uid << flag);
34 SetPhyHeaders(txVector, ppduDuration);
35}
36
37void
38EhtPpdu::SetPhyHeaders(const WifiTxVector& txVector, Time ppduDuration)
39{
40 NS_LOG_FUNCTION(this << txVector << ppduDuration);
41 SetEhtPhyHeader(txVector);
42}
43
44void
46{
47 const auto bssColor = txVector.GetBssColor();
48 NS_ASSERT(bssColor < 64);
50 {
51 const auto p20Index = m_operatingChannel.GetPrimaryChannelIndex(MHz_u{20});
54 .m_bssColor = bssColor,
55 .m_ppduType = txVector.GetEhtPpduType(),
56 // TODO: EHT PPDU should store U-SIG per 20 MHz band, assume it is the lowest 20 MHz
57 // band for now
58 .m_puncturedChannelInfo =
60 txVector.GetEhtPpduType(),
61 (txVector.IsDlMu() && (txVector.GetChannelWidth() > MHz_u{80}))
62 ? std::optional{true}
63 : std::nullopt),
64 .m_ehtSigMcs = txVector.GetSigBMode().GetMcsValue(),
65 .m_giLtfSize = GetGuardIntervalAndNltfEncoding(txVector.GetGuardInterval(),
66 2 /*NLTF currently unused*/),
67 /* See section 36.3.12.8.2 of IEEE 802.11be D3.0 (EHT-SIG content channels):
68 * In non-OFDMA transmission, the Common field of the EHT-SIG content channel does not
69 * contain the RU Allocation subfield. For non-OFDMA transmission except for EHT
70 * sounding NDP, the Common field of the EHT-SIG content channel is encoded together
71 * with the first User field and this encoding block contains a CRC and Tail, referred
72 * to as a common encoding block. */
73 .m_ruAllocationA =
74 txVector.IsMu() ? std::optional{txVector.GetRuAllocation(p20Index)} : std::nullopt,
75 // TODO: RU Allocation-B not supported yet
76 .m_contentChannels = GetEhtSigContentChannels(txVector, p20Index)});
77 }
78 else if (ns3::IsUlMu(m_preamble))
79 {
82 .m_bssColor = bssColor,
83 .m_ppduType = txVector.GetEhtPpduType()});
84 }
85}
86
89{
90 if (m_psdus.contains(SU_STA_ID))
91 {
92 return WIFI_PPDU_TYPE_SU;
93 }
94 switch (m_preamble)
95 {
100 default:
101 NS_ASSERT_MSG(false, "invalid preamble " << m_preamble);
102 return WIFI_PPDU_TYPE_SU;
103 }
104}
105
106bool
108{
109 return (m_preamble == WIFI_PREAMBLE_EHT_MU) && !m_psdus.contains(SU_STA_ID);
110}
111
112bool
114{
115 return (m_preamble == WIFI_PREAMBLE_EHT_TB) && !m_psdus.contains(SU_STA_ID);
116}
117
118void
120{
121 txVector.SetLength(m_lSig.GetLength());
122 txVector.SetAggregation(m_psdus.size() > 1 || m_psdus.begin()->second->IsAggregate());
124 {
125 auto ehtPhyHeader = std::get_if<EhtMuPhyHeader>(&m_ehtPhyHeader);
126 NS_ASSERT(ehtPhyHeader);
127 const auto bw = GetChannelWidthMhzFromEncoding(ehtPhyHeader->m_bandwidth);
128 txVector.SetChannelWidth(bw);
129 txVector.SetBssColor(ehtPhyHeader->m_bssColor);
130 txVector.SetEhtPpduType(ehtPhyHeader->m_ppduType);
131 if (bw > MHz_u{80})
132 {
133 // TODO: use punctured channel information
134 }
135 txVector.SetSigBMode(HePhy::GetVhtMcs(ehtPhyHeader->m_ehtSigMcs));
136 txVector.SetGuardInterval(GetGuardIntervalFromEncoding(ehtPhyHeader->m_giLtfSize));
137 const auto ruAllocation = ehtPhyHeader->m_ruAllocationA; // RU Allocation-B not supported
138 // yet
139 if (const auto p20Index = m_operatingChannel.GetPrimaryChannelIndex(MHz_u{20});
140 ruAllocation.has_value())
141 {
142 txVector.SetRuAllocation(ruAllocation.value(), p20Index);
143 const auto isMuMimo = (ehtPhyHeader->m_ppduType == 2);
144 const auto muMimoUsers =
145 isMuMimo
146 ? std::accumulate(ehtPhyHeader->m_contentChannels.cbegin(),
147 ehtPhyHeader->m_contentChannels.cend(),
148 0,
149 [](uint8_t prev, const auto& cc) { return prev + cc.size(); })
150 : 0;
151 SetHeMuUserInfos(txVector,
152 ruAllocation.value(),
153 ehtPhyHeader->m_contentChannels,
154 ehtPhyHeader->m_ppduType == 2,
155 muMimoUsers);
156 }
157 if (ehtPhyHeader->m_ppduType == 1) // EHT SU
158 {
159 NS_ASSERT(ehtPhyHeader->m_contentChannels.size() == 1 &&
160 ehtPhyHeader->m_contentChannels.front().size() == 1);
161 txVector.SetMode(
162 EhtPhy::GetEhtMcs(ehtPhyHeader->m_contentChannels.front().front().mcs));
163 txVector.SetNss(ehtPhyHeader->m_contentChannels.front().front().nss);
164 }
165 }
166 else if (ns3::IsUlMu(m_preamble))
167 {
168 auto ehtPhyHeader = std::get_if<EhtTbPhyHeader>(&m_ehtPhyHeader);
169 NS_ASSERT(ehtPhyHeader);
170 txVector.SetChannelWidth(GetChannelWidthMhzFromEncoding(ehtPhyHeader->m_bandwidth));
171 txVector.SetBssColor(ehtPhyHeader->m_bssColor);
172 txVector.SetEhtPpduType(ehtPhyHeader->m_ppduType);
173 }
174}
175
176std::pair<std::size_t, std::size_t>
178 uint8_t ehtPpduType,
179 const RuAllocation& ruAllocation,
180 bool compression,
181 std::size_t numMuMimoUsers)
182{
183 if (ehtPpduType == 1)
184 {
185 return {1, 0};
186 }
188 ruAllocation,
189 compression,
190 numMuMimoUsers);
191}
192
194EhtPpdu::GetEhtSigContentChannels(const WifiTxVector& txVector, uint8_t p20Index)
195{
196 if (txVector.GetEhtPpduType() == 1)
197 {
198 // according to spec the TXVECTOR shall have a correct STA-ID even for SU transmission,
199 // but this is not set by the MAC for simplification, so set to 0 for now.
200 return HeSigBContentChannels{{{0, txVector.GetNss(), txVector.GetMode().GetMcsValue()}}};
201 }
202 return HePpdu::GetHeSigBContentChannels(txVector, p20Index);
203}
204
207 const RuAllocation& ruAllocation,
208 uint8_t ehtPpduType,
209 bool compression,
210 std::size_t numMuMimoUsers)
211{
212 // FIXME: EHT-SIG is not implemented yet, hence this is a copy of HE-SIG-B
213 uint32_t commonFieldSize = 0;
214 if (!compression)
215 {
216 commonFieldSize = 4 /* CRC */ + 6 /* tail */;
217 if (channelWidth <= MHz_u{40})
218 {
219 commonFieldSize += 8; // only one allocation subfield
220 }
221 else
222 {
223 commonFieldSize +=
224 8 * (channelWidth / MHz_u{40}) /* one allocation field per 40 MHz */ +
225 1 /* center RU */;
226 }
227 }
228
229 auto numRusPerContentChannel = GetNumRusPerEhtSigBContentChannel(channelWidth,
230 ehtPpduType,
231 ruAllocation,
232 compression,
233 numMuMimoUsers);
234 auto maxNumRusPerContentChannel =
235 std::max(numRusPerContentChannel.first, numRusPerContentChannel.second);
236 auto maxNumUserBlockFields = maxNumRusPerContentChannel /
237 2; // handle last user block with single user, if any, further down
238 std::size_t userSpecificFieldSize =
239 maxNumUserBlockFields * (2 * 21 /* user fields (2 users) */ + 4 /* tail */ + 6 /* CRC */);
240 if (maxNumRusPerContentChannel % 2 != 0)
241 {
242 userSpecificFieldSize += 21 /* last user field */ + 4 /* CRC */ + 6 /* tail */;
243 }
244
245 return commonFieldSize + userSpecificFieldSize;
246}
247
248uint8_t
249EhtPpdu::GetPuncturedInfo(const std::vector<bool>& inactiveSubchannels,
250 uint8_t ehtPpduType,
251 std::optional<bool> isLow80MHz)
252{
253 if (inactiveSubchannels.size() < 4)
254 {
255 // no puncturing if less than 80 MHz
256 return 0;
257 }
258 NS_ASSERT_MSG(inactiveSubchannels.size() <= 8,
259 "Puncturing over more than 160 MHz is not supported");
260 if (ehtPpduType == 0)
261 {
262 // IEEE 802.11be D5.0 Table 36-28
263 NS_ASSERT(inactiveSubchannels.size() <= 4 || isLow80MHz.has_value());
264 const auto startIndex = (inactiveSubchannels.size() <= 4) ? 0 : (*isLow80MHz ? 0 : 4);
265 const auto stopIndex =
266 (inactiveSubchannels.size() <= 4) ? inactiveSubchannels.size() : (*isLow80MHz ? 4 : 8);
267 uint8_t puncturedInfoField = 0;
268 for (std::size_t i = startIndex; i < stopIndex; ++i)
269 {
270 if (!inactiveSubchannels.at(i))
271 {
272 puncturedInfoField |= 1 << (i / 4);
273 }
274 }
275 return puncturedInfoField;
276 }
277 // IEEE 802.11be D5.0 Table 36-30
278 const auto numPunctured = std::count_if(inactiveSubchannels.cbegin(),
279 inactiveSubchannels.cend(),
280 [](bool punctured) { return punctured; });
281 if (numPunctured == 0)
282 {
283 // no puncturing
284 return 0;
285 }
286 const auto firstPunctured = std::find_if(inactiveSubchannels.cbegin(),
287 inactiveSubchannels.cend(),
288 [](bool punctured) { return punctured; });
289 const auto firstIndex = std::distance(inactiveSubchannels.cbegin(), firstPunctured);
290 switch (numPunctured)
291 {
292 case 1:
293 return firstIndex + 1;
294 case 2:
295 NS_ASSERT_MSG(((firstIndex % 2) == 0) && inactiveSubchannels.at(firstIndex + 1),
296 "invalid 40 MHz puncturing pattern");
297 return 9 + (firstIndex / 2);
298 default:
299 break;
300 }
301 NS_ASSERT_MSG(false, "invalid puncturing pattern");
302 return 0;
303}
304
307{
308 return Ptr<WifiPpdu>(new EhtPpdu(*this), false);
309}
310
311} // namespace ns3
static WifiMode GetEhtMcs(uint8_t index)
Return the EHT MCS corresponding to the provided index.
Definition eht-phy.cc:232
static uint32_t GetEhtSigFieldSize(MHz_u channelWidth, const RuAllocation &ruAllocation, uint8_t ehtPpduType, bool compression, std::size_t numMuMimoUsers)
Get variable length EHT-SIG field size.
Definition eht-ppdu.cc:206
static HeSigBContentChannels GetEhtSigContentChannels(const WifiTxVector &txVector, uint8_t p20Index)
Get the EHT-SIG content channels for a given PPDU IEEE 802.11be-D3.1 36.3.12.8.2 EHT-SIG content chan...
Definition eht-ppdu.cc:194
bool IsDlMu() const override
Return true if the PPDU is a DL MU PPDU.
Definition eht-ppdu.cc:107
bool IsUlMu() const override
Return true if the PPDU is an UL MU PPDU.
Definition eht-ppdu.cc:113
void SetEhtPhyHeader(const WifiTxVector &txVector)
Fill in the EHT PHY header.
Definition eht-ppdu.cc:45
static std::pair< std::size_t, std::size_t > GetNumRusPerEhtSigBContentChannel(MHz_u channelWidth, uint8_t ehtPpduType, const RuAllocation &ruAllocation, bool compression, std::size_t numMuMimoUsers)
Get the number of RUs per EHT-SIG-B content channel.
Definition eht-ppdu.cc:177
Ptr< WifiPpdu > Copy() const override
Copy this instance.
Definition eht-ppdu.cc:306
void SetTxVectorFromPhyHeaders(WifiTxVector &txVector) const override
Fill in the TXVECTOR from PHY headers.
Definition eht-ppdu.cc:119
void SetPhyHeaders(const WifiTxVector &txVector, Time ppduDuration)
Fill in the PHY headers.
Definition eht-ppdu.cc:38
WifiPpduType GetType() const override
Return the PPDU type (.
Definition eht-ppdu.cc:88
static uint8_t GetPuncturedInfo(const std::vector< bool > &inactiveSubchannels, uint8_t ehtPpduType, std::optional< bool > isLow80MHz)
Get the Punctured Channel Information field in the U-SIG.
Definition eht-ppdu.cc:249
EhtPhyHeader m_ehtPhyHeader
the EHT PHY header
Definition eht-ppdu.h:173
EhtPpdu(const WifiConstPsduMap &psdus, const WifiTxVector &txVector, const WifiPhyOperatingChannel &channel, Time ppduDuration, uint64_t uid, TxPsdFlag flag)
Create an EHT PPDU, storing a map of PSDUs.
Definition eht-ppdu.cc:25
HE PPDU (11ax)
Definition he-ppdu.h:39
TxPsdFlag
The transmit power spectral density flag, namely used to correctly build PSDs for pre-HE and HE porti...
Definition he-ppdu.h:104
static Time GetGuardIntervalFromEncoding(uint8_t giAndNltfSize)
Convert guard interval from its encoding in HE-SIG-A.
Definition he-ppdu.cc:750
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:544
void SetHeMuUserInfos(WifiTxVector &txVector, const RuAllocation &ruAllocation, const HeSigBContentChannels &contentChannels, bool sigBCompression, uint8_t numMuMimoUsers) const
Reconstruct HeMuUserInfoMap from HE-SIG-B header.
Definition he-ppdu.cc:214
std::vector< std::vector< HeSigBUserSpecificField > > HeSigBContentChannels
HE SIG-B Content Channels.
Definition he-ppdu.h:50
static std::pair< std::size_t, std::size_t > GetNumRusPerHeSigBContentChannel(MHz_u channelWidth, const RuAllocation &ruAllocation, bool sigBCompression, uint8_t numMuMimoUsers)
Get the number of STAs per HE-SIG-B content channel.
Definition he-ppdu.cc:476
static MHz_u GetChannelWidthMhzFromEncoding(uint8_t bandwidth)
Convert channel width expressed in MHz from bandwidth field encoding in HE-SIG-A.
Definition he-ppdu.cc:707
static uint8_t GetChannelWidthEncodingFromMhz(MHz_u channelWidth)
Convert channel width expressed in MHz to bandwidth field encoding in HE-SIG-A.
Definition he-ppdu.cc:686
static uint8_t GetGuardIntervalAndNltfEncoding(Time guardInterval, uint8_t nltf)
Convert guard interval and NLTF to its encoding in HE-SIG-A.
Definition he-ppdu.cc:728
uint16_t GetLength() const
Return the LENGTH field of L-SIG (in bytes).
Definition ofdm-ppdu.cc:199
LSigHeader m_lSig
the L-SIG PHY header
Definition ofdm-ppdu.h:99
Smart pointer class similar to boost::intrusive_ptr.
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
static WifiMode GetVhtMcs(uint8_t index)
Return the VHT MCS corresponding to the provided index.
Definition vht-phy.cc:334
uint8_t GetMcsValue() const
Definition wifi-mode.cc:152
Class that keeps track of all information about the current PHY operating channel.
uint8_t GetPrimaryChannelIndex(MHz_u primaryChannelWidth) const
If the operating channel width is a multiple of 20 MHz, return the index of the primary channel of th...
const WifiPhyOperatingChannel & m_operatingChannel
the operating channel of the PHY
Definition wifi-ppdu.h:201
WifiPreamble m_preamble
the PHY preamble
Definition wifi-ppdu.h:192
WifiConstPsduMap m_psdus
the PSDUs contained in this PPDU
Definition wifi-ppdu.h:194
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetRuAllocation(const RuAllocation &ruAlloc, uint8_t p20Index)
Set RU_ALLOCATION field.
void SetEhtPpduType(uint8_t type)
Set the EHT_PPDU_TYPE parameter.
uint8_t GetBssColor() const
Get the BSS color.
const RuAllocation & GetRuAllocation(uint8_t p20Index) const
Get RU_ALLOCATION field.
void SetGuardInterval(Time guardInterval)
Sets the guard interval duration (in nanoseconds)
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.
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
uint8_t GetEhtPpduType() const
Get the EHT_PPDU_TYPE parameter.
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.
MHz_u GetChannelWidth() const
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
void SetBssColor(uint8_t color)
Set the BSS color.
Time GetGuardInterval() 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.
const std::vector< bool > & GetInactiveSubchannels() const
Get the 20 MHz subchannels that are punctured.
Declaration of ns3::EhtPhy class.
Declaration of ns3::EhtPpdu class.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
WifiPpduType
The type of PPDU (SU, DL MU, or UL MU)
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_PPDU_TYPE_DL_MU
@ WIFI_PPDU_TYPE_UL_MU
@ WIFI_PPDU_TYPE_SU
Every class exported by the ns3 library is enclosed in the ns3 namespace.
bool IsDlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a downlink multi-user transmission.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition wifi-mode.h:24
bool IsUlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a uplink multi-user transmission.
std::vector< uint16_t > RuAllocation
9 bits RU_ALLOCATION per 20 MHz
PHY header for EHT MU PPDUs.
Definition eht-ppdu.h:50
uint8_t m_bandwidth
Bandwidth field.
Definition eht-ppdu.h:53
PHY header for EHT TB PPDUs.
Definition eht-ppdu.h:38
uint8_t m_bandwidth
Bandwidth field.
Definition eht-ppdu.h:41
uint32_t prev