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