A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
minstrel-ht-wifi-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 Duy Nguyen
3 * Copyright (c) 2015 Ghada Badawy
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 * Authors: Duy Nguyen <duy@soe.ucsc.edu>
8 * Ghada Badawy <gbadawy@gmail.com>
9 * Matias Richart <mrichart@fing.edu.uy>
10 *
11 * Some Comments:
12 *
13 * 1) By default, Minstrel applies the multi-rate retry (the core of Minstrel
14 * algorithm). Otherwise, please use ConstantRateWifiManager instead.
15 *
16 * 2) Sampling is done differently from legacy Minstrel. Minstrel-HT tries
17 * to sample all rates in all groups at least once and to avoid many
18 * consecutive samplings.
19 *
20 * 3) Sample rate is tried only once, at first place of the MRR chain.
21 *
22 * reference: http://lwn.net/Articles/376765/
23 */
24
26
27#include "ns3/ht-configuration.h"
28#include "ns3/log.h"
29#include "ns3/packet.h"
30#include "ns3/random-variable-stream.h"
31#include "ns3/simulator.h"
32#include "ns3/wifi-mac.h"
33#include "ns3/wifi-net-device.h"
34#include "ns3/wifi-phy.h"
35#include "ns3/wifi-psdu.h"
36
37#include <algorithm>
38#include <iomanip>
39
40#define Min(a, b) ((a < b) ? a : b)
41#define Max(a, b) ((a > b) ? a : b)
42
43NS_LOG_COMPONENT_DEFINE("MinstrelHtWifiManager");
44
45namespace ns3
46{
47
48/**
49 * @brief standard information for each modulation class
50 */
51const std::map<WifiModulationClass, MinstrelHtWifiManager::StandardInfo> minstrelHtStandardInfos{
52 {
54 {
55 .groupType = WIFI_MINSTREL_GROUP_HT,
56 .maxMcs = 7,
57 .maxWidth = MHz_u{40},
58 .guardIntervals = {NanoSeconds(800), NanoSeconds(400)},
59 .maxStreams = 4,
60 },
61 },
62 {
64 {
65 .groupType = WIFI_MINSTREL_GROUP_VHT,
66 .maxMcs = 9,
67 .maxWidth = MHz_u{160},
68 .guardIntervals = {NanoSeconds(800), NanoSeconds(400)},
69 .maxStreams = 8,
70 },
71 },
72 {
74 {
75 .groupType = WIFI_MINSTREL_GROUP_HE,
76 .maxMcs = 11,
77 .maxWidth = MHz_u{160},
78 .guardIntervals = {NanoSeconds(3200), NanoSeconds(1600), NanoSeconds(800)},
79 .maxStreams = 8,
80 },
81 },
82 {
84 {
85 .groupType = WIFI_MINSTREL_GROUP_EHT,
86 .maxMcs = 13,
87 .maxWidth = MHz_u{320},
88 .guardIntervals = {NanoSeconds(3200), NanoSeconds(1600), NanoSeconds(800)},
89 .maxStreams = 8,
90 },
91 },
92};
93
94/// MinstrelHtWifiRemoteStation structure
96{
97 uint8_t m_sampleGroup; //!< The group that the sample rate belongs to.
98
99 uint32_t m_sampleWait; //!< How many transmission attempts to wait until a new sample.
100 uint32_t m_sampleTries; //!< Number of sample tries after waiting sampleWait.
101 uint32_t m_sampleCount; //!< Max number of samples per update interval.
102 uint32_t m_numSamplesSlow; //!< Number of times a slow rate was sampled.
103
104 uint32_t m_avgAmpduLen; //!< Average number of MPDUs in an A-MPDU.
105 uint32_t m_ampduLen; //!< Number of MPDUs in an A-MPDU.
106 uint32_t m_ampduPacketCount; //!< Number of A-MPDUs transmitted.
107
108 McsGroupData m_groupsTable; //!< Table of groups with stats.
109 bool m_isHt; //!< If the station is HT capable.
110
111 std::ofstream m_statsFile; //!< File where statistics table is written.
112};
113
115
116TypeId
118{
119 static TypeId tid =
120 TypeId("ns3::MinstrelHtWifiManager")
122 .AddConstructor<MinstrelHtWifiManager>()
123 .SetGroupName("Wifi")
124 .AddAttribute("UpdateStatistics",
125 "The interval between updating statistics table",
129 .AddAttribute("LegacyUpdateStatistics",
130 "The interval between updating statistics table (for legacy Minstrel)",
134 .AddAttribute("LookAroundRate",
135 "The percentage to try other rates (for legacy Minstrel)",
136 UintegerValue(10),
139 .AddAttribute("EWMA",
140 "EWMA level",
141 UintegerValue(75),
144 .AddAttribute("SampleColumn",
145 "The number of columns used for sampling",
146 UintegerValue(10),
149 .AddAttribute("PacketLength",
150 "The packet length used for calculating mode TxTime (bytes)",
151 UintegerValue(1200),
154 .AddAttribute("UseLatestAmendmentOnly",
155 "Use only the latest amendment when it is supported by both peers",
156 BooleanValue(true),
159 .AddAttribute("PrintStats",
160 "Control the printing of the statistics table",
161 BooleanValue(false),
164 .AddTraceSource("Rate",
165 "Traced value for rate changes (b/s)",
167 "ns3::TracedValueCallback::Uint64");
168 return tid;
169}
170
172 : m_numGroups(0),
173 m_numRates(0),
174 m_currentRate(0)
175{
176 NS_LOG_FUNCTION(this);
178 /**
179 * Create the legacy Minstrel manager in case HT is not supported by the device
180 * or non-HT stations want to associate.
181 */
183}
184
186{
187 NS_LOG_FUNCTION(this);
188 for (std::size_t i = 0; i < m_numGroups; i++)
189 {
190 m_minstrelGroups[i].ratesFirstMpduTxTimeTable.clear();
191 m_minstrelGroups[i].ratesTxTimeTable.clear();
192 }
193}
194
195int64_t
197{
198 NS_LOG_FUNCTION(this << stream);
199 int64_t numStreamsAssigned = 0;
200 m_uniformRandomVariable->SetStream(stream);
201 numStreamsAssigned++;
202 numStreamsAssigned += m_legacyManager->AssignStreams(stream);
203 return numStreamsAssigned;
204}
205
206void
208{
209 NS_LOG_FUNCTION(this << phy);
210 // Setup PHY for legacy manager.
211 m_legacyManager->SetupPhy(phy);
213}
214
215void
217{
218 NS_LOG_FUNCTION(this << mac);
219 m_legacyManager->SetupMac(mac);
221}
222
223void
225{
226 const auto& standardInfos = minstrelHtStandardInfos.at(mc);
227 for (MHz_u chWidth{20}; chWidth <= standardInfos.maxWidth; chWidth *= 2)
228 {
229 for (const auto& guardInterval : standardInfos.guardIntervals)
230 {
231 for (uint8_t streams = 1; streams <= standardInfos.maxStreams; ++streams)
232 {
233 const auto groupId =
234 GetGroupIdForType(standardInfos.groupType, streams, guardInterval, chWidth);
235
236 m_minstrelGroups[groupId].streams = streams;
237 m_minstrelGroups[groupId].gi = guardInterval;
238 m_minstrelGroups[groupId].chWidth = chWidth;
239 m_minstrelGroups[groupId].type = standardInfos.groupType;
240 m_minstrelGroups[groupId].isSupported = false;
241
242 // Check capabilities of the device
243 if ((((mc >= WIFI_MOD_CLASS_HE) &&
244 (GetGuardInterval() <=
245 guardInterval)) || /// Is GI supported by the transmitter?
246 ((mc < WIFI_MOD_CLASS_HE) &&
248 (guardInterval.GetNanoSeconds() ==
249 400)))) /// Is SGI supported by the transmitter?
250 && (GetPhy()->GetChannelWidth() >=
251 chWidth) /// Is channel width supported by the transmitter?
252 && (GetPhy()->GetMaxSupportedTxSpatialStreams() >=
253 streams)) /// Are streams supported by the transmitter?
254 {
255 m_minstrelGroups[groupId].isSupported = true;
256
257 // Calculate TX time for all rates of the group
258 WifiModeList mcsList = GetDeviceMcsList(mc);
259 for (uint8_t i = 0; i <= standardInfos.maxMcs; ++i)
260 {
261 const auto mcsIndex = (mc == WIFI_MOD_CLASS_HT)
262 ? (i + (m_minstrelGroups[groupId].streams - 1) *
263 (standardInfos.maxMcs + 1))
264 : i;
265 WifiMode mode = mcsList.at(mcsIndex);
266 // Check for invalid MCSs and do not add time to array.
267 if (IsValidMcs(streams, chWidth, mode))
268 {
269 AddFirstMpduTxTime(groupId,
270 mode,
272 guardInterval,
273 chWidth,
274 mode,
276 AddMpduTxTime(groupId,
277 mode,
279 guardInterval,
280 chWidth,
281 mode,
283 }
284 }
285 NS_LOG_DEBUG("Initialized group " << groupId << ": (" << +streams << ","
286 << guardInterval << "," << chWidth << ")");
287 }
288 }
289 }
290 }
291}
292
293void
295{
296 NS_LOG_FUNCTION(this);
297 /**
298 * Here we initialize m_minstrelGroups with all the possible groups.
299 * If a group is not supported by the device, then it is marked as not supported.
300 * Then, after all initializations are finished, we check actual support for each receiving
301 * station.
302 */
303
304 m_numGroups = 0;
305 if (GetHtSupported())
306 {
309 }
310 if (GetVhtSupported())
311 {
314 }
315 if (GetHeSupported())
316 {
319 }
320 if (GetEhtSupported())
321 {
324 }
325
326 /**
327 * Initialize the groups array.
328 * The HT groups come first, then the VHT ones, then the HE ones, and finally the EHT ones.
329 * Minstrel maintains different types of indexes:
330 * - A global continuous index, which identifies all rates within all groups, in [0,
331 * m_numGroups * m_numRates]
332 * - A groupId, which indexes a group in the array, in [0, m_numGroups]
333 * - A rateId, which identifies a rate within a group, in [0, m_numRates]
334 * - A deviceIndex, which indexes a MCS in the PHY MCS array.
335 * - A mcsIndex, which indexes a MCS in the wifi-remote-station-manager supported MCSs
336 * array.
337 */
338 NS_LOG_DEBUG("Initialize MCS Groups:");
340
341 if (GetHtSupported())
342 {
343 // Initialize all HT groups
345 }
346
347 if (GetVhtSupported())
348 {
349 // Initialize all VHT groups
351 }
352
353 if (GetHeSupported())
354 {
355 // Initialize all HE groups
357 }
358
359 if (GetEhtSupported())
360 {
361 // Initialize all EHT groups
363 }
364}
365
366bool
367MinstrelHtWifiManager::IsValidMcs(uint8_t streams, MHz_u chWidth, WifiMode mode)
368{
369 NS_LOG_FUNCTION(this << streams << chWidth << mode);
370 WifiTxVector txvector;
371 txvector.SetNss(streams);
372 txvector.SetChannelWidth(chWidth);
373 txvector.SetMode(mode);
374 return txvector.IsValid();
375}
376
377bool
379{
380 for (const auto& [mc, infos] : minstrelHtStandardInfos)
381 {
382 if ((m_minstrelGroups[groupId].type == infos.groupType) &&
383 (mode.GetModulationClass() == mc) &&
384 IsValidMcs(m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
385 {
386 if (mc == WIFI_MOD_CLASS_HT)
387 {
388 /// Check if the HT MCS corresponds to groups number of streams.
389 return ((mode.GetMcsValue() < (m_minstrelGroups[groupId].streams * 8)) &&
390 (mode.GetMcsValue() >= ((m_minstrelGroups[groupId].streams - 1) * 8)));
391 }
392 return true;
393 }
394 }
395 return false;
396}
397
398Time
400 Time gi,
401 MHz_u chWidth,
402 WifiMode mode,
403 MpduType mpduType)
404{
405 NS_LOG_FUNCTION(this << streams << gi << chWidth << mode << mpduType);
406 WifiTxVector txvector{};
407 txvector.SetNss(streams);
408 txvector.SetGuardInterval(gi);
409 txvector.SetChannelWidth(chWidth);
410 txvector.SetMode(mode);
411 txvector.SetPreambleType(GetPreambleForTransmission(mode.GetModulationClass()));
413 WifiPhy::GetPayloadDuration(m_frameLength, txvector, GetPhy()->GetPhyBand(), mpduType);
414}
415
416Time
418{
419 NS_LOG_FUNCTION(this << groupId << mode);
420 const auto it = m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.find(mode);
421 NS_ASSERT(it != m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.cend());
422 return it->second;
423}
424
425void
427{
428 NS_LOG_FUNCTION(this << groupId << mode << t);
429 m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.insert(std::make_pair(mode, t));
430}
431
432Time
433MinstrelHtWifiManager::GetMpduTxTime(std::size_t groupId, WifiMode mode) const
434{
435 NS_LOG_FUNCTION(this << groupId << mode);
436 auto it = m_minstrelGroups[groupId].ratesTxTimeTable.find(mode);
437 NS_ASSERT(it != m_minstrelGroups[groupId].ratesTxTimeTable.end());
438 return it->second;
439}
440
441void
443{
444 NS_LOG_FUNCTION(this << groupId << mode << t);
445 m_minstrelGroups[groupId].ratesTxTimeTable.insert(std::make_pair(mode, t));
446}
447
450{
451 NS_LOG_FUNCTION(this);
452 auto station = new MinstrelHtWifiRemoteStation();
453
454 // Initialize variables common to both stations.
455 station->m_nextStatsUpdate = Simulator::Now() + m_updateStats;
456 station->m_col = 0;
457 station->m_index = 0;
458 station->m_maxTpRate = 0;
459 station->m_maxTpRate2 = 0;
460 station->m_maxProbRate = 0;
461 station->m_nModes = 0;
462 station->m_totalPacketsCount = 0;
463 station->m_samplePacketsCount = 0;
464 station->m_isSampling = false;
465 station->m_sampleRate = 0;
466 station->m_sampleDeferred = false;
467 station->m_shortRetry = 0;
468 station->m_longRetry = 0;
469 station->m_txrate = 0;
470 station->m_initialized = false;
471
472 // Variables specific to HT station
473 station->m_sampleGroup = 0;
474 station->m_numSamplesSlow = 0;
475 station->m_sampleCount = 16;
476 station->m_sampleWait = 0;
477 station->m_sampleTries = 4;
478
479 station->m_avgAmpduLen = 1;
480 station->m_ampduLen = 0;
481 station->m_ampduPacketCount = 0;
482
483 // Use the variable in the station to indicate whether the device supports HT.
484 // When correct information available it will be checked.
485 station->m_isHt = static_cast<bool>(GetPhy()->GetDevice()->GetHtConfiguration());
486
487 return station;
488}
489
490void
492{
493 NS_LOG_FUNCTION(this << station);
494 // Note: we appear to be doing late initialization of the table
495 // to make sure that the set of supported rates has been initialized
496 // before we perform our own initialization.
497 if (!station->m_initialized)
498 {
499 /**
500 * Check if the station supports HT.
501 * Assume that if the device do not supports HT then
502 * the station will not support HT either.
503 * We save from using another check and variable.
504 */
506 {
507 NS_LOG_INFO("non-HT station " << station);
508 station->m_isHt = false;
509 // We will use non-HT minstrel for this station. Initialize the manager.
510 m_legacyManager->SetAttribute("UpdateStatistics", TimeValue(m_legacyUpdateStats));
511 m_legacyManager->SetAttribute("LookAroundRate", UintegerValue(m_lookAroundRate));
512 m_legacyManager->SetAttribute("EWMA", UintegerValue(m_ewmaLevel));
513 m_legacyManager->SetAttribute("SampleColumn", UintegerValue(m_nSampleCol));
514 m_legacyManager->SetAttribute("PacketLength", UintegerValue(m_frameLength));
515 m_legacyManager->SetAttribute("PrintStats", BooleanValue(m_printStats));
516 m_legacyManager->CheckInit(station);
517 }
518 else
519 {
520 NS_LOG_DEBUG("HT station " << station);
521 station->m_isHt = true;
522 station->m_nModes = GetNMcsSupported(station);
523 station->m_minstrelTable = MinstrelRate(station->m_nModes);
524 station->m_sampleTable = SampleRate(m_numRates, std::vector<uint8_t>(m_nSampleCol));
525 InitSampleTable(station);
526 RateInit(station);
527 station->m_initialized = true;
528 }
529 }
530}
531
532void
534{
535 NS_LOG_FUNCTION(this << st);
537 "DoReportRxOk m_txrate=" << static_cast<MinstrelHtWifiRemoteStation*>(st)->m_txrate);
538}
539
540void
542{
543 NS_LOG_FUNCTION(this << st);
544 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
545 CheckInit(station);
546 if (!station->m_initialized)
547 {
548 return;
549 }
550 NS_LOG_DEBUG("DoReportRtsFailed m_txrate = " << station->m_txrate);
551 station->m_shortRetry++;
552}
553
554void
556 double ctsSnr,
557 WifiMode ctsMode,
558 double rtsSnr)
559{
560 NS_LOG_FUNCTION(this << st);
561}
562
563void
565{
566 NS_LOG_FUNCTION(this << st);
567 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
568 NS_LOG_DEBUG("Final RTS failed");
569 CheckInit(station);
570 if (!station->m_initialized)
571 {
572 return;
573 }
574 UpdateRetry(station);
575}
576
577void
579{
580 NS_LOG_FUNCTION(this << st);
581 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
582
583 CheckInit(station);
584 if (!station->m_initialized)
585 {
586 return;
587 }
588
589 NS_LOG_DEBUG("DoReportDataFailed " << station << "\t rate " << station->m_txrate
590 << "\tlongRetry \t" << station->m_longRetry);
591
592 if (!station->m_isHt)
593 {
594 m_legacyManager->UpdateRate(station);
595 }
596 else if (station->m_longRetry < CountRetries(station))
597 {
598 const auto rateId = GetRateId(station->m_txrate);
599 const auto groupId = GetGroupId(station->m_txrate);
600 station->m_groupsTable[groupId]
601 .m_ratesTable[rateId]
602 .numRateAttempt++; // Increment the attempts counter for the rate used.
603 UpdateRate(station);
604 }
605}
606
607void
609 double ackSnr,
610 WifiMode ackMode,
611 double dataSnr,
612 MHz_u dataChannelWidth,
613 uint8_t dataNss)
614{
615 NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << dataNss);
616 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
617
618 CheckInit(station);
619 if (!station->m_initialized)
620 {
621 return;
622 }
623
624 if (!station->m_isHt)
625 {
626 NS_LOG_DEBUG("DoReportDataOk m_txrate = "
627 << station->m_txrate
628 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
629 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
630 << " (before update).");
631
632 station->m_minstrelTable[station->m_txrate].numRateSuccess++;
633 station->m_minstrelTable[station->m_txrate].numRateAttempt++;
634
635 m_legacyManager->UpdatePacketCounters(station);
636
637 NS_LOG_DEBUG("DoReportDataOk m_txrate = "
638 << station->m_txrate
639 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
640 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
641 << " (after update).");
642
643 UpdateRetry(station);
644 m_legacyManager->UpdateStats(station);
645
646 if (station->m_nModes >= 1)
647 {
648 station->m_txrate = m_legacyManager->FindRate(station);
649 }
650 }
651 else
652 {
653 const auto rateId = GetRateId(station->m_txrate);
654 const auto groupId = GetGroupId(station->m_txrate);
655
657 "DoReportDataOk m_txrate = "
658 << station->m_txrate
659 << ", attempt = " << station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt
660 << ", success = " << station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess
661 << " (before update).");
662
663 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
664 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
665
666 UpdatePacketCounters(station, 1, 0);
667
669 "DoReportDataOk m_txrate = "
670 << station->m_txrate
671 << ", attempt = " << station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt
672 << ", success = " << station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess
673 << " (after update).");
674
675 station->m_isSampling = false;
676 station->m_sampleDeferred = false;
677
678 UpdateRetry(station);
679 if (Simulator::Now() >= station->m_nextStatsUpdate)
680 {
681 UpdateStats(station);
682 }
683
684 if (station->m_nModes >= 1)
685 {
686 station->m_txrate = FindRate(station);
687 }
688 }
689
690 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
691}
692
693void
695{
696 NS_LOG_FUNCTION(this << st);
697 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
698
699 CheckInit(station);
700 if (!station->m_initialized)
701 {
702 return;
703 }
704
705 NS_LOG_DEBUG("DoReportFinalDataFailed - TxRate=" << station->m_txrate);
706
707 if (!station->m_isHt)
708 {
709 m_legacyManager->UpdatePacketCounters(station);
710
711 UpdateRetry(station);
712
713 m_legacyManager->UpdateStats(station);
714 if (station->m_nModes >= 1)
715 {
716 station->m_txrate = m_legacyManager->FindRate(station);
717 }
718 }
719 else
720 {
721 UpdatePacketCounters(station, 0, 1);
722
723 station->m_isSampling = false;
724 station->m_sampleDeferred = false;
725
726 UpdateRetry(station);
727 if (Simulator::Now() >= station->m_nextStatsUpdate)
728 {
729 UpdateStats(station);
730 }
731
732 if (station->m_nModes >= 1)
733 {
734 station->m_txrate = FindRate(station);
735 }
736 }
737 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
738}
739
740void
742 uint16_t nSuccessfulMpdus,
743 uint16_t nFailedMpdus,
744 double rxSnr,
745 double dataSnr,
746 MHz_u dataChannelWidth,
747 uint8_t dataNss)
748{
749 NS_LOG_FUNCTION(this << st << nSuccessfulMpdus << nFailedMpdus << rxSnr << dataSnr
750 << dataChannelWidth << dataNss);
751 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
752
753 CheckInit(station);
754 if (!station->m_initialized)
755 {
756 return;
757 }
758
759 NS_ASSERT_MSG(station->m_isHt, "A-MPDU Tx Status called but this is a non-HT STA.");
760
761 NS_LOG_DEBUG("DoReportAmpduTxStatus. TxRate=" << station->m_txrate
762 << " SuccMpdus=" << nSuccessfulMpdus
763 << " FailedMpdus=" << nFailedMpdus);
764
765 station->m_ampduPacketCount++;
766 station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
767
768 UpdatePacketCounters(station, nSuccessfulMpdus, nFailedMpdus);
769
770 const auto rateId = GetRateId(station->m_txrate);
771 const auto groupId = GetGroupId(station->m_txrate);
772 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
773 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt +=
774 nSuccessfulMpdus + nFailedMpdus;
775
776 if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries(station))
777 {
778 // We do not receive a BlockAck. The entire AMPDU fail.
779 UpdateRate(station);
780 }
781 else
782 {
783 station->m_isSampling = false;
784 station->m_sampleDeferred = false;
785
786 UpdateRetry(station);
787 if (Simulator::Now() >= station->m_nextStatsUpdate)
788 {
789 UpdateStats(station);
790 }
791
792 if (station->m_nModes >= 1)
793 {
794 station->m_txrate = FindRate(station);
795 }
796 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
797 }
798}
799
800void
802{
803 NS_LOG_FUNCTION(this << station);
804
805 /**
806 * Retry Chain table is implemented here.
807 *
808 * FIXME
809 * Currently, NS3 does not retransmit an entire A-MPDU when BACK is missing
810 * but retransmits each MPDU until MPDUs lifetime expires (or a BACK is received).
811 * Then, there is no way to control A-MPDU retries (no call to NeedDataRetransmission).
812 * So, it is possible that the A-MPDU keeps retrying after longRetry reaches its limit.
813 *
814 *
815 * Try | LOOKAROUND RATE | NORMAL RATE
816 * -------------------------------------------------------
817 * 1 | Random rate | Best throughput
818 * 2 | Next best throughput | Next best throughput
819 * 3 | Best probability | Best probability
820 *
821 * Note: For clarity, multiple blocks of if's and else's are used
822 * Following implementation in Linux, in MinstrelHT lowest base rate is not used.
823 * Explanation can be found here: http://marc.info/?l=linux-wireless&m=144602778611966&w=2
824 */
825
826 CheckInit(station);
827 if (!station->m_initialized)
828 {
829 return;
830 }
831 station->m_longRetry++;
832
833 /**
834 * Get the IDs for all rates.
835 */
836 const auto maxTpRateId = GetRateId(station->m_maxTpRate);
837 const auto maxTpGroupId = GetGroupId(station->m_maxTpRate);
838 const auto maxTp2RateId = GetRateId(station->m_maxTpRate2);
839 const auto maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
840 const auto maxProbRateId = GetRateId(station->m_maxProbRate);
841 const auto maxProbGroupId = GetGroupId(station->m_maxProbRate);
842
843 /// For normal rate, we're not currently sampling random rates.
844 if (!station->m_isSampling)
845 {
846 /// Use best throughput rate.
847 if (station->m_longRetry <
848 station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
849 {
850 NS_LOG_DEBUG("Not Sampling; use the same rate again");
851 station->m_txrate = station->m_maxTpRate; //!< There are still a few retries.
852 }
853
854 /// Use second best throughput rate.
855 else if (station->m_longRetry <
856 (station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
857 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
858 {
859 NS_LOG_DEBUG("Not Sampling; use the Max TP2");
860 station->m_txrate = station->m_maxTpRate2;
861 }
862
863 /// Use best probability rate.
864 else if (station->m_longRetry <=
865 (station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
866 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
867 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
868 {
869 NS_LOG_DEBUG("Not Sampling; use Max Prob");
870 station->m_txrate = station->m_maxProbRate;
871 }
872 else
873 {
874 NS_FATAL_ERROR("Max retries reached and m_longRetry not cleared properly. longRetry= "
875 << station->m_longRetry);
876 }
877 }
878
879 /// We're currently sampling random rates.
880 else
881 {
882 /// Sample rate is used only once
883 /// Use the best rate.
884 if (station->m_longRetry <
885 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
886 {
887 NS_LOG_DEBUG("Sampling use the MaxTP rate");
888 station->m_txrate = station->m_maxTpRate2;
889 }
890
891 /// Use the best probability rate.
892 else if (station->m_longRetry <=
893 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
894 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
895 {
896 NS_LOG_DEBUG("Sampling use the MaxProb rate");
897 station->m_txrate = station->m_maxProbRate;
898 }
899 else
900 {
901 NS_FATAL_ERROR("Max retries reached and m_longRetry not cleared properly. longRetry= "
902 << station->m_longRetry);
903 }
904 }
905 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
906}
907
908void
910{
911 NS_LOG_FUNCTION(this << station);
912 station->m_shortRetry = 0;
913 station->m_longRetry = 0;
914}
915
916void
918 uint16_t nSuccessfulMpdus,
919 uint16_t nFailedMpdus)
920{
921 NS_LOG_FUNCTION(this << station << nSuccessfulMpdus << nFailedMpdus);
922
923 station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
924 if (station->m_isSampling)
925 {
926 station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
927 }
928 if (station->m_totalPacketsCount == ~0)
929 {
930 station->m_samplePacketsCount = 0;
931 station->m_totalPacketsCount = 0;
932 }
933
934 if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
935 {
936 station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
937 station->m_sampleTries = 1;
938 station->m_sampleCount--;
939 }
940}
941
942uint16_t
944{
945 NS_LOG_FUNCTION(this << txRate << allowedWidth);
946
947 auto groupId = GetGroupId(txRate);
948 McsGroup group = m_minstrelGroups[groupId];
949
950 if (group.chWidth <= allowedWidth)
951 {
952 NS_LOG_DEBUG("Channel width is not greater than allowed width, nothing to do");
953 return txRate;
954 }
955
956 NS_ASSERT(GetPhy()->GetDevice()->GetHtConfiguration() != nullptr);
957 NS_ASSERT(static_cast<uint16_t>(group.chWidth) % 20 == 0);
958 // try halving the channel width and check if the group with the same number of
959 // streams and same GI is supported, until either a supported group is found or
960 // the width becomes lower than 20 MHz
961 auto width = group.chWidth / 2;
962
963 while (width >= MHz_u{20})
964 {
965 if (width > allowedWidth)
966 {
967 width /= 2;
968 continue;
969 }
970 groupId = GetGroupIdForType(group.type, group.streams, group.gi, width);
971 group = m_minstrelGroups[groupId];
972 if (group.isSupported)
973 {
974 break;
975 }
976 width /= 2;
977 }
978
979 NS_ABORT_MSG_IF(width < MHz_u{20}, "No rate compatible with the allowed width found");
980
981 return GetIndex(groupId, GetRateId(txRate));
982}
983
986{
987 NS_LOG_FUNCTION(this << st << allowedWidth);
988 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
989
990 if (!station->m_initialized)
991 {
992 CheckInit(station);
993 }
994
995 if (!station->m_isHt)
996 {
997 WifiTxVector vector = m_legacyManager->GetDataTxVector(station);
998 uint64_t dataRate = vector.GetMode().GetDataRate(vector);
999 if (m_currentRate != dataRate && !station->m_isSampling)
1000 {
1001 NS_LOG_DEBUG("New datarate: " << dataRate);
1002 m_currentRate = dataRate;
1003 }
1004 return vector;
1005 }
1006
1007 station->m_txrate = UpdateRateAfterAllowedWidth(station->m_txrate, allowedWidth);
1008 NS_LOG_DEBUG("DoGetDataMode m_txrate= " << station->m_txrate);
1009
1010 const auto rateId = GetRateId(station->m_txrate);
1011 const auto groupId = GetGroupId(station->m_txrate);
1012 const auto mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
1013
1014 NS_LOG_DEBUG("DoGetDataMode rateId= " << rateId << " groupId= " << groupId
1015 << " mode= " << GetMcsSupported(station, mcsIndex));
1016
1017 McsGroup group = m_minstrelGroups[groupId];
1018
1019 // Check consistency of rate selected.
1020 if (((group.type >= WIFI_MINSTREL_GROUP_HE) && (group.gi < GetGuardInterval(station))) ||
1021 ((group.type < WIFI_MINSTREL_GROUP_HE) && (group.gi.GetNanoSeconds() == 400) &&
1022 !GetShortGuardIntervalSupported(station)) ||
1023 (group.chWidth > GetChannelWidth(station)) ||
1024 (group.streams > GetNumberOfSupportedStreams(station)))
1025 {
1026 NS_FATAL_ERROR("Inconsistent group selected. Group: ("
1027 << +group.streams << "," << group.gi << "," << group.chWidth << ")"
1028 << " Station capabilities: (" << GetNumberOfSupportedStreams(station) << ","
1029 << ((group.type >= WIFI_MINSTREL_GROUP_HE)
1030 ? GetGuardInterval(station)
1031 : NanoSeconds(GetShortGuardIntervalSupported(station) ? 400 : 800))
1032 << "," << GetChannelWidth(station) << ")");
1033 }
1034 WifiMode mode = GetMcsSupported(station, mcsIndex);
1035 WifiTxVector txVector{
1036 mode,
1039 group.gi,
1041 group.streams,
1042 GetNess(station),
1043 GetPhy()->GetTxBandwidth(mode, group.chWidth),
1044 GetAggregation(station) && !station->m_isSampling};
1045 uint64_t dataRate = mode.GetDataRate(txVector);
1046 if (m_currentRate != dataRate && !station->m_isSampling)
1047 {
1048 NS_LOG_DEBUG("New datarate: " << dataRate);
1049 m_currentRate = dataRate;
1050 }
1051 return txVector;
1052}
1053
1056{
1057 NS_LOG_FUNCTION(this << st);
1058 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1059
1060 if (!station->m_initialized)
1061 {
1062 CheckInit(station);
1063 }
1064
1065 if (!station->m_isHt)
1066 {
1067 return m_legacyManager->GetRtsTxVector(station);
1068 }
1069 else
1070 {
1071 NS_LOG_DEBUG("DoGetRtsMode m_txrate=" << station->m_txrate);
1072
1073 /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
1074 * When supported, decision of using HT has to follow rules in Section 9.7.6 from
1075 * 802.11-2012. From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is
1076 * carried in a non-HT PPDU shall be transmitted by the STA using a rate no higher than the
1077 * highest rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
1078 * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
1079 * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
1080 * these conditions, the control frame shall be transmitted at a rate no higher than the
1081 * highest mandatory rate of the attached PHY that is less than or equal to the rate
1082 * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
1083 * directed to the same receiving STA."
1084 */
1085
1086 // As we are in Minstrel HT, assume the last rate was an HT rate.
1087 const auto rateId = GetRateId(station->m_txrate);
1088 const auto groupId = GetGroupId(station->m_txrate);
1089 const auto mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
1090
1091 const auto lastRate = GetMcsSupported(station, mcsIndex);
1092 const auto lastDataRate = lastRate.GetNonHtReferenceRate();
1093 const auto nBasicRates = GetNBasicModes();
1094
1095 WifiMode rtsRate;
1096 bool rateFound = false;
1097
1098 for (uint8_t i = 0; i < nBasicRates; i++)
1099 {
1100 const auto rate = GetBasicMode(i).GetDataRate(MHz_u{20});
1101 if (rate <= lastDataRate)
1102 {
1103 rtsRate = GetBasicMode(i);
1104 rateFound = true;
1105 }
1106 }
1107
1108 if (!rateFound)
1109 {
1110 for (const auto& mode : GetPhy()->GetModeList())
1111 {
1112 const auto rate = mode.GetDataRate(MHz_u{20});
1113 if (rate <= lastDataRate)
1114 {
1115 rtsRate = mode;
1116 rateFound = true;
1117 }
1118 }
1119 }
1120
1121 NS_ASSERT(rateFound);
1122
1123 return WifiTxVector(
1124 rtsRate,
1127 NanoSeconds(800),
1128 1,
1129 1,
1130 0,
1131 GetPhy()->GetTxBandwidth(rtsRate, GetChannelWidth(station)),
1132 GetAggregation(station));
1133 }
1134}
1135
1136std::list<Ptr<WifiMpdu>>
1138{
1139 NS_LOG_FUNCTION(this << *psdu);
1140
1141 std::list<Ptr<WifiMpdu>> mpdusToDrop;
1142
1143 for (const auto& mpdu : *PeekPointer(psdu))
1144 {
1145 if (!DoNeedRetransmission(station,
1146 mpdu->GetPacket(),
1147 (mpdu->GetRetryCount() < GetMac()->GetFrameRetryLimit())))
1148 {
1149 // this MPDU needs to be dropped
1150 mpdusToDrop.push_back(mpdu);
1151 }
1152 }
1153
1154 return mpdusToDrop;
1155}
1156
1157bool
1159 Ptr<const Packet> packet,
1160 bool normally)
1161{
1162 NS_LOG_FUNCTION(this << st << packet << normally);
1163
1164 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1165
1166 CheckInit(station);
1167 if (!station->m_initialized)
1168 {
1169 return normally;
1170 }
1171
1172 uint32_t maxRetries;
1173
1174 if (!station->m_isHt)
1175 {
1176 maxRetries = m_legacyManager->CountRetries(station);
1177 }
1178 else
1179 {
1180 maxRetries = CountRetries(station);
1181 }
1182
1183 if (station->m_longRetry >= maxRetries)
1184 {
1185 NS_LOG_DEBUG("No re-transmission allowed. Retries: " << station->m_longRetry
1186 << " Max retries: " << maxRetries);
1187 return false;
1188 }
1189 else
1190 {
1191 NS_LOG_DEBUG("Re-transmit. Retries: " << station->m_longRetry
1192 << " Max retries: " << maxRetries);
1193 return true;
1194 }
1195}
1196
1199{
1200 const auto maxProbRateId = GetRateId(station->m_maxProbRate);
1201 const auto maxProbGroupId = GetGroupId(station->m_maxProbRate);
1202 const auto maxTpRateId = GetRateId(station->m_maxTpRate);
1203 const auto maxTpGroupId = GetGroupId(station->m_maxTpRate);
1204 const auto maxTp2RateId = GetRateId(station->m_maxTpRate2);
1205 const auto maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1206
1207 if (!station->m_isSampling)
1208 {
1209 return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
1210 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
1211 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1212 }
1213 else
1214 {
1215 return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1216 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1217 }
1218}
1219
1220uint16_t
1222{
1223 NS_LOG_FUNCTION(this << station);
1224 const auto sampleGroup = station->m_sampleGroup;
1225 const auto index = station->m_groupsTable[sampleGroup].m_index;
1226 const auto col = station->m_groupsTable[sampleGroup].m_col;
1227 const auto sampleIndex = station->m_sampleTable[index][col];
1228 const auto rateIndex = GetIndex(sampleGroup, sampleIndex);
1229 NS_LOG_DEBUG("Next Sample is " << rateIndex);
1230 SetNextSample(station); // Calculate the next sample rate.
1231 return rateIndex;
1232}
1233
1234void
1236{
1237 NS_LOG_FUNCTION(this << station);
1238 do
1239 {
1240 station->m_sampleGroup++;
1241 station->m_sampleGroup %= m_numGroups;
1242 } while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1243
1244 station->m_groupsTable[station->m_sampleGroup].m_index++;
1245
1246 const auto sampleGroup = station->m_sampleGroup;
1247 auto index = station->m_groupsTable[station->m_sampleGroup].m_index;
1248 auto col = station->m_groupsTable[sampleGroup].m_col;
1249
1250 if (index >= m_numRates)
1251 {
1252 station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1253 station->m_groupsTable[station->m_sampleGroup].m_col++;
1254 if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1255 {
1256 station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1257 }
1258 index = station->m_groupsTable[station->m_sampleGroup].m_index;
1259 col = station->m_groupsTable[sampleGroup].m_col;
1260 }
1261 NS_LOG_DEBUG("New sample set: group= " << +sampleGroup
1262 << " index= " << +station->m_sampleTable[index][col]);
1263}
1264
1265uint16_t
1267{
1268 NS_LOG_FUNCTION(this << station);
1269 NS_LOG_DEBUG("FindRate packet=" << station->m_totalPacketsCount);
1270
1271 if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1272 {
1273 return station->m_maxTpRate;
1274 }
1275
1276 // If we have waited enough, then sample.
1277 if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1278 {
1279 // SAMPLING
1280 NS_LOG_DEBUG("Obtaining a sampling rate");
1281 /// Now go through the table and find an index rate.
1282 const auto sampleIdx = GetNextSample(station);
1283 NS_LOG_DEBUG("Sampling rate = " << sampleIdx);
1284
1285 // Evaluate if the sampling rate selected should be used.
1286 const auto sampleGroupId = GetGroupId(sampleIdx);
1287 const auto sampleRateId = GetRateId(sampleIdx);
1288
1289 // If the rate selected is not supported, then don't sample.
1290 if (station->m_groupsTable[sampleGroupId].m_supported &&
1291 station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1292 {
1293 /**
1294 * Sampling might add some overhead to the frame.
1295 * Hence, don't use sampling for the currently used rates.
1296 *
1297 * Also do not sample if the probability is already higher than 95%
1298 * to avoid wasting airtime.
1299 */
1300 const auto sampleRateInfo =
1301 station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1302
1303 NS_LOG_DEBUG("Use sample rate? MaxTpRate= "
1304 << station->m_maxTpRate << " CurrentRate= " << station->m_txrate
1305 << " SampleRate= " << sampleIdx
1306 << " SampleProb= " << sampleRateInfo.ewmaProb);
1307
1308 if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2 &&
1309 sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1310 {
1311 /**
1312 * Make sure that lower rates get sampled only occasionally,
1313 * if the link is working perfectly.
1314 */
1315
1316 const auto maxTpGroupId = GetGroupId(station->m_maxTpRate);
1317 const auto maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1318 const auto maxTp2RateId = GetRateId(station->m_maxTpRate2);
1319 const auto maxProbGroupId = GetGroupId(station->m_maxProbRate);
1320 const auto maxProbRateId = GetRateId(station->m_maxProbRate);
1321
1322 const auto maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1323 const auto sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1324
1325 const auto sampleDuration = sampleRateInfo.perfectTxTime;
1326 const auto maxTp2Duration =
1327 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1328 const auto maxProbDuration = station->m_groupsTable[maxProbGroupId]
1329 .m_ratesTable[maxProbRateId]
1330 .perfectTxTime;
1331
1332 NS_LOG_DEBUG("Use sample rate? SampleDuration= "
1333 << sampleDuration << " maxTp2Duration= " << maxTp2Duration
1334 << " maxProbDuration= " << maxProbDuration << " sampleStreams= "
1335 << +sampleStreams << " maxTpStreams= " << +maxTpStreams);
1336 if (sampleDuration < maxTp2Duration ||
1337 (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1338 {
1339 /// Set flag that we are currently sampling.
1340 station->m_isSampling = true;
1341
1342 /// set the rate that we're currently sampling
1343 station->m_sampleRate = sampleIdx;
1344
1345 NS_LOG_DEBUG("FindRate sampleRate=" << sampleIdx);
1346 station->m_sampleTries--;
1347 return sampleIdx;
1348 }
1349 else
1350 {
1351 station->m_numSamplesSlow++;
1352 if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1353 {
1354 /// Set flag that we are currently sampling.
1355 station->m_isSampling = true;
1356
1357 /// set the rate that we're currently sampling
1358 station->m_sampleRate = sampleIdx;
1359
1360 NS_LOG_DEBUG("FindRate sampleRate=" << sampleIdx);
1361 station->m_sampleTries--;
1362 return sampleIdx;
1363 }
1364 }
1365 }
1366 }
1367 }
1368 if (station->m_sampleWait > 0)
1369 {
1370 station->m_sampleWait--;
1371 }
1372
1373 /// Continue using the best rate.
1374
1375 NS_LOG_DEBUG("FindRate maxTpRrate=" << station->m_maxTpRate);
1376 return station->m_maxTpRate;
1377}
1378
1379void
1381{
1382 NS_LOG_FUNCTION(this << station);
1383
1385
1386 station->m_numSamplesSlow = 0;
1387 station->m_sampleCount = 0;
1388
1389 double tempProb;
1390
1391 if (station->m_ampduPacketCount > 0)
1392 {
1393 uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1394 station->m_avgAmpduLen =
1395 (newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel)) / 100;
1396 station->m_ampduLen = 0;
1397 station->m_ampduPacketCount = 0;
1398 }
1399
1400 /* Initialize global rate indexes */
1401 station->m_maxTpRate = GetLowestIndex(station);
1402 station->m_maxTpRate2 = GetLowestIndex(station);
1403 station->m_maxProbRate = GetLowestIndex(station);
1404
1405 /// Update throughput and EWMA for each rate inside each group.
1406 for (std::size_t j = 0; j < m_numGroups; j++)
1407 {
1408 if (station->m_groupsTable[j].m_supported)
1409 {
1410 station->m_sampleCount++;
1411
1412 /* (re)Initialize group rate indexes */
1413 station->m_groupsTable[j].m_maxTpRate = GetLowestIndex(station, j);
1414 station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex(station, j);
1415 station->m_groupsTable[j].m_maxProbRate = GetLowestIndex(station, j);
1416
1417 for (uint8_t i = 0; i < m_numRates; i++)
1418 {
1419 if (station->m_groupsTable[j].m_ratesTable[i].supported)
1420 {
1421 station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1422
1424 +i << " "
1425 << GetMcsSupported(station,
1426 station->m_groupsTable[j].m_ratesTable[i].mcsIndex)
1427 << "\t attempt="
1428 << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt
1429 << "\t success="
1430 << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1431
1432 /// If we've attempted something.
1433 if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1434 {
1435 station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1436 /**
1437 * Calculate the probability of success.
1438 * Assume probability scales from 0 to 100.
1439 */
1440 tempProb =
1441 (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) /
1442 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1443
1444 /// Bookkeeping.
1445 station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1446
1447 if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1448 {
1449 station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1450 }
1451 else
1452 {
1453 station->m_groupsTable[j].m_ratesTable[i].ewmsdProb =
1454 CalculateEwmsd(station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1455 tempProb,
1456 station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1457 m_ewmaLevel);
1458 /// EWMA probability
1459 tempProb =
1460 (tempProb * (100 - m_ewmaLevel) +
1461 station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) /
1462 100;
1463 station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1464 }
1465
1466 station->m_groupsTable[j].m_ratesTable[i].throughput =
1467 CalculateThroughput(station, j, i, tempProb);
1468
1469 station->m_groupsTable[j].m_ratesTable[i].successHist +=
1470 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1471 station->m_groupsTable[j].m_ratesTable[i].attemptHist +=
1472 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1473 }
1474 else
1475 {
1476 station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1477 }
1478
1479 /// Bookkeeping.
1480 station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess =
1481 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1482 station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt =
1483 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1484 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1485 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1486
1487 if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1488 {
1489 SetBestStationThRates(station, GetIndex(j, i));
1490 SetBestProbabilityRate(station, GetIndex(j, i));
1491 }
1492 }
1493 }
1494 }
1495 }
1496
1497 // Try to sample all available rates during each interval.
1498 station->m_sampleCount *= 8;
1499
1500 // Recalculate retries for the rates selected.
1501 CalculateRetransmits(station, station->m_maxTpRate);
1502 CalculateRetransmits(station, station->m_maxTpRate2);
1503 CalculateRetransmits(station, station->m_maxProbRate);
1504
1505 NS_LOG_DEBUG("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2
1506 << "\nmax prob=" << station->m_maxProbRate);
1507 if (m_printStats)
1508 {
1509 PrintTable(station);
1510 }
1511}
1512
1513double
1515 std::size_t groupId,
1516 uint8_t rateId,
1517 double ewmaProb)
1518{
1519 /**
1520 * Calculating throughput.
1521 * Do not account throughput if probability of success is below 10%
1522 * (as done in minstrel_ht linux implementation).
1523 */
1524 if (ewmaProb < 10)
1525 {
1526 return 0;
1527 }
1528 else
1529 {
1530 /**
1531 * For the throughput calculation, limit the probability value to 90% to
1532 * account for collision related packet error rate fluctuation.
1533 */
1534 const auto txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1535 if (ewmaProb > 90)
1536 {
1537 return 90 / txTime.GetSeconds();
1538 }
1539 else
1540 {
1541 return ewmaProb / txTime.GetSeconds();
1542 }
1543 }
1544}
1545
1546void
1548{
1549 GroupInfo* group;
1550 MinstrelHtRateInfo rate;
1551 std::size_t tmpGroupId;
1552 uint8_t tmpRateId;
1553 double tmpTh;
1554 double tmpProb;
1555 std::size_t groupId;
1556 uint8_t rateId;
1557 double currentTh;
1558 // maximum group probability (GP) variables
1559 std::size_t maxGPGroupId;
1560 uint8_t maxGPRateId;
1561 double maxGPTh;
1562
1563 groupId = GetGroupId(index);
1564 rateId = GetRateId(index);
1565 group = &station->m_groupsTable[groupId];
1566 rate = group->m_ratesTable[rateId];
1567
1568 tmpGroupId = GetGroupId(station->m_maxProbRate);
1569 tmpRateId = GetRateId(station->m_maxProbRate);
1570 tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1571 tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1572
1573 if (rate.ewmaProb > 75)
1574 {
1575 currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1576 if (currentTh > tmpTh)
1577 {
1578 station->m_maxProbRate = index;
1579 }
1580
1581 maxGPGroupId = GetGroupId(group->m_maxProbRate);
1582 maxGPRateId = GetRateId(group->m_maxProbRate);
1583 maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1584
1585 if (currentTh > maxGPTh)
1586 {
1587 group->m_maxProbRate = index;
1588 }
1589 }
1590 else
1591 {
1592 if (rate.ewmaProb > tmpProb)
1593 {
1594 station->m_maxProbRate = index;
1595 }
1596 maxGPRateId = GetRateId(group->m_maxProbRate);
1597 if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1598 {
1599 group->m_maxProbRate = index;
1600 }
1601 }
1602}
1603
1604/*
1605 * Find & sort topmost throughput rates
1606 *
1607 * If multiple rates provide equal throughput the sorting is based on their
1608 * current success probability. Higher success probability is preferred among
1609 * MCS groups.
1610 */
1611void
1613{
1614 std::size_t groupId;
1615 uint8_t rateId;
1616 double th;
1617 double prob;
1618 std::size_t maxTpGroupId;
1619 uint8_t maxTpRateId;
1620 std::size_t maxTp2GroupId;
1621 uint8_t maxTp2RateId;
1622 double maxTpTh;
1623 double maxTpProb;
1624 double maxTp2Th;
1625 double maxTp2Prob;
1626
1627 groupId = GetGroupId(index);
1628 rateId = GetRateId(index);
1629 prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1630 th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1631
1632 maxTpGroupId = GetGroupId(station->m_maxTpRate);
1633 maxTpRateId = GetRateId(station->m_maxTpRate);
1634 maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1635 maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1636
1637 maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1638 maxTp2RateId = GetRateId(station->m_maxTpRate2);
1639 maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1640 maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1641
1642 if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1643 {
1644 station->m_maxTpRate2 = station->m_maxTpRate;
1645 station->m_maxTpRate = index;
1646 }
1647 else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1648 {
1649 station->m_maxTpRate2 = index;
1650 }
1651
1652 // Find best rates per group
1653
1654 GroupInfo* group = &station->m_groupsTable[groupId];
1655 maxTpGroupId = GetGroupId(group->m_maxTpRate);
1656 maxTpRateId = GetRateId(group->m_maxTpRate);
1657 maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1658 maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1659
1660 maxTp2GroupId = GetGroupId(group->m_maxTpRate2);
1661 maxTp2RateId = GetRateId(group->m_maxTpRate2);
1662 maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1663 maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1664
1665 if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1666 {
1667 group->m_maxTpRate2 = group->m_maxTpRate;
1668 group->m_maxTpRate = index;
1669 }
1670 else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1671 {
1672 group->m_maxTpRate2 = index;
1673 }
1674}
1675
1676void
1678{
1679 NS_LOG_FUNCTION(this << station);
1680
1682
1683 /**
1684 * Initialize groups supported by the receiver.
1685 */
1686 NS_LOG_DEBUG("Supported groups by station:");
1687 bool noSupportedGroupFound = true;
1688 for (std::size_t groupId = 0; groupId < m_numGroups; groupId++)
1689 {
1690 if (m_minstrelGroups[groupId].isSupported)
1691 {
1692 station->m_groupsTable[groupId].m_supported = false;
1693
1694 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_EHT) &&
1695 !GetEhtSupported(station))
1696 {
1697 // It is a EHT group but the receiver does not support EHT: skip
1698 continue;
1699 }
1700 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1701 !GetHeSupported(station))
1702 {
1703 // It is a HE group but the receiver does not support HE: skip
1704 continue;
1705 }
1706 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_VHT) &&
1707 !GetVhtSupported(station))
1708 {
1709 // It is a VHT group but the receiver does not support VHT: skip
1710 continue;
1711 }
1712 if ((m_minstrelGroups[groupId].type != WIFI_MINSTREL_GROUP_EHT) &&
1714 {
1715 // It is not a EHT group and the receiver supports EHT: skip since
1716 // UseLatestAmendmentOnly attribute is enabled
1717 continue;
1718 }
1719 if (!GetEhtSupported(station) &&
1720 (m_minstrelGroups[groupId].type != WIFI_MINSTREL_GROUP_HE) &&
1722 {
1723 // It is not a HE group and the receiver supports HE (but not EHT): skip since
1724 // UseLatestAmendmentOnly attribute is enabled
1725 continue;
1726 }
1727 if (!GetHeSupported(station) &&
1728 (m_minstrelGroups[groupId].type != WIFI_MINSTREL_GROUP_VHT) &&
1730 {
1731 // It is not a VHT group and the receiver supports VHT (but not HE): skip since
1732 // UseLatestAmendmentOnly attribute is enabled
1733 continue;
1734 }
1735 if ((m_minstrelGroups[groupId].type < WIFI_MINSTREL_GROUP_HE) &&
1736 (m_minstrelGroups[groupId].gi.GetNanoSeconds() == 400) &&
1738 {
1739 // It is a SGI group but the receiver does not support SGI: skip
1740 continue;
1741 }
1742 if ((m_minstrelGroups[groupId].type >= WIFI_MINSTREL_GROUP_HE) &&
1743 (m_minstrelGroups[groupId].gi < GetGuardInterval(station)))
1744 {
1745 // The receiver does not support the GI: skip
1746 continue;
1747 }
1748 if (GetChannelWidth(station) < m_minstrelGroups[groupId].chWidth)
1749 {
1750 // The receiver does not support the channel width: skip
1751 continue;
1752 }
1753 if (GetNumberOfSupportedStreams(station) < m_minstrelGroups[groupId].streams)
1754 {
1755 // The receiver does not support the number of spatial streams: skip
1756 continue;
1757 }
1758
1759 NS_LOG_DEBUG("Group: " << groupId << " type: " << m_minstrelGroups[groupId].type
1760 << " streams: " << +m_minstrelGroups[groupId].streams
1761 << " GI: " << m_minstrelGroups[groupId].gi
1762 << " width: " << m_minstrelGroups[groupId].chWidth);
1763
1764 noSupportedGroupFound = false;
1765 station->m_groupsTable[groupId].m_supported = true;
1766 station->m_groupsTable[groupId].m_col = 0;
1767 station->m_groupsTable[groupId].m_index = 0;
1768
1769 station->m_groupsTable[groupId].m_ratesTable =
1770 MinstrelHtRate(m_numRates); /// Create the rate list for the group.
1771 for (uint8_t i = 0; i < m_numRates; i++)
1772 {
1773 station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1774 }
1775
1776 // Initialize all modes supported by the remote station that belong to the current
1777 // group.
1778 for (uint8_t i = 0; i < station->m_nModes; i++)
1779 {
1780 if (const auto mode = GetMcsSupported(station, i);
1781 ShouldAddMcsToGroup(mode, groupId))
1782 {
1783 NS_LOG_DEBUG("Mode " << +i << ": " << mode);
1784
1785 /// Use the McsValue as the index in the rate table.
1786 /// This way, MCSs not supported are not initialized.
1787 auto rateId = mode.GetMcsValue();
1788 if (mode.GetModulationClass() == WIFI_MOD_CLASS_HT)
1789 {
1790 rateId %= (minstrelHtStandardInfos.at(WIFI_MOD_CLASS_HT).maxMcs + 1);
1791 }
1792
1793 station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1794 station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex =
1795 i; /// Mapping between rateId and operationalMcsSet
1796 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1797 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1798 station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1799 station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1800 station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1801 station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1802 station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1803 station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1804 station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1805 station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1806 station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime =
1807 GetFirstMpduTxTime(groupId, GetMcsSupported(station, i));
1808 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1809 station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1810 CalculateRetransmits(station, groupId, rateId);
1811 }
1812 }
1813 }
1814 }
1815 /// make sure at least one group is supported, otherwise we end up with an infinite loop in
1816 /// SetNextSample
1817 if (noSupportedGroupFound)
1818 {
1819 NS_FATAL_ERROR("No supported group has been found");
1820 }
1821 SetNextSample(station); /// Select the initial sample index.
1822 UpdateStats(station); /// Calculate the initial high throughput rates.
1823 station->m_txrate = FindRate(station); /// Select the rate to use.
1824}
1825
1826void
1828{
1829 NS_LOG_FUNCTION(this << station << index);
1830 const auto groupId = GetGroupId(index);
1831 const auto rateId = GetRateId(index);
1832 if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1833 {
1834 CalculateRetransmits(station, groupId, rateId);
1835 }
1836}
1837
1838void
1840 std::size_t groupId,
1841 uint8_t rateId)
1842{
1843 NS_LOG_FUNCTION(this << station << groupId << rateId);
1844
1845 uint32_t cw = 15; // Is an approximation.
1846 uint32_t cwMax = 1023;
1847 Time cwTime;
1848 Time txTime;
1849 const auto slotTime = GetPhy()->GetSlot();
1850
1851 if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1852 {
1853 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1854 }
1855 else
1856 {
1857 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1858 station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1859
1860 auto mode =
1861 GetMcsSupported(station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex);
1862 WifiTxVector txVector;
1863 txVector.SetMode(mode);
1864 txVector.SetPreambleType(GetPreambleForTransmission(mode.GetModulationClass()));
1865
1866 const auto dataTxTime = GetFirstMpduTxTime(groupId, mode) +
1867 GetMpduTxTime(groupId, mode) * (station->m_avgAmpduLen - 1);
1868 const auto ackTime = GetPhy()->GetSifs() + GetEstimatedAckTxTime(txVector);
1869
1870 /* Contention time for first 2 tries */
1871 cwTime = (cw / 2) * slotTime;
1872 cw = Min((cw + 1) * 2, cwMax);
1873 cwTime += (cw / 2) * slotTime;
1874 cw = Min((cw + 1) * 2, cwMax);
1875
1876 /* Total TX time for data and Contention after first 2 tries */
1877 txTime = cwTime + 2 * (dataTxTime + ackTime);
1878
1879 /* See how many more tries we can fit inside segment size */
1880 do
1881 {
1882 /* Contention time for this try */
1883 cwTime = (cw / 2) * slotTime;
1884 cw = Min((cw + 1) * 2, cwMax);
1885
1886 /* Total TX time after this try */
1887 txTime += cwTime + ackTime + dataTxTime;
1888 } while ((txTime < MilliSeconds(6)) &&
1889 (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1890 }
1891}
1892
1893double
1895 double currentProb,
1896 double ewmaProb,
1897 double weight)
1898{
1899 double diff;
1900 double incr;
1901 double tmp;
1902
1903 /* calculate exponential weighted moving variance */
1904 diff = currentProb - ewmaProb;
1905 incr = (100 - weight) * diff / 100;
1906 tmp = oldEwmsd * oldEwmsd;
1907 tmp = weight * (tmp + diff * incr) / 100;
1908
1909 /* return standard deviation */
1910 return sqrt(tmp);
1911}
1912
1913void
1915{
1916 NS_LOG_FUNCTION(this << station);
1917 station->m_col = station->m_index = 0;
1918
1919 // for off-setting to make rates fall between 0 and nModes
1920 auto numSampleRates = m_numRates;
1921
1922 uint16_t newIndex;
1923 for (uint8_t col = 0; col < m_nSampleCol; col++)
1924 {
1925 for (uint8_t i = 0; i < numSampleRates; i++)
1926 {
1927 /**
1928 * The next two lines basically tries to generate a random number
1929 * between 0 and the number of available rates
1930 */
1931 int uv = m_uniformRandomVariable->GetInteger(0, numSampleRates);
1932 newIndex = (i + uv) % numSampleRates;
1933
1934 // this loop is used for filling in other uninitialized places
1935 while (station->m_sampleTable[newIndex][col] != 0)
1936 {
1937 newIndex = (newIndex + 1) % m_numRates;
1938 }
1939 station->m_sampleTable[newIndex][col] = i;
1940 }
1941 }
1942}
1943
1944void
1946{
1947 if (!station->m_statsFile.is_open())
1948 {
1949 std::ostringstream tmp;
1950 tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1951 station->m_statsFile.open(tmp.str(), std::ios::out);
1952 }
1953
1954 station->m_statsFile
1955 << " best ____________rate__________ ________statistics________ "
1956 "________last_______ ______sum-of________\n"
1957 << " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] "
1958 "[prob.|retry|suc|att] [#success | #attempts]\n";
1959 for (std::size_t i = 0; i < m_numGroups; i++)
1960 {
1961 StatsDump(station, i, station->m_statsFile);
1962 }
1963
1964 station->m_statsFile << "\nTotal packet count:: ideal "
1965 << Max(0, station->m_totalPacketsCount - station->m_samplePacketsCount)
1966 << " lookaround " << station->m_samplePacketsCount << "\n";
1967 station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen
1968 << "\n\n";
1969
1970 station->m_statsFile.flush();
1971}
1972
1973void
1975 std::size_t groupId,
1976 std::ofstream& of)
1977{
1978 auto numRates = m_numRates;
1979 McsGroup group = m_minstrelGroups[groupId];
1980 Time txTime;
1981 for (uint8_t i = 0; i < numRates; i++)
1982 {
1983 if (station->m_groupsTable[groupId].m_supported &&
1984 station->m_groupsTable[groupId].m_ratesTable[i].supported)
1985 {
1986 of << group.type << " " << group.chWidth << " " << group.gi << " " << +group.streams
1987 << " ";
1988
1989 const auto maxTpRate = station->m_maxTpRate;
1990 const auto maxTpRate2 = station->m_maxTpRate2;
1991 const auto maxProbRate = station->m_maxProbRate;
1992
1993 const auto idx = GetIndex(groupId, i);
1994 if (idx == maxTpRate)
1995 {
1996 of << 'A';
1997 }
1998 else
1999 {
2000 of << ' ';
2001 }
2002 if (idx == maxTpRate2)
2003 {
2004 of << 'B';
2005 }
2006 else
2007 {
2008 of << ' ';
2009 }
2010 if (idx == maxProbRate)
2011 {
2012 of << 'P';
2013 }
2014 else
2015 {
2016 of << ' ';
2017 }
2018
2019 if (group.type == WIFI_MINSTREL_GROUP_HT)
2020 {
2021 of << std::setw(4) << " MCS"
2022 << (group.streams - 1) *
2024 i;
2025 }
2026 else
2027 {
2028 of << std::setw(7) << " MCS" << +i << "/" << static_cast<int>(group.streams);
2029 }
2030
2031 of << " " << std::setw(3) << idx << " ";
2032
2033 /* tx_time[rate(i)] in usec */
2034 txTime = GetFirstMpduTxTime(
2035 groupId,
2036 GetMcsSupported(station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
2037 of << std::setw(6) << txTime.GetMicroSeconds() << " ";
2038
2039 of << std::setw(7) << CalculateThroughput(station, groupId, i, 100) / 100 << " "
2040 << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100
2041 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb
2042 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb
2043 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].prob
2044 << " " << std::setw(2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount
2045 << " " << std::setw(3)
2046 << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " "
2047 << std::setw(3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt
2048 << " " << std::setw(9)
2049 << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " "
2050 << std::setw(9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist
2051 << "\n";
2052 }
2053 }
2054}
2055
2056uint16_t
2057MinstrelHtWifiManager::GetIndex(std::size_t groupId, uint8_t rateId)
2058{
2059 NS_LOG_FUNCTION(this << groupId << rateId);
2060 return groupId * m_numRates + rateId;
2061}
2062
2063uint8_t
2065{
2066 NS_LOG_FUNCTION(this << index);
2067 return index % m_numRates;
2068}
2069
2070std::size_t
2072{
2073 NS_LOG_FUNCTION(this << index);
2074 return index / m_numRates;
2075}
2076
2077std::size_t
2079 uint8_t streams,
2080 Time guardInterval,
2081 MHz_u chWidth)
2082{
2083 NS_LOG_FUNCTION(this << mc << streams << guardInterval << chWidth);
2084 const auto& standardInfos = minstrelHtStandardInfos.at(mc);
2085 const auto it = std::find(standardInfos.guardIntervals.cbegin(),
2086 standardInfos.guardIntervals.cend(),
2087 guardInterval);
2088 const auto giIndex = std::distance(standardInfos.guardIntervals.cbegin(), it);
2089 const auto widthIndex = std::log2(chWidth / MHz_u{20});
2090 return (standardInfos.maxStreams * standardInfos.guardIntervals.size() * widthIndex) +
2091 (standardInfos.maxStreams * giIndex) + streams - 1;
2092}
2093
2094std::size_t
2096{
2097 const auto& standardInfos = minstrelHtStandardInfos.at(mc);
2098 const auto numWidths = std::log2(standardInfos.maxWidth / MHz_u{20}) + 1;
2099 return numWidths * standardInfos.guardIntervals.size() * standardInfos.maxStreams;
2100}
2101
2102std::size_t
2103MinstrelHtWifiManager::GetHtGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
2104{
2105 NS_LOG_FUNCTION(this << streams << guardInterval << chWidth);
2106 return GetIdInGroup(WIFI_MOD_CLASS_HT, streams, guardInterval, chWidth);
2107}
2108
2109std::size_t
2110MinstrelHtWifiManager::GetVhtGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
2111{
2112 NS_LOG_FUNCTION(this << streams << guardInterval << chWidth);
2113 const auto allHtGroups = GetNumGroups(WIFI_MOD_CLASS_HT);
2114 const auto vhtGroupId = GetIdInGroup(WIFI_MOD_CLASS_VHT, streams, guardInterval, chWidth);
2115 return allHtGroups + vhtGroupId;
2116}
2117
2118std::size_t
2119MinstrelHtWifiManager::GetHeGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
2120{
2121 NS_LOG_FUNCTION(this << streams << guardInterval << chWidth);
2122 // This check is needed since HT is not supported in 6 GHz band
2123 std::size_t allHtGroups = (GetHtSupported()) ? GetNumGroups(WIFI_MOD_CLASS_HT) : 0;
2124 // This check is needed since VHT is not supported in 2.4 and 6 GHz bands
2125 std::size_t allVhtGroups = (GetVhtSupported()) ? GetNumGroups(WIFI_MOD_CLASS_VHT) : 0;
2126 const auto heGroupId = GetIdInGroup(WIFI_MOD_CLASS_HE, streams, guardInterval, chWidth);
2127 return allHtGroups + allVhtGroups + heGroupId;
2128}
2129
2130std::size_t
2131MinstrelHtWifiManager::GetEhtGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
2132{
2133 NS_LOG_FUNCTION(this << streams << guardInterval << chWidth);
2134 // This check is needed since HT is not supported in 6 GHz band
2135 std::size_t allHtGroups = (GetHtSupported()) ? GetNumGroups(WIFI_MOD_CLASS_HT) : 0;
2136 // This check is needed since VHT is not supported in 2.4 and 6 GHz bands
2137 std::size_t allVhtGroups = (GetVhtSupported()) ? GetNumGroups(WIFI_MOD_CLASS_VHT) : 0;
2138 const auto allHeGroups = GetNumGroups(WIFI_MOD_CLASS_HE);
2139 const auto ehtGroupId = GetIdInGroup(WIFI_MOD_CLASS_EHT, streams, guardInterval, chWidth);
2140 return allHtGroups + allVhtGroups + allHeGroups + ehtGroupId;
2141}
2142
2143std::size_t
2145 uint8_t streams,
2146 Time guardInterval,
2147 MHz_u chWidth)
2148{
2149 switch (type)
2150 {
2152 return GetHtGroupId(streams, guardInterval, chWidth);
2154 return GetVhtGroupId(streams, guardInterval, chWidth);
2156 return GetHeGroupId(streams, guardInterval, chWidth);
2158 return GetEhtGroupId(streams, guardInterval, chWidth);
2159 default:
2160 NS_ABORT_MSG("Unknown group type: " << type);
2161 }
2162 return 0;
2163}
2164
2165uint16_t
2167{
2168 NS_LOG_FUNCTION(this << station);
2169
2170 std::size_t groupId = 0;
2171 uint8_t rateId = 0;
2172 while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
2173 {
2174 groupId++;
2175 }
2176 while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
2177 {
2178 rateId++;
2179 }
2180 NS_ASSERT(station->m_groupsTable[groupId].m_supported &&
2181 station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
2182 return GetIndex(groupId, rateId);
2183}
2184
2185uint16_t
2187{
2188 NS_LOG_FUNCTION(this << station << groupId);
2189
2190 uint8_t rateId = 0;
2191 while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
2192 {
2193 rateId++;
2194 }
2195 NS_ASSERT(station->m_groupsTable[groupId].m_supported &&
2196 station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
2197 return GetIndex(groupId, rateId);
2198}
2199
2202{
2203 const auto& phyMcsList = GetPhy()->GetMcsList(mc);
2204 WifiModeList mcsList(phyMcsList.cbegin(), phyMcsList.cend());
2205 return mcsList;
2206}
2207
2208} // namespace ns3
#define Max(a, b)
#define Min(a, b)
AttributeValue implementation for Boolean.
Definition boolean.h:26
Implementation of Minstrel-HT Rate Control Algorithm.
static TypeId GetTypeId()
Get the type ID.
uint32_t CountRetries(MinstrelHtWifiRemoteStation *station)
Count retries.
void StatsDump(MinstrelHtWifiRemoteStation *station, std::size_t groupId, std::ofstream &of)
Print group statistics.
uint32_t m_frameLength
Frame length used to calculate modes TxTime in bytes.
void InitSampleTable(MinstrelHtWifiRemoteStation *station)
Initialize Sample Table.
bool m_printStats
If statistics table should be printed.
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model.
void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode) override
This method is a pure virtual method that must be implemented by the sub-class.
void DoReportDataOk(WifiRemoteStation *station, double ackSnr, WifiMode ackMode, double dataSnr, MHz_u dataChannelWidth, uint8_t dataNss) override
This method is a pure virtual method that must be implemented by the sub-class.
WifiTxVector DoGetRtsTxVector(WifiRemoteStation *station) override
Time GetFirstMpduTxTime(std::size_t groupId, WifiMode mode) const
Obtain the TxTime saved in the group information.
MinstrelMcsGroups m_minstrelGroups
Global array for groups information.
void SetNextSample(MinstrelHtWifiRemoteStation *station)
Set the next sample from Sample Table.
uint8_t m_numRates
Number of rates per group Minstrel should consider.
uint16_t UpdateRateAfterAllowedWidth(uint16_t txRate, MHz_u allowedWidth)
Given the index of the current TX rate, check whether the channel width is not greater than the given...
uint8_t m_nSampleCol
Number of sample columns.
std::list< Ptr< WifiMpdu > > DoGetMpdusToDropOnTxFailure(WifiRemoteStation *station, Ptr< WifiPsdu > psdu) override
Find the MPDUs to drop (possibly based on their frame retry count) in the given PSDU,...
void RateInit(MinstrelHtWifiRemoteStation *station)
Initialize Minstrel Table.
void SetBestStationThRates(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxTpRate or maxTp2Rate if is better than current values.
void AddMpduTxTime(std::size_t groupId, WifiMode mode, Time t)
Save a TxTime to the vector of groups.
void PrintTable(MinstrelHtWifiRemoteStation *station)
Printing Minstrel Table.
std::size_t GetHeGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the groupId of an HE MCS with the given number of streams, GI and channel width used.
double CalculateEwmsd(double oldEwmsd, double currentProb, double ewmaProb, double weight)
Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation.
void DoReportDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void SetBestProbabilityRate(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxProbRate if it is better than current value.
void AddFirstMpduTxTime(std::size_t groupId, WifiMode mode, Time t)
Save a TxTime to the vector of groups.
double CalculateThroughput(MinstrelHtWifiRemoteStation *station, std::size_t groupId, uint8_t rateId, double ewmaProb)
Return the average throughput of the MCS defined by groupId and rateId.
Time m_updateStats
How frequent do we calculate the stats.
Time GetMpduTxTime(std::size_t groupId, WifiMode mode) const
Obtain the TxTime saved in the group information.
TracedValue< uint64_t > m_currentRate
Trace rate changes.
uint16_t GetLowestIndex(MinstrelHtWifiRemoteStation *station)
Returns the lowest global index of the rates supported by the station.
void DoInitialize() override
Initialize() implementation.
bool ShouldAddMcsToGroup(WifiMode mode, std::size_t groupId)
Check whether a given MCS mode should be added to a given group.
std::size_t GetGroupId(uint16_t index)
Return the groupId from the global index.
std::size_t GetIdInGroup(WifiModulationClass mc, uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the Id of a MCS of a given modulation class with the given number of streams,...
WifiTxVector DoGetDataTxVector(WifiRemoteStation *station, MHz_u allowedWidth) override
void CheckInit(MinstrelHtWifiRemoteStation *station)
Check for initializations.
bool DoNeedRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally)
std::size_t GetNumGroups(WifiModulationClass mc)
Returns the number of groups for a given modulation class.
void UpdateRetry(MinstrelHtWifiRemoteStation *station)
Update the number of retries and reset accordingly.
void CalculateRetransmits(MinstrelHtWifiRemoteStation *station, uint16_t index)
Calculate the number of retransmissions to set for the index rate.
void SetupPhy(const Ptr< WifiPhy > phy) override
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
std::size_t GetVhtGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the groupId of a VHT MCS with the given number of streams, GI and channel width used.
bool IsValidMcs(uint8_t streams, MHz_u chWidth, WifiMode mode)
Check the validity of a combination of number of streams, chWidth and mode.
std::size_t GetEhtGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the groupId of an EHT MCS with the given number of streams, GI and channel width used.
void InitializeGroups(WifiModulationClass mc)
Initialize all groups belonging to a given modulation class.
uint8_t m_ewmaLevel
Exponential weighted moving average level (or coefficient).
uint16_t FindRate(MinstrelHtWifiRemoteStation *station)
Find a rate to use from Minstrel Table.
uint8_t m_lookAroundRate
The % to try other rates than our current rate.
std::size_t GetHtGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the groupId of an HT MCS with the given number of streams, GI and channel width used.
std::size_t m_numGroups
Number of groups Minstrel should consider.
Time CalculateMpduTxDuration(uint8_t streams, Time gi, MHz_u chWidth, WifiMode mode, MpduType mpduType)
Estimates the TxTime of a frame with a given mode and group (stream, guard interval and channel width...
void UpdateRate(MinstrelHtWifiRemoteStation *station)
Update rate.
uint8_t GetRateId(uint16_t index)
Return the rateId inside a group, from the global index.
Time m_legacyUpdateStats
How frequent do we calculate the stats for legacy MinstrelWifiManager.
WifiModeList GetDeviceMcsList(WifiModulationClass mc) const
Returns a list of only the MCS supported by the device for a given modulation class.
void DoReportRtsOk(WifiRemoteStation *station, double ctsSnr, WifiMode ctsMode, double rtsSnr) override
This method is a pure virtual method that must be implemented by the sub-class.
Ptr< UniformRandomVariable > m_uniformRandomVariable
Provides uniform random variables.
uint16_t GetNextSample(MinstrelHtWifiRemoteStation *station)
Getting the next sample from Sample Table.
uint16_t GetIndex(std::size_t groupId, uint8_t rateId)
Returns the global index corresponding to the groupId and rateId.
void UpdateStats(MinstrelHtWifiRemoteStation *station)
Update the Minstrel Table.
WifiRemoteStation * DoCreateStation() const override
Ptr< MinstrelWifiManager > m_legacyManager
Pointer to an instance of MinstrelWifiManager.
void SetupMac(const Ptr< WifiMac > mac) override
Set up MAC associated with this device since it is the object that knows the full set of timing param...
void DoReportFinalDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void UpdatePacketCounters(MinstrelHtWifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus)
Update the number of sample count variables.
void DoReportFinalRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
std::size_t GetGroupIdForType(McsGroupType type, uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the group ID of an MCS of a given group type with the given number of streams,...
bool m_useLatestAmendmentOnly
Flag if only the latest supported amendment by both peers should be used.
void DoReportRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void DoReportAmpduTxStatus(WifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus, double rxSnr, double dataSnr, MHz_u dataChannelWidth, uint8_t dataNss) override
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:407
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:402
AttributeValue implementation for Time.
Definition nstime.h:1432
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
represent a single transmission mode
Definition wifi-mode.h:38
WifiModulationClass GetModulationClass() const
Definition wifi-mode.cc:172
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
Definition wifi-mode.cc:110
uint8_t GetMcsValue() const
Definition wifi-mode.cc:151
static Time GetPayloadDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, MpduType mpdutype=NORMAL_MPDU, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1516
Time GetSlot() const
Return the slot duration for this PHY.
Definition wifi-phy.cc:850
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition wifi-phy.cc:838
MHz_u GetTxBandwidth(WifiMode mode, MHz_u maxAllowedBandWidth=MHz_u{ std::numeric_limits< double >::max()}) const
Get the bandwidth for a transmission occurring on the current operating channel and using the given W...
Definition wifi-phy.cc:1111
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
Definition wifi-phy.cc:656
std::list< WifiMode > GetMcsList() const
The WifiPhy::GetMcsList() method is used (e.g., by a WifiRemoteStationManager) to determine the set o...
Definition wifi-phy.cc:2111
std::list< WifiMode > GetModeList() const
The WifiPhy::GetModeList() method is used (e.g., by a WifiRemoteStationManager) to determine the set ...
Definition wifi-phy.cc:2062
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition wifi-phy.cc:1556
hold a list of per-remote-station state.
uint8_t GetNumberOfSupportedStreams(Mac48Address address) const
Return the number of spatial streams supported by the station.
uint8_t GetNess(const WifiRemoteStation *station) const
uint8_t GetNBasicModes() const
Return the number of basic modes we support.
Time GetGuardInterval() const
Return the shortest supported HE guard interval duration.
Ptr< WifiPhy > GetPhy() const
Return the WifiPhy.
MHz_u GetChannelWidth(const WifiRemoteStation *station) const
Return the channel width supported by the station.
Ptr< const He6GhzBandCapabilities > GetStationHe6GhzCapabilities(const Mac48Address &from) const
Return the HE 6 GHz Band Capabilities sent by a remote station.
bool GetAggregation(const WifiRemoteStation *station) const
Return whether the given station supports A-MPDU.
bool GetHtSupported() const
Return whether the device has HT capability support enabled on the link this manager is associated wi...
bool GetEhtSupported() const
Return whether the device has EHT capability support enabled.
Ptr< WifiMac > GetMac() const
Return the WifiMac.
uint8_t GetNMcsSupported(Mac48Address address) const
Return the number of MCS supported by the station.
WifiMode GetBasicMode(uint8_t i) const
Return a basic mode from the set of basic modes.
bool GetShortGuardIntervalSupported() const
Return whether the device has SGI support enabled.
virtual void SetupPhy(const Ptr< WifiPhy > phy)
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
WifiMode GetMcsSupported(const WifiRemoteStation *station, uint8_t i) const
Return the WifiMode supported by the specified station at the specified index.
bool GetVhtSupported() const
Return whether the device has VHT capability support enabled on the link this manager is associated w...
bool GetShortPreambleEnabled() const
Return whether the device uses short PHY preambles.
bool GetHeSupported() const
Return whether the device has HE capability support enabled.
virtual void SetupMac(const Ptr< WifiMac > mac)
Set up MAC associated with this device since it is the object that knows the full set of timing param...
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
bool IsValid(WifiPhyBand band=WIFI_PHY_BAND_UNSPECIFIED) const
The standard disallows certain combinations of WifiMode, number of spatial streams,...
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 SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
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: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
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1433
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1453
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiModulationClass
This enumeration defines the modulation classes per (Table 10-6 "Modulation classes"; IEEE 802....
MpduType
The type of an MPDU.
Definition wifi-types.h:48
@ WIFI_MOD_CLASS_HT
HT (Clause 19)
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ FIRST_MPDU_IN_AGGREGATE
The MPDU is the first aggregate in an A-MPDU with multiple MPDUs, but is not the last aggregate.
Definition wifi-types.h:55
@ MIDDLE_MPDU_IN_AGGREGATE
The MPDU is part of an A-MPDU with multiple MPDUs, but is neither the first nor the last aggregate.
Definition wifi-types.h:58
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
std::vector< RateInfo > MinstrelRate
Data structure for a Minstrel Rate table A vector of a struct RateInfo.
std::vector< McsGroup > MinstrelMcsGroups
Data structure for a table of group definitions.
McsGroupType
Available MCS group types.
const std::map< WifiModulationClass, MinstrelHtWifiManager::StandardInfo > minstrelHtStandardInfos
standard information for each modulation class
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Time GetEstimatedAckTxTime(const WifiTxVector &txVector)
std::vector< MinstrelHtRateInfo > MinstrelHtRate
Data structure for a Minstrel Rate table.
std::vector< WifiMode > WifiModeList
In various parts of the code, folk are interested in maintaining a list of transmission modes.
Definition wifi-mode.h:252
std::vector< std::vector< uint8_t > > SampleRate
Data structure for a Sample Rate table A vector of a vector uint8_t.
std::vector< GroupInfo > McsGroupData
Data structure for a table of groups.
WifiPreamble GetPreambleForTransmission(WifiModulationClass modulation, bool useShortPreamble)
Return the preamble to be used for the transmission.
A struct to contain information of a group.
MinstrelHtRate m_ratesTable
Information about rates of this group.
uint16_t m_maxTpRate2
The second max throughput rate of this group in bps.
uint16_t m_maxProbRate
The highest success probability rate of this group in bps.
uint16_t m_maxTpRate
The max throughput rate of this group in bps.
Data structure to contain the information that defines a group.
MHz_u chWidth
channel width
Time gi
guard interval duration
McsGroupType type
identifies the group,
bool isSupported
flag whether group is supported
uint8_t streams
number of spatial streams
A struct to contain all statistics information related to a data rate.
double ewmaProb
Exponential weighted moving average of probability.
MinstrelHtWifiRemoteStation structure.
McsGroupData m_groupsTable
Table of groups with stats.
uint32_t m_sampleCount
Max number of samples per update interval.
uint8_t m_sampleGroup
The group that the sample rate belongs to.
uint32_t m_ampduPacketCount
Number of A-MPDUs transmitted.
uint32_t m_numSamplesSlow
Number of times a slow rate was sampled.
uint32_t m_sampleTries
Number of sample tries after waiting sampleWait.
std::ofstream m_statsFile
File where statistics table is written.
uint32_t m_sampleWait
How many transmission attempts to wait until a new sample.
bool m_isHt
If the station is HT capable.
uint32_t m_avgAmpduLen
Average number of MPDUs in an A-MPDU.
uint32_t m_ampduLen
Number of MPDUs in an A-MPDU.
hold per-remote-station state for Minstrel Wifi manager.
uint16_t m_maxTpRate2
second highest throughput rate in bps
Time m_nextStatsUpdate
10 times every second
bool m_initialized
for initializing tables
uint16_t m_sampleRate
current sample rate in bps
uint16_t m_txrate
current transmit rate in bps
int m_totalPacketsCount
total number of packets as of now
bool m_isSampling
a flag to indicate we are currently sampling
MinstrelRate m_minstrelTable
minstrel table
uint32_t m_shortRetry
short retries such as control packets
uint16_t m_maxTpRate
the current throughput rate in bps
uint8_t m_nModes
number of modes supported
int m_samplePacketsCount
how many packets we have sample so far
uint8_t m_col
To keep track of the current position in the our random sample table going row by row from 1st column...
uint32_t m_longRetry
long retries such as data packets
uint16_t m_maxProbRate
rate with highest probability of success in bps
hold per-remote-station state.
WifiRemoteStationState * m_state
Remote station state.
Mac48Address m_address
Mac48Address of the remote station.
void CalculateThroughput()
Calculate the throughput.
Definition wifi-tcp.cc:51