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),
1094 GetPhy()->GetTxBandwidth(mode, group.chWidth),
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,
1184 GetPhy()->GetTxBandwidth(rtsRate, GetChannelWidth(station)),
1185 GetAggregation(station));
1186 }
1187}
1188
1189bool
1191 Ptr<const Packet> packet,
1192 bool normally)
1193{
1194 NS_LOG_FUNCTION(this << st << packet << normally);
1195
1196 MinstrelHtWifiRemoteStation* station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1197
1198 CheckInit(station);
1199 if (!station->m_initialized)
1200 {
1201 return normally;
1202 }
1203
1204 uint32_t maxRetries;
1205
1206 if (!station->m_isHt)
1207 {
1208 maxRetries = m_legacyManager->CountRetries(station);
1209 }
1210 else
1211 {
1212 maxRetries = CountRetries(station);
1213 }
1214
1215 if (station->m_longRetry >= maxRetries)
1216 {
1217 NS_LOG_DEBUG("No re-transmission allowed. Retries: " << station->m_longRetry
1218 << " Max retries: " << maxRetries);
1219 return false;
1220 }
1221 else
1222 {
1223 NS_LOG_DEBUG("Re-transmit. Retries: " << station->m_longRetry
1224 << " Max retries: " << maxRetries);
1225 return true;
1226 }
1227}
1228
1231{
1232 uint8_t maxProbRateId = GetRateId(station->m_maxProbRate);
1233 uint8_t maxProbGroupId = GetGroupId(station->m_maxProbRate);
1234 uint8_t maxTpRateId = GetRateId(station->m_maxTpRate);
1235 uint8_t maxTpGroupId = GetGroupId(station->m_maxTpRate);
1236 uint8_t maxTp2RateId = GetRateId(station->m_maxTpRate2);
1237 uint8_t maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1238
1239 if (!station->m_isSampling)
1240 {
1241 return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
1242 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
1243 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1244 }
1245 else
1246 {
1247 return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1248 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1249 }
1250}
1251
1252uint16_t
1254{
1255 NS_LOG_FUNCTION(this << station);
1256 uint8_t sampleGroup = station->m_sampleGroup;
1257 uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1258 uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1259 uint8_t sampleIndex = station->m_sampleTable[index][col];
1260 uint16_t rateIndex = GetIndex(sampleGroup, sampleIndex);
1261 NS_LOG_DEBUG("Next Sample is " << rateIndex);
1262 SetNextSample(station); // Calculate the next sample rate.
1263 return rateIndex;
1264}
1265
1266void
1268{
1269 NS_LOG_FUNCTION(this << station);
1270 do
1271 {
1272 station->m_sampleGroup++;
1273 station->m_sampleGroup %= m_numGroups;
1274 } while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1275
1276 station->m_groupsTable[station->m_sampleGroup].m_index++;
1277
1278 uint8_t sampleGroup = station->m_sampleGroup;
1279 uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1280 uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1281
1282 if (index >= m_numRates)
1283 {
1284 station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1285 station->m_groupsTable[station->m_sampleGroup].m_col++;
1286 if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1287 {
1288 station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1289 }
1290 index = station->m_groupsTable[station->m_sampleGroup].m_index;
1291 col = station->m_groupsTable[sampleGroup].m_col;
1292 }
1293 NS_LOG_DEBUG("New sample set: group= " << +sampleGroup
1294 << " index= " << +station->m_sampleTable[index][col]);
1295}
1296
1297uint16_t
1299{
1300 NS_LOG_FUNCTION(this << station);
1301 NS_LOG_DEBUG("FindRate packet=" << station->m_totalPacketsCount);
1302
1303 if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1304 {
1305 return station->m_maxTpRate;
1306 }
1307
1308 // If we have waited enough, then sample.
1309 if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1310 {
1311 // SAMPLING
1312 NS_LOG_DEBUG("Obtaining a sampling rate");
1314 uint16_t sampleIdx = GetNextSample(station);
1315 NS_LOG_DEBUG("Sampling rate = " << sampleIdx);
1316
1317 // Evaluate if the sampling rate selected should be used.
1318 uint8_t sampleGroupId = GetGroupId(sampleIdx);
1319 uint8_t sampleRateId = GetRateId(sampleIdx);
1320
1321 // If the rate selected is not supported, then don't sample.
1322 if (station->m_groupsTable[sampleGroupId].m_supported &&
1323 station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1324 {
1332 MinstrelHtRateInfo sampleRateInfo =
1333 station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1334
1335 NS_LOG_DEBUG("Use sample rate? MaxTpRate= "
1336 << station->m_maxTpRate << " CurrentRate= " << station->m_txrate
1337 << " SampleRate= " << sampleIdx
1338 << " SampleProb= " << sampleRateInfo.ewmaProb);
1339
1340 if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2 &&
1341 sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1342 {
1348 uint8_t maxTpGroupId = GetGroupId(station->m_maxTpRate);
1349 uint8_t maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1350 uint8_t maxTp2RateId = GetRateId(station->m_maxTpRate2);
1351 uint8_t maxProbGroupId = GetGroupId(station->m_maxProbRate);
1352 uint8_t maxProbRateId = GetRateId(station->m_maxProbRate);
1353
1354 uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1355 uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1356
1357 Time sampleDuration = sampleRateInfo.perfectTxTime;
1358 Time maxTp2Duration =
1359 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1360 Time maxProbDuration = station->m_groupsTable[maxProbGroupId]
1361 .m_ratesTable[maxProbRateId]
1362 .perfectTxTime;
1363
1364 NS_LOG_DEBUG("Use sample rate? SampleDuration= "
1365 << sampleDuration << " maxTp2Duration= " << maxTp2Duration
1366 << " maxProbDuration= " << maxProbDuration << " sampleStreams= "
1367 << +sampleStreams << " maxTpStreams= " << +maxTpStreams);
1368 if (sampleDuration < maxTp2Duration ||
1369 (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1370 {
1372 station->m_isSampling = true;
1373
1375 station->m_sampleRate = sampleIdx;
1376
1377 NS_LOG_DEBUG("FindRate "
1378 << "sampleRate=" << sampleIdx);
1379 station->m_sampleTries--;
1380 return sampleIdx;
1381 }
1382 else
1383 {
1384 station->m_numSamplesSlow++;
1385 if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1386 {
1388 station->m_isSampling = true;
1389
1391 station->m_sampleRate = sampleIdx;
1392
1393 NS_LOG_DEBUG("FindRate "
1394 << "sampleRate=" << sampleIdx);
1395 station->m_sampleTries--;
1396 return sampleIdx;
1397 }
1398 }
1399 }
1400 }
1401 }
1402 if (station->m_sampleWait > 0)
1403 {
1404 station->m_sampleWait--;
1405 }
1406
1408
1409 NS_LOG_DEBUG("FindRate "
1410 << "maxTpRrate=" << station->m_maxTpRate);
1411 return station->m_maxTpRate;
1412}
1413
1414void
1416{
1417 NS_LOG_FUNCTION(this << station);
1418
1420
1421 station->m_numSamplesSlow = 0;
1422 station->m_sampleCount = 0;
1423
1424 double tempProb;
1425
1426 if (station->m_ampduPacketCount > 0)
1427 {
1428 uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1429 station->m_avgAmpduLen =
1430 (newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel)) / 100;
1431 station->m_ampduLen = 0;
1432 station->m_ampduPacketCount = 0;
1433 }
1434
1435 /* Initialize global rate indexes */
1436 station->m_maxTpRate = GetLowestIndex(station);
1437 station->m_maxTpRate2 = GetLowestIndex(station);
1438 station->m_maxProbRate = GetLowestIndex(station);
1439
1441 for (uint8_t j = 0; j < m_numGroups; j++)
1442 {
1443 if (station->m_groupsTable[j].m_supported)
1444 {
1445 station->m_sampleCount++;
1446
1447 /* (re)Initialize group rate indexes */
1448 station->m_groupsTable[j].m_maxTpRate = GetLowestIndex(station, j);
1449 station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex(station, j);
1450 station->m_groupsTable[j].m_maxProbRate = GetLowestIndex(station, j);
1451
1452 for (uint8_t i = 0; i < m_numRates; i++)
1453 {
1454 if (station->m_groupsTable[j].m_ratesTable[i].supported)
1455 {
1456 station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1457
1459 +i << " "
1460 << GetMcsSupported(station,
1461 station->m_groupsTable[j].m_ratesTable[i].mcsIndex)
1462 << "\t attempt="
1463 << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt
1464 << "\t success="
1465 << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1466
1468 if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1469 {
1470 station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1475 tempProb =
1476 (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) /
1477 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1478
1480 station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1481
1482 if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1483 {
1484 station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1485 }
1486 else
1487 {
1488 station->m_groupsTable[j].m_ratesTable[i].ewmsdProb =
1489 CalculateEwmsd(station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1490 tempProb,
1491 station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1492 m_ewmaLevel);
1494 tempProb =
1495 (tempProb * (100 - m_ewmaLevel) +
1496 station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) /
1497 100;
1498 station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1499 }
1500
1501 station->m_groupsTable[j].m_ratesTable[i].throughput =
1502 CalculateThroughput(station, j, i, tempProb);
1503
1504 station->m_groupsTable[j].m_ratesTable[i].successHist +=
1505 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1506 station->m_groupsTable[j].m_ratesTable[i].attemptHist +=
1507 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1508 }
1509 else
1510 {
1511 station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1512 }
1513
1515 station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess =
1516 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1517 station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt =
1518 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1519 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1520 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1521
1522 if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1523 {
1524 SetBestStationThRates(station, GetIndex(j, i));
1525 SetBestProbabilityRate(station, GetIndex(j, i));
1526 }
1527 }
1528 }
1529 }
1530 }
1531
1532 // Try to sample all available rates during each interval.
1533 station->m_sampleCount *= 8;
1534
1535 // Recalculate retries for the rates selected.
1536 CalculateRetransmits(station, station->m_maxTpRate);
1537 CalculateRetransmits(station, station->m_maxTpRate2);
1538 CalculateRetransmits(station, station->m_maxProbRate);
1539
1540 NS_LOG_DEBUG("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2
1541 << "\nmax prob=" << station->m_maxProbRate);
1542 if (m_printStats)
1543 {
1544 PrintTable(station);
1545 }
1546}
1547
1548double
1550 uint8_t groupId,
1551 uint8_t rateId,
1552 double ewmaProb)
1553{
1559 if (ewmaProb < 10)
1560 {
1561 return 0;
1562 }
1563 else
1564 {
1569 Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1570 if (ewmaProb > 90)
1571 {
1572 return 90 / txTime.GetSeconds();
1573 }
1574 else
1575 {
1576 return ewmaProb / txTime.GetSeconds();
1577 }
1578 }
1579}
1580
1581void
1583{
1584 GroupInfo* group;
1585 MinstrelHtRateInfo rate;
1586 uint8_t tmpGroupId;
1587 uint8_t tmpRateId;
1588 double tmpTh;
1589 double tmpProb;
1590 uint8_t groupId;
1591 uint8_t rateId;
1592 double currentTh;
1593 // maximum group probability (GP) variables
1594 uint8_t maxGPGroupId;
1595 uint8_t maxGPRateId;
1596 double maxGPTh;
1597
1598 groupId = GetGroupId(index);
1599 rateId = GetRateId(index);
1600 group = &station->m_groupsTable[groupId];
1601 rate = group->m_ratesTable[rateId];
1602
1603 tmpGroupId = GetGroupId(station->m_maxProbRate);
1604 tmpRateId = GetRateId(station->m_maxProbRate);
1605 tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1606 tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1607
1608 if (rate.ewmaProb > 75)
1609 {
1610 currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1611 if (currentTh > tmpTh)
1612 {
1613 station->m_maxProbRate = index;
1614 }
1615
1616 maxGPGroupId = GetGroupId(group->m_maxProbRate);
1617 maxGPRateId = GetRateId(group->m_maxProbRate);
1618 maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1619
1620 if (currentTh > maxGPTh)
1621 {
1622 group->m_maxProbRate = index;
1623 }
1624 }
1625 else
1626 {
1627 if (rate.ewmaProb > tmpProb)
1628 {
1629 station->m_maxProbRate = index;
1630 }
1631 maxGPRateId = GetRateId(group->m_maxProbRate);
1632 if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1633 {
1634 group->m_maxProbRate = index;
1635 }
1636 }
1637}
1638
1639/*
1640 * Find & sort topmost throughput rates
1641 *
1642 * If multiple rates provide equal throughput the sorting is based on their
1643 * current success probability. Higher success probability is preferred among
1644 * MCS groups.
1645 */
1646void
1648{
1649 uint8_t groupId;
1650 uint8_t rateId;
1651 double th;
1652 double prob;
1653 uint8_t maxTpGroupId;
1654 uint8_t maxTpRateId;
1655 uint8_t maxTp2GroupId;
1656 uint8_t maxTp2RateId;
1657 double maxTpTh;
1658 double maxTpProb;
1659 double maxTp2Th;
1660 double maxTp2Prob;
1661
1662 groupId = GetGroupId(index);
1663 rateId = GetRateId(index);
1664 prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1665 th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1666
1667 maxTpGroupId = GetGroupId(station->m_maxTpRate);
1668 maxTpRateId = GetRateId(station->m_maxTpRate);
1669 maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1670 maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1671
1672 maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1673 maxTp2RateId = GetRateId(station->m_maxTpRate2);
1674 maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1675 maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1676
1677 if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1678 {
1679 station->m_maxTpRate2 = station->m_maxTpRate;
1680 station->m_maxTpRate = index;
1681 }
1682 else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1683 {
1684 station->m_maxTpRate2 = index;
1685 }
1686
1687 // Find best rates per group
1688
1689 GroupInfo* group = &station->m_groupsTable[groupId];
1690 maxTpGroupId = GetGroupId(group->m_maxTpRate);
1691 maxTpRateId = GetRateId(group->m_maxTpRate);
1692 maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1693 maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1694
1695 maxTp2GroupId = GetGroupId(group->m_maxTpRate2);
1696 maxTp2RateId = GetRateId(group->m_maxTpRate2);
1697 maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1698 maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1699
1700 if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1701 {
1702 group->m_maxTpRate2 = group->m_maxTpRate;
1703 group->m_maxTpRate = index;
1704 }
1705 else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1706 {
1707 group->m_maxTpRate2 = index;
1708 }
1709}
1710
1711void
1713{
1714 NS_LOG_FUNCTION(this << station);
1715
1717
1721 NS_LOG_DEBUG("Supported groups by station:");
1722 bool noSupportedGroupFound = true;
1723 for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1724 {
1725 if (m_minstrelGroups[groupId].isSupported)
1726 {
1727 station->m_groupsTable[groupId].m_supported = false;
1728
1729 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1730 !GetHeSupported(station))
1731 {
1732 // It is a HE group but the receiver does not support HE: skip
1733 continue;
1734 }
1735 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_VHT) &&
1736 !GetVhtSupported(station))
1737 {
1738 // It is a VHT group but the receiver does not support VHT: skip
1739 continue;
1740 }
1741 if ((m_minstrelGroups[groupId].type != WIFI_MINSTREL_GROUP_HE) &&
1743 {
1744 // It is not a HE group and the receiver supports HE: skip since
1745 // UseLatestAmendmentOnly attribute is enabled
1746 continue;
1747 }
1748 if (!GetHeSupported(station) &&
1751 {
1752 // It is not a VHT group and the receiver supports VHT (but not HE): skip since
1753 // UseLatestAmendmentOnly attribute is enabled
1754 continue;
1755 }
1756 if (((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HT) ||
1758 (m_minstrelGroups[groupId].gi == 400) && !GetShortGuardIntervalSupported(station))
1759 {
1760 // It is a SGI group but the receiver does not support SGI: skip
1761 continue;
1762 }
1763 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1764 (m_minstrelGroups[groupId].gi < GetGuardInterval(station)))
1765 {
1766 // The receiver does not support the GI: skip
1767 continue;
1768 }
1769 if (GetChannelWidth(station) < m_minstrelGroups[groupId].chWidth)
1770 {
1771 // The receiver does not support the channel width: skip
1772 continue;
1773 }
1774 if (GetNumberOfSupportedStreams(station) < m_minstrelGroups[groupId].streams)
1775 {
1776 // The receiver does not support the number of spatial streams: skip
1777 continue;
1778 }
1779
1780 NS_LOG_DEBUG("Group: " << +groupId << " type: " << m_minstrelGroups[groupId].type
1781 << " streams: " << +m_minstrelGroups[groupId].streams
1782 << " GI: " << m_minstrelGroups[groupId].gi
1783 << " width: " << m_minstrelGroups[groupId].chWidth);
1784
1785 noSupportedGroupFound = false;
1786 station->m_groupsTable[groupId].m_supported = true;
1787 station->m_groupsTable[groupId].m_col = 0;
1788 station->m_groupsTable[groupId].m_index = 0;
1789
1790 station->m_groupsTable[groupId].m_ratesTable =
1792 for (uint8_t i = 0; i < m_numRates; i++)
1793 {
1794 station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1795 }
1796
1797 // Initialize all modes supported by the remote station that belong to the current
1798 // group.
1799 for (uint8_t i = 0; i < station->m_nModes; i++)
1800 {
1801 WifiMode mode = GetMcsSupported(station, i);
1802
1805 uint8_t rateId = mode.GetMcsValue();
1807 {
1808 rateId %= MAX_HT_GROUP_RATES;
1809 }
1810
1811 if (((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1812 (mode.GetModulationClass() ==
1814 && IsValidMcs(GetPhy(),
1815 m_minstrelGroups[groupId].streams,
1816 m_minstrelGroups[groupId].chWidth,
1817 mode))
1818 || ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_VHT) &&
1819 (mode.GetModulationClass() ==
1821 && IsValidMcs(GetPhy(),
1822 m_minstrelGroups[groupId].streams,
1823 m_minstrelGroups[groupId].chWidth,
1824 mode))
1825 || ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HT) &&
1826 (mode.GetModulationClass() ==
1828 && (mode.GetMcsValue() <
1829 (m_minstrelGroups[groupId].streams *
1830 8))
1831 && (mode.GetMcsValue() >= ((m_minstrelGroups[groupId].streams - 1) * 8))))
1832 {
1833 NS_LOG_DEBUG("Mode " << +i << ": " << mode);
1834
1835 station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1836 station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex =
1837 i;
1838 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1839 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1840 station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1841 station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1842 station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1843 station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1844 station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1845 station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1846 station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1847 station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1848 station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime =
1849 GetFirstMpduTxTime(groupId, GetMcsSupported(station, i));
1850 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1851 station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1852 CalculateRetransmits(station, groupId, rateId);
1853 }
1854 }
1855 }
1856 }
1859 if (noSupportedGroupFound)
1860 {
1861 NS_FATAL_ERROR("No supported group has been found");
1862 }
1863 SetNextSample(station);
1864 UpdateStats(station);
1865 station->m_txrate = FindRate(station);
1866}
1867
1868void
1870{
1871 NS_LOG_FUNCTION(this << station << index);
1872 uint8_t groupId = GetGroupId(index);
1873 uint8_t rateId = GetRateId(index);
1874 if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1875 {
1876 CalculateRetransmits(station, groupId, rateId);
1877 }
1878}
1879
1880void
1882 uint8_t groupId,
1883 uint8_t rateId)
1884{
1885 NS_LOG_FUNCTION(this << station << +groupId << +rateId);
1886
1887 uint32_t cw = 15; // Is an approximation.
1888 uint32_t cwMax = 1023;
1889 Time cwTime;
1890 Time txTime;
1891 Time dataTxTime;
1892 Time slotTime = GetPhy()->GetSlot();
1893 Time ackTime = GetPhy()->GetSifs() + GetPhy()->GetBlockAckTxTime();
1894
1895 if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1896 {
1897 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1898 }
1899 else
1900 {
1901 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1902 station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1903
1904 dataTxTime =
1906 groupId,
1907 GetMcsSupported(station,
1908 station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1910 groupId,
1911 GetMcsSupported(station,
1912 station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) *
1913 (station->m_avgAmpduLen - 1);
1914
1915 /* Contention time for first 2 tries */
1916 cwTime = (cw / 2) * slotTime;
1917 cw = Min((cw + 1) * 2, cwMax);
1918 cwTime += (cw / 2) * slotTime;
1919 cw = Min((cw + 1) * 2, cwMax);
1920
1921 /* Total TX time for data and Contention after first 2 tries */
1922 txTime = cwTime + 2 * (dataTxTime + ackTime);
1923
1924 /* See how many more tries we can fit inside segment size */
1925 do
1926 {
1927 /* Contention time for this try */
1928 cwTime = (cw / 2) * slotTime;
1929 cw = Min((cw + 1) * 2, cwMax);
1930
1931 /* Total TX time after this try */
1932 txTime += cwTime + ackTime + dataTxTime;
1933 } while ((txTime < MilliSeconds(6)) &&
1934 (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1935 }
1936}
1937
1938double
1940 double currentProb,
1941 double ewmaProb,
1942 double weight)
1943{
1944 double diff;
1945 double incr;
1946 double tmp;
1947
1948 /* calculate exponential weighted moving variance */
1949 diff = currentProb - ewmaProb;
1950 incr = (100 - weight) * diff / 100;
1951 tmp = oldEwmsd * oldEwmsd;
1952 tmp = weight * (tmp + diff * incr) / 100;
1953
1954 /* return standard deviation */
1955 return sqrt(tmp);
1956}
1957
1958void
1960{
1961 NS_LOG_FUNCTION(this << station);
1962 station->m_col = station->m_index = 0;
1963
1964 // for off-setting to make rates fall between 0 and nModes
1965 uint8_t numSampleRates = m_numRates;
1966
1967 uint16_t newIndex;
1968 for (uint8_t col = 0; col < m_nSampleCol; col++)
1969 {
1970 for (uint8_t i = 0; i < numSampleRates; i++)
1971 {
1976 int uv = m_uniformRandomVariable->GetInteger(0, numSampleRates);
1977 newIndex = (i + uv) % numSampleRates;
1978
1979 // this loop is used for filling in other uninitialized places
1980 while (station->m_sampleTable[newIndex][col] != 0)
1981 {
1982 newIndex = (newIndex + 1) % m_numRates;
1983 }
1984 station->m_sampleTable[newIndex][col] = i;
1985 }
1986 }
1987}
1988
1989void
1991{
1992 if (!station->m_statsFile.is_open())
1993 {
1994 std::ostringstream tmp;
1995 tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1996 station->m_statsFile.open(tmp.str(), std::ios::out);
1997 }
1998
1999 station->m_statsFile
2000 << " best ____________rate__________ ________statistics________ "
2001 "________last_______ ______sum-of________\n"
2002 << " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] "
2003 "[prob.|retry|suc|att] [#success | #attempts]\n";
2004 for (uint8_t i = 0; i < m_numGroups; i++)
2005 {
2006 StatsDump(station, i, station->m_statsFile);
2007 }
2008
2009 station->m_statsFile << "\nTotal packet count:: ideal "
2010 << Max(0, station->m_totalPacketsCount - station->m_samplePacketsCount)
2011 << " lookaround " << station->m_samplePacketsCount << "\n";
2012 station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen
2013 << "\n\n";
2014
2015 station->m_statsFile.flush();
2016}
2017
2018void
2020 uint8_t groupId,
2021 std::ofstream& of)
2022{
2023 uint8_t numRates = m_numRates;
2024 McsGroup group = m_minstrelGroups[groupId];
2025 Time txTime;
2026 for (uint8_t i = 0; i < numRates; i++)
2027 {
2028 if (station->m_groupsTable[groupId].m_supported &&
2029 station->m_groupsTable[groupId].m_ratesTable[i].supported)
2030 {
2031 of << group.type << " " << group.chWidth << " " << group.gi << " " << +group.streams
2032 << " ";
2033
2034 uint16_t maxTpRate = station->m_maxTpRate;
2035 uint16_t maxTpRate2 = station->m_maxTpRate2;
2036 uint16_t maxProbRate = station->m_maxProbRate;
2037
2038 uint16_t idx = GetIndex(groupId, i);
2039 if (idx == maxTpRate)
2040 {
2041 of << 'A';
2042 }
2043 else
2044 {
2045 of << ' ';
2046 }
2047 if (idx == maxTpRate2)
2048 {
2049 of << 'B';
2050 }
2051 else
2052 {
2053 of << ' ';
2054 }
2055 if (idx == maxProbRate)
2056 {
2057 of << 'P';
2058 }
2059 else
2060 {
2061 of << ' ';
2062 }
2063
2064 if (group.type == WIFI_MINSTREL_GROUP_HT)
2065 {
2066 of << std::setw(4) << " MCS" << (group.streams - 1) * 8 + i;
2067 }
2068 else
2069 {
2070 of << std::setw(7) << " MCS" << +i << "/" << static_cast<int>(group.streams);
2071 }
2072
2073 of << " " << std::setw(3) << +idx << " ";
2074
2075 /* tx_time[rate(i)] in usec */
2076 txTime = GetFirstMpduTxTime(
2077 groupId,
2078 GetMcsSupported(station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
2079 of << std::setw(6) << txTime.GetMicroSeconds() << " ";
2080
2081 of << std::setw(7) << CalculateThroughput(station, groupId, i, 100) / 100 << " "
2082 << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100
2083 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb
2084 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb
2085 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].prob
2086 << " " << std::setw(2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount
2087 << " " << std::setw(3)
2088 << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " "
2089 << std::setw(3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt
2090 << " " << std::setw(9)
2091 << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " "
2092 << std::setw(9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist
2093 << "\n";
2094 }
2095 }
2096}
2097
2098uint16_t
2099MinstrelHtWifiManager::GetIndex(uint8_t groupId, uint8_t rateId)
2100{
2101 NS_LOG_FUNCTION(this << +groupId << +rateId);
2102 uint16_t index;
2103 index = groupId * m_numRates + rateId;
2104 return index;
2105}
2106
2107uint8_t
2109{
2110 NS_LOG_FUNCTION(this << index);
2111 uint8_t id;
2112 id = index % m_numRates;
2113 return id;
2114}
2115
2116uint8_t
2118{
2119 NS_LOG_FUNCTION(this << index);
2120 return index / m_numRates;
2121}
2122
2123uint8_t
2124MinstrelHtWifiManager::GetHtGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2125{
2126 NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2127 uint8_t giIndex = (gi == 400) ? 1 : 0;
2128 uint8_t widthIndex = (chWidth == 40) ? 1 : 0;
2129 return (MAX_HT_SUPPORTED_STREAMS * 2 * widthIndex) + (MAX_HT_SUPPORTED_STREAMS * giIndex) +
2130 txstreams - 1;
2131}
2132
2133uint8_t
2134MinstrelHtWifiManager::GetVhtGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2135{
2136 NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2137 uint8_t giIndex = (gi == 400) ? 1 : 0;
2138 uint8_t widthIndex;
2139 if (chWidth == 160)
2140 {
2141 widthIndex = 3;
2142 }
2143 else if (chWidth == 80)
2144 {
2145 widthIndex = 2;
2146 }
2147 else if (chWidth == 40)
2148 {
2149 widthIndex = 1;
2150 }
2151 else // 20 MHz
2152 {
2153 widthIndex = 0;
2154 }
2155 uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
2156 groupId += (MAX_VHT_SUPPORTED_STREAMS * 2 * widthIndex) +
2157 (MAX_VHT_SUPPORTED_STREAMS * giIndex) + txstreams - 1;
2158 return groupId;
2159}
2160
2161uint8_t
2162MinstrelHtWifiManager::GetHeGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2163{
2164 NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2165 uint8_t giIndex;
2166 if (gi == 800)
2167 {
2168 giIndex = 2;
2169 }
2170 else if (gi == 1600)
2171 {
2172 giIndex = 1;
2173 }
2174 else // 3200 ns
2175 {
2176 giIndex = 0;
2177 }
2178 uint8_t widthIndex;
2179 if (chWidth == 160)
2180 {
2181 widthIndex = 3;
2182 }
2183 else if (chWidth == 80)
2184 {
2185 widthIndex = 2;
2186 }
2187 else if (chWidth == 40)
2188 {
2189 widthIndex = 1;
2190 }
2191 else // 20 MHz
2192 {
2193 widthIndex = 0;
2194 }
2195 uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
2196 if (GetVhtSupported())
2197 {
2199 }
2200 groupId += (MAX_HE_SUPPORTED_STREAMS * 3 * widthIndex) + (MAX_HE_SUPPORTED_STREAMS * giIndex) +
2201 txstreams - 1;
2202 return groupId;
2203}
2204
2205uint16_t
2207{
2208 NS_LOG_FUNCTION(this << station);
2209
2210 uint8_t groupId = 0;
2211 uint8_t rateId = 0;
2212 while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
2213 {
2214 groupId++;
2215 }
2216 while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
2217 {
2218 rateId++;
2219 }
2220 NS_ASSERT(station->m_groupsTable[groupId].m_supported &&
2221 station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
2222 return GetIndex(groupId, rateId);
2223}
2224
2225uint16_t
2227{
2228 NS_LOG_FUNCTION(this << station << +groupId);
2229
2230 uint8_t rateId = 0;
2231 while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
2232 {
2233 rateId++;
2234 }
2235 NS_ASSERT(station->m_groupsTable[groupId].m_supported &&
2236 station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
2237 return GetIndex(groupId, rateId);
2238}
2239
2242{
2243 WifiModeList heMcsList;
2244 for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_HE))
2245 {
2246 heMcsList.push_back(mode);
2247 }
2248 return heMcsList;
2249}
2250
2253{
2254 WifiModeList vhtMcsList;
2255 for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_VHT))
2256 {
2257 vhtMcsList.push_back(mode);
2258 }
2259 return vhtMcsList;
2260}
2261
2264{
2265 WifiModeList htMcsList;
2266 for (const auto& mode : GetPhy()->GetMcsList(WIFI_MOD_CLASS_HT))
2267 {
2268 htMcsList.push_back(mode);
2269 }
2270 return htMcsList;
2271}
2272
2273} // 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:1423
a unique identifier for an interface.
Definition: type-id.h:59
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 drawn from the distribution.
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:810
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:1433
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:786
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:774
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:1050
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1473
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:1424
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: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
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:46
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
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
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.