27#include "ns3/ht-configuration.h" 
   29#include "ns3/packet.h" 
   30#include "ns3/random-variable-stream.h" 
   31#include "ns3/simulator.h" 
   32#include "ns3/wifi-mac.h" 
   33#include "ns3/wifi-net-device.h" 
   34#include "ns3/wifi-phy.h" 
   35#include "ns3/wifi-psdu.h" 
   40#define Min(a, b) ((a < b) ? a : b) 
   41#define Max(a, b) ((a > b) ? a : b) 
   57            .maxWidth = 
MHz_u{40},
 
   67            .maxWidth = 
MHz_u{160},
 
   77            .maxWidth = 
MHz_u{160},
 
   87            .maxWidth = 
MHz_u{320},
 
 
  120        TypeId(
"ns3::MinstrelHtWifiManager")
 
  122            .AddConstructor<MinstrelHtWifiManager>()
 
  123            .SetGroupName(
"Wifi")
 
  124            .AddAttribute(
"UpdateStatistics",
 
  125                          "The interval between updating statistics table",
 
  129            .AddAttribute(
"LegacyUpdateStatistics",
 
  130                          "The interval between updating statistics table (for legacy Minstrel)",
 
  134            .AddAttribute(
"LookAroundRate",
 
  135                          "The percentage to try other rates (for legacy Minstrel)",
 
  139            .AddAttribute(
"EWMA",
 
  144            .AddAttribute(
"SampleColumn",
 
  145                          "The number of columns used for sampling",
 
  149            .AddAttribute(
"PacketLength",
 
  150                          "The packet length used for calculating mode TxTime (bytes)",
 
  154            .AddAttribute(
"UseLatestAmendmentOnly",
 
  155                          "Use only the latest amendment when it is supported by both peers",
 
  159            .AddAttribute(
"PrintStats",
 
  160                          "Control the printing of the statistics table",
 
  164            .AddTraceSource(
"Rate",
 
  165                            "Traced value for rate changes (b/s)",
 
  167                            "ns3::TracedValueCallback::Uint64");
 
 
  199    int64_t numStreamsAssigned = 0;
 
  201    numStreamsAssigned++;
 
  203    return numStreamsAssigned;
 
 
  227    for (
MHz_u chWidth{20}; chWidth <= standardInfos.maxWidth; chWidth *= 2)
 
  229        for (
const auto& guardInterval : standardInfos.guardIntervals)
 
  231            for (uint8_t streams = 1; streams <= standardInfos.maxStreams; ++streams)
 
  248                        (guardInterval.GetNanoSeconds() ==
 
  252                    && (
GetPhy()->GetMaxSupportedTxSpatialStreams() >=
 
  259                    for (uint8_t i = 0; i <= standardInfos.maxMcs; ++i)
 
  263                                                             (standardInfos.maxMcs + 1))
 
  265                        WifiMode mode = mcsList.at(mcsIndex);
 
  285                    NS_LOG_DEBUG(
"Initialized group " << groupId << 
": (" << +streams << 
"," 
  286                                                      << guardInterval << 
"," << chWidth << 
")");
 
 
  408    txvector.SetGuardInterval(gi);
 
  409    txvector.SetChannelWidth(chWidth);
 
  410    txvector.SetMode(mode);
 
 
  420    const auto it = 
m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.find(mode);
 
 
  429    m_minstrelGroups[groupId].ratesFirstMpduTxTimeTable.insert(std::make_pair(mode, t));
 
 
  457    station->m_index = 0;
 
  458    station->m_maxTpRate = 0;
 
  459    station->m_maxTpRate2 = 0;
 
  460    station->m_maxProbRate = 0;
 
  461    station->m_nModes = 0;
 
  462    station->m_totalPacketsCount = 0;
 
  463    station->m_samplePacketsCount = 0;
 
  464    station->m_isSampling = 
false;
 
  465    station->m_sampleRate = 0;
 
  466    station->m_sampleDeferred = 
false;
 
  467    station->m_shortRetry = 0;
 
  468    station->m_longRetry = 0;
 
  469    station->m_txrate = 0;
 
  470    station->m_initialized = 
false;
 
  473    station->m_sampleGroup = 0;
 
  474    station->m_numSamplesSlow = 0;
 
  475    station->m_sampleCount = 16;
 
  476    station->m_sampleWait = 0;
 
  477    station->m_sampleTries = 4;
 
  479    station->m_avgAmpduLen = 1;
 
  480    station->m_ampduLen = 0;
 
  481    station->m_ampduPacketCount = 0;
 
  485    station->m_isHt = 
static_cast<bool>(
GetPhy()->
GetDevice()->GetHtConfiguration());
 
 
  546    if (!station->m_initialized)
 
  550    NS_LOG_DEBUG(
"DoReportRtsFailed m_txrate = " << station->m_txrate);
 
  551    station->m_shortRetry++;
 
 
  570    if (!station->m_initialized)
 
 
  584    if (!station->m_initialized)
 
  589    NS_LOG_DEBUG(
"DoReportDataFailed " << station << 
"\t rate " << station->m_txrate
 
  590                                       << 
"\tlongRetry \t" << station->m_longRetry);
 
  592    if (!station->m_isHt)
 
  598        const auto rateId = 
GetRateId(station->m_txrate);
 
  599        const auto groupId = 
GetGroupId(station->m_txrate);
 
  600        station->m_groupsTable[groupId]
 
  601            .m_ratesTable[rateId]
 
 
  612                                      MHz_u dataChannelWidth,
 
  615    NS_LOG_FUNCTION(
this << st << ackSnr << ackMode << dataSnr << dataChannelWidth << dataNss);
 
  619    if (!station->m_initialized)
 
  624    if (!station->m_isHt)
 
  628                     << 
", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
 
  629                     << 
", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
 
  630                     << 
" (before update).");
 
  632        station->m_minstrelTable[station->m_txrate].numRateSuccess++;
 
  633        station->m_minstrelTable[station->m_txrate].numRateAttempt++;
 
  639                     << 
", attempt = " << station->m_minstrelTable[station->m_txrate].numRateAttempt
 
  640                     << 
", success = " << station->m_minstrelTable[station->m_txrate].numRateSuccess
 
  641                     << 
" (after update).");
 
  646        if (station->m_nModes >= 1)
 
  653        const auto rateId = 
GetRateId(station->m_txrate);
 
  654        const auto groupId = 
GetGroupId(station->m_txrate);
 
  657            "DoReportDataOk m_txrate = " 
  659            << 
", attempt = " << station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt
 
  660            << 
", success = " << station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess
 
  661            << 
" (before update).");
 
  663        station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess++;
 
  664        station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt++;
 
  669            "DoReportDataOk m_txrate = " 
  671            << 
", attempt = " << station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt
 
  672            << 
", success = " << station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess
 
  673            << 
" (after update).");
 
  675        station->m_isSampling = 
false;
 
  676        station->m_sampleDeferred = 
false;
 
  684        if (station->m_nModes >= 1)
 
  686            station->m_txrate = 
FindRate(station);
 
  690    NS_LOG_DEBUG(
"Next rate to use TxRate = " << station->m_txrate);
 
 
  700    if (!station->m_initialized)
 
  705    NS_LOG_DEBUG(
"DoReportFinalDataFailed - TxRate=" << station->m_txrate);
 
  707    if (!station->m_isHt)
 
  714        if (station->m_nModes >= 1)
 
  723        station->m_isSampling = 
false;
 
  724        station->m_sampleDeferred = 
false;
 
  732        if (station->m_nModes >= 1)
 
  734            station->m_txrate = 
FindRate(station);
 
  737    NS_LOG_DEBUG(
"Next rate to use TxRate = " << station->m_txrate);
 
 
  742                                             uint16_t nSuccessfulMpdus,
 
  743                                             uint16_t nFailedMpdus,
 
  746                                             MHz_u dataChannelWidth,
 
  749    NS_LOG_FUNCTION(
this << st << nSuccessfulMpdus << nFailedMpdus << rxSnr << dataSnr
 
  750                         << dataChannelWidth << dataNss);
 
  754    if (!station->m_initialized)
 
  759    NS_ASSERT_MSG(station->m_isHt, 
"A-MPDU Tx Status called but this is a non-HT STA.");
 
  761    NS_LOG_DEBUG(
"DoReportAmpduTxStatus. TxRate=" << station->m_txrate
 
  762                                                  << 
" SuccMpdus=" << nSuccessfulMpdus
 
  763                                                  << 
" FailedMpdus=" << nFailedMpdus);
 
  765    station->m_ampduPacketCount++;
 
  766    station->m_ampduLen += nSuccessfulMpdus + nFailedMpdus;
 
  770    const auto rateId = 
GetRateId(station->m_txrate);
 
  771    const auto groupId = 
GetGroupId(station->m_txrate);
 
  772    station->m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess += nSuccessfulMpdus;
 
  773    station->m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt +=
 
  774        nSuccessfulMpdus + nFailedMpdus;
 
  776    if (nSuccessfulMpdus == 0 && station->m_longRetry < 
CountRetries(station))
 
  783        station->m_isSampling = 
false;
 
  784        station->m_sampleDeferred = 
false;
 
  792        if (station->m_nModes >= 1)
 
  794            station->m_txrate = 
FindRate(station);
 
  796        NS_LOG_DEBUG(
"Next rate to use TxRate = " << station->m_txrate);
 
 
  848            station->
m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount)
 
  856                 (station->
m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
 
  857                  station->
m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount))
 
  865                 (station->
m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
 
  866                  station->
m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
 
  867                  station->
m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount))
 
  874            NS_FATAL_ERROR(
"Max retries reached and m_longRetry not cleared properly. longRetry= " 
  885            1 + station->
m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount)
 
  893                 1 + station->
m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
 
  894                     station->
m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount)
 
  901            NS_FATAL_ERROR(
"Max retries reached and m_longRetry not cleared properly. longRetry= " 
 
  918                                            uint16_t nSuccessfulMpdus,
 
  919                                            uint16_t nFailedMpdus)
 
 
  950    if (group.
chWidth <= allowedWidth)
 
  952        NS_LOG_DEBUG(
"Channel width is not greater than allowed width, nothing to do");
 
  961    auto width = group.
chWidth / 2;
 
  963    while (width >= 
MHz_u{20})
 
  965        if (width > allowedWidth)
 
 
  990    if (!station->m_initialized)
 
  995    if (!station->m_isHt)
 
 1008    NS_LOG_DEBUG(
"DoGetDataMode m_txrate= " << station->m_txrate);
 
 1010    const auto rateId = 
GetRateId(station->m_txrate);
 
 1011    const auto groupId = 
GetGroupId(station->m_txrate);
 
 1012    const auto mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
 
 1014    NS_LOG_DEBUG(
"DoGetDataMode rateId= " << rateId << 
" groupId= " << groupId
 
 
 1060    if (!station->m_initialized)
 
 1065    if (!station->m_isHt)
 
 1071        NS_LOG_DEBUG(
"DoGetRtsMode m_txrate=" << station->m_txrate);
 
 1087        const auto rateId = 
GetRateId(station->m_txrate);
 
 1088        const auto groupId = 
GetGroupId(station->m_txrate);
 
 1089        const auto mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
 
 1092        const auto lastDataRate = lastRate.GetNonHtReferenceRate();
 
 1096        bool rateFound = 
false;
 
 1098        for (uint8_t i = 0; i < nBasicRates; i++)
 
 1101            if (rate <= lastDataRate)
 
 1112                const auto rate = mode.GetDataRate(
MHz_u{20});
 
 1113                if (rate <= lastDataRate)
 
 
 1136std::list<Ptr<WifiMpdu>>
 
 1141    std::list<Ptr<WifiMpdu>> mpdusToDrop;
 
 1147                                  (mpdu->GetRetryCount() < 
GetMac()->GetFrameRetryLimit())))
 
 1150            mpdusToDrop.push_back(mpdu);
 
 
 1167    if (!station->m_initialized)
 
 1174    if (!station->m_isHt)
 
 1183    if (station->m_longRetry >= maxRetries)
 
 1185        NS_LOG_DEBUG(
"No re-transmission allowed. Retries: " << station->m_longRetry
 
 1186                                                             << 
" Max retries: " << maxRetries);
 
 1191        NS_LOG_DEBUG(
"Re-transmit. Retries: " << station->m_longRetry
 
 1192                                              << 
" Max retries: " << maxRetries);
 
 
 1209        return station->
