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 "wifi-mac.h"
44 #include "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 (100)),
86  MakeTimeChecker ())
87  .AddAttribute ("LookAroundRate",
88  "The percentage to try other rates (for legacy Minstrel)",
89  UintegerValue (10),
91  MakeUintegerChecker<uint8_t>(0, 100))
92  .AddAttribute ("EWMA",
93  "EWMA level",
94  UintegerValue (75),
96  MakeUintegerChecker<uint8_t>(0, 100))
97  .AddAttribute ("SampleColumn",
98  "The number of columns used for sampling",
99  UintegerValue (10),
101  MakeUintegerChecker <uint8_t> ())
102  .AddAttribute ("PacketLength",
103  "The packet length used for calculating mode TxTime (bytes)",
104  UintegerValue (1200),
106  MakeUintegerChecker <uint32_t> ())
107  .AddAttribute ("UseVhtOnly",
108  "Use only VHT MCSs (and not HT) when VHT is available",
109  BooleanValue (true),
112  .AddAttribute ("PrintStats",
113  "Control the printing of the statistics table",
114  BooleanValue (false),
117  .AddTraceSource ("Rate",
118  "Traced value for rate changes (b/s)",
120  "ns3::TracedValueCallback::Uint64")
121  ;
122  return tid;
123 }
124 
126  : m_numGroups (0),
127  m_numRates (0),
128  m_currentRate (0)
129 {
130  NS_LOG_FUNCTION (this);
131  m_uniformRandomVariable = CreateObject<UniformRandomVariable> ();
136  m_legacyManager = CreateObject<MinstrelWifiManager> ();
137 }
138 
140 {
141  NS_LOG_FUNCTION (this);
142  for (uint8_t i = 0; i < m_numGroups; i++)
143  {
144  m_minstrelGroups[i].ratesFirstMpduTxTimeTable.clear ();
145  m_minstrelGroups[i].ratesTxTimeTable.clear ();
146  }
147 }
148 
149 int64_t
151 {
152  NS_LOG_FUNCTION (this << stream);
153  int64_t numStreamsAssigned = 0;
155  numStreamsAssigned++;
156  numStreamsAssigned += m_legacyManager->AssignStreams (stream);
157  return numStreamsAssigned;
158 }
159 
160 void
162 {
163  NS_LOG_FUNCTION (this << phy);
164  // Setup PHY for legacy manager.
165  m_legacyManager->SetupPhy (phy);
167 }
168 
169 void
171 {
172  NS_LOG_FUNCTION (this << mac);
173  m_legacyManager->SetupMac (mac);
175 }
176 
177 void
179 {
180  NS_LOG_FUNCTION (this);
181  if (GetHeSupported ())
182  {
183  NS_FATAL_ERROR ("WifiRemoteStationManager selected does not support HE rates");
184  }
191  // Check if the device supports HT
192  if (GetHtSupported ())
193  {
196 
197  if (GetVhtSupported ())
198  {
201  }
202 
213  NS_LOG_DEBUG ("Initialize MCS Groups:");
215 
216  // Initialize all HT groups
217  for (uint16_t chWidth = 20; chWidth <= MAX_HT_WIDTH; chWidth *= 2)
218  {
219  for (uint8_t sgi = 0; sgi <= 1; sgi++)
220  {
221  for (uint8_t streams = 1; streams <= MAX_SUPPORTED_STREAMS; streams++)
222  {
223  uint8_t groupId = GetHtGroupId (streams, sgi, chWidth);
224 
225  m_minstrelGroups[groupId].streams = streams;
226  m_minstrelGroups[groupId].sgi = sgi;
227  m_minstrelGroups[groupId].chWidth = chWidth;
228  m_minstrelGroups[groupId].isVht = false;
229  m_minstrelGroups[groupId].isSupported = false;
230 
231  // Check capabilities of the device
232  if (!(!GetShortGuardIntervalSupported () && m_minstrelGroups[groupId].sgi)
233  && (GetPhy ()->GetChannelWidth () >= m_minstrelGroups[groupId].chWidth)
234  && (GetPhy ()->GetMaxSupportedTxSpatialStreams () >= m_minstrelGroups[groupId].streams))
235  {
236  m_minstrelGroups[groupId].isSupported = true;
237 
238  // Calculate TX time for all rates of the group
239  WifiModeList htMcsList = GetHtDeviceMcsList ();
240  for (uint8_t i = 0; i < MAX_HT_GROUP_RATES; i++)
241  {
242  uint16_t deviceIndex = i + (m_minstrelGroups[groupId].streams - 1) * 8;
243  WifiMode mode = htMcsList[deviceIndex];
244  AddFirstMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode, FIRST_MPDU_IN_AGGREGATE));
245  AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode, MIDDLE_MPDU_IN_AGGREGATE));
246  }
247  NS_LOG_DEBUG ("Initialized group " << +groupId << ": (" << +streams << "," << +sgi << "," << chWidth << ")");
248  }
249  }
250  }
251  }
252 
253  if (GetVhtSupported ())
254  {
255  // Initialize all VHT groups
256  for (uint16_t chWidth = 20; chWidth <= MAX_VHT_WIDTH; chWidth *= 2)
257  {
258  for (uint8_t sgi = 0; sgi <= 1; sgi++)
259  {
260  for (uint8_t streams = 1; streams <= MAX_SUPPORTED_STREAMS; streams++)
261  {
262  uint8_t groupId = GetVhtGroupId (streams, sgi, chWidth);
263 
264  m_minstrelGroups[groupId].streams = streams;
265  m_minstrelGroups[groupId].sgi = sgi;
266  m_minstrelGroups[groupId].chWidth = chWidth;
267  m_minstrelGroups[groupId].isVht = true;
268  m_minstrelGroups[groupId].isSupported = false;
269 
270  // Check capabilities of the device
271  if (!(!GetShortGuardIntervalSupported () && m_minstrelGroups[groupId].sgi)
272  && (GetPhy ()->GetChannelWidth () >= m_minstrelGroups[groupId].chWidth)
273  && (GetPhy ()->GetMaxSupportedTxSpatialStreams () >= m_minstrelGroups[groupId].streams))
274  {
275  m_minstrelGroups[groupId].isSupported = true;
276 
277  // Calculate TX time for all rates of the group
278  WifiModeList vhtMcsList = GetVhtDeviceMcsList ();
279  for (uint8_t i = 0; i < MAX_VHT_GROUP_RATES; i++)
280  {
281  WifiMode mode = vhtMcsList[i];
282  // Check for invalid VHT MCSs and do not add time to array.
283  if (IsValidMcs (GetPhy (), streams, chWidth, mode))
284  {
285  AddFirstMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode, FIRST_MPDU_IN_AGGREGATE));
286  AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode, MIDDLE_MPDU_IN_AGGREGATE));
287  }
288  }
289  NS_LOG_DEBUG ("Initialized group " << +groupId << ": (" << +streams << "," << +sgi << "," << chWidth << ")");
290  }
291  }
292  }
293  }
294  }
295  }
296 }
297 
298 bool
299 MinstrelHtWifiManager::IsValidMcs (Ptr<WifiPhy> phy, uint8_t streams, uint16_t chWidth, WifiMode mode)
300 {
301  NS_LOG_FUNCTION (this << phy << +streams << chWidth << mode);
302  WifiTxVector txvector;
303  txvector.SetNss (streams);
304  txvector.SetChannelWidth (chWidth);
305  txvector.SetMode (mode);
306  return txvector.IsValid ();
307 }
308 
309 Time
311  uint16_t chWidth, WifiMode mode, MpduType mpduType)
312 {
313  NS_LOG_FUNCTION (this << phy << +streams << +sgi << chWidth << mode << mpduType);
314  WifiTxVector txvector;
315  txvector.SetNss (streams);
316  txvector.SetGuardInterval (sgi ? 400 : 800);
317  txvector.SetChannelWidth (chWidth);
318  txvector.SetNess (0);
319  txvector.SetStbc (0);
320  txvector.SetMode (mode);
323  + WifiPhy::GetPayloadDuration (m_frameLength, txvector, phy->GetFrequency (), mpduType);
324 }
325 
326 Time
328 {
329  NS_LOG_FUNCTION (this << +groupId << mode);
330  auto it = m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.find (mode);
331  NS_ASSERT (it != m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.end ());
332  return it->second;
333 }
334 
335 void
337 {
338  NS_LOG_FUNCTION (this << +groupId << mode << t);
339  m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.insert (std::make_pair (mode, t));
340 }
341 
342 Time
343 MinstrelHtWifiManager::GetMpduTxTime (uint8_t groupId, WifiMode mode) const
344 {
345  NS_LOG_FUNCTION (this << +groupId << mode);
346  auto it = m_minstrelGroups[groupId].ratesTxTimeTable.find (mode);
347  NS_ASSERT (it != m_minstrelGroups[groupId].ratesTxTimeTable.end ());
348  return it->second;
349 }
350 
351 void
353 {
354  NS_LOG_FUNCTION (this << +groupId << mode << t);
355  m_minstrelGroups[groupId].ratesTxTimeTable.insert (std::make_pair (mode, t));
356 }
357 
360 {
361  NS_LOG_FUNCTION (this);
363 
364  // Initialize variables common to both stations.
366  station->m_col = 0;
367  station->m_index = 0;
368  station->m_maxTpRate = 0;
369  station->m_maxTpRate2 = 0;
370  station->m_maxProbRate = 0;
371  station->m_nModes = 0;
372  station->m_totalPacketsCount = 0;
373  station->m_samplePacketsCount = 0;
374  station->m_isSampling = false;
375  station->m_sampleRate = 0;
376  station->m_sampleDeferred = false;
377  station->m_shortRetry = 0;
378  station->m_longRetry = 0;
379  station->m_txrate = 0;
380  station->m_initialized = false;
381 
382  // Variables specific to HT station
383  station->m_sampleGroup = 0;
384  station->m_numSamplesSlow = 0;
385  station->m_sampleCount = 16;
386  station->m_sampleWait = 0;
387  station->m_sampleTries = 4;
388 
389  station->m_avgAmpduLen = 1;
390  station->m_ampduLen = 0;
391  station->m_ampduPacketCount = 0;
392 
393  // If the device supports HT
394  if (GetHtSupported ())
395  {
400  station->m_isHt = true;
401  }
402  // Use the variable in the station to indicate that the device do not support HT
403  else
404  {
405  station->m_isHt = false;
406  }
407 
408  return station;
409 }
410 
411 void
413 {
414  NS_LOG_FUNCTION (this << station);
415  // Note: we appear to be doing late initialization of the table
416  // to make sure that the set of supported rates has been initialized
417  // before we perform our own initialization.
418  if (!station->m_initialized)
419  {
426  if (!GetHtSupported (station))
427  {
428  NS_LOG_INFO ("non-HT station " << station);
429  station->m_isHt = false;
430  // We will use non-HT minstrel for this station. Initialize the manager.
431  m_legacyManager->SetAttribute ("UpdateStatistics", TimeValue (m_updateStats));
432  m_legacyManager->SetAttribute ("LookAroundRate", UintegerValue (m_lookAroundRate));
433  m_legacyManager->SetAttribute ("EWMA", UintegerValue (m_ewmaLevel));
434  m_legacyManager->SetAttribute ("SampleColumn", UintegerValue (m_nSampleCol));
435  m_legacyManager->SetAttribute ("PacketLength", UintegerValue (m_frameLength));
436  m_legacyManager->SetAttribute ("PrintStats", BooleanValue (m_printStats));
437  m_legacyManager->CheckInit (station);
438  }
439  else
440  {
441  NS_LOG_DEBUG ("HT station " << station);
442  station->m_isHt = true;
443  station->m_nModes = GetNMcsSupported (station);
444  station->m_minstrelTable = MinstrelRate (station->m_nModes);
445  station->m_sampleTable = SampleRate (m_numRates, std::vector<uint8_t> (m_nSampleCol));
446  InitSampleTable (station);
447  RateInit (station);
448  station->m_initialized = true;
449  }
450  }
451 }
452 
453 void
455 {
456  NS_LOG_FUNCTION (this << st);
457  NS_LOG_DEBUG ("DoReportRxOk m_txrate=" << static_cast<MinstrelHtWifiRemoteStation*> (st)->m_txrate);
458 }
459 
460 void
462 {
463  NS_LOG_FUNCTION (this << st);
464  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
465  CheckInit (station);
466  if (!station->m_initialized)
467  {
468  return;
469  }
470  NS_LOG_DEBUG ("DoReportRtsFailed m_txrate = " << station->m_txrate);
471  station->m_shortRetry++;
472 }
473 
474 void
475 MinstrelHtWifiManager::DoReportRtsOk (WifiRemoteStation *st, double ctsSnr, WifiMode ctsMode, double rtsSnr)
476 {
477  NS_LOG_FUNCTION (this << st);
478 }
479 
480 void
482 {
483  NS_LOG_FUNCTION (this << st);
484  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
485  NS_LOG_DEBUG ("Final RTS failed");
486  CheckInit (station);
487  if (!station->m_initialized)
488  {
489  return;
490  }
491  UpdateRetry (station);
492 }
493 
494 void
496 {
497  NS_LOG_FUNCTION (this << st);
498  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
499 
500  CheckInit (station);
501  if (!station->m_initialized)
502  {
503  return;
504  }
505 
506  NS_LOG_DEBUG ("DoReportDataFailed " << station << "\t rate " << station->m_txrate << "\tlongRetry \t" << station->m_longRetry);
507 
508  if (!station->m_isHt)
509  {
510  m_legacyManager->UpdateRate (station);
511  }
512  else
513  {
514  uint8_t rateId = GetRateId (station->m_txrate);
515  uint8_t groupId = GetGroupId (station->m_txrate);
516  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++; // Increment the attempts counter for the rate used.
517  UpdateRate (station);
518  }
519 }
520 
521 void
522 MinstrelHtWifiManager::DoReportDataOk (WifiRemoteStation *st, double ackSnr, WifiMode ackMode, double dataSnr)
523 {
524  NS_LOG_FUNCTION (this << st << ackSnr << ackMode << dataSnr);
525  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
526 
527  CheckInit (station);
528  if (!station->m_initialized)
529  {
530  return;
531  }
532 
533  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).");
534 
535  if (!station->m_isHt)
536  {
537  station->m_minstrelTable[station->m_txrate].numRateSuccess++;
538  station->m_minstrelTable[station->m_txrate].numRateAttempt++;
539 
540  m_legacyManager->UpdatePacketCounters (station);
541 
542  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).");
543 
544  UpdateRetry (station);
545  m_legacyManager->UpdateStats (station);
546 
547  if (station->m_nModes >= 1)
548  {
549  station->m_txrate = m_legacyManager->FindRate (station);
550  }
551  }
552  else
553  {
554  uint8_t rateId = GetRateId (station->m_txrate);
555  uint8_t groupId = GetGroupId (station->m_txrate);
556  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
557  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
558 
559  UpdatePacketCounters (station, 1, 0);
560 
561  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).");
562 
563  station->m_isSampling = false;
564  station->m_sampleDeferred = false;
565 
566  UpdateRetry (station);
567  if (Simulator::Now () >= station->m_nextStatsUpdate)
568  {
569  UpdateStats (station);
570  }
571 
572  if (station->m_nModes >= 1)
573  {
574  station->m_txrate = FindRate (station);
575  }
576  }
577 
578  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate );
579 }
580 
581 void
583 {
584  NS_LOG_FUNCTION (this << st);
585  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
586 
587  CheckInit (station);
588  if (!station->m_initialized)
589  {
590  return;
591  }
592 
593  NS_LOG_DEBUG ("DoReportFinalDataFailed - TxRate=" << station->m_txrate);
594 
595  if (!station->m_isHt)
596  {
597  m_legacyManager->UpdatePacketCounters (station);
598 
599  UpdateRetry (station);
600 
601  m_legacyManager->UpdateStats (station);
602  if (station->m_nModes >= 1)
603  {
604  station->m_txrate = m_legacyManager->FindRate (station);
605  }
606  }
607  else
608  {
609  UpdatePacketCounters (station, 0, 1);
610 
611  station->m_isSampling = false;
612  station->m_sampleDeferred = false;
613 
614  UpdateRetry (station);
615  if (Simulator::Now () >= station->m_nextStatsUpdate)
616  {
617  UpdateStats (station);
618  }
619 
620  if (station->m_nModes >= 1)
621  {
622  station->m_txrate = FindRate (station);
623  }
624  }
625  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
626 }
627 
628 void
629 MinstrelHtWifiManager::DoReportAmpduTxStatus (WifiRemoteStation *st, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus, double rxSnr, double dataSnr)
630 {
631  NS_LOG_FUNCTION (this << st << +nSuccessfulMpdus << +nFailedMpdus << rxSnr << dataSnr);
632  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
633 
634  CheckInit (station);
635  if (!station->m_initialized)
636  {
637  return;
638  }
639 
640  NS_ASSERT_MSG (station->m_isHt, "A-MPDU Tx Status called but no HT or VHT supported.");
641 
642  NS_LOG_DEBUG ("DoReportAmpduTxStatus. TxRate=" << station->m_txrate << " SuccMpdus=" <<
643  +nSuccessfulMpdus << " FailedMpdus=" << +nFailedMpdus);
644 
645  station->m_ampduPacketCount++;
646  station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
647 
648  UpdatePacketCounters (station, nSuccessfulMpdus, nFailedMpdus);
649 
650  uint8_t rateId = GetRateId (station->m_txrate);
651  uint8_t groupId = GetGroupId (station->m_txrate);
652  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
653  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt += nSuccessfulMpdus + nFailedMpdus;
654 
655  if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries (station))
656  {
657  // We do not receive a BlockAck. The entire AMPDU fail.
658  UpdateRate (station);
659  }
660  else
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  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
676  }
677 }
678 
679 void
681 {
682  NS_LOG_FUNCTION (this << station);
683 
705  CheckInit (station);
706  if (!station->m_initialized)
707  {
708  return;
709  }
710  station->m_longRetry++;
711 
715  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
716  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
717  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
718  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
719  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
720  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
721 
723  if (!station->m_isSampling)
724  {
726  if (station->m_longRetry < station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
727  {
728  NS_LOG_DEBUG ("Not Sampling; use the same rate again");
729  station->m_txrate = station->m_maxTpRate;
730  }
731 
733  else if (station->m_longRetry < ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
734  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
735  {
736  NS_LOG_DEBUG ("Not Sampling; use the Max TP2");
737  station->m_txrate = station->m_maxTpRate2;
738  }
739 
741  else if (station->m_longRetry <= ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
742  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
743  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
744  {
745  NS_LOG_DEBUG ("Not Sampling; use Max Prob");
746  station->m_txrate = station->m_maxProbRate;
747  }
748  else
749  {
750  NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
751  }
752  }
753 
755  else
756  {
759  if (station->m_longRetry < 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
760  {
761  NS_LOG_DEBUG ("Sampling use the MaxTP rate");
762  station->m_txrate = station->m_maxTpRate2;
763  }
764 
766  else if (station->m_longRetry <= 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
767  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
768  {
769  NS_LOG_DEBUG ("Sampling use the MaxProb rate");
770  station->m_txrate = station->m_maxProbRate;
771  }
772  else
773  {
774  NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
775  }
776  }
777  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
778 }
779 
780 void
782 {
783  NS_LOG_FUNCTION (this << station);
784  station->m_shortRetry = 0;
785  station->m_longRetry = 0;
786 }
787 
788 void
789 MinstrelHtWifiManager::UpdatePacketCounters (MinstrelHtWifiRemoteStation *station, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus)
790 {
791  NS_LOG_FUNCTION (this << station << +nSuccessfulMpdus << +nFailedMpdus);
792 
793  station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
794  if (station->m_isSampling)
795  {
796  station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
797  }
798  if (station->m_totalPacketsCount == ~0)
799  {
800  station->m_samplePacketsCount = 0;
801  station->m_totalPacketsCount = 0;
802  }
803 
804  if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
805  {
806  station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
807  station->m_sampleTries = 1;
808  station->m_sampleCount--;
809  }
810 }
811 
814 {
815  NS_LOG_FUNCTION (this << st);
816  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
817 
818  if (!station->m_initialized)
819  {
820  CheckInit (station);
821  }
822 
823  if (!station->m_isHt)
824  {
825  WifiTxVector vector = m_legacyManager->GetDataTxVector (station);
826  uint64_t dataRate = vector.GetMode ().GetDataRate (vector);
827  if (m_currentRate != dataRate && !station->m_isSampling)
828  {
829  NS_LOG_DEBUG ("New datarate: " << dataRate);
830  m_currentRate = dataRate;
831  }
832  return vector;
833  }
834  else
835  {
836  NS_LOG_DEBUG ("DoGetDataMode m_txrate= " << station->m_txrate);
837 
838  uint8_t rateId = GetRateId (station->m_txrate);
839  uint8_t groupId = GetGroupId (station->m_txrate);
840  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
841 
842  NS_LOG_DEBUG ("DoGetDataMode rateId= " << +rateId << " groupId= " << +groupId << " mode= " << GetMcsSupported (station, mcsIndex));
843 
844  McsGroup group = m_minstrelGroups[groupId];
845 
846  // Check consistency of rate selected.
847  if ((group.sgi && !GetShortGuardIntervalSupported (station)) || group.chWidth > GetChannelWidth (station) || group.streams > GetNumberOfSupportedStreams (station))
848  {
849  NS_FATAL_ERROR ("Inconsistent group selected. Group: (" << +group.streams <<
850  "," << +group.sgi << "," << group.chWidth << ")" <<
851  " Station capabilities: (" << GetNumberOfSupportedStreams (station) <<
852  "," << GetShortGuardIntervalSupported (station) << "," << GetChannelWidth (station) << ")");
853  }
854  WifiMode mode = GetMcsSupported (station, mcsIndex);
855  uint64_t dataRate = mode.GetDataRate (group.chWidth, group.sgi ? 400 : 800, group.streams);
856  if (m_currentRate != dataRate && !station->m_isSampling)
857  {
858  NS_LOG_DEBUG ("New datarate: " << dataRate);
859  m_currentRate = dataRate;
860  }
862  }
863 }
864 
867 {
868  NS_LOG_FUNCTION (this << st);
869  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
870 
871  if (!station->m_initialized)
872  {
873  CheckInit (station);
874  }
875 
876  if (!station->m_isHt)
877  {
878  return m_legacyManager->GetRtsTxVector (station);
879  }
880  else
881  {
882  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
883 
884  /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
885  * When supported, decision of using HT has to follow rules in Section 9.7.6 from 802.11-2012.
886  * From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is carried in a
887  * non-HT PPDU shall be transmitted by the STA using a rate no higher than the highest
888  * rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
889  * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
890  * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
891  * these conditions, the control frame shall be transmitted at a rate no higher than the
892  * highest mandatory rate of the attached PHY that is less than or equal to the rate
893  * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
894  * directed to the same receiving STA."
895  */
896 
897  // As we are in Minstrel HT, assume the last rate was an HT rate.
898  uint8_t rateId = GetRateId (station->m_txrate);
899  uint8_t groupId = GetGroupId (station->m_txrate);
900  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
901 
902  WifiMode lastRate = GetMcsSupported (station, mcsIndex);
903  uint64_t lastDataRate = lastRate.GetNonHtReferenceRate ();
904  uint8_t nBasicRates = GetNBasicModes ();
905 
906  WifiMode rtsRate;
907  bool rateFound = false;
908 
909  for (uint8_t i = 0; i < nBasicRates; i++)
910  {
911  uint64_t rate = GetBasicMode (i).GetDataRate (20);
912  if (rate <= lastDataRate)
913  {
914  rtsRate = GetBasicMode (i);
915  rateFound = true;
916  }
917  }
918 
919  if (!rateFound)
920  {
921  Ptr<WifiPhy> phy = GetPhy ();
922  uint8_t nSupportRates = phy->GetNModes ();
923  for (uint8_t i = 0; i < nSupportRates; i++)
924  {
925  uint64_t rate = phy->GetMode (i).GetDataRate (20);
926  if (rate <= lastDataRate)
927  {
928  rtsRate = phy->GetMode (i);
929  rateFound = true;
930  }
931  }
932  }
933 
934  NS_ASSERT (rateFound);
935 
937  800, 1, 1, 0, GetChannelWidthForTransmission (rtsRate, GetChannelWidth (station)), GetAggregation (station), false);
938  }
939 }
940 
941 bool
943 {
944  NS_LOG_FUNCTION (this << st << packet << normally);
945 
946  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
947 
948  CheckInit (station);
949  if (!station->m_initialized)
950  {
951  return normally;
952  }
953 
954  uint32_t maxRetries;
955 
956  if (!station->m_isHt)
957  {
958  maxRetries = m_legacyManager->CountRetries (station);
959  }
960  else
961  {
962  maxRetries = CountRetries (station);
963  }
964 
965  if (station->m_longRetry >= maxRetries)
966  {
967  NS_LOG_DEBUG ("No re-transmission allowed. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
968  return false;
969  }
970  else
971  {
972  NS_LOG_DEBUG ("Re-transmit. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
973  return true;
974  }
975 }
976 
977 uint32_t
979 {
980  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
981  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
982  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
983  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
984  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
985  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
986 
987  if (!station->m_isSampling)
988  {
989  return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
990  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
991  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
992  }
993  else
994  {
995  return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
996  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
997  }
998 }
999 
1000 bool
1002 {
1003  return true;
1004 }
1005 
1006 uint16_t
1008 {
1009  NS_LOG_FUNCTION (this << station);
1010  uint8_t sampleGroup = station->m_sampleGroup;
1011  uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1012  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1013  uint8_t sampleIndex = station->m_sampleTable[index][col];
1014  uint16_t rateIndex = GetIndex (sampleGroup, sampleIndex);
1015  NS_LOG_DEBUG ("Next Sample is " << rateIndex);
1016  SetNextSample (station); //Calculate the next sample rate.
1017  return rateIndex;
1018 }
1019 
1020 void
1022 {
1023  NS_LOG_FUNCTION (this << station);
1024  do
1025  {
1026  station->m_sampleGroup++;
1027  station->m_sampleGroup %= m_numGroups;
1028  }
1029  while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1030 
1031  station->m_groupsTable[station->m_sampleGroup].m_index++;
1032 
1033  uint8_t sampleGroup = station->m_sampleGroup;
1034  uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1035  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1036 
1037  if (index >= m_numRates)
1038  {
1039  station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1040  station->m_groupsTable[station->m_sampleGroup].m_col++;
1041  if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1042  {
1043  station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1044  }
1045  index = station->m_groupsTable[station->m_sampleGroup].m_index;
1046  col = station->m_groupsTable[sampleGroup].m_col;
1047  }
1048  NS_LOG_DEBUG ("New sample set: group= " << +sampleGroup << " index= " << +station->m_sampleTable[index][col]);
1049 }
1050 
1051 uint16_t
1053 {
1054  NS_LOG_FUNCTION (this << station);
1055  NS_LOG_DEBUG ("FindRate packet=" << station->m_totalPacketsCount);
1056 
1057  if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1058  {
1059  return station->m_maxTpRate;
1060  }
1061 
1062  // If we have waited enough, then sample.
1063  if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1064  {
1065  //SAMPLING
1066  NS_LOG_DEBUG ("Obtaining a sampling rate");
1068  uint16_t sampleIdx = GetNextSample (station);
1069  NS_LOG_DEBUG ("Sampling rate = " << sampleIdx);
1070 
1071  //Evaluate if the sampling rate selected should be used.
1072  uint8_t sampleGroupId = GetGroupId (sampleIdx);
1073  uint8_t sampleRateId = GetRateId (sampleIdx);
1074 
1075  // If the rate selected is not supported, then don't sample.
1076  if (station->m_groupsTable[sampleGroupId].m_supported && station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1077  {
1085  HtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1086 
1087  NS_LOG_DEBUG ("Use sample rate? MaxTpRate= " << station->m_maxTpRate << " CurrentRate= " << station->m_txrate <<
1088  " SampleRate= " << sampleIdx << " SampleProb= " << sampleRateInfo.ewmaProb);
1089 
1090  if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2
1091  && sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1092  {
1093 
1099  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1100  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1101  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1102  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1103  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
1104 
1105  uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1106  uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1107 
1108  Time sampleDuration = sampleRateInfo.perfectTxTime;
1109  Time maxTp2Duration = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1110  Time maxProbDuration = station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].perfectTxTime;
1111 
1112  NS_LOG_DEBUG ("Use sample rate? SampleDuration= " << sampleDuration << " maxTp2Duration= " << maxTp2Duration <<
1113  " maxProbDuration= " << maxProbDuration << " sampleStreams= " << +sampleStreams <<
1114  " maxTpStreams= " << +maxTpStreams);
1115  if (sampleDuration < maxTp2Duration || (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1116  {
1118  station->m_isSampling = true;
1119 
1121  station->m_sampleRate = sampleIdx;
1122 
1123  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1124  station->m_sampleTries--;
1125  return sampleIdx;
1126  }
1127  else
1128  {
1129  station->m_numSamplesSlow++;
1130  if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1131  {
1133  station->m_isSampling = true;
1134 
1136  station->m_sampleRate = sampleIdx;
1137 
1138  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1139  station->m_sampleTries--;
1140  return sampleIdx;
1141  }
1142  }
1143  }
1144  }
1145  }
1146  if (station->m_sampleWait > 0)
1147  {
1148  station->m_sampleWait--;
1149  }
1150 
1152 
1153  NS_LOG_DEBUG ("FindRate " << "maxTpRrate=" << station->m_maxTpRate);
1154  return station->m_maxTpRate;
1155 }
1156 void
1158 {
1159  NS_LOG_FUNCTION (this << station);
1160 
1162 
1163  station->m_numSamplesSlow = 0;
1164  station->m_sampleCount = 0;
1165 
1166  double tempProb;
1167 
1168  if (station->m_ampduPacketCount > 0)
1169  {
1170  uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1171  station->m_avgAmpduLen = ( newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel) ) / 100;
1172  station->m_ampduLen = 0;
1173  station->m_ampduPacketCount = 0;
1174  }
1175 
1176  /* Initialize global rate indexes */
1177  station->m_maxTpRate = GetLowestIndex (station);
1178  station->m_maxTpRate2 = GetLowestIndex (station);
1179  station->m_maxProbRate = GetLowestIndex (station);
1180 
1182  for (uint8_t j = 0; j < m_numGroups; j++)
1183  {
1184  if (station->m_groupsTable[j].m_supported)
1185  {
1186  station->m_sampleCount++;
1187 
1188  /* (re)Initialize group rate indexes */
1189  station->m_groupsTable[j].m_maxTpRate = GetLowestIndex (station, j);
1190  station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex (station, j);
1191  station->m_groupsTable[j].m_maxProbRate = GetLowestIndex (station, j);
1192 
1193  for (uint8_t i = 0; i < m_numRates; i++)
1194  {
1195  if (station->m_groupsTable[j].m_ratesTable[i].supported)
1196  {
1197  station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1198 
1199  NS_LOG_DEBUG (+i << " " << GetMcsSupported (station, station->m_groupsTable[j].m_ratesTable[i].mcsIndex) <<
1200  "\t attempt=" << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt <<
1201  "\t success=" << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1202 
1204  if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1205  {
1206  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1211  tempProb = (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) / station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1212 
1214  station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1215 
1216  if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1217  {
1218  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1219  }
1220  else
1221  {
1222  station->m_groupsTable[j].m_ratesTable[i].ewmsdProb = CalculateEwmsd (station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1223  tempProb, station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1224  m_ewmaLevel);
1226  tempProb = (tempProb * (100 - m_ewmaLevel) + station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) / 100;
1227  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1228  }
1229 
1230  station->m_groupsTable[j].m_ratesTable[i].throughput = CalculateThroughput (station, j, i, tempProb);
1231 
1232  station->m_groupsTable[j].m_ratesTable[i].successHist += station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1233  station->m_groupsTable[j].m_ratesTable[i].attemptHist += station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1234  }
1235  else
1236  {
1237  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1238  }
1239 
1241  station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess = station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1242  station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt = station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1243  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1244  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1245 
1246  if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1247  {
1248  SetBestStationThRates (station, GetIndex (j, i));
1249  SetBestProbabilityRate (station, GetIndex (j, i));
1250  }
1251 
1252  }
1253  }
1254  }
1255  }
1256 
1257  //Try to sample all available rates during each interval.
1258  station->m_sampleCount *= 8;
1259 
1260  //Recalculate retries for the rates selected.
1261  CalculateRetransmits (station, station->m_maxTpRate);
1262  CalculateRetransmits (station, station->m_maxTpRate2);
1263  CalculateRetransmits (station, station->m_maxProbRate);
1264 
1265  NS_LOG_DEBUG ("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2 << "\nmax prob=" << station->m_maxProbRate);
1266  if (m_printStats)
1267  {
1268  PrintTable (station);
1269  }
1270 }
1271 
1272 double
1273 MinstrelHtWifiManager::CalculateThroughput (MinstrelHtWifiRemoteStation *station, uint8_t groupId, uint8_t rateId, double ewmaProb)
1274 {
1280  if (ewmaProb < 10)
1281  {
1282  return 0;
1283  }
1284  else
1285  {
1290  Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1291  if (ewmaProb > 90)
1292  {
1293  return 90 / txTime.GetSeconds ();
1294  }
1295  else
1296  {
1297  return ewmaProb / txTime.GetSeconds ();
1298  }
1299  }
1300 }
1301 
1302 void
1304 {
1305  GroupInfo *group;
1306  HtRateInfo rate;
1307  uint8_t tmpGroupId, tmpRateId;
1308  double tmpTh, tmpProb;
1309  uint8_t groupId, rateId;
1310  double currentTh;
1311  // maximum group probability (GP) variables
1312  uint8_t maxGPGroupId, maxGPRateId;
1313  double maxGPTh;
1314 
1315  groupId = GetGroupId (index);
1316  rateId = GetRateId (index);
1317  group = &station->m_groupsTable[groupId];
1318  rate = group->m_ratesTable[rateId];
1319 
1320  tmpGroupId = GetGroupId (station->m_maxProbRate);
1321  tmpRateId = GetRateId (station->m_maxProbRate);
1322  tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1323  tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1324 
1325  if (rate.ewmaProb > 75)
1326  {
1327  currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1328  if (currentTh > tmpTh)
1329  {
1330  station->m_maxProbRate = index;
1331  }
1332 
1333  maxGPGroupId = GetGroupId (group->m_maxProbRate);
1334  maxGPRateId = GetRateId (group->m_maxProbRate);
1335  maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1336 
1337  if (currentTh > maxGPTh)
1338  {
1339  group->m_maxProbRate = index;
1340  }
1341  }
1342  else
1343  {
1344  if (rate.ewmaProb > tmpProb)
1345  {
1346  station->m_maxProbRate = index;
1347  }
1348  maxGPRateId = GetRateId (group->m_maxProbRate);
1349  if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1350  {
1351  group->m_maxProbRate = index;
1352  }
1353  }
1354 }
1355 
1356 /*
1357  * Find & sort topmost throughput rates
1358  *
1359  * If multiple rates provide equal throughput the sorting is based on their
1360  * current success probability. Higher success probability is preferred among
1361  * MCS groups.
1362  */
1363 void
1365 {
1366  uint8_t groupId, rateId;
1367  double th, prob;
1368  uint8_t maxTpGroupId, maxTpRateId;
1369  uint8_t maxTp2GroupId, maxTp2RateId;
1370  double maxTpTh, maxTpProb;
1371  double maxTp2Th, maxTp2Prob;
1372 
1373  groupId = GetGroupId (index);
1374  rateId = GetRateId (index);
1375  prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1376  th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1377 
1378  maxTpGroupId = GetGroupId (station->m_maxTpRate);
1379  maxTpRateId = GetRateId (station->m_maxTpRate);
1380  maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1381  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1382 
1383  maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1384  maxTp2RateId = GetRateId (station->m_maxTpRate2);
1385  maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1386  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1387 
1388  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1389  {
1390  station->m_maxTpRate2 = station->m_maxTpRate;
1391  station->m_maxTpRate = index;
1392  }
1393  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1394  {
1395  station->m_maxTpRate2 = index;
1396  }
1397 
1398  //Find best rates per group
1399 
1400  GroupInfo *group = &station->m_groupsTable[groupId];
1401  maxTpGroupId = GetGroupId (group->m_maxTpRate);
1402  maxTpRateId = GetRateId (group->m_maxTpRate);
1403  maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1404  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1405 
1406  maxTp2GroupId = GetGroupId (group->m_maxTpRate2);
1407  maxTp2RateId = GetRateId (group->m_maxTpRate2);
1408  maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1409  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1410 
1411  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1412  {
1413  group->m_maxTpRate2 = group->m_maxTpRate;
1414  group->m_maxTpRate = index;
1415  }
1416  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1417  {
1418  group->m_maxTpRate2 = index;
1419  }
1420 }
1421 
1422 void
1424 {
1425  NS_LOG_FUNCTION (this << station);
1426 
1427  station->m_groupsTable = McsGroupData (m_numGroups);
1428 
1432  NS_LOG_DEBUG ("Supported groups by station:");
1433  for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1434  {
1435  if (m_minstrelGroups[groupId].isSupported)
1436  {
1437  station->m_groupsTable[groupId].m_supported = false;
1438  if (!(!GetVhtSupported (station) && m_minstrelGroups[groupId].isVht)
1439  && (m_minstrelGroups[groupId].isVht || !GetVhtSupported (station) || !m_useVhtOnly)
1440  && !(!GetShortGuardIntervalSupported (station) && m_minstrelGroups[groupId].sgi)
1441  && (GetChannelWidth (station) >= m_minstrelGroups[groupId].chWidth)
1442  && (GetNumberOfSupportedStreams (station) >= m_minstrelGroups[groupId].streams))
1443  {
1444  NS_LOG_DEBUG ("Group " << +groupId << ": (" << +m_minstrelGroups[groupId].streams <<
1445  "," << +m_minstrelGroups[groupId].sgi << "," << m_minstrelGroups[groupId].chWidth << ")");
1446 
1447  station->m_groupsTable[groupId].m_supported = true;
1448  station->m_groupsTable[groupId].m_col = 0;
1449  station->m_groupsTable[groupId].m_index = 0;
1450 
1451  station->m_groupsTable[groupId].m_ratesTable = HtMinstrelRate (m_numRates);
1452  for (uint8_t i = 0; i < m_numRates; i++)
1453  {
1454  station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1455  }
1456 
1457  // Initialize all modes supported by the remote station that belong to the current group.
1458  for (uint8_t i = 0; i < station->m_nModes; i++)
1459  {
1460  WifiMode mode = GetMcsSupported (station, i);
1461 
1464  uint8_t rateId = mode.GetMcsValue ();
1465  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1466  {
1467  rateId %= MAX_HT_GROUP_RATES;
1468  }
1469 
1470  if ((m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_VHT
1471  && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1472  || (!m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_HT
1473  && mode.GetMcsValue () < (m_minstrelGroups[groupId].streams * 8)
1474  && mode.GetMcsValue () >= ((m_minstrelGroups[groupId].streams - 1) * 8)))
1475  {
1476  NS_LOG_DEBUG ("Mode " << +i << ": " << mode << " isVht: " << m_minstrelGroups[groupId].isVht);
1477 
1478  station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1479  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex = i;
1480  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1481  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1482  station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1483  station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1484  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1485  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1486  station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1487  station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1488  station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1489  station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1490  station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
1491  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1492  station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1493  CalculateRetransmits (station, groupId, rateId);
1494  }
1495  }
1496  }
1497  }
1498  }
1499  SetNextSample (station);
1500  UpdateStats (station);
1501  station->m_txrate = FindRate (station);
1502 }
1503 
1504 void
1506 {
1507  NS_LOG_FUNCTION (this << station << index);
1508  uint8_t groupId = GetGroupId (index);
1509  uint8_t rateId = GetRateId (index);
1510  if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1511  {
1512  CalculateRetransmits (station, groupId, rateId);
1513  }
1514 }
1515 
1516 void
1518 {
1519  NS_LOG_FUNCTION (this << station << +groupId << +rateId);
1520 
1521  uint32_t cw = 15; // Is an approximation.
1522  uint32_t cwMax = 1023;
1523  Time cwTime, txTime, dataTxTime;
1524  Time slotTime = GetMac ()->GetSlot ();
1525  Time ackTime = GetMac ()->GetBasicBlockAckTimeout ();
1526 
1527  if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1528  {
1529  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1530  }
1531  else
1532  {
1533  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1534  station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1535 
1536  dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1537  GetMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) * (station->m_avgAmpduLen - 1);
1538 
1539  /* Contention time for first 2 tries */
1540  cwTime = (cw / 2) * slotTime;
1541  cw = Min ((cw + 1) * 2, cwMax);
1542  cwTime += (cw / 2) * slotTime;
1543  cw = Min ((cw + 1) * 2, cwMax);
1544 
1545  /* Total TX time for data and Contention after first 2 tries */
1546  txTime = cwTime + 2 * (dataTxTime + ackTime);
1547 
1548  /* See how many more tries we can fit inside segment size */
1549  do
1550  {
1551  /* Contention time for this try */
1552  cwTime = (cw / 2) * slotTime;
1553  cw = Min ((cw + 1) * 2, cwMax);
1554 
1555  /* Total TX time after this try */
1556  txTime += cwTime + ackTime + dataTxTime;
1557  }
1558  while ((txTime < MilliSeconds (6))
1559  && (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1560  }
1561 }
1562 
1563 double
1564 MinstrelHtWifiManager::CalculateEwmsd (double oldEwmsd, double currentProb, double ewmaProb, double weight)
1565 {
1566  double diff, incr, tmp;
1567 
1568  /* calculate exponential weighted moving variance */
1569  diff = currentProb - ewmaProb;
1570  incr = (100 - weight) * diff / 100;
1571  tmp = oldEwmsd * oldEwmsd;
1572  tmp = weight * (tmp + diff * incr) / 100;
1573 
1574  /* return standard deviation */
1575  return sqrt (tmp);
1576 }
1577 
1578 void
1580 {
1581  NS_LOG_FUNCTION (this << station);
1582  station->m_col = station->m_index = 0;
1583 
1584  //for off-setting to make rates fall between 0 and nModes
1585  uint8_t numSampleRates = m_numRates;
1586 
1587  uint16_t newIndex;
1588  for (uint8_t col = 0; col < m_nSampleCol; col++)
1589  {
1590  for (uint8_t i = 0; i < numSampleRates; i++ )
1591  {
1596  int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
1597  newIndex = (i + uv) % numSampleRates;
1598 
1599  //this loop is used for filling in other uninitialized places
1600  while (station->m_sampleTable[newIndex][col] != 0)
1601  {
1602  newIndex = (newIndex + 1) % m_numRates;
1603  }
1604  station->m_sampleTable[newIndex][col] = i;
1605  }
1606  }
1607 }
1608 
1609 void
1611 {
1612  if (!station->m_statsFile.is_open ())
1613  {
1614  std::ostringstream tmp;
1615  tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1616  station->m_statsFile.open (tmp.str ().c_str (), std::ios::out);
1617  }
1618 
1619  station->m_statsFile << " best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n" <<
1620  " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n";
1621  for (uint8_t i = 0; i < m_numGroups; i++)
1622  {
1623  StatsDump (station, i, station->m_statsFile);
1624  }
1625 
1626  station->m_statsFile << "\nTotal packet count:: ideal " << Max (0, station->m_totalPacketsCount - station->m_samplePacketsCount) <<
1627  " lookaround " << station->m_samplePacketsCount << "\n";
1628  station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen << "\n\n";
1629 
1630  station->m_statsFile.flush ();
1631 }
1632 
1633 void
1634 MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint8_t groupId, std::ofstream &of)
1635 {
1636  uint8_t numRates = m_numRates;
1637  McsGroup group = m_minstrelGroups[groupId];
1638  Time txTime;
1639  char giMode;
1640  if (group.sgi)
1641  {
1642  giMode = 'S';
1643  }
1644  else
1645  {
1646  giMode = 'L';
1647  }
1648  for (uint8_t i = 0; i < numRates; i++)
1649  {
1650  if (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[i].supported)
1651  {
1652  if (!group.isVht)
1653  {
1654  of << "HT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1655  }
1656  else
1657  {
1658  of << "VHT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1659  }
1660 
1661  uint16_t maxTpRate = station->m_maxTpRate;
1662  uint16_t maxTpRate2 = station->m_maxTpRate2;
1663  uint16_t maxProbRate = station->m_maxProbRate;
1664 
1665  uint16_t idx = GetIndex (groupId, i);
1666  if (idx == maxTpRate)
1667  {
1668  of << 'A';
1669  }
1670  else
1671  {
1672  of << ' ';
1673  }
1674  if (idx == maxTpRate2)
1675  {
1676  of << 'B';
1677  }
1678  else
1679  {
1680  of << ' ';
1681  }
1682  if (idx == maxProbRate)
1683  {
1684  of << 'P';
1685  }
1686  else
1687  {
1688  of << ' ';
1689  }
1690 
1691  if (!group.isVht)
1692  {
1693  of << std::setw (4) << " MCS" << (group.streams - 1) * 8 + i;
1694  }
1695  else
1696  {
1697  of << std::setw (7) << " MCS" << +i << "/" << (int) group.streams;
1698  }
1699 
1700  of << " " << std::setw (3) << +idx << " ";
1701 
1702  /* tx_time[rate(i)] in usec */
1703  txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
1704  of << std::setw (6) << txTime.GetMicroSeconds () << " ";
1705 
1706  of << std::setw (7) << CalculateThroughput (station, groupId, i, 100) / 100 << " " <<
1707  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100 << " " <<
1708  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb << " " <<
1709  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb << " " <<
1710  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].prob << " " <<
1711  std::setw (2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount << " " <<
1712  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " " <<
1713  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt << " " <<
1714  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " " <<
1715  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist << "\n";
1716  }
1717  }
1718 }
1719 uint16_t
1720 MinstrelHtWifiManager::GetIndex (uint8_t groupId, uint8_t rateId)
1721 {
1722  NS_LOG_FUNCTION (this << +groupId << +rateId);
1723  uint16_t index;
1724  index = groupId * m_numRates + rateId;
1725  return index;
1726 }
1727 
1728 uint8_t
1730 {
1731  NS_LOG_FUNCTION (this << index);
1732  uint8_t id;
1733  id = index % m_numRates;
1734  return id;
1735 }
1736 
1737 uint8_t
1739 {
1740  NS_LOG_FUNCTION (this << index);
1741  return index / m_numRates;
1742 }
1743 
1744 uint8_t
1745 MinstrelHtWifiManager::GetHtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1746 {
1747  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1748  return MAX_SUPPORTED_STREAMS * 2 * (chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
1749 }
1750 
1751 uint8_t
1752 MinstrelHtWifiManager::GetVhtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1753 {
1754  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1755  return MAX_HT_STREAM_GROUPS * MAX_SUPPORTED_STREAMS + MAX_SUPPORTED_STREAMS * 2 * (chWidth == 160 ? 3 : chWidth == 80 ? 2 : chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
1756 }
1757 
1758 uint16_t
1760 {
1761  NS_LOG_FUNCTION (this << station);
1762 
1763  uint8_t groupId = 0;
1764  uint8_t rateId = 0;
1765  while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
1766  {
1767  groupId++;
1768  }
1769  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1770  {
1771  rateId++;
1772  }
1773  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1774  return GetIndex (groupId, rateId);
1775 }
1776 
1777 uint16_t
1779 {
1780  NS_LOG_FUNCTION (this << station << +groupId);
1781 
1782  uint8_t rateId = 0;
1783  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1784  {
1785  rateId++;
1786  }
1787  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1788  return GetIndex (groupId, rateId);
1789 }
1790 
1793 {
1794  WifiModeList vhtMcsList;
1795  Ptr<WifiPhy> phy = GetPhy ();
1796  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1797  {
1798  WifiMode mode = phy->GetMcs (i);
1799  if (mode.GetModulationClass () == WIFI_MOD_CLASS_VHT)
1800  {
1801  vhtMcsList.push_back (mode);
1802  }
1803  }
1804  return vhtMcsList;
1805 }
1806 
1809 {
1810  WifiModeList htMcsList;
1811  Ptr<WifiPhy> phy = GetPhy ();
1812  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1813  {
1814  WifiMode mode = phy->GetMcs (i);
1815  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1816  {
1817  htMcsList.push_back (mode);
1818  }
1819  }
1820  return htMcsList;
1821 }
1822 
1823 } // namespace ns3
void DoReportRtsOk(WifiRemoteStation *station, double ctsSnr, WifiMode ctsMode, double rtsSnr)
This method is a pure virtual method that must be implemented by the sub-class.
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
uint8_t m_nSampleCol
Number of sample columns.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
Ptr< WifiMac > GetMac(void) const
Return the WifiMac.
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.
void DoReportAmpduTxStatus(WifiRemoteStation *station, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus, double rxSnr, double dataSnr)
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
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.
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...
static const uint8_t MAX_SUPPORTED_STREAMS
Constants for maximum values.
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.
uint16_t GetLowestIndex(MinstrelHtWifiRemoteStation *station)
Returns the lowest global index of the rates supported by the station.
NS_ASSERT_MSG(false, "Ipv4AddressGenerator::MaskToIndex(): Impossible")
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 UpdatePacketCounters(MinstrelHtWifiRemoteStation *station, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus)
Update the number of sample count variables.
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
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:361
WifiTxVector DoGetDataTxVector(WifiRemoteStation *station)
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.
static const uint8_t MAX_VHT_STREAM_GROUPS
Maximal number of groups per stream in VHT (4 possible channel widths and 2 possible SGI configuratio...
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:1078
WifiRemoteStation * DoCreateStation(void) const
uint16_t m_sampleRate
current sample rate in bps
void SetStbc(bool stbc)
Sets if STBC is being used.
void DoReportFinalRtsFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
Mac48Address m_address
Mac48Address of the remote station.
HtMinstrelRate m_ratesTable
Information about rates of this group.
#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:162
uint8_t sgi
short guard interval (0 or 1)
uint16_t FindRate(MinstrelHtWifiRemoteStation *station)
Find a rate to use from Minstrel Table.
void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode)
This method is a pure virtual method that must be implemented by the sub-class.
VHT PHY (Clause 22)
Definition: wifi-mode.h:60
MinstrelRate m_minstrelTable
minstrel table
WifiPreamble GetPreambleForTransmission(WifiModulationClass modulation, bool useShortPreamble, bool useGreenfield)
Return the preamble to be used for the transmission.
Definition: wifi-utils.cc:128
uint32_t m_frameLength
Frame length used for calculate modes TxTime in bytes.
MinstrelMcsGroups m_minstrelGroups
Global array for groups information.
STL namespace.
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:97
std::vector< RateInfo > MinstrelRate
Data structure for a Minstrel Rate table A vector of a struct RateInfo.
bool DoNeedRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally)
uint8_t m_nModes
number of modes supported
uint8_t GetRateId(uint16_t index)
For managing rates from different groups, a global index for all rates in all groups is used...
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
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:449
uint8_t m_ewmaLevel
Exponential weighted moving average level (or coefficient).
void SetBestStationThRates(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxTpRate or maxTp2Rate if is better than current values.
Time GetFirstMpduTxTime(uint8_t groupId, WifiMode mode) const
Obtain the TxTime saved in the group information.
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
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
WifiTxVector DoGetRtsTxVector(WifiRemoteStation *station)
bool IsValid(void) const
The standard disallows certain combinations of WifiMode, number of spatial streams, and channel widths.
AttributeValue implementation for Time.
Definition: nstime.h:1132
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...
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_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
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 SGI configuration...
WifiMode GetMode(void) const
HT PHY (Clause 20)
Definition: wifi-mode.h:58
uint32_t m_sampleWait
How many transmission attempts to wait until a new sample.
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:463
bool m_useVhtOnly
If only VHT MCS should be used, instead of HT and VHT.
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 refer to IEEE 802.11n Table 20-28 for explanation and range.
bool m_initialized
for initializing tables
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model...
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:369
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.
double ewmaProb
Exponential weighted moving average of probability.
Time perfectTxTime
Perfect transmission time calculation, or frame calculation.
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.
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
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 DoReportRtsFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
void UpdateRetry(MinstrelHtWifiRemoteStation *station)
Update the number of retries and reset accordingly.
uint32_t m_sampleCount
Max number of samples per update interval.
void DoReportFinalDataFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
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:109
uint8_t m_numGroups
Number of groups Minstrel should consider.
bool UseGreenfieldForDestination(Mac48Address dest) const
Time m_updateStats
How frequent do we calculate the stats (1/10 seconds).
static const uint8_t MAX_HT_GROUP_RATES
Number of rates (or MCS) per HT group.
Mac48Address GetAddress(const WifiRemoteStation *station) const
Return the address of the station.
void DoReportDataFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
void UpdateStats(MinstrelHtWifiRemoteStation *station)
Update the Minstrel Table every 1/10 seconds.
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:1133
std::vector< WifiMode > WifiModeList
In various parts of the code, folk are interested in maintaining a list of transmission modes...
Definition: wifi-mode.h:283
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:193
std::vector< HtRateInfo > HtMinstrelRate
Data structure for a Minstrel Rate table.
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.
static Time GetPayloadDuration(uint32_t size, WifiTxVector txVector, uint16_t frequency, MpduType mpdutype=NORMAL_MPDU)
Definition: wifi-phy.cc:2125
Implementation of Minstrel HT Rate Control AlgorithmMinstrel-HT is a rate adaptation mechanism for th...
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...
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
Data structure to contain the information that defines a group.
void DoInitialize(void)
Initialize() implementation.
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:470
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...
Ptr< WifiPhy > GetPhy(void) const
Return the WifiPhy.
uint8_t GetVhtGroupId(uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
Returns the groupId of a VHT MCS with the given number of streams, if using SGI and the channel width...
double CalculateEwmsd(double oldEwmsd, double currentProb, double ewmaProb, double weight)
Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation.
if(desigRtr==addrLocal)
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.
A struct to contain all statistics information related to a data rate.
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< MinstrelWifiManager > m_legacyManager
Pointer to an instance of MinstrelWifiManager.
uint32_t numSamplesSkipped
Number of times this rate statistics were not updated because no attempts have been made...
uint32_t m_sampleTries
Number of sample tries after waiting sampleWait.
uint8_t GetHtGroupId(uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
Returns the groupId of a HT MCS with the given number of streams, if using SGI and the channel width ...
void SetNess(uint8_t ness)
Sets the Ness number refer to IEEE 802.11n Table 20-6 for explanation.
uint8_t GetGroupId(uint16_t index)
Return the groupId from the global index.
Time CalculateMpduTxDuration(Ptr< WifiPhy > phy, uint8_t streams, uint8_t sgi, 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...
uint32_t m_avgAmpduLen
Average number of MPDUs in an A-MPDU.
uint32_t CountRetries(MinstrelHtWifiRemoteStation *station)
Count retries.
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.
void DoReportDataOk(WifiRemoteStation *station, double ackSnr, WifiMode ackMode, double dataSnr)
This method is a pure virtual method that must be implemented by the sub-class.
uint8_t GetMcsValue(void) const
Definition: wifi-mode.cc:441
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:119
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
static Time CalculatePhyPreambleAndHeaderDuration(WifiTxVector txVector)
Definition: wifi-phy.cc:2403
Time m_nextStatsUpdate
10 times every second