src/devices/wifi/minstrel-wifi-manager.cc
author Duy Nguyen <duy@soe.ucsc.edu>
Thu Aug 13 08:45:47 2009 +0200 (2009-08-13)
changeset 4703 e1259e2fdaad
child 4725 4e068296f09f
permissions -rw-r--r--
add an implementation of the minstrel rate control algorithm
duy@4703
     1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
duy@4703
     2
/*
duy@4703
     3
 * Copyright (c) 2009 Duy Nguyen 
duy@4703
     4
 *
duy@4703
     5
 * This program is free software; you can redistribute it and/or modify
duy@4703
     6
 * it under the terms of the GNU General Public License version 2 as
duy@4703
     7
 * published by the Free Software Foundation;
duy@4703
     8
 *
duy@4703
     9
 * This program is distributed in the hope that it will be useful,
duy@4703
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
duy@4703
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
duy@4703
    12
 * GNU General Public License for more details.
duy@4703
    13
 *
duy@4703
    14
 * You should have received a copy of the GNU General Public License
duy@4703
    15
 * along with this program; if not, write to the Free Software
duy@4703
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
duy@4703
    17
 *
duy@4703
    18
 * Author: Duy Nguyen <duy@soe.ucsc.edu>
duy@4703
    19
 * 
duy@4703
    20
 * Some Comments: 
duy@4703
    21
 * 
duy@4703
    22
 * 1) Segment Size is declared for completeness but not used  because it has 
duy@4703
    23
 *    to do more with the requirement of the specific hardware.
duy@4703
    24
 *
duy@4703
    25
 * 2) By default, Minstrel applies the multi-rate retry(the core of Minstrel 
duy@4703
    26
 *    algorithm). Otherwise, please use ConstantRateWifiManager instead.
duy@4703
    27
 *
duy@4703
    28
 * http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/minstrel
duy@4703
    29
 */
duy@4703
    30
duy@4703
    31
duy@4703
    32
duy@4703
    33
#include "minstrel-wifi-manager.h"
duy@4703
    34
#include "wifi-phy.h"
duy@4703
    35
#include "ns3/random-variable.h"
duy@4703
    36
#include "ns3/simulator.h"
duy@4703
    37
#include "ns3/log.h"
duy@4703
    38
#include "ns3/uinteger.h"
duy@4703
    39
#include "ns3/double.h"
duy@4703
    40
#include "ns3/wifi-mac.h"
duy@4703
    41
#include "ns3/assert.h"
duy@4703
    42
#include <vector>
duy@4703
    43
duy@4703
    44
NS_LOG_COMPONENT_DEFINE ("MinstrelWifiManager");
duy@4703
    45
duy@4703
    46
duy@4703
    47
