5G-LENA nr-v4.0
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
cttc-fh-compression.cc
Go to the documentation of this file.
1// Copyright (c) 2020 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4
33/*
34 * Include part. Often, you will have to include the headers for an entire module;
35 * do that by including the name of the module you need with the suffix "-module.h".
36 */
37
38#include "ns3/antenna-module.h"
39#include "ns3/applications-module.h"
40#include "ns3/config-store-module.h"
41#include "ns3/config-store.h"
42#include "ns3/core-module.h"
43#include "ns3/flow-monitor-module.h"
44#include "ns3/internet-apps-module.h"
45#include "ns3/internet-module.h"
46#include "ns3/lte-module.h"
47#include "ns3/mobility-module.h"
48#include "ns3/nr-module.h"
49#include "ns3/point-to-point-module.h"
50#include "ns3/rng-seed-manager.h"
51#include "ns3/three-gpp-ftp-m1-helper.h"
52
53#include <algorithm>
54#include <iostream>
55/*
56 * To be able to use LOG_* functions.
57 */
58#include "ns3/log.h"
59
60/*
61 * Use, always, the namespace ns3. All the NR classes are inside such namespace.
62 */
63using namespace ns3;
64
65/*
66 * With this line, we will be able to see the logs of the file by enabling the
67 * component "FhCompression", in this way:
68 *
69 * $ export NS_LOG="FhCompression=level_info|prefix_func|prefix_time"
70 */
71NS_LOG_COMPONENT_DEFINE("FhCompression");
72
73class RadioNetworkParametersHelper
74{
75 public:
80 void SetNetworkToLte(const std::string scenario,
81 const std::string operationMode,
82 uint16_t numCcs);
83
90 void SetNetworkToNr(const std::string scenario,
91 const std::string operationMode,
92 uint16_t numerology,
93 uint16_t numCcs);
94
99 double GetTxPower() const;
100
105 double GetBandwidth() const;
106
111 double GetCentralFrequency() const;
112
117 uint16_t GetNumerology() const;
118
123 std::vector<int16_t> GetMcsVectorFromInput();
124
125 private:
126 double m_txPower{-1.0};
127 double m_bandwidth{0.0};
128 double m_centralFrequency{-1.0};
129 uint16_t m_numerology{0};
130};
131
132std::vector<int16_t>
133GetMcsVectorFromInput(const std::string& pattern)
134{
135 static std::unordered_map<std::string, int16_t> lookupTable = {
136 {"1", 1}, {"2", 2}, {"3", 3}, {"4", 4}, {"5", 5}, {"6", 6}, {"7", 7},
137 {"8", 8}, {"9", 9}, {"10", 10}, {"11", 11}, {"12", 12}, {"13", 13}, {"14", 14},
138 {"15", 15}, {"16", 16}, {"17", 17}, {"18", 18}, {"19", 19}, {"20", 20}, {"21", 21},
139 {"22", 22}, {"23", 23}, {"24", 24}, {"25", 25}, {"26", 26}, {"27", 27}, {"28", 28},
140 };
141
142 std::vector<int16_t> vector;
143 std::stringstream ss(pattern);
144 std::string token;
145 std::vector<std::string> extracted;
146
147 while (std::getline(ss, token, '|'))
148 {
149 extracted.push_back(token);
150 }
151
152 for (const auto& v : extracted)
153 {
154 if (lookupTable.find(v) == lookupTable.end())
155 {
156 NS_FATAL_ERROR("Not valid MCS input");
157 }
158 vector.push_back(lookupTable[v]);
159 }
160
161 return vector;
162}
163
164void
165RadioNetworkParametersHelper::SetNetworkToLte(const std::string scenario,
166 const std::string operationMode,
167 uint16_t numCcs)
168{
169 NS_ABORT_MSG_IF(scenario != "UMa" && scenario != "UMi", "Unsupported scenario");
170
171 m_numerology = 0;
172 m_centralFrequency = 2e9;
173 m_bandwidth = 20e6 * numCcs; // 100 RBs per CC (freqReuse)
174 if (operationMode == "FDD")
175 {
176 m_bandwidth += m_bandwidth;
177 }
178 if (scenario == "UMa")
179 {
180 m_txPower = 43;
181 }
182 else
183 {
184 m_txPower = 30;
185 }
186}
187
188void
189RadioNetworkParametersHelper::SetNetworkToNr(const std::string scenario,
190 const std::string operationMode,
191 uint16_t numerology,
192 uint16_t numCcs)
193{
194 NS_ABORT_MSG_IF(scenario != "UMa" && scenario != "UMi", "Unsupported scenario");
195
196 m_numerology = numerology;
197 m_centralFrequency = 2e9;
198 m_bandwidth = 100e6 * numCcs; // 20e6 = 100 RBs per CC (freqReuse)
199 if (operationMode == "FDD")
200 {
201 m_bandwidth += m_bandwidth;
202 }
203 if (scenario == "UMa")
204 {
205 m_txPower = 43;
206 }
207 else
208 {
209 m_txPower = 30;
210 }
211}
212
213double
214RadioNetworkParametersHelper::GetTxPower() const
215{
216 return m_txPower;
217}
218
219double
220RadioNetworkParametersHelper::GetBandwidth() const
221{
222 return m_bandwidth;
223}
224
225double
226RadioNetworkParametersHelper::GetCentralFrequency() const
227{
228 return m_centralFrequency;
229}
230
231uint16_t
232RadioNetworkParametersHelper::GetNumerology() const
233{
234 return m_numerology;
235}
236
237void
239 std::string scenario,
240 std::string radioNetwork,
241 std::string errorModel,
242 std::string operationMode,
243 std::string direction,
244 uint16_t numerology,
245 std::string pattern1,
246 std::string pattern2,
247 bool uniformPattern,
248 NodeContainer gnbSector1Container,
249 NodeContainer gnbSector2Container,
250 NodeContainer gnbSector3Container,
251 NodeContainer ueSector1Container,
252 NodeContainer ueSector2Container,
253 NodeContainer ueSector3Container,
254 Ptr<NrPointToPointEpcHelper>& baseNrEpcHelper,
255 Ptr<NrHelper>& nrHelper,
256 NetDeviceContainer& gnbSector1NetDev,
257 NetDeviceContainer& gnbSector2NetDev,
258 NetDeviceContainer& gnbSector3NetDev,
259 NetDeviceContainer& ueSector1NetDev,
260 NetDeviceContainer& ueSector2NetDev,
261 NetDeviceContainer& ueSector3NetDev,
262 int16_t maxMcsDl1,
263 int16_t maxMcsDl2,
264 std::vector<int16_t>& maxMcsVector,
265 bool uniformMcs,
266 bool uniformLambda)
267{
268 /*
269 * Create the radio network related parameters
270 */
271 RadioNetworkParametersHelper ranHelper;
272 if (radioNetwork == "LTE")
273 {
274 ranHelper.SetNetworkToLte(scenario, operationMode, 1);
275 if (errorModel.empty())
276 {
277 errorModel = "ns3::LenaErrorModel";
278 }
279 else if (errorModel != "ns3::NrLteMiErrorModel" && errorModel != "ns3::LenaErrorModel")
280 {
281 NS_ABORT_MSG("The selected error model is not recommended for LTE");
282 }
283 }
284 else if (radioNetwork == "NR")
285 {
286 ranHelper.SetNetworkToNr(scenario, operationMode, numerology, 1);
287 if (errorModel.empty())
288 {
289 errorModel = "ns3::NrEesmIrT2";
290 }
291 else if (errorModel == "ns3::NrLteMiErrorModel")
292 {
293 NS_ABORT_MSG("The selected error model is not recommended for NR");
294 }
295 }
296 else
297 {
298 NS_ABORT_MSG("Unrecognized radio network technology");
299 }
300
301 /*
302 * Setup the NR module. We create the various helpers needed for the
303 * NR simulation:
304 * - IdealBeamformingHelper, which takes care of the beamforming part
305 * - NrHelper, which takes care of creating and connecting the various
306 * part of the NR stack
307 * - NrChannelHelper, which takes care of the spectrum channel
308 */
309
310 Ptr<IdealBeamformingHelper> idealBeamformingHelper = CreateObject<IdealBeamformingHelper>();
311 nrHelper = CreateObject<NrHelper>();
312
313 // Put the pointers inside nrHelper
314 nrHelper->SetBeamformingHelper(idealBeamformingHelper);
315
316 Ptr<NrPointToPointEpcHelper> nrEpcHelper =
317 DynamicCast<NrPointToPointEpcHelper>(baseNrEpcHelper);
318 nrHelper->SetEpcHelper(nrEpcHelper);
319 /*
320 * Spectrum division. We create one operational band containing three
321 * component carriers, and each CC containing a single bandwidth part
322 * centered at the frequency specified by the input parameters.
323 * Each spectrum part length is, as well, specified by the input parameters.
324 * The operational band will use StreetCanyon channel or UrbanMacro modeling.
325 */
330 CcBwpCreator ccBwpCreator;
331 // Create the configuration for the CcBwpHelper. SimpleOperationBandConf creates
332 // a single BWP per CC. Get the spectrum values from the RadioNetworkParametersHelper
333 double centralFrequencyBand = ranHelper.GetCentralFrequency();
334 double bandwidthBand = ranHelper.GetBandwidth();
335 const uint8_t numCcPerBand = 1; // In this example, each cell will have one CC with one BWP
336
337 NS_ABORT_MSG_UNLESS(scenario == "UMa" || scenario == "UMi", "Unsupported scenario");
338
339 // Error Model: UE and GNB with same spectrum error model.
340 nrHelper->SetUlErrorModel(errorModel);
341 nrHelper->SetDlErrorModel(errorModel);
342
343 // Both DL and UL AMC will have the same model behind.
344 nrHelper->SetGnbDlAmcAttribute(
345 "AmcModel",
346 EnumValue(NrAmc::ErrorModel)); // NrAmc::ShannonModel or NrAmc::ErrorModel
347 nrHelper->SetGnbUlAmcAttribute(
348 "AmcModel",
349 EnumValue(NrAmc::ErrorModel)); // NrAmc::ShannonModel or NrAmc::ErrorModel
350
351 /*
352 * Create the necessary operation bands. In this example, each sector operates
353 * in a separate band. Each band contains a single component carrier (CC),
354 * which is made of one BWP in TDD operation mode or two BWPs in FDD mode.
355 * Note that BWPs have the same bandwidth. Therefore, CCs and bands in FDD are
356 * twice larger than in TDD.
357 *
358 * The configured spectrum division for TDD operation is:
359 * |---Band1---|---Band2---|---Band3---|
360 * |----CC1----|----CC2----|----CC3----|
361 * |----BWP1---|----BWP2---|----BWP3---|
362 *
363 * And the configured spectrum division for FDD operation is:
364 * |---------Band1---------|---------Band2---------|---------Band3---------|
365 * |----------CC1----------|----------CC2----------|----------CC3----------|
366 * |----BWP1---|----BWP2---|----BWP3---|----BWP4---|----BWP5---|----BWP6---|
367 */
368 double centralFrequencyBand1 = centralFrequencyBand - bandwidthBand;
369 double centralFrequencyBand2 = centralFrequencyBand;
370 double centralFrequencyBand3 = centralFrequencyBand + bandwidthBand;
371 double bandwidthBand1 = bandwidthBand;
372 double bandwidthBand2 = bandwidthBand;
373 double bandwidthBand3 = bandwidthBand;
374
375 uint8_t numBwpPerCc = 1;
376 if (operationMode == "FDD")
377 {
378 numBwpPerCc = 2; // FDD will have 2 BWPs per CC
379 Config::SetDefault("ns3::NrUeNetDevice::PrimaryUlIndex", UintegerValue(1));
380 }
381
382 CcBwpCreator::SimpleOperationBandConf bandConf1(centralFrequencyBand1,
383 bandwidthBand1,
384 numCcPerBand);
385 bandConf1.m_numBwp = numBwpPerCc; // FDD will have 2 BWPs per CC
386 CcBwpCreator::SimpleOperationBandConf bandConf2(centralFrequencyBand2,
387 bandwidthBand2,
388 numCcPerBand);
389 bandConf2.m_numBwp = numBwpPerCc; // FDD will have 2 BWPs per CC
390 CcBwpCreator::SimpleOperationBandConf bandConf3(centralFrequencyBand3,
391 bandwidthBand3,
392 numCcPerBand);
393 bandConf3.m_numBwp = numBwpPerCc; // FDD will have 2 BWPs per CC
394
395 // By using the configuration created, it is time to make the operation bands
396 OperationBandInfo band1 = ccBwpCreator.CreateOperationBandContiguousCc(bandConf1);
397 OperationBandInfo band2 = ccBwpCreator.CreateOperationBandContiguousCc(bandConf2);
398 OperationBandInfo band3 = ccBwpCreator.CreateOperationBandContiguousCc(bandConf3);
399 Ptr<NrChannelHelper> channelHelper = CreateObject<NrChannelHelper>();
400 channelHelper->ConfigureFactories(scenario);
401 // Set the attributes for the channel model
402 Config::SetDefault("ns3::ThreeGppChannelModel::UpdatePeriod", TimeValue(MilliSeconds(0)));
403 channelHelper->SetChannelConditionModelAttribute("UpdatePeriod", TimeValue(MilliSeconds(0)));
404 channelHelper->SetPathlossAttribute("ShadowingEnabled", BooleanValue(false));
409 channelHelper->AssignChannelsToBands({band1, band2, band3});
410 allBwps = CcBwpCreator::GetAllBwps({band1, band2, band3});
411 bwps1 = CcBwpCreator::GetAllBwps({band1});
412 bwps2 = CcBwpCreator::GetAllBwps({band2});
413 bwps3 = CcBwpCreator::GetAllBwps({band3});
414
415 /*
416 * Start to account for the bandwidth used by the example, as well as
417 * the total power that has to be divided among the BWPs. Since there is only
418 * one band and one BWP occupying the entire band, there is no need to divide
419 * power among BWPs.
420 */
421 double totalTxPower = ranHelper.GetTxPower(); // Convert to mW
422 double x = pow(10, totalTxPower / 10);
423
424 /*
425 * allBwps contains all the spectrum configuration needed for the nrHelper.
426 *
427 * Now, we can setup the attributes. We can have three kind of attributes:
428 * (i) parameters that are valid for all the bandwidth parts and applies to
429 * all nodes, (ii) parameters that are valid for all the bandwidth parts
430 * and applies to some node only, and (iii) parameters that are different for
431 * every bandwidth parts. The approach is:
432 *
433 * - for (i): Configure the attribute through the helper, and then install;
434 * - for (ii): Configure the attribute through the helper, and then install
435 * for the first set of nodes. Then, change the attribute through the helper,
436 * and install again;
437 * - for (iii): Install, and then configure the attributes by retrieving
438 * the pointer needed, and calling "SetAttribute" on top of such pointer.
439 *
440 */
441
442 Packet::EnableChecking();
443 Packet::EnablePrinting();
444
445 /*
446 * Case (i): Attributes valid for all the nodes
447 */
448 // Beamforming method
449 if (radioNetwork == "LTE")
450 {
451 idealBeamformingHelper->SetAttribute(
452 "BeamformingMethod",
454 }
455 else
456 {
457 idealBeamformingHelper->SetAttribute("BeamformingMethod",
458 TypeIdValue(DirectPathBeamforming::GetTypeId()));
459 }
460
461 //
462
463 // Scheduler type
464 if (radioNetwork == "LTE")
465 {
466 nrHelper->SetSchedulerTypeId(TypeId::LookupByName("ns3::NrMacSchedulerOfdmaPF"));
467 nrHelper->SetSchedulerAttribute("DlCtrlSymbols", UintegerValue(1));
468 }
469 // nrHelper->SetSchedulerAttribute ("MaxDlMcs", UintegerValue (maxMcsDl1));
470 // nrHelper->SetSchedulerAttribute ("MaxDlMcs", UintegerValue (10)); // 27, 19, 10, 4 for
471 // mcsT2,
472 // 28, 16, 9 for mcsT1
473
474 // Core latency
475 nrEpcHelper->SetAttribute("S1uLinkDelay", TimeValue(MilliSeconds(0)));
476
477 // Antennas for all the UEs
478 nrHelper->SetUeAntennaAttribute("NumRows", UintegerValue(1));
479 nrHelper->SetUeAntennaAttribute("NumColumns", UintegerValue(1));
480 nrHelper->SetUeAntennaAttribute("AntennaElement",
481 PointerValue(CreateObject<IsotropicAntennaModel>()));
482
483 // Antennas for all the gNbs
484 nrHelper->SetGnbAntennaAttribute("NumRows", UintegerValue(8));
485 nrHelper->SetGnbAntennaAttribute("NumColumns", UintegerValue(8));
486 nrHelper->SetGnbAntennaAttribute("AntennaElement",
487 PointerValue(CreateObject<ThreeGppAntennaModel>()));
488
489 // UE transmit power
490 nrHelper->SetUePhyAttribute("TxPower", DoubleValue(20.0));
491
492 // Set LTE RBG size
493 if (radioNetwork == "LTE")
494 {
495 nrHelper->SetGnbMacAttribute("NumRbPerRbg", UintegerValue(4));
496 }
497
498 // We assume a common traffic pattern for all UEs
499 uint32_t bwpIdForLowLat = 0;
500 if (operationMode == "FDD" && direction == "UL")
501 {
502 bwpIdForLowLat = 1;
503 }
504
505 // gNb routing between Bearer and bandwidth part
506 nrHelper->SetGnbBwpManagerAlgorithmAttribute("NGBR_VIDEO_TCP_DEFAULT",
507 UintegerValue(bwpIdForLowLat));
508
509 // Ue routing between Bearer and bandwidth part
510 nrHelper->SetUeBwpManagerAlgorithmAttribute("NGBR_VIDEO_TCP_DEFAULT",
511 UintegerValue(bwpIdForLowLat));
512
513 /*
514 * We miss many other parameters. By default, not configuring them is equivalent
515 * to use the default values. Please, have a look at the documentation to see
516 * what are the default values for all the attributes you are not seeing here.
517 */
518
519 /*
520 * Case (ii): Attributes valid for a subset of the nodes
521 */
522
523 // NOT PRESENT IN THIS SIMPLE EXAMPLE
524
525 /*
526 * We have configured the attributes we needed. Now, install and get the pointers
527 * to the NetDevices, which contains all the NR stack:
528 */
529
530 // NetDeviceContainer gnbNetDev = nrHelper->InstallGnbDevice (gridScenario.GetBaseStations (),
531 // allBwps);
532 gnbSector1NetDev = nrHelper->InstallGnbDevice(gnbSector1Container, bwps1);
533 gnbSector2NetDev = nrHelper->InstallGnbDevice(gnbSector2Container, bwps2);
534 gnbSector3NetDev = nrHelper->InstallGnbDevice(gnbSector3Container, bwps3);
535 ueSector1NetDev = nrHelper->InstallUeDevice(ueSector1Container, bwps1);
536 ueSector2NetDev = nrHelper->InstallUeDevice(ueSector2Container, bwps2);
537 ueSector3NetDev = nrHelper->InstallUeDevice(ueSector3Container, bwps3);
538
539 int64_t randomStream = 1;
540 randomStream += nrHelper->AssignStreams(gnbSector1NetDev, randomStream);
541 randomStream += nrHelper->AssignStreams(gnbSector2NetDev, randomStream);
542 randomStream += nrHelper->AssignStreams(gnbSector3NetDev, randomStream);
543 randomStream += nrHelper->AssignStreams(ueSector1NetDev, randomStream);
544 randomStream += nrHelper->AssignStreams(ueSector2NetDev, randomStream);
545 randomStream += nrHelper->AssignStreams(ueSector3NetDev, randomStream);
546
547 /*
548 * Case (iii): Go node for node and change the attributes we have to setup
549 * per-node.
550 */
551 std::vector<int16_t> maxMcsPerCell(gridScenario.GetNumCells());
552 if (uniformMcs) // if uniformMcs -> same maximum MCS for all cells, input parameter maxMcsDl1
553 {
554 for (uint32_t i = 0; i < gridScenario.GetNumCells(); ++i)
555 {
556 maxMcsPerCell[i] = maxMcsDl1;
557 std::cout << "Cell: " << i << " mcs (same mcs): " << maxMcsPerCell[i] << std::endl;
558 }
559 }
560 else // Different cells may use different maxMcs (in case of different TDD patterns)
561 {
562 // algorithms for non-uniform max MCS
563 if (uniformPattern &&
564 uniformLambda) // if uniformPattern and uniformLambda --> no difference in max MCS
565 {
566 for (uint32_t i = 0; i < gridScenario.GetNumCells(); ++i)
567 {
568 maxMcsPerCell[i] = maxMcsDl1;
569 std::cout << "Cell: " << i << " mcs (diff mcs): " << maxMcsPerCell[i] << std::endl;
570 }
571 }
572 else if (uniformLambda &&
573 !uniformPattern) // case of using different TDD patterns (per cell)
574 {
575 for (uint32_t i = 0; i < gridScenario.GetNumCells(); ++i)
576 {
577 if (i % 2 == 1) // pattern1
578 {
579 maxMcsPerCell[i] = maxMcsDl1;
580 }
581 else // pattern2
582 {
583 maxMcsPerCell[i] = maxMcsDl2;
584 }
585 std::cout << "Cell: " << i << " mcs (diff tdd): " << maxMcsPerCell[i] << std::endl;
586 }
587 }
588 else if (uniformPattern && !uniformLambda) // case of using different lambda (per cell)
589 {
590 for (uint32_t i = 0; i < gridScenario.GetNumCells(); ++i)
591 {
592 maxMcsPerCell[i] = maxMcsVector[i];
593 std::cout << "Cell: " << i << " mcs (diff lambda): " << maxMcsPerCell[i]
594 << std::endl;
595 }
596 }
597 }
598
599 // Sectors (cells) of a site are pointing at different directions
600 double orientationRads = gridScenario.GetAntennaOrientationRadians(0);
601 uint32_t globalCellId = 0;
602 for (uint32_t numCell = 0; numCell < gnbSector1NetDev.GetN(); ++numCell)
603 {
604 Ptr<NetDevice> gnb = gnbSector1NetDev.Get(numCell);
605 uint32_t numBwps = nrHelper->GetNumberBwp(gnb);
606 if (numBwps == 1) // TDD
607 {
608 // Change the antenna orientation
609 Ptr<NrGnbPhy> phy = nrHelper->GetGnbPhy(gnb, 0);
610 Ptr<UniformPlanarArray> antenna =
611 DynamicCast<UniformPlanarArray>(phy->GetSpectrumPhy()->GetAntenna());
612 antenna->SetAttribute("BearingAngle", DoubleValue(orientationRads));
613
614 // Set numerology
615 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Numerology",
616 UintegerValue(ranHelper.GetNumerology()));
617
618 // Set TX power
619 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("TxPower", DoubleValue(10 * log10(x)));
620
621 // Set TDD pattern
622 if (uniformPattern || (globalCellId % 2 == 1))
623 {
624 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Pattern", StringValue(pattern1));
625 }
626 else
627 {
628 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Pattern", StringValue(pattern2));
629 }
630
631 // Set max MCS
632 nrHelper->GetScheduler(gnb, 0)->SetAttribute("MaxDlMcs",
633 IntegerValue(maxMcsPerCell[globalCellId]));
634 // nrHelper->GetGnbMac (gnb, 0)->SetAttribute ("MaxDlMcs", UintegerValue (10)); // 27,
635 // 19, 10, 4 for mcsT2,
636 // 28, 16, 9 for mcsT1
637 }
638
639 else if (numBwps == 2) // FDD
640 {
641 // Change the antenna orientation
642 Ptr<NrGnbPhy> phy0 = nrHelper->GetGnbPhy(gnb, 0);
643 Ptr<UniformPlanarArray> antenna0 =
644 DynamicCast<UniformPlanarArray>(phy0->GetSpectrumPhy()->GetAntenna());
645 antenna0->SetAttribute("BearingAngle", DoubleValue(orientationRads));
646 Ptr<NrGnbPhy> phy1 = nrHelper->GetGnbPhy(gnb, 1);
647 Ptr<UniformPlanarArray> antenna1 =
648 DynamicCast<UniformPlanarArray>(phy1->GetSpectrumPhy()->GetAntenna());
649 antenna1->SetAttribute("BearingAngle", DoubleValue(orientationRads));
650
651 // Set numerology
652 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Numerology",
653 UintegerValue(ranHelper.GetNumerology()));
654 nrHelper->GetGnbPhy(gnb, 1)->SetAttribute("Numerology",
655 UintegerValue(ranHelper.GetNumerology()));
656
657 // Set TX power
658 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("TxPower", DoubleValue(10 * log10(x)));
659 nrHelper->GetGnbPhy(gnb, 1)->SetAttribute("TxPower", DoubleValue(-30.0));
660 // Set TDD pattern
661 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute(
662 "Pattern",
663 StringValue("DL|DL|DL|DL|DL|DL|DL|DL|DL|DL|"));
664 nrHelper->GetGnbPhy(gnb, 1)->SetAttribute(
665 "Pattern",
666 StringValue("UL|UL|UL|UL|UL|UL|UL|UL|UL|UL|"));
667
668 // Link the two FDD BWP
669 nrHelper->GetBwpManagerGnb(gnb)->SetOutputLink(1, 0);
670 }
671
672 else
673 {
674 NS_ABORT_MSG("Incorrect number of BWPs per CC");
675 }
676 globalCellId++;
677 }
678
679 orientationRads = gridScenario.GetAntennaOrientationRadians(1);
680 for (uint32_t numCell = 0; numCell < gnbSector2NetDev.GetN(); ++numCell)
681 {
682 Ptr<NetDevice> gnb = gnbSector2NetDev.Get(numCell);
683 uint32_t numBwps = nrHelper->GetNumberBwp(gnb);
684 if (numBwps == 1) // TDD
685 {
686 // Change the antenna orientation
687 Ptr<NrGnbPhy> phy = nrHelper->GetGnbPhy(gnb, 0);
688 Ptr<UniformPlanarArray> antenna =
689 DynamicCast<UniformPlanarArray>(phy->GetSpectrumPhy()->GetAntenna());
690 antenna->SetAttribute("BearingAngle", DoubleValue(orientationRads));
691
692 // Set numerology
693 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Numerology",
694 UintegerValue(ranHelper.GetNumerology()));
695
696 // Set TX power
697 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("TxPower", DoubleValue(10 * log10(x)));
698
699 // Set TDD pattern
700 if (uniformPattern || (globalCellId % 2 == 1))
701 {
702 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Pattern", StringValue(pattern1));
703 }
704 else
705 {
706 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Pattern", StringValue(pattern2));
707 }
708
709 // Set max MCS
710 nrHelper->GetScheduler(gnb, 0)->SetAttribute("MaxDlMcs",
711 IntegerValue(maxMcsPerCell[globalCellId]));
712 // nrHelper->GetGnbMac (gnb, 0)->SetAttribute ("MaxDlMcs", UintegerValue (10)); // 27,
713 // 19, 10, 4 for mcsT2,
714 // 28, 16, 9 for mcsT1
715 }
716
717 else if (numBwps == 2) // FDD
718 {
719 // Change the antenna orientation
720 Ptr<NrGnbPhy> phy0 = nrHelper->GetGnbPhy(gnb, 0);
721 Ptr<UniformPlanarArray> antenna0 =
722 DynamicCast<UniformPlanarArray>(phy0->GetSpectrumPhy()->GetAntenna());
723 antenna0->SetAttribute("BearingAngle", DoubleValue(orientationRads));
724 Ptr<NrGnbPhy> phy1 = nrHelper->GetGnbPhy(gnb, 1);
725 Ptr<UniformPlanarArray> antenna1 =
726 DynamicCast<UniformPlanarArray>(phy1->GetSpectrumPhy()->GetAntenna());
727 antenna1->SetAttribute("BearingAngle", DoubleValue(orientationRads));
728
729 // Set numerology
730 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Numerology",
731 UintegerValue(ranHelper.GetNumerology()));
732 nrHelper->GetGnbPhy(gnb, 1)->SetAttribute("Numerology",
733 UintegerValue(ranHelper.GetNumerology()));
734
735 // Set TX power
736 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("TxPower", DoubleValue(10 * log10(x)));
737 nrHelper->GetGnbPhy(gnb, 1)->SetAttribute("TxPower", DoubleValue(-30.0));
738
739 // Set TDD pattern
740 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute(
741 "Pattern",
742 StringValue("DL|DL|DL|DL|DL|DL|DL|DL|DL|DL|"));
743 nrHelper->GetGnbPhy(gnb, 1)->SetAttribute(
744 "Pattern",
745 StringValue("UL|UL|UL|UL|UL|UL|UL|UL|UL|UL|"));
746
747 // Link the two FDD BWP
748 nrHelper->GetBwpManagerGnb(gnb)->SetOutputLink(1, 0);
749 }
750
751 else
752 {
753 NS_ABORT_MSG("Incorrect number of BWPs per CC");
754 }
755 globalCellId++;
756 }
757
758 orientationRads = gridScenario.GetAntennaOrientationRadians(2);
759 for (uint32_t numCell = 0; numCell < gnbSector3NetDev.GetN(); ++numCell)
760 {
761 Ptr<NetDevice> gnb = gnbSector3NetDev.Get(numCell);
762 uint32_t numBwps = nrHelper->GetNumberBwp(gnb);
763 if (numBwps == 1) // TDD
764 {
765 // Change the antenna orientation
766 Ptr<NrGnbPhy> phy = nrHelper->GetGnbPhy(gnb, 0);
767 Ptr<UniformPlanarArray> antenna =
768 DynamicCast<UniformPlanarArray>(phy->GetSpectrumPhy()->GetAntenna());
769 antenna->SetAttribute("BearingAngle", DoubleValue(orientationRads));
770
771 // Set numerology
772 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Numerology",
773 UintegerValue(ranHelper.GetNumerology()));
774
775 // Set TX power
776 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("TxPower", DoubleValue(10 * log10(x)));
777
778 // Set TDD pattern
779 if (uniformPattern || (globalCellId % 2 == 1))
780 {
781 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Pattern", StringValue(pattern1));
782 }
783 else
784 {
785 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Pattern", StringValue(pattern2));
786 }
787
788 // Set max MCS
789 nrHelper->GetScheduler(gnb, 0)->SetAttribute("MaxDlMcs",
790 IntegerValue(maxMcsPerCell[globalCellId]));
791 // nrHelper->GetGnbMac (gnb, 0)->SetAttribute ("MaxDlMcs", UintegerValue (10)); // 27,
792 // 19, 10, 4 for mcsT2,
793 // 28, 16, 9 for mcsT1
794 }
795
796 else if (numBwps == 2) // FDD
797 {
798 // Change the antenna orientation
799 Ptr<NrGnbPhy> phy0 = nrHelper->GetGnbPhy(gnb, 0);
800 Ptr<UniformPlanarArray> antenna0 =
801 DynamicCast<UniformPlanarArray>(phy0->GetSpectrumPhy()->GetAntenna());
802 antenna0->SetAttribute("BearingAngle", DoubleValue(orientationRads));
803 Ptr<NrGnbPhy> phy1 = nrHelper->GetGnbPhy(gnb, 1);
804 Ptr<UniformPlanarArray> antenna1 =
805 DynamicCast<UniformPlanarArray>(phy1->GetSpectrumPhy()->GetAntenna());
806 antenna1->SetAttribute("BearingAngle", DoubleValue(orientationRads));
807
808 // Set numerology
809 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("Numerology",
810 UintegerValue(ranHelper.GetNumerology()));
811 nrHelper->GetGnbPhy(gnb, 1)->SetAttribute("Numerology",
812 UintegerValue(ranHelper.GetNumerology()));
813
814 // Set TX power
815 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute("TxPower", DoubleValue(10 * log10(x)));
816 nrHelper->GetGnbPhy(gnb, 1)->SetAttribute("TxPower", DoubleValue(-30.0));
817
818 // Set TDD pattern
819 nrHelper->GetGnbPhy(gnb, 0)->SetAttribute(
820 "Pattern",
821 StringValue("DL|DL|DL|DL|DL|DL|DL|DL|DL|DL|"));
822 nrHelper->GetGnbPhy(gnb, 1)->SetAttribute(
823 "Pattern",
824 StringValue("UL|UL|UL|UL|UL|UL|UL|UL|UL|UL|"));
825
826 // Link the two FDD BWP
827 nrHelper->GetBwpManagerGnb(gnb)->SetOutputLink(1, 0);
828 }
829
830 else
831 {
832 NS_ABORT_MSG("Incorrect number of BWPs per CC");
833 }
834 globalCellId++;
835 }
836
837 // Set the UE routing:
838
839 if (operationMode == "FDD")
840 {
841 for (uint32_t i = 0; i < ueSector1NetDev.GetN(); i++)
842 {
843 nrHelper->GetBwpManagerUe(ueSector1NetDev.Get(i))->SetOutputLink(0, 1);
844 }
845
846 for (uint32_t i = 0; i < ueSector2NetDev.GetN(); i++)
847 {
848 nrHelper->GetBwpManagerUe(ueSector2NetDev.Get(i))->SetOutputLink(0, 1);
849 }
850
851 for (uint32_t i = 0; i < ueSector3NetDev.GetN(); i++)
852 {
853 nrHelper->GetBwpManagerUe(ueSector3NetDev.Get(i))->SetOutputLink(0, 1);
854 }
855 }
856}
857
858template <typename T>
859Ptr<T>
860CreateLowLatTft(uint16_t start, uint16_t end, std::string dir)
861{
862 Ptr<T> lowLatTft;
863 lowLatTft = Create<T>();
864 typename T::PacketFilter dlpfLowLat;
865 if (dir == "DL")
866 {
867 dlpfLowLat.localPortStart = start;
868 dlpfLowLat.localPortEnd = end;
869 dlpfLowLat.direction = T::DOWNLINK;
870 }
871 else
872 {
873 dlpfLowLat.remotePortStart = start;
874 dlpfLowLat.remotePortEnd = end;
875 dlpfLowLat.direction = T::UPLINK;
876 }
877 lowLatTft->Add(dlpfLowLat);
878 return lowLatTft;
879}
880
881template Ptr<ns3::EpcTft> CreateLowLatTft<ns3::EpcTft>(uint16_t, uint16_t, std::string);
882template Ptr<ns3::NrEpcTft> CreateLowLatTft<ns3::NrEpcTft>(uint16_t, uint16_t, std::string);
883
884int
885main(int argc, char* argv[])
886{
887 /*
888 * Variables that represent the parameters we will accept as input by the
889 * command line. Each of them is initialized with a default value.
890 */
891 // Scenario parameters (that we will use inside this script):
892 uint16_t numOuterRings = 0;
893 uint16_t ueNumPergNb = 2;
894 bool logging = false;
895 bool traces = true;
896 std::string simulator = "";
897 std::string scenario = "UMi";
898 std::string radioNetwork = "NR"; // LTE or NR
899 std::string operationMode = "TDD"; // TDD or FDD
900
901 // Traffic parameters (that we will use inside this script:)
902 uint32_t udpPacketSize = 600; // bytes
903 uint32_t lambda = 2000; // 4000*600*8 = 19.2 Mbps/UE,
904 // 3000*600*8 = 14.4 Mbps/UE,
905 // 2000*600*8 = 9.6 Mbps/UE
906 // 1500*600*8 = 7.2 Mbps/UE
907 // 1000*600*8 = 4.8 Mbps/UE
908
909 bool ftpM1Enabled = true;
910 double ftpLambda = 5;
911 uint32_t ftpFileSize = 512000; // in bytes
912 uint16_t ftpPortSector1 = 2001;
913 uint16_t ftpPortSector2 = 2002;
914 uint16_t ftpPortSector3 = 2003;
915 uint32_t ftpClientAppStartTimeMs = 400;
916 uint32_t ftpServerAppStartTimeMs = 400;
917 // Simulation parameters. Please don't use double to indicate seconds, use
918 // milliseconds and integers to avoid representation errors.
919 uint32_t simTimeMs = 1400;
920 uint32_t udpAppStartTimeMs = 400;
921 std::string direction = "DL";
922
923 // Spectrum parameters. We will take the input from the command line, and then
924 // we will pass them inside the NR module.
925 uint16_t numerologyBwp = 2;
926 // double centralFrequencyBand = 0.0; // RadioNetworkParametersHelper provides this hard-coded
927 // value double bandwidthBand = 0.0; // RadioNetworkParametersHelper provides this hard-coded
928 // values
929 std::string pattern1 =
930 "F|F|F|F|F|F|F|F|F|F|"; // Pattern can be e.g. "DL|S|UL|UL|DL|DL|S|UL|UL|DL|"
931 std::string pattern2 = "F|F|F|F|F|UL|UL|UL|UL|UL|";
932 bool uniformPattern = true;
933 bool uniformMcs = true;
934 bool uniformLambda = true;
935
936 // Where we will store the output files.
937 std::string simTag = "default";
938 std::string outputDir = "./";
939
940 // Error models
941 std::string errorModel = "ns3::NrEesmIrT2";
942
943 // Max DL MCS index
944 int16_t maxMcs1 = 28;
945 int16_t maxMcs2 = 28;
946 // std::vector<uint16_t> maxMcsVector ={4,6,8};
947 std::string maxMcsVectorInput = "1|2|4";
948
949 /*
950 * From here, we instruct the ns3::CommandLine class of all the input parameters
951 * that we may accept as input, as well as their description, and the storage
952 * variable.
953 */
954 CommandLine cmd(__FILE__);
955
956 cmd.AddValue("scenario", "The urban scenario string (UMa or UMi)", scenario);
957 cmd.AddValue("numRings", "The number of rings around the central site", numOuterRings);
958 cmd.AddValue("ueNumPergNb",
959 "The number of UE per cell or gNB in multiple-ue topology",
960 ueNumPergNb);
961 cmd.AddValue("logging", "Enable logging", logging);
962 cmd.AddValue("traces", "Enable output traces", traces);
963 cmd.AddValue("packetSize", "packet size in bytes to be used by UE traffic", udpPacketSize);
964 cmd.AddValue("lambda", "Number of UDP packets generated in one second per UE", lambda);
965 cmd.AddValue("uniformLambda",
966 "1: Use same lambda (packets/s) for all UEs and cells (equal to 'lambda' input), "
967 "0: use different packet arrival rates (lambdas) among cells",
968 uniformLambda);
969 cmd.AddValue("simTimeMs", "Simulation time", simTimeMs);
970 cmd.AddValue("numerologyBwp", "The numerology to be used (NR only)", numerologyBwp);
971 cmd.AddValue("pattern1", "The TDD pattern to use", pattern1);
972 cmd.AddValue("pattern2", "The TDD pattern to use", pattern2);
973 cmd.AddValue("uniformPattern",
974 "1: Use same TDD pattern (pattern1) for all cells, 0: use different TDD patterns "
975 "(pattern1 and pattern2) for cells",
976 uniformPattern);
977 cmd.AddValue("direction", "The flow direction (DL or UL)", direction);
978 // cmd.AddValue ("centralFrequencyBand",
979 // "The system frequency to be used in band 1",
980 // centralFrequencyBand);
981 // cmd.AddValue ("bandwidthBand",
982 // "The system bandwidth to be used in band 1",
983 // bandwidthBand);
984 cmd.AddValue("technology", "The radio access network technology", radioNetwork);
985 cmd.AddValue("operationMode", "The network operation mode can be TDD or FDD", operationMode);
986 cmd.AddValue("simTag",
987 "tag to be appended to output filenames to distinguish simulation campaigns",
988 simTag);
989 cmd.AddValue("outputDir", "directory where to store simulation results", outputDir);
990 cmd.AddValue("ftpM1Enabled",
991 "An indicator whether to enable FTP Model 1 traffic model. To enable configure 1, "
992 "to disable 0.",
993 ftpM1Enabled);
994
995 // Parse the command line
996 cmd.Parse(argc, argv);
997
998 /*
999 * Check if the frequency and numerology are in the allowed range.
1000 * If you need to add other checks, here is the best position to put them.
1001 */
1002 // NS_ABORT_IF (centralFrequencyBand > 100e9);
1003 NS_ABORT_IF(numerologyBwp > 4);
1004 NS_ABORT_MSG_IF(direction != "DL" && direction != "UL", "Flow direction can only be DL or UL");
1005 NS_ABORT_MSG_IF(operationMode != "TDD" && operationMode != "FDD",
1006 "Operation mode can only be TDD or FDD");
1007 NS_ABORT_MSG_IF(radioNetwork != "LTE" && radioNetwork != "NR",
1008 "Unrecognized radio network technology");
1009 /*
1010 * If the logging variable is set to true, enable the log of some components
1011 * through the code. The same effect can be obtained through the use
1012 * of the NS_LOG environment variable:
1013 *
1014 * export NS_LOG="UdpClient=level_info|prefix_time|prefix_func|prefix_node:UdpServer=..."
1015 *
1016 * Usually, the environment variable way is preferred, as it is more customizable,
1017 * and more expressive.
1018 */
1019 if (logging)
1020 {
1021 LogComponentEnable("UdpClient", LOG_LEVEL_INFO);
1022 LogComponentEnable("UdpServer", LOG_LEVEL_INFO);
1023 LogComponentEnable("NrPdcp", LOG_LEVEL_INFO);
1024 // LogComponentEnable ("NrMacSchedulerOfdma", LOG_LEVEL_ALL);
1025 }
1026
1027 /*
1028 * Default values for the simulation. We are progressively removing all
1029 * the instances of SetDefault, but we need it for legacy code (LTE)
1030 */
1031 Config::SetDefault("ns3::NrRlcUm::MaxTxBufferSize", UintegerValue(999999999));
1032
1033 /*
1034 * Create the scenario. In our examples, we heavily use helpers that setup
1035 * the gnbs and ue following a pre-defined pattern. Please have a look at the
1036 * GridScenarioHelper documentation to see how the nodes will be distributed.
1037 */
1038 HexagonalGridScenarioHelper gridScenario;
1039 gridScenario.SetSectorization(HexagonalGridScenarioHelper::TRIPLE);
1040 gridScenario.SetNumRings(numOuterRings);
1041 gridScenario.SetScenarioParameters(scenario);
1042 uint16_t gNbNum = gridScenario.GetNumCells();
1043 std::cout << "numcells: " << gNbNum << std::endl;
1044 uint32_t ueNum = ueNumPergNb * gNbNum;
1045 std::cout << "numUEs: " << ueNum << std::endl;
1046 gridScenario.SetUtNumber(ueNum);
1047 gridScenario.AssignStreams(RngSeedManager::GetRun());
1048 gridScenario.CreateScenario();
1049 const uint16_t ffr =
1050 3; // Fractional Frequency Reuse scheme to mitigate intra-site inter-sector interferences
1051
1052 /*
1053 * Create different gNB NodeContainer for the different sectors.
1054 */
1055 NodeContainer gnbSector1Container;
1056 NodeContainer gnbSector2Container;
1057 NodeContainer gnbSector3Container;
1058 for (uint32_t j = 0; j < gridScenario.GetBaseStations().GetN(); ++j)
1059 {
1060 Ptr<Node> gnb = gridScenario.GetBaseStations().Get(j);
1061 switch (j % ffr)
1062 {
1063 case 0:
1064 gnbSector1Container.Add(gnb);
1065 break;
1066 case 1:
1067 gnbSector2Container.Add(gnb);
1068 break;
1069 case 2:
1070 gnbSector3Container.Add(gnb);
1071 break;
1072 default:
1073 NS_ABORT_MSG("ffr param cannot be larger than 3");
1074 break;
1075 }
1076 }
1077
1078 /*
1079 * Create different UE NodeContainer for the different sectors.
1080 */
1081 NodeContainer ueSector1Container;
1082 NodeContainer ueSector2Container;
1083 NodeContainer ueSector3Container;
1084
1085 for (uint32_t j = 0; j < gridScenario.GetUserTerminals().GetN(); ++j)
1086 {
1087 Ptr<Node> ue = gridScenario.GetUserTerminals().Get(j);
1088 switch (j % ffr)
1089 {
1090 case 0:
1091 ueSector1Container.Add(ue);
1092 break;
1093 case 1:
1094 ueSector2Container.Add(ue);
1095 break;
1096 case 2:
1097 ueSector3Container.Add(ue);
1098 break;
1099 default:
1100 NS_ABORT_MSG("ffr param cannot be larger than 3");
1101 break;
1102 }
1103 }
1104
1105 /*
1106 * Setup the LTE or NR module. We create the various helpers needed inside
1107 * their respective configuration functions
1108 */
1109 Ptr<NrPointToPointEpcHelper> nrEpcHelper;
1110
1111 NetDeviceContainer gnbSector1NetDev;
1112 NetDeviceContainer gnbSector2NetDev;
1113 NetDeviceContainer gnbSector3NetDev;
1114 NetDeviceContainer ueSector1NetDev;
1115 NetDeviceContainer ueSector2NetDev;
1116 NetDeviceContainer ueSector3NetDev;
1117
1118 Ptr<LteHelper> lteHelper;
1119 Ptr<NrHelper> nrHelper;
1120
1121 std::vector<int16_t> maxMcsVector = GetMcsVectorFromInput(maxMcsVectorInput);
1122
1123 nrEpcHelper = CreateObject<NrPointToPointEpcHelper>();
1124 Set5gLenaSimulatorParameters(gridScenario,
1125 scenario,
1126 radioNetwork,
1127 errorModel,
1128 operationMode,
1129 direction,
1130 numerologyBwp,
1131 pattern1,
1132 pattern2,
1133 uniformPattern,
1134 gnbSector1Container,
1135 gnbSector2Container,
1136 gnbSector3Container,
1137 ueSector1Container,
1138 ueSector2Container,
1139 ueSector3Container,
1140 nrEpcHelper,
1141 nrHelper,
1142 gnbSector1NetDev,
1143 gnbSector2NetDev,
1144 gnbSector3NetDev,
1145 ueSector1NetDev,
1146 ueSector2NetDev,
1147 ueSector3NetDev,
1148 maxMcs1,
1149 maxMcs2,
1150 maxMcsVector,
1151 uniformMcs,
1152 uniformLambda);
1153
1154 // From here, it is standard NS3. In the future, we will create helpers
1155 // for this part as well.
1156
1157 auto [remoteHost, remoteHostIpv4Address] =
1158 nrEpcHelper->SetupRemoteHost("100Gb/s", 2500, Seconds(0.000));
1159 auto remoteHostContainer = NodeContainer(remoteHost);
1160
1161 InternetStackHelper internet;
1162
1163 internet.Install(gridScenario.GetUserTerminals());
1164
1165 Ipv4InterfaceContainer ueSector1IpIface =
1166 nrEpcHelper->AssignUeIpv4Address(NetDeviceContainer(ueSector1NetDev));
1167 Ipv4InterfaceContainer ueSector2IpIface =
1168 nrEpcHelper->AssignUeIpv4Address(NetDeviceContainer(ueSector2NetDev));
1169 Ipv4InterfaceContainer ueSector3IpIface =
1170 nrEpcHelper->AssignUeIpv4Address(NetDeviceContainer(ueSector3NetDev));
1171
1172 // attach UEs to their gNB. Try to attach them per cellId order
1173 for (uint32_t u = 0; u < ueNum; ++u)
1174 {
1175 uint32_t sector = u % ffr;
1176 uint32_t i = u / ffr;
1177 if (sector == 0)
1178 {
1179 Ptr<NetDevice> gnbNetDev = gnbSector1NetDev.Get(i % gridScenario.GetNumSites());
1180 Ptr<NetDevice> ueNetDev = ueSector1NetDev.Get(i);
1181 if (lteHelper != nullptr)
1182 {
1183 lteHelper->Attach(ueNetDev, gnbNetDev);
1184 }
1185 else if (nrHelper != nullptr)
1186 {
1187 nrHelper->AttachToGnb(ueNetDev, gnbNetDev);
1188 }
1189 else
1190 {
1191 NS_ABORT_MSG("Programming error");
1192 }
1193 if (logging)
1194 {
1195 Vector gnbpos = gnbNetDev->GetNode()->GetObject<MobilityModel>()->GetPosition();
1196 Vector uepos = ueNetDev->GetNode()->GetObject<MobilityModel>()->GetPosition();
1197 double distance = CalculateDistance(gnbpos, uepos);
1198 std::cout << "Distance = " << distance << " meters" << std::endl;
1199 }
1200 }
1201 else if (sector == 1)
1202 {
1203 Ptr<NetDevice> gnbNetDev = gnbSector2NetDev.Get(i % gridScenario.GetNumSites());
1204 Ptr<NetDevice> ueNetDev = ueSector2NetDev.Get(i);
1205 if (lteHelper != nullptr)
1206 {
1207 lteHelper->Attach(ueNetDev, gnbNetDev);
1208 }
1209 else if (nrHelper != nullptr)
1210 {
1211 nrHelper->AttachToGnb(ueNetDev, gnbNetDev);
1212 }
1213 else
1214 {
1215 NS_ABORT_MSG("Programming error");
1216 }
1217 if (logging)
1218 {
1219 Vector gnbpos = gnbNetDev->GetNode()->GetObject<MobilityModel>()->GetPosition();
1220 Vector uepos = ueNetDev->GetNode()->GetObject<MobilityModel>()->GetPosition();
1221 double distance = CalculateDistance(gnbpos, uepos);
1222 std::cout << "Distance = " << distance << " meters" << std::endl;
1223 }
1224 }
1225 else if (sector == 2)
1226 {
1227 Ptr<NetDevice> gnbNetDev = gnbSector3NetDev.Get(i % gridScenario.GetNumSites());
1228 Ptr<NetDevice> ueNetDev = ueSector3NetDev.Get(i);
1229 if (lteHelper != nullptr)
1230 {
1231 lteHelper->Attach(ueNetDev, gnbNetDev);
1232 }
1233 else if (nrHelper != nullptr)
1234 {
1235 nrHelper->AttachToGnb(ueNetDev, gnbNetDev);
1236 }
1237 else
1238 {
1239 NS_ABORT_MSG("Programming error");
1240 }
1241 if (logging)
1242 {
1243 Vector gnbpos = gnbNetDev->GetNode()->GetObject<MobilityModel>()->GetPosition();
1244 Vector uepos = ueNetDev->GetNode()->GetObject<MobilityModel>()->GetPosition();
1245 double distance = CalculateDistance(gnbpos, uepos);
1246 std::cout << "Distance = " << distance << " meters" << std::endl;
1247 }
1248 }
1249 else
1250 {
1251 NS_ABORT_MSG("Number of sector cannot be larger than 3");
1252 }
1253 }
1254
1255 /*
1256 * Traffic part. Install two kind of traffic: low-latency and voice, each
1257 * identified by a particular source port.
1258 */
1259 uint16_t dlPortLowLat = 1234;
1260
1261 ApplicationContainer serverApps;
1262
1263 // The sink will always listen to the specified ports
1264 UdpServerHelper dlPacketSinkLowLat(dlPortLowLat);
1265
1266 // The server, that is the application which is listening, is installed in the UE
1267 if (direction == "DL")
1268 {
1269 serverApps.Add(dlPacketSinkLowLat.Install(
1270 {ueSector1Container, ueSector2Container, ueSector3Container}));
1271 }
1272 else
1273 {
1274 serverApps.Add(dlPacketSinkLowLat.Install(remoteHost));
1275 }
1276
1277 /*
1278 * Configure attributes for the different generators, using user-provided
1279 * parameters for generating a CBR traffic
1280 *
1281 * Low-Latency configuration and object creation:
1282 */
1283 UdpClientHelper dlClientLowLat;
1284 dlClientLowLat.SetAttribute("MaxPackets", UintegerValue(0xFFFFFFFF));
1285 dlClientLowLat.SetAttribute("PacketSize", UintegerValue(udpPacketSize));
1286 // dlClientLowLat.SetAttribute ("Interval", TimeValue (Seconds (1.0/lambda)));
1287
1288 // The bearer that will carry low latency traffic
1289 EpsBearer lowLatBearer(EpsBearer::NGBR_VIDEO_TCP_DEFAULT);
1291
1292 // The filter for the low-latency traffic
1293 Ptr<EpcTft> lowLatTft = CreateLowLatTft<EpcTft>(dlPortLowLat, dlPortLowLat, direction);
1294 Ptr<NrEpcTft> nrLowLatTft = CreateLowLatTft<NrEpcTft>(dlPortLowLat, dlPortLowLat, direction);
1295
1296 std::vector<uint32_t> lambdaPerCell(gridScenario.GetNumCells());
1297 if (uniformLambda)
1298 {
1299 for (uint32_t bs = 0; bs < gridScenario.GetNumCells(); ++bs)
1300 {
1301 lambdaPerCell[bs] = lambda;
1302 std::cout << "Cell: " << bs << " lambda (same lambda): " << lambdaPerCell[bs]
1303 << std::endl;
1304 }
1305 }
1306 else // non-uniform lambda values among the cells!
1307 {
1308 for (uint32_t bs = 0; bs < gridScenario.GetNumCells(); ++bs)
1309 {
1310 lambdaPerCell[bs] = 1000 + bs * 2000;
1311 std::cout << "Cell: " << bs << " lambda (diff lambda): " << lambdaPerCell[bs]
1312 << std::endl;
1313 }
1314 }
1315
1316 /*
1317 * Let's install the applications!
1318 */
1319 ApplicationContainer clientApps;
1320 ApplicationContainer ftpClientAppsSector1;
1321 ApplicationContainer ftpServerAppsSector1;
1322 ApplicationContainer ftpClientAppsSector2;
1323 ApplicationContainer ftpServerAppsSector2;
1324 ApplicationContainer ftpClientAppsSector3;
1325 ApplicationContainer ftpServerAppsSector3;
1326 Ptr<ThreeGppFtpM1Helper> ftpHelperSector1;
1327 Ptr<ThreeGppFtpM1Helper> ftpHelperSector2;
1328 Ptr<ThreeGppFtpM1Helper> ftpHelperSector3;
1329
1330 if (ftpM1Enabled)
1331 {
1332 // sector 1 FTP M1 applications configuration
1333 ftpHelperSector1 = CreateObject<ThreeGppFtpM1Helper>(&ftpServerAppsSector1,
1334 &ftpClientAppsSector1,
1335 &ueSector1Container,
1336 &remoteHostContainer,
1337 &ueSector1IpIface);
1338 ftpHelperSector1->Configure(ftpPortSector1,
1339 MilliSeconds(ftpServerAppStartTimeMs),
1340 MilliSeconds(ftpClientAppStartTimeMs),
1341 MilliSeconds(simTimeMs),
1342 ftpLambda,
1343 ftpFileSize);
1344 ftpHelperSector1->Start();
1345
1346 // sector 2 FTP M1 applications configuration
1347 ftpHelperSector2 = CreateObject<ThreeGppFtpM1Helper>(&ftpServerAppsSector2,
1348 &ftpClientAppsSector2,
1349 &ueSector2Container,
1350 &remoteHostContainer,
1351 &ueSector2IpIface);
1352 ftpHelperSector2->Configure(ftpPortSector2,
1353 MilliSeconds(ftpServerAppStartTimeMs),
1354 MilliSeconds(ftpClientAppStartTimeMs),
1355 MilliSeconds(simTimeMs),
1356 ftpLambda,
1357 ftpFileSize);
1358 ftpHelperSector2->Start();
1359
1360 // sector 3 FTP M1 applications configuration
1361 ftpHelperSector3 = CreateObject<ThreeGppFtpM1Helper>(&ftpServerAppsSector3,
1362 &ftpClientAppsSector3,
1363 &ueSector3Container,
1364 &remoteHostContainer,
1365 &ueSector3IpIface);
1366 ftpHelperSector3->Configure(ftpPortSector3,
1367 MilliSeconds(ftpServerAppStartTimeMs),
1368 MilliSeconds(ftpClientAppStartTimeMs),
1369 MilliSeconds(simTimeMs),
1370 ftpLambda,
1371 ftpFileSize);
1372 ftpHelperSector3->Start();
1373
1374 clientApps.Add(ftpClientAppsSector1);
1375 clientApps.Add(ftpClientAppsSector2);
1376 clientApps.Add(ftpClientAppsSector3);
1377
1378 serverApps.Add(ftpServerAppsSector1);
1379 serverApps.Add(ftpServerAppsSector2);
1380 serverApps.Add(ftpServerAppsSector3);
1381 }
1382 else
1383 {
1384 for (uint32_t i = 0; i < ueSector1Container.GetN(); ++i)
1385 {
1386 dlClientLowLat.SetAttribute(
1387 "Interval",
1388 TimeValue(Seconds(1.0 / lambdaPerCell[(i % gridScenario.GetNumSites()) *
1389 gridScenario.GetNumSectorsPerSite()])));
1390 std::cout << "ue (sector1): " << i << " index: "
1391 << (i % gridScenario.GetNumSites()) * gridScenario.GetNumSectorsPerSite()
1392 << " lambda: "
1393 << lambdaPerCell[(i % gridScenario.GetNumSites()) *
1394 gridScenario.GetNumSectorsPerSite()]
1395 << std::endl;
1396 Ptr<Node> ue = ueSector1Container.Get(i);
1397 Ptr<NetDevice> ueDevice = ueSector1NetDev.Get(i);
1398 Address ueAddress = ueSector1IpIface.GetAddress(i);
1399
1400 // The client, who is transmitting, is installed in the remote host,
1401 // with destination address set to the address of the UE
1402 if (direction == "DL")
1403 {
1404 dlClientLowLat.SetAttribute(
1405 "Remote",
1406 AddressValue(addressUtils::ConvertToSocketAddress(ueAddress, dlPortLowLat)));
1407 clientApps.Add(dlClientLowLat.Install(remoteHost));
1408 }
1409 else
1410 {
1411 dlClientLowLat.SetAttribute(
1412 "Remote",
1413 AddressValue(
1414 addressUtils::ConvertToSocketAddress(remoteHostIpv4Address, dlPortLowLat)));
1415 clientApps.Add(dlClientLowLat.Install(ue));
1416 }
1417 // Activate a dedicated bearer for the traffic type
1418 if (lteHelper != nullptr)
1419 {
1420 lteHelper->ActivateDedicatedEpsBearer(ueDevice, lowLatBearer, lowLatTft);
1421 }
1422 else if (nrHelper != nullptr)
1423 {
1424 nrHelper->ActivateDedicatedEpsBearer(ueDevice, nrLowLatBearer, nrLowLatTft);
1425 }
1426 else
1427 {
1428 NS_ABORT_MSG("Programming error");
1429 }
1430 }
1431
1432 for (uint32_t i = 0; i < ueSector2Container.GetN(); ++i)
1433 {
1434 dlClientLowLat.SetAttribute(
1435 "Interval",
1436 TimeValue(Seconds(1.0 / lambdaPerCell[(i % gridScenario.GetNumSites()) *
1437 gridScenario.GetNumSectorsPerSite() +
1438 1])));
1439 std::cout << "ue (sector2): " << i << " index: "
1440 << (i % gridScenario.GetNumSites()) * gridScenario.GetNumSectorsPerSite() + 1
1441 << " lambda: "
1442 << lambdaPerCell[(i % gridScenario.GetNumSites()) *
1443 gridScenario.GetNumSectorsPerSite() +
1444 1]
1445 << std::endl;
1446 Ptr<Node> ue = ueSector2Container.Get(i);
1447 Ptr<NetDevice> ueDevice = ueSector2NetDev.Get(i);
1448 Address ueAddress = ueSector2IpIface.GetAddress(i);
1449
1450 // The client, who is transmitting, is instaviso entonces pronto, sualled in the remote
1451 // host, with destination address set to the address of the UE
1452 if (direction == "DL")
1453 {
1454 dlClientLowLat.SetAttribute(
1455 "Remote",
1456 AddressValue(addressUtils::ConvertToSocketAddress(ueAddress, dlPortLowLat)));
1457 clientApps.Add(dlClientLowLat.Install(remoteHost));
1458 }
1459 else
1460 {
1461 dlClientLowLat.SetAttribute(
1462 "Remote",
1463 AddressValue(
1464 addressUtils::ConvertToSocketAddress(remoteHostIpv4Address, dlPortLowLat)));
1465 clientApps.Add(dlClientLowLat.Install(ue));
1466 }
1467 // Activate a dedicated bearer for the traffic type
1468 if (lteHelper != nullptr)
1469 {
1470 lteHelper->ActivateDedicatedEpsBearer(ueDevice, lowLatBearer, lowLatTft);
1471 }
1472 else if (nrHelper != nullptr)
1473 {
1474 nrHelper->ActivateDedicatedEpsBearer(ueDevice, nrLowLatBearer, nrLowLatTft);
1475 }
1476 else
1477 {
1478 NS_ABORT_MSG("Programming error");
1479 }
1480 }
1481
1482 for (uint32_t i = 0; i < ueSector3Container.GetN(); ++i)
1483 {
1484 dlClientLowLat.SetAttribute(
1485 "Interval",
1486 TimeValue(Seconds(1.0 / lambdaPerCell[(i % gridScenario.GetNumSites()) *
1487 gridScenario.GetNumSectorsPerSite() +
1488 2])));
1489 std::cout << "ue (sector3): " << i << " index: "
1490 << (i % gridScenario.GetNumSites()) * gridScenario.GetNumSectorsPerSite() + 2
1491 << " lambda: "
1492 << lambdaPerCell[(i % gridScenario.GetNumSites()) *
1493 gridScenario.GetNumSectorsPerSite() +
1494 2]
1495 << std::endl;
1496 Ptr<Node> ue = ueSector3Container.Get(i);
1497 Ptr<NetDevice> ueDevice = ueSector3NetDev.Get(i);
1498 Address ueAddress = ueSector3IpIface.GetAddress(i);
1499
1500 // The client, who is transmitting, is installed in the remote host,
1501 // with destination address set to the address of the UE
1502 if (direction == "DL")
1503 {
1504 dlClientLowLat.SetAttribute(
1505 "Remote",
1506 AddressValue(addressUtils::ConvertToSocketAddress(ueAddress, dlPortLowLat)));
1507 clientApps.Add(dlClientLowLat.Install(remoteHost));
1508 }
1509 else
1510 {
1511 dlClientLowLat.SetAttribute(
1512 "Remote",
1513 AddressValue(
1514 addressUtils::ConvertToSocketAddress(remoteHostIpv4Address, dlPortLowLat)));
1515 clientApps.Add(dlClientLowLat.Install(ue));
1516 }
1517 // Activate a dedicated bearer for the traffic type
1518 if (lteHelper != nullptr)
1519 {
1520 lteHelper->ActivateDedicatedEpsBearer(ueDevice, lowLatBearer, lowLatTft);
1521 }
1522 else if (nrHelper != nullptr)
1523 {
1524 nrHelper->ActivateDedicatedEpsBearer(ueDevice, nrLowLatBearer, nrLowLatTft);
1525 }
1526 else
1527 {
1528 NS_ABORT_MSG("Programming error");
1529 }
1530 }
1531 }
1532
1533 // start UDP server and client apps
1534 serverApps.Start(MilliSeconds(udpAppStartTimeMs));
1535 clientApps.Start(MilliSeconds(udpAppStartTimeMs));
1536 serverApps.Stop(MilliSeconds(simTimeMs));
1537 clientApps.Stop(MilliSeconds(simTimeMs));
1538
1539 // enable the traces provided by the nr module
1540 if (traces)
1541 {
1542 if (lteHelper != nullptr)
1543 {
1544 lteHelper->EnableTraces();
1545 }
1546 else if (nrHelper != nullptr)
1547 {
1548 nrHelper->EnableTraces();
1549 }
1550 }
1551
1552 FlowMonitorHelper flowmonHelper;
1553 NodeContainer endpointNodes;
1554 endpointNodes.Add(remoteHost);
1555 endpointNodes.Add(gridScenario.GetUserTerminals());
1556
1557 Ptr<ns3::FlowMonitor> monitor = flowmonHelper.Install(endpointNodes);
1558 monitor->SetAttribute("DelayBinWidth", DoubleValue(0.001));
1559 monitor->SetAttribute("JitterBinWidth", DoubleValue(0.001));
1560 monitor->SetAttribute("PacketSizeBinWidth", DoubleValue(20));
1561
1562 Simulator::Stop(MilliSeconds(simTimeMs));
1563 Simulator::Run();
1564
1565 /*
1566 * To check what was installed in the memory, i.e., BWPs of gNB Device, and its configuration.
1567 * Example is: Node 1 -> Device 0 -> BandwidthPartMap -> {0,1} BWPs -> NrGnbPhy -> Numerology,
1568 GtkConfigStore config;
1569 config.ConfigureAttributes ();
1570 */
1571
1572 // Print per-flow statistics
1573 monitor->CheckForLostPackets();
1574 Ptr<Ipv4FlowClassifier> classifier =
1575 DynamicCast<Ipv4FlowClassifier>(flowmonHelper.GetClassifier());
1576 FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats();
1577
1578 double averageFlowThroughput = 0.0;
1579 double averageFlowDelay = 0.0;
1580
1581 std::ofstream outFile;
1582 std::string filename = outputDir + "/" + simTag;
1583 std::vector<double> delayValues(stats.size());
1584 uint64_t cont = 0;
1585
1586 outFile.open(filename.c_str(), std::ofstream::out | std::ofstream::trunc);
1587 if (!outFile.is_open())
1588 {
1589 std::cerr << "Can't open file " << filename << std::endl;
1590 return 1;
1591 }
1592
1593 outFile.setf(std::ios_base::fixed);
1594
1595 for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i = stats.begin();
1596 i != stats.end();
1597 ++i)
1598 {
1599 Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(i->first);
1600 std::stringstream protoStream;
1601 protoStream << (uint16_t)t.protocol;
1602 if (t.protocol == 6)
1603 {
1604 protoStream.str("TCP");
1605 }
1606 if (t.protocol == 17)
1607 {
1608 protoStream.str("UDP");
1609 }
1610 // outFile << "Flow " << i->first << " (" << t.sourceAddress << ":" << t.sourcePort << " ->
1611 // " << t.destinationAddress << ":" << t.destinationPort << ") proto " << protoStream.str ()
1612 // << "\n"; outFile << " Tx Packets: " << i->second.txPackets << "\n"; outFile << " Tx
1613 // Bytes: " << i->second.txBytes << "\n"; outFile << " TxOffered: " << i->second.txBytes
1614 // * 8.0 / ((simTimeMs - udpAppStartTimeMs) / 1000.0) / 1000.0 / 1000.0 << " Mbps\n";
1615 // outFile << " Rx Bytes: " << i->second.rxBytes << "\n";
1616 if (i->second.rxPackets > 0)
1617 {
1618 // Measure the duration of the flow from receiver's perspective
1619 // double rxDuration = i->second.timeLastRxPacket.GetSeconds () -
1620 // i->second.timeFirstTxPacket.GetSeconds ();
1621 double rxDuration = (simTimeMs - udpAppStartTimeMs) / 1000.0;
1622
1623 averageFlowThroughput += i->second.rxBytes * 8.0 / rxDuration / 1000 / 1000;
1624 averageFlowDelay += 1000 * i->second.delaySum.GetSeconds() / i->second.rxPackets;
1625 delayValues[cont] = 1000 * i->second.delaySum.GetSeconds() / i->second.rxPackets;
1626 cont++;
1627
1628 // outFile << " Throughput: " << i->second.rxBytes * 8.0 / rxDuration / 1000 / 1000 <<
1629 // " Mbps\n"; outFile << " Mean delay: " << 1000 * i->second.delaySum.GetSeconds () /
1630 // i->second.rxPackets << " ms\n"; outFile << " Mean upt: " << i->second.uptSum /
1631 // i->second.rxPackets / 1000/1000 << " Mbps \n"; outFile << " Mean jitter: " << 1000
1632 // * i->second.jitterSum.GetSeconds () / i->second.rxPackets << " ms\n";
1633 }
1634 else
1635 {
1636 // outFile << " Throughput: 0 Mbps\n";
1637 // outFile << " Mean delay: 0 ms\n";
1638 // outFile << " Mean jitter: 0 ms\n";
1639 }
1640 // outFile << " Rx Packets: " << i->second.rxPackets << "\n";
1641 }
1642 std::stable_sort(delayValues.begin(), delayValues.end());
1643 // for (uint32_t i = 0; i < stats.size(); i++)
1644 // {
1645 // std::cout << delayValues[i] << " ";
1646 // }
1647 // double FiftyTileFlowDelay = (delayValues[stats.size()/2] + delayValues[stats.size()/2 -1])/2;
1648 double FiftyTileFlowDelay = delayValues[stats.size() / 2];
1649
1650 outFile << "\n\n Mean flow throughput: " << averageFlowThroughput / stats.size() << "\n";
1651 outFile << " Mean flow delay: " << averageFlowDelay / stats.size() << "\n";
1652 outFile << " Median flow delay: " << FiftyTileFlowDelay << "\n";
1653
1654 outFile.close();
1655
1656 std::ifstream f(filename.c_str());
1657
1658 if (f.is_open())
1659 {
1660 std::cout << f.rdbuf();
1661 }
1662
1663 Simulator::Destroy();
1664 return 0;
1665}
Manages the correct creation of operation bands, component carriers and bandwidth parts.
OperationBandInfo CreateOperationBandContiguousCc(const SimpleOperationBandConf &conf)
Create an operation band with the CC specified.
static BandwidthPartInfoPtrVector GetAllBwps(const std::vector< std::reference_wrapper< OperationBandInfo > > &operationBands)
Get all the BWP pointers from the specified vector of operation bands.
static TypeId GetTypeId()
Get the type id.
The HexagonalGridScenarioHelper class.
void CreateScenario() override
Create the scenario, with the configured parameter.
void SetNumRings(uint8_t numRings)
Sets the number of outer rings of sites around the central site.
const NodeContainer & GetUserTerminals() const
Get the list of user nodes.
std::size_t GetNumSites() const
Gets the number of sites with cell base stations.
void SetUtNumber(std::size_t n)
Set the number of UT/UE.
std::size_t GetNumCells() const
Gets the total number of cells deployed.
const NodeContainer & GetBaseStations() const
Get the list of gnb/base station nodes.
double GetAntennaOrientationRadians(std::size_t cellId) const
Returns the orientation in radians of the antenna array for the given cellId.
@ ErrorModel
Error Model version (can use different error models, see NrErrorModel)
Definition nr-amc.h:81
This class contains the specification of EPS Bearers.
@ NGBR_VIDEO_TCP_DEFAULT
Non-GBR TCP-based Video (Buffered Streaming, e.g., www, e-mail...)
uint32_t GetNumSectorsPerSite() const
Gets the number of sectors per site.
void SetSectorization(SiteSectorizationType numSectors)
Sets the number of sectors of every site.
void SetScenarioParameters(const std::string &scenario)
Sets parameters to the specified scenario.
void Set5gLenaSimulatorParameters(HexagonalGridScenarioHelper gridScenario, std::string scenario, std::string radioNetwork, std::string errorModel, std::string operationMode, std::string direction, uint16_t numerology, std::string pattern1, std::string pattern2, bool uniformPattern, NodeContainer gnbSector1Container, NodeContainer gnbSector2Container, NodeContainer gnbSector3Container, NodeContainer ueSector1Container, NodeContainer ueSector2Container, NodeContainer ueSector3Container, Ptr< NrPointToPointEpcHelper > &baseNrEpcHelper, Ptr< NrHelper > &nrHelper, NetDeviceContainer &gnbSector1NetDev, NetDeviceContainer &gnbSector2NetDev, NetDeviceContainer &gnbSector3NetDev, NetDeviceContainer &ueSector1NetDev, NetDeviceContainer &ueSector2NetDev, NetDeviceContainer &ueSector3NetDev, int16_t maxMcsDl1, int16_t maxMcsDl2, std::vector< int16_t > &maxMcsVector, bool uniformMcs, bool uniformLambda)
std::vector< std::reference_wrapper< BandwidthPartInfoPtr > > BandwidthPartInfoPtrVector
vector of unique_ptr of BandwidthPartInfo
Minimum configuration requirements for a OperationBand.
uint8_t m_numBwp
Number of BWP per CC.
Operation band information structure.