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
523  double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss)
524 {
525  NS_LOG_FUNCTION (this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
526  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
527 
528  CheckInit (station);
529  if (!station->m_initialized)
530  {
531  return;
532  }
533 
534  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).");
535 
536  if (!station->m_isHt)
537  {
538  station->m_minstrelTable[station->m_txrate].numRateSuccess++;
539  station->m_minstrelTable[station->m_txrate].numRateAttempt++;
540 
541  m_legacyManager->UpdatePacketCounters (station);
542 
543  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).");
544 
545  UpdateRetry (station);
546  m_legacyManager->UpdateStats (station);
547 
548  if (station->m_nModes >= 1)
549  {
550  station->m_txrate = m_legacyManager->FindRate (station);
551  }
552  }
553  else
554  {
555  uint8_t rateId = GetRateId (station->m_txrate);
556  uint8_t groupId = GetGroupId (station->m_txrate);
557  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
558  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
559 
560  UpdatePacketCounters (station, 1, 0);
561 
562  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).");
563 
564  station->m_isSampling = false;
565  station->m_sampleDeferred = false;
566 
567  UpdateRetry (station);
568  if (Simulator::Now () >= station->m_nextStatsUpdate)
569  {
570  UpdateStats (station);
571  }
572 
573  if (station->m_nModes >= 1)
574  {
575  station->m_txrate = FindRate (station);
576  }
577  }
578 
579  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate );
580 }
581 
582 void
584 {
585  NS_LOG_FUNCTION (this << st);
586  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
587 
588  CheckInit (station);
589  if (!station->m_initialized)
590  {
591  return;
592  }
593 
594  NS_LOG_DEBUG ("DoReportFinalDataFailed - TxRate=" << station->m_txrate);
595 
596  if (!station->m_isHt)
597  {
598  m_legacyManager->UpdatePacketCounters (station);
599 
600  UpdateRetry (station);
601 
602  m_legacyManager->UpdateStats (station);
603  if (station->m_nModes >= 1)
604  {
605  station->m_txrate = m_legacyManager->FindRate (station);
606  }
607  }
608  else
609  {
610  UpdatePacketCounters (station, 0, 1);
611 
612  station->m_isSampling = false;
613  station->m_sampleDeferred = false;
614 
615  UpdateRetry (station);
616  if (Simulator::Now () >= station->m_nextStatsUpdate)
617  {
618  UpdateStats (station);
619  }
620 
621  if (station->m_nModes >= 1)
622  {
623  station->m_txrate = FindRate (station);
624  }
625  }
626  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
627 }
628 
629 void
630 MinstrelHtWifiManager::DoReportAmpduTxStatus (WifiRemoteStation *st, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus,
631  double rxSnr, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss)
632 {
633  NS_LOG_FUNCTION (this << st << +nSuccessfulMpdus << +nFailedMpdus << rxSnr << dataSnr << dataChannelWidth << +dataNss);
634  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
635 
636  CheckInit (station);
637  if (!station->m_initialized)
638  {
639  return;
640  }
641 
642  NS_ASSERT_MSG (station->m_isHt, "A-MPDU Tx Status called but no HT or VHT supported.");
643 
644  NS_LOG_DEBUG ("DoReportAmpduTxStatus. TxRate=" << station->m_txrate << " SuccMpdus=" <<
645  +nSuccessfulMpdus << " FailedMpdus=" << +nFailedMpdus);
646 
647  station->m_ampduPacketCount++;
648  station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
649 
650  UpdatePacketCounters (station, nSuccessfulMpdus, nFailedMpdus);
651 
652  uint8_t rateId = GetRateId (station->m_txrate);
653  uint8_t groupId = GetGroupId (station->m_txrate);
654  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
655  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt += nSuccessfulMpdus + nFailedMpdus;
656 
657  if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries (station))
658  {
659  // We do not receive a BlockAck. The entire AMPDU fail.
660  UpdateRate (station);
661  }
662  else
663  {
664  station->m_isSampling = false;
665  station->m_sampleDeferred = false;
666 
667  UpdateRetry (station);
668  if (Simulator::Now () >= station->m_nextStatsUpdate)
669  {
670  UpdateStats (station);
671  }
672 
673  if (station->m_nModes >= 1)
674  {
675  station->m_txrate = FindRate (station);
676  }
677  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
678  }
679 }
680 
681 void
683 {
684  NS_LOG_FUNCTION (this << station);
685 
707  CheckInit (station);
708  if (!station->m_initialized)
709  {
710  return;
711  }
712  station->m_longRetry++;
713 
717  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
718  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
719  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
720  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
721  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
722  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
723 
725  if (!station->m_isSampling)
726  {
728  if (station->m_longRetry < station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
729  {
730  NS_LOG_DEBUG ("Not Sampling; use the same rate again");
731  station->m_txrate = station->m_maxTpRate;
732  }
733 
735  else if (station->m_longRetry < ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
736  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
737  {
738  NS_LOG_DEBUG ("Not Sampling; use the Max TP2");
739  station->m_txrate = station->m_maxTpRate2;
740  }
741 
743  else if (station->m_longRetry <= ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
744  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
745  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
746  {
747  NS_LOG_DEBUG ("Not Sampling; use Max Prob");
748  station->m_txrate = station->m_maxProbRate;
749  }
750  else
751  {
752  NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
753  }
754  }
755 
757  else
758  {
761  if (station->m_longRetry < 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
762  {
763  NS_LOG_DEBUG ("Sampling use the MaxTP rate");
764  station->m_txrate = station->m_maxTpRate2;
765  }
766 
768  else if (station->m_longRetry <= 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
769  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
770  {
771  NS_LOG_DEBUG ("Sampling use the MaxProb rate");
772  station->m_txrate = station->m_maxProbRate;
773  }
774  else
775  {
776  NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
777  }
778  }
779  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
780 }
781 
782 void
784 {
785  NS_LOG_FUNCTION (this << station);
786  station->m_shortRetry = 0;
787  station->m_longRetry = 0;
788 }
789 
790 void
791 MinstrelHtWifiManager::UpdatePacketCounters (MinstrelHtWifiRemoteStation *station, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus)
792 {
793  NS_LOG_FUNCTION (this << station << +nSuccessfulMpdus << +nFailedMpdus);
794 
795  station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
796  if (station->m_isSampling)
797  {
798  station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
799  }
800  if (station->m_totalPacketsCount == ~0)
801  {
802  station->m_samplePacketsCount = 0;
803  station->m_totalPacketsCount = 0;
804  }
805 
806  if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
807  {
808  station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
809  station->m_sampleTries = 1;
810  station->m_sampleCount--;
811  }
812 }
813 
816 {
817  NS_LOG_FUNCTION (this << st);
818  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
819 
820  if (!station->m_initialized)
821  {
822  CheckInit (station);
823  }
824 
825  if (!station->m_isHt)
826  {
827  WifiTxVector vector = m_legacyManager->GetDataTxVector (station);
828  uint64_t dataRate = vector.GetMode ().GetDataRate (vector);
829  if (m_currentRate != dataRate && !station->m_isSampling)
830  {
831  NS_LOG_DEBUG ("New datarate: " << dataRate);
832  m_currentRate = dataRate;
833  }
834  return vector;
835  }
836  else
837  {
838  NS_LOG_DEBUG ("DoGetDataMode m_txrate= " << station->m_txrate);
839 
840  uint8_t rateId = GetRateId (station->m_txrate);
841  uint8_t groupId = GetGroupId (station->m_txrate);
842  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
843 
844  NS_LOG_DEBUG ("DoGetDataMode rateId= " << +rateId << " groupId= " << +groupId << " mode= " << GetMcsSupported (station, mcsIndex));
845 
846  McsGroup group = m_minstrelGroups[groupId];
847 
848  // Check consistency of rate selected.
849  if ((group.sgi && !GetShortGuardIntervalSupported (station)) || group.chWidth > GetChannelWidth (station) || group.streams > GetNumberOfSupportedStreams (station))
850  {
851  NS_FATAL_ERROR ("Inconsistent group selected. Group: (" << +group.streams <<
852  "," << +group.sgi << "," << group.chWidth << ")" <<
853  " Station capabilities: (" << GetNumberOfSupportedStreams (station) <<
854  "," << GetShortGuardIntervalSupported (station) << "," << GetChannelWidth (station) << ")");
855  }
856  WifiMode mode = GetMcsSupported (station, mcsIndex);
857  uint64_t dataRate = mode.GetDataRate (group.chWidth, group.sgi ? 400 : 800, group.streams);
858  if (m_currentRate != dataRate && !station->m_isSampling)
859  {
860  NS_LOG_DEBUG ("New datarate: " << dataRate);
861  m_currentRate = dataRate;
862  }
864  }
865 }
866 
869 {
870  NS_LOG_FUNCTION (this << st);
871  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
872 
873  if (!station->m_initialized)
874  {
875  CheckInit (station);
876  }
877 
878  if (!station->m_isHt)
879  {
880  return m_legacyManager->GetRtsTxVector (station);
881  }
882  else
883  {
884  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
885 
886  /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
887  * When supported, decision of using HT has to follow rules in Section 9.7.6 from 802.11-2012.
888  * From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is carried in a
889  * non-HT PPDU shall be transmitted by the STA using a rate no higher than the highest
890  * rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
891  * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
892  * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
893  * these conditions, the control frame shall be transmitted at a rate no higher than the
894  * highest mandatory rate of the attached PHY that is less than or equal to the rate
895  * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
896  * directed to the same receiving STA."
897  */
898 
899  // As we are in Minstrel HT, assume the last rate was an HT rate.
900  uint8_t rateId = GetRateId (station->m_txrate);
901  uint8_t groupId = GetGroupId (station->m_txrate);
902  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
903 
904  WifiMode lastRate = GetMcsSupported (station, mcsIndex);
905  uint64_t lastDataRate = lastRate.GetNonHtReferenceRate ();
906  uint8_t nBasicRates = GetNBasicModes ();
907 
908  WifiMode rtsRate;
909  bool rateFound = false;
910 
911  for (uint8_t i = 0; i < nBasicRates; i++)
912  {
913  uint64_t rate = GetBasicMode (i).GetDataRate (20);
914  if (rate <= lastDataRate)
915  {
916  rtsRate = GetBasicMode (i);
917  rateFound = true;
918  }
919  }
920 
921  if (!rateFound)
922  {
923  Ptr<WifiPhy> phy = GetPhy ();
924  uint8_t nSupportRates = phy->GetNModes ();
925  for (uint8_t i = 0; i < nSupportRates; i++)
926  {
927  uint64_t rate = phy->GetMode (i).GetDataRate (20);
928  if (rate <= lastDataRate)
929  {
930  rtsRate = phy->GetMode (i);
931  rateFound = true;
932  }
933  }
934  }
935 
936  NS_ASSERT (rateFound);
937 
939  800, 1, 1, 0, GetChannelWidthForTransmission (rtsRate, GetChannelWidth (station)), GetAggregation (station), false);
940  }
941 }
942 
943 bool
945 {
946  NS_LOG_FUNCTION (this << st << packet << normally);
947 
948  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
949 
950  CheckInit (station);
951  if (!station->m_initialized)
952  {
953  return normally;
954  }
955 
956  uint32_t maxRetries;
957 
958  if (!station->m_isHt)
959  {
960  maxRetries = m_legacyManager->CountRetries (station);
961  }
962  else
963  {
964  maxRetries = CountRetries (station);
965  }
966 
967  if (station->m_longRetry >= maxRetries)
968  {
969  NS_LOG_DEBUG ("No re-transmission allowed. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
970  return false;
971  }
972  else
973  {
974  NS_LOG_DEBUG ("Re-transmit. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
975  return true;
976  }
977 }
978 
979 uint32_t
981 {
982  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
983  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
984  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
985  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
986  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
987  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
988 
989  if (!station->m_isSampling)
990  {
991  return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
992  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
993  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
994  }
995  else
996  {
997  return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
998  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
999  }
1000 }
1001 
1002 uint16_t
1004 {
1005  NS_LOG_FUNCTION (this << station);
1006  uint8_t sampleGroup = station->m_sampleGroup;
1007  uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1008  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1009  uint8_t sampleIndex = station->m_sampleTable[index][col];
1010  uint16_t rateIndex = GetIndex (sampleGroup, sampleIndex);
1011  NS_LOG_DEBUG ("Next Sample is " << rateIndex);
1012  SetNextSample (station); //Calculate the next sample rate.
1013  return rateIndex;
1014 }
1015 
1016 void
1018 {
1019  NS_LOG_FUNCTION (this << station);
1020  do
1021  {
1022  station->m_sampleGroup++;
1023  station->m_sampleGroup %= m_numGroups;
1024  }
1025  while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1026 
1027  station->m_groupsTable[station->m_sampleGroup].m_index++;
1028 
1029  uint8_t sampleGroup = station->m_sampleGroup;
1030  uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1031  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1032 
1033  if (index >= m_numRates)
1034  {
1035  station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1036  station->m_groupsTable[station->m_sampleGroup].m_col++;
1037  if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1038  {
1039  station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1040  }
1041  index = station->m_groupsTable[station->m_sampleGroup].m_index;
1042  col = station->m_groupsTable[sampleGroup].m_col;
1043  }
1044  NS_LOG_DEBUG ("New sample set: group= " << +sampleGroup << " index= " << +station->m_sampleTable[index][col]);
1045 }
1046 
1047 uint16_t
1049 {
1050  NS_LOG_FUNCTION (this << station);
1051  NS_LOG_DEBUG ("FindRate packet=" << station->m_totalPacketsCount);
1052 
1053  if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1054  {
1055  return station->m_maxTpRate;
1056  }
1057 
1058  // If we have waited enough, then sample.
1059  if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1060  {
1061  //SAMPLING
1062  NS_LOG_DEBUG ("Obtaining a sampling rate");
1064  uint16_t sampleIdx = GetNextSample (station);
1065  NS_LOG_DEBUG ("Sampling rate = " << sampleIdx);
1066 
1067  //Evaluate if the sampling rate selected should be used.
1068  uint8_t sampleGroupId = GetGroupId (sampleIdx);
1069  uint8_t sampleRateId = GetRateId (sampleIdx);
1070 
1071  // If the rate selected is not supported, then don't sample.
1072  if (station->m_groupsTable[sampleGroupId].m_supported && station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1073  {
1081  HtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1082 
1083  NS_LOG_DEBUG ("Use sample rate? MaxTpRate= " << station->m_maxTpRate << " CurrentRate= " << station->m_txrate <<
1084  " SampleRate= " << sampleIdx << " SampleProb= " << sampleRateInfo.ewmaProb);
1085 
1086  if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2
1087  && sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1088  {
1089 
1095  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1096  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1097  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1098  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1099  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
1100 
1101  uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1102  uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1103 
1104  Time sampleDuration = sampleRateInfo.perfectTxTime;
1105  Time maxTp2Duration = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1106  Time maxProbDuration = station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].perfectTxTime;
1107 
1108  NS_LOG_DEBUG ("Use sample rate? SampleDuration= " << sampleDuration << " maxTp2Duration= " << maxTp2Duration <<
1109  " maxProbDuration= " << maxProbDuration << " sampleStreams= " << +sampleStreams <<
1110  " maxTpStreams= " << +maxTpStreams);
1111  if (sampleDuration < maxTp2Duration || (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1112  {
1114  station->m_isSampling = true;
1115 
1117  station->m_sampleRate = sampleIdx;
1118 
1119  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1120  station->m_sampleTries--;
1121  return sampleIdx;
1122  }
1123  else
1124  {
1125  station->m_numSamplesSlow++;
1126  if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1127  {
1129  station->m_isSampling = true;
1130 
1132  station->m_sampleRate = sampleIdx;
1133 
1134  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1135  station->m_sampleTries--;
1136  return sampleIdx;
1137  }
1138  }
1139  }
1140  }
1141  }
1142  if (station->m_sampleWait > 0)
1143  {
1144  station->m_sampleWait--;
1145  }
1146 
1148 
1149  NS_LOG_DEBUG ("FindRate " << "maxTpRrate=" << station->m_maxTpRate);
1150  return station->m_maxTpRate;
1151 }
1152 void
1154 {
1155  NS_LOG_FUNCTION (this << station);
1156 
1158 
1159  station->m_numSamplesSlow = 0;
1160  station->m_sampleCount = 0;
1161 
1162  double tempProb;
1163 
1164  if (station->m_ampduPacketCount > 0)
1165  {
1166  uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1167  station->m_avgAmpduLen = ( newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel) ) / 100;
1168  station->m_ampduLen = 0;
1169  station->m_ampduPacketCount = 0;
1170  }
1171 
1172  /* Initialize global rate indexes */
1173  station->m_maxTpRate = GetLowestIndex (station);
1174  station->m_maxTpRate2 = GetLowestIndex (station);
1175  station->m_maxProbRate = GetLowestIndex (station);
1176 
1178  for (uint8_t j = 0; j < m_numGroups; j++)
1179  {
1180  if (station->m_groupsTable[j].m_supported)
1181  {
1182  station->m_sampleCount++;
1183 
1184  /* (re)Initialize group rate indexes */
1185  station->m_groupsTable[j].m_maxTpRate = GetLowestIndex (station, j);
1186  station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex (station, j);
1187  station->m_groupsTable[j].m_maxProbRate = GetLowestIndex (station, j);
1188 
1189  for (uint8_t i = 0; i < m_numRates; i++)
1190  {
1191  if (station->m_groupsTable[j].m_ratesTable[i].supported)
1192  {
1193  station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1194 
1195  NS_LOG_DEBUG (+i << " " << GetMcsSupported (station, station->m_groupsTable[j].m_ratesTable[i].mcsIndex) <<
1196  "\t attempt=" << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt <<
1197  "\t success=" << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1198 
1200  if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1201  {
1202  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1207  tempProb = (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) / station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1208 
1210  station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1211 
1212  if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1213  {
1214  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1215  }
1216  else
1217  {
1218  station->m_groupsTable[j].m_ratesTable[i].ewmsdProb = CalculateEwmsd (station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1219  tempProb, station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1220  m_ewmaLevel);
1222  tempProb = (tempProb * (100 - m_ewmaLevel) + station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) / 100;
1223  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1224  }
1225 
1226  station->m_groupsTable[j].m_ratesTable[i].throughput = CalculateThroughput (station, j, i, tempProb);
1227 
1228  station->m_groupsTable[j].m_ratesTable[i].successHist += station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1229  station->m_groupsTable[j].m_ratesTable[i].attemptHist += station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1230  }
1231  else
1232  {
1233  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1234  }
1235 
1237  station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess = station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1238  station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt = station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1239  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1240  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1241 
1242  if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1243  {
1244  SetBestStationThRates (station, GetIndex (j, i));
1245  SetBestProbabilityRate (station, GetIndex (j, i));
1246  }
1247 
1248  }
1249  }
1250  }
1251  }
1252 
1253  //Try to sample all available rates during each interval.
1254  station->m_sampleCount *= 8;
1255 
1256  //Recalculate retries for the rates selected.
1257  CalculateRetransmits (station, station->m_maxTpRate);
1258  CalculateRetransmits (station, station->m_maxTpRate2);
1259  CalculateRetransmits (station, station->m_maxProbRate);
1260 
1261  NS_LOG_DEBUG ("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2 << "\nmax prob=" << station->m_maxProbRate);
1262  if (m_printStats)
1263  {
1264  PrintTable (station);
1265  }
1266 }
1267 
1268 double
1269 MinstrelHtWifiManager::CalculateThroughput (MinstrelHtWifiRemoteStation *station, uint8_t groupId, uint8_t rateId, double ewmaProb)
1270 {
1276  if (ewmaProb < 10)
1277  {
1278  return 0;
1279  }
1280  else
1281  {
1286  Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1287  if (ewmaProb > 90)
1288  {
1289  return 90 / txTime.GetSeconds ();
1290  }
1291  else
1292  {
1293  return ewmaProb / txTime.GetSeconds ();
1294  }
1295  }
1296 }
1297 
1298 void
1300 {
1301  GroupInfo *group;
1302  HtRateInfo rate;
1303  uint8_t tmpGroupId, tmpRateId;
1304  double tmpTh, tmpProb;
1305  uint8_t groupId, rateId;
1306  double currentTh;
1307  // maximum group probability (GP) variables
1308  uint8_t maxGPGroupId, maxGPRateId;
1309  double maxGPTh;
1310 
1311  groupId = GetGroupId (index);
1312  rateId = GetRateId (index);
1313  group = &station->m_groupsTable[groupId];
1314  rate = group->m_ratesTable[rateId];
1315 
1316  tmpGroupId = GetGroupId (station->m_maxProbRate);
1317  tmpRateId = GetRateId (station->m_maxProbRate);
1318  tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1319  tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1320 
1321  if (rate.ewmaProb > 75)
1322  {
1323  currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1324  if (currentTh > tmpTh)
1325  {
1326  station->m_maxProbRate = index;
1327  }
1328 
1329  maxGPGroupId = GetGroupId (group->m_maxProbRate);
1330  maxGPRateId = GetRateId (group->m_maxProbRate);
1331  maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1332 
1333  if (currentTh > maxGPTh)
1334  {
1335  group->m_maxProbRate = index;
1336  }
1337  }
1338  else
1339  {
1340  if (rate.ewmaProb > tmpProb)
1341  {
1342  station->m_maxProbRate = index;
1343  }
1344  maxGPRateId = GetRateId (group->m_maxProbRate);
1345  if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1346  {
1347  group->m_maxProbRate = index;
1348  }
1349  }
1350 }
1351 
1352 /*
1353  * Find & sort topmost throughput rates
1354  *
1355  * If multiple rates provide equal throughput the sorting is based on their
1356  * current success probability. Higher success probability is preferred among
1357  * MCS groups.
1358  */
1359 void
1361 {
1362  uint8_t groupId, rateId;
1363  double th, prob;
1364  uint8_t maxTpGroupId, maxTpRateId;
1365  uint8_t maxTp2GroupId, maxTp2RateId;
1366  double maxTpTh, maxTpProb;
1367  double maxTp2Th, maxTp2Prob;
1368 
1369  groupId = GetGroupId (index);
1370  rateId = GetRateId (index);
1371  prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1372  th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1373 
1374  maxTpGroupId = GetGroupId (station->m_maxTpRate);
1375  maxTpRateId = GetRateId (station->m_maxTpRate);
1376  maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1377  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1378 
1379  maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1380  maxTp2RateId = GetRateId (station->m_maxTpRate2);
1381  maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1382  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1383 
1384  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1385  {
1386  station->m_maxTpRate2 = station->m_maxTpRate;
1387  station->m_maxTpRate = index;
1388  }
1389  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1390  {
1391  station->m_maxTpRate2 = index;
1392  }
1393 
1394  //Find best rates per group
1395 
1396  GroupInfo *group = &station->m_groupsTable[groupId];
1397  maxTpGroupId = GetGroupId (group->m_maxTpRate);
1398  maxTpRateId = GetRateId (group->m_maxTpRate);
1399  maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1400  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1401 
1402  maxTp2GroupId = GetGroupId (group->m_maxTpRate2);
1403  maxTp2RateId = GetRateId (group->m_maxTpRate2);
1404  maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1405  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1406 
1407  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1408  {
1409  group->m_maxTpRate2 = group->m_maxTpRate;
1410  group->m_maxTpRate = index;
1411  }
1412  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1413  {
1414  group->m_maxTpRate2 = index;
1415  }
1416 }
1417 
1418 void
1420 {
1421  NS_LOG_FUNCTION (this << station);
1422 
1423  station->m_groupsTable = McsGroupData (m_numGroups);
1424 
1428  NS_LOG_DEBUG ("Supported groups by station:");
1429  for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1430  {
1431  if (m_minstrelGroups[groupId].isSupported)
1432  {
1433  station->m_groupsTable[groupId].m_supported = false;
1434  if (!(!GetVhtSupported (station) && m_minstrelGroups[groupId].isVht)
1435  && (m_minstrelGroups[groupId].isVht || !GetVhtSupported (station) || !m_useVhtOnly)
1436  && !(!GetShortGuardIntervalSupported (station) && m_minstrelGroups[groupId].sgi)
1437  && (GetChannelWidth (station) >= m_minstrelGroups[groupId].chWidth)
1438  && (GetNumberOfSupportedStreams (station) >= m_minstrelGroups[groupId].streams))
1439  {
1440  NS_LOG_DEBUG ("Group " << +groupId << ": (" << +m_minstrelGroups[groupId].streams <<
1441  "," << +m_minstrelGroups[groupId].sgi << "," << m_minstrelGroups[groupId].chWidth << ")");
1442 
1443  station->m_groupsTable[groupId].m_supported = true;
1444  station->m_groupsTable[groupId].m_col = 0;
1445  station->m_groupsTable[groupId].m_index = 0;
1446 
1447  station->m_groupsTable[groupId].m_ratesTable = HtMinstrelRate (m_numRates);
1448  for (uint8_t i = 0; i < m_numRates; i++)
1449  {
1450  station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1451  }
1452 
1453  // Initialize all modes supported by the remote station that belong to the current group.
1454  for (uint8_t i = 0; i < station->m_nModes; i++)
1455  {
1456  WifiMode mode = GetMcsSupported (station, i);
1457 
1460  uint8_t rateId = mode.GetMcsValue ();
1461  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1462  {
1463  rateId %= MAX_HT_GROUP_RATES;
1464  }
1465 
1466  if ((m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_VHT
1467  && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1468  || (!m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_HT
1469  && mode.GetMcsValue () < (m_minstrelGroups[groupId].streams * 8)
1470  && mode.GetMcsValue () >= ((m_minstrelGroups[groupId].streams - 1) * 8)))
1471  {
1472  NS_LOG_DEBUG ("Mode " << +i << ": " << mode << " isVht: " << m_minstrelGroups[groupId].isVht);
1473 
1474  station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1475  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex = i;
1476  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1477  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1478  station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1479  station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1480  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1481  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1482  station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1483  station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1484  station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1485  station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1486  station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
1487  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1488  station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1489  CalculateRetransmits (station, groupId, rateId);
1490  }
1491  }
1492  }
1493  }
1494  }
1495  SetNextSample (station);
1496  UpdateStats (station);
1497  station->m_txrate = FindRate (station);
1498 }
1499 
1500 void
1502 {
1503  NS_LOG_FUNCTION (this << station << index);
1504  uint8_t groupId = GetGroupId (index);
1505  uint8_t rateId = GetRateId (index);
1506  if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1507  {
1508  CalculateRetransmits (station, groupId, rateId);
1509  }
1510 }
1511 
1512 void
1514 {
1515  NS_LOG_FUNCTION (this << station << +groupId << +rateId);
1516 
1517  uint32_t cw = 15; // Is an approximation.
1518  uint32_t cwMax = 1023;
1519  Time cwTime, txTime, dataTxTime;
1520  Time slotTime = GetPhy ()->GetSlot ();
1521  Time ackTime = GetPhy ()->GetSifs () + GetPhy ()->GetBlockAckTxTime ();
1522 
1523  if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1524  {
1525  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1526  }
1527  else
1528  {
1529  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1530  station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1531 
1532  dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1533  GetMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) * (station->m_avgAmpduLen - 1);
1534 
1535  /* Contention time for first 2 tries */
1536  cwTime = (cw / 2) * slotTime;
1537  cw = Min ((cw + 1) * 2, cwMax);
1538  cwTime += (cw / 2) * slotTime;
1539  cw = Min ((cw + 1) * 2, cwMax);
1540 
1541  /* Total TX time for data and Contention after first 2 tries */
1542  txTime = cwTime + 2 * (dataTxTime + ackTime);
1543 
1544  /* See how many more tries we can fit inside segment size */
1545  do
1546  {
1547  /* Contention time for this try */
1548  cwTime = (cw / 2) * slotTime;
1549  cw = Min ((cw + 1) * 2, cwMax);
1550 
1551  /* Total TX time after this try */
1552  txTime += cwTime + ackTime + dataTxTime;
1553  }
1554  while ((txTime < MilliSeconds (6))
1555  && (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1556  }
1557 }
1558 
1559 double
1560 MinstrelHtWifiManager::CalculateEwmsd (double oldEwmsd, double currentProb, double ewmaProb, double weight)
1561 {
1562  double diff, incr, tmp;
1563 
1564  /* calculate exponential weighted moving variance */
1565  diff = currentProb - ewmaProb;
1566  incr = (100 - weight) * diff / 100;
1567  tmp = oldEwmsd * oldEwmsd;
1568  tmp = weight * (tmp + diff * incr) / 100;
1569 
1570  /* return standard deviation */
1571  return sqrt (tmp);
1572 }
1573 
1574 void
1576 {
1577  NS_LOG_FUNCTION (this << station);
1578  station->m_col = station->m_index = 0;
1579 
1580  //for off-setting to make rates fall between 0 and nModes
1581  uint8_t numSampleRates = m_numRates;
1582 
1583  uint16_t newIndex;
1584  for (uint8_t col = 0; col < m_nSampleCol; col++)
1585  {
1586  for (uint8_t i = 0; i < numSampleRates; i++ )
1587  {
1592  int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
1593  newIndex = (i + uv) % numSampleRates;
1594 
1595  //this loop is used for filling in other uninitialized places
1596  while (station->m_sampleTable[newIndex][col] != 0)
1597  {
1598  newIndex = (newIndex + 1) % m_numRates;
1599  }
1600  station->m_sampleTable[newIndex][col] = i;
1601  }
1602  }
1603 }
1604 
1605 void
1607 {
1608  if (!station->m_statsFile.is_open ())
1609  {
1610  std::ostringstream tmp;
1611  tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1612  station->m_statsFile.open (tmp.str ().c_str (), std::ios::out);
1613  }
1614 
1615  station->m_statsFile << " best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n" <<
1616  " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n";
1617  for (uint8_t i = 0; i < m_numGroups; i++)
1618  {
1619  StatsDump (station, i, station->m_statsFile);
1620  }
1621 
1622  station->m_statsFile << "\nTotal packet count:: ideal " << Max (0, station->m_totalPacketsCount - station->m_samplePacketsCount) <<
1623  " lookaround " << station->m_samplePacketsCount << "\n";
1624  station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen << "\n\n";
1625 
1626  station->m_statsFile.flush ();
1627 }
1628 
1629 void
1630 MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint8_t groupId, std::ofstream &of)
1631 {
1632  uint8_t numRates = m_numRates;
1633  McsGroup group = m_minstrelGroups[groupId];
1634  Time txTime;
1635  char giMode;
1636  if (group.sgi)
1637  {
1638  giMode = 'S';
1639  }
1640  else
1641  {
1642  giMode = 'L';
1643  }
1644  for (uint8_t i = 0; i < numRates; i++)
1645  {
1646  if (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[i].supported)
1647  {
1648  if (!group.isVht)
1649  {
1650  of << "HT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1651  }
1652  else
1653  {
1654  of << "VHT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1655  }
1656 
1657  uint16_t maxTpRate = station->m_maxTpRate;
1658  uint16_t maxTpRate2 = station->m_maxTpRate2;
1659  uint16_t maxProbRate = station->m_maxProbRate;
1660 
1661  uint16_t idx = GetIndex (groupId, i);
1662  if (idx == maxTpRate)
1663  {
1664  of << 'A';
1665  }
1666  else
1667  {
1668  of << ' ';
1669  }
1670  if (idx == maxTpRate2)
1671  {
1672  of << 'B';
1673  }
1674  else
1675  {
1676  of << ' ';
1677  }
1678  if (idx == maxProbRate)
1679  {
1680  of << 'P';
1681  }
1682  else
1683  {
1684  of << ' ';
1685  }
1686 
1687  if (!group.isVht)
1688  {
1689  of << std::setw (4) << " MCS" << (group.streams - 1) * 8 + i;
1690  }
1691  else
1692  {
1693  of << std::setw (7) << " MCS" << +i << "/" << (int) group.streams;
1694  }
1695 
1696  of << " " << std::setw (3) << +idx << " ";
1697 
1698  /* tx_time[rate(i)] in usec */
1699  txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
1700  of << std::setw (6) << txTime.GetMicroSeconds () << " ";
1701 
1702  of << std::setw (7) << CalculateThroughput (station, groupId, i, 100) / 100 << " " <<
1703  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100 << " " <<
1704  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb << " " <<
1705  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb << " " <<
1706  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].prob << " " <<
1707  std::setw (2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount << " " <<
1708  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " " <<
1709  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt << " " <<
1710  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " " <<
1711  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist << "\n";
1712  }
1713  }
1714 }
1715 uint16_t
1716 MinstrelHtWifiManager::GetIndex (uint8_t groupId, uint8_t rateId)
1717 {
1718  NS_LOG_FUNCTION (this << +groupId << +rateId);
1719  uint16_t index;
1720  index = groupId * m_numRates + rateId;
1721  return index;
1722 }
1723 
1724 uint8_t
1726 {
1727  NS_LOG_FUNCTION (this << index);
1728  uint8_t id;
1729  id = index % m_numRates;
1730  return id;
1731 }
1732 
1733 uint8_t
1735 {
1736  NS_LOG_FUNCTION (this << index);
1737  return index / m_numRates;
1738 }
1739 
1740 uint8_t
1741 MinstrelHtWifiManager::GetHtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1742 {
1743  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1744  return MAX_SUPPORTED_STREAMS * 2 * (chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
1745 }
1746 
1747 uint8_t
1748 MinstrelHtWifiManager::GetVhtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1749 {
1750  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1751  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;
1752 }
1753 
1754 uint16_t
1756 {
1757  NS_LOG_FUNCTION (this << station);
1758 
1759  uint8_t groupId = 0;
1760  uint8_t rateId = 0;
1761  while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
1762  {
1763  groupId++;
1764  }
1765  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1766  {
1767  rateId++;
1768  }
1769  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1770  return GetIndex (groupId, rateId);
1771 }
1772 
1773 uint16_t
1775 {
1776  NS_LOG_FUNCTION (this << station << +groupId);
1777 
1778  uint8_t rateId = 0;
1779  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1780  {
1781  rateId++;
1782  }
1783  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1784  return GetIndex (groupId, rateId);
1785 }
1786 
1789 {
1790  WifiModeList vhtMcsList;
1791  Ptr<WifiPhy> phy = GetPhy ();
1792  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1793  {
1794  WifiMode mode = phy->GetMcs (i);
1795  if (mode.GetModulationClass () == WIFI_MOD_CLASS_VHT)
1796  {
1797  vhtMcsList.push_back (mode);
1798  }
1799  }
1800  return vhtMcsList;
1801 }
1802 
1805 {
1806  WifiModeList htMcsList;
1807  Ptr<WifiPhy> phy = GetPhy ();
1808  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1809  {
1810  WifiMode mode = phy->GetMcs (i);
1811  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1812  {
1813  htMcsList.push_back (mode);
1814  }
1815  }
1816  return htMcsList;
1817 }
1818 
1819 } // 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
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.
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:1070
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
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...
void DoReportAmpduTxStatus(WifiRemoteStation *station, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus, double rxSnr, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss)
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
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:1124
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 DoReportDataOk(WifiRemoteStation *station, double ackSnr, WifiMode ackMode, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss)
This method is a pure virtual method that must be implemented by the sub-class.
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...
Time GetBlockAckTxTime(void) const
Return the estimated BlockAck TX time for this PHY.
Definition: wifi-phy.cc:983
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.
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:1125
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:195
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:2241
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)
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:947
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< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
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...
Time GetSlot(void) const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:959
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.
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:449
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.
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:2519
Time m_nextStatsUpdate
10 times every second