namespace ns3 {
duy@4703
    48
duy@4703
    49
NS_OBJECT_ENSURE_REGISTERED (MinstrelWifiManager);
duy@4703
    50
duy@4703
    51
TypeId
duy@4703
    52
MinstrelWifiManager::GetTypeId (void)
duy@4703
    53
{
duy@4703
    54
  static TypeId tid = TypeId ("ns3::MinstrelWifiManager")
duy@4703
    55
    .SetParent<WifiRemoteStationManager> ()
duy@4703
    56
    .AddConstructor<MinstrelWifiManager> ()
duy@4703
    57
    .AddAttribute ("UpdateStatistics",
duy@4703
    58
                   "The interval between updating statistics table ",
duy@4703
    59
                   TimeValue (Seconds (0.1)),
duy@4703
    60
                   MakeTimeAccessor (&MinstrelWifiManager::m_updateStats),
duy@4703
    61
                   MakeTimeChecker ())
duy@4703
    62
    .AddAttribute ("LookAroundRate", 
duy@4703
    63
                   "the percentage to try other rates",
duy@4703
    64
                   DoubleValue (10),
duy@4703
    65
                   MakeDoubleAccessor (&MinstrelWifiManager::m_lookAroundRate),
duy@4703
    66
                   MakeDoubleChecker<double> ())
duy@4703
    67
    .AddAttribute ("EWMA", 
duy@4703
    68
                   "EWMA level",
duy@4703
    69
                   DoubleValue (75),
duy@4703
    70
                   MakeDoubleAccessor (&MinstrelWifiManager::m_ewmaLevel),
duy@4703
    71
                   MakeDoubleChecker<double> ())
duy@4703
    72
    .AddAttribute ("SegmentSize",
duy@4703
    73
                   "The largest allowable segment size packet",
duy@4703
    74
                   DoubleValue (6000),
duy@4703
    75
                   MakeDoubleAccessor (&MinstrelWifiManager::m_segmentSize),
duy@4703
    76
                   MakeDoubleChecker <double> ())
duy@4703
    77
    .AddAttribute ("SampleColumn",
duy@4703
    78
                   "The number of columns used for sampling",
duy@4703
    79
                   DoubleValue (10),
duy@4703
    80
                   MakeDoubleAccessor (&MinstrelWifiManager::m_sampleCol),
duy@4703
    81
                   MakeDoubleChecker <double> ())
duy@4703
    82
    .AddAttribute ("PacketLength",
duy@4703
    83
                   "The packet length used for calculating mode TxTime",
duy@4703
    84
                   DoubleValue (1200),
duy@4703
    85
                   MakeDoubleAccessor (&MinstrelWifiManager::m_pktLen),
duy@4703
    86
                   MakeDoubleChecker <double> ())
duy@4703
    87
    ;
duy@4703
    88
  return tid;
duy@4703
    89
}
duy@4703
    90
duy@4703
    91
MinstrelWifiManager::MinstrelWifiManager ()
duy@4703
    92
{}
duy@4703
    93
duy@4703
    94
MinstrelWifiManager::~MinstrelWifiManager ()
duy@4703
    95
{}
duy@4703
    96
duy@4703
    97
void
duy@4703
    98
MinstrelWifiManager::SetupPhy (Ptr<WifiPhy> phy)
duy@4703
    99
{
duy@4703
   100
  uint32_t nModes = phy->GetNModes ();
duy@4703
   101
  for (uint32_t i = 0; i < nModes; i++)
duy@4703
   102
    {
duy@4703
   103
      WifiMode mode = phy->GetMode (i);
duy@4703
   104
      AddCalcTxTime (mode, phy->CalculateTxDuration (m_pktLen, mode, WIFI_PREAMBLE_LONG));
duy@4703
   105
    }
duy@4703
   106
  WifiRemoteStationManager::SetupPhy (phy);
duy@4703
   107
}
duy@4703
   108
duy@4703
   109
WifiRemoteStation *
duy@4703
   110
MinstrelWifiManager::CreateStation (void)
duy@4703
   111
{
duy@4703
   112
  return new MinstrelWifiRemoteStation (this);
duy@4703
   113
}
duy@4703
   114
duy@4703
   115
Time
duy@4703
   116
MinstrelWifiManager::GetCalcTxTime (WifiMode mode) const
duy@4703
   117
{
duy@4703
   118
duy@4703
   119
  for (TxTime::const_iterator i = m_calcTxTime.begin (); i != m_calcTxTime.end (); i++)
duy@4703
   120
    {
duy@4703
   121
      if (mode == i->second)
duy@4703
   122
        {
duy@4703
   123
          return i->first;
duy@4703
   124
        }
duy@4703
   125
    }
duy@4703
   126
  NS_ASSERT (false);
duy@4703
   127
  return Seconds (0);
duy@4703
   128
}
duy@4703
   129
duy@4703
   130
void
duy@4703
   131
MinstrelWifiManager::AddCalcTxTime (WifiMode mode, Time t)
duy@4703
   132
{
duy@4703
   133
  m_calcTxTime.push_back (std::make_pair (t, mode));
duy@4703
   134
}
duy@4703
   135
duy@4703
   136
MinstrelWifiRemoteStation::MinstrelWifiRemoteStation (Ptr<MinstrelWifiManager> stations)
duy@4703
   137
  :m_stations (stations),
duy@4703
   138
  m_nextStatsUpdate (Simulator::Now () + stations->m_updateStats),
duy@4703
   139
  m_col (0), 
duy@4703
   140
  m_index (0), 
duy@4703
   141
  m_maxTpRate (0), 
duy@4703
   142
  m_maxTpRate2 (0), 
duy@4703
   143
  m_maxProbRate (0),
duy@4703
   144
  m_packetCount (0), 
duy@4703
   145
  m_sampleCount (0), 
duy@4703
   146
  m_isSampling (false), 
duy@4703
   147
  m_sampleRate (0), 
duy@4703
   148
  m_sampleRateSlower (false),
duy@4703
   149
  m_currentRate (0),
duy@4703
   150
  m_shortRetry (0),
duy@4703
   151
  m_longRetry (0),
duy@4703
   152
  m_retry (0),
duy@4703
   153
  m_err (0),
duy@4703
   154
  m_txrate (0),
duy@4703
   155
  m_initialized (false)
duy@4703
   156
{}
duy@4703
   157
duy@4703
   158
MinstrelWifiRemoteStation::~MinstrelWifiRemoteStation ()
duy@4703
   159
{}
duy@4703
   160
duy@4703
   161
void 
duy@4703
   162
MinstrelWifiRemoteStation::CheckInit(void)
duy@4703
   163
{
duy@4703
   164
  if (!m_initialized)
duy@4703
   165
    {
duy@4703
   166
      m_minstrelTable  =  MinstrelRate(GetNSupportedModes ());
duy@4703
   167
      m_sampleTable = SampleRate(GetNSupportedModes (), std::vector<uint32_t> (m_stations->m_sampleCol));
duy@4703
   168
      InitSampleTable ();
duy@4703
   169
      RateInit ();
duy@4703
   170
      m_initialized = true;
duy@4703
   171
    }
duy@4703
   172
}
duy@4703
   173
duy@4703
   174
void
duy@4703
   175
MinstrelWifiRemoteStation::DoReportRxOk (double rxSnr, WifiMode txMode)
duy@4703
   176
{
duy@4703
   177
  NS_LOG_DEBUG("DoReportRxOk m_txrate=" << m_txrate);
duy@4703
   178
}
duy@4703
   179
duy@4703
   180
void
duy@4703
   181
MinstrelWifiRemoteStation::DoReportRtsFailed (void)
duy@4703
   182
{
duy@4703
   183
  NS_LOG_DEBUG("DoReportRtsFailed m_txrate=" << m_txrate);
duy@4703
   184
duy@4703
   185
  m_shortRetry++;
duy@4703
   186
}
duy@4703
   187
duy@4703
   188
void
duy@4703
   189
MinstrelWifiRemoteStation::DoReportRtsOk (double ctsSnr, WifiMode ctsMode, double rtsSnr)
duy@4703
   190
{
duy@4703
   191
  NS_LOG_DEBUG ("self="<<this<<" rts ok");
duy@4703
   192
}
duy@4703
   193
duy@4703
   194
void
duy@4703
   195
MinstrelWifiRemoteStation::DoReportFinalRtsFailed (void)
duy@4703
   196
{
duy@4703
   197
  UpdateRetry ();
duy@4703
   198
  m_err++;
duy@4703
   199
}
duy@4703
   200
duy@4703
   201
void
duy@4703
   202
MinstrelWifiRemoteStation::DoReportDataFailed (void)
duy@4703
   203
{
duy@4703
   204
  CheckInit();
duy@4703
   205
duy@4703
   206
  m_longRetry++;
duy@4703
   207
duy@4703
   208
  NS_LOG_DEBUG ("DoReportDataFailed " << this << "\t rate " << m_txrate << "\tlongRetry \t" << m_longRetry);
duy@4703
   209
duy@4703
   210
  /// for normal rate, we're not currently sampling random rates
duy@4703
   211
  if (!m_isSampling)
duy@4703
   212
    {
duy@4703
   213
      /// use best throughput rate
duy@4703
   214
      if( m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
duy@4703
   215
        {
duy@4703
   216
          ;  ///<  there's still a few retries left
duy@4703
   217
        }
duy@4703
   218
duy@4703
   219
      /// use second best throughput rate
duy@4703
   220
      else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +  
duy@4703
   221
               m_minstrelTable[m_maxTpRate].adjustedRetryCount))
duy@4703
   222
        {
duy@4703
   223
          m_txrate = m_maxTpRate2;
duy@4703
   224
        }
duy@4703
   225
duy@4703
   226
      /// use best probability rate
duy@4703
   227
      else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +  
duy@4703
   228
               m_minstrelTable[m_maxTpRate2].adjustedRetryCount + 
duy@4703
   229
               m_minstrelTable[m_maxTpRate].adjustedRetryCount))
