add PARF and APARF WiFi rate controls
authorMatias Richart <mrichart@fing.edu.uy>
Sun, 25 Jan 2015 11:21:46 -0800
changeset 11153 324c767aefdd
parent 11152 613c316c7c18
child 11154 305803f4125c
add PARF and APARF WiFi rate controls
examples/wireless/power-adaptation-distance.cc
examples/wireless/power-adaptation-interference.cc
examples/wireless/wscript
src/wifi/doc/wifi.rst
src/wifi/model/aparf-wifi-manager.cc
src/wifi/model/aparf-wifi-manager.h
src/wifi/model/parf-wifi-manager.cc
src/wifi/model/parf-wifi-manager.h
src/wifi/test/power-rate-adaptation-test.cc
src/wifi/wscript
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/wireless/power-adaptation-distance.cc	Sun Jan 25 11:21:46 2015 -0800
@@ -0,0 +1,472 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014 Universidad de la República - Uruguay
+ *
+ * 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: Matias Richart <mrichart@fing.edu.uy>
+ */
+
+/**
+ * This example program is designed to illustrate the behavior of two
+ * power/rate-adaptive WiFi rate controls; namely, ns3::ParfWifiManager
+ * and ns3::AparfWifiManager.
+ *
+ * The output of this is typically two plot files, named throughput-parf.plt
+ * (or throughput-aparf.plt, if Aparf is used) and power-parf.plt If 
+ * Gnuplot program is available, one can use it to convert the plt file
+ * into an eps file, by running:
+ * \code{.sh}
+ *   gnuplot throughput-parf.plt
+ * \endcode
+ * Also, to enable logging of rate and power changes to the terminal, set this
+ * environment variable:
+ * \code{.sh}
+ *   export NS_LOG=PowerAdaptationDistance=level_info
+ * \endcode
+ *
+ * This simulation consist of 2 nodes, one AP and one STA.
+ * The AP generates UDP traffic with a CBR of 54 Mbps to the STA.
+ * The AP can use any power and rate control mechanism and the STA uses 
+ * only Minstrel rate control.
+ * The STA can be configured to move away from (or towards to) the AP.
+ * By default, the AP is at coordinate (0,0,0) and the STA starts at 
+ * coordinate (5,0,0) (meters) and moves away on the x axis by 1 meter every
+ * second.
+ *
+ * The output consists of:
+ * - A plot of average throughput vs. distance.
+ * - A plot of average transmit power vs. distance.
+ * - (if logging is enabled) the changes of power and rate to standard output.
+ *
+ * The Average Transmit Power is defined as an average of the power
+ * consumed per measurement interval, expressed in milliwatts.  The
+ * power level for each frame transmission is reported by the simulator, 
+ * and the energy consumed is obtained by multiplying the power by the
+ * frame duration.  At every 'stepTime' (defaulting to 1 second), the
+ * total energy for the collection period is divided by the step time 
+ * and converted from dbm to milliwatt units, and this average is 
+ * plotted against time.
+ *
+ * When neither Parf nor Aparf is selected as the rate control, the
+ * generation of the plot of average transmit power vs distance is suppressed
+ * since the other Wifi rate controls do not support the necessary callbacks
+ * for computing the average power.
+ *
+ * To display all the possible arguments and their defaults:
+ * \code{.sh}
+ *   ./waf --run "power-adaptation-distance --help"
+ * \endcode
+ * 
+ * Example usage (selecting Aparf rather than Parf):
+ * \code{.sh}
+ *   ./waf --run "power-adaptation-distance --manager=ns3::AparfWifiManager --outputFileName=aparf"
+ * \endcode
+ *
+ * Another example (moving towards the AP):
+ * \code{.sh}
+ *   ./waf --run "power-adaptation-distance --manager=ns3::AparfWifiManager --outputFileName=aparf --stepsSize=-1 --STA1_x=200"
+ * \endcode
+ *
+ * To enable the log of rate and power changes:
+ * \code{.sh}
+ *   export NS_LOG=PowerAdaptationDistance=level_info
+ * \endcode
+ */
+
+#include <sstream>
+#include <fstream>
+#include <math.h>
+
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/mobility-module.h"
+#include "ns3/wifi-module.h"
+#include "ns3/applications-module.h"
+#include "ns3/stats-module.h"
+#include "ns3/flow-monitor-module.h"
+
+using namespace ns3;
+using namespace std;
+
+NS_LOG_COMPONENT_DEFINE ("PowerAdaptationDistance");
+
+// packet size generated at the AP
+static const uint32_t packetSize = 1420;
+
+class NodeStatistics
+{
+public:
+  NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas);
+
+  void CheckStatistics (double time);
+
+  void PhyCallback (std::string path, Ptr<const Packet> packet);
+  void RxCallback (std::string path, Ptr<const Packet> packet, const Address &from);
+  void PowerCallback (std::string path, uint8_t power, Mac48Address dest);
+  void RateCallback (std::string path, uint32_t rate, Mac48Address dest);
+  void SetPosition (Ptr<Node> node, Vector position);
+  void AdvancePosition (Ptr<Node> node, int stepsSize, int stepsTime);
+  Vector GetPosition (Ptr<Node> node);
+
+  Gnuplot2dDataset GetDatafile ();
+  Gnuplot2dDataset GetPowerDatafile ();
+
+private:
+  typedef std::vector<std::pair<Time,WifiMode> > TxTime;
+  void SetupPhy (Ptr<WifiPhy> phy);
+  Time GetCalcTxTime (WifiMode mode);
+
+  std::map<Mac48Address, uint32_t> actualPower;
+  std::map<Mac48Address, WifiMode> actualMode;
+  uint32_t m_bytesTotal;
+  double totalEnergy;
+  double totalTime;
+  Ptr<WifiPhy> myPhy;
+  TxTime timeTable;
+  Gnuplot2dDataset m_output;
+  Gnuplot2dDataset m_output_power;
+};
+
+NodeStatistics::NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas)
+{
+  Ptr<NetDevice> device = aps.Get (0);
+  Ptr<WifiNetDevice> wifiDevice = DynamicCast<WifiNetDevice> (device);
+  Ptr<WifiPhy> phy = wifiDevice->GetPhy ();
+  myPhy = phy;
+  SetupPhy (phy);
+  for (uint32_t j = 0; j < stas.GetN (); j++)
+    {
+      Ptr<NetDevice> staDevice = stas.Get (j);
+      Ptr<WifiNetDevice> wifiStaDevice = DynamicCast<WifiNetDevice> (staDevice);
+      Mac48Address addr = wifiStaDevice->GetMac ()->GetAddress ();
+      actualPower[addr] = 17;
+      actualMode[addr] = phy->GetMode (0);
+    }
+  actualMode[Mac48Address ("ff:ff:ff:ff:ff:ff")] = phy->GetMode (0);
+  totalEnergy = 0;
+  totalTime = 0;
+  m_bytesTotal = 0;
+  m_output.SetTitle ("Throughput Mbits/s");
+  m_output_power.SetTitle ("Average Transmit Power");
+}
+
+void
+NodeStatistics::SetupPhy (Ptr<WifiPhy> phy)
+{
+  uint32_t nModes = phy->GetNModes ();
+  for (uint32_t i = 0; i < nModes; i++)
+    {
+      WifiMode mode = phy->GetMode (i);
+      WifiTxVector txVector;
+      txVector.SetMode (mode);
+      timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency ()), mode));
+    }
+}
+
+Time
+NodeStatistics::GetCalcTxTime (WifiMode mode)
+{
+  for (TxTime::const_iterator i = timeTable.begin (); i != timeTable.end (); i++)
+    {
+      if (mode == i->second)
+        {
+          return i->first;
+        }
+    }
+  NS_ASSERT (false);
+  return Seconds (0);
+}
+
+void
+NodeStatistics::PhyCallback (std::string path, Ptr<const Packet> packet)
+{
+  WifiMacHeader head;
+  packet->PeekHeader (head);
+  Mac48Address dest = head.GetAddr1 ();
+
+  totalEnergy += actualPower[dest] * GetCalcTxTime (actualMode[dest]).GetSeconds ();
+  totalTime += GetCalcTxTime (actualMode[dest]).GetSeconds ();
+
+}
+
+void
+NodeStatistics::PowerCallback (std::string path, uint8_t power, Mac48Address dest)
+{
+  double   txPowerBaseDbm = myPhy->GetTxPowerStart ();
+  double   txPowerEndDbm = myPhy->GetTxPowerEnd ();
+  uint32_t nTxPower = myPhy->GetNTxPower ();
+  double dbm;
+  if (nTxPower > 1)
+    {
+      dbm = txPowerBaseDbm + power * (txPowerEndDbm - txPowerBaseDbm) / (nTxPower - 1);
+    }
+  else
+    {
+      NS_ASSERT_MSG (txPowerBaseDbm == txPowerEndDbm, "cannot have TxPowerEnd != TxPowerStart with TxPowerLevels == 1");
+      dbm = txPowerBaseDbm;
+    }
+  actualPower[dest] = dbm;
+}
+
+void
+NodeStatistics::RateCallback (std::string path, uint32_t rate, Mac48Address dest)
+{
+  actualMode[dest] = myPhy->GetMode (rate);
+}
+
+void
+NodeStatistics::RxCallback (std::string path, Ptr<const Packet> packet, const Address &from)
+{
+  m_bytesTotal += packet->GetSize ();
+}
+
+void
+NodeStatistics::CheckStatistics (double time)
+{
+
+}
+
+void
+NodeStatistics::SetPosition (Ptr<Node> node, Vector position)
+{
+  Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
+  mobility->SetPosition (position);
+}
+
+Vector
+NodeStatistics::GetPosition (Ptr<Node> node)
+{
+  Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
+  return mobility->GetPosition ();
+}
+
+void
+NodeStatistics::AdvancePosition (Ptr<Node> node, int stepsSize, int stepsTime)
+{
+  Vector pos = GetPosition (node);
+  double mbs = ((m_bytesTotal * 8.0) / (1000000 * stepsTime));
+  m_bytesTotal = 0;
+  double atm = pow (10, ((totalEnergy / stepsTime) / 10));
+  totalEnergy = 0;
+  totalTime = 0;
+  m_output_power.Add (pos.x, atm);
+  m_output.Add (pos.x, mbs);
+  pos.x += stepsSize;
+  SetPosition (node, pos);
+  NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << " sec; setting new position to " << pos);
+  Simulator::Schedule (Seconds (stepsTime), &NodeStatistics::AdvancePosition, this, node, stepsSize, stepsTime);
+}
+
+Gnuplot2dDataset
+NodeStatistics::GetDatafile ()
+{
+  return m_output;
+}
+
+Gnuplot2dDataset
+NodeStatistics::GetPowerDatafile ()
+{
+  return m_output_power;
+}
+
+void PowerCallback (std::string path, uint8_t power, Mac48Address dest)
+{
+  NS_LOG_INFO ((Simulator::Now ()).GetSeconds () << " " << dest << " Power " << (int)power);
+}
+
+void RateCallback (std::string path, uint32_t rate, Mac48Address dest)
+{
+  NS_LOG_INFO ((Simulator::Now ()).GetSeconds () << " " << dest << " Rate " <<  rate);
+}
+
+int main (int argc, char *argv[])
+{
+  double maxPower = 17;
+  double minPower = 0;
+  uint32_t powerLevels = 18;
+
+  uint32_t rtsThreshold = 2346;
+  std::string manager = "ns3::ParfWifiManager";
+  std::string outputFileName = "parf";
+  int ap1_x = 0;
+  int ap1_y = 0;
+  int sta1_x = 5;
+  int sta1_y = 0;
+  uint32_t steps = 200;
+  uint32_t stepsSize = 1;
+  uint32_t stepsTime = 1;
+
+  CommandLine cmd;
+  cmd.AddValue ("manager", "PRC Manager", manager);
+  cmd.AddValue ("rtsThreshold", "RTS threshold", rtsThreshold);
+  cmd.AddValue ("outputFileName", "Output filename", outputFileName);
+  cmd.AddValue ("steps", "How many different distances to try", steps);
+  cmd.AddValue ("stepsTime", "Time on each step", stepsTime);
+  cmd.AddValue ("stepsSize", "Distance between steps", stepsSize);
+  cmd.AddValue ("maxPower", "Maximum available transmission level (dbm).", maxPower);
+  cmd.AddValue ("minPower", "Minimum available transmission level (dbm).", minPower);
+  cmd.AddValue ("powerLevels", "Number of transmission power levels available between "
+                "TxPowerStart and TxPowerEnd included.", powerLevels);
+  cmd.AddValue ("AP1_x", "Position of AP1 in x coordinate", ap1_x);
+  cmd.AddValue ("AP1_y", "Position of AP1 in y coordinate", ap1_y);
+  cmd.AddValue ("STA1_x", "Position of STA1 in x coordinate", sta1_x);
+  cmd.AddValue ("STA1_y", "Position of STA1 in y coordinate", sta1_y);
+  cmd.Parse (argc, argv);
+
+  if (steps == 0)
+    {
+      std::cout << "Exiting without running simulation; steps value of 0" << std::endl;
+    }
+
+  uint32_t simuTime = (steps + 1) * stepsTime;
+
+  // Define the APs
+  NodeContainer wifiApNodes;
+  wifiApNodes.Create (1);
+
+  //Define the STAs
+  NodeContainer wifiStaNodes;
+  wifiStaNodes.Create (1);
+
+  WifiHelper wifi = WifiHelper::Default ();
+  wifi.SetStandard (WIFI_PHY_STANDARD_80211a);
+  NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default ();
+  YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
+  YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
+
+  wifiPhy.SetChannel (wifiChannel.Create ());
+
+  NetDeviceContainer wifiApDevices;
+  NetDeviceContainer wifiStaDevices;
+  NetDeviceContainer wifiDevices;
+
+  //Configure the STA node
+  wifi.SetRemoteStationManager ("ns3::MinstrelWifiManager", "RtsCtsThreshold", UintegerValue (rtsThreshold));
+  wifiPhy.Set ("TxPowerStart", DoubleValue (maxPower));
+  wifiPhy.Set ("TxPowerEnd", DoubleValue (maxPower));
+
+  Ssid ssid = Ssid ("AP");
+  wifiMac.SetType ("ns3::StaWifiMac",
+                   "Ssid", SsidValue (ssid),
+                   "ActiveProbing", BooleanValue (false));
+  wifiStaDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiStaNodes.Get (0)));
+
+  //Configure the AP node
+  wifi.SetRemoteStationManager (manager, "DefaultTxPowerLevel", UintegerValue (maxPower), "RtsCtsThreshold", UintegerValue (rtsThreshold));
+  wifiPhy.Set ("TxPowerStart", DoubleValue (minPower));
+  wifiPhy.Set ("TxPowerEnd", DoubleValue (maxPower));
+  wifiPhy.Set ("TxPowerLevels", UintegerValue (powerLevels));
+
+  ssid = Ssid ("AP");
+  wifiMac.SetType ("ns3::ApWifiMac",
+                   "Ssid", SsidValue (ssid));
+  wifiApDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiApNodes.Get (0)));
+
+  wifiDevices.Add (wifiStaDevices);
+  wifiDevices.Add (wifiApDevices);
+
+  // Configure the mobility.
+  MobilityHelper mobility;
+  Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
+  //Initial position of AP and STA
+  positionAlloc->Add (Vector (ap1_x, ap1_y, 0.0));
+  NS_LOG_INFO ("Setting initial AP position to " << Vector (ap1_x, ap1_y, 0.0));
+  positionAlloc->Add (Vector (sta1_x, sta1_y, 0.0));
+  NS_LOG_INFO ("Setting initial STA position to " << Vector (sta1_x, sta1_y, 0.0));
+  mobility.SetPositionAllocator (positionAlloc);
+  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+  mobility.Install (wifiApNodes.Get (0));
+  mobility.Install (wifiStaNodes.Get (0));
+ 
+  //Statistics counter
+  NodeStatistics statistics = NodeStatistics (wifiApDevices, wifiStaDevices);
+
+  //Move the STA by stepsSize meters every stepsTime seconds
+  Simulator::Schedule (Seconds (0.5 + stepsTime), &NodeStatistics::AdvancePosition, &statistics, wifiStaNodes.Get (0), stepsSize, stepsTime);
+
+  //Configure the IP stack
+  InternetStackHelper stack;
+  stack.Install (wifiApNodes);
+  stack.Install (wifiStaNodes);
+  Ipv4AddressHelper address;
+  address.SetBase ("10.1.1.0", "255.255.255.0");
+  Ipv4InterfaceContainer i = address.Assign (wifiDevices);
+  Ipv4Address sinkAddress = i.GetAddress (0);
+  uint16_t port = 9;
+
+  //Configure the CBR generator
+  PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress, port));
+  ApplicationContainer apps_sink = sink.Install (wifiStaNodes.Get (0));
+
+  OnOffHelper onoff ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress, port));
+  onoff.SetConstantRate (DataRate ("54Mb/s"), packetSize);
+  onoff.SetAttribute ("StartTime", TimeValue (Seconds (0.5)));
+  onoff.SetAttribute ("StopTime", TimeValue (Seconds (simuTime)));
+  ApplicationContainer apps_source = onoff.Install (wifiApNodes.Get (0));
+
+  apps_sink.Start (Seconds (0.5));
+  apps_sink.Stop (Seconds (simuTime));
+
+  //------------------------------------------------------------
+  //-- Setup stats and data collection
+  //--------------------------------------------
+
+  //Register packet receptions to calculate throughput
+  Config::Connect ("/NodeList/1/ApplicationList/*/$ns3::PacketSink/Rx",
+                   MakeCallback (&NodeStatistics::RxCallback, &statistics));
+
+  //Register power and rate changes to calculate the Average Transmit Power
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/PowerChange",
+                   MakeCallback (&NodeStatistics::PowerCallback, &statistics));
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/RateChange",
+                   MakeCallback (&NodeStatistics::RateCallback, &statistics));
+
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin",
+                   MakeCallback (&NodeStatistics::PhyCallback, &statistics));
+
+  //Callbacks to print every change of power and rate
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/PowerChange",
+                   MakeCallback (PowerCallback));
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/RateChange",
+                   MakeCallback (RateCallback));
+
+  Simulator::Stop (Seconds (simuTime));
+  Simulator::Run ();
+
+  std::ofstream outfile (("throughput-" + outputFileName + ".plt").c_str ());
+  Gnuplot gnuplot = Gnuplot (("throughput-" + outputFileName + ".eps").c_str (), "Throughput");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Throughput (Mb/s)");
+  gnuplot.SetTitle ("Throughput (AP to STA) vs time");
+  gnuplot.AddDataset (statistics.GetDatafile ());
+  gnuplot.GenerateOutput (outfile);
+
+  if (manager.compare ("ns3::ParfWifiManager") == 0 ||
+      manager.compare ("ns3::AparfWifiManager") == 0)
+    {
+      std::ofstream outfile2 (("power-" + outputFileName + ".plt").c_str ());
+      gnuplot = Gnuplot (("power-" + outputFileName + ".eps").c_str (), "Average Transmit Power");
+      gnuplot.SetTerminal ("post eps color enhanced");
+      gnuplot.SetLegend ("Time (seconds)", "Power (mW)");
+      gnuplot.SetTitle ("Average transmit power (AP to STA) vs time");
+      gnuplot.AddDataset (statistics.GetPowerDatafile ());
+      gnuplot.GenerateOutput (outfile2);
+    }
+
+  Simulator::Destroy ();
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/wireless/power-adaptation-interference.cc	Sun Jan 25 11:21:46 2015 -0800
@@ -0,0 +1,671 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014 Universidad de la República - Uruguay
+ *
+ * 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: Matias Richart <mrichart@fing.edu.uy>
+ */
+
+/**
+ * This example program is designed to illustrate the behavior of two
+ * power/rate-adaptive WiFi rate controls; namely, ns3::ParfWifiManager
+ * and ns3::AparfWifiManager.
+ *
+ * This simulation consist of 4 nodes, two APs and two STAs.
+ * The APs generates UDP traffic with a CBR of 54 Mbps to the STAs.
+ * The APa use any power and rate control mechanism, and the STAs use only 
+ * Minstrel rate control.
+ * The STAs can be configured to be at any distance from the APs.
+ *
+ * The objective is to test power and rate control in the links with 
+ * interference from the other link.
+ *
+ * The output consists of:
+ * - A plot of average throughput vs. time.
+ * - A plot of average transmit power vs. time.
+ * - Plots for the percentage of time the APs are in each MAC state (IDLE, TX, RX, BUSY)
+ * - If enabled, the changes of power and rate to standard output.
+ * - If enabled, the average throughput, delay, jitter and tx opportunity for the total simulation time.
+ *
+ * Example usage:
+ * \code{.sh}
+ *   ./waf --run "power-adaptation-interference --manager=ns3::AparfWifiManager --outputFileName=aparf"
+ * \endcode
+ *
+ * Another example (changing STAs position):
+ * \code{.sh}
+ *   ./waf --run "power-adaptation-interference --manager=ns3::AparfWifiManager --outputFileName=aparf --STA1_x=5 --STA2_x=205"
+ * \endcode
+ *
+ * To enable the log of rate and power changes:
+ * \code{.sh}
+ *   export NS_LOG=PowerAdaptationInterference=level_info
+ * \endcode
+ */
+
+#include <sstream>
+#include <fstream>
+
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/mobility-module.h"
+#include "ns3/wifi-module.h"
+#include "ns3/applications-module.h"
+#include "ns3/stats-module.h"
+#include "ns3/flow-monitor-module.h"
+
+using namespace ns3;
+using namespace std;
+
+NS_LOG_COMPONENT_DEFINE ("PowerAdaptationInterference");
+
+// packet size generated at the AP
+static const uint32_t packetSize = 1420;
+
+class NodeStatistics
+{
+public:
+  NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas);
+
+  void CheckStatistics (double time);
+
+  void PhyCallback (std::string path, Ptr<const Packet> packet);
+  void RxCallback (std::string path, Ptr<const Packet> packet, const Address &from);
+  void PowerCallback (std::string path, uint8_t power, Mac48Address dest);
+  void RateCallback (std::string path, uint32_t rate, Mac48Address dest);
+  void StateCallback (std::string path, Time init, Time duration, enum WifiPhy::State state);
+
+  Gnuplot2dDataset GetDatafile ();
+  Gnuplot2dDataset GetPowerDatafile ();
+  Gnuplot2dDataset GetIdleDatafile ();
+  Gnuplot2dDataset GetBusyDatafile ();
+  Gnuplot2dDataset GetTxDatafile ();
+  Gnuplot2dDataset GetRxDatafile ();
+
+  double GetBusyTime ();
+
+private:
+  typedef std::vector<std::pair<Time,WifiMode> > TxTime;
+  void SetupPhy (Ptr<WifiPhy> phy);
+  Time GetCalcTxTime (WifiMode mode);
+
+  std::map<Mac48Address, uint32_t> actualPower;
+  std::map<Mac48Address, WifiMode> actualMode;
+  uint32_t m_bytesTotal;
+  double totalEnergy;
+  double totalTime;
+  double busyTime;
+  double idleTime;
+  double txTime;
+  double rxTime;
+  double totalBusyTime;
+  double totalIdleTime;
+  double totalTxTime;
+  double totalRxTime;
+  Ptr<WifiPhy> myPhy;
+  TxTime timeTable;
+  Gnuplot2dDataset m_output;
+  Gnuplot2dDataset m_output_power;
+  Gnuplot2dDataset m_output_idle;
+  Gnuplot2dDataset m_output_busy;
+  Gnuplot2dDataset m_output_rx;
+  Gnuplot2dDataset m_output_tx;
+};
+
+NodeStatistics::NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas)
+{
+  Ptr<NetDevice> device = aps.Get (0);
+  Ptr<WifiNetDevice> wifiDevice = DynamicCast<WifiNetDevice> (device);
+  Ptr<WifiPhy> phy = wifiDevice->GetPhy ();
+  myPhy = phy;
+  SetupPhy (phy);
+  for (uint32_t j = 0; j < stas.GetN (); j++)
+    {
+      Ptr<NetDevice> staDevice = stas.Get (j);
+      Ptr<WifiNetDevice> wifiStaDevice = DynamicCast<WifiNetDevice> (staDevice);
+      Mac48Address addr = wifiStaDevice->GetMac ()->GetAddress ();
+      actualPower[addr] = 17;
+      actualMode[addr] = phy->GetMode (0);
+    }
+  actualMode[Mac48Address ("ff:ff:ff:ff:ff:ff")] = phy->GetMode (0);
+  totalEnergy = 0;
+  totalTime = 0;
+  busyTime = 0;
+  idleTime = 0;
+  txTime = 0;
+  rxTime = 0;
+  totalBusyTime = 0;
+  totalIdleTime = 0;
+  totalTxTime = 0;
+  totalRxTime = 0;
+  m_bytesTotal = 0;
+  m_output.SetTitle ("Throughput Mbits/s");
+  m_output_idle.SetTitle ("Idle Time");
+  m_output_busy.SetTitle ("Busy Time");
+  m_output_rx.SetTitle ("RX Time");
+  m_output_tx.SetTitle ("TX Time");
+}
+
+void
+NodeStatistics::SetupPhy (Ptr<WifiPhy> phy)
+{
+  uint32_t nModes = phy->GetNModes ();
+  for (uint32_t i = 0; i < nModes; i++)
+    {
+      WifiMode mode = phy->GetMode (i);
+      WifiTxVector txVector;
+      txVector.SetMode (mode);
+      timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency ()), mode));
+    }
+}
+
+Time
+NodeStatistics::GetCalcTxTime (WifiMode mode)
+{
+  for (TxTime::const_iterator i = timeTable.begin (); i != timeTable.end (); i++)
+    {
+      if (mode == i->second)
+        {
+          return i->first;
+        }
+    }
+  NS_ASSERT (false);
+  return Seconds (0);
+}
+
+void
+NodeStatistics::PhyCallback (std::string path, Ptr<const Packet> packet)
+{
+  WifiMacHeader head;
+  packet->PeekHeader (head);
+  Mac48Address dest = head.GetAddr1 ();
+
+  totalEnergy += actualPower[dest] * GetCalcTxTime (actualMode[dest]).GetSeconds ();
+  totalTime += GetCalcTxTime (actualMode[dest]).GetSeconds ();
+
+}
+
+void
+NodeStatistics::PowerCallback (std::string path, uint8_t power, Mac48Address dest)
+{
+  double   txPowerBaseDbm = myPhy->GetTxPowerStart ();
+  double   txPowerEndDbm = myPhy->GetTxPowerEnd ();
+  uint32_t nTxPower = myPhy->GetNTxPower ();
+  double dbm;
+  if (nTxPower > 1)
+    {
+      dbm = txPowerBaseDbm + power * (txPowerEndDbm - txPowerBaseDbm) / (nTxPower - 1);
+    }
+  else
+    {
+      NS_ASSERT_MSG (txPowerBaseDbm == txPowerEndDbm, "cannot have TxPowerEnd != TxPowerStart with TxPowerLevels == 1");
+      dbm = txPowerBaseDbm;
+    }
+  actualPower[dest] = dbm;
+}
+
+void
+NodeStatistics::RateCallback (std::string path, uint32_t rate, Mac48Address dest)
+{
+  actualMode[dest] = myPhy->GetMode (rate);
+}
+
+void
+NodeStatistics::StateCallback (std::string path, Time init, Time duration, enum WifiPhy::State state)
+{
+  if (state == WifiPhy::CCA_BUSY)
+    {
+      busyTime += duration.GetSeconds ();
+      totalBusyTime += duration.GetSeconds ();
+    }
+  else if (state == WifiPhy::IDLE)
+    {
+      idleTime += duration.GetSeconds ();
+      totalIdleTime += duration.GetSeconds ();
+    }
+  else if (state == WifiPhy::TX)
+    {
+      txTime += duration.GetSeconds ();
+      totalTxTime += duration.GetSeconds ();
+    }
+  else if (state == WifiPhy::RX)
+    {
+      rxTime += duration.GetSeconds ();
+      totalRxTime += duration.GetSeconds ();
+    }
+}
+
+void
+NodeStatistics::RxCallback (std::string path, Ptr<const Packet> packet, const Address &from)
+{
+  m_bytesTotal += packet->GetSize ();
+}
+
+void
+NodeStatistics::CheckStatistics (double time)
+{
+  double mbs = ((m_bytesTotal * 8.0) / (1000000 * time));
+  m_bytesTotal = 0;
+  double atm = pow (10, ((totalEnergy / time) / 10));
+  totalEnergy = 0;
+  totalTime = 0;
+  m_output_power.Add ((Simulator::Now ()).GetSeconds (), atm);
+  m_output.Add ((Simulator::Now ()).GetSeconds (), mbs);
+
+  m_output_idle.Add ((Simulator::Now ()).GetSeconds (), idleTime * 100);
+  m_output_busy.Add ((Simulator::Now ()).GetSeconds (), busyTime * 100);
+  m_output_tx.Add ((Simulator::Now ()).GetSeconds (), txTime * 100);
+  m_output_rx.Add ((Simulator::Now ()).GetSeconds (), rxTime * 100);
+  busyTime = 0;
+  idleTime = 0;
+  txTime = 0;
+  rxTime = 0;
+
+  Simulator::Schedule (Seconds (time), &NodeStatistics::CheckStatistics, this, time);
+}
+
+Gnuplot2dDataset
+NodeStatistics::GetDatafile ()
+{
+  return m_output;
+}
+
+Gnuplot2dDataset
+NodeStatistics::GetPowerDatafile ()
+{
+  return m_output_power;
+}
+
+Gnuplot2dDataset
+NodeStatistics::GetIdleDatafile ()
+{
+  return m_output_idle;
+}
+
+Gnuplot2dDataset
+NodeStatistics::GetBusyDatafile ()
+{
+  return m_output_busy;
+}
+
+Gnuplot2dDataset
+NodeStatistics::GetRxDatafile ()
+{
+  return m_output_rx;
+}
+
+Gnuplot2dDataset
+NodeStatistics::GetTxDatafile ()
+{
+  return m_output_tx;
+}
+
+double
+NodeStatistics::GetBusyTime ()
+{
+  return totalBusyTime + totalRxTime;
+}
+
+void PowerCallback (std::string path, uint8_t power, Mac48Address dest)
+{
+  NS_LOG_INFO ((Simulator::Now ()).GetSeconds () << " " << dest << " Power " <<  (int)power);
+  // end PowerCallback
+}
+
+void RateCallback (std::string path, uint32_t rate, Mac48Address dest)
+{
+  NS_LOG_INFO ((Simulator::Now ()).GetSeconds () << " " << dest << " Rate " <<  rate);
+  // end PowerCallback
+}
+
+int main (int argc, char *argv[])
+{
+  //LogComponentEnable("ConstantRateWifiManager", LOG_LEVEL_FUNCTION);
+
+  double maxPower = 17;
+  double minPower = 0;
+  uint32_t powerLevels = 18;
+
+  uint32_t rtsThreshold = 2346;
+  std::string manager = "ns3::ParfWifiManager";
+  std::string outputFileName = "parf";
+  int ap1_x = 0;
+  int ap1_y = 0;
+  int sta1_x = 10;
+  int sta1_y = 0;
+  int ap2_x = 200;
+  int ap2_y = 0;
+  int sta2_x = 180;
+  int sta2_y = 0;
+  uint32_t simuTime = 100;
+
+  CommandLine cmd;
+  cmd.AddValue ("manager", "PRC Manager", manager);
+  cmd.AddValue ("rtsThreshold", "RTS threshold", rtsThreshold);
+  cmd.AddValue ("outputFileName", "Output filename", outputFileName);
+  cmd.AddValue ("simuTime", "Total simulation time (sec)", simuTime);
+  cmd.AddValue ("maxPower", "Maximum available transmission level (dbm).", maxPower);
+  cmd.AddValue ("minPower", "Minimum available transmission level (dbm).", minPower);
+  cmd.AddValue ("powerLevels", "Number of transmission power levels available between "
+                "TxPowerStart and TxPowerEnd included.", powerLevels);
+  cmd.AddValue ("AP1_x", "Position of AP1 in x coordinate", ap1_x);
+  cmd.AddValue ("AP1_y", "Position of AP1 in y coordinate", ap1_y);
+  cmd.AddValue ("STA1_x", "Position of STA1 in x coordinate", sta1_x);
+  cmd.AddValue ("STA1_y", "Position of STA1 in y coordinate", sta1_y);
+  cmd.AddValue ("AP2_x", "Position of AP2 in x coordinate", ap2_x);
+  cmd.AddValue ("AP2_y", "Position of AP2 in y coordinate", ap2_y);
+  cmd.AddValue ("STA2_x", "Position of STA2 in x coordinate", sta2_x);
+  cmd.AddValue ("STA2_y", "Position of STA2 in y coordinate", sta2_y);
+  cmd.Parse (argc, argv);
+
+  // Define the APs
+  NodeContainer wifiApNodes;
+  wifiApNodes.Create (2);
+
+  //Define the STAs
+  NodeContainer wifiStaNodes;
+  wifiStaNodes.Create (2);
+
+  WifiHelper wifi = WifiHelper::Default ();
+  wifi.SetStandard (WIFI_PHY_STANDARD_80211a);
+  NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default ();
+  YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
+  YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
+
+  wifiPhy.SetChannel (wifiChannel.Create ());
+
+  NetDeviceContainer wifiApDevices;
+  NetDeviceContainer wifiStaDevices;
+  NetDeviceContainer wifiDevices;
+
+  //Configure the STA nodes
+  wifi.SetRemoteStationManager ("ns3::AarfWifiManager", "RtsCtsThreshold", UintegerValue (rtsThreshold));
+  //wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", "DataMode",StringValue ("ErpOfdmRate6Mbps"),"ControlMode",StringValue ("ErpOfdmRate6Mbps"));
+  wifiPhy.Set ("TxPowerStart", DoubleValue (maxPower));
+  wifiPhy.Set ("TxPowerEnd", DoubleValue (maxPower));
+
+  Ssid ssid = Ssid ("AP0");
+  wifiMac.SetType ("ns3::StaWifiMac",
+                   "Ssid", SsidValue (ssid),
+                   "ActiveProbing", BooleanValue (false),
+                   "MaxMissedBeacons", UintegerValue (1000));
+  wifiStaDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiStaNodes.Get (0)));
+
+  ssid = Ssid ("AP1");
+  wifiMac.SetType ("ns3::StaWifiMac",
+                   "Ssid", SsidValue (ssid),
+                   "ActiveProbing", BooleanValue (false));
+  wifiStaDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiStaNodes.Get (1)));
+
+  //Configure the AP nodes
+  wifi.SetRemoteStationManager (manager, "DefaultTxPowerLevel", UintegerValue (maxPower), "RtsCtsThreshold", UintegerValue (rtsThreshold));
+  wifiPhy.Set ("TxPowerStart", DoubleValue (minPower));
+  wifiPhy.Set ("TxPowerEnd", DoubleValue (maxPower));
+  wifiPhy.Set ("TxPowerLevels", UintegerValue (powerLevels));
+
+  ssid = Ssid ("AP0");
+  wifiMac.SetType ("ns3::ApWifiMac",
+                   "Ssid", SsidValue (ssid));
+  wifiApDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiApNodes.Get (0)));
+
+  ssid = Ssid ("AP1");
+  wifiMac.SetType ("ns3::ApWifiMac",
+                   "Ssid", SsidValue (ssid),
+                   "BeaconInterval", TimeValue (MicroSeconds (103424))); //for avoiding collisions);
+  wifiApDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiApNodes.Get (1)));
+
+  wifiDevices.Add (wifiStaDevices);
+  wifiDevices.Add (wifiApDevices);
+
+  // Configure the mobility.
+  MobilityHelper mobility;
+  Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
+  positionAlloc->Add (Vector (ap1_x, ap1_y, 0.0));
+  positionAlloc->Add (Vector (sta1_x, sta1_y, 0.0));
+  positionAlloc->Add (Vector (ap2_x, ap2_y, 0.0));
+  positionAlloc->Add (Vector (sta2_x, sta2_y, 0.0));
+  mobility.SetPositionAllocator (positionAlloc);
+  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+  mobility.Install (wifiApNodes.Get (0));
+  mobility.Install (wifiStaNodes.Get (0));
+  mobility.Install (wifiApNodes.Get (1));
+  mobility.Install (wifiStaNodes.Get (1));
+
+
+  //Configure the IP stack
+  InternetStackHelper stack;
+  stack.Install (wifiApNodes);
+  stack.Install (wifiStaNodes);
+  Ipv4AddressHelper address;
+  address.SetBase ("10.1.1.0", "255.255.255.0");
+  Ipv4InterfaceContainer i = address.Assign (wifiDevices);
+  Ipv4Address sinkAddress = i.GetAddress (0);
+  Ipv4Address sinkAddress1 = i.GetAddress (1);
+  uint16_t port = 9;
+
+  //Configure the CBR generator
+  PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress, port));
+  ApplicationContainer apps_sink = sink.Install (wifiStaNodes.Get (0));
+
+  OnOffHelper onoff ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress, port));
+  onoff.SetConstantRate (DataRate ("54Mb/s"), packetSize);
+  onoff.SetAttribute ("StartTime", TimeValue (Seconds (0.0)));
+  onoff.SetAttribute ("StopTime", TimeValue (Seconds (100.0)));
+  ApplicationContainer apps_source = onoff.Install (wifiApNodes.Get (0));
+
+  PacketSinkHelper sink1 ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress1, port));
+  apps_sink.Add (sink1.Install (wifiStaNodes.Get (1)));
+
+  OnOffHelper onoff1 ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress1, port));
+  onoff1.SetConstantRate (DataRate ("54Mb/s"), packetSize);
+  onoff1.SetAttribute ("StartTime", TimeValue (Seconds (0.0)));
+  onoff1.SetAttribute ("StopTime", TimeValue (Seconds (100.0)));
+  apps_source.Add (onoff1.Install (wifiApNodes.Get (1)));
+
+  apps_sink.Start (Seconds (0.5));
+  apps_sink.Stop (Seconds (simuTime));
+
+  //------------------------------------------------------------
+  //-- Setup stats and data collection
+  //--------------------------------------------
+
+  //Statistics counters
+  NodeStatistics statisticsAp0 = NodeStatistics (wifiApDevices, wifiStaDevices);
+  NodeStatistics statisticsAp1 = NodeStatistics (wifiApDevices, wifiStaDevices);
+
+  //Register packet receptions to calculate throughput
+  Config::Connect ("/NodeList/2/ApplicationList/*/$ns3::PacketSink/Rx",
+                   MakeCallback (&NodeStatistics::RxCallback, &statisticsAp0));
+  Config::Connect ("/NodeList/3/ApplicationList/*/$ns3::PacketSink/Rx",
+                   MakeCallback (&NodeStatistics::RxCallback, &statisticsAp1));
+
+  //Register power and rate changes to calculate the Average Transmit Power
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/PowerChange",
+                   MakeCallback (&NodeStatistics::PowerCallback, &statisticsAp0));
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/RateChange",
+                   MakeCallback (&NodeStatistics::RateCallback, &statisticsAp0));
+  Config::Connect ("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/PowerChange",
+                   MakeCallback (&NodeStatistics::PowerCallback, &statisticsAp1));
+  Config::Connect ("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/RateChange",
+                   MakeCallback (&NodeStatistics::RateCallback, &statisticsAp1));
+
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin",
+                   MakeCallback (&NodeStatistics::PhyCallback, &statisticsAp0));
+  Config::Connect ("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin",
+                   MakeCallback (&NodeStatistics::PhyCallback, &statisticsAp1));
+
+  //Register States
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phy/$ns3::YansWifiPhy/State/State",
+                   MakeCallback (&NodeStatistics::StateCallback, &statisticsAp0));
+  Config::Connect ("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Phy/$ns3::YansWifiPhy/State/State",
+                   MakeCallback (&NodeStatistics::StateCallback, &statisticsAp1));
+
+  statisticsAp0.CheckStatistics (1);
+  statisticsAp1.CheckStatistics (1);
+
+  //Callbacks to print every change of power and rate
+  Config::Connect ("/NodeList/[0-1]/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/PowerChange",
+                   MakeCallback (PowerCallback));
+  Config::Connect ("/NodeList/[0-1]/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/RateChange",
+                   MakeCallback (RateCallback));
+
+
+  // Calculate Throughput using Flowmonitor
+  //
+
+  FlowMonitorHelper flowmon;
+  Ptr<FlowMonitor> monitor = flowmon.InstallAll ();
+
+  Simulator::Stop (Seconds (simuTime));
+  Simulator::Run ();
+
+  Ptr<Ipv4FlowClassifier> classifier = DynamicCast<Ipv4FlowClassifier> (flowmon.GetClassifier ());
+  std::map<FlowId, FlowMonitor::FlowStats> stats = monitor->GetFlowStats ();
+  for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i = stats.begin (); i != stats.end (); ++i)
+    {
+      Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow (i->first);
+      if ((t.sourceAddress == "10.1.1.3" && t.destinationAddress == "10.1.1.1"))
+        {
+          NS_LOG_INFO ("Flow " << i->first  << " (" << t.sourceAddress << " -> " << t.destinationAddress << ")\n");
+          NS_LOG_INFO ("  Tx Bytes:   " << i->second.txBytes << "\n");
+          NS_LOG_INFO ("  Rx Bytes:   " << i->second.rxBytes << "\n");
+          NS_LOG_UNCOND ("  Throughput to 10.1.1.1: " << i->second.rxBytes * 8.0 / (i->second.timeLastRxPacket.GetSeconds () - i->second.timeFirstTxPacket.GetSeconds ()) / 1024 / 1024  << " Mbps\n");
+          NS_LOG_INFO ("  Mean delay:   " << i->second.delaySum.GetSeconds () / i->second.rxPackets << "\n");
+          NS_LOG_INFO ("  Mean jitter:   " << i->second.jitterSum.GetSeconds () / (i->second.rxPackets - 1) << "\n");
+          NS_LOG_INFO ("  Tx Opp: " << 1 - (statisticsAp0.GetBusyTime () / simuTime));
+        }
+      if ((t.sourceAddress == "10.1.1.4" && t.destinationAddress == "10.1.1.2"))
+        {
+          NS_LOG_INFO ("Flow " << i->first  << " (" << t.sourceAddress << " -> " << t.destinationAddress << ")\n");
+          NS_LOG_INFO ("  Tx Bytes:   " << i->second.txBytes << "\n");
+          NS_LOG_INFO ("  Rx Bytes:   " << i->second.rxBytes << "\n");
+          NS_LOG_UNCOND ("  Throughput to 10.1.1.2: " << i->second.rxBytes * 8.0 / (i->second.timeLastRxPacket.GetSeconds () - i->second.timeFirstTxPacket.GetSeconds ()) / 1024 / 1024  << " Mbps\n");
+          NS_LOG_INFO ("  Mean delay:   " << i->second.delaySum.GetSeconds () / i->second.rxPackets << "\n");
+          NS_LOG_INFO ("  Mean jitter:   " << i->second.jitterSum.GetSeconds () / (i->second.rxPackets - 1) << "\n");
+          NS_LOG_INFO ("  Tx Opp: " << 1 - (statisticsAp1.GetBusyTime () / simuTime));
+        }
+    }
+
+  //Plots for AP0
+  std::ofstream outfileTh0 (("throughput-" + outputFileName + "-0.plt").c_str ());
+  Gnuplot gnuplot = Gnuplot (("throughput-" + outputFileName + "-0.eps").c_str (), "Throughput");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Throughput (Mb/s)");
+  gnuplot.SetTitle ("Throughput (AP0 to STA) vs time");
+  gnuplot.AddDataset (statisticsAp0.GetDatafile ());
+  gnuplot.GenerateOutput (outfileTh0);
+
+  if (manager.compare ("ns3::ParfWifiManager") == 0 ||
+      manager.compare ("ns3::AparfWifiManager") == 0)
+    {
+      std::ofstream outfilePower0 (("power-" + outputFileName + "-0.plt").c_str ());
+      gnuplot = Gnuplot (("power-" + outputFileName + "-0.eps").c_str (), "Average Transmit Power");
+      gnuplot.SetTerminal ("post eps color enhanced");
+      gnuplot.SetLegend ("Time (seconds)", "Power (mW)");
+      gnuplot.SetTitle ("Average transmit power (AP0 to STA) vs time");
+      gnuplot.AddDataset (statisticsAp0.GetPowerDatafile ());
+      gnuplot.GenerateOutput (outfilePower0);
+    } 
+
+  std::ofstream outfileTx0 (("tx-" + outputFileName + "-0.plt").c_str ());
+  gnuplot = Gnuplot (("tx-" + outputFileName + "-0.eps").c_str (), "Time in TX State");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Percent");
+  gnuplot.SetTitle ("Percentage time AP0 in TX state vs time");
+  gnuplot.AddDataset (statisticsAp0.GetTxDatafile ());
+  gnuplot.GenerateOutput (outfileTx0);
+
+  std::ofstream outfileRx0 (("rx-" + outputFileName + "-0.plt").c_str ());
+  gnuplot = Gnuplot (("rx-" + outputFileName + "-0.eps").c_str (), "Time in RX State");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Percent");
+  gnuplot.SetTitle ("Percentage time AP0 in RX state vs time");
+  gnuplot.AddDataset (statisticsAp0.GetRxDatafile ());
+  gnuplot.GenerateOutput (outfileRx0);
+
+  std::ofstream outfileBusy0 (("busy-" + outputFileName + "-0.plt").c_str ());
+  gnuplot = Gnuplot (("busy-" + outputFileName + "-0.eps").c_str (), "Time in Busy State");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Percent");
+  gnuplot.SetTitle ("Percentage time AP0 in Busy state vs time");
+  gnuplot.AddDataset (statisticsAp0.GetBusyDatafile ());
+  gnuplot.GenerateOutput (outfileBusy0);
+
+  std::ofstream outfileIdle0 (("idle-" + outputFileName + "-0.plt").c_str ());
+  gnuplot = Gnuplot (("idle-" + outputFileName + "-0.eps").c_str (), "Time in Idle State");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Percent");
+  gnuplot.SetTitle ("Percentage time AP0 in Idle state vs time");
+  gnuplot.AddDataset (statisticsAp0.GetIdleDatafile ());
+  gnuplot.GenerateOutput (outfileIdle0);
+
+  //Plots for AP1
+  std::ofstream outfileTh1 (("throughput-" + outputFileName + "-1.plt").c_str ());
+  gnuplot = Gnuplot (("throughput-" + outputFileName + "-1.eps").c_str (), "Throughput");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Throughput (Mb/s)");
+  gnuplot.SetTitle ("Throughput (AP1 to STA) vs time");
+  gnuplot.AddDataset (statisticsAp1.GetDatafile ());
+  gnuplot.GenerateOutput (outfileTh1);
+
+  if (manager.compare ("ns3::ParfWifiManager") == 0 ||
+      manager.compare ("ns3::AparfWifiManager") == 0)
+    {
+      std::ofstream outfilePower1 (("power-" + outputFileName + "-1.plt").c_str ());
+      gnuplot = Gnuplot (("power-" + outputFileName + "-1.eps").c_str (), "Average Transmit Power");
+      gnuplot.SetTerminal ("post eps color enhanced");
+      gnuplot.SetLegend ("Time (seconds)", "Power (mW)");
+      gnuplot.SetTitle ("Average transmit power (AP1 to STA) vs time");
+      gnuplot.AddDataset (statisticsAp1.GetPowerDatafile ());
+      gnuplot.GenerateOutput (outfilePower1);
+    } 
+
+  std::ofstream outfileTx1 (("tx-" + outputFileName + "-1.plt").c_str ());
+  gnuplot = Gnuplot (("tx-" + outputFileName + "-1.eps").c_str (), "Time in TX State");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Percent");
+  gnuplot.SetTitle ("Percentage time AP1 in TX state vs time");
+  gnuplot.AddDataset (statisticsAp1.GetTxDatafile ());
+  gnuplot.GenerateOutput (outfileTx1);
+
+  std::ofstream outfileRx1 (("rx-" + outputFileName + "-1.plt").c_str ());
+  gnuplot = Gnuplot (("rx-" + outputFileName + "-1.eps").c_str (), "Time in RX State");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Percent");
+  gnuplot.SetTitle ("Percentage time AP1 in RX state vs time");
+  gnuplot.AddDataset (statisticsAp1.GetRxDatafile ());
+  gnuplot.GenerateOutput (outfileRx1);
+
+  std::ofstream outfileBusy1 (("busy-" + outputFileName + "-1.plt").c_str ());
+  gnuplot = Gnuplot (("busy-" + outputFileName + "-1.eps").c_str (), "Time in Busy State");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Percent");
+  gnuplot.SetTitle ("Percentage time AP1 in Busy state vs time");
+  gnuplot.AddDataset (statisticsAp1.GetBusyDatafile ());
+  gnuplot.GenerateOutput (outfileBusy1);
+
+  std::ofstream outfileIdle1 (("idle-" + outputFileName + "-1.plt").c_str ());
+  gnuplot = Gnuplot (("idle-" + outputFileName + "-1.eps").c_str (), "Time in Idle State");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Percent");
+  gnuplot.SetTitle ("Percentage time AP1 in Idle state vs time");
+  gnuplot.AddDataset (statisticsAp1.GetIdleDatafile ());
+  gnuplot.GenerateOutput (outfileIdle1);
+
+  Simulator::Destroy ();
+
+  return 0;
+}
--- a/examples/wireless/wscript	Sat Jan 24 23:16:24 2015 +0100
+++ b/examples/wireless/wscript	Sun Jan 25 11:21:46 2015 -0800
@@ -57,3 +57,9 @@
 
     obj = bld.create_ns3_program('wifi-sleep', ['core', 'network', 'internet', 'mobility', 'wifi', 'applications', 'energy', 'config-store'])
     obj.source = 'wifi-sleep.cc'
