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",
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);
322  return phy->CalculateTxDuration (m_frameLength, txvector, phy->GetFrequency (), mpduType, 0);
323 }
324 
325 Time
327 {
328  NS_LOG_FUNCTION (this << +groupId << mode);
329  auto it = m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.find (mode);
330  NS_ASSERT (it != m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.end ());
331  return it->second;
332 }
333 
334 void
336 {
337  NS_LOG_FUNCTION (this << +groupId << mode << t);
338  m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.insert (std::make_pair (mode, t));
339 }
340 
341 Time
342 MinstrelHtWifiManager::GetMpduTxTime (uint8_t groupId, WifiMode mode) const
343 {
344  NS_LOG_FUNCTION (this << +groupId << mode);
345  auto it = m_minstrelGroups[groupId].ratesTxTimeTable.find (mode);
346  NS_ASSERT (it != m_minstrelGroups[groupId].ratesTxTimeTable.end ());
347  return it->second;
348 }
349 
350 void
352 {
353  NS_LOG_FUNCTION (this << +groupId << mode << t);
354  m_minstrelGroups[groupId].ratesTxTimeTable.insert (std::make_pair (mode, t));
355 }
356 
359 {
360  NS_LOG_FUNCTION (this);
362 
363  // Initialize variables common to both stations.
365  station->m_col = 0;
366  station->m_index = 0;
367  station->m_maxTpRate = 0;
368  station->m_maxTpRate2 = 0;
369  station->m_maxProbRate = 0;
370  station->m_nModes = 0;
371  station->m_totalPacketsCount = 0;
372  station->m_samplePacketsCount = 0;
373  station->m_isSampling = false;
374  station->m_sampleRate = 0;
375  station->m_sampleDeferred = false;
376  station->m_shortRetry = 0;
377  station->m_longRetry = 0;
378  station->m_txrate = 0;
379  station->m_initialized = false;
380 
381  // Variables specific to HT station
382  station->m_sampleGroup = 0;
383  station->m_numSamplesSlow = 0;
384  station->m_sampleCount = 16;
385  station->m_sampleWait = 0;
386  station->m_sampleTries = 4;
387 
388  station->m_avgAmpduLen = 1;
389  station->m_ampduLen = 0;
390  station->m_ampduPacketCount = 0;
391 
392  // If the device supports HT
393  if (GetHtSupported ())
394  {
399  station->m_isHt = true;
400  }
401  // Use the variable in the station to indicate that the device do not support HT
402  else
403  {
404  station->m_isHt = false;
405  }
406 
407  return station;
408 }
409 
410 void
412 {
413  NS_LOG_FUNCTION (this << station);
414  // Note: we appear to be doing late initialization of the table
415  // to make sure that the set of supported rates has been initialized
416  // before we perform our own initialization.
417  if (!station->m_initialized)
418  {
425  if (!GetHtSupported (station))
426  {
427  NS_LOG_INFO ("non-HT station " << station);
428  station->m_isHt = false;
429  // We will use non-HT minstrel for this station. Initialize the manager.
430  m_legacyManager->SetAttribute ("UpdateStatistics", TimeValue (m_updateStats));
431  m_legacyManager->SetAttribute ("LookAroundRate", UintegerValue (m_lookAroundRate));
432  m_legacyManager->SetAttribute ("EWMA", UintegerValue (m_ewmaLevel));
433  m_legacyManager->SetAttribute ("SampleColumn", UintegerValue (m_nSampleCol));
434  m_legacyManager->SetAttribute ("PacketLength", UintegerValue (m_frameLength));
435  m_legacyManager->SetAttribute ("PrintStats", BooleanValue (m_printStats));
436  m_legacyManager->CheckInit (station);
437  }
438  else
439  {
440  NS_LOG_DEBUG ("HT station " << station);
441  station->m_isHt = true;
442  station->m_nModes = GetNMcsSupported (station);
443  station->m_minstrelTable = MinstrelRate (station->m_nModes);
444  station->m_sampleTable = SampleRate (m_numRates, std::vector<uint8_t> (m_nSampleCol));
445  InitSampleTable (station);
446  RateInit (station);
447  station->m_initialized = true;
448  }
449  }
450 }
451 
452 void
454 {
455  NS_LOG_FUNCTION (this << st);
456  NS_LOG_DEBUG ("DoReportRxOk m_txrate=" << ((MinstrelHtWifiRemoteStation *)st)->m_txrate);
457 }
458 
459 void
461 {
462  NS_LOG_FUNCTION (this << st);
464  CheckInit (station);
465  if (!station->m_initialized)
466  {
467  return;
468  }
469  NS_LOG_DEBUG ("DoReportRtsFailed m_txrate = " << station->m_txrate);
470  station->m_shortRetry++;
471 }
472 
473 void
474 MinstrelHtWifiManager::DoReportRtsOk (WifiRemoteStation *st, double ctsSnr, WifiMode ctsMode, double rtsSnr)
475 {
476  NS_LOG_FUNCTION (this << st);
477 }
478 
479 void
481 {
482  NS_LOG_FUNCTION (this << st);
484  NS_LOG_DEBUG ("Final RTS failed");
485  CheckInit (station);
486  if (!station->m_initialized)
487  {
488  return;
489  }
490  UpdateRetry (station);
491 }
492 
493 void
495 {
496  NS_LOG_FUNCTION (this << st);
498 
499  CheckInit (station);
500  if (!station->m_initialized)
501  {
502  return;
503  }
504 
505  NS_LOG_DEBUG ("DoReportDataFailed " << station << "\t rate " << station->m_txrate << "\tlongRetry \t" << station->m_longRetry);
506 
507  if (!station->m_isHt)
508  {
509  m_legacyManager->UpdateRate (station);
510  }
511  else
512  {
513  uint8_t rateId = GetRateId (station->m_txrate);
514  uint8_t groupId = GetGroupId (station->m_txrate);
515  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++; // Increment the attempts counter for the rate used.
516  UpdateRate (station);
517  }
518 }
519 
520 void
521 MinstrelHtWifiManager::DoReportDataOk (WifiRemoteStation *st, double ackSnr, WifiMode ackMode, double dataSnr)
522 {
523  NS_LOG_FUNCTION (this << st << ackSnr << ackMode << dataSnr);
525 
526  CheckInit (station);
527  if (!station->m_initialized)
528  {
529  return;
530  }
531 
532  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).");
533 
534  if (!station->m_isHt)
535  {
536  station->m_minstrelTable[station->m_txrate].numRateSuccess++;
537  station->m_minstrelTable[station->m_txrate].numRateAttempt++;
538 
539  m_legacyManager->UpdatePacketCounters (station);
540 
541  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).");
542 
543  UpdateRetry (station);
544  m_legacyManager->UpdateStats (station);
545 
546  if (station->m_nModes >= 1)
547  {
548  station->m_txrate = m_legacyManager->FindRate (station);
549  }
550  }
551  else
552  {
553  uint8_t rateId = GetRateId (station->m_txrate);
554  uint8_t groupId = GetGroupId (station->m_txrate);
555  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
556  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
557 
558  UpdatePacketCounters (station, 1, 0);
559 
560  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).");
561 
562  station->m_isSampling = false;
563  station->m_sampleDeferred = false;
564 
565  UpdateRetry (station);
566  if (Simulator::Now () >= station->m_nextStatsUpdate)
567  {
568  UpdateStats (station);
569  }
570 
571  if (station->m_nModes >= 1)
572  {
573  station->m_txrate = FindRate (station);
574  }
575  }
576 
577  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate );
578 }
579 
580 void
582 {
583  NS_LOG_FUNCTION (this << st);
585 
586  CheckInit (station);
587  if (!station->m_initialized)
588  {
589  return;
590  }
591 
592  NS_LOG_DEBUG ("DoReportFinalDataFailed - TxRate=" << station->m_txrate);
593 
594  if (!station->m_isHt)
595  {
596  m_legacyManager->UpdatePacketCounters (station);
597 
598  UpdateRetry (station);
599 
600  m_legacyManager->UpdateStats (station);
601  if (station->m_nModes >= 1)
602  {
603  station->m_txrate = m_legacyManager->FindRate (station);
604  }
605  }
606  else
607  {
608  UpdatePacketCounters (station, 0, 1);
609 
610  station->m_isSampling = false;
611  station->m_sampleDeferred = false;
612 
613  UpdateRetry (station);
614  if (Simulator::Now () >= station->m_nextStatsUpdate)
615  {
616  UpdateStats (station);
617  }
618 
619  if (station->m_nModes >= 1)
620  {
621  station->m_txrate = FindRate (station);
622  }
623  }
624  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
625 }
626 
627 void
628 MinstrelHtWifiManager::DoReportAmpduTxStatus (WifiRemoteStation *st, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus, double rxSnr, double dataSnr)
629 {
630  NS_LOG_FUNCTION (this << st << +nSuccessfulMpdus << +nFailedMpdus << rxSnr << dataSnr);
632 
633  CheckInit (station);
634  if (!station->m_initialized)
635  {
636  return;
637  }
638 
639  NS_ASSERT_MSG (station->m_isHt, "A-MPDU Tx Status called but no HT or VHT supported.");
640 
641  NS_LOG_DEBUG ("DoReportAmpduTxStatus. TxRate=" << station->m_txrate << " SuccMpdus= " <<
642  +nSuccessfulMpdus << " FailedMpdus= " << +nFailedMpdus);
643 
644  station->m_ampduPacketCount++;
645  station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
646 
647  UpdatePacketCounters (station, nSuccessfulMpdus, nFailedMpdus);
648 
649  uint8_t rateId = GetRateId (station->m_txrate);
650  uint8_t groupId = GetGroupId (station->m_txrate);
651  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
652  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt += nSuccessfulMpdus + nFailedMpdus;
653 
654  if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries (station))
655  {
656  // We do not receive a BlockAck. The entire AMPDU fail.
657  UpdateRate (station);
658  }
659  else
660  {
661  station->m_isSampling = false;
662  station->m_sampleDeferred = false;
663 
664  UpdateRetry (station);
665  if (Simulator::Now () >= station->m_nextStatsUpdate)
666  {
667  UpdateStats (station);
668  }
669 
670  if (station->m_nModes >= 1)
671  {
672  station->m_txrate = FindRate (station);
673  }
674  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
675  }
676 }
677 
678 void
680 {
681  NS_LOG_FUNCTION (this << station);
682 
704  CheckInit (station);
705  if (!station->m_initialized)
706  {
707  return;
708  }
709  station->m_longRetry++;
710 
714  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
715  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
716  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
717  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
718  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
719  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
720 
722  if (!station->m_isSampling)
723  {
725  if (station->m_longRetry < station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
726  {
727  NS_LOG_DEBUG ("Not Sampling; use the same rate again");
728  station->m_txrate = station->m_maxTpRate;
729  }
730 
732  else if (station->m_longRetry < ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
733  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
734  {
735  NS_LOG_DEBUG ("Not Sampling; use the Max TP2");
736  station->m_txrate = station->m_maxTpRate2;
737  }
738 
740  else if (station->m_longRetry <= ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
741  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
742  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
743  {
744  NS_LOG_DEBUG ("Not Sampling; use Max Prob");
745  station->m_txrate = station->m_maxProbRate;
746  }
747  else
748  {
749  NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
750  }
751  }
752 
754  else
755  {
758  if (station->m_longRetry < 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
759  {
760  NS_LOG_DEBUG ("Sampling use the MaxTP rate");
761  station->m_txrate = station->m_maxTpRate2;
762  }
763 
765  else if (station->m_longRetry <= 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
766  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
767  {
768  NS_LOG_DEBUG ("Sampling use the MaxProb rate");
769  station->m_txrate = station->m_maxProbRate;
770  }
771  else
772  {
773  NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
774  }
775  }
776  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
777 }
778 
779 void
781 {
782  NS_LOG_FUNCTION (this << station);
783  station->m_shortRetry = 0;
784  station->m_longRetry = 0;
785 }
786 
787 void
788 MinstrelHtWifiManager::UpdatePacketCounters (MinstrelHtWifiRemoteStation *station, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus)
789 {
790  NS_LOG_FUNCTION (this << station << +nSuccessfulMpdus << +nFailedMpdus);
791 
792  station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
793  if (station->m_isSampling)
794  {
795  station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
796  }
797  if (station->m_totalPacketsCount == ~0)
798  {
799  station->m_samplePacketsCount = 0;
800  station->m_totalPacketsCount = 0;
801  }
802 
803  if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
804  {
805  station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
806  station->m_sampleTries = 1;
807  station->m_sampleCount--;
808  }
809 }
810 
813 {
814  NS_LOG_FUNCTION (this << st);
816 
817  if (!station->m_initialized)
818  {
819  CheckInit (station);
820  }
821 
822  if (!station->m_isHt)
823  {
824  WifiTxVector vector = m_legacyManager->GetDataTxVector (station);
825  uint64_t dataRate = vector.GetMode ().GetDataRate (vector);
826  if (m_currentRate != dataRate && !station->m_isSampling)
827  {
828  NS_LOG_DEBUG ("New datarate: " << dataRate);
829  m_currentRate = dataRate;
830  }
831  return vector;
832  }
833  else
834  {
835  NS_LOG_DEBUG ("DoGetDataMode m_txrate= " << station->m_txrate);
836 
837  uint8_t rateId = GetRateId (station->m_txrate);
838  uint8_t groupId = GetGroupId (station->m_txrate);
839  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
840 
841  NS_LOG_DEBUG ("DoGetDataMode rateId= " << +rateId << " groupId= " << +groupId << " mode= " << GetMcsSupported (station, mcsIndex));
842 
843  McsGroup group = m_minstrelGroups[groupId];
844 
845  // Check consistency of rate selected.
846  if ((group.sgi && !GetShortGuardIntervalSupported (station)) || group.chWidth > GetChannelWidth (station) || group.streams > GetNumberOfSupportedStreams (station))
847  {
848  NS_FATAL_ERROR ("Inconsistent group selected. Group: (" << +group.streams <<
849  "," << +group.sgi << "," << group.chWidth << ")" <<
850  " Station capabilities: (" << GetNumberOfSupportedStreams (station) <<
851  "," << GetShortGuardIntervalSupported (station) << "," << GetChannelWidth (station) << ")");
852  }
853  WifiMode mode = GetMcsSupported (station, mcsIndex);
854  uint64_t dataRate = mode.GetDataRate (group.chWidth, group.sgi ? 400 : 800, group.streams);
855  if (m_currentRate != dataRate && !station->m_isSampling)
856  {
857  NS_LOG_DEBUG ("New datarate: " << dataRate);
858  m_currentRate = dataRate;
859  }
861  }
862 }
863 
866 {
867  NS_LOG_FUNCTION (this << st);
869 
870  if (!station->m_initialized)
871  {
872  CheckInit (station);
873  }
874 
875  if (!station->m_isHt)
876  {
877  return m_legacyManager->GetRtsTxVector (station);
878  }
879  else
880  {
881  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
882 
883  /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
884  * When supported, decision of using HT has to follow rules in Section 9.7.6 from 802.11-2012.
885  * From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is carried in a
886  * non-HT PPDU shall be transmitted by the STA using a rate no higher than the highest
887  * rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
888  * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
889  * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
890  * these conditions, the control frame shall be transmitted at a rate no higher than the
891  * highest mandatory rate of the attached PHY that is less than or equal to the rate
892  * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
893  * directed to the same receiving STA."
894  */
895 
896  // As we are in Minstrel HT, assume the last rate was an HT rate.
897  uint8_t rateId = GetRateId (station->m_txrate);
898  uint8_t groupId = GetGroupId (station->m_txrate);
899  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
900 
901  WifiMode lastRate = GetMcsSupported (station, mcsIndex);
902  uint64_t lastDataRate = lastRate.GetNonHtReferenceRate ();
903  uint8_t nBasicRates = GetNBasicModes ();
904 
905  WifiMode rtsRate;
906  bool rateFound = false;
907 
908  for (uint8_t i = 0; i < nBasicRates; i++)
909  {
910  uint64_t rate = GetBasicMode (i).GetDataRate (20);
911  if (rate <= lastDataRate)
912  {
913  rtsRate = GetBasicMode (i);
914  rateFound = true;
915  }
916  }
917 
918  if (!rateFound)
919  {
920  Ptr<WifiPhy> phy = GetPhy ();
921  uint8_t nSupportRates = phy->GetNModes ();
922  for (uint8_t i = 0; i < nSupportRates; i++)
923  {
924  uint64_t rate = phy->GetMode (i).GetDataRate (20);
925  if (rate <= lastDataRate)
926  {
927  rtsRate = phy->GetMode (i);
928  rateFound = true;
929  }
930  }
931  }
932 
933  NS_ASSERT (rateFound);
934 
936  800, 1, 1, 0, GetChannelWidthForTransmission (rtsRate, GetChannelWidth (station)), GetAggregation (station), false);
937  }
938 }
939 
940 bool
942 {
943  NS_LOG_FUNCTION (this << st << packet << normally);
944 
946 
947  CheckInit (station);
948  if (!station->m_initialized)
949  {
950  return normally;
951  }
952 
953  uint32_t maxRetries;
954 
955  if (!station->m_isHt)
956  {
957  maxRetries = m_legacyManager->CountRetries (station);
958  }
959  else
960  {
961  maxRetries = CountRetries (station);
962  }
963 
964  if (station->m_longRetry >= maxRetries)
965  {
966  NS_LOG_DEBUG ("No re-transmission allowed. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
967  return false;
968  }
969  else
970  {
971  NS_LOG_DEBUG ("Re-transmit. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
972  return true;
973  }
974 }
975 
976 uint32_t
978 {
979  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
980  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
981  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
982  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
983  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
984  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
985 
986  if (!station->m_isSampling)
987  {
988  return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
989  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
990  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
991  }
992  else
993  {
994  return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
995  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
996  }
997 }
998 
999 bool
1001 {
1002  return true;
1003 }
1004 
1005 uint16_t
1007 {
1008  NS_LOG_FUNCTION (this << station);
1009  uint8_t sampleGroup = station->m_sampleGroup;
1010  uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1011  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1012  uint8_t sampleIndex = station->m_sampleTable[index][col];
1013  uint16_t rateIndex = GetIndex (sampleGroup, sampleIndex);
1014  NS_LOG_DEBUG ("Next Sample is " << rateIndex);
1015  SetNextSample (station); //Calculate the next sample rate.
1016  return rateIndex;
1017 }
1018 
1019 void
1021 {
1022  NS_LOG_FUNCTION (this << station);
1023  do
1024  {
1025  station->m_sampleGroup++;
1026  station->m_sampleGroup %= m_numGroups;
1027  }
1028  while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1029 
1030  station->m_groupsTable[station->m_sampleGroup].m_index++;
1031 
1032  uint8_t sampleGroup = station->m_sampleGroup;
1033  uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1034  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1035 
1036  if (index >= m_numRates)
1037  {
1038  station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1039  station->m_groupsTable[station->m_sampleGroup].m_col++;
1040  if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1041  {
1042  station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1043  }
1044  index = station->m_groupsTable[station->m_sampleGroup].m_index;
1045  col = station->m_groupsTable[sampleGroup].m_col;
1046  }
1047  NS_LOG_DEBUG ("New sample set: group= " << +sampleGroup << " index= " << +station->m_sampleTable[index][col]);
1048 }
1049 
1050 uint16_t
1052 {
1053  NS_LOG_FUNCTION (this << station);
1054  NS_LOG_DEBUG ("FindRate packet=" << station->m_totalPacketsCount);
1055 
1056  if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1057  {
1058  return station->m_maxTpRate;
1059  }
1060 
1061  // If we have waited enough, then sample.
1062  if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1063  {
1064  //SAMPLING
1065  NS_LOG_DEBUG ("Obtaining a sampling rate");
1067  uint16_t sampleIdx = GetNextSample (station);
1068  NS_LOG_DEBUG ("Sampling rate = " << sampleIdx);
1069 
1070  //Evaluate if the sampling rate selected should be used.
1071  uint8_t sampleGroupId = GetGroupId (sampleIdx);
1072  uint8_t sampleRateId = GetRateId (sampleIdx);
1073 
1074  // If the rate selected is not supported, then don't sample.
1075  if (station->m_groupsTable[sampleGroupId].m_supported && station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1076  {
1084  HtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1085 
1086  NS_LOG_DEBUG ("Use sample rate? MaxTpRate= " << station->m_maxTpRate << " CurrentRate= " << station->m_txrate <<
1087  " SampleRate= " << sampleIdx << " SampleProb= " << sampleRateInfo.ewmaProb);
1088 
1089  if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2
1090  && sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1091  {
1092 
1098  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1099  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1100  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1101  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1102  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
1103 
1104  uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1105  uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1106 
1107  Time sampleDuration = sampleRateInfo.perfectTxTime;
1108  Time maxTp2Duration = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1109  Time maxProbDuration = station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].perfectTxTime;
1110 
1111  NS_LOG_DEBUG ("Use sample rate? SampleDuration= " << sampleDuration << " maxTp2Duration= " << maxTp2Duration <<
1112  " maxProbDuration= " << maxProbDuration << " sampleStreams= " << +sampleStreams <<
1113  " maxTpStreams= " << +maxTpStreams);
1114  if (sampleDuration < maxTp2Duration || (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1115  {
1117  station->m_isSampling = true;
1118 
1120  station->m_sampleRate = sampleIdx;
1121 
1122  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1123  station->m_sampleTries--;
1124  return sampleIdx;
1125  }
1126  else
1127  {
1128  station->m_numSamplesSlow++;
1129  if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1130  {
1132  station->m_isSampling = true;
1133 
1135  station->m_sampleRate = sampleIdx;
1136 
1137  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1138  station->m_sampleTries--;
1139  return sampleIdx;
1140  }
1141  }
1142  }
1143  }
1144  }
1145  if (station->m_sampleWait > 0)
1146  {
1147  station->m_sampleWait--;
1148  }
1149 
1151 
1152  NS_LOG_DEBUG ("FindRate " << "maxTpRrate=" << station->m_maxTpRate);
1153  return station->m_maxTpRate;
1154 }
1155 void
1157 {
1158  NS_LOG_FUNCTION (this << station);
1159 
1161 
1162  station->m_numSamplesSlow = 0;
1163  station->m_sampleCount = 0;
1164 
1165  double tempProb;
1166 
1167  if (station->m_ampduPacketCount > 0)
1168  {
1169  uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1170  station->m_avgAmpduLen = ( newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel) ) / 100;
1171  station->m_ampduLen = 0;
1172  station->m_ampduPacketCount = 0;
1173  }
1174 
1175  /* Initialize global rate indexes */
1176  station->m_maxTpRate = GetLowestIndex (station);
1177  station->m_maxTpRate2 = GetLowestIndex (station);
1178  station->m_maxProbRate = GetLowestIndex (station);
1179 
1181  for (uint8_t j = 0; j < m_numGroups; j++)
1182  {
1183  if (station->m_groupsTable[j].m_supported)
1184  {
1185  station->m_sampleCount++;
1186 
1187  /* (re)Initialize group rate indexes */
1188  station->m_groupsTable[j].m_maxTpRate = GetLowestIndex (station, j);
1189  station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex (station, j);
1190  station->m_groupsTable[j].m_maxProbRate = GetLowestIndex (station, j);
1191 
1192  for (uint8_t i = 0; i < m_numRates; i++)
1193  {
1194  if (station->m_groupsTable[j].m_ratesTable[i].supported)
1195  {
1196  station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1197 
1198  NS_LOG_DEBUG (+i << " " << GetMcsSupported (station, station->m_groupsTable[j].m_ratesTable[i].mcsIndex) <<
1199  "\t attempt=" << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt <<
1200  "\t success=" << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1201 
1203  if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1204  {
1205  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1210  tempProb = (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) / station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1211 
1213  station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1214 
1215  if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1216  {
1217  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1218  }
1219  else
1220  {
1221  station->m_groupsTable[j].m_ratesTable[i].ewmsdProb = CalculateEwmsd (station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1222  tempProb, station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1223  m_ewmaLevel);
1225  tempProb = (tempProb * (100 - m_ewmaLevel) + station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) / 100;
1226  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1227  }
1228 
1229  station->m_groupsTable[j].m_ratesTable[i].throughput = CalculateThroughput (station, j, i, tempProb);
1230 
1231  station->m_groupsTable[j].m_ratesTable[i].successHist += station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1232  station->m_groupsTable[j].m_ratesTable[i].attemptHist += station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1233  }
1234  else
1235  {
1236  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1237  }
1238 
1240  station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess = station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1241  station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt = station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1242  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1243  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1244 
1245  if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1246  {
1247  SetBestStationThRates (station, GetIndex (j, i));
1248  SetBestProbabilityRate (station, GetIndex (j, i));
1249  }
1250 
1251  }
1252  }
1253  }
1254  }
1255 
1256  //Try to sample all available rates during each interval.
1257  station->m_sampleCount *= 8;
1258 
1259  //Recalculate retries for the rates selected.
1260  CalculateRetransmits (station, station->m_maxTpRate);
1261  CalculateRetransmits (station, station->m_maxTpRate2);
1262  CalculateRetransmits (station, station->m_maxProbRate);
1263 
1264  NS_LOG_DEBUG ("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2 << "\nmax prob=" << station->m_maxProbRate);
1265  if (m_printStats)
1266  {
1267  PrintTable (station);
1268  }
1269 }
1270 
1271 double
1272 MinstrelHtWifiManager::CalculateThroughput (MinstrelHtWifiRemoteStation *station, uint8_t groupId, uint8_t rateId, double ewmaProb)
1273 {
1279  if (ewmaProb < 10)
1280  {
1281  return 0;
1282  }
1283  else
1284  {
1289  Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1290  if (ewmaProb > 90)
1291  {
1292  return 90 / txTime.GetSeconds ();
1293  }
1294  else
1295  {
1296  return ewmaProb / txTime.GetSeconds ();
1297  }
1298  }
1299 }
1300 
1301 void
1303 {
1304  GroupInfo *group;
1305  HtRateInfo rate;
1306  uint8_t tmpGroupId, tmpRateId;
1307  double tmpTh, tmpProb;
1308  uint8_t groupId, rateId;
1309  double currentTh;
1310  // maximum group probability (GP) variables
1311  uint8_t maxGPGroupId, maxGPRateId;
1312  double maxGPTh;
1313 
1314  groupId = GetGroupId (index);
1315  rateId = GetRateId (index);
1316  group = &station->m_groupsTable[groupId];
1317  rate = group->m_ratesTable[rateId];
1318 
1319  tmpGroupId = GetGroupId (station->m_maxProbRate);
1320  tmpRateId = GetRateId (station->m_maxProbRate);
1321  tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1322  tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1323 
1324  if (rate.ewmaProb > 75)
1325  {
1326  currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1327  if (currentTh > tmpTh)
1328  {
1329  station->m_maxProbRate = index;
1330  }
1331 
1332  maxGPGroupId = GetGroupId (group->m_maxProbRate);
1333  maxGPRateId = GetRateId (group->m_maxProbRate);
1334  maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1335 
1336  if (currentTh > maxGPTh)
1337  {
1338  group->m_maxProbRate = index;
1339  }
1340  }
1341  else
1342  {
1343  if (rate.ewmaProb > tmpProb)
1344  {
1345  station->m_maxProbRate = index;
1346  }
1347  maxGPRateId = GetRateId (group->m_maxProbRate);
1348  if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1349  {
1350  group->m_maxProbRate = index;
1351  }
1352  }
1353 }
1354 
1355 /*
1356  * Find & sort topmost throughput rates
1357  *
1358  * If multiple rates provide equal throughput the sorting is based on their
1359  * current success probability. Higher success probability is preferred among
1360  * MCS groups.
1361  */
1362 void
1364 {
1365  uint8_t groupId, rateId;
1366  double th, prob;
1367  uint8_t maxTpGroupId, maxTpRateId;
1368  uint8_t maxTp2GroupId, maxTp2RateId;
1369  double maxTpTh, maxTpProb;
1370  double maxTp2Th, maxTp2Prob;
1371 
1372  groupId = GetGroupId (index);
1373  rateId = GetRateId (index);
1374  prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1375  th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1376 
1377  maxTpGroupId = GetGroupId (station->m_maxTpRate);
1378  maxTpRateId = GetRateId (station->m_maxTpRate);
1379  maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1380  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1381 
1382  maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1383  maxTp2RateId = GetRateId (station->m_maxTpRate2);
1384  maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1385  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1386 
1387  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1388  {
1389  station->m_maxTpRate2 = station->m_maxTpRate;
1390  station->m_maxTpRate = index;
1391  }
1392  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1393  {
1394  station->m_maxTpRate2 = index;
1395  }
1396 
1397  //Find best rates per group
1398 
1399  GroupInfo *group = &station->m_groupsTable[groupId];
1400  maxTpGroupId = GetGroupId (group->m_maxTpRate);
1401  maxTpRateId = GetRateId (group->m_maxTpRate);
1402  maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1403  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1404 
1405  maxTp2GroupId = GetGroupId (group->m_maxTpRate2);
1406  maxTp2RateId = GetRateId (group->m_maxTpRate2);
1407  maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1408  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1409 
1410  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1411  {
1412  group->m_maxTpRate2 = group->m_maxTpRate;
1413  group->m_maxTpRate = index;
1414  }
1415  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1416  {
1417  group->m_maxTpRate2 = index;
1418  }
1419 }
1420 
1421 void
1423 {
1424  NS_LOG_FUNCTION (this << station);
1425 
1426  station->m_groupsTable = McsGroupData (m_numGroups);
1427 
1431  NS_LOG_DEBUG ("Supported groups by station:");
1432  for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1433  {
1434  if (m_minstrelGroups[groupId].isSupported)
1435  {
1436  station->m_groupsTable[groupId].m_supported = false;
1437  if (!(!GetVhtSupported (station) && m_minstrelGroups[groupId].isVht)
1438  && (m_minstrelGroups[groupId].isVht || !GetVhtSupported (station) || !m_useVhtOnly)
1439  && !(!GetShortGuardIntervalSupported (station) && m_minstrelGroups[groupId].sgi)
1440  && (GetChannelWidth (station) >= m_minstrelGroups[groupId].chWidth)
1441  && (GetNumberOfSupportedStreams (station) >= m_minstrelGroups[groupId].streams))
1442  {
1443  NS_LOG_DEBUG ("Group " << +groupId << ": (" << +m_minstrelGroups[groupId].streams <<
1444  "," << +m_minstrelGroups[groupId].sgi << "," << m_minstrelGroups[groupId].chWidth << ")");
1445 
1446  station->m_groupsTable[groupId].m_supported = true;
1447  station->m_groupsTable[groupId].m_col = 0;
1448  station->m_groupsTable[groupId].m_index = 0;
1449 
1450  station->m_groupsTable[groupId].m_ratesTable = HtMinstrelRate (m_numRates);
1451  for (uint8_t i = 0; i < m_numRates; i++)
1452  {
1453  station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1454  }
1455 
1456  // Initialize all modes supported by the remote station that belong to the current group.
1457  for (uint8_t i = 0; i < station->m_nModes; i++)
1458  {
1459  WifiMode mode = GetMcsSupported (station, i);
1460 
1463  uint8_t rateId = mode.GetMcsValue ();
1464  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1465  {
1466  rateId %= MAX_HT_GROUP_RATES;
1467  }
1468 
1469  if ((m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_VHT
1470  && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1471  || (!m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_HT
1472  && mode.GetMcsValue () < (m_minstrelGroups[groupId].streams * 8)
1473  && mode.GetMcsValue () >= ((m_minstrelGroups[groupId].streams - 1) * 8)))
1474  {
1475  NS_LOG_DEBUG ("Mode " << +i << ": " << mode << " isVht: " << m_minstrelGroups[groupId].isVht);
1476 
1477  station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1478  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex = i;
1479  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1480  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1481  station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1482  station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1483  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1484  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1485  station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1486  station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1487  station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1488  station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1489  station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
1490  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1491  station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1492  CalculateRetransmits (station, groupId, rateId);
1493  }
1494  }
1495  }
1496  }
1497  }
1498  SetNextSample (station);
1499  UpdateStats (station);
1500  station->m_txrate = FindRate (station);
1501 }
1502 
1503 void
1505 {
1506  NS_LOG_FUNCTION (this << station << index);
1507  uint8_t groupId = GetGroupId (index);
1508  uint8_t rateId = GetRateId (index);
1509  if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1510  {
1511  CalculateRetransmits (station, groupId, rateId);
1512  }
1513 }
1514 
1515 void
1517 {
1518  NS_LOG_FUNCTION (this << station << +groupId << +rateId);
1519 
1520  uint32_t cw = 15; // Is an approximation.
1521  uint32_t cwMax = 1023;
1522  Time cwTime, txTime, dataTxTime;
1523  Time slotTime = GetMac ()->GetSlot ();
1524  Time ackTime = GetMac ()->GetBasicBlockAckTimeout ();
1525 
1526  if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1527  {
1528  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1529  }
1530  else
1531  {
1532  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1533  station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1534 
1535  dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1536  GetMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) * (station->m_avgAmpduLen - 1);
1537 
1538  /* Contention time for first 2 tries */
1539  cwTime = (cw / 2) * slotTime;
1540  cw = Min ((cw + 1) * 2, cwMax);
1541  cwTime += (cw / 2) * slotTime;
1542  cw = Min ((cw + 1) * 2, cwMax);
1543 
1544  /* Total TX time for data and Contention after first 2 tries */
1545  txTime = cwTime + 2 * (dataTxTime + ackTime);
1546 
1547  /* See how many more tries we can fit inside segment size */
1548  do
1549  {
1550  /* Contention time for this try */
1551  cwTime = (cw / 2) * slotTime;
1552  cw = Min ((cw + 1) * 2, cwMax);
1553 
1554  /* Total TX time after this try */
1555  txTime += cwTime + ackTime + dataTxTime;
1556  }
1557  while ((txTime < MilliSeconds (6))
1558  && (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1559  }
1560 }
1561 
1562 double
1563 MinstrelHtWifiManager::CalculateEwmsd (double oldEwmsd, double currentProb, double ewmaProb, double weight)
1564 {
1565  double diff, incr, tmp;
1566 
1567  /* calculate exponential weighted moving variance */
1568  diff = currentProb - ewmaProb;
1569  incr = (100 - weight) * diff / 100;
1570  tmp = oldEwmsd * oldEwmsd;
1571  tmp = weight * (tmp + diff * incr) / 100;
1572 
1573  /* return standard deviation */
1574  return sqrt (tmp);
1575 }
1576 
1577 void
1579 {
1580  NS_LOG_FUNCTION (this << station);
1581  station->m_col = station->m_index = 0;
1582 
1583  //for off-setting to make rates fall between 0 and nModes
1584  uint8_t numSampleRates = m_numRates;
1585 
1586  uint16_t newIndex;
1587  for (uint8_t col = 0; col < m_nSampleCol; col++)
1588  {
1589  for (uint8_t i = 0; i < numSampleRates; i++ )
1590  {
1595  int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
1596  newIndex = (i + uv) % numSampleRates;
1597 
1598  //this loop is used for filling in other uninitialized places
1599  while (station->m_sampleTable[newIndex][col] != 0)
1600  {
1601  newIndex = (newIndex + 1) % m_numRates;
1602  }
1603  station->m_sampleTable[newIndex][col] = i;
1604  }
1605  }
1606 }
1607 
1608 void
1610 {
1611  if (!station->m_statsFile.is_open ())
1612  {
1613  std::ostringstream tmp;
1614  tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1615  station->m_statsFile.open (tmp.str ().c_str (), std::ios::out);
1616  }
1617 
1618  station->m_statsFile << " best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n" <<
1619  " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n";
1620  for (uint8_t i = 0; i < m_numGroups; i++)
1621  {
1622  StatsDump (station, i, station->m_statsFile);
1623  }
1624 
1625  station->m_statsFile << "\nTotal packet count:: ideal " << Max (0, station->m_totalPacketsCount - station->m_samplePacketsCount) <<
1626  " lookaround " << station->m_samplePacketsCount << "\n";
1627  station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen << "\n\n";
1628 
1629  station->m_statsFile.flush ();
1630 }
1631 
1632 void
1633 MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint8_t groupId, std::ofstream &of)
1634 {
1635  uint8_t numRates = m_numRates;
1636  McsGroup group = m_minstrelGroups[groupId];
1637  Time txTime;
1638  char giMode;
1639  if (group.sgi)
1640  {
1641  giMode = 'S';
1642  }
1643  else
1644  {
1645  giMode = 'L';
1646  }
1647  for (uint8_t i = 0; i < numRates; i++)
1648  {
1649  if (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[i].supported)
1650  {
1651  if (!group.isVht)
1652  {
1653  of << "HT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1654  }
1655  else
1656  {
1657  of << "VHT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1658  }
1659 
1660  uint16_t maxTpRate = station->m_maxTpRate;
1661  uint16_t maxTpRate2 = station->m_maxTpRate2;
1662  uint16_t maxProbRate = station->m_maxProbRate;
1663 
1664  uint16_t idx = GetIndex (groupId, i);
1665  if (idx == maxTpRate)
1666  {
1667  of << 'A';
1668  }
1669  else
1670  {
1671  of << ' ';
1672  }
1673  if (idx == maxTpRate2)
1674  {
1675  of << 'B';
1676  }
1677  else
1678  {
1679  of << ' ';
1680  }
1681  if (idx == maxProbRate)
1682  {
1683  of << 'P';
1684  }
1685  else
1686  {
1687  of << ' ';
1688  }
1689 
1690  if (!group.isVht)
1691  {
1692  of << std::setw (4) << " MCS" << (group.streams - 1) * 8 + i;
1693  }
1694  else
1695  {
1696  of << std::setw (7) << " MCS" << +i << "/" << (int) group.streams;
1697  }
1698 
1699  of << " " << std::setw (3) << +idx << " ";
1700 
1701  /* tx_time[rate(i)] in usec */
1702  txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
1703  of << std::setw (6) << txTime.GetMicroSeconds () << " ";
1704 
1705  of << std::setw (7) << CalculateThroughput (station, groupId, i, 100) / 100 << " " <<
1706  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100 << " " <<
1707  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb << " " <<
1708  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb << " " <<
1709  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].prob << " " <<
1710  std::setw (2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount << " " <<
1711  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " " <<
1712  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt << " " <<
1713  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " " <<
1714  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist << "\n";
1715  }
1716  }
1717 }
1718 uint16_t
1719 MinstrelHtWifiManager::GetIndex (uint8_t groupId, uint8_t rateId)
1720 {
1721  NS_LOG_FUNCTION (this << +groupId << +rateId);
1722  uint16_t index;
1723  index = groupId * m_numRates + rateId;
1724  return index;
1725 }
1726 
1727 uint8_t
1729 {
1730  NS_LOG_FUNCTION (this << index);
1731  uint8_t id;
1732  id = index % m_numRates;
1733  return id;
1734 }
1735 
1736 uint8_t
1738 {
1739  NS_LOG_FUNCTION (this << index);
1740  return index / m_numRates;
1741 }
1742 
1743 uint8_t
1744 MinstrelHtWifiManager::GetHtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1745 {
1746  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1747  return MAX_SUPPORTED_STREAMS * 2 * (chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
1748 }
1749 
1750 uint8_t
1751 MinstrelHtWifiManager::GetVhtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1752 {
1753  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1754  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;
1755 }
1756 
1757 uint16_t
1759 {
1760  NS_LOG_FUNCTION (this << station);
1761 
1762  uint8_t groupId = 0;
1763  uint8_t rateId = 0;
1764  while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
1765  {
1766  groupId++;
1767  }
1768  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1769  {
1770  rateId++;
1771  }
1772  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1773  return GetIndex (groupId, rateId);
1774 }
1775 
1776 uint16_t
1778 {
1779  NS_LOG_FUNCTION (this << station << +groupId);
1780 
1781  uint8_t rateId = 0;
1782  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1783  {
1784  rateId++;
1785  }
1786  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1787  return GetIndex (groupId, rateId);
1788 }
1789 
1792 {
1793  WifiModeList vhtMcsList;
1794  Ptr<WifiPhy> phy = GetPhy ();
1795  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1796  {
1797  WifiMode mode = phy->GetMcs (i);
1798  if (mode.GetModulationClass () == WIFI_MOD_CLASS_VHT)
1799  {
1800  vhtMcsList.push_back (mode);
1801  }
1802  }
1803  return vhtMcsList;
1804 }
1805 
1808 {
1809  WifiModeList htMcsList;
1810  Ptr<WifiPhy> phy = GetPhy ();
1811  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1812  {
1813  WifiMode mode = phy->GetMcs (i);
1814  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1815  {
1816  htMcsList.push_back (mode);
1817  }
1818  }
1819  return htMcsList;
1820 }
1821 
1822 } // 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.
uint8_t GetNMcsSupported(Mac48Address address) const
Return the number of MCS supported by the station.
uint16_t m_maxProbRate
rate with highest prob of success
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.
#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
uint16_t m_txrate
current transmit rate
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:84
MinstrelHtWifiRemoteStation structure.
uint16_t m_maxTpRate2
second highest throughput rate
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:355
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:204
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
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:280
#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.
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:446
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 PLCP preambles.
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:197
The MPDU is the first aggregate in an A-MPDU with multiple MPDUs, but is not the last aggregate...
virtual uint32_t GetInteger(void)=0
Get the next random value as an integer drawn from the distribution.
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 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.
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:209
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:494
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.
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:363
uint16_t GetNextSample(MinstrelHtWifiRemoteStation *station)
Getting the next sample from Sample Table.
uint16_t m_maxTpRate2
The second max throughput rate of this group.
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)
Updating 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:252
uint16_t m_maxTpRate
The max throughput rate of this group.
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.
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:501
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:272
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 packts
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:472
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:915
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:150
WifiMode GetMcsSupported(const WifiRemoteStation *station, uint8_t i) const
Return the WifiMode supported by the specified station at the specified index.
uint16_t GetChannelWidth(const WifiRemoteStation *station) const
Return the channel width supported by the station.
uint8_t GetNess(const WifiRemoteStation *station) const
Time m_nextStatsUpdate
10 times every second