A Discrete-Event Network Simulator
API
minstrel-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  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Duy Nguyen <duy@soe.ucsc.edu>
19  *
20  * Some Comments:
21  *
22  * 1) Segment Size is declared for completeness but not used because it has
23  * to do more with the requirement of the specific hardware.
24  *
25  * 2) By default, Minstrel applies the multi-rate retry(the core of Minstrel
26  * algorithm). Otherwise, please use ConstantRateWifiManager instead.
27  *
28  * http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/minstrel
29  */
30 
31 #include "minstrel-wifi-manager.h"
32 #include "wifi-phy.h"
33 #include "ns3/simulator.h"
34 #include "ns3/log.h"
35 #include "ns3/uinteger.h"
36 #include "ns3/double.h"
37 #include "ns3/wifi-mac.h"
38 #include "ns3/assert.h"
39 #include <vector>
40 
41 #define Min(a,b) ((a < b) ? a : b)
42 
43 namespace ns3 {
44 
45 NS_LOG_COMPONENT_DEFINE ("MinstrelWifiManager");
46 
54 {
56 
63  uint32_t m_col, m_index;
64  uint32_t m_maxTpRate;
65  uint32_t m_maxTpRate2;
66  uint32_t m_maxProbRate;
69  bool m_isSampling;
70  uint32_t m_sampleRate;
72  uint32_t m_shortRetry;
73  uint32_t m_longRetry;
74  uint32_t m_retry;
75  uint32_t m_err;
76  uint32_t m_txrate;
80 };
81 
83 
84 TypeId
86 {
87  static TypeId tid = TypeId ("ns3::MinstrelWifiManager")
89  .SetGroupName ("Wifi")
90  .AddConstructor<MinstrelWifiManager> ()
91  .AddAttribute ("UpdateStatistics",
92  "The interval between updating statistics table ",
93  TimeValue (Seconds (0.1)),
95  MakeTimeChecker ())
96  .AddAttribute ("LookAroundRate",
97  "the percentage to try other rates",
98  DoubleValue (10),
100  MakeDoubleChecker<double> ())
101  .AddAttribute ("EWMA",
102  "EWMA level",
103  DoubleValue (75),
105  MakeDoubleChecker<double> ())
106  .AddAttribute ("SampleColumn",
107  "The number of columns used for sampling",
108  DoubleValue (10),
110  MakeDoubleChecker <double> ())
111  .AddAttribute ("PacketLength",
112  "The packet length used for calculating mode TxTime",
113  DoubleValue (1200),
115  MakeDoubleChecker <double> ())
116  ;
117  return tid;
118 }
119 
121 {
122  m_uniformRandomVariable = CreateObject<UniformRandomVariable> ();
123 
124  m_nsupported = 0;
125 }
126 
128 {
129 }
130 
131 void
133 {
134  NS_LOG_FUNCTION (this << phy);
135  uint32_t nModes = phy->GetNModes ();
136  for (uint32_t i = 0; i < nModes; i++)
137  {
138  WifiMode mode = phy->GetMode (i);
139  WifiTxVector txVector;
140  txVector.SetMode (mode);
141  AddCalcTxTime (mode, phy->CalculateTxDuration (m_pktLen, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency (), 0, 0));
142  }
144 }
145 
146 int64_t
148 {
149  NS_LOG_FUNCTION (this << stream);
151  return 1;
152 }
153 
154 Time
156 {
157 
158  for (TxTime::const_iterator i = m_calcTxTime.begin (); i != m_calcTxTime.end (); i++)
159  {
160  if (mode == i->second)
161  {
162  return i->first;
163  }
164  }
165  NS_ASSERT (false);
166  return Seconds (0);
167 }
168 
169 void
171 {
172  m_calcTxTime.push_back (std::make_pair (t, mode));
173 }
174 
177 {
179 
181  station->m_col = 0;
182  station->m_index = 0;
183  station->m_maxTpRate = 0;
184  station->m_maxTpRate2 = 0;
185  station->m_maxProbRate = 0;
186  station->m_packetCount = 0;
187  station->m_sampleCount = 0;
188  station->m_isSampling = false;
189  station->m_sampleRate = 0;
190  station->m_sampleRateSlower = false;
191  station->m_shortRetry = 0;
192  station->m_longRetry = 0;
193  station->m_retry = 0;
194  station->m_err = 0;
195  station->m_txrate = 0;
196  station->m_initialized = false;
197 
198  return station;
199 }
200 
201 void
203 {
204  if (!station->m_initialized && GetNSupported (station) > 1)
205  {
206  //Note: we appear to be doing late initialization of the table
207  //to make sure that the set of supported rates has been initialized
208  //before we perform our own initialization.
209  m_nsupported = GetNSupported (station);
211  station->m_sampleTable = SampleRate (m_nsupported, std::vector<uint32_t> (m_sampleCol));
212  InitSampleTable (station);
213  RateInit (station);
214  station->m_initialized = true;
215 
216  PrintTable (station);
217  PrintSampleTable (station);
218  }
219 }
220 
221 void
223  double rxSnr, WifiMode txMode)
224 {
225  NS_LOG_FUNCTION (this);
226 }
227 
228 void
230 {
232  NS_LOG_DEBUG ("DoReportRtsFailed m_txrate=" << station->m_txrate);
233 
234  station->m_shortRetry++;
235 }
236 
237 void
238 MinstrelWifiManager::DoReportRtsOk (WifiRemoteStation *st, double ctsSnr, WifiMode ctsMode, double rtsSnr)
239 {
240  NS_LOG_DEBUG ("self=" << st << " rts ok");
241 }
242 
243 void
245 {
247  UpdateRetry (station);
248  station->m_err++;
249 }
250 
251 void
253 {
271  CheckInit (station);
272  if (!station->m_initialized)
273  {
274  return;
275  }
276 
277  station->m_longRetry++;
278  station->m_minstrelTable[station->m_txrate].numRateAttempt++;
279 
280  PrintTable (station);
281 
282  NS_LOG_DEBUG ("DoReportDataFailed " << station << " rate " << station->m_txrate << " longRetry " << station->m_longRetry);
283 
284  //for normal rate, we're not currently sampling random rates
285  if (!station->m_isSampling)
286  {
287  NS_LOG_DEBUG ("Failed with normal rate: current=" << station->m_txrate << ", sample=" << station->m_sampleRate << ", maxTp=" << station->m_maxTpRate << ", maxTp2=" << station->m_maxTpRate2 << ", maxProb=" << station->m_maxProbRate);
288  //use best throughput rate
289  if (station->m_longRetry < station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount)
290  {
291  NS_LOG_DEBUG (" More retries left for the maximum throughput rate.");
292  station->m_txrate = station->m_maxTpRate;
293  }
294 
295  //use second best throughput rate
296  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
297  station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount))
298  {
299  NS_LOG_DEBUG (" More retries left for the second maximum throughput rate.");
300  station->m_txrate = station->m_maxTpRate2;
301  }
302 
303  //use best probability rate
304  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
305  station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount +
306  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
307  {
308  NS_LOG_DEBUG (" More retries left for the maximum probability rate.");
309  station->m_txrate = station->m_maxProbRate;
310  }
311 
312  //use lowest base rate
313  else if (station->m_longRetry > (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
314  station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount +
315  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
316  {
317  NS_LOG_DEBUG (" More retries left for the base rate.");
318  station->m_txrate = 0;
319  }
320  }
321 
322  //for look-around rate, we're currently sampling random rates
323  else
324  {
325  NS_LOG_DEBUG ("Failed with look around rate: current=" << station->m_txrate << ", sample=" << station->m_sampleRate << ", maxTp=" << station->m_maxTpRate << ", maxTp2=" << station->m_maxTpRate2 << ", maxProb=" << station->m_maxProbRate);
326  //current sampling rate is slower than the current best rate
327  if (station->m_sampleRateSlower)
328  {
329  NS_LOG_DEBUG ("Look around rate is slower than the maximum throughput rate.");
330  //use best throughput rate
331  if (station->m_longRetry < station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount)
332  {
333  NS_LOG_DEBUG (" More retries left for the maximum throughput rate.");
334  station->m_txrate = station->m_maxTpRate;
335  }
336 
337  //use random rate
338  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
339  station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount))
340  {
341  NS_LOG_DEBUG (" More retries left for the sampling rate.");
342  station->m_txrate = station->m_sampleRate;
343  }
344 
345  //use max probability rate
346  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
347  station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
348  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount ))
349  {
350  NS_LOG_DEBUG (" More retries left for the maximum probability rate.");
351  station->m_txrate = station->m_maxProbRate;
352  }
353 
354  //use lowest base rate
355  else if (station->m_longRetry > (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
356  station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
357  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
358  {
359  NS_LOG_DEBUG (" More retries left for the base rate.");
360  station->m_txrate = 0;
361  }
362  }
363  //current sampling rate is better than current best rate
364  else
365  {
366  NS_LOG_DEBUG ("Look around rate is faster than the maximum throughput rate.");
367  //use random rate
368  if (station->m_longRetry < station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount)
369  {
370  NS_LOG_DEBUG (" More retries left for the sampling rate.");
371  station->m_txrate = station->m_sampleRate;
372  }
373 
374  //use the best throughput rate
375  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
376  station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount))
377  {
378  NS_LOG_DEBUG (" More retries left for the maximum throughput rate.");
379  station->m_txrate = station->m_maxTpRate;
380  }
381 
382  //use the best probability rate
383  else if (station->m_longRetry <= (station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
384  station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
385  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
386  {
387  NS_LOG_DEBUG (" More retries left for the maximum probability rate.");
388  station->m_txrate = station->m_maxProbRate;
389  }
390 
391  //use the lowest base rate
392  else if (station->m_longRetry > (station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
393  station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
394  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
395  {
396  NS_LOG_DEBUG (" More retries left for the base rate.");
397  station->m_txrate = 0;
398  }
399  }
400  }
401 }
402 
403 void
405  double ackSnr, WifiMode ackMode, double dataSnr)
406 {
407  NS_LOG_FUNCTION (st << ackSnr << ackMode << dataSnr);
409 
410  station->m_isSampling = false;
411  station->m_sampleRateSlower = false;
412 
413  CheckInit (station);
414  if (!station->m_initialized)
415  {
416  return;
417  }
418  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).");
419 
420  station->m_minstrelTable[station->m_txrate].numRateSuccess++;
421  station->m_minstrelTable[station->m_txrate].numRateAttempt++;
422 
423  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).");
424 
425  UpdateRetry (station);
426 
427  station->m_packetCount++;
428 
429  if (m_nsupported >= 1)
430  {
431  station->m_txrate = FindRate (station);
432  }
433 }
434 
435 void
437 {
438  NS_LOG_FUNCTION (st);
440 
441  CheckInit (station);
442  if (!station->m_initialized)
443  {
444  return;
445  }
446 
447  NS_LOG_DEBUG ("DoReportFinalDataFailed m_txrate = " << station->m_txrate << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess << " (before update).");
448 
449  station->m_isSampling = false;
450  station->m_sampleRateSlower = false;
451 
452  UpdateRetry (station);
453 
454  station->m_err++;
455 
456  NS_LOG_DEBUG ("DoReportFinalDataFailed m_txrate = " << station->m_txrate << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess << " (after update).");
457 
458  if (m_nsupported >= 1)
459  {
460  station->m_txrate = FindRate (station);
461  }
462 }
463 
464 void
466 {
467  station->m_retry = station->m_shortRetry + station->m_longRetry;
468  station->m_shortRetry = 0;
469  station->m_longRetry = 0;
470 }
471 
474  uint32_t size)
475 {
477  uint32_t channelWidth = GetChannelWidth (station);
478  if (channelWidth > 20 && channelWidth != 22)
479  {
480  //avoid to use legacy rate adaptation algorithms for IEEE 802.11n/ac
481  channelWidth = 20;
482  }
483  if (!station->m_initialized)
484  {
485  CheckInit (station);
486 
487  //start the rate at half way
488  station->m_txrate = m_nsupported / 2;
489  }
490  UpdateStats (station);
491  return WifiTxVector (GetSupported (station, station->m_txrate), GetDefaultTxPowerLevel (), GetLongRetryCount (station), false, 1, 0, channelWidth, GetAggregation (station), false);
492 }
493 
496 {
498  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
499  uint32_t channelWidth = GetChannelWidth (station);
500  if (channelWidth > 20 && channelWidth != 22)
501  {
502  //avoid to use legacy rate adaptation algorithms for IEEE 802.11n/ac
503  channelWidth = 20;
504  }
505  return WifiTxVector (GetSupported (station, 0), GetDefaultTxPowerLevel (), GetShortRetryCount (station), false, 1, 0, channelWidth, GetAggregation (station), false);
506 }
507 
508 bool
510 {
512 
513  CheckInit (station);
514  if (!station->m_initialized)
515  {
516  return normally;
517  }
518 
519  if (!station->m_isSampling)
520  {
521  if (station->m_longRetry > (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
522  station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount +
523  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount +
524  station->m_minstrelTable[0].adjustedRetryCount))
525  {
526  return false;
527  }
528  else
529  {
530  return true;
531  }
532  }
533  else
534  {
535  if (station->m_longRetry > (station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
536  station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
537  station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount +
538  station->m_minstrelTable[0].adjustedRetryCount))
539  {
540  return false;
541  }
542  else
543  {
544  return true;
545  }
546  }
547 }
548 
549 bool
551 {
552  return true;
553 }
554 
555 uint32_t
557 {
558  uint32_t bitrate;
559  bitrate = station->m_sampleTable[station->m_index][station->m_col];
560  station->m_index++;
561 
562  //bookeeping for m_index and m_col variables
563  if (station->m_index > (m_nsupported - 2))
564  {
565  station->m_index = 0;
566  station->m_col++;
567  if (station->m_col >= m_sampleCol)
568  {
569  station->m_col = 0;
570  }
571  }
572  return bitrate;
573 }
574 
575 uint32_t
577 {
578  NS_LOG_FUNCTION (this << station);
579 
580  if ((station->m_sampleCount + station->m_packetCount) == 0)
581  {
582  return 0;
583  }
584 
585 
586  uint32_t idx;
587 
588  //for determining when to try a sample rate
589  int coinFlip = m_uniformRandomVariable->GetInteger (0, 100) % 2;
590 
596  if ( (((100 * station->m_sampleCount) / (station->m_sampleCount + station->m_packetCount )) < m_lookAroundRate)
597  && (coinFlip == 1) )
598  {
599  NS_LOG_DEBUG ("Using look around rate");
600  //now go through the table and find an index rate
601  idx = GetNextSample (station);
602 
607  if (idx != station->m_maxTpRate && idx != station->m_txrate)
608  {
609 
610  //start sample count
611  station->m_sampleCount++;
612 
613  //set flag that we are currently sampling
614  station->m_isSampling = true;
615 
616  //bookeeping for resetting stuff
617  if (station->m_packetCount >= 10000)
618  {
619  station->m_sampleCount = 0;
620  station->m_packetCount = 0;
621  }
622 
623  //error check
624  if (idx >= m_nsupported)
625  {
626  NS_LOG_DEBUG ("ALERT!!! ERROR");
627  }
628 
629  //set the rate that we're currently sampling
630  station->m_sampleRate = idx;
631 
632  if (station->m_sampleRate == station->m_maxTpRate)
633  {
634  station->m_sampleRate = station->m_maxTpRate2;
635  }
636 
637  //is this rate slower than the current best rate
638  station->m_sampleRateSlower =
639  (station->m_minstrelTable[idx].perfectTxTime > station->m_minstrelTable[station->m_maxTpRate].perfectTxTime);
640 
641  //using the best rate instead
642  if (station->m_sampleRateSlower)
643  {
644  NS_LOG_DEBUG ("The next look around rate is slower than the maximum throughput rate, continue with the maximum throughput rate: " << station->m_maxTpRate << "(" << GetSupported (station, station->m_maxTpRate) << ")");
645  idx = station->m_maxTpRate;
646  }
647  }
648  }
649  //continue using the best rate
650  else
651  {
652  NS_LOG_DEBUG ("Continue using the maximum throughput rate: " << station->m_maxTpRate << "(" << GetSupported (station, station->m_maxTpRate) << ")");
653  idx = station->m_maxTpRate;
654  }
655 
656  NS_LOG_DEBUG ("Rate = " << idx << "(" << GetSupported (station, idx) << ")");
657 
658  return idx;
659 }
660 
661 void
663 {
664  if (Simulator::Now () < station->m_nextStatsUpdate)
665  {
666  return;
667  }
668 
669  if (!station->m_initialized)
670  {
671  return;
672  }
673  NS_LOG_FUNCTION (this);
675  NS_LOG_DEBUG ("Next update at " << station->m_nextStatsUpdate);
676  NS_LOG_DEBUG ("Currently using rate: " << station->m_txrate << " (" << GetSupported (station, station->m_txrate) << ")");
677 
678  Time txTime;
679  uint32_t tempProb;
680 
681  NS_LOG_DEBUG ("Index-Rate\t\tAttempt\tSuccess");
682  for (uint32_t i = 0; i < m_nsupported; i++)
683  {
684 
685  //calculate the perfect tx time for this rate
686  txTime = station->m_minstrelTable[i].perfectTxTime;
687 
688  //just for initialization
689  if (txTime.GetMicroSeconds () == 0)
690  {
691  txTime = Seconds (1);
692  }
693 
694  NS_LOG_DEBUG (i << " " << GetSupported (station, i) <<
695  "\t" << station->m_minstrelTable[i].numRateAttempt <<
696  "\t" << station->m_minstrelTable[i].numRateSuccess);
697 
698  //if we've attempted something
699  if (station->m_minstrelTable[i].numRateAttempt)
700  {
705  tempProb = (station->m_minstrelTable[i].numRateSuccess * 18000) / station->m_minstrelTable[i].numRateAttempt;
706 
707  //bookeeping
708  station->m_minstrelTable[i].prob = tempProb;
709 
710  //ewma probability (cast for gcc 3.4 compatibility)
711  tempProb = static_cast<uint32_t> (((tempProb * (100 - m_ewmaLevel)) + (station->m_minstrelTable[i].ewmaProb * m_ewmaLevel) ) / 100);
712 
713  station->m_minstrelTable[i].ewmaProb = tempProb;
714 
715  //calculating throughput
716  station->m_minstrelTable[i].throughput = tempProb * (1000000 / txTime.GetMicroSeconds ());
717 
718  }
719 
720  //bookeeping
721  station->m_minstrelTable[i].numRateSuccess = 0;
722  station->m_minstrelTable[i].numRateAttempt = 0;
723 
724  //Sample less often below 10% and above 95% of success
725  if ((station->m_minstrelTable[i].ewmaProb > 17100) || (station->m_minstrelTable[i].ewmaProb < 1800))
726  {
734  if (station->m_minstrelTable[i].retryCount > 2)
735  {
736  station->m_minstrelTable[i].adjustedRetryCount = 2;
737  }
738  else
739  {
740  station->m_minstrelTable[i].adjustedRetryCount = station->m_minstrelTable[i].retryCount;
741  }
742  }
743  else
744  {
745  station->m_minstrelTable[i].adjustedRetryCount = station->m_minstrelTable[i].retryCount;
746  }
747 
748  //if it's 0 allow one retry limit
749  if (station->m_minstrelTable[i].adjustedRetryCount == 0)
750  {
751  station->m_minstrelTable[i].adjustedRetryCount = 1;
752  }
753  }
754 
755  NS_LOG_DEBUG ("Attempt/success resetted to 0");
756 
757  uint32_t max_prob = 0, index_max_prob = 0, max_tp = 0, index_max_tp = 0, index_max_tp2 = 0;
758 
759  //go find max throughput, second maximum throughput, high probability succ
760  NS_LOG_DEBUG ("Finding the maximum throughput, second maximum throughput, and highest probability");
761  NS_LOG_DEBUG ("Index-Rate\t\tT-put\tEWMA");
762  for (uint32_t i = 0; i < m_nsupported; i++)
763  {
764  NS_LOG_DEBUG (i << " " << GetSupported (station, i) <<
765  "\t" << station->m_minstrelTable[i].throughput <<
766  "\t" << station->m_minstrelTable[i].ewmaProb);
767 
768  if (max_tp < station->m_minstrelTable[i].throughput)
769  {
770  index_max_tp = i;
771  max_tp = station->m_minstrelTable[i].throughput;
772  }
773 
774  if (max_prob < station->m_minstrelTable[i].ewmaProb)
775  {
776  index_max_prob = i;
777  max_prob = station->m_minstrelTable[i].ewmaProb;
778  }
779  }
780 
781 
782  max_tp = 0;
783  //find the second highest max
784  for (uint32_t i = 0; i < m_nsupported; i++)
785  {
786  if ((i != index_max_tp) && (max_tp < station->m_minstrelTable[i].throughput))
787  {
788  index_max_tp2 = i;
789  max_tp = station->m_minstrelTable[i].throughput;
790  }
791  }
792 
793  station->m_maxTpRate = index_max_tp;
794  station->m_maxTpRate2 = index_max_tp2;
795  station->m_maxProbRate = index_max_prob;
796 
797  if (index_max_tp > station->m_txrate)
798  {
799  station->m_txrate = index_max_tp;
800  }
801 
802  NS_LOG_DEBUG ("max throughput=" << index_max_tp << "(" << GetSupported (station, index_max_tp) <<
803  ")\tsecond max throughput=" << index_max_tp2 << "(" << GetSupported (station, index_max_tp2) <<
804  ")\tmax prob=" << index_max_prob << "(" << GetSupported (station, index_max_prob) << ")");
805 }
806 
807 void
809 {
810  NS_LOG_FUNCTION (station);
811 
812  for (uint32_t i = 0; i < m_nsupported; i++)
813  {
814  NS_LOG_DEBUG ("Initializing rate index " << i << " " << GetSupported (station, i));
815  station->m_minstrelTable[i].numRateAttempt = 0;
816  station->m_minstrelTable[i].numRateSuccess = 0;
817  station->m_minstrelTable[i].prob = 0;
818  station->m_minstrelTable[i].ewmaProb = 0;
819  station->m_minstrelTable[i].throughput = 0;
820  station->m_minstrelTable[i].perfectTxTime = GetCalcTxTime (GetSupported (station, i));
821  NS_LOG_DEBUG (" perfectTxTime = " << station->m_minstrelTable[i].perfectTxTime);
822  station->m_minstrelTable[i].retryCount = 1;
823  station->m_minstrelTable[i].adjustedRetryCount = 1;
824  //Emulating minstrel.c::ath_rate_ctl_reset
825  //We only check from 2 to 10 retries. This guarantee that
826  //at least one retry is permitter.
827  Time totalTxTimeWithGivenRetries = Seconds (0.0); //tx_time in minstrel.c
828  NS_LOG_DEBUG (" Calculating the number of retries");
829  for (uint32_t retries = 2; retries < 11; retries++)
830  {
831  NS_LOG_DEBUG (" Checking " << retries << " retries");
832  totalTxTimeWithGivenRetries = CalculateTimeUnicastPacket (station->m_minstrelTable[i].perfectTxTime, 0, retries);
833  NS_LOG_DEBUG (" totalTxTimeWithGivenRetries = " << totalTxTimeWithGivenRetries);
834  if (totalTxTimeWithGivenRetries > MilliSeconds (6))
835  {
836  break;
837  }
838  station->m_minstrelTable[i].retryCount = retries;
839  station->m_minstrelTable[i].adjustedRetryCount = retries;
840  }
841  }
842 }
843 
844 Time
845 MinstrelWifiManager::CalculateTimeUnicastPacket (Time dataTransmissionTime, uint32_t shortRetries, uint32_t longRetries)
846 {
847  NS_LOG_FUNCTION (this << dataTransmissionTime << shortRetries << longRetries);
848  //See rc80211_minstrel.c
849 
850  //First transmission (DATA + ACK timeout)
851  Time tt = dataTransmissionTime + GetMac ()->GetAckTimeout ();
852 
853  uint32_t cwMax = 1023;
854  uint32_t cw = 31;
855  for (uint32_t retry = 0; retry < longRetries; retry++)
856  {
857  //Add one re-transmission (DATA + ACK timeout)
858  tt += dataTransmissionTime + GetMac ()->GetAckTimeout ();
859 
860  //Add average back off (half the current contention window)
861  tt += NanoSeconds ((cw / 2) * GetMac ()->GetSlot ());
862 
863  //Update contention window
864  cw = std::min (cwMax, (cw + 1) * 2);
865  }
866 
867  return tt;
868 }
869 
870 void
872 {
873  NS_LOG_DEBUG ("InitSampleTable=" << this);
874 
875  station->m_col = station->m_index = 0;
876 
877  //for off-seting to make rates fall between 0 and numrates
878  uint32_t numSampleRates = m_nsupported;
879 
880  uint32_t newIndex;
881  for (uint32_t col = 0; col < m_sampleCol; col++)
882  {
883  for (uint32_t i = 0; i < numSampleRates; i++ )
884  {
889  int uv = m_uniformRandomVariable->GetInteger (0, numSampleRates);
890  newIndex = (i + uv) % numSampleRates;
891 
892  //this loop is used for filling in other uninitilized places
893  while (station->m_sampleTable[newIndex][col] != 0)
894  {
895  newIndex = (newIndex + 1) % m_nsupported;
896  }
897  station->m_sampleTable[newIndex][col] = i;
898  }
899  }
900 }
901 
902 void
904 {
905  NS_LOG_DEBUG ("PrintSampleTable=" << station);
906 
907  uint32_t numSampleRates = m_nsupported;
908  std::stringstream table;
909  for (uint32_t i = 0; i < numSampleRates; i++)
910  {
911  for (uint32_t j = 0; j < m_sampleCol; j++)
912  {
913  table << station->m_sampleTable[i][j] << "\t";
914  }
915  table << std::endl;
916  }
917  NS_LOG_DEBUG (table.str ());
918 }
919 
920 void
922 {
923  NS_LOG_DEBUG ("PrintTable=" << station);
924 
925  for (uint32_t i = 0; i < m_nsupported; i++)
926  {
927  NS_LOG_DEBUG (i << " (" << GetSupported (station, i) << "): " << station->m_minstrelTable[i].perfectTxTime << ", retryCount = " << station->m_minstrelTable[i].retryCount << ", adjustedRetryCount = " << station->m_minstrelTable[i].adjustedRetryCount);
928  }
929 }
930 
931 } //namespace ns3
uint32_t m_nsupported
modes supported
void CheckInit(MinstrelWifiRemoteStation *station)
check for initializations
void PrintTable(MinstrelWifiRemoteStation *station)
uint32_t GetNSupported(const WifiRemoteStation *station) const
Return the number of modes supported by the given station.
virtual uint32_t GetFrequency(void) const =0
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
void SetStream(int64_t stream)
Specifies the stream number for this RNG stream.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
Implementation of Minstrel Rate Control AlgorithmPorting Minstrel from Madwifi and Linux Kernel http:...
virtual uint32_t GetNModes(void) const =0
The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used (e.g., by a WifiRemoteStationManager...
virtual void DoReportFinalDataFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
hold per-remote-station state for Minstrel Wifi manager.
Time m_updateStats
how frequent do we calculate the stats (1/10 seconds)
void UpdateStats(MinstrelWifiRemoteStation *station)
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
uint32_t m_sampleRate
current sample rate
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:903
uint32_t GetNextSample(MinstrelWifiRemoteStation *station)
virtual bool DoNeedDataRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally)
uint32_t m_txrate
current transmit rate
MinstrelRate m_minstrelTable
minstrel table
virtual void SetupPhy(Ptr< WifiPhy > phy)
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
represent a single transmission modeA WifiMode is implemented by a single integer which is used to lo...
Definition: wifi-mode.h:97
bool GetAggregation(const WifiRemoteStation *station) const
Return whether the given station supports A-MPDU.
WifiMode GetSupported(const WifiRemoteStation *station, uint32_t i) const
Return whether mode associated with the specified station at the specified index. ...
uint32_t FindRate(MinstrelWifiRemoteStation *station)
uint32_t m_pktLen
packet length used for calculate mode TxTime
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:446
virtual void DoReportDataOk(WifiRemoteStation *station, double ackSnr, WifiMode ackMode, double dataSnr)
This method is a pure virtual method that must be implemented by the sub-class.
virtual void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode)
This method is a pure virtual method that must be implemented by the sub-class.
uint32_t m_col
To keep track of the current position in the our random sample table going row by row from 1st column...
virtual uint32_t GetInteger(void)=0
Get the next random value as an integer drawn from the distribution.
tuple phy
Definition: third.py:86
bool m_isSampling
a flag to indicate we are currently sampling
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:349
int m_sampleCount
how many packets we have sample so far
AttributeValue implementation for Time.
Definition: nstime.h:957
SampleRate m_sampleTable
sample table
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:919
void PrintSampleTable(MinstrelWifiRemoteStation *station)
virtual void SetupPhy(Ptr< WifiPhy > phy)
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
double m_ewmaLevel
exponential weighted moving average
virtual WifiRemoteStation * DoCreateStation(void) const
virtual WifiTxVector DoGetDataTxVector(WifiRemoteStation *station, uint32_t size)
void AddCalcTxTime(WifiMode mode, Time t)
Add transmission time for the given mode to an internal list.
virtual void DoReportFinalRtsFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
hold a list of per-remote-station state.
virtual WifiTxVector DoGetRtsTxVector(WifiRemoteStation *station)
uint32_t m_longRetry
long retries such as data packets
bool m_initialized
for initializing tables
TxTime m_calcTxTime
to hold all the calculated TxTime for all modes
virtual bool IsLowLatency(void) const
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model...
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint32_t m_maxTpRate2
second highest throughput rate
virtual WifiMode GetMode(uint32_t mode) const =0
The WifiPhy::GetNModes() and WifiPhy::GetMode() methods are used (e.g., by a WifiRemoteStationManager...
Time CalculateTxDuration(uint32_t size, WifiTxVector txVector, enum WifiPreamble preamble, double frequency, uint8_t packetType, uint8_t incFlag)
Definition: wifi-phy.cc:605
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:958
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:223
uint32_t m_retry
total retries short + long
Ptr< UniformRandomVariable > m_uniformRandomVariable
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void UpdateRetry(MinstrelWifiRemoteStation *station)
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: double.h:42
double m_lookAroundRate
the % to try other rates than our current rate
void InitSampleTable(MinstrelWifiRemoteStation *station)
uint32_t m_maxProbRate
rate with highest prob of success
uint32_t GetLongRetryCount(const WifiRemoteStation *station) const
Return the long retry limit of the given station.
virtual void DoReportRtsFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
uint32_t m_maxTpRate
the current throughput rate
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:236
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:895
Time GetCalcTxTime(WifiMode mode) const
virtual void DoReportDataFailed(WifiRemoteStation *station)
This method is a pure virtual method that must be implemented by the sub-class.
std::vector< struct RateInfo > MinstrelRate
Data structure for a Minstrel Rate table A vector of a struct RateInfo.
uint32_t GetChannelWidth(const WifiRemoteStation *station) const
Return the channel width supported by the station.
uint32_t GetShortRetryCount(const WifiRemoteStation *station) const
Return the short retry limit of the given station.
uint32_t m_sampleCol
number of sample columns
uint32_t m_shortRetry
short retries such as control packts
This class can be used to hold variables of floating point type such as 'double' or 'float'...
Definition: double.h:41
bool m_sampleRateSlower
a flag to indicate sample rate is slower
int m_packetCount
total number of packets as of now
virtual 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.
a unique identifier for an interface.
Definition: type-id.h:58
Time CalculateTimeUnicastPacket(Time dataTransmissionTime, uint32_t shortRetries, uint32_t longRetries)
Estimate the time to transmit the given packet with the given number of retries.
void RateInit(MinstrelWifiRemoteStation *station)
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:826
std::vector< std::vector< uint32_t > > SampleRate
Data structure for a Sample Rate table A vector of a vector uint32_t.
hold per-remote-station state.
Ptr< WifiMac > GetMac(void) const
Return the WifiMac.
Time m_nextStatsUpdate
10 times every second