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);
911  uint64_t dataRate = mode.GetDataRate (group.chWidth, group.gi, group.streams);
912  if (m_currentRate != dataRate && !station->m_isSampling)
913  {
914  NS_LOG_DEBUG ("New datarate: " << dataRate);
915  m_currentRate = dataRate;
916  }
918  }
919 }
920 
923 {
924  NS_LOG_FUNCTION (this << st);
925  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
926 
927  if (!station->m_initialized)
928  {
929  CheckInit (station);
930  }
931 
932  if (!station->m_isHt)
933  {
934  return m_legacyManager->GetRtsTxVector (station);
935  }
936  else
937  {
938  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
939 
940  /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
941  * When supported, decision of using HT has to follow rules in Section 9.7.6 from 802.11-2012.
942  * From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is carried in a
943  * non-HT PPDU shall be transmitted by the STA using a rate no higher than the highest
944  * rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
945  * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
946  * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
947  * these conditions, the control frame shall be transmitted at a rate no higher than the
948  * highest mandatory rate of the attached PHY that is less than or equal to the rate
949  * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
950  * directed to the same receiving STA."
951  */
952 
953  // As we are in Minstrel HT, assume the last rate was an HT rate.
954  uint8_t rateId = GetRateId (station->m_txrate);
955  uint8_t groupId = GetGroupId (station->m_txrate);
956  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
957 
958  WifiMode lastRate = GetMcsSupported (station, mcsIndex);
959  uint64_t lastDataRate = lastRate.GetNonHtReferenceRate ();
960  uint8_t nBasicRates = GetNBasicModes ();
961 
962  WifiMode rtsRate;
963  bool rateFound = false;
964 
965  for (uint8_t i = 0; i < nBasicRates; i++)
966  {
967  uint64_t rate = GetBasicMode (i).GetDataRate (20);
968  if (rate <= lastDataRate)
969  {
970  rtsRate = GetBasicMode (i);
971  rateFound = true;
972  }
973  }
974 
975  if (!rateFound)
976  {
977  Ptr<WifiPhy> phy = GetPhy ();
978  for (const auto & mode : phy->GetModeList ())
979  {
980  uint64_t rate = mode.GetDataRate (20);
981  if (rate <= lastDataRate)
982  {
983  rtsRate = mode;
984  rateFound = true;
985  }
986  }
987  }
988 
989  NS_ASSERT (rateFound);
990 
992  800, 1, 1, 0, GetChannelWidthForTransmission (rtsRate, GetChannelWidth (station)), GetAggregation (station));
993  }
994 }
995 
996 bool
998 {
999  NS_LOG_FUNCTION (this << st << packet << normally);
1000 
1001  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
1002 
1003  CheckInit (station);
1004  if (!station->m_initialized)
1005  {
1006  return normally;
1007  }
1008 
1009  uint32_t maxRetries;
1010 
1011  if (!station->m_isHt)
1012  {
1013  maxRetries = m_legacyManager->CountRetries (station);
1014  }
1015  else
1016  {
1017  maxRetries = CountRetries (station);
1018  }
1019 
1020  if (station->m_longRetry >= maxRetries)
1021  {
1022  NS_LOG_DEBUG ("No re-transmission allowed. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
1023  return false;
1024  }
1025  else
1026  {
1027  NS_LOG_DEBUG ("Re-transmit. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
1028  return true;
1029  }
1030 }
1031 
1032 uint32_t
1034 {
1035  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
1036  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1037  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
1038  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1039  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1040  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1041 
1042  if (!station->m_isSampling)
1043  {
1044  return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
1045  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
1046  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1047  }
1048  else
1049  {
1050  return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1051  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1052  }
1053 }
1054 
1055 uint16_t
1057 {
1058  NS_LOG_FUNCTION (this << station);
1059  uint8_t sampleGroup = station->m_sampleGroup;
1060  uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1061  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1062  uint8_t sampleIndex = station->m_sampleTable[index][col];
1063  uint16_t rateIndex = GetIndex (sampleGroup, sampleIndex);
1064  NS_LOG_DEBUG ("Next Sample is " << rateIndex);
1065  SetNextSample (station); //Calculate the next sample rate.
1066  return rateIndex;
1067 }
1068 
1069 void
1071 {
1072  NS_LOG_FUNCTION (this << station);
1073  do
1074  {
1075  station->m_sampleGroup++;
1076  station->m_sampleGroup %= m_numGroups;
1077  }
1078  while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1079 
1080  station->m_groupsTable[station->m_sampleGroup].m_index++;
1081 
1082  uint8_t sampleGroup = station->m_sampleGroup;
1083  uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1084  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1085 
1086  if (index >= m_numRates)
1087  {
1088  station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1089  station->m_groupsTable[station->m_sampleGroup].m_col++;
1090  if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1091  {
1092  station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1093  }
1094  index = station->m_groupsTable[station->m_sampleGroup].m_index;
1095  col = station->m_groupsTable[sampleGroup].m_col;
1096  }
1097  NS_LOG_DEBUG ("New sample set: group= " << +sampleGroup << " index= " << +station->m_sampleTable[index][col]);
1098 }
1099 
1100 uint16_t
1102 {
1103  NS_LOG_FUNCTION (this << station);
1104  NS_LOG_DEBUG ("FindRate packet=" << station->m_totalPacketsCount);
1105 
1106  if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1107  {
1108  return station->m_maxTpRate;
1109  }
1110 
1111  // If we have waited enough, then sample.
1112  if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1113  {
1114  //SAMPLING
1115  NS_LOG_DEBUG ("Obtaining a sampling rate");
1117  uint16_t sampleIdx = GetNextSample (station);
1118  NS_LOG_DEBUG ("Sampling rate = " << sampleIdx);
1119 
1120  //Evaluate if the sampling rate selected should be used.
1121  uint8_t sampleGroupId = GetGroupId (sampleIdx);
1122  uint8_t sampleRateId = GetRateId (sampleIdx);
1123 
1124  // If the rate selected is not supported, then don't sample.
1125  if (station->m_groupsTable[sampleGroupId].m_supported && station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1126  {
1134  MinstrelHtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1135 
1136  NS_LOG_DEBUG ("Use sample rate? MaxTpRate= " << station->m_maxTpRate << " CurrentRate= " << station->m_txrate <<
1137  " SampleRate= " << sampleIdx << " SampleProb= " << sampleRateInfo.ewmaProb);
1138 
1139  if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2
1140  && sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1141  {
1142 
1148  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1149  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1150  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1151  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1152  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
1153 
1154  uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1155  uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1156 
1157  Time sampleDuration = sampleRateInfo.perfectTxTime;
1158  Time maxTp2Duration = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1159  Time maxProbDuration = station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].perfectTxTime;
1160 
1161  NS_LOG_DEBUG ("Use sample rate? SampleDuration= " << sampleDuration << " maxTp2Duration= " << maxTp2Duration <<
1162  " maxProbDuration= " << maxProbDuration << " sampleStreams= " << +sampleStreams <<
1163  " maxTpStreams= " << +maxTpStreams);
1164  if (sampleDuration < maxTp2Duration || (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1165  {
1167  station->m_isSampling = true;
1168 
1170  station->m_sampleRate = sampleIdx;
1171 
1172  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1173  station->m_sampleTries--;
1174  return sampleIdx;
1175  }
1176  else
1177  {
1178  station->m_numSamplesSlow++;
1179  if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1180  {
1182  station->m_isSampling = true;
1183 
1185  station->m_sampleRate = sampleIdx;
1186 
1187  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1188  station->m_sampleTries--;
1189  return sampleIdx;
1190  }
1191  }
1192  }
1193  }
1194  }
1195  if (station->m_sampleWait > 0)
1196  {
1197  station->m_sampleWait--;
1198  }
1199 
1201 
1202  NS_LOG_DEBUG ("FindRate " << "maxTpRrate=" << station->m_maxTpRate);
1203  return station->m_maxTpRate;
1204 }
1205 void
1207 {
1208  NS_LOG_FUNCTION (this << station);
1209 
1211 
1212  station->m_numSamplesSlow = 0;
1213  station->m_sampleCount = 0;
1214 
1215  double tempProb;
1216 
1217  if (station->m_ampduPacketCount > 0)
1218  {
1219  uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1220  station->m_avgAmpduLen = ( newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel) ) / 100;
1221  station->m_ampduLen = 0;
1222  station->m_ampduPacketCount = 0;
1223  }
1224 
1225  /* Initialize global rate indexes */
1226  station->m_maxTpRate = GetLowestIndex (station);
1227  station->m_maxTpRate2 = GetLowestIndex (station);
1228  station->m_maxProbRate = GetLowestIndex (station);
1229 
1231  for (uint8_t j = 0; j < m_numGroups; j++)
1232  {
1233  if (station->m_groupsTable[j].m_supported)
1234  {
1235  station->m_sampleCount++;
1236 
1237  /* (re)Initialize group rate indexes */
1238  station->m_groupsTable[j].m_maxTpRate = GetLowestIndex (station, j);
1239  station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex (station, j);
1240  station->m_groupsTable[j].m_maxProbRate = GetLowestIndex (station, j);
1241 
1242  for (uint8_t i = 0; i < m_numRates; i++)
1243  {
1244  if (station->m_groupsTable[j].m_ratesTable[i].supported)
1245  {
1246  station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1247 
1248  NS_LOG_DEBUG (+i << " " << GetMcsSupported (station, station->m_groupsTable[j].m_ratesTable[i].mcsIndex) <<
1249  "\t attempt=" << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt <<
1250  "\t success=" << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1251 
1253  if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1254  {
1255  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1260  tempProb = (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) / station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1261 
1263  station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1264 
1265  if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1266  {
1267  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1268  }
1269  else
1270  {
1271  station->m_groupsTable[j].m_ratesTable[i].ewmsdProb = CalculateEwmsd (station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1272  tempProb, station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1273  m_ewmaLevel);
1275  tempProb = (tempProb * (100 - m_ewmaLevel) + station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) / 100;
1276  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1277  }
1278 
1279  station->m_groupsTable[j].m_ratesTable[i].throughput = CalculateThroughput (station, j, i, tempProb);
1280 
1281  station->m_groupsTable[j].m_ratesTable[i].successHist += station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1282  station->m_groupsTable[j].m_ratesTable[i].attemptHist += station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1283  }
1284  else
1285  {
1286  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1287  }
1288 
1290  station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess = station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1291  station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt = station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1292  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1293  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1294 
1295  if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1296  {
1297  SetBestStationThRates (station, GetIndex (j, i));
1298  SetBestProbabilityRate (station, GetIndex (j, i));
1299  }
1300 
1301  }
1302  }
1303  }
1304  }
1305 
1306  //Try to sample all available rates during each interval.
1307  station->m_sampleCount *= 8;
1308 
1309  //Recalculate retries for the rates selected.
1310  CalculateRetransmits (station, station->m_maxTpRate);
1311  CalculateRetransmits (station, station->m_maxTpRate2);
1312  CalculateRetransmits (station, station->m_maxProbRate);
1313 
1314  NS_LOG_DEBUG ("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2 << "\nmax prob=" << station->m_maxProbRate);
1315  if (m_printStats)
1316  {
1317  PrintTable (station);
1318  }
1319 }
1320 
1321 double
1322 MinstrelHtWifiManager::CalculateThroughput (MinstrelHtWifiRemoteStation *station, uint8_t groupId, uint8_t rateId, double ewmaProb)
1323 {
1329  if (ewmaProb < 10)
1330  {
1331  return 0;
1332  }
1333  else
1334  {
1339  Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1340  if (ewmaProb > 90)
1341  {
1342  return 90 / txTime.GetSeconds ();
1343  }
1344  else
1345  {
1346  return ewmaProb / txTime.GetSeconds ();
1347  }
1348  }
1349 }
1350 
1351 void
1353 {
1354  GroupInfo *group;
1355  MinstrelHtRateInfo rate;
1356  uint8_t tmpGroupId, tmpRateId;
1357  double tmpTh, tmpProb;
1358  uint8_t groupId, rateId;
1359  double currentTh;
1360  // maximum group probability (GP) variables
1361  uint8_t maxGPGroupId, maxGPRateId;
1362  double maxGPTh;
1363 
1364  groupId = GetGroupId (index);
1365  rateId = GetRateId (index);
1366  group = &station->m_groupsTable[groupId];
1367  rate = group->m_ratesTable[rateId];
1368 
1369  tmpGroupId = GetGroupId (station->m_maxProbRate);
1370  tmpRateId = GetRateId (station->m_maxProbRate);
1371  tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1372  tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1373 
1374  if (rate.ewmaProb > 75)
1375  {
1376  currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1377  if (currentTh > tmpTh)
1378  {
1379  station->m_maxProbRate = index;
1380  }
1381 
1382  maxGPGroupId = GetGroupId (group->m_maxProbRate);
1383  maxGPRateId = GetRateId (group->m_maxProbRate);
1384  maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1385 
1386  if (currentTh > maxGPTh)
1387  {
1388  group->m_maxProbRate = index;
1389  }
1390  }
1391  else
1392  {
1393  if (rate.ewmaProb > tmpProb)
1394  {
1395  station->m_maxProbRate = index;
1396  }
1397  maxGPRateId = GetRateId (group->m_maxProbRate);
1398  if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1399  {
1400  group->m_maxProbRate = index;
1401  }
1402  }
1403 }
1404 
1405 /*
1406  * Find & sort topmost throughput rates
1407  *
1408  * If multiple rates provide equal throughput the sorting is based on their
1409  * current success probability. Higher success probability is preferred among
1410  * MCS groups.
1411  */
1412 void
1414 {
1415  uint8_t groupId, rateId;
1416  double th, prob;
1417  uint8_t maxTpGroupId, maxTpRateId;
1418  uint8_t maxTp2GroupId, maxTp2RateId;
1419  double maxTpTh, maxTpProb;
1420  double maxTp2Th, maxTp2Prob;
1421 
1422  groupId = GetGroupId (index);
1423  rateId = GetRateId (index);
1424  prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1425  th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1426 
1427  maxTpGroupId = GetGroupId (station->m_maxTpRate);
1428  maxTpRateId = GetRateId (station->m_maxTpRate);
1429  maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1430  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1431 
1432  maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1433  maxTp2RateId = GetRateId (station->m_maxTpRate2);
1434  maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1435  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1436 
1437  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1438  {
1439  station->m_maxTpRate2 = station->m_maxTpRate;
1440  station->m_maxTpRate = index;
1441  }
1442  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1443  {
1444  station->m_maxTpRate2 = index;
1445  }
1446 
1447  //Find best rates per group
1448 
1449  GroupInfo *group = &station->m_groupsTable[groupId];
1450  maxTpGroupId = GetGroupId (group->m_maxTpRate);
1451  maxTpRateId = GetRateId (group->m_maxTpRate);
1452  maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1453  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1454 
1455  maxTp2GroupId = GetGroupId (group->m_maxTpRate2);
1456  maxTp2RateId = GetRateId (group->m_maxTpRate2);
1457  maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1458  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1459 
1460  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1461  {
1462  group->m_maxTpRate2 = group->m_maxTpRate;
1463  group->m_maxTpRate = index;
1464  }
1465  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1466  {
1467  group->m_maxTpRate2 = index;
1468  }
1469 }
1470 
1471 void
1473 {
1474  NS_LOG_FUNCTION (this << station);
1475 
1476  station->m_groupsTable = McsGroupData (m_numGroups);
1477 
1481  NS_LOG_DEBUG ("Supported groups by station:");
1482  bool noSupportedGroupFound = true;
1483  for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1484  {
1485  if (m_minstrelGroups[groupId].isSupported)
1486  {
1487  station->m_groupsTable[groupId].m_supported = false;
1488 
1489  if ((m_minstrelGroups[groupId].type == GROUP_HE) && !GetHeSupported (station))
1490  {
1491  //It is a HE group but the receiver does not support HE: skip
1492  continue;
1493  }
1494  if ((m_minstrelGroups[groupId].type == GROUP_VHT) && !GetVhtSupported (station))
1495  {
1496  //It is a VHT group but the receiver does not support VHT: skip
1497  continue;
1498  }
1499  if ((m_minstrelGroups[groupId].type != GROUP_HE) && GetHeSupported (station) && m_useLatestAmendmentOnly)
1500  {
1501  //It is not a HE group and the receiver supports HE: skip since UseLatestAmendmentOnly attribute is enabled
1502  continue;
1503  }
1504  if (!GetHeSupported (station) && (m_minstrelGroups[groupId].type != GROUP_VHT) && GetVhtSupported (station) && m_useLatestAmendmentOnly)
1505  {
1506  //It is not a VHT group and the receiver supports VHT (but not HE): skip since UseLatestAmendmentOnly attribute is enabled
1507  continue;
1508  }
1509  if (((m_minstrelGroups[groupId].type == GROUP_HT) || (m_minstrelGroups[groupId].type == GROUP_VHT))
1510  && (m_minstrelGroups[groupId].gi == 400) && !GetShortGuardIntervalSupported (station))
1511  {
1512  //It is a SGI group but the receiver does not support SGI: skip
1513  continue;
1514  }
1515  if ((m_minstrelGroups[groupId].type == GROUP_HE) && (m_minstrelGroups[groupId].gi < GetGuardInterval (station)))
1516  {
1517  //The receiver does not support the GI: skip
1518  continue;
1519  }
1520  if (GetChannelWidth (station) < m_minstrelGroups[groupId].chWidth)
1521  {
1522  //The receiver does not support the channel width: skip
1523  continue;
1524  }
1525  if (GetNumberOfSupportedStreams (station) < m_minstrelGroups[groupId].streams)
1526  {
1527  //The receiver does not support the number of spatial streams: skip
1528  continue;
1529  }
1530 
1531  NS_LOG_DEBUG ("Group: " << +groupId
1532  << " type: " << m_minstrelGroups[groupId].type
1533  << " streams: " << +m_minstrelGroups[groupId].streams
1534  << " GI: " << m_minstrelGroups[groupId].gi
1535  << " width: " << m_minstrelGroups[groupId].chWidth);
1536 
1537  noSupportedGroupFound = false;
1538  station->m_groupsTable[groupId].m_supported = true;
1539  station->m_groupsTable[groupId].m_col = 0;
1540  station->m_groupsTable[groupId].m_index = 0;
1541 
1542  station->m_groupsTable[groupId].m_ratesTable = MinstrelHtRate (m_numRates);
1543  for (uint8_t i = 0; i < m_numRates; i++)
1544  {
1545  station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1546  }
1547 
1548  // Initialize all modes supported by the remote station that belong to the current group.
1549  for (uint8_t i = 0; i < station->m_nModes; i++)
1550  {
1551  WifiMode mode = GetMcsSupported (station, i);
1552 
1555  uint8_t rateId = mode.GetMcsValue ();
1556  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1557  {
1558  rateId %= MAX_HT_GROUP_RATES;
1559  }
1560 
1561  if (((m_minstrelGroups[groupId].type == GROUP_HE)
1562  && (mode.GetModulationClass () == WIFI_MOD_CLASS_HE)
1563  && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1564  || ((m_minstrelGroups[groupId].type == GROUP_VHT)
1565  && (mode.GetModulationClass () == WIFI_MOD_CLASS_VHT)
1566  && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1567  || ((m_minstrelGroups[groupId].type == GROUP_HT)
1568  && (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1569  && (mode.GetMcsValue () < (m_minstrelGroups[groupId].streams * 8))
1570  && (mode.GetMcsValue () >= ((m_minstrelGroups[groupId].streams - 1) * 8))))
1571  {
1572  NS_LOG_DEBUG ("Mode " << +i << ": " << mode);
1573 
1574  station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1575  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex = i;
1576  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1577  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1578  station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1579  station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1580  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1581  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1582  station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1583  station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1584  station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1585  station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1586  station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
1587  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1588  station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1589  CalculateRetransmits (station, groupId, rateId);
1590  }
1591  }
1592  }
1593  }
1595  if (noSupportedGroupFound)
1596  {
1597  NS_FATAL_ERROR ("No supported group has been found");
1598  }
1599  SetNextSample (station);
1600  UpdateStats (station);
1601  station->m_txrate = FindRate (station);
1602 }
1603 
1604 void
1606 {
1607  NS_LOG_FUNCTION (this << station << index);
1608  uint8_t groupId = GetGroupId (index);
1609  uint8_t rateId = GetRateId (index);
1610  if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1611  {
1612  CalculateRetransmits (station, groupId, rateId);
1613  }
1614 }
1615 
1616 void
1618 {
1619  NS_LOG_FUNCTION (this << station << +groupId << +rateId);
1620 
1621  uint32_t cw = 15; // Is an approximation.
1622  uint32_t cwMax = 1023;
1623  Time cwTime, txTime, dataTxTime;
1624  Time slotTime = GetPhy ()->GetSlot ();
1625  Time ackTime = GetPhy ()->GetSifs () + GetPhy ()->GetBlockAckTxTime ();
1626 
1627  if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1628  {
1629  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1630  }
1631  else
1632  {
1633  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1634  station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1635 
1636  dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1637  GetMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) * (station->m_avgAmpduLen - 1);
1638 
1639  /* Contention time for first 2 tries */
1640  cwTime = (cw / 2) * slotTime;
1641  cw = Min ((cw + 1) * 2, cwMax);
1642  cwTime += (cw / 2) * slotTime;
1643  cw = Min ((cw + 1) * 2, cwMax);
1644 
1645  /* Total TX time for data and Contention after first 2 tries */
1646  txTime = cwTime + 2 * (dataTxTime + ackTime);
1647 
1648  /* See how many more tries we can fit inside segment size */
1649  do
1650  {
1651  /* Contention time for this try */
1652  cwTime = (cw / 2) * slotTime;
1653  cw = Min ((cw + 1) * 2, cwMax);
1654 
1655  /* Total TX time after this try */
1656  txTime += cwTime + ackTime + dataTxTime;
1657  }
1658  while ((txTime < MilliSeconds (6))
1659  && (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1660  }
1661 }
1662 
1663 double
1664 MinstrelHtWifiManager::CalculateEwmsd (double oldEwmsd, double currentProb, double ewmaProb, double weight)
1665 {
1666  double diff, incr, tmp;
1667 
1668  /* calculate exponential weighted moving variance */
1669  diff = currentProb - ewmaProb;
1670  incr = (100 - weight) * diff / 100;
1671  tmp = oldEwmsd * oldEwmsd;
1672  tmp = weight * (tmp + diff * incr) / 100;
1673 
1674  /* return standard deviation */
1675  return sqrt (tmp);
1676 }
1677 
1678 void
1680 {
1681  NS_LOG_FUNCTION (this << station);
1682  station->m_col = station->m_index = 0;
1683 
1684  //for off-setting to make rates fall between 0 and nModes
1685  uint8_t numSampleRates = m_numRates;
1686 
1687  uint16_t newIndex;
1688  for (uint8_t col = 0; col < m_nSampleCol; col++)
1689  {
1690  for (uint8_t i = 0; i < numSampleRates; i++ )
1691  {
1696  int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
1697  newIndex = (i + uv) % numSampleRates;
1698 
1699  //this loop is used for filling in other uninitialized places
1700  while (station->m_sampleTable[newIndex][col] != 0)
1701  {
1702  newIndex = (newIndex + 1) % m_numRates;
1703  }
1704  station->m_sampleTable[newIndex][col] = i;
1705  }
1706  }
1707 }
1708 
1709 void
1711 {
1712  if (!station->m_statsFile.is_open ())
1713  {
1714  std::ostringstream tmp;
1715  tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1716  station->m_statsFile.open (tmp.str ().c_str (), std::ios::out);
1717  }
1718 
1719  station->m_statsFile << " best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n" <<
1720  " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n";
1721  for (uint8_t i = 0; i < m_numGroups; i++)
1722  {
1723  StatsDump (station, i, station->m_statsFile);
1724  }
1725 
1726  station->m_statsFile << "\nTotal packet count:: ideal " << Max (0, station->m_totalPacketsCount - station->m_samplePacketsCount) <<
1727  " lookaround " << station->m_samplePacketsCount << "\n";
1728  station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen << "\n\n";
1729 
1730  station->m_statsFile.flush ();
1731 }
1732 
1733 void
1734 MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint8_t groupId, std::ofstream &of)
1735 {
1736  uint8_t numRates = m_numRates;
1737  McsGroup group = m_minstrelGroups[groupId];
1738  Time txTime;
1739  for (uint8_t i = 0; i < numRates; i++)
1740  {
1741  if (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[i].supported)
1742  {
1743  of << group.type << " " << group.chWidth << " " << group.gi << " " << +group.streams << " ";
1744 
1745  uint16_t maxTpRate = station->m_maxTpRate;
1746  uint16_t maxTpRate2 = station->m_maxTpRate2;
1747  uint16_t maxProbRate = station->m_maxProbRate;
1748 
1749  uint16_t idx = GetIndex (groupId, i);
1750  if (idx == maxTpRate)
1751  {
1752  of << 'A';
1753  }
1754  else
1755  {
1756  of << ' ';
1757  }
1758  if (idx == maxTpRate2)
1759  {
1760  of << 'B';
1761  }
1762  else
1763  {
1764  of << ' ';
1765  }
1766  if (idx == maxProbRate)
1767  {
1768  of << 'P';
1769  }
1770  else
1771  {
1772  of << ' ';
1773  }
1774 
1775  if (group.type == GROUP_HT)
1776  {
1777  of << std::setw (4) << " MCS" << (group.streams - 1) * 8 + i;
1778  }
1779  else
1780  {
1781  of << std::setw (7) << " MCS" << +i << "/" << static_cast<int>(group.streams);
1782  }
1783 
1784  of << " " << std::setw (3) << +idx << " ";
1785 
1786  /* tx_time[rate(i)] in usec */
1787  txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
1788  of << std::setw (6) << txTime.GetMicroSeconds () << " ";
1789 
1790  of << std::setw (7) << CalculateThroughput (station, groupId, i, 100) / 100 << " " <<
1791  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100 << " " <<
1792  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb << " " <<
1793  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb << " " <<
1794  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].prob << " " <<
1795  std::setw (2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount << " " <<
1796  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " " <<
1797  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt << " " <<
1798  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " " <<
1799  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist << "\n";
1800  }
1801  }
1802 }
1803 uint16_t
1804 MinstrelHtWifiManager::GetIndex (uint8_t groupId, uint8_t rateId)
1805 {
1806  NS_LOG_FUNCTION (this << +groupId << +rateId);
1807  uint16_t index;
1808  index = groupId * m_numRates + rateId;
1809  return index;
1810 }
1811 
1812 uint8_t
1814 {
1815  NS_LOG_FUNCTION (this << index);
1816  uint8_t id;
1817  id = index % m_numRates;
1818  return id;
1819 }
1820 
1821 uint8_t
1823 {
1824  NS_LOG_FUNCTION (this << index);
1825  return index / m_numRates;
1826 }
1827 
1828 uint8_t
1829 MinstrelHtWifiManager::GetHtGroupId (uint8_t txstreams, uint16_t gi, uint16_t chWidth)
1830 {
1831  NS_LOG_FUNCTION (this << +txstreams << gi << chWidth);
1832  uint8_t giIndex = (gi == 400) ? 1 : 0;
1833  uint8_t widthIndex = (chWidth == 40) ? 1 : 0;
1834  return (MAX_HT_SUPPORTED_STREAMS * 2 * widthIndex) + (MAX_HT_SUPPORTED_STREAMS * giIndex) + txstreams - 1;
1835 }
1836 
1837 uint8_t
1838 MinstrelHtWifiManager::GetVhtGroupId (uint8_t txstreams, uint16_t gi, uint16_t chWidth)
1839 {
1840  NS_LOG_FUNCTION (this << +txstreams << gi << chWidth);
1841  uint8_t giIndex = (gi == 400) ? 1 : 0;
1842  uint8_t widthIndex;
1843  if (chWidth == 160)
1844  {
1845  widthIndex = 3;
1846  }
1847  else if (chWidth == 80)
1848  {
1849  widthIndex = 2;
1850  }
1851  else if (chWidth == 40)
1852  {
1853  widthIndex = 1;
1854  }
1855  else //20 MHz
1856  {
1857  widthIndex = 0;
1858  }
1859  uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
1860  groupId += (MAX_VHT_SUPPORTED_STREAMS * 2 * widthIndex) + (MAX_VHT_SUPPORTED_STREAMS * giIndex) + txstreams - 1;
1861  return groupId;
1862 }
1863 
1864 uint8_t
1865 MinstrelHtWifiManager::GetHeGroupId (uint8_t txstreams, uint16_t gi, uint16_t chWidth)
1866 {
1867  NS_LOG_FUNCTION (this << +txstreams << gi << chWidth);
1868  uint8_t giIndex;
1869  if (gi == 800)
1870  {
1871  giIndex = 2;
1872  }
1873  else if (gi == 1600)
1874  {
1875  giIndex = 1;
1876  }
1877  else //3200 ns
1878  {
1879  giIndex = 0;
1880  }
1881  uint8_t widthIndex;
1882  if (chWidth == 160)
1883  {
1884  widthIndex = 3;
1885  }
1886  else if (chWidth == 80)
1887  {
1888  widthIndex = 2;
1889  }
1890  else if (chWidth == 40)
1891  {
1892  widthIndex = 1;
1893  }
1894  else //20 MHz
1895  {
1896  widthIndex = 0;
1897  }
1898  uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS);
1899  if (GetVhtSupported ())
1900  {
1902  }
1903  groupId += (MAX_HE_SUPPORTED_STREAMS * 3 * widthIndex) + (MAX_HE_SUPPORTED_STREAMS * giIndex) + txstreams - 1;
1904  return groupId;
1905 }
1906 
1907 uint16_t
1909 {
1910  NS_LOG_FUNCTION (this << station);
1911 
1912  uint8_t groupId = 0;
1913  uint8_t rateId = 0;
1914  while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
1915  {
1916  groupId++;
1917  }
1918  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1919  {
1920  rateId++;
1921  }
1922  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1923  return GetIndex (groupId, rateId);
1924 }
1925 
1926 uint16_t
1928 {
1929  NS_LOG_FUNCTION (this << station << +groupId);
1930 
1931  uint8_t rateId = 0;
1932  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1933  {
1934  rateId++;
1935  }
1936  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1937  return GetIndex (groupId, rateId);
1938 }
1939 
1942 {
1943  WifiModeList heMcsList;
1944  for (const auto & mode : GetPhy ()->GetMcsList (WIFI_MOD_CLASS_HE))
1945  {
1946  heMcsList.push_back (mode);
1947  }
1948  return heMcsList;
1949 }
1950 
1953 {
1954  WifiModeList vhtMcsList;
1955  for (const auto & mode : GetPhy ()->GetMcsList (WIFI_MOD_CLASS_VHT))
1956  {
1957  vhtMcsList.push_back (mode);
1958  }
1959  return vhtMcsList;
1960 }
1961 
1964 {
1965  WifiModeList htMcsList;
1966  for (const auto & mode : GetPhy ()->GetMcsList (WIFI_MOD_CLASS_HT))
1967  {
1968  htMcsList.push_back (mode);
1969  }
1970  return htMcsList;
1971 }
1972 
1973 } // namespace ns3
uint16_t m_maxProbRate
The highest success probability rate of this group in bps.
uint8_t GetNMcsSupported(Mac48Address address) const
Return the number of MCS supported by the station.
uint16_t m_maxProbRate
rate with highest probability of success in bps
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...
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...
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...
uint8_t m_nSampleCol
Number of sample columns.
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...
void DoReportRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
Time GetMpduTxTime(uint8_t groupId, WifiMode mode) const
Obtain the TxTime saved in the group information.
bool GetVhtSupported(void) const
Return whether the device has VHT capability support enabled.
A struct to contain information of a group.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
WifiModeList GetVhtDeviceMcsList(void) const
Returns a list of only the VHT MCS supported by the device.
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
bool DoNeedRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally) override
uint8_t m_sampleGroup
The group that the sample rate belongs to.
AttributeValue implementation for Boolean.
Definition: boolean.h:36
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
TracedValue< uint64_t > m_currentRate
Trace rate changes.
uint32_t GetInteger(uint32_t min, uint32_t max)
Get the next random value, as an unsigned integer in the specified range .
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void PrintTable(MinstrelHtWifiRemoteStation *station)
Printing Minstrel Table.
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...
uint16_t GetLowestIndex(MinstrelHtWifiRemoteStation *station)
Returns the lowest global index of the rates supported by the station.
WifiModeList GetHeDeviceMcsList() const
Returns a list of only the HE MCS supported by the device.
void SetBestProbabilityRate(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxProbRate if it is better than current value.
uint16_t m_maxTpRate
the current throughput rate in bps
uint16_t m_txrate
current transmit rate in bps
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
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...
MinstrelHtWifiRemoteStation structure.
uint16_t m_maxTpRate2
second highest throughput rate in bps
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:380
void DoReportFinalDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
hold per-remote-station state for Minstrel Wifi manager.
void CalculateRetransmits(MinstrelHtWifiRemoteStation *station, uint16_t index)
Calculate the number of retransmissions to set for the index rate.
uint32_t m_ampduPacketCount
Number of A-MPDUs transmitted.
void DoInitialize(void) override
Initialize() implementation.
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...
bool GetHeSupported(void) const
Return whether the device has HE capability support enabled.
#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_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1297
uint16_t m_sampleRate
current sample rate in bps
void SetStbc(bool stbc)
Sets if STBC is being used.
Mac48Address m_address
Mac48Address of the remote station.
Time m_legacyUpdateStats
How frequent do we calculate the stats for legacy MinstrelWifiManager.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:281
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
uint16_t FindRate(MinstrelHtWifiRemoteStation *station)
Find a rate to use from Minstrel Table.
A struct to contain all statistics information related to a data rate.
MinstrelRate m_minstrelTable
minstrel table
uint32_t m_frameLength
Frame length used for calculate modes TxTime in bytes.
MinstrelMcsGroups m_minstrelGroups
Global array for groups information.
WifiPreamble GetPreambleForTransmission(WifiModulationClass modulation, bool useShortPreamble)
Return the preamble to be used for the transmission.
Definition: wifi-utils.cc:116
bool m_isHt
If the station is HT capable.
bool m_sampleDeferred
a flag to indicate sample rate is on the second stage
std::vector< std::vector< uint8_t > > SampleRate
Data structure for a Sample Rate table A vector of a vector uint8_t.
represent a single transmission modeA WifiMode is implemented by a single integer which is used to lo...
Definition: wifi-mode.h:47
std::vector< RateInfo > MinstrelRate
Data structure for a Minstrel Rate table A vector of a struct RateInfo.
WifiRemoteStation * DoCreateStation(void) const override
uint16_t gi
guard interval duration (nanoseconds)
uint8_t m_nModes
number of modes supported
uint8_t GetRateId(uint16_t index)
Return the rateId inside a group, from the global index.
WifiRemoteStationState * m_state
Remote station state.
bool m_printStats
If statistics table should be printed.
MpduType
The type of an MPDU.
uint16_t GetIndex(uint8_t groupId, uint8_t rateId)
Returns the global index corresponding to the groupId and rateId.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
uint8_t m_lookAroundRate
The % to try other rates than our current rate.
phy
Definition: third.py:93
uint8_t m_ewmaLevel
Exponential weighted moving average level (or coefficient).
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode...
void SetBestStationThRates(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxTpRate or maxTp2Rate if is better than current values.
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...
Time GetFirstMpduTxTime(uint8_t groupId, WifiMode mode) const
Obtain the TxTime saved in the group information.
std::vector< MinstrelHtRateInfo > MinstrelHtRate
Data structure for a Minstrel Rate table.
uint8_t GetNumberOfSupportedStreams(Mac48Address address) const
Return the number of spatial streams supported by the station.
bool GetShortPreambleEnabled(void) const
Return whether the device uses short PHY preambles.
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:218
McsGroupType type
identifies the group,
The MPDU is the first aggregate in an A-MPDU with multiple MPDUs, but is not the last aggregate...
uint16_t chWidth
channel width (MHz)
bool m_isSampling
a flag to indicate we are currently sampling
bool IsValid(void) const
The standard disallows certain combinations of WifiMode, number of spatial streams, and channel widths.
WifiTxVector DoGetDataTxVector(WifiRemoteStation *station) override
AttributeValue implementation for Time.
Definition: nstime.h:1353
SampleRate m_sampleTable
sample table
uint8_t m_col
To keep track of the current position in the our random sample table going row by row from 1st column...
Time perfectTxTime
Perfect transmission time calculation, or frame calculation.
double ewmaProb
Exponential weighted moving average of probability.
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
Hold an unsigned integer type.
Definition: uinteger.h:44
static const uint8_t MAX_HE_SUPPORTED_STREAMS
Maximal number of streams supported by the HE PHY layer.
static const uint8_t MAX_VHT_GROUP_RATES
Number of rates (or MCS) per VHT group.
static const uint8_t MAX_HT_WIDTH
Maximal channel width in MHz.
bool GetHtSupported(void) const
Return whether the device has HT capability support enabled.
mac
Definition: third.py:99
uint8_t streams
number of spatial streams
The MPDU is part of an A-MPDU with multiple MPDUs, but is neither the first nor the last aggregate...
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:230
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...
uint32_t m_sampleWait
How many transmission attempts to wait until a new sample.
bool m_useLatestAmendmentOnly
Flag if only the latest supported amendment by both peers should be used.
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...
Ptr< UniformRandomVariable > m_uniformRandomVariable
Provides uniform random variables.
hold a list of per-remote-station state.
WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:159
std::vector< struct GroupInfo > McsGroupData
Data structure for a table of groups.
uint32_t m_longRetry
long retries such as data packets
static TypeId GetTypeId(void)
Get the type ID.
static const uint8_t MAX_VHT_WIDTH
Maximal channel width in MHz.
uint32_t m_ampduLen
Number of MPDUs in an A-MPDU.
void SetNss(uint8_t nss)
Sets the number of Nss.
bool m_initialized
for initializing tables
Time GetBlockAckTxTime(void) const
Return the estimated BlockAck TX time for this PHY.
Definition: wifi-phy.cc:946
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:388
uint16_t GetNextSample(MinstrelHtWifiRemoteStation *station)
Getting the next sample from Sample Table.
uint16_t m_maxTpRate2
The second max throughput rate of this group in bps.
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.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint8_t m_numRates
Number of rates per group Minstrel should consider.
void InitSampleTable(MinstrelHtWifiRemoteStation *station)
Initialize Sample Table.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
double CalculateThroughput(MinstrelHtWifiRemoteStation *station, uint8_t groupId, uint8_t rateId, double ewmaProb)
Return the average throughput of the MCS defined by groupId and rateId.
void UpdateRetry(MinstrelHtWifiRemoteStation *station)
Update the number of retries and reset accordingly.
uint32_t m_sampleCount
Max number of samples per update interval.
uint16_t GetChannelWidthForTransmission(WifiMode mode, uint16_t maxSupportedChannelWidth)
Return the channel width that corresponds to the selected mode (instead of letting the PHY&#39;s default ...
Definition: wifi-utils.cc:97
uint8_t m_numGroups
Number of groups Minstrel should consider.
uint32_t numSamplesSkipped
Number of times this rate statistics were not updated because no attempts have been made...
Time m_updateStats
How frequent do we calculate the stats.
void DoReportFinalRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
static const uint8_t MAX_HT_GROUP_RATES
Number of rates (or MCS) per HT group.
void UpdateStats(MinstrelHtWifiRemoteStation *station)
Update the Minstrel Table.
McsGroupData m_groupsTable
Table of groups with stats.
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:1354
std::vector< WifiMode > WifiModeList
In various parts of the code, folk are interested in maintaining a list of transmission modes...
Definition: wifi-mode.h:254
static const uint8_t MAX_VHT_SUPPORTED_STREAMS
Maximal number of streams supported by the VHT PHY layer.
uint16_t m_maxTpRate
The max throughput rate of this group in bps.
bool GetShortGuardIntervalSupported(void) const
Return whether the device has SGI support enabled.
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
std::ofstream m_statsFile
File where statistics table is written.
void RateInit(MinstrelHtWifiRemoteStation *station)
Initialize Minstrel Table.
int m_totalPacketsCount
total number of packets as of now
bool GetAggregation(const WifiRemoteStation *station) const
Return whether the given station supports A-MPDU.
Implementation of Minstrel-HT Rate Control AlgorithmMinstrel-HT is a rate adaptation mechanism for th...
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model...
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
Data structure to contain the information that defines a group.
#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
void DoReportDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
uint8_t GetNBasicModes(void) const
Return the number of basic modes we support.
void StatsDump(MinstrelHtWifiRemoteStation *station, uint8_t groupId, std::ofstream &of)
Print group statistics.
uint64_t GetNonHtReferenceRate(void) const
Definition: wifi-mode.cc:166
int m_samplePacketsCount
how many packets we have sample so far
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...
void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode) override
This method is a pure virtual method that must be implemented by the sub-class.
void UpdatePacketCounters(MinstrelHtWifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus)
Update the number of sample count variables.
Ptr< WifiPhy > GetPhy(void) const
Return the WifiPhy.
double CalculateEwmsd(double oldEwmsd, double currentProb, double ewmaProb, double weight)
Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation.
uint16_t GetGuardInterval(void) const
Return the supported HE guard interval duration (in nanoseconds).
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:910
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.
std::vector< McsGroup > MinstrelMcsGroups
Data structure for a table of group definitions.
void AddMpduTxTime(uint8_t groupId, WifiMode mode, Time t)
Save a TxTime to the vector of groups.
WifiTxVector DoGetRtsTxVector(WifiRemoteStation *station) override
void SetNextSample(MinstrelHtWifiRemoteStation *station)
Set the next sample from Sample Table.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
WifiModeList GetHtDeviceMcsList(void) const
Returns a list of only the HT MCS supported by the device.
uint32_t m_numSamplesSlow
Number of times a slow rate was sampled.
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
MinstrelHtRate m_ratesTable
Information about rates of this group.
Ptr< MinstrelWifiManager > m_legacyManager
Pointer to an instance of MinstrelWifiManager.
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:1586
Time GetSlot(void) const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:922
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1604
uint32_t m_sampleTries
Number of sample tries after waiting sampleWait.
void SetNess(uint8_t ness)
Sets the Ness number.
uint8_t GetGroupId(uint16_t index)
Return the groupId from the global index.
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:533
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...
static const uint8_t MAX_HE_WIDTH
Maximal channel width in MHz.
static const uint8_t MAX_HT_SUPPORTED_STREAMS
Constants for maximum values.
uint32_t m_avgAmpduLen
Average number of MPDUs in an A-MPDU.
uint32_t CountRetries(MinstrelHtWifiRemoteStation *station)
Count retries.
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.
void UpdateRate(MinstrelHtWifiRemoteStation *station)
Update rate.
uint32_t m_shortRetry
short retries such as control packets
WifiMode GetBasicMode(uint8_t i) const
Return a basic mode from the set of basic modes.
uint8_t GetMcsValue(void) const
Definition: wifi-mode.cc:137
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
void AddFirstMpduTxTime(uint8_t groupId, WifiMode mode, Time t)
Save a TxTime to the vector of groups.
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
void CheckInit(MinstrelHtWifiRemoteStation *station)
Check for initializations.
hold per-remote-station state.
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:100
static const uint8_t MAX_HE_GROUP_RATES
Number of rates (or MCS) per HE group.
WifiMode GetMcsSupported(const WifiRemoteStation *station, uint8_t i) const
Return the WifiMode supported by the specified station at the specified index.
uint16_t GetChannelWidth(const WifiRemoteStation *station) const
Return the channel width supported by the station.
uint8_t GetNess(const WifiRemoteStation *station) const
Time m_nextStatsUpdate
10 times every second