duy@4703
   230
        {
duy@4703
   231
          m_txrate = m_maxProbRate;
duy@4703
   232
        }
duy@4703
   233
duy@4703
   234
      /// use lowest base rate	
duy@4703
   235
      else if (m_longRetry > (m_minstrelTable[m_txrate].adjustedRetryCount +  
duy@4703
   236
               m_minstrelTable[m_maxTpRate2].adjustedRetryCount + 
duy@4703
   237
               m_minstrelTable[m_maxTpRate].adjustedRetryCount))
duy@4703
   238
        {
duy@4703
   239
          m_txrate = 0;
duy@4703
   240
        }
duy@4703
   241
    }
duy@4703
   242
duy@4703
   243
  /// for look-around rate, we're currently sampling random rates
duy@4703
   244
  else
duy@4703
   245
    {
duy@4703
   246
      /// current sampling rate is slower than the current best rate
duy@4703
   247
      if (m_sampleRateSlower)
duy@4703
   248
        {
duy@4703
   249
          /// use best throughput rate
duy@4703
   250
          if (m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
duy@4703
   251
            {
duy@4703
   252
              ;	///<  there are a few retries left
duy@4703
   253
            }
duy@4703
   254
duy@4703
   255
          ///	use random rate
duy@4703
   256
          else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount + 
duy@4703
   257
                   m_minstrelTable[m_maxTpRate].adjustedRetryCount))
duy@4703
   258
            {
duy@4703
   259
              m_txrate = m_sampleRate;
duy@4703
   260
            }
duy@4703
   261
duy@4703
   262
          /// use max probability rate
duy@4703
   263
          else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +  
duy@4703
   264
                   m_minstrelTable[m_sampleRate].adjustedRetryCount + 
duy@4703
   265
                   m_minstrelTable[m_maxTpRate].adjustedRetryCount ))
