|
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 } |