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