--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/wifi/minstrel-wifi-manager.cc Thu Aug 13 08:45:47 2009 +0200
@@ -0,0 +1,720 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Duy Nguyen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Duy Nguyen <duy@soe.ucsc.edu>
+ *
+ * Some Comments:
+ *
+ * 1) Segment Size is declared for completeness but not used because it has
+ * to do more with the requirement of the specific hardware.
+ *
+ * 2) By default, Minstrel applies the multi-rate retry(the core of Minstrel
+ * algorithm). Otherwise, please use ConstantRateWifiManager instead.
+ *
+ * http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/minstrel
+ */
+
+
+
+#include "minstrel-wifi-manager.h"
+#include "wifi-phy.h"
+#include "ns3/random-variable.h"
+#include "ns3/simulator.h"
+#include "ns3/log.h"
+#include "ns3/uinteger.h"
+#include "ns3/double.h"
+#include "ns3/wifi-mac.h"
+#include "ns3/assert.h"
+#include <vector>
+
+NS_LOG_COMPONENT_DEFINE ("MinstrelWifiManager");
+
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (MinstrelWifiManager);
+
+TypeId
+MinstrelWifiManager::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::MinstrelWifiManager")
+ .SetParent<WifiRemoteStationManager> ()
+ .AddConstructor<MinstrelWifiManager> ()
+ .AddAttribute ("UpdateStatistics",
+ "The interval between updating statistics table ",
+ TimeValue (Seconds (0.1)),
+ MakeTimeAccessor (&MinstrelWifiManager::m_updateStats),
+ MakeTimeChecker ())
+ .AddAttribute ("LookAroundRate",
+ "the percentage to try other rates",
+ DoubleValue (10),
+ MakeDoubleAccessor (&MinstrelWifiManager::m_lookAroundRate),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("EWMA",
+ "EWMA level",
+ DoubleValue (75),
+ MakeDoubleAccessor (&MinstrelWifiManager::m_ewmaLevel),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("SegmentSize",
+ "The largest allowable segment size packet",
+ DoubleValue (6000),
+ MakeDoubleAccessor (&MinstrelWifiManager::m_segmentSize),
+ MakeDoubleChecker <double> ())
+ .AddAttribute ("SampleColumn",
+ "The number of columns used for sampling",
+ DoubleValue (10),
+ MakeDoubleAccessor (&MinstrelWifiManager::m_sampleCol),
+ MakeDoubleChecker <double> ())
+ .AddAttribute ("PacketLength",
+ "The packet length used for calculating mode TxTime",
+ DoubleValue (1200),
+ MakeDoubleAccessor (&MinstrelWifiManager::m_pktLen),
+ MakeDoubleChecker <double> ())
+ ;
+ return tid;
+}
+
+MinstrelWifiManager::MinstrelWifiManager ()
+{}
+
+MinstrelWifiManager::~MinstrelWifiManager ()
+{}
+
+void
+MinstrelWifiManager::SetupPhy (Ptr<WifiPhy> phy)
+{
+ uint32_t nModes = phy->GetNModes ();
+ for (uint32_t i = 0; i < nModes; i++)
+ {
+ WifiMode mode = phy->GetMode (i);
+ AddCalcTxTime (mode, phy->CalculateTxDuration (m_pktLen, mode, WIFI_PREAMBLE_LONG));
+ }
+ WifiRemoteStationManager::SetupPhy (phy);
+}
+
+WifiRemoteStation *
+MinstrelWifiManager::CreateStation (void)
+{
+ return new MinstrelWifiRemoteStation (this);
+}
+
+Time
+MinstrelWifiManager::GetCalcTxTime (WifiMode mode) const
+{
+
+ for (TxTime::const_iterator i = m_calcTxTime.begin (); i != m_calcTxTime.end (); i++)
+ {
+ if (mode == i->second)
+ {
+ return i->first;
+ }
+ }
+ NS_ASSERT (false);
+ return Seconds (0);
+}
+
+void
+MinstrelWifiManager::AddCalcTxTime (WifiMode mode, Time t)
+{
+ m_calcTxTime.push_back (std::make_pair (t, mode));
+}
+
+MinstrelWifiRemoteStation::MinstrelWifiRemoteStation (Ptr<MinstrelWifiManager> stations)
+ :m_stations (stations),
+ m_nextStatsUpdate (Simulator::Now () + stations->m_updateStats),
+ m_col (0),
+ m_index (0),
+ m_maxTpRate (0),
+ m_maxTpRate2 (0),
+ m_maxProbRate (0),
+ m_packetCount (0),
+ m_sampleCount (0),
+ m_isSampling (false),
+ m_sampleRate (0),
+ m_sampleRateSlower (false),
+ m_currentRate (0),
+ m_shortRetry (0),
+ m_longRetry (0),
+ m_retry (0),
+ m_err (0),
+ m_txrate (0),
+ m_initialized (false)
+{}
+
+MinstrelWifiRemoteStation::~MinstrelWifiRemoteStation ()
+{}
+
+void
+MinstrelWifiRemoteStation::CheckInit(void)
+{
+ if (!m_initialized)
+ {
+ m_minstrelTable = MinstrelRate(GetNSupportedModes ());
+ m_sampleTable = SampleRate(GetNSupportedModes (), std::vector<uint32_t> (m_stations->m_sampleCol));
+ InitSampleTable ();
+ RateInit ();
+ m_initialized = true;
+ }
+}
+
+void
+MinstrelWifiRemoteStation::DoReportRxOk (double rxSnr, WifiMode txMode)
+{
+ NS_LOG_DEBUG("DoReportRxOk m_txrate=" << m_txrate);
+}
+
+void
+MinstrelWifiRemoteStation::DoReportRtsFailed (void)
+{
+ NS_LOG_DEBUG("DoReportRtsFailed m_txrate=" << m_txrate);
+
+ m_shortRetry++;
+}
+
+void
+MinstrelWifiRemoteStation::DoReportRtsOk (double ctsSnr, WifiMode ctsMode, double rtsSnr)
+{
+ NS_LOG_DEBUG ("self="<<this<<" rts ok");
+}
+
+void
+MinstrelWifiRemoteStation::DoReportFinalRtsFailed (void)
+{
+ UpdateRetry ();
+ m_err++;
+}
+
+void
+MinstrelWifiRemoteStation::DoReportDataFailed (void)
+{
+ CheckInit();
+
+ m_longRetry++;
+
+ NS_LOG_DEBUG ("DoReportDataFailed " << this << "\t rate " << m_txrate << "\tlongRetry \t" << m_longRetry);
+
+ /// for normal rate, we're not currently sampling random rates
+ if (!m_isSampling)
+ {
+ /// use best throughput rate
+ if( m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
+ {
+ ; ///< there's still a few retries left
+ }
+
+ /// use second best throughput rate
+ else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
+ m_minstrelTable[m_maxTpRate].adjustedRetryCount))
+ {
+ m_txrate = m_maxTpRate2;
+ }
+
+ /// use best probability rate
+ else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
+ m_minstrelTable[m_maxTpRate2].adjustedRetryCount +
+ m_minstrelTable[m_maxTpRate].adjustedRetryCount))
+ {
+ m_txrate = m_maxProbRate;
+ }
+
+ /// use lowest base rate
+ else if (m_longRetry > (m_minstrelTable[m_txrate].adjustedRetryCount +
+ m_minstrelTable[m_maxTpRate2].adjustedRetryCount +
+ m_minstrelTable[m_maxTpRate].adjustedRetryCount))
+ {
+ m_txrate = 0;
+ }
+ }
+
+ /// for look-around rate, we're currently sampling random rates
+ else
+ {
+ /// current sampling rate is slower than the current best rate
+ if (m_sampleRateSlower)
+ {
+ /// use best throughput rate
+ if (m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
+ {
+ ; ///< there are a few retries left
+ }
+
+ /// use random rate
+ else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
+ m_minstrelTable[m_maxTpRate].adjustedRetryCount))
+ {
+ m_txrate = m_sampleRate;
+ }
+
+ /// use max probability rate
+ else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
+ m_minstrelTable[m_sampleRate].adjustedRetryCount +
+ m_minstrelTable[m_maxTpRate].adjustedRetryCount ))
+ {
+ m_txrate = m_maxProbRate;
+ }
+
+ /// use lowest base rate
+ else if (m_longRetry > (m_minstrelTable[m_txrate].adjustedRetryCount +
+ m_minstrelTable[m_sampleRate].adjustedRetryCount +
+ m_minstrelTable[m_maxTpRate].adjustedRetryCount))
+ {
+ m_txrate = 0;
+ }
+ }
+
+ /// current sampling rate is better than current best rate
+ else
+ {
+ /// use random rate
+ if (m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
+ {
+ ; ///< keep using it
+ }
+
+ /// use the best rate
+ else if (m_longRetry <= m_minstrelTable[m_txrate].adjustedRetryCount +
+ m_minstrelTable[m_sampleRate].adjustedRetryCount)
+ {
+ m_txrate = m_maxTpRate;
+ }
+
+ /// use the best probability rate
+ else if (m_longRetry <= m_minstrelTable[m_txrate].adjustedRetryCount +
+ m_minstrelTable[m_maxTpRate].adjustedRetryCount +
+ m_minstrelTable[m_sampleRate].adjustedRetryCount)
+ {
+ m_txrate = m_maxProbRate;
+ }
+
+ /// use the lowest base rate
+ else if (m_longRetry > m_minstrelTable[m_txrate].adjustedRetryCount +
+ m_minstrelTable[m_maxTpRate].adjustedRetryCount +
+ m_minstrelTable[m_sampleRate].adjustedRetryCount)
+ {
+ m_txrate = 0;
+ }
+ }
+ }
+}
+
+void
+MinstrelWifiRemoteStation::DoReportDataOk (double ackSnr, WifiMode ackMode, double dataSnr)
+{
+ m_isSampling = false;
+ m_sampleRateSlower=false;
+
+ CheckInit ();
+
+ m_minstrelTable[m_txrate].numRateSuccess++;
+ m_minstrelTable[m_txrate].numRateAttempt++;
+
+ UpdateRetry ();
+
+ m_minstrelTable[m_txrate].numRateAttempt += m_retry;
+ m_packetCount++;
+
+ if (GetNSupportedModes () >= 1)
+ {
+ m_txrate = FindRate ();
+ }
+}
+
+void
+MinstrelWifiRemoteStation::DoReportFinalDataFailed (void)
+{
+ NS_LOG_DEBUG ("DoReportFinalDataFailed m_txrate=" << m_txrate);
+
+ m_isSampling = false;
+ m_sampleRateSlower=false;
+
+ UpdateRetry ();
+
+ m_minstrelTable[m_txrate].numRateAttempt += m_retry;
+ m_err++;
+
+ if (GetNSupportedModes () >= 1)
+ {
+ m_txrate = FindRate ();
+ }
+}
+
+void
+MinstrelWifiRemoteStation::UpdateRetry (void)
+{
+ m_retry = m_shortRetry + m_longRetry;
+ m_shortRetry = 0;
+ m_longRetry = 0;
+}
+
+Ptr<WifiRemoteStationManager>
+MinstrelWifiRemoteStation::GetManager (void) const
+{
+ return m_stations;
+}
+
+WifiMode
+MinstrelWifiRemoteStation::DoGetDataMode (uint32_t size)
+{
+ UpdateStats ();
+ if (!m_initialized)
+ {
+ CheckInit ();
+
+ /// start the rate at half way
+ m_txrate = GetNSupportedModes () / 2;
+ }
+ return GetSupportedMode (m_txrate);
+}
+
+WifiMode
+MinstrelWifiRemoteStation::DoGetRtsMode (void)
+{
+ NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << m_txrate);
+
+ UpdateStats ();
+ return GetSupportedMode (0);
+}
+
+uint32_t
+MinstrelWifiRemoteStation::GetNextSample ()
+{
+ uint32_t bitrate;
+ bitrate = m_sampleTable[m_index][m_col];
+ m_index++;
+
+ /// bookeeping for m_index and m_col variables
+ if (m_index > (GetNSupportedModes () -2))
+ {
+ m_index =0;
+ m_col++;
+ if (m_col >= m_stations->m_sampleCol)
+ {
+ m_col = 0;
+ }
+ }
+ return bitrate;
+}
+
+uint32_t
+MinstrelWifiRemoteStation::FindRate ()
+{
+ NS_LOG_DEBUG ("FindRate " << "packet=" << m_packetCount );
+
+ if ((m_sampleCount + m_packetCount) == 0)
+ {
+ return 0;
+ }
+
+
+ uint32_t idx;
+
+ /// for determining when to try a sample rate
+ UniformVariable coinFlip (0, 100);
+
+ /**
+ * if we are below the target of look around rate percentage, look around
+ * note: do it randomly by flipping a coin instead sampling
+ * all at once until it reaches the look around rate
+ */
+ if ( (((100* m_sampleCount) / (m_sampleCount + m_packetCount )) < m_stations->m_lookAroundRate) &&
+ ((int)coinFlip.GetValue ()) % 2 == 1 )
+ {
+
+ /// now go through the table and find an index rate
+ idx = GetNextSample ();
+
+
+ /**
+ * This if condition is used to make sure that we don't need to use
+ * the sample rate it is the same as our current rate
+ */
+ if (idx != m_maxTpRate && idx != m_txrate)
+ {
+
+ /// start sample count
+ m_sampleCount++;
+
+ /// set flag that we are currently sampling
+ m_isSampling = true;
+
+ /// bookeeping for resetting stuff
+ if (m_packetCount >= 10000)
+ {
+ m_sampleCount = 0;
+ m_packetCount = 0;
+ }
+
+ /// error check
+ if (idx >= GetNSupportedModes () || idx < 0 )
+ {
+ NS_LOG_DEBUG ("ALERT!!! ERROR");
+ }
+
+ /// set the rate that we're currently sampling
+ m_sampleRate = idx;
+
+ if (m_sampleRate == m_maxTpRate)
+ {
+ m_sampleRate = m_maxTpRate2;
+ }
+
+ /// is this rate slower than the current best rate
+ m_sampleRateSlower = (m_minstrelTable[idx].perfectTxTime > m_minstrelTable[m_maxTpRate].perfectTxTime);
+
+ /// using the best rate instead
+ if (m_sampleRateSlower)
+ {
+ idx = m_maxTpRate;
+ }
+ }
+
+ }
+
+ /// continue using the best rate
+ else
+ {
+ idx = m_maxTpRate;
+ }
+
+
+ NS_LOG_DEBUG ("FindRate " << "sample rate=" << idx);
+
+ return idx;
+}
+
+void
+MinstrelWifiRemoteStation::UpdateStats ()
+{
+ if (Simulator::Now () < m_nextStatsUpdate)
+ {
+ return;
+ }
+
+ NS_LOG_DEBUG ("Updating stats="<<this);
+
+ m_nextStatsUpdate = Simulator::Now () + m_stations->m_updateStats;
+
+ Time txTime;
+ uint32_t tempProb;
+
+ for (uint32_t i =0; i < GetNSupportedModes (); i++)
+ {
+
+ /// calculate the perfect tx time for this rate
+ txTime = m_minstrelTable[i].perfectTxTime;
+
+ /// just for initialization
+ if (txTime.GetMicroSeconds () == 0)
+ {
+ txTime = Seconds (1);
+ }
+
+ NS_LOG_DEBUG ("m_txrate=" << m_txrate << "\t attempt=" << m_minstrelTable[i].numRateAttempt << "\t success=" << m_minstrelTable[i].numRateSuccess);
+
+ /// if we've attempted something
+ if (m_minstrelTable[i].numRateAttempt)
+ {
+ /**
+ * calculate the probability of success
+ * assume probability scales from 0 to 18000
+ */
+ tempProb = (m_minstrelTable[i].numRateSuccess * 18000) / m_minstrelTable[i].numRateAttempt;
+
+ /// bookeeping
+ m_minstrelTable[i].successHist += m_minstrelTable[i].numRateSuccess;
+ m_minstrelTable[i].attemptHist += m_minstrelTable[i].numRateAttempt;
+ m_minstrelTable[i].prob = tempProb;
+
+ /// ewma probability
+ tempProb = ((tempProb * (100 - m_stations->m_ewmaLevel)) + (m_minstrelTable[i].ewmaProb * m_stations->m_ewmaLevel) )/100;
+
+ m_minstrelTable[i].ewmaProb = tempProb;
+
+ /// calculating throughput
+ m_minstrelTable[i].throughput = tempProb * (1000000 / txTime.GetMicroSeconds());
+
+ }
+
+ /// bookeeping
+ m_minstrelTable[i].prevNumRateAttempt= m_minstrelTable[i].numRateAttempt;
+ m_minstrelTable[i].prevNumRateSuccess = m_minstrelTable[i].numRateSuccess;
+ m_minstrelTable[i].numRateSuccess = 0;
+ m_minstrelTable[i].numRateAttempt = 0;
+
+ /// Sample less often below 10% and above 95% of success
+ if ((m_minstrelTable[i].ewmaProb > 17100) || (m_minstrelTable[i].ewmaProb < 1800))
+ {
+ /**
+ * retry count denotes the number of retries permitted for each rate
+ * # retry_count/2
+ */
+ m_minstrelTable[i].adjustedRetryCount = m_minstrelTable[i].retryCount >> 1;
+ if (m_minstrelTable[i].adjustedRetryCount > 2)
+ {
+ m_minstrelTable[i].adjustedRetryCount = 2 ;
+ }
+ }
+ else
+ {
+ m_minstrelTable[i].adjustedRetryCount = m_minstrelTable[i].retryCount;
+ }
+
+ /// if it's 0 allow one retry limit
+ if (m_minstrelTable[i].adjustedRetryCount == 0)
+ {
+ m_minstrelTable[i].adjustedRetryCount = 1;
+ }
+ }
+
+
+ uint32_t max_prob = 0, index_max_prob =0, max_tp =0, index_max_tp=0, index_max_tp2=0;
+
+ /// go find max throughput, second maximum throughput, high probability succ
+ for (uint32_t i =0; i < GetNSupportedModes (); i++)
+ {
+ NS_LOG_DEBUG ("throughput" << m_minstrelTable[i].throughput << "\n ewma" << m_minstrelTable[i].ewmaProb);
+
+ if (max_tp < m_minstrelTable[i].throughput)
+ {
+ index_max_tp = i;
+ max_tp = m_minstrelTable[i].throughput;
+ }
+
+ if (max_prob < m_minstrelTable[i].ewmaProb)
+ {
+ index_max_prob = i;
+ max_prob = m_minstrelTable[i].ewmaProb;
+ }
+ }
+
+
+ max_tp = 0;
+ /// find the second highest max
+ for (uint32_t i =0; i < GetNSupportedModes (); i++)
+ {
+ if ((i != index_max_tp) && (max_tp < m_minstrelTable[i].throughput))
+ {
+ index_max_tp2 = i;
+ max_tp = m_minstrelTable[i].throughput;
+ }
+ }
+
+ m_maxTpRate = index_max_tp;
+ m_maxTpRate2 = index_max_tp2;
+ m_maxProbRate = index_max_prob;
+ m_currentRate = index_max_tp;
+
+ if (index_max_tp > m_txrate)
+ {
+ m_txrate= index_max_tp;
+ }
+
+ NS_LOG_DEBUG ("max tp="<< index_max_tp << "\nmax tp2="<< index_max_tp2<< "\nmax prob="<< index_max_prob);
+
+ /// reset it
+ RateInit ();
+}
+
+void
+MinstrelWifiRemoteStation::RateInit ()
+{
+ NS_LOG_DEBUG ("RateInit="<<this);
+
+ for (uint32_t i = 0; i < GetNSupportedModes (); i++)
+ {
+ m_minstrelTable[i].numRateAttempt = 0;
+ m_minstrelTable[i].numRateSuccess = 0;
+ m_minstrelTable[i].prob = 0;
+ m_minstrelTable[i].ewmaProb = 0;
+ m_minstrelTable[i].prevNumRateAttempt = 0;
+ m_minstrelTable[i].prevNumRateSuccess = 0;
+ m_minstrelTable[i].successHist = 0;
+ m_minstrelTable[i].attemptHist = 0;
+ m_minstrelTable[i].throughput = 0;
+ m_minstrelTable[i].perfectTxTime = m_stations->GetCalcTxTime (GetSupportedMode (i));
+ m_minstrelTable[i].retryCount =1;
+ m_minstrelTable[i].adjustedRetryCount =1;
+ }
+}
+
+void
+MinstrelWifiRemoteStation::InitSampleTable ()
+{
+ NS_LOG_DEBUG ("InitSampleTable="<<this);
+
+ m_col = m_index = 0;
+
+ /// for off-seting to make rates fall between 0 and numrates
+ uint32_t numSampleRates= GetNSupportedModes () - 1;
+
+ uint32_t newIndex;
+ for (uint32_t col = 0; col < m_stations->m_sampleCol; col++)
+ {
+ for (uint32_t i = 0; i < numSampleRates; i++ )
+ {
+
+ /**
+ * The next two lines basically tries to generate a random number
+ * between 0 and the number of available rates
+ */
+ UniformVariable uv (0, numSampleRates);
+ newIndex = (i + (uint32_t)uv.GetValue ()) % numSampleRates;
+
+ /// this loop is used for filling in other uninitilized places
+ while (m_sampleTable[newIndex][col] != 0)
+ {
+ newIndex = (newIndex + 1)%GetNSupportedModes ();
+ }
+ m_sampleTable[newIndex][col] = i+1;
+
+ }
+ }
+}
+
+void
+MinstrelWifiRemoteStation::PrintSampleTable ()
+{
+ NS_LOG_DEBUG ("PrintSampleTable="<<this );
+
+ uint32_t numSampleRates= GetNSupportedModes ();
+ for (uint32_t i=0; i < numSampleRates; i++)
+ {
+ for (uint32_t j=0; j < m_stations->m_sampleCol; j++)
+ {
+ std::cout << m_sampleTable[i][j] << "\t";
+ }
+ std::cout << std::endl;
+ }
+}
+
+void
+MinstrelWifiRemoteStation::PrintTable ()
+{
+ NS_LOG_DEBUG ("PrintTable="<<this);
+
+ for (uint32_t i=0; i < GetNSupportedModes (); i++)
+ {
+ std::cout << "index(" << i << ") = " << m_minstrelTable[i].perfectTxTime<< "\n";
+ }
+}
+
+} //namespace ns3
+
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/wifi/minstrel-wifi-manager.h Thu Aug 13 08:45:47 2009 +0200
@@ -0,0 +1,255 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Duy Nguyen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Duy Nguyen <duy@soe.ucsc.edu>
+ */
+
+
+
+#ifndef MINSTREL_WIFI_MANAGER_H
+#define MINSTREL_WIFI_MANAGER_H
+
+#include "wifi-remote-station-manager.h"
+#include "wifi-mode.h"
+#include "ns3/nstime.h"
+#include <vector>
+
+
+
+/**
+ * \author Duy Nguyen
+ * \brief Implementation of Minstrel Rate Control Algorithm
+ *
+ * Porting Minstrel from Madwifi and Linux Kernel
+ * http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/minstrel
+ */
+
+
+namespace ns3 {
+
+
+/**
+ * A struct to contain all information related to a data rate
+ */
+struct RateInfo{
+
+ /**
+ * Perfect transmission time calculation, or frame calculation
+ * Given a bit rate and a packet length n bytes
+ */
+ Time perfectTxTime;
+
+
+ uint32_t retryCount; ///< retry limit
+ uint32_t adjustedRetryCount; ///< adjust the retry limit for this rate
+ uint32_t numRateAttempt; ///< how many number of attempts so far
+ uint32_t numRateSuccess; ///< number of successful pkts
+ uint32_t prob; ///< (# pkts success )/(# total pkts)
+
+ /**
+ * EWMA calculation
+ * ewma_prob =[prob *(100 - ewma_level) + (ewma_prob_old * ewma_level)]/100
+ */
+ uint32_t ewmaProb;
+
+ uint32_t prevNumRateAttempt; ///< from last rate
+ uint32_t prevNumRateSuccess; ///< from last rate
+ uint64_t successHist; ///< aggregate of all successes
+ uint64_t attemptHist; ///< aggregate of all attempts
+ uint32_t throughput; ///< throughput of a rate
+};
+
+/**
+ * Data structure for a Minstrel Rate table
+ * A vector of a struct RateInfo
+ */
+typedef std::vector<struct RateInfo> MinstrelRate;
+
+/**
+ * Data structure for a Sample Rate table
+ * A vector of a vector uint32_t
+ */
+typedef std::vector<std::vector<uint32_t> > SampleRate;
+
+
+class MinstrelWifiManager : public WifiRemoteStationManager
+{
+
+public:
+ static TypeId GetTypeId (void);
+ MinstrelWifiManager ();
+ virtual ~MinstrelWifiManager();
+
+ virtual void SetupPhy (Ptr<WifiPhy> phy);
+
+ /// for estimating the TxTime of a packet with a given mode
+ Time GetCalcTxTime (WifiMode mode) const;
+ void AddCalcTxTime (WifiMode mode, Time t);
+
+private:
+ friend class MinstrelWifiRemoteStation;
+ virtual class WifiRemoteStation *CreateStation (void);
+
+ typedef std::vector<std::pair<Time,WifiMode> > TxTime;
+
+ TxTime m_calcTxTime; ///< to hold all the calculated TxTime for all modes
+ Time m_updateStats; ///< how frequent do we calculate the stats(1/10 seconds)
+ double m_lookAroundRate; ///< the % to try other rates than our current rate
+ double m_ewmaLevel; ///< exponential weighted moving average
+ uint32_t m_segmentSize; ///< largest allowable segment size
+ uint32_t m_sampleCol; ///< number of sample columns
+ uint32_t m_pktLen; ///< packet length used for calculate mode TxTime
+
+};
+
+class MinstrelWifiRemoteStation : public WifiRemoteStation
+{
+public:
+ MinstrelWifiRemoteStation (Ptr<MinstrelWifiManager> stations);
+
+ virtual ~MinstrelWifiRemoteStation ();
+
+protected:
+
+ /**
+ * when packet is successfully received
+ * see wifi-remote-station-manager.h for more documentation
+ */
+ virtual void DoReportRxOk (double rxSnr, WifiMode txMode);
+
+ /// when RTS timeout expires
+ virtual void DoReportRtsFailed (void);
+
+
+ /**
+ *
+ * Retry Chain table is implemented here
+ *
+ * Try | LOOKAROUND RATE | NORMAL RATE
+ * | random < best | random > best |
+ * --------------------------------------------------------------
+ * 1 | Best throughput | Random rate | Best throughput
+ * 2 | Random rate | Best throughput | Next best throughput
+ * 3 | Best probability | Best probability | Best probability
+ * 4 | Lowest Baserate | Lowest baserate | Lowest baserate
+ *
+ * Note: For clarity, multiple blocks of if's and else's are used
+ * After a failing 7 times, DoReportFinalDataFailed will be called
+ */
+ virtual void DoReportDataFailed (void);
+
+ /// when receive a CTS, associated with an RTS
+ virtual void DoReportRtsOk (double ctsSnr, WifiMode ctsMode, double rtsSnr);
+
+ /// when an ACK, associated with a data pkt, is received
+ virtual void DoReportDataOk (double ackSnr, WifiMode ackMode, double dataSnr);
+
+ /// after calling ReportRtsFailed if NeedRtsRetransmission returns false
+ virtual void DoReportFinalRtsFailed (void);
+
+ /// after calling ReportDataFailed if NeedDataRetransmission returns false
+ virtual void DoReportFinalDataFailed (void);
+
+
+private:
+ virtual Ptr<WifiRemoteStationManager> GetManager (void) const;
+
+ /**
+ * returns the transmission mode for sending this packet
+ * this function gets called when node is getting ready to send DATA
+ * see wifi-remote-station-manager.h for more documentation
+ */
+ virtual WifiMode DoGetDataMode (uint32_t size);
+
+ /// returns the transmission mode for sending RTS packet
+ virtual WifiMode DoGetRtsMode (void);
+
+ /// update the number of retries and reset accordingly
+ void UpdateRetry (void);
+
+ /// getting the next sample from Sample Table
+ uint32_t GetNextSample (void);
+
+ /// find a rate to use from Minstrel Table
+ uint32_t FindRate (void);
+
+ /// updating the Minstrel Table every 1/10 seconds
+ void UpdateStats (void);
+
+ /// initialize Minstrel Table
+ void RateInit (void);
+
+ /// initialize Sample Table
+ void InitSampleTable (void);
+
+ /// printing Sample Table
+ void PrintSampleTable (void);
+
+ /// printing Minstrel Table
+ void PrintTable (void);
+
+ /**
+ * \param packet lenghth
+ * \param current WifiMode
+ * \returns calcuated transmit duration
+ */
+ Time CalcRatePacket (uint32_t, WifiMode);
+
+ void CheckInit(void); ///< check for initializations
+
+ Ptr<MinstrelWifiManager> m_stations;
+
+ Time m_nextStatsUpdate; ///< 10 times every second
+
+ MinstrelRate m_minstrelTable; ///< minstrel table
+
+ SampleRate m_sampleTable; ///< sample table
+
+ /**
+ * To keep track of the current position in the our random sample table
+ * going row by row from 1st column until the 10th column(Minstrel defines 10)
+ * then we wrap back to the row 1 col 1.
+ * note: there are many other ways to do this.
+ */
+ uint32_t m_col, m_index;
+
+ uint32_t m_maxTpRate; ///< the current throughput rate
+ uint32_t m_maxTpRate2; ///< second highest throughput rate
+ uint32_t m_maxProbRate; ///< rate with highest prob of success
+
+ int m_packetCount; ///< total number of packets as of now
+ int m_sampleCount; ///< how many packets we have sample so far
+
+ bool m_isSampling; ///< a flag to indicate we are currently sampling
+ uint32_t m_sampleRate; ///< current sample rate
+ bool m_sampleRateSlower; ///< a flag to indicate sample rate is slower
+ uint32_t m_currentRate; ///< current rate we are using
+
+ uint32_t m_shortRetry; ///< short retries such as control packts
+ uint32_t m_longRetry; ///< long retries such as data packets
+ uint32_t m_retry; ///< total retries short + long
+ uint32_t m_err; ///< retry errors
+ uint32_t m_txrate; ///< current transmit rate
+
+ bool m_initialized; ///< for initializing tables
+
+
+};
+
+}// namespace ns3
+
+#endif /* MINSTREL_WIFI_MANAGER_H */
--- a/src/devices/wifi/wscript Wed Aug 12 12:07:25 2009 +0100
+++ b/src/devices/wifi/wscript Thu Aug 13 08:45:47 2009 +0200
@@ -63,6 +63,7 @@
'msdu-aggregator.cc',
'amsdu-subframe-header.cc',
'msdu-standard-aggregator.cc',
+ 'minstrel-wifi-manager.cc',
]
headers = bld.new_task_gen('ns3header')
headers.module = 'wifi'
@@ -113,6 +114,7 @@
'dcf-manager.h',
'mac-rx-middle.h',
'mac-low.h',
+ 'minstrel-wifi-manager.h'
]
if bld.env['ENABLE_GSL']: