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  uint16_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  NS_ASSERT_MSG (station->m_isHt, "A-MPDU Tx Status called but no HT or VHT supported.");
657 
658  NS_LOG_DEBUG ("DoReportAmpduTxStatus. TxRate=" << station->m_txrate << " SuccMpdus= " <<
659  +nSuccessfulMpdus << " FailedMpdus= " << +nFailedMpdus);
660 
661  station->m_ampduPacketCount++;
662  station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
663 
664  UpdatePacketCounters (station, nSuccessfulMpdus, nFailedMpdus);
665 
666  uint8_t rateId = GetRateId (station->m_txrate);
667  uint8_t groupId = GetGroupId (station->m_txrate);
668  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
669  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt += nSuccessfulMpdus + nFailedMpdus;
670 
671  if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries (station))
672  {
673  // We do not receive a BlockAck. The entire AMPDU fail.
674  UpdateRate (station);
675  }
676  else
677  {
678  station->m_isSampling = false;
679  station->m_sampleDeferred = false;
680 
681  UpdateRetry (station);
682  if (Simulator::Now () >= station->m_nextStatsUpdate)
683  {
684  UpdateStats (station);
685  }
686 
687  if (station->m_nModes >= 1)
688  {
689  station->m_txrate = FindRate (station);
690  }
691  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
692  }
693 }
694 
695 void
697 {
698  NS_LOG_FUNCTION (this << station);
699 
721  CheckInit (station);
722  if (!station->m_initialized)
723  {
724  return;
725  }
726  station->m_longRetry++;
727 
731  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
732  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
733  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
734  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
735  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
736  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
737 
739  if (!station->m_isSampling)
740  {
742  if (station->m_longRetry < station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
743  {
744  NS_LOG_DEBUG ("Not Sampling; use the same rate again");
745  station->m_txrate = station->m_maxTpRate;
746  }
747 
749  else if (station->m_longRetry < ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
750  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
751  {
752  NS_LOG_DEBUG ("Not Sampling; use the Max TP2");
753  station->m_txrate = station->m_maxTpRate2;
754  }
755 
757  else if (station->m_longRetry <= ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
758  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
759  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
760  {
761  NS_LOG_DEBUG ("Not Sampling; use Max Prob");
762  station->m_txrate = station->m_maxProbRate;
763  }
764  else
765  {
766  NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
767  }
768  }
769 
771  else
772  {
775  if (station->m_longRetry < 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
776  {
777  NS_LOG_DEBUG ("Sampling use the MaxTP rate");
778  station->m_txrate = station->m_maxTpRate2;
779  }
780 
782  else if (station->m_longRetry <= 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
783  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
784  {
785  NS_LOG_DEBUG ("Sampling use the MaxProb rate");
786  station->m_txrate = station->m_maxProbRate;
787  }
788  else
789  {
790  NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
791  }
792  }
793  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
794 }
795 
796 void
798 {
799  NS_LOG_FUNCTION (this << station);
800  station->m_shortRetry = 0;
801  station->m_longRetry = 0;
802 }
803 
804 void
805 MinstrelHtWifiManager::UpdatePacketCounters (MinstrelHtWifiRemoteStation *station, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus)
806 {
807  NS_LOG_FUNCTION (this << station << +nSuccessfulMpdus << +nFailedMpdus);
808 
809  station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
810  if (station->m_isSampling)
811  {
812  station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
813  }
814  if (station->m_totalPacketsCount == ~0)
815  {
816  station->m_samplePacketsCount = 0;
817  station->m_totalPacketsCount = 0;
818  }
819 
820  if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
821  {
822  station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
823  station->m_sampleTries = 1;
824  station->m_sampleCount--;
825  }
826 }
827 
830 {
831  NS_LOG_FUNCTION (this << st);
833 
834  if (!station->m_initialized)
835  {
836  CheckInit (station);
837  }
838 
839  if (!station->m_isHt)
840  {
841  WifiTxVector vector = m_legacyManager->GetDataTxVector (station);
842  uint64_t dataRate = vector.GetMode ().GetDataRate (vector);
843  if (m_currentRate != dataRate && !station->m_isSampling)
844  {
845  NS_LOG_DEBUG ("New datarate: " << dataRate);
846  m_currentRate = dataRate;
847  }
848  return vector;
849  }
850  else
851  {
852  NS_LOG_DEBUG ("DoGetDataMode m_txrate= " << station->m_txrate);
853 
854  uint8_t rateId = GetRateId (station->m_txrate);
855  uint8_t groupId = GetGroupId (station->m_txrate);
856  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
857 
858  NS_LOG_DEBUG ("DoGetDataMode rateId= " << +rateId << " groupId= " << +groupId << " mode= " << GetMcsSupported (station, mcsIndex));
859 
860  McsGroup group = m_minstrelGroups[groupId];
861 
862  // Check consistency of rate selected.
863  if ((group.sgi && !GetShortGuardInterval (station)) || group.chWidth > GetChannelWidth (station) || group.streams > GetNumberOfSupportedStreams (station))
864  {
865  NS_FATAL_ERROR ("Inconsistent group selected. Group: (" << +group.streams <<
866  "," << +group.sgi << "," << group.chWidth << ")" <<
867  " Station capabilities: (" << GetNumberOfSupportedStreams (station) <<
868  "," << GetShortGuardInterval (station) << "," << GetChannelWidth (station) << ")");
869  }
870  WifiMode mode = GetMcsSupported (station, mcsIndex);
871  uint64_t dataRate = mode.GetDataRate (group.chWidth, group.sgi ? 400 : 800, group.streams);
872  if (m_currentRate != dataRate && !station->m_isSampling)
873  {
874  NS_LOG_DEBUG ("New datarate: " << dataRate);
875  m_currentRate = dataRate;
876  }
877  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);
878  }
879 }
880 
883 {
884  NS_LOG_FUNCTION (this << st);
886 
887  if (!station->m_initialized)
888  {
889  CheckInit (station);
890  }
891 
892  if (!station->m_isHt)
893  {
894  return m_legacyManager->GetRtsTxVector (station);
895  }
896  else
897  {
898  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
899 
900  /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
901  * When supported, decision of using HT has to follow rules in Section 9.7.6 from 802.11-2012.
902  * From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is carried in a
903  * non-HT PPDU shall be transmitted by the STA using a rate no higher than the highest
904  * rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
905  * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
906  * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
907  * these conditions, the control frame shall be transmitted at a rate no higher than the
908  * highest mandatory rate of the attached PHY that is less than or equal to the rate
909  * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
910  * directed to the same receiving STA."
911  */
912 
913  // As we are in Minstrel HT, assume the last rate was an HT rate.
914  uint8_t rateId = GetRateId (station->m_txrate);
915  uint8_t groupId = GetGroupId (station->m_txrate);
916  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
917 
918  WifiMode lastRate = GetMcsSupported (station, mcsIndex);
919  uint64_t lastDataRate = lastRate.GetNonHtReferenceRate ();
920  uint8_t nBasicRates = GetNBasicModes ();
921 
922  WifiMode rtsRate;
923  bool rateFound = false;
924 
925  for (uint8_t i = 0; i < nBasicRates; i++)
926  {
927  uint64_t rate = GetBasicMode (i).GetDataRate (20);
928  if (rate <= lastDataRate)
929  {
930  rtsRate = GetBasicMode (i);
931  rateFound = true;
932  }
933  }
934 
935  if (!rateFound)
936  {
937  Ptr<WifiPhy> phy = GetPhy ();
938  uint8_t nSupportRates = phy->GetNModes ();
939  for (uint8_t i = 0; i < nSupportRates; i++)
940  {
941  uint64_t rate = phy->GetMode (i).GetDataRate (20);
942  if (rate <= lastDataRate)
943  {
944  rtsRate = phy->GetMode (i);
945  rateFound = true;
946  }
947  }
948  }
949 
950  NS_ASSERT (rateFound);
951 
952  return WifiTxVector (rtsRate, GetDefaultTxPowerLevel (), GetPreambleForTransmission (rtsRate, GetAddress (station)),
953  800, 1, 1, 0, GetChannelWidthForTransmission (rtsRate, GetChannelWidth (station)), GetAggregation (station), false);
954  }
955 }
956 
957 bool
959 {
960  NS_LOG_FUNCTION (this << st << packet << normally);
961 
963 
964  CheckInit (station);
965  if (!station->m_initialized)
966  {
967  return normally;
968  }
969 
970  uint32_t maxRetries;
971 
972  if (!station->m_isHt)
973  {
974  maxRetries = m_legacyManager->CountRetries (station);
975  }
976  else
977  {
978  maxRetries = CountRetries (station);
979  }
980 
981  if (station->m_longRetry >= maxRetries)
982  {
983  NS_LOG_DEBUG ("No re-transmission allowed. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
984  return false;
985  }
986  else
987  {
988  NS_LOG_DEBUG ("Re-transmit. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
989  return true;
990  }
991 }
992 
993 uint32_t
995 {
996  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
997  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
998  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
999  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1000  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1001  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1002 
1003  if (!station->m_isSampling)
1004  {
1005  return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
1006  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
1007  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1008  }
1009  else
1010  {
1011  return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1012  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1013  }
1014 }
1015 
1016 bool
1018 {
1019  return true;
1020 }
1021 
1022 uint16_t
1024 {
1025  NS_LOG_FUNCTION (this << station);
1026  uint8_t sampleGroup = station->m_sampleGroup;
1027  uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1028  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1029  uint8_t sampleIndex = station->m_sampleTable[index][col];
1030  uint16_t rateIndex = GetIndex (sampleGroup, sampleIndex);
1031  NS_LOG_DEBUG ("Next Sample is " << rateIndex);
1032  SetNextSample (station); //Calculate the next sample rate.
1033  return rateIndex;
1034 }
1035 
1036 void
1038 {
1039  NS_LOG_FUNCTION (this << station);
1040  do
1041  {
1042  station->m_sampleGroup++;
1043  station->m_sampleGroup %= m_numGroups;
1044  }
1045  while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1046 
1047  station->m_groupsTable[station->m_sampleGroup].m_index++;
1048 
1049  uint8_t sampleGroup = station->m_sampleGroup;
1050  uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1051  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1052 
1053  if (index >= m_numRates)
1054  {
1055  station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1056  station->m_groupsTable[station->m_sampleGroup].m_col++;
1057  if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1058  {
1059  station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1060  }
1061  index = station->m_groupsTable[station->m_sampleGroup].m_index;
1062  col = station->m_groupsTable[sampleGroup].m_col;
1063  }
1064  NS_LOG_DEBUG ("New sample set: group= " << +sampleGroup << " index= " << +station->m_sampleTable[index][col]);
1065 }
1066 
1067 uint16_t
1069 {
1070  NS_LOG_FUNCTION (this << station);
1071  NS_LOG_DEBUG ("FindRate packet=" << station->m_totalPacketsCount);
1072 
1073  if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1074  {
1075  return station->m_maxTpRate;
1076  }
1077 
1078  // If we have waited enough, then sample.
1079  if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1080  {
1081  //SAMPLING
1082  NS_LOG_DEBUG ("Obtaining a sampling rate");
1084  uint16_t sampleIdx = GetNextSample (station);
1085  NS_LOG_DEBUG ("Sampling rate = " << sampleIdx);
1086 
1087  //Evaluate if the sampling rate selected should be used.
1088  uint8_t sampleGroupId = GetGroupId (sampleIdx);
1089  uint8_t sampleRateId = GetRateId (sampleIdx);
1090 
1091  // If the rate selected is not supported, then don't sample.
1092  if (station->m_groupsTable[sampleGroupId].m_supported && station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1093  {
1101  HtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1102 
1103  NS_LOG_DEBUG ("Use sample rate? MaxTpRate= " << station->m_maxTpRate << " CurrentRate= " << station->m_txrate <<
1104  " SampleRate= " << sampleIdx << " SampleProb= " << sampleRateInfo.ewmaProb);
1105 
1106  if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2
1107  && sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1108  {
1109 
1115  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1116  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1117  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1118  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1119  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
1120 
1121  uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1122  uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1123 
1124  Time sampleDuration = sampleRateInfo.perfectTxTime;
1125  Time maxTp2Duration = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1126  Time maxProbDuration = station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].perfectTxTime;
1127 
1128  NS_LOG_DEBUG ("Use sample rate? SampleDuration= " << sampleDuration << " maxTp2Duration= " << maxTp2Duration <<
1129  " maxProbDuration= " << maxProbDuration << " sampleStreams= " << +sampleStreams <<
1130  " maxTpStreams= " << +maxTpStreams);
1131  if (sampleDuration < maxTp2Duration || (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1132  {
1134  station->m_isSampling = true;
1135 
1137  station->m_sampleRate = sampleIdx;
1138 
1139  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1140  station->m_sampleTries--;
1141  return sampleIdx;
1142  }
1143  else
1144  {
1145  station->m_numSamplesSlow++;
1146  if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1147  {
1149  station->m_isSampling = true;
1150 
1152  station->m_sampleRate = sampleIdx;
1153 
1154  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1155  station->m_sampleTries--;
1156  return sampleIdx;
1157  }
1158  }
1159  }
1160  }
1161  }
1162  if (station->m_sampleWait > 0)
1163  {
1164  station->m_sampleWait--;
1165  }
1166 
1168 
1169  NS_LOG_DEBUG ("FindRate " << "maxTpRrate=" << station->m_maxTpRate);
1170  return station->m_maxTpRate;
1171 }
1172 void
1174 {
1175  NS_LOG_FUNCTION (this << station);
1176 
1178 
1179  station->m_numSamplesSlow = 0;
1180  station->m_sampleCount = 0;
1181 
1182  double tempProb;
1183 
1184  if (station->m_ampduPacketCount > 0)
1185  {
1186  uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1187  station->m_avgAmpduLen = ( newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel) ) / 100;
1188  station->m_ampduLen = 0;
1189  station->m_ampduPacketCount = 0;
1190  }
1191 
1192  /* Initialize global rate indexes */
1193  station->m_maxTpRate = GetLowestIndex (station);
1194  station->m_maxTpRate2 = GetLowestIndex (station);
1195  station->m_maxProbRate = GetLowestIndex (station);
1196 
1198  for (uint8_t j = 0; j < m_numGroups; j++)
1199  {
1200  if (station->m_groupsTable[j].m_supported)
1201  {
1202  station->m_sampleCount++;
1203 
1204  /* (re)Initialize group rate indexes */
1205  station->m_groupsTable[j].m_maxTpRate = GetLowestIndex (station, j);
1206  station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex (station, j);
1207  station->m_groupsTable[j].m_maxProbRate = GetLowestIndex (station, j);
1208 
1209  for (uint8_t i = 0; i < m_numRates; i++)
1210  {
1211  if (station->m_groupsTable[j].m_ratesTable[i].supported)
1212  {
1213  station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1214 
1215  NS_LOG_DEBUG (+i << " " << GetMcsSupported (station, station->m_groupsTable[j].m_ratesTable[i].mcsIndex) <<
1216  "\t attempt=" << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt <<
1217  "\t success=" << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1218 
1220  if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1221  {
1222  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1227  tempProb = (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) / station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1228 
1230  station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1231 
1232  if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1233  {
1234  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1235  }
1236  else
1237  {
1238  station->m_groupsTable[j].m_ratesTable[i].ewmsdProb = CalculateEwmsd (station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1239  tempProb, station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1240  m_ewmaLevel);
1242  tempProb = (tempProb * (100 - m_ewmaLevel) + station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) / 100;
1243  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1244  }
1245 
1246  station->m_groupsTable[j].m_ratesTable[i].throughput = CalculateThroughput (station, j, i, tempProb);
1247 
1248  station->m_groupsTable[j].m_ratesTable[i].successHist += station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1249  station->m_groupsTable[j].m_ratesTable[i].attemptHist += station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1250  }
1251  else
1252  {
1253  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1254  }
1255 
1257  station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess = station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1258  station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt = station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1259  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1260  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1261 
1262  if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1263  {
1264  SetBestStationThRates (station, GetIndex (j, i));
1265  SetBestProbabilityRate (station, GetIndex (j, i));
1266  }
1267 
1268  }
1269  }
1270  }
1271  }
1272 
1273  //Try to sample all available rates during each interval.
1274  station->m_sampleCount *= 8;
1275 
1276  //Recalculate retries for the rates selected.
1277  CalculateRetransmits (station, station->m_maxTpRate);
1278  CalculateRetransmits (station, station->m_maxTpRate2);
1279  CalculateRetransmits (station, station->m_maxProbRate);
1280 
1281  NS_LOG_DEBUG ("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2 << "\nmax prob=" << station->m_maxProbRate);
1282  if (m_printStats)
1283  {
1284  PrintTable (station);
1285  }
1286 }
1287 
1288 double
1289 MinstrelHtWifiManager::CalculateThroughput (MinstrelHtWifiRemoteStation *station, uint8_t groupId, uint8_t rateId, double ewmaProb)
1290 {
1296  if (ewmaProb < 10)
1297  {
1298  return 0;
1299  }
1300  else
1301  {
1306  Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1307  if (ewmaProb > 90)
1308  {
1309  return 90 / txTime.GetSeconds ();
1310  }
1311  else
1312  {
1313  return ewmaProb / txTime.GetSeconds ();
1314  }
1315  }
1316 }
1317 
1318 void
1320 {
1321  GroupInfo *group;
1322  HtRateInfo rate;
1323  uint8_t tmpGroupId, tmpRateId;
1324  double tmpTh, tmpProb;
1325  uint8_t groupId, rateId;
1326  double currentTh;
1327  // maximum group probability (GP) variables
1328  uint8_t maxGPGroupId, maxGPRateId;
1329  double maxGPTh;
1330 
1331  groupId = GetGroupId (index);
1332  rateId = GetRateId (index);
1333  group = &station->m_groupsTable[groupId];
1334  rate = group->m_ratesTable[rateId];
1335 
1336  tmpGroupId = GetGroupId (station->m_maxProbRate);
1337  tmpRateId = GetRateId (station->m_maxProbRate);
1338  tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1339  tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1340 
1341  if (rate.ewmaProb > 75)
1342  {
1343  currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1344  if (currentTh > tmpTh)
1345  {
1346  station->m_maxProbRate = index;
1347  }
1348 
1349  maxGPGroupId = GetGroupId (group->m_maxProbRate);
1350  maxGPRateId = GetRateId (group->m_maxProbRate);
1351  maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1352 
1353  if (currentTh > maxGPTh)
1354  {
1355  group->m_maxProbRate = index;
1356  }
1357  }
1358  else
1359  {
1360  if (rate.ewmaProb > tmpProb)
1361  {
1362  station->m_maxProbRate = index;
1363  }
1364  maxGPRateId = GetRateId (group->m_maxProbRate);
1365  if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1366  {
1367  group->m_maxProbRate = index;
1368  }
1369  }
1370 }
1371 
1372 /*
1373  * Find & sort topmost throughput rates
1374  *
1375  * If multiple rates provide equal throughput the sorting is based on their
1376  * current success probability. Higher success probability is preferred among
1377  * MCS groups.
1378  */
1379 void
1381 {
1382  uint8_t groupId, rateId;
1383  double th, prob;
1384  uint8_t maxTpGroupId, maxTpRateId;
1385  uint8_t maxTp2GroupId, maxTp2RateId;
1386  double maxTpTh, maxTpProb;
1387  double maxTp2Th, maxTp2Prob;
1388 
1389  groupId = GetGroupId (index);
1390  rateId = GetRateId (index);
1391  prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1392  th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1393 
1394  maxTpGroupId = GetGroupId (station->m_maxTpRate);
1395  maxTpRateId = GetRateId (station->m_maxTpRate);
1396  maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1397  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1398 
1399  maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1400  maxTp2RateId = GetRateId (station->m_maxTpRate2);
1401  maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1402  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1403 
1404  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1405  {
1406  station->m_maxTpRate2 = station->m_maxTpRate;
1407  station->m_maxTpRate = index;
1408  }
1409  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1410  {
1411  station->m_maxTpRate2 = index;
1412  }
1413 
1414  //Find best rates per group
1415 
1416  GroupInfo *group = &station->m_groupsTable[groupId];
1417  maxTpGroupId = GetGroupId (group->m_maxTpRate);
1418  maxTpRateId = GetRateId (group->m_maxTpRate);
1419  maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1420  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1421 
1422  maxTp2GroupId = GetGroupId (group->m_maxTpRate2);
1423  maxTp2RateId = GetRateId (group->m_maxTpRate2);
1424  maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1425  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1426 
1427  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1428  {
1429  group->m_maxTpRate2 = group->m_maxTpRate;
1430  group->m_maxTpRate = index;
1431  }
1432  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1433  {
1434  group->m_maxTpRate2 = index;
1435  }
1436 }
1437 
1438 void
1440 {
1441  NS_LOG_FUNCTION (this << station);
1442 
1443  station->m_groupsTable = McsGroupData (m_numGroups);
1444 
1448  NS_LOG_DEBUG ("Supported groups by station:");
1449  for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1450  {
1451  if (m_minstrelGroups[groupId].isSupported)
1452  {
1453  station->m_groupsTable[groupId].m_supported = false;
1454  if (!(!GetVhtSupported (station) && m_minstrelGroups[groupId].isVht)
1455  && (m_minstrelGroups[groupId].isVht || !GetVhtSupported (station) || !m_useVhtOnly)
1456  && !(!GetShortGuardInterval (station) && m_minstrelGroups[groupId].sgi)
1457  && (GetChannelWidth (station) >= m_minstrelGroups[groupId].chWidth)
1458  && (GetNumberOfSupportedStreams (station) >= m_minstrelGroups[groupId].streams))
1459  {
1460  NS_LOG_DEBUG ("Group " << +groupId << ": (" << +m_minstrelGroups[groupId].streams <<
1461  "," << +m_minstrelGroups[groupId].sgi << "," << m_minstrelGroups[groupId].chWidth << ")");
1462 
1463  station->m_groupsTable[groupId].m_supported = true;
1464  station->m_groupsTable[groupId].m_col = 0;
1465  station->m_groupsTable[groupId].m_index = 0;
1466 
1467  station->m_groupsTable[groupId].m_ratesTable = HtMinstrelRate (m_numRates);
1468  for (uint8_t i = 0; i < m_numRates; i++)
1469  {
1470  station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1471  }
1472 
1473  // Initialize all modes supported by the remote station that belong to the current group.
1474  for (uint8_t i = 0; i < station->m_nModes; i++)
1475  {
1476  WifiMode mode = GetMcsSupported (station, i);
1477 
1480  uint8_t rateId = mode.GetMcsValue ();
1481  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1482  {
1483  rateId %= MAX_HT_GROUP_RATES;
1484  }
1485 
1486  if ((m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_VHT
1487  && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1488  || (!m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_HT
1489  && mode.GetMcsValue () < (m_minstrelGroups[groupId].streams * 8)
1490  && mode.GetMcsValue () >= ((m_minstrelGroups[groupId].streams - 1) * 8)))
1491  {
1492  NS_LOG_DEBUG ("Mode " << +i << ": " << mode << " isVht: " << m_minstrelGroups[groupId].isVht);
1493 
1494  station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1495  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex = i;
1496  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1497  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1498  station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1499  station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1500  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1501  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1502  station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1503  station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1504  station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1505  station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1506  station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
1507  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1508  station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1509  CalculateRetransmits (station, groupId, rateId);
1510  }
1511  }
1512  }
1513  }
1514  }
1515  SetNextSample (station);
1516  UpdateStats (station);
1517  station->m_txrate = FindRate (station);
1518 }
1519 
1520 void
1522 {
1523  NS_LOG_FUNCTION (this << station << index);
1524  uint8_t groupId = GetGroupId (index);
1525  uint8_t rateId = GetRateId (index);
1526  if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1527  {
1528  CalculateRetransmits (station, groupId, rateId);
1529  }
1530 }
1531 
1532 void
1534 {
1535  NS_LOG_FUNCTION (this << station << +groupId << +rateId);
1536 
1537  uint32_t cw = 15; // Is an approximation.
1538  uint32_t cwMax = 1023;
1539  Time cwTime, txTime, dataTxTime;
1540  Time slotTime = GetMac ()->GetSlot ();
1541  Time ackTime = GetMac ()->GetBasicBlockAckTimeout ();
1542 
1543  if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1544  {
1545  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1546  }
1547  else
1548  {
1549  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1550  station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1551 
1552  dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1553  GetMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) * (station->m_avgAmpduLen - 1);
1554 
1555  /* Contention time for first 2 tries */
1556  cwTime = (cw / 2) * slotTime;
1557  cw = Min ((cw + 1) * 2, cwMax);
1558  cwTime += (cw / 2) * slotTime;
1559  cw = Min ((cw + 1) * 2, cwMax);
1560 
1561  /* Total TX time for data and Contention after first 2 tries */
1562  txTime = cwTime + 2 * (dataTxTime + ackTime);
1563 
1564  /* See how many more tries we can fit inside segment size */
1565  do
1566  {
1567  /* Contention time for this try */
1568  cwTime = (cw / 2) * slotTime;
1569  cw = Min ((cw + 1) * 2, cwMax);
1570 
1571  /* Total TX time after this try */
1572  txTime += cwTime + ackTime + dataTxTime;
1573  }
1574  while ((txTime < MilliSeconds (6))
1575  && (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1576  }
1577 }
1578 
1579 double
1580 MinstrelHtWifiManager::CalculateEwmsd (double oldEwmsd, double currentProb, double ewmaProb, double weight)
1581 {
1582  double diff, incr, tmp;
1583 
1584  /* calculate exponential weighted moving variance */
1585  diff = currentProb - ewmaProb;
1586  incr = (100 - weight) * diff / 100;
1587  tmp = oldEwmsd * oldEwmsd;
1588  tmp = weight * (tmp + diff * incr) / 100;
1589 
1590  /* return standard deviation */
1591  return sqrt (tmp);
1592 }
1593 
1594 void
1596 {
1597  NS_LOG_FUNCTION (this << station);
1598  station->m_col = station->m_index = 0;
1599 
1600  //for off-setting to make rates fall between 0 and nModes
1601  uint8_t numSampleRates = m_numRates;
1602 
1603  uint16_t newIndex;
1604  for (uint8_t col = 0; col < m_nSampleCol; col++)
1605  {
1606  for (uint8_t i = 0; i < numSampleRates; i++ )
1607  {
1612  int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
1613  newIndex = (i + uv) % numSampleRates;
1614 
1615  //this loop is used for filling in other uninitialized places
1616  while (station->m_sampleTable[newIndex][col] != 0)
1617  {
1618  newIndex = (newIndex + 1) % m_numRates;
1619  }
1620  station->m_sampleTable[newIndex][col] = i;
1621  }
1622  }
1623 }
1624 
1625 void
1627 {
1628  station->m_statsFile << " best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n" <<
1629  " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n";
1630  for (uint8_t i = 0; i < m_numGroups; i++)
1631  {
1632  StatsDump (station, i, station->m_statsFile);
1633  }
1634 
1635  station->m_statsFile << "\nTotal packet count:: ideal " << Max (0, station->m_totalPacketsCount - station->m_samplePacketsCount) <<
1636  " lookaround " << station->m_samplePacketsCount << "\n";
1637  station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen << "\n\n";
1638 
1639  station->m_statsFile.flush ();
1640 }
1641 
1642 void
1643 MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint8_t groupId, std::ofstream &of)
1644 {
1645  uint8_t numRates = m_numRates;
1646  McsGroup group = m_minstrelGroups[groupId];
1647  Time txTime;
1648  char giMode;
1649  if (group.sgi)
1650  {
1651  giMode = 'S';
1652  }
1653  else
1654  {
1655  giMode = 'L';
1656  }
1657  for (uint8_t i = 0; i < numRates; i++)
1658  {
1659  if (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[i].supported)
1660  {
1661  if (!group.isVht)
1662  {
1663  of << "HT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1664  }
1665  else
1666  {
1667  of << "VHT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1668  }
1669 
1670  uint16_t maxTpRate = station->m_maxTpRate;
1671  uint16_t maxTpRate2 = station->m_maxTpRate2;
1672  uint16_t maxProbRate = station->m_maxProbRate;
1673 
1674  uint16_t idx = GetIndex (groupId, i);
1675  if (idx == maxTpRate)
1676  {
1677  of << 'A';
1678  }
1679  else
1680  {
1681  of << ' ';
1682  }
1683  if (idx == maxTpRate2)
1684  {
1685  of << 'B';
1686  }
1687  else
1688  {
1689  of << ' ';
1690  }
1691  if (idx == maxProbRate)
1692  {
1693  of << 'P';
1694  }
1695  else
1696  {
1697  of << ' ';
1698  }
1699 
1700  if (!group.isVht)
1701  {
1702  of << std::setw (4) << " MCS" << (group.streams - 1) * 8 + i;
1703  }
1704  else
1705  {
1706  of << std::setw (7) << " MCS" << +i << "/" << (int) group.streams;
1707  }
1708 
1709  of << " " << std::setw (3) << +idx << " ";
1710 
1711  /* tx_time[rate(i)] in usec */
1712  txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
1713  of << std::setw (6) << txTime.GetMicroSeconds () << " ";
1714 
1715  of << std::setw (7) << CalculateThroughput (station, groupId, i, 100) / 100 << " " <<
1716  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100 << " " <<
1717  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb << " " <<
1718  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb << " " <<
1719  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].prob << " " <<
1720  std::setw (2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount << " " <<
1721  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " " <<
1722  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt << " " <<
1723  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " " <<
1724  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist << "\n";
1725  }
1726  }
1727 }
1728 uint16_t
1729 MinstrelHtWifiManager::GetIndex (uint8_t groupId, uint8_t rateId)
1730 {
1731  NS_LOG_FUNCTION (this << +groupId << +rateId);
1732  uint16_t index;
1733  index = groupId * m_numRates + rateId;
1734  return index;
1735 }
1736 
1737 uint8_t
1739 {
1740  NS_LOG_FUNCTION (this << index);
1741  uint8_t id;
1742  id = index % m_numRates;
1743  return id;
1744 }
1745 
1746 uint8_t
1748 {
1749  NS_LOG_FUNCTION (this << index);
1750  return index / m_numRates;
1751 }
1752 
1753 uint8_t
1754 MinstrelHtWifiManager::GetHtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1755 {
1756  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1757  return MAX_SUPPORTED_STREAMS * 2 * (chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
1758 }
1759 
1760 uint8_t
1761 MinstrelHtWifiManager::GetVhtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1762 {
1763  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1764  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;
1765 }
1766 
1767 uint16_t
1769 {
1770  NS_LOG_FUNCTION (this << station);
1771 
1772  uint8_t groupId = 0;
1773  uint8_t rateId = 0;
1774  while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
1775  {
1776  groupId++;
1777  }
1778  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1779  {
1780  rateId++;
1781  }
1782  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1783  return GetIndex (groupId, rateId);
1784 }
1785 
1786 uint16_t
1788 {
1789  NS_LOG_FUNCTION (this << station << +groupId);
1790 
1791  uint8_t rateId = 0;
1792  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1793  {
1794  rateId++;
1795  }
1796  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1797  return GetIndex (groupId, rateId);
1798 }
1799 
1802 {
1803  WifiModeList vhtMcsList;
1804  Ptr<WifiPhy> phy = GetPhy ();
1805  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1806  {
1807  WifiMode mode = phy->GetMcs (i);
1808  if (mode.GetModulationClass () == WIFI_MOD_CLASS_VHT)
1809  {
1810  vhtMcsList.push_back (mode);
1811  }
1812  }
1813  return vhtMcsList;
1814 }
1815 
1818 {
1819  WifiModeList htMcsList;
1820  Ptr<WifiPhy> phy = GetPhy ();
1821  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1822  {
1823  WifiMode mode = phy->GetMcs (i);
1824  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1825  {
1826  htMcsList.push_back (mode);
1827  }
1828  }
1829  return htMcsList;
1830 }
1831 
1832 void
1834 {
1835  //HE is not supported yet by this algorithm.
1836  if (enable)
1837  {
1838  NS_FATAL_ERROR ("WifiRemoteStationManager selected does not support HE rates");
1839  }
1840 }
1841 
1842 } // namespace ns3
void DoReportRtsOk(WifiRemoteStation *station, double ctsSnr, WifiMode ctsMode, double rtsSnr)
This method is a pure virtual method that must be implemented by the sub-class.
uint16_t m_maxProbRate
The highest success probability rate of this group.
uint8_t GetNMcsSupported(Mac48Address address) const
Return the number of MCS supported by the station.
uint16_t m_maxProbRate
rate with highest prob of success
bool HasVhtSupported(void) const
Return whether the device has VHT capability support enabled.
uint8_t m_nSampleCol
Number of sample columns.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
Ptr< WifiMac > GetMac(void) const
Return the WifiMac.
Time GetMpduTxTime(uint8_t groupId, WifiMode mode) const
Obtain the TXtime saved in the group information.
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 "...
WifiModeList GetVhtDeviceMcsList(void) const
Returns a list of only the VHT MCS supported by the device.
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
uint8_t m_sampleGroup
The group that the sample rate belongs to.
AttributeValue implementation for Boolean.
Definition: boolean.h:36
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
static const uint8_t MAX_SUPPORTED_STREAMS
Constants for maximum values.
TracedValue< uint64_t > m_currentRate
Trace rate changes.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void PrintTable(MinstrelHtWifiRemoteStation *station)
Printing Minstrel Table.
uint16_t GetLowestIndex(MinstrelHtWifiRemoteStation *station)
Returns the lowest global index of the rates supported by the station.
NS_ASSERT_MSG(false, "Ipv4AddressGenerator::MaskToIndex(): Impossible")
void SetupMac(const Ptr< WifiMac > mac)
Set up MAC associated with this device since it is the object that knows the full set of timing param...
void UpdatePacketCounters(MinstrelHtWifiRemoteStation *station, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus)
Update the number of sample count variables.
void SetBestProbabilityRate(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxProbRate if it is better than current value.
uint16_t m_maxTpRate
the current throughput rate
uint16_t m_txrate
current transmit rate
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: boolean.h:84
MinstrelHtWifiRemoteStation structure.
uint16_t m_maxTpRate2
second highest throughput rate
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:355
WifiTxVector DoGetDataTxVector(WifiRemoteStation *station)
hold per-remote-station state for Minstrel Wifi manager.
void CalculateRetransmits(MinstrelHtWifiRemoteStation *station, uint16_t index)
Calculate the number of retransmissions to set for the index rate.
uint32_t m_ampduPacketCount
Number of A-MPDUs transmitted.
static const uint8_t MAX_VHT_STREAM_GROUPS
Maximal number of groups per stream in VHT (4 possible channel widths and 2 possible SGI configuratio...
#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:202
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1022
WifiRemoteStation * DoCreateStation(void) const
uint16_t m_sampleRate
current sample rate
void SetStbc(bool stbc)
Sets if STBC is being used.
void DoReportFinalRtsFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
Mac48Address m_address
Mac48Address of the remote station.
HtMinstrelRate m_ratesTable
Information about rates of this group.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h: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)
uint16_t FindRate(MinstrelHtWifiRemoteStation *station)
Find a rate to use from Minstrel Table.
void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode)
This method is a pure virtual method that must be implemented by the sub-class.
VHT PHY (Clause 22)
Definition: wifi-mode.h:60
MinstrelRate m_minstrelTable
minstrel table
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.
MinstrelMcsGroups m_minstrelGroups
Global array for groups information.
STL namespace.
bool m_isHt
If the station is HT capable.
bool m_sampleDeferred
a flag to indicate sample rate is on the second stage
std::vector< std::vector< uint8_t > > SampleRate
Data structure for a Sample Rate table A vector of a vector uint8_t.
represent a single transmission modeA WifiMode is implemented by a single integer which is used to lo...
Definition: wifi-mode.h:97
std::vector< RateInfo > MinstrelRate
Data structure for a Minstrel Rate table A vector of a struct RateInfo.
bool DoNeedRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally)
uint8_t m_nModes
number of modes supported
uint8_t GetRateId(uint16_t index)
For managing rates from different groups, a global index for all rates in all groups is used...
WifiRemoteStationState * m_state
Remote station state.
bool m_printStats
If statistics table should be printed.
uint16_t GetIndex(uint8_t groupId, uint8_t rateId)
Returns the global index corresponding to the groupId and rateId.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
uint8_t m_lookAroundRate
The % to try other rates than our current rate.
phy
Definition: third.py:86
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:446
uint8_t m_ewmaLevel
Exponential weighted moving average level (or coefficient).
void SetBestStationThRates(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxTpRate or maxTp2Rate if is better than current values.
Time GetFirstMpduTxTime(uint8_t groupId, WifiMode mode) const
Obtain the TXtime saved in the group information.
uint8_t GetNumberOfSupportedStreams(Mac48Address address) const
Return the number of spatial streams supported by the station.
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:197
bool GetVhtSupported(Mac48Address address) const
Return whether the station supports VHT or not.
virtual uint32_t GetInteger(void)=0
Get the next random value as an integer drawn from the distribution.
uint16_t chWidth
channel width (MHz)
bool m_isSampling
a flag to indicate we are currently sampling
WifiTxVector DoGetRtsTxVector(WifiRemoteStation *station)
bool IsValid(void) const
The standard disallows certain combinations of WifiMode, number of spatial streams, and channel widths.
AttributeValue implementation for Time.
Definition: nstime.h:1076
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(void) const
HT PHY (Clause 20)
Definition: wifi-mode.h:58
uint32_t m_sampleWait
How many transmission attempts to wait until a new sample.
virtual void SetupPhy(const Ptr< WifiPhy > phy)
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
Ptr< UniformRandomVariable > m_uniformRandomVariable
Provides uniform random variables.
hold a list of per-remote-station state.
WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:500
bool m_useVhtOnly
If only VHT MCS should be used, instead of HT and VHT.
std::vector< struct GroupInfo > McsGroupData
Data structure for a table of groups.
uint32_t m_longRetry
long retries such as data packets
static TypeId GetTypeId(void)
Get the type ID.
static const uint8_t MAX_VHT_WIDTH
Maximal channel width.
uint32_t m_ampduLen
Number of MPDUs in an A-MPDU.
void SetNss(uint8_t nss)
Sets the number of Nss refer to IEEE 802.11n Table 20-28 for explanation and range.
bool m_initialized
for initializing tables
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model...
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:363
The MPDU is part of an A-MPDU, but is not the last aggregate.
uint16_t GetNextSample(MinstrelHtWifiRemoteStation *station)
Getting the next sample from Sample Table.
uint16_t m_maxTpRate2
The second max throughput rate of this group.
double ewmaProb
Exponential weighted moving average of probability.
Time perfectTxTime
Perfect transmission time calculation, or frame calculation.
bool IsValidMcs(Ptr< WifiPhy > phy, uint8_t streams, uint16_t chWidth, WifiMode mode)
Check the validity of a combination of number of streams, chWidth and mode.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint8_t m_numRates
Number of rates per group Minstrel should consider.
void InitSampleTable(MinstrelHtWifiRemoteStation *station)
Initialize Sample Table.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
double CalculateThroughput(MinstrelHtWifiRemoteStation *station, uint8_t groupId, uint8_t rateId, double ewmaProb)
Return the average throughput of the MCS defined by groupId and rateId.
void DoReportRtsFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
void UpdateRetry(MinstrelHtWifiRemoteStation *station)
Update the number of retries and reset accordingly.
uint32_t m_sampleCount
Max number of samples per update interval.
void DoReportFinalDataFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
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).
static const uint8_t MAX_HT_GROUP_RATES
Number of rates (or MCS) per HT group.
Mac48Address GetAddress(const WifiRemoteStation *station) const
Return the address of the station.
void DoReportDataFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
void UpdateStats(MinstrelHtWifiRemoteStation *station)
Updating the Minstrel Table every 1/10 seconds.
McsGroupData m_groupsTable
Table of groups with stats.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: nstime.h:1077
std::vector< WifiMode > WifiModeList
In various parts of the code, folk are interested in maintaining a list of transmission modes...
Definition: wifi-mode.h:252
uint16_t m_maxTpRate
The max throughput rate of this group.
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.
int m_totalPacketsCount
total number of packets as of now
bool GetAggregation(const WifiRemoteStation *station) const
Return whether the given station supports A-MPDU.
Implementation of Minstrel HT Rate Control AlgorithmMinstrel-HT is a rate adaptation mechanism for th...
bool HasHtSupported(void) const
Return whether the device has HT capability support enabled.
void SetupPhy(const Ptr< WifiPhy > phy)
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
Data structure to contain the information that defines a group.
void DoInitialize(void)
Initialize() implementation.
uint8_t GetNBasicModes(void) const
Return the number of basic modes we support.
void StatsDump(MinstrelHtWifiRemoteStation *station, uint8_t groupId, std::ofstream &of)
Print group statistics.
uint64_t GetNonHtReferenceRate(void) const
Definition: wifi-mode.cc:507
int m_samplePacketsCount
how many packets we have sample so far
virtual void SetupMac(const Ptr< WifiMac > mac)
Set up MAC associated with this device since it is the object that knows the full set of timing param...
Ptr< WifiPhy > GetPhy(void) const
Return the WifiPhy.
uint8_t GetVhtGroupId(uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
Returns the groupId of a VHT MCS with the given number of streams, if using sgi and the channel width...
double CalculateEwmsd(double oldEwmsd, double currentProb, double ewmaProb, double weight)
Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation.
bool GetHtSupported(Mac48Address address) const
Return whether the station supports HT or not.
if(desigRtr==addrLocal)
std::vector< McsGroup > MinstrelMcsGroups
Data structure for a table of group definitions.
void AddMpduTxTime(uint8_t groupId, WifiMode mode, Time t)
Save a TxTime to the vector of groups.
A struct to contain all statistics information related to a data rate.
void SetNextSample(MinstrelHtWifiRemoteStation *station)
Set the next sample from Sample Table.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:270
WifiModeList GetHtDeviceMcsList(void) const
Returns a list of only the HT MCS supported by the device.
uint32_t m_numSamplesSlow
Number of times a slow rate was sampled.
Ptr< MinstrelWifiManager > m_legacyManager
Pointer to an instance of MinstrelWifiManager.
uint32_t numSamplesSkipped
Number of times this rate statistics were not updated because no attempts have been made...
uint32_t m_sampleTries
Number of sample tries after waiting sampleWait.
uint8_t GetHtGroupId(uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
Returns the groupId of a HT MCS with the given number of streams, if using sgi and the channel width ...
void SetNess(uint8_t ness)
Sets the Ness number refer to IEEE 802.11n Table 20-6 for explanation.
uint8_t GetGroupId(uint16_t index)
Return the groupId from the global index.
uint32_t m_avgAmpduLen
Average number of MPDUs in an A-MPDU.
uint32_t CountRetries(MinstrelHtWifiRemoteStation *station)
Count retries.
bool GetShortGuardInterval(Mac48Address address) const
Return whether the station supports HT/VHT short guard interval.
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
WifiMode GetBasicMode(uint8_t i) const
Return a basic mode from the set of basic modes.
void DoReportDataOk(WifiRemoteStation *station, double ackSnr, WifiMode ackMode, double dataSnr)
This method is a pure virtual method that must be implemented by the sub-class.
uint8_t GetMcsValue(void) const
Definition: wifi-mode.cc:478
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: uinteger.h:45
void AddFirstMpduTxTime(uint8_t groupId, WifiMode mode, Time t)
Save a TxTime to the vector of groups.
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:915
void CheckInit(MinstrelHtWifiRemoteStation *station)
Check for initializations.
hold per-remote-station state.
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:156
WifiMode GetMcsSupported(const WifiRemoteStation *station, uint8_t i) const
Return the WifiMode supported by the specified station at the specified index.
uint16_t GetChannelWidth(const WifiRemoteStation *station) const
Return the channel width supported by the station.
uint8_t GetNess(const WifiRemoteStation *station) const
Time m_nextStatsUpdate
10 times every second