A Discrete-Event Network Simulator
API
minstrel-ht-wifi-manager.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2009 Duy Nguyen
4 * Copyright (c) 2015 Ghada Badawy
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation;
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * Authors: Duy Nguyen <duy@soe.ucsc.edu>
20 * Ghada Badawy <gbadawy@gmail.com>
21 * Matias Richart <mrichart@fing.edu.uy>
22 *
23 * Some Comments:
24 *
25 * 1) By default, Minstrel applies the multi-rate retry (the core of Minstrel
26 * algorithm). Otherwise, please use ConstantRateWifiManager instead.
27 *
28 * 2) Sampling is done differently from legacy Minstrel. Minstrel-HT tries
29 * to sample all rates in all groups at least once and to avoid many
30 * consecutive samplings.
31 *
32 * 3) Sample rate is tried only once, at first place of the MRR chain.
33 *
34 * reference: http://lwn.net/Articles/376765/
35 */
36
37#include <iomanip>
38#include "ns3/packet.h"
39#include "ns3/simulator.h"
40#include "ns3/log.h"
41#include "ns3/random-variable-stream.h"
43#include "ns3/wifi-mac.h"
44#include "ns3/wifi-phy.h"
45
46#define Min(a,b) ((a < b) ? a : b)
47#define Max(a,b) ((a > b) ? a : b)
48
49NS_LOG_COMPONENT_DEFINE ("MinstrelHtWifiManager");
50
51namespace ns3 {
52
55{
56 uint8_t m_sampleGroup;
57
62
66
68 bool m_isHt;
69
70 std::ofstream m_statsFile;
71};
72
74
77{
78 static TypeId tid = TypeId ("ns3::MinstrelHtWifiManager")
80 .AddConstructor<MinstrelHtWifiManager> ()
81 .SetGroupName ("Wifi")
82 .AddAttribute ("UpdateStatistics",
83 "The interval between updating statistics table ",
87 .AddAttribute ("LegacyUpdateStatistics",
88 "The interval between updating statistics table (for legacy Minstrel) ",
89 TimeValue (MilliSeconds (100)),
92 .AddAttribute ("LookAroundRate",
93 "The percentage to try other rates (for legacy Minstrel)",
94 UintegerValue (10),
96 MakeUintegerChecker<uint8_t>(0, 100))
97 .AddAttribute ("EWMA",
98 "EWMA level",
99 UintegerValue (75),
101 MakeUintegerChecker<uint8_t>(0, 100))
102 .AddAttribute ("SampleColumn",
103 "The number of columns used for sampling",
104 UintegerValue (10),
106 MakeUintegerChecker <uint8_t> ())
107 .AddAttribute ("PacketLength",
108 "The packet length used for calculating mode TxTime (bytes)",
109 UintegerValue (1200),
111 MakeUintegerChecker <uint32_t> ())
112 .AddAttribute ("UseLatestAmendmentOnly",
113 "Use only the latest amendment when it is supported by both peers",
114 BooleanValue (true),
117 .AddAttribute ("PrintStats",
118 "Control the printing of the statistics table",
119 BooleanValue (false),
122 .AddTraceSource ("Rate",
123 "Traced value for rate changes (b/s)",
125 "ns3::TracedValueCallback::Uint64")
126 ;
127 return tid;
128}
129
131 : m_numGroups (0),
132 m_numRates (0),
133 m_currentRate (0)
134{
135 NS_LOG_FUNCTION (this);
136 m_uniformRandomVariable = CreateObject<UniformRandomVariable> ();
141 m_legacyManager = CreateObject<MinstrelWifiManager> ();
142}
143
145{
146 NS_LOG_FUNCTION (this);
147 for (uint8_t i = 0; i < m_numGroups; i++)
148 {
149 m_minstrelGroups[i].ratesFirstMpduTxTimeTable.clear ();
150 m_minstrelGroups[i].ratesTxTimeTable.clear ();
151 }
152}
153
154int64_t
156{
157 NS_LOG_FUNCTION (this << stream);
158 int64_t numStreamsAssigned = 0;
160 numStreamsAssigned++;
161 numStreamsAssigned += m_legacyManager->AssignStreams (stream);
162 return numStreamsAssigned;
163}
164
165void
167{
168 NS_LOG_FUNCTION (this << phy);
169 // Setup PHY for legacy manager.
170 m_legacyManager->SetupPhy (phy);
172}
173
174void
176{
177 NS_LOG_FUNCTION (this << mac);
178 m_legacyManager->SetupMac (mac);
180}
181
182void
184{
185 NS_LOG_FUNCTION (this);
192 if (GetHtSupported ())
193 {
196 if (GetVhtSupported ())
197 {
200 }
201 if (GetHeSupported ())
202 {
205 }
206
217 NS_LOG_DEBUG ("Initialize MCS Groups:");
219
220 // Initialize all HT groups
221 for (uint16_t chWidth = 20; chWidth <= MAX_HT_WIDTH; chWidth *= 2)
222 {
223 for (int gi = 800; gi >= 400; )
224 {
225 for (uint8_t streams = 1; streams <= MAX_HT_SUPPORTED_STREAMS; streams++)
226 {
227 uint8_t groupId = GetHtGroupId (streams, gi, chWidth);
228
229 m_minstrelGroups[groupId].streams = streams;
230 m_minstrelGroups[groupId].gi = gi;
231 m_minstrelGroups[groupId].chWidth = chWidth;
232 m_minstrelGroups[groupId].type = GROUP_HT;
233 m_minstrelGroups[groupId].isSupported = false;
234
235 // Check capabilities of the device
236 if (!(!GetShortGuardIntervalSupported () && (gi == 400))
237 && (GetPhy ()->GetChannelWidth () >= chWidth)
238 && (GetPhy ()->GetMaxSupportedTxSpatialStreams () >= streams))
239 {
240 m_minstrelGroups[groupId].isSupported = true;
241
242 // Calculate TX time for all rates of the group
243 WifiModeList htMcsList = GetHtDeviceMcsList ();
244 for (uint8_t i = 0; i < MAX_HT_GROUP_RATES; i++)
245 {
246 uint16_t deviceIndex = i + (m_minstrelGroups[groupId].streams - 1) * 8;
247 WifiMode mode = htMcsList[deviceIndex];
248 AddFirstMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, gi, chWidth, mode, FIRST_MPDU_IN_AGGREGATE));
249 AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, gi, chWidth, mode, MIDDLE_MPDU_IN_AGGREGATE));
250 }
251 NS_LOG_DEBUG ("Initialized group " << +groupId << ": (" << +streams << "," << gi << "," << chWidth << ")");
252 }
253 }
254 gi /= 2;
255 }
256 }
257
258 if (GetVhtSupported ())
259 {
260 // Initialize all VHT groups
261 for (uint16_t chWidth = 20; chWidth <= MAX_VHT_WIDTH; chWidth *= 2)
262 {
263 for (int gi = 800; gi >= 400; )
264 {
265 for (uint8_t streams = 1; streams <= MAX_VHT_SUPPORTED_STREAMS; streams++)
266 {
267 uint8_t groupId = GetVhtGroupId (streams, gi, chWidth);
268
269 m_minstrelGroups[groupId].streams = streams;
270 m_minstrelGroups[groupId].gi = gi;
271 m_minstrelGroups[groupId].chWidth = chWidth;
272 m_minstrelGroups[groupId].type = GROUP_VHT;
273 m_minstrelGroups[groupId].isSupported = false;
274
275 // Check capabilities of the device
276 if (!(!GetShortGuardIntervalSupported () && (gi == 400))
277 && (GetPhy ()->GetChannelWidth () >= chWidth)
278 && (GetPhy ()->GetMaxSupportedTxSpatialStreams () >= streams))
279 {
280 m_minstrelGroups[groupId].isSupported = true;
281
282 // Calculate TX time for all rates of the group
283 WifiModeList vhtMcsList = GetVhtDeviceMcsList ();
284 for (uint8_t i = 0; i < MAX_VHT_GROUP_RATES; i++)
285 {
286 WifiMode mode = vhtMcsList[i];
287 // Check for invalid VHT MCSs and do not add time to array.
288 if (IsValidMcs (GetPhy (), streams, chWidth, mode))
289 {
290 AddFirstMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, gi, chWidth, mode, FIRST_MPDU_IN_AGGREGATE));
291 AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, gi, chWidth, mode, MIDDLE_MPDU_IN_AGGREGATE));
292 }
293 }
294 NS_LOG_DEBUG ("Initialized group " << +groupId << ": (" << +streams << "," << gi << "," << chWidth << ")");
295 }
296 }
297 gi /= 2;
298 }
299 }
300 }
301
302 if (GetHeSupported ())
303 {
304 // Initialize all HE groups
305 for (uint16_t chWidth = 20; chWidth <= MAX_HE_WIDTH; chWidth *= 2)
306 {
307 for (int gi = 3200; gi >= 800; )
308 {
309 for (uint8_t streams = 1; streams <= MAX_HE_SUPPORTED_STREAMS; streams++)
310 {
311 uint8_t groupId = GetHeGroupId (streams, gi, chWidth);
312
313 m_minstrelGroups[groupId].streams = streams;
314 m_minstrelGroups[groupId].gi = gi;
315 m_minstrelGroups[groupId].chWidth = chWidth;
316 m_minstrelGroups[groupId].type = GROUP_HE;
317 m_minstrelGroups[groupId].isSupported = false;
318
319 // Check capabilities of the device
320 if ((GetGuardInterval () <= gi)
321 && (GetPhy ()->GetChannelWidth () >= chWidth)
322 && (GetPhy ()->GetMaxSupportedTxSpatialStreams () >= streams))
323 {
324 m_minstrelGroups[groupId].isSupported = true;
325
326 // Calculate tx time for all rates of the group
327 WifiModeList heMcsList = GetHeDeviceMcsList ();
328 for (uint8_t i = 0; i < MAX_HE_GROUP_RATES; i++)
329 {
330 WifiMode mode = heMcsList.at (i);
331 // Check for invalid HE MCSs and do not add time to array.
332 if (IsValidMcs (GetPhy (), streams, chWidth, mode))
333 {
334 AddFirstMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, gi, chWidth, mode, FIRST_MPDU_IN_AGGREGATE));
335 AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, gi, chWidth, mode, MIDDLE_MPDU_IN_AGGREGATE));
336 }
337 }
338 NS_LOG_DEBUG ("Initialized group " << +groupId << ": (" << +streams << "," << gi << "," << chWidth << ")");
339 }
340 }
341 gi /= 2;
342 }
343 }
344 }
345 }
346}
347
348bool
349MinstrelHtWifiManager::IsValidMcs (Ptr<WifiPhy> phy, uint8_t streams, uint16_t chWidth, WifiMode mode)
350{
351 NS_LOG_FUNCTION (this << phy << +streams << chWidth << mode);
352 WifiTxVector txvector;
353 txvector.SetNss (streams);
354 txvector.SetChannelWidth (chWidth);
355 txvector.SetMode (mode);
356 return txvector.IsValid ();
357}
358
359Time
361 uint16_t chWidth, WifiMode mode, MpduType mpduType)
362{
363 NS_LOG_FUNCTION (this << phy << +streams << gi << chWidth << mode << mpduType);
364 WifiTxVector txvector;
365 txvector.SetNss (streams);
366 txvector.SetGuardInterval (gi);
367 txvector.SetChannelWidth (chWidth);
368 txvector.SetNess (0);
369 txvector.SetStbc (0);
370 txvector.SetMode (mode);
373 + WifiPhy::GetPayloadDuration (m_frameLength, txvector, phy->GetPhyBand (), mpduType);
374}
375
376Time
378{
379 NS_LOG_FUNCTION (this << +groupId << mode);
380 auto it = m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.find (mode);
381 NS_ASSERT (it != m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.end ());
382 return it->second;
383}
384
385void
387{
388 NS_LOG_FUNCTION (this << +groupId << mode << t);
389 m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.insert (std::make_pair (mode, t));
390}
391
392Time
394{
395 NS_LOG_FUNCTION (this << +groupId << mode);
396 auto it = m_minstrelGroups[groupId].ratesTxTimeTable.find (mode);
397 NS_ASSERT (it != m_minstrelGroups[groupId].ratesTxTimeTable.end ());
398 return it->second;
399}
400
401void
403{
404 NS_LOG_FUNCTION (this << +groupId << mode << t);
405 m_minstrelGroups[groupId].ratesTxTimeTable.insert (std::make_pair (mode, t));
406}
407
410{
411 NS_LOG_FUNCTION (this);
413
414 // Initialize variables common to both stations.
416 station->m_col = 0;
417 station->m_index = 0;
418 station->m_maxTpRate = 0;
419 station->m_maxTpRate2 = 0;
420 station->m_maxProbRate = 0;
421 station->m_nModes = 0;
422 station->m_totalPacketsCount = 0;
423 station->m_samplePacketsCount = 0;
424 station->m_isSampling = false;
425 station->m_sampleRate = 0;
426 station->m_sampleDeferred = false;
427 station->m_shortRetry = 0;
428 station->m_longRetry = 0;
429 station->m_txrate = 0;
430 station->m_initialized = false;
431
432 // Variables specific to HT station
433 station->m_sampleGroup = 0;
434 station->m_numSamplesSlow = 0;
435 station->m_sampleCount = 16;
436 station->m_sampleWait = 0;
437 station->m_sampleTries = 4;
438
439 station->m_avgAmpduLen = 1;
440 station->m_ampduLen = 0;
441 station->m_ampduPacketCount = 0;
442
443 // If the device supports HT
444 if (GetHtSupported ())
445 {
450 station->m_isHt = true;
451 }
452 // Use the variable in the station to indicate that the device do not support HT
453 else
454 {
455 station->m_isHt = false;
456 }
457
458 return station;
459}
460
461void
463{
464 NS_LOG_FUNCTION (this << station);
465 // Note: we appear to be doing late initialization of the table
466 // to make sure that the set of supported rates has been initialized
467 // before we perform our own initialization.
468 if (!station->m_initialized)
469 {
476 if (!GetHtSupported (station))
477 {
478 NS_LOG_INFO ("non-HT station " << station);
479 station->m_isHt = false;
480 // We will use non-HT minstrel for this station. Initialize the manager.
481 m_legacyManager->SetAttribute ("UpdateStatistics", TimeValue (m_legacyUpdateStats));
482 m_legacyManager->SetAttribute ("LookAroundRate", UintegerValue (m_lookAroundRate));
483 m_legacyManager->SetAttribute ("EWMA", UintegerValue (m_ewmaLevel));
484 m_legacyManager->SetAttribute ("SampleColumn", UintegerValue (m_nSampleCol));
485 m_legacyManager->SetAttribute ("PacketLength", UintegerValue (m_frameLength));
486 m_legacyManager->SetAttribute ("PrintStats", BooleanValue (m_printStats));
487 m_legacyManager->CheckInit (station);
488 }
489 else
490 {
491 NS_LOG_DEBUG ("HT station " << station);
492 station->m_isHt = true;
493 station->m_nModes = GetNMcsSupported (station);
494 station->m_minstrelTable = MinstrelRate (station->m_nModes);
495 station->m_sampleTable = SampleRate (m_numRates, std::vector<uint8_t> (m_nSampleCol));
496 InitSampleTable (station);
497 RateInit (station);
498 station->m_initialized = true;
499 }
500 }
501}
502
503void
505{
506 NS_LOG_FUNCTION (this << st);
507 NS_LOG_DEBUG ("DoReportRxOk m_txrate=" << static_cast<MinstrelHtWifiRemoteStation*> (st)->m_txrate);
508}
509
510void
512{
513 NS_LOG_FUNCTION (this << st);
514 MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
515 CheckInit (station);
516 if (!station->m_initialized)
517 {
518 return;
519 }
520 NS_LOG_DEBUG ("DoReportRtsFailed m_txrate = " << station->m_txrate);
521 station->m_shortRetry++;
522}
523
524void
525MinstrelHtWifiManager::DoReportRtsOk (WifiRemoteStation *st, double ctsSnr, WifiMode ctsMode, double rtsSnr)
526{
527 NS_LOG_FUNCTION (this << st);
528}
529
530void
532{
533 NS_LOG_FUNCTION (this << st);
534 MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
535 NS_LOG_DEBUG ("Final RTS failed");
536 CheckInit (station);
537 if (!station->m_initialized)
538 {
539 return;
540 }
541 UpdateRetry (station);
542}
543
544void
546{
547 NS_LOG_FUNCTION (this << st);
548 MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
549
550 CheckInit (station);
551 if (!station->m_initialized)
552 {
553 return;
554 }
555
556 NS_LOG_DEBUG ("DoReportDataFailed " << station << "\t rate " << station->m_txrate << "\tlongRetry \t" << station->m_longRetry);
557
558 if (!station->m_isHt)
559 {
560 m_legacyManager->UpdateRate (station);
561 }
562 else if (station->m_longRetry < CountRetries (station))
563 {
564 uint8_t rateId = GetRateId (station->m_txrate);
565 uint8_t groupId = GetGroupId (station->m_txrate);
566 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++; // Increment the attempts counter for the rate used.
567 UpdateRate (station);
568 }
569}
570
571void
573 double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss)
574{
575 NS_LOG_FUNCTION (this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
576 MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
577
578 CheckInit (station);
579 if (!station->m_initialized)
580 {
581 return;
582 }
583
584 NS_LOG_DEBUG ("DoReportDataOk m_txrate = " << station->m_txrate << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess << " (before update).");
585
586 if (!station->m_isHt)
587 {
588 station->m_minstrelTable[station->m_txrate].numRateSuccess++;
589 station->m_minstrelTable[station->m_txrate].numRateAttempt++;
590
591 m_legacyManager->UpdatePacketCounters (station);
592
593 NS_LOG_DEBUG ("DoReportDataOk m_txrate = " << station->m_txrate << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess << " (after update).");
594
595 UpdateRetry (station);
596 m_legacyManager->UpdateStats (station);
597
598 if (station->m_nModes >= 1)
599 {
600 station->m_txrate = m_legacyManager->FindRate (station);
601 }
602 }
603 else
604 {
605 uint8_t rateId = GetRateId (station->m_txrate);
606 uint8_t groupId = GetGroupId (station->m_txrate);
607 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
608 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
609
610 UpdatePacketCounters (station, 1, 0);
611
612 NS_LOG_DEBUG ("DoReportDataOk m_txrate = " << station->m_txrate << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess << " (after update).");
613
614 station->m_isSampling = false;
615 station->m_sampleDeferred = false;
616
617 UpdateRetry (station);
618 if (Simulator::Now () >= station->m_nextStatsUpdate)
619 {
620 UpdateStats (station);
621 }
622
623 if (station->m_nModes >= 1)
624 {
625 station->m_txrate = FindRate (station);
626 }
627 }
628
629 NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate );
630}
631
632void
634{
635 NS_LOG_FUNCTION (this << st);
636 MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
637
638 CheckInit (station);
639 if (!station->m_initialized)
640 {
641 return;
642 }
643
644 NS_LOG_DEBUG ("DoReportFinalDataFailed - TxRate=" << station->m_txrate);
645
646 if (!station->m_isHt)
647 {
648 m_legacyManager->UpdatePacketCounters (station);
649
650 UpdateRetry (station);
651
652 m_legacyManager->UpdateStats (station);
653 if (station->m_nModes >= 1)
654 {
655 station->m_txrate = m_legacyManager->FindRate (station);
656 }
657 }
658 else
659 {
660 UpdatePacketCounters (station, 0, 1);
661
662 station->m_isSampling = false;
663 station->m_sampleDeferred = false;
664
665 UpdateRetry (station);
666 if (Simulator::Now () >= station->m_nextStatsUpdate)
667 {
668 UpdateStats (station);
669 }
670
671 if (station->m_nModes >= 1)
672 {
673 station->m_txrate = FindRate (station);
674 }
675 }
676 NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
677}
678
679void
680MinstrelHtWifiManager::DoReportAmpduTxStatus (WifiRemoteStation *st, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus,
681 double rxSnr, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss)
682{
683 NS_LOG_FUNCTION (this << st << nSuccessfulMpdus << nFailedMpdus << rxSnr << dataSnr << dataChannelWidth << +dataNss);
684 MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
685
686 CheckInit (station);
687 if (!station->m_initialized)
688 {
689 return;
690 }
691
692 NS_ASSERT_MSG (station->m_isHt, "A-MPDU Tx Status called but this is a non-HT STA.");
693
694 NS_LOG_DEBUG ("DoReportAmpduTxStatus. TxRate=" << station->m_txrate << " SuccMpdus=" <<
695 nSuccessfulMpdus << " FailedMpdus=" << nFailedMpdus);
696
697 station->m_ampduPacketCount++;
698 station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
699
700 UpdatePacketCounters (station, nSuccessfulMpdus, nFailedMpdus);
701
702 uint8_t rateId = GetRateId (station->m_txrate);
703 uint8_t groupId = GetGroupId (station->m_txrate);
704 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
705 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt += nSuccessfulMpdus + nFailedMpdus;
706
707 if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries (station))
708 {
709 // We do not receive a BlockAck. The entire AMPDU fail.
710 UpdateRate (station);
711 }
712 else
713 {
714 station->m_isSampling = false;
715 station->m_sampleDeferred = false;
716
717 UpdateRetry (station);
718 if (Simulator::Now () >= station->m_nextStatsUpdate)
719 {
720 UpdateStats (station);
721 }
722
723 if (station->m_nModes >= 1)
724 {
725 station->m_txrate = FindRate (station);
726 }
727 NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
728 }
729}
730
731void
733{
734 NS_LOG_FUNCTION (this << station);
735
757 CheckInit (station);
758 if (!station->m_initialized)
759 {
760 return;
761 }
762 station->m_longRetry++;
763
767 uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
768 uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
769 uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
770 uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
771 uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
772 uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
773
775 if (!station->m_isSampling)
776 {
778 if (station->m_longRetry < station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
779 {
780 NS_LOG_DEBUG ("Not Sampling; use the same rate again");
781 station->m_txrate = station->m_maxTpRate;
782 }
783
785 else if (station->m_longRetry < ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
786 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
787 {
788 NS_LOG_DEBUG ("Not Sampling; use the Max TP2");
789 station->m_txrate = station->m_maxTpRate2;
790 }
791
793 else if (station->m_longRetry <= ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
794 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
795 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
796 {
797 NS_LOG_DEBUG ("Not Sampling; use Max Prob");
798 station->m_txrate = station->m_maxProbRate;
799 }
800 else
801 {
802 NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
803 }
804 }
805
807 else
808 {
811 if (station->m_longRetry < 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
812 {
813 NS_LOG_DEBUG ("Sampling use the MaxTP rate");
814 station->m_txrate = station->m_maxTpRate2;
815 }
816
818 else if (station->m_longRetry <= 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
819 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
820 {
821 NS_LOG_DEBUG ("Sampling use the MaxProb rate");
822 station->m_txrate = station->m_maxProbRate;
823 }
824 else
825 {
826 NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
827 }
828 }
829 NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
830}
831
832void
834{
835 NS_LOG_FUNCTION (this << station);
836 station->m_shortRetry = 0;
837 station->m_longRetry = 0;
838}
839
840void
841MinstrelHtWifiManager::UpdatePacketCounters (MinstrelHtWifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus)
842{
843 NS_LOG_FUNCTION (this << station << nSuccessfulMpdus << nFailedMpdus);
844
845 station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
846 if (station->m_isSampling)
847 {
848 station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
849 }
850 if (station->m_totalPacketsCount == ~0)
851 {
852 station->m_samplePacketsCount = 0;
853 station->m_totalPacketsCount = 0;
854 }
855
856 if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
857 {
858 station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
859 station->m_sampleTries = 1;
860 station->m_sampleCount--;
861 }
862}
863
866{
867 NS_LOG_FUNCTION (this << st);
868 MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
869
870 if (!station->m_initialized)
871 {
872 CheckInit (station);
873 }
874
875 if (!station->m_isHt)
876 {
877 WifiTxVector vector = m_legacyManager->GetDataTxVector (station);
878 uint64_t dataRate = vector.GetMode ().GetDataRate (vector);
879 if (m_currentRate != dataRate && !station->m_isSampling)
880 {
881 NS_LOG_DEBUG ("New datarate: " << dataRate);
882 m_currentRate = dataRate;
883 }
884 return vector;
885 }
886 else
887 {
888 NS_LOG_DEBUG ("DoGetDataMode m_txrate= " << station->m_txrate);
889
890 uint8_t rateId = GetRateId (station->m_txrate);
891 uint8_t groupId = GetGroupId (station->m_txrate);
892 uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
893
894 NS_LOG_DEBUG ("DoGetDataMode rateId= " << +rateId << " groupId= " << +groupId << " mode= " << GetMcsSupported (station, mcsIndex));
895
896 McsGroup group = m_minstrelGroups[groupId];
897
898 // Check consistency of rate selected.
899 if (((group.type == GROUP_HE) && (group.gi < GetGuardInterval (station))) ||
900 (((group.type == GROUP_HT) || (group.type == GROUP_VHT)) && (group.gi == 400) && !GetShortGuardIntervalSupported (station)) ||
901 (group.chWidth > GetChannelWidth (station)) ||
902 (group.streams > GetNumberOfSupportedStreams (station)))
903 {
904 NS_FATAL_ERROR ("Inconsistent group selected. Group: (" << +group.streams <<
905 "," << group.gi << "," << group.chWidth << ")" <<
906 " Station capabilities: (" << GetNumberOfSupportedStreams (station) <<
907 "," << ((group.type == GROUP_HE) ? GetGuardInterval (station) : (GetShortGuardIntervalSupported (station) ? 400 : 800)) <<
908 "," << GetChannelWidth (station) << ")");
909 }
910 WifiMode mode = GetMcsSupported (station, mcsIndex);
912 uint64_t dataRate = mode.GetDataRate (txVector);
913 if (m_currentRate != dataRate && !station->m_isSampling)
914 {
915 NS_LOG_DEBUG ("New datarate: " << dataRate);
916 m_currentRate = dataRate;
917 }
918 return txVector;
919 }
920}
921
924{
925 NS_LOG_FUNCTION (this << st);
926 MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
927
928 if (!station->m_initialized)
929 {
930 CheckInit (station);
931 }
932
933 if (!station->m_isHt)
934 {
935 return m_legacyManager->GetRtsTxVector (station);
936 }
937 else
938 {
939 NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
940
941 /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
942 * When supported, decision of using HT has to follow rules in Section 9.7.6 from 802.11-2012.
943 * From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is carried in a
944 * non-HT PPDU shall be transmitted by the STA using a rate no higher than the highest
945 * rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
946 * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
947 * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
948 * these conditions, the control frame shall be transmitted at a rate no higher than the
949 * highest mandatory rate of the attached PHY that is less than or equal to the rate
950 * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
951 * directed to the same receiving STA."
952 */
953
954 // As we are in Minstrel HT, assume the last rate was an HT rate.
955 uint8_t rateId = GetRateId (station->m_txrate);
956 uint8_t groupId = GetGroupId (station->m_txrate);
957 uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
958
959 WifiMode lastRate = GetMcsSupported (station, mcsIndex);
960 uint64_t lastDataRate = lastRate.GetNonHtReferenceRate ();
961 uint8_t nBasicRates = GetNBasicModes ();
962
963 WifiMode rtsRate;
964 bool rateFound = false;
965
966 for (uint8_t i = 0; i < nBasicRates; i++)
967 {
968 uint64_t rate = GetBasicMode (i).GetDataRate (20);
969 if (rate <= lastDataRate)
970 {
971 rtsRate = GetBasicMode (i);
972 rateFound = true;
973 }
974 }
975
976 if (!rateFound)
977 {
979 for (const auto & mode : phy->GetModeList ())
980 {
981 uint64_t rate = mode.GetDataRate (20);
982 if (rate <= lastDataRate)
983 {
984 rtsRate = mode;
985 rateFound = true;
986 }
987 }
988 }
989
990 NS_ASSERT (rateFound);
991
993 800, 1, 1, 0, GetChannelWidthForTransmission (rtsRate, GetChannelWidth (station)), GetAggregation (station));
994 }
995}
996
997bool
999{
1000 NS_LOG_FUNCTION (this << st << packet << normally);
1001
1002 MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
1003
1004 CheckInit (station);
1005 if (!station->m_initialized)
1006 {
1007 return normally;
1008 }
1009
1010 uint32_t maxRetries;
1011
1012 if (!station->m_isHt)
1013 {
1014 maxRetries = m_legacyManager->CountRetries (station);
1015 }
1016 else
1017 {
1018 maxRetries = CountRetries (station);
1019 }
1020
1021 if (station->m_longRetry >= maxRetries)
1022 {
1023 NS_LOG_DEBUG ("No re-transmission allowed. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
1024 return false;
1025 }
1026 else
1027 {
1028 NS_LOG_DEBUG ("Re-transmit. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
1029 return true;
1030 }
1031}
1032
1035{
1036 uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
1037 uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1038 uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
1039 uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1040 uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1041 uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1042
1043 if (!station->m_isSampling)
1044 {
1045 return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
1046 station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
1047 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1048 }
1049 else
1050 {
1051 return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1052 station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1053 }
1054}
1055
1056uint16_t
1058{
1059 NS_LOG_FUNCTION (this << station);
1060 uint8_t sampleGroup = station->m_sampleGroup;
1061 uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1062 uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1063 uint8_t sampleIndex = station->m_sampleTable[index][col];
1064 uint16_t rateIndex = GetIndex (sampleGroup, sampleIndex);
1065 NS_LOG_DEBUG ("Next Sample is " << rateIndex);
1066 SetNextSample (station); //Calculate the next sample rate.
1067 return rateIndex;
1068}
1069
1070void
1072{
1073 NS_LOG_FUNCTION (this << station);
1074 do
1075 {
1076 station->m_sampleGroup++;
1077 station->m_sampleGroup %= m_numGroups;
1078 }
1079 while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1080
1081 station->m_groupsTable[station->m_sampleGroup].m_index++;
1082
1083 uint8_t sampleGroup = station->m_sampleGroup;
1084 uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1085 uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1086
1087 if (index >= m_numRates)
1088 {
1089 station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1090 station->m_groupsTable[station->m_sampleGroup].m_col++;
1091 if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1092 {
1093 station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1094 }
1095 index = station->m_groupsTable[station->m_sampleGroup].m_index;
1096 col = station->m_groupsTable[sampleGroup].m_col;
1097 }
1098 NS_LOG_DEBUG ("New sample set: group= " << +sampleGroup << " index= " << +station->m_sampleTable[index][col]);
1099}
1100
1101uint16_t
1103{
1104 NS_LOG_FUNCTION (this << station);
1105 NS_LOG_DEBUG ("FindRate packet=" << station->m_totalPacketsCount);
1106
1107 if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1108 {
1109 return station->m_maxTpRate;
1110 }
1111
1112 // If we have waited enough, then sample.
1113 if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1114 {
1115 //SAMPLING
1116 NS_LOG_DEBUG ("Obtaining a sampling rate");
1118 uint16_t sampleIdx = GetNextSample (station);
1119 NS_LOG_DEBUG ("Sampling rate = " << sampleIdx);
1120
1121 //Evaluate if the sampling rate selected should be used.
1122 uint8_t sampleGroupId = GetGroupId (sampleIdx);
1123 uint8_t sampleRateId = GetRateId (sampleIdx);
1124
1125 // If the rate selected is not supported, then don't sample.
1126 if (station->m_groupsTable[sampleGroupId].m_supported && station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1127 {
1135 MinstrelHtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1136
1137 NS_LOG_DEBUG ("Use sample rate? MaxTpRate= " << station->m_maxTpRate << " CurrentRate= " << station->m_txrate <<
1138 " SampleRate= " << sampleIdx << " SampleProb= " << sampleRateInfo.ewmaProb);
1139
1140 if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2
1141 && sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1142 {
1143
1149 uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1150 uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1151 uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1152 uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1153 uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
1154
1155 uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1156 uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1157
1158 Time sampleDuration = sampleRateInfo.perfectTxTime;
1159 Time maxTp2Duration = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1160 Time maxProbDuration = station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].perfectTxTime;
1161
1162 NS_LOG_DEBUG ("Use sample rate? SampleDuration= " << sampleDuration << " maxTp2Duration= " << maxTp2Duration <<
1163 " maxProbDuration= " << maxProbDuration << " sampleStreams= " << +sampleStreams <<
1164 " maxTpStreams= " << +maxTpStreams);
1165 if (sampleDuration < maxTp2Duration || (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1166 {
1168 station->m_isSampling = true;
1169
1171 station->m_sampleRate = sampleIdx;
1172
1173 NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1174 station->m_sampleTries--;
1175 return sampleIdx;
1176 }
1177 else
1178 {
1179 station->m_numSamplesSlow++;
1180 if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1181 {
1183 station->m_isSampling = true;
1184
1186 station->m_sampleRate = sampleIdx;
1187
1188 NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1189 station->m_sampleTries--;
1190 return sampleIdx;
1191 }
1192 }
1193 }
1194 }
1195 }
1196 if (station->m_sampleWait > 0)
1197 {
1198 station->m_sampleWait--;
1199 }
1200
1202
1203 NS_LOG_DEBUG ("FindRate " << "maxTpRrate=" << station->m_maxTpRate);
1204 return station->m_maxTpRate;
1205}
1206void
1208{
1209 NS_LOG_FUNCTION (this << station);
1210
1212
1213 station->m_numSamplesSlow = 0;
1214 station->m_sampleCount = 0;
1215
1216 double tempProb;
1217
1218 if (station->m_ampduPacketCount > 0)
1219 {
1220 uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1221 station->m_avgAmpduLen = ( newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel) ) / 100;
1222 station->m_ampduLen = 0;
1223 station->m_ampduPacketCount = 0;
1224 }
1225
1226 /* Initialize global rate indexes */
1227 station->m_maxTpRate = GetLowestIndex (station);
1228 station->m_maxTpRate2 = GetLowestIndex (station);
1229 station->m_maxProbRate = GetLowestIndex (station);
1230
1232 for (uint8_t j = 0; j < m_numGroups; j++)
1233 {
1234 if (station->m_groupsTable[j].m_supported)
1235 {
1236 station->m_sampleCount++;
1237
1238 /* (re)Initialize group rate indexes */
1239 station->m_groupsTable[j].m_maxTpRate = GetLowestIndex (station, j);
1240 station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex (station, j);
1241 station->m_groupsTable[j].m_maxProbRate = GetLowestIndex (station, j);
1242
1243 for (uint8_t i = 0; i < m_numRates; i++)
1244 {
1245 if (station->m_groupsTable[j].m_ratesTable[i].supported)
1246 {
1247 station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1248
1249 NS_LOG_DEBUG (+i << " " << GetMcsSupported (station, station->m_groupsTable[j].m_ratesTable[i].mcsIndex) <<
1250 "\t attempt=" << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt <<
1251 "\t success=" << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1252
1254 if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1255 {
1256 station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1261 tempProb = (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) / station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1262
1264 station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1265
1266 if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1267 {
1268 station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1269 }
1270 else
1271 {
1272 station->m_groupsTable[j].m_ratesTable[i].ewmsdProb = CalculateEwmsd (station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1273 tempProb, station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1274 m_ewmaLevel);
1276 tempProb = (tempProb * (100 - m_ewmaLevel) + station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) / 100;
1277 station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1278 }
1279
1280 station->m_groupsTable[j].m_ratesTable[i].throughput = CalculateThroughput (station, j, i, tempProb);
1281
1282 station->m_groupsTable[j].m_ratesTable[i].successHist += station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1283 station->m_groupsTable[j].m_ratesTable[i].attemptHist += station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1284 }
1285 else
1286 {
1287 station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1288 }
1289
1291 station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess = station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1292 station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt = station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1293 station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1294 station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1295
1296 if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1297 {
1298 SetBestStationThRates (station, GetIndex (j, i));
1299 SetBestProbabilityRate (station, GetIndex (j, i));
1300 }
1301
1302 }
1303 }
1304 }
1305 }
1306
1307 //Try to sample all available rates during each interval.
1308 station->m_sampleCount *= 8;
1309
1310 //Recalculate retries for the rates selected.
1311 CalculateRetransmits (station, station->m_maxTpRate);
1312 CalculateRetransmits (station, station->m_maxTpRate2);
1313 CalculateRetransmits (station, station->m_maxProbRate);
1314
1315 NS_LOG_DEBUG ("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2 << "\nmax prob=" << station->m_maxProbRate);
1316 if (m_printStats)
1317 {
1318 PrintTable (station);
1319 }
1320}
1321
1322double
1323MinstrelHtWifiManager::CalculateThroughput (MinstrelHtWifiRemoteStation *station, uint8_t groupId, uint8_t rateId, double ewmaProb)
1324{
1330 if (ewmaProb < 10)
1331 {
1332 return 0;
1333 }
1334 else
1335 {
1340 Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1341 if (ewmaProb > 90)
1342 {
1343 return 90 / txTime.GetSeconds ();
1344 }
1345 else
1346 {
1347 return ewmaProb / txTime.GetSeconds ();
1348 }
1349 }
1350}
1351
1352void
1354{
1355 GroupInfo *group;
1356 MinstrelHtRateInfo rate;
1357 uint8_t tmpGroupId, tmpRateId;
1358 double tmpTh, tmpProb;
1359 uint8_t groupId, rateId;
1360 double currentTh;
1361 // maximum group probability (GP) variables
1362 uint8_t maxGPGroupId, maxGPRateId;
1363 double maxGPTh;
1364
1365 groupId = GetGroupId (index);
1366 rateId = GetRateId (index);
1367 group = &station->m_groupsTable[groupId];
1368 rate = group->m_ratesTable[rateId];
1369
1370 tmpGroupId = GetGroupId (station->m_maxProbRate);
1371 tmpRateId = GetRateId (station->m_maxProbRate);
1372 tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1373 tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1374
1375 if (rate.ewmaProb > 75)
1376 {
1377 currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1378 if (currentTh > tmpTh)
1379 {
1380 station->m_maxProbRate = index;
1381 }
1382
1383 maxGPGroupId = GetGroupId (group->m_maxProbRate);
1384 maxGPRateId = GetRateId (group->m_maxProbRate);
1385 maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1386
1387 if (currentTh > maxGPTh)
1388 {
1389 group->m_maxProbRate = index;
1390 }
1391 }
1392 else
1393 {
1394 if (rate.ewmaProb > tmpProb)
1395 {
1396 station->m_maxProbRate = index;
1397 }
1398 maxGPRateId = GetRateId (group->m_maxProbRate);
1399 if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1400 {
1401 group->m_maxProbRate = index;
1402 }
1403 }
1404}
1405
1406/*
1407 * Find & sort topmost throughput rates
1408 *
1409 * If multiple rates provide equal throughput the sorting is based on their
1410 * current success probability. Higher success probability is preferred among
1411 * MCS groups.
1412 */
1413void
1415{
1416 uint8_t groupId, rateId;
1417 double th, prob;
1418 uint8_t maxTpGroupId, maxTpRateId;
1419 uint8_t maxTp2GroupId, maxTp2RateId;
1420 double maxTpTh, maxTpProb;
1421 double maxTp2Th, maxTp2Prob;
1422
1423 groupId = GetGroupId (index);
1424 rateId = GetRateId (index);
1425 prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1426 th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1427
1428 maxTpGroupId = GetGroupId (station->m_maxTpRate);
1429 maxTpRateId = GetRateId (station->m_maxTpRate);
1430 maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1431 maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1432
1433 maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1434 maxTp2RateId = GetRateId (station->m_maxTpRate2);
1435 maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1436 maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1437
1438 if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1439 {
1440 station->m_maxTpRate2 = station->m_maxTpRate;
1441 station->m_maxTpRate = index;
1442 }
1443 else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1444 {
1445 station->m_maxTpRate2 = index;
1446 }
1447
1448 //Find best rates per group
1449
1450 GroupInfo *group = &station->m_groupsTable[groupId];
1451 maxTpGroupId = GetGroupId (group->m_maxTpRate);
1452 maxTpRateId = GetRateId (group->m_maxTpRate);
1453 maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1454 maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1455
1456 maxTp2GroupId = GetGroupId (group->m_maxTpRate2);
1457 maxTp2RateId = GetRateId (group->m_maxTpRate2);
1458 maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1459 maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1460
1461 if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1462 {
1463 group->m_maxTpRate2 = group->m_maxTpRate;
1464 group->m_maxTpRate = index;
1465 }
1466 else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1467 {
1468 group->m_maxTpRate2 = index;
1469 }
1470}
1471
1472void
1474{
1475 NS_LOG_FUNCTION (this << station);
1476
1478
1482 NS_LOG_DEBUG ("Supported groups by station:");
1483 bool noSupportedGroupFound = true;
1484 for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1485 {
1486 if (m_minstrelGroups[groupId].isSupported)
1487 {
1488 station->m_groupsTable[groupId].m_supported = false;
1489
1490 if ((m_minstrelGroups[groupId].type == GROUP_HE) && !GetHeSupported (station))
1491 {
1492 //It is a HE group but the receiver does not support HE: skip
1493 continue;
1494 }
1495 if ((m_minstrelGroups[groupId].type == GROUP_VHT) && !GetVhtSupported (station))
1496 {
1497 //It is a VHT group but the receiver does not support VHT: skip
1498 continue;
1499 }
1500 if ((m_minstrelGroups[groupId].type != GROUP_HE) && GetHeSupported (station) && m_useLatestAmendmentOnly)
1501 {
1502 //It is not a HE group and the receiver supports HE: skip since UseLatestAmendmentOnly attribute is enabled
1503 continue;
1504 }
1505 if (!GetHeSupported (station) && (m_minstrelGroups[groupId].type != GROUP_VHT) && GetVhtSupported (station) && m_useLatestAmendmentOnly)
1506 {
1507 //It is not a VHT group and the receiver supports VHT (but not HE): skip since UseLatestAmendmentOnly attribute is enabled
1508 continue;
1509 }
1510 if (((m_minstrelGroups[groupId].type == GROUP_HT) || (m_minstrelGroups[groupId].type == GROUP_VHT))
1511 && (m_minstrelGroups[groupId].gi == 400) && !GetShortGuardIntervalSupported (station))
1512 {
1513 //It is a SGI group but the receiver does not support SGI: skip
1514 continue;
1515 }
1516 if ((m_minstrelGroups[groupId].type == GROUP_HE) && (m_minstrelGroups[groupId].gi < GetGuardInterval (station)))
1517 {
1518 //The receiver does not support the GI: skip
1519 continue;
1520 }
1521 if (GetChannelWidth (station) < m_minstrelGroups[groupId].chWidth)
1522 {
1523 //The receiver does not support the channel width: skip
1524 continue;
1525 }
1526 if (GetNumberOfSupportedStreams (station) < m_minstrelGroups[groupId].streams)
1527 {
1528 //The receiver does not support the number of spatial streams: skip
1529 continue;
1530 }
1531
1532 NS_LOG_DEBUG ("Group: " << +groupId
1533 << " type: " << m_minstrelGroups[groupId].type
1534 << " streams: " << +m_minstrelGroups[groupId].streams
1535 << " GI: " << m_minstrelGroups[groupId].gi
1536 << " width: " << m_minstrelGroups[groupId].chWidth);
1537
1538 noSupportedGroupFound = false;
1539 station->m_groupsTable[groupId].m_supported = true;
1540 station->m_groupsTable[groupId].m_col = 0;
1541 station->m_groupsTable[groupId].m_index = 0;
1542
1543 station->m_groupsTable[groupId].m_ratesTable = MinstrelHtRate (m_numRates);
1544 for (uint8_t i = 0; i < m_numRates; i++)
1545 {
1546 station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1547 }
1548
1549 // Initialize all modes supported by the remote station that belong to the current group.
1550 for (uint8_t i = 0; i < station->m_nModes; i++)
1551 {
1552 WifiMode mode = GetMcsSupported (station, i);
1553
1556 uint8_t rateId = mode.GetMcsValue ();
1558 {
1559 rateId %= MAX_HT_GROUP_RATES;
1560 }
1561
1562 if (((m_minstrelGroups[groupId].type == GROUP_HE)
1563 && (mode.GetModulationClass () == WIFI_MOD_CLASS_HE)
1564 && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1565 || ((m_minstrelGroups[groupId].type == GROUP_VHT)
1566 && (mode.GetModulationClass () == WIFI_MOD_CLASS_VHT)
1567 && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1568 || ((m_minstrelGroups[groupId].type == GROUP_HT)
1569 && (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1570 && (mode.GetMcsValue () < (m_minstrelGroups[groupId].streams * 8))
1571 && (mode.GetMcsValue () >= ((m_minstrelGroups[groupId].streams - 1) * 8))))
1572 {
1573 NS_LOG_DEBUG ("Mode " << +i << ": " << mode);
1574
1575 station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1576 station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex = i;
1577 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1578 station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1579 station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1580 station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1581 station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1582 station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1583 station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1584 station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1585 station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1586 station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1587 station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
1588 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1589 station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1590 CalculateRetransmits (station, groupId, rateId);
1591 }
1592 }
1593 }
1594 }
1596 if (noSupportedGroupFound)
1597 {
1598 NS_FATAL_ERROR ("No supported group has been found");
1599 }
1600 SetNextSample (station);
1601 UpdateStats (station);
1602 station->m_txrate = FindRate (station);
1603}
1604
1605void
1607{
1608 NS_LOG_FUNCTION (this << station << index);
1609 uint8_t groupId = GetGroupId (index);
1610 uint8_t rateId = GetRateId (index);
1611 if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1612 {
1613 CalculateRetransmits (station, groupId, rateId);
1614 }
1615}
1616
1617void
1619{
1620 NS_LOG_FUNCTION (this << station << +groupId << +rateId);
1621
1622 uint32_t cw = 15; // Is an approximation.
1623 uint32_t cwMax = 1023;
1624 Time cwTime, txTime, dataTxTime;
1625 Time slotTime = GetPhy ()->GetSlot ();
1626 Time ackTime = GetPhy ()->GetSifs () + GetPhy ()->GetBlockAckTxTime ();
1627
1628 if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1629 {
1630 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1631 }
1632 else
1633 {
1634 station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1635 station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1636
1637 dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1638 GetMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) * (station->m_avgAmpduLen - 1);
1639
1640 /* Contention time for first 2 tries */
1641 cwTime = (cw / 2) * slotTime;
1642 cw = Min ((cw + 1) * 2, cwMax);
1643 cwTime += (cw / 2) * slotTime;
1644 cw = Min ((cw + 1) * 2, cwMax);
1645
1646 /* Total TX time for data and Contention after first 2 tries */
1647 txTime = cwTime + 2 * (dataTxTime + ackTime);
1648
1649 /* See how many more tries we can fit inside segment size */
1650 do
1651 {
1652 /* Contention time for this try */
1653 cwTime = (cw / 2) * slotTime;
1654 cw = Min ((cw + 1) * 2, cwMax);
1655
1656 /* Total TX time after this try */
1657 txTime += cwTime + ackTime + dataTxTime;
1658 }
1659 while ((txTime < MilliSeconds (6))
1660 && (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1661 }
1662}
1663
1664double
1665MinstrelHtWifiManager::CalculateEwmsd (double oldEwmsd, double currentProb, double ewmaProb, double weight)
1666{
1667 double diff, incr, tmp;
1668
1669 /* calculate exponential weighted moving variance */
1670 diff = currentProb - ewmaProb;
1671 incr = (100 - weight) * diff / 100;
1672 tmp = oldEwmsd * oldEwmsd;
1673 tmp = weight * (tmp + diff * incr) / 100;
1674
1675 /* return standard deviation */
1676 return sqrt (tmp);
1677}
1678
1679void
1681{
1682 NS_LOG_FUNCTION (this << station);
1683 station->m_col = station->m_index = 0;
1684
1685 //for off-setting to make rates fall between 0 and nModes
1686 uint8_t numSampleRates = m_numRates;
1687
1688 uint16_t newIndex;
1689 for (uint8_t col = 0; col < m_nSampleCol; col++)
1690 {
1691 for (uint8_t i = 0; i < numSampleRates; i++ )
1692 {
1697 int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
1698 newIndex = (i + uv) % numSampleRates;
1699
1700 //this loop is used for filling in other uninitialized places
1701 while (station->m_sampleTable[newIndex][col] != 0)
1702 {
1703 newIndex = (newIndex + 1) % m_numRates;
1704 }
1705 station->m_sampleTable[newIndex][col] = i;
1706 }
1707 }
1708}
1709
1710void
1712{
1713 if (!station->m_statsFile.is_open ())
1714 {
1715 std::ostringstream tmp;
1716 tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1717 station->m_statsFile.open (tmp.str ().c_str (), std::ios::out);
1718 }
1719
1720 station->m_statsFile << " best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n" <<
1721 " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n";
1722 for (uint8_t i = 0; i < m_numGroups; i++)
1723 {
1724 StatsDump (station, i, station->m_statsFile);
1725 }
1726
1727 station->m_statsFile << "\nTotal packet count:: ideal " << Max (0, station->m_totalPacketsCount - station->m_samplePacketsCount) <<
1728 " lookaround " << station->m_samplePacketsCount << "\n";
1729 station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen << "\n\n";
1730
1731 station->m_statsFile.flush ();
1732}
1733
1734void
1735MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint8_t groupId, std::ofstream &of)
1736{
1737 uint8_t numRates = m_numRates;
1738 McsGroup group = m_minstrelGroups[groupId];
1739 Time txTime;
1740 for (uint8_t i = 0; i < numRates; i++)
1741 {
1742 if (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[i].supported)
1743 {
1744 of << group.type << " " << group.chWidth << " " << group.gi << " " << +group.streams << " ";
1745
1746 uint16_t maxTpRate = station->m_maxTpRate;
1747 uint16_t maxTpRate2 = station->m_maxTpRate2;
1748 uint16_t maxProbRate = station->m_maxProbRate;
1749
1750 uint16_t idx = GetIndex (groupId, i);
1751 if (idx == maxTpRate)
1752 {
1753 of << 'A';
1754 }
1755 else
1756 {
1757 of << ' ';
1758 }
1759 if (idx == maxTpRate2)
1760 {
1761 of << 'B';
1762 }
1763 else
1764 {
1765 of << ' ';
1766 }
1767 if (idx == maxProbRate)
1768 {
1769 of << 'P';
1770 }
1771 else
1772 {
1773 of << ' ';
1774 }
1775
1776 if (group.type == GROUP_HT)
1777 {
1778 of << std::setw (4) << " MCS" << (group.streams - 1) * 8 + i;
1779 }
1780 else
1781 {
1782 of << std::setw (7) << " MCS" << +i << "/" << static_cast<int>(group.streams);
1783 }
1784
1785 of << " " << std::setw (3) << +idx << " ";
1786
1787 /* tx_time[rate(i)] in usec */
1788 txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
1789 of << std::setw (6) << txTime.GetMicroSeconds () << " ";
1790
1791 of << std::setw (7) << CalculateThroughput (station, groupId, i, 100) / 100 << " " <<
1792 std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100 << " " <<
1793 std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb << " " <<
1794 std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb << " " <<
1795 std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].prob << " " <<
1796 std::setw (2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount << " " <<
1797 std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " " <<
1798 std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt << " " <<
1799 std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " " <<
1800 std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist << "\n";
1801 }
1802 }
1803}
1804uint16_t
1805MinstrelHtWifiManager::GetIndex (uint8_t groupId, uint8_t rateId)
1806{
1807 NS_LOG_FUNCTION (this << +groupId << +rateId);
1808 uint16_t index;
1809 index = groupId * m_numRates + rateId;
1810 return index;
1811}
1812
1813uint8_t
1815{
1816 NS_LOG_FUNCTION (this << index);
1817 uint8_t id;
1818 id = index % m_numRates;
1819 return id;
1820}
1821
1822uint8_t
1824{
1825 NS_LOG_FUNCTION (this << index);
1826 return index / m_numRates;
1827}
1828
1829uint8_t
1830MinstrelHtWifiManager::GetHtGroupId (uint8_t txstreams, uint16_t gi, uint16_t chWidth)
1831{
1832 NS_LOG_FUNCTION (this << +txstreams << gi << chWidth);
1833 uint8_t giIndex = (gi == 400) ? 1 : 0;
1834 uint8_t widthIndex = (chWidth == 40) ? 1 : 0;
1835 return (MAX_HT_SUPPORTED_STREAMS * 2 * widthIndex) + (MAX_HT_SUPPORTED_STREAMS * giIndex) + txstreams - 1;
1836}
1837
1838uint8_t
1839MinstrelHtWifiManager::GetVhtGroupId (uint8_t txstreams, uint16_t gi, uint16_t chWidth)
1840{
1841 NS_LOG_FUNCTION (this << +txstreams << gi << chWidth);
1842 uint8_t giIndex = (gi == 400) ? 1 : 0;
1843 uint8_t widthIndex;
1844 if (chWidth == 160)
1845 {
1846 widthIndex = 3;
1847 }
1848 else if (chWidth == 80)
1849 {
1850 widthIndex = 2;
1851 }
1852 else if (chWidth == 40)
1853 {
1854 widthIndex = 1;
1855 }
1856 else //20 MHz
1857 {
1858 widthIndex = 0;
1859 }
1860 uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
1861 groupId += (MAX_VHT_SUPPORTED_STREAMS * 2 * widthIndex) + (MAX_VHT_SUPPORTED_STREAMS * giIndex) + txstreams - 1;
1862 return groupId;
1863}
1864
1865uint8_t
1866MinstrelHtWifiManager::GetHeGroupId (uint8_t txstreams, uint16_t gi, uint16_t chWidth)
1867{
1868 NS_LOG_FUNCTION (this << +txstreams << gi << chWidth);
1869 uint8_t giIndex;
1870 if (gi == 800)
1871 {
1872 giIndex = 2;
1873 }
1874 else if (gi == 1600)
1875 {
1876 giIndex = 1;
1877 }
1878 else //3200 ns
1879 {
1880 giIndex = 0;
1881 }
1882 uint8_t widthIndex;
1883 if (chWidth == 160)
1884 {
1885 widthIndex = 3;
1886 }
1887 else if (chWidth == 80)
1888 {
1889 widthIndex = 2;
1890 }
1891 else if (chWidth == 40)
1892 {
1893 widthIndex = 1;
1894 }
1895 else //20 MHz
1896 {
1897 widthIndex = 0;
1898 }
1899 uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
1900 if (GetVhtSupported ())
1901 {
1903 }
1904 groupId += (MAX_HE_SUPPORTED_STREAMS * 3 * widthIndex) + (MAX_HE_SUPPORTED_STREAMS * giIndex) + txstreams - 1;
1905 return groupId;
1906}
1907
1908uint16_t
1910{
1911 NS_LOG_FUNCTION (this << station);
1912
1913 uint8_t groupId = 0;
1914 uint8_t rateId = 0;
1915 while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
1916 {
1917 groupId++;
1918 }
1919 while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1920 {
1921 rateId++;
1922 }
1923 NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1924 return GetIndex (groupId, rateId);
1925}
1926
1927uint16_t
1929{
1930 NS_LOG_FUNCTION (this << station << +groupId);
1931
1932 uint8_t rateId = 0;
1933 while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1934 {
1935 rateId++;
1936 }
1937 NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1938 return GetIndex (groupId, rateId);
1939}
1940
1943{
1944 WifiModeList heMcsList;
1945 for (const auto & mode : GetPhy ()->GetMcsList (WIFI_MOD_CLASS_HE))
1946 {
1947 heMcsList.push_back (mode);
1948 }
1949 return heMcsList;
1950}
1951
1954{
1955 WifiModeList vhtMcsList;
1956 for (const auto & mode : GetPhy ()->GetMcsList (WIFI_MOD_CLASS_VHT))
1957 {
1958 vhtMcsList.push_back (mode);
1959 }
1960 return vhtMcsList;
1961}
1962
1965{
1966 WifiModeList htMcsList;
1967 for (const auto & mode : GetPhy ()->GetMcsList (WIFI_MOD_CLASS_HT))
1968 {
1969 htMcsList.push_back (mode);
1970 }
1971 return htMcsList;
1972}
1973
1974} // namespace ns3
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Implementation of Minstrel-HT Rate Control Algorithm.
uint32_t CountRetries(MinstrelHtWifiRemoteStation *station)
Count retries.
uint32_t m_frameLength
Frame length used for 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 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 DoInitialize(void) override
Initialize() implementation.
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.
WifiModeList GetHtDeviceMcsList(void) const
Returns a list of only the HT MCS supported by the device.
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.
WifiModeList GetVhtDeviceMcsList(void) const
Returns a list of only the VHT MCS supported by the device.
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.
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.
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.
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.
WifiRemoteStation * DoCreateStation(void) const override
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.
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.
WifiTxVector DoGetDataTxVector(WifiRemoteStation *station) override
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.
static TypeId GetTypeId(void)
Get the type ID.
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(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:387
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:379
AttributeValue implementation for Time.
Definition: nstime.h:1308
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
Hold an unsigned integer type.
Definition: uinteger.h:44
uint32_t GetInteger(uint32_t min, uint32_t max)
Get the next random value, as an unsigned integer in the specified range .
represent a single transmission mode
Definition: wifi-mode.h:48
uint64_t GetNonHtReferenceRate(void) const
Definition: wifi-mode.cc:184
uint8_t GetMcsValue(void) const
Definition: wifi-mode.cc:155
WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:177
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:114
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:1282
Time GetSlot(void) const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:671
Time GetBlockAckTxTime(void) const
Return the estimated BlockAck TX time for this PHY.
Definition: wifi-phy.cc:695
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:659
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1300
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
uint16_t GetChannelWidth(const WifiRemoteStation *station) const
Return the channel width supported by the station.
bool GetVhtSupported(void) const
Return whether the device has VHT capability support enabled.
Ptr< WifiPhy > GetPhy(void) const
Return the WifiPhy.
uint8_t GetNBasicModes(void) const
Return the number of basic modes we support.
bool GetAggregation(const WifiRemoteStation *station) const
Return whether the given station supports A-MPDU.
bool GetShortPreambleEnabled(void) const
Return whether the device uses short PHY preambles.
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.
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...
bool GetHeSupported(void) const
Return whether the device has HE capability support enabled.
WifiMode GetMcsSupported(const WifiRemoteStation *station, uint8_t i) const
Return the WifiMode supported by the specified station at the specified index.
bool GetShortGuardIntervalSupported(void) const
Return whether the device has SGI support enabled.
bool GetHtSupported(void) const
Return whether the device has HT 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...
uint16_t GetGuardInterval(void) const
Return the supported HE guard interval duration (in nanoseconds).
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)
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.
bool IsValid(void) const
The standard disallows certain combinations of WifiMode, number of spatial streams,...
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:67
#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:88
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:85
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1309
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:45
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:230
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:218
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#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:281
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1252
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.
uint16_t GetChannelWidthForTransmission(WifiMode mode, uint16_t maxSupportedChannelWidth)
Return the channel width that corresponds to the selected mode (instead of letting the PHY's default ...
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:536
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:260
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:96
phy
Definition: third.py:93
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,
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.