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