duy@4703
   266
            {
duy@4703
   267
              m_txrate = m_maxProbRate;
duy@4703
   268
            }
duy@4703
   269
duy@4703
   270
          /// use lowest base rate
duy@4703
   271
          else if (m_longRetry > (m_minstrelTable[m_txrate].adjustedRetryCount +  
duy@4703
   272
                   m_minstrelTable[m_sampleRate].adjustedRetryCount + 
duy@4703
   273
                   m_minstrelTable[m_maxTpRate].adjustedRetryCount)) 
duy@4703
   274
            {
duy@4703
   275
              m_txrate = 0;
duy@4703
   276
            }
duy@4703
   277
        }
duy@4703
   278
duy@4703
   279
        /// current sampling rate is better than current best rate 
duy@4703
   280
        else
duy@4703
   281
          {
duy@4703
   282
            /// use random rate
duy@4703
   283
            if (m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
duy@4703
   284
              {
duy@4703
   285
                ;  ///< keep using it
duy@4703
   286
              }
duy@4703
   287
duy@4703
   288
            /// use the best rate
duy@4703
   289
            else if (m_longRetry <= m_minstrelTable[m_txrate].adjustedRetryCount + 
duy@4703
   290
                     m_minstrelTable[m_sampleRate].adjustedRetryCount)
duy@4703
   291
              {
duy@4703
   292
                m_txrate = m_maxTpRate;
duy@4703
   293
              }
duy@4703
   294
duy@4703
   295
            /// use the best probability rate
duy@4703
   296
            else if (m_longRetry <= m_minstrelTable[m_txrate].adjustedRetryCount + 
duy@4703
   297
                     m_minstrelTable[m_maxTpRate].adjustedRetryCount +  
duy@4703
   298
                     m_minstrelTable[m_sampleRate].adjustedRetryCount)
duy@4703
   299
              {
duy@4703
   300
                m_txrate = m_maxProbRate;
duy@4703
   301
              }
duy@4703
   302
duy@4703
   303
            /// use the lowest base rate
duy@4703
   304
            else if (m_longRetry > m_minstrelTable[m_txrate].adjustedRetryCount + 
duy@4703
   305
                     m_minstrelTable[m_maxTpRate].adjustedRetryCount +  
duy@4703
   306
                     m_minstrelTable[m_sampleRate].adjustedRetryCount) 
duy@4703
   307
              {
duy@4703
   308
                m_txrate = 0;
duy@4703
   309
              }
duy@4703
   310
          }
duy@4703
   311
    }
duy@4703
   312
}
duy@4703
   313
duy@4703
   314
void
duy@4703
   315
MinstrelWifiRemoteStation::DoReportDataOk (double ackSnr, WifiMode ackMode, double dataSnr)
duy@4703
   316
{
duy@4703
   317
  m_isSampling = false;
duy@4703
   318
  m_sampleRateSlower=false;
duy@4703
   319
duy@4703
   320
  CheckInit ();
duy@4703
   321
duy@4703
   322
  m_minstrelTable[m_txrate].numRateSuccess++;
duy@4703
   323
  m_minstrelTable[m_txrate].numRateAttempt++;
duy@4703
   324
	
duy@4703
   325
  UpdateRetry ();
duy@4703
   326
duy@4703
   327
  m_minstrelTable[m_txrate].numRateAttempt += m_retry;
duy@4703
   328
  m_packetCount++;
duy@4703
   329
duy@4703
   330
  if (GetNSupportedModes () >= 1)
duy@4703
   331
    {
duy@4703
   332
      m_txrate = FindRate ();
duy@4703
   333
    }
duy@4703
   334
}
duy@4703
   335
duy@4703
   336
void
duy@4703
   337
MinstrelWifiRemoteStation::DoReportFinalDataFailed (void)
duy@4703
   338
{
duy@4703
   339
  NS_LOG_DEBUG ("DoReportFinalDataFailed m_txrate=" << m_txrate);
duy@4703
   340
duy@4703
   341
  m_isSampling = false;
duy@4703
   342
  m_sampleRateSlower=false;
duy@4703
   343
duy@4703
   344
  UpdateRetry ();
duy@4703
   345
duy@4703
   346
  m_minstrelTable[m_txrate].numRateAttempt += m_retry;
duy@4703
   347
  m_err++;
duy@4703
   348
duy@4703
   349
  if (GetNSupportedModes () >= 1)
duy@4703
   350
    {
duy@4703
   351
      m_txrate = FindRate ();
duy@4703
   352
    }
duy@4703
   353
}
duy@4703
   354
duy@4703
   355
