# HG changeset patch # User Matias Richart # Date 1422213706 28800 # Node ID 324c767aefddd3cee4892268de802e77fa9c44d2 # Parent 613c316c7c182b6515c5186ad3737557c9284a32 add PARF and APARF WiFi rate controls diff -r 613c316c7c18 -r 324c767aefdd examples/wireless/power-adaptation-distance.cc --- /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 + */ + +/** + * 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 +#include +#include + +#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 packet); + void RxCallback (std::string path, Ptr 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, Vector position); + void AdvancePosition (Ptr node, int stepsSize, int stepsTime); + Vector GetPosition (Ptr node); + + Gnuplot2dDataset GetDatafile (); + Gnuplot2dDataset GetPowerDatafile (); + +private: + typedef std::vector > TxTime; + void SetupPhy (Ptr phy); + Time GetCalcTxTime (WifiMode mode); + + std::map actualPower; + std::map actualMode; + uint32_t m_bytesTotal; + double totalEnergy; + double totalTime; + Ptr myPhy; + TxTime timeTable; + Gnuplot2dDataset m_output; + Gnuplot2dDataset m_output_power; +}; + +NodeStatistics::NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas) +{ + Ptr device = aps.Get (0); + Ptr wifiDevice = DynamicCast (device); + Ptr phy = wifiDevice->GetPhy (); + myPhy = phy; + SetupPhy (phy); + for (uint32_t j = 0; j < stas.GetN (); j++) + { + Ptr staDevice = stas.Get (j); + Ptr wifiStaDevice = DynamicCast (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 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 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 packet, const Address &from) +{ + m_bytesTotal += packet->GetSize (); +} + +void +NodeStatistics::CheckStatistics (double time) +{ + +} + +void +NodeStatistics::SetPosition (Ptr node, Vector position) +{ + Ptr mobility = node->GetObject (); + mobility->SetPosition (position); +} + +Vector +NodeStatistics::GetPosition (Ptr node) +{ + Ptr mobility = node->GetObject (); + return mobility->GetPosition (); +} + +void +NodeStatistics::AdvancePosition (Ptr 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 positionAlloc = CreateObject (); + //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; +} diff -r 613c316c7c18 -r 324c767aefdd examples/wireless/power-adaptation-interference.cc --- /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 + */ + +/** + * 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 +#include + +#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 packet); + void RxCallback (std::string path, Ptr 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 > TxTime; + void SetupPhy (Ptr phy); + Time GetCalcTxTime (WifiMode mode); + + std::map actualPower; + std::map 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 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 device = aps.Get (0); + Ptr wifiDevice = DynamicCast (device); + Ptr phy = wifiDevice->GetPhy (); + myPhy = phy; + SetupPhy (phy); + for (uint32_t j = 0; j < stas.GetN (); j++) + { + Ptr staDevice = stas.Get (j); + Ptr wifiStaDevice = DynamicCast (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 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 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 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 positionAlloc = CreateObject (); + 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 monitor = flowmon.InstallAll (); + + Simulator::Stop (Seconds (simuTime)); + Simulator::Run (); + + Ptr classifier = DynamicCast (flowmon.GetClassifier ()); + std::map stats = monitor->GetFlowStats (); + for (std::map::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; +} diff -r 613c316c7c18 -r 324c767aefdd examples/wireless/wscript --- 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' diff -r 613c316c7c18 -r 324c767aefdd src/wifi/doc/wifi.rst --- 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. ``_ + +.. [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. ``_ diff -r 613c316c7c18 -r 324c767aefdd src/wifi/model/aparf-wifi-manager.cc --- /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 + */ +#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 () + .AddConstructor () + .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 ()) + .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 ()) + .AddAttribute ("FailThreshold", + "The minimum number of failed transmissions to try a new power or rate.", + UintegerValue (1), + MakeUintegerAccessor (&AparfWifiManager::m_failMax), + MakeUintegerChecker ()) + .AddAttribute ("PowerThreshold", + "The maximum number of power changes.", + UintegerValue (10), + MakeUintegerAccessor (&AparfWifiManager::m_powerMax), + MakeUintegerChecker ()) + .AddAttribute ("Power decrement step", + "Step size for decrement the power.", + UintegerValue (1), + MakeUintegerAccessor (&AparfWifiManager::m_powerDec), + MakeUintegerChecker ()) + .AddAttribute ("Power increment step", + "Step size for increment the power.", + UintegerValue (1), + MakeUintegerAccessor (&AparfWifiManager::m_powerInc), + MakeUintegerChecker ()) + .AddAttribute ("Rate decrement step", + "Step size for decrement the rate.", + UintegerValue (1), + MakeUintegerAccessor (&AparfWifiManager::m_rateDec), + MakeUintegerChecker ()) + .AddAttribute ("Rate increment step", + "Step size for increment the rate.", + UintegerValue (1), + MakeUintegerAccessor (&AparfWifiManager::m_rateInc), + MakeUintegerChecker ()) + .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 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 diff -r 613c316c7c18 -r 324c767aefdd src/wifi/model/aparf-wifi-manager.h --- /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 + */ +#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 Dynamic data rate and transmit power adjustment + * in IEEE 802.11 wireless LANs 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 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 m_powerChange; + /** + * The trace source fired when the transmission rate change + */ + TracedCallback m_rateChange; + +}; + +} // namespace ns3 + +#endif /* APARF_WIFI_MANAGER_H */ diff -r 613c316c7c18 -r 324c767aefdd src/wifi/model/parf-wifi-manager.cc --- /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 + */ + +#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 () + .AddConstructor () + .AddAttribute ("AttemptThreshold", + "The minimum number of transmission attempts to try a new power or rate.", + UintegerValue (15), + MakeUintegerAccessor (&ParfWifiManager::m_attemptThreshold), + MakeUintegerChecker ()) + .AddAttribute ("SuccessThreshold", + "The minimum number of successful transmissions to try a new power or rate.", + UintegerValue (10), + MakeUintegerAccessor (&ParfWifiManager::m_successThreshold), + MakeUintegerChecker ()) + .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 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 diff -r 613c316c7c18 -r 324c767aefdd src/wifi/model/parf-wifi-manager.h --- /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 + */ + +#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 + * Self-management in chaotic wireless deployments, 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 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 m_powerChange; + /** + * The trace source fired when the transmission rate changes. + */ + TracedCallback m_rateChange; + +}; + +} // namespace ns3 + +#endif /* PARF_WIFI_MANAGER_H */ diff -r 613c316c7c18 -r 324c767aefdd src/wifi/test/power-rate-adaptation-test.cc --- /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 + */ + +#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 ConfigureNode (); + + ObjectFactory m_manager; +}; + +PowerRateAdaptationTest::PowerRateAdaptationTest () + : TestCase ("PowerRateAdaptation") +{ +} + +Ptr +PowerRateAdaptationTest::ConfigureNode () +{ + /* + * Create channel model. Is is necessary to configure correctly the phy layer. + */ + Ptr channel = CreateObject (); + + /* + * Create mac layer. We use Adhoc because association is not needed to get supported rates. + */ + Ptr mac = CreateObject (); + mac->ConfigureStandard (WIFI_PHY_STANDARD_80211a); + + /* + * Create mobility model. Is needed by the phy layer for transmission. + */ + Ptr mobility = CreateObject (); + + /* + * Create and configure phy layer. + */ + Ptr dev = CreateObject (); + Ptr phy = CreateObject (); + 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 manager = m_manager.Create (); + + /* + * Create and configure node. Add mac and phy layer and the manager. + */ + Ptr node = CreateObject (); + 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 = ConfigureNode(); + Ptr dev = DynamicCast (node->GetDevice(0)); + Ptr 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 = Create (10); + WifiMode ackMode; + + /* + * To initialize the manager we need to generate a transmission. + */ + Ptr p = Create (); + 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 = ConfigureNode(); + Ptr dev = DynamicCast (node->GetDevice(0)); + Ptr 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 = Create (10); + WifiMode ackMode; + + /* + * To initialize the manager we need to generate a transmission. + */ + Ptr p = Create (); + 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; diff -r 613c316c7c18 -r 324c767aefdd src/wifi/wscript --- 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',