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