examples/wireless/power-adaptation-distance.cc
changeset 11153 324c767aefdd
child 11174 780a43e4980c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/wireless/power-adaptation-distance.cc	Sun Jan 25 11:21:46 2015 -0800
@@ -0,0 +1,472 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014 Universidad de la República - Uruguay
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Matias Richart <mrichart@fing.edu.uy>
+ */
+
+/**
+ * This example program is designed to illustrate the behavior of two
+ * power/rate-adaptive WiFi rate controls; namely, ns3::ParfWifiManager
+ * and ns3::AparfWifiManager.
+ *
+ * The output of this is typically two plot files, named throughput-parf.plt
+ * (or throughput-aparf.plt, if Aparf is used) and power-parf.plt If 
+ * Gnuplot program is available, one can use it to convert the plt file
+ * into an eps file, by running:
+ * \code{.sh}
+ *   gnuplot throughput-parf.plt
+ * \endcode
+ * Also, to enable logging of rate and power changes to the terminal, set this
+ * environment variable:
+ * \code{.sh}
+ *   export NS_LOG=PowerAdaptationDistance=level_info
+ * \endcode
+ *
+ * This simulation consist of 2 nodes, one AP and one STA.
+ * The AP generates UDP traffic with a CBR of 54 Mbps to the STA.
+ * The AP can use any power and rate control mechanism and the STA uses 
+ * only Minstrel rate control.
+ * The STA can be configured to move away from (or towards to) the AP.
+ * By default, the AP is at coordinate (0,0,0) and the STA starts at 
+ * coordinate (5,0,0) (meters) and moves away on the x axis by 1 meter every
+ * second.
+ *
+ * The output consists of:
+ * - A plot of average throughput vs. distance.
+ * - A plot of average transmit power vs. distance.
+ * - (if logging is enabled) the changes of power and rate to standard output.
+ *
+ * The Average Transmit Power is defined as an average of the power
+ * consumed per measurement interval, expressed in milliwatts.  The
+ * power level for each frame transmission is reported by the simulator, 
+ * and the energy consumed is obtained by multiplying the power by the
+ * frame duration.  At every 'stepTime' (defaulting to 1 second), the
+ * total energy for the collection period is divided by the step time 
+ * and converted from dbm to milliwatt units, and this average is 
+ * plotted against time.
+ *
+ * When neither Parf nor Aparf is selected as the rate control, the
+ * generation of the plot of average transmit power vs distance is suppressed
+ * since the other Wifi rate controls do not support the necessary callbacks
+ * for computing the average power.
+ *
+ * To display all the possible arguments and their defaults:
+ * \code{.sh}
+ *   ./waf --run "power-adaptation-distance --help"
+ * \endcode
+ * 
+ * Example usage (selecting Aparf rather than Parf):
+ * \code{.sh}
+ *   ./waf --run "power-adaptation-distance --manager=ns3::AparfWifiManager --outputFileName=aparf"
+ * \endcode
+ *
+ * Another example (moving towards the AP):
+ * \code{.sh}
+ *   ./waf --run "power-adaptation-distance --manager=ns3::AparfWifiManager --outputFileName=aparf --stepsSize=-1 --STA1_x=200"
+ * \endcode
+ *
+ * To enable the log of rate and power changes:
+ * \code{.sh}
+ *   export NS_LOG=PowerAdaptationDistance=level_info
+ * \endcode
+ */
+
+#include <sstream>
+#include <fstream>
+#include <math.h>
+
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/mobility-module.h"
+#include "ns3/wifi-module.h"
+#include "ns3/applications-module.h"
+#include "ns3/stats-module.h"
+#include "ns3/flow-monitor-module.h"
+
+using namespace ns3;
+using namespace std;
+
+NS_LOG_COMPONENT_DEFINE ("PowerAdaptationDistance");
+
+// packet size generated at the AP
+static const uint32_t packetSize = 1420;
+
+class NodeStatistics
+{
+public:
+  NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas);
+
+  void CheckStatistics (double time);
+
+  void PhyCallback (std::string path, Ptr<const Packet> packet);
+  void RxCallback (std::string path, Ptr<const Packet> packet, const Address &from);
+  void PowerCallback (std::string path, uint8_t power, Mac48Address dest);
+  void RateCallback (std::string path, uint32_t rate, Mac48Address dest);
+  void SetPosition (Ptr<Node> node, Vector position);
+  void AdvancePosition (Ptr<Node> node, int stepsSize, int stepsTime);
+  Vector GetPosition (Ptr<Node> node);
+
+  Gnuplot2dDataset GetDatafile ();
+  Gnuplot2dDataset GetPowerDatafile ();
+
+private:
+  typedef std::vector<std::pair<Time,WifiMode> > TxTime;
+  void SetupPhy (Ptr<WifiPhy> phy);
+  Time GetCalcTxTime (WifiMode mode);
+
+  std::map<Mac48Address, uint32_t> actualPower;
+  std::map<Mac48Address, WifiMode> actualMode;
+  uint32_t m_bytesTotal;
+  double totalEnergy;
+  double totalTime;
+  Ptr<WifiPhy> myPhy;
+  TxTime timeTable;
+  Gnuplot2dDataset m_output;
+  Gnuplot2dDataset m_output_power;
+};
+
+NodeStatistics::NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas)
+{
+  Ptr<NetDevice> device = aps.Get (0);
+  Ptr<WifiNetDevice> wifiDevice = DynamicCast<WifiNetDevice> (device);
+  Ptr<WifiPhy> phy = wifiDevice->GetPhy ();
+  myPhy = phy;
+  SetupPhy (phy);
+  for (uint32_t j = 0; j < stas.GetN (); j++)
+    {
+      Ptr<NetDevice> staDevice = stas.Get (j);
+      Ptr<WifiNetDevice> wifiStaDevice = DynamicCast<WifiNetDevice> (staDevice);
+      Mac48Address addr = wifiStaDevice->GetMac ()->GetAddress ();
+      actualPower[addr] = 17;
+      actualMode[addr] = phy->GetMode (0);
+    }
+  actualMode[Mac48Address ("ff:ff:ff:ff:ff:ff")] = phy->GetMode (0);
+  totalEnergy = 0;
+  totalTime = 0;
+  m_bytesTotal = 0;
+  m_output.SetTitle ("Throughput Mbits/s");
+  m_output_power.SetTitle ("Average Transmit Power");
+}
+
+void
+NodeStatistics::SetupPhy (Ptr<WifiPhy> phy)
+{
+  uint32_t nModes = phy->GetNModes ();
+  for (uint32_t i = 0; i < nModes; i++)
+    {
+      WifiMode mode = phy->GetMode (i);
+      WifiTxVector txVector;
+      txVector.SetMode (mode);
+      timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency ()), mode));
+    }
+}
+
+Time
+NodeStatistics::GetCalcTxTime (WifiMode mode)
+{
+  for (TxTime::const_iterator i = timeTable.begin (); i != timeTable.end (); i++)
+    {
+      if (mode == i->second)
+        {
+          return i->first;
+        }
+    }
+  NS_ASSERT (false);
+  return Seconds (0);
+}
+
+void
+NodeStatistics::PhyCallback (std::string path, Ptr<const Packet> packet)
+{
+  WifiMacHeader head;
+  packet->PeekHeader (head);
+  Mac48Address dest = head.GetAddr1 ();
+
+  totalEnergy += actualPower[dest] * GetCalcTxTime (actualMode[dest]).GetSeconds ();
+  totalTime += GetCalcTxTime (actualMode[dest]).GetSeconds ();
+
+}
+
+void
+NodeStatistics::PowerCallback (std::string path, uint8_t power, Mac48Address dest)
+{
+  double   txPowerBaseDbm = myPhy->GetTxPowerStart ();
+  double   txPowerEndDbm = myPhy->GetTxPowerEnd ();
+  uint32_t nTxPower = myPhy->GetNTxPower ();
+  double dbm;
+  if (nTxPower > 1)
+    {
+      dbm = txPowerBaseDbm + power * (txPowerEndDbm - txPowerBaseDbm) / (nTxPower - 1);
+    }
+  else
+    {
+      NS_ASSERT_MSG (txPowerBaseDbm == txPowerEndDbm, "cannot have TxPowerEnd != TxPowerStart with TxPowerLevels == 1");
+      dbm = txPowerBaseDbm;
+    }
+  actualPower[dest] = dbm;
+}
+
+void
+NodeStatistics::RateCallback (std::string path, uint32_t rate, Mac48Address dest)
+{
+  actualMode[dest] = myPhy->GetMode (rate);
+}
+
+void
+NodeStatistics::RxCallback (std::string path, Ptr<const Packet> packet, const Address &from)
+{
+  m_bytesTotal += packet->GetSize ();
+}
+
+void
+NodeStatistics::CheckStatistics (double time)
+{
+
+}
+
+void
+NodeStatistics::SetPosition (Ptr<Node> node, Vector position)
+{
+  Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
+  mobility->SetPosition (position);
+}
+
+Vector
+NodeStatistics::GetPosition (Ptr<Node> node)
+{
+  Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
+  return mobility->GetPosition ();
+}
+
+void
+NodeStatistics::AdvancePosition (Ptr<Node> node, int stepsSize, int stepsTime)
+{
+  Vector pos = GetPosition (node);
+  double mbs = ((m_bytesTotal * 8.0) / (1000000 * stepsTime));
+  m_bytesTotal = 0;
+  double atm = pow (10, ((totalEnergy / stepsTime) / 10));
+  totalEnergy = 0;
+  totalTime = 0;
+  m_output_power.Add (pos.x, atm);
+  m_output.Add (pos.x, mbs);
+  pos.x += stepsSize;
+  SetPosition (node, pos);
+  NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << " sec; setting new position to " << pos);
+  Simulator::Schedule (Seconds (stepsTime), &NodeStatistics::AdvancePosition, this, node, stepsSize, stepsTime);
+}
+
+Gnuplot2dDataset
+NodeStatistics::GetDatafile ()
+{
+  return m_output;
+}
+
+Gnuplot2dDataset
+NodeStatistics::GetPowerDatafile ()
+{
+  return m_output_power;
+}
+
+void PowerCallback (std::string path, uint8_t power, Mac48Address dest)
+{
+  NS_LOG_INFO ((Simulator::Now ()).GetSeconds () << " " << dest << " Power " << (int)power);
+}
+
+void RateCallback (std::string path, uint32_t rate, Mac48Address dest)
+{
+  NS_LOG_INFO ((Simulator::Now ()).GetSeconds () << " " << dest << " Rate " <<  rate);
+}
+
+int main (int argc, char *argv[])
+{
+  double maxPower = 17;
+  double minPower = 0;
+  uint32_t powerLevels = 18;
+
+  uint32_t rtsThreshold = 2346;
+  std::string manager = "ns3::ParfWifiManager";
+  std::string outputFileName = "parf";
+  int ap1_x = 0;
+  int ap1_y = 0;
+  int sta1_x = 5;
+  int sta1_y = 0;
+  uint32_t steps = 200;
+  uint32_t stepsSize = 1;
+  uint32_t stepsTime = 1;
+
+  CommandLine cmd;
+  cmd.AddValue ("manager", "PRC Manager", manager);
+  cmd.AddValue ("rtsThreshold", "RTS threshold", rtsThreshold);
+  cmd.AddValue ("outputFileName", "Output filename", outputFileName);
+  cmd.AddValue ("steps", "How many different distances to try", steps);
+  cmd.AddValue ("stepsTime", "Time on each step", stepsTime);
+  cmd.AddValue ("stepsSize", "Distance between steps", stepsSize);
+  cmd.AddValue ("maxPower", "Maximum available transmission level (dbm).", maxPower);
+  cmd.AddValue ("minPower", "Minimum available transmission level (dbm).", minPower);
+  cmd.AddValue ("powerLevels", "Number of transmission power levels available between "
+                "TxPowerStart and TxPowerEnd included.", powerLevels);
+  cmd.AddValue ("AP1_x", "Position of AP1 in x coordinate", ap1_x);
+  cmd.AddValue ("AP1_y", "Position of AP1 in y coordinate", ap1_y);
+  cmd.AddValue ("STA1_x", "Position of STA1 in x coordinate", sta1_x);
+  cmd.AddValue ("STA1_y", "Position of STA1 in y coordinate", sta1_y);
+  cmd.Parse (argc, argv);
+
+  if (steps == 0)
+    {
+      std::cout << "Exiting without running simulation; steps value of 0" << std::endl;
+    }
+
+  uint32_t simuTime = (steps + 1) * stepsTime;
+
+  // Define the APs
+  NodeContainer wifiApNodes;
+  wifiApNodes.Create (1);
+
+  //Define the STAs
+  NodeContainer wifiStaNodes;
+  wifiStaNodes.Create (1);
+
+  WifiHelper wifi = WifiHelper::Default ();
+  wifi.SetStandard (WIFI_PHY_STANDARD_80211a);
+  NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default ();
+  YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
+  YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
+
+  wifiPhy.SetChannel (wifiChannel.Create ());
+
+  NetDeviceContainer wifiApDevices;
+  NetDeviceContainer wifiStaDevices;
+  NetDeviceContainer wifiDevices;
+
+  //Configure the STA node
+  wifi.SetRemoteStationManager ("ns3::MinstrelWifiManager", "RtsCtsThreshold", UintegerValue (rtsThreshold));
+  wifiPhy.Set ("TxPowerStart", DoubleValue (maxPower));
+  wifiPhy.Set ("TxPowerEnd", DoubleValue (maxPower));
+
+  Ssid ssid = Ssid ("AP");
+  wifiMac.SetType ("ns3::StaWifiMac",
+                   "Ssid", SsidValue (ssid),
+                   "ActiveProbing", BooleanValue (false));
+  wifiStaDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiStaNodes.Get (0)));
+
+  //Configure the AP node
+  wifi.SetRemoteStationManager (manager, "DefaultTxPowerLevel", UintegerValue (maxPower), "RtsCtsThreshold", UintegerValue (rtsThreshold));
+  wifiPhy.Set ("TxPowerStart", DoubleValue (minPower));
+  wifiPhy.Set ("TxPowerEnd", DoubleValue (maxPower));
+  wifiPhy.Set ("TxPowerLevels", UintegerValue (powerLevels));
+
+  ssid = Ssid ("AP");
+  wifiMac.SetType ("ns3::ApWifiMac",
+                   "Ssid", SsidValue (ssid));
+  wifiApDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiApNodes.Get (0)));
+
+  wifiDevices.Add (wifiStaDevices);
+  wifiDevices.Add (wifiApDevices);
+
+  // Configure the mobility.
+  MobilityHelper mobility;
+  Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
+  //Initial position of AP and STA
+  positionAlloc->Add (Vector (ap1_x, ap1_y, 0.0));
+  NS_LOG_INFO ("Setting initial AP position to " << Vector (ap1_x, ap1_y, 0.0));
+  positionAlloc->Add (Vector (sta1_x, sta1_y, 0.0));
+  NS_LOG_INFO ("Setting initial STA position to " << Vector (sta1_x, sta1_y, 0.0));
+  mobility.SetPositionAllocator (positionAlloc);
+  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+  mobility.Install (wifiApNodes.Get (0));
+  mobility.Install (wifiStaNodes.Get (0));
+ 
+  //Statistics counter
+  NodeStatistics statistics = NodeStatistics (wifiApDevices, wifiStaDevices);
+
+  //Move the STA by stepsSize meters every stepsTime seconds
+  Simulator::Schedule (Seconds (0.5 + stepsTime), &NodeStatistics::AdvancePosition, &statistics, wifiStaNodes.Get (0), stepsSize, stepsTime);
+
+  //Configure the IP stack
+  InternetStackHelper stack;
+  stack.Install (wifiApNodes);
+  stack.Install (wifiStaNodes);
+  Ipv4AddressHelper address;
+  address.SetBase ("10.1.1.0", "255.255.255.0");
+  Ipv4InterfaceContainer i = address.Assign (wifiDevices);
+  Ipv4Address sinkAddress = i.GetAddress (0);
+  uint16_t port = 9;
+
+  //Configure the CBR generator
+  PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress, port));
+  ApplicationContainer apps_sink = sink.Install (wifiStaNodes.Get (0));
+
+  OnOffHelper onoff ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress, port));
+  onoff.SetConstantRate (DataRate ("54Mb/s"), packetSize);
+  onoff.SetAttribute ("StartTime", TimeValue (Seconds (0.5)));
+  onoff.SetAttribute ("StopTime", TimeValue (Seconds (simuTime)));
+  ApplicationContainer apps_source = onoff.Install (wifiApNodes.Get (0));
+
+  apps_sink.Start (Seconds (0.5));
+  apps_sink.Stop (Seconds (simuTime));
+
+  //------------------------------------------------------------
+  //-- Setup stats and data collection
+  //--------------------------------------------
+
+  //Register packet receptions to calculate throughput
+  Config::Connect ("/NodeList/1/ApplicationList/*/$ns3::PacketSink/Rx",
+                   MakeCallback (&NodeStatistics::RxCallback, &statistics));
+
+  //Register power and rate changes to calculate the Average Transmit Power
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/PowerChange",
+                   MakeCallback (&NodeStatistics::PowerCallback, &statistics));
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/RateChange",
+                   MakeCallback (&NodeStatistics::RateCallback, &statistics));
+
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin",
+                   MakeCallback (&NodeStatistics::PhyCallback, &statistics));
+
+  //Callbacks to print every change of power and rate
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/PowerChange",
+                   MakeCallback (PowerCallback));
+  Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/RateChange",
+                   MakeCallback (RateCallback));
+
+  Simulator::Stop (Seconds (simuTime));
+  Simulator::Run ();
+
+  std::ofstream outfile (("throughput-" + outputFileName + ".plt").c_str ());
+  Gnuplot gnuplot = Gnuplot (("throughput-" + outputFileName + ".eps").c_str (), "Throughput");
+  gnuplot.SetTerminal ("post eps color enhanced");
+  gnuplot.SetLegend ("Time (seconds)", "Throughput (Mb/s)");
+  gnuplot.SetTitle ("Throughput (AP to STA) vs time");
+  gnuplot.AddDataset (statistics.GetDatafile ());
+  gnuplot.GenerateOutput (outfile);
+
+  if (manager.compare ("ns3::ParfWifiManager") == 0 ||
+      manager.compare ("ns3::AparfWifiManager") == 0)
+    {
+      std::ofstream outfile2 (("power-" + outputFileName + ".plt").c_str ());
+      gnuplot = Gnuplot (("power-" + outputFileName + ".eps").c_str (), "Average Transmit Power");
+      gnuplot.SetTerminal ("post eps color enhanced");
+      gnuplot.SetLegend ("Time (seconds)", "Power (mW)");
+      gnuplot.SetTitle ("Average transmit power (AP to STA) vs time");
+      gnuplot.AddDataset (statistics.GetPowerDatafile ());
+      gnuplot.GenerateOutput (outfile2);
+    }
+
+  Simulator::Destroy ();
+
+  return 0;
+}