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