m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].retryCount +
 
 1210               station->
m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].retryCount +
 
 1211               station->
m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
 
 1215        return 1 + station->
m_groupsTable[maxTpGroupId].m_ratesTable[maxTp2RateId].retryCount +
 
 1216               station->
m_groupsTable[maxProbGroupId].m_ratesTable[maxProbRateId].retryCount;
 
 
 1225    const auto index = station->
m_groupsTable[sampleGroup].m_index;
 
 1227    const auto sampleIndex = station->
m_sampleTable[index][col];
 
 1228    const auto rateIndex = 
GetIndex(sampleGroup, sampleIndex);
 
 
 1286        const auto sampleGroupId = 
GetGroupId(sampleIdx);
 
 1287        const auto sampleRateId = 
GetRateId(sampleIdx);
 
 1291            station->
m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId].supported)
 
 1300            const auto sampleRateInfo =
 
 1301                station->
m_groupsTable[sampleGroupId].m_ratesTable[sampleRateId];
 
 1305                         << 
" SampleRate= " << sampleIdx
 
 1306                         << 
" SampleProb= " << sampleRateInfo.ewmaProb);
 
 1309                sampleIdx != station->
m_maxProbRate && sampleRateInfo.ewmaProb <= 95)
 
 1325                const auto sampleDuration = sampleRateInfo.perfectTxTime;
 
 1326                const auto maxTp2Duration =
 
 1327                    station->