void
duy@4703
   356
MinstrelWifiRemoteStation::UpdateRetry (void)
duy@4703
   357
{
duy@4703
   358
  m_retry = m_shortRetry + m_longRetry;
duy@4703
   359
  m_shortRetry = 0;
duy@4703
   360
  m_longRetry = 0;
duy@4703
   361
}
duy@4703
   362
duy@4703
   363
Ptr<WifiRemoteStationManager>
duy@4703
   364
MinstrelWifiRemoteStation::GetManager (void) const
duy@4703
   365
{
duy@4703
   366
  return m_stations;
duy@4703
   367
}
duy@4703
   368
duy@4703
   369
WifiMode
duy@4703
   370
MinstrelWifiRemoteStation::DoGetDataMode (uint32_t size)
duy@4703
   371
{
duy@4703
   372
  UpdateStats ();
duy@4703
   373
  if (!m_initialized)
duy@4703
   374
    {
duy@4703
   375
      CheckInit ();
duy@4703
   376
duy@4703
   377
      /// start the rate at half way
duy@4703
   378
      m_txrate = GetNSupportedModes () / 2;
duy@4703
   379
    }
duy@4703
   380
  return GetSupportedMode (m_txrate);
duy@4703
   381
}
duy@4703
   382
duy@4703
   383
WifiMode
duy@4703
   384
MinstrelWifiRemoteStation::DoGetRtsMode (void)
duy@4703
   385
{
duy@4703
   386
  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << m_txrate);
duy@4703
   387
duy@4703
   388
  UpdateStats ();
duy@4703
   389
  return GetSupportedMode (0);
duy@4703
   390
}
duy@4703
   391
duy@4703
   392
uint32_t 
duy@4703
   393
MinstrelWifiRemoteStation::GetNextSample ()
duy@4703
   394
{
duy@4703
   395
  uint32_t bitrate;
duy@4703
   396
  bitrate = m_sampleTable[m_index][m_col];
duy@4703
   397
  m_index++;
duy@4703
   398
duy@4703
   399
  /// bookeeping for m_index and m_col variables
duy@4703
   400
  if (m_index > (GetNSupportedModes () -2)) 
duy@4703
   401
    {
duy@4703
   402
      m_index =0;
duy@4703
   403
      m_col++;
duy@4703
   404
      if (m_col >= m_stations->m_sampleCol)
duy@4703
   405
        {
duy@4703
   406
          m_col = 0;
duy@4703
   407
        }
duy@4703
   408
    }
duy@4703
   409
  return bitrate;
duy@4703
   410
}
duy@4703
   411
duy@4703
   412
uint32_t
duy@4703
   413
MinstrelWifiRemoteStation::FindRate ()
duy@4703
   414
{
duy@4703
   415
  NS_LOG_DEBUG ("FindRate " << "packet=" << m_packetCount );
duy@4703
   416
duy@4703
   417
  if ((m_sampleCount + m_packetCount) == 0)
duy@4703
   418
    {
duy@4703
   419
      return 0;
duy@4703
   420
    }
duy@4703
   421
duy@4703
   422
duy@4703
   423
  uint32_t idx;
duy@4703
   424
duy@4703
   425
  /// for determining when to try a sample rate 
duy@4703
   426
  UniformVariable coinFlip (0, 100);
duy@4703
   427
duy@4703
   428
  /**
duy@4703
   429
   * if we are below the target of look around rate percentage, look around
duy@4703
   430
   * note: do it randomly by flipping a coin instead sampling 
duy@4703
   431
   * all at once until it reaches the look around rate
duy@4703
   432
   */
duy@4703
   433
  if ( (((100* m_sampleCount) / (m_sampleCount + m_packetCount )) < m_stations->m_lookAroundRate) &&
duy@4703
   434
     ((int)coinFlip.GetValue ()) % 2 == 1 )
duy@4703
   435
    {
duy@4703
   436
duy@4703
   437
      /// now go through the table and find an index rate
duy@4703
   438
      idx = GetNextSample	();
duy@4703
   439
			
duy@4703
   440
			
duy@4703
   441
      /**
duy@4703
   442
       * This if condition is used to make sure that we don't need to use
duy@4703
   443
       * the sample rate it is the same as our current rate
duy@4703
   444
       */
duy@4703
   445
      if (idx != m_maxTpRate && idx != m_txrate) 
duy@4703
   446
        {
duy@4703
   447
		
duy@4703
   448
          /// start sample count
duy@4703
   449
          m_sampleCount++;
duy@4703
   450
duy@4703
   451
          /// set flag that we are currently sampling
duy@4703
   452
          m_isSampling = true;
duy@4703
   453
duy@4703
   454
          /// bookeeping for resetting stuff
duy@4703
   455
          if (m_packetCount >= 10000) 
duy@4703
   456
            {
duy@4703
   457
              m_sampleCount = 0;
duy@4703
   458
              m_packetCount = 0;
duy@4703
   459
            }
duy@4703
   460
duy@4703
   461
          /// error check
duy@4703
   462
          if (idx >= GetNSupportedModes	() || idx < 0 )
duy@4703
   463
            {
duy@4703
   464
              NS_LOG_DEBUG ("ALERT!!! ERROR");
duy@4703
   465
            }
duy@4703
   466
duy@4703
   467
          /// set the rate that we're currently sampling
duy@4703
   468
          m_sampleRate = idx;
duy@4703
   469
duy@4703
   470
          if (m_sampleRate == m_maxTpRate)
duy@4703
   471
            {
duy@4703
   472
              m_sampleRate = m_maxTpRate2;
duy@4703
   473
            }
duy@4703
   474
duy@4703
   475
          /// is this rate slower than the current best rate
duy@4703
   476
          m_sampleRateSlower = (m_minstrelTable[idx].perfectTxTime > m_minstrelTable[m_maxTpRate].perfectTxTime);
duy@4703
   477
duy@4703
   478
          /// using the best rate instead
duy@4703
   479
          if (m_sampleRateSlower)
duy@4703
   480
            {
duy@4703
   481
              idx =  m_maxTpRate;
duy@4703
   482
            }
duy@4703
   483
        }
duy@4703
   484
			
duy@4703
   485
    } 
duy@4703
   486
duy@4703
   487
  ///	continue using the best rate
duy@4703
   488
  else
duy@4703
   489
    {
duy@4703
   490
      idx = m_maxTpRate; 
duy@4703
   491
    }
duy@4703
   492
duy@4703
   493
duy@4703
   494
  NS_LOG_DEBUG ("FindRate " << "sample rate=" << idx);
duy@4703
   495
duy@4703
   496
  return idx;
duy@4703
   497
}
duy@4703
   498
