A Discrete-Event Network Simulator
API
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/log.h"
39#include "ns3/packet.h"
40#include "ns3/random-variable-stream.h"
41#include "ns3/simulator.h"
42#include "ns3/wifi-mac.h"
43#include "ns3/wifi-phy.h"
44
45#include <iomanip>
46
47#define Min(a, b) ((a < b) ? a : b)
48#define Max(a, b) ((a > b) ? a : b)
49
50NS_LOG_COMPONENT_DEFINE("MinstrelHtWifiManager");
51
52namespace ns3
53{
54
57{
58 uint8_t m_sampleGroup;
59
64
68
70 bool m_isHt;
71
72 std::ofstream m_statsFile;
73};
74
76
79{
80 static TypeId tid =
81 TypeId("ns3::MinstrelHtWifiManager")
83 .AddConstructor<MinstrelHtWifiManager>()
84 .SetGroupName("Wifi")
85 .AddAttribute("UpdateStatistics",
86 "The interval between updating statistics table",
90 .AddAttribute("LegacyUpdateStatistics",
91 "The interval between updating statistics table (for legacy Minstrel)",
95 .AddAttribute("LookAroundRate",
96 "The percentage to try other rates (for legacy Minstrel)",
97 UintegerValue(10),
99 MakeUintegerChecker<uint8_t>(0, 100))
100 .AddAttribute("EWMA",
101 "EWMA level",
102 UintegerValue(75),
104 MakeUintegerChecker<uint8_t>(0, 100))
105 .AddAttribute("SampleColumn",
106 "The number of columns used for sampling",
107 UintegerValue(10),
109 MakeUintegerChecker<uint8_t>())
110 .AddAttribute("PacketLength",
111 "The packet length used for calculating mode TxTime (bytes)",
112 UintegerValue(1200),
114 MakeUintegerChecker<uint32_t>())
115 .AddAttribute("UseLatestAmendmentOnly",
116 "Use only the latest amendment when it is supported by both peers",
117 BooleanValue(true),
120 .AddAttribute("PrintStats",
121 "Control the printing of the statistics table",
122 BooleanValue(false),
125 .AddTraceSource("Rate",
126 "Traced value for rate changes (b/s)",
128 "ns3::TracedValueCallback::Uint64");
129 return tid;
130}
131
133 : m_numGroups(0),
134 m_numRates(0),
135 m_currentRate(0)
136{
137 NS_LOG_FUNCTION(this);
138 m_uniformRandomVariable = CreateObject<UniformRandomVariable>();
143 m_legacyManager = CreateObject<MinstrelWifiManager>();
144}
145
147{
148 NS_LOG_FUNCTION(this);
149 for (uint8_t i = 0; i < m_numGroups; i++)
150 {
151 m_minstrelGroups[i].ratesFirstMpduTxTimeTable.clear();
152 m_minstrelGroups[i].ratesTxTimeTable.clear();
153 }
154}
155
156int64_t
158{
159 NS_LOG_FUNCTION(this << stream);
160 int64_t numStreamsAssigned = 0;
162 numStreamsAssigned++;
163 numStreamsAssigned += m_legacyManager->AssignStreams(stream);
164 return numStreamsAssigned;
165}
166
167void
169{
170 NS_LOG_FUNCTION(this << phy);
171 // Setup PHY for legacy manager.
172 m_legacyManager->SetupPhy(phy);
174}
175
176void
178{
179 NS_LOG_FUNCTION(this << mac);
180 m_legacyManager->SetupMac(mac);
182}
183
184void
186{
187 NS_LOG_FUNCTION(this);
195 if (GetHtSupported())
196 {
199 if (GetVhtSupported())
200 {
203 }
204 if (GetHeSupported())
205 {
208 }
209
222 NS_LOG_DEBUG("Initialize MCS Groups:");
224
225 // Initialize all HT groups
226 for (uint16_t chWidth = 20; chWidth <= MAX_HT_WIDTH; chWidth *= 2)
227 {
228 for (int gi = 800; gi >= 400;)
229 {
230 for (uint8_t streams = 1; streams <= MAX_HT_SUPPORTED_STREAMS; streams++)
231 {
232 uint8_t groupId = GetHtGroupId(streams, gi, chWidth);
233
234 m_minstrelGroups[groupId].streams = streams;
235 m_minstrelGroups[groupId].gi = gi;
236 m_minstrelGroups[groupId].chWidth = chWidth;
238 m_minstrelGroups[groupId].isSupported = false;
239
240 // Check capabilities of the device
242 (gi == 400))
243 && (GetPhy()->GetChannelWidth() >=
244 chWidth)
245 && (GetPhy()->GetMaxSupportedTxSpatialStreams() >=
246 streams))
247 {
248 m_minstrelGroups[groupId].isSupported = true;
249
250 // Calculate TX time for all rates of the group
251 WifiModeList htMcsList = GetHtDeviceMcsList();
252 for (uint8_t i = 0; i < MAX_HT_GROUP_RATES; i++)
253 {
254 uint16_t deviceIndex = i + (m_minstrelGroups[groupId].streams - 1) * 8;
255 WifiMode mode = htMcsList[deviceIndex];
256 AddFirstMpduTxTime(groupId,
257 mode,
259 streams,
260 gi,
261 chWidth,
262 mode,
264 AddMpduTxTime(groupId,
265 mode,
267 streams,
268 gi,
269 chWidth,
270 mode,
272 }
273 NS_LOG_DEBUG("Initialized group " << +groupId << ": (" << +streams << ","
274 << gi << "," << chWidth << ")");
275 }
276 }
277 gi /= 2;
278 }
279 }
280
281 if (GetVhtSupported())
282 {
283 // Initialize all VHT groups
284 for (uint16_t chWidth = 20; chWidth <= MAX_VHT_WIDTH; chWidth *= 2)
285 {
286 for (int gi = 800; gi >= 400;)
287 {
288 for (uint8_t streams = 1; streams <= MAX_VHT_SUPPORTED_STREAMS; streams++)
289 {
290 uint8_t groupId = GetVhtGroupId(streams, gi, chWidth);
291
292 m_minstrelGroups[groupId].streams = streams;
293 m_minstrelGroups[groupId].gi = gi;
294 m_minstrelGroups[groupId].chWidth = chWidth;
296 m_minstrelGroups[groupId].isSupported = false;
297
298 // Check capabilities of the device
300 (gi == 400))
301 && (GetPhy()->GetChannelWidth() >=
302 chWidth)
303 && (GetPhy()->GetMaxSupportedTxSpatialStreams() >=
304 streams))
305 {
306 m_minstrelGroups[groupId].isSupported = true;
307
308 // Calculate TX time for all rates of the group
309 WifiModeList vhtMcsList = GetVhtDeviceMcsList();
310 for (uint8_t i = 0; i < MAX_VHT_GROUP_RATES; i++)
311 {
312 WifiMode mode = vhtMcsList[i];
313 // Check for invalid VHT MCSs and do not add time to array.
314 if (IsValidMcs(GetPhy(), streams, chWidth, mode))
315 {
317 groupId,
318 mode,
320 streams,
321 gi,
322 chWidth,
323 mode,
326 groupId,
327 mode,
329 streams,
330 gi,
331 chWidth,
332 mode,
334 }
335 }
336 NS_LOG_DEBUG("Initialized group " << +groupId << ": (" << +streams
337 << "," << gi << "," << chWidth
338 << ")");
339 }
340 }
341 gi /= 2;
342 }
343 }
344 }
345
346 if (GetHeSupported())
347 {
348 // Initialize all HE groups
349 for (uint16_t chWidth = 20; chWidth <= MAX_HE_WIDTH; chWidth *= 2)
350 {
351 for (int gi = 3200; gi >= 800;)
352 {
353 for (uint8_t streams = 1; streams <= MAX_HE_SUPPORTED_STREAMS; streams++)
354 {
355 uint8_t groupId = GetHeGroupId(streams, gi, chWidth);
356
357 m_minstrelGroups[groupId].streams = streams;
358 m_minstrelGroups[groupId].gi = gi;
359 m_minstrelGroups[groupId].chWidth = chWidth;
361 m_minstrelGroups[groupId].isSupported = false;
362
363 // Check capabilities of the device
364 if ((GetGuardInterval() <= gi)
365 && (GetPhy()->GetChannelWidth() >=
366 chWidth)
367 && (GetPhy()->GetMaxSupportedTxSpatialStreams() >=
368 streams))
369 {
370 m_minstrelGroups[groupId].isSupported = true;
371
372 // Calculate tx time for all rates of the group
373 WifiModeList heMcsList = GetHeDeviceMcsList();
374 for (uint8_t i = 0; i < MAX_HE_GROUP_RATES; i++)
375 {
376 WifiMode mode = heMcsList.at(i);
377 // Check for invalid HE MCSs and do not add time to array.
378 if (IsValidMcs(GetPhy(), streams, chWidth, mode))
379 {
381 groupId,
382 mode,
384 streams,
385 gi,
386 chWidth,
387 mode,
390 groupId,
391 mode,
393 streams,
394 gi,
395 chWidth,
396 mode,
398 }
399 }
400 NS_LOG_DEBUG("Initialized group " << +groupId << ": (" << +streams
401 << "," << gi << "," << chWidth
402 << ")");
403 }
404 }
405 gi /= 2;
406 }
407 }
408 }
409 }
410}
411
412bool
414 uint8_t streams,
415 uint16_t chWidth,
416 WifiMode mode)
417{
418 NS_LOG_FUNCTION(this << phy << +streams << chWidth << mode);
419 WifiTxVector txvector;
420 txvector.SetNss(streams);
421 txvector.SetChannelWidth(chWidth);
422 txvector.SetMode(mode);
423 return txvector.IsValid();
424}
425
426Time
428 uint8_t streams,
429 uint16_t gi,
430 uint16_t chWidth,
431 WifiMode mode,
432 MpduType mpduType)
433{
434 NS_LOG_FUNCTION(this << phy << +streams << gi << chWidth << mode << mpduType);
435 WifiTxVector txvector;
436 txvector.SetNss(streams);
437 txvector.SetGuardInterval(gi);
438 txvector.SetChannelWidth(chWidth);
439 txvector.SetNess(0);
440 txvector.SetStbc(0);
441 txvector.SetMode(mode);
444 WifiPhy::GetPayloadDuration(m_frameLength, txvector, phy->GetPhyBand(), mpduType);
445}
446
447Time
449{
450 NS_LOG_FUNCTION(this << +groupId << mode);
451 auto it = m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.find(mode);
452 NS_ASSERT(it != m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.end());
453 return it->second;
454}
455
456void
458{
459 NS_LOG_FUNCTION(this << +groupId << mode << t);
460 m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.insert(std::make_pair(mode, t));
461}
462
463Time
465{
466 NS_LOG_FUNCTION(this << +groupId << mode);
467 auto it = m_minstrelGroups[groupId].ratesTxTimeTable.find(mode);
468 NS_ASSERT(it != m_minstrelGroups[groupId].ratesTxTimeTable.end());
469 return it->second;
470}
471
472void
474{
475 NS_LOG_FUNCTION(this << +groupId << mode << t);
476 m_minstrelGroups[groupId].ratesTxTimeTable.insert(std::make_pair(mode, t));
477}
478
481{
482 NS_LOG_FUNCTION(this);
484
485 // Initialize variables common to both stations.
487 station->m_col = 0;
488 station->m_index = 0;
489 station->m_maxTpRate = 0;
490 station->m_maxTpRate2 = 0;
491 station->m_maxProbRate = 0;
492 station->m_nModes = 0;
493 station->m_totalPacketsCount = 0;
494 station->m_samplePacketsCount = 0;
495 station->m_isSampling = false;
496 station->m_sampleRate = 0;
497 station->m_sampleDeferred = false;
498 station->m_shortRetry = 0;
499 station->m_longRetry = 0;
500 station->m_txrate = 0;
501 station->m_initialized = false;
502
503 // Variables specific to HT station
504 station->m_sampleGroup = 0;
505 station->m_numSamplesSlow = 0;
506 station->m_sampleCount = 16;
507 station->m_sampleWait = 0;
508 station->m_sampleTries = 4;
509
510 station->m_avgAmpduLen = 1;
511 station->m_ampduLen = 0;
512 station->m_ampduPacketCount = 0;
513
514 // If the device supports HT
515 if (GetHtSupported())
516 {
521 station->m_isHt = true;
522 }
523 // Use the variable in the station to indicate that the device do not support HT
524 else
525 {
526 station->m_isHt = false;
527 }
528
529 return station;
530}
531
532void
534{
535 NS_LOG_FUNCTION(this << station);
536 // Note: we appear to be doing late initialization of the table
537 // to make sure that the set of supported rates has been initialized
538 // before we perform our own initialization.
539 if (!station->m_initialized)
540 {
547 if (!GetHtSupported(station))
548 {
549 NS_LOG_INFO("non-HT station " << station);
550 station->m_isHt = false;
551 // We will use non-HT minstrel for this station. Initialize the manager.
552 m_legacyManager->SetAttribute("UpdateStatistics", TimeValue(m_legacyUpdateStats));
553 m_legacyManager->SetAttribute("LookAroundRate", UintegerValue(m_lookAroundRate));
554 m_legacyManager->SetAttribute("EWMA", UintegerValue(m_ewmaLevel));
555 m_legacyManager->SetAttribute("SampleColumn", UintegerValue(m_nSampleCol));
556 m_legacyManager->SetAttribute("PacketLength", UintegerValue(m_frameLength));
557 m_legacyManager->SetAttribute("PrintStats", BooleanValue(m_printStats));
558 m_legacyManager->CheckInit(station);
559 }
560 else
561 {
562 NS_LOG_DEBUG("HT station " << station);
563 station->m_isHt = true;
564 station->m_nModes = GetNMcsSupported(station);
565 station->m_minstrelTable = MinstrelRate(station->m_nModes);
566 station->m_sampleTable = SampleRate(m_numRates, std::vector<uint8_t>(m_nSampleCol));
567 InitSampleTable(station);
568 RateInit(station);
569 station->m_initialized = true;
570 }
571 }
572}
573
574void
576{
577 NS_LOG_FUNCTION(this << st);
579 "DoReportRxOk m_txrate=" << static_cast<MinstrelHtWifiRemoteStation*>(st)->m_txrate);
580}
581
582void
584{
585 NS_LOG_FUNCTION(this << st);
586 MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
587 CheckInit(station);
588 if (!station->m_initialized)
589 {
590 return;
591 }
592 NS_LOG_DEBUG("DoReportRtsFailed m_txrate = " << station->m_txrate);
593 station->m_shortRetry++;
594}
595
596void
598 double ctsSnr,
599 WifiMode ctsMode,
600 double rtsSnr)
601{
602 NS_LOG_FUNCTION(this << st);
603}
604
605void
607{
608 NS_LOG_FUNCTION(this << st);
609 MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
610 NS_LOG_DEBUG("Final RTS failed");
611 CheckInit(station);
612 if (!station->m_initialized)
613 {
614 return;
615 }
616 UpdateRetry(station);
617}
618
619void
621{
622 NS_LOG_FUNCTION(this << st);
623 MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
624
625 CheckInit(station);
626 if (!station->m_initialized)
627 {
628 return;
629 }
630
631 NS_LOG_DEBUG("DoReportDataFailed " << station << "\t rate " << station->m_txrate
632 << "\tlongRetry \t" << station->m_longRetry);
633
634 if (!station->m_isHt)
635 {
636 m_legacyManager->UpdateRate(station);
637 }
638 else if (station->m_longRetry < CountRetries(station))
639 {
640 uint8_t rateId = GetRateId(station->m_txrate);
641 uint8_t groupId = GetGroupId(station->m_txrate);
642 station->m_groupsTable[groupId]
643 .m_ratesTable[rateId]
644 .numRateAttempt++; // Increment the attempts counter for the rate used.
645 UpdateRate(station);
646 }
647}
648
649void
651 double ackSnr,
652 WifiMode ackMode,
653 double dataSnr,
654 uint16_t dataChannelWidth,
655 uint8_t dataNss)
656{
657 NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
658 MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
659
660 CheckInit(station);
661 if (!station->m_initialized)
662 {
663 return;
664 }
665
666 NS_LOG_DEBUG("DoReportDataOk m_txrate = "
667 << station->m_txrate
668 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
669 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
670 << " (before update).");
671
672 if (!station->m_isHt)
673 {
674 station->m_minstrelTable[station->m_txrate].numRateSuccess++;
675 station->m_minstrelTable[station->m_txrate].numRateAttempt++;
676
677 m_legacyManager->UpdatePacketCounters(station);
678
679 NS_LOG_DEBUG("DoReportDataOk m_txrate = "
680 << station->m_txrate
681 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
682 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
683 << " (after update).");
684
685 UpdateRetry(station);
686 m_legacyManager->UpdateStats(station);
687
688 if (station->m_nModes >= 1)
689 {
690 station->m_txrate = m_legacyManager->FindRate(station);
691 }
692 }
693 else
694 {
695 uint8_t rateId = GetRateId(station->m_txrate);
696 uint8_t groupId = GetGroupId(station->m_txrate);
697 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
698 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
699
700 UpdatePacketCounters(station, 1, 0);
701
702 NS_LOG_DEBUG("DoReportDataOk m_txrate = "
703 << station->m_txrate
704 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
705 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
706 << " (after update).");
707
708 station->m_isSampling = false;
709 station->m_sampleDeferred = false;
710
711 UpdateRetry(station);
712 if (Simulator::Now() >= station->m_nextStatsUpdate)
713 {
714 UpdateStats(station);
715 }
716
717 if (station->m_nModes >= 1)
718 {
719 station->m_txrate = FindRate(station);
720 }
721 }
722
723 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
724}
725
726void
728{
729 NS_LOG_FUNCTION(this << st);
730 MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
731
732 CheckInit(station);
733 if (!station->m_initialized)
734 {
735 return;
736 }
737
738 NS_LOG_DEBUG("DoReportFinalDataFailed - TxRate=" << station->m_txrate);
739
740 if (!station->m_isHt)
741 {
742 m_legacyManager->UpdatePacketCounters(station);
743
744 UpdateRetry(station);
745
746 m_legacyManager->UpdateStats(station);
747 if (station->m_nModes >= 1)
748 {
749 station->m_txrate = m_legacyManager->FindRate(station);
750 }
751 }
752 else
753 {
754 UpdatePacketCounters(station, 0, 1);
755
756 station->m_isSampling = false;
757 station->m_sampleDeferred = false;
758
759 UpdateRetry(station);
760 if (Simulator::Now() >= station->m_nextStatsUpdate)
761 {
762 UpdateStats(station);
763 }
764
765 if (station->m_nModes >= 1)
766 {
767 station->m_txrate = FindRate(station);
768 }
769 }
770 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
771}
772
773void
775 uint16_t nSuccessfulMpdus,
776 uint16_t nFailedMpdus,
777 double rxSnr,
778 double dataSnr,
779 uint16_t dataChannelWidth,
780 uint8_t dataNss)
781{
782 NS_LOG_FUNCTION(this << st << nSuccessfulMpdus << nFailedMpdus << rxSnr << dataSnr
783 << dataChannelWidth << +dataNss);
784 MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
785
786 CheckInit(station);
787 if (!station->m_initialized)
788 {
789 return;
790 }
791
792 NS_ASSERT_MSG(station->m_isHt, "A-MPDU Tx Status called but this is a non-HT STA.");
793
794 NS_LOG_DEBUG("DoReportAmpduTxStatus. TxRate=" << station->m_txrate
795 << " SuccMpdus=" << nSuccessfulMpdus
796 << " FailedMpdus=" << nFailedMpdus);
797
798 station->m_ampduPacketCount++;
799 station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
800
801 UpdatePacketCounters(station, nSuccessfulMpdus, nFailedMpdus);
802
803 uint8_t rateId = GetRateId(station->m_txrate);
804 uint8_t groupId = GetGroupId(station->m_txrate);
805 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
806 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt +=
807 nSuccessfulMpdus + nFailedMpdus;
808
809 if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries(station))
810 {
811 // We do not receive a BlockAck. The entire AMPDU fail.
812 UpdateRate(station);
813 }
814 else
815 {
816 station->m_isSampling = false;
817 station->m_sampleDeferred = false;
818
819 UpdateRetry(station);
820 if (Simulator::Now() >= station->m_nextStatsUpdate)
821 {
822 UpdateStats(station);
823 }
824
825 if (station->m_nModes >= 1)
826 {
827 station->m_txrate = FindRate(station);
828 }
829 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
830 }
831}
832
833void
835{
836 NS_LOG_FUNCTION(this << station);
837
859 CheckInit(station);
860 if (!station->m_initialized)
861 {
862 return;
863 }
864 station->m_longRetry++;
865
869 uint8_t maxTpRateId = GetRateId(station->m_maxTpRate);
870 uint8_t maxTpGroupId = GetGroupId(station->m_maxTpRate);
871 uint8_t maxTp2RateId = GetRateId(station->m_maxTpRate2);
872 uint8_t maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
873 uint8_t maxProbRateId = GetRateId(station->m_maxProbRate);
874 uint8_t maxProbGroupId = GetGroupId(station->m_maxProbRate);
875
877 if (!station->m_isSampling)
878 {
880 if (station->m_longRetry <
881 station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
882 {
883 NS_LOG_DEBUG("Not Sampling; use the same rate again");
884 station->m_txrate = station->m_maxTpRate;
885 }
886
888 else if (station->m_longRetry <
889 (station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
890 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
891 {
892 NS_LOG_DEBUG("Not Sampling; use the Max TP2");
893 station->m_txrate = station->m_maxTpRate2;
894 }
895
897 else if (station->m_longRetry <=
898 (station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
899 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
900 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
901 {
902 NS_LOG_DEBUG("Not Sampling; use Max Prob");
903 station->m_txrate = station->m_maxProbRate;
904 }
905 else
906 {
907 NS_FATAL_ERROR("Max retries reached and m_longRetry not cleared properly. longRetry= "
908 << station->m_longRetry);
909 }
910 }
911
913 else
914 {
917 if (station->m_longRetry <
918 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
919 {
920 NS_LOG_DEBUG("Sampling use the MaxTP rate");
921 station->m_txrate = station->m_maxTpRate2;
922 }
923
925 else if (station->m_longRetry <=
926 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
927 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
928 {
929 NS_LOG_DEBUG("Sampling use the MaxProb rate");
930 station->m_txrate = station->m_maxProbRate;
931 }
932 else
933 {
934 NS_FATAL_ERROR("Max retries reached and m_longRetry not cleared properly. longRetry= "
935 << station->m_longRetry);
936 }
937 }
938 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
939}
940
941void
943{
944 NS_LOG_FUNCTION(this << station);
945 station->m_shortRetry = 0;
946 station->m_longRetry = 0;
947}
948
949void
951 uint16_t nSuccessfulMpdus,
952 uint16_t nFailedMpdus)
953{
954 NS_LOG_FUNCTION(this << station << nSuccessfulMpdus << nFailedMpdus);
955
956 station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
957 if (station->m_isSampling)
958 {
959 station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
960 }
961 if (station->m_totalPacketsCount == ~0)
962 {
963 station->m_samplePacketsCount = 0;
964 station->m_totalPacketsCount = 0;
965 }
966
967 if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
968 {
969 station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
970 station->m_sampleTries = 1;
971 station->m_sampleCount--;
972 }
973}
974
975uint16_t
976MinstrelHtWifiManager::UpdateRateAfterAllowedWidth(uint16_t txRate, uint16_t allowedWidth)
977{
978 NS_LOG_FUNCTION(this << txRate << allowedWidth);
979
980 auto groupId = GetGroupId(txRate);
981 McsGroup group = m_minstrelGroups[groupId];
982
983 if (group.chWidth <= allowedWidth)
984 {
985 NS_LOG_DEBUG("Channel width is not greater than allowed width, nothing to do");
986 return txRate;
987 }
988
990 NS_ASSERT(group.chWidth % 20 == 0);
991 // try halving the channel width and check if the group with the same number of
992 // streams and same GI is supported, until either a supported group is found or
993 // the width becomes lower than 20 MHz
994 uint16_t width = group.chWidth / 2;
995
996 while (width >= 20)
997 {
998 if (width > allowedWidth)
999 {
1000 width /= 2;
1001 continue;
1002 }
1003
1004 switch (group.type)
1005 {
1007 groupId = GetHtGroupId(group.streams, group.gi, width);
1008 break;
1010 groupId = GetVhtGroupId(group.streams, group.gi, width);
1011 break;
1013 groupId = GetHeGroupId(group.streams, group.gi, width);
1014 break;
1015 default:
1016 NS_ABORT_MSG("Unknown group type: " << group.type);
1017 }
1018
1019 group = m_minstrelGroups[groupId];
1020 if (group.isSupported)
1021 {
1022 break;
1023 }
1024
1025 width /= 2;
1026 }
1027
1028 NS_ABORT_MSG_IF(width < 20, "No rate compatible with the allowed width found");
1029
1030 return GetIndex(groupId, GetRateId(txRate));
1031}
1032
1035{
1036 NS_LOG_FUNCTION(this << st << allowedWidth);
1037 MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1038
1039 if (!station->m_initialized)
1040 {
1041 CheckInit(station);
1042 }
1043
1044 if (!station->m_isHt)
1045 {
1046 WifiTxVector vector = m_legacyManager->GetDataTxVector(station);
1047 uint64_t dataRate = vector.GetMode().GetDataRate(vector);
1048 if (m_currentRate != dataRate && !station->m_isSampling)
1049 {
1050 NS_LOG_DEBUG("New datarate: " << dataRate);
1051 m_currentRate = dataRate;
1052 }
1053 return vector;
1054 }
1055 else
1056 {
1057 station->m_txrate = UpdateRateAfterAllowedWidth(station->m_txrate, allowedWidth);
1058 NS_LOG_DEBUG("DoGetDataMode m_txrate= " << station->m_txrate);
1059
1060 uint8_t rateId = GetRateId(station->m_txrate);
1061 uint8_t groupId = GetGroupId(station->m_txrate);
1062 uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
1063
1064 NS_LOG_DEBUG("DoGetDataMode rateId= " << +rateId << " groupId= " << +groupId
1065 << " mode= " << GetMcsSupported(station, mcsIndex));
1066
1067 McsGroup group = m_minstrelGroups[groupId];
1068
1069 // Check consistency of rate selected.
1070 if (((group.type == WIFI_MINSTREL_GROUP_HE) && (group.gi < GetGuardInterval(station))) ||
1071 (((group.type == WIFI_MINSTREL_GROUP_HT) || (group.type == WIFI_MINSTREL_GROUP_VHT)) &&
1072 (group.gi == 400) && !GetShortGuardIntervalSupported(station)) ||
1073 (group.chWidth > GetChannelWidth(station)) ||
1074 (group.streams > GetNumberOfSupportedStreams(station)))
1075 {
1076 NS_FATAL_ERROR("Inconsistent group selected. Group: ("
1077 << +group.streams << "," << group.gi << "," << group.chWidth << ")"
1078 << " Station capabilities: (" << GetNumberOfSupportedStreams(station)
1079 << ","
1080 << ((group.type == WIFI_MINSTREL_GROUP_HE)
1081 ? GetGuardInterval(station)
1082 : (GetShortGuardIntervalSupported(station) ? 400 : 800))
1083 << "," << GetChannelWidth(station) << ")");
1084 }
1085 WifiMode mode = GetMcsSupported(station, mcsIndex);
1086 WifiTxVector txVector{
1087 mode,
1090 group.gi,
1092 group.streams,
1093 GetNess(station),
1095 GetAggregation(station) && !station->m_isSampling};
1096 uint64_t dataRate = mode.GetDataRate(txVector);
1097 if (m_currentRate != dataRate && !station->m_isSampling)
1098 {
1099 NS_LOG_DEBUG("New datarate: " << dataRate);
1100 m_currentRate = dataRate;
1101 }
1102 return txVector;
1103 }
1104}
1105
1108{
1109 NS_LOG_FUNCTION(this << st);
1110 MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1111
1112 if (!station->m_initialized)
1113 {
1114 CheckInit(station);
1115 }
1116
1117 if (!station->m_isHt)
1118 {
1119 return m_legacyManager->GetRtsTxVector(station);
1120 }
1121 else
1122 {
1123 NS_LOG_DEBUG("DoGetRtsMode m_txrate=" << station->m_txrate);
1124
1125 /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
1126 * When supported, decision of using HT has to follow rules in Section 9.7.6 from
1127 * 802.11-2012. From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is
1128 * carried in a non-HT PPDU shall be transmitted by the STA using a rate no higher than the
1129 * highest rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
1130 * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
1131 * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
1132 * these conditions, the control frame shall be transmitted at a rate no higher than the
1133 * highest mandatory rate of the attached PHY that is less than or equal to the rate
1134 * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
1135 * directed to the same receiving STA."
1136 */
1137
1138 // As we are in Minstrel HT, assume the last rate was an HT rate.
1139 uint8_t rateId = GetRateId(station->m_txrate);
1140 uint8_t groupId = GetGroupId(station->m_txrate);
1141 uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
1142
1143 WifiMode lastRate = GetMcsSupported(station, mcsIndex);
1144 uint64_t lastDataRate = lastRate.GetNonHtReferenceRate();
1145 uint8_t nBasicRates = GetNBasicModes();
1146
1147 WifiMode rtsRate;
1148 bool rateFound = false;
1149
1150 for (uint8_t i = 0; i < nBasicRates; i++)
1151 {
1152 uint64_t rate = GetBasicMode(i).GetDataRate(20);
1153 if (rate <= lastDataRate)
1154 {
1155 rtsRate = GetBasicMode(i);
1156 rateFound = true;
1157 }
1158 }
1159
1160 if (!rateFound)
1161 {
1163 for (const auto& mode : phy->GetModeList())
1164 {
1165 uint64_t rate = mode.GetDataRate(20);
1166 if (rate <= lastDataRate)
1167 {
1168 rtsRate = mode;
1169 rateFound = true;
1170 }
1171 }
1172 }
1173
1174 NS_ASSERT(rateFound);
1175
1176 return WifiTxVector(
1177 rtsRate,
1180 800,
1181 1,
1182 1,
1183 0,
1186 GetChannelWidth(station)),
1187 GetAggregation(station));
1188 }
1189}
1190
1191bool
1193 Ptr<const Packet> packet,
1194 bool normally)
1195{
1196 NS_LOG_FUNCTION(this << st << packet << normally);
1197
1198 MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1199
1200 CheckInit(station);
1201 if (!station->m_initialized)
1202 {
1203 return normally;
1204 }
1205
1206 uint32_t maxRetries;
1207
1208 if (!station->m_isHt)
1209 {
1210 maxRetries = m_legacyManager->CountRetries(station);
1211 }
1212 else
1213 {
1214 maxRetries = CountRetries(station);
1215 }
1216
1217 if (station->m_longRetry >= maxRetries)
1218 {
1219 NS_LOG_DEBUG("No re-transmission allowed. Retries: " << station->m_longRetry
1220 << " Max retries: " << maxRetries);
1221 return false;
1222 }
1223 else
1224 {
1225 NS_LOG_DEBUG("Re-transmit. Retries: " << station->m_longRetry
1226 << " Max retries: " << maxRetries);
1227 return true;
1228 }
1229}
1230
1233{
1234 uint8_t maxProbRateId = GetRateId(station->m_maxProbRate);
1235 uint8_t maxProbGroupId = GetGroupId(station->m_maxProbRate);
1236 uint8_t maxTpRateId = GetRateId(station->m_maxTpRate);
1237 uint8_t maxTpGroupId = GetGroupId(station->m_maxTpRate);
1238 uint8_t maxTp2RateId = GetRateId(station->m_maxTpRate2);
1239 uint8_t maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1240
1241 if (!station->m_isSampling)
1242 {
1243 return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
1244 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
1245 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1246 }
1247 else
1248 {
1249 return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1250 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1251 }
1252}
1253
1254uint16_t
1256{
1257 NS_LOG_FUNCTION(this << station);
1258 uint8_t sampleGroup = station->m_sampleGroup;
1259 uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1260 uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1261 uint8_t sampleIndex = station->m_sampleTable[index][col];
1262 uint16_t rateIndex = GetIndex(sampleGroup, sampleIndex);
1263 NS_LOG_DEBUG("Next Sample is " << rateIndex);
1264 SetNextSample(station); // Calculate the next sample rate.
1265 return rateIndex;
1266}
1267
1268void
1270{
1271 NS_LOG_FUNCTION(this << station);
1272 do
1273 {
1274 station->m_sampleGroup++;
1275 station->m_sampleGroup %= m_numGroups;
1276 } while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1277
1278 station->m_groupsTable[station->m_sampleGroup].m_index++;
1279
1280 uint8_t sampleGroup = station->m_sampleGroup;
1281 uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1282 uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1283
1284 if (index >= m_numRates)
1285 {
1286 station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1287 station->m_groupsTable[station->m_sampleGroup].m_col++;
1288 if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1289 {
1290 station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1291 }
1292 index = station->m_groupsTable[station->m_sampleGroup].m_index;
1293 col = station->m_groupsTable[sampleGroup].m_col;
1294 }
1295 NS_LOG_DEBUG("New sample set: group= " << +sampleGroup
1296 << " index= " << +station->m_sampleTable[index][col]);
1297}
1298
1299uint16_t
1301{
1302 NS_LOG_FUNCTION(this << station);
1303 NS_LOG_DEBUG("FindRate packet=" << station->m_totalPacketsCount);
1304
1305 if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1306 {
1307 return station->m_maxTpRate;
1308 }
1309
1310 // If we have waited enough, then sample.
1311 if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1312 {
1313 // SAMPLING
1314 NS_LOG_DEBUG("Obtaining a sampling rate");
1316 uint16_t sampleIdx = GetNextSample(station);
1317 NS_LOG_DEBUG("Sampling rate = " << sampleIdx);
1318
1319 // Evaluate if the sampling rate selected should be used.
1320 uint8_t sampleGroupId = GetGroupId(sampleIdx);
1321 uint8_t sampleRateId = GetRateId(sampleIdx);
1322
1323 // If the rate selected is not supported, then don't sample.
1324 if (station->m_groupsTable[sampleGroupId].m_supported &&
1325 station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1326 {
1334 MinstrelHtRateInfo sampleRateInfo =
1335 station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1336
1337 NS_LOG_DEBUG("Use sample rate? MaxTpRate= "
1338 << station->m_maxTpRate << " CurrentRate= " << station->m_txrate
1339 << " SampleRate= " << sampleIdx
1340 << " SampleProb= " << sampleRateInfo.ewmaProb);
1341
1342 if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2 &&
1343 sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1344 {
1350 uint8_t maxTpGroupId = GetGroupId(station->m_maxTpRate);
1351 uint8_t maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1352 uint8_t maxTp2RateId = GetRateId(station->m_maxTpRate2);
1353 uint8_t maxProbGroupId = GetGroupId(station->m_maxProbRate);
1354 uint8_t maxProbRateId = GetRateId(station->m_maxProbRate);
1355
1356 uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1357 uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1358
1359 Time sampleDuration = sampleRateInfo.perfectTxTime;
1360 Time maxTp2Duration =
1361 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1362 Time maxProbDuration = station->m_groupsTable[maxProbGroupId]
1363 .m_ratesTable[maxProbRateId]
1364 .perfectTxTime;
1365
1366 NS_LOG_DEBUG("Use sample rate? SampleDuration= "
1367 << sampleDuration << " maxTp2Duration= " << maxTp2Duration
1368 << " maxProbDuration= " << maxProbDuration << " sampleStreams= "
1369 << +sampleStreams << " maxTpStreams= " << +maxTpStreams);
1370 if (sampleDuration < maxTp2Duration ||
1371 (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1372 {
1374 station->m_isSampling = true;
1375
1377 station->m_sampleRate = sampleIdx;
1378
1379 NS_LOG_DEBUG("FindRate "
1380 << "sampleRate=" << sampleIdx);
1381 station->m_sampleTries--;
1382 return sampleIdx;
1383 }
1384 else
1385 {
1386 station->m_numSamplesSlow++;
1387 if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1388 {
1390 station->m_isSampling = true;
1391
1393 station->m_sampleRate = sampleIdx;
1394
1395 NS_LOG_DEBUG("FindRate "
1396 << "sampleRate=" << sampleIdx);
1397 station->m_sampleTries--;
1398 return sampleIdx;
1399 }
1400 }
1401 }
1402 }
1403 }
1404 if (station->m_sampleWait > 0)
1405 {
1406 station->m_sampleWait--;
1407 }
1408
1410
1411 NS_LOG_DEBUG("FindRate "
1412 << "maxTpRrate=" << station->m_maxTpRate);
1413 return station->m_maxTpRate;
1414}
1415
1416void
1418{
1419 NS_LOG_FUNCTION(this << station);
1420
1422
1423 station->m_numSamplesSlow = 0;
1424 station->m_sampleCount = 0;
1425
1426 double tempProb;
1427
1428 if (station->m_ampduPacketCount > 0)
1429 {
1430 uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1431 station->m_avgAmpduLen =
1432 (newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel)) / 100;
1433 station->m_ampduLen = 0;
1434 station->m_ampduPacketCount = 0;
1435 }
1436
1437 /* Initialize global rate indexes */
1438 station->m_maxTpRate = GetLowestIndex(station);
1439 station->m_maxTpRate2 = GetLowestIndex(station);
1440 station->m_maxProbRate = GetLowestIndex(station);
1441
1443 for (uint8_t j = 0; j < m_numGroups; j++)
1444 {
1445 if (station->m_groupsTable[j].m_supported)
1446 {
1447 station->m_sampleCount++;
1448
1449 /* (re)Initialize group rate indexes */
1450 station->m_groupsTable[j].m_maxTpRate = GetLowestIndex(station, j);
1451 station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex(station, j);
1452 station->m_groupsTable[j].m_maxProbRate = GetLowestIndex(station, j);
1453
1454 for (uint8_t i = 0; i < m_numRates; i++)
1455 {
1456 if (station->m_groupsTable[j].m_ratesTable[i].supported)
1457 {
1458 station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1459
1461 +i << " "
1462 << GetMcsSupported(station,
1463 station->m_groupsTable[j].m_ratesTable[i].mcsIndex)
1464 << "\t attempt="
1465 << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt
1466 << "\t success="
1467 << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1468
1470 if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1471 {
1472 station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1477 tempProb =
1478 (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) /
1479 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1480
1482 station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1483
1484 if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1485 {
1486 station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1487 }
1488 else
1489 {
1490 station->m_groupsTable[j].m_ratesTable[i].ewmsdProb =
1491 CalculateEwmsd(station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1492 tempProb,
1493 station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1494 m_ewmaLevel);
1496 tempProb =
1497 (tempProb * (100 - m_ewmaLevel) +
1498 station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) /
1499 100;
1500 station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1501 }
1502
1503 station->m_groupsTable[j].m_ratesTable[i].throughput =
1504 CalculateThroughput(station, j, i, tempProb);
1505
1506 station->m_groupsTable[j].m_ratesTable[i].successHist +=
1507 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1508 station->m_groupsTable[j].m_ratesTable[i].attemptHist +=
1509 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1510 }
1511 else
1512 {
1513 station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1514 }
1515
1517 station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess =
1518 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1519 station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt =
1520 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1521 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1522 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1523
1524 if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1525 {
1526 SetBestStationThRates(station, GetIndex(j, i));
1527 SetBestProbabilityRate(station, GetIndex(j, i));
1528 }
1529 }
1530 }
1531 }
1532 }
1533
1534 // Try to sample all available rates during each interval.
1535 station->m_sampleCount *= 8;
1536
1537 // Recalculate retries for the rates selected.
1538 CalculateRetransmits(station, station->m_maxTpRate);
1539 CalculateRetransmits(station, station->m_maxTpRate2);
1540 CalculateRetransmits(station, station->m_maxProbRate);
1541
1542 NS_LOG_DEBUG("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2
1543 << "\nmax prob=" << station->m_maxProbRate);
1544 if (m_printStats)
1545 {
1546 PrintTable(station);
1547 }
1548}
1549
1550double
1552 uint8_t groupId,
1553 uint8_t rateId,
1554 double ewmaProb)
1555{
1561 if (ewmaProb < 10)
1562 {
1563 return 0;
1564 }
1565 else
1566 {
1571 Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1572 if (ewmaProb > 90)
1573 {
1574 return 90 / txTime.GetSeconds();
1575 }
1576 else
1577 {
1578 return ewmaProb / txTime.GetSeconds();
1579 }
1580 }
1581}
1582
1583void
1585{
1586 GroupInfo* group;
1587 MinstrelHtRateInfo rate;
1588 uint8_t tmpGroupId;
1589 uint8_t tmpRateId;
1590 double tmpTh;
1591 double tmpProb;
1592 uint8_t groupId;
1593 uint8_t rateId;
1594 double currentTh;
1595 // maximum group probability (GP) variables
1596 uint8_t maxGPGroupId;
1597 uint8_t maxGPRateId;
1598 double maxGPTh;
1599
1600 groupId = GetGroupId(index);
1601 rateId = GetRateId(index);
1602 group = &station->m_groupsTable[groupId];
1603 rate = group->m_ratesTable[rateId];
1604
1605 tmpGroupId = GetGroupId(station->m_maxProbRate);
1606 tmpRateId = GetRateId(station->m_maxProbRate);
1607 tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1608 tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1609
1610 if (rate.ewmaProb > 75)
1611 {
1612 currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1613 if (currentTh > tmpTh)
1614 {
1615 station->m_maxProbRate = index;
1616 }
1617
1618 maxGPGroupId = GetGroupId(group->m_maxProbRate);
1619 maxGPRateId = GetRateId(group->m_maxProbRate);
1620 maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1621
1622 if (currentTh > maxGPTh)
1623 {
1624 group->m_maxProbRate = index;
1625 }
1626 }
1627 else
1628 {
1629 if (rate.ewmaProb > tmpProb)
1630 {
1631 station->m_maxProbRate = index;
1632 }
1633 maxGPRateId = GetRateId(group->m_maxProbRate);
1634 if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1635 {
1636 group->m_maxProbRate = index;
1637 }
1638 }
1639}
1640
1641/*
1642 * Find & sort topmost throughput rates
1643 *
1644 * If multiple rates provide equal throughput the sorting is based on their
1645 * current success probability. Higher success probability is preferred among
1646 * MCS groups.
1647 */
1648void
1650{
1651 uint8_t groupId;
1652 uint8_t rateId;
1653 double th;
1654 double prob;
1655 uint8_t maxTpGroupId;
1656 uint8_t maxTpRateId;
1657 uint8_t maxTp2GroupId;
1658 uint8_t maxTp2RateId;
1659 double maxTpTh;
1660 double maxTpProb;
1661 double maxTp2Th;
1662 double maxTp2Prob;
1663
1664 groupId = GetGroupId(index);
1665 rateId = GetRateId(index);
1666 prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1667 th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1668
1669 maxTpGroupId = GetGroupId(station->m_maxTpRate);
1670 maxTpRateId = GetRateId(station->m_maxTpRate);
1671 maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1672 maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1673
1674 maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1675 maxTp2RateId = GetRateId(station->m_maxTpRate2);
1676 maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1677 maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1678
1679 if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1680 {
1681 station->m_maxTpRate2 = station->m_maxTpRate;
1682 station->m_maxTpRate = index;
1683 }
1684 else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1685 {
1686 station->m_maxTpRate2 = index;
1687 }
1688
1689 // Find best rates per group
1690
1691 GroupInfo* group = &station->m_groupsTable[groupId];
1692 maxTpGroupId = GetGroupId(group->m_maxTpRate);
1693 maxTpRateId = GetRateId(group->m_maxTpRate);
1694 maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1695 maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1696
1697 maxTp2GroupId = GetGroupId(group->m_maxTpRate2);
1698 maxTp2RateId = GetRateId(group->m_maxTpRate2);
1699 maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1700 maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1701
1702 if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1703 {
1704 group->m_maxTpRate2 = group->m_maxTpRate;
1705 group->m_maxTpRate = index;
1706 }
1707 else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1708 {
1709 group->m_maxTpRate2 = index;
1710 }
1711}
1712
1713void
1715{
1716 NS_LOG_FUNCTION(this << station);
1717
1719
1723 NS_LOG_DEBUG("Supported groups by station:");
1724 bool noSupportedGroupFound = true;
1725 for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1726 {
1727 if (m_minstrelGroups[groupId].isSupported)
1728 {
1729 station->m_groupsTable[groupId].m_supported = false;
1730
1731 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1732 !GetHeSupported(station))
1733 {
1734 // It is a HE group but the receiver does not support HE: skip
1735 continue;
1736 }
1737 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_VHT) &&
1738 !GetVhtSupported(station))
1739 {
1740 // It is a VHT group but the receiver does not support VHT: skip
1741 continue;
1742 }
1743 if ((m_minstrelGroups[groupId].type != WIFI_MINSTREL_GROUP_HE) &&
1745 {
1746 // It is not a HE group and the receiver supports HE: skip since
1747 // UseLatestAmendmentOnly attribute is enabled
1748 continue;
1749 }
1750 if (!GetHeSupported(station) &&
1753 {
1754 // It is not a VHT group and the receiver supports VHT (but not HE): skip since
1755 // UseLatestAmendmentOnly attribute is enabled
1756 continue;
1757 }
1758 if (((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HT) ||
1760 (m_minstrelGroups[groupId].gi == 400) && !GetShortGuardIntervalSupported(station))
1761 {
1762 // It is a SGI group but the receiver does not support SGI: skip
1763 continue;
1764 }
1765 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1766 (m_minstrelGroups[groupId].gi < GetGuardInterval(station)))
1767 {
1768 // The receiver does not support the GI: skip
1769 continue;
1770 }
1771 if (GetChannelWidth(station) < m_minstrelGroups[groupId].chWidth)
1772 {
1773 // The receiver does not support the channel width: skip
1774 continue;
1775 }
1776 if (GetNumberOfSupportedStreams(station) < m_minstrelGroups[groupId].streams)
1777 {
1778 // The receiver does not support the number of spatial streams: skip
1779 continue;
1780 }
1781
1782 NS_LOG_DEBUG("Group: " << +groupId << " type: " << m_minstrelGroups[groupId].type
1783 << " streams: " << +m_minstrelGroups[groupId].streams
1784 << " GI: " << m_minstrelGroups[groupId].gi
1785 << " width: " << m_minstrelGroups[groupId].chWidth);
1786
1787 noSupportedGroupFound = false;
1788 station->m_groupsTable[groupId].m_supported = true;
1789 station->m_groupsTable[groupId].m_col = 0;
1790 station->m_groupsTable[groupId].m_index = 0;
1791
1792 station->m_groupsTable[groupId].m_ratesTable =
1794 for (uint8_t i = 0; i < m_numRates; i++)
1795 {
1796 station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1797 }
1798
1799 // Initialize all modes supported by the remote station that belong to the current
1800 // group.
1801 for (uint8_t i = 0; i < station->m_nModes; i++)
1802 {
1803 WifiMode mode = GetMcsSupported(station, i);
1804
1807 uint8_t rateId = mode.GetMcsValue();
1809 {
1810 rateId %= MAX_HT_GROUP_RATES;
1811 }
1812
1813 if (((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1814 (mode.GetModulationClass() ==
1816 && IsValidMcs(GetPhy(),
1817 m_minstrelGroups[groupId].streams,
1818 m_minstrelGroups[groupId].chWidth,
1819 mode))
1820 || ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_VHT) &&
1821 (mode.GetModulationClass() ==
1823 && IsValidMcs(GetPhy(),
1824 m_minstrelGroups[groupId].streams,
1825 m_minstrelGroups[groupId].chWidth,
1826 mode))
1827 || ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HT) &&
1828 (mode.GetModulationClass() ==
1830 && (mode.GetMcsValue() <
1831 (m_minstrelGroups[groupId].streams *
1832 8))
1833 && (mode.GetMcsValue() >= ((m_minstrelGroups[groupId].streams - 1) * 8))))
1834 {
1835 NS_LOG_DEBUG("Mode " << +i << ": " << mode);
1836
1837 station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1838 station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex =
1839 i;
1840 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1841 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1842 station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1843 station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1844 station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1845 station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1846 station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1847 station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1848 station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1849 station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1850 station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime =
1851 GetFirstMpduTxTime(groupId, GetMcsSupported(station, i));
1852 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1853 station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1854 CalculateRetransmits(station, groupId, rateId);
1855 }
1856 }
1857 }
1858 }
1861 if (noSupportedGroupFound)
1862 {
1863 NS_FATAL_ERROR("No supported group has been found");
1864 }
1865 SetNextSample(station);
1866 UpdateStats(station);
1867 station->m_txrate = FindRate(station);
1868}
1869
1870void
1872{
1873 NS_LOG_FUNCTION(this << station << index);
1874 uint8_t groupId = GetGroupId(index);
1875 uint8_t rateId = GetRateId(index);
1876 if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1877 {
1878 CalculateRetransmits(station, groupId, rateId);
1879 }
1880}
1881
1882void
1884 uint8_t groupId,
1885 uint8_t rateId)
1886{
1887 NS_LOG_FUNCTION(this << station << +groupId << +rateId);
1888
1889 uint32_t cw = 15; // Is an approximation.
1890 uint32_t cwMax = 1023;
1891 Time cwTime;
1892 Time txTime;
1893 Time dataTxTime;
1894 Time slotTime = GetPhy()->GetSlot();
1895 Time ackTime = GetPhy()->GetSifs() + GetPhy()->GetBlockAckTxTime();
1896
1897 if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1898 {
1899 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1900 }
1901 else
1902 {
1903 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1904 station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1905
1906 dataTxTime =
1908 groupId,
1909 GetMcsSupported(station,
1910 station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1912 groupId,
1913 GetMcsSupported(station,
1914 station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) *
1915 (station->m_avgAmpduLen - 1);
1916
1917 /* Contention time for first 2 tries */
1918 cwTime = (cw / 2) * slotTime;
1919 cw = Min((cw + 1) * 2, cwMax);
1920 cwTime += (cw / 2) * slotTime;
1921 cw = Min((cw + 1) * 2, cwMax);
1922
1923 /* Total TX time for data and Contention after first 2 tries */
1924 txTime = cwTime + 2 * (dataTxTime + ackTime);
1925
1926 /* See how many more tries we can fit inside segment size */
1927 do
1928 {
1929 /* Contention time for this try */
1930 cwTime = (cw / 2) * slotTime;
1931 cw = Min((cw + 1) * 2, cwMax);
1932
1933 /* Total TX time after this try */
1934 txTime += cwTime + ackTime + dataTxTime;
1935 } while ((txTime < MilliSeconds(6)) &&
1936 (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1937 }
1938}
1939
1940double
1942 double currentProb,
1943 double ewmaProb,
1944 double weight)
1945{
1946 double diff;
1947 double incr;
1948 double tmp;
1949
1950 /* calculate exponential weighted moving variance */
1951 diff = currentProb - ewmaProb;
1952 incr = (100 - weight) * diff / 100;
1953 tmp = oldEwmsd * oldEwmsd;
1954 tmp = weight * (tmp + diff * incr) / 100;
1955
1956 /* return standard deviation */
1957 return sqrt(tmp);
1958}
1959
1960void
1962{
1963 NS_LOG_FUNCTION(this << station);
1964 station->m_col = station->m_index = 0;
1965
1966 // for off-setting to make rates fall between 0 and nModes
1967 uint8_t numSampleRates = m_numRates;
1968
1969 uint16_t newIndex;
1970 for (uint8_t col = 0; col < m_nSampleCol; col++)
1971 {
1972 for (uint8_t i = 0; i < numSampleRates; i++)
1973 {
1978 int uv = m_uniformRandomVariable->GetInteger(0, numSampleRates);
1979 newIndex = (i + uv) % numSampleRates;
1980
1981 // this loop is used for filling in other uninitialized places
1982 while (station->m_sampleTable[newIndex][col] != 0)
1983 {
1984 newIndex = (newIndex + 1) % m_numRates;
1985 }
1986 station->m_sampleTable[newIndex][col] = i;
1987 }
1988 }
1989}
1990
1991void
1993{
1994 if (!station->m_statsFile.is_open())
1995 {
1996 std::ostringstream tmp;
1997 tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1998 station->m_statsFile.open(tmp.str(), std::ios::out);
1999 }
2000
2001 station->m_statsFile
2002 << " best ____________rate__________ ________statistics________ "
2003 "________last_______ ______sum-of________\n"
2004 << " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] "
2005 "[prob.|retry|suc|att] [#success | #attempts]\n";
2006 for (uint8_t i = 0; i < m_numGroups; i++)
2007 {
2008 StatsDump(station, i, station->m_statsFile);
2009 }
2010
2011 station->m_statsFile << "\nTotal packet count:: ideal "
2012 << Max(0, station->m_totalPacketsCount - station->m_samplePacketsCount)
2013 << " lookaround " << station->m_samplePacketsCount << "\n";
2014 station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen
2015 << "\n\n";
2016
2017 station->m_statsFile.flush();
2018}
2019
2020void
2022 uint8_t groupId,
2023 std::ofstream& of)
2024{
2025 uint8_t numRates = m_numRates;
2026 McsGroup group = m_minstrelGroups[groupId];
2027 Time txTime;
2028 for (uint8_t i = 0; i < numRates; i++)
2029 {
2030 if (station->m_groupsTable[groupId].m_supported &&
2031 station->m_groupsTable[groupId].m_ratesTable[i].supported)
2032 {
2033 of << group.type << " " << group.chWidth << " " << group.gi << " " << +group.streams
2034 << " ";
2035
2036 uint16_t maxTpRate = station->m_maxTpRate;
2037 uint16_t maxTpRate2 = station->m_maxTpRate2;
2038 uint16_t maxProbRate = station->m_maxProbRate;
2039
2040 uint16_t idx = GetIndex(groupId, i);
2041 if (idx == maxTpRate)
2042 {
2043 of << 'A';
2044 }
2045 else
2046 {
2047 of << ' ';
2048 }
2049 if (idx == maxTpRate2)
2050 {
2051 of << 'B';
2052 }
2053 else
2054 {
2055 of << ' ';
2056 }
2057 if (idx == maxProbRate)
2058 {
2059 of << 'P';
2060 }
2061 else
2062 {
2063 of << ' ';
2064 }
2065
2066 if (group.type == WIFI_MINSTREL_GROUP_HT)
2067 {
2068 of << std::setw(4) << " MCS" << (group.streams - 1) * 8 + i;
2069 }
2070 else
2071 {
2072 of << std::setw(7) << " MCS" << +i << "/" << static_cast<int>(group.streams);
2073 }
2074
2075 of << " " << std::setw(3) << +idx << " ";
2076
2077 /* tx_time[rate(i)] in usec */
2078 txTime = GetFirstMpduTxTime(
2079 groupId,
2080 GetMcsSupported(station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
2081 of << std::setw(6) << txTime.GetMicroSeconds() << " ";
2082
2083 of << std::setw(7) << CalculateThroughput(station, groupId, i, 100) / 100 << " "
2084 << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100
2085 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb
2086 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb
2087 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].prob
2088 << " " << std::setw(2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount
2089 << " " << std::setw(3)
2090 << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " "
2091 << std::setw(3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt
2092 << " " << std::setw(9)
2093 << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " "
2094 << std::setw(9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist
2095 << "\n";
2096 }
2097 }
2098}
2099
2100uint16_t
2101MinstrelHtWifiManager::GetIndex(uint8_t groupId, uint8_t rateId)
2102{
2103 NS_LOG_FUNCTION(this << +groupId << +rateId);
2104 uint16_t index;
2105 index = groupId * m_numRates + rateId;
2106 return index;
2107}
2108
2109uint8_t
2111{
2112 NS_LOG_FUNCTION(this << index);
2113 uint8_t id;
2114 id = index % m_numRates;
2115 return id;
2116}
2117
2118uint8_t
2120{
2121 NS_LOG_FUNCTION(this << index);
2122 return index / m_numRates;
2123}
2124
2125uint8_t
2126MinstrelHtWifiManager::GetHtGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2127{
2128 NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2129 uint8_t giIndex = (gi == 400) ? 1 : 0;
2130 uint8_t widthIndex = (chWidth == 40) ? 1 : 0;
2131 return (MAX_HT_SUPPORTED_STREAMS * 2 * widthIndex) + (MAX_HT_SUPPORTED_STREAMS * giIndex) +
2132 txstreams - 1;
2133}
2134
2135uint8_t
2136MinstrelHtWifiManager::GetVhtGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2137{
2138 NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2139 uint8_t giIndex = (gi == 400) ? 1 : 0;
2140 uint8_t widthIndex;
2141 if (chWidth == 160)
2142 {
2143 widthIndex = 3;
2144 }
2145 else if (chWidth == 80)
2146 {
2147 widthIndex = 2;
2148 }
2149 else if (chWidth == 40)
2150 {
2151 widthIndex = 1;
2152 }
2153 else // 20 MHz
2154 {
2155 widthIndex = 0;
2156 }
2157 uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
2158 groupId += (MAX_VHT_SUPPORTED_STREAMS * 2 * widthIndex) +
2159 (MAX_VHT_SUPPORTED_STREAMS * giIndex) + txstreams - 1;
2160 return groupId;
2161}
2162
2163uint8_t
2164MinstrelHtWifiManager::GetHeGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2165{
2166 NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2167 uint8_t giIndex;
2168 if (gi == 800)
2169 {
2170 giIndex = 2;
2171 }
2172 else if (gi == 1600)
2173 {
2174 giIndex = 1;
2175 }
2176 else // 3200 ns
2177 {
2178 giIndex = 0;
2179 }
2180 uint8_t widthIndex;
2181 if (chWidth == 160)
2182 {
2183 widthIndex = 3;
2184 }
2185 else if (chWidth == 80)
2186 {
2187 widthIndex = 2;
2188 }
2189 else if (chWidth == 40)
2190 {
2191 widthIndex = 1;
2192 }
2193 else // 20 MHz
2194 {
2195 widthIndex = 0;
2196 }
2197 uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
2198 if (GetVhtSupported())
2199 {
2201 }
2202 groupId += (MAX_HE_SUPPORTED_STREAMS * 3 * widthIndex) + (MAX_HE_SUPPORTED_STREAMS * giIndex) +
2203 txstreams - 1;
2204 return groupId;
2205}
2206
2207uint16_t
2209{
2210 NS_LOG_FUNCTION(this << station);
2211
2212 uint8_t groupId = 0;
2213 uint8_t rateId = 0;
2214 while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
2215 {
2216 groupId++;
2217 }
2218 while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
2219 {
2220 rateId++;
2221 }
2222 NS_ASSERT(station->m_groupsTable[groupId].m_supported &&
2223 station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
2224 return GetIndex(groupId, rateId);
2225}
2226
2227uint16_t
2229{
2230 NS_LOG_FUNCTION(this << station << +groupId);
2231
2232 uint8_t rateId = 0;
2233 while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
2234 {
2235 rateId++;
2236 }
2237 NS_ASSERT(station->m_groupsTable[groupId].m_supported &&
2238 station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
2239 return GetIndex(groupId, rateId);
2240}
2241
2244{
2245 WifiModeList heMcsList;
2246 for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_HE))
2247 {
2248 heMcsList.push_back(mode);
2249 }
2250 return heMcsList;
2251}
2252
2255{
2256 WifiModeList vhtMcsList;
2257 for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_VHT))
2258 {
2259 vhtMcsList.push_back(mode);
2260 }
2261 return vhtMcsList;
2262}
2263
2266{
2267 WifiModeList htMcsList;
2268 for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_HT))
2269 {
2270 htMcsList.push_back(mode);
2271 }
2272 return htMcsList;
2273}
2274
2275} // namespace ns3
AttributeValue implementation for Boolean.
Definition: boolean.h:37
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.
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
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:402
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:412
AttributeValue implementation for Time.
Definition: nstime.h:1425
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
Hold an unsigned integer type.
Definition: uinteger.h:45
uint32_t GetInteger(uint32_t min, uint32_t max)
Get the next random value, as an unsigned integer in the specified range .
represent a single transmission mode
Definition: wifi-mode.h:50
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
Time GetBlockAckTxTime() const
Return the estimated BlockAck TX time for this PHY.
Definition: wifi-phy.cc:764
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:1375
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:740
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:728
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1415
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).
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.
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.
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.
bool IsValid() const
The standard disallows certain combinations of WifiMode, number of spatial streams,...
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void 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
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:86
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1426
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:160
#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
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:243
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:229
#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:45
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
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.
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.
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.
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:535
uint16_t GetChannelWidthForTransmission(WifiMode mode, uint16_t maxAllowedChannelWidth)
Return the channel width that is allowed based on the selected mode and the given maximum channel wid...
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.
std::vector< WifiMode > WifiModeList
In various parts of the code, folk are interested in maintaining a list of transmission modes.
Definition: wifi-mode.h:261
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.
std::vector< struct GroupInfo > McsGroupData
Data structure for a table of groups.
static const uint8_t MAX_VHT_WIDTH
Maximal channel width in MHz.
static const uint8_t MAX_HE_SUPPORTED_STREAMS
Maximal number of streams supported by the HE PHY layer.
mac
Definition: third.py:85
phy
Definition: third.py:82
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
bool m_sampleDeferred
a flag to indicate sample rate is on the second stage
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.