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 {
57  void DisposeStation ();
58 
59  uint32_t m_sampleGroup;
60 
61  uint32_t m_sampleWait;
62  uint32_t m_sampleTries;
63  uint32_t m_sampleCount;
64  uint32_t m_numSamplesSlow;
65 
66  double m_avgAmpduLen;
67  double m_ampduLen;
68  uint32_t m_ampduPacketCount;
69 
71  bool m_isHt;
72 
73  std::ofstream m_statsFile;
74 };
75 
76 void
78 {
79  if (m_isHt)
80  {
81  std::vector<std::vector<uint32_t> > ().swap (m_sampleTable);
82  for (uint8_t j = 0; j < m_groupsTable.size (); j++)
83  {
84  std::vector<HtRateInfo> ().swap (m_groupsTable[j].m_ratesTable);
85  }
86  std::vector<GroupInfo> ().swap (m_groupsTable);
87  m_statsFile.close ();
88  }
89 }
90 
92 
93 TypeId
95 {
96  static TypeId tid = TypeId ("ns3::MinstrelHtWifiManager")
98  .AddConstructor<MinstrelHtWifiManager> ()
99  .SetGroupName ("Wifi")
100  .AddAttribute ("UpdateStatistics",
101  "The interval between updating statistics table ",
102  TimeValue (MilliSeconds (100)),
104  MakeTimeChecker ())
105  .AddAttribute ("LookAroundRate",
106  "The percentage to try other rates (for legacy Minstrel)",
107  DoubleValue (10),
109  MakeDoubleChecker<double> (0, 100))
110  .AddAttribute ("EWMA",
111  "EWMA level",
112  DoubleValue (75),
114  MakeDoubleChecker<double> (0, 100))
115  .AddAttribute ("SampleColumn",
116  "The number of columns used for sampling",
117  UintegerValue (10),
119  MakeUintegerChecker <uint32_t> ())
120  .AddAttribute ("PacketLength",
121  "The packet length used for calculating mode TxTime",
122  UintegerValue (1200),
124  MakeUintegerChecker <uint32_t> ())
125  .AddAttribute ("UseVhtOnly",
126  "Use only VHT MCSs (and not HT) when VHT is available",
127  BooleanValue (true),
130  .AddAttribute ("PrintStats",
131  "Control the printing of the statistics table",
132  BooleanValue (false),
135  .AddTraceSource ("RateChange",
136  "The transmission rate has changed",
138  "ns3::MinstrelHtWifiManager::RateChangeTracedCallback")
139  ;
140  return tid;
141 }
142 
144  : m_numGroups (0),
145  m_numRates (0)
146 {
147  NS_LOG_FUNCTION (this);
148  m_uniformRandomVariable = CreateObject<UniformRandomVariable> ();
153  m_legacyManager = CreateObject<MinstrelWifiManager> ();
154 }
155 
157 {
158  NS_LOG_FUNCTION (this);
159  if (HasHtSupported ())
160  {
161  for (uint32_t i = 0; i < m_numGroups; i++)
162  {
163  m_minstrelGroups[i].ratesFirstMpduTxTimeTable.clear ();
164  m_minstrelGroups[i].ratesTxTimeTable.clear ();
165  }
166  }
167 }
168 
169 int64_t
171 {
172  NS_LOG_FUNCTION (this << stream);
173  int64_t numStreamsAssigned = 0;
175  numStreamsAssigned++;
176  numStreamsAssigned += m_legacyManager->AssignStreams (stream);
177  return numStreamsAssigned;
178 }
179 
180 void
182 {
183  NS_LOG_FUNCTION (this << phy);
184  // Setup phy for legacy manager.
185  m_legacyManager->SetupPhy (phy);
187 }
188 
189 void
191 {
192  NS_LOG_FUNCTION (this);
193 
200  // Check if the device supports HT or VHT
201  if (HasHtSupported () || HasVhtSupported ())
202  {
205 
206  if (HasVhtSupported ())
207  {
210  }
211 
222  NS_LOG_DEBUG ("Initialize MCS Groups:");
224 
225  // Initialize all HT groups
226  for (uint8_t chWidth = 20; chWidth <= MAX_HT_WIDTH; chWidth *= 2)
227  {
228  for (uint8_t sgi = 0; sgi <= 1; sgi++)
229  {
230  for (uint8_t streams = 1; streams <= MAX_SUPPORTED_STREAMS; streams++)
231  {
232  uint32_t groupId = GetHtGroupId (streams, sgi, chWidth);
233 
234  m_minstrelGroups[groupId].streams = streams;
235  m_minstrelGroups[groupId].sgi = sgi;
236  m_minstrelGroups[groupId].chWidth = chWidth;
237  m_minstrelGroups[groupId].isVht = false;
238  m_minstrelGroups[groupId].isSupported = false;
239 
240  // Check capabilities of the device
241  if (!(!GetPhy ()->GetShortGuardInterval () && m_minstrelGroups[groupId].sgi)
242  && (GetPhy ()->GetChannelWidth () >= m_minstrelGroups[groupId].chWidth)
243  && (GetPhy ()->GetMaxSupportedTxSpatialStreams () >= m_minstrelGroups[groupId].streams))
244  {
245  m_minstrelGroups[groupId].isSupported = true;
246 
247  // Calculate tx time for all rates of the group
248  WifiModeList htMcsList = GetHtDeviceMcsList ();
249  for (uint8_t i = 0; i < MAX_HT_GROUP_RATES; i++)
250  {
251  uint32_t deviceIndex = i + (m_minstrelGroups[groupId].streams - 1) * 8;
252  WifiMode mode = htMcsList[deviceIndex];
253  AddFirstMpduTxTime (groupId, mode, CalculateFirstMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
254  AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
255  }
256  NS_LOG_DEBUG ("Initialized group " << groupId << ": (" << (uint16_t)streams << "," << (uint16_t)sgi << "," << (uint16_t)chWidth << ")");
257  }
258  }
259  }
260  }
261 
262  if (HasVhtSupported ())
263  {
264  // Initialize all VHT groups
265  for (uint16_t chWidth = 20; chWidth <= MAX_VHT_WIDTH; chWidth *= 2)
266  {
267  for (uint8_t sgi = 0; sgi <= 1; sgi++)
268  {
269  for (uint8_t streams = 1; streams <= MAX_SUPPORTED_STREAMS; streams++)
270  {
271  uint32_t groupId = GetVhtGroupId (streams, sgi, chWidth);
272 
273  m_minstrelGroups[groupId].streams = streams;
274  m_minstrelGroups[groupId].sgi = sgi;
275  m_minstrelGroups[groupId].chWidth = chWidth;
276  m_minstrelGroups[groupId].isVht = true;
277  m_minstrelGroups[groupId].isSupported = false;
278 
279  // Check capabilities of the device
280  if (!(!GetPhy ()->GetShortGuardInterval () && m_minstrelGroups[groupId].sgi)
281  && (GetPhy ()->GetChannelWidth () >= m_minstrelGroups[groupId].chWidth)
282  && (GetPhy ()->GetMaxSupportedTxSpatialStreams () >= m_minstrelGroups[groupId].streams))
283  {
284  m_minstrelGroups[groupId].isSupported = true;
285 
286  // Calculate tx time for all rates of the group
287  WifiModeList vhtMcsList = GetVhtDeviceMcsList ();
288  for (uint8_t i = 0; i < MAX_VHT_GROUP_RATES; i++)
289  {
290  WifiMode mode = vhtMcsList[i];
291  // Check for invalid VHT MCSs and do not add time to array.
292  if (IsValidMcs (GetPhy (), streams, chWidth, mode))
293  {
294  AddFirstMpduTxTime (groupId, mode, CalculateFirstMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
295  AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode));
296  }
297  }
298  NS_LOG_DEBUG ("Initialized group " << groupId << ": (" << (uint16_t)streams << "," << (uint16_t)sgi << "," << (uint16_t)chWidth << ")");
299  }
300  }
301  }
302  }
303  }
304  }
305 }
306 
307 void
309 {
310  NS_LOG_FUNCTION (this << mac);
311  m_legacyManager->SetupMac (mac);
313 }
314 
315 bool
316 MinstrelHtWifiManager::IsValidMcs (Ptr<WifiPhy> phy, uint8_t streams, uint8_t chWidth, WifiMode mode)
317 {
318  NS_LOG_FUNCTION (this << phy << (uint16_t)streams << (uint16_t)chWidth << mode);
319 
320  WifiTxVector txvector;
321  txvector.SetNss (streams);
322  txvector.SetChannelWidth (chWidth);
323  txvector.SetMode (mode);
324  return phy->IsValidTxVector (txvector);
325 }
326 
327 Time
328 MinstrelHtWifiManager::CalculateFirstMpduTxDuration (Ptr<WifiPhy> phy, uint8_t streams, uint8_t sgi, uint8_t chWidth, WifiMode mode)
329 {
330  NS_LOG_FUNCTION (this << phy << (uint16_t)streams << (uint16_t)sgi << (uint16_t)chWidth << mode);
331 
332  WifiTxVector txvector;
333  txvector.SetNss (streams);
334  txvector.SetGuardInterval (sgi ? 400 : 800);
335  txvector.SetChannelWidth (chWidth);
336  txvector.SetNess (0);
337  txvector.SetStbc (phy->GetStbc ());
338  txvector.SetMode (mode);
340  return phy->CalculateTxDuration (m_frameLength, txvector, phy->GetFrequency (), MPDU_IN_AGGREGATE, 0);
341 }
342 
343 Time
344 MinstrelHtWifiManager::CalculateMpduTxDuration (Ptr<WifiPhy> phy, uint8_t streams, uint8_t sgi, uint8_t chWidth, WifiMode mode)
345 {
346  NS_LOG_FUNCTION (this << phy << (uint16_t)streams << (uint16_t)sgi << (uint16_t)chWidth << mode);
347 
348  WifiTxVector txvector;
349  txvector.SetNss (streams);
350  txvector.SetGuardInterval (sgi ? 400 : 800);
351  txvector.SetChannelWidth (chWidth);
352  txvector.SetNess (0);
353  txvector.SetStbc (phy->GetStbc ());
354  txvector.SetMode (mode);
356  return phy->CalculateTxDuration (m_frameLength, txvector, phy->GetFrequency (), MPDU_IN_AGGREGATE, 0);
357 }
358 
359 Time
361 {
362  NS_LOG_FUNCTION (this << groupId << mode);
363 
364  for (TxTime::const_iterator i = m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.begin (); i != m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.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 
380  m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.push_back (std::make_pair (t, mode));
381 }
382 
383 Time
384 MinstrelHtWifiManager::GetMpduTxTime (uint32_t groupId, WifiMode mode) const
385 {
386  NS_LOG_FUNCTION (this << groupId << mode);
387 
388  for (TxTime::const_iterator i = m_minstrelGroups[groupId].ratesTxTimeTable.begin (); i != m_minstrelGroups[groupId].ratesTxTimeTable.end (); i++)
389  {
390  if (mode == i->second)
391  {
392  return i->first;
393  }
394  }
395  NS_ASSERT (false);
396  return Seconds (0);
397 }
398 
399 void
401 {
402  NS_LOG_FUNCTION (this << groupId << mode << t);
403 
404  m_minstrelGroups[groupId].ratesTxTimeTable.push_back (std::make_pair (t, mode));
405 }
406 
409 {
410  NS_LOG_FUNCTION (this);
411 
413 
414  // Initialize variables common to both stations.
416  station->m_col = 0;
417  station->m_index = 0;
418  station->m_maxTpRate = 0;
419  station->m_maxTpRate2 = 0;
420  station->m_maxProbRate = 0;
421  station->m_nModes = 0;
422  station->m_totalPacketsCount = 0;
423  station->m_samplePacketsCount = 0;
424  station->m_isSampling = false;
425  station->m_sampleRate = 0;
426  station->m_sampleDeferred = false;
427  station->m_shortRetry = 0;
428  station->m_longRetry = 0;
429  station->m_txrate = 0;
430  station->m_initialized = false;
431 
432  // Variables specific to HT station
433  station->m_sampleGroup = 0;
434  station->m_numSamplesSlow = 0;
435  station->m_sampleCount = 16;
436  station->m_sampleWait = 0;
437  station->m_sampleTries = 4;
438 
439  station->m_avgAmpduLen = 1;
440  station->m_ampduLen = 0;
441  station->m_ampduPacketCount = 0;
442 
443  // If the device supports HT
444  if (HasHtSupported () || HasVhtSupported ())
445  {
450  station->m_isHt = true;
451  }
452  // Use the variable in the station to indicate that the device do not support HT
453  else
454  {
455  station->m_isHt = false;
456  }
457 
458  return station;
459 }
460 
461 void
463 {
464  NS_LOG_FUNCTION (this << station);
465 
466  // Note: we appear to be doing late initialization of the table
467  // to make sure that the set of supported rates has been initialized
468  // before we perform our own initialization.
469  if (!station->m_initialized)
470  {
477  if (!GetHtSupported (station) && !GetVhtSupported (station))
478  {
479  NS_LOG_DEBUG ("Non-HT station " << station);
480  station->m_isHt = false;
481  // We will use non-HT minstrel for this station. Initialize the manager.
482  m_legacyManager->SetAttribute ("UpdateStatistics", TimeValue (m_updateStats));
483  m_legacyManager->SetAttribute ("LookAroundRate", DoubleValue (m_lookAroundRate));
484  m_legacyManager->SetAttribute ("EWMA", DoubleValue (m_ewmaLevel));
485  m_legacyManager->SetAttribute ("SampleColumn", UintegerValue (m_nSampleCol));
486  m_legacyManager->SetAttribute ("PacketLength", UintegerValue (m_frameLength));
487  m_legacyManager->SetAttribute ("PrintStats", BooleanValue (m_printStats));
488  m_legacyManager->CheckInit (station);
489  }
490  else
491  {
492  NS_LOG_DEBUG ("HT station " << station);
493  station->m_isHt = true;
494  station->m_nModes = GetNMcsSupported (station);
495  station->m_sampleTable = SampleRate (m_numRates, std::vector<uint32_t> (m_nSampleCol));
496  InitSampleTable (station);
497  RateInit (station);
498  std::ostringstream tmp;
499  tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
500  station->m_statsFile.open (tmp.str ().c_str (), std::ios::out);
501  station->m_initialized = true;
502  }
503  }
504 }
505 
506 void
508  double rxSnr, WifiMode txMode)
509 {
510  NS_LOG_FUNCTION (this << st);
511 
512  NS_LOG_DEBUG ("DoReportRxOk m_txrate=" << ((MinstrelHtWifiRemoteStation *)st)->m_txrate);
513 }
514 
515 void
517 {
518  NS_LOG_FUNCTION (this << st);
519 
521 
522  CheckInit (station);
523  if (!station->m_initialized)
524  {
525  return;
526  }
527 
528  NS_LOG_DEBUG ("DoReportRtsFailed m_txrate=" << station->m_txrate);
529  station->m_shortRetry++;
530 }
531 
532 void
533 MinstrelHtWifiManager::DoReportRtsOk (WifiRemoteStation *st, double ctsSnr, WifiMode ctsMode, double rtsSnr)
534 {
535  NS_LOG_FUNCTION (this << st);
536 
537  NS_LOG_DEBUG ("self=" << st << " rts ok");
538 }
539 
540 void
542 {
543  NS_LOG_FUNCTION (this << st);
544 
546  NS_LOG_DEBUG ("Final RTS failed");
547 
548  CheckInit (station);
549  if (!station->m_initialized)
550  {
551  return;
552  }
553 
554  UpdateRetry (station);
555 }
556 
557 void
559 {
560  NS_LOG_FUNCTION (this << st);
561 
563 
564  CheckInit (station);
565  if (!station->m_initialized)
566  {
567  return;
568  }
569 
570  if (!station->m_isHt)
571  {
572  m_legacyManager->UpdateRate (station);
573  }
574  else
575  {
576  NS_LOG_DEBUG ("DoReportDataFailed " << station << "\t rate " << station->m_txrate << "\tlongRetry \t" << station->m_longRetry);
577 
578  uint32_t rateId = GetRateId (station->m_txrate);
579  uint32_t groupId = GetGroupId (station->m_txrate);
580  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++; // Increment the attempts counter for the rate used.
581 
582  UpdateRate (station);
583  }
584 }
585 
586 void
588  double ackSnr, WifiMode ackMode, double dataSnr)
589 {
590  NS_LOG_FUNCTION (this << st << ackSnr << ackMode << dataSnr);
592 
593  CheckInit (station);
594  if (!station->m_initialized)
595  {
596  return;
597  }
598 
599  NS_LOG_DEBUG ("Data OK - Txrate = " << station->m_txrate );
600 
601  if (!station->m_isHt)
602  {
603  station->m_minstrelTable[station->m_txrate].numRateSuccess++;
604  station->m_minstrelTable[station->m_txrate].numRateAttempt++;
605 
606  m_legacyManager->UpdatePacketCounters (station);
607 
608  UpdateRetry (station);
609  m_legacyManager->UpdateStats (station);
610 
611  if (station->m_nModes >= 1)
612  {
613  station->m_txrate = m_legacyManager->FindRate (station);
614  }
615  }
616  else
617  {
618  uint32_t rateId = GetRateId (station->m_txrate);
619  uint32_t groupId = GetGroupId (station->m_txrate);
620  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
621  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
622 
623  UpdatePacketCounters (station, 1, 0);
624 
625  station->m_isSampling = false;
626  station->m_sampleDeferred = false;
627 
628  UpdateRetry (station);
629  if (Simulator::Now () >= station->m_nextStatsUpdate)
630  {
631  UpdateStats (station);
632  }
633 
634  if (station->m_nModes >= 1)
635  {
636  station->m_txrate = FindRate (station);
637  }
638  }
639 
640  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate );
641 }
642 
643 void
645 {
646  NS_LOG_FUNCTION (this << st);
648 
649  CheckInit (station);
650  if (!station->m_initialized)
651  {
652  return;
653  }
654 
655  NS_LOG_DEBUG ("DoReportFinalDataFailed - TxRate=" << station->m_txrate);
656 
657  if (!station->m_isHt)
658  {
659  m_legacyManager->UpdatePacketCounters (station);
660 
661  UpdateRetry (station);
662 
663  m_legacyManager->UpdateStats (station);
664  if (station->m_nModes >= 1)
665  {
666  station->m_txrate = m_legacyManager->FindRate (station);
667  }
668  }
669  else
670  {
671  UpdatePacketCounters (station, 0, 1);
672 
673  station->m_isSampling = false;
674  station->m_sampleDeferred = false;
675 
676  UpdateRetry (station);
677  if (Simulator::Now () >= station->m_nextStatsUpdate)
678  {
679  UpdateStats (station);
680  }
681 
682  if (station->m_nModes >= 1)
683  {
684  station->m_txrate = FindRate (station);
685  }
686  }
687  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate );
688 }
689 
690 void
691 MinstrelHtWifiManager::DoReportAmpduTxStatus (WifiRemoteStation *st, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus, double rxSnr, double dataSnr)
692 {
693  NS_LOG_FUNCTION (this << st << (uint16_t)nSuccessfulMpdus << (uint16_t)nFailedMpdus << rxSnr << dataSnr);
695 
696  CheckInit (station);
697  if (!station->m_initialized)
698  {
699  return;
700  }
701 
702  if (!station->m_isHt)
703  {
704  NS_ASSERT_MSG (false,"A-MPDU Tx Status called but no HT or VHT supported.");
705  }
706 
707  NS_LOG_DEBUG ("DoReportAmpduTxStatus. TxRate=" << station->m_txrate << " SuccMpdus= " <<
708  (uint16_t)nSuccessfulMpdus << " FailedMpdus= " << (uint16_t)nFailedMpdus);
709 
710  station->m_ampduPacketCount++;
711  station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
712 
713  UpdatePacketCounters (station, nSuccessfulMpdus, nFailedMpdus);
714 
715  uint32_t rateId = GetRateId (station->m_txrate);
716  uint32_t groupId = GetGroupId (station->m_txrate);
717  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
718  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt += nSuccessfulMpdus + nFailedMpdus;
719 
720  if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries (station))
721  {
722  // We do not receive a BlockAck. The entire AMPDU fail.
723  UpdateRate (station);
724  }
725  else
726  {
727  station->m_isSampling = false;
728  station->m_sampleDeferred = false;
729 
730  UpdateRetry (station);
731  if (Simulator::Now () >= station->m_nextStatsUpdate)
732  {
733  UpdateStats (station);
734  }
735 
736  if (station->m_nModes >= 1)
737  {
738  station->m_txrate = FindRate (station);
739  }
740  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
741  }
742 }
743 
744 void
746 {
747  NS_LOG_FUNCTION (this << station);
748 
770  CheckInit (station);
771  if (!station->m_initialized)
772  {
773  return;
774  }
775  station->m_longRetry++;
776 
780  uint32_t maxTpRateId = GetRateId (station->m_maxTpRate);
781  uint32_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
782  uint32_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
783  uint32_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
784  uint32_t maxProbRateId = GetRateId (station->m_maxProbRate);
785  uint32_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
786 
788  if (!station->m_isSampling)
789  {
791  if (station->m_longRetry < station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
792  {
793  NS_LOG_DEBUG ("Not Sampling; use the same rate again");
794  station->m_txrate = station->m_maxTpRate;
795  }
796 
798  else if (station->m_longRetry < ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
799  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
800  {
801  NS_LOG_DEBUG ("Not Sampling; use the Max TP2");
802  station->m_txrate = station->m_maxTpRate2;
803  }
804 
806  else if (station->m_longRetry <= ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
807  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
808  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
809  {
810  NS_LOG_DEBUG ("Not Sampling; use Max Prob");
811  station->m_txrate = station->m_maxProbRate;
812  }
813  else
814  {
815  NS_ASSERT_MSG (false,"Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
816  }
817  }
818 
820  else
821  {
824  if (station->m_longRetry < 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
825  {
826  NS_LOG_DEBUG ("Sampling use the MaxTP rate");
827  station->m_txrate = station->m_maxTpRate2;
828  }
829 
831  else if (station->m_longRetry <= 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
832  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
833  {
834  NS_LOG_DEBUG ("Sampling use the MaxProb rate");
835  station->m_txrate = station->m_maxProbRate;
836  }
837  else
838  {
839  NS_ASSERT_MSG (false,"Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
840  }
841  }
842  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
843 }
844 
845 void
847 {
848  NS_LOG_FUNCTION (this << station);
849  station->m_shortRetry = 0;
850  station->m_longRetry = 0;
851 
852 }
853 
854 void
855 MinstrelHtWifiManager::UpdatePacketCounters (MinstrelHtWifiRemoteStation *station, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus)
856 {
857  NS_LOG_FUNCTION (this << station << (uint16_t)nSuccessfulMpdus << (uint16_t)nFailedMpdus);
858 
859  station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
860  if (station->m_isSampling)
861  {
862  station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
863  }
864  if (station->m_totalPacketsCount == ~0)
865  {
866  station->m_samplePacketsCount = 0;
867  station->m_totalPacketsCount = 0;
868  }
869 
870  if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
871  {
872  station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
873  station->m_sampleTries = 1;
874  station->m_sampleCount--;
875  }
876 
877 }
878 void
880 {
881  NS_LOG_FUNCTION (this << st);
883  station->DisposeStation ();
884 }
885 
888 {
889  NS_LOG_FUNCTION (this << st);
891 
892  if (!station->m_initialized)
893  {
894  CheckInit (station);
895  }
896 
897  if (!station->m_isHt)
898  {
899  WifiTxVector vector = m_legacyManager->GetDataTxVector (station);
900 
901  uint64_t dataRate = vector.GetMode ().GetDataRate (vector);
902  if (!station->m_isSampling)
903  {
904  m_rateChange (dataRate, station->m_state->m_address);
905  }
906 
907  return vector;
908  }
909  else
910  {
911  NS_LOG_DEBUG ("DoGetDataMode m_txrate= " << station->m_txrate);
912 
913  uint32_t rateId = GetRateId (station->m_txrate);
914  uint32_t groupId = GetGroupId (station->m_txrate);
915  uint32_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
916 
917  NS_LOG_DEBUG ("DoGetDataMode rateId= " << rateId << " groupId= " << groupId << " mode= " << GetMcsSupported (station, mcsIndex));
918 
919  McsGroup group = m_minstrelGroups[groupId];
920 
921  // Check consistency of rate selected.
922  if ((group.sgi && !GetShortGuardInterval (station)) || group.chWidth > GetChannelWidth (station) || group.streams > GetNumberOfSupportedStreams (station))
923  {
924  NS_ASSERT_MSG (false,"Inconsistent group selected. Group: (" << (uint16_t)group.streams << "," << (uint16_t)group.sgi << "," << (uint16_t)group.chWidth << ")" <<
925  " Station capabilities: (" << GetNumberOfSupportedStreams (station) << "," << GetShortGuardInterval (station) << "," << GetChannelWidth (station) << ")");
926  }
927 
928  uint64_t dataRate = GetMcsSupported (station, mcsIndex).GetDataRate (group.chWidth, group.sgi ? 400 : 800, group.streams);
929  if (!station->m_isSampling)
930  {
931  m_rateChange (dataRate, station->m_state->m_address);
932  }
933  WifiMode mode = GetMcsSupported (station, mcsIndex);
934  return WifiTxVector (mode, GetDefaultTxPowerLevel (), GetLongRetryCount (station),
935  GetPreambleForTransmission (mode, GetAddress (station)), group.sgi ? 400 : 800, GetNumberOfAntennas (), group.streams, GetNess (station), group.chWidth, GetAggregation (station) && !station->m_isSampling, GetStbc (station));
936  }
937 }
938 
941 {
942  NS_LOG_FUNCTION (this << st);
944 
945  if (!station->m_initialized)
946  {
947  CheckInit (station);
948  }
949 
950  if (!station->m_isHt)
951  {
952  return m_legacyManager->GetRtsTxVector (station);
953  }
954  else
955  {
956  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
957 
958  /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
959  * When supported, decision of using HT has to follow rules in Section 9.7.6 from 802.11-2012.
960  * From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is carried in a
961  * non-HT PPDU shall be transmitted by the STA using a rate no higher than the highest
962  * rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
963  * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
964  * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
965  * these conditions, the control frame shall be transmitted at a rate no higher than the
966  * highest mandatory rate of the attached PHY that is less than or equal to the rate
967  * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
968  * directed to the same receiving STA."
969  */
970 
971  // As we are in Minstrel HT, assume the last rate was an HT rate.
972  uint32_t rateId = GetRateId (station->m_txrate);
973  uint32_t groupId = GetGroupId (station->m_txrate);
974  uint32_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
975 
976  WifiMode lastRate = GetMcsSupported (station, mcsIndex);
977  uint64_t lastDataRate = lastRate.GetNonHtReferenceRate ();
978  uint32_t nBasicRates = GetNBasicModes ();
979 
980  WifiMode rtsRate;
981  bool rateFound = false;
982 
983  for (uint32_t i = 0; i < nBasicRates; i++)
984  {
985  uint64_t rate = GetBasicMode (i).GetDataRate (20);
986  if (rate <= lastDataRate)
987  {
988  rtsRate = GetBasicMode (i);
989  rateFound = true;
990  }
991  }
992 
993  if (!rateFound)
994  {
995  Ptr<WifiPhy> phy = GetPhy ();
996  uint32_t nSupportRates = phy->GetNModes ();
997  for (uint32_t i = 0; i < nSupportRates; i++)
998  {
999  uint64_t rate = phy->GetMode (i).GetDataRate (20);
1000  if (rate <= lastDataRate)
1001  {
1002  rtsRate = phy->GetMode (i);
1003  rateFound = true;
1004  }
1005  }
1006  }
1007 
1008  NS_ASSERT (rateFound);
1009 
1010  return WifiTxVector (rtsRate, GetDefaultTxPowerLevel (), GetShortRetryCount (station), GetPreambleForTransmission (rtsRate, GetAddress (station)),
1011  800, 1, 1, 0, GetChannelWidth (station), GetAggregation (station), false);
1012  }
1013 }
1014 
1015 bool
1017 {
1018  NS_LOG_FUNCTION (this << st << packet << normally);
1019 
1021 
1022  CheckInit (station);
1023  if (!station->m_initialized)
1024  {
1025  return normally;
1026  }
1027 
1028  uint32_t maxRetries;
1029 
1030  if (!station->m_isHt)
1031  {
1032  maxRetries = m_legacyManager->CountRetries (station);
1033  }
1034  else
1035  {
1036  maxRetries = CountRetries (station);
1037  }
1038 
1039  if (station->m_longRetry >= maxRetries)
1040  {
1041  NS_LOG_DEBUG ("No re-transmission allowed. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
1042  return false;
1043  }
1044  else
1045  {
1046  NS_LOG_DEBUG ("Re-transmit. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
1047  return true;
1048  }
1049 }
1050 
1051 uint32_t
1053 {
1054  uint32_t maxProbRateId = GetRateId (station->m_maxProbRate);
1055  uint32_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1056  uint32_t maxTpRateId = GetRateId (station->m_maxTpRate);
1057  uint32_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1058  uint32_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1059  uint32_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1060 
1061  if (!station->m_isSampling)
1062  {
1063  return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
1064  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
1065  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1066  }
1067  else
1068  {
1069  return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1070  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1071  }
1072 }
1073 
1074 bool
1076 {
1077  NS_LOG_FUNCTION (this);
1078  return true;
1079 }
1080 
1081 uint32_t
1083 {
1084  NS_LOG_FUNCTION (this << station);
1085 
1086  uint32_t sampleGroup = station->m_sampleGroup;
1087 
1088  uint32_t index = station->m_groupsTable[sampleGroup].m_index;
1089  uint32_t col = station->m_groupsTable[sampleGroup].m_col;
1090 
1091  uint32_t sampleIndex = station->m_sampleTable[index][col];
1092 
1093  uint32_t rateIndex = GetIndex (sampleGroup, sampleIndex);
1094  NS_LOG_DEBUG ("Next Sample is " << rateIndex);
1095 
1096  SetNextSample (station); //Calculate the next sample rate.
1097 
1098  return rateIndex;
1099 }
1100 
1101 void
1103 {
1104  NS_LOG_FUNCTION (this << station);
1105  do
1106  {
1107  station->m_sampleGroup++;
1108  station->m_sampleGroup %= m_numGroups;
1109  }
1110  while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1111 
1112  station->m_groupsTable[station->m_sampleGroup].m_index++;
1113 
1114  uint32_t sampleGroup = station->m_sampleGroup;
1115  uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1116  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1117 
1118  if (index >= m_numRates)
1119  {
1120  station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1121  station->m_groupsTable[station->m_sampleGroup].m_col++;
1122  if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1123  {
1124  station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1125  }
1126  index = station->m_groupsTable[station->m_sampleGroup].m_index;
1127  col = station->m_groupsTable[sampleGroup].m_col;
1128  }
1129  NS_LOG_DEBUG ("New sample set: group= " << sampleGroup << " index= " << station->m_sampleTable[index][col]);
1130 }
1131 
1132 uint32_t
1134 {
1135  NS_LOG_FUNCTION (this << station);
1136  NS_LOG_DEBUG ("FindRate " << "packet=" << station->m_totalPacketsCount );
1137 
1138  if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1139  {
1140  return station->m_maxTpRate;
1141  }
1142 
1143  // If we have waited enough, then sample.
1144  if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1145  {
1146  //SAMPLING
1147  NS_LOG_DEBUG ("Obtaining a sampling rate");
1149  uint32_t sampleIdx = GetNextSample (station);
1150  NS_LOG_DEBUG ("Sampling rate = " << sampleIdx);
1151 
1152  //Evaluate if the sampling rate selected should be used.
1153  uint32_t sampleGroupId = GetGroupId (sampleIdx);
1154  uint32_t sampleRateId = GetRateId (sampleIdx);
1155 
1156  // If the rate selected is not supported, then don't sample.
1157  if (station->m_groupsTable[sampleGroupId].m_supported && station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1158  {
1166  HtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1167 
1168  NS_LOG_DEBUG ("Use sample rate? MaxTpRate= " << station->m_maxTpRate << " CurrentRate= " << station->m_txrate <<
1169  " SampleRate= " << sampleIdx << " SampleProb= " << sampleRateInfo.ewmaProb);
1170 
1171  if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2
1172  && sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1173  {
1174 
1180  uint32_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1181  uint32_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1182  uint32_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1183  uint32_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1184  uint32_t maxProbRateId = GetRateId (station->m_maxProbRate);
1185 
1186  uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1187  uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1188 
1189  Time sampleDuration = sampleRateInfo.perfectTxTime;
1190  Time maxTp2Duration = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1191  Time maxProbDuration = station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].perfectTxTime;
1192 
1193  NS_LOG_DEBUG ("Use sample rate? SampleDuration= " << sampleDuration << " maxTp2Duration= " << maxTp2Duration <<
1194  " maxProbDuration= " << maxProbDuration << " sampleStreams= " << (uint16_t)sampleStreams <<
1195  " maxTpStreams= " << (uint16_t)maxTpStreams);
1196  if (sampleDuration < maxTp2Duration || (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1197  {
1199  station->m_isSampling = true;
1200 
1202  station->m_sampleRate = sampleIdx;
1203 
1204  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1205  station->m_sampleTries--;
1206  return sampleIdx;
1207  }
1208  else
1209  {
1210  station->m_numSamplesSlow++;
1211  if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1212  {
1214  station->m_isSampling = true;
1215 
1217  station->m_sampleRate = sampleIdx;
1218 
1219  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1220  station->m_sampleTries--;
1221  return sampleIdx;
1222  }
1223  }
1224  }
1225  }
1226  }
1227  if (station->m_sampleWait > 0)
1228  {
1229  station->m_sampleWait--;
1230  }
1231 
1233 
1234  NS_LOG_DEBUG ("FindRate " << "maxTpRrate=" << station->m_maxTpRate);
1235  return station->m_maxTpRate;
1236 }
1237 void
1239 {
1240  NS_LOG_FUNCTION (this << station);
1241 
1242  NS_LOG_DEBUG ("Updating stats=" << this);
1243 
1245 
1246  station->m_numSamplesSlow = 0;
1247  station->m_sampleCount = 0;
1248 
1249  double tempProb;
1250 
1251  if (station->m_ampduPacketCount > 0)
1252  {
1253  double newLen = station->m_ampduLen / station->m_ampduPacketCount;
1254  station->m_avgAmpduLen = ( newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel) ) / 100;
1255  station->m_ampduLen = 0;
1256  station->m_ampduPacketCount = 0;
1257  }
1258 
1259  /* Initialize global rate indexes */
1260  station->m_maxTpRate = GetLowestIndex (station);
1261  station->m_maxTpRate2 = GetLowestIndex (station);
1262  station->m_maxProbRate = GetLowestIndex (station);
1263 
1265  for (uint32_t j = 0; j < m_numGroups; j++)
1266  {
1267  if (station->m_groupsTable[j].m_supported)
1268  {
1269  station->m_sampleCount++;
1270 
1271  /* (re)Initialize group rate indexes */
1272  station->m_groupsTable[j].m_maxTpRate = GetLowestIndex (station, j);
1273  station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex (station, j);
1274  station->m_groupsTable[j].m_maxProbRate = GetLowestIndex (station, j);
1275 
1276  for (uint32_t i = 0; i < m_numRates; i++)
1277  {
1278  if (station->m_groupsTable[j].m_ratesTable[i].supported)
1279  {
1280  station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1281 
1282  NS_LOG_DEBUG (i << " " << GetMcsSupported (station, station->m_groupsTable[j].m_ratesTable[i].mcsIndex) <<
1283  "\t attempt=" << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt <<
1284  "\t success=" << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1285 
1287  if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1288  {
1289  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1294  tempProb = (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) / station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1295 
1297  station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1298 
1299  if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1300  {
1301  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1302  }
1303  else
1304  {
1305  station->m_groupsTable[j].m_ratesTable[i].ewmsdProb = CalculateEwmsd (station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1306  tempProb, station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1307  m_ewmaLevel);
1309  tempProb = (tempProb * (100 - m_ewmaLevel) + station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) / 100;
1310  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1311  }
1312 
1313  station->m_groupsTable[j].m_ratesTable[i].throughput = CalculateThroughput (station, j, i, tempProb);
1314 
1315  station->m_groupsTable[j].m_ratesTable[i].successHist += station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1316  station->m_groupsTable[j].m_ratesTable[i].attemptHist += station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1317  }
1318  else
1319  {
1320  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1321  }
1322 
1324  station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess = station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1325  station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt = station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1326  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1327  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1328 
1329  if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1330  {
1331  SetBestStationThRates (station, GetIndex (j, i));
1332  SetBestProbabilityRate (station, GetIndex (j, i));
1333  }
1334 
1335  }
1336  }
1337  }
1338  }
1339 
1340  //Try to sample all available rates during each interval.
1341  station->m_sampleCount *= 8;
1342 
1343  //Recalculate retries for the rates selected.
1344  CalculateRetransmits (station, station->m_maxTpRate);
1345  CalculateRetransmits (station, station->m_maxTpRate2);
1346  CalculateRetransmits (station, station->m_maxProbRate);
1347 
1348  NS_LOG_DEBUG ("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2 << "\nmax prob=" << station->m_maxProbRate);
1349  if (m_printStats)
1350  {
1351  PrintTable (station);
1352  }
1353 }
1354 
1355 double
1356 MinstrelHtWifiManager::CalculateThroughput (MinstrelHtWifiRemoteStation *station, uint32_t groupId, uint32_t rateId, double ewmaProb)
1357 {
1363  if (ewmaProb < 10)
1364  {
1365  return 0;
1366  }
1367  else
1368  {
1373  Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1374  if (ewmaProb > 90)
1375  {
1376  return 90 / txTime.GetSeconds ();
1377  }
1378  else
1379  {
1380  return ewmaProb / txTime.GetSeconds ();
1381  }
1382  }
1383 }
1384 
1385 void
1387 {
1388  GroupInfo *group;
1389  HtRateInfo rate;
1390  uint32_t tmpGroupId, tmpRateId;
1391  double tmpTh, tmpProb;
1392  uint32_t groupId, rateId;
1393  double currentTh;
1394  // maximum group probability (GP) variables
1395  uint32_t maxGPGroupId, maxGPRateId;
1396  double maxGPTh;
1397 
1398  groupId = GetGroupId (index);
1399  rateId = GetRateId (index);
1400  group = &station->m_groupsTable[groupId];
1401  rate = group->m_ratesTable[rateId];
1402 
1403  tmpGroupId = GetGroupId (station->m_maxProbRate);
1404  tmpRateId = GetRateId (station->m_maxProbRate);
1405  tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1406  tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1407 
1408  if (rate.ewmaProb > 75)
1409  {
1410  currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1411  if (currentTh > tmpTh)
1412  {
1413  station->m_maxProbRate = index;
1414  }
1415 
1416  maxGPGroupId = GetGroupId (group->m_maxProbRate);
1417  maxGPRateId = GetRateId (group->m_maxProbRate);
1418  maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1419 
1420  if (currentTh > maxGPTh)
1421  {
1422  group->m_maxProbRate = index;
1423  }
1424  }
1425  else
1426  {
1427  if (rate.ewmaProb > tmpProb)
1428  {
1429  station->m_maxProbRate = index;
1430  }
1431  maxGPRateId = GetRateId (group->m_maxProbRate);
1432  if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1433  {
1434  group->m_maxProbRate = index;
1435  }
1436  }
1437 }
1438 
1439 /*
1440  * Find & sort topmost throughput rates
1441  *
1442  * If multiple rates provide equal throughput the sorting is based on their
1443  * current success probability. Higher success probability is preferred among
1444  * MCS groups.
1445  */
1446 void
1448 {
1449  uint32_t groupId, rateId;
1450  double th, prob;
1451  uint32_t maxTpGroupId, maxTpRateId;
1452  uint32_t maxTp2GroupId, maxTp2RateId;
1453  double maxTpTh, maxTpProb;
1454  double maxTp2Th, maxTp2Prob;
1455 
1456  groupId = GetGroupId (index);
1457  rateId = GetRateId (index);
1458  prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1459  th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1460 
1461  maxTpGroupId = GetGroupId (station->m_maxTpRate);
1462  maxTpRateId = GetRateId (station->m_maxTpRate);
1463  maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1464  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1465 
1466  maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1467  maxTp2RateId = GetRateId (station->m_maxTpRate2);
1468  maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1469  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1470 
1471  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1472  {
1473  station->m_maxTpRate2 = station->m_maxTpRate;
1474  station->m_maxTpRate = index;
1475  }
1476  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1477  {
1478  station->m_maxTpRate2 = index;
1479  }
1480 
1481  //Find best rates per group
1482 
1483  GroupInfo *group = &station->m_groupsTable[groupId];
1484  maxTpGroupId = GetGroupId (group->m_maxTpRate);
1485  maxTpRateId = GetRateId (group->m_maxTpRate);
1486  maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1487  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1488 
1489  maxTp2GroupId = GetGroupId (group->m_maxTpRate2);
1490  maxTp2RateId = GetRateId (group->m_maxTpRate2);
1491  maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1492  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1493 
1494  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1495  {
1496  group->m_maxTpRate2 = group->m_maxTpRate;
1497  group->m_maxTpRate = index;
1498  }
1499  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1500  {
1501  group->m_maxTpRate2 = index;
1502  }
1503 }
1504 
1505 void
1507 {
1508  NS_LOG_FUNCTION (this << station);
1509  NS_LOG_DEBUG ("RateInit=" << station);
1510 
1511  station->m_groupsTable = McsGroupData (m_numGroups);
1512 
1516  NS_LOG_DEBUG ("Supported groups by station:");
1517  for (uint32_t groupId = 0; groupId < m_numGroups; groupId++)
1518  {
1519  if (m_minstrelGroups[groupId].isSupported)
1520  {
1521  station->m_groupsTable[groupId].m_supported = false;
1522  if (!(!GetVhtSupported (station) && m_minstrelGroups[groupId].isVht)
1523  && (m_minstrelGroups[groupId].isVht || !GetVhtSupported (station) || !m_useVhtOnly)
1524  && !(!GetShortGuardInterval (station) && m_minstrelGroups[groupId].sgi)
1525  && (GetChannelWidth (station) >= m_minstrelGroups[groupId].chWidth)
1526  && (GetNumberOfSupportedStreams (station) >= m_minstrelGroups[groupId].streams))
1527  {
1528  NS_LOG_DEBUG ("Group " << groupId << ": (" << (uint16_t)m_minstrelGroups[groupId].streams <<
1529  "," << (uint16_t)m_minstrelGroups[groupId].sgi << "," << (uint16_t)m_minstrelGroups[groupId].chWidth << ")");
1530 
1531  station->m_groupsTable[groupId].m_supported = true;
1532  station->m_groupsTable[groupId].m_col = 0;
1533  station->m_groupsTable[groupId].m_index = 0;
1534 
1535  station->m_groupsTable[groupId].m_ratesTable = HtMinstrelRate (m_numRates);
1536  for (uint32_t i = 0; i < m_numRates; i++)
1537  {
1538  station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1539  }
1540 
1541  // Initialize all modes supported by the remote station that belong to the current group.
1542  for (uint32_t i = 0; i < station->m_nModes; i++)
1543  {
1544  WifiMode mode = GetMcsSupported (station, i);
1545 
1548  uint32_t rateId = mode.GetMcsValue ();
1549  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1550  {
1551  rateId %= MAX_HT_GROUP_RATES;
1552  }
1553 
1554  if ((m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_VHT
1555  && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1556  || (!m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_HT
1557  && mode.GetMcsValue () < (m_minstrelGroups[groupId].streams * 8)
1558  && mode.GetMcsValue () >= ((m_minstrelGroups[groupId].streams - 1) * 8)))
1559  {
1560  NS_LOG_DEBUG ("Mode " << i << ": " << mode << " isVht: " << m_minstrelGroups[groupId].isVht);
1561 
1562  station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1563  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex = i;
1564  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1565  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1566  station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1567  station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1568  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1569  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1570  station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1571  station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1572  station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1573  station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1574  station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
1575  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1576  station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1577  CalculateRetransmits (station, groupId, rateId);
1578  }
1579  }
1580  }
1581  }
1582  }
1583  SetNextSample (station);
1584  UpdateStats (station);
1585  station->m_txrate = FindRate (station);
1586 }
1587 
1588 void
1590 {
1591  NS_LOG_FUNCTION (this << station << index);
1592  uint32_t groupId = GetGroupId (index);
1593  uint32_t rateId = GetRateId (index);
1594  if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1595  {
1596  CalculateRetransmits (station, groupId, rateId);
1597  }
1598 }
1599 
1600 void
1602 {
1603  NS_LOG_FUNCTION (this << station << groupId << groupId);
1604  NS_LOG_DEBUG (" Calculating the number of retries");
1605 
1606  uint32_t cw = 15; // Is an approximation.
1607  uint32_t cwMax = 1023;
1608  Time cwTime, txTime, dataTxTime;
1609  Time slotTime = GetMac ()->GetSlot ();
1610  Time ackTime = GetMac ()->GetBasicBlockAckTimeout ();
1611 
1612  if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1613  {
1614  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1615  }
1616  else
1617  {
1618  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1619  station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1620 
1621  dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1622  GetMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) * (station->m_avgAmpduLen - 1);
1623 
1624  /* Contention time for first 2 tries */
1625  cwTime = (cw / 2) * slotTime;
1626  cw = Min ((cw + 1) * 2, cwMax);
1627  cwTime += (cw / 2) * slotTime;
1628  cw = Min ((cw + 1) * 2, cwMax);
1629 
1630  /* Total TX time for data and Contention after first 2 tries */
1631  txTime = cwTime + 2 * (dataTxTime + ackTime);
1632 
1633  /* See how many more tries we can fit inside segment size */
1634  do
1635  {
1636  /* Contention time for this try */
1637  cwTime = (cw / 2) * slotTime;
1638  cw = Min ((cw + 1) * 2, cwMax);
1639 
1640  /* Total TX time after this try */
1641  txTime += cwTime + ackTime + dataTxTime;
1642  }
1643  while ((txTime < MilliSeconds (6))
1644  && (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1645  }
1646 }
1647 
1648 double
1649 MinstrelHtWifiManager::CalculateEwmsd (double oldEwmsd, double currentProb, double ewmaProb, uint32_t weight)
1650 {
1651  double diff, incr, tmp;
1652 
1653  /* calculate exponential weighted moving variance */
1654  diff = currentProb - ewmaProb;
1655  incr = (100 - weight) * diff / 100;
1656  tmp = oldEwmsd * oldEwmsd;
1657  tmp = weight * (tmp + diff * incr) / 100;
1658 
1659  /* return standard deviation */
1660  return sqrt (tmp);
1661 }
1662 
1663 void
1665 {
1666  NS_LOG_DEBUG ("InitSampleTable=" << this);
1667 
1668  station->m_col = station->m_index = 0;
1669 
1670  //for off-setting to make rates fall between 0 and nModes
1671  uint32_t numSampleRates = m_numRates;
1672 
1673  uint32_t newIndex;
1674  for (uint32_t col = 0; col < m_nSampleCol; col++)
1675  {
1676  for (uint32_t i = 0; i < numSampleRates; i++ )
1677  {
1682  int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
1683  newIndex = (i + uv) % numSampleRates;
1684 
1685  //this loop is used for filling in other uninitialized places
1686  while (station->m_sampleTable[newIndex][col] != 0)
1687  {
1688  newIndex = (newIndex + 1) % m_numRates;
1689  }
1690  station->m_sampleTable[newIndex][col] = i;
1691  }
1692  }
1693 }
1694 
1695 void
1697 {
1698  NS_LOG_FUNCTION (this << station);
1699  NS_LOG_DEBUG ("PrintTable=" << station);
1700 
1701  station->m_statsFile << " best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n" <<
1702  " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n";
1703  for (uint32_t i = 0; i < m_numGroups; i++)
1704  {
1705  StatsDump (station, i, station->m_statsFile);
1706  }
1707 
1708  station->m_statsFile << "\nTotal packet count:: ideal " << Max (0, station->m_totalPacketsCount - station->m_samplePacketsCount) <<
1709  " lookaround " << station->m_samplePacketsCount << "\n";
1710  station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen << "\n\n";
1711 
1712  station->m_statsFile.flush ();
1713 }
1714 
1715 void
1716 MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint32_t groupId, std::ofstream &of)
1717 {
1718  uint32_t numRates = m_numRates;
1719  McsGroup group = m_minstrelGroups[groupId];
1720  Time txTime;
1721  char giMode;
1722  if (group.sgi)
1723  {
1724  giMode = 'S';
1725  }
1726  else
1727  {
1728  giMode = 'L';
1729  }
1730  for (uint32_t i = 0; i < numRates; i++)
1731  {
1732  if (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[i].supported)
1733  {
1734  if (!group.isVht)
1735  {
1736  of << "HT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1737  }
1738  else
1739  {
1740  of << "VHT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1741  }
1742 
1743  uint32_t maxTpRate = station->m_maxTpRate;
1744  uint32_t maxTpRate2 = station->m_maxTpRate2;
1745  uint32_t maxProbRate = station->m_maxProbRate;
1746 
1747  uint32_t idx = GetIndex (groupId, i);
1748  if (idx == maxTpRate)
1749  {
1750  of << 'A';
1751  }
1752  else
1753  {
1754  of << ' ';
1755  }
1756  if (idx == maxTpRate2)
1757  {
1758  of << 'B';
1759  }
1760  else
1761  {
1762  of << ' ';
1763  }
1764  if (idx == maxProbRate)
1765  {
1766  of << 'P';
1767  }
1768  else
1769  {
1770  of << ' ';
1771  }
1772 
1773  if (!group.isVht)
1774  {
1775  of << std::setw (4) << " MCS" << (group.streams - 1) * 8 + i;
1776  }
1777  else
1778  {
1779  of << std::setw (7) << " MCS" << i << "/" << (int) group.streams;
1780  }
1781 
1782  of << " " << std::setw (3) << idx << " ";
1783 
1784  /* tx_time[rate(i)] in usec */
1785  txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
1786  of << std::setw (6) << txTime.GetMicroSeconds () << " ";
1787 
1788  of << std::setw (7) << CalculateThroughput (station, groupId, i, 100) / 100 << " " <<
1789  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100 << " " <<
1790  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb << " " <<
1791  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb << " " <<
1792  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].prob << " " <<
1793  std::setw (2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount << " " <<
1794  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " " <<
1795  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt << " " <<
1796  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " " <<
1797  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist << "\n";
1798  }
1799  }
1800 }
1801 uint32_t
1802 MinstrelHtWifiManager::GetIndex (uint32_t groupId, uint32_t rateId)
1803 {
1804  NS_LOG_FUNCTION (this << groupId << rateId);
1805  uint32_t index;
1806  index = groupId * m_numRates + rateId;
1807  return index;
1808 }
1809 
1810 uint32_t
1812 {
1813  NS_LOG_FUNCTION (this << index);
1814 
1815  uint32_t id;
1816  id = index % m_numRates;
1817  return id;
1818 }
1819 
1820 uint32_t
1822 {
1823  NS_LOG_FUNCTION (this << index);
1824 
1825  return index / m_numRates;
1826 }
1827 
1828 uint32_t
1829 MinstrelHtWifiManager::GetHtGroupId (uint8_t txstreams, uint8_t sgi, uint8_t chWidth)
1830 {
1831  NS_LOG_FUNCTION (this << (uint16_t)txstreams << (uint16_t)sgi << (uint16_t)chWidth);
1832 
1833  return MAX_SUPPORTED_STREAMS * 2 * (chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
1834 }
1835 
1836 uint32_t
1837 MinstrelHtWifiManager::GetVhtGroupId (uint8_t txstreams, uint8_t sgi, uint8_t chWidth)
1838 {
1839  NS_LOG_FUNCTION (this << (uint16_t)txstreams << (uint16_t)sgi << (uint16_t)chWidth);
1840 
1841  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;
1842 }
1843 
1844 uint32_t
1846 {
1847  NS_LOG_FUNCTION (this << station);
1848 
1849  uint32_t groupId = 0;
1850  uint32_t rateId = 0;
1851  while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
1852  {
1853  groupId++;
1854  }
1855  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1856  {
1857  rateId++;
1858  }
1859  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1860  return GetIndex (groupId, rateId);
1861 }
1862 
1863 uint32_t
1865 {
1866  NS_LOG_FUNCTION (this << station);
1867 
1868  uint32_t rateId = 0;
1869  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1870  {
1871  rateId++;
1872  }
1873  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1874  return GetIndex (groupId, rateId);
1875 }
1876 
1877 
1880 {
1881  WifiModeList vhtMcsList;
1882  Ptr<WifiPhy> phy = GetPhy ();
1883  for (uint32_t i = 0; i < phy->GetNMcs (); i++)
1884  {
1885  WifiMode mode = phy->GetMcs (i);
1886  if (mode.GetModulationClass () == WIFI_MOD_CLASS_VHT)
1887  {
1888  vhtMcsList.push_back (mode);
1889  }
1890  }
1891  return vhtMcsList;
1892 }
1893 
1896 {
1897  WifiModeList htMcsList;
1898  Ptr<WifiPhy> phy = GetPhy ();
1899  for (uint32_t i = 0; i < phy->GetNMcs (); i++)
1900  {
1901  WifiMode mode = phy->GetMcs (i);
1902  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1903  {
1904  htMcsList.push_back (mode);
1905  }
1906  }
1907  return htMcsList;
1908 }
1909 
1910 void
1912 {
1913  //HE is not supported yet by this algorithm.
1914  if (enable)
1915  {
1916  NS_FATAL_ERROR ("WifiRemoteStationManager selected does not support HE rates");
1917  }
1918 }
1919 
1920 } // namespace ns3
1921 
1922 
1923 
1924 
1925 
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
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:1001
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_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:3553
void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode)
This method is a pure virtual method that must be implemented by the sub-class.
WifiMode GetMcsSupported(const WifiRemoteStation *station, uint32_t i) const
Return the WifiMode supported by the specified station at the specified index.
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:1270
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:611
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:2262
bool GetStbc(const WifiRemoteStation *station) const
Return whether the given station supports space-time block coding (STBC).
uint32_t m_col
To keep track of the current position in the our random sample table going row by row from 1st column...
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:341
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.
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:349
AttributeValue implementation for Time.
Definition: nstime.h:1055
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
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
WifiMode GetBasicMode(uint32_t i) const
Return a basic mode from the set of basic modes.
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...
void DoDisposeStation(WifiRemoteStation *station)
Dispose station function.
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.
uint8_t GetNumberOfSupportedStreams(const WifiRemoteStation *station) const
Return the number of supported streams the station has.
Mac48Address GetAddress(const WifiRemoteStation *station) const
Return the address of the station.
uint32_t GetNModes(void) const
The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used (e.g., by a WifiRemoteStationManager...
Definition: wifi-phy.cc:3541
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:3559
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.
static bool IsValidTxVector(WifiTxVector txVector)
The standard disallows certain combinations of WifiMode, number of spatial streams, and channel widths.
Definition: wifi-phy.cc:3479
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
void DisposeStation()
Dispose station function.
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:1056
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
bool GetShortGuardInterval(const WifiRemoteStation *station) const
Return whether the given station supports HT/VHT short guard interval.
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.
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.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:90
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
uint32_t GetNBasicModes(void) const
Return the number of basic modes we support.
if(desigRtr==addrLocal)
uint32_t GetLongRetryCount(const WifiRemoteStation *station) const
Return the long retry limit of the given station.
std::vector< McsGroup > MinstrelMcsGroups
Data structure for a table of group definitions.
uint32_t GetNMcsSupported(const WifiRemoteStation *station) const
Return the number of MCS supported by the given station.
uint32_t m_nModes
number of modes supported
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:993
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)
uint32_t GetShortRetryCount(const WifiRemoteStation *station) const
Return the short retry limit of the given station.
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:61
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
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.
bool GetHtSupported(const WifiRemoteStation *station) const
Return whether the given station is HT capable.
Ptr< WifiMac > GetMac(void) const
Return the WifiMac.
WifiMode GetMode(uint32_t mode) const
The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used (e.g., by a WifiRemoteStationManager...
Definition: wifi-phy.cc:3547
Time m_nextStatsUpdate
10 times every second