duy@4703
   499
void
duy@4703
   500
MinstrelWifiRemoteStation::UpdateStats ()
duy@4703
   501
{
duy@4703
   502
  if (Simulator::Now () <  m_nextStatsUpdate)
duy@4703
   503
    {
duy@4703
   504
      return;
duy@4703
   505
    }
duy@4703
   506
duy@4703
   507
  NS_LOG_DEBUG ("Updating stats="<<this);
duy@4703
   508
duy@4703
   509
  m_nextStatsUpdate = Simulator::Now () + m_stations->m_updateStats;
duy@4703
   510
duy@4703
   511
  Time txTime;
duy@4703
   512
  uint32_t tempProb;
duy@4703
   513
duy@4703
   514
  for (uint32_t i =0; i < GetNSupportedModes (); i++)
duy@4703
   515
    {        
duy@4703
   516
duy@4703
   517
      /// calculate the perfect tx time for this rate
duy@4703
   518
      txTime = m_minstrelTable[i].perfectTxTime;       
duy@4703
   519
duy@4703
   520
      /// just for initialization
duy@4703
   521
      if (txTime.GetMicroSeconds () == 0)
duy@4703
   522
        {
duy@4703
   523
          txTime = Seconds (1);
duy@4703
   524
        }
duy@4703
   525
duy@4703
   526
      NS_LOG_DEBUG ("m_txrate=" << m_txrate << "\t attempt=" << m_minstrelTable[i].numRateAttempt << "\t success=" << m_minstrelTable[i].numRateSuccess);
duy@4703
   527
duy@4703
   528
      /// if we've attempted something
duy@4703
   529
      if (m_minstrelTable[i].numRateAttempt)
duy@4703
   530
        {
duy@4703
   531
          /**
duy@4703
   532
           * calculate the probability of success
duy@4703
   533
           * assume probability scales from 0 to 18000
duy@4703
   534
           */
duy@4703
   535
          tempProb = (m_minstrelTable[i].numRateSuccess * 18000) / m_minstrelTable[i].numRateAttempt;
duy@4703
   536
duy@4703
   537
          /// bookeeping
duy@4703
   538
          m_minstrelTable[i].successHist += m_minstrelTable[i].numRateSuccess;
duy@4703
   539
          m_minstrelTable[i].attemptHist += m_minstrelTable[i].numRateAttempt;
duy@4703
   540
          m_minstrelTable[i].prob = tempProb;
duy@4703
   541
duy@4703
   542
          /// ewma probability
duy@4703
   543
          tempProb = ((tempProb * (100 - m_stations->m_ewmaLevel)) + (m_minstrelTable[i].ewmaProb * m_stations->m_ewmaLevel) )/100;
duy@4703
   544
duy@4703
   545
          m_minstrelTable[i].ewmaProb = tempProb;
duy@4703
   546
duy@4703
   547
          /// calculating throughput
duy@4703
   548
          m_minstrelTable[i].throughput = tempProb * (1000000 / txTime.GetMicroSeconds());
duy@4703
   549
duy@4703
   550
        }
duy@4703
   551
duy@4703
   552
      /// bookeeping
duy@4703
   553
      m_minstrelTable[i].prevNumRateAttempt= m_minstrelTable[i].numRateAttempt;
duy@4703
   554
      m_minstrelTable[i].prevNumRateSuccess = m_minstrelTable[i].numRateSuccess;
duy@4703
   555
      m_minstrelTable[i].numRateSuccess = 0;
duy@4703
   556
      m_minstrelTable[i].numRateAttempt = 0;
duy@4703
   557
duy@4703
   558
      /// Sample less often below 10% and  above 95% of success
duy@4703
   559
      if ((m_minstrelTable[i].ewmaProb > 17100) || (m_minstrelTable[i].ewmaProb < 1800)) 
duy@4703
   560
        {
duy@4703
   561
          /**
duy@4703
   562
           * retry count denotes the number of retries permitted for each rate
duy@4703
   563
           * # retry_count/2
duy@4703
   564
           */
duy@4703
   565
          m_minstrelTable[i].adjustedRetryCount = m_minstrelTable[i].retryCount >> 1;
duy@4703
   566
          if (m_minstrelTable[i].adjustedRetryCount > 2)
duy@4703
   567
            {
duy@4703
   568
              m_minstrelTable[i].adjustedRetryCount = 2 ;
duy@4703
   569
            }
duy@4703
   570
        }
duy@4703
   571
      else
duy@4703
   572
        {
duy@4703
   573
          m_minstrelTable[i].adjustedRetryCount = m_minstrelTable[i].retryCount;
duy@4703
   574
        }
duy@4703
   575
duy@4703
   576
      /// if it's 0 allow one retry limit
duy@4703
   577
      if (m_minstrelTable[i].adjustedRetryCount == 0)
duy@4703
   578
        {
duy@4703
   579
          m_minstrelTable[i].adjustedRetryCount = 1;
duy@4703
   580
        }
duy@4703
   581
    }
duy@4703
   582
duy@4703
   583
duy@4703
   584
  uint32_t max_prob = 0, index_max_prob =0, max_tp =0, index_max_tp=0, index_max_tp2=0;
duy@4703
   585
duy@4703
   586
  /// go find max throughput, second maximum throughput, high probability succ
duy@4703
   587
  for (uint32_t i =0; i < GetNSupportedModes (); i++) 
duy@4703
   588
    {
duy@4703
   589
      NS_LOG_DEBUG ("throughput" << m_minstrelTable[i].throughput << "\n ewma" << m_minstrelTable[i].ewmaProb);
duy@4703
   590
duy@4703
   591
      if (max_tp < m_minstrelTable[i].throughput) 
duy@4703
   592
        {
duy@4703
   593
          index_max_tp = i;
duy@4703
   594
          max_tp = m_minstrelTable[i].throughput;
duy@4703
   595
        }
duy@4703
   596
duy@4703
   597
      if (max_prob < m_minstrelTable[i].ewmaProb) 
duy@4703
   598
        {
duy@4703
   599
          index_max_prob = i;
duy@4703
   600
          max_prob = m_minstrelTable[i].ewmaProb;
duy@4703
   601
        }
duy@4703
   602
    }
duy@4703
   603
duy@4703
   604
duy@4703
   605
  max_tp = 0;
duy@4703
   606
  /// find the second highest max
duy@4703
   607
  for (uint32_t i =0; i < GetNSupportedModes (); i++) 
duy@4703
   608
    {
duy@4703
   609
      if ((i != index_max_tp) && (max_tp < m_minstrelTable[i].throughput))
duy@4703
   610
        {
duy@4703
   611
          index_max_tp2 = i;
duy@4703
   612
          max_tp = m_minstrelTable[i].throughput;
duy@4703
   613
        }
duy@4703
   614
    }
duy@4703
   615
duy@4703
   616
  m_maxTpRate = index_max_tp;
duy@4703
   617
  m_maxTpRate2 = index_max_tp2;
duy@4703
   618
  m_maxProbRate = index_max_prob;
duy@4703
   619
  m_currentRate = index_max_tp;
duy@4703
   620
duy@4703
   621
  if (index_max_tp > m_txrate)
duy@4703
   622
    {
duy@4703
   623
      m_txrate= index_max_tp;
duy@4703
   624
    }
duy@4703
   625
duy@4703
   626
  NS_LOG_DEBUG ("max tp="<< index_max_tp << "\nmax tp2="<< index_max_tp2<< "\nmax prob="<< index_max_prob);
duy@4703
   627
duy@4703
   628
  /// reset it
duy@4703
   629
  RateInit ();
duy@4703
   630
}
duy@4703
   631
