A Discrete-Event Network Simulator
API
tx-duration-test.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2009 CTTC
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Authors: Nicola Baldo <nbaldo@cttc.es>
19 * S├ębastien Deronne <sebastien.deronne@gmail.com>
20 */
21
22#include "ns3/log.h"
23#include "ns3/simulator.h"
24#include "ns3/test.h"
25#include "ns3/yans-wifi-phy.h"
26#include "ns3/he-ru.h"
27#include "ns3/wifi-psdu.h"
28#include "ns3/packet.h"
29#include "ns3/dsss-phy.h"
30#include "ns3/erp-ofdm-phy.h"
31#include "ns3/he-phy.h" //includes OFDM, HT, and VHT
32#include <numeric>
33
34using namespace ns3;
35
36NS_LOG_COMPONENT_DEFINE ("InterferenceHelperTxDurationTest");
37
45{
46public:
48 virtual ~TxDurationTest ();
49 void DoRun (void) override;
50
51
52private:
66 bool CheckPayloadDuration (uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration);
67
81 bool CheckTxDuration (uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration);
82
95 static bool CheckHeMuTxDuration (std::list<uint32_t> sizes, std::list<HeMuUserInfo> userInfos,
96 uint16_t channelWidth, uint16_t guardInterval,
97 Time knownDuration);
98
113 static Time CalculateTxDurationUsingList (std::list<uint32_t> sizes, std::list<uint16_t> staIds,
114 WifiTxVector txVector, WifiPhyBand band);
115};
116
118 : TestCase ("Wifi TX Duration")
119{
120}
121
123{
124}
125
126bool
127TxDurationTest::CheckPayloadDuration (uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
128{
129 WifiTxVector txVector;
130 txVector.SetMode (payloadMode);
131 txVector.SetPreambleType (preamble);
132 txVector.SetChannelWidth (channelWidth);
133 txVector.SetGuardInterval (guardInterval);
134 txVector.SetNss (1);
135 txVector.SetStbc (0);
136 txVector.SetNess (0);
138 Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy> ();
139 if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_OFDM
140 || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT
141 || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_VHT
142 || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HE)
143 {
144 band = WIFI_PHY_BAND_5GHZ;
145 }
146 Time calculatedDuration = phy->GetPayloadDuration (size, txVector, band);
147 if (calculatedDuration != knownDuration)
148 {
149 std::cerr << "size=" << size
150 << " mode=" << payloadMode
151 << " channelWidth=" << channelWidth
152 << " guardInterval=" << guardInterval
153 << " datarate=" << payloadMode.GetDataRate (channelWidth, guardInterval, 1)
154 << " known=" << knownDuration
155 << " calculated=" << calculatedDuration
156 << std::endl;
157 return false;
158 }
159 if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HE)
160 {
161 //Durations vary depending on frequency; test also 2.4 GHz (bug 1971)
163 calculatedDuration = phy->GetPayloadDuration (size, txVector, band);
164 knownDuration += MicroSeconds (6);
165 if (calculatedDuration != knownDuration)
166 {
167 std::cerr << "size=" << size
168 << " mode=" << payloadMode
169 << " channelWidth=" << channelWidth
170 << " guardInterval=" << guardInterval
171 << " datarate=" << payloadMode.GetDataRate (channelWidth, guardInterval, 1)
172 << " known=" << knownDuration
173 << " calculated=" << calculatedDuration
174 << std::endl;
175 return false;
176 }
177 }
178 return true;
179}
180
181bool
182TxDurationTest::CheckTxDuration (uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
183{
184 WifiTxVector txVector;
185 txVector.SetMode (payloadMode);
186 txVector.SetPreambleType (preamble);
187 txVector.SetChannelWidth (channelWidth);
188 txVector.SetGuardInterval (guardInterval);
189 txVector.SetNss (1);
190 txVector.SetStbc (0);
191 txVector.SetNess (0);
193 Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy> ();
194 if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_OFDM
195 || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT
196 || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_VHT
197 || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HE)
198 {
199 band = WIFI_PHY_BAND_5GHZ;
200 }
201 Time calculatedDuration = phy->CalculateTxDuration (size, txVector, band);
202 Time calculatedDurationUsingList = CalculateTxDurationUsingList (std::list<uint32_t> {size}, std::list<uint16_t> {SU_STA_ID},
203 txVector, band);
204 if (calculatedDuration != knownDuration || calculatedDuration != calculatedDurationUsingList)
205 {
206 std::cerr << "size=" << size
207 << " mode=" << payloadMode
208 << " channelWidth=" << +channelWidth
209 << " guardInterval=" << guardInterval
210 << " datarate=" << payloadMode.GetDataRate (channelWidth, guardInterval, 1)
211 << " preamble=" << preamble
212 << " known=" << knownDuration
213 << " calculated=" << calculatedDuration
214 << " calculatedUsingList=" << calculatedDurationUsingList
215 << std::endl;
216 return false;
217 }
218 if (payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HT || payloadMode.GetModulationClass () == WIFI_MOD_CLASS_HE)
219 {
220 //Durations vary depending on frequency; test also 2.4 GHz (bug 1971)
222 calculatedDuration = phy->CalculateTxDuration (size, txVector, band);
223 calculatedDurationUsingList = CalculateTxDurationUsingList (std::list<uint32_t> {size}, std::list<uint16_t> {SU_STA_ID},
224 txVector, band);
225 knownDuration += MicroSeconds (6);
226 if (calculatedDuration != knownDuration || calculatedDuration != calculatedDurationUsingList)
227 {
228 std::cerr << "size=" << size
229 << " mode=" << payloadMode
230 << " channelWidth=" << channelWidth
231 << " guardInterval=" << guardInterval
232 << " datarate=" << payloadMode.GetDataRate (channelWidth, guardInterval, 1)
233 << " preamble=" << preamble
234 << " known=" << knownDuration
235 << " calculated=" << calculatedDuration
236 << " calculatedUsingList=" << calculatedDurationUsingList
237 << std::endl;
238 return false;
239 }
240 }
241 return true;
242}
243
244bool
245TxDurationTest::CheckHeMuTxDuration (std::list<uint32_t> sizes, std::list<HeMuUserInfo> userInfos,
246 uint16_t channelWidth, uint16_t guardInterval,
247 Time knownDuration)
248{
249 NS_ASSERT (sizes.size () == userInfos.size () && sizes.size () > 1);
250 NS_ABORT_MSG_IF (channelWidth < std::accumulate (std::begin (userInfos), std::end (userInfos), 0,
251 [](const uint16_t prevBw, const HeMuUserInfo &info)
252 { return prevBw + HeRu::GetBandwidth (info.ru.GetRuType ()); }),
253 "Cannot accommodate all the RUs in the provided band"); //MU-MIMO (for which allocations use the same RU) is not supported
254 WifiTxVector txVector;
256 txVector.SetChannelWidth (channelWidth);
257 txVector.SetGuardInterval (guardInterval);
258 txVector.SetStbc (0);
259 txVector.SetNess (0);
260 std::list<uint16_t> staIds;
261 uint16_t staId = 1;
262 for (const auto & userInfo : userInfos)
263 {
264 txVector.SetHeMuUserInfo (staId, userInfo);
265 staIds.push_back (staId++);
266 }
267 Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy> ();
268 std::list<WifiPhyBand> testedBands {WIFI_PHY_BAND_5GHZ, WIFI_PHY_BAND_2_4GHZ}; //Durations vary depending on frequency; test also 2.4 GHz (bug 1971)
269 for (auto & testedBand : testedBands)
270 {
271 if (testedBand == WIFI_PHY_BAND_2_4GHZ)
272 {
273 knownDuration += MicroSeconds (6);
274 }
275 Time calculatedDuration = NanoSeconds (0);
276 uint32_t longuestSize = 0;
277 auto iterStaId = staIds.begin ();
278 for (auto & size : sizes)
279 {
280 Time ppduDurationForSta = phy->CalculateTxDuration (size, txVector, testedBand, *iterStaId);
281 if (ppduDurationForSta > calculatedDuration)
282 {
283 calculatedDuration = ppduDurationForSta;
284 staId = *iterStaId;
285 longuestSize = size;
286 }
287 ++iterStaId;
288 }
289 Time calculatedDurationUsingList = CalculateTxDurationUsingList (sizes, staIds, txVector, testedBand);
290 if (calculatedDuration != knownDuration || calculatedDuration != calculatedDurationUsingList)
291 {
292 std::cerr << "size=" << longuestSize
293 << " band=" << testedBand
294 << " staId=" << staId
295 << " nss=" << +txVector.GetNss (staId)
296 << " mode=" << txVector.GetMode (staId)
297 << " channelWidth=" << channelWidth
298 << " guardInterval=" << guardInterval
299 << " datarate=" << txVector.GetMode (staId).GetDataRate (channelWidth, guardInterval, txVector.GetNss (staId))
300 << " known=" << knownDuration
301 << " calculated=" << calculatedDuration
302 << " calculatedUsingList=" << calculatedDurationUsingList
303 << std::endl;
304 return false;
305 }
306 }
307 return true;
308}
309
310Time
311TxDurationTest::CalculateTxDurationUsingList (std::list<uint32_t> sizes, std::list<uint16_t> staIds,
312 WifiTxVector txVector, WifiPhyBand band)
313{
314 NS_ASSERT (sizes.size () == staIds.size ());
315 WifiConstPsduMap psduMap;
316 auto itStaId = staIds.begin ();
317 WifiMacHeader hdr;
318 hdr.SetType (WIFI_MAC_CTL_ACK); //so that size may not be empty while being as short as possible
319 for (auto & size : sizes)
320 {
321 // MAC header and FCS are to deduce from size
322 psduMap[*itStaId++] = Create<WifiPsdu> (Create<Packet> (size - hdr.GetSerializedSize () - 4), hdr);
323 }
324 return WifiPhy::CalculateTxDuration (psduMap, txVector, band);
325}
326
327void
329{
330 bool retval = true;
331
332 //IEEE Std 802.11-2007 Table 18-2 "Example of LENGTH calculations for CCK"
333 retval = retval
334 && CheckPayloadDuration (1023, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (744))
335 && CheckPayloadDuration (1024, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (745))
336 && CheckPayloadDuration (1025, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (746))
337 && CheckPayloadDuration (1026, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (747));
338
339 NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11b CCK duration failed");
340
341 //Similar, but we add PHY preamble and header durations
342 //and we test different rates.
343 //The payload durations for modes other than 11mbb have been
344 //calculated by hand according to IEEE Std 802.11-2007 18.2.3.5
345 retval = retval
346 && CheckTxDuration (1023, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (744 + 96))
347 && CheckTxDuration (1024, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (745 + 96))
348 && CheckTxDuration (1025, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (746 + 96))
349 && CheckTxDuration (1026, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (747 + 96))
350 && CheckTxDuration (1023, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (744 + 192))
351 && CheckTxDuration (1024, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (745 + 192))
352 && CheckTxDuration (1025, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (746 + 192))
353 && CheckTxDuration (1026, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (747 + 192))
354 && CheckTxDuration (1023, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (1488 + 96))
355 && CheckTxDuration (1024, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (1490 + 96))
356 && CheckTxDuration (1025, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (1491 + 96))
357 && CheckTxDuration (1026, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (1493 + 96))
358 && CheckTxDuration (1023, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (1488 + 192))
359 && CheckTxDuration (1024, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (1490 + 192))
360 && CheckTxDuration (1025, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (1491 + 192))
361 && CheckTxDuration (1026, DsssPhy::GetDsssRate5_5Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (1493 + 192))
362 && CheckTxDuration (1023, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (4092 + 96))
363 && CheckTxDuration (1024, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (4096 + 96))
364 && CheckTxDuration (1025, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (4100 + 96))
365 && CheckTxDuration (1026, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (4104 + 96))
366 && CheckTxDuration (1023, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (4092 + 192))
367 && CheckTxDuration (1024, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (4096 + 192))
368 && CheckTxDuration (1025, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (4100 + 192))
369 && CheckTxDuration (1026, DsssPhy::GetDsssRate2Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (4104 + 192))
370 && CheckTxDuration (1023, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (8184 + 192))
371 && CheckTxDuration (1024, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (8192 + 192))
372 && CheckTxDuration (1025, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (8200 + 192))
373 && CheckTxDuration (1026, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_SHORT, MicroSeconds (8208 + 192))
374 && CheckTxDuration (1023, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (8184 + 192))
375 && CheckTxDuration (1024, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (8192 + 192))
376 && CheckTxDuration (1025, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (8200 + 192))
377 && CheckTxDuration (1026, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (8208 + 192));
378
379 //values from http://mailman.isi.edu/pipermail/ns-developers/2009-July/006226.html
380 retval = retval && CheckTxDuration (14, DsssPhy::GetDsssRate1Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (304));
381
382 //values from http://www.oreillynet.com/pub/a/wireless/2003/08/08/wireless_throughput.html
383 retval = retval
384 && CheckTxDuration (1536, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (1310))
385 && CheckTxDuration (76, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (248))
386 && CheckTxDuration (14, DsssPhy::GetDsssRate11Mbps (), 22, 800, WIFI_PREAMBLE_LONG, MicroSeconds (203));
387
388 NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11b duration failed");
389
390 //802.11a durations
391 //values from http://www.oreillynet.com/pub/a/wireless/2003/08/08/wireless_throughput.html
392 retval = retval
393 && CheckTxDuration (1536, OfdmPhy::GetOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (248))
394 && CheckTxDuration (76, OfdmPhy::GetOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (32))
395 && CheckTxDuration (14, OfdmPhy::GetOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (24));
396
397 NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11a duration failed");
398
399 //802.11g durations are same as 802.11a durations but with 6 us signal extension
400 retval = retval
401 && CheckTxDuration (1536, ErpOfdmPhy::GetErpOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (254))
402 && CheckTxDuration (76, ErpOfdmPhy::GetErpOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (38))
403 && CheckTxDuration (14, ErpOfdmPhy::GetErpOfdmRate54Mbps (), 20, 800, WIFI_PREAMBLE_LONG, MicroSeconds (30));
404
405 NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11g duration failed");
406
407 //802.11n durations
408 retval = retval
409 && CheckTxDuration (1536, HtPhy::GetHtMcs7 (), 20, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (228))
410 && CheckTxDuration (76, HtPhy::GetHtMcs7 (), 20, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (48))
411 && CheckTxDuration (14, HtPhy::GetHtMcs7 (), 20, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (40))
412 && CheckTxDuration (1536, HtPhy::GetHtMcs0 (), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (1742400))
413 && CheckTxDuration (76, HtPhy::GetHtMcs0 (), 20, 400, WIFI_PREAMBLE_HT_MF, MicroSeconds (126))
414 && CheckTxDuration (14, HtPhy::GetHtMcs0 (), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (57600))
415 && CheckTxDuration (1536, HtPhy::GetHtMcs6 (), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (226800))
416 && CheckTxDuration (76, HtPhy::GetHtMcs6 (), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (46800))
417 && CheckTxDuration (14, HtPhy::GetHtMcs6 (), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (39600))
418 && CheckTxDuration (1536, HtPhy::GetHtMcs7 (), 40, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (128))
419 && CheckTxDuration (76, HtPhy::GetHtMcs7 (), 40, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (44))
420 && CheckTxDuration (14, HtPhy::GetHtMcs7 (), 40, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds (40))
421 && CheckTxDuration (1536, HtPhy::GetHtMcs7 (), 40, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (118800))
422 && CheckTxDuration (76, HtPhy::GetHtMcs7 (), 40, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (43200))
423 && CheckTxDuration (14, HtPhy::GetHtMcs7 (), 40, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds (39600));
424
425 NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11n duration failed");
426
427 //802.11ac durations
428 retval = retval
429 && CheckTxDuration (1536, VhtPhy::GetVhtMcs8 (), 20, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (196))
430 && CheckTxDuration (76, VhtPhy::GetVhtMcs8 (), 20, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (48))
431 && CheckTxDuration (14, VhtPhy::GetVhtMcs8 (), 20, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
432 && CheckTxDuration (1536, VhtPhy::GetVhtMcs8 (), 20, 400, WIFI_PREAMBLE_VHT_SU, MicroSeconds (180))
433 && CheckTxDuration (76, VhtPhy::GetVhtMcs8 (), 20, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (46800))
434 && CheckTxDuration (14, VhtPhy::GetVhtMcs8 (), 20, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
435 && CheckTxDuration (1536, VhtPhy::GetVhtMcs9 (), 40, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (108))
436 && CheckTxDuration (76, VhtPhy::GetVhtMcs9 (), 40, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
437 && CheckTxDuration (14, VhtPhy::GetVhtMcs9 (), 40, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
438 && CheckTxDuration (1536, VhtPhy::GetVhtMcs9 (), 40, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (100800))
439 && CheckTxDuration (76, VhtPhy::GetVhtMcs9 (), 40, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
440 && CheckTxDuration (14, VhtPhy::GetVhtMcs9 (), 40, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
441 && CheckTxDuration (1536, VhtPhy::GetVhtMcs0 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (460))
442 && CheckTxDuration (76, VhtPhy::GetVhtMcs0 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (60))
443 && CheckTxDuration (14, VhtPhy::GetVhtMcs0 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (44))
444 && CheckTxDuration (1536, VhtPhy::GetVhtMcs0 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (417600))
445 && CheckTxDuration (76, VhtPhy::GetVhtMcs0 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (57600))
446 && CheckTxDuration (14, VhtPhy::GetVhtMcs0 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (43200))
447 && CheckTxDuration (1536, VhtPhy::GetVhtMcs9 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (68))
448 && CheckTxDuration (76, VhtPhy::GetVhtMcs9 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
449 && CheckTxDuration (14, VhtPhy::GetVhtMcs9 (), 80, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
450 && CheckTxDuration (1536, VhtPhy::GetVhtMcs9 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (64800))
451 && CheckTxDuration (76, VhtPhy::GetVhtMcs9 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
452 && CheckTxDuration (14, VhtPhy::GetVhtMcs9 (), 80, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
453 && CheckTxDuration (1536, VhtPhy::GetVhtMcs8 (), 160, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (56))
454 && CheckTxDuration (76, VhtPhy::GetVhtMcs8 (), 160, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
455 && CheckTxDuration (14, VhtPhy::GetVhtMcs8 (), 160, 800, WIFI_PREAMBLE_VHT_SU, MicroSeconds (40))
456 && CheckTxDuration (1536, VhtPhy::GetVhtMcs8 (), 160, 400, WIFI_PREAMBLE_VHT_SU, MicroSeconds (54))
457 && CheckTxDuration (76, VhtPhy::GetVhtMcs8 (), 160, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600))
458 && CheckTxDuration (14, VhtPhy::GetVhtMcs8 (), 160, 400, WIFI_PREAMBLE_VHT_SU, NanoSeconds (39600));
459
460 NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11ac duration failed");
461
462 //802.11ax SU durations
463 retval = retval
464 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (1485600))
465 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (125600))
466 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (71200))
467 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (764800))
468 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (84800))
469 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
470 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (397600))
471 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (71200))
472 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
473 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (220800))
474 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
475 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
476 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (1570400))
477 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (130400))
478 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (72800))
479 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (807200))
480 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (87200))
481 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
482 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (418400))
483 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (72800))
484 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
485 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (231200))
486 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
487 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
488 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (1740))
489 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (140))
490 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (76))
491 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (892))
492 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (92))
493 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
494 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (460))
495 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (76))
496 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
497 && CheckTxDuration (1536, HePhy::GetHeMcs0 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (252))
498 && CheckTxDuration (76, HePhy::GetHeMcs0 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
499 && CheckTxDuration (14, HePhy::GetHeMcs0 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
500 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (139200))
501 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
502 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
503 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (98400))
504 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
505 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
506 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (71200))
507 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
508 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
509 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
510 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
511 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 160, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds (57600))
512 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (144800))
513 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
514 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 20, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
515 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (101600))
516 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
517 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 40, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
518 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (72800))
519 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
520 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 80, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
521 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
522 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
523 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 160, 1600, WIFI_PREAMBLE_HE_SU, NanoSeconds (58400))
524 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (156))
525 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
526 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
527 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (108))
528 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
529 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
530 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (76))
531 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
532 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
533 && CheckTxDuration (1536, HePhy::GetHeMcs11 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
534 && CheckTxDuration (76, HePhy::GetHeMcs11 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60))
535 && CheckTxDuration (14, HePhy::GetHeMcs11 (), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds (60));
536
537 NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11ax SU duration failed");
538
539 //802.11ax MU durations
540 retval = retval
541 && CheckHeMuTxDuration (std::list<uint32_t> {1536,
542 1536},
543 std::list<HeMuUserInfo> { {{HeRu::RU_242_TONE, 1, true}, HePhy::GetHeMcs0 (), 1},
544 {{HeRu::RU_242_TONE, 2, true}, HePhy::GetHeMcs0 (), 1} },
545 40, 800, NanoSeconds (1493600)) //equivalent to HE_SU for 20 MHz with 2 extra HE-SIG-B (i.e. 8 us)
546 && CheckHeMuTxDuration (std::list<uint32_t> {1536,
547 1536},
548 std::list<HeMuUserInfo> { {{HeRu::RU_242_TONE, 1, true}, HePhy::GetHeMcs1 (), 1},
549 {{HeRu::RU_242_TONE, 2, true}, HePhy::GetHeMcs0 (), 1} },
550 40, 800, NanoSeconds (1493600)) //shouldn't change if first PSDU is shorter
551 && CheckHeMuTxDuration (std::list<uint32_t> {1536,
552 76},
553 std::list<HeMuUserInfo> { {{HeRu::RU_242_TONE, 1, true}, HePhy::GetHeMcs0 (), 1},
554 {{HeRu::RU_242_TONE, 2, true}, HePhy::GetHeMcs0 (), 1} },
555 40, 800, NanoSeconds (1493600));
556
557 NS_TEST_EXPECT_MSG_EQ (retval, true, "an 802.11ax MU duration failed");
558
559 Simulator::Destroy ();
560}
561
569{
570public:
572 virtual ~HeSigBDurationTest ();
573 void DoRun (void) override;
574
575private:
584 static WifiTxVector BuildTxVector (uint16_t bw, std::list <HeMuUserInfo> userInfos);
585};
586
588 : TestCase ("Check HE-SIG-B duration computation")
589{
590}
591
593{
594}
595
597HeSigBDurationTest::BuildTxVector (uint16_t bw, std::list <HeMuUserInfo> userInfos)
598{
599 WifiTxVector txVector;
601 txVector.SetChannelWidth (bw);
602 txVector.SetGuardInterval (3200);
603 txVector.SetStbc (0);
604 txVector.SetNess (0);
605 std::list<uint16_t> staIds;
606 uint16_t staId = 1;
607 for (const auto & userInfo : userInfos)
608 {
609 txVector.SetHeMuUserInfo (staId, userInfo);
610 staIds.push_back (staId++);
611 }
612 return txVector;
613}
614
615void
617{
618 const auto & hePhy = WifiPhy::GetStaticPhyEntity(WIFI_MOD_CLASS_HE);
619
620 //20 MHz band
621 std::list<HeMuUserInfo> userInfos;
622 userInfos.push_back ({{HeRu::RU_106_TONE, 1, true}, HePhy::GetHeMcs11 (), 1});
623 userInfos.push_back ({{HeRu::RU_106_TONE, 2, true}, HePhy::GetHeMcs10 (), 4});
624 WifiTxVector txVector = BuildTxVector (20, userInfos);
625 NS_TEST_EXPECT_MSG_EQ (hePhy->GetSigMode (WIFI_PPDU_FIELD_SIG_B, txVector), VhtPhy::GetVhtMcs5 (), "HE-SIG-B should be sent at MCS 5");
626 std::pair<std::size_t, std::size_t> numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
627 NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 2, "Both users should be on HE-SIG-B content channel 1");
628 NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 0, "Both users should be on HE-SIG-B content channel 2");
629 NS_TEST_EXPECT_MSG_EQ (hePhy->GetDuration (WIFI_PPDU_FIELD_SIG_B, txVector), MicroSeconds (4), "HE-SIG-B should only last one OFDM symbol");
630
631 //40 MHz band, even number of users per HE-SIG-B content channel
632 userInfos.push_back ({{HeRu::RU_52_TONE, 5, true}, HePhy::GetHeMcs4 (), 1});
633 userInfos.push_back ({{HeRu::RU_52_TONE, 6, true}, HePhy::GetHeMcs6 (), 2});
634 userInfos.push_back ({{HeRu::RU_52_TONE, 7, true}, HePhy::GetHeMcs5 (), 3});
635 userInfos.push_back ({{HeRu::RU_52_TONE, 8, true}, HePhy::GetHeMcs6 (), 2});
636 txVector = BuildTxVector (40, userInfos);
637 NS_TEST_EXPECT_MSG_EQ (hePhy->GetSigMode (WIFI_PPDU_FIELD_SIG_B, txVector), VhtPhy::GetVhtMcs4 (), "HE-SIG-B should be sent at MCS 4");
638 numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
639 NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 2, "Two users should be on HE-SIG-B content channel 1");
640 NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 4, "Four users should be on HE-SIG-B content channel 2");
641 NS_TEST_EXPECT_MSG_EQ (hePhy->GetDuration (WIFI_PPDU_FIELD_SIG_B, txVector), MicroSeconds (4), "HE-SIG-B should only last one OFDM symbol");
642
643 //40 MHz band, odd number of users per HE-SIG-B content channel
644 userInfos.push_back ({{HeRu::RU_26_TONE, 13, true}, HePhy::GetHeMcs3 (), 1});
645 txVector = BuildTxVector (40, userInfos);
646 NS_TEST_EXPECT_MSG_EQ (hePhy->GetSigMode (WIFI_PPDU_FIELD_SIG_B, txVector), VhtPhy::GetVhtMcs3 (), "HE-SIG-B should be sent at MCS 3");
647 numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
648 NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 2, "Two users should be on HE-SIG-B content channel 1");
649 NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 5, "Five users should be on HE-SIG-B content channel 2");
650 NS_TEST_EXPECT_MSG_EQ (hePhy->GetDuration (WIFI_PPDU_FIELD_SIG_B, txVector), MicroSeconds (8), "HE-SIG-B should last two OFDM symbols");
651
652 //80 MHz band
653 userInfos.push_back ({{HeRu::RU_242_TONE, 3, true}, HePhy::GetHeMcs1 (), 1});
654 userInfos.push_back ({{HeRu::RU_242_TONE, 4, true}, HePhy::GetHeMcs4 (), 1});
655 txVector = BuildTxVector (80, userInfos);
656 NS_TEST_EXPECT_MSG_EQ (hePhy->GetSigMode (WIFI_PPDU_FIELD_SIG_B, txVector), VhtPhy::GetVhtMcs1 (), "HE-SIG-B should be sent at MCS 1");
657 numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
658 NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 3, "Three users should be on HE-SIG-B content channel 1");
659 NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 6, "Six users should be on HE-SIG-B content channel 2");
660 NS_TEST_EXPECT_MSG_EQ (hePhy->GetDuration (WIFI_PPDU_FIELD_SIG_B, txVector), MicroSeconds (16), "HE-SIG-B should last four OFDM symbols");
661
662 //160 MHz band
663 userInfos.push_back ({{HeRu::RU_996_TONE, 1, false}, HePhy::GetHeMcs1 (), 1});
664 txVector = BuildTxVector (160, userInfos);
665 NS_TEST_EXPECT_MSG_EQ (hePhy->GetSigMode (WIFI_PPDU_FIELD_SIG_B, txVector), VhtPhy::GetVhtMcs1 (), "HE-SIG-B should be sent at MCS 1");
666 numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel ();
667 NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.first, 4, "Four users should be on HE-SIG-B content channel 1");
668 NS_TEST_EXPECT_MSG_EQ (numUsersPerCc.second, 7, "Seven users should be on HE-SIG-B content channel 2");
669 NS_TEST_EXPECT_MSG_EQ (hePhy->GetDuration (WIFI_PPDU_FIELD_SIG_B, txVector), MicroSeconds (20), "HE-SIG-B should last five OFDM symbols");
670}
671
679{
680public:
682 virtual ~PhyHeaderSectionsTest ();
683 void DoRun (void) override;
684
685
686private:
696};
697
699 : TestCase ("PHY header sections consistency")
700{
701}
702
704{
705}
706
707void
710{
711 NS_TEST_EXPECT_MSG_EQ (obtained.size (), expected.size (), "The expected map size (" << expected.size () << ") was not obtained (" << obtained.size () << ")");
712
713 auto itObtained = obtained.begin ();
714 auto itExpected = expected.begin ();
715 for (;itObtained != obtained.end () || itExpected != expected.end ();)
716 {
717 WifiPpduField field = itObtained->first;
718 auto window = itObtained->second.first;
719 auto mode = itObtained->second.second;
720
721 WifiPpduField fieldRef = itExpected->first;
722 auto windowRef = itExpected->second.first;
723 auto modeRef = itExpected->second.second;
724
725 NS_TEST_EXPECT_MSG_EQ (field, fieldRef, "The expected PPDU field (" << fieldRef << ") was not obtained (" << field << ")");
726 NS_TEST_EXPECT_MSG_EQ (window.first, windowRef.first, "The expected start time (" << windowRef.first << ") was not obtained (" << window.first << ")");
727 NS_TEST_EXPECT_MSG_EQ (window.second, windowRef.second, "The expected stop time (" << windowRef.second << ") was not obtained (" << window.second << ")");
728 NS_TEST_EXPECT_MSG_EQ (mode, modeRef, "The expected mode (" << modeRef << ") was not obtained (" << mode << ")");
729 ++itObtained;
730 ++itExpected;
731 }
732}
733
734void
736{
737 Time ppduStart = Seconds (1.0);
738 Ptr<PhyEntity> phyEntity;
740 WifiTxVector txVector;
741 WifiMode nonHtMode;
742
743
744 // ==================================================================================
745 // 11b (HR/DSSS)
746 phyEntity = Create<DsssPhy> ();
747 txVector.SetMode (DsssPhy::GetDsssRate1Mbps ());
748 txVector.SetChannelWidth (22);
749
750 // -> long PPDU format
752 nonHtMode = DsssPhy::GetDsssRate1Mbps ();
753 sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
754 ppduStart + MicroSeconds (144) },
755 nonHtMode } },
756 { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (144),
757 ppduStart + MicroSeconds (192) },
758 nonHtMode } } };
759 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
760
761 // -> long PPDU format if data rate is 1 Mbps (even if preamble is tagged short)
763 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
764
765 // -> short PPDU format
766 txVector.SetMode (DsssPhy::GetDsssRate11Mbps ());
767 nonHtMode = DsssPhy::GetDsssRate2Mbps ();
769 sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
770 ppduStart + MicroSeconds (72) },
771 nonHtMode } },
772 { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (72),
773 ppduStart + MicroSeconds (96) },
774 nonHtMode } } };
775 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
776
777
778 // ==================================================================================
779 // 11a (OFDM)
781
782 // -> one iteration per variant: default, 10 MHz, and 5 MHz
783 std::map<OfdmPhyVariant, std::size_t> variants { //number to use to deduce rate and BW info for each variant
784 { OFDM_PHY_DEFAULT, 1},
785 { OFDM_PHY_10_MHZ, 2},
786 { OFDM_PHY_5_MHZ, 4}
787 };
788 for (auto variant : variants)
789 {
790 phyEntity = Create<OfdmPhy> (variant.first);
791 std::size_t ratio = variant.second;
792 uint16_t bw = 20 / ratio; //MHz
793 txVector.SetChannelWidth (bw);
794 txVector.SetMode (OfdmPhy::GetOfdmRate (12000000 / ratio, bw));
795 nonHtMode = OfdmPhy::GetOfdmRate (6000000 / ratio, bw);
796 sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
797 ppduStart + MicroSeconds (16 * ratio) },
798 nonHtMode } },
799 { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (16 * ratio),
800 ppduStart + MicroSeconds (20 * ratio) },
801 nonHtMode } } };
802 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
803 }
804
805
806 // ==================================================================================
807 // 11g (ERP-OFDM)
808 phyEntity = Create<ErpOfdmPhy> ();
809 txVector.SetChannelWidth (20);
810 txVector.SetMode (ErpOfdmPhy::GetErpOfdmRate (54000000));
811 nonHtMode = ErpOfdmPhy::GetErpOfdmRate6Mbps ();
812 sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
813 ppduStart + MicroSeconds (16) },
814 nonHtMode } },
815 { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (16),
816 ppduStart + MicroSeconds (20) },
817 nonHtMode } } };
818 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
819
820
821 // ==================================================================================
822 // 11n (HT)
823 phyEntity = Create<HtPhy> (4);
824 txVector.SetChannelWidth (20);
825 txVector.SetMode (HtPhy::GetHtMcs6 ());
826 nonHtMode = OfdmPhy::GetOfdmRate6Mbps ();
827 WifiMode htSigMode = nonHtMode;
828
829 // -> HT-mixed format for 2 SS and no ESS
831 txVector.SetNss (2);
832 txVector.SetNess (0);
833 sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
834 ppduStart + MicroSeconds (16) },
835 nonHtMode } },
836 { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (16),
837 ppduStart + MicroSeconds (20) },
838 nonHtMode } },
839 { WIFI_PPDU_FIELD_HT_SIG, { { ppduStart + MicroSeconds (20),
840 ppduStart + MicroSeconds (28) },
841 htSigMode } },
842 { WIFI_PPDU_FIELD_TRAINING, { { ppduStart + MicroSeconds (28),
843 ppduStart + MicroSeconds (40) }, // 1 HT-STF + 2 HT-LTFs
844 htSigMode } } };
845 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
846 txVector.SetChannelWidth (20); //shouldn't have any impact
847 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
848
849 // -> HT-mixed format for 3 SS and 1 ESS
850 txVector.SetNss (3);
851 txVector.SetNess (1);
852 sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (28),
853 ppduStart + MicroSeconds (52) }, // 1 HT-STF + 5 HT-LTFs (4 data + 1 extension)
854 htSigMode };
855 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
856
857
858 // ==================================================================================
859 // 11ac (VHT)
860 phyEntity = Create<VhtPhy> ();
861 txVector.SetChannelWidth (20);
862 txVector.SetNess (0);
863 txVector.SetMode (VhtPhy::GetVhtMcs7 ());
864 WifiMode sigAMode = nonHtMode;
865 WifiMode sigBMode = VhtPhy::GetVhtMcs0 ();
866
867 // -> VHT SU format for 5 SS
869 txVector.SetNss (5);
870 sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
871 ppduStart + MicroSeconds (16) },
872 nonHtMode } },
873 { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (16),
874 ppduStart + MicroSeconds (20) },
875 nonHtMode } },
876 { WIFI_PPDU_FIELD_SIG_A, { { ppduStart + MicroSeconds (20),
877 ppduStart + MicroSeconds (28) },
878 sigAMode } },
879 { WIFI_PPDU_FIELD_TRAINING, { { ppduStart + MicroSeconds (28),
880 ppduStart + MicroSeconds (56) }, // 1 VHT-STF + 6 VHT-LTFs
881 sigAMode } } };
882 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
883
884 // -> VHT SU format for 7 SS
885 txVector.SetNss (7);
886 sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (28),
887 ppduStart + MicroSeconds (64) }, // 1 VHT-STF + 8 VHT-LTFs
888 sigAMode };
889 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
890
891 // -> VHT MU format for 3 SS
893 txVector.SetNss (3);
894 sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (28),
895 ppduStart + MicroSeconds (48) }, // 1 VHT-STF + 4 VHT-LTFs
896 sigAMode };
897 sections[WIFI_PPDU_FIELD_SIG_B] = { { ppduStart + MicroSeconds (48),
898 ppduStart + MicroSeconds (52) },
899 sigBMode };
900 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
901 txVector.SetChannelWidth (80); //shouldn't have any impact
902 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
903
904
905 // ==================================================================================
906 // 11ax (HE)
907 phyEntity = Create<HePhy> ();
908 txVector.SetChannelWidth (20);
909 txVector.SetNss (2); //HE-LTF duration assumed to be always 8 us for the time being (see note in HePhy::GetTrainingDuration)
910 txVector.SetMode (HePhy::GetHeMcs9 ());
911 std::map<uint16_t, HeMuUserInfo> userInfoMap = { { 1, { {HeRu::RU_106_TONE, 1, true}, HePhy::GetHeMcs4 (), 2 } },
912 { 2, { {HeRu::RU_106_TONE, 1, true}, HePhy::GetHeMcs9 (), 1 } } };
913 sigAMode = HePhy::GetVhtMcs0 ();
914 sigBMode = HePhy::GetVhtMcs4 (); //because of first user info map
915
916 // -> HE SU format
918 sections = { { WIFI_PPDU_FIELD_PREAMBLE, { { ppduStart,
919 ppduStart + MicroSeconds (16) },
920 nonHtMode } },
921 { WIFI_PPDU_FIELD_NON_HT_HEADER, { { ppduStart + MicroSeconds (16),
922 ppduStart + MicroSeconds (24) }, // L-SIG + RL-SIG
923 nonHtMode } },
924 { WIFI_PPDU_FIELD_SIG_A, { { ppduStart + MicroSeconds (24),
925 ppduStart + MicroSeconds (32) },
926 sigAMode } },
927 { WIFI_PPDU_FIELD_TRAINING, { { ppduStart + MicroSeconds (32),
928 ppduStart + MicroSeconds (52) }, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
929 sigAMode } } };
930 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
931
932 // -> HE ER SU format
934 sections[WIFI_PPDU_FIELD_SIG_A] = { { ppduStart + MicroSeconds (24),
935 ppduStart + MicroSeconds (40) }, // 16 us HE-SIG-A
936 sigAMode };
937 sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (40),
938 ppduStart + MicroSeconds (60) }, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
939 sigAMode };
940 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
941
942 // -> HE TB format
944 txVector.SetHeMuUserInfo (1, userInfoMap.at (1));
945 txVector.SetHeMuUserInfo (2, userInfoMap.at (2));
946 sections[WIFI_PPDU_FIELD_SIG_A] = { { ppduStart + MicroSeconds (24),
947 ppduStart + MicroSeconds (32) },
948 sigAMode };
949 sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (32),
950 ppduStart + MicroSeconds (56) }, // 1 HE-STF (@ 8 us) + 2 HE-LTFs (@ 8 us)
951 sigAMode };
952 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
953
954 // -> HE MU format
956 sections[WIFI_PPDU_FIELD_SIG_A] = { { ppduStart + MicroSeconds (24),
957 ppduStart + MicroSeconds (32) },
958 sigAMode };
959 sections[WIFI_PPDU_FIELD_SIG_B] = { { ppduStart + MicroSeconds (32),
960 ppduStart + MicroSeconds (36) }, // only one symbol
961 sigBMode };
962 sections[WIFI_PPDU_FIELD_TRAINING] = { { ppduStart + MicroSeconds (36),
963 ppduStart + MicroSeconds (56) }, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
964 sigBMode };
965 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
966 txVector.SetChannelWidth (160); //shouldn't have any impact
967 CheckPhyHeaderSections (phyEntity->GetPhyHeaderSections (txVector, ppduStart), sections);
968}
969
977{
978public:
980};
981
983 : TestSuite ("wifi-devices-tx-duration", UNIT)
984{
985 AddTestCase (new HeSigBDurationTest, TestCase::QUICK);
986 AddTestCase (new TxDurationTest, TestCase::QUICK);
987 AddTestCase (new PhyHeaderSectionsTest, TestCase::QUICK);
988}
989
HE-SIG-B duration test.
void DoRun(void) override
Implementation to actually run this TestCase.
static WifiTxVector BuildTxVector(uint16_t bw, std::list< HeMuUserInfo > userInfos)
Build a TXVECTOR for HE MU with the given bandwith and user informations.
PHY header sections consistency test.
void DoRun(void) override
Implementation to actually run this TestCase.
void CheckPhyHeaderSections(PhyEntity::PhyHeaderSections obtained, PhyEntity::PhyHeaderSections expected)
Check if map of PHY header sections returned by a given PHY entity corresponds to a known value.
Tx Duration Test.
static Time CalculateTxDurationUsingList(std::list< uint32_t > sizes, std::list< uint16_t > staIds, WifiTxVector txVector, WifiPhyBand band)
Calculate the overall Tx duration returned by WifiPhy for list of sizes.
bool CheckTxDuration(uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
Check if the overall tx duration returned by InterferenceHelper corresponds to a known value.
bool CheckPayloadDuration(uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
Check if the payload tx duration returned by InterferenceHelper corresponds to a known value.
virtual ~TxDurationTest()
static bool CheckHeMuTxDuration(std::list< uint32_t > sizes, std::list< HeMuUserInfo > userInfos, uint16_t channelWidth, uint16_t guardInterval, Time knownDuration)
Check if the overall Tx duration returned by WifiPhy for a HE MU PPDU corresponds to a known value.
void DoRun(void) override
Implementation to actually run this TestCase.
Tx Duration Test Suite.
RuType GetRuType(void) const
Get the RU type.
Definition: he-ru.cc:167
std::map< WifiPpduField, PhyHeaderChunkInfo > PhyHeaderSections
A map of PhyHeaderChunkInfo elements per PPDU field.
Definition: phy-entity.h:301
encapsulates test code
Definition: test.h:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
Implements the IEEE 802.11 MAC header.
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
uint32_t GetSerializedSize(void) const override
represent a single transmission mode
Definition: wifi-mode.h:48
WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:177
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:114
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetStbc(bool stbc)
Sets if STBC is being used.
void SetNess(uint8_t ness)
Sets the Ness number.
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t 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.
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.
std::pair< std::size_t, std::size_t > GetNumRusPerHeSigBContentChannel(void) const
Get the number of RUs per HE-SIG-B content channel.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
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:67
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:240
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1260
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1268
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
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
WifiPpduField
The type of PPDU field (grouped for convenience)
@ WIFI_PREAMBLE_LONG
@ WIFI_PREAMBLE_HE_ER_SU
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PREAMBLE_HE_SU
@ WIFI_PREAMBLE_VHT_MU
@ WIFI_PREAMBLE_VHT_SU
@ WIFI_PREAMBLE_SHORT
@ WIFI_PREAMBLE_HT_MF
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
Definition: wifi-phy-band.h:35
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Definition: wifi-phy-band.h:37
@ WIFI_MOD_CLASS_OFDM
OFDM (Clause 17)
@ WIFI_MOD_CLASS_HT
HT (Clause 19)
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ OFDM_PHY_10_MHZ
Definition: ofdm-phy.h:46
@ OFDM_PHY_DEFAULT
Definition: ofdm-phy.h:45
@ OFDM_PHY_5_MHZ
Definition: ofdm-phy.h:47
@ 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_HT_SIG
HT-SIG field.
@ WIFI_PPDU_FIELD_PREAMBLE
SYNC + SFD fields for DSSS or ERP, shortSYNC + shortSFD fields for HR/DSSS or ERP,...
@ WIFI_PPDU_FIELD_SIG_A
SIG-A field.
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.
@ WIFI_MAC_CTL_ACK
phy
Definition: third.py:93
HE MU specific user transmission parameters.
HeRu::RuSpec ru
RU specification.
static TxDurationTestSuite g_txDurationTestSuite
the test suite
#define SU_STA_ID
Definition: wifi-mode.h:32