A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
minstrel-wifi-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 Duy Nguyen
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Authors: Duy Nguyen <duy@soe.ucsc.edu>
18 * Matías Richart <mrichart@fing.edu.uy>
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 * https://wireless.wiki.kernel.org/en/developers/documentation/mac80211/ratecontrol/minstrel
29 */
30
32
33#include "ns3/log.h"
34#include "ns3/packet.h"
35#include "ns3/random-variable-stream.h"
36#include "ns3/simulator.h"
37#include "ns3/wifi-mac.h"
38#include "ns3/wifi-phy.h"
39
40#include <iomanip>
41
42#define Min(a, b) ((a < b) ? a : b)
43
44namespace ns3
45{
46
47NS_LOG_COMPONENT_DEFINE("MinstrelWifiManager");
48
49NS_OBJECT_ENSURE_REGISTERED(MinstrelWifiManager);
50
51TypeId
53{
54 static TypeId tid =
55 TypeId("ns3::MinstrelWifiManager")
57 .SetGroupName("Wifi")
58 .AddConstructor<MinstrelWifiManager>()
59 .AddAttribute("UpdateStatistics",
60 "The interval between updating statistics table",
61 TimeValue(Seconds(0.1)),
64 .AddAttribute("LookAroundRate",
65 "The percentage to try other rates",
66 UintegerValue(10),
68 MakeUintegerChecker<uint8_t>())
69 .AddAttribute("EWMA",
70 "EWMA level",
71 UintegerValue(75),
73 MakeUintegerChecker<uint8_t>())
74 .AddAttribute("SampleColumn",
75 "The number of columns used for sampling",
76 UintegerValue(10),
78 MakeUintegerChecker<uint8_t>())
79 .AddAttribute("PacketLength",
80 "The packet length used for calculating mode TxTime",
81 UintegerValue(1200),
83 MakeUintegerChecker<uint32_t>())
84 .AddAttribute("PrintStats",
85 "Print statistics table",
86 BooleanValue(false),
89 .AddAttribute("PrintSamples",
90 "Print samples table",
91 BooleanValue(false),
94 .AddTraceSource("Rate",
95 "Traced value for rate changes (b/s)",
97 "ns3::TracedValueCallback::Uint64");
98 return tid;
99}
100
103 m_currentRate(0)
104{
105 NS_LOG_FUNCTION(this);
106 m_uniformRandomVariable = CreateObject<UniformRandomVariable>();
107}
108
110{
111 NS_LOG_FUNCTION(this);
112}
113
114void
116{
117 NS_LOG_FUNCTION(this << phy);
118 for (const auto& mode : phy->GetModeList())
119 {
120 WifiTxVector txVector;
121 txVector.SetMode(mode);
123 AddCalcTxTime(mode, phy->CalculateTxDuration(m_pktLen, txVector, phy->GetPhyBand()));
124 }
126}
127
128void
130{
131 NS_LOG_FUNCTION(this << mac);
133}
134
135void
137{
138 NS_LOG_FUNCTION(this);
139 if (GetHtSupported())
140 {
141 NS_FATAL_ERROR("WifiRemoteStationManager selected does not support HT rates");
142 }
143 if (GetVhtSupported())
144 {
145 NS_FATAL_ERROR("WifiRemoteStationManager selected does not support VHT rates");
146 }
147 if (GetHeSupported())
148 {
149 NS_FATAL_ERROR("WifiRemoteStationManager selected does not support HE rates");
150 }
151}
152
153int64_t
155{
156 NS_LOG_FUNCTION(this << stream);
158 return 1;
159}
160
161Time
163{
164 NS_LOG_FUNCTION(this << mode);
165 auto it = m_calcTxTime.find(mode);
166 NS_ASSERT(it != m_calcTxTime.end());
167 return it->second;
168}
169
170void
172{
173 NS_LOG_FUNCTION(this << mode << t);
174 m_calcTxTime.insert(std::make_pair(mode, t));
175}
176
179{
180 NS_LOG_FUNCTION(this);
181 auto station = new MinstrelWifiRemoteStation();
182
183 station->m_nextStatsUpdate = Simulator::Now() + m_updateStats;
184 station->m_col = 0;
185 station->m_index = 0;
186 station->m_maxTpRate = 0;
187 station->m_maxTpRate2 = 0;
188 station->m_maxProbRate = 0;
189 station->m_nModes = 0;
190 station->m_totalPacketsCount = 0;
191 station->m_samplePacketsCount = 0;
192 station->m_isSampling = false;
193 station->m_sampleRate = 0;
194 station->m_sampleDeferred = false;
195 station->m_shortRetry = 0;
196 station->m_longRetry = 0;
197 station->m_retry = 0;
198 station->m_txrate = 0;
199 station->m_initialized = false;
200
201 return station;
202}
203
204void
206{
207 NS_LOG_FUNCTION(this << station);
208 if (!station->m_initialized && GetNSupported(station) > 1)
209 {
210 // Note: we appear to be doing late initialization of the table
211 // to make sure that the set of supported rates has been initialized
212 // before we perform our own initialization.
213 station->m_nModes = GetNSupported(station);
214 station->m_minstrelTable = MinstrelRate(station->m_nModes);
215 station->m_sampleTable = SampleRate(station->m_nModes, std::vector<uint8_t>(m_sampleCol));
216 InitSampleTable(station);
217 RateInit(station);
218 station->m_initialized = true;
219 }
220}
221
237void
239{
240 NS_LOG_FUNCTION(this << station);
241 station->m_longRetry++;
242 station->m_minstrelTable[station->m_txrate].numRateAttempt++;
243
244 NS_LOG_DEBUG("DoReportDataFailed " << station << " rate " << station->m_txrate << " longRetry "
245 << station->m_longRetry);
246
247 // for normal rate, we're not currently sampling random rates
248 if (!station->m_isSampling)
249 {
250 NS_LOG_DEBUG("Failed with normal rate: current="
251 << station->m_txrate << ", sample=" << station->m_sampleRate
252 << ", maxTp=" << station->m_maxTpRate << ", maxTp2=" << station->m_maxTpRate2
253 << ", maxProb=" << station->m_maxProbRate);
254 // use best throughput rate
255 if (station->m_longRetry <
256 station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount)
257 {
258 NS_LOG_DEBUG(" More retries left for the maximum throughput rate.");
259 station->m_txrate = station->m_maxTpRate;
260 }
261
262 // use second best throughput rate
263 else if (station->m_longRetry <=
264 (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
265 station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount))
266 {
267 NS_LOG_DEBUG(" More retries left for the second maximum throughput rate.");
268 station->m_txrate = station->m_maxTpRate2;
269 }
270
271 // use best probability rate
272 else if (station->m_longRetry <=
273 (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
274 station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount +
275 station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
276 {
277 NS_LOG_DEBUG(" More retries left for the maximum probability rate.");
278 station->m_txrate = station->m_maxProbRate;
279 }
280
281 // use lowest base rate
282 else if (station->m_longRetry >
283 (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
284 station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount +
285 station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
286 {
287 NS_LOG_DEBUG(" More retries left for the base rate.");
288 station->m_txrate = 0;
289 }
290 }
291
292 // for look-around rate, we're currently sampling random rates
293 else
294 {
295 NS_LOG_DEBUG("Failed with look around rate: current="
296 << station->m_txrate << ", sample=" << station->m_sampleRate
297 << ", maxTp=" << station->m_maxTpRate << ", maxTp2=" << station->m_maxTpRate2
298 << ", maxProb=" << station->m_maxProbRate);
299 // current sampling rate is slower than the current best rate
300 if (station->m_sampleDeferred)
301 {
302 NS_LOG_DEBUG("Look around rate is slower than the maximum throughput rate.");
303 // use best throughput rate
304 if (station->m_longRetry <
305 station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount)
306 {
307 NS_LOG_DEBUG(" More retries left for the maximum throughput rate.");
308 station->m_txrate = station->m_maxTpRate;
309 }
310
311 // use random rate
312 else if (station->m_longRetry <=
313 (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
314 station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount))
315 {
316 NS_LOG_DEBUG(" More retries left for the sampling rate.");
317 station->m_txrate = station->m_sampleRate;
318 }
319
320 // use max probability rate
321 else if (station->m_longRetry <=
322 (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
323 station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
324 station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
325 {
326 NS_LOG_DEBUG(" More retries left for the maximum probability rate.");
327 station->m_txrate = station->m_maxProbRate;
328 }
329
330 // use lowest base rate
331 else if (station->m_longRetry >
332 (station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
333 station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
334 station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
335 {
336 NS_LOG_DEBUG(" More retries left for the base rate.");
337 station->m_txrate = 0;
338 }
339 }
340 // current sampling rate is better than current best rate
341 else
342 {
343 NS_LOG_DEBUG("Look around rate is faster than the maximum throughput rate.");
344 // use random rate
345 if (station->m_longRetry <
346 station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount)
347 {
348 NS_LOG_DEBUG(" More retries left for the sampling rate.");
349 station->m_txrate = station->m_sampleRate;
350 }
351
352 // use the best throughput rate
353 else if (station->m_longRetry <=
354 (station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
355 station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount))
356 {
357 NS_LOG_DEBUG(" More retries left for the maximum throughput rate.");
358 station->m_txrate = station->m_maxTpRate;
359 }
360
361 // use the best probability rate
362 else if (station->m_longRetry <=
363 (station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
364 station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
365 station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
366 {
367 NS_LOG_DEBUG(" More retries left for the maximum probability rate.");
368 station->m_txrate = station->m_maxProbRate;
369 }
370
371 // use the lowest base rate
372 else if (station->m_longRetry >
373 (station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
374 station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
375 station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount))
376 {
377 NS_LOG_DEBUG(" More retries left for the base rate.");
378 station->m_txrate = 0;
379 }
380 }
381 }
382}
383
386{
387 NS_LOG_FUNCTION(this << station);
388 uint16_t channelWidth = GetChannelWidth(station);
389 if (channelWidth > 20 && channelWidth != 22)
390 {
391 channelWidth = 20;
392 }
393 if (!station->m_initialized)
394 {
395 CheckInit(station);
396 }
397 WifiMode mode = GetSupported(station, station->m_txrate);
398 uint64_t rate = mode.GetDataRate(channelWidth);
399 if (m_currentRate != rate && !station->m_isSampling)
400 {
401 NS_LOG_DEBUG("New datarate: " << rate);
402 m_currentRate = rate;
403 }
404 return WifiTxVector(
405 mode,
408 800,
409 1,
410 1,
411 0,
412 channelWidth,
413 GetAggregation(station));
414}
415
418{
419 NS_LOG_FUNCTION(this << station);
420 NS_LOG_DEBUG("DoGetRtsMode m_txrate=" << station->m_txrate);
421 uint16_t channelWidth = GetChannelWidth(station);
422 if (channelWidth > 20 && channelWidth != 22)
423 {
424 channelWidth = 20;
425 }
426 WifiMode mode;
428 {
429 mode = GetSupported(station, 0);
430 }
431 else
432 {
433 mode = GetNonErpSupported(station, 0);
434 }
435 return WifiTxVector(
436 mode,
439 800,
440 1,
441 1,
442 0,
443 channelWidth,
444 GetAggregation(station));
445}
446
449{
450 if (!station->m_isSampling)
451 {
452 return station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
453 station->m_minstrelTable[station->m_maxTpRate2].adjustedRetryCount +
454 station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount +
455 station->m_minstrelTable[0].adjustedRetryCount;
456 }
457 else
458 {
459 return station->m_minstrelTable[station->m_sampleRate].adjustedRetryCount +
460 station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount +
461 station->m_minstrelTable[station->m_maxProbRate].adjustedRetryCount +
462 station->m_minstrelTable[0].adjustedRetryCount;
463 }
464}
465
466uint16_t
468{
469 NS_LOG_FUNCTION(this << station);
470
471 if (station->m_totalPacketsCount == 0)
472 {
473 return 0;
474 }
475
476 uint16_t idx = 0;
477 NS_LOG_DEBUG("Total: " << station->m_totalPacketsCount
478 << " Sample: " << station->m_samplePacketsCount
479 << " Deferred: " << station->m_numSamplesDeferred);
480
481 int delta = (station->m_totalPacketsCount * m_lookAroundRate / 100) -
482 (station->m_samplePacketsCount + station->m_numSamplesDeferred / 2);
483
484 NS_LOG_DEBUG("Decide sampling. Delta: " << delta << " lookAroundRatio: " << m_lookAroundRate);
485
486 /* delta < 0: no sampling required */
487 if (delta >= 0)
488 {
489 NS_LOG_DEBUG("Search next sampling rate");
490 uint8_t ratesSupported = station->m_nModes;
491 if (delta > ratesSupported * 2)
492 {
493 /* From Linux implementation:
494 * With multi-rate retry, not every planned sample
495 * attempt actually gets used, due to the way the retry
496 * chain is set up - [max_tp,sample,prob,lowest] for
497 * sample_rate < max_tp.
498 *
499 * If there's too much sampling backlog and the link
500 * starts getting worse, minstrel would start bursting
501 * out lots of sampling frames, which would result
502 * in a large throughput loss. */
503 station->m_samplePacketsCount += (delta - ratesSupported * 2);
504 }
505
506 // now go through the table and find an index rate
507 idx = GetNextSample(station);
508
509 NS_LOG_DEBUG("Sample rate = " << idx << "(" << GetSupported(station, idx) << ")");
510
511 // error check
512 if (idx >= station->m_nModes)
513 {
514 NS_LOG_DEBUG("ALERT!!! ERROR");
515 }
516
517 // set the rate that we're currently sampling
518 station->m_sampleRate = idx;
519
520 /* From Linux implementation:
521 * Decide if direct ( 1st MRR stage) or indirect (2nd MRR stage)
522 * rate sampling method should be used.
523 * Respect such rates that are not sampled for 20 iterations.
524 */
525 if ((station->m_minstrelTable[idx].perfectTxTime >
526 station->m_minstrelTable[station->m_maxTpRate].perfectTxTime) &&
527 (station->m_minstrelTable[idx].numSamplesSkipped < 20))
528 {
529 // If the rate is slower and we have sample it enough, defer to second stage
530 station->m_sampleDeferred = true;
531 station->m_numSamplesDeferred++;
532
533 // set flag that we are currently sampling
534 station->m_isSampling = true;
535 }
536 else
537 {
538 // if samplieLimit is zero, then don't sample this rate
539 if (!station->m_minstrelTable[idx].sampleLimit)
540 {
541 idx = station->m_maxTpRate;
542 station->m_isSampling = false;
543 }
544 else
545 {
546 // set flag that we are currently sampling
547 station->m_isSampling = true;
548 if (station->m_minstrelTable[idx].sampleLimit > 0)
549 {
550 station->m_minstrelTable[idx].sampleLimit--;
551 }
552 }
553 }
554
555 // using the best rate instead
556 if (station->m_sampleDeferred)
557 {
558 NS_LOG_DEBUG("The next look around rate is slower than the maximum throughput rate, "
559 "continue with the maximum throughput rate: "
560 << station->m_maxTpRate << "("
561 << GetSupported(station, station->m_maxTpRate) << ")");
562 idx = station->m_maxTpRate;
563 }
564 }
565 // continue using the best rate
566 else
567 {
568 NS_LOG_DEBUG("Continue using the maximum throughput rate: "
569 << station->m_maxTpRate << "(" << GetSupported(station, station->m_maxTpRate)
570 << ")");
571 idx = station->m_maxTpRate;
572 }
573
574 NS_LOG_DEBUG("Rate = " << idx << "(" << GetSupported(station, idx) << ")");
575
576 return idx;
577}
578
579void
581{
582 NS_LOG_FUNCTION(this << station);
583 if (Simulator::Now() < station->m_nextStatsUpdate)
584 {
585 return;
586 }
587
588 if (!station->m_initialized)
589 {
590 return;
591 }
592 NS_LOG_FUNCTION(this);
594 NS_LOG_DEBUG("Next update at " << station->m_nextStatsUpdate);
595 NS_LOG_DEBUG("Currently using rate: " << station->m_txrate << " ("
596 << GetSupported(station, station->m_txrate) << ")");
597
598 Time txTime;
599 uint32_t tempProb;
600
601 NS_LOG_DEBUG("Index-Rate\t\tAttempt\tSuccess");
602 for (uint8_t i = 0; i < station->m_nModes; i++)
603 {
604 // calculate the perfect TX time for this rate
605 txTime = station->m_minstrelTable[i].perfectTxTime;
606
607 // just for initialization
608 if (txTime.GetMicroSeconds() == 0)
609 {
610 txTime = Seconds(1);
611 }
612
613 NS_LOG_DEBUG(+i << " " << GetSupported(station, i) << "\t"
614 << station->m_minstrelTable[i].numRateAttempt << "\t"
615 << station->m_minstrelTable[i].numRateSuccess);
616
617 // if we've attempted something
618 if (station->m_minstrelTable[i].numRateAttempt)
619 {
620 station->m_minstrelTable[i].numSamplesSkipped = 0;
625 tempProb = (station->m_minstrelTable[i].numRateSuccess * 18000) /
626 station->m_minstrelTable[i].numRateAttempt;
627
628 // bookkeeping
629 station->m_minstrelTable[i].prob = tempProb;
630
631 if (station->m_minstrelTable[i].successHist == 0)
632 {
633 station->m_minstrelTable[i].ewmaProb = tempProb;
634 }
635 else
636 {
637 // EWMA probability (cast for gcc 3.4 compatibility)
638 tempProb = ((tempProb * (100 - m_ewmaLevel)) +
639 (station->m_minstrelTable[i].ewmaProb * m_ewmaLevel)) /
640 100;
641
642 station->m_minstrelTable[i].ewmaProb = tempProb;
643 }
644
645 // calculating throughput
646 station->m_minstrelTable[i].throughput =
647 tempProb * static_cast<uint32_t>(1000000 / txTime.GetMicroSeconds());
648 }
649 else
650 {
651 station->m_minstrelTable[i].numSamplesSkipped++;
652 }
653
654 // bookkeeping
655 station->m_minstrelTable[i].successHist += station->m_minstrelTable[i].numRateSuccess;
656 station->m_minstrelTable[i].attemptHist += station->m_minstrelTable[i].numRateAttempt;
657 station->m_minstrelTable[i].prevNumRateSuccess = station->m_minstrelTable[i].numRateSuccess;
658 station->m_minstrelTable[i].prevNumRateAttempt = station->m_minstrelTable[i].numRateAttempt;
659 station->m_minstrelTable[i].numRateSuccess = 0;
660 station->m_minstrelTable[i].numRateAttempt = 0;
661
662 // Sample less often below 10% and above 95% of success
663 if ((station->m_minstrelTable[i].ewmaProb > 17100) ||
664 (station->m_minstrelTable[i].ewmaProb < 1800))
665 {
675 if (station->m_minstrelTable[i].retryCount > 2)
676 {
677 station->m_minstrelTable[i].adjustedRetryCount = 2;
678 }
679 station->m_minstrelTable[i].sampleLimit = 4;
680 }
681 else
682 {
683 // no sampling limit.
684 station->m_minstrelTable[i].sampleLimit = -1;
685 station->m_minstrelTable[i].adjustedRetryCount = station->m_minstrelTable[i].retryCount;
686 }
687
688 // if it's 0 allow two retries.
689 if (station->m_minstrelTable[i].adjustedRetryCount == 0)
690 {
691 station->m_minstrelTable[i].adjustedRetryCount = 2;
692 }
693 }
694
695 NS_LOG_DEBUG("Attempt/success reset to 0");
696
697 uint32_t max_tp = 0;
698 uint8_t index_max_tp = 0;
699 uint8_t index_max_tp2 = 0;
700
701 // go find max throughput, second maximum throughput, high probability of success
703 "Finding the maximum throughput, second maximum throughput, and highest probability");
704 NS_LOG_DEBUG("Index-Rate\t\tT-put\tEWMA");
705 for (uint8_t i = 0; i < station->m_nModes; i++)
706 {
707 NS_LOG_DEBUG(+i << " " << GetSupported(station, i) << "\t"
708 << station->m_minstrelTable[i].throughput << "\t"
709 << station->m_minstrelTable[i].ewmaProb);
710
711 if (max_tp < station->m_minstrelTable[i].throughput)
712 {
713 index_max_tp = i;
714 max_tp = station->m_minstrelTable[i].throughput;
715 }
716 }
717
718 max_tp = 0;
719 // find the second highest max
720 for (uint8_t i = 0; i < station->m_nModes; i++)
721 {
722 if ((i != index_max_tp) && (max_tp < station->m_minstrelTable[i].throughput))
723 {
724 index_max_tp2 = i;
725 max_tp = station->m_minstrelTable[i].throughput;
726 }
727 }
728
729 uint32_t max_prob = 0;
730 uint8_t index_max_prob = 0;
731 for (uint8_t i = 0; i < station->m_nModes; i++)
732 {
733 if ((station->m_minstrelTable[i].ewmaProb >= 95 * 180) &&
734 (station->m_minstrelTable[i].throughput >=
735 station->m_minstrelTable[index_max_prob].throughput))
736 {
737 index_max_prob = i;
738 max_prob = station->m_minstrelTable[i].ewmaProb;
739 }
740 else if (station->m_minstrelTable[i].ewmaProb >= max_prob)
741 {
742 index_max_prob = i;
743 max_prob = station->m_minstrelTable[i].ewmaProb;
744 }
745 }
746
747 station->m_maxTpRate = index_max_tp;
748 station->m_maxTpRate2 = index_max_tp2;
749 station->m_maxProbRate = index_max_prob;
750
751 if (index_max_tp > station->m_txrate)
752 {
753 station->m_txrate = index_max_tp;
754 }
755
756 NS_LOG_DEBUG("max throughput=" << +index_max_tp << "(" << GetSupported(station, index_max_tp)
757 << ")\tsecond max throughput=" << +index_max_tp2 << "("
758 << GetSupported(station, index_max_tp2)
759 << ")\tmax prob=" << +index_max_prob << "("
760 << GetSupported(station, index_max_prob) << ")");
761 if (m_printStats)
762 {
763 PrintTable(station);
764 }
765 if (m_printSamples)
766 {
767 PrintSampleTable(station);
768 }
769}
770
771void
773{
774 NS_LOG_FUNCTION(this << st << rxSnr << txMode);
775 NS_LOG_DEBUG("DoReportRxOk m_txrate=" << static_cast<MinstrelWifiRemoteStation*>(st)->m_txrate);
776}
777
778void
780{
781 NS_LOG_FUNCTION(this << st);
782 auto station = static_cast<MinstrelWifiRemoteStation*>(st);
783 NS_LOG_DEBUG("DoReportRtsFailed m_txrate=" << station->m_txrate);
784 station->m_shortRetry++;
785}
786
787void
789 double ctsSnr,
790 WifiMode ctsMode,
791 double rtsSnr)
792{
793 NS_LOG_FUNCTION(this << st << ctsSnr << ctsMode << rtsSnr);
794}
795
796void
798{
799 NS_LOG_FUNCTION(this << st);
800 auto station = static_cast<MinstrelWifiRemoteStation*>(st);
801 UpdateRetry(station);
802}
803
804void
806{
807 NS_LOG_FUNCTION(this << st);
808 auto station = static_cast<MinstrelWifiRemoteStation*>(st);
809 NS_LOG_DEBUG("DoReportDataFailed " << station << "\t rate " << station->m_txrate
810 << "\tlongRetry \t" << station->m_longRetry);
811 CheckInit(station);
812 if (!station->m_initialized)
813 {
814 return;
815 }
816
817 UpdateRate(station);
818}
819
820void
822 double ackSnr,
823 WifiMode ackMode,
824 double dataSnr,
825 uint16_t dataChannelWidth,
826 uint8_t dataNss)
827{
828 NS_LOG_FUNCTION(this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << +dataNss);
829 auto station = static_cast<MinstrelWifiRemoteStation*>(st);
830
831 CheckInit(station);
832 if (!station->m_initialized)
833 {
834 return;
835 }
836
837 NS_LOG_DEBUG("DoReportDataOk m_txrate = "
838 << station->m_txrate
839 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
840 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
841 << " (before update).");
842
843 station->m_minstrelTable[station->m_txrate].numRateSuccess++;
844 station->m_minstrelTable[station->m_txrate].numRateAttempt++;
845
846 UpdatePacketCounters(station);
847
848 NS_LOG_DEBUG("DoReportDataOk m_txrate = "
849 << station->m_txrate
850 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
851 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
852 << " (after update).");
853
854 UpdateRetry(station);
855 UpdateStats(station);
856
857 if (station->m_nModes >= 1)
858 {
859 station->m_txrate = FindRate(station);
860 }
861 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
862}
863
864void
866{
867 NS_LOG_FUNCTION(this << st);
868 auto station = static_cast<MinstrelWifiRemoteStation*>(st);
869
870 CheckInit(station);
871 if (!station->m_initialized)
872 {
873 return;
874 }
875
876 NS_LOG_DEBUG("DoReportFinalDataFailed m_txrate = "
877 << station->m_txrate
878 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
879 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
880 << " (before update).");
881
882 UpdatePacketCounters(station);
883
884 UpdateRetry(station);
885 UpdateStats(station);
886
887 NS_LOG_DEBUG("DoReportFinalDataFailed m_txrate = "
888 << station->m_txrate
889 << ", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
890 << ", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
891 << " (after update).");
892
893 if (station->m_nModes >= 1)
894 {
895 station->m_txrate = FindRate(station);
896 }
897 NS_LOG_DEBUG("Next rate to use TxRate = " << station->m_txrate);
898}
899
900void
902{
903 NS_LOG_FUNCTION(this << station);
904
905 station->m_totalPacketsCount++;
906 // If it is a sampling frame and the sampleRate was used, increase counter
907 if (station->m_isSampling &&
908 (!station->m_sampleDeferred ||
909 station->m_longRetry >= station->m_minstrelTable[station->m_maxTpRate].adjustedRetryCount))
910 {
911 station->m_samplePacketsCount++;
912 }
913
914 if (station->m_numSamplesDeferred > 0)
915 {
916 station->m_numSamplesDeferred--;
917 }
918
919 if (station->m_totalPacketsCount == ~0)
920 {
921 station->m_numSamplesDeferred = 0;
922 station->m_samplePacketsCount = 0;
923 station->m_totalPacketsCount = 0;
924 }
925 station->m_isSampling = false;
926 station->m_sampleDeferred = false;
927}
928
929void
931{
932 NS_LOG_FUNCTION(this << station);
933 station->m_retry = station->m_shortRetry + station->m_longRetry;
934 station->m_shortRetry = 0;
935 station->m_longRetry = 0;
936}
937
940{
941 NS_LOG_FUNCTION(this << st << allowedWidth);
942 auto station = static_cast<MinstrelWifiRemoteStation*>(st);
943 return GetDataTxVector(station);
944}
945
948{
949 NS_LOG_FUNCTION(this << st);
950 auto station = static_cast<MinstrelWifiRemoteStation*>(st);
951 return GetRtsTxVector(station);
952}
953
954bool
956 Ptr<const Packet> packet,
957 bool normally)
958{
959 NS_LOG_FUNCTION(this << st << packet << normally);
960 auto station = static_cast<MinstrelWifiRemoteStation*>(st);
961
962 CheckInit(station);
963 if (!station->m_initialized)
964 {
965 return normally;
966 }
967 if (station->m_longRetry >= CountRetries(station))
968 {
969 NS_LOG_DEBUG("No re-transmission allowed. Retries: "
970 << station->m_longRetry << " Max retries: " << CountRetries(station));
971 return false;
972 }
973 else
974 {
975 NS_LOG_DEBUG("Re-transmit. Retries: " << station->m_longRetry
976 << " Max retries: " << CountRetries(station));
977 return true;
978 }
979}
980
981uint16_t
983{
984 NS_LOG_FUNCTION(this << station);
985 uint16_t bitrate;
986 bitrate = station->m_sampleTable[station->m_index][station->m_col];
987 station->m_index++;
988
989 // bookkeeping for m_index and m_col variables
990 NS_ABORT_MSG_IF(station->m_nModes < 2, "Integer overflow detected");
991 if (station->m_index > station->m_nModes - 2)
992 {
993 station->m_index = 0;
994 station->m_col++;
995 if (station->m_col >= m_sampleCol)
996 {
997 station->m_col = 0;
998 }
999 }
1000 return bitrate;
1001}
1002
1003void
1005{
1006 NS_LOG_FUNCTION(this << station);
1007 for (uint8_t i = 0; i < station->m_nModes; i++)
1008 {
1009 NS_LOG_DEBUG("Initializing rate index " << +i << " " << GetSupported(station, i));
1010 station->m_minstrelTable[i].numRateAttempt = 0;
1011 station->m_minstrelTable[i].numRateSuccess = 0;
1012 station->m_minstrelTable[i].prevNumRateSuccess = 0;
1013 station->m_minstrelTable[i].prevNumRateAttempt = 0;
1014 station->m_minstrelTable[i].successHist = 0;
1015 station->m_minstrelTable[i].attemptHist = 0;
1016 station->m_minstrelTable[i].numSamplesSkipped = 0;
1017 station->m_minstrelTable[i].prob = 0;
1018 station->m_minstrelTable[i].ewmaProb = 0;
1019 station->m_minstrelTable[i].throughput = 0;
1020 station->m_minstrelTable[i].perfectTxTime = GetCalcTxTime(GetSupported(station, i));
1021 NS_LOG_DEBUG(" perfectTxTime = " << station->m_minstrelTable[i].perfectTxTime);
1022 station->m_minstrelTable[i].retryCount = 1;
1023 station->m_minstrelTable[i].adjustedRetryCount = 1;
1024 // Emulating minstrel.c::ath_rate_ctl_reset
1025 // We only check from 2 to 10 retries. This guarantee that
1026 // at least one retry is permitted.
1027 Time totalTxTimeWithGivenRetries = Seconds(0.0); // tx_time in minstrel.c
1028 NS_LOG_DEBUG(" Calculating the number of retries");
1029 for (uint32_t retries = 2; retries < 11; retries++)
1030 {
1031 NS_LOG_DEBUG(" Checking " << retries << " retries");
1032 totalTxTimeWithGivenRetries =
1033 CalculateTimeUnicastPacket(station->m_minstrelTable[i].perfectTxTime, 0, retries);
1034 NS_LOG_DEBUG(" totalTxTimeWithGivenRetries = " << totalTxTimeWithGivenRetries);
1035 if (totalTxTimeWithGivenRetries > MilliSeconds(6))
1036 {
1037 break;
1038 }
1039 station->m_minstrelTable[i].sampleLimit = -1;
1040 station->m_minstrelTable[i].retryCount = retries;
1041 station->m_minstrelTable[i].adjustedRetryCount = retries;
1042 }
1043 }
1044 UpdateStats(station);
1045}
1046
1047Time
1049 uint32_t shortRetries,
1050 uint32_t longRetries)
1051{
1052 NS_LOG_FUNCTION(this << dataTransmissionTime << shortRetries << longRetries);
1053 // See rc80211_minstrel.c
1054
1055 // First transmission (Data + Ack timeout)
1056 Time tt = dataTransmissionTime + GetPhy()->GetSifs() + GetPhy()->GetAckTxTime();
1057
1058 uint32_t cwMax = 1023;
1059 uint32_t cw = 31;
1060 for (uint32_t retry = 0; retry < longRetries; retry++)
1061 {
1062 // Add one re-transmission (Data + Ack timeout)
1063 tt += dataTransmissionTime + GetPhy()->GetSifs() + GetPhy()->GetAckTxTime();
1064
1065 // Add average back off (half the current contention window)
1066 tt += (cw / 2.0) * GetPhy()->GetSlot();
1067
1068 // Update contention window
1069 cw = std::min(cwMax, (cw + 1) * 2);
1070 }
1071
1072 return tt;
1073}
1074
1075void
1077{
1078 NS_LOG_FUNCTION(this << station);
1079 station->m_col = station->m_index = 0;
1080
1081 // for off-setting to make rates fall between 0 and nModes
1082 uint8_t numSampleRates = station->m_nModes;
1083
1084 uint16_t newIndex;
1085 for (uint8_t col = 0; col < m_sampleCol; col++)
1086 {
1087 for (uint8_t i = 0; i < numSampleRates; i++)
1088 {
1093 int uv = m_uniformRandomVariable->GetInteger(0, numSampleRates);
1094 NS_LOG_DEBUG("InitSampleTable uv: " << uv);
1095 newIndex = (i + uv) % numSampleRates;
1096
1097 // this loop is used for filling in other uninitialized places
1098 while (station->m_sampleTable[newIndex][col] != 0)
1099 {
1100 newIndex = (newIndex + 1) % station->m_nModes;
1101 }
1102 station->m_sampleTable[newIndex][col] = i;
1103 }
1104 }
1105}
1106
1107void
1109{
1110 uint8_t numSampleRates = station->m_nModes;
1111 std::stringstream table;
1112 for (uint8_t i = 0; i < numSampleRates; i++)
1113 {
1114 for (uint8_t j = 0; j < m_sampleCol; j++)
1115 {
1116 table << station->m_sampleTable[i][j] << "\t";
1117 }
1118 table << std::endl;
1119 }
1120 NS_LOG_DEBUG(table.str());
1121}
1122
1123void
1125{
1126 if (!station->m_statsFile.is_open())
1127 {
1128 std::ostringstream tmp;
1129 tmp << "minstrel-stats-" << station->m_state->m_address << ".txt";
1130 station->m_statsFile.open(tmp.str(), std::ios::out);
1131 }
1132
1133 station->m_statsFile
1134 << "best _______________rate________________ ________statistics________ "
1135 "________last_______ ______sum-of________\n"
1136 << "rate [ name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] "
1137 "[prob.|retry|suc|att] [#success | #attempts]\n";
1138
1139 uint16_t maxTpRate = station->m_maxTpRate;
1140 uint16_t maxTpRate2 = station->m_maxTpRate2;
1141 uint16_t maxProbRate = station->m_maxProbRate;
1142
1143 for (uint8_t i = 0; i < station->m_nModes; i++)
1144 {
1145 RateInfo rate = station->m_minstrelTable[i];
1146
1147 if (i == maxTpRate)
1148 {
1149 station->m_statsFile << 'A';
1150 }
1151 else
1152 {
1153 station->m_statsFile << ' ';
1154 }
1155 if (i == maxTpRate2)
1156 {
1157 station->m_statsFile << 'B';
1158 }
1159 else
1160 {
1161 station->m_statsFile << ' ';
1162 }
1163 if (i == maxProbRate)
1164 {
1165 station->m_statsFile << 'P';
1166 }
1167 else
1168 {
1169 station->m_statsFile << ' ';
1170 }
1171
1172 float tmpTh = rate.throughput / 100000.0F;
1173 station->m_statsFile << " " << std::setw(17) << GetSupported(station, i) << " "
1174 << std::setw(2) << i << " " << std::setw(4)
1175 << rate.perfectTxTime.GetMicroSeconds() << std::setw(8)
1176 << " ----- " << std::setw(8) << tmpTh << " " << std::setw(3)
1177 << rate.ewmaProb / 180 << std::setw(3) << " --- "
1178 << std::setw(3) << rate.prob / 180 << " " << std::setw(1)
1179 << rate.adjustedRetryCount << " " << std::setw(3)
1180 << rate.prevNumRateSuccess << " " << std::setw(3)
1181 << rate.prevNumRateAttempt << " " << std::setw(9) << rate.successHist
1182 << " " << std::setw(9) << rate.attemptHist << "\n";
1183 }
1184 station->m_statsFile << "\nTotal packet count: ideal "
1185 << station->m_totalPacketsCount - station->m_samplePacketsCount
1186 << " lookaround " << station->m_samplePacketsCount << "\n\n";
1187
1188 station->m_statsFile.flush();
1189}
1190
1191} // namespace ns3
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Implementation of Minstrel Rate Control Algorithm.
WifiRemoteStation * DoCreateStation() const override
WifiTxVector DoGetRtsTxVector(WifiRemoteStation *station) override
uint8_t m_lookAroundRate
the % to try other rates than our current rate
void PrintSampleTable(MinstrelWifiRemoteStation *station) const
Print Sample Table.
void AddCalcTxTime(WifiMode mode, Time t)
Add transmission time for the given mode to an internal list.
void RateInit(MinstrelWifiRemoteStation *station)
Initialize Minstrel Table.
uint32_t m_pktLen
packet length used to calculate mode TxTime
void DoReportFinalDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void DoInitialize() override
Initialize() implementation.
void UpdateStats(MinstrelWifiRemoteStation *station)
Update the Minstrel Table.
void CheckInit(MinstrelWifiRemoteStation *station)
Check for initializations.
static TypeId GetTypeId()
Get the type ID.
Ptr< UniformRandomVariable > m_uniformRandomVariable
Provides uniform random variables.
TxTime m_calcTxTime
to hold all the calculated TxTime for all modes
bool m_printSamples
whether samples table should be printed.
void DoReportDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
bool m_printStats
whether statistics table should be printed.
WifiTxVector GetRtsTxVector(MinstrelWifiRemoteStation *station)
Get RTS transmit vector.
uint8_t m_sampleCol
number of sample columns
void DoReportFinalRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void SetupMac(const Ptr< WifiMac > mac) override
Set up MAC associated with this device since it is the object that knows the full set of timing param...
uint16_t FindRate(MinstrelWifiRemoteStation *station)
Find a rate to use from Minstrel Table.
Time GetCalcTxTime(WifiMode mode) const
Estimate the TxTime of a packet with a given mode.
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 DoReportRtsOk(WifiRemoteStation *station, double ctsSnr, WifiMode ctsMode, double rtsSnr) override
This method is a pure virtual method that must be implemented by the sub-class.
void InitSampleTable(MinstrelWifiRemoteStation *station)
Initialize Sample Table.
WifiTxVector DoGetDataTxVector(WifiRemoteStation *station, uint16_t allowedWidth) override
TracedValue< uint64_t > m_currentRate
Trace rate changes.
Time m_updateStats
how frequent do we calculate the stats
bool DoNeedRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally) override
void UpdatePacketCounters(MinstrelWifiRemoteStation *station)
Update packet counters.
void UpdateRate(MinstrelWifiRemoteStation *station)
Update the rate.
void DoReportDataOk(WifiRemoteStation *station, double ackSnr, WifiMode ackMode, double dataSnr, uint16_t dataChannelWidth, uint8_t dataNss) override
This method is a pure virtual method that must be implemented by the sub-class.
void PrintTable(MinstrelWifiRemoteStation *station)
Print Minstrel Table.
uint16_t GetNextSample(MinstrelWifiRemoteStation *station)
Get the next sample from Sample Table.
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model.
void DoReportRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode) override
This method is a pure virtual method that must be implemented by the sub-class.
uint8_t m_ewmaLevel
exponential weighted moving average
void SetupPhy(const Ptr< WifiPhy > phy) override
Set up PHY associated with this device since it is the object that knows the full set of transmit rat...
uint32_t CountRetries(MinstrelWifiRemoteStation *station)
Get the number of retries.
void UpdateRetry(MinstrelWifiRemoteStation *station)
Update the number of retries and reset accordingly.
WifiTxVector GetDataTxVector(MinstrelWifiRemoteStation *station)
Get data transmit vector.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:413
AttributeValue implementation for Time.
Definition: nstime.h:1413
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
Hold an unsigned integer type.
Definition: uinteger.h:45
uint32_t GetInteger(uint32_t min, uint32_t max)
Get the next random value drawn from the distribution.
represent a single transmission mode
Definition: wifi-mode.h:51
WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:185
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:122
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:811
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:799
Time GetAckTxTime() const
Return the estimated Ack TX time for this PHY.
Definition: wifi-phy.cc:829
hold a list of per-remote-station state.
uint16_t GetChannelWidth(const WifiRemoteStation *station) const
Return the channel width supported by the station.
uint8_t GetNSupported(const WifiRemoteStation *station) const
Return the number of modes supported by the given station.
Ptr< WifiPhy > GetPhy() const
Return the WifiPhy.
bool GetAggregation(const WifiRemoteStation *station) const
Return whether the given station supports A-MPDU.
bool GetHtSupported() const
Return whether the device has HT capability support enabled.
WifiMode GetNonErpSupported(const WifiRemoteStation *station, uint8_t i) const
Return whether non-ERP mode associated with the specified station at the specified index.
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...
bool GetUseNonErpProtection() const
Return whether the device supports protection of non-ERP stations.
bool GetVhtSupported() const
Return whether the device has VHT capability support enabled.
bool GetShortPreambleEnabled() const
Return whether the device uses short PHY preambles.
WifiMode GetSupported(const WifiRemoteStation *station, uint8_t i) const
Return whether mode associated with the specified station at the specified index.
bool GetHeSupported() const
Return whether the device has HE capability support enabled.
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...
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:81
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1434
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1414
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
@ WIFI_PREAMBLE_LONG
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::vector< RateInfo > MinstrelRate
Data structure for a Minstrel Rate table A vector of a struct RateInfo.
WifiPreamble GetPreambleForTransmission(WifiModulationClass modulation, bool useShortPreamble)
Return the preamble to be used for the transmission.
std::vector< std::vector< uint8_t > > SampleRate
Data structure for a Sample Rate table A vector of a vector uint8_t.
hold per-remote-station state for Minstrel Wifi manager.
uint16_t m_maxTpRate2
second highest throughput rate in bps
Time m_nextStatsUpdate
10 times every second
bool m_initialized
for initializing tables
uint16_t m_sampleRate
current sample rate in bps
int m_numSamplesDeferred
number samples deferred
uint16_t m_txrate
current transmit rate in bps
int m_totalPacketsCount
total number of packets as of now
bool m_isSampling
a flag to indicate we are currently sampling
MinstrelRate m_minstrelTable
minstrel table
uint32_t m_shortRetry
short retries such as control packets
uint32_t m_retry
total retries short + long
uint16_t m_maxTpRate
the current throughput rate in bps
bool m_sampleDeferred
a flag to indicate sample rate is on the second stage
uint8_t m_nModes
number of modes supported
SampleRate m_sampleTable
sample table
int m_samplePacketsCount
how many packets we have sample so far
std::ofstream m_statsFile
stats file
uint8_t m_col
To keep track of the current position in the our random sample table going row by row from 1st column...
uint32_t m_longRetry
long retries such as data packets
uint16_t m_maxProbRate
rate with highest probability of success in bps
A struct to contain all information related to a data rate.
uint32_t ewmaProb
EWMA calculation ewma_prob =[prob *(100 - ewma_level) + (ewma_prob_old * ewma_level)]/100.
uint32_t adjustedRetryCount
adjust the retry limit for this rate
uint32_t prevNumRateSuccess
Number of successful frames transmitted with previous rate.
uint32_t prob
(# packets success)/(# total packets)
Time perfectTxTime
Perfect transmission time calculation, or frame calculation Given a bit rate and a packet length n by...
uint64_t successHist
Aggregate of all transmission successes.
uint32_t throughput
throughput of a rate in bps
uint32_t prevNumRateAttempt
Number of transmission attempts with previous rate.
uint64_t attemptHist
Aggregate of all transmission attempts.
hold per-remote-station state.
WifiRemoteStationState * m_state
Remote station state.
Mac48Address m_address
Mac48Address of the remote station.
std::ofstream throughput