m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].perfectTxTime;
 
 1328                const auto maxProbDuration = station->
m_groupsTable[maxProbGroupId]
 
 1329                                                 .m_ratesTable[maxProbRateId]
 
 1333                             << sampleDuration << 
" maxTp2Duration= " << maxTp2Duration
 
 1334                             << 
" maxProbDuration= " << maxProbDuration << 
" sampleStreams= " 
 1335                             << +sampleStreams << 
" maxTpStreams= " << +maxTpStreams);
 
 1336                if (sampleDuration < maxTp2Duration ||
 
 1337                    (sampleStreams < maxTpStreams && sampleDuration < maxProbDuration))
 
 1352                    if (sampleRateInfo.numSamplesSkipped >= 20 && station->
m_numSamplesSlow <= 2)
 
 
 1421                    station->
m_groupsTable[j].m_ratesTable[i].retryUpdated = 
false;
 
 1430                           << station->
m_groupsTable[j].m_ratesTable[i].numRateSuccess);
 
 1433                    if (station->
m_groupsTable[j].m_ratesTable[i].numRateAttempt > 0)
 
 1435                        station->
m_groupsTable[j].m_ratesTable[i].numSamplesSkipped = 0;
 
 1441                            (100 * station->
m_groupsTable[j].m_ratesTable[i].numRateSuccess) /
 
 1447                        if (station->
m_groupsTable[j].m_ratesTable[i].successHist == 0)
 
 1449                            station->
