A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
minstrel-ht-wifi-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 Duy Nguyen
3 * Copyright (c) 2015 Ghada Badawy
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Authors: Duy Nguyen <duy@soe.ucsc.edu>
19 * Ghada Badawy <gbadawy@gmail.com>
20 * Matias Richart <mrichart@fing.edu.uy>
21 *
22 * Some Comments:
23 *
24 * 1) By default, Minstrel applies the multi-rate retry (the core of Minstrel
25 * algorithm). Otherwise, please use ConstantRateWifiManager instead.
26 *
27 * 2) Sampling is done differently from legacy Minstrel. Minstrel-HT tries
28 * to sample all rates in all groups at least once and to avoid many
29 * consecutive samplings.
30 *
31 * 3) Sample rate is tried only once, at first place of the MRR chain.
32 *
33 * reference: http://lwn.net/Articles/376765/
34 */
35
37
38#include "ns3/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(false);
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);
483 auto station = new MinstrelHtWifiRemoteStation();
484
485 // Initialize variables common to both stations.
486 station->m_nextStatsUpdate = Simulator::Now() + m_updateStats;
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 // Use the variable in the station to indicate whether the device supports HT.
515 // When correct information available it will be checked.
516 station->m_isHt = GetHtSupported();
517
518 return station;
519}
520
521void
523{
524 NS_LOG_FUNCTION(this << station);
525 // Note: we appear to be doing late initialization of the table
526 // to make sure that the set of supported rates has been initialized
527 // before we perform our own initialization.
528 if (!station->m_initialized)
529 {
536 if (!GetHtSupported(station))
537 {
538 NS_LOG_INFO("non-HT station " << station);
539 station->m_isHt = false;
540 // We will use non-HT minstrel for this station. Initialize the manager.
541 m_legacyManager->SetAttribute("UpdateStatistics", TimeValue(m_legacyUpdateStats));
542 m_legacyManager->SetAttribute("LookAroundRate", UintegerValue(m_lookAroundRate));
543 m_legacyManager->SetAttribute("EWMA", UintegerValue(m_ewmaLevel));
544 m_legacyManager->SetAttribute("SampleColumn", UintegerValue(m_nSampleCol));
545 m_legacyManager->SetAttribute("PacketLength", UintegerValue(m_frameLength));
546 m_legacyManager->SetAttribute("PrintStats", BooleanValue(m_printStats));
547 m_legacyManager->CheckInit(station);
548 }
549 else
550 {
551 NS_LOG_DEBUG("HT station " << station);
552 station->m_isHt = true;
553 station->m_nModes = GetNMcsSupported(station);
554 station->m_minstrelTable = MinstrelRate(station->m_nModes);
555 station->m_sampleTable = SampleRate(m_numRates, std::vector<uint8_t>(m_nSampleCol));
556 InitSampleTable(station);
557 RateInit(station);
558 station->m_initialized = true;
559 }
560 }
561}
562
563void
565{
566 NS_LOG_FUNCTION(this << st);
568 "DoReportRxOk m_txrate=" << static_cast<MinstrelHtWifiRemoteStation*>(st)->m_txrate);
569}
570
571void
573{
574 NS_LOG_FUNCTION(this << st);
575 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
576 CheckInit(station);
577 if (!station->m_initialized)
578 {
579 return;
580 }
581 NS_LOG_DEBUG("DoReportRtsFailed m_txrate = " << station->m_txrate);
582 station->m_shortRetry++;
583}
584
585void
587 double ctsSnr,
588 WifiMode ctsMode,
589 double rtsSnr)
590{
591 NS_LOG_FUNCTION(this << st);
592}
593
594void
596{
597 NS_LOG_FUNCTION(this << st);
598 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
599 NS_LOG_DEBUG("Final RTS failed");
600 CheckInit(station);
601 if (!station->m_initialized)
602 {
603 return;
604 }
605 UpdateRetry(station);
606}
607
608void
610{
611 NS_LOG_FUNCTION(this << st);
612 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
613
614 CheckInit(station);
615 if (!station->m_initialized)
616 {
617 return;
618 }
619
620 NS_LOG_DEBUG("DoReportDataFailed " << station << "\t rate " << station->m_txrate
621 << "\tlongRetry \t" << station->m_longRetry);
622
623 if (!station->m_isHt)
624 {
625 m_legacyManager->UpdateRate(station);
626 }
627 else if (station->m_longRetry < CountRetries(station))
628 {
629 uint8_t rateId = GetRateId(station->m_txrate);
630 uint8_t groupId = GetGroupId(station->m_txrate);
631 station->m_groupsTable[groupId]
632 .m_ratesTable[rateId]
633 .numRateAttempt++; // Increment the attempts counter for the rate used.
634 UpdateRate(station);
635 }
636}
637
638void
640 double ackSnr,
641 WifiMode ackMode,
642 double dataSnr,
643 uint16_t dataChannelWidth,
644 uint8_t dataNss)
645{
646 NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
647 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
648
649 CheckInit(station);
650 if (!station->m_initialized)
651 {
652 return;
653 }
654
655 NS_LOG_DEBUG("DoReportDataOk m_txrate = "
656 << station->m_txrate
657 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
658 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
659 << " (before update).");
660
661 if (!station->m_isHt)
662 {
663 station->m_minstrelTable[station->m_txrate].numRateSuccess++;
664 station->m_minstrelTable[station->m_txrate].numRateAttempt++;
665
666 m_legacyManager->UpdatePacketCounters(station);
667
668 NS_LOG_DEBUG("DoReportDataOk m_txrate = "
669 << station->m_txrate
670 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
671 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
672 << " (after update).");
673
674 UpdateRetry(station);
675 m_legacyManager->UpdateStats(station);
676
677 if (station->m_nModes >= 1)
678 {
679 station->m_txrate = m_legacyManager->FindRate(station);
680 }
681 }
682 else
683 {
684 uint8_t rateId = GetRateId(station->m_txrate);
685 uint8_t groupId = GetGroupId(station->m_txrate);
686 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
687 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
688
689 UpdatePacketCounters(station, 1, 0);
690
691 NS_LOG_DEBUG("DoReportDataOk m_txrate = "
692 << station->m_txrate
693 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
694 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
695 << " (after update).");
696
697 station->m_isSampling = false;
698 station->m_sampleDeferred = false;
699
700 UpdateRetry(station);
701 if (Simulator::Now() >= station->m_nextStatsUpdate)
702 {
703 UpdateStats(station);
704 }
705
706 if (station->m_nModes >= 1)
707 {
708 station->m_txrate = FindRate(station);
709 }
710 }
711
712 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
713}
714
715void
717{
718 NS_LOG_FUNCTION(this << st);
719 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
720
721 CheckInit(station);
722 if (!station->m_initialized)
723 {
724 return;
725 }
726
727 NS_LOG_DEBUG("DoReportFinalDataFailed - TxRate=" << station->m_txrate);
728
729 if (!station->m_isHt)
730 {
731 m_legacyManager->UpdatePacketCounters(station);
732
733 UpdateRetry(station);
734
735 m_legacyManager->UpdateStats(station);
736 if (station->m_nModes >= 1)
737 {
738 station->m_txrate = m_legacyManager->FindRate(station);
739 }
740 }
741 else
742 {
743 UpdatePacketCounters(station, 0, 1);
744
745 station->m_isSampling = false;
746 station->m_sampleDeferred = false;
747
748 UpdateRetry(station);
749 if (Simulator::Now() >= station->m_nextStatsUpdate)
750 {
751 UpdateStats(station);
752 }
753
754 if (station->m_nModes >= 1)
755 {
756 station->m_txrate = FindRate(station);
757 }
758 }
759 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
760}
761
762void
764 uint16_t nSuccessfulMpdus,
765 uint16_t nFailedMpdus,
766 double rxSnr,
767 double dataSnr,
768 uint16_t dataChannelWidth,
769 uint8_t dataNss)
770{
771 NS_LOG_FUNCTION(this << st << nSuccessfulMpdus << nFailedMpdus << rxSnr << dataSnr
772 << dataChannelWidth << +dataNss);
773 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
774
775 CheckInit(station);
776 if (!station->m_initialized)
777 {
778 return;
779 }
780
781 NS_ASSERT_MSG(station->m_isHt, "A-MPDU Tx Status called but this is a non-HT STA.");
782
783 NS_LOG_DEBUG("DoReportAmpduTxStatus. TxRate=" << station->m_txrate
784 << " SuccMpdus=" << nSuccessfulMpdus
785 << " FailedMpdus=" << nFailedMpdus);
786
787 station->m_ampduPacketCount++;
788 station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
789
790 UpdatePacketCounters(station, nSuccessfulMpdus, nFailedMpdus);
791
792 uint8_t rateId = GetRateId(station->m_txrate);
793 uint8_t groupId = GetGroupId(station->m_txrate);
794 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
795 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt +=
796 nSuccessfulMpdus + nFailedMpdus;
797
798 if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries(station))
799 {
800 // We do not receive a BlockAck. The entire AMPDU fail.
801 UpdateRate(station);
802 }
803 else
804 {
805 station->m_isSampling = false;
806 station->m_sampleDeferred = false;
807
808 UpdateRetry(station);
809 if (Simulator::Now() >= station->m_nextStatsUpdate)
810 {
811 UpdateStats(station);
812 }
813
814 if (station->m_nModes >= 1)
815 {
816 station->m_txrate = FindRate(station);
817 }
818 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
819 }
820}
821
822void
824{
825 NS_LOG_FUNCTION(this << station);
826
848 CheckInit(station);
849 if (!station->m_initialized)
850 {
851 return;
852 }
853 station->m_longRetry++;
854
858 uint8_t maxTpRateId = GetRateId(station->m_maxTpRate);
859 uint8_t maxTpGroupId = GetGroupId(station->m_maxTpRate);
860 uint8_t maxTp2RateId = GetRateId(station->m_maxTpRate2);
861 uint8_t maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
862 uint8_t maxProbRateId = GetRateId(station->m_maxProbRate);
863 uint8_t maxProbGroupId = GetGroupId(station->m_maxProbRate);
864
866 if (!station->m_isSampling)
867 {
869 if (station->m_longRetry <
870 station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
871 {
872 NS_LOG_DEBUG("Not Sampling; use the same rate again");
873 station->m_txrate = station->m_maxTpRate;
874 }
875
877 else if (station->m_longRetry <
878 (station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
879 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
880 {
881 NS_LOG_DEBUG("Not Sampling; use the Max TP2");
882 station->m_txrate = station->m_maxTpRate2;
883 }
884
886 else if (station->m_longRetry <=
887 (station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
888 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
889 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
890 {
891 NS_LOG_DEBUG("Not Sampling; use Max Prob");
892 station->m_txrate = station->m_maxProbRate;
893 }
894 else
895 {
896 NS_FATAL_ERROR("Max retries reached and m_longRetry not cleared properly. longRetry= "
897 << station->m_longRetry);
898 }
899 }
900
902 else
903 {
906 if (station->m_longRetry <
907 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
908 {
909 NS_LOG_DEBUG("Sampling use the MaxTP rate");
910 station->m_txrate = station->m_maxTpRate2;
911 }
912
914 else if (station->m_longRetry <=
915 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
916 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
917 {
918 NS_LOG_DEBUG("Sampling use the MaxProb rate");
919 station->m_txrate = station->m_maxProbRate;
920 }
921 else
922 {
923 NS_FATAL_ERROR("Max retries reached and m_longRetry not cleared properly. longRetry= "
924 << station->m_longRetry);
925 }
926 }
927 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
928}
929
930void
932{
933 NS_LOG_FUNCTION(this << station);
934 station->m_shortRetry = 0;
935 station->m_longRetry = 0;
936}
937
938void
940 uint16_t nSuccessfulMpdus,
941 uint16_t nFailedMpdus)
942{
943 NS_LOG_FUNCTION(this << station << nSuccessfulMpdus << nFailedMpdus);
944
945 station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
946 if (station->m_isSampling)
947 {
948 station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
949 }
950 if (station->m_totalPacketsCount == ~0)
951 {
952 station->m_samplePacketsCount = 0;
953 station->m_totalPacketsCount = 0;
954 }
955
956 if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
957 {
958 station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
959 station->m_sampleTries = 1;
960 station->m_sampleCount--;
961 }
962}
963
964uint16_t
965MinstrelHtWifiManager::UpdateRateAfterAllowedWidth(uint16_t txRate, uint16_t allowedWidth)
966{
967 NS_LOG_FUNCTION(this << txRate << allowedWidth);
968
969 auto groupId = GetGroupId(txRate);
970 McsGroup group = m_minstrelGroups[groupId];
971
972 if (group.chWidth <= allowedWidth)
973 {
974 NS_LOG_DEBUG("Channel width is not greater than allowed width, nothing to do");
975 return txRate;
976 }
977
979 NS_ASSERT(group.chWidth % 20 == 0);
980 // try halving the channel width and check if the group with the same number of
981 // streams and same GI is supported, until either a supported group is found or
982 // the width becomes lower than 20 MHz
983 uint16_t width = group.chWidth / 2;
984
985 while (width >= 20)
986 {
987 if (width > allowedWidth)
988 {
989 width /= 2;
990 continue;
991 }
992
993 switch (group.type)
994 {
996 groupId = GetHtGroupId(group.streams, group.gi, width);
997 break;
999 groupId = GetVhtGroupId(group.streams, group.gi, width);
1000 break;
1002 groupId = GetHeGroupId(group.streams, group.gi, width);
1003 break;
1004 default:
1005 NS_ABORT_MSG("Unknown group type: " << group.type);
1006 }
1007
1008 group = m_minstrelGroups[groupId];
1009 if (group.isSupported)
1010 {
1011 break;
1012 }
1013
1014 width /= 2;
1015 }
1016
1017 NS_ABORT_MSG_IF(width < 20, "No rate compatible with the allowed width found");
1018
1019 return GetIndex(groupId, GetRateId(txRate));
1020}
1021
1024{
1025 NS_LOG_FUNCTION(this << st << allowedWidth);
1026 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1027
1028 if (!station->m_initialized)
1029 {
1030 CheckInit(station);
1031 }
1032
1033 if (!station->m_isHt)
1034 {
1035 WifiTxVector vector = m_legacyManager->GetDataTxVector(station);
1036 uint64_t dataRate = vector.GetMode().GetDataRate(vector);
1037 if (m_currentRate != dataRate && !station->m_isSampling)
1038 {
1039 NS_LOG_DEBUG("New datarate: " << dataRate);
1040 m_currentRate = dataRate;
1041 }
1042 return vector;
1043 }
1044 else
1045 {
1046 station->m_txrate = UpdateRateAfterAllowedWidth(station->m_txrate, allowedWidth);
1047 NS_LOG_DEBUG("DoGetDataMode m_txrate= " << station->m_txrate);
1048
1049 uint8_t rateId = GetRateId(station->m_txrate);
1050 uint8_t groupId = GetGroupId(station->m_txrate);
1051 uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
1052
1053 NS_LOG_DEBUG("DoGetDataMode rateId= " << +rateId << " groupId= " << +groupId
1054 << " mode= " << GetMcsSupported(station, mcsIndex));
1055
1056 McsGroup group = m_minstrelGroups[groupId];
1057
1058 // Check consistency of rate selected.
1059 if (((group.type == WIFI_MINSTREL_GROUP_HE) && (group.gi < GetGuardInterval(station))) ||
1060 (((group.type == WIFI_MINSTREL_GROUP_HT) || (group.type == WIFI_MINSTREL_GROUP_VHT)) &&
1061 (group.gi == 400) && !GetShortGuardIntervalSupported(station)) ||
1062 (group.chWidth > GetChannelWidth(station)) ||
1063 (group.streams > GetNumberOfSupportedStreams(station)))
1064 {
1065 NS_FATAL_ERROR("Inconsistent group selected. Group: ("
1066 << +group.streams << "," << group.gi << "," << group.chWidth << ")"
1067 << " Station capabilities: (" << GetNumberOfSupportedStreams(station)
1068 << ","
1069 << ((group.type == WIFI_MINSTREL_GROUP_HE)
1070 ? GetGuardInterval(station)
1071 : (GetShortGuardIntervalSupported(station) ? 400 : 800))
1072 << "," << GetChannelWidth(station) << ")");
1073 }
1074 WifiMode mode = GetMcsSupported(station, mcsIndex);
1075 WifiTxVector txVector{
1076 mode,
1079 group.gi,
1081 group.streams,
1082 GetNess(station),
1083 GetPhy()->GetTxBandwidth(mode, group.chWidth),
1084 GetAggregation(station) && !station->m_isSampling};
1085 uint64_t dataRate = mode.GetDataRate(txVector);
1086 if (m_currentRate != dataRate && !station->m_isSampling)
1087 {
1088 NS_LOG_DEBUG("New datarate: " << dataRate);
1089 m_currentRate = dataRate;
1090 }
1091 return txVector;
1092 }
1093}
1094
1097{
1098 NS_LOG_FUNCTION(this << st);
1099 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1100
1101 if (!station->m_initialized)
1102 {
1103 CheckInit(station);
1104 }
1105
1106 if (!station->m_isHt)
1107 {
1108 return m_legacyManager->GetRtsTxVector(station);
1109 }
1110 else
1111 {
1112 NS_LOG_DEBUG("DoGetRtsMode m_txrate=" << station->m_txrate);
1113
1114 /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
1115 * When supported, decision of using HT has to follow rules in Section 9.7.6 from
1116 * 802.11-2012. From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is
1117 * carried in a non-HT PPDU shall be transmitted by the STA using a rate no higher than the
1118 * highest rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
1119 * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
1120 * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
1121 * these conditions, the control frame shall be transmitted at a rate no higher than the
1122 * highest mandatory rate of the attached PHY that is less than or equal to the rate
1123 * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
1124 * directed to the same receiving STA."
1125 */
1126
1127 // As we are in Minstrel HT, assume the last rate was an HT rate.
1128 uint8_t rateId = GetRateId(station->m_txrate);
1129 uint8_t groupId = GetGroupId(station->m_txrate);
1130 uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
1131
1132 WifiMode lastRate = GetMcsSupported(station, mcsIndex);
1133 uint64_t lastDataRate = lastRate.GetNonHtReferenceRate();
1134 uint8_t nBasicRates = GetNBasicModes();
1135
1136 WifiMode rtsRate;
1137 bool rateFound = false;
1138
1139 for (uint8_t i = 0; i < nBasicRates; i++)
1140 {
1141 uint64_t rate = GetBasicMode(i).GetDataRate(20);
1142 if (rate <= lastDataRate)
1143 {
1144 rtsRate = GetBasicMode(i);
1145 rateFound = true;
1146 }
1147 }
1148
1149 if (!rateFound)
1150 {
1151 Ptr<WifiPhy> phy = GetPhy();
1152 for (const auto& mode : phy->GetModeList())
1153 {
1154 uint64_t rate = mode.GetDataRate(20);
1155 if (rate <= lastDataRate)
1156 {
1157 rtsRate = mode;
1158 rateFound = true;
1159 }
1160 }
1161 }
1162
1163 NS_ASSERT(rateFound);
1164
1165 return WifiTxVector(
1166 rtsRate,
1169 800,
1170 1,
1171 1,
1172 0,
1173 GetPhy()->GetTxBandwidth(rtsRate, GetChannelWidth(station)),
1174 GetAggregation(station));
1175 }
1176}
1177
1178bool
1180 Ptr<const Packet> packet,
1181 bool normally)
1182{
1183 NS_LOG_FUNCTION(this << st << packet << normally);
1184
1185 auto station = static_cast<MinstrelHtWifiRemoteStation*>(st);
1186
1187 CheckInit(station);
1188 if (!station->m_initialized)
1189 {
1190 return normally;
1191 }
1192
1193 uint32_t maxRetries;
1194
1195 if (!station->m_isHt)
1196 {
1197 maxRetries = m_legacyManager->CountRetries(station);
1198 }
1199 else
1200 {
1201 maxRetries = CountRetries(station);
1202 }
1203
1204 if (station->m_longRetry >= maxRetries)
1205 {
1206 NS_LOG_DEBUG("No re-transmission allowed. Retries: " << station->m_longRetry
1207 << " Max retries: " << maxRetries);
1208 return false;
1209 }
1210 else
1211 {
1212 NS_LOG_DEBUG("Re-transmit. Retries: " << station->m_longRetry
1213 << " Max retries: " << maxRetries);
1214 return true;
1215 }
1216}
1217
1220{
1221 uint8_t maxProbRateId = GetRateId(station->m_maxProbRate);
1222 uint8_t maxProbGroupId = GetGroupId(station->m_maxProbRate);
1223 uint8_t maxTpRateId = GetRateId(station->m_maxTpRate);
1224 uint8_t maxTpGroupId = GetGroupId(station->m_maxTpRate);
1225 uint8_t maxTp2RateId = GetRateId(station->m_maxTpRate2);
1226 uint8_t maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1227
1228 if (!station->m_isSampling)
1229 {
1230 return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
1231 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
1232 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1233 }
1234 else
1235 {
1236 return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1237 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1238 }
1239}
1240
1241uint16_t
1243{
1244 NS_LOG_FUNCTION(this << station);
1245 uint8_t sampleGroup = station->m_sampleGroup;
1246 uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1247 uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1248 uint8_t sampleIndex = station->m_sampleTable[index][col];
1249 uint16_t rateIndex = GetIndex(sampleGroup, sampleIndex);
1250 NS_LOG_DEBUG("Next Sample is " << rateIndex);
1251 SetNextSample(station); // Calculate the next sample rate.
1252 return rateIndex;
1253}
1254
1255void
1257{
1258 NS_LOG_FUNCTION(this << station);
1259 do
1260 {
1261 station->m_sampleGroup++;
1262 station->m_sampleGroup %= m_numGroups;
1263 } while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1264
1265 station->m_groupsTable[station->m_sampleGroup].m_index++;
1266
1267 uint8_t sampleGroup = station->m_sampleGroup;
1268 uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1269 uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1270
1271 if (index >= m_numRates)
1272 {
1273 station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1274 station->m_groupsTable[station->m_sampleGroup].m_col++;
1275 if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1276 {
1277 station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1278 }
1279 index = station->m_groupsTable[station->m_sampleGroup].m_index;
1280 col = station->m_groupsTable[sampleGroup].m_col;
1281 }
1282 NS_LOG_DEBUG("New sample set: group= " << +sampleGroup
1283 << " index= " << +station->m_sampleTable[index][col]);
1284}
1285
1286uint16_t
1288{
1289 NS_LOG_FUNCTION(this << station);
1290 NS_LOG_DEBUG("FindRate packet=" << station->m_totalPacketsCount);
1291
1292 if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1293 {
1294 return station->m_maxTpRate;
1295 }
1296
1297 // If we have waited enough, then sample.
1298 if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1299 {
1300 // SAMPLING
1301 NS_LOG_DEBUG("Obtaining a sampling rate");
1303 uint16_t sampleIdx = GetNextSample(station);
1304 NS_LOG_DEBUG("Sampling rate = " << sampleIdx);
1305
1306 // Evaluate if the sampling rate selected should be used.
1307 uint8_t sampleGroupId = GetGroupId(sampleIdx);
1308 uint8_t sampleRateId = GetRateId(sampleIdx);
1309
1310 // If the rate selected is not supported, then don't sample.
1311 if (station->m_groupsTable[sampleGroupId].m_supported &&
1312 station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1313 {
1321 MinstrelHtRateInfo sampleRateInfo =
1322 station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1323
1324 NS_LOG_DEBUG("Use sample rate? MaxTpRate= "
1325 << station->m_maxTpRate << " CurrentRate= " << station->m_txrate
1326 << " SampleRate= " << sampleIdx
1327 << " SampleProb= " << sampleRateInfo.ewmaProb);
1328
1329 if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2 &&
1330 sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1331 {
1337 uint8_t maxTpGroupId = GetGroupId(station->m_maxTpRate);
1338 uint8_t maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1339 uint8_t maxTp2RateId = GetRateId(station->m_maxTpRate2);
1340 uint8_t maxProbGroupId = GetGroupId(station->m_maxProbRate);
1341 uint8_t maxProbRateId = GetRateId(station->m_maxProbRate);
1342
1343 uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1344 uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1345
1346 Time sampleDuration = sampleRateInfo.perfectTxTime;
1347 Time maxTp2Duration =
1348 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1349 Time maxProbDuration = station->m_groupsTable[maxProbGroupId]
1350 .m_ratesTable[maxProbRateId]
1351 .perfectTxTime;
1352
1353 NS_LOG_DEBUG("Use sample rate? SampleDuration= "
1354 << sampleDuration << " maxTp2Duration= " << maxTp2Duration
1355 << " maxProbDuration= " << maxProbDuration << " sampleStreams= "
1356 << +sampleStreams << " maxTpStreams= " << +maxTpStreams);
1357 if (sampleDuration < maxTp2Duration ||
1358 (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1359 {
1361 station->m_isSampling = true;
1362
1364 station->m_sampleRate = sampleIdx;
1365
1366 NS_LOG_DEBUG("FindRate "
1367 << "sampleRate=" << sampleIdx);
1368 station->m_sampleTries--;
1369 return sampleIdx;
1370 }
1371 else
1372 {
1373 station->m_numSamplesSlow++;
1374 if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1375 {
1377 station->m_isSampling = true;
1378
1380 station->m_sampleRate = sampleIdx;
1381
1382 NS_LOG_DEBUG("FindRate "
1383 << "sampleRate=" << sampleIdx);
1384 station->m_sampleTries--;
1385 return sampleIdx;
1386 }
1387 }
1388 }
1389 }
1390 }
1391 if (station->m_sampleWait > 0)
1392 {
1393 station->m_sampleWait--;
1394 }
1395
1397
1398 NS_LOG_DEBUG("FindRate "
1399 << "maxTpRrate=" << station->m_maxTpRate);
1400 return station->m_maxTpRate;
1401}
1402
1403void
1405{
1406 NS_LOG_FUNCTION(this << station);
1407
1409
1410 station->m_numSamplesSlow = 0;
1411 station->m_sampleCount = 0;
1412
1413 double tempProb;
1414
1415 if (station->m_ampduPacketCount > 0)
1416 {
1417 uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1418 station->m_avgAmpduLen =
1419 (newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel)) / 100;
1420 station->m_ampduLen = 0;
1421 station->m_ampduPacketCount = 0;
1422 }
1423
1424 /* Initialize global rate indexes */
1425 station->m_maxTpRate = GetLowestIndex(station);
1426 station->m_maxTpRate2 = GetLowestIndex(station);
1427 station->m_maxProbRate = GetLowestIndex(station);
1428
1430 for (uint8_t j = 0; j < m_numGroups; j++)
1431 {
1432 if (station->m_groupsTable[j].m_supported)
1433 {
1434 station->m_sampleCount++;
1435
1436 /* (re)Initialize group rate indexes */
1437 station->m_groupsTable[j].m_maxTpRate = GetLowestIndex(station, j);
1438 station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex(station, j);
1439 station->m_groupsTable[j].m_maxProbRate = GetLowestIndex(station, j);
1440
1441 for (uint8_t i = 0; i < m_numRates; i++)
1442 {
1443 if (station->m_groupsTable[j].m_ratesTable[i].supported)
1444 {
1445 station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1446
1448 +i << " "
1449 << GetMcsSupported(station,
1450 station->m_groupsTable[j].m_ratesTable[i].mcsIndex)
1451 << "\t attempt="
1452 << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt
1453 << "\t success="
1454 << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1455
1457 if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1458 {
1459 station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1464 tempProb =
1465 (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) /
1466 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1467
1469 station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1470
1471 if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1472 {
1473 station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1474 }
1475 else
1476 {
1477 station->m_groupsTable[j].m_ratesTable[i].ewmsdProb =
1478 CalculateEwmsd(station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1479 tempProb,
1480 station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1481 m_ewmaLevel);
1483 tempProb =
1484 (tempProb * (100 - m_ewmaLevel) +
1485 station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) /
1486 100;
1487 station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1488 }
1489
1490 station->m_groupsTable[j].m_ratesTable[i].throughput =
1491 CalculateThroughput(station, j, i, tempProb);
1492
1493 station->m_groupsTable[j].m_ratesTable[i].successHist +=
1494 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1495 station->m_groupsTable[j].m_ratesTable[i].attemptHist +=
1496 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1497 }
1498 else
1499 {
1500 station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1501 }
1502
1504 station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess =
1505 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1506 station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt =
1507 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1508 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1509 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1510
1511 if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1512 {
1513 SetBestStationThRates(station, GetIndex(j, i));
1514 SetBestProbabilityRate(station, GetIndex(j, i));
1515 }
1516 }
1517 }
1518 }
1519 }
1520
1521 // Try to sample all available rates during each interval.
1522 station->m_sampleCount *= 8;
1523
1524 // Recalculate retries for the rates selected.
1525 CalculateRetransmits(station, station->m_maxTpRate);
1526 CalculateRetransmits(station, station->m_maxTpRate2);
1527 CalculateRetransmits(station, station->m_maxProbRate);
1528
1529 NS_LOG_DEBUG("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2
1530 << "\nmax prob=" << station->m_maxProbRate);
1531 if (m_printStats)
1532 {
1533 PrintTable(station);
1534 }
1535}
1536
1537double
1539 uint8_t groupId,
1540 uint8_t rateId,
1541 double ewmaProb)
1542{
1548 if (ewmaProb < 10)
1549 {
1550 return 0;
1551 }
1552 else
1553 {
1558 Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1559 if (ewmaProb > 90)
1560 {
1561 return 90 / txTime.GetSeconds();
1562 }
1563 else
1564 {
1565 return ewmaProb / txTime.GetSeconds();
1566 }
1567 }
1568}
1569
1570void
1572{
1573 GroupInfo* group;
1574 MinstrelHtRateInfo rate;
1575 uint8_t tmpGroupId;
1576 uint8_t tmpRateId;
1577 double tmpTh;
1578 double tmpProb;
1579 uint8_t groupId;
1580 uint8_t rateId;
1581 double currentTh;
1582 // maximum group probability (GP) variables
1583 uint8_t maxGPGroupId;
1584 uint8_t maxGPRateId;
1585 double maxGPTh;
1586
1587 groupId = GetGroupId(index);
1588 rateId = GetRateId(index);
1589 group = &station->m_groupsTable[groupId];
1590 rate = group->m_ratesTable[rateId];
1591
1592 tmpGroupId = GetGroupId(station->m_maxProbRate);
1593 tmpRateId = GetRateId(station->m_maxProbRate);
1594 tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1595 tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1596
1597 if (rate.ewmaProb > 75)
1598 {
1599 currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1600 if (currentTh > tmpTh)
1601 {
1602 station->m_maxProbRate = index;
1603 }
1604
1605 maxGPGroupId = GetGroupId(group->m_maxProbRate);
1606 maxGPRateId = GetRateId(group->m_maxProbRate);
1607 maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1608
1609 if (currentTh > maxGPTh)
1610 {
1611 group->m_maxProbRate = index;
1612 }
1613 }
1614 else
1615 {
1616 if (rate.ewmaProb > tmpProb)
1617 {
1618 station->m_maxProbRate = index;
1619 }
1620 maxGPRateId = GetRateId(group->m_maxProbRate);
1621 if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1622 {
1623 group->m_maxProbRate = index;
1624 }
1625 }
1626}
1627
1628/*
1629 * Find & sort topmost throughput rates
1630 *
1631 * If multiple rates provide equal throughput the sorting is based on their
1632 * current success probability. Higher success probability is preferred among
1633 * MCS groups.
1634 */
1635void
1637{
1638 uint8_t groupId;
1639 uint8_t rateId;
1640 double th;
1641 double prob;
1642 uint8_t maxTpGroupId;
1643 uint8_t maxTpRateId;
1644 uint8_t maxTp2GroupId;
1645 uint8_t maxTp2RateId;
1646 double maxTpTh;
1647 double maxTpProb;
1648 double maxTp2Th;
1649 double maxTp2Prob;
1650
1651 groupId = GetGroupId(index);
1652 rateId = GetRateId(index);
1653 prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1654 th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1655
1656 maxTpGroupId = GetGroupId(station->m_maxTpRate);
1657 maxTpRateId = GetRateId(station->m_maxTpRate);
1658 maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1659 maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1660
1661 maxTp2GroupId = GetGroupId(station->m_maxTpRate2);
1662 maxTp2RateId = GetRateId(station->m_maxTpRate2);
1663 maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1664 maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1665
1666 if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1667 {
1668 station->m_maxTpRate2 = station->m_maxTpRate;
1669 station->m_maxTpRate = index;
1670 }
1671 else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1672 {
1673 station->m_maxTpRate2 = index;
1674 }
1675
1676 // Find best rates per group
1677
1678 GroupInfo* group = &station->m_groupsTable[groupId];
1679 maxTpGroupId = GetGroupId(group->m_maxTpRate);
1680 maxTpRateId = GetRateId(group->m_maxTpRate);
1681 maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1682 maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1683
1684 maxTp2GroupId = GetGroupId(group->m_maxTpRate2);
1685 maxTp2RateId = GetRateId(group->m_maxTpRate2);
1686 maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1687 maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1688
1689 if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1690 {
1691 group->m_maxTpRate2 = group->m_maxTpRate;
1692 group->m_maxTpRate = index;
1693 }
1694 else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1695 {
1696 group->m_maxTpRate2 = index;
1697 }
1698}
1699
1700void
1702{
1703 NS_LOG_FUNCTION(this << station);
1704
1706
1710 NS_LOG_DEBUG("Supported groups by station:");
1711 bool noSupportedGroupFound = true;
1712 for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1713 {
1714 if (m_minstrelGroups[groupId].isSupported)
1715 {
1716 station->m_groupsTable[groupId].m_supported = false;
1717
1718 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1719 !GetHeSupported(station))
1720 {
1721 // It is a HE group but the receiver does not support HE: skip
1722 continue;
1723 }
1724 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_VHT) &&
1725 !GetVhtSupported(station))
1726 {
1727 // It is a VHT group but the receiver does not support VHT: skip
1728 continue;
1729 }
1730 if ((m_minstrelGroups[groupId].type != WIFI_MINSTREL_GROUP_HE) &&
1732 {
1733 // It is not a HE group and the receiver supports HE: skip since
1734 // UseLatestAmendmentOnly attribute is enabled
1735 continue;
1736 }
1737 if (!GetHeSupported(station) &&
1738 (m_minstrelGroups[groupId].type != WIFI_MINSTREL_GROUP_VHT) &&
1740 {
1741 // It is not a VHT group and the receiver supports VHT (but not HE): skip since
1742 // UseLatestAmendmentOnly attribute is enabled
1743 continue;
1744 }
1745 if (((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HT) ||
1746 (m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_VHT)) &&
1747 (m_minstrelGroups[groupId].gi == 400) && !GetShortGuardIntervalSupported(station))
1748 {
1749 // It is a SGI group but the receiver does not support SGI: skip
1750 continue;
1751 }
1752 if ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1753 (m_minstrelGroups[groupId].gi < GetGuardInterval(station)))
1754 {
1755 // The receiver does not support the GI: skip
1756 continue;
1757 }
1758 if (GetChannelWidth(station) < m_minstrelGroups[groupId].chWidth)
1759 {
1760 // The receiver does not support the channel width: skip
1761 continue;
1762 }
1763 if (GetNumberOfSupportedStreams(station) < m_minstrelGroups[groupId].streams)
1764 {
1765 // The receiver does not support the number of spatial streams: skip
1766 continue;
1767 }
1768
1769 NS_LOG_DEBUG("Group: " << +groupId << " type: " << m_minstrelGroups[groupId].type
1770 << " streams: " << +m_minstrelGroups[groupId].streams
1771 << " GI: " << m_minstrelGroups[groupId].gi
1772 << " width: " << m_minstrelGroups[groupId].chWidth);
1773
1774 noSupportedGroupFound = false;
1775 station->m_groupsTable[groupId].m_supported = true;
1776 station->m_groupsTable[groupId].m_col = 0;
1777 station->m_groupsTable[groupId].m_index = 0;
1778
1779 station->m_groupsTable[groupId].m_ratesTable =
1781 for (uint8_t i = 0; i < m_numRates; i++)
1782 {
1783 station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1784 }
1785
1786 // Initialize all modes supported by the remote station that belong to the current
1787 // group.
1788 for (uint8_t i = 0; i < station->m_nModes; i++)
1789 {
1790 WifiMode mode = GetMcsSupported(station, i);
1791
1794 uint8_t rateId = mode.GetMcsValue();
1796 {
1797 rateId %= MAX_HT_GROUP_RATES;
1798 }
1799
1800 if (((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HE) &&
1801 (mode.GetModulationClass() ==
1803 && IsValidMcs(GetPhy(),
1804 m_minstrelGroups[groupId].streams,
1805 m_minstrelGroups[groupId].chWidth,
1806 mode))
1807 || ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_VHT) &&
1808 (mode.GetModulationClass() ==
1810 && IsValidMcs(GetPhy(),
1811 m_minstrelGroups[groupId].streams,
1812 m_minstrelGroups[groupId].chWidth,
1813 mode))
1814 || ((m_minstrelGroups[groupId].type == WIFI_MINSTREL_GROUP_HT) &&
1815 (mode.GetModulationClass() ==
1817 && (mode.GetMcsValue() <
1818 (m_minstrelGroups[groupId].streams *
1819 8))
1820 && (mode.GetMcsValue() >= ((m_minstrelGroups[groupId].streams - 1) * 8))))
1821 {
1822 NS_LOG_DEBUG("Mode " << +i << ": " << mode);
1823
1824 station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1825 station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex =
1826 i;
1827 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1828 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1829 station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1830 station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1831 station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1832 station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1833 station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1834 station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1835 station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1836 station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1837 station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime =
1838 GetFirstMpduTxTime(groupId, GetMcsSupported(station, i));
1839 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1840 station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1841 CalculateRetransmits(station, groupId, rateId);
1842 }
1843 }
1844 }
1845 }
1848 if (noSupportedGroupFound)
1849 {
1850 NS_FATAL_ERROR("No supported group has been found");
1851 }
1852 SetNextSample(station);
1853 UpdateStats(station);
1854 station->m_txrate = FindRate(station);
1855}
1856
1857void
1859{
1860 NS_LOG_FUNCTION(this << station << index);
1861 uint8_t groupId = GetGroupId(index);
1862 uint8_t rateId = GetRateId(index);
1863 if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1864 {
1865 CalculateRetransmits(station, groupId, rateId);
1866 }
1867}
1868
1869void
1871 uint8_t groupId,
1872 uint8_t rateId)
1873{
1874 NS_LOG_FUNCTION(this << station << +groupId << +rateId);
1875
1876 uint32_t cw = 15; // Is an approximation.
1877 uint32_t cwMax = 1023;
1878 Time cwTime;
1879 Time txTime;
1880 Time dataTxTime;
1881 Time slotTime = GetPhy()->GetSlot();
1882 Time ackTime = GetPhy()->GetSifs() + GetPhy()->GetBlockAckTxTime();
1883
1884 if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1885 {
1886 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1887 }
1888 else
1889 {
1890 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1891 station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1892
1893 dataTxTime =
1895 groupId,
1896 GetMcsSupported(station,
1897 station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1899 groupId,
1900 GetMcsSupported(station,
1901 station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) *
1902 (station->m_avgAmpduLen - 1);
1903
1904 /* Contention time for first 2 tries */
1905 cwTime = (cw / 2) * slotTime;
1906 cw = Min((cw + 1) * 2, cwMax);
1907 cwTime += (cw / 2) * slotTime;
1908 cw = Min((cw + 1) * 2, cwMax);
1909
1910 /* Total TX time for data and Contention after first 2 tries */
1911 txTime = cwTime + 2 * (dataTxTime + ackTime);
1912
1913 /* See how many more tries we can fit inside segment size */
1914 do
1915 {
1916 /* Contention time for this try */
1917 cwTime = (cw / 2) * slotTime;
1918 cw = Min((cw + 1) * 2, cwMax);
1919
1920 /* Total TX time after this try */
1921 txTime += cwTime + ackTime + dataTxTime;
1922 } while ((txTime < MilliSeconds(6)) &&
1923 (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1924 }
1925}
1926
1927double
1929 double currentProb,
1930 double ewmaProb,
1931 double weight)
1932{
1933 double diff;
1934 double incr;
1935 double tmp;
1936
1937 /* calculate exponential weighted moving variance */
1938 diff = currentProb - ewmaProb;
1939 incr = (100 - weight) * diff / 100;
1940 tmp = oldEwmsd * oldEwmsd;
1941 tmp = weight * (tmp + diff * incr) / 100;
1942
1943 /* return standard deviation */
1944 return sqrt(tmp);
1945}
1946
1947void
1949{
1950 NS_LOG_FUNCTION(this << station);
1951 station->m_col = station->m_index = 0;
1952
1953 // for off-setting to make rates fall between 0 and nModes
1954 uint8_t numSampleRates = m_numRates;
1955
1956 uint16_t newIndex;
1957 for (uint8_t col = 0; col < m_nSampleCol; col++)
1958 {
1959 for (uint8_t i = 0; i < numSampleRates; i++)
1960 {
1965 int uv = m_uniformRandomVariable->GetInteger(0, numSampleRates);
1966 newIndex = (i + uv) % numSampleRates;
1967
1968 // this loop is used for filling in other uninitialized places
1969 while (station->m_sampleTable[newIndex][col] != 0)
1970 {
1971 newIndex = (newIndex + 1) % m_numRates;
1972 }
1973 station->m_sampleTable[newIndex][col] = i;
1974 }
1975 }
1976}
1977
1978void
1980{
1981 if (!station->m_statsFile.is_open())
1982 {
1983 std::ostringstream tmp;
1984 tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1985 station->m_statsFile.open(tmp.str(), std::ios::out);
1986 }
1987
1988 station->m_statsFile
1989 << " best ____________rate__________ ________statistics________ "
1990 "________last_______ ______sum-of________\n"
1991 << " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] "
1992 "[prob.|retry|suc|att] [#success | #attempts]\n";
1993 for (uint8_t i = 0; i < m_numGroups; i++)
1994 {
1995 StatsDump(station, i, station->m_statsFile);
1996 }
1997
1998 station->m_statsFile << "\nTotal packet count:: ideal "
1999 << Max(0, station->m_totalPacketsCount - station->m_samplePacketsCount)
2000 << " lookaround " << station->m_samplePacketsCount << "\n";
2001 station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen
2002 << "\n\n";
2003
2004 station->m_statsFile.flush();
2005}
2006
2007void
2009 uint8_t groupId,
2010 std::ofstream& of)
2011{
2012 uint8_t numRates = m_numRates;
2013 McsGroup group = m_minstrelGroups[groupId];
2014 Time txTime;
2015 for (uint8_t i = 0; i < numRates; i++)
2016 {
2017 if (station->m_groupsTable[groupId].m_supported &&
2018 station->m_groupsTable[groupId].m_ratesTable[i].supported)
2019 {
2020 of << group.type << " " << group.chWidth << " " << group.gi << " " << +group.streams
2021 << " ";
2022
2023 uint16_t maxTpRate = station->m_maxTpRate;
2024 uint16_t maxTpRate2 = station->m_maxTpRate2;
2025 uint16_t maxProbRate = station->m_maxProbRate;
2026
2027 uint16_t idx = GetIndex(groupId, i);
2028 if (idx == maxTpRate)
2029 {
2030 of << 'A';
2031 }
2032 else
2033 {
2034 of << ' ';
2035 }
2036 if (idx == maxTpRate2)
2037 {
2038 of << 'B';
2039 }
2040 else
2041 {
2042 of << ' ';
2043 }
2044 if (idx == maxProbRate)
2045 {
2046 of << 'P';
2047 }
2048 else
2049 {
2050 of << ' ';
2051 }
2052
2053 if (group.type == WIFI_MINSTREL_GROUP_HT)
2054 {
2055 of << std::setw(4) << " MCS" << (group.streams - 1) * 8 + i;
2056 }
2057 else
2058 {
2059 of << std::setw(7) << " MCS" << +i << "/" << static_cast<int>(group.streams);
2060 }
2061
2062 of << " " << std::setw(3) << +idx << " ";
2063
2064 /* tx_time[rate(i)] in usec */
2065 txTime = GetFirstMpduTxTime(
2066 groupId,
2067 GetMcsSupported(station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
2068 of << std::setw(6) << txTime.GetMicroSeconds() << " ";
2069
2070 of << std::setw(7) << CalculateThroughput(station, groupId, i, 100) / 100 << " "
2071 << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100
2072 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb
2073 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb
2074 << " " << std::setw(7) << station->m_groupsTable[groupId].m_ratesTable[i].prob
2075 << " " << std::setw(2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount
2076 << " " << std::setw(3)
2077 << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " "
2078 << std::setw(3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt
2079 << " " << std::setw(9)
2080 << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " "
2081 << std::setw(9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist
2082 << "\n";
2083 }
2084 }
2085}
2086
2087uint16_t
2088MinstrelHtWifiManager::GetIndex(uint8_t groupId, uint8_t rateId)
2089{
2090 NS_LOG_FUNCTION(this << +groupId << +rateId);
2091 uint16_t index;
2092 index = groupId * m_numRates + rateId;
2093 return index;
2094}
2095
2096uint8_t
2098{
2099 NS_LOG_FUNCTION(this << index);
2100 uint8_t id;
2101 id = index % m_numRates;
2102 return id;
2103}
2104
2105uint8_t
2107{
2108 NS_LOG_FUNCTION(this << index);
2109 return index / m_numRates;
2110}
2111
2112uint8_t
2113MinstrelHtWifiManager::GetHtGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2114{
2115 NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2116 uint8_t giIndex = (gi == 400) ? 1 : 0;
2117 uint8_t widthIndex = (chWidth == 40) ? 1 : 0;
2118 return (MAX_HT_SUPPORTED_STREAMS * 2 * widthIndex) + (MAX_HT_SUPPORTED_STREAMS * giIndex) +
2119 txstreams - 1;
2120}
2121
2122uint8_t
2123MinstrelHtWifiManager::GetVhtGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2124{
2125 NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2126 uint8_t giIndex = (gi == 400) ? 1 : 0;
2127 uint8_t widthIndex;
2128 if (chWidth == 160)
2129 {
2130 widthIndex = 3;
2131 }
2132 else if (chWidth == 80)
2133 {
2134 widthIndex = 2;
2135 }
2136 else if (chWidth == 40)
2137 {
2138 widthIndex = 1;
2139 }
2140 else // 20 MHz
2141 {
2142 widthIndex = 0;
2143 }
2144 uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
2145 groupId += (MAX_VHT_SUPPORTED_STREAMS * 2 * widthIndex) +
2146 (MAX_VHT_SUPPORTED_STREAMS * giIndex) + txstreams - 1;
2147 return groupId;
2148}
2149
2150uint8_t
2151MinstrelHtWifiManager::GetHeGroupId(uint8_t txstreams, uint16_t gi, uint16_t chWidth)
2152{
2153 NS_LOG_FUNCTION(this << +txstreams << gi << chWidth);
2154 uint8_t giIndex;
2155 if (gi == 800)
2156 {
2157 giIndex = 2;
2158 }
2159 else if (gi == 1600)
2160 {
2161 giIndex = 1;
2162 }
2163 else // 3200 ns
2164 {
2165 giIndex = 0;
2166 }
2167 uint8_t widthIndex;
2168 if (chWidth == 160)
2169 {
2170 widthIndex = 3;
2171 }
2172 else if (chWidth == 80)
2173 {
2174 widthIndex = 2;
2175 }
2176 else if (chWidth == 40)
2177 {
2178 widthIndex = 1;
2179 }
2180 else // 20 MHz
2181 {
2182 widthIndex = 0;
2183 }
2184 uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
2185 if (GetVhtSupported())
2186 {
2188 }
2189 groupId += (MAX_HE_SUPPORTED_STREAMS * 3 * widthIndex) + (MAX_HE_SUPPORTED_STREAMS * giIndex) +
2190 txstreams - 1;
2191 return groupId;
2192}
2193
2194uint16_t
2196{
2197 NS_LOG_FUNCTION(this << station);
2198
2199 uint8_t groupId = 0;
2200 uint8_t rateId = 0;
2201 while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
2202 {
2203 groupId++;
2204 }
2205 while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
2206 {
2207 rateId++;
2208 }
2209 NS_ASSERT(station->m_groupsTable[groupId].m_supported &&
2210 station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
2211 return GetIndex(groupId, rateId);
2212}
2213
2214uint16_t
2216{
2217 NS_LOG_FUNCTION(this << station << +groupId);
2218
2219 uint8_t rateId = 0;
2220 while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
2221 {
2222 rateId++;
2223 }
2224 NS_ASSERT(station->m_groupsTable[groupId].m_supported &&
2225 station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
2226 return GetIndex(groupId, rateId);
2227}
2228
2231{
2232 const auto& mcsList = GetPhy()->GetMcsList(WIFI_MOD_CLASS_HE);
2233 WifiModeList heMcsList(mcsList.begin(), mcsList.end());
2234 return heMcsList;
2235}
2236
2239{
2240 const auto& mcsList = GetPhy()->GetMcsList(WIFI_MOD_CLASS_VHT);
2241 WifiModeList vhtMcsList(mcsList.begin(), mcsList.end());
2242 return vhtMcsList;
2243}
2244
2247{
2248 const auto& mcsList = GetPhy()->GetMcsList(WIFI_MOD_CLASS_HT);
2249 WifiModeList htMcsList(mcsList.begin(), mcsList.end());
2250 return htMcsList;
2251}
2252
2253} // namespace ns3
#define Max(a, b)
#define Min(a, b)
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.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:413
AttributeValue implementation for Time.
Definition: nstime.h:1413
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
Hold an unsigned integer type.
Definition: uinteger.h:45
uint32_t GetInteger(uint32_t min, uint32_t max)
Get the next random value drawn from the distribution.
represent a single transmission mode
Definition: wifi-mode.h:51
WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:185
uint64_t GetNonHtReferenceRate() const
Definition: wifi-mode.cc:192
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:122
uint8_t GetMcsValue() const
Definition: wifi-mode.cc:163
Time GetBlockAckTxTime() const
Return the estimated BlockAck TX time for this PHY.
Definition: wifi-phy.cc:835
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:1478
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:811
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:799
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:1093
std::list< WifiMode > GetMcsList() const
The WifiPhy::GetMcsList() method is used (e.g., by a WifiRemoteStationManager) to determine the set o...
Definition: wifi-phy.cc:2021
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1518
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.
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
bool IsValid(WifiPhyBand band=WIFI_PHY_BAND_UNSPECIFIED) const
The standard disallows certain combinations of WifiMode, number of spatial streams,...
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetNss(uint8_t nss)
Sets the number of Nss.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:81
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1434
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1414
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
#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:1338
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.
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:262
std::vector< std::vector< uint8_t > > SampleRate
Data structure for a Sample Rate table A vector of a vector uint8_t.
static const uint8_t MAX_HE_WIDTH
Maximal channel width in MHz.
static const uint8_t MAX_VHT_WIDTH
Maximal channel width in MHz.
std::vector< GroupInfo > McsGroupData
Data structure for a table of groups.
static const uint8_t MAX_HE_SUPPORTED_STREAMS
Maximal number of streams supported by the HE PHY layer.
A struct to contain information of a group.
MinstrelHtRate m_ratesTable
Information about rates of this group.
uint16_t m_maxTpRate2
The second max throughput rate of this group in bps.
uint16_t m_maxProbRate
The highest success probability rate of this group in bps.
uint16_t m_maxTpRate
The max throughput rate of this group in bps.
Data structure to contain the information that defines a group.
uint16_t chWidth
channel width (MHz)
uint16_t gi
guard interval duration (nanoseconds)
McsGroupType type
identifies the group,
bool isSupported
flag whether group is supported
uint8_t streams
number of spatial streams
A struct to contain all statistics information related to a data rate.
Time perfectTxTime
Perfect transmission time calculation, or frame calculation.
double ewmaProb
Exponential weighted moving average of probability.
uint32_t numSamplesSkipped
Number of times this rate statistics were not updated because no attempts have been made.
MinstrelHtWifiRemoteStation structure.
McsGroupData m_groupsTable
Table of groups with stats.
uint32_t m_sampleCount
Max number of samples per update interval.
uint8_t m_sampleGroup
The group that the sample rate belongs to.
uint32_t m_ampduPacketCount
Number of A-MPDUs transmitted.
uint32_t m_numSamplesSlow
Number of times a slow rate was sampled.
uint32_t m_sampleTries
Number of sample tries after waiting sampleWait.
std::ofstream m_statsFile
File where statistics table is written.
uint32_t m_sampleWait
How many transmission attempts to wait until a new sample.
bool m_isHt
If the station is HT capable.
uint32_t m_avgAmpduLen
Average number of MPDUs in an A-MPDU.
uint32_t m_ampduLen
Number of MPDUs in an A-MPDU.
hold per-remote-station state for Minstrel Wifi manager.
uint16_t m_maxTpRate2
second highest throughput rate in bps
Time m_nextStatsUpdate
10 times every second
bool m_initialized
for initializing tables
uint16_t m_sampleRate
current sample rate in bps
uint16_t m_txrate
current transmit rate in bps
int m_totalPacketsCount
total number of packets as of now
bool m_isSampling
a flag to indicate we are currently sampling
MinstrelRate m_minstrelTable
minstrel table
uint32_t m_shortRetry
short retries such as control packets
uint16_t m_maxTpRate
the current throughput rate in bps
uint8_t m_nModes
number of modes supported
SampleRate m_sampleTable
sample table
int m_samplePacketsCount
how many packets we have sample so far
uint8_t m_col
To keep track of the current position in the our random sample table going row by row from 1st column...
uint32_t m_longRetry
long retries such as data packets
uint16_t m_maxProbRate
rate with highest probability of success in bps
hold per-remote-station state.
WifiRemoteStationState * m_state
Remote station state.
Mac48Address m_address
Mac48Address of the remote station.
void CalculateThroughput()
Calculate the throughput.
Definition: wifi-tcp.cc:62