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 
38 #include "ns3/simulator.h"
39 #include "ns3/log.h"
40 #include "ns3/double.h"
41 #include "ns3/boolean.h"
42 #include "wifi-mac.h"
43 #include "wifi-phy.h"
44 #include <iomanip>
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  uint32_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  double m_avgAmpduLen;
64  double 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  DoubleValue (10),
91  MakeDoubleChecker<double> (0, 100))
92  .AddAttribute ("EWMA",
93  "EWMA level",
94  DoubleValue (75),
96  MakeDoubleChecker<double> (0, 100))
97  .AddAttribute ("SampleColumn",
98  "The number of columns used for sampling",
99  UintegerValue (10),
101  MakeUintegerChecker <uint32_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 ("RateChange",
118  "The transmission rate has changed",
120  "ns3::MinstrelHtWifiManager::RateChangeTracedCallback")
121  ;
122  return tid;
123 }
124 
126  : m_numGroups (0),
127  m_numRates (0)
128 {
129  NS_LOG_FUNCTION (this);
130  m_uniformRandomVariable = CreateObject<UniformRandomVariable> ();
135  m_legacyManager = CreateObject<MinstrelWifiManager> ();
136 }
137 
139 {
140  NS_LOG_FUNCTION (this);
141  if (HasHtSupported ())
142  {
143  for (uint8_t i = 0; i < m_numGroups; i++)
144  {
145  m_minstrelGroups[i].ratesFirstMpduTxTimeTable.clear ();
146  m_minstrelGroups[i].ratesTxTimeTable.clear ();
147  }
148  }
149 }
150 
151 int64_t
153 {
154  NS_LOG_FUNCTION (this << stream);
155  int64_t numStreamsAssigned = 0;
157  numStreamsAssigned++;
158  numStreamsAssigned += m_legacyManager->AssignStreams (stream);
159  return numStreamsAssigned;
160 }
161 
162 void
164 {
165  NS_LOG_FUNCTION (this << phy);
166  // Setup phy for legacy manager.
167  m_legacyManager->SetupPhy (phy);
169 }
170 
171 void
173 {
174  NS_LOG_FUNCTION (this);
175 
182  // Check if the device supports HT or VHT
183  if (HasHtSupported () || HasVhtSupported ())
184  {
187 
188  if (HasVhtSupported ())
189  {
192  }
193 
204  NS_LOG_DEBUG ("Initialize MCS Groups:");
206 
207  // Initialize all HT groups
208  for (uint8_t chWidth = 20; chWidth <= MAX_HT_WIDTH; chWidth *= 2)
209  {
210  for (uint8_t sgi = 0; sgi <= 1; sgi++)
211  {
212  for (uint8_t streams = 1; streams <= MAX_SUPPORTED_STREAMS; streams++)
213  {
214  uint32_t groupId = GetHtGroupId (streams, sgi, chWidth);
215 
216  m_minstrelGroups[groupId].streams = streams;
217  m_minstrelGroups[groupId].sgi = sgi;
218  m_minstrelGroups[groupId].chWidth = chWidth;
219  m_minstrelGroups[groupId].isVht = false;
220  m_minstrelGroups[groupId].isSupported = false;
221 
222  // Check capabilities of the device
223  if (!(!GetPhy ()->GetShortGuardInterval () && m_minstrelGroups[groupId].sgi)
224  && (GetPhy ()->GetChannelWidth () >= m_minstrelGroups[groupId].chWidth)
225  && (GetPhy ()->GetMaxSupportedTxSpatialStreams () >= m_minstrelGroups[groupId].streams))
226  {
227  m_minstrelGroups[groupId].isSupported = true;
228 
229  // Calculate tx time for all rates of the group
230  WifiModeList htMcsList = GetHtDeviceMcsList ();
231  for (uint8_t i = 0; i < MAX_HT_GROUP_RATES; i++)
232  {
233  uint32_t deviceIndex = i + (m_minstrelGroups[groupId].streams - 1) * 8;
234  WifiMode mode = htMcsList[deviceIndex];
235  AddFirstMpduTxTime (groupId, mode, CalculateFirstMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
236  AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
237  }
238  NS_LOG_DEBUG ("Initialized group " << groupId << ": (" << +streams << "," << +sgi << "," << +chWidth << ")");
239  }
240  }
241  }
242  }
243 
244  if (HasVhtSupported ())
245  {
246  // Initialize all VHT groups
247  for (uint16_t chWidth = 20; chWidth <= MAX_VHT_WIDTH; chWidth *= 2)
248  {
249  for (uint8_t sgi = 0; sgi <= 1; sgi++)
250  {
251  for (uint8_t streams = 1; streams <= MAX_SUPPORTED_STREAMS; streams++)
252  {
253  uint32_t groupId = GetVhtGroupId (streams, sgi, chWidth);
254 
255  m_minstrelGroups[groupId].streams = streams;
256  m_minstrelGroups[groupId].sgi = sgi;
257  m_minstrelGroups[groupId].chWidth = chWidth;
258  m_minstrelGroups[groupId].isVht = true;
259  m_minstrelGroups[groupId].isSupported = false;
260 
261  // Check capabilities of the device
262  if (!(!GetPhy ()->GetShortGuardInterval () && m_minstrelGroups[groupId].sgi)
263  && (GetPhy ()->GetChannelWidth () >= m_minstrelGroups[groupId].chWidth)
264  && (GetPhy ()->GetMaxSupportedTxSpatialStreams () >= m_minstrelGroups[groupId].streams))
265  {
266  m_minstrelGroups[groupId].isSupported = true;
267 
268  // Calculate tx time for all rates of the group
269  WifiModeList vhtMcsList = GetVhtDeviceMcsList ();
270  for (uint8_t i = 0; i < MAX_VHT_GROUP_RATES; i++)
271  {
272  WifiMode mode = vhtMcsList[i];
273  // Check for invalid VHT MCSs and do not add time to array.
274  if (IsValidMcs (GetPhy (), streams, chWidth, mode))
275  {
276  AddFirstMpduTxTime (groupId, mode, CalculateFirstMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
277  AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
278  }
279  }
280  NS_LOG_DEBUG ("Initialized group " << groupId << ": (" << +streams << "," << +sgi << "," << +chWidth << ")");
281  }
282  }
283  }
284  }
285  }
286  }
287 }
288 
289 void
291 {
292  NS_LOG_FUNCTION (this << mac);
293  m_legacyManager->SetupMac (mac);
295 }
296 
297 bool
298 MinstrelHtWifiManager::IsValidMcs (Ptr<WifiPhy> phy, uint8_t streams, uint8_t chWidth, WifiMode mode)
299 {
300  NS_LOG_FUNCTION (this << phy << +streams << +chWidth << mode);
301  WifiTxVector txvector;
302  txvector.SetNss (streams);
303  txvector.SetChannelWidth (chWidth);
304  txvector.SetMode (mode);
305  return txvector.IsValid ();
306 }
307 
308 Time
309 MinstrelHtWifiManager::CalculateFirstMpduTxDuration (Ptr<WifiPhy> phy, uint8_t streams, uint8_t sgi, uint8_t chWidth, WifiMode mode)
310 {
311  NS_LOG_FUNCTION (this << phy << +streams << +sgi << +chWidth << mode);
312  WifiTxVector txvector;
313  txvector.SetNss (streams);
314  txvector.SetGuardInterval (sgi ? 400 : 800);
315  txvector.SetChannelWidth (chWidth);
316  txvector.SetNess (0);
317  txvector.SetStbc (phy->GetStbc ());
318  txvector.SetMode (mode);
320  return phy->CalculateTxDuration (m_frameLength, txvector, phy->GetFrequency (), MPDU_IN_AGGREGATE, 0);
321 }
322 
323 Time
324 MinstrelHtWifiManager::CalculateMpduTxDuration (Ptr<WifiPhy> phy, uint8_t streams, uint8_t sgi, uint8_t chWidth, WifiMode mode)
325 {
326  NS_LOG_FUNCTION (this << phy << +streams << +sgi << +chWidth << mode);
327  WifiTxVector txvector;
328  txvector.SetNss (streams);
329  txvector.SetGuardInterval (sgi ? 400 : 800);
330  txvector.SetChannelWidth (chWidth);
331  txvector.SetNess (0);
332  txvector.SetStbc (phy->GetStbc ());
333  txvector.SetMode (mode);
335  return phy->CalculateTxDuration (m_frameLength, txvector, phy->GetFrequency (), MPDU_IN_AGGREGATE, 0);
336 }
337 
338 Time
340 {
341  NS_LOG_FUNCTION (this << groupId << mode);
342  for (TxTime::const_iterator i = m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.begin (); i != m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.end (); i++)
343  {
344  if (mode == i->second)
345  {
346  return i->first;
347  }
348  }
349  NS_ASSERT (false);
350  return Seconds (0);
351 }
352 
353 void
355 {
356  NS_LOG_FUNCTION (this << groupId << mode << t);
357  m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.push_back (std::make_pair (t, mode));
358 }
359 
360 Time
361 MinstrelHtWifiManager::GetMpduTxTime (uint32_t groupId, WifiMode mode) const
362 {
363  NS_LOG_FUNCTION (this << groupId << mode);
364  for (TxTime::const_iterator i = m_minstrelGroups[groupId].ratesTxTimeTable.begin (); i != m_minstrelGroups[groupId].ratesTxTimeTable.end (); i++)
365  {
366  if (mode == i->second)
367  {
368  return i->first;
369  }
370  }
371  NS_ASSERT (false);
372  return Seconds (0);
373 }
374 
375 void
377 {
378  NS_LOG_FUNCTION (this << groupId << mode << t);
379  m_minstrelGroups[groupId].ratesTxTimeTable.push_back (std::make_pair (t, mode));
380 }
381 
384 {
385  NS_LOG_FUNCTION (this);
387 
388  // Initialize variables common to both stations.
390  station->m_col = 0;
391  station->m_index = 0;
392  station->m_maxTpRate = 0;
393  station->m_maxTpRate2 = 0;
394  station->m_maxProbRate = 0;
395  station->m_nModes = 0;
396  station->m_totalPacketsCount = 0;
397  station->m_samplePacketsCount = 0;
398  station->m_isSampling = false;
399  station->m_sampleRate = 0;
400  station->m_sampleDeferred = false;
401  station->m_shortRetry = 0;
402  station->m_longRetry = 0;
403  station->m_txrate = 0;
404  station->m_initialized = false;
405 
406  // Variables specific to HT station
407  station->m_sampleGroup = 0;
408  station->m_numSamplesSlow = 0;
409  station->m_sampleCount = 16;
410  station->m_sampleWait = 0;
411  station->m_sampleTries = 4;
412 
413  station->m_avgAmpduLen = 1;
414  station->m_ampduLen = 0;
415  station->m_ampduPacketCount = 0;
416 
417  // If the device supports HT
418  if (HasHtSupported () || HasVhtSupported ())
419  {
424  station->m_isHt = true;
425  }
426  // Use the variable in the station to indicate that the device do not support HT
427  else
428  {
429  station->m_isHt = false;
430  }
431 
432  return station;
433 }
434 
435 void
437 {
438  NS_LOG_FUNCTION (this << station);
439  // Note: we appear to be doing late initialization of the table
440  // to make sure that the set of supported rates has been initialized
441  // before we perform our own initialization.
442  if (!station->m_initialized)
443  {
450  if (!GetHtSupported (station) && !GetVhtSupported (station))
451  {
452  NS_LOG_INFO ("Non-HT station " << station);
453  station->m_isHt = false;
454  // We will use non-HT minstrel for this station. Initialize the manager.
455  m_legacyManager->SetAttribute ("UpdateStatistics", TimeValue (m_updateStats));
456  m_legacyManager->SetAttribute ("LookAroundRate", DoubleValue (m_lookAroundRate));
457  m_legacyManager->SetAttribute ("EWMA", DoubleValue (m_ewmaLevel));
458  m_legacyManager->SetAttribute ("SampleColumn", UintegerValue (m_nSampleCol));
459  m_legacyManager->SetAttribute ("PacketLength", UintegerValue (m_frameLength));
460  m_legacyManager->SetAttribute ("PrintStats", BooleanValue (m_printStats));
461  m_legacyManager->CheckInit (station);
462  }
463  else
464  {
465  NS_LOG_DEBUG ("HT station " << station);
466  station->m_isHt = true;
467  station->m_nModes = GetNMcsSupported (station);
468  station->m_sampleTable = SampleRate (m_numRates, std::vector<uint32_t> (m_nSampleCol));
469  InitSampleTable (station);
470  RateInit (station);
471  std::ostringstream tmp;
472  tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
473  station->m_statsFile.open (tmp.str ().c_str (), std::ios::out);
474  station->m_initialized = true;
475  }
476  }
477 }
478 
479 void
481 {
482  NS_LOG_FUNCTION (this << st);
483  NS_LOG_DEBUG ("DoReportRxOk m_txrate=" << ((MinstrelHtWifiRemoteStation *)st)->m_txrate);
484 }
485 
486 void
488 {
489  NS_LOG_FUNCTION (this << st);
491  CheckInit (station);
492  if (!station->m_initialized)
493  {
494  return;
495  }
496  NS_LOG_DEBUG ("DoReportRtsFailed m_txrate=" << station->m_txrate);
497  station->m_shortRetry++;
498 }
499 
500 void
501 MinstrelHtWifiManager::DoReportRtsOk (WifiRemoteStation *st, double ctsSnr, WifiMode ctsMode, double rtsSnr)
502 {
503  NS_LOG_FUNCTION (this << st);
504 }
505 
506 void
508 {
509  NS_LOG_FUNCTION (this << st);
511  NS_LOG_DEBUG ("Final RTS failed");
512  CheckInit (station);
513  if (!station->m_initialized)
514  {
515  return;
516  }
517  UpdateRetry (station);
518 }
519 
520 void
522 {
523  NS_LOG_FUNCTION (this << st);
525 
526  CheckInit (station);
527  if (!station->m_initialized)
528  {
529  return;
530  }
531 
532  NS_LOG_DEBUG ("DoReportDataFailed " << station << "\t rate " << station->m_txrate << "\tlongRetry \t" << station->m_longRetry);
533 
534  if (!station->m_isHt)
535  {
536  m_legacyManager->UpdateRate (station);
537  }
538  else
539  {
540  uint32_t rateId = GetRateId (station->m_txrate);
541  uint32_t groupId = GetGroupId (station->m_txrate);
542  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++; // Increment the attempts counter for the rate used.
543  UpdateRate (station);
544  }
545 }
546 
547 void
548 MinstrelHtWifiManager::DoReportDataOk (WifiRemoteStation *st, double ackSnr, WifiMode ackMode, double dataSnr)
549 {
550  NS_LOG_FUNCTION (this << st << ackSnr << ackMode << dataSnr);
552 
553  CheckInit (station);
554  if (!station->m_initialized)
555  {
556  return;
557  }
558 
559  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).");
560 
561  if (!station->m_isHt)
562  {
563  station->m_minstrelTable[station->m_txrate].numRateSuccess++;
564  station->m_minstrelTable[station->m_txrate].numRateAttempt++;
565 
566  m_legacyManager->UpdatePacketCounters (station);
567 
568  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).");
569 
570  UpdateRetry (station);
571  m_legacyManager->UpdateStats (station);
572 
573  if (station->m_nModes >= 1)
574  {
575  station->m_txrate = m_legacyManager->FindRate (station);
576  }
577  }
578  else
579  {
580  uint32_t rateId = GetRateId (station->m_txrate);
581  uint32_t groupId = GetGroupId (station->m_txrate);
582  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
583  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
584 
585  UpdatePacketCounters (station, 1, 0);
586 
587  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).");
588 
589  station->m_isSampling = false;
590  station->m_sampleDeferred = false;
591 
592  UpdateRetry (station);
593  if (Simulator::Now () >= station->m_nextStatsUpdate)
594  {
595  UpdateStats (station);
596  }
597 
598  if (station->m_nModes >= 1)
599  {
600  station->m_txrate = FindRate (station);
601  }
602  }
603 
604  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate );
605 }
606 
607 void
609 {
610  NS_LOG_FUNCTION (this << st);
612 
613  CheckInit (station);
614  if (!station->m_initialized)
615  {
616  return;
617  }
618 
619  NS_LOG_DEBUG ("DoReportFinalDataFailed - TxRate=" << station->m_txrate);
620 
621  if (!station->m_isHt)
622  {
623  m_legacyManager->UpdatePacketCounters (station);
624 
625  UpdateRetry (station);
626 
627  m_legacyManager->UpdateStats (station);
628  if (station->m_nModes >= 1)
629  {
630  station->m_txrate = m_legacyManager->FindRate (station);
631  }
632  }
633  else
634  {
635  UpdatePacketCounters (station, 0, 1);
636 
637  station->m_isSampling = false;
638  station->m_sampleDeferred = false;
639 
640  UpdateRetry (station);
641  if (Simulator::Now () >= station->m_nextStatsUpdate)
642  {
643  UpdateStats (station);
644  }
645 
646  if (station->m_nModes >= 1)
647  {
648  station->m_txrate = FindRate (station);
649  }
650  }
651  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate );
652 }
653 
654 void
655 MinstrelHtWifiManager::DoReportAmpduTxStatus (WifiRemoteStation *st, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus, double rxSnr, double dataSnr)
656 {
657  NS_LOG_FUNCTION (this << st << +nSuccessfulMpdus << +nFailedMpdus << rxSnr << dataSnr);
659 
660  CheckInit (station);
661  if (!station->m_initialized)
662  {
663  return;
664  }
665 
666  if (!station->m_isHt)
667  {
668  NS_ASSERT_MSG (false,"A-MPDU Tx Status called but no HT or VHT supported.");
669  }
670 
671  NS_LOG_DEBUG ("DoReportAmpduTxStatus. TxRate=" << station->m_txrate << " SuccMpdus= " <<
672  +nSuccessfulMpdus << " FailedMpdus= " << +nFailedMpdus);
673 
674  station->m_ampduPacketCount++;
675  station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
676 
677  UpdatePacketCounters (station, nSuccessfulMpdus, nFailedMpdus);
678 
679  uint32_t rateId = GetRateId (station->m_txrate);
680  uint32_t groupId = GetGroupId (station->m_txrate);
681  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
682  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt += nSuccessfulMpdus + nFailedMpdus;
683 
684  if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries (station))
685  {
686  // We do not receive a BlockAck. The entire AMPDU fail.
687  UpdateRate (station);
688  }
689  else
690  {
691  station->m_isSampling = false;
692  station->m_sampleDeferred = false;
693 
694  UpdateRetry (station);
695  if (Simulator::Now () >= station->m_nextStatsUpdate)
696  {
697  UpdateStats (station);
698  }
699 
700  if (station->m_nModes >= 1)
701  {
702  station->m_txrate = FindRate (station);
703  }
704  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
705  }
706 }
707 
708 void
710 {
711  NS_LOG_FUNCTION (this << station);
712 
734  CheckInit (station);
735  if (!station->m_initialized)
736  {
737  return;
738  }
739  station->m_longRetry++;
740 
744  uint32_t maxTpRateId = GetRateId (station->m_maxTpRate);
745  uint32_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
746  uint32_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
747  uint32_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
748  uint32_t maxProbRateId = GetRateId (station->m_maxProbRate);
749  uint32_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
750 
752  if (!station->m_isSampling)
753  {
755  if (station->m_longRetry < station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
756  {
757  NS_LOG_DEBUG ("Not Sampling; use the same rate again");
758  station->m_txrate = station->m_maxTpRate;
759  }
760 
762  else if (station->m_longRetry < ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
763  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
764  {
765  NS_LOG_DEBUG ("Not Sampling; use the Max TP2");
766  station->m_txrate = station->m_maxTpRate2;
767  }
768 
770  else if (station->m_longRetry <= ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
771  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
772  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
773  {
774  NS_LOG_DEBUG ("Not Sampling; use Max Prob");
775  station->m_txrate = station->m_maxProbRate;
776  }
777  else
778  {
779  NS_ASSERT_MSG (false,"Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
780  }
781  }
782 
784  else
785  {
788  if (station->m_longRetry < 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
789  {
790  NS_LOG_DEBUG ("Sampling use the MaxTP rate");
791  station->m_txrate = station->m_maxTpRate2;
792  }
793 
795  else if (station->m_longRetry <= 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
796  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
797  {
798  NS_LOG_DEBUG ("Sampling use the MaxProb rate");
799  station->m_txrate = station->m_maxProbRate;
800  }
801  else
802  {
803  NS_ASSERT_MSG (false,"Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
804  }
805  }
806  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
807 }
808 
809 void
811 {
812  NS_LOG_FUNCTION (this << station);
813  station->m_shortRetry = 0;
814  station->m_longRetry = 0;
815 }
816 
817 void
818 MinstrelHtWifiManager::UpdatePacketCounters (MinstrelHtWifiRemoteStation *station, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus)
819 {
820  NS_LOG_FUNCTION (this << station << +nSuccessfulMpdus << +nFailedMpdus);
821 
822  station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
823  if (station->m_isSampling)
824  {
825  station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
826  }
827  if (station->m_totalPacketsCount == ~0)
828  {
829  station->m_samplePacketsCount = 0;
830  station->m_totalPacketsCount = 0;
831  }
832 
833  if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
834  {
835  station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
836  station->m_sampleTries = 1;
837  station->m_sampleCount--;
838  }
839 }
840 
843 {
844  NS_LOG_FUNCTION (this << st);
846 
847  if (!station->m_initialized)
848  {
849  CheckInit (station);
850  }
851 
852  if (!station->m_isHt)
853  {
854  WifiTxVector vector = m_legacyManager->GetDataTxVector (station);
855 
856  uint64_t dataRate = vector.GetMode ().GetDataRate (vector);
857  if (!station->m_isSampling)
858  {
859  m_rateChange (dataRate, station->m_state->m_address);
860  }
861 
862  return vector;
863  }
864  else
865  {
866  NS_LOG_DEBUG ("DoGetDataMode m_txrate= " << station->m_txrate);
867 
868  uint32_t rateId = GetRateId (station->m_txrate);
869  uint32_t groupId = GetGroupId (station->m_txrate);
870  uint32_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
871 
872  NS_LOG_DEBUG ("DoGetDataMode rateId= " << rateId << " groupId= " << groupId << " mode= " << GetMcsSupported (station, mcsIndex));
873 
874  McsGroup group = m_minstrelGroups[groupId];
875 
876  // Check consistency of rate selected.
877  if ((group.sgi && !GetShortGuardInterval (station)) || group.chWidth > GetChannelWidth (station) || group.streams > GetNumberOfSupportedStreams (station))
878  {
879  NS_ASSERT_MSG (false, "Inconsistent group selected. Group: (" << +group.streams <<
880  "," << +group.sgi << "," << +group.chWidth << ")" <<
881  " Station capabilities: (" << GetNumberOfSupportedStreams (station) <<
882  "," << GetShortGuardInterval (station) << "," << GetChannelWidth (station) << ")");
883  }
884 
885  uint64_t dataRate = GetMcsSupported (station, mcsIndex).GetDataRate (group.chWidth, group.sgi ? 400 : 800, group.streams);
886  if (!station->m_isSampling)
887  {
888  m_rateChange (dataRate, station->m_state->m_address);
889  }
890  WifiMode mode = GetMcsSupported (station, mcsIndex);
891  return WifiTxVector (mode, GetDefaultTxPowerLevel (), GetPreambleForTransmission (mode, GetAddress (station)), group.sgi ? 400 : 800, GetNumberOfAntennas (), group.streams, GetNess (station), GetChannelWidthForTransmission (mode, group.chWidth), GetAggregation (station) && !station->m_isSampling, false);
892  }
893 }
894 
897 {
898  NS_LOG_FUNCTION (this << st);
900 
901  if (!station->m_initialized)
902  {
903  CheckInit (station);
904  }
905 
906  if (!station->m_isHt)
907  {
908  return m_legacyManager->GetRtsTxVector (station);
909  }
910  else
911  {
912  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
913 
914  /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
915  * When supported, decision of using HT has to follow rules in Section 9.7.6 from 802.11-2012.
916  * From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is carried in a
917  * non-HT PPDU shall be transmitted by the STA using a rate no higher than the highest
918  * rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
919  * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
920  * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
921  * these conditions, the control frame shall be transmitted at a rate no higher than the
922  * highest mandatory rate of the attached PHY that is less than or equal to the rate
923  * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
924  * directed to the same receiving STA."
925  */
926 
927  // As we are in Minstrel HT, assume the last rate was an HT rate.
928  uint32_t rateId = GetRateId (station->m_txrate);
929  uint32_t groupId = GetGroupId (station->m_txrate);
930  uint32_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
931 
932  WifiMode lastRate = GetMcsSupported (station, mcsIndex);
933  uint64_t lastDataRate = lastRate.GetNonHtReferenceRate ();
934  uint8_t nBasicRates = GetNBasicModes ();
935 
936  WifiMode rtsRate;
937  bool rateFound = false;
938 
939  for (uint8_t i = 0; i < nBasicRates; i++)
940  {
941  uint64_t rate = GetBasicMode (i).GetDataRate (20);
942  if (rate <= lastDataRate)
943  {
944  rtsRate = GetBasicMode (i);
945  rateFound = true;
946  }
947  }
948 
949  if (!rateFound)
950  {
951  Ptr<WifiPhy> phy = GetPhy ();
952  uint8_t nSupportRates = phy->GetNModes ();
953  for (uint8_t i = 0; i < nSupportRates; i++)
954  {
955  uint64_t rate = phy->GetMode (i).GetDataRate (20);
956  if (rate <= lastDataRate)
957  {
958  rtsRate = phy->GetMode (i);
959  rateFound = true;
960  }
961  }
962  }
963 
964  NS_ASSERT (rateFound);
965 
966  return WifiTxVector (rtsRate, GetDefaultTxPowerLevel (), GetPreambleForTransmission (rtsRate, GetAddress (station)),
967  800, 1, 1, 0, GetChannelWidthForTransmission (rtsRate, GetChannelWidth (station)), GetAggregation (station), false);
968  }
969 }
970 
971 bool
973 {
974  NS_LOG_FUNCTION (this << st << packet << normally);
975 
977 
978  CheckInit (station);
979  if (!station->m_initialized)
980  {
981  return normally;
982  }
983 
984  uint32_t maxRetries;
985 
986  if (!station->m_isHt)
987  {
988  maxRetries = m_legacyManager->CountRetries (station);
989  }
990  else
991  {
992  maxRetries = CountRetries (station);
993  }
994 
995  if (station->m_longRetry >= maxRetries)
996  {
997  NS_LOG_DEBUG ("No re-transmission allowed. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
998  return false;
999  }
1000  else
1001  {
1002  NS_LOG_DEBUG ("Re-transmit. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
1003  return true;
1004  }
1005 }
1006 
1007 uint32_t
1009 {
1010  uint32_t maxProbRateId = GetRateId (station->m_maxProbRate);
1011  uint32_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1012  uint32_t maxTpRateId = GetRateId (station->m_maxTpRate);
1013  uint32_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1014  uint32_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1015  uint32_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1016 
1017  if (!station->m_isSampling)
1018  {
1019  return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
1020  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
1021  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1022  }
1023  else
1024  {
1025  return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1026  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1027  }
1028 }
1029 
1030 bool
1032 {
1033  return true;
1034 }
1035 
1036 uint32_t
1038 {
1039  NS_LOG_FUNCTION (this << station);
1040 
1041  uint32_t sampleGroup = station->m_sampleGroup;
1042 
1043  uint32_t index = station->m_groupsTable[sampleGroup].m_index;
1044  uint32_t col = station->m_groupsTable[sampleGroup].m_col;
1045 
1046  uint32_t sampleIndex = station->m_sampleTable[index][col];
1047 
1048  uint32_t rateIndex = GetIndex (sampleGroup, sampleIndex);
1049  NS_LOG_DEBUG ("Next Sample is " << rateIndex);
1050 
1051  SetNextSample (station); //Calculate the next sample rate.
1052 
1053  return rateIndex;
1054 }
1055 
1056 void
1058 {
1059  NS_LOG_FUNCTION (this << station);
1060  do
1061  {
1062  station->m_sampleGroup++;
1063  station->m_sampleGroup %= m_numGroups;
1064  }
1065  while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1066 
1067  station->m_groupsTable[station->m_sampleGroup].m_index++;
1068 
1069  uint32_t sampleGroup = station->m_sampleGroup;
1070  uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1071  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1072 
1073  if (index >= m_numRates)
1074  {
1075  station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1076  station->m_groupsTable[station->m_sampleGroup].m_col++;
1077  if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1078  {
1079  station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1080  }
1081  index = station->m_groupsTable[station->m_sampleGroup].m_index;
1082  col = station->m_groupsTable[sampleGroup].m_col;
1083  }
1084  NS_LOG_DEBUG ("New sample set: group= " << sampleGroup << " index= " << station->m_sampleTable[index][col]);
1085 }
1086 
1087 uint32_t
1089 {
1090  NS_LOG_FUNCTION (this << station);
1091  NS_LOG_DEBUG ("FindRate packet=" << station->m_totalPacketsCount );
1092 
1093  if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1094  {
1095  return station->m_maxTpRate;
1096  }
1097 
1098  // If we have waited enough, then sample.
1099  if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1100  {
1101  //SAMPLING
1102  NS_LOG_DEBUG ("Obtaining a sampling rate");
1104  uint32_t sampleIdx = GetNextSample (station);
1105  NS_LOG_DEBUG ("Sampling rate = " << sampleIdx);
1106 
1107  //Evaluate if the sampling rate selected should be used.
1108  uint32_t sampleGroupId = GetGroupId (sampleIdx);
1109  uint32_t sampleRateId = GetRateId (sampleIdx);
1110 
1111  // If the rate selected is not supported, then don't sample.
1112  if (station->m_groupsTable[sampleGroupId].m_supported && station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1113  {
1121  HtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1122 
1123  NS_LOG_DEBUG ("Use sample rate? MaxTpRate= " << station->m_maxTpRate << " CurrentRate= " << station->m_txrate <<
1124  " SampleRate= " << sampleIdx << " SampleProb= " << sampleRateInfo.ewmaProb);
1125 
1126  if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2
1127  && sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1128  {
1129 
1135  uint32_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1136  uint32_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1137  uint32_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1138  uint32_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1139  uint32_t maxProbRateId = GetRateId (station->m_maxProbRate);
1140 
1141  uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1142  uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1143 
1144  Time sampleDuration = sampleRateInfo.perfectTxTime;
1145  Time maxTp2Duration = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1146  Time maxProbDuration = station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].perfectTxTime;
1147 
1148  NS_LOG_DEBUG ("Use sample rate? SampleDuration= " << sampleDuration << " maxTp2Duration= " << maxTp2Duration <<
1149  " maxProbDuration= " << maxProbDuration << " sampleStreams= " << +sampleStreams <<
1150  " maxTpStreams= " << +maxTpStreams);
1151  if (sampleDuration < maxTp2Duration || (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1152  {
1154  station->m_isSampling = true;
1155 
1157  station->m_sampleRate = sampleIdx;
1158 
1159  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1160  station->m_sampleTries--;
1161  return sampleIdx;
1162  }
1163  else
1164  {
1165  station->m_numSamplesSlow++;
1166  if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1167  {
1169  station->m_isSampling = true;
1170 
1172  station->m_sampleRate = sampleIdx;
1173 
1174  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1175  station->m_sampleTries--;
1176  return sampleIdx;
1177  }
1178  }
1179  }
1180  }
1181  }
1182  if (station->m_sampleWait > 0)
1183  {
1184  station->m_sampleWait--;
1185  }
1186 
1188 
1189  NS_LOG_DEBUG ("FindRate " << "maxTpRrate=" << station->m_maxTpRate);
1190  return station->m_maxTpRate;
1191 }
1192 void
1194 {
1195  NS_LOG_FUNCTION (this << station);
1196 
1198 
1199  station->m_numSamplesSlow = 0;
1200  station->m_sampleCount = 0;
1201 
1202  double tempProb;
1203 
1204  if (station->m_ampduPacketCount > 0)
1205  {
1206  double newLen = station->m_ampduLen / station->m_ampduPacketCount;
1207  station->m_avgAmpduLen = ( newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel) ) / 100;
1208  station->m_ampduLen = 0;
1209  station->m_ampduPacketCount = 0;
1210  }
1211 
1212  /* Initialize global rate indexes */
1213  station->m_maxTpRate = GetLowestIndex (station);
1214  station->m_maxTpRate2 = GetLowestIndex (station);
1215  station->m_maxProbRate = GetLowestIndex (station);
1216 
1218  for (uint8_t j = 0; j < m_numGroups; j++)
1219  {
1220  if (station->m_groupsTable[j].m_supported)
1221  {
1222  station->m_sampleCount++;
1223 
1224  /* (re)Initialize group rate indexes */
1225  station->m_groupsTable[j].m_maxTpRate = GetLowestIndex (station, j);
1226  station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex (station, j);
1227  station->m_groupsTable[j].m_maxProbRate = GetLowestIndex (station, j);
1228 
1229  for (uint8_t i = 0; i < m_numRates; i++)
1230  {
1231  if (station->m_groupsTable[j].m_ratesTable[i].supported)
1232  {
1233  station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1234 
1235  NS_LOG_DEBUG (i << " " << GetMcsSupported (station, station->m_groupsTable[j].m_ratesTable[i].mcsIndex) <<
1236  "\t attempt=" << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt <<
1237  "\t success=" << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1238 
1240  if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1241  {
1242  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1247  tempProb = (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) / station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1248 
1250  station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1251 
1252  if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1253  {
1254  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1255  }
1256  else
1257  {
1258  station->m_groupsTable[j].m_ratesTable[i].ewmsdProb = CalculateEwmsd (station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1259  tempProb, station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1260  m_ewmaLevel);
1262  tempProb = (tempProb * (100 - m_ewmaLevel) + station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) / 100;
1263  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1264  }
1265 
1266  station->m_groupsTable[j].m_ratesTable[i].throughput = CalculateThroughput (station, j, i, tempProb);
1267 
1268  station->m_groupsTable[j].m_ratesTable[i].successHist += station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1269  station->m_groupsTable[j].m_ratesTable[i].attemptHist += station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1270  }
1271  else
1272  {
1273  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1274  }
1275 
1277  station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess = station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1278  station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt = station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1279  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1280  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1281 
1282  if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1283  {
1284  SetBestStationThRates (station, GetIndex (j, i));
1285  SetBestProbabilityRate (station, GetIndex (j, i));
1286  }
1287 
1288  }
1289  }
1290  }
1291  }
1292 
1293  //Try to sample all available rates during each interval.
1294  station->m_sampleCount *= 8;
1295 
1296  //Recalculate retries for the rates selected.
1297  CalculateRetransmits (station, station->m_maxTpRate);
1298  CalculateRetransmits (station, station->m_maxTpRate2);
1299  CalculateRetransmits (station, station->m_maxProbRate);
1300 
1301  NS_LOG_DEBUG ("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2 << "\nmax prob=" << station->m_maxProbRate);
1302  if (m_printStats)
1303  {
1304  PrintTable (station);
1305  }
1306 }
1307 
1308 double
1309 MinstrelHtWifiManager::CalculateThroughput (MinstrelHtWifiRemoteStation *station, uint32_t groupId, uint32_t rateId, double ewmaProb)
1310 {
1316  if (ewmaProb < 10)
1317  {
1318  return 0;
1319  }
1320  else
1321  {
1326  Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1327  if (ewmaProb > 90)
1328  {
1329  return 90 / txTime.GetSeconds ();
1330  }
1331  else
1332  {
1333  return ewmaProb / txTime.GetSeconds ();
1334  }
1335  }
1336 }
1337 
1338 void
1340 {
1341  GroupInfo *group;
1342  HtRateInfo rate;
1343  uint32_t tmpGroupId, tmpRateId;
1344  double tmpTh, tmpProb;
1345  uint32_t groupId, rateId;
1346  double currentTh;
1347  // maximum group probability (GP) variables
1348  uint32_t maxGPGroupId, maxGPRateId;
1349  double maxGPTh;
1350 
1351  groupId = GetGroupId (index);
1352  rateId = GetRateId (index);
1353  group = &station->m_groupsTable[groupId];
1354  rate = group->m_ratesTable[rateId];
1355 
1356  tmpGroupId = GetGroupId (station->m_maxProbRate);
1357  tmpRateId = GetRateId (station->m_maxProbRate);
1358  tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1359  tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1360 
1361  if (rate.ewmaProb > 75)
1362  {
1363  currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1364  if (currentTh > tmpTh)
1365  {
1366  station->m_maxProbRate = index;
1367  }
1368 
1369  maxGPGroupId = GetGroupId (group->m_maxProbRate);
1370  maxGPRateId = GetRateId (group->m_maxProbRate);
1371  maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1372 
1373  if (currentTh > maxGPTh)
1374  {
1375  group->m_maxProbRate = index;
1376  }
1377  }
1378  else
1379  {
1380  if (rate.ewmaProb > tmpProb)
1381  {
1382  station->m_maxProbRate = index;
1383  }
1384  maxGPRateId = GetRateId (group->m_maxProbRate);
1385  if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1386  {
1387  group->m_maxProbRate = index;
1388  }
1389  }
1390 }
1391 
1392 /*
1393  * Find & sort topmost throughput rates
1394  *
1395  * If multiple rates provide equal throughput the sorting is based on their
1396  * current success probability. Higher success probability is preferred among
1397  * MCS groups.
1398  */
1399 void
1401 {
1402  uint32_t groupId, rateId;
1403  double th, prob;
1404  uint32_t maxTpGroupId, maxTpRateId;
1405  uint32_t maxTp2GroupId, maxTp2RateId;
1406  double maxTpTh, maxTpProb;
1407  double maxTp2Th, maxTp2Prob;
1408 
1409  groupId = GetGroupId (index);
1410  rateId = GetRateId (index);
1411  prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1412  th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1413 
1414  maxTpGroupId = GetGroupId (station->m_maxTpRate);
1415  maxTpRateId = GetRateId (station->m_maxTpRate);
1416  maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1417  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1418 
1419  maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1420  maxTp2RateId = GetRateId (station->m_maxTpRate2);
1421  maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1422  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1423 
1424  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1425  {
1426  station->m_maxTpRate2 = station->m_maxTpRate;
1427  station->m_maxTpRate = index;
1428  }
1429  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1430  {
1431  station->m_maxTpRate2 = index;
1432  }
1433 
1434  //Find best rates per group
1435 
1436  GroupInfo *group = &station->m_groupsTable[groupId];
1437  maxTpGroupId = GetGroupId (group->m_maxTpRate);
1438  maxTpRateId = GetRateId (group->m_maxTpRate);
1439  maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1440  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1441 
1442  maxTp2GroupId = GetGroupId (group->m_maxTpRate2);
1443  maxTp2RateId = GetRateId (group->m_maxTpRate2);
1444  maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1445  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1446 
1447  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1448  {
1449  group->m_maxTpRate2 = group->m_maxTpRate;
1450  group->m_maxTpRate = index;
1451  }
1452  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1453  {
1454  group->m_maxTpRate2 = index;
1455  }
1456 }
1457 
1458 void
1460 {
1461  NS_LOG_FUNCTION (this << station);
1462 
1463  station->m_groupsTable = McsGroupData (m_numGroups);
1464 
1468  NS_LOG_DEBUG ("Supported groups by station:");
1469  for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1470  {
1471  if (m_minstrelGroups[groupId].isSupported)
1472  {
1473  station->m_groupsTable[groupId].m_supported = false;
1474  if (!(!GetVhtSupported (station) && m_minstrelGroups[groupId].isVht)
1475  && (m_minstrelGroups[groupId].isVht || !GetVhtSupported (station) || !m_useVhtOnly)
1476  && !(!GetShortGuardInterval (station) && m_minstrelGroups[groupId].sgi)
1477  && (GetChannelWidth (station) >= m_minstrelGroups[groupId].chWidth)
1478  && (GetNumberOfSupportedStreams (station) >= m_minstrelGroups[groupId].streams))
1479  {
1480  NS_LOG_DEBUG ("Group " << groupId << ": (" << +m_minstrelGroups[groupId].streams <<
1481  "," << +m_minstrelGroups[groupId].sgi << "," << +m_minstrelGroups[groupId].chWidth << ")");
1482 
1483  station->m_groupsTable[groupId].m_supported = true;
1484  station->m_groupsTable[groupId].m_col = 0;
1485  station->m_groupsTable[groupId].m_index = 0;
1486 
1487  station->m_groupsTable[groupId].m_ratesTable = HtMinstrelRate (m_numRates);
1488  for (uint8_t i = 0; i < m_numRates; i++)
1489  {
1490  station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1491  }
1492 
1493  // Initialize all modes supported by the remote station that belong to the current group.
1494  for (uint8_t i = 0; i < station->m_nModes; i++)
1495  {
1496  WifiMode mode = GetMcsSupported (station, i);
1497 
1500  uint32_t rateId = mode.GetMcsValue ();
1501  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1502  {
1503  rateId %= MAX_HT_GROUP_RATES;
1504  }
1505 
1506  if ((m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_VHT
1507  && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1508  || (!m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_HT
1509  && mode.GetMcsValue () < (m_minstrelGroups[groupId].streams * 8)
1510  && mode.GetMcsValue () >= ((m_minstrelGroups[groupId].streams - 1) * 8)))
1511  {
1512  NS_LOG_DEBUG ("Mode " << i << ": " << mode << " isVht: " << m_minstrelGroups[groupId].isVht);
1513 
1514  station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1515  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex = i;
1516  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1517  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1518  station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1519  station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1520  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1521  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1522  station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1523  station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1524  station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1525  station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1526  station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
1527  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1528  station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1529  CalculateRetransmits (station, groupId, rateId);
1530  }
1531  }
1532  }
1533  }
1534  }
1535  SetNextSample (station);
1536  UpdateStats (station);
1537  station->m_txrate = FindRate (station);
1538 }
1539 
1540 void
1542 {
1543  NS_LOG_FUNCTION (this << station << index);
1544  uint32_t groupId = GetGroupId (index);
1545  uint32_t rateId = GetRateId (index);
1546  if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1547  {
1548  CalculateRetransmits (station, groupId, rateId);
1549  }
1550 }
1551 
1552 void
1554 {
1555  NS_LOG_FUNCTION (this << station << groupId << groupId);
1556  NS_LOG_DEBUG (" Calculating the number of retries");
1557 
1558  uint32_t cw = 15; // Is an approximation.
1559  uint32_t cwMax = 1023;
1560  Time cwTime, txTime, dataTxTime;
1561  Time slotTime = GetMac ()->GetSlot ();
1562  Time ackTime = GetMac ()->GetBasicBlockAckTimeout ();
1563 
1564  if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1565  {
1566  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1567  }
1568  else
1569  {
1570  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1571  station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1572 
1573  dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1574  GetMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) * (station->m_avgAmpduLen - 1);
1575 
1576  /* Contention time for first 2 tries */
1577  cwTime = (cw / 2) * slotTime;
1578  cw = Min ((cw + 1) * 2, cwMax);
1579  cwTime += (cw / 2) * slotTime;
1580  cw = Min ((cw + 1) * 2, cwMax);
1581 
1582  /* Total TX time for data and Contention after first 2 tries */
1583  txTime = cwTime + 2 * (dataTxTime + ackTime);
1584 
1585  /* See how many more tries we can fit inside segment size */
1586  do
1587  {
1588  /* Contention time for this try */
1589  cwTime = (cw / 2) * slotTime;
1590  cw = Min ((cw + 1) * 2, cwMax);
1591 
1592  /* Total TX time after this try */
1593  txTime += cwTime + ackTime + dataTxTime;
1594  }
1595  while ((txTime < MilliSeconds (6))
1596  && (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1597  }
1598 }
1599 
1600 double
1601 MinstrelHtWifiManager::CalculateEwmsd (double oldEwmsd, double currentProb, double ewmaProb, uint32_t weight)
1602 {
1603  double diff, incr, tmp;
1604 
1605  /* calculate exponential weighted moving variance */
1606  diff = currentProb - ewmaProb;
1607  incr = (100 - weight) * diff / 100;
1608  tmp = oldEwmsd * oldEwmsd;
1609  tmp = weight * (tmp + diff * incr) / 100;
1610 
1611  /* return standard deviation */
1612  return sqrt (tmp);
1613 }
1614 
1615 void
1617 {
1618  NS_LOG_DEBUG ("InitSampleTable=" << this);
1619 
1620  station->m_col = station->m_index = 0;
1621 
1622  //for off-setting to make rates fall between 0 and nModes
1623  uint8_t numSampleRates = m_numRates;
1624 
1625  uint32_t newIndex;
1626  for (uint32_t col = 0; col < m_nSampleCol; col++)
1627  {
1628  for (uint32_t i = 0; i < numSampleRates; i++ )
1629  {
1634  int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
1635  newIndex = (i + uv) % numSampleRates;
1636 
1637  //this loop is used for filling in other uninitialized places
1638  while (station->m_sampleTable[newIndex][col] != 0)
1639  {
1640  newIndex = (newIndex + 1) % m_numRates;
1641  }
1642  station->m_sampleTable[newIndex][col] = i;
1643  }
1644  }
1645 }
1646 
1647 void
1649 {
1650  NS_LOG_FUNCTION (this << station);
1651  NS_LOG_DEBUG ("PrintTable=" << station);
1652 
1653  station->m_statsFile << " best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n" <<
1654  " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n";
1655  for (uint8_t i = 0; i < m_numGroups; i++)
1656  {
1657  StatsDump (station, i, station->m_statsFile);
1658  }
1659 
1660  station->m_statsFile << "\nTotal packet count:: ideal " << Max (0, station->m_totalPacketsCount - station->m_samplePacketsCount) <<
1661  " lookaround " << station->m_samplePacketsCount << "\n";
1662  station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen << "\n\n";
1663 
1664  station->m_statsFile.flush ();
1665 }
1666 
1667 void
1668 MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint32_t groupId, std::ofstream &of)
1669 {
1670  uint8_t numRates = m_numRates;
1671  McsGroup group = m_minstrelGroups[groupId];
1672  Time txTime;
1673  char giMode;
1674  if (group.sgi)
1675  {
1676  giMode = 'S';
1677  }
1678  else
1679  {
1680  giMode = 'L';
1681  }
1682  for (uint8_t i = 0; i < numRates; i++)
1683  {
1684  if (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[i].supported)
1685  {
1686  if (!group.isVht)
1687  {
1688  of << "HT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1689  }
1690  else
1691  {
1692  of << "VHT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1693  }
1694 
1695  uint32_t maxTpRate = station->m_maxTpRate;
1696  uint32_t maxTpRate2 = station->m_maxTpRate2;
1697  uint32_t maxProbRate = station->m_maxProbRate;
1698 
1699  uint32_t idx = GetIndex (groupId, i);
1700  if (idx == maxTpRate)
1701  {
1702  of << 'A';
1703  }
1704  else
1705  {
1706  of << ' ';
1707  }
1708  if (idx == maxTpRate2)
1709  {
1710  of << 'B';
1711  }
1712  else
1713  {
1714  of << ' ';
1715  }
1716  if (idx == maxProbRate)
1717  {
1718  of << 'P';
1719  }
1720  else
1721  {
1722  of << ' ';
1723  }
1724 
1725  if (!group.isVht)
1726  {
1727  of << std::setw (4) << " MCS" << (group.streams - 1) * 8 + i;
1728  }
1729  else
1730  {
1731  of << std::setw (7) << " MCS" << i << "/" << (int) group.streams;
1732  }
1733 
1734  of << " " << std::setw (3) << idx << " ";
1735 
1736  /* tx_time[rate(i)] in usec */
1737  txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
1738  of << std::setw (6) << txTime.GetMicroSeconds () << " ";
1739 
1740  of << std::setw (7) << CalculateThroughput (station, groupId, i, 100) / 100 << " " <<
1741  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100 << " " <<
1742  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb << " " <<
1743  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb << " " <<
1744  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].prob << " " <<
1745  std::setw (2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount << " " <<
1746  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " " <<
1747  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt << " " <<
1748  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " " <<
1749  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist << "\n";
1750  }
1751  }
1752 }
1753 uint32_t
1754 MinstrelHtWifiManager::GetIndex (uint32_t groupId, uint32_t rateId)
1755 {
1756  NS_LOG_FUNCTION (this << groupId << rateId);
1757  uint32_t index;
1758  index = groupId * m_numRates + rateId;
1759  return index;
1760 }
1761 
1762 uint32_t
1764 {
1765  NS_LOG_FUNCTION (this << index);
1766  uint32_t id;
1767  id = index % m_numRates;
1768  return id;
1769 }
1770 
1771 uint32_t
1773 {
1774  NS_LOG_FUNCTION (this << index);
1775  return index / m_numRates;
1776 }
1777 
1778 uint32_t
1779 MinstrelHtWifiManager::GetHtGroupId (uint8_t txstreams, uint8_t sgi, uint8_t chWidth)
1780 {
1781  NS_LOG_FUNCTION (this << +txstreams << +sgi << +chWidth);
1782  return MAX_SUPPORTED_STREAMS * 2 * (chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
1783 }
1784 
1785 uint32_t
1786 MinstrelHtWifiManager::GetVhtGroupId (uint8_t txstreams, uint8_t sgi, uint8_t chWidth)
1787 {
1788  NS_LOG_FUNCTION (this << +txstreams << +sgi << +chWidth);
1789  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;
1790 }
1791 
1792 uint32_t
1794 {
1795  NS_LOG_FUNCTION (this << station);
1796 
1797  uint32_t groupId = 0;
1798  uint32_t rateId = 0;
1799  while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
1800  {
1801  groupId++;
1802  }
1803  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1804  {
1805  rateId++;
1806  }
1807  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1808  return GetIndex (groupId, rateId);
1809 }
1810 
1811 uint32_t
1813 {
1814  NS_LOG_FUNCTION (this << station);
1815 
1816  uint32_t rateId = 0;
1817  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1818  {
1819  rateId++;
1820  }
1821  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1822  return GetIndex (groupId, rateId);
1823 }
1824 
1827 {
1828  WifiModeList vhtMcsList;
1829  Ptr<WifiPhy> phy = GetPhy ();
1830  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1831  {
1832  WifiMode mode = phy->GetMcs (i);
1833  if (mode.GetModulationClass () == WIFI_MOD_CLASS_VHT)
1834  {
1835  vhtMcsList.push_back (mode);
1836  }
1837  }
1838  return vhtMcsList;
1839 }
1840 
1843 {
1844  WifiModeList htMcsList;
1845  Ptr<WifiPhy> phy = GetPhy ();
1846  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1847  {
1848  WifiMode mode = phy->GetMcs (i);
1849  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1850  {
1851  htMcsList.push_back (mode);
1852  }
1853  }
1854  return htMcsList;
1855 }
1856 
1857 void
1859 {
1860  //HE is not supported yet by this algorithm.
1861  if (enable)
1862  {
1863  NS_FATAL_ERROR ("WifiRemoteStationManager selected does not support HE rates");
1864  }
1865 }
1866 
1867 } // 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.
bool GetVhtSupported(Mac48Address address) const
Return whether the station supports VHT or not.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
bool GetShortGuardInterval(Mac48Address address) const
Return whether the station supports HT/VHT short guard interval.
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 "...
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
AttributeValue implementation for Boolean.
Definition: boolean.h:36
double CalculateThroughput(MinstrelHtWifiRemoteStation *station, uint32_t groupId, uint32_t rateId, double ewmaProb)
Return the average throughput of the MCS defined by groupId and rateId.
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.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
WifiModeList GetHtDeviceMcsList(void) const
Returns a list of only the HT MCS supported by the device.
void PrintTable(MinstrelHtWifiRemoteStation *station)
Printing Minstrel Table.
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.
uint32_t GetLowestIndex(MinstrelHtWifiRemoteStation *station)
Returns the lowest global index of the rates supported by the station.
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
uint32_t m_maxProbRate
The highest success probability rate of this group.
double CalculateEwmsd(double oldEwmsd, double currentProb, double ewmaProb, uint32_t weight)
Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation.
MinstrelHtWifiRemoteStation structure.
WifiTxVector DoGetDataTxVector(WifiRemoteStation *station)
hold per-remote-station state for Minstrel Wifi manager.
uint32_t m_ampduPacketCount
Number of A-MPDUs transmitted.
uint32_t GetIndex(uint32_t groupId, uint32_t rateId)
Returns the global index corresponding to the groupId and rateId.
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...
#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:201
uint32_t m_sampleRate
current sample rate
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1015
uint32_t m_maxTpRate
The max throughput rate of this group.
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.
void StatsDump(MinstrelHtWifiRemoteStation *station, uint32_t index, std::ofstream &of)
Print group statistics.
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:277
#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)
uint32_t m_txrate
current transmit rate
uint32_t GetHtGroupId(uint8_t txstreams, uint8_t sgi, uint8_t chWidth)
Returns the groupId of a HT MCS with the given number of streams, if using sgi and the channel width ...
uint8_t GetNMcs(void) const
The WifiPhy::GetNMcs() method is used (e.g., by a WifiRemoteStationManager) to determine the set of t...
Definition: wifi-phy.cc:3582
void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode)
This method is a pure virtual method that must be implemented by the sub-class.
bool DoNeedDataRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally)
VHT PHY (Clause 22)
Definition: wifi-mode.h:60
MinstrelRate m_minstrelTable
minstrel table
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
uint32_t m_maxTpRate2
The second max throughput rate of this group.
uint16_t GetFrequency(void) const
Definition: wifi-phy.cc:1260
represent a single transmission modeA WifiMode is implemented by a single integer which is used to lo...
Definition: wifi-mode.h:97
bool GetAggregation(const WifiRemoteStation *station) const
Return whether the given station supports A-MPDU.
bool GetStbc(void) const
Return whether STBC is supported.
Definition: wifi-phy.cc:595
uint8_t m_nModes
number of modes supported
WifiRemoteStationState * m_state
Remote station state.
bool m_printStats
If statistics table should be printed.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:446
Ptr< WifiPhy > GetPhy(void) const
Return the WifiPhy.
Time CalculateTxDuration(uint32_t size, WifiTxVector txVector, uint16_t frequency)
Definition: wifi-phy.cc:2301
bool IsValid(void) const
The standard disallows certain combinations of WifiMode, number of spatial streams, and channel widths.
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:355
uint8_t GetNBasicModes(void) const
Return the number of basic modes we support.
static uint8_t GetChannelWidthForTransmission(WifiMode mode, uint8_t maxSupportedChannelWidth)
Return the channel width that corresponds to the selected mode (instead of letting the PHY's default ...
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:197
void AddFirstMpduTxTime(uint32_t groupId, WifiMode mode, Time t)
Save a TxTime to the vector of groups.
virtual uint32_t GetInteger(void)=0
Get the next random value as an integer drawn from the distribution.
NS_ASSERT_MSG(false,"Ipv4AddressGenerator::MaskToIndex(): Impossible")
tuple phy
Definition: third.py:86
bool m_isSampling
a flag to indicate we are currently sampling
WifiTxVector DoGetRtsTxVector(WifiRemoteStation *station)
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:363
AttributeValue implementation for Time.
Definition: nstime.h:1069
double m_ewmaLevel
Exponential weighted moving average level (or coefficient).
void CalculateRetransmits(MinstrelHtWifiRemoteStation *station, uint32_t index)
Calculate the number of retransmissions to set for the index rate.
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.
Time GetMpduTxTime(uint32_t groupId, WifiMode mode) const
Obtain the TXtime saved in the group information.
static const uint8_t MAX_HT_WIDTH
Maximal channel width.
bool IsValidMcs(Ptr< WifiPhy > phy, uint8_t streams, uint8_t chWidth, WifiMode mode)
Check the validity of a combination of number of streams, chWidth and mode.
WifiPreamble GetPreambleForTransmission(WifiMode mode, Mac48Address dest)
Return the preamble to be used for the transmission.
uint64_t GetDataRate(uint8_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:143
uint8_t GetChannelWidth(const WifiRemoteStation *station) const
Return the channel width supported by the station.
uint8_t streams
streams
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(uint8_t mode) const
The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used (e.g., by a WifiRemoteStationManager...
Definition: wifi-phy.cc:3576
HT PHY (Clause 20)
Definition: wifi-mode.h:58
uint8_t GetMcsValue(void) const
Definition: wifi-mode.cc:465
uint32_t GetRateId(uint32_t index)
For managing rates from different groups, a global index for all rates in all groups is used...
uint32_t m_sampleWait
How many transmission attempts to wait until a new sample.
Mac48Address GetAddress(const WifiRemoteStation *station) const
Return the address of the station.
tuple mac
Definition: third.py:92
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.
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 GetNess(const WifiRemoteStation *station) const
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...
WifiRemoteStation * DoCreateStation(void) const
Time CalculateFirstMpduTxDuration(Ptr< WifiPhy > phy, uint8_t streams, uint8_t sgi, uint8_t chWidth, WifiMode mode)
Estimates the TxTime of a frame with a given mode and group (stream, guard interval and channel width...
WifiMode GetMcs(uint8_t mcs) const
The WifiPhy::GetMcs() method is used (e.g., by a WifiRemoteStationManager) to determine the set of tr...
Definition: wifi-phy.cc:3588
double ewmaProb
Exponential weighted moving average of probability.
Time perfectTxTime
Perfect transmission time calculation, or frame calculation.
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.
uint32_t m_maxTpRate2
second highest throughput rate
void SetBestStationThRates(MinstrelHtWifiRemoteStation *station, uint32_t index)
Set index rate as maxTpRate or maxTp2Rate if is better than current values.
void InitSampleTable(MinstrelHtWifiRemoteStation *station)
Initialize Sample Table.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
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_nSampleCol
Number of sample columns.
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.
uint8_t m_numGroups
Number of groups Minstrel should consider.
void SetHeSupported(bool enable)
Enable or disable HE capability support.
Time m_updateStats
How frequent do we calculate the stats (1/10 seconds).
bool HasVhtSupported(void) const
Return whether the device has VHT capability support enabled.
static const uint8_t MAX_HT_GROUP_RATES
Number of rates (or MCS) per HT group.
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:1070
std::vector< WifiMode > WifiModeList
In various parts of the code, folk are interested in maintaining a list of transmission modes...
Definition: wifi-mode.h:251
uint32_t GetVhtGroupId(uint8_t txstreams, uint8_t sgi, uint8_t chWidth)
Returns the groupId of a VHT MCS with the given number of streams, if using sgi and the channel width...
WifiModeList GetVhtDeviceMcsList(void) const
Returns a list of only the VHT MCS supported by the device.
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:249
double m_ampduLen
Number of MPDUs in an A-MPDU.
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.
WifiMode GetBasicMode(uint8_t i) const
Return a basic mode from the set of basic modes.
int m_totalPacketsCount
total number of packets as of now
uint64_t GetNonHtReferenceRate(void) const
Definition: wifi-mode.cc:494
Implementation of Minstrel HT Rate Control AlgorithmMinstrel-HT is a rate adaptation mechanism for th...
uint32_t FindRate(MinstrelHtWifiRemoteStation *station)
Find a rate to use from Minstrel Table.
void SetupPhy(const Ptr< WifiPhy > phy)
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
bool HasHtSupported(void) const
Return whether the device has HT capability support enabled.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
Data structure to contain the information that defines a group.
WifiMode GetMcsSupported(const WifiRemoteStation *station, uint8_t i) const
Return the WifiMode supported by the specified station at the specified index.
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: double.h:42
void DoInitialize(void)
Initialize() implementation.
Time CalculateMpduTxDuration(Ptr< WifiPhy > phy, uint8_t streams, uint8_t sgi, uint8_t chWidth, WifiMode mode)
Estimates the TxTime of a frame with a given mode and group (stream, guard interval and channel width...
int m_samplePacketsCount
how many packets we have sample so far
double m_lookAroundRate
The % to try other rates than our current rate.
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...
uint32_t m_maxProbRate
rate with highest prob of success
if(desigRtr==addrLocal)
std::vector< McsGroup > MinstrelMcsGroups
Data structure for a table of group definitions.
uint8_t GetNumberOfSupportedStreams(Mac48Address address) const
Return the number of spatial streams supported by the station.
void AddMpduTxTime(uint32_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.
uint32_t m_maxTpRate
the current throughput rate
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:269
uint32_t m_numSamplesSlow
Number of times a slow rate was sampled.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1007
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 GetGroupId(uint32_t index)
Return the groupId from the global index.
void SetBestProbabilityRate(MinstrelHtWifiRemoteStation *station, uint32_t index)
Set index rate as maxProbRate if it is better than current value.
uint32_t m_sampleTries
Number of sample tries after waiting sampleWait.
uint8_t chWidth
channel width (MHz)
void SetNess(uint8_t ness)
Sets the Ness number refer to IEEE 802.11n Table 20-6 for explanation.
Time GetFirstMpduTxTime(uint32_t groupId, WifiMode mode) const
Obtain the TXtime saved in the group information.
void SetChannelWidth(uint8_t channelWidth)
Sets the selected channelWidth (in MHz)
bool GetHtSupported(Mac48Address address) const
Return whether the station supports HT or not.
uint32_t CountRetries(MinstrelHtWifiRemoteStation *station)
Count retries.
TracedCallback< uint64_t, Mac48Address > m_rateChange
The trace source fired when the transmission rate change.
WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:487
WifiMode GetMode(void) const
void UpdateRate(MinstrelHtWifiRemoteStation *station)
Update rate.
uint32_t GetNextSample(MinstrelHtWifiRemoteStation *station)
Getting the next sample from Sample Table.
The MPDU is part of an A-MPDU, but is not the last aggregate.
Definition: wifi-phy.h:66
double m_avgAmpduLen
Average number of MPDUs in an A-MPDU.
uint32_t m_shortRetry
short retries such as control packts
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.
This class can be used to hold variables of floating point type such as 'double' or 'float'...
Definition: double.h:41
uint8_t GetNMcsSupported(Mac48Address address) const
Return the number of MCS supported by the station.
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
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:914
std::vector< std::vector< uint32_t > > SampleRate
Data structure for a Sample Rate table A vector of a vector uint32_t.
void CheckInit(MinstrelHtWifiRemoteStation *station)
Check for initializations.
uint32_t m_sampleGroup
The group that the sample rate belongs to.
hold per-remote-station state.
uint8_t GetNModes(void) const
The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used (e.g., by a WifiRemoteStationManager...
Definition: wifi-phy.cc:3570
Ptr< WifiMac > GetMac(void) const
Return the WifiMac.
Time m_nextStatsUpdate
10 times every second