m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
 
 1463                            station->
m_groupsTable[j].m_ratesTable[i].ewmaProb = tempProb;
 
 1476                        station->
m_groupsTable[j].m_ratesTable[i].numSamplesSkipped++;
 
 1480                    station->
m_groupsTable[j].m_ratesTable[i].prevNumRateSuccess =
 
 1482                    station->
m_groupsTable[j].m_ratesTable[i].prevNumRateAttempt =
 
 1484                    station->
m_groupsTable[j].m_ratesTable[i].numRateSuccess = 0;
 
 1485                    station->
m_groupsTable[j].m_ratesTable[i].numRateAttempt = 0;
 
 1487                    if (station->
m_groupsTable[j].m_ratesTable[i].throughput != 0)
 
 
 1515                                           std::size_t groupId,
 
 1534        const auto txTime = station->
m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime;
 
 1537            return 90 / txTime.GetSeconds();
 
 1541            return ewmaProb / txTime.GetSeconds();
 
 
 1551    std::size_t tmpGroupId;
 
 1555    std::size_t groupId;
 
 1559    std::size_t maxGPGroupId;
 
 1560    uint8_t maxGPRateId;
 
 1570    tmpProb = station->
m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].ewmaProb;
 
 1571    tmpTh = station->
m_groupsTable[tmpGroupId].m_ratesTable[tmpRateId].throughput;
 
 1575        currentTh = station->
m_groupsTable[groupId].m_ratesTable[rateId].throughput;
 
 1576        if (currentTh > tmpTh)
 
 1583        maxGPTh = station->
m_groupsTable[maxGPGroupId].m_ratesTable[maxGPRateId].throughput;
 
 1585        if (currentTh > maxGPTh)
 
 
 1614    std::size_t groupId;
 
 1618    std::size_t maxTpGroupId;
 
 1619    uint8_t maxTpRateId;
 
 1620    std::size_t maxTp2GroupId;
 
 1621    uint8_t maxTp2RateId;
 
 1629    prob = station->
m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb;
 
 1630    th = station->
m_groupsTable[groupId].m_ratesTable[rateId].throughput;
 
 1634    maxTpProb = station->
m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].ewmaProb;
 
 1635    maxTpTh = station->
m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
 
 1639    maxTp2Prob = station->
m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].ewmaProb;
 
 1640    maxTp2Th = station->
m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
 
 1642    if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
 
 1647    else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
 
 1658    maxTpTh = station->
m_groupsTable[maxTpGroupId].m_ratesTable[maxTpRateId].throughput;
 
 1662    maxTp2Prob = group->
m_ratesTable[maxTp2RateId].ewmaProb;
 
 1663    maxTp2Th = station->
m_groupsTable[maxTp2GroupId].m_ratesTable[maxTp2RateId].throughput;
 
 1665    if (th > maxTpTh || (th == maxTpTh && prob > maxTpProb))
 
 1670    else if (th > maxTp2Th || (th == maxTp2Th && prob > maxTp2Prob))
 
 
 1687    bool noSupportedGroupFound = 
true;
 
 1688    for (std::size_t groupId = 0; groupId < 
m_numGroups; groupId++)
 
 1764            noSupportedGroupFound = 
false;
 
 1773                station->
m_groupsTable[groupId].m_ratesTable[i].supported = 
false;
 
 1778            for (uint8_t i = 0; i < station->
m_nModes; i++)
 
 1787                    auto rateId = mode.GetMcsValue();
 
 1793                    station->
m_groupsTable[groupId].m_ratesTable[rateId].supported = 
true;
 
 1794                    station->
m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex =
 
 1796                    station->
m_groupsTable[groupId].m_ratesTable[rateId].numRateAttempt = 0;
 
 1797                    station->
m_groupsTable[groupId].m_ratesTable[rateId].numRateSuccess = 0;
 
 1798                    station->
m_groupsTable[groupId].m_ratesTable[rateId].prob = 0;
 
 1799                    station->
m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb = 0;
 
 1800                    station->
m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateAttempt = 0;
 
 1801                    station->
m_groupsTable[groupId].m_ratesTable[rateId].prevNumRateSuccess = 0;
 
 1802                    station->
m_groupsTable[groupId].m_ratesTable[rateId].numSamplesSkipped = 0;
 
 1803                    station->