+    
+    obj = bld.create_ns3_program('power-adaptation-distance', ['core', 'mobility', 'wifi', 'applications', 'flow-monitor'])
+    obj.source = 'power-adaptation-distance.cc'
+    
+    obj = bld.create_ns3_program('power-adaptation-interference', ['core', 'mobility', 'wifi', 'applications', 'flow-monitor'])
+    obj.source = 'power-adaptation-interference.cc'
--- a/src/wifi/doc/wifi.rst	Sat Jan 24 23:16:24 2015 +0100
+++ b/src/wifi/doc/wifi.rst	Sun Jan 25 11:21:46 2015 -0800
@@ -598,6 +598,8 @@
 * ``CaraWifiManager`` [kim2006cara]_
 * ``RraaWifiManager`` [wong2006rraa]_
 * ``AarfcdWifiManager`` [maguolo2008aarfcd]_
+* ``ParfWifiManager`` [akella2007parf]_
+* ``AparfWifiManager`` [chevillat2005aparf]_
 
 ConstantRateWifiManager
 =======================
@@ -734,3 +736,7 @@
 .. [wong2006rraa] \ S. Wong, H. Yang, S. Lu, and V. Bharghavan, *Robust Rate Adaptation for 802.11 Wireless Networks*, in Proc. 12th Annual International Conference on Mobile Computing and Networking, 2006
 
 .. [maguolo2008aarfcd] \ F. Maguolo, M. Lacage, and T. Turletti, *Efficient collision detection for auto rate fallback algorithm*, in IEEE Symposium on Computers and Communications, 2008