duy@4703
   632
void
duy@4703
   633
MinstrelWifiRemoteStation::RateInit ()
duy@4703
   634
{
duy@4703
   635
  NS_LOG_DEBUG ("RateInit="<<this);
duy@4703
   636
duy@4703
   637
  for (uint32_t i = 0; i < GetNSupportedModes (); i++)
duy@4703
   638
    {
duy@4703
   639
      m_minstrelTable[i].numRateAttempt = 0;
duy@4703
   640
      m_minstrelTable[i].numRateSuccess = 0;
duy@4703
   641
      m_minstrelTable[i].prob = 0;
duy@4703
   642
      m_minstrelTable[i].ewmaProb = 0;
duy@4703
   643
      m_minstrelTable[i].prevNumRateAttempt = 0;
duy@4703
   644
      m_minstrelTable[i].prevNumRateSuccess = 0;
duy@4703
   645
      m_minstrelTable[i].successHist = 0;
duy@4703
   646
      m_minstrelTable[i].attemptHist = 0;
duy@4703
   647
      m_minstrelTable[i].throughput = 0;
duy@4703
   648
      m_minstrelTable[i].perfectTxTime = m_stations->GetCalcTxTime (GetSupportedMode (i));
duy@4703
   649
      m_minstrelTable[i].retryCount =1;
duy@4703
   650
      m_minstrelTable[i].adjustedRetryCount =1;
duy@4703
   651
    }
duy@4703
   652
}
duy@4703
   653