m_groupsTable[groupId].m_ratesTable[rateId].successHist = 0;
 
 1804                    station->
m_groupsTable[groupId].m_ratesTable[rateId].attemptHist = 0;
 
 1805                    station->
m_groupsTable[groupId].m_ratesTable[rateId].throughput = 0;
 
 1806                    station->
m_groupsTable[groupId].m_ratesTable[rateId].perfectTxTime =
 
 1808                    station->
m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 0;
 
 1809                    station->
m_groupsTable[groupId].m_ratesTable[rateId].adjustedRetryCount = 0;
 
 1817    if (noSupportedGroupFound)
 
 
 1832    if (!station->
m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated)
 
 
 1840                                            std::size_t groupId,
 
 1851    if (station->
m_groupsTable[groupId].m_ratesTable[rateId].ewmaProb < 1)
 
 1853        station->
m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 1;
 
 1857        station->
m_groupsTable[groupId].m_ratesTable[rateId].retryCount = 2;
 
 1858        station->
m_groupsTable[groupId].m_ratesTable[rateId].retryUpdated = 
true;
 
 1871        cwTime = (cw / 2) * slotTime;
 
 1872        cw = 
Min((cw + 1) * 2, cwMax);
 
 1873        cwTime += (cw / 2) * slotTime;
 
 1874        cw = 
Min((cw + 1) * 2, cwMax);
 
 1877        txTime = cwTime + 2 * (dataTxTime + ackTime);
 
 1883            cwTime = (cw / 2) * slotTime;
 
 1884            cw = 
Min((cw + 1) * 2, cwMax);
 
 1887            txTime += cwTime + ackTime + dataTxTime;
 
 1889                 (++station->
m_groupsTable[groupId].m_ratesTable[rateId].retryCount < 7));
 
 
 1904    diff = currentProb - ewmaProb;
 
 1905    incr = (100 - weight) * diff / 100;
 
 1906    tmp = oldEwmsd * oldEwmsd;
 
 1907    tmp = weight * (tmp + diff * incr) / 100;
 
 
 1925        for (uint8_t i = 0; i < numSampleRates; i++)
 
 1932            newIndex = (i + uv) % numSampleRates;
 
 
 1949        std::ostringstream tmp;
 
 1951        station->
m_statsFile.open(tmp.str(), std::ios::out);
 
 1955        << 
"               best   ____________rate__________    ________statistics________    " 
 1956           "________last_______    ______sum-of________\n" 
 1957        << 
" mode guard #  rate  [name   idx airtime  max_tp]  [avg(tp) avg(prob) sd(prob)]  " 
 1958           "[prob.|retry|suc|att]  [#success | #attempts]\n";
 
 1964    station->
m_statsFile << 
"\nTotal packet count::    ideal " 
 
 1975                                 std::size_t groupId,
 
 1981    for (uint8_t i = 0; i < numRates; i++)
 
 1993            const auto idx = 
GetIndex(groupId, i);
 
 1994            if (idx == maxTpRate)
 
 2002            if (idx == maxTpRate2)
 
 2010            if (idx == maxProbRate)
 
 2021                of << std::setw(4) << 
"   MCS" 
 2028                of << std::setw(7) << 
"   MCS" << +i << 
"/" << 
static_cast<int>(group.
streams);
 
 2031            of << 
"  " << std::setw(3) << idx << 
"  ";
 
 2040               << std::setw(7) << station->
m_groupsTable[groupId].m_ratesTable[i].throughput / 100
 
 2041               << 
"   " << std::setw(7) << station->
m_groupsTable[groupId].m_ratesTable[i].ewmaProb
 
 2042               << 
"  " << std::setw(7) << station->
m_groupsTable[groupId].m_ratesTable[i].ewmsdProb
 
 2043               << 
"  " << std::setw(7) << station->
m_groupsTable[groupId].m_ratesTable[i].prob
 
 2044               << 
"  " << std::setw(2) << station->
m_groupsTable[groupId].m_ratesTable[i].retryCount
 
 2045               << 
"   " << std::setw(3)
 
 2046               << station->
m_groupsTable[groupId].m_ratesTable[i].prevNumRateSuccess << 
"  " 
 2047               << std::setw(3) << station->
m_groupsTable[groupId].m_ratesTable[i].prevNumRateAttempt
 
 2048               << 
"   " << std::setw(9)
 
 2049               << station->
m_groupsTable[groupId].m_ratesTable[i].successHist << 
"   " 
 2050               << std::setw(9) << station->
