1. #include "ns3/core-module.h"
  2. #include "ns3/common-module.h"
  3. #include "ns3/node-module.h"
  4. #include "ns3/wifi-module.h"
  5. #include "ns3/mobility-module.h"
  6. #include "ns3/simulator-module.h"
  7.  
  8. #include "ns3/helper-module.h"
  9. #include "ns3/contrib-module.h"
  10.  
  11. #include "ns3/ipv4-global-routing-helper.h"
  12. #include "ns3/onoff-application.h"
  13.  
  14. #include "ns3/vector.h"
  15.  
  16. #include "ns3/visualizer.h"
  17.  
  18. using namespace ns3;
  19.  
  20. NS_LOG_COMPONENT_DEFINE("WifiPairsThroughputSimulation");
  21.  
  22. struct SimulationConfig
  23. {
  24. unsigned int PACKET_SIZE;
  25. int NUM_PAIRS; // number of pairs in an experiment
  26. int NUM_STEPS; // number of throughputs to test
  27. std::string START; // first throughput tested
  28. std::string STEP; // throughput shift between 2 tests
  29. SimulationConfig(const unsigned int ps,
  30. const int np,
  31. const int ns,
  32. const int start,
  33. const int step,
  34. const std::string unit) :
  35. PACKET_SIZE(ps), NUM_PAIRS(np), NUM_STEPS(ns)
  36. {
  37. std::ostringstream oss1, oss2;
  38. oss1<<start<<unit;oss2<<step<<unit;
  39. START=oss1.str();STEP=oss2.str();
  40. }
  41. };
  42. // packet size, num pairs, num steps, start, step, unit
  43. const SimulationConfig CONFIGS[] = {
  44. SimulationConfig(1000,7,26,62,62,"Kbps"),
  45. SimulationConfig(1000,7,26,62,62,"Kbps"),
  46. // SimulationConfig(1000,7,30,62,62,"Kbps"),
  47. // SimulationConfig(1000,7,30,62,62,"Kbps"),
  48. // SimulationConfig(1000,8,24,250,250,"Kbps"),
  49. // SimulationConfig(1000,8,24,250,250,"Kbps"),
  50. }; const unsigned int NUM_CONFIGS = sizeof(CONFIGS)/sizeof(SimulationConfig);
  51. const std::string OUTPUT_IMAGE_NAME = "wifi_udp_throughput.png";
  52. const double DX_m = 3.0; // space between a AP and a MS
  53. const double DY_m = 3.0; // space between 2 pairs
  54. const unsigned int NUM_WIFI_CHANNELS = 1; // all the pairs are put in # chans
  55. const int SAMPLING_PERIOD_s = 20;
  56. const unsigned int NUM_RUNS_BY_CONFIG = 1;
  57. const WifiPhyStandard USED_WIFI_STANDARD = WIFI_PHY_STANDARD_80211g;
  58.  
  59. //output parameters
  60. const bool OUTPUT_PCAP = true;
  61. const bool IFTRUEOUTPUTAP_PCAP = true;
  62.  
  63. template <typename T> class Point2d
  64. {
  65. public:
  66. T x,y;
  67. Point2d(T _x, T _y) : x(_x), y(_y) {};
  68. };
  69.  
  70. class Pair : public Object
  71. { // An AP/MS pair that will store the "#bits transmitted" data
  72. public:
  73. Ptr<Node> client;
  74. Ptr<Node> server;
  75. uint64_t bits;
  76. std::vector<Point2d<double> > output;
  77. Pair() {};
  78. void ReceivePacket(Ptr<Socket> socket);
  79. };
  80.  
  81. void Pair::ReceivePacket(Ptr<Socket> socket)
  82. { // simply refresh the #bits transmitted data
  83. Ptr<Packet> packet;
  84.  
  85. while(packet = socket->Recv())
  86. {
  87. bits += packet->GetSize()*8;
  88. }
  89. }
  90.  
  91. class ChannelChooser
  92. {
  93. /* naive divide a segment and put numbers algo
  94.   we actually consider the channels as coords on a 2d line
  95.   then we create 2d segments on that line "unused channels"
  96.   and always break the biggest one in 2, putting a (increasing)
  97.   number on the middle point
  98.   then we have all the points of our segment ordered
  99.   we just loop on it to linearily attribute channels =) */
  100. private:
  101. class Segment1d : public Point2d<unsigned int> {
  102. public:
  103. Segment1d(unsigned int a, unsigned int b) : Point2d<unsigned int>(a,b) {}
  104. int size() { return y - x + 1; }
  105. };
  106.  
  107. std::vector<Segment1d> segs_to_divide;
  108. std::vector<unsigned int> channel_attrib_vector; // used a vector because cba managing mem by myself here
  109. unsigned int num_chans;
  110.  
  111. void divide(std::vector<Segment1d>::iterator it);
  112. std::vector<Segment1d>::iterator look_for_biggest_segment();
  113. public:
  114. ChannelChooser(unsigned int s); // choose between s channels
  115. unsigned int get(unsigned int i); // my i-th channel will be ...
  116. };
  117.  
  118. ChannelChooser::ChannelChooser(unsigned int s) : num_chans(s) {
  119. segs_to_divide.push_back(Segment1d(0,s-1));
  120. divide(segs_to_divide.begin());
  121. }
  122.  
  123. void ChannelChooser::divide(std::vector<Segment1d>::iterator it)
  124. {
  125. switch(it->size())
  126. {
  127. case 0:
  128. segs_to_divide.erase(it);
  129. break;
  130. case 1:
  131. segs_to_divide.erase(it);
  132. channel_attrib_vector.push_back(it->x);
  133. break;
  134. default:
  135. {
  136. unsigned int a = it->x;
  137. unsigned int b = it->y;
  138. unsigned int pivot = (a+b) / 2;
  139. // first we tag the pivot
  140. segs_to_divide.erase(it);
  141. channel_attrib_vector.push_back(pivot);
  142. // btw be it pair or impair the right size is systematically bigger
  143. segs_to_divide.push_back(Segment1d(pivot+1,b));
  144. if (pivot != a) // if size == 2 then pivot == a...
  145. segs_to_divide.push_back(Segment1d(a,pivot-1));
  146. }
  147. }
  148. if(segs_to_divide.size() > 0)
  149. divide(look_for_biggest_segment()); // dat tail call o//
  150. }
  151.  
  152. std::vector<ChannelChooser::Segment1d>::iterator ChannelChooser::look_for_biggest_segment()
  153. {
  154. // ugly bubble sort, we could do a lot better but not worth the effort
  155. int max_size = 0;
  156. std::vector<Segment1d>::iterator res;
  157. for(std::vector<Segment1d>::iterator it = segs_to_divide.begin(); it < segs_to_divide.end(); it++)
  158. {
  159. if(it->size() < max_size)
  160. continue;
  161. max_size = it->size();
  162. res = it;
  163. }
  164. return res;
  165. }
  166.  
  167. unsigned int ChannelChooser::get(unsigned int i)
  168. {
  169. return channel_attrib_vector[i % num_chans];
  170. }
  171.  
  172. class ExperimentWifiPairs
  173. {
  174. /* The class that will actually run an experiment given appropriate params
  175.   It is quite stateless, but not completely :p
  176.   It is quite easy to make it completely stateless
  177.   Just diffuse *step* where it needs to be
  178.   */
  179. private:
  180. void AdvanceRate(const Ptr<Pair> p);
  181. Ptr<Socket> SetupPacketReceive(Ptr<Pair> p, const Address &);
  182. uint32_t step; // bps(throughput) shift between 2 sampling in an experiment
  183. public:
  184. ExperimentWifiPairs() {};
  185. std::vector <Ptr<Pair> > Run(const std::string sstart,
  186. const std::string sstep,
  187. const int numstep,
  188. const int numpairs,
  189. const unsigned int packet_size,
  190. const YansWifiChannelHelper &channel);
  191. };
  192.  
  193. Ptr<Socket> ExperimentWifiPairs::SetupPacketReceive(Ptr<Pair> p, const Address & address)
  194. {
  195. TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
  196. Ptr<Socket> sink = Socket::CreateSocket(p->server, tid);
  197. sink->Bind(address);
  198. sink->SetRecvCallback(MakeCallback(&Pair::ReceivePacket, p));
  199. return sink;
  200. }
  201.  
  202. void ExperimentWifiPairs::AdvanceRate(const Ptr<Pair> p)
  203. {
  204. DataRateValue drv = DataRateValue(DataRate(0));
  205. double measured_mbps = p->bits/1000000.0/SAMPLING_PERIOD_s;
  206. p->bits = 0;
  207.  
  208. Ptr<Application> onoff = p->client->GetApplication(0);
  209. onoff->GetAttribute("DataRate", drv);
  210.  
  211. double theoric_mbps;
  212. theoric_mbps = drv.Get().GetBitRate()/ 1000000.0;
  213. onoff->SetAttribute("DataRate", DataRateValue(DataRate(drv.Get().GetBitRate()+step)));
  214.  
  215. p->output.push_back(Point2d<double>(theoric_mbps, measured_mbps));
  216.  
  217. Simulator::Schedule(Seconds(SAMPLING_PERIOD_s), &ExperimentWifiPairs::AdvanceRate, this, p);
  218. }
  219.  
  220. std::vector<Ptr<Pair> > ExperimentWifiPairs::Run(const std::string sstart,
  221. const std::string sstep,
  222. const int numstep,
  223. const int numpairs,
  224. const unsigned int packet_size,
  225. const YansWifiChannelHelper &channel)
  226. {
  227. step = DataRate(sstep).GetBitRate();
  228.  
  229. std::vector<Ptr<Pair> > res;
  230.  
  231. NodeContainer APnodes,MSnodes;
  232. NetDeviceContainer APdevices, MSdevices;
  233. Ipv4InterfaceContainer MSinterfaces, APinterfaces;
  234. MobilityHelper mobility;
  235. InternetStackHelper stack;
  236. Ipv4AddressHelper address;
  237.  
  238. ChannelChooser chan = ChannelChooser(NUM_WIFI_CHANNELS);
  239.  
  240. APnodes.Create(numpairs);
  241. MSnodes.Create(numpairs);
  242.  
  243. NqosWifiMacHelper mac = NqosWifiMacHelper::Default();
  244. YansWifiPhyHelper phy = YansWifiPhyHelper::Default();
  245. phy.SetChannel(channel.Create());
  246.  
  247. // now going to the MAC layer
  248. WifiHelper wifi = WifiHelper::Default();
  249. wifi.SetStandard(USED_WIFI_STANDARD); // USED... is a global in this file
  250. //wifi.SetRemoteStationManager("ns3::ArfWifiManager");
  251.  
  252. // then we add mobility to the mobile stations
  253. mobility.SetPositionAllocator("ns3::GridPositionAllocator",
  254. "MinX", DoubleValue(0.0),
  255. "MinY", DoubleValue(0.0),
  256. "DeltaX", DoubleValue(DX_m),
  257. "DeltaY", DoubleValue(DY_m),
  258. "GridWidth", UintegerValue(2),
  259. "LayoutType", StringValue("RowFirst")
  260. );
  261. mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
  262.  
  263. for(int i = 0; i < numpairs; i++)
  264. {
  265. std::ostringstream oss;
  266. oss<<"exp_ssid_"<<i;
  267. std::string ssid = oss.str();
  268.  
  269. phy.Set("ChannelNumber", UintegerValue(chan.get(i)));
  270.  
  271. // creating a MAC layer and devices for the MS
  272. mac.SetType("ns3::StaWifiMac",
  273. "Ssid", SsidValue(ssid),
  274. "ActiveProbing", BooleanValue(false)
  275. ,"QosSupported", BooleanValue(false)
  276. );
  277. MSdevices.Add(wifi.Install(phy, mac, MSnodes.Get(i)));
  278. //and same for the AP
  279.  
  280. mac.SetType("ns3::ApWifiMac",
  281. "Ssid", SsidValue(ssid),
  282. "BeaconGeneration", BooleanValue(true),
  283. "BeaconInterval", TimeValue(Seconds(2.5))
  284. ,"QosSupported", BooleanValue(false)
  285. );
  286. APdevices.Add(wifi.Install(phy, mac, APnodes.Get(i)));
  287.  
  288. mobility.Install(APnodes.Get(i));
  289. mobility.Install(MSnodes.Get(i));
  290. }
  291.  
  292. // now we load internet stacks into our nodes
  293. stack.Install(APnodes);
  294. stack.Install(MSnodes);
  295.  
  296. address.SetBase("192.128.0.0", "255.255.255.0");
  297.  
  298. MSinterfaces = address.Assign(MSdevices);
  299. APinterfaces = address.Assign(APdevices);
  300.  
  301. // now the routes
  302. ns3::Ipv4GlobalRoutingHelper::PopulateRoutingTables();
  303. // and our network is configured!!
  304.  
  305. for(int i = 0; i < numpairs; i++)
  306. {
  307. Ptr<Pair> p = CreateObject<Pair>();
  308. p->server = APnodes.Get(i);
  309. p->client = MSnodes.Get(i);
  310. p->bits = 0;
  311. res.push_back(p);
  312.  
  313. Ipv4Address serverAddress = APinterfaces.GetAddress(i, 0);
  314.  
  315. OnOffHelper onoff("ns3::UdpSocketFactory", Address(InetSocketAddress(serverAddress,22)));
  316. onoff.SetAttribute("OnTime", RandomVariableValue(ConstantVariable(SAMPLING_PERIOD_s*(numstep+1)+1.5)));
  317. onoff.SetAttribute("OffTime", RandomVariableValue(ConstantVariable(0)));
  318. onoff.SetAttribute("DataRate", DataRateValue(DataRate(sstart)));
  319. onoff.SetAttribute("PacketSize", UintegerValue(packet_size)); // bytes/s
  320.  
  321. ApplicationContainer apps = onoff.Install(p->client);
  322. apps.Start(Seconds(1.5));
  323. apps.Stop(Seconds(SAMPLING_PERIOD_s*(numstep+1)+1.5));
  324.  
  325. Simulator::Schedule(Seconds(SAMPLING_PERIOD_s+1.5), &ExperimentWifiPairs::AdvanceRate, this, p);
  326. Ptr<Socket> recvSink = SetupPacketReceive(p, Address(InetSocketAddress(serverAddress,22)));
  327. }
  328.  
  329. if(OUTPUT_PCAP)
  330. phy.EnablePcap("iperf_sim", (IFTRUEOUTPUTAP_PCAP ? APdevices : MSdevices));
  331.  
  332. Simulator::Stop(Seconds(SAMPLING_PERIOD_s*(numstep+1)+2));
  333. //Simulator::Run();
  334. Visualizer::Run();
  335. Simulator::Destroy();
  336.  
  337. return res;
  338. }
  339.  
  340. // should divide this one when i get time
  341. void processRunsData(const std::vector<std::vector<Ptr<Pair> > > p,
  342. Gnuplot2dDataset &d)
  343. {
  344. const int num_runs = p.size();
  345. if(num_runs == 0)
  346. return;
  347. const int num_pairs = p.back().size();
  348. if(num_pairs == 0)
  349. return;
  350. const int num_samples = p.back().back()->output.size();
  351. if(num_samples == 0)
  352. return;
  353. double acc,iacc;
  354. // look at how to optimize this loop later
  355. // it can VERY probably be HEAVY optimized
  356. // though I don't know if this small summing
  357. // operations needs such optim
  358. for(int i = 0; i < num_samples; i++)
  359. { // but here we will process the data for 1 run
  360. acc = 0.0;
  361. for(int j = 0; j < num_pairs; j++)
  362. {
  363. iacc = 0.0;
  364. for(int k = 0; k < num_runs; k++)
  365. iacc += p[k][j]->output[i].y; // acc of one pair in the runs
  366. acc += iacc / num_runs; // we mean the iacc on the runs
  367. }
  368. d.Add(p.back().back()->output[i].x*num_pairs, acc);
  369. }
  370. }
  371.  
  372. int main(int argc, char *argv[])
  373. {
  374. Gnuplot gnuplot = Gnuplot(OUTPUT_IMAGE_NAME);
  375.  
  376. ExperimentWifiPairs experiment;
  377. Gnuplot2dDataset ds;
  378. YansWifiChannelHelper channel;
  379.  
  380. //YansWifiChannelHelper channel;
  381. //channel.SetPropagationDelay("ns3::ConstantSpeedPropagationDelayModel", "Speed", DoubleValue(299792458));
  382. //channel.AddPropagationLoss("ns3::RandomPropagationLossModel", "Variable", RandomVariableValue(ConstantVariable(50)));
  383.  
  384. typedef std::vector<Ptr<Pair> > ConfigRun;
  385. for(unsigned int i = 0; i < NUM_CONFIGS; i++)
  386. {
  387. std::vector<ConfigRun> config_runs;
  388. channel = YansWifiChannelHelper::Default();
  389. std::ostringstream oss;
  390. oss<<CONFIGS[i].NUM_PAIRS<<" pairs "
  391. <<CONFIGS[i].PACKET_SIZE<<"bits/packet";
  392. for(unsigned int j = 0; j < NUM_RUNS_BY_CONFIG; j++)
  393. {
  394. SeedManager::SetRun(i*NUM_RUNS_BY_CONFIG+j);
  395. config_runs.push_back(experiment.Run(CONFIGS[i].START,
  396. CONFIGS[i].STEP,
  397. CONFIGS[i].NUM_STEPS,
  398. CONFIGS[i].NUM_PAIRS,
  399. CONFIGS[i].PACKET_SIZE,
  400. channel));
  401. }
  402. ds = Gnuplot2dDataset(oss.str());
  403. ds.SetStyle(Gnuplot2dDataset::LINES_POINTS);
  404. processRunsData(config_runs, ds);
  405. gnuplot.AddDataset(ds);
  406. }
  407. std::ostringstream oss;
  408. const std::string ws =
  409. (USED_WIFI_STANDARD == WIFI_PHY_STANDARD_80211a ? "802.11a" :
  410. (USED_WIFI_STANDARD == WIFI_PHY_STANDARD_80211b ? "802.11b" :
  411. (USED_WIFI_STANDARD == WIFI_PHY_STANDARD_80211g ? "802.11g" :
  412. "???")));
  413. oss<<"WiFi UDP pairs Mbps/Mbps "<<NUM_RUNS_BY_CONFIG<<" runs";
  414. oss<<" - "<<SAMPLING_PERIOD_s<<"s/point ";
  415. oss<<ws<<" "<<NUM_WIFI_CHANNELS<<" channels used";
  416. gnuplot.SetTitle(oss.str());
  417.  
  418. gnuplot.GenerateOutput(std::cout);
  419.  
  420. return 0;
  421. }
  422.