add an implementation of the minstrel rate control algorithm
authorDuy Nguyen <duy@soe.ucsc.edu>
Thu Aug 13 08:45:47 2009 +0200 (6 months ago)
changeset 4703e1259e2fdaad
parent 4702 e33a677e8864
child 4704 84b36a63dc23
add an implementation of the minstrel rate control algorithm
src/devices/wifi/minstrel-wifi-manager.cc
src/devices/wifi/minstrel-wifi-manager.h
src/devices/wifi/wscript
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/devices/wifi/minstrel-wifi-manager.cc	Thu Aug 13 08:45:47 2009 +0200
     1.3 @@ -0,0 +1,720 @@
     1.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
     1.5 +/*
     1.6 + * Copyright (c) 2009 Duy Nguyen 
     1.7 + *
     1.8 + * This program is free software; you can redistribute it and/or modify
     1.9 + * it under the terms of the GNU General Public License version 2 as
    1.10 + * published by the Free Software Foundation;
    1.11 + *
    1.12 + * This program is distributed in the hope that it will be useful,
    1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.15 + * GNU General Public License for more details.
    1.16 + *
    1.17 + * You should have received a copy of the GNU General Public License
    1.18 + * along with this program; if not, write to the Free Software
    1.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.20 + *
    1.21 + * Author: Duy Nguyen <duy@soe.ucsc.edu>
    1.22 + * 
    1.23 + * Some Comments: 
    1.24 + * 
    1.25 + * 1) Segment Size is declared for completeness but not used  because it has 
    1.26 + *    to do more with the requirement of the specific hardware.
    1.27 + *
    1.28 + * 2) By default, Minstrel applies the multi-rate retry(the core of Minstrel 
    1.29 + *    algorithm). Otherwise, please use ConstantRateWifiManager instead.
    1.30 + *
    1.31 + * http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/minstrel
    1.32 + */
    1.33 +
    1.34 +
    1.35 +
    1.36 +#include "minstrel-wifi-manager.h"
    1.37 +#include "wifi-phy.h"
    1.38 +#include "ns3/random-variable.h"
    1.39 +#include "ns3/simulator.h"
    1.40 +#include "ns3/log.h"
    1.41 +#include "ns3/uinteger.h"
    1.42 +#include "ns3/double.h"
    1.43 +#include "ns3/wifi-mac.h"
    1.44 +#include "ns3/assert.h"
    1.45 +#include <vector>
    1.46 +
    1.47 +NS_LOG_COMPONENT_DEFINE ("MinstrelWifiManager");
    1.48 +
    1.49 +
    1.50 +namespace ns3 {
    1.51 +
    1.52 +NS_OBJECT_ENSURE_REGISTERED (MinstrelWifiManager);
    1.53 +
    1.54 +TypeId
    1.55 +MinstrelWifiManager::GetTypeId (void)
    1.56 +{
    1.57 +  static TypeId tid = TypeId ("ns3::MinstrelWifiManager")
    1.58 +    .SetParent<WifiRemoteStationManager> ()
    1.59 +    .AddConstructor<MinstrelWifiManager> ()
    1.60 +    .AddAttribute ("UpdateStatistics",
    1.61 +                   "The interval between updating statistics table ",
    1.62 +                   TimeValue (Seconds (0.1)),
    1.63 +                   MakeTimeAccessor (&MinstrelWifiManager::m_updateStats),
    1.64 +                   MakeTimeChecker ())
    1.65 +    .AddAttribute ("LookAroundRate", 
    1.66 +                   "the percentage to try other rates",
    1.67 +                   DoubleValue (10),
    1.68 +                   MakeDoubleAccessor (&MinstrelWifiManager::m_lookAroundRate),
    1.69 +                   MakeDoubleChecker<double> ())
    1.70 +    .AddAttribute ("EWMA", 
    1.71 +                   "EWMA level",
    1.72 +                   DoubleValue (75),
    1.73 +                   MakeDoubleAccessor (&MinstrelWifiManager::m_ewmaLevel),
    1.74 +                   MakeDoubleChecker<double> ())
    1.75 +    .AddAttribute ("SegmentSize",
    1.76 +                   "The largest allowable segment size packet",
    1.77 +                   DoubleValue (6000),
    1.78 +                   MakeDoubleAccessor (&MinstrelWifiManager::m_segmentSize),
    1.79 +                   MakeDoubleChecker <double> ())
    1.80 +    .AddAttribute ("SampleColumn",
    1.81 +                   "The number of columns used for sampling",
    1.82 +                   DoubleValue (10),
    1.83 +                   MakeDoubleAccessor (&MinstrelWifiManager::m_sampleCol),
    1.84 +                   MakeDoubleChecker <double> ())
    1.85 +    .AddAttribute ("PacketLength",
    1.86 +                   "The packet length used for calculating mode TxTime",
    1.87 +                   DoubleValue (1200),
    1.88 +                   MakeDoubleAccessor (&MinstrelWifiManager::m_pktLen),
    1.89 +                   MakeDoubleChecker <double> ())
    1.90 +    ;
    1.91 +  return tid;
    1.92 +}
    1.93 +
    1.94 +MinstrelWifiManager::MinstrelWifiManager ()
    1.95 +{}
    1.96 +
    1.97 +MinstrelWifiManager::~MinstrelWifiManager ()
    1.98 +{}
    1.99 +
   1.100 +void
   1.101 +MinstrelWifiManager::SetupPhy (Ptr<WifiPhy> phy)
   1.102 +{
   1.103 +  uint32_t nModes = phy->GetNModes ();
   1.104 +  for (uint32_t i = 0; i < nModes; i++)
   1.105 +    {
   1.106 +      WifiMode mode = phy->GetMode (i);
   1.107 +      AddCalcTxTime (mode, phy->CalculateTxDuration (m_pktLen, mode, WIFI_PREAMBLE_LONG));
   1.108 +    }
   1.109 +  WifiRemoteStationManager::SetupPhy (phy);
   1.110 +}
   1.111 +
   1.112 +WifiRemoteStation *
   1.113 +MinstrelWifiManager::CreateStation (void)
   1.114 +{
   1.115 +  return new MinstrelWifiRemoteStation (this);
   1.116 +}
   1.117 +
   1.118 +Time
   1.119 +MinstrelWifiManager::GetCalcTxTime (WifiMode mode) const
   1.120 +{
   1.121 +
   1.122 +  for (TxTime::const_iterator i = m_calcTxTime.begin (); i != m_calcTxTime.end (); i++)
   1.123 +    {
   1.124 +      if (mode == i->second)
   1.125 +        {
   1.126 +          return i->first;
   1.127 +        }
   1.128 +    }
   1.129 +  NS_ASSERT (false);
   1.130 +  return Seconds (0);
   1.131 +}
   1.132 +
   1.133 +void
   1.134 +MinstrelWifiManager::AddCalcTxTime (WifiMode mode, Time t)
   1.135 +{
   1.136 +  m_calcTxTime.push_back (std::make_pair (t, mode));
   1.137 +}
   1.138 +
   1.139 +MinstrelWifiRemoteStation::MinstrelWifiRemoteStation (Ptr<MinstrelWifiManager> stations)
   1.140 +  :m_stations (stations),
   1.141 +  m_nextStatsUpdate (Simulator::Now () + stations->m_updateStats),
   1.142 +  m_col (0), 
   1.143 +  m_index (0), 
   1.144 +  m_maxTpRate (0), 
   1.145 +  m_maxTpRate2 (0), 
   1.146 +  m_maxProbRate (0),
   1.147 +  m_packetCount (0), 
   1.148 +  m_sampleCount (0), 
   1.149 +  m_isSampling (false), 
   1.150 +  m_sampleRate (0), 
   1.151 +  m_sampleRateSlower (false),
   1.152 +  m_currentRate (0),
   1.153 +  m_shortRetry (0),
   1.154 +  m_longRetry (0),
   1.155 +  m_retry (0),
   1.156 +  m_err (0),
   1.157 +  m_txrate (0),
   1.158 +  m_initialized (false)
   1.159 +{}
   1.160 +
   1.161 +MinstrelWifiRemoteStation::~MinstrelWifiRemoteStation ()
   1.162 +{}
   1.163 +
   1.164 +void 
   1.165 +MinstrelWifiRemoteStation::CheckInit(void)
   1.166 +{
   1.167 +  if (!m_initialized)
   1.168 +    {
   1.169 +      m_minstrelTable  =  MinstrelRate(GetNSupportedModes ());
   1.170 +      m_sampleTable = SampleRate(GetNSupportedModes (), std::vector<uint32_t> (m_stations->m_sampleCol));
   1.171 +      InitSampleTable ();
   1.172 +      RateInit ();
   1.173 +      m_initialized = true;
   1.174 +    }
   1.175 +}
   1.176 +
   1.177 +void
   1.178 +MinstrelWifiRemoteStation::DoReportRxOk (double rxSnr, WifiMode txMode)
   1.179 +{
   1.180 +  NS_LOG_DEBUG("DoReportRxOk m_txrate=" << m_txrate);
   1.181 +}
   1.182 +
   1.183 +void
   1.184 +MinstrelWifiRemoteStation::DoReportRtsFailed (void)
   1.185 +{
   1.186 +  NS_LOG_DEBUG("DoReportRtsFailed m_txrate=" << m_txrate);
   1.187 +
   1.188 +  m_shortRetry++;
   1.189 +}
   1.190 +
   1.191 +void
   1.192 +MinstrelWifiRemoteStation::DoReportRtsOk (double ctsSnr, WifiMode ctsMode, double rtsSnr)
   1.193 +{
   1.194 +  NS_LOG_DEBUG ("self="<<this<<" rts ok");
   1.195 +}
   1.196 +
   1.197 +void
   1.198 +MinstrelWifiRemoteStation::DoReportFinalRtsFailed (void)
   1.199 +{
   1.200 +  UpdateRetry ();
   1.201 +  m_err++;
   1.202 +}
   1.203 +
   1.204 +void
   1.205 +MinstrelWifiRemoteStation::DoReportDataFailed (void)
   1.206 +{
   1.207 +  CheckInit();
   1.208 +
   1.209 +  m_longRetry++;
   1.210 +
   1.211 +  NS_LOG_DEBUG ("DoReportDataFailed " << this << "\t rate " << m_txrate << "\tlongRetry \t" << m_longRetry);
   1.212 +
   1.213 +  /// for normal rate, we're not currently sampling random rates
   1.214 +  if (!m_isSampling)
   1.215 +    {
   1.216 +      /// use best throughput rate
   1.217 +      if( m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
   1.218 +        {
   1.219 +          ;  ///<  there's still a few retries left
   1.220 +        }
   1.221 +
   1.222 +      /// use second best throughput rate
   1.223 +      else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +  
   1.224 +               m_minstrelTable[m_maxTpRate].adjustedRetryCount))
   1.225 +        {
   1.226 +          m_txrate = m_maxTpRate2;
   1.227 +        }
   1.228 +
   1.229 +      /// use best probability rate
   1.230 +      else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +  
   1.231 +               m_minstrelTable[m_maxTpRate2].adjustedRetryCount + 
   1.232 +               m_minstrelTable[m_maxTpRate].adjustedRetryCount))
   1.233 +        {
   1.234 +          m_txrate = m_maxProbRate;
   1.235 +        }
   1.236 +
   1.237 +      /// use lowest base rate	
   1.238 +      else if (m_longRetry > (m_minstrelTable[m_txrate].adjustedRetryCount +  
   1.239 +               m_minstrelTable[m_maxTpRate2].adjustedRetryCount + 
   1.240 +               m_minstrelTable[m_maxTpRate].adjustedRetryCount))
   1.241 +        {
   1.242 +          m_txrate = 0;
   1.243 +        }
   1.244 +    }
   1.245 +
   1.246 +  /// for look-around rate, we're currently sampling random rates
   1.247 +  else
   1.248 +    {
   1.249 +      /// current sampling rate is slower than the current best rate
   1.250 +      if (m_sampleRateSlower)
   1.251 +        {
   1.252 +          /// use best throughput rate
   1.253 +          if (m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
   1.254 +            {
   1.255 +              ;	///<  there are a few retries left
   1.256 +            }
   1.257 +
   1.258 +          ///	use random rate
   1.259 +          else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount + 
   1.260 +                   m_minstrelTable[m_maxTpRate].adjustedRetryCount))
   1.261 +            {
   1.262 +              m_txrate = m_sampleRate;
   1.263 +            }
   1.264 +
   1.265 +          /// use max probability rate
   1.266 +          else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +  
   1.267 +                   m_minstrelTable[m_sampleRate].adjustedRetryCount + 
   1.268 +                   m_minstrelTable[m_maxTpRate].adjustedRetryCount ))
   1.269 +            {
   1.270 +              m_txrate = m_maxProbRate;
   1.271 +            }
   1.272 +
   1.273 +          /// use lowest base rate
   1.274 +          else if (m_longRetry > (m_minstrelTable[m_txrate].adjustedRetryCount +  
   1.275 +                   m_minstrelTable[m_sampleRate].adjustedRetryCount + 
   1.276 +                   m_minstrelTable[m_maxTpRate].adjustedRetryCount)) 
   1.277 +            {
   1.278 +              m_txrate = 0;
   1.279 +            }
   1.280 +        }
   1.281 +
   1.282 +        /// current sampling rate is better than current best rate 
   1.283 +        else
   1.284 +          {
   1.285 +            /// use random rate
   1.286 +            if (m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
   1.287 +              {
   1.288 +                ;  ///< keep using it
   1.289 +              }
   1.290 +
   1.291 +            /// use the best rate
   1.292 +            else if (m_longRetry <= m_minstrelTable[m_txrate].adjustedRetryCount + 
   1.293 +                     m_minstrelTable[m_sampleRate].adjustedRetryCount)
   1.294 +              {
   1.295 +                m_txrate = m_maxTpRate;
   1.296 +              }
   1.297 +
   1.298 +            /// use the best probability rate
   1.299 +            else if (m_longRetry <= m_minstrelTable[m_txrate].adjustedRetryCount + 
   1.300 +                     m_minstrelTable[m_maxTpRate].adjustedRetryCount +  
   1.301 +                     m_minstrelTable[m_sampleRate].adjustedRetryCount)
   1.302 +              {
   1.303 +                m_txrate = m_maxProbRate;
   1.304 +              }
   1.305 +
   1.306 +            /// use the lowest base rate
   1.307 +            else if (m_longRetry > m_minstrelTable[m_txrate].adjustedRetryCount + 
   1.308 +                     m_minstrelTable[m_maxTpRate].adjustedRetryCount +  
   1.309 +                     m_minstrelTable[m_sampleRate].adjustedRetryCount) 
   1.310 +              {
   1.311 +                m_txrate = 0;
   1.312 +              }
   1.313 +          }
   1.314 +    }
   1.315 +}
   1.316 +
   1.317 +void
   1.318 +MinstrelWifiRemoteStation::DoReportDataOk (double ackSnr, WifiMode ackMode, double dataSnr)
   1.319 +{
   1.320 +  m_isSampling = false;
   1.321 +  m_sampleRateSlower=false;
   1.322 +
   1.323 +  CheckInit ();
   1.324 +
   1.325 +  m_minstrelTable[m_txrate].numRateSuccess++;
   1.326 +  m_minstrelTable[m_txrate].numRateAttempt++;
   1.327 +	
   1.328 +  UpdateRetry ();
   1.329 +
   1.330 +  m_minstrelTable[m_txrate].numRateAttempt += m_retry;
   1.331 +  m_packetCount++;
   1.332 +
   1.333 +  if (GetNSupportedModes () >= 1)
   1.334 +    {
   1.335 +      m_txrate = FindRate ();
   1.336 +    }
   1.337 +}
   1.338 +
   1.339 +void
   1.340 +MinstrelWifiRemoteStation::DoReportFinalDataFailed (void)
   1.341 +{
   1.342 +  NS_LOG_DEBUG ("DoReportFinalDataFailed m_txrate=" << m_txrate);
   1.343 +
   1.344 +  m_isSampling = false;
   1.345 +  m_sampleRateSlower=false;
   1.346 +
   1.347 +  UpdateRetry ();
   1.348 +
   1.349 +  m_minstrelTable[m_txrate].numRateAttempt += m_retry;
   1.350 +  m_err++;
   1.351 +
   1.352 +  if (GetNSupportedModes () >= 1)
   1.353 +    {
   1.354 +      m_txrate = FindRate ();
   1.355 +    }
   1.356 +}
   1.357 +
   1.358 +void
   1.359 +MinstrelWifiRemoteStation::UpdateRetry (void)
   1.360 +{
   1.361 +  m_retry = m_shortRetry + m_longRetry;
   1.362 +  m_shortRetry = 0;
   1.363 +  m_longRetry = 0;
   1.364 +}
   1.365 +
   1.366 +Ptr<WifiRemoteStationManager>
   1.367 +MinstrelWifiRemoteStation::GetManager (void) const
   1.368 +{
   1.369 +  return m_stations;
   1.370 +}
   1.371 +
   1.372 +WifiMode
   1.373 +MinstrelWifiRemoteStation::DoGetDataMode (uint32_t size)
   1.374 +{
   1.375 +  UpdateStats ();
   1.376 +  if (!m_initialized)
   1.377 +    {
   1.378 +      CheckInit ();
   1.379 +
   1.380 +      /// start the rate at half way
   1.381 +      m_txrate = GetNSupportedModes () / 2;
   1.382 +    }
   1.383 +  return GetSupportedMode (m_txrate);
   1.384 +}
   1.385 +
   1.386 +WifiMode
   1.387 +MinstrelWifiRemoteStation::DoGetRtsMode (void)
   1.388 +{
   1.389 +  NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << m_txrate);
   1.390 +
   1.391 +  UpdateStats ();
   1.392 +  return GetSupportedMode (0);
   1.393 +}
   1.394 +
   1.395 +uint32_t 
   1.396 +MinstrelWifiRemoteStation::GetNextSample ()
   1.397 +{
   1.398 +  uint32_t bitrate;
   1.399 +  bitrate = m_sampleTable[m_index][m_col];
   1.400 +  m_index++;
   1.401 +
   1.402 +  /// bookeeping for m_index and m_col variables
   1.403 +  if (m_index > (GetNSupportedModes () -2)) 
   1.404 +    {
   1.405 +      m_index =0;
   1.406 +      m_col++;
   1.407 +      if (m_col >= m_stations->m_sampleCol)
   1.408 +        {
   1.409 +          m_col = 0;
   1.410 +        }
   1.411 +    }
   1.412 +  return bitrate;
   1.413 +}
   1.414 +
   1.415 +uint32_t
   1.416 +MinstrelWifiRemoteStation::FindRate ()
   1.417 +{
   1.418 +  NS_LOG_DEBUG ("FindRate " << "packet=" << m_packetCount );
   1.419 +
   1.420 +  if ((m_sampleCount + m_packetCount) == 0)
   1.421 +    {
   1.422 +      return 0;
   1.423 +    }
   1.424 +
   1.425 +
   1.426 +  uint32_t idx;
   1.427 +
   1.428 +  /// for determining when to try a sample rate 
   1.429 +  UniformVariable coinFlip (0, 100);
   1.430 +
   1.431 +  /**
   1.432 +   * if we are below the target of look around rate percentage, look around
   1.433 +   * note: do it randomly by flipping a coin instead sampling 
   1.434 +   * all at once until it reaches the look around rate
   1.435 +   */
   1.436 +  if ( (((100* m_sampleCount) / (m_sampleCount + m_packetCount )) < m_stations->m_lookAroundRate) &&
   1.437 +     ((int)coinFlip.GetValue ()) % 2 == 1 )
   1.438 +    {
   1.439 +
   1.440 +      /// now go through the table and find an index rate
   1.441 +      idx = GetNextSample	();
   1.442 +			
   1.443 +			
   1.444 +      /**
   1.445 +       * This if condition is used to make sure that we don't need to use
   1.446 +       * the sample rate it is the same as our current rate
   1.447 +       */
   1.448 +      if (idx != m_maxTpRate && idx != m_txrate) 
   1.449 +        {
   1.450 +		
   1.451 +          /// start sample count
   1.452 +          m_sampleCount++;
   1.453 +
   1.454 +          /// set flag that we are currently sampling
   1.455 +          m_isSampling = true;
   1.456 +
   1.457 +          /// bookeeping for resetting stuff
   1.458 +          if (m_packetCount >= 10000) 
   1.459 +            {
   1.460 +              m_sampleCount = 0;
   1.461 +              m_packetCount = 0;
   1.462 +            }
   1.463 +
   1.464 +          /// error check
   1.465 +          if (idx >= GetNSupportedModes	() || idx < 0 )
   1.466 +            {
   1.467 +              NS_LOG_DEBUG ("ALERT!!! ERROR");
   1.468 +            }
   1.469 +
   1.470 +          /// set the rate that we're currently sampling
   1.471 +          m_sampleRate = idx;
   1.472 +
   1.473 +          if (m_sampleRate == m_maxTpRate)
   1.474 +            {
   1.475 +              m_sampleRate = m_maxTpRate2;
   1.476 +            }
   1.477 +
   1.478 +          /// is this rate slower than the current best rate
   1.479 +          m_sampleRateSlower = (m_minstrelTable[idx].perfectTxTime > m_minstrelTable[m_maxTpRate].perfectTxTime);
   1.480 +
   1.481 +          /// using the best rate instead
   1.482 +          if (m_sampleRateSlower)
   1.483 +            {
   1.484 +              idx =  m_maxTpRate;
   1.485 +            }
   1.486 +        }
   1.487 +			
   1.488 +    } 
   1.489 +
   1.490 +  ///	continue using the best rate
   1.491 +  else
   1.492 +    {
   1.493 +      idx = m_maxTpRate; 
   1.494 +    }
   1.495 +
   1.496 +
   1.497 +  NS_LOG_DEBUG ("FindRate " << "sample rate=" << idx);
   1.498 +
   1.499 +  return idx;
   1.500 +}
   1.501 +
   1.502 +void
   1.503 +MinstrelWifiRemoteStation::UpdateStats ()
   1.504 +{
   1.505 +  if (Simulator::Now () <  m_nextStatsUpdate)
   1.506 +    {
   1.507 +      return;
   1.508 +    }
   1.509 +
   1.510 +  NS_LOG_DEBUG ("Updating stats="<<this);
   1.511 +
   1.512 +  m_nextStatsUpdate = Simulator::Now () + m_stations->m_updateStats;
   1.513 +
   1.514 +  Time txTime;
   1.515 +  uint32_t tempProb;
   1.516 +
   1.517 +  for (uint32_t i =0; i < GetNSupportedModes (); i++)
   1.518 +    {        
   1.519 +
   1.520 +      /// calculate the perfect tx time for this rate
   1.521 +      txTime = m_minstrelTable[i].perfectTxTime;       
   1.522 +
   1.523 +      /// just for initialization
   1.524 +      if (txTime.GetMicroSeconds () == 0)
   1.525 +        {
   1.526 +          txTime = Seconds (1);
   1.527 +        }
   1.528 +
   1.529 +      NS_LOG_DEBUG ("m_txrate=" << m_txrate << "\t attempt=" << m_minstrelTable[i].numRateAttempt << "\t success=" << m_minstrelTable[i].numRateSuccess);
   1.530 +
   1.531 +      /// if we've attempted something
   1.532 +      if (m_minstrelTable[i].numRateAttempt)
   1.533 +        {
   1.534 +          /**
   1.535 +           * calculate the probability of success
   1.536 +           * assume probability scales from 0 to 18000
   1.537 +           */
   1.538 +          tempProb = (m_minstrelTable[i].numRateSuccess * 18000) / m_minstrelTable[i].numRateAttempt;
   1.539 +
   1.540 +          /// bookeeping
   1.541 +          m_minstrelTable[i].successHist += m_minstrelTable[i].numRateSuccess;
   1.542 +          m_minstrelTable[i].attemptHist += m_minstrelTable[i].numRateAttempt;
   1.543 +          m_minstrelTable[i].prob = tempProb;
   1.544 +
   1.545 +          /// ewma probability
   1.546 +          tempProb = ((tempProb * (100 - m_stations->m_ewmaLevel)) + (m_minstrelTable[i].ewmaProb * m_stations->m_ewmaLevel) )/100;
   1.547 +
   1.548 +          m_minstrelTable[i].ewmaProb = tempProb;
   1.549 +
   1.550 +          /// calculating throughput
   1.551 +          m_minstrelTable[i].throughput = tempProb * (1000000 / txTime.GetMicroSeconds());
   1.552 +
   1.553 +        }
   1.554 +
   1.555 +      /// bookeeping
   1.556 +      m_minstrelTable[i].prevNumRateAttempt= m_minstrelTable[i].numRateAttempt;
   1.557 +      m_minstrelTable[i].prevNumRateSuccess = m_minstrelTable[i].numRateSuccess;
   1.558 +      m_minstrelTable[i].numRateSuccess = 0;
   1.559 +      m_minstrelTable[i].numRateAttempt = 0;
   1.560 +
   1.561 +      /// Sample less often below 10% and  above 95% of success
   1.562 +      if ((m_minstrelTable[i].ewmaProb > 17100) || (m_minstrelTable[i].ewmaProb < 1800)) 
   1.563 +        {
   1.564 +          /**
   1.565 +           * retry count denotes the number of retries permitted for each rate
   1.566 +           * # retry_count/2
   1.567 +           */
   1.568 +          m_minstrelTable[i].adjustedRetryCount = m_minstrelTable[i].retryCount >> 1;
   1.569 +          if (m_minstrelTable[i].adjustedRetryCount > 2)
   1.570 +            {
   1.571 +              m_minstrelTable[i].adjustedRetryCount = 2 ;
   1.572 +            }
   1.573 +        }
   1.574 +      else
   1.575 +        {
   1.576 +          m_minstrelTable[i].adjustedRetryCount = m_minstrelTable[i].retryCount;
   1.577 +        }
   1.578 +
   1.579 +      /// if it's 0 allow one retry limit
   1.580 +      if (m_minstrelTable[i].adjustedRetryCount == 0)
   1.581 +        {
   1.582 +          m_minstrelTable[i].adjustedRetryCount = 1;
   1.583 +        }
   1.584 +    }
   1.585 +
   1.586 +
   1.587 +  uint32_t max_prob = 0, index_max_prob =0, max_tp =0, index_max_tp=0, index_max_tp2=0;
   1.588 +
   1.589 +  /// go find max throughput, second maximum throughput, high probability succ
   1.590 +  for (uint32_t i =0; i < GetNSupportedModes (); i++) 
   1.591 +    {
   1.592 +      NS_LOG_DEBUG ("throughput" << m_minstrelTable[i].throughput << "\n ewma" << m_minstrelTable[i].ewmaProb);
   1.593 +
   1.594 +      if (max_tp < m_minstrelTable[i].throughput) 
   1.595 +        {
   1.596 +          index_max_tp = i;
   1.597 +          max_tp = m_minstrelTable[i].throughput;
   1.598 +        }
   1.599 +
   1.600 +      if (max_prob < m_minstrelTable[i].ewmaProb) 
   1.601 +        {
   1.602 +          index_max_prob = i;
   1.603 +          max_prob = m_minstrelTable[i].ewmaProb;
   1.604 +        }
   1.605 +    }
   1.606 +
   1.607 +
   1.608 +  max_tp = 0;
   1.609 +  /// find the second highest max
   1.610 +  for (uint32_t i =0; i < GetNSupportedModes (); i++) 
   1.611 +    {
   1.612 +      if ((i != index_max_tp) && (max_tp < m_minstrelTable[i].throughput))
   1.613 +        {
   1.614 +          index_max_tp2 = i;
   1.615 +          max_tp = m_minstrelTable[i].throughput;
   1.616 +        }
   1.617 +    }
   1.618 +
   1.619 +  m_maxTpRate = index_max_tp;
   1.620 +  m_maxTpRate2 = index_max_tp2;
   1.621 +  m_maxProbRate = index_max_prob;
   1.622 +  m_currentRate = index_max_tp;
   1.623 +
   1.624 +  if (index_max_tp > m_txrate)
   1.625 +    {
   1.626 +      m_txrate= index_max_tp;
   1.627 +    }
   1.628 +
   1.629 +  NS_LOG_DEBUG ("max tp="<< index_max_tp << "\nmax tp2="<< index_max_tp2<< "\nmax prob="<< index_max_prob);
   1.630 +
   1.631 +  /// reset it
   1.632 +  RateInit ();
   1.633 +}
   1.634 +
   1.635 +void
   1.636 +MinstrelWifiRemoteStation::RateInit ()
   1.637 +{
   1.638 +  NS_LOG_DEBUG ("RateInit="<<this);
   1.639 +
   1.640 +  for (uint32_t i = 0; i < GetNSupportedModes (); i++)
   1.641 +    {
   1.642 +      m_minstrelTable[i].numRateAttempt = 0;
   1.643 +      m_minstrelTable[i].numRateSuccess = 0;
   1.644 +      m_minstrelTable[i].prob = 0;
   1.645 +      m_minstrelTable[i].ewmaProb = 0;
   1.646 +      m_minstrelTable[i].prevNumRateAttempt = 0;
   1.647 +      m_minstrelTable[i].prevNumRateSuccess = 0;
   1.648 +      m_minstrelTable[i].successHist = 0;
   1.649 +      m_minstrelTable[i].attemptHist = 0;
   1.650 +      m_minstrelTable[i].throughput = 0;
   1.651 +      m_minstrelTable[i].perfectTxTime = m_stations->GetCalcTxTime (GetSupportedMode (i));
   1.652 +      m_minstrelTable[i].retryCount =1;
   1.653 +      m_minstrelTable[i].adjustedRetryCount =1;
   1.654 +    }
   1.655 +}
   1.656 +
   1.657 +void
   1.658 +MinstrelWifiRemoteStation::InitSampleTable ()
   1.659 +{
   1.660 +  NS_LOG_DEBUG ("InitSampleTable="<<this);
   1.661 +	
   1.662 +  m_col = m_index = 0;
   1.663 +
   1.664 +  /// for off-seting to make rates fall between 0 and numrates 
   1.665 +  uint32_t numSampleRates= GetNSupportedModes () - 1;
   1.666 +
   1.667 +  uint32_t newIndex;
   1.668 +  for (uint32_t col = 0; col < m_stations->m_sampleCol; col++)
   1.669 +    {
   1.670 +      for (uint32_t i = 0; i < numSampleRates; i++ )
   1.671 +        {
   1.672 +
   1.673 +          /**
   1.674 +           * The next two lines basically tries to generate a random number
   1.675 +           * between 0 and the number of available rates 
   1.676 +           */
   1.677 +          UniformVariable uv (0, numSampleRates);
   1.678 +          newIndex = (i + (uint32_t)uv.GetValue	()) % numSampleRates;	
   1.679 +
   1.680 +          /// this loop is used for filling in other uninitilized places
   1.681 +          while	(m_sampleTable[newIndex][col] != 0)
   1.682 +            {
   1.683 +              newIndex = (newIndex + 1)%GetNSupportedModes ();
   1.684 +            }
   1.685 +          m_sampleTable[newIndex][col] = i+1;
   1.686 +
   1.687 +        }
   1.688 +    }
   1.689 +}
   1.690 +
   1.691 +void
   1.692 +MinstrelWifiRemoteStation::PrintSampleTable ()
   1.693 +{
   1.694 +  NS_LOG_DEBUG ("PrintSampleTable="<<this );
   1.695 +
   1.696 +  uint32_t numSampleRates= GetNSupportedModes ();
   1.697 +  for (uint32_t i=0; i < numSampleRates; i++)
   1.698 +    {
   1.699 +      for (uint32_t j=0; j < m_stations->m_sampleCol; j++)
   1.700 +        {
   1.701 +          std::cout << m_sampleTable[i][j] << "\t";
   1.702 +        }
   1.703 +      std::cout << std::endl;
   1.704 +    }
   1.705 +}
   1.706 +	
   1.707 +void
   1.708 +MinstrelWifiRemoteStation::PrintTable ()
   1.709 +{
   1.710 +  NS_LOG_DEBUG ("PrintTable="<<this);
   1.711 +
   1.712 +  for (uint32_t i=0; i < GetNSupportedModes (); i++)
   1.713 +    {
   1.714 +      std::cout << "index(" << i << ") = " << m_minstrelTable[i].perfectTxTime<< "\n";
   1.715 +    }
   1.716 +}
   1.717 +
   1.718 +} //namespace ns3
   1.719 +
   1.720 +
   1.721 +
   1.722 +
   1.723 +
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/devices/wifi/minstrel-wifi-manager.h	Thu Aug 13 08:45:47 2009 +0200
     2.3 @@ -0,0 +1,255 @@
     2.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
     2.5 +/* 
     2.6 + * Copyright (c) 2009 Duy Nguyen 
     2.7 + * 
     2.8 + * This program is free software; you can redistribute it and/or modify
     2.9 + * it under the terms of the GNU General Public License version 2 as
    2.10 + * published by the Free Software Foundation;
    2.11 + *
    2.12 + * This program is distributed in the hope that it will be useful,
    2.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.15 + * GNU General Public License for more details.
    2.16 + *
    2.17 + * You should have received a copy of the GNU General Public License
    2.18 + * along with this program; if not, write to the Free Software
    2.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    2.20 + * 
    2.21 + * Author: Duy Nguyen <duy@soe.ucsc.edu> 
    2.22 + */
    2.23 +
    2.24 +
    2.25 +
    2.26 +#ifndef MINSTREL_WIFI_MANAGER_H
    2.27 +#define MINSTREL_WIFI_MANAGER_H
    2.28 +
    2.29 +#include "wifi-remote-station-manager.h"
    2.30 +#include "wifi-mode.h"
    2.31 +#include "ns3/nstime.h"
    2.32 +#include <vector>
    2.33 +
    2.34 +
    2.35 +
    2.36 +/**
    2.37 + * \author Duy Nguyen
    2.38 + * \brief Implementation of Minstrel Rate Control Algorithm 
    2.39 + *
    2.40 + * Porting Minstrel from Madwifi and Linux Kernel 
    2.41 + * http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/minstrel
    2.42 + */
    2.43 +
    2.44 +
    2.45 +namespace ns3 {
    2.46 +
    2.47 +
    2.48 +/**
    2.49 + * A struct to contain all information related to a data rate 
    2.50 + */
    2.51 +struct RateInfo{
    2.52 +
    2.53 +  /**
    2.54 +   * Perfect transmission time calculation, or frame calculation
    2.55 +   * Given a bit rate and a packet length n bytes 
    2.56 +   */
    2.57 +  Time perfectTxTime;		
    2.58 +
    2.59 +
    2.60 +  uint32_t retryCount;  ///< retry limit
    2.61 +  uint32_t adjustedRetryCount;  ///< adjust the retry limit for this rate
    2.62 +  uint32_t numRateAttempt;  ///< how many number of attempts so far
    2.63 +  uint32_t numRateSuccess;  ///< number of successful pkts 
    2.64 +  uint32_t prob;  ///< (# pkts success )/(# total pkts)
    2.65 +
    2.66 +  /**
    2.67 +   * EWMA calculation
    2.68 +   * ewma_prob =[prob *(100 - ewma_level) + (ewma_prob_old * ewma_level)]/100 
    2.69 +   */
    2.70 +  uint32_t ewmaProb;
    2.71 +
    2.72 +  uint32_t prevNumRateAttempt;  ///< from last rate
    2.73 +  uint32_t prevNumRateSuccess;  ///< from last rate
    2.74 +  uint64_t successHist;  ///< aggregate of all successes
    2.75 +  uint64_t attemptHist;  ///< aggregate of all attempts
    2.76 +  uint32_t throughput;  ///< throughput of a rate
    2.77 +};
    2.78 +
    2.79 +/**
    2.80 + * Data structure for a Minstrel Rate table 
    2.81 + * A vector of a struct RateInfo 
    2.82 + */
    2.83 +typedef std::vector<struct RateInfo> MinstrelRate;
    2.84 +
    2.85 +/**
    2.86 + * Data structure for a Sample Rate table
    2.87 + * A vector of a vector uint32_t 
    2.88 + */
    2.89 +typedef std::vector<std::vector<uint32_t> > SampleRate;
    2.90 +
    2.91 +
    2.92 +class MinstrelWifiManager : public WifiRemoteStationManager
    2.93 +{
    2.94 +
    2.95 +public:
    2.96 +  static TypeId GetTypeId (void);
    2.97 +  MinstrelWifiManager ();
    2.98 +  virtual ~MinstrelWifiManager();
    2.99 +
   2.100 +  virtual void SetupPhy (Ptr<WifiPhy> phy);
   2.101 +
   2.102 +  /// for estimating the TxTime of a packet with a given mode  
   2.103 +  Time GetCalcTxTime (WifiMode mode) const;
   2.104 +  void AddCalcTxTime (WifiMode mode, Time t);
   2.105 +
   2.106 +private:
   2.107 +  friend class MinstrelWifiRemoteStation;
   2.108 +  virtual class WifiRemoteStation *CreateStation (void);
   2.109 +
   2.110 +  typedef std::vector<std::pair<Time,WifiMode> > TxTime;
   2.111 +
   2.112 +  TxTime m_calcTxTime;  ///< to hold all the calculated TxTime for all modes
   2.113 +  Time m_updateStats;  ///< how frequent do we calculate the stats(1/10 seconds)
   2.114 +  double m_lookAroundRate;  ///< the % to try other rates than our current rate 
   2.115 +  double m_ewmaLevel;  ///< exponential weighted moving average
   2.116 +  uint32_t m_segmentSize;  ///< largest allowable segment size
   2.117 +  uint32_t m_sampleCol;  ///< number of sample columns
   2.118 +  uint32_t m_pktLen;  ///< packet length used  for calculate mode TxTime
   2.119 +  
   2.120 +};
   2.121 +
   2.122 +class MinstrelWifiRemoteStation : public WifiRemoteStation
   2.123 +{
   2.124 +public:
   2.125 +  MinstrelWifiRemoteStation (Ptr<MinstrelWifiManager> stations);
   2.126 + 
   2.127 +  virtual ~MinstrelWifiRemoteStation ();
   2.128 +
   2.129 +protected:
   2.130 +
   2.131 +  /** 
   2.132 +   * when packet is successfully received
   2.133 +   * see wifi-remote-station-manager.h for more documentation
   2.134 +   */
   2.135 +  virtual void DoReportRxOk (double rxSnr, WifiMode txMode);
   2.136 +
   2.137 +  /// when RTS timeout expires
   2.138 +  virtual void DoReportRtsFailed (void);
   2.139 +
   2.140 +
   2.141 +  /**
   2.142 +   *
   2.143 +   * Retry Chain table is implemented here
   2.144 +   *
   2.145 +   * Try |         LOOKAROUND RATE              | NORMAL RATE
   2.146 +   *     | random < best    | random > best     |
   2.147 +   * --------------------------------------------------------------
   2.148 +   *  1  | Best throughput  | Random rate       | Best throughput
   2.149 +   *  2  | Random rate      | Best throughput   | Next best throughput
   2.150 +   *  3  | Best probability | Best probability  | Best probability
   2.151 +   *  4  | Lowest Baserate  | Lowest baserate   | Lowest baserate
   2.152 +   *
   2.153 +   * Note: For clarity, multiple blocks of if's and else's are used
   2.154 +   * After a failing 7 times, DoReportFinalDataFailed will be called
   2.155 +   */
   2.156 +  virtual void DoReportDataFailed (void);
   2.157 +
   2.158 +  /// when receive a CTS, associated with an RTS
   2.159 +  virtual void DoReportRtsOk (double ctsSnr, WifiMode ctsMode, double rtsSnr);
   2.160 +
   2.161 +  /// when an ACK, associated with a data pkt, is received
   2.162 +  virtual void DoReportDataOk (double ackSnr, WifiMode ackMode, double dataSnr);
   2.163 +
   2.164 +  /// after calling ReportRtsFailed if NeedRtsRetransmission returns false
   2.165 +  virtual void DoReportFinalRtsFailed (void);
   2.166 +
   2.167 +  /// after calling ReportDataFailed if NeedDataRetransmission returns false
   2.168 +  virtual void DoReportFinalDataFailed (void);
   2.169 +
   2.170 +
   2.171 +private:
   2.172 +  virtual Ptr<WifiRemoteStationManager> GetManager (void) const;
   2.173 +
   2.174 +  /** 
   2.175 +   * returns the transmission mode for sending this packet
   2.176 +   * this function gets called when node is getting ready to send DATA
   2.177 +   * see wifi-remote-station-manager.h for more documentation
   2.178 +   */
   2.179 +  virtual WifiMode DoGetDataMode (uint32_t size);
   2.180 +
   2.181 +  /// returns the transmission mode for sending RTS packet
   2.182 +  virtual WifiMode DoGetRtsMode (void);
   2.183 +
   2.184 +  /// update the number of retries and reset accordingly
   2.185 +  void UpdateRetry (void);
   2.186 +
   2.187 +  /// getting the next sample from Sample Table
   2.188 +  uint32_t GetNextSample (void);
   2.189 +
   2.190 +  /// find a rate to use from Minstrel Table
   2.191 +  uint32_t FindRate (void);
   2.192 +
   2.193 +  /// updating the Minstrel Table every 1/10 seconds
   2.194 +  void UpdateStats (void);
   2.195 +
   2.196 +  /// initialize Minstrel Table
   2.197 +  void RateInit (void);
   2.198 +
   2.199 +  /// initialize Sample Table
   2.200 +  void InitSampleTable (void);
   2.201 +
   2.202 +  /// printing Sample Table
   2.203 +  void PrintSampleTable (void);
   2.204 +
   2.205 +  /// printing Minstrel Table
   2.206 +  void PrintTable (void);
   2.207 +
   2.208 +  /**
   2.209 +   * \param packet lenghth 
   2.210 +   * \param current WifiMode
   2.211 +   * \returns calcuated transmit duration 
   2.212 +   */
   2.213 +  Time CalcRatePacket (uint32_t, WifiMode);
   2.214 +
   2.215 +  void CheckInit(void);  ///< check for initializations
   2.216 +
   2.217 +  Ptr<MinstrelWifiManager> m_stations;
   2.218 +
   2.219 +  Time m_nextStatsUpdate;  ///< 10 times every second
   2.220 +
   2.221 +  MinstrelRate m_minstrelTable;  ///< minstrel table	
   2.222 +
   2.223 +  SampleRate m_sampleTable;  ///< sample table
   2.224 +
   2.225 +  /**
   2.226 +   * To keep track of the current position in the our random sample table
   2.227 +   * going row by row from 1st column until the 10th column(Minstrel defines 10)
   2.228 +   * then we wrap back to the row 1 col 1.
   2.229 +   * note: there are many other ways to do this.
   2.230 +   */
   2.231 +  uint32_t m_col, m_index;							
   2.232 +
   2.233 +  uint32_t m_maxTpRate;  ///< the current throughput rate 
   2.234 +  uint32_t m_maxTpRate2;  ///< second highest throughput rate
   2.235 +  uint32_t m_maxProbRate;  ///< rate with highest prob of success
   2.236 +
   2.237 +  int m_packetCount;  ///< total number of packets as of now
   2.238 +  int m_sampleCount;  ///< how many packets we have sample so far
   2.239 +
   2.240 +  bool m_isSampling;  ///< a flag to indicate we are currently sampling
   2.241 +  uint32_t m_sampleRate;  ///< current sample rate
   2.242 +  bool 	m_sampleRateSlower;  ///< a flag to indicate sample rate is slower
   2.243 +  uint32_t m_currentRate;  ///< current rate we are using
   2.244 +
   2.245 +  uint32_t m_shortRetry;  ///< short retries such as control packts
   2.246 +  uint32_t m_longRetry;  ///< long retries such as data packets
   2.247 +  uint32_t m_retry;  ///< total retries short + long
   2.248 +  uint32_t m_err;  ///< retry errors
   2.249 +  uint32_t m_txrate;  ///< current transmit rate
   2.250 +
   2.251 +  bool m_initialized;  ///< for initializing tables
   2.252 +
   2.253 +
   2.254 +}; 
   2.255 +
   2.256 +}// namespace ns3
   2.257 +
   2.258 +#endif /* MINSTREL_WIFI_MANAGER_H */
     3.1 --- a/src/devices/wifi/wscript	Wed Aug 12 12:07:25 2009 +0100
     3.2 +++ b/src/devices/wifi/wscript	Thu Aug 13 08:45:47 2009 +0200
     3.3 @@ -63,6 +63,7 @@
     3.4          'msdu-aggregator.cc',
     3.5          'amsdu-subframe-header.cc',
     3.6          'msdu-standard-aggregator.cc',
     3.7 +        'minstrel-wifi-manager.cc',
     3.8          ]
     3.9      headers = bld.new_task_gen('ns3header')
    3.10      headers.module = 'wifi'
    3.11 @@ -113,6 +114,7 @@
    3.12          'dcf-manager.h',
    3.13          'mac-rx-middle.h', 
    3.14          'mac-low.h',
    3.15 +        'minstrel-wifi-manager.h'
    3.16          ]
    3.17  
    3.18      if bld.env['ENABLE_GSL']: