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 = txVector.IsMu() && !txVector.IsSigBCompression()
74 ? std::optional{txVector.GetRuAllocation(p20Index)}
75 : std::nullopt,
76 // TODO: RU Allocation-B not supported yet
77 .m_contentChannels = GetEhtSigContentChannels(txVector, p20Index)});
78 }
79 else if (ns3::IsUlMu(m_preamble))
80 {
83 .m_bssColor = bssColor,
84 .m_ppduType = txVector.GetEhtPpduType()});
85 }
86}
87
90{
91 if (m_psdus.contains(SU_STA_ID))
92 {
93 return WIFI_PPDU_TYPE_SU;
94 }
95 switch (m_preamble)
96 {
101 default:
102 NS_ASSERT_MSG(false, "invalid preamble " << m_preamble);
103 return WIFI_PPDU_TYPE_SU;
104 }
105}
106
107bool
109{
110 return (m_preamble == WIFI_PREAMBLE_EHT_MU) && !m_psdus.contains(SU_STA_ID);
111}
112
113bool
115{
116 return (m_preamble == WIFI_PREAMBLE_EHT_TB) && !m_psdus.contains(SU_STA_ID);
117}
118
119void
121{
122 txVector.SetLength(m_lSig.GetLength());
123 txVector.SetAggregation(m_psdus.size() > 1 || m_psdus.begin()->second->IsAggregate());
125 {
126 auto ehtPhyHeader = std::get_if<EhtMuPhyHeader>(&m_ehtPhyHeader);
127 NS_ASSERT(ehtPhyHeader);
128 const auto bw = GetChannelWidthMhzFromEncoding(ehtPhyHeader->m_bandwidth);
129 txVector.SetChannelWidth(bw);
130 txVector.SetBssColor(ehtPhyHeader->m_bssColor);
131 txVector.SetEhtPpduType(ehtPhyHeader->m_ppduType);
132 if (bw > MHz_u{80})
133 {
134 // TODO: use punctured channel information
135 }
136 txVector.SetSigBMode(HePhy::GetVhtMcs(ehtPhyHeader->m_ehtSigMcs));
137 txVector.SetGuardInterval(GetGuardIntervalFromEncoding(ehtPhyHeader->m_giLtfSize));
138 const auto ruAllocation = ehtPhyHeader->m_ruAllocationA; // RU Allocation-B not supported
139 // yet
140 if (const auto p20Index = m_operatingChannel.GetPrimaryChannelIndex(MHz_u{20});
141 ruAllocation.has_value())
142 {
143 txVector.SetRuAllocation(ruAllocation.value(), p20Index);
144 const auto isMuMimo = (ehtPhyHeader->m_ppduType == 2);
145 const auto muMimoUsers =
146 isMuMimo
147 ? std::accumulate(ehtPhyHeader->m_contentChannels.cbegin(),
148 ehtPhyHeader->m_contentChannels.cend(),
149 0,
150 [](uint8_t prev, const auto& cc) { return prev + cc.size(); })
151 : 0;
152 SetHeMuUserInfos(txVector,
153 ruAllocation.value(),
154 std::nullopt,
155 ehtPhyHeader->m_contentChannels,
156 ehtPhyHeader->m_ppduType == 2,
157 muMimoUsers);
158 }
159 else if (ehtPhyHeader->m_ppduType == 1) // EHT SU
160 {
161 NS_ASSERT(ehtPhyHeader->m_contentChannels.size() == 1 &&
162 ehtPhyHeader->m_contentChannels.front().size() == 1);
163 txVector.SetMode(
164 EhtPhy::GetEhtMcs(ehtPhyHeader->m_contentChannels.front().front().mcs));
165 txVector.SetNss(ehtPhyHeader->m_contentChannels.front().front().nss);
166 }
167 else
168 {
169 const auto fullBwRu{HeRu::RuSpec(WifiRu::GetRuType(bw), 1, true)};
170 txVector.SetHeMuUserInfo(ehtPhyHeader->m_contentChannels.front().front().staId,
171 {fullBwRu,
172 ehtPhyHeader->m_contentChannels.front().front().mcs,
173 ehtPhyHeader->m_contentChannels.front().front().nss});
174 }
175 }
176 else if (ns3::IsUlMu(m_preamble))
177 {
178 auto ehtPhyHeader = std::get_if<EhtTbPhyHeader>(&m_ehtPhyHeader);
179 NS_ASSERT(ehtPhyHeader);
180 txVector.SetChannelWidth(GetChannelWidthMhzFromEncoding(ehtPhyHeader->m_bandwidth));
181 txVector.SetBssColor(ehtPhyHeader->m_bssColor);
182 txVector.SetEhtPpduType(ehtPhyHeader->m_ppduType);
183 }
184}
185
186std::pair<std::size_t, std::size_t>
188 uint8_t ehtPpduType,
189 const RuAllocation& ruAllocation,
190 bool compression,
191 std::size_t numMuMimoUsers)
192{
193 if (ehtPpduType == 1)
194 {
195 return {1, 0};
196 }
198 ruAllocation,
199 std::nullopt,
200 compression,
201 numMuMimoUsers);
202}
203
205EhtPpdu::GetEhtSigContentChannels(const WifiTxVector& txVector, uint8_t p20Index)
206{
207 if (txVector.GetEhtPpduType() == 1)
208 {
209 // according to spec the TXVECTOR shall have a correct STA-ID even for SU transmission,
210 // but this is not set by the MAC for simplification, so set to 0 for now.
211 return HeSigBContentChannels{{{0, txVector.GetNss(), txVector.GetMode().GetMcsValue()}}};
212 }
213 return HePpdu::GetHeSigBContentChannels(txVector, p20Index);
214}
215
218 const RuAllocation& ruAllocation,
219 uint8_t ehtPpduType,
220 bool compression,
221 std::size_t numMuMimoUsers)
222{
223 // FIXME: EHT-SIG is not implemented yet, hence this is a copy of HE-SIG-B
224 uint32_t commonFieldSize = 0;
225 if (!compression)
226 {
227 commonFieldSize = 4 /* CRC */ + 6 /* tail */;
228 if (channelWidth <= MHz_u{40})
229 {
230 commonFieldSize += 8; // only one allocation subfield
231 }
232 else
233 {
234 commonFieldSize +=
235 8 * (channelWidth / MHz_u{40}) /* one allocation field per 40 MHz */ +
236 1 /* center RU */;
237 }
238 }
239
240 auto numRusPerContentChannel = GetNumRusPerEhtSigBContentChannel(channelWidth,
241 ehtPpduType,
242 ruAllocation,
243 compression,
244 numMuMimoUsers);
245 auto maxNumRusPerContentChannel =
246 std::max(numRusPerContentChannel.first, numRusPerContentChannel.second);
247 auto maxNumUserBlockFields = maxNumRusPerContentChannel /
248 2; // handle last user block with single user, if any, further down
249 std::size_t userSpecificFieldSize =
250 maxNumUserBlockFields * (2 * 21 /* user fields (2 users) */ + 4 /* tail */ + 6 /* CRC */);
251 if (maxNumRusPerContentChannel % 2 != 0)
252 {
253 userSpecificFieldSize += 21 /* last user field */ + 4 /* CRC */ + 6 /* tail */;
254 }
255
256 return commonFieldSize + userSpecificFieldSize;
257}
258
259uint8_t
260EhtPpdu::GetPuncturedInfo(const std::vector<bool>& inactiveSubchannels,
261 uint8_t ehtPpduType,
262 std::optional<bool> isLow80MHz)
263{
264 if (inactiveSubchannels.size() < 4)
265 {
266 // no puncturing if less than 80 MHz
267 return 0;
268 }
269 NS_ASSERT_MSG(inactiveSubchannels.size() <= 8,
270 "Puncturing over more than 160 MHz is not supported");
271 if (ehtPpduType == 0)
272 {
273 // IEEE 802.11be D5.0 Table 36-28
274 NS_ASSERT(inactiveSubchannels.size() <= 4 || isLow80MHz.has_value());
275 const auto startIndex = (inactiveSubchannels.size() <= 4) ? 0 : (*isLow80MHz ? 0 : 4);
276 const auto stopIndex =
277 (inactiveSubchannels.size() <= 4) ? inactiveSubchannels.size() : (*isLow80MHz ? 4 : 8);
278 uint8_t puncturedInfoField = 0;
279 for (std::size_t i = startIndex; i < stopIndex; ++i)
280 {
281 if (!inactiveSubchannels.at(i))
282 {
283 puncturedInfoField |= 1 << (i / 4);
284 }
285 }
286 return puncturedInfoField;
287 }
288 // IEEE 802.11be D5.0 Table 36-30
289 const auto numPunctured = std::count_if(inactiveSubchannels.cbegin(),
290 inactiveSubchannels.cend(),
291 [](bool punctured) { return punctured; });
292 if (numPunctured == 0)
293 {
294 // no puncturing
295 return 0;
296 }
297 const auto firstPunctured = std::find_if(inactiveSubchannels.cbegin(),
298 inactiveSubchannels.cend(),
299 [](bool punctured) { return punctured; });
300 const auto firstIndex = std::distance(inactiveSubchannels.cbegin(), firstPunctured);
301 switch (numPunctured)
302 {
303 case 1:
304 return firstIndex + 1;
305 case 2:
306 NS_ASSERT_MSG(((firstIndex % 2) == 0) && inactiveSubchannels.at(firstIndex + 1),
307 "invalid 40 MHz puncturing pattern");
308 return 9 + (firstIndex / 2);
309 default:
310 break;
311 }
312 NS_ASSERT_MSG(false, "invalid puncturing pattern");
313 return 0;
314}
315
318{
319 return Ptr<WifiPpdu>(new EhtPpdu(*this), false);
320}
321
322} // 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:217
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:205
bool IsDlMu() const override
Return true if the PPDU is a DL MU PPDU.
Definition eht-ppdu.cc:108
bool IsUlMu() const override
Return true if the PPDU is an UL MU PPDU.
Definition eht-ppdu.cc:114
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:187
Ptr< WifiPpdu > Copy() const override
Copy this instance.
Definition eht-ppdu.cc:317
void SetTxVectorFromPhyHeaders(WifiTxVector &txVector) const override
Fill in the TXVECTOR from PHY headers.
Definition eht-ppdu.cc:120
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:89
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:260
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
void SetHeMuUserInfos(WifiTxVector &txVector, const RuAllocation &ruAllocation, std::optional< Center26ToneRuIndication > center26ToneRuIndication, const HeSigBContentChannels &contentChannels, bool sigBCompression, uint8_t numMuMimoUsers) const
Reconstruct HeMuUserInfoMap from HE-SIG-B header.
Definition he-ppdu.cc:249
static Time GetGuardIntervalFromEncoding(uint8_t giAndNltfSize)
Convert guard interval from its encoding in HE-SIG-A.
Definition he-ppdu.cc:941
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:655
std::vector< std::vector< HeSigBUserSpecificField > > HeSigBContentChannels
HE SIG-B Content Channels.
Definition he-ppdu.h:50
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:898
static std::pair< std::size_t, std::size_t > GetNumRusPerHeSigBContentChannel(MHz_u channelWidth, const RuAllocation &ruAllocation, std::optional< Center26ToneRuIndication > center26ToneRuIndication, bool sigBCompression, uint8_t numMuMimoUsers)
Get the number of STAs per HE-SIG-B content channel.
Definition he-ppdu.cc:544
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:877
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:919
RU Specification.
Definition he-ru.h:37
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:101
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:151
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
static RuType GetRuType(RuSpec ru)
Get the type of a given RU.
Definition wifi-ru.cc:45
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.
bool IsSigBCompression() const
Indicate whether the Common field is present in the HE-SIG-B field.
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 SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
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