m_groupsTable[groupId].m_ratesTable[i].attemptHist
 
 
 2085    const auto it = std::find(standardInfos.guardIntervals.cbegin(),
 
 2086                              standardInfos.guardIntervals.cend(),
 
 2088    const auto giIndex = std::distance(standardInfos.guardIntervals.cbegin(), it);
 
 2089    const auto widthIndex = std::log2(chWidth / 
MHz_u{20});
 
 2090    return (standardInfos.maxStreams * standardInfos.guardIntervals.size() * widthIndex) +
 
 2091           (standardInfos.maxStreams * giIndex) + streams - 1;
 
 
 2098    const auto numWidths = std::log2(standardInfos.maxWidth / 
MHz_u{20}) + 1;
 
 2099    return numWidths * standardInfos.guardIntervals.size() * standardInfos.maxStreams;
 
 
 2115    return allHtGroups + vhtGroupId;
 
 
 2127    return allHtGroups + allVhtGroups + heGroupId;
 
 
 2140    return allHtGroups + allVhtGroups + allHeGroups + ehtGroupId;
 
 
 2170    std::size_t groupId = 0;
 
 2172    while (groupId < m_numGroups && !station->m_groupsTable[groupId].m_supported)
 
 2176    while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
 
 2181              station->
m_groupsTable[groupId].m_ratesTable[rateId].supported);
 
 
 2191    while (rateId < m_numRates && !station->m_groupsTable[groupId].m_ratesTable[rateId].supported)
 
 2196              station->
m_groupsTable[groupId].m_ratesTable[rateId].supported);
 
 
 2204    WifiModeList mcsList(phyMcsList.cbegin(), phyMcsList.cend());
 
 
