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