5G-LENA nr-v3.3-120-gdac69c56
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
lena-lte-comparison.cc
1// Copyright (c) 2020 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4
5#include "lena-lte-comparison.h"
6
7#include "flow-monitor-output-stats.h"
8#include "lena-v1-utils.h"
9#include "lena-v2-utils.h"
10#include "power-output-stats.h"
11#include "rb-output-stats.h"
12#include "sinr-output-stats.h"
13#include "slot-output-stats.h"
14
15#include "ns3/antenna-module.h"
16#include "ns3/applications-module.h"
17#include "ns3/config-store-module.h"
18#include "ns3/config-store.h"
19#include "ns3/core-module.h"
20#include "ns3/flow-monitor-module.h"
21#include "ns3/internet-apps-module.h"
22#include "ns3/internet-module.h"
23#include "ns3/lte-module.h"
24#include "ns3/mobility-module.h"
25#include "ns3/network-module.h"
26#include "ns3/point-to-point-module.h"
27#include "ns3/radio-environment-map-helper.h"
28#include "ns3/sqlite-output.h"
29
30#include <iomanip>
31
32/*
33 * To be able to use LOG_* functions.
34 */
35#include "ns3/log.h"
36
37/*
38 * With this line, we will be able to see the logs of the file by enabling the
39 * component "LenaLteComparison", in this way:
40 *
41 * $ export NS_LOG="LenaLteComparison=level_info|prefix_func|prefix_time"
42 */
43NS_LOG_COMPONENT_DEFINE("LenaLteComparison");
44
45namespace ns3
46{
47
48const Time appStartWindow = MilliSeconds(50);
49
50template <typename T>
51Ptr<T>
52CreateLowLatTft(uint16_t start, uint16_t end, std::string dir)
53{
54 Ptr<T> lowLatTft;
55 lowLatTft = Create<T>();
56 typename T::PacketFilter dlpfLowLat;
57 if (dir == "DL")
58 {
59 dlpfLowLat.localPortStart = start;
60 dlpfLowLat.localPortEnd = end;
61 dlpfLowLat.direction = T::DOWNLINK;
62 }
63 else
64 {
65 dlpfLowLat.remotePortStart = start;
66 dlpfLowLat.remotePortEnd = end;
67 dlpfLowLat.direction = T::UPLINK;
68 }
69 lowLatTft->Add(dlpfLowLat);
70 return lowLatTft;
71}
72
73template Ptr<ns3::EpcTft> CreateLowLatTft<ns3::EpcTft>(uint16_t, uint16_t, std::string);
74template Ptr<ns3::NrEpcTft> CreateLowLatTft<ns3::NrEpcTft>(uint16_t, uint16_t, std::string);
75
76static std::pair<ApplicationContainer, Time>
77InstallApps(const Ptr<Node>& ue,
78 const Ptr<NetDevice>& ueDevice,
79 const Address& ueAddress,
80 const std::string& direction,
81 UdpClientHelper* dlClientLowLat,
82 const Ptr<Node>& remoteHost,
83 const Ipv4Address& remoteHostAddr,
84 Time udpAppStartTime,
85 uint16_t dlPortLowLat,
86 const Ptr<UniformRandomVariable>& x,
87 Time appGenerationTime,
88 const Ptr<LteHelper>& lteHelper,
89 const Ptr<NrHelper>& nrHelper)
90{
91 ApplicationContainer app;
92
93 // The bearer that will carry low latency traffic
94 EpsBearer lowLatBearer(EpsBearer::NGBR_VIDEO_TCP_DEFAULT);
95 NrEpsBearer nrLowLatBearer(NrEpsBearer::NGBR_VIDEO_TCP_DEFAULT);
96
97 // The filter for the low-latency traffic
98 Ptr<EpcTft> lowLatTft = CreateLowLatTft<EpcTft>(dlPortLowLat, dlPortLowLat, direction);
99 Ptr<NrEpcTft> nrLowLatTft = CreateLowLatTft<NrEpcTft>(dlPortLowLat, dlPortLowLat, direction);
100
101 // The client, who is transmitting, is installed in the remote host,
102 // with destination address set to the address of the UE
103 if (direction == "DL")
104 {
105 dlClientLowLat->SetAttribute("RemoteAddress", AddressValue(ueAddress));
106 app = dlClientLowLat->Install(remoteHost);
107 }
108 else
109 {
110 dlClientLowLat->SetAttribute("RemoteAddress", AddressValue(remoteHostAddr));
111 app = dlClientLowLat->Install(ue);
112 }
113
114 double start = x->GetValue(udpAppStartTime.GetMilliSeconds(),
115 (udpAppStartTime + appStartWindow).GetMilliSeconds());
116 Time startTime = MilliSeconds(start);
117 app.Start(startTime);
118 app.Stop(startTime + appGenerationTime);
119
120 std::cout << "\tStarts at time " << startTime.As(Time::MS) << " and ends at "
121 << (startTime + appGenerationTime).As(Time::MS) << std::endl;
122
123 // Activate a dedicated bearer for the traffic type
124 if (lteHelper != nullptr)
125 {
126 lteHelper->ActivateDedicatedEpsBearer(ueDevice, lowLatBearer, lowLatTft);
127 }
128 else if (nrHelper != nullptr)
129 {
130 nrHelper->ActivateDedicatedEpsBearer(ueDevice, nrLowLatBearer, nrLowLatTft);
131 }
132
133 return std::make_pair(app, startTime);
134}
135
136bool
137Parameters::Validate() const
138{
139 NS_ABORT_MSG_IF(bandwidthMHz != 20 && bandwidthMHz != 10 && bandwidthMHz != 5,
140 "Valid bandwidth values are 20, 10, 5, you set " << bandwidthMHz);
141
142 NS_ABORT_MSG_IF(trafficScenario > 3,
143 "Traffic scenario " << trafficScenario
144 << " not valid. Valid values are 0 1 2 3");
145
146 NS_ABORT_MSG_IF(numerologyBwp > 4, "At most 4 bandwidth parts supported.");
147
148 NS_ABORT_MSG_IF(direction != "DL" && direction != "UL",
149 "Flow direction can only be DL or UL: " << direction);
150 NS_ABORT_MSG_IF(operationMode != "TDD" && operationMode != "FDD",
151 "Operation mode can only be TDD or FDD: " << operationMode);
152 NS_ABORT_MSG_IF(radioNetwork != "LTE" && radioNetwork != "NR",
153 "Unrecognized radio network technology: " << radioNetwork);
154 NS_ABORT_MSG_IF(radioNetwork == "LTE" && operationMode != "FDD",
155 "Operation mode must be FDD in a 4G LTE network: " << operationMode);
156 NS_ABORT_MSG_IF(simulator != "LENA" && simulator != "5GLENA",
157 "Unrecognized simulator: " << simulator);
158 NS_ABORT_MSG_IF(scheduler != "PF" && scheduler != "RR",
159 "Unrecognized scheduler: " << scheduler);
160
161 if (dlRem || ulRem)
162 {
163 NS_ABORT_MSG_IF(simulator != "5GLENA",
164 "Cannot do the REM with the simulator " << simulator);
165 NS_ABORT_MSG_IF(dlRem && ulRem, "You selected both DL and UL REM, that is not supported");
166 NS_ABORT_MSG_IF(remSector > 3, "Only three sectors supported for REM");
167
168 NS_ABORT_MSG_IF(remSector == 0 && freqScenario != 1,
169 "RemSector == 0 makes sense only in a OVERLAPPING scenario");
170 }
171
172 return true;
173}
174
175void
176LenaLteComparison(const Parameters& params)
177{
178 params.Validate();
179
180 // Traffic parameters (that we will use inside this script:)
181 uint32_t udpPacketSize = 1000;
182 uint32_t lambda;
183 uint32_t packetCount;
184
185 std::cout << "\n----------------------------------------\n"
186 << "Configuring scenario" << std::endl;
187
188 std::cout << " traffic parameters\n";
189 switch (params.trafficScenario)
190 {
191 case 0: // let's put 80 Mbps with 20 MHz of bandwidth. Everything else is scaled
192 packetCount = 0xFFFFFFFF;
193 switch (params.bandwidthMHz)
194 {
195 case 20:
196 udpPacketSize = 1000;
197 break;
198 case 10:
199 udpPacketSize = 500;
200 break;
201 case 5:
202 udpPacketSize = 250;
203 break;
204 default:
205 udpPacketSize = 1000;
206 }
207 lambda = 10000 / params.ueNumPergNb;
208 break;
209 case 1:
210 packetCount = 1;
211 udpPacketSize = 12;
212 lambda = 1;
213 break;
214 case 2: // 1 Mbps == 0.125 MB/s in case of 20 MHz, everything else is scaled
215 packetCount = 0xFFFFFFFF;
216 switch (params.bandwidthMHz)
217 {
218 case 20:
219 udpPacketSize = 125;
220 break;
221 case 10:
222 udpPacketSize = 63;
223 break;
224 case 5:
225 udpPacketSize = 32;
226 break;
227 default:
228 udpPacketSize = 125;
229 }
230 lambda = 1000 / params.ueNumPergNb;
231 break;
232 case 3: // 20 Mbps == 2.5 MB/s in case of 20 MHz, everything else is scaled
233 packetCount = 0xFFFFFFFF;
234 switch (params.bandwidthMHz)
235 {
236 case 20:
237 udpPacketSize = 250;
238 break;
239 case 10:
240 udpPacketSize = 125;
241 break;
242 case 5:
243 udpPacketSize = 75;
244 break;
245 default:
246 udpPacketSize = 250;
247 }
248 lambda = 10000 / params.ueNumPergNb;
249 break;
250 default:
251 NS_FATAL_ERROR("Traffic scenario " << params.trafficScenario
252 << " not valid. Valid values are 0 1 2 3");
253 }
254
255 std::cout << " statistics\n";
256 SQLiteOutput db(params.outputDir + "/" + params.simTag + ".db");
257 SinrOutputStats sinrStats;
258 PowerOutputStats ueTxPowerStats;
259 PowerOutputStats gnbRxPowerStats;
260 SlotOutputStats slotStats;
261 RbOutputStats rbStats;
262
263 sinrStats.SetDb(&db);
264 ueTxPowerStats.SetDb(&db, "ueTxPower");
265 slotStats.SetDb(&db);
266 rbStats.SetDb(&db);
267 gnbRxPowerStats.SetDb(&db, "gnbRxPower");
268
269 /*
270 * Check if the frequency and numerology are in the allowed range.
271 * If you need to add other checks, here is the best position to put them.
272 */
273 std::cout << " checking frequency and numerology\n";
274
275 /*
276 * If the logging variable is set to true, enable the log of some components
277 * through the code. The same effect can be obtained through the use
278 * of the NS_LOG environment variable:
279 *
280 * export NS_LOG="UdpClient=level_info|prefix_time|prefix_func|prefix_node:UdpServer=..."
281 *
282 * Usually, the environment variable way is preferred, as it is more customizable,
283 * and more expressive.
284 */
285 std::cout << " logging\n";
286 if (params.logging)
287 {
288 LogComponentEnable("UdpClient", LOG_LEVEL_INFO);
289 LogComponentEnable("UdpServer", LOG_LEVEL_INFO);
290 LogComponentEnable("LtePdcp", LOG_LEVEL_INFO);
291 // LogComponentEnable ("NrMacSchedulerOfdma", LOG_LEVEL_ALL);
292 }
293
294 /*
295 * Default values for the simulation. We are progressively removing all
296 * the instances of SetDefault, but we need it for legacy code (LTE)
297 */
298 std::cout << " max tx buffer size\n";
299 Config::SetDefault("ns3::LteRlcUm::MaxTxBufferSize", UintegerValue(999999999));
300
301 /*
302 * Create the scenario. In our examples, we heavily use helpers that setup
303 * the gnbs and ue following a pre-defined pattern. Please have a look at the
304 * HexagonalGridScenarioHelper documentation to see how the nodes will be distributed.
305 */
306
307 ScenarioParameters scenarioParams;
308 scenarioParams.SetScenarioParameters(params.scenario);
309 // Customize parameters here
310 // scenarioParams.isd = ...
311
312 // The essentials describing a laydown
313 uint32_t gnbSites = 0;
314 NodeContainer gnbNodes;
315 NodeContainer ueNodes;
316 double sector0AngleRad = 0;
317 const uint32_t sectors = 3;
318
319 //
320 NodeDistributionScenarioInterface* scenario{nullptr};
321 FileScenarioHelper fileScenario;
322 HexagonalGridScenarioHelper gridScenario;
323
324 if (!params.baseStationFile.empty() and params.useSiteFile)
325 {
326 std::cout << " using tower positions from " << params.baseStationFile << std::endl;
327 std::cout << " setting sectorization" << std::endl;
328 fileScenario.SetSectorization(sectors);
329 std::cout << " adding site file" << std::endl;
330 fileScenario.Add(params.baseStationFile);
331 std::cout << " setting scenario" << std::endl;
332 fileScenario.SetScenarioParameters(params.scenario);
333 std::cout << " getting number of sites..." << std::flush;
334 gnbSites = fileScenario.GetNumSites();
335 std::cout << gnbSites << std::endl;
336 std::cout << " getting number of cells..." << std::flush;
337 uint32_t gnbNum = fileScenario.GetNumCells();
338 std::cout << gnbNum << std::endl;
339 uint32_t ueNum = params.ueNumPergNb * gnbNum;
340 std::cout << " setting number of UEs..." << ueNum << std::endl;
341 fileScenario.SetUtNumber(ueNum);
342 std::cout << " getting sector 0 angle..." << std::flush;
343 sector0AngleRad = fileScenario.GetAntennaOrientationRadians(0);
344 std::cout << sector0AngleRad << std::endl;
345
346 // Creates and plots the network deployment
347 std::cout << " creating scenario" << std::endl;
348 fileScenario.CreateScenario();
349 std::cout << " getting gnbNodes..." << std::flush;
350 gnbNodes = fileScenario.GetBaseStations();
351 std::cout << gnbNodes.GetN() << std::endl;
352 std::cout << " getting ueNodes..." << std::flush;
353 ueNodes = fileScenario.GetUserTerminals();
354 std::cout << ueNodes.GetN() << std::endl;
355 std::cout << " setting scenario pointer..." << std::flush;
356 scenario = &fileScenario;
357 std::cout << "0x" << std::hex << scenario << std::dec << std::endl;
358 }
359 else
360 {
361 std::cout << " hexagonal grid: ";
362 gridScenario.SetScenarioParameters(scenarioParams);
363 gridScenario.SetNumRings(params.numOuterRings);
364 gnbSites = gridScenario.GetNumSites();
365 uint32_t ueNum = params.ueNumPergNb * gnbSites * sectors;
366 gridScenario.SetUtNumber(ueNum);
367 sector0AngleRad = gridScenario.GetAntennaOrientationRadians(0);
368 std::cout << sector0AngleRad << std::endl;
369
370 // Creates and plots the network deployment
371 gridScenario.CreateScenario();
372 gnbNodes = gridScenario.GetBaseStations();
373 ueNodes = gridScenario.GetUserTerminals();
374 scenario = &gridScenario;
375 }
376
377 // Log the configuration
378 std::cout << "\n Topology configuration: " << gnbSites << " sites, " << sectors
379 << " sectors/site, " << gnbNodes.GetN() << " cells, " << ueNodes.GetN() << " UEs\n";
380
381 /*
382 * Create different gNB NodeContainer for the different sectors.
383 *
384 * Relationships between ueId, cellId, sectorId and siteId:
385 * ~~~{.cc}
386 * cellId = scenario->GetCellIndex (ueId);
387 * sector = scenario->GetSectorIndex (cellId);
388 * siteId = scenario->GetSiteIndex (cellId);
389 * ~~~{.cc}
390 *
391 * Iterate/index gnbNodes, gnbNetDevs by `cellId`.
392 * Iterate/index gnbSector<N>Container, gnbNodesBySector[sector],
393 * gnbSector<N>NetDev, gnbNdBySector[sector] by `siteId`
394 */
395 NodeContainer gnbSector1Container;
396 NodeContainer gnbSector2Container;
397 NodeContainer gnbSector3Container;
398 std::vector<NodeContainer*> gnbNodesBySector{&gnbSector1Container,
399 &gnbSector2Container,
400 &gnbSector3Container};
401 for (uint32_t cellId = 0; cellId < gnbNodes.GetN(); ++cellId)
402 {
403 Ptr<Node> gnb = gnbNodes.Get(cellId);
404 auto sector = scenario->GetSectorIndex(cellId);
405 gnbNodesBySector[sector]->Add(gnb);
406 }
407 std::cout << " gNb containers: " << gnbSector1Container.GetN() << ", "
408 << gnbSector2Container.GetN() << ", " << gnbSector3Container.GetN() << std::endl;
409
410 /*
411 * Create different UE NodeContainer for the different sectors.
412 *
413 * Multiple UEs per sector!
414 * Iterate/index ueNodes, ueNetDevs, ueIpIfaces by `ueId`.
415 * Iterate/Index ueSector<N>Container, ueNodesBySector[sector],
416 * ueSector<N>NetDev, ueNdBySector[sector] with i % gnbSites
417 */
418 NodeContainer ueSector1Container;
419 NodeContainer ueSector2Container;
420 NodeContainer ueSector3Container;
421 std::vector<NodeContainer*> ueNodesBySector{&ueSector1Container,
422 &ueSector2Container,
423 &ueSector3Container};
424 for (uint32_t ueId = 0; ueId < ueNodes.GetN(); ++ueId)
425 {
426 Ptr<Node> ue = ueNodes.Get(ueId);
427 auto cellId = scenario->GetCellIndex(ueId);
428 auto sector = scenario->GetSectorIndex(cellId);
429 ueNodesBySector[sector]->Add(ue);
430 }
431 std::cout << " UE containers: " << ueSector1Container.GetN() << ", "
432 << ueSector2Container.GetN() << ", " << ueSector3Container.GetN() << std::endl;
433
434 /*
435 * Setup the LTE or NR module. We create the various helpers needed inside
436 * their respective configuration functions
437 */
438 std::cout << " helpers\n";
439 Ptr<PointToPointEpcHelper> epcHelper;
440 Ptr<NrPointToPointEpcHelper> nrEpcHelper;
441
442 NetDeviceContainer gnbSector1NetDev;
443 NetDeviceContainer gnbSector2NetDev;
444 NetDeviceContainer gnbSector3NetDev;
445 std::vector<NetDeviceContainer*> gnbNdBySector{&gnbSector1NetDev,
446 &gnbSector2NetDev,
447 &gnbSector3NetDev};
448 NetDeviceContainer ueSector1NetDev;
449 NetDeviceContainer ueSector2NetDev;
450 NetDeviceContainer ueSector3NetDev;
451 std::vector<NetDeviceContainer*> ueNdBySector{&ueSector1NetDev,
452 &ueSector2NetDev,
453 &ueSector3NetDev};
454
455 Ptr<LteHelper> lteHelper = nullptr;
456 Ptr<NrHelper> nrHelper = nullptr;
457
458 if (params.simulator == "LENA")
459 {
460 epcHelper = CreateObject<PointToPointEpcHelper>();
461 LenaV1Utils::SetLenaV1SimulatorParameters(sector0AngleRad,
462 params.scenario,
463 gnbSector1Container,
464 gnbSector2Container,
465 gnbSector3Container,
466 ueSector1Container,
467 ueSector2Container,
468 ueSector3Container,
469 epcHelper,
470 lteHelper,
471 gnbSector1NetDev,
472 gnbSector2NetDev,
473 gnbSector3NetDev,
474 ueSector1NetDev,
475 ueSector2NetDev,
476 ueSector3NetDev,
477 params.calibration,
478 params.enableUlPc,
479 &sinrStats,
480 &ueTxPowerStats,
481 params.scheduler,
482 params.bandwidthMHz,
483 params.freqScenario,
484 params.downtiltAngle);
485 }
486 else if (params.simulator == "5GLENA")
487 {
488 nrEpcHelper = CreateObject<NrPointToPointEpcHelper>();
490 params.scenario,
491 params.radioNetwork,
492 params.errorModel,
493 params.operationMode,
494 params.direction,
495 params.numerologyBwp,
496 params.pattern,
497 gnbSector1Container,
498 gnbSector2Container,
499 gnbSector3Container,
500 ueSector1Container,
501 ueSector2Container,
502 ueSector3Container,
503 nrEpcHelper,
504 nrHelper,
505 gnbSector1NetDev,
506 gnbSector2NetDev,
507 gnbSector3NetDev,
508 ueSector1NetDev,
509 ueSector2NetDev,
510 ueSector3NetDev,
511 params.calibration,
512 params.enableUlPc,
513 params.powerAllocation,
514 &sinrStats,
515 &ueTxPowerStats,
516 &gnbRxPowerStats,
517 &slotStats,
518 &rbStats,
519 params.scheduler,
520 params.bandwidthMHz,
521 params.freqScenario,
522 params.downtiltAngle);
523 }
524
525 // Check we got one valid helper
526 if ((lteHelper == nullptr) && (nrHelper == nullptr))
527 {
528 NS_ABORT_MSG("Programming error: no valid helper");
529 }
530
531 // From here, it is standard NS3. In the future, we will create helpers
532 // for this part as well.
533
534 // create the internet and install the IP stack on the UEs
535 // get SGW/PGW and create a single RemoteHost
536 std::cout << " pgw and internet\n";
537 Ptr<Node> pgw;
538 if (params.simulator == "LENA")
539 {
540 pgw = epcHelper->GetPgwNode();
541 }
542 else
543 {
544 pgw = nrEpcHelper->GetPgwNode();
545 }
546 NodeContainer remoteHostContainer;
547 remoteHostContainer.Create(1);
548 Ptr<Node> remoteHost = remoteHostContainer.Get(0);
549 InternetStackHelper internet;
550 internet.Install(remoteHostContainer);
551
552 // connect a remoteHost to pgw. Setup routing too
553 PointToPointHelper p2ph;
554 p2ph.SetDeviceAttribute("DataRate", DataRateValue(DataRate("100Gb/s")));
555 p2ph.SetDeviceAttribute("Mtu", UintegerValue(2500));
556 p2ph.SetChannelAttribute("Delay", TimeValue(Seconds(0.000)));
557 NetDeviceContainer internetDevices = p2ph.Install(pgw, remoteHost);
558 Ipv4AddressHelper ipv4h;
559 Ipv4StaticRoutingHelper ipv4RoutingHelper;
560 ipv4h.SetBase("1.0.0.0", "255.0.0.0");
561 Ipv4InterfaceContainer internetIpIfaces = ipv4h.Assign(internetDevices);
562 Ptr<Ipv4StaticRouting> remoteHostStaticRouting =
563 ipv4RoutingHelper.GetStaticRouting(remoteHost->GetObject<Ipv4>());
564 remoteHostStaticRouting->AddNetworkRouteTo(Ipv4Address("7.0.0.0"), Ipv4Mask("255.0.0.0"), 1);
565 internet.Install(ueNodes);
566
567 NetDeviceContainer gnbNetDevs(gnbSector1NetDev, gnbSector2NetDev);
568 gnbNetDevs.Add(gnbSector3NetDev);
569 NetDeviceContainer ueNetDevs(ueSector1NetDev, ueSector2NetDev);
570 ueNetDevs.Add(ueSector3NetDev);
571
572 Ipv4InterfaceContainer ueIpIfaces;
573 Ipv4Address gatewayAddress;
574 if (params.simulator == "LENA")
575 {
576 ueIpIfaces = epcHelper->AssignUeIpv4Address(ueNetDevs);
577 gatewayAddress = epcHelper->GetUeDefaultGatewayAddress();
578 }
579 else
580 {
581 ueIpIfaces = nrEpcHelper->AssignUeIpv4Address(ueNetDevs);
582 gatewayAddress = nrEpcHelper->GetUeDefaultGatewayAddress();
583 }
584
585 Ipv4Address remoteHostAddr = internetIpIfaces.GetAddress(1);
586
587 // Set the default gateway for the UEs
588 std::cout << " default gateway\n";
589 for (auto ue = ueNodes.Begin(); ue != ueNodes.End(); ++ue)
590 {
591 Ptr<Ipv4StaticRouting> ueStaticRouting =
592 ipv4RoutingHelper.GetStaticRouting((*ue)->GetObject<Ipv4>());
593 ueStaticRouting->SetDefaultRoute(gatewayAddress, 1);
594 }
595
596 // attach UEs to their gNB. Try to attach them per cellId order
597 std::cout << " attach UEs to gNBs\n" << std::endl;
598 for (uint32_t ueId = 0; ueId < ueNodes.GetN(); ++ueId)
599 {
600 auto cellId = scenario->GetCellIndex(ueId);
601 Ptr<NetDevice> gnbNetDev = gnbNodes.Get(cellId)->GetDevice(0);
602 Ptr<NetDevice> ueNetDev = ueNodes.Get(ueId)->GetDevice(0);
603 if (lteHelper != nullptr)
604 {
605 lteHelper->Attach(ueNetDev, gnbNetDev);
606 }
607 else if (nrHelper != nullptr)
608 {
609 nrHelper->AttachToGnb(ueNetDev, gnbNetDev);
610 auto uePhyBwp0{nrHelper->GetUePhy(ueNetDev, 0)};
611 auto gnbPhyBwp0{nrHelper->GetGnbPhy(gnbNetDev, 0)};
612 Vector gnbpos = gnbNetDev->GetNode()->GetObject<MobilityModel>()->GetPosition();
613 Vector uepos = ueNetDev->GetNode()->GetObject<MobilityModel>()->GetPosition();
614 double distance = CalculateDistance(gnbpos, uepos);
615 std::cout << "ueId " << ueId << ", cellIndex " << cellId << ", ue freq "
616 << uePhyBwp0->GetCentralFrequency() / 1e9 << ", gnb freq "
617 << gnbPhyBwp0->GetCentralFrequency() / 1e9 << ", sector "
618 << scenario->GetSectorIndex(cellId) << ", distance " << distance
619 << ", azimuth gnb->ue:"
620 << RadiansToDegrees(Angles(gnbpos, uepos).GetAzimuth()) << std::endl;
621 }
622 }
623
624 /*
625 * Traffic part. Install two kind of traffic: low-latency and voice, each
626 * identified by a particular source port.
627 */
628 std::cout << " server factory\n";
629 uint16_t dlPortLowLat = 1234;
630
631 ApplicationContainer serverApps;
632
633 // The sink will always listen to the specified ports
634 UdpServerHelper dlPacketSinkLowLat(dlPortLowLat);
635
636 // The server, that is the application which is listening, is installed in the UE
637 if (params.direction == "DL")
638 {
639 serverApps.Add(dlPacketSinkLowLat.Install(ueNodes));
640 }
641 else
642 {
643 serverApps.Add(dlPacketSinkLowLat.Install(remoteHost));
644 }
645
646 // start UDP server
647 serverApps.Start(params.udpAppStartTime);
648
649 /*
650 * Configure attributes for the different generators, using user-provided
651 * parameters for generating a CBR traffic
652 *
653 * Low-Latency configuration and object creation:
654 */
655 Time interval = Seconds(1.0 / lambda);
656 std::cout << " client factory:"
657 << "\n packet size: " << udpPacketSize << "\n interval: " << interval
658 << "\n max packets: " << packetCount << std::endl;
659
660 UdpClientHelper dlClientLowLat;
661 dlClientLowLat.SetAttribute("RemotePort", UintegerValue(dlPortLowLat));
662 dlClientLowLat.SetAttribute("MaxPackets", UintegerValue(packetCount));
663 dlClientLowLat.SetAttribute("PacketSize", UintegerValue(udpPacketSize));
664 dlClientLowLat.SetAttribute("Interval", TimeValue(interval));
665
666 /*
667 * Let's install the applications!
668 */
669 std::cout << " applications\n";
670 ApplicationContainer clientApps;
671 Ptr<UniformRandomVariable> startRng = CreateObject<UniformRandomVariable>();
672 startRng->SetStream(RngSeedManager::GetRun());
673 Time maxStartTime;
674
675 for (uint32_t ueId = 0; ueId < ueNodes.GetN(); ++ueId)
676 {
677 auto cellId = scenario->GetCellIndex(ueId);
678 auto sector = scenario->GetSectorIndex(cellId);
679 auto siteId = scenario->GetSiteIndex(cellId);
680 Ptr<Node> node = ueNodes.Get(ueId);
681 Ptr<NetDevice> dev = ueNetDevs.Get(ueId);
682 Address addr = ueIpIfaces.GetAddress(ueId);
683
684 std::cout << "app for ue " << ueId << ", cellId " << cellId << ", sector " << sector
685 << ", siteId " << siteId;
686 // << ":" << std::endl;
687
688 auto app = InstallApps(node,
689 dev,
690 addr,
691 params.direction,
692 &dlClientLowLat,
693 remoteHost,
694 remoteHostAddr,
695 params.udpAppStartTime,
696 dlPortLowLat,
697 startRng,
698 params.appGenerationTime,
699 lteHelper,
700 nrHelper);
701 maxStartTime = std::max(app.second, maxStartTime);
702 clientApps.Add(app.first);
703 }
704 std::cout << clientApps.GetN() << " apps\n";
705
706 // enable the traces provided by the nr module
707 std::cout << " tracing\n";
708 if (params.traces)
709 {
710 if (lteHelper != nullptr)
711 {
712 lteHelper->EnableTraces();
713 }
714 else if (nrHelper != nullptr)
715 {
716 nrHelper->EnableTraces();
717 }
718 }
719
720 std::cout << " flowmon\n";
721 FlowMonitorHelper flowmonHelper;
722 NodeContainer endpointNodes;
723 endpointNodes.Add(remoteHost);
724 endpointNodes.Add(ueNodes);
725
726 Ptr<FlowMonitor> monitor = flowmonHelper.Install(endpointNodes);
727 monitor->SetAttribute("DelayBinWidth", DoubleValue(0.001));
728 monitor->SetAttribute("JitterBinWidth", DoubleValue(0.001));
729 monitor->SetAttribute("PacketSizeBinWidth", DoubleValue(20));
730
731 std::string tableName = "e2e";
732
733 Ptr<NrRadioEnvironmentMapHelper>
734 remHelper; // Must be placed outside of block "if (generateRem)" because otherwise it gets
735 // destroyed, and when simulation starts the object does not exist anymore, but
736 // the scheduled REM events do (exist). So, REM events would be called with
737 // invalid pointer to remHelper ...
738
739 if (params.dlRem || params.ulRem)
740 {
741 std::cout << " rem helper\n";
742
743 uint16_t remPhyIndex = 0;
744 if (params.operationMode == "FDD" && params.direction == "UL")
745 {
746 remPhyIndex = 1;
747 }
748
749 NetDeviceContainer remNd;
750 Ptr<NetDevice> remDevice;
751
752 // params.ulRem:
753 std::vector<NetDeviceContainer*> remNdBySector{ueNdBySector};
754 std::vector<NetDeviceContainer*> remDevBySector{gnbNdBySector};
755
756 if (params.dlRem)
757 {
758 remNdBySector = gnbNdBySector;
759 remDevBySector = ueNdBySector;
760 }
761
762 uint32_t sectorIndex = 0;
763 // Reverse order so we get sector 1 for the remSector == 0 case
764 for (uint32_t sector = sectors; sector > 0; --sector)
765 {
766 if (params.remSector == sector || params.remSector == 0)
767 {
768 sectorIndex = sector - 1;
769 remNd.Add(*remNdBySector[sectorIndex]);
770 remDevice = remDevBySector[sectorIndex]->Get(0);
771 }
772 }
773
774 if (params.ulRem)
775 {
776 auto antArray =
777 DynamicCast<NrGnbNetDevice>(remDevice)->GetPhy(0)->GetSpectrumPhy()->GetAntenna();
778 auto antenna = DynamicCast<UniformPlanarArray>(antArray);
779 antenna->SetAttribute("AntennaElement",
780 PointerValue(CreateObject<IsotropicAntennaModel>()));
781 }
782
783 // Radio Environment Map Generation for ccId 0
784 remHelper = CreateObject<NrRadioEnvironmentMapHelper>();
785 remHelper->SetMinX(params.xMinRem);
786 remHelper->SetMaxX(params.xMaxRem);
787 remHelper->SetResX(params.xResRem);
788 remHelper->SetMinY(params.yMinRem);
789 remHelper->SetMaxY(params.yMaxRem);
790 remHelper->SetResY(params.yResRem);
791 remHelper->SetZ(params.zRem);
792
793 // save beamforming vectors, one per site (?)
794 for (uint32_t sector = sectors; sector > 0; --sector)
795 {
796 if ((params.remSector == sector) || (params.remSector == 0))
797 {
798 sectorIndex = sector - 1;
799 for (uint32_t siteId = 0; siteId < gnbSites; ++siteId)
800 {
801 gnbNdBySector[sectorIndex]
802 ->Get(siteId)
803 ->GetObject<NrGnbNetDevice>()
804 ->GetPhy(remPhyIndex)
805 ->ChangeBeamformingVector(
806 DynamicCast<NrUeNetDevice>(ueNdBySector[sectorIndex]->Get(siteId)));
807 }
808 }
809 }
810
811 remHelper->CreateRem(remNd, remDevice, remPhyIndex);
812 }
813
814 std::cout << "\n----------------------------------------\n"
815 << "Start simulation" << std::endl;
816 // Add some extra time for the last generated packets to be received
817 const Time appStopWindow = MilliSeconds(50);
818 Time stopTime = maxStartTime + params.appGenerationTime + appStopWindow;
819 Simulator::Stop(stopTime);
820 Simulator::Run();
821
822 sinrStats.EmptyCache();
823 ueTxPowerStats.EmptyCache();
824 gnbRxPowerStats.EmptyCache();
825 slotStats.EmptyCache();
826 rbStats.EmptyCache();
827
828 /*
829 * To check what was installed in the memory, i.e., BWPs of gNB Device, and its configuration.
830 * Example is: Node 1 -> Device 0 -> BandwidthPartMap -> {0,1} BWPs -> NrGnbPhy -> Numerology,
831 GtkConfigStore config;
832 config.ConfigureAttributes ();
833 */
834
835 FlowMonitorOutputStats flowMonStats;
836 flowMonStats.SetDb(&db, tableName);
837 flowMonStats.Save(monitor, flowmonHelper, params.outputDir + "/" + params.simTag);
838
839 std::cout << "\n----------------------------------------\n"
840 << "End simulation" << std::endl;
841
842 Simulator::Destroy();
843}
844
845std::ostream&
846operator<<(std::ostream& os, const Parameters& parameters)
847{
848 // Use p as shorthand for arg parametersx
849 auto p{parameters};
850
851#define MSG(m) \
852 os << "\n" << m << std::left << std::setw(40 - strlen(m)) << (strlen(m) > 0 ? ":" : "")
853
854 MSG("LENA LTE Scenario Parameters");
855 MSG("");
856 MSG("Model version") << p.simulator << (p.simulator == "LENA" ? " (v1)" : " (v2)");
857 if (p.simulator == "5GLENA")
858 {
859 MSG("LTE Standard") << p.radioNetwork << (p.radioNetwork == "LTE" ? " (4G)" : " (5G NR)");
860 MSG("4G-NR calibration mode") << (p.calibration ? "ON" : "off");
861 MSG("4G-NR ULPC mode") << (p.enableUlPc ? "Enabled" : "Disabled");
862 MSG("Operation mode") << p.operationMode;
863 if (p.operationMode == "TDD")
864 {
865 MSG("Numerology") << p.numerologyBwp;
866 MSG("TDD pattern") << p.pattern;
867 }
868 if (!p.errorModel.empty())
869 {
870 MSG("Error model") << p.errorModel;
871 }
872 else if (p.radioNetwork == "LTE")
873 {
874 MSG("Error model") << "ns3::LenaErrorModel";
875 }
876 else if (p.radioNetwork == "NR")
877 {
878 MSG("Error model") << "ns3::NrEesmCcT2";
879 }
880 }
881 else
882 {
883 // LENA v1
884 p.operationMode = "FDD";
885 MSG("LTE Standard") << "4G";
886 MSG("Calibration mode") << (p.calibration ? "ON" : "off");
887 MSG("LTE ULPC mode") << (p.enableUlPc ? "Enabled" : "Disabled");
888 MSG("Operation mode") << p.operationMode;
889 }
890
891 if (!p.baseStationFile.empty() and p.useSiteFile)
892 {
893 MSG("Base station positions") << "read from file " << p.baseStationFile;
894 }
895 else
896 {
897 MSG("Base station positions") << "regular hexaonal lay down";
898 MSG("Number of rings") << p.numOuterRings;
899 }
900
901 MSG("");
902 MSG("Channel bandwidth") << p.bandwidthMHz << " MHz";
903 MSG("Spectrum configuration") << (p.freqScenario == 0 ? "non-" : "") << "overlapping";
904 MSG("LTE Scheduler") << p.scheduler;
905
906 MSG("");
907 MSG("Basic scenario") << p.scenario;
908 if (p.scenario == "UMa")
909 {
910 os << "\n (ISD: 1.7 km, BS: 30 m, UE: 1.5 m, UE-BS min: 30.2 m)";
911 }
912 else if (p.scenario == "UMi")
913 {
914 os << "\n (ISD: 0.5 km, BS: 10 m, UE: 1.5 m, UE-BS min: 10 m)";
915 }
916 else if (p.scenario == "RMa")
917 {
918 os << "\n (ISD: 7.0 km, BS: 45 m, UE: 1.5 m, UE-BS min: 44.6 m)";
919 }
920 else
921 {
922 os << "\n (unknown configuration)";
923 }
924 if (p.baseStationFile.empty() and p.useSiteFile)
925 {
926 MSG("Number of outer rings") << p.numOuterRings;
927 }
928 MSG("Number of UEs per sector") << p.ueNumPergNb;
929 MSG("Antenna downtilt angle (deg)") << p.downtiltAngle;
930
931 MSG("");
932 MSG("Network loading") << p.trafficScenario;
933 switch (p.trafficScenario)
934 {
935 case 0:
936 MSG(" Max loading (80 Mbps/20 MHz)");
937 MSG(" Number of packets") << "infinite";
938 MSG(" Packet size");
939 switch (p.bandwidthMHz)
940 {
941 case 20:
942 os << "1000 bytes";
943 break;
944 case 10:
945 os << "500 bytes";
946 break;
947 case 5:
948 os << "250 bytes";
949 break;
950 default:
951 os << "1000 bytes";
952 }
953 // 1 s / (10000 / nUes)
954 MSG(" Inter-packet interval (per UE)") << p.ueNumPergNb / 10.0 << " ms";
955 break;
956
957 case 1:
958 MSG(" Latency");
959 MSG(" Number of packets") << 1;
960 MSG(" Packet size") << "12 bytes";
961 MSG(" Inter-packet interval (per UE)") << "1 s";
962 break;
963
964 case 2:
965 MSG(" Moderate loading");
966 MSG(" Number of packets") << "infinite";
967 MSG(" Packet size");
968 switch (p.bandwidthMHz)
969 {
970 case 20:
971 os << "125 bytes";
972 break;
973 case 10:
974 os << "63 bytes";
975 break;
976 case 5:
977 os << "32 bytes";
978 break;
979 default:
980 os << "125 bytes";
981 }
982 // 1 s / (1000 / nUes)
983 MSG(" Inter-packet interval (per UE)") << 1 / (1000 / p.ueNumPergNb) << " s";
984
985 break;
986
987 case 3:
988 MSG(" Moderate-high loading");
989 MSG(" Number of packets") << "infinite";
990 MSG(" Packet size");
991 switch (p.bandwidthMHz)
992 {
993 case 20:
994 os << "250 bytes";
995 break;
996 case 10:
997 os << "125 bytes";
998 break;
999 case 5:
1000 os << "75 bytes";
1001 break;
1002 default:
1003 os << "250 bytes";
1004 }
1005 // 1 s / (10000 / nUes)
1006 MSG(" Inter-packet interval (per UE)") << 1 / (10000.0 / p.ueNumPergNb) << " s";
1007
1008 break;
1009 default:
1010 os << "\n (Unknown configuration)";
1011 }
1012
1013 MSG("Application start window")
1014 << p.udpAppStartTime.As(Time::MS) << " + " << appStartWindow.As(Time::MS);
1015 MSG("Application on duration") << p.appGenerationTime.As(Time::MS);
1016 MSG("Traffic direction") << p.direction;
1017
1018 MSG("");
1019 MSG("Output file name") << p.simTag;
1020 MSG("Output directory") << p.outputDir;
1021 MSG("Logging") << (p.logging ? "ON" : "off");
1022 MSG("Trace file generation") << (p.traces ? "ON" : "off");
1023 MSG("");
1024 MSG("Radio environment map") << (p.dlRem ? "DL" : (p.ulRem ? "UL" : "off"));
1025 if (p.dlRem || p.ulRem)
1026 {
1027 MSG(" Sector to sample");
1028 if (p.remSector == 0)
1029 {
1030 os << "all";
1031 }
1032 else
1033 {
1034 os << p.remSector;
1035 }
1036 MSG(" X range") << p.xMinRem << " - " << p.xMaxRem << ", in " << p.xResRem << " m steps";
1037 MSG(" Y range") << p.yMinRem << " - " << p.yMaxRem << ", in " << p.yResRem << " m steps";
1038 MSG(" Altitude (Z)") << p.zRem << " m";
1039 }
1040
1041 os << std::endl;
1042 return os;
1043}
1044
1045} // namespace ns3
static void SetLenaV2SimulatorParameters(const double sector0AngleRad, const std::string &scenario, const std::string &confType, const std::string &radioNetwork, std::string errorModel, const std::string &operationMode, const std::string &direction, uint16_t numerology, const std::string &pattern, const NodeContainer &gnbSector1Container, const NodeContainer &gnbSector2Container, const NodeContainer &gnbSector3Container, const NodeContainer &ueSector1Container, const NodeContainer &ueSector2Container, const NodeContainer &ueSector3Container, const Ptr< NrPointToPointEpcHelper > &baseEpcHelper, Ptr< NrHelper > &nrHelper, NetDeviceContainer &gnbSector1NetDev, NetDeviceContainer &gnbSector2NetDev, NetDeviceContainer &gnbSector3NetDev, NetDeviceContainer &ueSector1NetDev, NetDeviceContainer &ueSector2NetDev, NetDeviceContainer &ueSector3NetDev, bool enableFading, bool enableUlPc, std::string powerAllocation, SinrOutputStats *sinrStats, PowerOutputStats *ueTxPowerStats, PowerOutputStats *gnbRxPowerStats, SlotOutputStats *slotStats, RbOutputStats *rbStats, const std::string &scheduler, uint32_t bandwidthMHz, double startingFreq, uint32_t freqScenario, double gnbTxPower, double ueTxPower, double downtiltAngle, const uint32_t gnbNumRows, const uint32_t gnbNumColumns, const uint32_t ueNumRows, const uint32_t ueNumColumns, bool gnbEnable3gppElement, bool ueEnable3gppElement, const double gnbHSpacing, const double gnbVSpacing, const double ueHSpacing, const double ueVSpacing, const double gnbNoiseFigure, const double ueNoiseFigure, bool enableRealBF, bool enableShadowing, double o2iThreshold, double o2iLowLossThreshold, bool linkO2iConditionToAntennaHeight, bool crossPolarizedGnb, bool crossPolarizedUe, double polSlantAngleGnb1, double polSlantAngleGnb2, double polSlantAngleUe1, double polSlantAngleUe2, std::string bfMethod, uint16_t beamConfSector, double beamConfElevation, double isd, bool ueBearingAngle)
@ NGBR_VIDEO_TCP_DEFAULT
Non-GBR TCP-based Video (Buffered Streaming, e.g., www, e-mail...)