AttributeValue implementation for Boolean.
Implementation of Minstrel-HT Rate Control Algorithm.
static TypeId GetTypeId()
Get the type ID.
uint32_t CountRetries(MinstrelHtWifiRemoteStation *station)
Count retries.
void StatsDump(MinstrelHtWifiRemoteStation *station, std::size_t groupId, std::ofstream &of)
Print group statistics.
uint32_t m_frameLength
Frame length used to calculate modes TxTime in bytes.
void InitSampleTable(MinstrelHtWifiRemoteStation *station)
Initialize Sample Table.
bool m_printStats
If statistics table should be printed.
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model.
void DoReportRxOk(WifiRemoteStation *station, double rxSnr, WifiMode txMode) override
This method is a pure virtual method that must be implemented by the sub-class.
void 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.
WifiTxVector DoGetRtsTxVector(WifiRemoteStation *station) override
Time GetFirstMpduTxTime(std::size_t groupId, WifiMode mode) const
Obtain the TxTime saved in the group information.
MinstrelMcsGroups m_minstrelGroups
Global array for groups information.
void SetNextSample(MinstrelHtWifiRemoteStation *station)
Set the next sample from Sample Table.
uint8_t m_numRates
Number of rates per group Minstrel should consider.
uint16_t UpdateRateAfterAllowedWidth(uint16_t txRate, MHz_u allowedWidth)
Given the index of the current TX rate, check whether the channel width is not greater than the given...
uint8_t m_nSampleCol
Number of sample columns.
std::list< Ptr< WifiMpdu > > DoGetMpdusToDropOnTxFailure(WifiRemoteStation *station, Ptr< WifiPsdu > psdu) override
Find the MPDUs to drop (possibly based on their frame retry count) in the given PSDU,...
void RateInit(MinstrelHtWifiRemoteStation *station)
Initialize Minstrel Table.
void SetBestStationThRates(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxTpRate or maxTp2Rate if is better than current values.
~MinstrelHtWifiManager() override
void AddMpduTxTime(std::size_t groupId, WifiMode mode, Time t)
Save a TxTime to the vector of groups.
void PrintTable(MinstrelHtWifiRemoteStation *station)
Printing Minstrel Table.
std::size_t GetHeGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the groupId of an HE MCS with the given number of streams, GI and channel width used.
double CalculateEwmsd(double oldEwmsd, double currentProb, double ewmaProb, double weight)
Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation.
void DoReportDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void SetBestProbabilityRate(MinstrelHtWifiRemoteStation *station, uint16_t index)
Set index rate as maxProbRate if it is better than current value.
void AddFirstMpduTxTime(std::size_t groupId, WifiMode mode, Time t)
Save a TxTime to the vector of groups.
double CalculateThroughput(MinstrelHtWifiRemoteStation *station, std::size_t groupId, uint8_t rateId, double ewmaProb)
Return the average throughput of the MCS defined by groupId and rateId.
Time m_updateStats
How frequent do we calculate the stats.
Time GetMpduTxTime(std::size_t groupId, WifiMode mode) const
Obtain the TxTime saved in the group information.
TracedValue< uint64_t > m_currentRate
Trace rate changes.
uint16_t GetLowestIndex(MinstrelHtWifiRemoteStation *station)
Returns the lowest global index of the rates supported by the station.
void DoInitialize() override
Initialize() implementation.
bool ShouldAddMcsToGroup(WifiMode mode, std::size_t groupId)
Check whether a given MCS mode should be added to a given group.
std::size_t GetGroupId(uint16_t index)
Return the groupId from the global index.
std::size_t GetIdInGroup(WifiModulationClass mc, uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the Id of a MCS of a given modulation class with the given number of streams,...
WifiTxVector DoGetDataTxVector(WifiRemoteStation *station, MHz_u allowedWidth) override
void CheckInit(MinstrelHtWifiRemoteStation *station)
Check for initializations.
bool DoNeedRetransmission(WifiRemoteStation *st, Ptr< const Packet > packet, bool normally)
std::size_t GetNumGroups(WifiModulationClass mc)
Returns the number of groups for a given modulation class.
void UpdateRetry(MinstrelHtWifiRemoteStation *station)
Update the number of retries and reset accordingly.
void CalculateRetransmits(MinstrelHtWifiRemoteStation *station, uint16_t index)
Calculate the number of retransmissions to set for the index rate.
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...
std::size_t GetVhtGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the groupId of a VHT MCS with the given number of streams, GI and channel width used.
bool IsValidMcs(uint8_t streams, MHz_u chWidth, WifiMode mode)
Check the validity of a combination of number of streams, chWidth and mode.
std::size_t GetEhtGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the groupId of an EHT MCS with the given number of streams, GI and channel width used.
void InitializeGroups(WifiModulationClass mc)
Initialize all groups belonging to a given modulation class.
uint8_t m_ewmaLevel
Exponential weighted moving average level (or coefficient).
uint16_t FindRate(MinstrelHtWifiRemoteStation *station)
Find a rate to use from Minstrel Table.
uint8_t m_lookAroundRate
The % to try other rates than our current rate.
std::size_t GetHtGroupId(uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the groupId of an HT MCS with the given number of streams, GI and channel width used.
std::size_t m_numGroups
Number of groups Minstrel should consider.
Time CalculateMpduTxDuration(uint8_t streams, Time gi, MHz_u chWidth, WifiMode mode, MpduType mpduType)
Estimates the TxTime of a frame with a given mode and group (stream, guard interval and channel width...
void UpdateRate(MinstrelHtWifiRemoteStation *station)
Update rate.
uint8_t GetRateId(uint16_t index)
Return the rateId inside a group, from the global index.
Time m_legacyUpdateStats
How frequent do we calculate the stats for legacy MinstrelWifiManager.
WifiModeList GetDeviceMcsList(WifiModulationClass mc) const
Returns a list of only the MCS supported by the device for a given modulation class.
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.
Ptr< UniformRandomVariable > m_uniformRandomVariable
Provides uniform random variables.
uint16_t GetNextSample(MinstrelHtWifiRemoteStation *station)
Getting the next sample from Sample Table.
uint16_t GetIndex(std::size_t groupId, uint8_t rateId)
Returns the global index corresponding to the groupId and rateId.
void UpdateStats(MinstrelHtWifiRemoteStation *station)
Update the Minstrel Table.
WifiRemoteStation * DoCreateStation() const override
Ptr< MinstrelWifiManager > m_legacyManager
Pointer to an instance of MinstrelWifiManager.
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...
void DoReportFinalDataFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void UpdatePacketCounters(MinstrelHtWifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus)
Update the number of sample count variables.
void DoReportFinalRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
std::size_t GetGroupIdForType(McsGroupType type, uint8_t streams, Time guardInterval, MHz_u chWidth)
Returns the group ID of an MCS of a given group type with the given number of streams,...
bool m_useLatestAmendmentOnly
Flag if only the latest supported amendment by both peers should be used.
void DoReportRtsFailed(WifiRemoteStation *station) override
This method is a pure virtual method that must be implemented by the sub-class.
void DoReportAmpduTxStatus(WifiRemoteStation *station, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus, double rxSnr, double dataSnr, MHz_u dataChannelWidth, uint8_t dataNss) override
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
Simulation virtual time values and global simulation resolution.
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
AttributeValue implementation for Time.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Hold an unsigned integer type.
represent a single transmission mode
WifiModulationClass GetModulationClass() const
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
uint8_t GetMcsValue() const
static Time GetPayloadDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, MpduType mpdutype=NORMAL_MPDU, uint16_t staId=SU_STA_ID)
Time GetSlot() const
Return the slot duration for this PHY.
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
MHz_u GetTxBandwidth(WifiMode mode, MHz_u maxAllowedBandWidth=MHz_u{ std::numeric_limits< double >::max()}) const
Get the bandwidth for a transmission occurring on the current operating channel and using the given W...
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
std::list< WifiMode > GetMcsList() const
The WifiPhy::GetMcsList() method is used (e.g., by a WifiRemoteStationManager) to determine the set o...
std::list< WifiMode > GetModeList() const
The WifiPhy::GetModeList() method is used (e.g., by a WifiRemoteStationManager) to determine the set ...
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
hold a list of per-remote-station state.
uint8_t GetNumberOfSupportedStreams(Mac48Address address) const
Return the number of spatial streams supported by the station.
uint8_t GetNess(const WifiRemoteStation *station) const
uint8_t GetNBasicModes() const
Return the number of basic modes we support.
Time GetGuardInterval() const
Return the shortest supported HE guard interval duration.
uint8_t GetDefaultTxPowerLevel() const
Ptr< WifiPhy > GetPhy() const
Return the WifiPhy.
MHz_u GetChannelWidth(const WifiRemoteStation *station) const
Return the channel width supported by the station.
Ptr< const He6GhzBandCapabilities > GetStationHe6GhzCapabilities(const Mac48Address &from) const
Return the HE 6 GHz Band Capabilities sent by a remote 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...
bool GetEhtSupported() const
Return whether the device has EHT capability support enabled.
Ptr< WifiMac > GetMac() const
Return the WifiMac.
uint8_t GetNumberOfAntennas() const
uint8_t GetNMcsSupported(Mac48Address address) const
Return the number of MCS supported by the station.
WifiMode GetBasicMode(uint8_t i) const
Return a basic mode from the set of basic modes.
bool GetShortGuardIntervalSupported() const
Return whether the device has SGI support enabled.
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...
WifiMode GetMcsSupported(const WifiRemoteStation *station, uint8_t i) const
Return the WifiMode supported by the specified station at the specified index.
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.
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...
bool IsValid(WifiPhyBand band=WIFI_PHY_BAND_UNSPECIFIED) const
The standard disallows certain combinations of WifiMode, number of spatial streams,...
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetNss(uint8_t nss)
Sets the number of Nss.
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,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Ptr< const AttributeChecker > MakeUintegerChecker()
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiModulationClass
This enumeration defines the modulation classes per (Table 10-6 "Modulation classes"; IEEE 802....
MpduType
The type of an MPDU.
@ WIFI_MOD_CLASS_HT
HT (Clause 19)
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ FIRST_MPDU_IN_AGGREGATE
The MPDU is the first aggregate in an A-MPDU with multiple MPDUs, but is not the last aggregate.
@ MIDDLE_MPDU_IN_AGGREGATE
The MPDU is part of an A-MPDU with multiple MPDUs, but is neither the first nor the last aggregate.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
std::vector< RateInfo > MinstrelRate
Data structure for a Minstrel Rate table A vector of a struct RateInfo.
std::vector< McsGroup > MinstrelMcsGroups
Data structure for a table of group definitions.
McsGroupType
Available MCS group types.
@ WIFI_MINSTREL_GROUP_VHT
@ WIFI_MINSTREL_GROUP_EHT
const std::map< WifiModulationClass, MinstrelHtWifiManager::StandardInfo > minstrelHtStandardInfos
standard information for each modulation class
double MHz_u
MHz weak type.
Time GetEstimatedAckTxTime(const WifiTxVector &txVector)
std::vector< MinstrelHtRateInfo > MinstrelHtRate
Data structure for a Minstrel Rate table.
std::vector< WifiMode > WifiModeList
In various parts of the code, folk are interested in maintaining a list of transmission modes.
std::vector< std::vector< uint8_t > > SampleRate
Data structure for a Sample Rate table A vector of a vector uint8_t.
std::vector< GroupInfo > McsGroupData
Data structure for a table of groups.
WifiPreamble GetPreambleForTransmission(WifiModulationClass modulation, bool useShortPreamble)
Return the preamble to be used for the transmission.
A struct to contain information of a group.
MinstrelHtRate m_ratesTable
Information about rates of this group.
uint16_t m_maxTpRate2
The second max throughput rate of this group in bps.
uint16_t m_maxProbRate
The highest success probability rate of this group in bps.
uint16_t m_maxTpRate
The max throughput rate of this group in bps.
Data structure to contain the information that defines a group.
MHz_u chWidth
channel width
Time gi
guard interval duration
McsGroupType type
identifies the group,
bool isSupported
flag whether group is supported
uint8_t streams
number of spatial streams
A struct to contain all statistics information related to a data rate.
double ewmaProb
Exponential weighted moving average of probability.
MinstrelHtWifiRemoteStation structure.
McsGroupData m_groupsTable
Table of groups with stats.
uint32_t m_sampleCount
Max number of samples per update interval.
uint8_t m_sampleGroup
The group that the sample rate belongs to.
uint32_t m_ampduPacketCount
Number of A-MPDUs transmitted.
uint32_t m_numSamplesSlow
Number of times a slow rate was sampled.
uint32_t m_sampleTries
Number of sample tries after waiting sampleWait.
std::ofstream m_statsFile
File where statistics table is written.
uint32_t m_sampleWait
How many transmission attempts to wait until a new sample.
bool m_isHt
If the station is HT capable.
uint32_t m_avgAmpduLen
Average number of MPDUs in an A-MPDU.
uint32_t m_ampduLen
Number of MPDUs in an A-MPDU.
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
uint8_t m_index
vector index
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
uint16_t m_maxTpRate
the current throughput rate in bps
uint8_t m_nModes
number of modes supported
SampleRate m_sampleTable
sample table
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
hold per-remote-station state.
WifiRemoteStationState * m_state
Remote station state.
Mac48Address m_address
Mac48Address of the remote station.
void CalculateThroughput()
Calculate the throughput.