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 three
23  * power/rate-adaptive WiFi rate controls; namely, ns3::ParfWifiManager,
24  * ns3::AparfWifiManager and ns3::RrpaaWifiManager.
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, Aparf or Rrpaa 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 "wifi-power-adaptation-distance --help"
70  * \endcode
71  *
72  * Example usage (selecting Aparf rather than Parf):
73  * \code{.sh}
74  *   ./waf --run "wifi-power-adaptation-distance --manager=ns3::AparfWifiManager --outputFileName=aparf"
75  * \endcode
76  *
77  * Another example (moving towards the AP):
78  * \code{.sh}
79  *   ./waf --run "wifi-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 "ns3/gnuplot.h"
89 #include "ns3/command-line.h"
90 #include "ns3/config.h"
91 #include "ns3/uinteger.h"
92 #include "ns3/double.h"
93 #include "ns3/log.h"
94 #include "ns3/yans-wifi-helper.h"
95 #include "ns3/ssid.h"
96 #include "ns3/mobility-helper.h"
97 #include "ns3/internet-stack-helper.h"
98 #include "ns3/ipv4-address-helper.h"
99 #include "ns3/packet-sink-helper.h"
100 #include "ns3/on-off-helper.h"
101 #include "ns3/yans-wifi-channel.h"
102 #include "ns3/wifi-net-device.h"
103 #include "ns3/wifi-mac.h"
104 #include "ns3/wifi-mac-header.h"
105 #include "ns3/mobility-model.h"
106 
107 using namespace ns3;
108 using namespace std;
109 
110 NS_LOG_COMPONENT_DEFINE ("PowerAdaptationDistance");
111 
112 //packet size generated at the AP
113 static const uint32_t packetSize = 1420;
114 
115 class NodeStatistics
116 {
117 public:
118   NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas);
119 
120   void PhyCallback (std::string path, Ptr<const Packet> packet, double powerW);
121   void RxCallback (std::string path, Ptr<const Packet> packet, const Address &from);
122   void PowerCallback (std::string path, double oldPower, double newPower, Mac48Address dest);
123   void RateCallback (std::string path, DataRate oldRate, DataRate newRate, Mac48Address dest);
124   void SetPosition (Ptr<Node> node, Vector position);
125   void AdvancePosition (Ptr<Node> node, int stepsSize, int stepsTime);
126   Vector GetPosition (Ptr<Node> node);
127 
128   Gnuplot2dDataset GetDatafile ();
129   Gnuplot2dDataset GetPowerDatafile ();
130 
131 
132 private:
133   typedef std::vector<std::pair<Time, DataRate> > TxTime;
134   void SetupPhy (Ptr<WifiPhy> phy);
135   Time GetCalcTxTime (DataRate rate);
136 
137   std::map<Mac48Address, double> currentPower;
138   std::map<Mac48Address, DataRate> currentRate;
139   uint32_t m_bytesTotal;
140   double totalEnergy;
141   double totalTime;
142   Ptr<WifiPhy> myPhy;
143   TxTime timeTable;
144   Gnuplot2dDataset m_output;
145   Gnuplot2dDataset m_output_power;
146 };
147 
NodeStatistics(NetDeviceContainer aps,NetDeviceContainer stas)148 NodeStatistics::NodeStatistics (NetDeviceContainer aps, NetDeviceContainer stas)
149 {
150   Ptr<NetDevice> device = aps.Get (0);
151   Ptr<WifiNetDevice> wifiDevice = DynamicCast<WifiNetDevice> (device);
152   Ptr<WifiPhy> phy = wifiDevice->GetPhy ();
153   myPhy = phy;
154   SetupPhy (phy);
155   DataRate dataRate = DataRate (phy->GetDefaultMode ().GetDataRate (phy->GetChannelWidth ()));
156   double power = phy->GetTxPowerEnd ();
157   for (uint32_t j = 0; j < stas.GetN (); j++)
158     {
159       Ptr<NetDevice> staDevice = stas.Get (j);
160       Ptr<WifiNetDevice> wifiStaDevice = DynamicCast<WifiNetDevice> (staDevice);
161       Mac48Address addr = wifiStaDevice->GetMac ()->GetAddress ();
162       currentPower[addr] = power;
163       currentRate[addr] = dataRate;
164     }
165   currentRate[Mac48Address ("ff:ff:ff:ff:ff:ff")] = dataRate;
166   totalEnergy = 0;
167   totalTime = 0;
168   m_bytesTotal = 0;
169   m_output.SetTitle ("Throughput Mbits/s");
170   m_output_power.SetTitle ("Average Transmit Power");
171 }
172 
173 void
SetupPhy(Ptr<WifiPhy> phy)174 NodeStatistics::SetupPhy (Ptr<WifiPhy> phy)
175 {
176   for (const auto & mode : phy->GetModeList ())
177     {
178       WifiTxVector txVector;
179       txVector.SetMode (mode);
180       txVector.SetPreambleType (WIFI_PREAMBLE_LONG);
181       txVector.SetChannelWidth (phy->GetChannelWidth ());
182       DataRate dataRate = DataRate (mode.GetDataRate (phy->GetChannelWidth ()));
183       Time time = phy->CalculateTxDuration (packetSize, txVector, phy->GetPhyBand ());
184       NS_LOG_DEBUG (mode.GetUniqueName () << " " << time.GetSeconds () << " " << dataRate);
185       timeTable.push_back (std::make_pair (time, dataRate));
186     }
187 }
188 
189 Time
GetCalcTxTime(DataRate rate)190 NodeStatistics::GetCalcTxTime (DataRate rate)
191 {
192   for (TxTime::const_iterator i = timeTable.begin (); i != timeTable.end (); i++)
193     {
194       if (rate == i->second)
195         {
196           return i->first;
197         }
198     }
199   NS_ASSERT (false);
200   return Seconds (0);
201 }
202 
203 void
PhyCallback(std::string path,Ptr<const Packet> packet,double powerW)204 NodeStatistics::PhyCallback (std::string path, Ptr<const Packet> packet, double powerW)
205 {
206   WifiMacHeader head;
207   packet->PeekHeader (head);
208   Mac48Address dest = head.GetAddr1 ();
209 
210   if (head.GetType () == WIFI_MAC_DATA)
211     {
212       totalEnergy += pow (10.0, currentPower[dest] / 10.0) * GetCalcTxTime (currentRate[dest]).GetSeconds ();
213       totalTime += GetCalcTxTime (currentRate[dest]).GetSeconds ();
214     }
215 }
216 
217 void
PowerCallback(std::string path,double oldPower,double newPower,Mac48Address dest)218 NodeStatistics::PowerCallback (std::string path, double oldPower, double newPower, Mac48Address dest)
219 {
220   currentPower[dest] = newPower;
221 }
222 
223 void
RateCallback(std::string path,DataRate oldRate,DataRate newRate,Mac48Address dest)224 NodeStatistics::RateCallback (std::string path, DataRate oldRate, DataRate newRate, Mac48Address dest)
225 {
226   currentRate[dest] = newRate;
227 }
228 
229 void
RxCallback(std::string path,Ptr<const Packet> packet,const Address & from)230 NodeStatistics::RxCallback (std::string path, Ptr<const Packet> packet, const Address &from)
231 {
232   m_bytesTotal += packet->GetSize ();
233 }
234 
235 void
SetPosition(Ptr<Node> node,Vector position)236 NodeStatistics::SetPosition (Ptr<Node> node, Vector position)
237 {
238   Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
239   mobility->SetPosition (position);
240 }
241 
242 Vector
GetPosition(Ptr<Node> node)243 NodeStatistics::GetPosition (Ptr<Node> node)
244 {
245   Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
246   return mobility->GetPosition ();
247 }
248 
249 void
AdvancePosition(Ptr<Node> node,int stepsSize,int stepsTime)250 NodeStatistics::AdvancePosition (Ptr<Node> node, int stepsSize, int stepsTime)
251 {
252   Vector pos = GetPosition (node);
253   double mbs = ((m_bytesTotal * 8.0) / (1000000 * stepsTime));
254   m_bytesTotal = 0;
255   double atp = totalEnergy / stepsTime;
256   totalEnergy = 0;
257   totalTime = 0;
258   m_output_power.Add (pos.x, atp);
259   m_output.Add (pos.x, mbs);
260   pos.x += stepsSize;
261   SetPosition (node, pos);
262   NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << " sec; setting new position to " << pos);
263   Simulator::Schedule (Seconds (stepsTime), &NodeStatistics::AdvancePosition, this, node, stepsSize, stepsTime);
264 }
265 
266 Gnuplot2dDataset
GetDatafile()267 NodeStatistics::GetDatafile ()
268 {
269   return m_output;
270 }
271 
272 Gnuplot2dDataset
GetPowerDatafile()273 NodeStatistics::GetPowerDatafile ()
274 {
275   return m_output_power;
276 }
277 
PowerCallback(std::string path,double oldPower,double newPower,Mac48Address dest)278 void PowerCallback (std::string path, double oldPower, double newPower, Mac48Address dest)
279 {
280   NS_LOG_INFO ((Simulator::Now ()).GetSeconds () << " " << dest << " Old power=" << oldPower << " New power=" << newPower);
281 }
282 
RateCallback(std::string path,DataRate oldRate,DataRate newRate,Mac48Address dest)283 void RateCallback (std::string path, DataRate oldRate, DataRate newRate, Mac48Address dest)
284 {
285   NS_LOG_INFO ((Simulator::Now ()).GetSeconds () << " " << dest << " Old rate=" << oldRate << " New rate=" <<  newRate);
286 }
287 
main(int argc,char * argv[])288 int main (int argc, char *argv[])
289 {
290   double maxPower = 17;
291   double minPower = 0;
292   uint32_t powerLevels = 18;
293 
294   uint32_t rtsThreshold = 2346;
295   std::string manager = "ns3::ParfWifiManager";
296   std::string outputFileName = "parf";
297   int ap1_x = 0;
298   int ap1_y = 0;
299   int sta1_x = 5;
300   int sta1_y = 0;
301   uint32_t steps = 200;
302   uint32_t stepsSize = 1;
303   uint32_t stepsTime = 1;
304 
305   CommandLine cmd (__FILE__);
306   cmd.AddValue ("manager", "PRC Manager", manager);
307   cmd.AddValue ("rtsThreshold", "RTS threshold", rtsThreshold);
308   cmd.AddValue ("outputFileName", "Output filename", outputFileName);
309   cmd.AddValue ("steps", "How many different distances to try", steps);
310   cmd.AddValue ("stepsTime", "Time on each step", stepsTime);
311   cmd.AddValue ("stepsSize", "Distance between steps", stepsSize);
312   cmd.AddValue ("maxPower", "Maximum available transmission level (dbm).", maxPower);
313   cmd.AddValue ("minPower", "Minimum available transmission level (dbm).", minPower);
314   cmd.AddValue ("powerLevels", "Number of transmission power levels available between "
315                 "TxPowerStart and TxPowerEnd included.", powerLevels);
316   cmd.AddValue ("AP1_x", "Position of AP1 in x coordinate", ap1_x);
317   cmd.AddValue ("AP1_y", "Position of AP1 in y coordinate", ap1_y);
318   cmd.AddValue ("STA1_x", "Position of STA1 in x coordinate", sta1_x);
319   cmd.AddValue ("STA1_y", "Position of STA1 in y coordinate", sta1_y);
320   cmd.Parse (argc, argv);
321 
322   if (steps == 0)
323     {
324       std::cout << "Exiting without running simulation; steps value of 0" << std::endl;
325     }
326 
327   uint32_t simuTime = (steps + 1) * stepsTime;
328 
329   //Define the APs
330   NodeContainer wifiApNodes;
331   wifiApNodes.Create (1);
332 
333   //Define the STAs
334   NodeContainer wifiStaNodes;
335   wifiStaNodes.Create (1);
336 
337   WifiHelper wifi;
338   wifi.SetStandard (WIFI_STANDARD_80211a);
339   WifiMacHelper wifiMac;
340   YansWifiPhyHelper wifiPhy;
341   YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
342 
343   wifiPhy.SetChannel (wifiChannel.Create ());
344 
345   NetDeviceContainer wifiApDevices;
346   NetDeviceContainer wifiStaDevices;
347   NetDeviceContainer wifiDevices;
348 
349   //Configure the STA node
350   wifi.SetRemoteStationManager ("ns3::MinstrelWifiManager", "RtsCtsThreshold", UintegerValue (rtsThreshold));
351   wifiPhy.Set ("TxPowerStart", DoubleValue (maxPower));
352   wifiPhy.Set ("TxPowerEnd", DoubleValue (maxPower));
353 
354   Ssid ssid = Ssid ("AP");
355   wifiMac.SetType ("ns3::StaWifiMac",
356                    "Ssid", SsidValue (ssid));
357   wifiStaDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiStaNodes.Get (0)));
358 
359   //Configure the AP node
360   wifi.SetRemoteStationManager (manager, "DefaultTxPowerLevel", UintegerValue (powerLevels - 1), "RtsCtsThreshold", UintegerValue (rtsThreshold));
361   wifiPhy.Set ("TxPowerStart", DoubleValue (minPower));
362   wifiPhy.Set ("TxPowerEnd", DoubleValue (maxPower));
363   wifiPhy.Set ("TxPowerLevels", UintegerValue (powerLevels));
364 
365   ssid = Ssid ("AP");
366   wifiMac.SetType ("ns3::ApWifiMac",
367                    "Ssid", SsidValue (ssid));
368   wifiApDevices.Add (wifi.Install (wifiPhy, wifiMac, wifiApNodes.Get (0)));
369 
370   wifiDevices.Add (wifiStaDevices);
371   wifiDevices.Add (wifiApDevices);
372 
373   //Configure the mobility.
374   MobilityHelper mobility;
375   Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
376   //Initial position of AP and STA
377   positionAlloc->Add (Vector (ap1_x, ap1_y, 0.0));
378   NS_LOG_INFO ("Setting initial AP position to " << Vector (ap1_x, ap1_y, 0.0));
379   positionAlloc->Add (Vector (sta1_x, sta1_y, 0.0));
380   NS_LOG_INFO ("Setting initial STA position to " << Vector (sta1_x, sta1_y, 0.0));
381   mobility.SetPositionAllocator (positionAlloc);
382   mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
383   mobility.Install (wifiApNodes.Get (0));
384   mobility.Install (wifiStaNodes.Get (0));
385 
386   //Statistics counter
387   NodeStatistics statistics = NodeStatistics (wifiApDevices, wifiStaDevices);
388 
389   //Move the STA by stepsSize meters every stepsTime seconds
390   Simulator::Schedule (Seconds (0.5 + stepsTime), &NodeStatistics::AdvancePosition, &statistics, wifiStaNodes.Get (0), stepsSize, stepsTime);
391 
392   //Configure the IP stack
393   InternetStackHelper stack;
394   stack.Install (wifiApNodes);
395   stack.Install (wifiStaNodes);
396   Ipv4AddressHelper address;
397   address.SetBase ("10.1.1.0", "255.255.255.0");
398   Ipv4InterfaceContainer i = address.Assign (wifiDevices);
399   Ipv4Address sinkAddress = i.GetAddress (0);
400   uint16_t port = 9;
401 
402   //Configure the CBR generator
403   PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress, port));
404   ApplicationContainer apps_sink = sink.Install (wifiStaNodes.Get (0));
405 
406   OnOffHelper onoff ("ns3::UdpSocketFactory", InetSocketAddress (sinkAddress, port));
407   onoff.SetConstantRate (DataRate ("54Mb/s"), packetSize);
408   onoff.SetAttribute ("StartTime", TimeValue (Seconds (0.5)));
409   onoff.SetAttribute ("StopTime", TimeValue (Seconds (simuTime)));
410   ApplicationContainer apps_source = onoff.Install (wifiApNodes.Get (0));
411 
412   apps_sink.Start (Seconds (0.5));
413   apps_sink.Stop (Seconds (simuTime));
414 
415   //------------------------------------------------------------
416   //-- Setup stats and data collection
417   //--------------------------------------------
418 
419   //Register packet receptions to calculate throughput
420   Config::Connect ("/NodeList/1/ApplicationList/*/$ns3::PacketSink/Rx",
421                    MakeCallback (&NodeStatistics::RxCallback, &statistics));
422 
423   //Register power and rate changes to calculate the Average Transmit Power
424   Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/PowerChange",
425                    MakeCallback (&NodeStatistics::PowerCallback, &statistics));
426   Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/RateChange",
427                    MakeCallback (&NodeStatistics::RateCallback, &statistics));
428 
429   Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin",
430                    MakeCallback (&NodeStatistics::PhyCallback, &statistics));
431 
432   //Callbacks to print every change of power and rate
433   Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/PowerChange",
434                    MakeCallback (PowerCallback));
435   Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/RemoteStationManager/$" + manager + "/RateChange",
436                    MakeCallback (RateCallback));
437 
438   Simulator::Stop (Seconds (simuTime));
439   Simulator::Run ();
440 
441   std::ofstream outfile (("throughput-" + outputFileName + ".plt").c_str ());
442   Gnuplot gnuplot = Gnuplot (("throughput-" + outputFileName + ".eps").c_str (), "Throughput");
443   gnuplot.SetTerminal ("post eps color enhanced");
444   gnuplot.SetLegend ("Time (seconds)", "Throughput (Mb/s)");
445   gnuplot.SetTitle ("Throughput (AP to STA) vs time");
446   gnuplot.AddDataset (statistics.GetDatafile ());
447   gnuplot.GenerateOutput (outfile);
448 
449   if (manager.compare ("ns3::ParfWifiManager") == 0
450       || manager.compare ("ns3::AparfWifiManager") == 0
451       || manager.compare ("ns3::RrpaaWifiManager") == 0)
452     {
453       std::ofstream outfile2 (("power-" + outputFileName + ".plt").c_str ());
454       gnuplot = Gnuplot (("power-" + outputFileName + ".eps").c_str (), "Average Transmit Power");
455       gnuplot.SetTerminal ("post eps color enhanced");
456       gnuplot.SetLegend ("Time (seconds)", "Power (mW)");
457       gnuplot.SetTitle ("Average transmit power (AP to STA) vs time");
458       gnuplot.AddDataset (statistics.GetPowerDatafile ());
459       gnuplot.GenerateOutput (outfile2);
460     }
461 
462   Simulator::Destroy ();
463 
464   return 0;
465 }
466