duy@4703
   654
void
duy@4703
   655
MinstrelWifiRemoteStation::InitSampleTable ()
duy@4703
   656
{
duy@4703
   657
  NS_LOG_DEBUG ("InitSampleTable="<<this);
duy@4703
   658
	
duy@4703
   659
  m_col = m_index = 0;
duy@4703
   660
duy@4703
   661
  /// for off-seting to make rates fall between 0 and numrates 
duy@4703
   662
  uint32_t numSampleRates= GetNSupportedModes () - 1;
duy@4703
   663
duy@4703
   664
  uint32_t newIndex;
duy@4703
   665
  for (uint32_t col = 0; col < m_stations->m_sampleCol; col++)
duy@4703
   666
    {
duy@4703
   667
      for (uint32_t i = 0; i < numSampleRates; i++ )
duy@4703
   668
        {
duy@4703
   669
duy@4703
   670
          /**
duy@4703
   671
           * The next two lines basically tries to generate a random number
duy@4703
   672
           * between 0 and the number of available rates 
duy@4703
   673
           */
duy@4703
   674
          UniformVariable uv (0, numSampleRates);
duy@4703
   675
          newIndex = (i + (uint32_t)uv.GetValue	()) % numSampleRates;	
duy@4703
   676
duy@4703
   677
          /// this loop is used for filling in other uninitilized places
duy@4703
   678
          while	(m_sampleTable[newIndex][col] != 0)
duy@4703
   679
            {
duy@4703
   680
              newIndex = (newIndex + 1)%GetNSupportedModes ();
duy@4703
   681
            }
duy@4703
   682
          m_sampleTable[newIndex][col] = i+1;
duy@4703
   683
duy@4703
   684
        }
duy@4703
   685
    }
duy@4703
   686
}
duy@4703
   687
duy@4703
   688
void
duy@4703
   689
MinstrelWifiRemoteStation::PrintSampleTable ()
duy@4703
   690
{
duy@4703
   691
  NS_LOG_DEBUG ("PrintSampleTable="<<this );
duy@4703
   692
duy@4703
   693
  uint32_t numSampleRates= GetNSupportedModes ();
duy@4703
   694
  for (uint32_t i=0; i < numSampleRates; i++)
duy@4703
   695
    {
duy@4703
   696
      for (uint32_t j=0; j < m_stations->m_sampleCol; j++)
duy@4703
   697
        {
duy@4703
   698
          std::cout << m_sampleTable[i][j] << "\t";
duy@4703
   699
        }
duy@4703
   700
      std::cout << std::endl;
duy@4703
   701
    }
duy@4703
   702
}
duy@4703
   703
	
duy@4703
   704
void
duy@4703
   705
MinstrelWifiRemoteStation::PrintTable ()
duy@4703
   706
{
duy@4703
   707
  NS_LOG_DEBUG ("PrintTable="<<this);
duy@4703
   708
duy@4703
   709
  for (uint32_t i=0; i < GetNSupportedModes (); i++)
duy@4703
   710
    {
duy@4703
   711
      std::cout << "index(" << i << ") = " << m_minstrelTable[i].perfectTxTime<< "\n";
duy@4703
   712
    }
duy@4703
   713
}
duy@4703
   714
duy@4703
   715
} //namespace ns3
duy@4703
   716
duy@4703
   717
duy@4703
   718
duy@4703
   719
duy@4703
   720