aboutsummaryrefslogtreecommitdiffstats
path: root/emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.cc')
-rw-r--r--emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.cc1127
1 files changed, 1127 insertions, 0 deletions
diff --git a/emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.cc b/emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.cc
new file mode 100644
index 00000000..ff773004
--- /dev/null
+++ b/emu-radio/ns3-patch/wifi/model/minstrel-ht-wifi-manager.cc
@@ -0,0 +1,1127 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2015 Ghada Badawy
+ *
+ * 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: Ghada Badawy <gbadawy@gmail.com>
+ *
+ * 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.
+ *
+ * 3) 40Mhz can't fall back to 20MHz
+ *
+ * reference: http://lwn.net/Articles/376765/
+ */
+
+#include "minstrel-ht-wifi-manager.h"
+#include "wifi-phy.h"
+#include "ns3/random-variable-stream.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>
+
+//newly added
+#include "ns3/ht-wifi-mac-helper.h"
+
+#define Min(a,b) ((a < b) ? a : b)
+
+
+
+
+namespace ns3 {
+
+ NS_LOG_COMPONENT_DEFINE ("MinstrelHtWifiManager");
+
+struct MinstrelHtWifiRemoteStation : public WifiRemoteStation
+{
+ void DisposeStation ();
+ Time m_nextStatsUpdate; ///< 10 times every second
+
+ /**
+ * 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
+ uint8_t m_maxTpStreams; ///< number of streams for max TP
+ uint8_t m_maxTp2Streams;///< number of streams for max TP2
+ uint8_t m_maxProbStreams;
+
+ 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_sampleGroup; ///< the group that the sample rate belong to
+ uint8_t m_sampleStreams; ///< the number of streams to use with the sample rate
+
+ 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
+ uint8_t m_txstreams; ///<current transmit streams
+
+ bool m_initialized; ///< for initializing tables
+
+ // MinstrelRate m_minstrelTable; ///< minstrel table
+ HtSampleRate m_sampleTable; ///< sample table
+ McsGroup m_mcsTable; ///< MCS groups table
+
+ //added by zeng
+ bool m_isNewPacketSent;
+ uint32_t m_txrateToUse;
+};
+
+void
+MinstrelHtWifiRemoteStation::DisposeStation ()
+{
+ std::vector<std::vector<uint32_t> >().swap(m_sampleTable);
+ for (uint8_t j=0; j< m_mcsTable.size();j++)
+ std::vector<struct HtRateInfo>().swap(m_mcsTable[j].m_minstrelTable);
+ std::vector<struct GroupInfo> ().swap(m_mcsTable);
+
+}
+
+NS_OBJECT_ENSURE_REGISTERED (MinstrelHtWifiManager);
+
+TypeId
+MinstrelHtWifiManager::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::MinstrelHtWifiManager")
+ .SetParent<WifiRemoteStationManager> ()
+ .AddConstructor<MinstrelHtWifiManager> ()
+ .AddAttribute ("UpdateStatistics",
+ "The interval between updating statistics table ",
+ TimeValue (Seconds (0.1)),
+ MakeTimeAccessor (&MinstrelHtWifiManager::m_updateStats),
+ MakeTimeChecker ())
+ .AddAttribute ("LookAroundRate",
+ "the percentage to try other rates",
+ DoubleValue (10),
+ MakeDoubleAccessor (&MinstrelHtWifiManager::m_lookAroundRate),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("EWMA",
+ "EWMA level",
+ DoubleValue (75),
+ MakeDoubleAccessor (&MinstrelHtWifiManager::m_ewmaLevel),
+ MakeDoubleChecker<double> ())
+ .AddAttribute ("SegmentSize",
+ "The largest allowable segment size packet",
+ DoubleValue (6000),
+ MakeDoubleAccessor (&MinstrelHtWifiManager::m_segmentSize),
+ MakeDoubleChecker <double> ())
+ .AddAttribute ("SampleColumn",
+ "The number of columns used for sampling",
+ DoubleValue (10),
+ MakeDoubleAccessor (&MinstrelHtWifiManager::m_sampleCol),
+ MakeDoubleChecker <double> ())
+ .AddAttribute ("PacketLength",
+ "The packet length used for calculating mode TxTime",
+ DoubleValue (65536),
+ MakeDoubleAccessor (&MinstrelHtWifiManager::m_pktLen),
+ MakeDoubleChecker <double> ())
+ .AddTraceSource ("RateChange",
+ "The transmission rate has changed",
+ MakeTraceSourceAccessor (&MinstrelHtWifiManager::m_rateChange),
+ "ns3::MinstrelHtWifiManager::RateChangeTracedCallback")
+ ;
+ return tid;
+}
+
+MinstrelHtWifiManager::MinstrelHtWifiManager ()
+{
+ m_nsupported = 0;
+}
+
+MinstrelHtWifiManager::~MinstrelHtWifiManager ()
+{
+ m_calcTxTime.clear();
+}
+
+void
+MinstrelHtWifiManager::SetupPhy (Ptr<WifiPhy> phy)
+{
+ //8
+ uint32_t nModes = phy->GetNMcs ();
+ for (uint32_t i = 0; i < nModes; i++)
+ {
+ //WifiMode mode = phy->GetMode (i);
+
+ StringValue DataRate = HtWifiMacHelper::DataRateForMcs (i);
+ WifiTxVector txvector;
+ txvector.SetMode(WifiMode(DataRate.Get()));
+ txvector.SetTxPowerLevel(0);
+ txvector.SetShortGuardInterval(phy->GetGuardInterval());
+ txvector.SetNss(1);
+ txvector.SetNess(0);
+ //txvector.SetStbc(phy->GetStbc());
+ txvector.SetStbc(false);
+ WifiPreamble preamble;
+ if (HasHtSupported())
+ preamble= WIFI_PREAMBLE_HT_MF;
+ else
+ preamble= WIFI_PREAMBLE_LONG;
+ AddCalcTxTime (txvector.GetMode(), phy->CalculateTxDuration (m_pktLen, txvector, preamble, phy->GetFrequency(),0,0));
+ }
+ WifiRemoteStationManager::SetupPhy (phy);
+}
+
+Time
+MinstrelHtWifiManager::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
+MinstrelHtWifiManager::AddCalcTxTime (WifiMode mode, Time t)
+{
+ m_calcTxTime.push_back (std::make_pair (t, mode));
+}
+
+WifiRemoteStation *
+MinstrelHtWifiManager::DoCreateStation (void) const
+{
+ MinstrelHtWifiRemoteStation *station = new MinstrelHtWifiRemoteStation ();
+
+ station->m_nextStatsUpdate = Simulator::Now () + m_updateStats;
+ station->m_col = 0;
+ station->m_index = 0;
+ station->m_maxTpRate = 0;
+ station->m_maxTpRate2 = 0;
+ station->m_maxProbRate = 0;
+ station->m_packetCount = 0;
+ station->m_sampleCount = 0;
+ station->m_isSampling = false;
+ station->m_sampleRate = 0;
+ station->m_sampleRateSlower = false;
+ station->m_currentRate = 0;
+ station->m_shortRetry = 0;
+ station->m_longRetry = 0;
+ station->m_retry = 0;
+ station->m_err = 0;
+ station->m_txrate = 0;
+ station->m_initialized = false;
+ station->m_sampleGroup = 0;
+ station->m_txstreams = 1;
+ station->m_maxTpStreams = 1;
+ station->m_maxTp2Streams = 1;
+ station->m_maxProbStreams = 1;
+ station->m_sampleStreams = 1;
+
+ //added by zeng
+ station->m_isNewPacketSent=false;
+ station->m_txrateToUse = 0;
+
+
+ return station;
+}
+
+void
+MinstrelHtWifiManager::CheckInit (MinstrelHtWifiRemoteStation *station)
+{
+ if (!station->m_initialized && GetNMcsSupported (station) > 1)
+ {
+ // Note: we appear to be doing late initialization of the table
+ // to make sure that the set of supported rates has been initialized
+ // before we perform our own initialization.
+ m_nsupported = GetNMcsSupported(station);
+ //NOTE: to be fixed later, it is hard coded now
+ m_nGroups=1;
+ station->m_mcsTable = McsGroup (m_nGroups);
+ station->m_sampleTable = HtSampleRate (8, std::vector<uint32_t> (m_sampleCol));
+ InitSampleTable (station);
+ RateInit (station);
+ station->m_initialized = true;
+
+ }
+}
+
+void
+MinstrelHtWifiManager::DoReportRxOk (WifiRemoteStation *st,
+ double rxSnr, WifiMode txMode)
+{
+ NS_LOG_DEBUG ("DoReportRxOk m_txrate=" << txMode);
+}
+
+void
+MinstrelHtWifiManager::DoReportRtsFailed (WifiRemoteStation *st)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *)st;
+ NS_LOG_DEBUG ("DoReportRtsFailed m_txrate=" << station->m_txrate);
+
+ station->m_shortRetry++;
+}
+
+void
+MinstrelHtWifiManager::DoReportRtsOk (WifiRemoteStation *st, double ctsSnr, WifiMode ctsMode, double rtsSnr)
+{
+ NS_LOG_DEBUG ("self=" << st << " rts ok");
+}
+
+void
+MinstrelHtWifiManager::DoReportFinalRtsFailed (WifiRemoteStation *st)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *)st;
+ NS_LOG_DEBUG ("Final RTS failed");
+ UpdateRetry (station);
+ station->m_err++;
+}
+
+uint32_t
+MinstrelHtWifiManager::GetRateId(uint32_t rate)
+{
+ uint32_t id;
+ id = rate % 8;
+ return id;
+}
+uint32_t
+MinstrelHtWifiManager::GetGroupId(uint32_t rate, WifiRemoteStation *st, uint8_t txstreams)
+{
+ uint32_t id;
+ //we have 2 groups if we have SGI else we only have 1 group for 40 or 20MHZ channel BW
+ //NOTE: to be fixed later, it is hard coded now
+ id=0;
+ return id;
+}
+
+void
+MinstrelHtWifiManager::DoReportDataFailed (WifiRemoteStation *st)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *)st;
+ /**
+ *
+ * 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
+ */
+
+ CheckInit (station);
+ if (!station->m_initialized)
+ {
+ return;
+ }
+
+ //******************
+// if(!station->m_isNewPacketSent)//if a new packet is not sent yet, don't update the counter and txrate, the idea is to view all AMPDU packets in one A-MPDU as one packet.
+// return;
+
+ station->m_longRetry++;
+ uint32_t rateid = GetRateId (station->m_txrate);
+ uint32_t groupid = GetGroupId (station->m_txrate,station,station->m_txstreams);
+ uint32_t maxtprateid = GetRateId (station->m_maxTpRate);
+ uint32_t maxtpgroupid = GetGroupId (station->m_maxTpRate,station,station->m_maxTpStreams);
+ uint32_t maxtp2rateid = GetRateId (station->m_maxTpRate2);
+ uint32_t maxtp2groupid = GetGroupId (station->m_maxTpRate2,station,station->m_maxTp2Streams);
+ uint32_t samplerateid = GetRateId (station->m_sampleRate);
+ uint32_t samplegroupid = GetGroupId (station->m_sampleRate,station,station->m_sampleStreams);
+
+ station->m_mcsTable[groupid].m_minstrelTable[rateid].numRateAttempt++; // for some reason kept track at FinalDataFail!!!
+
+ NS_LOG_DEBUG ("DoReportDataFailed " << station << "\t rate " << station->m_txrate << "\tlongRetry \t" << station->m_longRetry);
+
+
+ /// for normal rate, we're not currently sampling random rates
+ if (!station->m_isSampling)
+ {
+ /// use best throughput rate
+ if (station->m_longRetry < station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount)
+ {
+ NS_LOG_DEBUG ("Not Sampling use the same rate again");
+ station->m_txrateToUse = station->m_maxTpRate; ///< there's still a few retries left
+ }
+
+ /// use second best throughput rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Not Sampling use the Max TP2");
+ station->m_txrateToUse = station->m_maxTpRate2;
+ }
+
+ /// use best probability rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtp2groupid].m_minstrelTable[maxtp2rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Not Sampling use Max Prob");
+ station->m_txrateToUse = station->m_maxProbRate;
+ }
+
+ /// use lowest base rate
+ else if (station->m_longRetry > ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtp2groupid].m_minstrelTable[maxtp2rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Not Sampling use MCS0");
+ station->m_txrateToUse = 0;
+ }
+ }
+
+ /// for look-around rate, we're currently sampling random rates
+ else
+ {
+ /// current sampling rate is slower than the current best rate
+ if (station->m_sampleRateSlower)
+ {
+ /// use best throughput rate
+ if (station->m_longRetry < station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount)
+ {
+ NS_LOG_DEBUG ("Sampling use the same rate again");
+ station->m_txrateToUse = station->m_maxTpRate;///< there are a few retries left
+ }
+
+ /// use random rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Sampling use the sample rate");
+ station->m_txrateToUse = station->m_sampleRate;
+ }
+
+ /// use max probability rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount ))
+ {
+ NS_LOG_DEBUG ("Sampling use Max prob");
+ station->m_txrateToUse = station->m_maxProbRate;
+ }
+
+ /// use lowest base rate
+ else if (station->m_longRetry > ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Sampling use MCS0");
+ station->m_txrateToUse = 0;
+ }
+ }
+
+ /// current sampling rate is better than current best rate
+ else
+ {
+ /// use random rate
+ if (station->m_longRetry < station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount)
+ {
+ NS_LOG_DEBUG ("Sampling use the same sample rate");
+ station->m_txrateToUse = station->m_sampleRate; ///< keep using it
+ }
+
+ /// use the best rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Sampling use the MaxTP rate");
+ station->m_txrateToUse = station->m_maxTpRate;
+ }
+
+ /// use the best probability rate
+ else if (station->m_longRetry <= ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount +
+ station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Sampling use the MaxProb rate");
+ station->m_txrateToUse =station->m_maxProbRate;
+ }
+
+ /// use the lowest base rate
+ else if (station->m_longRetry > ( station->m_mcsTable[groupid].m_minstrelTable[rateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount +
+ station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("Sampling use the MCS0");
+ station->m_txrateToUse = 0;
+ }
+ }
+ }
+ NS_LOG_DEBUG ("Txrate = " << station->m_txrateToUse );
+
+ //****************
+// station->m_isNewPacketSent=false;
+}
+
+void
+MinstrelHtWifiManager::DoReportDataOk (WifiRemoteStation *st,
+ double ackSnr, WifiMode ackMode, double dataSnr)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *) st;
+ station->m_isSampling = false;
+ station->m_sampleRateSlower = false;
+
+ CheckInit (station);
+ if (!station->m_initialized)
+ {
+ return;
+ }
+
+ //******************
+// if(!station->m_isNewPacketSent)//if a new packet is not sent yet, don't update the counter and txrate, the idea is to view all AMPDU packets in one A-MPDU as one packet.
+// return;
+
+ uint32_t rateid = GetRateId(station->m_txrate);
+ uint32_t groupid = GetGroupId(station->m_txrate,station, station->m_txstreams);
+ station->m_mcsTable[groupid].m_minstrelTable[rateid].numRateSuccess++;
+ station->m_mcsTable[groupid].m_minstrelTable[rateid].numRateAttempt++;
+
+ UpdateRetry (station);
+
+ //station->m_minstrelTable[station->m_txrate].numRateAttempt += station->m_retry;
+ station->m_packetCount++;
+
+ if (m_nsupported >= 1)
+ {
+ station->m_txrateToUse = FindRate (station);
+ }
+ NS_LOG_DEBUG ("Data OK - Txrate = " << station->m_txrate );
+
+ //****************
+// station->m_isNewPacketSent=false;
+}
+
+void
+MinstrelHtWifiManager::DoReportFinalDataFailed (WifiRemoteStation *st)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *) st;
+ NS_LOG_DEBUG ("DoReportFinalDataFailed m_txrate=" << station->m_txrate);
+
+ //******************
+// if(!station->m_isNewPacketSent)//if a new packet is not sent yet, don't update the counter and txrate, the idea is to view all AMPDU packets in one A-MPDU as one packet.
+// return;
+
+ station->m_isSampling = false;
+ station->m_sampleRateSlower = false;
+
+ UpdateRetry (station);
+
+ CheckInit (station);
+ if (!station->m_initialized)
+ {
+ return;
+ }
+
+ uint32_t rateid = GetRateId(station->m_txrate);
+ uint32_t groupid = GetGroupId(station->m_txrate,station,station->m_txstreams );
+ station->m_mcsTable[groupid].m_minstrelTable[rateid].numRateAttempt++;
+ station->m_err++;
+
+ if (m_nsupported >= 1)
+ {
+ station->m_txrateToUse = FindRate (station);
+ }
+ NS_LOG_DEBUG ("Txrate = " << station->m_txrate );
+
+ //****************
+// station->m_isNewPacketSent=false;
+}
+
+void
+MinstrelHtWifiManager::UpdateRetry (MinstrelHtWifiRemoteStation *station)
+{
+ station->m_retry = station->m_shortRetry + station->m_longRetry;
+ station->m_shortRetry = 0;
+ station->m_longRetry = 0;
+}
+
+WifiTxVector
+MinstrelHtWifiManager::DoGetDataTxVector (WifiRemoteStation *st,
+ uint32_t size)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *) st;
+ station->m_txrate=station->m_txrateToUse;
+
+ if (!station->m_isSampling)
+ {
+ m_rateChange (station->m_txrate, station->m_state->m_address);
+ }
+
+ if (!station->m_initialized)
+ {
+
+ CheckInit (station);
+ if (!station->m_initialized)
+ {
+ station->m_txrate = 0;
+ }
+ else
+ {
+ /// start the rate at half way
+ station->m_txrate = m_nsupported / 2;
+ }
+ }
+
+ //****************
+// station->m_isNewPacketSent=true;
+ NS_LOG_DEBUG ("DoGetDataMode m_txrate=" << station->m_txrate << " m_nsupported " << m_nsupported);
+ UpdateStats (station);
+ //if station->txrate == something then this is a 2x2 stream
+ return WifiTxVector (GetMcsSupported (station, station->m_txrate), GetDefaultTxPowerLevel (), st->m_slrc, GetShortGuardInterval (st), 1, 0, GetChannelWidth (st), GetAggregation (st), false);
+}
+
+WifiTxVector
+MinstrelHtWifiManager::DoGetRtsTxVector (WifiRemoteStation *st)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *) st;
+ station->m_txrate=station->m_txrateToUse;
+ NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << station->m_txrate);
+
+ //****************
+// station->m_isNewPacketSent=true;
+ return WifiTxVector (GetMcsSupported (station, 0), GetDefaultTxPowerLevel (), st->m_ssrc, GetShortGuardInterval (st), 1, 0, GetChannelWidth (st), GetAggregation (st), false);
+}
+
+bool
+MinstrelHtWifiManager::DoNeedDataRetransmission (WifiRemoteStation *st, Ptr<const Packet> packet, bool normally)
+{
+ MinstrelHtWifiRemoteStation *station = (MinstrelHtWifiRemoteStation *)st;
+ uint32_t maxprobrateid = GetRateId (station->m_maxProbRate);
+ uint32_t maxprobgroupid = GetGroupId (station->m_maxProbRate,station, station->m_maxProbStreams);
+ uint32_t maxtprateid = GetRateId (station->m_maxTpRate);
+ uint32_t maxtpgroupid = GetGroupId (station->m_maxTpRate,station,station->m_maxTpStreams );
+ uint32_t maxtp2rateid = GetRateId (station->m_maxTpRate2);
+ uint32_t maxtp2groupid = GetGroupId (station->m_maxTpRate2,station,station->m_maxTp2Streams);
+ uint32_t samplerateid = GetRateId (station->m_sampleRate);
+ uint32_t samplegroupid = GetGroupId (station->m_sampleRate,station,station->m_sampleStreams);
+
+ CheckInit (station);
+ if (!station->m_initialized)
+ {
+ return normally;
+ }
+
+ if (!station->m_isSampling)
+ {
+ if (station->m_longRetry > (station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount +
+ station->m_mcsTable[maxtp2groupid].m_minstrelTable[maxtp2rateid].adjustedRetryCount +
+ station->m_mcsTable[maxprobgroupid].m_minstrelTable[maxprobrateid].adjustedRetryCount +
+ station->m_mcsTable[0].m_minstrelTable[0].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("No re-transmission allowed" );
+ return false;
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Re-tranmsit" );
+ return true;
+ }
+ }
+ else
+ {
+ if (station->m_longRetry > (station->m_mcsTable[samplegroupid].m_minstrelTable[samplerateid].adjustedRetryCount +
+ station->m_mcsTable[maxtpgroupid].m_minstrelTable[maxtprateid].adjustedRetryCount +
+ station->m_mcsTable[maxprobgroupid].m_minstrelTable[maxprobrateid].adjustedRetryCount +
+ station->m_mcsTable[0].m_minstrelTable[0].adjustedRetryCount))
+ {
+ NS_LOG_DEBUG ("No re-transmission allowed" );
+ return false;
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Re-tranmsit" );
+ return true;
+ }
+ }
+}
+
+bool
+MinstrelHtWifiManager::IsLowLatency (void) const
+{
+ return true;
+}
+uint8_t
+MinstrelHtWifiManager::GetStreams (uint32_t groupId, MinstrelHtWifiRemoteStation *station)
+{
+ uint8_t nstreams = 1;
+ if (GetShortGuardInterval(station) && m_nGroups > 2)
+ {
+ //SGI is supported and we have more than one stream
+ if (groupId > 2) //group 0 and 1 are SGI and LGI 1 stream
+ nstreams = 2;
+ }
+ else if (!GetShortGuardInterval(station) && m_nGroups > 1)
+ {
+ //SGI is not supported and we have more than one stream
+ if (groupId == 1)
+ nstreams = 2;
+ }
+ return nstreams;
+}
+uint32_t
+MinstrelHtWifiManager::GetNextSample (MinstrelHtWifiRemoteStation *station)
+{
+ uint32_t sampleindex;
+ uint32_t bitrate;
+ sampleindex = station->m_sampleTable[station->m_mcsTable[station->m_sampleGroup].m_index][station->m_mcsTable[station->m_sampleGroup].m_col];
+ bitrate = GetTxRate(station->m_sampleGroup,sampleindex);
+ station->m_mcsTable[station->m_sampleGroup].m_index++;
+ station->m_sampleStreams = GetStreams (station->m_sampleGroup, station);
+ station->m_sampleGroup++;
+ /// bookeeping for m_index and m_col variables
+ station->m_sampleGroup %= m_nGroups;
+ if (station->m_mcsTable[station->m_sampleGroup].m_index > 6)
+ {
+ station->m_mcsTable[station->m_sampleGroup].m_index = 0;
+ station->m_mcsTable[station->m_sampleGroup].m_col++;
+ if (station->m_mcsTable[station->m_sampleGroup].m_col >= m_sampleCol)
+ {
+ station->m_mcsTable[station->m_sampleGroup].m_col = 0;
+ }
+ }
+ NS_LOG_DEBUG ("Next Sample is " << bitrate );
+ return bitrate;
+}
+
+uint32_t
+MinstrelHtWifiManager::FindRate (MinstrelHtWifiRemoteStation *station)
+{
+ NS_LOG_DEBUG ("FindRate " << "packet=" << station->m_packetCount );
+
+ if ((station->m_sampleCount + station->m_packetCount) == 0)
+ {
+ return 0;
+ }
+
+ uint32_t idx;
+
+ /// for determining when to try a sample rate
+ Ptr<UniformRandomVariable> coinFlip = CreateObject<UniformRandomVariable> ();
+ coinFlip->SetAttribute ("Min", DoubleValue (0));
+ coinFlip->SetAttribute ("Max", DoubleValue (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 * station->m_sampleCount) / (station->m_sampleCount + station->m_packetCount )) < m_lookAroundRate)
+ && ((int)coinFlip->GetValue ()) % 2 == 1 )
+ {
+ NS_LOG_DEBUG ("Sampling");
+ /// now go through the table and find an index rate
+ idx = GetNextSample (station);
+ NS_LOG_DEBUG ("Sampling rate = " << idx);
+
+ /**
+ * 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 != station->m_maxTpRate && idx != station->m_txrate)
+ {
+
+ /// start sample count
+ station->m_sampleCount++;
+
+ /// set flag that we are currently sampling
+ station->m_isSampling = true;
+
+ /// bookeeping for resetting stuff
+ if (station->m_packetCount >= 10000)
+ {
+ station->m_sampleCount = 0;
+ station->m_packetCount = 0;
+ }
+
+ /// error check
+ if (idx >= m_nsupported)
+ {
+ NS_LOG_DEBUG ("ALERT!!! ERROR");
+ }
+
+ /// set the rate that we're currently sampling
+ station->m_sampleRate = idx;
+
+ if (station->m_sampleRate == station->m_maxTpRate)
+ {
+ station->m_sampleRate = station->m_maxTpRate2;
+ }
+
+ /// is this rate slower than the current best rate
+ uint32_t idxgroupid = GetGroupId(idx,station, station-> m_sampleStreams);
+ uint32_t idxrateid = GetRateId(idx);
+ uint32_t maxTpgroupid = GetGroupId(station->m_maxTpRate,station,station->m_maxTpStreams);
+ uint32_t maxTprateid = GetRateId(station->m_maxTpRate);
+ station->m_sampleRateSlower =
+ (station->m_mcsTable[idxgroupid].m_minstrelTable[idxrateid].perfectTxTime > station->m_mcsTable[maxTpgroupid].m_minstrelTable[maxTprateid].perfectTxTime);
+
+ /// using the best rate instead
+ if (station->m_sampleRateSlower)
+ {
+ idx = station->m_maxTpRate;
+ }
+ }
+
+ }
+
+ /// continue using the best rate
+ else
+ {
+ idx = station->m_maxTpRate;
+ }
+
+
+ NS_LOG_DEBUG ("FindRate " << "sample rate=" << idx);
+
+ return idx;
+}
+uint32_t
+MinstrelHtWifiManager::GetTxRate(uint32_t groupid, uint32_t index)
+{
+ uint32_t rate;
+ //Group 0 for LGI group 1 for SGI
+ //rate = (groupid*8)+ index;
+ rate=index%8;//to avoid MCS_index >7 to happen
+ return rate;
+}
+void
+MinstrelHtWifiManager::UpdateStats (MinstrelHtWifiRemoteStation *station)
+{
+ if (Simulator::Now () < station->m_nextStatsUpdate)
+ {
+ return;
+ }
+
+ if (!station->m_initialized)
+ {
+ return;
+ }
+ NS_LOG_DEBUG ("Updating stats=" << this);
+
+ station->m_nextStatsUpdate = Simulator::Now () + m_updateStats;
+
+ Time txTime;
+ uint32_t tempProb;
+
+
+ //update throughput and emwa for each rate inside each group
+ for (uint32_t j=0 ; j <m_nGroups ; j++)
+ {
+ for (uint32_t i = 0; i < 8; i++)
+ {
+
+ /// calculate the perfect tx time for this rate
+ txTime = station->m_mcsTable[j].m_minstrelTable[i].perfectTxTime;
+
+ /// just for initialization
+ if (txTime.GetMicroSeconds () == 0)
+ {
+ txTime = Seconds (1);
+ }
+
+ NS_LOG_DEBUG (i << " " << GetMcsSupported (station, GetTxRate(j,i)) <<
+ "\t attempt=" << station->m_mcsTable[j].m_minstrelTable[i].numRateAttempt <<
+ "\t success=" << station->m_mcsTable[j].m_minstrelTable[i].numRateSuccess);
+
+ /// if we've attempted something
+ if (station->m_mcsTable[j].m_minstrelTable[i].numRateAttempt)
+ {
+ /**
+ * calculate the probability of success
+ * assume probability scales from 0 to 18000
+ */
+ tempProb = (station->m_mcsTable[j].m_minstrelTable[i].numRateSuccess * 18000) / station->m_mcsTable[j].m_minstrelTable[i].numRateAttempt;
+
+ /// bookeeping
+ station->m_mcsTable[j].m_minstrelTable[i].prob = tempProb;
+
+ /// ewma probability (cast for gcc 3.4 compatibility)
+ tempProb = static_cast<uint32_t> (((tempProb * (100 - m_ewmaLevel)) + (station->m_mcsTable[j].m_minstrelTable[i].ewmaProb * m_ewmaLevel) ) / 100);
+
+ station->m_mcsTable[j].m_minstrelTable[i].ewmaProb = tempProb;
+
+ /// calculating throughput
+ station->m_mcsTable[j].m_minstrelTable[i].throughput = tempProb * (1000000 / txTime.GetMicroSeconds ());
+
+ }
+
+ /// bookeeping
+ station->m_mcsTable[j].m_minstrelTable[i].numRateSuccess = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].numRateAttempt = 0;
+
+ /// Sample less often below 10% and above 95% of success
+ if ((station->m_mcsTable[j].m_minstrelTable[i].ewmaProb > 17100) || (station->m_mcsTable[j].m_minstrelTable[i].ewmaProb < 1800))
+ {
+ /**
+ * retry count denotes the number of retries permitted for each rate
+ * # retry_count/2
+ */
+
+ if (station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount > 2)
+ {
+ station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount = 2;
+ }
+ else
+ {
+ station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount = station->m_mcsTable[j].m_minstrelTable[i].retryCount;
+ }
+ }
+ else
+ {
+ station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount = station->m_mcsTable[j].m_minstrelTable[i].retryCount;
+ }
+
+ /// if it's 0 allow one retry limit
+ if (station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount == 0)
+ {
+ station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount = 1;
+ }
+ }
+ }
+
+ //for each group get the max tp and maxtp2
+ uint32_t max_prob = 0, index_max_prob = 0, max_tp = 0, index_max_tp = 0, index_max_tp2 = 0;
+ uint32_t index_max_prob_streams =1, index_max_tp_streams =1 , index_max_tp2_streams =1;
+ for (uint32_t j = 0; j <m_nGroups; j++)
+ {
+ 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 < 8; i++)
+ {
+ NS_LOG_DEBUG ("throughput" << station->m_mcsTable[j].m_minstrelTable[i].throughput <<
+ "\n ewma" << station->m_mcsTable[j].m_minstrelTable[i].ewmaProb);
+
+ if (max_tp < station->m_mcsTable[j].m_minstrelTable[i].throughput)
+ {
+ index_max_tp = i;
+ max_tp = station->m_mcsTable[j].m_minstrelTable[i].throughput;
+ }
+
+ if (max_prob < station->m_mcsTable[j].m_minstrelTable[i].ewmaProb)
+ {
+ index_max_prob = i;
+ max_prob = station->m_mcsTable[j].m_minstrelTable[i].ewmaProb;
+ }
+ }
+
+ max_tp = 0;
+ /// find the second highest max
+ for (uint32_t i = 0; i <8; i++)
+ {
+ if ((i != index_max_tp) && (max_tp < station->m_mcsTable[j].m_minstrelTable[i].throughput))
+ {
+ index_max_tp2 = i;
+ max_tp = station->m_mcsTable[j].m_minstrelTable[i].throughput;
+ }
+ }
+
+ station->m_mcsTable[j].m_maxTpRate = index_max_tp;
+ station->m_mcsTable[j].m_maxTpRate2 = index_max_tp2;
+ station->m_mcsTable[j].m_maxProbRate = index_max_prob;
+ }
+
+ max_prob = 0;
+ index_max_prob = 0;
+ max_tp = 0;
+ index_max_tp = 0;
+ index_max_tp2 = 0;
+// get the maxtp and maxtp2 from all groups
+ for (uint32_t j = 0; j < m_nGroups; j++)
+ {
+ /// go find max throughput, second maximum throughput, high probability succ
+
+ if (max_tp < station->m_mcsTable[j].m_minstrelTable[station->m_mcsTable[j].m_maxTpRate].throughput)
+ {
+ index_max_tp = GetTxRate(j, station->m_mcsTable[j].m_maxTpRate);
+ max_tp = station->m_mcsTable[j].m_minstrelTable[station->m_mcsTable[j].m_maxTpRate].throughput;
+ index_max_tp_streams = GetStreams (j, station);
+ }
+
+ if (max_prob < station->m_mcsTable[j].m_minstrelTable[station->m_mcsTable[j].m_maxProbRate].ewmaProb)
+ {
+ index_max_prob = GetTxRate(j,station->m_mcsTable[j].m_maxProbRate);
+ max_prob = station->m_mcsTable[j].m_minstrelTable[station->m_mcsTable[j].m_maxProbRate].ewmaProb;
+ index_max_prob_streams = GetStreams (j, station);
+ }
+}
+ max_tp = 0;
+ /// find the second highest max
+ for (uint32_t i = 0; i <m_nGroups; i++)
+ {
+ if ((GetTxRate(i,station->m_mcsTable[i].m_maxTpRate) != index_max_tp) && (max_tp < station->m_mcsTable[i].m_minstrelTable[station->m_mcsTable[i].m_maxTpRate].throughput))
+ {
+ //finds if another group maxtp is better than the max tp2
+ index_max_tp2 = GetTxRate(i,station->m_mcsTable[i].m_maxTpRate);
+ max_tp = station->m_mcsTable[i].m_minstrelTable[station->m_mcsTable[i].m_maxTpRate].throughput;
+ index_max_tp2_streams = GetStreams (i, station);
+ }
+ if (max_tp < station->m_mcsTable[i].m_minstrelTable[station->m_mcsTable[i].m_maxTpRate2].throughput)
+ {
+ //find if another group maxtp2 is better than maxtp2
+ index_max_tp2 = GetTxRate(i,station->m_mcsTable[i].m_maxTpRate2);
+ max_tp = station->m_mcsTable[i].m_minstrelTable[station->m_mcsTable[i].m_maxTpRate2].throughput;
+ index_max_tp2_streams = GetStreams (i, station);
+ }
+ }
+
+
+ station->m_maxTpRate = index_max_tp;
+ station->m_maxTpStreams = index_max_tp_streams;
+ station->m_maxTpRate2 = index_max_tp2;
+ station->m_maxTp2Streams = index_max_tp2_streams;
+ station->m_maxProbRate = index_max_prob;
+ station->m_maxProbStreams = index_max_prob_streams;
+ station->m_currentRate = index_max_tp;
+
+ ///if the max tp rate is bigger than the current rate and uses the same number of streams
+ if ((index_max_tp > station->m_txrate) &&(index_max_tp_streams >= station->m_txstreams) )
+ {
+ station->m_txrate = index_max_tp;
+ station->m_txstreams = index_max_tp_streams;
+ }
+
+ NS_LOG_DEBUG ("max tp=" << index_max_tp << "\nmax tp2=" << index_max_tp2 << "\nmax prob=" << index_max_prob);
+
+ /// reset it
+ //RateInit (station);
+}
+
+void
+MinstrelHtWifiManager::RateInit (MinstrelHtWifiRemoteStation *station)
+{
+ NS_LOG_DEBUG ("RateInit=" << station);
+
+ for (uint32_t j = 0; j < m_nGroups; j++)
+ {
+ //should include MCS
+ station->m_mcsTable[j].m_minstrelTable = HtMinstrelRate (m_nsupported/m_nGroups);
+ station->m_mcsTable[j].m_col = 0;
+ station->m_mcsTable[j].m_index = 0;
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ station->m_mcsTable[j].m_minstrelTable[i].numRateAttempt = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].numRateSuccess = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].prob = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].ewmaProb = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].prevNumRateAttempt = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].prevNumRateSuccess = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].successHist = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].attemptHist = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].throughput = 0;
+ station->m_mcsTable[j].m_minstrelTable[i].perfectTxTime = GetCalcTxTime (GetMcsSupported (station, GetTxRate(j,i)));
+ station->m_mcsTable[j].m_minstrelTable[i].retryCount = 1;
+ station->m_mcsTable[j].m_minstrelTable[i].adjustedRetryCount = 1;
+ }
+ }
+}
+
+void
+MinstrelHtWifiManager::InitSampleTable (MinstrelHtWifiRemoteStation *station)
+{
+ NS_LOG_DEBUG ("InitSampleTable=" << this);
+
+ station->m_col = station->m_index = 0;
+
+ /// for off-seting to make rates fall between 0 and numrates
+ uint32_t numSampleRates = 8;
+
+ uint32_t newIndex;
+ for (uint32_t col = 0; col < 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
+ */
+ Ptr<UniformRandomVariable> uv = CreateObject<UniformRandomVariable> ();
+ uv->SetAttribute ("Min", DoubleValue (0));
+ uv->SetAttribute ("Max", DoubleValue (numSampleRates));
+
+ newIndex = (i + (uint32_t)uv->GetValue ()) % numSampleRates;
+
+ /// this loop is used for filling in other uninitilized places
+ while (station->m_sampleTable[newIndex][col] != 0)
+ {
+ newIndex = (newIndex + 1) % 8;
+ }
+ station->m_sampleTable[newIndex][col] = i;
+
+ }
+ }
+}
+
+void
+MinstrelHtWifiManager::PrintSampleTable (MinstrelHtWifiRemoteStation *station)
+{
+ NS_LOG_DEBUG ("PrintSampleTable=" << station);
+
+ uint32_t numSampleRates = 8;
+ for (uint32_t i = 0; i < numSampleRates; i++)
+ {
+ for (uint32_t j = 0; j < m_sampleCol; j++)
+ {
+ std::cout << station->m_sampleTable[i][j] << "\t";
+ }
+ std::cout << std::endl;
+ }
+}
+
+void
+MinstrelHtWifiManager::PrintTable (MinstrelHtWifiRemoteStation *station)
+{
+ NS_LOG_DEBUG ("PrintTable=" << station);
+ for (uint32_t j = 0; j < m_nGroups; j++)
+ {
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ std::cout << "index(" << i << ") = " << station->m_mcsTable[j].m_minstrelTable[i].perfectTxTime << "\n";
+ }
+ }
+}
+
+} // namespace ns3
+
+
+
+
+
+