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 
49 NS_LOG_COMPONENT_DEFINE ("MinstrelHtWifiManager");
50 
51 namespace ns3 {
52 
55 {
56  uint8_t m_sampleGroup;
57 
58  uint32_t m_sampleWait;
59  uint32_t m_sampleTries;
60  uint32_t m_sampleCount;
61  uint32_t m_numSamplesSlow;
62 
63  uint32_t m_avgAmpduLen;
64  uint32_t m_ampduLen;
65  uint32_t m_ampduPacketCount;
66 
68  bool m_isHt;
69 
70  std::ofstream m_statsFile;
71 };
72 
74 
75 TypeId
77 {
78  static TypeId tid = TypeId ("ns3::MinstrelHtWifiManager")
80  .AddConstructor<MinstrelHtWifiManager> ()
81  .SetGroupName ("Wifi")
82  .AddAttribute ("UpdateStatistics",
83  "The interval between updating statistics table ",
84  TimeValue (MilliSeconds (50)),
86  MakeTimeChecker ())
87  .AddAttribute ("LegacyUpdateStatistics",
88  "The interval between updating statistics table (for legacy Minstrel) ",
89  TimeValue (MilliSeconds (100)),
91  MakeTimeChecker ())
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 
154 int64_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 
165 void
167 {
168  NS_LOG_FUNCTION (this << phy);
169  // Setup PHY for legacy manager.
170  m_legacyManager->SetupPhy (phy);
172 }
173 
174 void
176 {
177  NS_LOG_FUNCTION (this << mac);
178  m_legacyManager->SetupMac (mac);
180 }
181 
182 void
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 
348 bool
349 MinstrelHtWifiManager::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 
359 Time
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 
376 Time
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 
385 void
387 {
388  NS_LOG_FUNCTION (this << +groupId << mode << t);
389  m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.insert (std::make_pair (mode, t));
390 }
391 
392 Time
393 MinstrelHtWifiManager::GetMpduTxTime (uint8_t groupId, WifiMode mode) const
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 
401 void
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 
461 void
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 
503 void
505 {
506  NS_LOG_FUNCTION (this << st);
507  NS_LOG_DEBUG ("DoReportRxOk m_txrate=" << static_cast<MinstrelHtWifiRemoteStation*> (st)->m_txrate);
508 }
509 
510 void
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 
524 void
525 MinstrelHtWifiManager::DoReportRtsOk (WifiRemoteStation *st, double ctsSnr, WifiMode ctsMode, double rtsSnr)
526 {
527  NS_LOG_FUNCTION (this << st);
528 }
529 
530 void
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 
544 void
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 
571 void
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 
632 void
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 
679 void
680 MinstrelHtWifiManager::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 
731 void
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 
832 void
834 {
835  NS_LOG_FUNCTION (this << station);
836  station->m_shortRetry = 0;
837  station->m_longRetry = 0;
838 }
839 
840 void
841 MinstrelHtWifiManager::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  {
978  Ptr<WifiPhy> phy = GetPhy ();
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, GetPhy ()->GetChannelWidth (), GetChannelWidth (station)), GetAggregation (station));
994  }
995 }
996 
997 bool
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 
1033 uint32_t
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 
1056 uint16_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 
1070 void
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 
1101 uint16_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 }
1206 void
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 
1322 double
1323 MinstrelHtWifiManager::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 
1352 void
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  */
1413 void
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 
1472 void
1474 {
1475  NS_LOG_FUNCTION (this << station);
1476 
1477  station->m_groupsTable = McsGroupData (m_numGroups);
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 ();
1557  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
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 
1605 void
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 
1617 void
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 
1664 double
1665 MinstrelHtWifiManager::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 
1679 void
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 
1710 void
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 
1734 void
1735 MinstrelHtWifiManager::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 }
1804 uint16_t
1805 MinstrelHtWifiManager::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 
1813 uint8_t
1815 {
1816  NS_LOG_FUNCTION (this << index);
1817  uint8_t id;
1818  id = index % m_numRates;
1819  return id;
1820 }
1821 
1822 uint8_t
1824 {
1825  NS_LOG_FUNCTION (this << index);
1826  return index / m_numRates;
1827 }
1828 
1829 uint8_t
1830 MinstrelHtWifiManager::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 
1838 uint8_t
1839 MinstrelHtWifiManager::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 
1865 uint8_t
1866 MinstrelHtWifiManager::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 
1908 uint16_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 
1927 uint16_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:1303
Time GetSlot(void) const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:688
Time GetBlockAckTxTime(void) const
Return the estimated BlockAck TX time for this PHY.
Definition: wifi-phy.cc:712
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:676
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1321
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)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: boolean.h:85
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: nstime.h:1309
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
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.
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:522
uint16_t GetChannelWidthForTransmission(WifiMode mode, uint16_t maxAllowedChannelWidth)
Return the channel width that is allowed based on the selected mode and the given maximum channel wid...
static const uint8_t MAX_HE_GROUP_RATES
Number of rates (or MCS) per HE group.
static const uint8_t MAX_HT_WIDTH
Maximal channel width in MHz.
static const uint8_t MAX_HT_STREAM_GROUPS
Maximal number of groups per stream in HT (2 possible channel widths and 2 possible GI configurations...
static const uint8_t MAX_HE_STREAM_GROUPS
Maximal number of groups per stream in HE (4 possible channel widths and 3 possible GI configurations...
WifiPreamble GetPreambleForTransmission(WifiModulationClass modulation, bool useShortPreamble)
Return the preamble to be used for the transmission.
std::vector< MinstrelHtRateInfo > MinstrelHtRate
Data structure for a Minstrel Rate table.
std::vector< WifiMode > WifiModeList
In various parts of the code, folk are interested in maintaining a list of transmission modes.
Definition: wifi-mode.h: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:99
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.