+
+.. [akella2007parf] \ A. Akella, G. Judd, S. Seshan, and P. Steenkiste, 'Self-management in chaotic wireless deployments', in Wireless Networks, Kluwer Academic Publishers, 2007, 13, 737-755.  `<http://www.cs.odu.edu/~nadeem/classes/cs795-WNS-S13/papers/enter-006.pdf>`_ 
+
+.. [chevillat2005aparf] \  Chevillat, P.; Jelitto, J., and Truong, H. L., 'Dynamic data rate and transmit power adjustment in IEEE 802.11 wireless LANs', in International Journal of Wireless Information Networks, Springer, 2005, 12, 123-145.  `<http://www.cs.mun.ca/~yzchen/papers/papers/rate_adaptation/80211_dynamic_rate_power_adjustment_chevillat_j2005.pdf>`_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/aparf-wifi-manager.cc	Sun Jan 25 11:21:46 2015 -0800
@@ -0,0 +1,338 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014 Universidad de la República - Uruguay
+ *
+ * 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: Matias Richart <mrichart@fing.edu.uy>
+ */
+#include "aparf-wifi-manager.h"
+#include "wifi-phy.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/uinteger.h"
+#include "ns3/trace-source-accessor.h"
+#define Min(a,b) ((a < b) ? a : b)
+NS_LOG_COMPONENT_DEFINE ("ns3::AparfWifiManager");
+
+namespace ns3 {
+
+/**
+ * Hold per-remote-station state for APARF Wifi manager.
+ *
+ * This struct extends from WifiRemoteStation struct to hold additional
+ * information required by the APARF Wifi manager
+ */
+struct
+AparfWifiRemoteStation : public WifiRemoteStation
+{
+  uint32_t m_nSuccess; //!< Number of successful transmission attempts.
+  uint32_t m_nFailed; //!< Number of failed transmission attempts.
+  uint32_t m_pCount; //!< Number of power changes.
+
+  uint32_t m_successThreshold; //!< The minimum number of successful transmissions to try a new power or rate.
+  uint32_t m_failThreshold; //!< The minimum number of failed transmissions to try a new power or rate.
+
+  uint32_t m_rate; //!< Current rate.
+  uint32_t m_rateCrit; //!< Critical rate.
+  uint8_t m_power; //!< Current power.
+
+  uint32_t m_nSupported; //!< Number of supported rates by the remote station.
+  bool m_initialized; //!< For initializing variables.
+
+  AparfWifiManager::State m_aparfState; //!< The estimated state of the channel.
+};
+
+NS_OBJECT_ENSURE_REGISTERED (AparfWifiManager);
+
+TypeId
+AparfWifiManager::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::AparfWifiManager")
+    .SetParent<WifiRemoteStationManager> ()
+    .AddConstructor<AparfWifiManager> ()
+    .AddAttribute ("SuccessThreshold 1",
+                   "The minimum number of successful transmissions in \"High\" state to try a new power or rate.",
+                   UintegerValue (3),
+                   MakeUintegerAccessor (&AparfWifiManager::m_succesMax1),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("SuccessThreshold 2",
+                   "The minimum number of successful transmissions in \"Low\" state to try a new power or rate.",
+                   UintegerValue (10),
+                   MakeUintegerAccessor (&AparfWifiManager::m_succesMax2),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("FailThreshold",
+                   "The minimum number of failed transmissions to try a new power or rate.",
+                   UintegerValue (1),
+                   MakeUintegerAccessor (&AparfWifiManager::m_failMax),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("PowerThreshold",
+                   "The maximum number of power changes.",
+                   UintegerValue (10),
+                   MakeUintegerAccessor (&AparfWifiManager::m_powerMax),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("Power decrement step",
+                   "Step size for decrement the power.",
+                   UintegerValue (1),
+                   MakeUintegerAccessor (&AparfWifiManager::m_powerDec),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("Power increment step",
+                   "Step size for increment the power.",
+                   UintegerValue (1),
+                   MakeUintegerAccessor (&AparfWifiManager::m_powerInc),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("Rate decrement step",
+                   "Step size for decrement the rate.",
+                   UintegerValue (1),
+                   MakeUintegerAccessor (&AparfWifiManager::m_rateDec),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("Rate increment step",
+                   "Step size for increment the rate.",
+                   UintegerValue (1),
+                   MakeUintegerAccessor (&AparfWifiManager::m_rateInc),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddTraceSource ("PowerChange",
+                     "The transmission power has change",
+                     MakeTraceSourceAccessor (&AparfWifiManager::m_powerChange),
+                     "ns3::AparfWifiManager::PowerChangeTracedCallback")
+    .AddTraceSource ("RateChange",
+                     "The transmission rate has change",
+                     MakeTraceSourceAccessor (&AparfWifiManager::m_rateChange),
+                     "ns3::AparfWifiManager::RateChangeTracedCallback")
+  ;
+  return tid;
+}
+
+AparfWifiManager::AparfWifiManager ()
+{
+  NS_LOG_FUNCTION (this);
+}
+AparfWifiManager::~AparfWifiManager ()
+{
+  NS_LOG_FUNCTION (this);
+}
+
+void
+AparfWifiManager::SetupPhy (Ptr<WifiPhy> phy)
+{
+  m_nPower = phy->GetNTxPower ();
+  WifiRemoteStationManager::SetupPhy (phy);
+}
+
+WifiRemoteStation *
+AparfWifiManager::DoCreateStation (void) const
+{
+  NS_LOG_FUNCTION (this);
+  AparfWifiRemoteStation *station = new AparfWifiRemoteStation ();
+
+  station->m_successThreshold = m_succesMax1;
+  station->m_failThreshold = m_failMax;
+  station->m_nSuccess = 0;
+  station->m_nFailed = 0;
+  station->m_pCount = 0;
+  station->m_aparfState = AparfWifiManager::High;
+  station->m_initialized = false;
+
+  NS_LOG_DEBUG ("create station=" << station << ", rate=" << station->m_rate
+                                  << ", power=" << (int)station->m_power);
+
+  return station;
+}
+
+void
+AparfWifiManager::CheckInit (AparfWifiRemoteStation *station)
+{
+  if (!station->m_initialized)
+    {
+      station->m_nSupported = GetNSupported (station);
+      station->m_rate = station->m_nSupported - 1;
+      station->m_power = m_nPower - 1;
+      station->m_rateCrit = 0;
+      m_powerChange (station->m_power, station->m_state->m_address);
+      m_rateChange (station->m_rate, station->m_state->m_address);
+      station->m_initialized = true;
+    }
+}
+
+void AparfWifiManager::DoReportRtsFailed (WifiRemoteStation *station)
+{
+  NS_LOG_FUNCTION (this << station);
+}
+
+void AparfWifiManager::DoReportDataFailed (WifiRemoteStation *st)
+{
+  NS_LOG_FUNCTION (this << st);
+  AparfWifiRemoteStation *station = (AparfWifiRemoteStation *) st;
+  CheckInit (station);
+  station->m_nFailed++;
+  station->m_nSuccess = 0;
+  NS_LOG_DEBUG ("station=" << station << ", rate=" << station->m_rate
+                           << ", power=" << (int)station->m_power);
+
+  if (station->m_aparfState == AparfWifiManager::Low)
+    {
+      station->m_aparfState = AparfWifiManager::High;
+      station->m_successThreshold = m_succesMax1;
+    }
+  else if (station->m_aparfState == AparfWifiManager::Spread)
+    {
+      station->m_aparfState = AparfWifiManager::Low;
+      station->m_successThreshold = m_succesMax2;
+    }
+
+  if (station->m_nFailed == station->m_failThreshold)
+    {
+      station->m_nFailed = 0;
+      station->m_nSuccess = 0;
+      station->m_pCount = 0;
+      if (station->m_power == (m_nPower - 1))
+        {
+          station->m_rateCrit = station->m_rate;
+          if (station->m_rate != 0)
+            {
+              NS_LOG_DEBUG ("station=" << station << " dec rate");
+              station->m_rate -= m_rateDec;
+              m_rateChange (station->m_rate, station->m_state->m_address);
+            }
+        }
+      else
+        {
+          NS_LOG_DEBUG ("station=" << station << " inc power");
+          station->m_power += m_powerInc;
+          m_powerChange (station->m_power, station->m_state->m_address);
+        }
+    }
+}
+void
+AparfWifiManager::DoReportRxOk (WifiRemoteStation *station, double rxSnr, WifiMode txMode)
+{
+  NS_LOG_FUNCTION (this << station << rxSnr << txMode);
+}
+void
+AparfWifiManager::DoReportRtsOk (WifiRemoteStation *station, double ctsSnr,
+                                 WifiMode ctsMode, double rtsSnr)
+{
+  NS_LOG_FUNCTION (this << station << ctsSnr << ctsMode << rtsSnr);
+  NS_LOG_DEBUG ("station=" << station << " rts ok");
+}
+void
+AparfWifiManager::DoReportDataOk (WifiRemoteStation *st, double ackSnr,
+                                  WifiMode ackMode, double dataSnr)
+{
+  NS_LOG_FUNCTION (this << st << ackSnr << ackMode << dataSnr);
+  AparfWifiRemoteStation *station = (AparfWifiRemoteStation *) st;
+  CheckInit (station);
+  station->m_nSuccess++;
+  station->m_nFailed = 0;
+  NS_LOG_DEBUG ("station=" << station << " data ok success=" << station->m_nSuccess << ", rate=" << station->m_rate << ", power=" << (int)station->m_power);
+
+  if ((station->m_aparfState == AparfWifiManager::High) && (station->m_nSuccess >= station->m_successThreshold))
+    {
+      station->m_aparfState = AparfWifiManager::Spread;
+    }
+  else if ((station->m_aparfState == AparfWifiManager::Low) && (station->m_nSuccess >= station->m_successThreshold))
+    {
+      station->m_aparfState = AparfWifiManager::Spread;
+    }
+  else if (station->m_aparfState == AparfWifiManager::Spread)
+    {
+      station->m_aparfState = AparfWifiManager::High;
+      station->m_successThreshold = m_succesMax1;
+    }
+
+  if (station->m_nSuccess == station->m_successThreshold)
+    {
+      station->m_nSuccess = 0;
+      station->m_nFailed = 0;
+      if (station->m_rate == (station->m_state->m_operationalRateSet.size () - 1))
+        {
+          if (station->m_power != 0)
+            {
+              NS_LOG_DEBUG ("station=" << station << " dec power");
+              station->m_power -= m_powerDec;
+              m_powerChange (station->m_power, station->m_state->m_address);
+            }
+        }
+      else
+        {
+          if (station->m_rateCrit == 0)
+            {
+              if (station->m_rate != (station->m_state->m_operationalRateSet.size () - 1))
+                {
+                  NS_LOG_DEBUG ("station=" << station << " inc rate");
+                  station->m_rate += m_rateInc;
+                  m_rateChange (station->m_rate, station->m_state->m_address);
+                }
+            }
+          else
+            {
+              if (station->m_pCount == m_powerMax)
+                {
+                  station->m_power = (m_nPower - 1);
+                  m_powerChange (station->m_power, station->m_state->m_address);
+                  station->m_rate = station->m_rateCrit;
+                  m_rateChange (station->m_rate, station->m_state->m_address);
+                  station->m_pCount = 0;
+                  station->m_rateCrit = 0;
+                }
+              else
+                {
+                  if (station->m_power != 0)
+                    {
+                      station->m_power -= m_powerDec;
+                      m_powerChange (station->m_power, station->m_state->m_address);
+                      station->m_pCount++;
+                    }
+                }
+            }
+        }
+    }
+}
+void
+AparfWifiManager::DoReportFinalRtsFailed (WifiRemoteStation *station)
+{
+  NS_LOG_FUNCTION (this << station);
+}
+void
+AparfWifiManager::DoReportFinalDataFailed (WifiRemoteStation *station)
+{
+  NS_LOG_FUNCTION (this << station);
+}
+
+WifiTxVector
+AparfWifiManager::DoGetDataTxVector (WifiRemoteStation *st, uint32_t size)
+{
+  NS_LOG_FUNCTION (this << st << size);
+  AparfWifiRemoteStation *station = (AparfWifiRemoteStation *) st;
+  CheckInit (station);
+  return WifiTxVector (GetSupported (station, station->m_rate), station->m_power, GetLongRetryCount (station), GetShortGuardInterval (station), Min (GetNumberOfReceiveAntennas (station),GetNumberOfTransmitAntennas ()), GetNumberOfTransmitAntennas (station), GetStbc (station));
+}
+WifiTxVector
+AparfWifiManager::DoGetRtsTxVector (WifiRemoteStation *st)
+{
+  NS_LOG_FUNCTION (this << st);
+  /// \todo we could/should implement the Arf algorithm for
+  /// RTS only by picking a single rate within the BasicRateSet.
+  AparfWifiRemoteStation *station = (AparfWifiRemoteStation *) st;
+  return WifiTxVector (GetSupported (station, 0), GetDefaultTxPowerLevel (), GetShortRetryCount (station), GetShortGuardInterval (station), Min (GetNumberOfReceiveAntennas (station),GetNumberOfTransmitAntennas ()), GetNumberOfTransmitAntennas (station), GetStbc (station));
+}
+
+bool
+AparfWifiManager::IsLowLatency (void) const
+{
+  NS_LOG_FUNCTION (this);
+  return true;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/aparf-wifi-manager.h	Sun Jan 25 11:21:46 2015 -0800
@@ -0,0 +1,131 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014 Universidad de la República - Uruguay
+ *
+ * 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: Matias Richart <mrichart@fing.edu.uy>
+ */
+#ifndef APARF_WIFI_MANAGER_H
+#define APARF_WIFI_MANAGER_H
+
+#include "wifi-remote-station-manager.h"
+
+namespace ns3 {
+
+struct AparfWifiRemoteStation;
+
+/**
+ * \ingroup wifi
+ * APARF Power and rate control algorithm
+ *
+ * This class implements the High Performance power and rate control algorithm
+ * described in <i>Dynamic data rate and transmit power adjustment
+ * in IEEE 802.11 wireless LANs</i> by Chevillat, P.; Jelitto, J.
+ * and Truong, H. L. in International Journal of Wireless Information
+ * Networks, Springer, 2005, 12, 123-145.
+ * http://www.cs.mun.ca/~yzchen/papers/papers/rate_adaptation/80211_dynamic_rate_power_adjustment_chevillat_j2005.pdf
+ *
+ */
+class AparfWifiManager : public WifiRemoteStationManager
+{
+public:
+  /**
+   * Register this type.
+   * \return The object TypeId.
+   */
+  static TypeId GetTypeId (void);
+  AparfWifiManager ();
+  virtual ~AparfWifiManager ();
+
+  virtual void SetupPhy (Ptr<WifiPhy> phy);
+
+  /**
+   * Enumeration of the possible states of the channel.
+   */
+  enum State
+  {
+    High,
+    Low,
+    Spread
+  };
+
+  /**
+   * TracedCallback signature for power change events.
+   *
+   * \param [in] power The new power.
+   * \param [in] address The remote station MAC address.
+   */
+  typedef void (*PowerChangeTracedCallback)(const uint8_t power, const Mac48Address remoteAddress);
+
+  /**
+   * TracedCallback signature for rate change events.
+   *
+   * \param [in] rate The new rate.
+   * \param [in] address The remote station MAC address.
+   */
+  typedef void (*RateChangeTracedCallback)(const uint32_t rate, const Mac48Address remoteAddress);
+
+private:
+  // overriden from base class
+  virtual WifiRemoteStation * DoCreateStation (void) const;
+  virtual void DoReportRxOk (WifiRemoteStation *station,
+                             double rxSnr, WifiMode txMode);
+  virtual void DoReportRtsFailed (WifiRemoteStation *station);
+  virtual void DoReportDataFailed (WifiRemoteStation *station);
+  virtual void DoReportRtsOk (WifiRemoteStation *station,
+                              double ctsSnr, WifiMode ctsMode, double rtsSnr);
+  virtual void DoReportDataOk (WifiRemoteStation *station,
+                               double ackSnr, WifiMode ackMode, double dataSnr);
+  virtual void DoReportFinalRtsFailed (WifiRemoteStation *station);
+  virtual void DoReportFinalDataFailed (WifiRemoteStation *station);
+  virtual WifiTxVector DoGetDataTxVector (WifiRemoteStation *station, uint32_t size);
+  virtual WifiTxVector DoGetRtsTxVector (WifiRemoteStation *station);
+  virtual bool IsLowLatency (void) const;
+
+  /** Check for initializations.
+   *
+   * \param station The remote station.
+   */
+  void CheckInit (AparfWifiRemoteStation *station);
+
+  uint32_t m_succesMax1; //!< The minimum number of successful transmissions in \"High\" state to try a new power or rate.
+  uint32_t m_succesMax2; //!< The minimum number of successful transmissions in \"Low\" state to try a new power or rate.
+  uint32_t m_failMax; //!< The minimum number of failed transmissions to try a new power or rate.
+  uint32_t m_powerMax; //!< The maximum number of power changes.
+  uint32_t m_powerInc; //!< Step size for increment the power.
+  uint32_t m_powerDec; //!< Step size for decrement the power.
+  uint32_t m_rateInc; //!< Step size for increment the rate.
+  uint32_t m_rateDec; //!< Step size for decrement the rate.
+  /**
+   * Number of power levels.
+   * Differently form rate, power levels do not depend on the remote station.
+   * The levels depend only on the physical layer of the device.
+   */
+  uint32_t m_nPower;
+
+  /**
+   * The trace source fired when the transmission power change
+   */
+  TracedCallback<uint8_t, Mac48Address> m_powerChange;
+  /**
+   * The trace source fired when the transmission rate change
+   */
+  TracedCallback<uint32_t, Mac48Address> m_rateChange;
+
+};
+
+} // namespace ns3
+
+#endif /* APARF_WIFI_MANAGER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/parf-wifi-manager.cc	Sun Jan 25 11:21:46 2015 -0800
@@ -0,0 +1,311 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014 Universidad de la República - Uruguay
+ *
+ * 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: Matias Richart <mrichart@fing.edu.uy>
+ */
+
+#include "parf-wifi-manager.h"
+#include "wifi-phy.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/uinteger.h"
+#include "ns3/trace-source-accessor.h"
+
+#define Min(a,b) ((a < b) ? a : b)
+
+NS_LOG_COMPONENT_DEFINE ("ns3::ParfWifiManager");
+
+
+namespace ns3 {
+
+/**
+ * Hold per-remote-station state for PARF Wifi manager.
+ *
+ * This struct extends from WifiRemoteStation struct to hold additional
+ * information required by the PARF Wifi manager
+ */
+struct ParfWifiRemoteStation : public WifiRemoteStation
+{
+  uint32_t m_nAttempt; //!< Number of transmission attempts.
+  uint32_t m_nSuccess; //!< Number of successful transmission attempts.
+  uint32_t m_nFail; //!< Number of failed transmission attempts.
+  bool m_usingRecoveryRate; //!< If using recovery rate.
+  bool m_usingRecoveryPower; //!< If using recovery power.
+  uint32_t m_nRetry; //!< Number of transmission retries.
+
+  uint32_t m_currentRate; //!< Current rate used by the remote station.
+
+  uint8_t m_currentPower; //!< Current power used by the remote station.
+
+  uint32_t m_nSupported; //!< Number of supported rates by the remote station.
+  bool m_initialized; //!< For initializing variables.
+};
+
+NS_OBJECT_ENSURE_REGISTERED (ParfWifiManager);
+
+TypeId
+ParfWifiManager::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::ParfWifiManager")
+    .SetParent<WifiRemoteStationManager> ()
+    .AddConstructor<ParfWifiManager> ()
+    .AddAttribute ("AttemptThreshold",
+                   "The minimum number of transmission attempts to try a new power or rate.",
+                   UintegerValue (15),
+                   MakeUintegerAccessor (&ParfWifiManager::m_attemptThreshold),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("SuccessThreshold",
+                   "The minimum number of successful transmissions to try a new power or rate.",
+                   UintegerValue (10),
+                   MakeUintegerAccessor (&ParfWifiManager::m_successThreshold),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddTraceSource ("PowerChange",
+                     "The transmission power has change",
+                     MakeTraceSourceAccessor (&ParfWifiManager::m_powerChange),
+                     "ns3::ParfWifiManager::PowerChangeTracedCallback")
+    .AddTraceSource ("RateChange",
+                     "The transmission rate has change",
+                     MakeTraceSourceAccessor (&ParfWifiManager::m_rateChange),
+                     "ns3::ParfWifiManager::RateChangeTracedCallback")
+  ;
+  return tid;
+}
+
+ParfWifiManager::ParfWifiManager ()
+{
+  NS_LOG_FUNCTION (this);
+}
+ParfWifiManager::~ParfWifiManager ()
+{
+  NS_LOG_FUNCTION (this);
+}
+
+void
+ParfWifiManager::SetupPhy (Ptr<WifiPhy> phy)
+{
+  m_nPower = phy->GetNTxPower ();
+  WifiRemoteStationManager::SetupPhy (phy);
+}
+
+WifiRemoteStation *
+ParfWifiManager::DoCreateStation (void) const
+{
+  NS_LOG_FUNCTION (this);
+  ParfWifiRemoteStation *station = new ParfWifiRemoteStation ();
+
+  station->m_nSuccess = 0;
+  station->m_nFail = 0;
+  station->m_usingRecoveryRate = false;
+  station->m_usingRecoveryPower = false;
+  station->m_initialized = false;
+  station->m_nRetry = 0;
+  station->m_nAttempt = 0;
+
+  NS_LOG_DEBUG ("create station=" << station << ", timer=" << station->m_nAttempt
+                                  << ", rate=" << station->m_currentRate << ", power=" << (int)station->m_currentPower);
+
+  return station;
+}
+
+void
+ParfWifiManager::CheckInit (ParfWifiRemoteStation *station)
+{
+  if (!station->m_initialized)
+    {
+      station->m_nSupported = GetNSupported (station);
+      station->m_currentRate = station->m_nSupported - 1;
+      station->m_currentPower = m_nPower - 1;
+      m_powerChange (station->m_currentPower, station->m_state->m_address);
+      m_rateChange (station->m_currentRate, station->m_state->m_address);
+      station->m_initialized = true;
+    }
+}
+
+void
+ParfWifiManager::DoReportRtsFailed (WifiRemoteStation *station)
+{
+  NS_LOG_FUNCTION (this << station);
+}
+/**
+ * \internal
+ * It is important to realize that "recovery" mode starts after failure of
+ * the first transmission after a rate increase and ends at the first successful
+ * transmission. Specifically, recovery mode spans retransmissions boundaries.
+ * Fundamentally, ARF handles each data transmission independently, whether it
+ * is the initial transmission of a packet or the retransmission of a packet.
+ * The fundamental reason for this is that there is a backoff between each data
+ * transmission, be it an initial transmission or a retransmission.
+ */
+void
+ParfWifiManager::DoReportDataFailed (WifiRemoteStation *st)
+{
+  NS_LOG_FUNCTION (this << st);
+  ParfWifiRemoteStation *station = (ParfWifiRemoteStation *)st;
+  CheckInit (station);
+  station->m_nAttempt++;
+  station->m_nFail++;
+  station->m_nRetry++;
+  station->m_nSuccess = 0;
+
+  NS_LOG_DEBUG ("station=" << station << " data fail retry=" << station->m_nRetry << ", timer=" << station->m_nAttempt
+                           << ", rate=" << station->m_currentRate << ", power=" << (int)station->m_currentPower);
+  if (station->m_usingRecoveryRate)
+    {
+      NS_ASSERT (station->m_nRetry >= 1);
+      if (station->m_nRetry == 1)
+        {
+          // need recovery fallback
+          if (station->m_currentRate != 0)
+            {
+              NS_LOG_DEBUG ("station=" << station << " dec rate");
+              station->m_currentRate--;
+              m_rateChange (station->m_currentRate, station->m_state->m_address);
+              station->m_usingRecoveryRate = false;
+            }
+        }
+      station->m_nAttempt = 0;
+    }
+  else if (station->m_usingRecoveryPower)
+    {
+      NS_ASSERT (station->m_nRetry >= 1);
+      if (station->m_nRetry == 1)
+        {
+          // need recovery fallback
+          if (station->m_currentPower < m_nPower - 1)
+            {
+              NS_LOG_DEBUG ("station=" << station << " inc power");
+              station->m_currentPower++;
+              m_powerChange (station->m_currentPower, station->m_state->m_address);
+              station->m_usingRecoveryPower = false;
+            }
+        }
+      station->m_nAttempt = 0;
+    }
+  else
+    {
+      NS_ASSERT (station->m_nRetry >= 1);
+      if (((station->m_nRetry - 1) % 2) == 1)
+        {
+          // need normal fallback
+          if (station->m_currentPower == m_nPower - 1)
+            {
+              if (station->m_currentRate != 0)
+                {
+                  NS_LOG_DEBUG ("station=" << station << " dec rate");
+                  station->m_currentRate--;
+                  m_rateChange (station->m_currentRate, station->m_state->m_address);
+                }
+            }
+          else
+            {
+              NS_LOG_DEBUG ("station=" << station << " inc power");
+              station->m_currentPower++;
+              m_powerChange (station->m_currentPower, station->m_state->m_address);
+            }
+        }
+      if (station->m_nRetry >= 2)
+        {
+          station->m_nAttempt = 0;
+        }
+    }
+}
+void
+ParfWifiManager::DoReportRxOk (WifiRemoteStation *station,
+                               double rxSnr, WifiMode txMode)
+{
+  NS_LOG_FUNCTION (this << station << rxSnr << txMode);
+}
+void ParfWifiManager::DoReportRtsOk (WifiRemoteStation *station,
+                                     double ctsSnr, WifiMode ctsMode, double rtsSnr)
+{
+  NS_LOG_FUNCTION (this << station << ctsSnr << ctsMode << rtsSnr);
+  NS_LOG_DEBUG ("station=" << station << " rts ok");
+}
+void ParfWifiManager::DoReportDataOk (WifiRemoteStation *st,
+                                      double ackSnr, WifiMode ackMode, double dataSnr)
+{
+  NS_LOG_FUNCTION (this << st << ackSnr << ackMode << dataSnr);
+  ParfWifiRemoteStation *station = (ParfWifiRemoteStation *) st;
+  CheckInit (station);
+  station->m_nAttempt++;
+  station->m_nSuccess++;
+  station->m_nFail = 0;
+  station->m_usingRecoveryRate = false;
+  station->m_usingRecoveryPower = false;
+  station->m_nRetry = 0;
+  NS_LOG_DEBUG ("station=" << station << " data ok success=" << station->m_nSuccess << ", timer=" << station->m_nAttempt << ", rate=" << station->m_currentRate << ", power=" << (int)station->m_currentPower);
+  if ((station->m_nSuccess == m_successThreshold
+       || station->m_nAttempt == m_attemptThreshold)
+      && (station->m_currentRate < (station->m_state->m_operationalRateSet.size () - 1)))
+    {
+      NS_LOG_DEBUG ("station=" << station << " inc rate");
+      station->m_currentRate++;
+      m_rateChange (station->m_currentRate, station->m_state->m_address);
+      station->m_nAttempt = 0;
+      station->m_nSuccess = 0;
+      station->m_usingRecoveryRate = true;
+    }
+  else if (station->m_nSuccess == m_successThreshold || station->m_nAttempt == m_attemptThreshold)
+    {
+      //we are at the maximum rate, we decrease power
+      if (station->m_currentPower != 0)
+        {
+          NS_LOG_DEBUG ("station=" << station << " dec power");
+          station->m_currentPower--;
+          m_powerChange (station->m_currentPower, station->m_state->m_address);
+        }
+      station->m_nAttempt = 0;
+      station->m_nSuccess = 0;
+      station->m_usingRecoveryPower = true;
+    }
+}
+void
+ParfWifiManager::DoReportFinalRtsFailed (WifiRemoteStation *station)
+{
+  NS_LOG_FUNCTION (this << station);
+}
+void
+ParfWifiManager::DoReportFinalDataFailed (WifiRemoteStation *station)
+{
+  NS_LOG_FUNCTION (this << station);
+}
+
+WifiTxVector
+ParfWifiManager::DoGetDataTxVector (WifiRemoteStation *st, uint32_t size)
+{
+  NS_LOG_FUNCTION (this << st << size);
+  ParfWifiRemoteStation *station = (ParfWifiRemoteStation *) st;
+  CheckInit (station);
+  return WifiTxVector (GetSupported (station, station->m_currentRate), station->m_currentPower, GetLongRetryCount (station), GetShortGuardInterval (station), Min (GetNumberOfReceiveAntennas (station),GetNumberOfTransmitAntennas ()), GetNumberOfTransmitAntennas (station), GetStbc (station));
+}
+WifiTxVector
+ParfWifiManager::DoGetRtsTxVector (WifiRemoteStation *st)
+{
+  NS_LOG_FUNCTION (this << st);
+  /// \todo we could/should implement the Arf algorithm for
+  /// RTS only by picking a single rate within the BasicRateSet.
+  ParfWifiRemoteStation *station = (ParfWifiRemoteStation *) st;
+  return WifiTxVector (GetSupported (station, 0), GetDefaultTxPowerLevel (), GetShortRetryCount (station), GetShortGuardInterval (station), Min (GetNumberOfReceiveAntennas (station),GetNumberOfTransmitAntennas ()), GetNumberOfTransmitAntennas (station), GetStbc (station));
+}
+
+bool
+ParfWifiManager::IsLowLatency (void) const
+{
+  NS_LOG_FUNCTION (this);
+  return true;
+}
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/parf-wifi-manager.h	Sun Jan 25 11:21:46 2015 -0800
@@ -0,0 +1,115 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014 Universidad de la República - Uruguay
+ *
+ * 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: Matias Richart <mrichart@fing.edu.uy>
+ */
+
+#ifndef PARF_WIFI_MANAGER_H
+#define PARF_WIFI_MANAGER_H
+
+#include "wifi-remote-station-manager.h"
+
+namespace ns3 {
+
+struct ParfWifiRemoteStation;
+/**
+ * \ingroup wifi
+ * PARF Rate control algorithm
+ *
+ * This class implements the PARF algorithm as described in
+ * <i>Self-management in chaotic wireless deployments</i>, by
+ * Akella, A.; Judd, G.; Seshan, S. and Steenkiste, P. in
+ * Wireless Networks, Kluwer Academic Publishers, 2007, 13, 737-755
+ * http://www.cs.odu.edu/~nadeem/classes/cs795-WNS-S13/papers/enter-006.pdf
+ *
+ */
+class ParfWifiManager : public WifiRemoteStationManager
+{
+public:
+  /**
+   * Register this type.
+   * \return The object TypeId.
+   */
+  static TypeId GetTypeId (void);
+  ParfWifiManager ();
+  virtual ~ParfWifiManager ();
+
+  virtual void SetupPhy (Ptr<WifiPhy> phy);
+
+  /**
+   * TracedCallback signature for power change events.
+   *
+   * \param [in] power The new power.
+   * \param [in] address The remote station MAC address.
+   */
+  typedef void (*PowerChangeTracedCallback)(const uint8_t power, const Mac48Address remoteAddress);
+
+  /**
+   * TracedCallback signature for rate change events.
+   *
+   * \param [in] rate The new rate.
+   * \param [in] address The remote station MAC address.
+   */
+  typedef void (*RateChangeTracedCallback)(const uint32_t rate, const Mac48Address remoteAddress);
+
+private:
+  // overriden from base class
+  virtual WifiRemoteStation * DoCreateStation (void) const;
+  virtual void DoReportRxOk (WifiRemoteStation *station,
+                             double rxSnr, WifiMode txMode);
+  virtual void DoReportRtsFailed (WifiRemoteStation *station);
+  virtual void DoReportDataFailed (WifiRemoteStation *station);
+  virtual void DoReportRtsOk (WifiRemoteStation *station,
+                              double ctsSnr, WifiMode ctsMode, double rtsSnr);
+  virtual void DoReportDataOk (WifiRemoteStation *station,
+                               double ackSnr, WifiMode ackMode, double dataSnr);
+  virtual void DoReportFinalRtsFailed (WifiRemoteStation *station);
+  virtual void DoReportFinalDataFailed (WifiRemoteStation *station);
+  virtual WifiTxVector DoGetDataTxVector (WifiRemoteStation *station, uint32_t size);
+  virtual WifiTxVector DoGetRtsTxVector (WifiRemoteStation *station);
+  virtual bool IsLowLatency (void) const;
+
+  /** Check for initializations.
+   *
+   * \param station The remote station.
+   */
+  void CheckInit (ParfWifiRemoteStation *station);
+
+
+  uint32_t m_attemptThreshold; //!< The minimum number of transmission attempts to try a new power or rate. The 'timer' threshold in the ARF algorithm.
+  uint32_t m_successThreshold; //!< The minimum number of successful transmissions to try a new power or rate.
+  /**
+   * Number of power levels.
+   * In contrast to rate, power levels do not depend on the remote station.
+   * The levels depend only on the physical layer of the device.
+   */
+  uint32_t m_nPower;
+
+  /**
+   * The trace source fired when the transmission power changes....
+   */
+  TracedCallback<uint8_t, Mac48Address> m_powerChange;
+  /**
+   * The trace source fired when the transmission rate changes.
+   */
+  TracedCallback<uint32_t, Mac48Address> m_rateChange;
+
+};
+
+} // namespace ns3
+
+#endif /* PARF_WIFI_MANAGER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/test/power-rate-adaptation-test.cc	Sun Jan 25 11:21:46 2015 -0800
@@ -0,0 +1,601 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014 Universidad de la República - Uruguay
+ *
+ * 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: Matías Richart <mrichart@fing.edu.uy>
+ */
+
+#include "ns3/wifi-net-device.h"
+#include "ns3/yans-wifi-channel.h"
+#include "ns3/adhoc-wifi-mac.h"
+#include "ns3/yans-wifi-phy.h"
+#include "ns3/parf-wifi-manager.h"
+#include "ns3/propagation-delay-model.h"
+#include "ns3/propagation-loss-model.h"
+#include "ns3/error-rate-model.h"
+#include "ns3/yans-error-rate-model.h"
+#include "ns3/constant-position-mobility-model.h"
+#include "ns3/node.h"
+#include "ns3/simulator.h"
+#include "ns3/test.h"
+#include "ns3/object-factory.h"
+#include "ns3/dca-txop.h"
+#include "ns3/mac-rx-middle.h"
+#include "ns3/pointer.h"
+#include "ns3/rng-seed-manager.h"
+#include "ns3/edca-txop-n.h"
+#include "ns3/config.h"
+#include "ns3/boolean.h"
+
+using namespace ns3;
+
+class PowerRateAdaptationTest : public TestCase
+{
+public:
+  PowerRateAdaptationTest ();
+
+  virtual void DoRun (void);
+private:
+  void TestParf ();
+  void TestAparf ();
+  Ptr<Node> ConfigureNode ();
+
+  ObjectFactory m_manager;
+};
+
+PowerRateAdaptationTest::PowerRateAdaptationTest ()
+  : TestCase ("PowerRateAdaptation")
+{
+}
+
+Ptr<Node>
+PowerRateAdaptationTest::ConfigureNode ()
+{
+  /*
+   * Create channel model. Is is necessary to configure correctly the phy layer.
+   */
+  Ptr<YansWifiChannel> channel = CreateObject<YansWifiChannel> ();
+
+  /*
+   * Create mac layer. We use Adhoc because association is not needed to get supported rates.
+   */
+  Ptr<AdhocWifiMac> mac = CreateObject<AdhocWifiMac> ();
+  mac->ConfigureStandard (WIFI_PHY_STANDARD_80211a);
+
+  /*
+   * Create mobility model. Is needed by the phy layer for transmission.
+   */
+  Ptr<ConstantPositionMobilityModel> mobility = CreateObject<ConstantPositionMobilityModel> ();
+
+  /*
+   * Create and configure phy layer.
+   */
+  Ptr<WifiNetDevice> dev = CreateObject<WifiNetDevice> ();
+  Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy> ();
+  phy->SetChannel (channel);
+  phy->SetDevice (dev);
+  phy->SetMobility (mobility);
+  phy->ConfigureStandard (WIFI_PHY_STANDARD_80211a);
+
+  /*
+   * Configure power control parameters.
+   */
+  phy->SetNTxPower(18);
+  phy->SetTxPowerStart(0);
+  phy->SetTxPowerEnd(17);
+
+  /*
+   * Create manager.
+   */
+  Ptr<WifiRemoteStationManager> manager = m_manager.Create<WifiRemoteStationManager> ();
+
+  /*
+   * Create and configure node. Add mac and phy layer and the manager.
+   */
+  Ptr<Node> node = CreateObject<Node> ();
+  mac->SetAddress (Mac48Address::Allocate ());
+  dev->SetMac (mac);
+  dev->SetPhy (phy);
+  dev->SetRemoteStationManager (manager);
+  node->AddDevice (dev);
+
+  return node;
+}
+
+void
+PowerRateAdaptationTest::TestParf ()
+{
+  m_manager.SetTypeId ("ns3::ParfWifiManager");
+  Ptr<Node> node = ConfigureNode();
+  Ptr<WifiNetDevice> dev = DynamicCast<WifiNetDevice> (node->GetDevice(0));
+  Ptr<WifiRemoteStationManager> manager = dev->GetRemoteStationManager();
+
+  /*
+   * Configure thresholds for rate and power control.
+   */
+  manager->SetAttribute("AttemptThreshold",UintegerValue (15));
+  manager->SetAttribute("SuccessThreshold",UintegerValue(10));
+
+  /*
+   * Create a dummy packet to simulate transmission.
+   */
+  Mac48Address remoteAddress = Mac48Address::Allocate ();
+  WifiMacHeader packetHeader;
+  packetHeader.SetTypeData ();
+  packetHeader.SetQosTid (0);
+  Ptr<Packet> packet = Create<Packet> (10);
+  WifiMode ackMode;
+
+  /*
+   * To initialize the manager we need to generate a transmission.
+   */
+  Ptr<Packet> p = Create<Packet> ();
+  dev->Send (p, remoteAddress, 1);
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * Parf initiates with maximal rate and power.
+   */
+  WifiTxVector txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  WifiMode mode = txVector.GetMode();
+  int power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "PARF: Initial data rate wrong");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "PARF: Initial power level wrong");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * After 10 consecutive successful transmissions parf increase rate or decrease power.
+   * As we are at maximal rate, the power should be decreased. recoveryPower=true.
+   */
+  for(int i = 0; i<10; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "PARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 16, "PARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * As we are using recovery power, one failure make power increase.
+   *
+   */
+  manager->ReportDataFailed(remoteAddress,&packetHeader);
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "PARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "PARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * After 15 transmissions attempts parf increase rate or decrease power.
+   * As we are at maximal rate, the power should be decreased. recoveryPower=true.
+   */
+  for(int i = 0; i<7; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+      manager->ReportDataFailed(remoteAddress,&packetHeader);
+    }
+  manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "PARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 16, "PARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * As we are using recovery power, one failure make power increase. recoveryPower=false.
+   */
+
+  manager->ReportDataFailed(remoteAddress,&packetHeader);
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "PARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "PARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * After two consecutive fails the rate is decreased or the power increased.
+   * As we are at maximal power, the rate should be decreased.
+   */
+  manager->ReportDataFailed(remoteAddress,&packetHeader);
+  manager->ReportDataFailed(remoteAddress,&packetHeader);
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 48000000, "PARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "PARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * After 10 consecutive successful transmissions parf increase rate or decrease power.
+   * As we are not at maximal rate, the rate is increased again. recoveryRate=true.
+   */
+  for(int i = 0; i<10; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "PARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "PARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * As we are using recovery rate, one failure make rate decrease. recoveryRate=false.
+   */
+
+  manager->ReportDataFailed(remoteAddress,&packetHeader);
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 48000000, "PARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "PARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * After 10 consecutive successful transmissions parf increase rate or decrease power.
+   * As we are not at maximal rate, the rate is increased again. recoveryRate=true.
+   */
+  for(int i = 0; i<10; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "PARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "PARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * After 10 consecutive successful transmissions parf increase rate or decrease power.
+   * As we are at maximal rate, the power is decreased. recoveryRate=false, recoveryPower=true.
+   */
+  for(int i = 0; i<10; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "PARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 16, "PARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * One successful transmissions after a power decrease make recoverPower=false.
+   * So we need two consecutive failures to increase power again.
+   */
+  manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+
+  for(int i = 0; i<2; i++)
+    {
+      manager->ReportDataFailed(remoteAddress,&packetHeader);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "PARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "PARF: Incorrect value of power level");
+
+  Simulator::Stop (Seconds (10.0));
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+}
+
+void
+PowerRateAdaptationTest::TestAparf ()
+{
+  m_manager.SetTypeId ("ns3::AparfWifiManager");
+  Ptr<Node> node = ConfigureNode();
+  Ptr<WifiNetDevice> dev = DynamicCast<WifiNetDevice> (node->GetDevice(0));
+  Ptr<WifiRemoteStationManager> manager = dev->GetRemoteStationManager();
+
+  /*
+   * Configure thresholds for rate and power control.
+   */
+  manager->SetAttribute("SuccessThreshold 1",UintegerValue (3));
+  manager->SetAttribute("SuccessThreshold 2",UintegerValue(10));
+  manager->SetAttribute("FailThreshold",UintegerValue (1));
+  manager->SetAttribute("PowerThreshold",UintegerValue(10));
+
+  /*
+   * Create a dummy packet to simulate transmission.
+   */
+  Mac48Address remoteAddress = Mac48Address::Allocate ();
+  WifiMacHeader packetHeader;
+  packetHeader.SetTypeData ();
+  packetHeader.SetQosTid (0);
+  Ptr<Packet> packet = Create<Packet> (10);
+  WifiMode ackMode;
+
+  /*
+   * To initialize the manager we need to generate a transmission.
+   */
+  Ptr<Packet> p = Create<Packet> ();
+  dev->Send (p, remoteAddress, 1);
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * Aparf initiates with maximal rate and power.
+   */
+  WifiTxVector txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  WifiMode mode = txVector.GetMode();
+  int power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "APARF: Initial data rate wrong");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "APARF: Initial power level wrong");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * As Aparf starts in state High, after 3 consecutive successful transmissions aparf increase rate or decrease power.
+   * As we are at maximal rate, the power should be decreased.
+   * Change to state Spread.
+   */
+  for(int i = 0; i<3; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "APARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 16, "APARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * One failure make the power to be increased again.
+   * Change to state Low.
+   */
+  manager->ReportDataFailed(remoteAddress,&packetHeader);
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "APARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "APARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * As we are in state Low we need 10 successful transmissions to increase rate or decrease power.
+   * As we are at maximal rate, the power should be decreased.
+   * Change to state Spread.
+   */
+  for(int i = 0; i<10; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "APARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 16, "APARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * One more successful transmission make to change to state High.
+   * Two more successful transmissions make power decrease.
+   */
+
+  for(int i = 0; i<3; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "APARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 15, "APARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * As we are in state High we need 3 successful transmissions to increase rate or decrease power.
+   * After 16*3 successful transmissions power is decreased to zero.
+   */
+  for(int i = 0; i<16*3; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "APARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 0, "APARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * After one fail the rate is decreased or the power increased.
+   * As we are at minimal power, the power should be increased.
+   */
+  manager->ReportDataFailed(remoteAddress,&packetHeader);
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 1, "Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * After one fail the rate is decreased or the power increased.
+   * After 16 failed transmissions power is increase to 17.
+   */
+  for(int i = 0; i<16; i++)
+    {
+      manager->ReportDataFailed(remoteAddress,&packetHeader);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "APARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "APARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * After one fail the rate is decreased or the power increased.
+   * As we are at maximal power, the rate should be decreased.
+   * Set critical rate to 54 Mbps.
+   */
+  manager->ReportDataFailed(remoteAddress,&packetHeader);
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 48000000, "Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * As we are in state High we need 3 successful transmissions to increase rate or decrease power.
+   * As rate critical is set, after 3 successful transmissions power is decreased.
+   */
+  for(int i = 0; i<3; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 48000000, "APARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 16, "APARF: Incorrect value of power level");
+
+  //-----------------------------------------------------------------------------------------------------
+
+  /*
+   * As we are in state High we need 3 successful transmissions to increase rate or decrease power.
+   * After 10 power changes critical rate is reseted.
+   * So after 10*3 successful transmissions critical rate is set to 0.
+   * And 3 successful transmissions more will make power increase to maximum and rate increase to the critical rate.
+   */
+  for(int i = 0; i<9*3; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 48000000, "APARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 7, "APARF: Incorrect value of power level");
+
+  for(int i = 0; i<3; i++)
+    {
+      manager->ReportDataOk(remoteAddress, &packetHeader, 0, ackMode, 0);
+    }
+
+  txVector = manager->GetDataTxVector(remoteAddress,&packetHeader,packet,packet->GetSize());
+  mode = txVector.GetMode();
+  power = (int) txVector.GetTxPowerLevel();
+
+  NS_TEST_ASSERT_MSG_EQ (mode.GetDataRate(), 54000000, "APARF: Incorrect vale of data rate");
+  NS_TEST_ASSERT_MSG_EQ (power, 17, "APARF: Incorrect value of power level");
+
+  Simulator::Stop (Seconds (10.0));
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+}
+
+void
+PowerRateAdaptationTest::DoRun (void)
+{
+
+  TestParf ();
+  TestAparf ();
+}
+
+//-----------------------------------------------------------------------------
+class PowerRateAdaptationTestSuite : public TestSuite
+{
+public:
+  PowerRateAdaptationTestSuite ();
+};
+
+PowerRateAdaptationTestSuite::PowerRateAdaptationTestSuite ()
+  : TestSuite ("power-rate-adaptation-wifi", UNIT)
+{
+  AddTestCase (new PowerRateAdaptationTest, TestCase::QUICK);
+}
+
+static PowerRateAdaptationTestSuite g_powerRateAdaptationTestSuite;
--- a/src/wifi/wscript	Sat Jan 24 23:16:24 2015 +0100
+++ b/src/wifi/wscript	Sun Jan 25 11:21:46 2015 -0800
@@ -63,6 +63,8 @@
         'model/snr-tag.cc',
         'model/ht-capabilities.cc',
         'model/wifi-tx-vector.cc',
+        'model/parf-wifi-manager.cc',
+        'model/aparf-wifi-manager.cc',
         'helper/ht-wifi-mac-helper.cc',
         'helper/athstats-helper.cc',
         'helper/wifi-helper.cc',
@@ -76,6 +78,7 @@
         'test/block-ack-test-suite.cc',
         'test/dcf-manager-test.cc',
         'test/tx-duration-test.cc',
+        'test/power-rate-adaptation-test.cc',
         'test/wifi-test.cc',
         ]
 
@@ -139,6 +142,8 @@
         'model/block-ack-cache.h',
         'model/snr-tag.h',
         'model/ht-capabilities.h',
+        'model/parf-wifi-manager.h',
+        'model/aparf-wifi-manager.h',
         'model/wifi-tx-vector.h',
         'helper/ht-wifi-mac-helper.h',
         'helper/athstats-helper.h',