examples/wireless/power-adaptation-distance.cc
changeset 11153 324c767aefdd
child 11174 780a43e4980c
equal deleted inserted replaced
11152:613c316c7c18 11153:324c767aefdd
       
     1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
       
     2 /*
       
     3  * Copyright (c) 2014 Universidad de la República - Uruguay
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License version 2 as
       
     7  * published by the Free Software Foundation;
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    17  *
       
    18  * Author: Matias Richart <mrichart@fing.edu.uy>
       
    19  */
       
    20 
       
    21 /**
       
    22  * This example program is designed to illustrate the behavior of two
       
    23  * power/rate-adaptive WiFi rate controls; namely, ns3::ParfWifiManager
       
    24  * and ns3::AparfWifiManager.
       
    25  *
       
    26  * The output of this is typically two plot files, named throughput-parf.plt
       
    27  * (or throughput-aparf.plt, if Aparf is used) and power-parf.plt If 
       
    28  * Gnuplot program is available, one can use it to convert the plt file
       
    29  * into an eps file, by running:
       
    30  * \code{.sh}
       
    31  *   gnuplot throughput-parf.plt
       
    32  * \endcode
       
    33  * Also, to enable logging of rate and power changes to the terminal, set this
       
    34  * environment variable:
       
    35  * \code{.sh}
       
    36  *   export NS_LOG=PowerAdaptationDistance=level_info
       
    37  * \endcode
       
    38  *
       
    39  * This simulation consist of 2 nodes, one AP and one STA.
       
    40  * The AP generates UDP traffic with a CBR of 54 Mbps to the STA.
       
    41  * The AP can use any power and rate control mechanism and the STA uses 
       
    42  * only Minstrel rate control.
       
    43  * The STA can be configured to move away from (or towards to) the AP.
       
    44  * By default, the AP is at coordinate (0,0,0) and the STA starts at 
       
    45  * coordinate (5,0,0) (meters) and moves away on the x axis by 1 meter every
       
    46  * second.
       
    47  *
       
    48  * The output consists of:
       
    49  * - A plot of average throughput vs. distance.
       
    50  * - A plot of average transmit power vs. distance.
       
    51  * - (if logging is enabled) the changes of power and rate to standard output.
       
    52  *
       
    53  * The Average Transmit Power is defined as an average of the power
       
    54  * consumed per measurement interval, expressed in milliwatts.  The
       
    55  * power level for each frame transmission is reported by the simulator, 
       
    56  * and the energy consumed is obtained by multiplying the power by the
       
    57  * frame duration.  At every 'stepTime' (defaulting to 1 second), the
       
    58  * total energy for the collection period is divided by the step time 
       
    59  * and converted from dbm to milliwatt units, and this average is 
       
    60  * plotted against time.
       
    61  *
       
    62  * When neither Parf nor Aparf is selected as the rate control, the
       
    63  * generation of the plot of average transmit power vs distance is suppressed
       
    64  * since the other Wifi rate controls do not support the necessary callbacks
       
    65  * for computing the average power.
       
    66  *
       
    67  * To display all the possible arguments and their defaults:
       
    68  * \code{.sh}
       
    69  *   ./waf --run "power-adaptation-distance --help"
       
    70  * \endcode
       
    71  * 
       
    72  * Example usage (selecting Aparf rather than Parf):
       
    73  * \code{.sh}
       
    74  *   ./waf --run "power-adaptation-distance --manager=ns3::AparfWifiManager --outputFileName=aparf"
       
    75  * \endcode
       
    76  *
       
    77  * Another example (moving towards the AP):
       
    78  * \code{.sh}
       
    79  *   ./waf --run "power-adaptation-distance --manager=ns3::AparfWifiManager --outputFileName=aparf --stepsSize=-1 --STA1_x=200"
       
    80  * \endcode
       
    81  *
       
    82  * To enable the log of rate and power changes:
       
    83  * \code{.sh}
       
    84  *   export NS_LOG=PowerAdaptationDistance=level_info
       
    85  * \endcode
       
    86  */
       
    87 
       
    88 #include <sstream>
       
    89 #include <fstream>
       
    90 #include <math.h>
       
    91 
       
    92 #include "ns3/core-module.h"
       
    93 #include "ns3/network-module.h"
       
    94 #include "ns3/internet-module.h"
       
    95 #include "ns3/mobility-module.h"
       
    96 #include "ns3/wifi-module.h"
       
    97 #include "ns3/applications-module.h"
       
    98 #include "ns3/stats-module.h"
       
    99 #include "ns3/flow-monitor-module.h"
       
   100 
       
   101 using namespace ns3;
       
   102 using namespace std;
       
   103 
       
   104 NS_LOG_COMPONENT_DEFINE ("PowerAdaptationDistance");
       
   105 
       
   106 // packet size generated at the AP
       
   107 static const uint32_t packetSize = 1420;
       
   108 
       
   109 class NodeStatistics
       
   110 {
       
   111 public:
       
   112   NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas);
       
   113 
       
   114   void CheckStatistics (double time);
       
   115 
       
   116   void PhyCallback (std::string path, Ptr<const Packet> packet);
       
   117   void RxCallback (std::string path, Ptr<const Packet> packet, const Address &from);
       
   118   void PowerCallback (std::string path, uint8_t power, Mac48Address dest);
       
   119   void RateCallback (std::string path, uint32_t rate, Mac48Address dest);
       
   120   void SetPosition (Ptr<Node> node, Vector position);
       
   121   void AdvancePosition (Ptr<Node> node, int stepsSize, int stepsTime);
       
   122   Vector GetPosition (Ptr<Node> node);
       
   123 
       
   124   Gnuplot2dDataset GetDatafile ();
       
   125   Gnuplot2dDataset GetPowerDatafile ();
       
   126 
       
   127 private:
       
   128   typedef std::vector<std::pair<Time,WifiMode> > TxTime;
       
   129   void SetupPhy (Ptr<WifiPhy> phy);
       
   130   Time GetCalcTxTime (WifiMode mode);
       
   131 
       
   132   std::map<Mac48Address, uint32_t> actualPower;
       
   133   std::map<Mac48Address, WifiMode> actualMode;
       
   134   uint32_t m_bytesTotal;
       
   135   double totalEnergy;
       
   136   double totalTime;
       
   137   Ptr<WifiPhy> myPhy;
       
   138   TxTime timeTable;
       
   139   Gnuplot2dDataset m_output;
       
   140   Gnuplot2dDataset m_output_power;
       
   141 };
       
   142 
       
   143 NodeStatistics::NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas)
       
   144 {
       
   145   Ptr<NetDevice> device = aps.Get (0);
       
   146   Ptr<WifiNetDevice> wifiDevice = DynamicCast<WifiNetDevice> (device);
       
   147   Ptr<WifiPhy> phy = wifiDevice->GetPhy ();
       
   148   myPhy = phy;
       
   149   SetupPhy (phy);
       
   150   for (uint32_t j = 0; j < stas.GetN (); j++)
       
   151     {
       
   152       Ptr<NetDevice> staDevice = stas.Get (j);
       
   153       Ptr<WifiNetDevice> wifiStaDevice = DynamicCast<WifiNetDevice> (staDevice);
       
   154       Mac48Address addr = wifiStaDevice->GetMac ()->GetAddress ();
       
   155       actualPower[addr] = 17;
       
   156       actualMode[addr] = phy->GetMode (0);
       
   157     }
       
   158   actualMode[Mac48Address ("ff:ff:ff:ff:ff:ff")] = phy->GetMode (0);
       
   159   totalEnergy = 0;
       
   160   totalTime = 0;
       
   161   m_bytesTotal = 0;
       
   162   m_output.SetTitle ("Throughput Mbits/s");
       
   163   m_output_power.SetTitle ("Average Transmit Power");
       
   164 }
       
   165 
       
   166 void
       
   167 NodeStatistics::SetupPhy (Ptr<WifiPhy> phy)
       
   168 {
       
   169   uint32_t nModes = phy->GetNModes ();
       
   170   for (uint32_t i = 0; i < nModes; i++)
       
   171     {
       
   172       WifiMode mode = phy->GetMode (i);
       
   173       WifiTxVector txVector;
       
   174       txVector.SetMode (mode);
       
   175       timeTable.push_back (std::make_pair (phy->CalculateTxDuration (packetSize, txVector, WIFI_PREAMBLE_LONG, phy->GetFrequency ()), mode));
       
   176     }
       
   177 }
       
   178 
       
   179 Time
       
   180 NodeStatistics::GetCalcTxTime (WifiMode mode)
       
   181 {
       
   182   for (TxTime::const_iterator i = timeTable.begin (); i != timeTable.end (); i++)
       
   183     {
       
   184       if (mode == i->second)
       
   185         {
       
   186           return i->first;
       
   187         }
       
   188     }
       
   189   NS_ASSERT (false);
       
   190   return Seconds (0);
       
   191 }
       
   192 
       
   193 void
       
   194 NodeStatistics::PhyCallback (std::string path, Ptr<const Packet> packet)
       
   195 {
       
   196   WifiMacHeader head;
       
   197   packet->PeekHeader (head);
       
   198   Mac48Address dest = head.GetAddr1 ();
       
   199 
       
   200   totalEnergy += actualPower[dest] * GetCalcTxTime (actualMode[dest]).GetSeconds ();
       
   201   totalTime += GetCalcTxTime (actualMode[dest]).GetSeconds ();
       
   202 
       
   203 }
       
   204 
       
   205 void
       
   206 NodeStatistics::PowerCallback (std::string path, uint8_t power, Mac48Address dest)
       
   207 {
       
   208   double   txPowerBaseDbm = myPhy->GetTxPowerStart ();
       
   209   double   txPowerEndDbm = myPhy->GetTxPowerEnd ();
       
   210   uint32_t nTxPower = myPhy->GetNTxPower ();
       
   211   double dbm;
       
   212   if (nTxPower > 1)
       
   213     {
       
   214       dbm = txPowerBaseDbm + power * (txPowerEndDbm - txPowerBaseDbm) / (nTxPower - 1);
       
   215     }
       
   216   else
       
   217     {
       
   218       NS_ASSERT_MSG (txPowerBaseDbm == txPowerEndDbm, "cannot have TxPowerEnd != TxPowerStart with TxPowerLevels == 1");
       
   219       dbm = txPowerBaseDbm;
       
   220     }
       
   221   actualPower[dest] = dbm;
       
   222 }
       
   223 
       
   224 void
       
   225 NodeStatistics::RateCallback (std::string path, uint32_t rate, Mac48Address dest)
       
   226 {
       
   227   actualMode[dest] = myPhy->GetMode (rate);
       
   228 }
       
   229 
       
   230 void
       
   231 NodeStatistics::RxCallback (std::string path, Ptr<const Packet> packet, const Address &from)
       
   232 {
       
   233   m_bytesTotal += packet->GetSize ();
       
   234 }
       
   235 
       
   236 void
       
   237 NodeStatistics::CheckStatistics (double time)
       
   238 {
       
   239 
       
   240 }
       
   241 
       
   242 void
       
   243 NodeStatistics::SetPosition (Ptr<Node> node, Vector position)
       
   244 {
       
   245   Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
       
   246   mobility->SetPosition (position);
       
   247 }
       
   248 
       
   249 Vector
       
   250 NodeStatistics::GetPosition (Ptr<Node> node)
       
   251 {
       
   252   Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
       
   253   return mobility->GetPosition ();
       
   254 }
       
   255 
       
   256 void
       
   257 NodeStatistics::AdvancePosition (Ptr<Node> node, int stepsSize, int stepsTime)
       
   258 {
       
   259   Vector pos = GetPosition (node);
       
   260   double mbs = ((m_bytesTotal * 8.0) / (1000000 * stepsTime));
       
   261   m_bytesTotal = 0;
       
   262   double atm = pow (10, ((totalEnergy / stepsTime) / 10));
       
   263   totalEnergy = 0;
       
   264   totalTime = 0;
       
   265   m_output_power.Add (pos.x, atm);
       
   266   m_output.Add (pos.x, mbs);
       
   267   pos.x += stepsSize;
       
   268   SetPosition (node, pos);
       
   269   NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << " sec; setting new position to " << pos);
       
   270   Simulator::Schedule (Seconds (stepsTime), &NodeStatistics::AdvancePosition, this, node, stepsSize, stepsTime);
       
   271 }
       
   272 
       
   273 Gnuplot2dDataset
       
   274 NodeStatistics::GetDatafile ()
       
   275 {
       
   276   return m_output;
       
   277 }
       
   278 
       
   279 Gnuplot2dDataset
       
   280 NodeStatistics::GetPowerDatafile ()
       
   281 {
       
   282   return m_output_power;
       
   283 }
       
   284 
       
   285 void PowerCallback (std::string path, uint8_t power, Mac48Address dest)
       
   286 {
       
   287   NS_LOG_INFO ((Simulator::Now ()).GetSeconds () << " " << dest << " Power " << (int)power);
       
   288 }
       
   289 
       
   290 void RateCallback (std::string path, uint32_t rate, Mac48Address dest)
       
   291 {
       
   292   NS_LOG_INFO ((Simulator::Now ()).GetSeconds () << " " << dest << " Rate " <<  rate);
       
   293 }
       
   294 
       
   295 int main (int argc, char *argv[])
       
   296 {
       
   297   double maxPower = 17;
       
   298   double minPower = 0;
       
   299   uint32_t powerLevels = 18;
       
   300 
       
   301   uint32_t rtsThreshold = 2346;
       
   302   std::string manager = "ns3::ParfWifiManager";
       
   303   std::string outputFileName = "parf";
       
   304   int ap1_x = 0;
       
   305   int ap1_y = 0;
       
   306   int sta1_x = 5;
       
   307   int sta1_y = 0;
       
   308   uint32_t steps = 200;
       
   309   uint32_t stepsSize = 1;
       
   310   uint32_t stepsTime = 1;
       
   311 
       
   312   CommandLine cmd;
       
   313   cmd.AddValue ("manager", "PRC Manager", manager);
       
   314   cmd.AddValue ("rtsThreshold", "RTS threshold", rtsThreshold);
       
   315   cmd.AddValue ("outputFileName", "Output filename", outputFileName);
       
   316   cmd.AddValue ("steps", "How many different distances to try", steps);
       
   317   cmd.AddValue ("stepsTime", "Time on each step", stepsTime);
       
   318   cmd.AddValue ("stepsSize", "Distance between steps", stepsSize);
       
   319   cmd.AddValue ("maxPower", "Maximum available transmission level (dbm).", maxPower);
       
   320   cmd.AddValue ("minPower", "Minimum available transmission level (dbm).", minPower);
       
   321   cmd.AddValue ("powerLevels", "Number of transmission power levels available between "
       
   322                 "TxPowerStart and TxPowerEnd included.", powerLevels);
       
   323   cmd.AddValue ("AP1_x", "Position of AP1 in x coordinate", ap1_x);
       
   324   cmd.AddValue ("AP1_y", "Position of AP1 in y coordinate", ap1_y);
       
   325   cmd.AddValue ("STA1_x", "Position of STA1 in x coordinate", sta1_x);
       
   326   cmd.AddValue ("STA1_y", "Position of STA1 in y coordinate", sta1_y);
       
   327   cmd.Parse (argc, argv);
       
   328 
       
   329   if (steps == 0)
       
   330     {
       
   331       std::cout << "Exiting without running simulation; steps value of 0" << std::endl;
       
   332     }
       
   333 
       
   334   uint32_t simuTime = (steps + 1) * stepsTime;
       
   335 
       
   336   // Define the APs
       
   337   NodeContainer wifiApNodes;
       
   338   wifiApNodes.Create (1);
       
   339 
       
   340   //Define the STAs
       
   341   NodeContainer wifiStaNodes;
       
   342   wifiStaNodes.Create (1);
       
   343 
       
   344   WifiHelper wifi = WifiHelper::Default ();
       
   345   wifi.SetStandard (WIFI_PHY_STANDARD_80211a);
       
   346   NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default ();
       
   347   YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
       
   348   YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
       
   349 
       
   350   wifiPhy.SetChannel (wifiChannel.Create ());
       
   351 
       
   352   NetDeviceContainer wifiApDevices;
       
   353   NetDeviceContainer wifiStaDevices;
       
   354   NetDeviceContainer wifiDevices;
       
   355 
       
   356   //Configure the STA node
       
   357   wifi.SetRemoteStationManager ("ns3::MinstrelWifiManager", "RtsCtsThreshold", UintegerValue (rtsThreshold));
       
   358   wifiPhy.Set ("TxPowerStart", DoubleValue (maxPower));
       
   359   wifiPhy.Set ("TxPowerEnd", DoubleValue (maxPower));
       
   360 
       
   361   Ssid ssid = Ssid ("AP");
       
   362   wifiMac.SetType ("ns3::StaWifiMac",
       
   363                    "Ssid", SsidValue (ssid),
       
   364                    "ActiveProbing", BooleanValue (false));
       
   365   wifiStaDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiStaNodes.Get (0)));
       
   366 
       
   367   //Configure the AP node
       
   368   wifi.SetRemoteStationManager (manager, "DefaultTxPowerLevel", UintegerValue (maxPower), "RtsCtsThreshold", UintegerValue (rtsThreshold));
       
   369   wifiPhy.Set ("TxPowerStart", DoubleValue (minPower));
       
   370   wifiPhy.Set ("TxPowerEnd", DoubleValue (maxPower));
       
   371   wifiPhy.Set ("TxPowerLevels", UintegerValue (powerLevels));
       
   372 
       
   373   ssid = Ssid ("AP");
       
   374   wifiMac.SetType ("ns3::ApWifiMac",
       
   375                    "Ssid", SsidValue (ssid));
       
   376   wifiApDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiApNodes.Get (0)));
       
   377 
       
   378   wifiDevices.Add (wifiStaDevices);
       
   379   wifiDevices.Add (wifiApDevices);
       
   380 
       
   381   // Configure the mobility.
       
   382   MobilityHelper mobility;
       
   383   Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
       
   384   //Initial position of AP and STA
       
   385   positionAlloc->Add (Vector (ap1_x, ap1_y, 0.0));
       
   386   NS_LOG_INFO ("Setting initial AP position to " << Vector (ap1_x, ap1_y, 0.0));
       
   387   positionAlloc->Add (Vector (sta1_x, sta1_y, 0.0));
       
   388   NS_LOG_INFO ("Setting initial STA position to " << Vector (sta1_x, sta1_y, 0.0));
       
   389   mobility.SetPositionAllocator (positionAlloc);
       
   390   mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
       
   391   mobility.Install (wifiApNodes.Get (0));
       
   392   mobility.Install (wifiStaNodes.Get (0));
       
   393  
       
   394   //Statistics counter
       
   395   NodeStatistics statistics = NodeStatistics (wifiApDevices, wifiStaDevices);
       
   396 
       
   397   //Move the STA by stepsSize meters every stepsTime seconds
       
   398   Simulator::Schedule (Seconds (0.5 + stepsTime), &NodeStatistics::AdvancePosition, &statistics, wifiStaNodes.Get (0), stepsSize, stepsTime);
       
   399 
       
   400   //Configure the IP stack
       
   401   InternetStackHelper stack;
       
   402   stack.Install (wifiApNodes);
       
   403   stack.Install (wifiStaNodes);
       
   404   Ipv4AddressHelper address;
       
   405   address.SetBase ("10.1.1.0", "255.255.255.0");
       
   406   Ipv4InterfaceContainer i = address.Assign (wifiDevices);
       
   407   Ipv4Address sinkAddress = i.GetAddress (0);
       
   408   uint16_t port = 9;
       
   409 
       
   410   //Configure the CBR generator
       
   411   PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress, port));
       
   412   ApplicationContainer apps_sink = sink.Install (wifiStaNodes.Get (0));
       
   413 
       
   414   OnOffHelper onoff ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress, port));
       
   415   onoff.SetConstantRate (DataRate ("54Mb/s"), packetSize);
       
   416   onoff.SetAttribute ("StartTime", TimeValue (Seconds (0.5)));
       
   417   onoff.SetAttribute ("StopTime", TimeValue (Seconds (simuTime)));
       
   418   ApplicationContainer apps_source = onoff.Install (wifiApNodes.Get (0));
       
   419 
       
   420   apps_sink.Start (Seconds (0.5));
       
   421   apps_sink.Stop (Seconds (simuTime));
       
   422 
       
   423   //------------------------------------------------------------
       
   424   //-- Setup stats and data collection
       
   425   //--------------------------------------------
       
   426 
       
   427   //Register packet receptions to calculate throughput
       
   428   Config::Connect ("/NodeList/1/ApplicationList/*/$ns3::PacketSink/Rx",
       
   429                    MakeCallback (&NodeStatistics::RxCallback, &statistics));
       
   430 
       
   431   //Register power and rate changes to calculate the Average Transmit Power
       
   432   Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/PowerChange",
       
   433                    MakeCallback (&NodeStatistics::PowerCallback, &statistics));
       
   434   Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/RateChange",
       
   435                    MakeCallback (&NodeStatistics::RateCallback, &statistics));
       
   436 
       
   437   Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin",
       
   438                    MakeCallback (&NodeStatistics::PhyCallback, &statistics));
       
   439 
       
   440   //Callbacks to print every change of power and rate
       
   441   Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/PowerChange",
       
   442                    MakeCallback (PowerCallback));
       
   443   Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/RateChange",
       
   444                    MakeCallback (RateCallback));
       
   445 
       
   446   Simulator::Stop (Seconds (simuTime));
       
   447   Simulator::Run ();
       
   448 
       
   449   std::ofstream outfile (("throughput-" + outputFileName + ".plt").c_str ());
       
   450   Gnuplot gnuplot = Gnuplot (("throughput-" + outputFileName + ".eps").c_str (), "Throughput");
       
   451   gnuplot.SetTerminal ("post eps color enhanced");
       
   452   gnuplot.SetLegend ("Time (seconds)", "Throughput (Mb/s)");
       
   453   gnuplot.SetTitle ("Throughput (AP to STA) vs time");
       
   454   gnuplot.AddDataset (statistics.GetDatafile ());
       
   455   gnuplot.GenerateOutput (outfile);
       
   456 
       
   457   if (manager.compare ("ns3::ParfWifiManager") == 0 ||
       
   458       manager.compare ("ns3::AparfWifiManager") == 0)
       
   459     {
       
   460       std::ofstream outfile2 (("power-" + outputFileName + ".plt").c_str ());
       
   461       gnuplot = Gnuplot (("power-" + outputFileName + ".eps").c_str (), "Average Transmit Power");
       
   462       gnuplot.SetTerminal ("post eps color enhanced");
       
   463       gnuplot.SetLegend ("Time (seconds)", "Power (mW)");
       
   464       gnuplot.SetTitle ("Average transmit power (AP to STA) vs time");
       
   465       gnuplot.AddDataset (statistics.GetPowerDatafile ());
       
   466       gnuplot.GenerateOutput (outfile2);
       
   467     }
       
   468 
       
   469   Simulator::Destroy ();
       
   470 
       
   471   return 0;
       
   472 }