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 (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
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, uint8_t nSuccessfulMpdus, uint8_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, uint8_t nSuccessfulMpdus, uint8_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  uint8_t nSupportRates = phy->GetNModes ();
930  for (uint8_t i = 0; i < nSupportRates; i++)
931  {
932  uint64_t rate = phy->GetMode (i).GetDataRate (20);
933  if (rate <= lastDataRate)
934  {
935  rtsRate = phy->GetMode (i);
936  rateFound = true;
937  }
938  }
939  }
940 
941  NS_ASSERT (rateFound);
942 
944  800, 1, 1, 0, GetChannelWidthForTransmission (rtsRate, GetChannelWidth (station)), GetAggregation (station));
945  }
946 }
947 
948 bool
950 {
951  NS_LOG_FUNCTION (this << st << packet << normally);
952 
953  MinstrelHtWifiRemoteStation *station = static_cast<MinstrelHtWifiRemoteStation*> (st);
954 
955  CheckInit (station);
956  if (!station->m_initialized)
957  {
958  return normally;
959  }
960 
961  uint32_t maxRetries;
962 
963  if (!station->m_isHt)
964  {
965  maxRetries = m_legacyManager->CountRetries (station);
966  }
967  else
968  {
969  maxRetries = CountRetries (station);
970  }
971 
972  if (station->m_longRetry >= maxRetries)
973  {
974  NS_LOG_DEBUG ("No re-transmission allowed. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
975  return false;
976  }
977  else
978  {
979  NS_LOG_DEBUG ("Re-transmit. Retries: " << station->m_longRetry << " Max retries: " << maxRetries);
980  return true;
981  }
982 }
983 
984 uint32_t
986 {
987  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
988  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
989  uint8_t maxTpRateId = GetRateId (station->m_maxTpRate);
990  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
991  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
992  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
993 
994  if (!station->m_isSampling)
995  {
996  return station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
997  station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
998  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
999  }
1000  else
1001  {
1002  return 1 + station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
1003  station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
1004  }
1005 }
1006 
1007 uint16_t
1009 {
1010  NS_LOG_FUNCTION (this << station);
1011  uint8_t sampleGroup = station->m_sampleGroup;
1012  uint8_t index = station->m_groupsTable[sampleGroup].m_index;
1013  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1014  uint8_t sampleIndex = station->m_sampleTable[index][col];
1015  uint16_t rateIndex = GetIndex (sampleGroup, sampleIndex);
1016  NS_LOG_DEBUG ("Next Sample is " << rateIndex);
1017  SetNextSample (station); //Calculate the next sample rate.
1018  return rateIndex;
1019 }
1020 
1021 void
1023 {
1024  NS_LOG_FUNCTION (this << station);
1025  do
1026  {
1027  station->m_sampleGroup++;
1028  station->m_sampleGroup %= m_numGroups;
1029  }
1030  while (!station->m_groupsTable[station->m_sampleGroup].m_supported);
1031 
1032  station->m_groupsTable[station->m_sampleGroup].m_index++;
1033 
1034  uint8_t sampleGroup = station->m_sampleGroup;
1035  uint8_t index = station->m_groupsTable[station->m_sampleGroup].m_index;
1036  uint8_t col = station->m_groupsTable[sampleGroup].m_col;
1037 
1038  if (index >= m_numRates)
1039  {
1040  station->m_groupsTable[station->m_sampleGroup].m_index = 0;
1041  station->m_groupsTable[station->m_sampleGroup].m_col++;
1042  if (station->m_groupsTable[station->m_sampleGroup].m_col >= m_nSampleCol)
1043  {
1044  station->m_groupsTable[station->m_sampleGroup].m_col = 0;
1045  }
1046  index = station->m_groupsTable[station->m_sampleGroup].m_index;
1047  col = station->m_groupsTable[sampleGroup].m_col;
1048  }
1049  NS_LOG_DEBUG ("New sample set: group= " << +sampleGroup << " index= " << +station->m_sampleTable[index][col]);
1050 }
1051 
1052 uint16_t
1054 {
1055  NS_LOG_FUNCTION (this << station);
1056  NS_LOG_DEBUG ("FindRate packet=" << station->m_totalPacketsCount);
1057 
1058  if ((station->m_samplePacketsCount + station->m_totalPacketsCount) == 0)
1059  {
1060  return station->m_maxTpRate;
1061  }
1062 
1063  // If we have waited enough, then sample.
1064  if (station->m_sampleWait == 0 && station->m_sampleTries != 0)
1065  {
1066  //SAMPLING
1067  NS_LOG_DEBUG ("Obtaining a sampling rate");
1069  uint16_t sampleIdx = GetNextSample (station);
1070  NS_LOG_DEBUG ("Sampling rate = " << sampleIdx);
1071 
1072  //Evaluate if the sampling rate selected should be used.
1073  uint8_t sampleGroupId = GetGroupId (sampleIdx);
1074  uint8_t sampleRateId = GetRateId (sampleIdx);
1075 
1076  // If the rate selected is not supported, then don't sample.
1077  if (station->m_groupsTable[sampleGroupId].m_supported && station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
1078  {
1086  HtRateInfo sampleRateInfo = station->m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
1087 
1088  NS_LOG_DEBUG ("Use sample rate? MaxTpRate= " << station->m_maxTpRate << " CurrentRate= " << station->m_txrate <<
1089  " SampleRate= " << sampleIdx << " SampleProb= " << sampleRateInfo.ewmaProb);
1090 
1091  if (sampleIdx != station->m_maxTpRate && sampleIdx != station->m_maxTpRate2
1092  && sampleIdx != station->m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
1093  {
1094 
1100  uint8_t maxTpGroupId = GetGroupId (station->m_maxTpRate);
1101  uint8_t maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1102  uint8_t maxTp2RateId = GetRateId (station->m_maxTpRate2);
1103  uint8_t maxProbGroupId = GetGroupId (station->m_maxProbRate);
1104  uint8_t maxProbRateId = GetRateId (station->m_maxProbRate);
1105 
1106  uint8_t maxTpStreams = m_minstrelGroups[maxTpGroupId].streams;
1107  uint8_t sampleStreams = m_minstrelGroups[sampleGroupId].streams;
1108 
1109  Time sampleDuration = sampleRateInfo.perfectTxTime;
1110  Time maxTp2Duration = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
1111  Time maxProbDuration = station->m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].perfectTxTime;
1112 
1113  NS_LOG_DEBUG ("Use sample rate? SampleDuration= " << sampleDuration << " maxTp2Duration= " << maxTp2Duration <<
1114  " maxProbDuration= " << maxProbDuration << " sampleStreams= " << +sampleStreams <<
1115  " maxTpStreams= " << +maxTpStreams);
1116  if (sampleDuration < maxTp2Duration || (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
1117  {
1119  station->m_isSampling = true;
1120 
1122  station->m_sampleRate = sampleIdx;
1123 
1124  NS_LOG_DEBUG ("FindRate " << "sampleRate=" << sampleIdx);
1125  station->m_sampleTries--;
1126  return sampleIdx;
1127  }
1128  else
1129  {
1130  station->m_numSamplesSlow++;
1131  if (sampleRateInfo.numSamplesSkipped >= 20 && station->m_numSamplesSlow <= 2)
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  }
1144  }
1145  }
1146  }
1147  if (station->m_sampleWait > 0)
1148  {
1149  station->m_sampleWait--;
1150  }
1151 
1153 
1154  NS_LOG_DEBUG ("FindRate " << "maxTpRrate=" << station->m_maxTpRate);
1155  return station->m_maxTpRate;
1156 }
1157 void
1159 {
1160  NS_LOG_FUNCTION (this << station);
1161 
1163 
1164  station->m_numSamplesSlow = 0;
1165  station->m_sampleCount = 0;
1166 
1167  double tempProb;
1168 
1169  if (station->m_ampduPacketCount > 0)
1170  {
1171  uint32_t newLen = station->m_ampduLen / station->m_ampduPacketCount;
1172  station->m_avgAmpduLen = ( newLen * (100 - m_ewmaLevel) + (station->m_avgAmpduLen * m_ewmaLevel) ) / 100;
1173  station->m_ampduLen = 0;
1174  station->m_ampduPacketCount = 0;
1175  }
1176 
1177  /* Initialize global rate indexes */
1178  station->m_maxTpRate = GetLowestIndex (station);
1179  station->m_maxTpRate2 = GetLowestIndex (station);
1180  station->m_maxProbRate = GetLowestIndex (station);
1181 
1183  for (uint8_t j = 0; j < m_numGroups; j++)
1184  {
1185  if (station->m_groupsTable[j].m_supported)
1186  {
1187  station->m_sampleCount++;
1188 
1189  /* (re)Initialize group rate indexes */
1190  station->m_groupsTable[j].m_maxTpRate = GetLowestIndex (station, j);
1191  station->m_groupsTable[j].m_maxTpRate2 = GetLowestIndex (station, j);
1192  station->m_groupsTable[j].m_maxProbRate = GetLowestIndex (station, j);
1193 
1194  for (uint8_t i = 0; i < m_numRates; i++)
1195  {
1196  if (station->m_groupsTable[j].m_ratesTable[i].supported)
1197  {
1198  station->m_groupsTable[j].m_ratesTable[i].retryUpdated = false;
1199 
1200  NS_LOG_DEBUG (+i << " " << GetMcsSupported (station, station->m_groupsTable[j].m_ratesTable[i].mcsIndex) <<
1201  "\t attempt=" << station->m_groupsTable[j].m_ratesTable[i].numRateAttempt <<
1202  "\t success=" << station->m_groupsTable[j].m_ratesTable[i].numRateSuccess);
1203 
1205  if (station->m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
1206  {
1207  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
1212  tempProb = (100 * station->m_groupsTable[j].m_ratesTable[i].numRateSuccess) / station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1213 
1215  station->m_groupsTable[j].m_ratesTable[i].prob = tempProb;
1216 
1217  if (station->m_groupsTable[j].m_ratesTable[i].successHist == 0)
1218  {
1219  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1220  }
1221  else
1222  {
1223  station->m_groupsTable[j].m_ratesTable[i].ewmsdProb = CalculateEwmsd (station->m_groupsTable[j].m_ratesTable[i].ewmsdProb,
1224  tempProb, station->m_groupsTable[j].m_ratesTable[i].ewmaProb,
1225  m_ewmaLevel);
1227  tempProb = (tempProb * (100 - m_ewmaLevel) + station->m_groupsTable[j].m_ratesTable[i].ewmaProb * m_ewmaLevel) / 100;
1228  station->m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
1229  }
1230 
1231  station->m_groupsTable[j].m_ratesTable[i].throughput = CalculateThroughput (station, j, i, tempProb);
1232 
1233  station->m_groupsTable[j].m_ratesTable[i].successHist += station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1234  station->m_groupsTable[j].m_ratesTable[i].attemptHist += station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1235  }
1236  else
1237  {
1238  station->m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
1239  }
1240 
1242  station->m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess = station->m_groupsTable[j].m_ratesTable[i].numRateSuccess;
1243  station->m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt = station->m_groupsTable[j].m_ratesTable[i].numRateAttempt;
1244  station->m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
1245  station->m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
1246 
1247  if (station->m_groupsTable[j].m_ratesTable[i].throughput != 0)
1248  {
1249  SetBestStationThRates (station, GetIndex (j, i));
1250  SetBestProbabilityRate (station, GetIndex (j, i));
1251  }
1252 
1253  }
1254  }
1255  }
1256  }
1257 
1258  //Try to sample all available rates during each interval.
1259  station->m_sampleCount *= 8;
1260 
1261  //Recalculate retries for the rates selected.
1262  CalculateRetransmits (station, station->m_maxTpRate);
1263  CalculateRetransmits (station, station->m_maxTpRate2);
1264  CalculateRetransmits (station, station->m_maxProbRate);
1265 
1266  NS_LOG_DEBUG ("max tp=" << station->m_maxTpRate << "\nmax tp2=" << station->m_maxTpRate2 << "\nmax prob=" << station->m_maxProbRate);
1267  if (m_printStats)
1268  {
1269  PrintTable (station);
1270  }
1271 }
1272 
1273 double
1274 MinstrelHtWifiManager::CalculateThroughput (MinstrelHtWifiRemoteStation *station, uint8_t groupId, uint8_t rateId, double ewmaProb)
1275 {
1281  if (ewmaProb < 10)
1282  {
1283  return 0;
1284  }
1285  else
1286  {
1291  Time txTime = station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
1292  if (ewmaProb > 90)
1293  {
1294  return 90 / txTime.GetSeconds ();
1295  }
1296  else
1297  {
1298  return ewmaProb / txTime.GetSeconds ();
1299  }
1300  }
1301 }
1302 
1303 void
1305 {
1306  GroupInfo *group;
1307  HtRateInfo rate;
1308  uint8_t tmpGroupId, tmpRateId;
1309  double tmpTh, tmpProb;
1310  uint8_t groupId, rateId;
1311  double currentTh;
1312  // maximum group probability (GP) variables
1313  uint8_t maxGPGroupId, maxGPRateId;
1314  double maxGPTh;
1315 
1316  groupId = GetGroupId (index);
1317  rateId = GetRateId (index);
1318  group = &station->m_groupsTable[groupId];
1319  rate = group->m_ratesTable[rateId];
1320 
1321  tmpGroupId = GetGroupId (station->m_maxProbRate);
1322  tmpRateId = GetRateId (station->m_maxProbRate);
1323  tmpProb = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
1324  tmpTh = station->m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
1325 
1326  if (rate.ewmaProb > 75)
1327  {
1328  currentTh = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1329  if (currentTh > tmpTh)
1330  {
1331  station->m_maxProbRate = index;
1332  }
1333 
1334  maxGPGroupId = GetGroupId (group->m_maxProbRate);
1335  maxGPRateId = GetRateId (group->m_maxProbRate);
1336  maxGPTh = station->m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
1337 
1338  if (currentTh > maxGPTh)
1339  {
1340  group->m_maxProbRate = index;
1341  }
1342  }
1343  else
1344  {
1345  if (rate.ewmaProb > tmpProb)
1346  {
1347  station->m_maxProbRate = index;
1348  }
1349  maxGPRateId = GetRateId (group->m_maxProbRate);
1350  if (rate.ewmaProb > group->m_ratesTable[maxGPRateId].ewmaProb)
1351  {
1352  group->m_maxProbRate = index;
1353  }
1354  }
1355 }
1356 
1357 /*
1358  * Find & sort topmost throughput rates
1359  *
1360  * If multiple rates provide equal throughput the sorting is based on their
1361  * current success probability. Higher success probability is preferred among
1362  * MCS groups.
1363  */
1364 void
1366 {
1367  uint8_t groupId, rateId;
1368  double th, prob;
1369  uint8_t maxTpGroupId, maxTpRateId;
1370  uint8_t maxTp2GroupId, maxTp2RateId;
1371  double maxTpTh, maxTpProb;
1372  double maxTp2Th, maxTp2Prob;
1373 
1374  groupId = GetGroupId (index);
1375  rateId = GetRateId (index);
1376  prob = station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
1377  th = station->m_groupsTable[groupId].m_ratesTable[rateId].throughput;
1378 
1379  maxTpGroupId = GetGroupId (station->m_maxTpRate);
1380  maxTpRateId = GetRateId (station->m_maxTpRate);
1381  maxTpProb = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
1382  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1383 
1384  maxTp2GroupId = GetGroupId (station->m_maxTpRate2);
1385  maxTp2RateId = GetRateId (station->m_maxTpRate2);
1386  maxTp2Prob = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
1387  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1388 
1389  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1390  {
1391  station->m_maxTpRate2 = station->m_maxTpRate;
1392  station->m_maxTpRate = index;
1393  }
1394  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1395  {
1396  station->m_maxTpRate2 = index;
1397  }
1398 
1399  //Find best rates per group
1400 
1401  GroupInfo *group = &station->m_groupsTable[groupId];
1402  maxTpGroupId = GetGroupId (group->m_maxTpRate);
1403  maxTpRateId = GetRateId (group->m_maxTpRate);
1404  maxTpProb = group->m_ratesTable[maxTpRateId].ewmaProb;
1405  maxTpTh = station->m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
1406 
1407  maxTp2GroupId = GetGroupId (group->m_maxTpRate2);
1408  maxTp2RateId = GetRateId (group->m_maxTpRate2);
1409  maxTp2Prob = group->m_ratesTable[maxTp2RateId].ewmaProb;
1410  maxTp2Th = station->m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
1411 
1412  if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
1413  {
1414  group->m_maxTpRate2 = group->m_maxTpRate;
1415  group->m_maxTpRate = index;
1416  }
1417  else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
1418  {
1419  group->m_maxTpRate2 = index;
1420  }
1421 }
1422 
1423 void
1425 {
1426  NS_LOG_FUNCTION (this << station);
1427 
1428  station->m_groupsTable = McsGroupData (m_numGroups);
1429 
1433  NS_LOG_DEBUG ("Supported groups by station:");
1434  for (uint8_t groupId = 0; groupId < m_numGroups; groupId++)
1435  {
1436  if (m_minstrelGroups[groupId].isSupported)
1437  {
1438  station->m_groupsTable[groupId].m_supported = false;
1439  if (!(!GetVhtSupported (station) && m_minstrelGroups[groupId].isVht)
1440  && (m_minstrelGroups[groupId].isVht || !GetVhtSupported (station) || !m_useVhtOnly)
1441  && !(!GetShortGuardIntervalSupported (station) && m_minstrelGroups[groupId].sgi)
1442  && (GetChannelWidth (station) >= m_minstrelGroups[groupId].chWidth)
1443  && (GetNumberOfSupportedStreams (station) >= m_minstrelGroups[groupId].streams))
1444  {
1445  NS_LOG_DEBUG ("Group " << +groupId << ": (" << +m_minstrelGroups[groupId].streams <<
1446  "," << +m_minstrelGroups[groupId].sgi << "," << m_minstrelGroups[groupId].chWidth << ")");
1447 
1448  station->m_groupsTable[groupId].m_supported = true;
1449  station->m_groupsTable[groupId].m_col = 0;
1450  station->m_groupsTable[groupId].m_index = 0;
1451 
1452  station->m_groupsTable[groupId].m_ratesTable = HtMinstrelRate (m_numRates);
1453  for (uint8_t i = 0; i < m_numRates; i++)
1454  {
1455  station->m_groupsTable[groupId].m_ratesTable[i].supported = false;
1456  }
1457 
1458  // Initialize all modes supported by the remote station that belong to the current group.
1459  for (uint8_t i = 0; i < station->m_nModes; i++)
1460  {
1461  WifiMode mode = GetMcsSupported (station, i);
1462 
1465  uint8_t rateId = mode.GetMcsValue ();
1466  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1467  {
1468  rateId %= MAX_HT_GROUP_RATES;
1469  }
1470 
1471  if ((m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_VHT
1472  && IsValidMcs (GetPhy (), m_minstrelGroups[groupId].streams, m_minstrelGroups[groupId].chWidth, mode))
1473  || (!m_minstrelGroups[groupId].isVht && mode.GetModulationClass () == WIFI_MOD_CLASS_HT
1474  && mode.GetMcsValue () < (m_minstrelGroups[groupId].streams * 8)
1475  && mode.GetMcsValue () >= ((m_minstrelGroups[groupId].streams - 1) * 8)))
1476  {
1477  NS_LOG_DEBUG ("Mode " << +i << ": " << mode << " isVht: " << m_minstrelGroups[groupId].isVht);
1478 
1479  station->m_groupsTable[groupId].m_ratesTable[rateId].supported = true;
1480  station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex = i;
1481  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
1482  station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
1483  station->m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
1484  station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
1485  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
1486  station->m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
1487  station->m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
1488  station->m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
1489  station->m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
1490  station->m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
1491  station->m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, i));
1492  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
1493  station->m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
1494  CalculateRetransmits (station, groupId, rateId);
1495  }
1496  }
1497  }
1498  }
1499  }
1500  SetNextSample (station);
1501  UpdateStats (station);
1502  station->m_txrate = FindRate (station);
1503 }
1504 
1505 void
1507 {
1508  NS_LOG_FUNCTION (this << station << index);
1509  uint8_t groupId = GetGroupId (index);
1510  uint8_t rateId = GetRateId (index);
1511  if (!station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
1512  {
1513  CalculateRetransmits (station, groupId, rateId);
1514  }
1515 }
1516 
1517 void
1519 {
1520  NS_LOG_FUNCTION (this << station << +groupId << +rateId);
1521 
1522  uint32_t cw = 15; // Is an approximation.
1523  uint32_t cwMax = 1023;
1524  Time cwTime, txTime, dataTxTime;
1525  Time slotTime = GetPhy ()->GetSlot ();
1526  Time ackTime = GetPhy ()->GetSifs () + GetPhy ()->GetBlockAckTxTime ();
1527 
1528  if (station->m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
1529  {
1530  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
1531  }
1532  else
1533  {
1534  station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
1535  station->m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = true;
1536 
1537  dataTxTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) +
1538  GetMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex)) * (station->m_avgAmpduLen - 1);
1539 
1540  /* Contention time for first 2 tries */
1541  cwTime = (cw / 2) * slotTime;
1542  cw = Min ((cw + 1) * 2, cwMax);
1543  cwTime += (cw / 2) * slotTime;
1544  cw = Min ((cw + 1) * 2, cwMax);
1545 
1546  /* Total TX time for data and Contention after first 2 tries */
1547  txTime = cwTime + 2 * (dataTxTime + ackTime);
1548 
1549  /* See how many more tries we can fit inside segment size */
1550  do
1551  {
1552  /* Contention time for this try */
1553  cwTime = (cw / 2) * slotTime;
1554  cw = Min ((cw + 1) * 2, cwMax);
1555 
1556  /* Total TX time after this try */
1557  txTime += cwTime + ackTime + dataTxTime;
1558  }
1559  while ((txTime < MilliSeconds (6))
1560  && (++station->m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
1561  }
1562 }
1563 
1564 double
1565 MinstrelHtWifiManager::CalculateEwmsd (double oldEwmsd, double currentProb, double ewmaProb, double weight)
1566 {
1567  double diff, incr, tmp;
1568 
1569  /* calculate exponential weighted moving variance */
1570  diff = currentProb - ewmaProb;
1571  incr = (100 - weight) * diff / 100;
1572  tmp = oldEwmsd * oldEwmsd;
1573  tmp = weight * (tmp + diff * incr) / 100;
1574 
1575  /* return standard deviation */
1576  return sqrt (tmp);
1577 }
1578 
1579 void
1581 {
1582  NS_LOG_FUNCTION (this << station);
1583  station->m_col = station->m_index = 0;
1584 
1585  //for off-setting to make rates fall between 0 and nModes
1586  uint8_t numSampleRates = m_numRates;
1587 
1588  uint16_t newIndex;
1589  for (uint8_t col = 0; col < m_nSampleCol; col++)
1590  {
1591  for (uint8_t i = 0; i < numSampleRates; i++ )
1592  {
1597  int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
1598  newIndex = (i + uv) % numSampleRates;
1599 
1600  //this loop is used for filling in other uninitialized places
1601  while (station->m_sampleTable[newIndex][col] != 0)
1602  {
1603  newIndex = (newIndex + 1) % m_numRates;
1604  }
1605  station->m_sampleTable[newIndex][col] = i;
1606  }
1607  }
1608 }
1609 
1610 void
1612 {
1613  if (!station->m_statsFile.is_open ())
1614  {
1615  std::ostringstream tmp;
1616  tmp << "minstrel-ht-stats-" << station->m_state->m_address << ".txt";
1617  station->m_statsFile.open (tmp.str ().c_str (), std::ios::out);
1618  }
1619 
1620  station->m_statsFile << " best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n" <<
1621  " mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n";
1622  for (uint8_t i = 0; i < m_numGroups; i++)
1623  {
1624  StatsDump (station, i, station->m_statsFile);
1625  }
1626 
1627  station->m_statsFile << "\nTotal packet count:: ideal " << Max (0, station->m_totalPacketsCount - station->m_samplePacketsCount) <<
1628  " lookaround " << station->m_samplePacketsCount << "\n";
1629  station->m_statsFile << "Average # of aggregated frames per A-MPDU: " << station->m_avgAmpduLen << "\n\n";
1630 
1631  station->m_statsFile.flush ();
1632 }
1633 
1634 void
1635 MinstrelHtWifiManager::StatsDump (MinstrelHtWifiRemoteStation *station, uint8_t groupId, std::ofstream &of)
1636 {
1637  uint8_t numRates = m_numRates;
1638  McsGroup group = m_minstrelGroups[groupId];
1639  Time txTime;
1640  char giMode;
1641  if (group.sgi)
1642  {
1643  giMode = 'S';
1644  }
1645  else
1646  {
1647  giMode = 'L';
1648  }
1649  for (uint8_t i = 0; i < numRates; i++)
1650  {
1651  if (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[i].supported)
1652  {
1653  if (!group.isVht)
1654  {
1655  of << "HT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1656  }
1657  else
1658  {
1659  of << "VHT" << group.chWidth << " " << giMode << "GI " << (int)group.streams << " ";
1660  }
1661 
1662  uint16_t maxTpRate = station->m_maxTpRate;
1663  uint16_t maxTpRate2 = station->m_maxTpRate2;
1664  uint16_t maxProbRate = station->m_maxProbRate;
1665 
1666  uint16_t idx = GetIndex (groupId, i);
1667  if (idx == maxTpRate)
1668  {
1669  of << 'A';
1670  }
1671  else
1672  {
1673  of << ' ';
1674  }
1675  if (idx == maxTpRate2)
1676  {
1677  of << 'B';
1678  }
1679  else
1680  {
1681  of << ' ';
1682  }
1683  if (idx == maxProbRate)
1684  {
1685  of << 'P';
1686  }
1687  else
1688  {
1689  of << ' ';
1690  }
1691 
1692  if (!group.isVht)
1693  {
1694  of << std::setw (4) << " MCS" << (group.streams - 1) * 8 + i;
1695  }
1696  else
1697  {
1698  of << std::setw (7) << " MCS" << +i << "/" << (int) group.streams;
1699  }
1700 
1701  of << " " << std::setw (3) << +idx << " ";
1702 
1703  /* tx_time[rate(i)] in usec */
1704  txTime = GetFirstMpduTxTime (groupId, GetMcsSupported (station, station->m_groupsTable[groupId].m_ratesTable[i].mcsIndex));
1705  of << std::setw (6) << txTime.GetMicroSeconds () << " ";
1706 
1707  of << std::setw (7) << CalculateThroughput (station, groupId, i, 100) / 100 << " " <<
1708  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].throughput / 100 << " " <<
1709  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmaProb << " " <<
1710  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].ewmsdProb << " " <<
1711  std::setw (7) << station->m_groupsTable[groupId].m_ratesTable[i].prob << " " <<
1712  std::setw (2) << station->m_groupsTable[groupId].m_ratesTable[i].retryCount << " " <<
1713  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << " " <<
1714  std::setw (3) << station->m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt << " " <<
1715  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].successHist << " " <<
1716  std::setw (9) << station->m_groupsTable[groupId].m_ratesTable[i].attemptHist << "\n";
1717  }
1718  }
1719 }
1720 uint16_t
1721 MinstrelHtWifiManager::GetIndex (uint8_t groupId, uint8_t rateId)
1722 {
1723  NS_LOG_FUNCTION (this << +groupId << +rateId);
1724  uint16_t index;
1725  index = groupId * m_numRates + rateId;
1726  return index;
1727 }
1728 
1729 uint8_t
1731 {
1732  NS_LOG_FUNCTION (this << index);
1733  uint8_t id;
1734  id = index % m_numRates;
1735  return id;
1736 }
1737 
1738 uint8_t
1740 {
1741  NS_LOG_FUNCTION (this << index);
1742  return index / m_numRates;
1743 }
1744 
1745 uint8_t
1746 MinstrelHtWifiManager::GetHtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1747 {
1748  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1749  return MAX_SUPPORTED_STREAMS * 2 * (chWidth == 40 ? 1 : 0) + MAX_SUPPORTED_STREAMS * sgi + txstreams - 1;
1750 }
1751 
1752 uint8_t
1753 MinstrelHtWifiManager::GetVhtGroupId (uint8_t txstreams, uint8_t sgi, uint16_t chWidth)
1754 {
1755  NS_LOG_FUNCTION (this << +txstreams << +sgi << chWidth);
1756  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;
1757 }
1758 
1759 uint16_t
1761 {
1762  NS_LOG_FUNCTION (this << station);
1763 
1764  uint8_t groupId = 0;
1765  uint8_t rateId = 0;
1766  while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
1767  {
1768  groupId++;
1769  }
1770  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1771  {
1772  rateId++;
1773  }
1774  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1775  return GetIndex (groupId, rateId);
1776 }
1777 
1778 uint16_t
1780 {
1781  NS_LOG_FUNCTION (this << station << +groupId);
1782 
1783  uint8_t rateId = 0;
1784  while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
1785  {
1786  rateId++;
1787  }
1788  NS_ASSERT (station->m_groupsTable[groupId].m_supported && station->m_groupsTable[groupId].m_ratesTable[rateId].supported);
1789  return GetIndex (groupId, rateId);
1790 }
1791 
1794 {
1795  WifiModeList vhtMcsList;
1796  Ptr<WifiPhy> phy = GetPhy ();
1797  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1798  {
1799  WifiMode mode = phy->GetMcs (i);
1800  if (mode.GetModulationClass () == WIFI_MOD_CLASS_VHT)
1801  {
1802  vhtMcsList.push_back (mode);
1803  }
1804  }
1805  return vhtMcsList;
1806 }
1807 
1810 {
1811  WifiModeList htMcsList;
1812  Ptr<WifiPhy> phy = GetPhy ();
1813  for (uint8_t i = 0; i < phy->GetNMcs (); i++)
1814  {
1815  WifiMode mode = phy->GetMcs (i);
1816  if (mode.GetModulationClass () == WIFI_MOD_CLASS_HT)
1817  {
1818  htMcsList.push_back (mode);
1819  }
1820  }
1821  return htMcsList;
1822 }
1823 
1824 } // 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 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
uint8_t m_nSampleCol
Number of sample columns.
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.
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 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 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
WifiTxVector DoGetDataTxVector(WifiRemoteStation *station)
hold per-remote-station state for Minstrel Wifi manager.
void CalculateRetransmits(MinstrelHtWifiRemoteStation *station, uint16_t index)
Calculate the number of retransmissions to set for the index rate.
uint32_t m_ampduPacketCount
Number of A-MPDUs transmitted.
static const uint8_t MAX_VHT_STREAM_GROUPS
Maximal number of groups per stream in VHT (4 possible channel widths and 2 possible SGI configuratio...
bool GetHeSupported(void) const
Return whether the device has HE capability support enabled.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1297
WifiRemoteStation * DoCreateStation(void) const
uint16_t m_sampleRate
current sample rate in bps
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.
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.
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:62
MinstrelRate m_minstrelTable
minstrel table
WifiPreamble GetPreambleForTransmission(WifiModulationClass modulation, bool useShortPreamble, bool useGreenfield)
Return the preamble to be used for the transmission.
Definition: wifi-utils.cc:116
uint32_t m_frameLength
Frame length used for calculate modes TxTime in bytes.
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:99
std::vector< RateInfo > MinstrelRate
Data structure for a Minstrel Rate table A vector of a struct RateInfo.
bool DoNeedRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally)
uint8_t m_nModes
number of modes supported
uint8_t GetRateId(uint16_t index)
For managing rates from different groups, a global index for all rates in all groups is used...
WifiRemoteStationState * m_state
Remote station state.
bool m_printStats
If statistics table should be printed.
MpduType
The type of an MPDU.
uint16_t GetIndex(uint8_t groupId, uint8_t rateId)
Returns the global index corresponding to the groupId and rateId.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
uint8_t m_lookAroundRate
The % to try other rates than our current rate.
phy
Definition: third.py: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.
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...
void DoReportAmpduTxStatus(WifiRemoteStation *station, uint8_t nSuccessfulMpdus, uint8_t nFailedMpdus, double rxSnr, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss)
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
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: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 DoReportDataOk(WifiRemoteStation *station, double ackSnr, WifiMode ackMode, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss)
This method is a pure virtual method that must be implemented by the sub-class.
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
Hold an unsigned integer type.
Definition: uinteger.h:44
static Time GetPayloadDuration(uint32_t size, WifiTxVector txVector, WifiPhyBand band, MpduType mpdutype=NORMAL_MPDU, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:2253
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...
HT PHY (Clause 20)
Definition: wifi-mode.h:60
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:480
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
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model...
Time GetBlockAckTxTime(void) const
Return the estimated BlockAck TX time for this PHY.
Definition: wifi-phy.cc:986
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 DoReportRtsFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
void UpdateRetry(MinstrelHtWifiRemoteStation *station)
Update the number of retries and reset accordingly.
uint32_t m_sampleCount
Max number of samples per update interval.
void DoReportFinalDataFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
uint16_t GetChannelWidthForTransmission(WifiMode mode, uint16_t maxSupportedChannelWidth)
Return the channel width that corresponds to the selected mode (instead of letting the PHY&#39;s default ...
Definition: wifi-utils.cc:97
uint8_t m_numGroups
Number of groups Minstrel should consider.
bool UseGreenfieldForDestination(Mac48Address dest) const
Time m_updateStats
How frequent do we calculate the stats.
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)
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:286
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...
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.
#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 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:487
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.
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:950
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: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...
Time GetSlot(void) const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:962
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 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:458
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:127
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
static Time CalculatePhyPreambleAndHeaderDuration(WifiTxVector txVector)
Definition: wifi-phy.cc:2532
Time m_nextStatsUpdate
10 times every second