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 "ns3/wifi-mac.h"
44 #include "ns3/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 (50)),
86  MakeTimeChecker ())
87  .AddAttribute ("LegacyUpdateStatistics",
88  "The interval between updating statistics table (for legacy Minstrel) ",
89  TimeValue (MilliSeconds (100)),
91  MakeTimeChecker ())
92  .AddAttribute ("LookAroundRate",
93  "The percentage to try other rates (for legacy Minstrel)",
94  UintegerValue (10),
96  MakeUintegerChecker<uint8_t>(0, 100))
97  .AddAttribute ("EWMA",
98  "EWMA level",
99  UintegerValue (75),
101  MakeUintegerChecker<uint8_t>(0, 100))
102  .AddAttribute ("SampleColumn",
103  "The number of columns used for sampling",
104  UintegerValue (10),
106  MakeUintegerChecker <uint8_t> ())
107  .AddAttribute ("PacketLength",
108  "The packet length used for calculating mode TxTime (bytes)",
109  UintegerValue (1200),
111  MakeUintegerChecker <uint32_t> ())
112  .AddAttribute ("UseVhtOnly",
113  "Use only VHT MCSs (and not HT) when VHT is available",
114  BooleanValue (true),
117  .AddAttribute ("PrintStats",
118  "Control the printing of the statistics table",
119  BooleanValue (false),
122  .AddTraceSource ("Rate",
123  "Traced value for rate changes (b/s)",
125  "ns3::TracedValueCallback::Uint64")
126  ;
127  return tid;
128 }
129 
131  : m_numGroups (0),
132  m_numRates (0),
133  m_currentRate (0)
134 {
135  NS_LOG_FUNCTION (this);
136  m_uniformRandomVariable = CreateObject<UniformRandomVariable> ();
141  m_legacyManager = CreateObject<MinstrelWifiManager> ();
142 }
143 
145 {
146  NS_LOG_FUNCTION (this);
147  for (uint8_t i = 0; i < m_numGroups; i++)
148  {
149  m_minstrelGroups[i].ratesFirstMpduTxTimeTable.clear ();
150  m_minstrelGroups[i].ratesTxTimeTable.clear ();
151  }
152 }
153 
154 int64_t
156 {
157  NS_LOG_FUNCTION (this << stream);
158  int64_t numStreamsAssigned = 0;
160  numStreamsAssigned++;
161  numStreamsAssigned += m_legacyManager->AssignStreams (stream);
162  return numStreamsAssigned;
163 }
164 
165 void
167 {
168  NS_LOG_FUNCTION (this << phy);
169  // Setup PHY for legacy manager.
170  m_legacyManager->SetupPhy (phy);
172 }
173 
174 void
176 {
177  NS_LOG_FUNCTION (this << mac);
178  m_legacyManager->SetupMac (mac);
180 }
181 
182 void
184 {
185  NS_LOG_FUNCTION (this);
186  if (GetHeSupported ())
187  {
188  NS_FATAL_ERROR ("WifiRemoteStationManager selected does not support HE rates");
189  }
196  // Check if the device supports HT
197  if (GetHtSupported ())
198  {
201 
202  if (GetVhtSupported ())
203  {
206  }
207 
218  NS_LOG_DEBUG ("Initialize MCS Groups:");
220 
221  // Initialize all HT groups
222  for (uint16_t chWidth = 20; chWidth <= MAX_HT_WIDTH; chWidth *= 2)
223  {
224  for (uint8_t sgi = 0; sgi <= 1; sgi++)
225  {
226  for (uint8_t streams = 1; streams <= MAX_SUPPORTED_STREAMS; streams++)
227  {
228  uint8_t groupId = GetHtGroupId (streams, sgi, chWidth);
229 
230  m_minstrelGroups[groupId].streams = streams;
231  m_minstrelGroups[groupId].sgi = sgi;
232  m_minstrelGroups[groupId].chWidth = chWidth;
233  m_minstrelGroups[groupId].isVht = false;
234  m_minstrelGroups[groupId].isSupported = false;
235 
236  // Check capabilities of the device
237  if (!(!GetShortGuardIntervalSupported () && m_minstrelGroups[groupId].sgi)
238  && (GetPhy ()->GetChannelWidth () >= m_minstrelGroups[groupId].chWidth)
239  && (GetPhy ()->GetMaxSupportedTxSpatialStreams () >= m_minstrelGroups[groupId].streams))
240  {
241  m_minstrelGroups[groupId].isSupported = true;
242 
243  // Calculate TX time for all rates of the group
244  WifiModeList htMcsList = GetHtDeviceMcsList ();
245  for (uint8_t i = 0; i < MAX_HT_GROUP_RATES; i++)
246  {
247  uint16_t deviceIndex = i + (m_minstrelGroups[groupId].streams - 1) * 8;
248  WifiMode mode = htMcsList[deviceIndex];
249  AddFirstMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode, FIRST_MPDU_IN_AGGREGATE));
250  AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode, MIDDLE_MPDU_IN_AGGREGATE));
251  }
252  NS_LOG_DEBUG ("Initialized group " << +groupId << ": (" << +streams << "," << +sgi << "," << chWidth << ")");
253  }
254  }
255  }
256  }
257 
258  if (GetVhtSupported ())
259  {
260  // Initialize all VHT groups
261  for (uint16_t chWidth = 20; chWidth <= MAX_VHT_WIDTH; chWidth *= 2)
262  {
263  for (uint8_t sgi = 0; sgi <= 1; sgi++)
264  {
265  for (uint8_t streams = 1; streams <= MAX_SUPPORTED_STREAMS; streams++)
266  {
267  uint8_t groupId = GetVhtGroupId (streams, sgi, chWidth);
268 
269  m_minstrelGroups[groupId].streams = streams;
270  m_minstrelGroups[groupId].sgi = sgi;
271  m_minstrelGroups[groupId].chWidth = chWidth;
272  m_minstrelGroups[groupId].isVht = true;
273  m_minstrelGroups[groupId].isSupported = false;
274 
275  // Check capabilities of the device
276  if (!(!GetShortGuardIntervalSupported () && m_minstrelGroups[groupId].sgi)
277  && (GetPhy ()->GetChannelWidth () >= m_minstrelGroups[groupId].chWidth)
278  && (GetPhy ()->GetMaxSupportedTxSpatialStreams () >= m_minstrelGroups[groupId].streams))
279  {
280  m_minstrelGroups[groupId].isSupported = true;
281 
282  // Calculate TX time for all rates of the group
283  WifiModeList vhtMcsList = GetVhtDeviceMcsList ();
284  for (uint8_t i = 0; i < MAX_VHT_GROUP_RATES; i++)
285  {
286  WifiMode mode = vhtMcsList[i];
287  // Check for invalid VHT MCSs and do not add time to array.
288  if (IsValidMcs (GetPhy (), streams, chWidth, mode))
289  {
290  AddFirstMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode, FIRST_MPDU_IN_AGGREGATE));
291  AddMpduTxTime (groupId, mode, CalculateMpduTxDuration (GetPhy (), streams, sgi, chWidth, mode, MIDDLE_MPDU_IN_AGGREGATE));
292  }
293  }
294  NS_LOG_DEBUG ("Initialized group " << +groupId << ": (" << +streams << "," << +sgi << "," << chWidth << ")");
295  }
296  }
297  }
298  }
299  }
300  }
301 }
302 
303 bool
304 MinstrelHtWifiManager::IsValidMcs (Ptr<WifiPhy> phy, uint8_t streams, uint16_t chWidth, WifiMode mode)
305 {
306  NS_LOG_FUNCTION (this << phy << +streams << chWidth << mode);
307  WifiTxVector txvector;
308  txvector.SetNss (streams);
309  txvector.SetChannelWidth (chWidth);
310  txvector.SetMode (mode);
311  return txvector.IsValid ();
312 }
313 
314 Time
316  uint16_t chWidth, WifiMode mode, MpduType mpduType)
317 {
318  NS_LOG_FUNCTION (this << phy << +streams << +sgi << chWidth << mode << mpduType);
319  WifiTxVector txvector;
320  txvector.SetNss (streams);
321  txvector.SetGuardInterval (sgi ? 400 : 800);
322  txvector.SetChannelWidth (chWidth);
323  txvector.SetNess (0);
324  txvector.SetStbc (0);
325  txvector.SetMode (mode);
328  + WifiPhy::GetPayloadDuration (m_frameLength, txvector, phy->GetPhyBand (), mpduType);
329 }
330 
331 Time
333 {
334  NS_LOG_FUNCTION (this << +groupId << mode);
335  auto it = m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.find (mode);
336  NS_ASSERT (it != m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.end ());
337  return it->second;
338 }
339 
340 void
342 {
343  NS_LOG_FUNCTION (this << +groupId << mode << t);
344  m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.insert (std::make_pair (mode, t));
345 }
346 
347 Time
348 MinstrelHtWifiManager::GetMpduTxTime (uint8_t groupId, WifiMode mode) const
349 {
350  NS_LOG_FUNCTION (this << +groupId << mode);
351  auto it = m_minstrelGroups[groupId].ratesTxTimeTable.find (mode);
352  NS_ASSERT (it != m_minstrelGroups[groupId].ratesTxTimeTable.end ());
353  return it->second;
354 }
355 
356 void
358 {
359  NS_LOG_FUNCTION (this << +groupId << mode << t);
360  m_minstrelGroups[groupId].ratesTxTimeTable.insert (std::make_pair (mode, t));
361 }
362 
365 {
366  NS_LOG_FUNCTION (this);
368 
369  // Initialize variables common to both stations.
371  station->m_col = 0;
372  station->m_index = 0;
373  station->m_maxTpRate = 0;
374  station->m_maxTpRate2 = 0;
375  station->m_maxProbRate = 0;
376  station->m_nModes = 0;
377  station->m_totalPacketsCount = 0;
378  station->m_samplePacketsCount = 0;
379  station->m_isSampling = false;
380  station->m_sampleRate = 0;
381  station->m_sampleDeferred = false;
382  station->m_shortRetry = 0;
383  station->m_longRetry = 0;
384  station->m_txrate = 0;
385  station->m_initialized = false;
386 
387  // Variables specific to HT station
388  station->m_sampleGroup = 0;
389  station->m_numSamplesSlow = 0;
390  station->m_sampleCount = 16;
391  station->m_sampleWait = 0;
392  station->m_sampleTries = 4;
393 
394  station->m_avgAmpduLen = 1;
395  station->m_ampduLen = 0;
396  station->m_ampduPacketCount = 0;
397 
398  // If the device supports HT
399  if (GetHtSupported ())
400  {
405  station->m_isHt = true;
406  }
407  // Use the variable in the station to indicate that the device do not support HT
408  else
409  {
410  station->m_isHt = false;
411  }
412 
413  return station;
414 }
415 
416 void
418 {
419  NS_LOG_FUNCTION (this << station);
420  // Note: we appear to be doing late initialization of the table
421  // to make sure that the set of supported rates has been initialized
422  // before we perform our own initialization.
423  if (!station->m_initialized)
424  {
431  if (!GetHtSupported (station))
432  {
433  NS_LOG_INFO ("non-HT station " << station);
434  station->m_isHt = false;
435  // We will use non-HT minstrel for this station. Initialize the manager.
436  m_legacyManager->SetAttribute ("UpdateStatistics", TimeValue (m_legacyUpdateStats));
437  m_legacyManager->SetAttribute ("LookAroundRate", UintegerValue (m_lookAroundRate));
438  m_legacyManager->SetAttribute ("EWMA", UintegerValue (m_ewmaLevel));
439  m_legacyManager->SetAttribute ("SampleColumn", UintegerValue (m_nSampleCol));
440  m_legacyManager->SetAttribute ("PacketLength", UintegerValue (m_frameLength));
441  m_legacyManager->SetAttribute ("PrintStats", BooleanValue (m_printStats));
442  m_legacyManager->CheckInit (station);
443  }
444  else
445  {
446  NS_LOG_DEBUG ("HT station " << station);
447  station->m_isHt = true;
448  station->m_nModes = GetNMcsSupported (station);
449  station->m_minstrelTable = MinstrelRate (station->m_nModes);
450  station->m_sampleTable = SampleRate (m_numRates, std::vector<uint8_t> (m_nSampleCol));
451  InitSampleTable (station);
452  RateInit (station);
453  station->m_initialized = true;
454  }
455  }
456 }
457 
458 void
460 {
461  NS_LOG_FUNCTION (this << st);
462  NS_LOG_DEBUG ("DoReportRxOk m_txrate=" << static_cast<MinstrelHtWifiRemoteStation*> (st)->m_txrate);
463 }
464 
465 void
467 {
468  NS_LOG_FUNCTION (this << st);
469  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
470  CheckInit (station);
471  if (!station->m_initialized)
472  {
473  return;
474  }
475  NS_LOG_DEBUG ("DoReportRtsFailed m_txrate = " << station->m_txrate);
476  station->m_shortRetry++;
477 }
478 
479 void
480 MinstrelHtWifiManager::DoReportRtsOk (WifiRemoteStation *st, double ctsSnr, WifiMode ctsMode, double rtsSnr)
481 {
482  NS_LOG_FUNCTION (this << st);
483 }
484 
485 void
487 {
488  NS_LOG_FUNCTION (this << st);
489  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
490  NS_LOG_DEBUG ("Final RTS failed");
491  CheckInit (station);
492  if (!station->m_initialized)
493  {
494  return;
495  }
496  UpdateRetry (station);
497 }
498 
499 void
501 {
502  NS_LOG_FUNCTION (this << st);
503  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
504 
505  CheckInit (station);
506  if (!station->m_initialized)
507  {
508  return;
509  }
510 
511  NS_LOG_DEBUG ("DoReportDataFailed " << station << "\t rate " << station->m_txrate << "\tlongRetry \t" << station->m_longRetry);
512 
513  if (!station->m_isHt)
514  {
515  m_legacyManager->UpdateRate (station);
516  }
517  else if (station->m_longRetry < CountRetries (station))
518  {
519  uint8_t rateId = GetRateId (station->m_txrate);
520  uint8_t groupId = GetGroupId (station->m_txrate);
521  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++; // Increment the attempts counter for the rate used.
522  UpdateRate (station);
523  }
524 }
525 
526 void
528  double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss)
529 {
530  NS_LOG_FUNCTION (this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
531  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
532 
533  CheckInit (station);
534  if (!station->m_initialized)
535  {
536  return;
537  }
538 
539  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).");
540 
541  if (!station->m_isHt)
542  {
543  station->m_minstrelTable[station->m_txrate].numRateSuccess++;
544  station->m_minstrelTable[station->m_txrate].numRateAttempt++;
545 
546  m_legacyManager->UpdatePacketCounters (station);
547 
548  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).");
549 
550  UpdateRetry (station);
551  m_legacyManager->UpdateStats (station);
552 
553  if (station->m_nModes >= 1)
554  {
555  station->m_txrate = m_legacyManager->FindRate (station);
556  }
557  }
558  else
559  {
560  uint8_t rateId = GetRateId (station->m_txrate);
561  uint8_t groupId = GetGroupId (station->m_txrate);
562  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
563  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
564 
565  UpdatePacketCounters (station, 1, 0);
566 
567  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).");
568 
569  station->m_isSampling = false;
570  station->m_sampleDeferred = false;
571 
572  UpdateRetry (station);
573  if (Simulator::Now () >= station->m_nextStatsUpdate)
574  {
575  UpdateStats (station);
576  }
577 
578  if (station->m_nModes >= 1)
579  {
580  station->m_txrate = FindRate (station);
581  }
582  }
583 
584  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate );
585 }
586 
587 void
589 {
590  NS_LOG_FUNCTION (this << st);
591  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
592 
593  CheckInit (station);
594  if (!station->m_initialized)
595  {
596  return;
597  }
598 
599  NS_LOG_DEBUG ("DoReportFinalDataFailed - TxRate=" << station->m_txrate);
600 
601  if (!station->m_isHt)
602  {
603  m_legacyManager->UpdatePacketCounters (station);
604 
605  UpdateRetry (station);
606 
607  m_legacyManager->UpdateStats (station);
608  if (station->m_nModes >= 1)
609  {
610  station->m_txrate = m_legacyManager->FindRate (station);
611  }
612  }
613  else
614  {
615  UpdatePacketCounters (station, 0, 1);
616 
617  station->m_isSampling = false;
618  station->m_sampleDeferred = false;
619 
620  UpdateRetry (station);
621  if (Simulator::Now () >= station->m_nextStatsUpdate)
622  {
623  UpdateStats (station);
624  }
625 
626  if (station->m_nModes >= 1)
627  {
628  station->m_txrate = FindRate (station);
629  }
630  }
631  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
632 }
633 
634 void
635 MinstrelHtWifiManager::DoReportAmpduTxStatus (WifiRemoteStation *st, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus,
636  double rxSnr, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss)
637 {
638  NS_LOG_FUNCTION (this << st << nSuccessfulMpdus << nFailedMpdus << rxSnr << dataSnr << dataChannelWidth << +dataNss);
639  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
640 
641  CheckInit (station);
642  if (!station->m_initialized)
643  {
644  return;
645  }
646 
647  NS_ASSERT_MSG (station->m_isHt, "A-MPDU Tx Status called but no HT or VHT supported.");
648 
649  NS_LOG_DEBUG ("DoReportAmpduTxStatus. TxRate=" << station->m_txrate << " SuccMpdus=" <<
650  nSuccessfulMpdus << " FailedMpdus=" << nFailedMpdus);
651 
652  station->m_ampduPacketCount++;
653  station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
654 
655  UpdatePacketCounters (station, nSuccessfulMpdus, nFailedMpdus);
656 
657  uint8_t rateId = GetRateId (station->m_txrate);
658  uint8_t groupId = GetGroupId (station->m_txrate);
659  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
660  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt += nSuccessfulMpdus + nFailedMpdus;
661 
662  if (nSuccessfulMpdus == 0 && station->m_longRetry < CountRetries (station))
663  {
664  // We do not receive a BlockAck. The entire AMPDU fail.
665  UpdateRate (station);
666  }
667  else
668  {
669  station->m_isSampling = false;
670  station->m_sampleDeferred = false;
671 
672  UpdateRetry (station);
673  if (Simulator::Now () >= station->m_nextStatsUpdate)
674  {
675  UpdateStats (station);
676  }
677 
678  if (station->m_nModes >= 1)
679  {
680  station->m_txrate = FindRate (station);
681  }
682  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
683  }
684 }
685 
686 void
688 {
689  NS_LOG_FUNCTION (this << station);
690 
712  CheckInit (station);
713  if (!station->m_initialized)
714  {
715  return;
716  }
717  station->m_longRetry++;
718 
722  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
723  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
724  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
725  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
726  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
727  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
728 
730  if (!station->m_isSampling)
731  {
733  if (station->m_longRetry < station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
734  {
735  NS_LOG_DEBUG ("Not Sampling; use the same rate again");
736  station->m_txrate = station->m_maxTpRate;
737  }
738 
740  else if (station->m_longRetry < ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
741  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
742  {
743  NS_LOG_DEBUG ("Not Sampling; use the Max TP2");
744  station->m_txrate = station->m_maxTpRate2;
745  }
746 
748  else if (station->m_longRetry <= ( station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
749  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
750  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
751  {
752  NS_LOG_DEBUG ("Not Sampling; use Max Prob");
753  station->m_txrate = station->m_maxProbRate;
754  }
755  else
756  {
757  NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
758  }
759  }
760 
762  else
763  {
766  if (station->m_longRetry < 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
767  {
768  NS_LOG_DEBUG ("Sampling use the MaxTP rate");
769  station->m_txrate = station->m_maxTpRate2;
770  }
771 
773  else if (station->m_longRetry <= 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
774  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
775  {
776  NS_LOG_DEBUG ("Sampling use the MaxProb rate");
777  station->m_txrate = station->m_maxProbRate;
778  }
779  else
780  {
781  NS_FATAL_ERROR ("Max retries reached and m_longRetry not cleared properly. longRetry= " << station->m_longRetry);
782  }
783  }
784  NS_LOG_DEBUG ("Next rate to use TxRate = " << station->m_txrate);
785 }
786 
787 void
789 {
790  NS_LOG_FUNCTION (this << station);
791  station->m_shortRetry = 0;
792  station->m_longRetry = 0;
793 }
794 
795 void
796 MinstrelHtWifiManager::UpdatePacketCounters (MinstrelHtWifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus)
797 {
798  NS_LOG_FUNCTION (this << station << nSuccessfulMpdus << nFailedMpdus);
799 
800  station->m_totalPacketsCount += nSuccessfulMpdus + nFailedMpdus;
801  if (station->m_isSampling)
802  {
803  station->m_samplePacketsCount += nSuccessfulMpdus + nFailedMpdus;
804  }
805  if (station->m_totalPacketsCount == ~0)
806  {
807  station->m_samplePacketsCount = 0;
808  station->m_totalPacketsCount = 0;
809  }
810 
811  if (!station->m_sampleWait && !station->m_sampleTries && station->m_sampleCount > 0)
812  {
813  station->m_sampleWait = 16 + 2 * station->m_avgAmpduLen;
814  station->m_sampleTries = 1;
815  station->m_sampleCount--;
816  }
817 }
818 
821 {
822  NS_LOG_FUNCTION (this << st);
823  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
824 
825  if (!station->m_initialized)
826  {
827  CheckInit (station);
828  }
829 
830  if (!station->m_isHt)
831  {
832  WifiTxVector vector = m_legacyManager->GetDataTxVector (station);
833  uint64_t dataRate = vector.GetMode ().GetDataRate (vector);
834  if (m_currentRate != dataRate && !station->m_isSampling)
835  {
836  NS_LOG_DEBUG ("New datarate: " << dataRate);
837  m_currentRate = dataRate;
838  }
839  return vector;
840  }
841  else
842  {
843  NS_LOG_DEBUG ("DoGetDataMode m_txrate= " << station->m_txrate);
844 
845  uint8_t rateId = GetRateId (station->m_txrate);
846  uint8_t groupId = GetGroupId (station->m_txrate);
847  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
848 
849  NS_LOG_DEBUG ("DoGetDataMode rateId= " << +rateId << " groupId= " << +groupId << " mode= " << GetMcsSupported (station, mcsIndex));
850 
851  McsGroup group = m_minstrelGroups[groupId];
852 
853  // Check consistency of rate selected.
854  if ((group.sgi && !GetShortGuardIntervalSupported (station)) || group.chWidth > GetChannelWidth (station) || group.streams > GetNumberOfSupportedStreams (station))
855  {
856  NS_FATAL_ERROR ("Inconsistent group selected. Group: (" << +group.streams <<
857  "," << +group.sgi << "," << group.chWidth << ")" <<
858  " Station capabilities: (" << GetNumberOfSupportedStreams (station) <<
859  "," << GetShortGuardIntervalSupported (station) << "," << GetChannelWidth (station) << ")");
860  }
861  WifiMode mode = GetMcsSupported (station, mcsIndex);
862  uint64_t dataRate = mode.GetDataRate (group.chWidth, group.sgi ? 400 : 800, group.streams);
863  if (m_currentRate != dataRate && !station->m_isSampling)
864  {
865  NS_LOG_DEBUG ("New datarate: " << dataRate);
866  m_currentRate = dataRate;
867  }
869  }
870 }
871 
874 {
875  NS_LOG_FUNCTION (this << st);
876  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
877 
878  if (!station->m_initialized)
879  {
880  CheckInit (station);
881  }
882 
883  if (!station->m_isHt)
884  {
885  return m_legacyManager->GetRtsTxVector (station);
886  }
887  else
888  {
889  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
890 
891  /* RTS is sent in a non-HT frame. RTS with HT is not supported yet in NS3.
892  * When supported, decision of using HT has to follow rules in Section 9.7.6 from 802.11-2012.
893  * From Sec. 9.7.6.5: "A frame other than a BlockAckReq or BlockAck that is carried in a
894  * non-HT PPDU shall be transmitted by the STA using a rate no higher than the highest
895  * rate in the BSSBasicRateSet parameter that is less than or equal to the rate or
896  * non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
897  * directed to the same receiving STA. If no rate in the BSSBasicRateSet parameter meets
898  * these conditions, the control frame shall be transmitted at a rate no higher than the
899  * highest mandatory rate of the attached PHY that is less than or equal to the rate
900  * or non-HT reference rate (see 9.7.9) of the previously transmitted frame that was
901  * directed to the same receiving STA."
902  */
903 
904  // As we are in Minstrel HT, assume the last rate was an HT rate.
905  uint8_t rateId = GetRateId (station->m_txrate);
906  uint8_t groupId = GetGroupId (station->m_txrate);
907  uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
908 
909  WifiMode lastRate = GetMcsSupported (station, mcsIndex);
910  uint64_t lastDataRate = lastRate.GetNonHtReferenceRate ();
911  uint8_t nBasicRates = GetNBasicModes ();
912 
913  WifiMode rtsRate;
914  bool rateFound = false;
915 
916  for (uint8_t i = 0; i < nBasicRates; i++)
917  {
918  uint64_t rate = GetBasicMode (i).GetDataRate (20);
919  if (rate <= lastDataRate)
920  {
921  rtsRate = GetBasicMode (i);
922  rateFound = true;
923  }
924  }
925 
926  if (!rateFound)
927  {
928  Ptr<WifiPhy> phy = GetPhy ();
929  for (const auto & mode : phy->GetModeList ())
930  {
931  uint64_t rate = mode.GetDataRate (20);
932  if (rate <= lastDataRate)
933  {
934  rtsRate = mode;
935  rateFound = true;
936  }
937  }
938  }
939 
940  NS_ASSERT (rateFound);
941 
943  800, 1, 1, 0, GetChannelWidthForTransmission (rtsRate, GetChannelWidth (station)), GetAggregation (station));
944  }
945 }
946 
947 bool
949 {
950  NS_LOG_FUNCTION (this << st << packet << normally);
951 
952  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
953 
954  CheckInit (station);
955  if (!station->m_initialized)
956  {
957  return normally;
958  }
959 
960  uint32_t maxRetries;
961 
962  if (!station->m_isHt)
963  {
964  maxRetries = m_legacyManager->CountRetries (station);
965  }
966  else
967  {
968  maxRetries = CountRetries (station);
969  }
970 
971  if (station->m_longRetry >= maxRetries)
972  {
973  NS_LOG_DEBUG ("No re-transmission allowed. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
974  return false;
975  }
976  else
977  {
978  NS_LOG_DEBUG ("Re-transmit. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
979  return true;
980  }
981 }
982 
983 uint32_t
985 {
986  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
987  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
988  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
989  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
990  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
991  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
992 
993  if (!station->m_isSampling)
994  {
995  return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
996  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
997  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
998  }
999  else
1000  {
1001  return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1002  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1003  }
1004 }
1005 
1006 uint16_t
1008 {
1009  NS_LOG_FUNCTION (this << station);
1010  uint8_t sampleGroup = station->m_sampleGroup;
1011  uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1012  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1013  uint8_t sampleIndex = station->m_sampleTable[index][col];
1014  uint16_t rateIndex = GetIndex (sampleGroup, sampleIndex);
1015  NS_LOG_DEBUG ("Next Sample is " << rateIndex);
1016  SetNextSample (station); //Calculate the next sample rate.
1017  return rateIndex;
1018 }
1019 
1020 void
1022 {
1023  NS_LOG_FUNCTION (this << station);
1024  do
1025  {
1026  station->m_sampleGroup++;
1027  station->m_sampleGroup %= m_numGroups;
1028  }
1029  while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1030 
1031  station->m_groupsTable[station->m_sampleGroup].m_index++;
1032 
1033  uint8_t sampleGroup = station->m_sampleGroup;
1034  uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1035  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1036 
1037  if (index >= m_numRates)
1038  {
1039  station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1040  station->m_groupsTable[station->m_sampleGroup].m_col++;
1041  if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1042  {
1043  station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1044  }
1045  index = station->m_groupsTable[station->m_sampleGroup].m_index;
1046  col = station->m_groupsTable[sampleGroup].m_col;
1047  }
1048  NS_LOG_DEBUG ("New sample set: group= " << +sampleGroup << " index= " << +station->m_sampleTable[index][col]);
1049 }
1050 
1051 uint16_t
1053 {
1054  NS_LOG_FUNCTION (this << station);
1055  NS_LOG_DEBUG ("FindRate packet=" << station->m_totalPacketsCount);
1056 
1057  if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1058  {
1059  return station->m_maxTpRate;
1060  }
1061 
1062  // If we have waited enough, then sample.
1063  if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1064  {
1065  //SAMPLING
1066  NS_LOG_DEBUG ("Obtaining a sampling rate");
1068  uint16_t sampleIdx = GetNextSample (station);
1069  NS_LOG_DEBUG ("Sampling rate = " << sampleIdx);
1070 
1071  //Evaluate if the sampling rate selected should be used.
1072  uint8_t sampleGroupId = GetGroupId (sampleIdx);
1073  uint8_t sampleRateId = GetRateId (sampleIdx);
1074 
1075  // If the rate selected is not supported, then don't sample.
1076  if (station->m_groupsTable[sampleGroupId].m_supported && station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1077  {
1085  HtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1086 
1087  NS_LOG_DEBUG ("Use sample rate? MaxTpRate= " << station->m_maxTpRate << " CurrentRate= " << station->m_txrate <<
1088  " SampleRate= " << sampleIdx << " SampleProb= " << sampleRateInfo.ewmaProb);
1089 
1090  if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2
1091  && sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1092  {
1093 
1099  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1100  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1101  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1102  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1103  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
1104 
1105  uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1106  uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1107 
1108  Time sampleDuration = sampleRateInfo.perfectTxTime;
1109  Time maxTp2Duration = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1110  Time maxProbDuration = station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].perfectTxTime;
1111 
1112  NS_LOG_DEBUG ("Use sample rate? SampleDuration= " << sampleDuration << " maxTp2Duration= " << maxTp2Duration <<
1113  " maxProbDuration= " << maxProbDuration << " sampleStreams= " << +sampleStreams <<
1114  " maxTpStreams= " << +maxTpStreams);
1115  if (sampleDuration < maxTp2Duration || (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1116  {
1118  station->m_isSampling = true;
1119 
1121  station->m_sampleRate = sampleIdx;
1122 
1123  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1124  station->m_sampleTries--;
1125  return sampleIdx;
1126  }
1127  else
1128  {
1129  station->m_numSamplesSlow++;
1130  if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
1131  {
1133  station->m_isSampling = true;
1134 
1136  station->m_sampleRate = sampleIdx;
1137 
1138  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1139  station->m_sampleTries--;
1140  return sampleIdx;
1141  }
1142  }
1143  }
1144  }
1145  }
1146  if (station->m_sampleWait > 0)
1147  {
1148  station->m_sampleWait--;
1149  }
1150 
1152 
1153  NS_LOG_DEBUG ("FindRate " << "maxTpRrate=" << station->m_maxTpRate);
1154  return station->m_maxTpRate;
1155 }
1156 void
1158 {
1159  NS_LOG_FUNCTION (this << station);
1160 
1162 
1163  station->m_numSamplesSlow = 0;
1164  station->m_sampleCount = 0;
1165 
1166  double tempProb;
1167 
1168  if (station->m_ampduPacketCount > 0)
1169  {
1170  uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1171  station->m_avgAmpduLen = ( newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel) ) / 100;
1172  station->m_ampduLen = 0;
1173  station->m_ampduPacketCount = 0;
1174  }
1175 
1176  /* Initialize global rate indexes */
1177  station->m_maxTpRate = GetLowestIndex (station);
1178  station->m_maxTpRate2 = GetLowestIndex (station);
1179  station->m_maxProbRate = GetLowestIndex (station);
1180 
1182  for (uint8_t j = 0; j < m_numGroups; j++)
1183  {
1184  if (station->m_groupsTable[j].m_supported)
1185  {
1186  station->m_sampleCount++;
1187 
1188  /* (re)Initialize group rate indexes */
1189  station->m_groupsTable[j].m_maxTpRate = GetLowestIndex (station, j);
1190  station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex (station, j);
1191  station->m_groupsTable[j].m_maxProbRate = GetLowestIndex (station, j);
1192 
1193  for (uint8_t i = 0; i < m_numRates; i++)
1194  {
1195  if (station->m_groupsTable[j].m_ratesTable[i].supported)
1196  {
1197  station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1198 
1199  NS_LOG_DEBUG (+i << " " << GetMcsSupported (station, station->m_groupsTable[j].m_ratesTable[i].mcsIndex) <<
1200  "\t attempt=" << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt <<
1201  "\t success=" << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1202 
1204  if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1205  {
1206  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1211  tempProb = (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) / station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1212 
1214  station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1215 
1216  if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1217  {
1218  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1219  }
1220  else
1221  {
1222  station->m_groupsTable[j].m_ratesTable[i].ewmsdProb = CalculateEwmsd (station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1223  tempProb, station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1224  m_ewmaLevel);
1226  tempProb = (tempProb * (100 - m_ewmaLevel) + station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) / 100;
1227  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1228  }
1229 
1230  station->m_groupsTable[j].m_ratesTable[i].throughput = CalculateThroughput (station, j, i, tempProb);
1231 
1232  station->m_groupsTable[j].m_ratesTable[i].successHist += station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1233  station->m_groupsTable[j].m_ratesTable[i].attemptHist += station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1234  }
1235  else
1236  {
1237  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1238  }
1239 
1241  station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess = station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1242  station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt = station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1243  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1244  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1245 
1246  if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1247  {
1248  SetBestStationThRates (station, GetIndex (j, i));
1249  SetBestProbabilityRate (station, GetIndex (j, i));
1250  }
1251 
1252  }
1253  }
1254  }
1255  }
1256 
1257  //Try to sample all available rates during each interval.
1258  station->m_sampleCount *= 8;
1259 
1260  //Recalculate retries for the rates selected.
1261  CalculateRetransmits (station, station->m_maxTpRate);
1262  CalculateRetransmits (station, station->m_maxTpRate2);
1263  CalculateRetransmits (station, station->m_maxProbRate);
1264 
1265  NS_LOG_DEBUG ("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2 << "\nmax prob=" << station->m_maxProbRate);
1266  if (m_printStats)
1267  {
1268  PrintTable (station);
1269  }
1270 }
1271 
1272 double
1273 MinstrelHtWifiManager::CalculateThroughput (MinstrelHtWifiRemoteStation *station, uint8_t groupId, uint8_t rateId, double ewmaProb)
1274 {
1280  if (ewmaProb < 10)
1281  {
1282  return 0;
1283  }
1284  else
1285  {
1290  Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1291  if (ewmaProb > 90)
1292  {
1293  return 90 / txTime.GetSeconds ();
1294  }
1295  else
1296  {
1297  return ewmaProb / txTime.GetSeconds ();
1298  }
1299  }
1300 }
1301 
1302 void
1304 {
1305  GroupInfo *group;
1306  HtRateInfo rate;
1307  uint8_t tmpGroupId, tmpRateId;
1308  double tmpTh, tmpProb;
1309  uint8_t groupId, rateId;
1310  double currentTh;
1311  // maximum group probability (GP) variables
1312  uint8_t maxGPGroupId, maxGPRateId;
1313  double maxGPTh;
1314 
1315  groupId = GetGroupId (index);
1316  rateId = GetRateId (index);
1317  group = &station->m_groupsTable[groupId];
1318  rate = group->m_ratesTable[rateId];
1319 
1320  tmpGroupId = GetGroupId (station->m_maxProbRate);
1321  tmpRateId = GetRateId (station->m_maxProbRate);
1322  tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1323  tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1324 
1325  if (rate.ewmaProb > 75)
1326  {
1327  currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1328  if (currentTh > tmpTh)
1329  {
1330  station->m_maxProbRate = index;
1331  }
1332 
1333  maxGPGroupId = GetGroupId (group->m_maxProbRate);
1334  maxGPRateId = GetRateId (group->m_maxProbRate);
1335  maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1336 
1337  if (currentTh > maxGPTh)
1338  {
1339  group->m_maxProbRate = index;
1340  }
1341  }
1342  else
1343  {
1344  if (rate.ewmaProb > tmpProb)
1345  {
1346  station->m_maxProbRate = index;
1347  }
1348  maxGPRateId = GetRateId (group->m_maxProbRate);
1349  if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1350  {
1351  group->m_maxProbRate = index;
1352  }
1353  }
1354 }
1355 
1356 /*
1357  * Find & sort topmost throughput rates
1358  *
1359  * If multiple rates provide equal throughput the sorting is based on their
1360  * current success probability. Higher success probability is preferred among
1361  * MCS groups.
1362  */
1363 void
1365 {
1366  uint8_t groupId, rateId;
1367  double th, prob;
1368  uint8_t maxTpGroupId, maxTpRateId;
1369  uint8_t maxTp2GroupId, maxTp2RateId;
1370  double maxTpTh, maxTpProb;
1371  double maxTp2Th, maxTp2Prob;
1372 
1373  groupId = GetGroupId (index);
1374  rateId = GetRateId (index);
1375  prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1376  th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1377 
1378  maxTpGroupId = GetGroupId (station->m_maxTpRate);
1379  maxTpRateId = GetRateId (station->m_maxTpRate);
1380  maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1381  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1382 
1383  maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1384  maxTp2RateId = GetRateId (station->m_maxTpRate2);
1385  maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1386  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1387 
1388  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1389  {
1390  station->m_maxTpRate2 = station->m_maxTpRate;
1391  station->m_maxTpRate = index;
1392  }
1393  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1394  {
1395  station->m_maxTpRate2 = index;
1396  }
1397 
1398  //Find best rates per group
1399 
1400  GroupInfo *group = &station->m_groupsTable[groupId];
1401  maxTpGroupId = GetGroupId (group->m_maxTpRate);
1402  maxTpRateId = GetRateId (group->m_maxTpRate);
1403  maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1404  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1405 
1406  maxTp2GroupId = GetGroupId (group->m_maxTpRate2);
1407  maxTp2RateId = GetRateId (group->m_maxTpRate2);
1408  maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1409  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1410 
1411  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1412  {
1413  group->m_maxTpRate2 = group->m_maxTpRate;
1414  group->m_maxTpRate = index;
1415  }
1416  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1417  {
1418  group->m_maxTpRate2 = index;
1419  }
1420 }
1421 
1422 void
1424 {
1425  NS_LOG_FUNCTION (this << station);
1426 
1427  station->m_groupsTable = McsGroupData (m_numGroups);
1428 
1432  NS_LOG_DEBUG ("Supported groups by station:");
1433  for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1434  {
1435  if (m_minstrelGroups[groupId].isSupported)
1436  {
1437  station->m_groupsTable[groupId].m_supported = false;
1438  if (!(!GetVhtSupported (station) && m_minstrelGroups[groupId].isVht)
1439  && (m_minstrelGroups[groupId].isVht || !GetVhtSupported (station) || !m_useVhtOnly)
1440  && !(!GetShortGuardIntervalSupported (station) && m_minstrelGroups[groupId].sgi)
1441  && (GetChannelWidth (station) >= m_minstrelGroups[groupId].chWidth)
1442  && (GetNumberOfSupportedStreams (station) >= m_minstrelGroups[groupId].streams))
1443  {
1444  NS_LOG_DEBUG ("Group " << +groupId << ": (" << +m_minstrelGroups[groupId].streams <<
1445  "," << +m_minstrelGroups[groupId].sgi << "," << m_minstrelGroups[groupId].chWidth << ")");
1446 
1447  station->m_groupsTable[groupId].m_supported = true;
1448  station->m_groupsTable[groupId].m_col = 0;
1449  station->m_groupsTable[groupId].m_index = 0;
1450 
1451  station->m_groupsTable[groupId].m_ratesTable = HtMinstrelRate (m_numRates);
1452  for (uint8_t i = 0; i < m_numRates; i++)
1453  {
1454  station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1455  }
1456 
1457  // Initialize all modes supported by the remote station that belong to the current group.
1458  for (uint8_t i = 0; i < station->m_nModes; i++)
1459  {
1460  WifiMode mode = GetMcsSupported (station, i);
1461 
1464  uint8_t rateId = mode.GetMcsValue ();
1465  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1466  {
1467  rateId %= MAX_HT_GROUP_RATES;
1468  }
1469 
1470  if ((m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_VHT
1471  && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1472  || (!m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_HT
1473  && mode.GetMcsValue () < (m_minstrelGroups[groupId].streams * 8)
1474  && mode.GetMcsValue () >= ((m_minstrelGroups[groupId].streams - 1) * 8)))
1475  {
1476  NS_LOG_DEBUG ("Mode " << +i << ": " << mode << " isVht: " << m_minstrelGroups[groupId].isVht);
1477 
1478  station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1479  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex = i;
1480  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1481  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1482  station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1483  station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1484  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1485  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1486  station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1487  station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1488  station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1489  station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1490  station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
1491  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1492  station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1493  CalculateRetransmits (station, groupId, rateId);
1494  }
1495  }
1496  }
1497  }
1498  }
1499  SetNextSample (station);
1500  UpdateStats (station);
1501  station->m_txrate = FindRate (station);
1502 }
1503 
1504 void
1506 {
1507  NS_LOG_FUNCTION (this << station << index);
1508  uint8_t groupId = GetGroupId (index);
1509  uint8_t rateId = GetRateId (index);
1510  if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1511  {
1512  CalculateRetransmits (station, groupId, rateId);
1513  }
1514 }
1515 
1516 void
1518 {
1519  NS_LOG_FUNCTION (this << station << +groupId << +rateId);
1520 
1521  uint32_t cw = 15; // Is an approximation.
1522  uint32_t cwMax = 1023;
1523  Time cwTime, txTime, dataTxTime;
1524  Time slotTime = GetPhy ()->GetSlot ();
1525  Time ackTime = GetPhy ()->GetSifs () + GetPhy ()->GetBlockAckTxTime ();
1526 
1527  if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1528  {
1529  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1530  }
1531  else
1532  {
1533  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1534  station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1535 
1536  dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1537  GetMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) * (station->m_avgAmpduLen - 1);
1538 
1539  /* Contention time for first 2 tries */
1540  cwTime = (cw / 2) * slotTime;
1541  cw = Min ((cw + 1) * 2, cwMax);
1542  cwTime += (cw / 2) * slotTime;
1543  cw = Min ((cw + 1) * 2, cwMax);
1544 
1545  /* Total TX time for data and Contention after first 2 tries */
1546  txTime = cwTime + 2 * (dataTxTime + ackTime);
1547 
1548  /* See how many more tries we can fit inside segment size */
1549  do
1550  {
1551  /* Contention time for this try */
1552  cwTime = (cw / 2) * slotTime;
1553  cw = Min ((cw + 1) * 2, cwMax);
1554 
1555  /* Total TX time after this try */
1556  txTime += cwTime + ackTime + dataTxTime;
1557  }
1558  while ((txTime < MilliSeconds (6))
1559  && (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1560  }
1561 }
1562 
1563 double
1564 MinstrelHtWifiManager::CalculateEwmsd (double oldEwmsd, double currentProb, double ewmaProb, double weight)
1565 {
1566  double diff, incr, tmp;
1567 
1568  /* calculate exponential weighted moving variance */
1569  diff = currentProb - ewmaProb;
1570  incr = (100 - weight) * diff / 100;
1571  tmp = oldEwmsd * oldEwmsd;
1572  tmp = weight * (tmp + diff * incr) / 100;
1573 
1574  /* return standard deviation */
1575  return sqrt (tmp);
1576 }
1577 
1578 void
1580 {
1581  NS_LOG_FUNCTION (this << station);
1582  station->m_col = station->m_index = 0;
1583 
1584  //for off-setting to make rates fall between 0 and nModes
1585  uint8_t numSampleRates = m_numRates;
1586 
1587  uint16_t newIndex;
1588  for (uint8_t col = 0; col < m_nSampleCol; col++)
1589  {
1590  for (uint8_t i = 0; i < numSampleRates; i++ )
1591  {
1596  int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
1597  newIndex = (i + uv) % numSampleRates;
1598 
1599  //this loop is used for filling in other uninitialized places
1600  while (station->m_sampleTable[newIndex][col] != 0)
1601  {
1602  newIndex = (newIndex + 1) % m_numRates;
1603  }
1604  station->m_sampleTable[newIndex][col] = i;
1605  }
1606  }
1607 }
1608 
1609 void
1611 {
1612  if (!station->m_statsFile.is_open ())
1613  {
1614  std::ostringstream tmp;
1615  tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1616  station->m_statsFile.open (tmp.str ().c_str (), std::ios::out);
1617  }
1618 
1619  station->m_statsFile << " best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n" <<
1620  " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n";
1621  for (uint8_t i = 0; i < m_numGroups; i++)
1622  {
1623  StatsDump (station, i, station->m_statsFile);
1624  }
1625 
1626  station->m_statsFile << "\nTotal packet count:: ideal " << Max (0, station->m_totalPacketsCount - station->m_samplePacketsCount) <<
1627  " lookaround " << station->m_samplePacketsCount << "\n";
1628  station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen << "\n\n";
1629 
1630  station->m_statsFile.flush ();
1631 }
1632 
1633 void
1634 MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint8_t groupId, std::ofstream &of)
1635 {
1636  uint8_t numRates = m_numRates;
1637  McsGroup group = m_minstrelGroups[groupId];
1638  Time txTime;
1639  char giMode;
1640  if (group.sgi)
1641  {
1642  giMode = 'S';
1643  }
1644  else
1645  {
1646  giMode = 'L';
1647  }
1648  for (uint8_t i = 0; i < numRates; i++)
1649  {
1650  if (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[i].supported)
1651  {
1652  if (!group.isVht)
1653  {
1654  of << "HT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1655  }
1656  else
1657  {
1658  of << "VHT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1659  }
1660 
1661  uint16_t maxTpRate = station->m_maxTpRate;
1662  uint16_t maxTpRate2 = station->m_maxTpRate2;
1663  uint16_t maxProbRate = station->m_maxProbRate;
1664 
1665  uint16_t idx = GetIndex (groupId, i);
1666  if (idx == maxTpRate)
1667  {
1668  of << 'A';
1669  }
1670  else
1671  {
1672  of << ' ';
1673  }
1674  if (idx == maxTpRate2)
1675  {
1676  of << 'B';
1677  }
1678  else
1679  {
1680  of << ' ';
1681  }
1682  if (idx == maxProbRate)
1683  {
1684  of << 'P';
1685  }
1686  else
1687  {
1688  of << ' ';
1689  }
1690 
1691  if (!group.isVht)
1692  {
1693  of << std::setw (4) << " MCS" << (group.streams - 1) * 8 + i;
1694  }
1695  else
1696  {
1697  of << std::setw (7) << " MCS" << +i << "/" << (int) group.streams;
1698  }
1699 
1700  of << " " << std::setw (3) << +idx << " ";
1701 
1702  /* tx_time[rate(i)] in usec */
1703  txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
1704  of << std::setw (6) << txTime.GetMicroSeconds () << " ";
1705 
1706  of << std::setw (7) << CalculateThroughput (station, groupId, i, 100) / 100 << " " <<
1707  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100 << " " <<
1708  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb << " " <<
1709  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb << " " <<
1710  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].prob << " " <<
1711  std::setw (2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount << " " <<
1712  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " " <<
1713  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt << " " <<
1714  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " " <<
1715  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist << "\n";
1716  }
1717  }
1718 }
1719 uint16_t
1720 MinstrelHtWifiManager::GetIndex (uint8_t groupId, uint8_t rateId)
1721 {
1722  NS_LOG_FUNCTION (this << +groupId << +rateId);
1723  uint16_t index;
1724  index = groupId * m_numRates + rateId;
1725  return index;
1726 }
1727 
1728 uint8_t
1730 {
1731  NS_LOG_FUNCTION (this << index);
1732  uint8_t id;
1733  id = index % m_numRates;
1734  return id;
1735 }
1736 
1737 uint8_t
1739 {
1740  NS_LOG_FUNCTION (this << index);
1741  return index / m_numRates;
1742 }
1743 
1744 uint8_t
1745 MinstrelHtWifiManager::GetHtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1746 {
1747  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1748  return MAX_SUPPORTED_STREAMS * 2 * (chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
1749 }
1750 
1751 uint8_t
1752 MinstrelHtWifiManager::GetVhtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1753 {
1754  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1755  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;
1756 }
1757 
1758 uint16_t
1760 {
1761  NS_LOG_FUNCTION (this << station);
1762 
1763  uint8_t groupId = 0;
1764  uint8_t rateId = 0;
1765  while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
1766  {
1767  groupId++;
1768  }
1769  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1770  {
1771  rateId++;
1772  }
1773  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1774  return GetIndex (groupId, rateId);
1775 }
1776 
1777 uint16_t
1779 {
1780  NS_LOG_FUNCTION (this << station << +groupId);
1781 
1782  uint8_t rateId = 0;
1783  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1784  {
1785  rateId++;
1786  }
1787  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1788  return GetIndex (groupId, rateId);
1789 }
1790 
1793 {
1794  WifiModeList vhtMcsList;
1795  for (const auto & mode : GetPhy ()->GetMcsList (WIFI_MOD_CLASS_VHT))
1796  {
1797  vhtMcsList.push_back (mode);
1798  }
1799  return vhtMcsList;
1800 }
1801 
1804 {
1805  WifiModeList htMcsList;
1806  for (const auto & mode : GetPhy ()->GetMcsList (WIFI_MOD_CLASS_HT))
1807  {
1808  htMcsList.push_back (mode);
1809  }
1810  return htMcsList;
1811 }
1812 
1813 } // namespace ns3
uint16_t m_maxProbRate
The highest success probability rate of this group in bps.
uint8_t GetNMcsSupported(Mac48Address address) const
Return the number of MCS supported by the station.
uint16_t m_maxProbRate
rate with highest probability of success in bps
void DoReportAmpduTxStatus(WifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus, double rxSnr, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss) override
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
void SetupPhy(const Ptr< WifiPhy > phy) override
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
uint8_t m_nSampleCol
Number of sample columns.
void DoReportRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
Time GetMpduTxTime(uint8_t groupId, WifiMode mode) const
Obtain the TxTime saved in the group information.
bool GetVhtSupported(void) const
Return whether the device has VHT capability support enabled.
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.
bool DoNeedRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally) override
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.
uint32_t GetInteger(uint32_t min, uint32_t max)
Get the next random value, as an unsigned integer in the specified range .
#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.
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 in bps
uint16_t m_txrate
current transmit rate in bps
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:85
MinstrelHtWifiRemoteStation structure.
uint16_t m_maxTpRate2
second highest throughput rate in bps
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:380
void DoReportFinalDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
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.
void DoInitialize(void) override
Initialize() implementation.
static const uint8_t MAX_VHT_STREAM_GROUPS
Maximal number of groups per stream in VHT (4 possible channel widths and 2 possible SGI configuratio...
bool GetHeSupported(void) const
Return whether the device has HE capability support enabled.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1297
uint16_t m_sampleRate
current sample rate in bps
void SetStbc(bool stbc)
Sets if STBC is being used.
Mac48Address m_address
Mac48Address of the remote station.
Time m_legacyUpdateStats
How frequent do we calculate the stats for legacy MinstrelWifiManager.
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:281
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
uint8_t sgi
short guard interval (0 or 1)
uint16_t FindRate(MinstrelHtWifiRemoteStation *station)
Find a rate to use from Minstrel Table.
MinstrelRate m_minstrelTable
minstrel table
uint32_t m_frameLength
Frame length used for calculate modes TxTime in bytes.
MinstrelMcsGroups m_minstrelGroups
Global array for groups information.
WifiPreamble GetPreambleForTransmission(WifiModulationClass modulation, bool useShortPreamble)
Return the preamble to be used for the transmission.
Definition: wifi-utils.cc:116
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:47
std::vector< RateInfo > MinstrelRate
Data structure for a Minstrel Rate table A vector of a struct RateInfo.
WifiRemoteStation * DoCreateStation(void) const override
uint8_t m_nModes
number of modes supported
uint8_t GetRateId(uint16_t index)
For managing rates from different groups, a global index for all rates in all groups is used...
WifiRemoteStationState * m_state
Remote station state.
bool m_printStats
If statistics table should be printed.
MpduType
The type of an MPDU.
uint16_t GetIndex(uint8_t groupId, uint8_t rateId)
Returns the global index corresponding to the groupId and rateId.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
uint8_t m_lookAroundRate
The % to try other rates than our current rate.
phy
Definition: third.py:93
uint8_t m_ewmaLevel
Exponential weighted moving average level (or coefficient).
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode...
void SetBestStationThRates(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxTpRate or maxTp2Rate if is better than current values.
void SetupMac(const Ptr< WifiMac > mac) override
Set up MAC associated with this device since it is the object that knows the full set of timing param...
Time GetFirstMpduTxTime(uint8_t groupId, WifiMode mode) const
Obtain the TxTime saved in the group information.
uint8_t GetNumberOfSupportedStreams(Mac48Address address) const
Return the number of spatial streams supported by the station.
bool GetShortPreambleEnabled(void) const
Return whether the device uses short PHY preambles.
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:218
The MPDU is the first aggregate in an A-MPDU with multiple MPDUs, but is not the last aggregate...
uint16_t chWidth
channel width (MHz)
bool m_isSampling
a flag to indicate we are currently sampling
bool IsValid(void) const
The standard disallows certain combinations of WifiMode, number of spatial streams, and channel widths.
WifiTxVector DoGetDataTxVector(WifiRemoteStation *station) override
AttributeValue implementation for Time.
Definition: nstime.h:1353
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 in MHz.
bool GetHtSupported(void) const
Return whether the device has HT capability support enabled.
mac
Definition: third.py:99
uint8_t streams
streams
The MPDU is part of an A-MPDU with multiple MPDUs, but is neither the first nor the last aggregate...
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:230
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...
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:159
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 in MHz.
uint32_t m_ampduLen
Number of MPDUs in an A-MPDU.
void SetNss(uint8_t nss)
Sets the number of Nss.
bool m_initialized
for initializing tables
Time GetBlockAckTxTime(void) const
Return the estimated BlockAck TX time for this PHY.
Definition: wifi-phy.cc:946
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:388
uint16_t GetNextSample(MinstrelHtWifiRemoteStation *station)
Getting the next sample from Sample Table.
uint16_t m_maxTpRate2
The second max throughput rate of this group in bps.
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.
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 UpdateRetry(MinstrelHtWifiRemoteStation *station)
Update the number of retries and reset accordingly.
uint32_t m_sampleCount
Max number of samples per update interval.
uint16_t GetChannelWidthForTransmission(WifiMode mode, uint16_t maxSupportedChannelWidth)
Return the channel width that corresponds to the selected mode (instead of letting the PHY&#39;s default ...
Definition: wifi-utils.cc:97
uint8_t m_numGroups
Number of groups Minstrel should consider.
Time m_updateStats
How frequent do we calculate the stats.
void DoReportFinalRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
static const uint8_t MAX_HT_GROUP_RATES
Number of rates (or MCS) per HT group.
void UpdateStats(MinstrelHtWifiRemoteStation *station)
Update the Minstrel Table.
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:1354
std::vector< WifiMode > WifiModeList
In various parts of the code, folk are interested in maintaining a list of transmission modes...
Definition: wifi-mode.h:254
uint16_t m_maxTpRate
The max throughput rate of this group in bps.
bool GetShortGuardIntervalSupported(void) const
Return whether the device has SGI support enabled.
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
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...
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model...
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
Data structure to contain the information that defines a group.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:88
void DoReportDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
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:166
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...
void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode) override
This method is a pure virtual method that must be implemented by the sub-class.
void UpdatePacketCounters(MinstrelHtWifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus)
Update the number of sample count variables.
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.
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:910
void DoReportRtsOk(WifiRemoteStation *station, double ctsSnr, WifiMode ctsMode, double rtsSnr) override
This method is a pure virtual method that must be implemented by the sub-class.
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.
WifiTxVector DoGetRtsTxVector(WifiRemoteStation *station) override
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:273
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< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
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...
static Time GetPayloadDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, MpduType mpdutype=NORMAL_MPDU, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1586
Time GetSlot(void) const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:922
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1604
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.
uint8_t GetGroupId(uint16_t index)
Return the groupId from the global index.
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:533
Time CalculateMpduTxDuration(Ptr< WifiPhy > phy, uint8_t streams, uint8_t sgi, uint16_t chWidth, WifiMode mode, MpduType mpduType)
Estimates the TxTime of a frame with a given mode and group (stream, guard interval and channel width...
uint32_t m_avgAmpduLen
Average number of MPDUs in an A-MPDU.
uint32_t CountRetries(MinstrelHtWifiRemoteStation *station)
Count retries.
void DoReportDataOk(WifiRemoteStation *station, double ackSnr, WifiMode ackMode, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss) override
This method is a pure virtual method that must be implemented by the sub-class.
void UpdateRate(MinstrelHtWifiRemoteStation *station)
Update rate.
uint32_t m_shortRetry
short retries such as control packets
WifiMode GetBasicMode(uint8_t i) const
Return a basic mode from the set of basic modes.
uint8_t GetMcsValue(void) const
Definition: wifi-mode.cc:137
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:923
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:100
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