5G-LENA nr-v4.0
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
cttc-nr-mimo-demo.cc
Go to the documentation of this file.
1// Copyright (c) 2023 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4
32#include "mimo-sim-helpers/cttc-mimo-simple-db-helper.h"
33
34#include "ns3/antenna-module.h"
35#include "ns3/applications-module.h"
36#include "ns3/basic-data-calculators.h"
37#include "ns3/config-store-module.h"
38#include "ns3/core-module.h"
39#include "ns3/flow-monitor-module.h"
40#include "ns3/internet-apps-module.h"
41#include "ns3/internet-module.h"
42#include "ns3/mobility-module.h"
43#include "ns3/network-module.h"
44#include "ns3/nr-module.h"
45#include "ns3/point-to-point-module.h"
46#include "ns3/stats-module.h"
47#include "ns3/traffic-generator-helper.h"
48
49#include <map>
50
51using namespace ns3;
52NS_LOG_COMPONENT_DEFINE("CttcNrMimoDemo");
53
54struct CqiFeedbackTraceStats
55{
56 Ptr<MinMaxAvgTotalCalculator<uint8_t>> m_ri;
57 Ptr<MinMaxAvgTotalCalculator<uint8_t>> m_mcs;
58
59 CqiFeedbackTraceStats()
60 {
61 m_ri = CreateObject<MinMaxAvgTotalCalculator<uint8_t>>();
62 m_mcs = CreateObject<MinMaxAvgTotalCalculator<uint8_t>>();
63 }
64
65 CqiFeedbackTraceStats(uint8_t rank, uint8_t mcs)
66 {
67 m_ri = CreateObject<MinMaxAvgTotalCalculator<uint8_t>>();
68 m_ri->Update(rank);
69 m_mcs = CreateObject<MinMaxAvgTotalCalculator<uint8_t>>();
70 m_mcs->Update(mcs);
71 }
72};
73
74void
75CqiFeedbackTracedCallback(std::map<uint16_t, CqiFeedbackTraceStats>* stats,
76 uint16_t rnti,
77 [[maybe_unused]] uint8_t cqi,
78 uint8_t mcs,
79 uint8_t rank)
80{
81 auto it = stats->find(rnti);
82 if (it != stats->end())
83 {
84 it->second.m_ri->Update(rank);
85 it->second.m_mcs->Update(mcs);
86 }
87 else
88 {
89 (*stats)[rnti] = CqiFeedbackTraceStats(rank, mcs);
90 }
91}
92
93namespace ns3
94{
95class FastFadingTestingMobilityModel : public ConstantPositionMobilityModel
96{
97 public:
98 static TypeId GetTypeId();
99 Vector m_fakeVelocity{0.0, 0.0, 0.0};
100
101 private:
102 Vector DoGetVelocity() const override;
103};
104
105NS_OBJECT_ENSURE_REGISTERED(FastFadingTestingMobilityModel);
106
107TypeId
108FastFadingTestingMobilityModel::GetTypeId()
109{
110 static TypeId tid =
111 TypeId("ns3::FastFadingTestingMobilityModel")
112 .SetParent<ConstantPositionMobilityModel>()
113 .SetGroupName("Mobility")
114 .AddConstructor<FastFadingTestingMobilityModel>()
115 .AddAttribute("FakeVelocity",
116 "The current velocity of the mobility model.",
117 VectorValue(Vector(0.0, 0.0, 0.0)), // ignored initial value.
118 MakeVectorAccessor(&FastFadingTestingMobilityModel::m_fakeVelocity),
119 MakeVectorChecker());
120 return tid;
121}
122
123Vector
124FastFadingTestingMobilityModel::DoGetVelocity() const
125{
126 return m_fakeVelocity;
127}
128} // namespace ns3
129
130int
131main(int argc, char* argv[])
132{
133 auto startExecTime = std::chrono::system_clock::now();
134 bool enableMimoFeedback = true;
135 bool useConfigSetDefault = false;
136 uint8_t csiFlags = 1;
137
140 apUe.antennaElem = "ns3::ThreeGppAntennaModel";
141 apUe.nAntCols = 2;
142 apUe.nAntRows = 2;
143 apUe.nHorizPorts = 2;
144 apUe.nVertPorts = 1;
145 apUe.isDualPolarized = false;
146 apGnb.antennaElem = "ns3::ThreeGppAntennaModel";
147 apGnb.nAntCols = 4;
148 apGnb.nAntRows = 2;
149 apGnb.nHorizPorts = 2;
150 apGnb.nVertPorts = 1;
151 apGnb.isDualPolarized = false;
152 double downtiltAngleGnb = 10;
153
154 // The polarization slant angle in degrees in case of x-polarized
155 double polSlantAngleGnb = 0.0;
156 double polSlantAngleUe = 90.0;
157 // The bearing angles in degrees
158 double bearingAngleGnb = 0.0;
159 double bearingAngleUe = 180.0;
160
161 std::string trafficType = "cbr";
162 // Traffic parameters
163 uint32_t udpPacketSize = 1000;
164 // Packet interval is 40000 ns to reach 200 Mbps
165 // For MCS Table 2, and 10 MHz BW, 200 Mbps can be achieved by using 4 MIMO streams
166 Time packetInterval = MilliSeconds(30);
167 Time udpAppStartTime = MilliSeconds(400);
168
169 // Interference
170 bool enableInterfNode = false; // if true an additional pair of gNB and UE will be created to
171 // create an interference towards the original pair
172 double interfDistance =
173 1000.0; // the distance in meters between the gNB1 and the interfering gNB2
174 double interfPolSlantDelta = 0; // the difference between the pol. slant angle between the
175 // original node and the interfering one
176
177 // Other simulation scenario parameters
178 Time simTime = MilliSeconds(1000);
179 uint16_t gnbUeDistance = 20; // meters
180 uint16_t numerology = 0;
181 double centralFrequency = 3.5e9;
182 double bandwidth = 10e6;
183 double txPowerGnb = 23; // dBm
184 double txPowerUe = 23; // dBm
185 uint16_t updatePeriodMs = 0;
186 std::string errorModel = "ns3::NrEesmIrT2";
187 std::string scheduler = "ns3::NrMacSchedulerTdmaRR";
188 std::string beamformingMethod = "ns3::DirectPathBeamforming";
189
190 uint32_t wbPmiUpdateIntervalMs = 10; // Wideband PMI update interval in ms
191 uint32_t sbPmiUpdateIntervalMs = 2; // Subband PMI update interval in ms
192
193 // Default channel condition
194 std::string losCondition = "Default";
195 NrHelper::MimoPmiParams mimoPmiParams;
196 mimoPmiParams.subbandSize = 8;
197 double xyVelocity = 0;
198
199 // Where the example stores the output files.
200 std::string simTag = "default";
201 std::string outputDir = "./";
202 bool logging = false;
203
204 CommandLine cmd(__FILE__);
208 cmd.AddValue("enableMimoFeedback", "Enables MIMO feedback", enableMimoFeedback);
209 cmd.AddValue(
210 "pmSearchMethod",
211 "Precoding matrix search method, currently implemented only exhaustive search method"
212 "[ns3::NrPmSearchFull, ns3::NrPmSearchFast, ns3::NrPmSearchIdeal, ns3::NrPmSearchSasaoka, "
213 "ns3::NrPmSearchMaleki (requires extra dependencies)]",
214 mimoPmiParams.pmSearchMethod);
215 cmd.AddValue("fullSearchCb",
216 "The codebook to be used for the full search. Available codebooks are "
217 "a) ns3::NrCbTwoPort, the two-port codebook defined in 3GPP TS 38.214 Table "
218 "5.2.2.2.1-1, and"
219 "b) ns3::NrCbTypeOneSp, Type-I Single-Panel Codebook 3GPP TS 38.214 Rel. 15, "
220 "Sec. 5.2.2.2.1 supporting codebook mode 1 only, and limited to rank 4.",
221 mimoPmiParams.fullSearchCb);
222 cmd.AddValue("rankLimit", "The maximum rank number to be used.", mimoPmiParams.rankLimit);
223 cmd.AddValue("rankTechnique",
224 "Technique used for RI selection by Fast and Sasaoka PMI selection [SVD, "
225 "WaterFilling, Sasaoka]",
226 mimoPmiParams.rankTechnique);
227 cmd.AddValue("rankThreshold", "Threshold used by rankTechnique", mimoPmiParams.rankThreshold);
228 cmd.AddValue("subbandSize", "Sub-band size for downsampling", mimoPmiParams.subbandSize);
229 cmd.AddValue("downsamplingTechnique",
230 "Sub-band downsampling technique",
231 mimoPmiParams.downsamplingTechnique);
232 cmd.AddValue("numRowsGnb", "Number of antenna rows at the gNB", apGnb.nAntRows);
233 cmd.AddValue("numRowsUe", "Number of antenna rows at the UE", apUe.nAntRows);
234 cmd.AddValue("numColumnsGnb", "Number of antenna columns at the gNB", apGnb.nAntCols);
235 cmd.AddValue("numColumnsUe", "Number of antenna columns at the UE", apUe.nAntCols);
236 cmd.AddValue("numVPortsGnb",
237 "Number of vertical ports of the antenna at the gNB",
238 apGnb.nVertPorts);
239 cmd.AddValue("numVPortsUe",
240 "Number of vertical ports of the antenna at the UE",
241 apUe.nVertPorts);
242 cmd.AddValue("numHPortsGnb",
243 "Number of horizontal ports of the antenna the gNB",
244 apGnb.nHorizPorts);
245 cmd.AddValue("numHPortsUe",
246 "Number of horizontal ports of the antenna at the UE",
247 apUe.nHorizPorts);
248 cmd.AddValue("xPolGnb",
249 "Whether the gNB antenna array has the cross polarized antenna "
250 "elements.",
251 apGnb.isDualPolarized);
252 cmd.AddValue("xPolUe",
253 "Whether the UE antenna array has the cross polarized antenna "
254 "elements.",
255 apUe.isDualPolarized);
256 cmd.AddValue("polSlantAngleGnb",
257 "Polarization slant angle of gNB in degrees",
258 polSlantAngleGnb);
259 cmd.AddValue("polSlantAngleUe", "Polarization slant angle of UE in degrees", polSlantAngleUe);
260 cmd.AddValue("bearingAngleGnb", "Bearing angle of gNB in degrees", bearingAngleGnb);
261 cmd.AddValue("bearingAngleUe", "Bearing angle of UE in degrees", bearingAngleUe);
262 cmd.AddValue("downtiltAngleGnb", "Downtilt angle of gNB in degrees", downtiltAngleGnb);
263 cmd.AddValue("enableInterfNode", "Whether to enable an interfering node", enableInterfNode);
264 cmd.AddValue("wbPmiUpdateInterval",
265 "Wideband PMI update interval in ms",
266 wbPmiUpdateIntervalMs);
267 cmd.AddValue("sbPmiUpdateInterval", "Subband PMI update interval in ms", sbPmiUpdateIntervalMs);
268 cmd.AddValue("interfDistance",
269 "The distance between the gNB1 and the interfering gNB2 (the original and the "
270 "interfering one)",
271 interfDistance);
272 cmd.AddValue("interfPolSlantDelta",
273 "The difference between the pol. slant angles of the original pairs of gNB and UE "
274 "and the interfering one",
275 interfPolSlantDelta);
276 cmd.AddValue("csiFlags", "CsiFlags to be configured. See NrHelper::CsiFlags", csiFlags);
280 cmd.AddValue("trafficType",
281 "Traffic type to be installed at the source: cbr or ftp.",
282 trafficType);
283 cmd.AddValue("packetSize",
284 "packet size in bytes to be used by best effort traffic",
285 udpPacketSize);
286 cmd.AddValue("packetInterval", "Inter-packet interval for CBR traffic", packetInterval);
287 cmd.AddValue("simTime", "Simulation time", simTime);
288 cmd.AddValue("numerology", "The numerology to be used", numerology);
289 cmd.AddValue("centralFrequency", "The system frequency to be used in band 1", centralFrequency);
290 cmd.AddValue("bandwidth", "The system bandwidth to be used", bandwidth);
291 cmd.AddValue("txPowerGnb", "gNB TX power", txPowerGnb);
292 cmd.AddValue("txPowerUe", "UE TX power", txPowerUe);
293 cmd.AddValue("gnbUeDistance",
294 "The distance between the gNB and the UE in the scenario",
295 gnbUeDistance);
296 cmd.AddValue(
297 "updatePeriodMs",
298 "Channel update period in ms. If set to 0 then the channel update will be disabled",
299 updatePeriodMs);
300 cmd.AddValue("errorModel",
301 "Error model: ns3::NrEesmCcT1, ns3::NrEesmCcT2, "
302 "ns3::NrEesmIrT1, ns3::NrEesmIrT2, ns3::NrLteMiErrorModel",
303 errorModel);
304 cmd.AddValue("scheduler",
305 "The scheduler: ns3::NrMacSchedulerTdmaRR, "
306 "ns3::NrMacSchedulerTdmaPF, ns3::NrMacSchedulerTdmaMR,"
307 "ns3::NrMacSchedulerTdmaQos, ns3::NrMacSchedulerOfdmaRR, "
308 "ns3::NrMacSchedulerOfdmaPF, ns3::NrMacSchedulerOfdmaMR,"
309 "ns3::NrMacSchedulerOfdmaQos",
310 scheduler);
311 cmd.AddValue("beamformingMethod",
312 "The beamforming method: ns3::CellScanBeamforming,"
313 "ns3::CellScanQuasiOmniBeamforming,"
314 "ns3::DirectPathBeamforming,"
315 "ns3::QuasiOmniDirectPathBeamforming,"
316 "ns3::DirectPathQuasiOmniBeamforming,"
317 "ns3::KronBeamforming,"
318 "ns3::KronQuasiOmniBeamforming",
319 beamformingMethod);
320 cmd.AddValue("losCondition",
321 "Default - for 3GPP channel condition model,"
322 "LOS - for always LOS channel condition model,"
323 "NLOS - for always NLOS channel condition model",
324 losCondition);
325 cmd.AddValue("simTag",
326 "tag to be appended to output filenames to distinguish simulation campaigns",
327 simTag);
328 cmd.AddValue("outputDir", "directory where to store simulation results", outputDir);
329 cmd.AddValue("logging", "Enable logging", logging);
330 cmd.AddValue("useConfigSetDefault",
331 "Configure via Config::SetDefault instead of the MimoPmiParams structure",
332 useConfigSetDefault);
333 cmd.AddValue("xyVelocity",
334 "Velocity in X and Y directions m/s for fake fading model.",
335 xyVelocity);
336 // Parse the command line
337 cmd.Parse(argc, argv);
338
339 // convert angle values into radians
340 apUe.bearingAngle = bearingAngleUe * (M_PI / 180);
341 apUe.polSlantAngle = polSlantAngleUe * (M_PI / 180);
342 apGnb.bearingAngle = bearingAngleGnb * (M_PI / 180);
343 apGnb.polSlantAngle = polSlantAngleGnb * (M_PI / 180);
344
345 NS_ABORT_IF(centralFrequency < 0.5e9 && centralFrequency > 100e9);
346
347 if (logging)
348 {
349 LogComponentEnable("UdpClient", LOG_LEVEL_INFO);
350 LogComponentEnable("UdpServer", LOG_LEVEL_INFO);
351 LogComponentEnable("NrPdcp", LOG_LEVEL_INFO);
352 }
353
354 Config::SetDefault("ns3::NrRlcUm::MaxTxBufferSize", UintegerValue(999999999));
355 Config::SetDefault("ns3::ThreeGppChannelModel::UpdatePeriod",
356 TimeValue(MilliSeconds(updatePeriodMs)));
357
358 uint16_t pairsToCreate = 1;
359 if (enableInterfNode)
360 {
361 pairsToCreate = 2;
362 }
363
364 NodeContainer gnbContainer;
365 gnbContainer.Create(pairsToCreate);
366 NodeContainer ueContainer;
367 ueContainer.Create(pairsToCreate);
368
377 MobilityHelper gnbMobility;
378 gnbMobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
379 Ptr<ListPositionAllocator> gnbPositionAlloc = CreateObject<ListPositionAllocator>();
380 gnbPositionAlloc->Add(Vector(0.0, 0.0, 25.0));
381
382 MobilityHelper ueMobility;
383 ueMobility.SetMobilityModel("ns3::FastFadingTestingMobilityModel",
384 "FakeVelocity",
385 VectorValue(Vector{xyVelocity, xyVelocity, 0}));
386 Ptr<ListPositionAllocator> uePositionAlloc = CreateObject<ListPositionAllocator>();
387 uePositionAlloc->Add(Vector(gnbUeDistance, 0.0, 1.5));
388 // the positions for the second interfering pair of gNB and UE
389 if (enableInterfNode)
390 {
391 gnbPositionAlloc->Add(Vector(interfDistance / 2, 0.0, 25.0)); // gNB2 position
392 uePositionAlloc->Add(Vector(interfDistance, 0.0, 1.5)); // UE2 position
393 }
394 gnbMobility.SetPositionAllocator(gnbPositionAlloc);
395 ueMobility.SetPositionAllocator(uePositionAlloc);
396
397 gnbMobility.Install(gnbContainer.Get(0));
398 ueMobility.Install(ueContainer.Get(0));
399 // install mobility of the second pair of gNB and UE
400 if (enableInterfNode)
401 {
402 gnbMobility.Install(gnbContainer.Get(1));
403 ueMobility.Install(ueContainer.Get(1));
404 }
405
409 Ptr<NrPointToPointEpcHelper> nrEpcHelper = CreateObject<NrPointToPointEpcHelper>();
410 Ptr<IdealBeamformingHelper> idealBeamformingHelper = CreateObject<IdealBeamformingHelper>();
411 Ptr<NrHelper> nrHelper = CreateObject<NrHelper>();
412 nrHelper->SetBeamformingHelper(idealBeamformingHelper);
413 nrHelper->SetEpcHelper(nrEpcHelper);
426 CcBwpCreator ccBwpCreator;
427 const uint8_t numCcPerBand = 1;
428 CcBwpCreator::SimpleOperationBandConf bandConf(centralFrequency, bandwidth, numCcPerBand);
429 OperationBandInfo band = ccBwpCreator.CreateOperationBandContiguousCc(bandConf);
430 // Create the channel helper
431 Ptr<NrChannelHelper> channelHelper = CreateObject<NrChannelHelper>();
432 // Set the channel using the scenario and user input
433 channelHelper->ConfigureFactories("UMa", losCondition, "ThreeGpp");
434 // Set the channel update period and shadowing
435 channelHelper->SetChannelConditionModelAttribute("UpdatePeriod",
436 TimeValue(MilliSeconds(updatePeriodMs)));
437 channelHelper->SetPathlossAttribute("ShadowingEnabled", BooleanValue(false));
438 // Create and set the channel with the band
439 channelHelper->AssignChannelsToBands({band});
440
441 // Configure NrHelper, prepare most of the parameters that will be used in the simulation.
442 nrHelper->SetAttribute("CsiFeedbackFlags", UintegerValue(csiFlags));
443 nrHelper->SetDlErrorModel(errorModel);
444 nrHelper->SetUlErrorModel(errorModel);
445 nrHelper->SetGnbDlAmcAttribute("AmcModel", EnumValue(NrAmc::ErrorModel));
446 nrHelper->SetGnbUlAmcAttribute("AmcModel", EnumValue(NrAmc::ErrorModel));
447 nrHelper->SetSchedulerTypeId(TypeId::LookupByName(scheduler));
448 idealBeamformingHelper->SetAttribute("BeamformingMethod",
449 TypeIdValue(TypeId::LookupByName(beamformingMethod)));
450 // Core latency
451 nrEpcHelper->SetAttribute("S1uLinkDelay", TimeValue(MilliSeconds(0)));
452
453 // We can configure via Config::SetDefault
454 if (enableMimoFeedback)
455 {
456 // We can configure not only via Config::SetDefault, but also via the MimoPmiParams
457 // structure
458 if (useConfigSetDefault)
459 {
460 Config::SetDefault("ns3::NrHelper::EnableMimoFeedback", BooleanValue(true));
461 Config::SetDefault("ns3::NrPmSearch::SubbandSize", UintegerValue(16));
462 }
463 else
464 {
465 nrHelper->SetupMimoPmi(mimoPmiParams);
466 }
467 }
468
472 nrHelper->SetupGnbAntennas(apGnb);
473 // TODO consider adding DowntiltAngle to AntennaParams
474 nrHelper->SetGnbAntennaAttribute("DowntiltAngle", DoubleValue(downtiltAngleGnb * M_PI / 180.0));
478 nrHelper->SetupUeAntennas(apUe);
479
480 nrHelper->SetGnbPhyAttribute("Numerology", UintegerValue(numerology));
481 nrHelper->SetGnbPhyAttribute("TxPower", DoubleValue(txPowerGnb));
482 nrHelper->SetUePhyAttribute("TxPower", DoubleValue(txPowerUe));
483 nrHelper->SetUePhyAttribute("WbPmiUpdateInterval",
484 TimeValue(MilliSeconds(wbPmiUpdateIntervalMs)));
485 nrHelper->SetUePhyAttribute("SbPmiUpdateInterval",
486 TimeValue(MilliSeconds(sbPmiUpdateIntervalMs)));
487
488 uint32_t bwpId = 0;
489 // gNb routing between bearer type and bandwidth part
490 nrHelper->SetGnbBwpManagerAlgorithmAttribute("NGBR_LOW_LAT_EMBB", UintegerValue(bwpId));
491 // UE routing between bearer type and bandwidth part
492 nrHelper->SetUeBwpManagerAlgorithmAttribute("NGBR_LOW_LAT_EMBB", UintegerValue(bwpId));
494 allBwps = CcBwpCreator::GetAllBwps({band});
495
499 NetDeviceContainer gnbNetDev = nrHelper->InstallGnbDevice(gnbContainer, allBwps);
500 NetDeviceContainer ueNetDev = nrHelper->InstallUeDevice(ueContainer, allBwps);
501
502 if (enableInterfNode)
503 {
504 nrHelper->GetGnbPhy(gnbNetDev.Get(1), 0)
505 ->GetSpectrumPhy()
506 ->GetAntenna()
507 ->SetAttribute("BearingAngle", DoubleValue(0));
508 nrHelper->GetUePhy(ueNetDev.Get(1), 0)
509 ->GetSpectrumPhy()
510 ->GetAntenna()
511 ->SetAttribute("BearingAngle", DoubleValue(M_PI));
512 if (interfPolSlantDelta)
513 {
514 // reconfigure the polarization slant angle of the interferer
515 nrHelper->GetGnbPhy(gnbNetDev.Get(1), 0)
516 ->GetSpectrumPhy()
517 ->GetAntenna()
518 ->SetAttribute(
519 "PolSlantAngle",
520 DoubleValue((polSlantAngleGnb + interfPolSlantDelta) * (M_PI / 180)));
521 nrHelper->GetUePhy(ueNetDev.Get(1), 0)
522 ->GetSpectrumPhy()
523 ->GetAntenna()
524 ->SetAttribute("PolSlantAngle",
525 DoubleValue((polSlantAngleUe + interfPolSlantDelta) * (M_PI / 180)));
526 }
527 }
528
534 int64_t randomStream = 1;
535 randomStream += nrHelper->AssignStreams(gnbNetDev, randomStream);
536 randomStream += nrHelper->AssignStreams(ueNetDev, randomStream);
537
538 std::map<uint16_t, CqiFeedbackTraceStats> cqiTraces;
539 for (auto it = ueNetDev.Begin(); it != ueNetDev.End(); ++it)
540 {
541 auto cqiCb = MakeBoundCallback(&CqiFeedbackTracedCallback, &cqiTraces);
542 nrHelper->GetUePhy(*it, 0)->TraceConnectWithoutContext("CqiFeedbackTrace", cqiCb);
543 }
544
545 // create the Internet and install the IP stack on the UEs
546 // get SGW/PGW and create a single RemoteHost
547 auto [remoteHost, remoteHostIpv4Address] =
548 nrEpcHelper->SetupRemoteHost("100Gb/s", 2500, Seconds(0.000));
549
550 InternetStackHelper internet;
551 internet.Install(ueContainer);
552 Ipv4InterfaceContainer ueIpIface =
553 nrEpcHelper->AssignUeIpv4Address(NetDeviceContainer(ueNetDev));
554
555 // attach each UE to its gNB according to desired scenario
556 nrHelper->AttachToGnb(ueNetDev.Get(0), gnbNetDev.Get(0));
557 if (enableInterfNode)
558 {
559 nrHelper->AttachToGnb(ueNetDev.Get(1), gnbNetDev.Get(1));
560 }
561
565 uint16_t dlPort = 1234;
566 ApplicationContainer serverApps;
567 // The sink will always listen to the specified ports
568 UdpServerHelper dlPacketSink(dlPort);
569 // The server, that is the application which is listening, is installed in the UE
570 serverApps.Add(dlPacketSink.Install(ueContainer));
571
572 // The bearer that will carry the traffic
574
575 // The filter for the traffic
576 Ptr<NrEpcTft> dlTft = Create<NrEpcTft>();
577 NrEpcTft::PacketFilter dlPktFilter;
578 dlPktFilter.localPortStart = dlPort;
579 dlPktFilter.localPortEnd = dlPort;
580 dlTft->Add(dlPktFilter);
581
585 ApplicationContainer clientApps;
586 if (trafficType == "cbr")
587 {
588 UdpClientHelper dlClient;
593 dlClient.SetAttribute("MaxPackets", UintegerValue(0xFFFFFFFF));
594 dlClient.SetAttribute("PacketSize", UintegerValue(udpPacketSize));
595 dlClient.SetAttribute("Interval", TimeValue(packetInterval));
596 // The client, who is transmitting, is installed in the remote host,
597 // with destination address set to the address of the UE
598 dlClient.SetAttribute(
599 "Remote",
600 AddressValue(addressUtils::ConvertToSocketAddress(ueIpIface.GetAddress(0), dlPort)));
601 clientApps.Add(dlClient.Install(remoteHost));
602 // Activate a dedicated bearer for the traffic
603 nrHelper->ActivateDedicatedEpsBearer(ueNetDev.Get(0), epsBearer, dlTft);
604 }
605 else if (trafficType == "ftp")
606 {
607 // configure FTP clients with file transfer application that generates multiple file
608 // transfers
609 TrafficGeneratorHelper ftpHelper =
610 TrafficGeneratorHelper("ns3::UdpSocketFactory",
611 Address(),
613 ftpHelper.SetAttribute("PacketSize", UintegerValue(512));
614 ftpHelper.SetAttribute("MaxFileSize", UintegerValue(5e6));
615 ftpHelper.SetAttribute("FileSizeMu", DoubleValue(14.45));
616
617 ftpHelper.SetAttribute("Remote",
618 AddressValue(InetSocketAddress(ueIpIface.GetAddress(0, 0), dlPort)));
619 clientApps.Add(ftpHelper.Install(remoteHost));
620 // Activate a dedicated bearer for the traffic
621 nrHelper->ActivateDedicatedEpsBearer(ueNetDev.Get(0), epsBearer, dlTft);
622 }
623
624 if (enableInterfNode)
625 {
626 UdpClientHelper dlClient;
631 dlClient.SetAttribute("MaxPackets", UintegerValue(0xFFFFFFFF));
632 dlClient.SetAttribute("PacketSize", UintegerValue(udpPacketSize));
633 dlClient.SetAttribute("Interval", TimeValue(MilliSeconds(1)));
634 // The client, who is transmitting, is installed in the remote host,
635 // with destination address set to the address of the UE
636 dlClient.SetAttribute(
637 "Remote",
638 AddressValue(addressUtils::ConvertToSocketAddress(ueIpIface.GetAddress(1), dlPort)));
639 clientApps.Add(dlClient.Install(remoteHost));
640
641 // Activate a dedicated bearer for the traffic
642 nrHelper->ActivateDedicatedEpsBearer(ueNetDev.Get(1), epsBearer, dlTft);
643 }
644
645 // start UDP server and client apps
646 serverApps.Start(udpAppStartTime);
647 clientApps.Start(udpAppStartTime);
648 serverApps.Stop(simTime);
649 clientApps.Stop(simTime);
650
651 // enable the traces provided by the nr module
652 nrHelper->EnableTraces();
653
654 FlowMonitorHelper flowmonHelper;
655 NodeContainer endpointNodes;
656 endpointNodes.Add(remoteHost);
657 endpointNodes.Add(ueContainer);
658
659 Ptr<ns3::FlowMonitor> monitor = flowmonHelper.Install(endpointNodes);
660 monitor->SetAttribute("DelayBinWidth", DoubleValue(0.001));
661 monitor->SetAttribute("JitterBinWidth", DoubleValue(0.001));
662 monitor->SetAttribute("PacketSizeBinWidth", DoubleValue(20));
663
664 Simulator::Stop(simTime);
665 Simulator::Run();
666
667 // Print per-flow statistics
668 monitor->CheckForLostPackets();
669 Ptr<Ipv4FlowClassifier> classifier =
670 DynamicCast<Ipv4FlowClassifier>(flowmonHelper.GetClassifier());
671 FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats();
672
673 double averageFlowThroughput = 0.0;
674 double averageFlowDelay = 0.0;
675
676 std::ofstream outFile;
677 std::string filename = outputDir + "/" + simTag;
678 outFile.open(filename.c_str(), std::ofstream::out | std::ofstream::trunc);
679 if (!outFile.is_open())
680 {
681 std::cerr << "Can't open file " << filename << std::endl;
682 return 1;
683 }
684
685 outFile.setf(std::ios_base::fixed);
686
687 CttcMimoSimpleDbHelper dbHelper;
688 dbHelper.SetResultsDirPath(outputDir);
689 dbHelper.SetDbName("MimoSimple.db");
690 dbHelper.PrepareTable();
691
692 CttcMimoSimpleResults dbResults;
693 // set the parameters
694 dbResults.simTime = simTime.GetSeconds();
695 dbResults.enableMimoFeedback = enableMimoFeedback;
696 dbResults.gnbUeDistance = gnbUeDistance;
697 dbResults.rngRun = SeedManager::GetRun();
698 dbResults.pmSearchMethod = mimoPmiParams.pmSearchMethod;
699 dbResults.fullSearchCb = mimoPmiParams.fullSearchCb;
700 dbResults.rankLimit = mimoPmiParams.rankLimit;
701 // gnb antenna params
702 dbResults.numRowsGnb = apGnb.nAntRows;
703 dbResults.numColumnsGnb = apGnb.nAntCols;
704 dbResults.numVPortsGnb = apGnb.nVertPorts;
705 dbResults.numHPortsGnb = apGnb.nHorizPorts;
706 dbResults.isXPolGnb = apGnb.isDualPolarized;
707 // ue antenna params
708 dbResults.numRowsUe = apUe.nAntRows;
709 dbResults.numColumnsUe = apUe.nAntCols;
710 dbResults.numVPortsUe = apUe.nVertPorts;
711 dbResults.numHPortsUe = apUe.nHorizPorts;
712 dbResults.isXPolUe = apUe.isDualPolarized;
713 dbResults.schedulerType = scheduler;
714 dbResults.sbPmiUpdateIntervalMs = sbPmiUpdateIntervalMs;
715 dbResults.wbPmiUpdateIntervalMs = wbPmiUpdateIntervalMs;
716 dbResults.enableInterfNode = enableInterfNode;
717 dbResults.csiFlags = csiFlags;
718 dbResults.trafficType = trafficType;
719 dbResults.xyVelocity = xyVelocity;
720
721 // calculate the execution time
722 auto endExecTime = std::chrono::system_clock::now();
723 std::chrono::duration<double> elapsed_seconds = endExecTime - startExecTime;
724 dbResults.execTimeSec = elapsed_seconds.count();
725
726 double averageMcsForAllUes = 0.0;
727 double averageRiForAllUes = 0.0;
728 for (const auto& ue : cqiTraces)
729 {
730 averageRiForAllUes += ue.second.m_ri->getMean();
731 averageMcsForAllUes += ue.second.m_mcs->getMean();
732 }
733
734 if (ueNetDev.GetN() != cqiTraces.size())
735 {
736 NS_LOG_WARN("Not all UEs have generated CQI feedback.");
737 }
738
739 if (!cqiTraces.empty())
740 {
741 dbResults.rank = averageRiForAllUes / cqiTraces.size();
742 dbResults.mcs = averageMcsForAllUes / cqiTraces.size();
743 }
744 else
745 {
746 dbResults.rank = 1;
747 dbResults.mcs = 0;
748 }
749
750 double flowDuration = (simTime - udpAppStartTime).GetSeconds();
751 for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i = stats.begin();
752 i != stats.end();
753 ++i)
754 {
755 Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(i->first);
756 std::stringstream protoStream;
757 protoStream << (uint16_t)t.protocol;
758 if (t.protocol == 6)
759 {
760 protoStream.str("TCP");
761 }
762 if (t.protocol == 17)
763 {
764 protoStream.str("UDP");
765 }
766 outFile << "Flow " << i->first << " (" << t.sourceAddress << ":" << t.sourcePort << " -> "
767 << t.destinationAddress << ":" << t.destinationPort << ") proto "
768 << protoStream.str() << "\n";
769 outFile << " Tx Packets: " << i->second.txPackets << "\n";
770 outFile << " Tx Bytes: " << i->second.txBytes << "\n";
771 outFile << " TxOffered: " << i->second.txBytes * 8.0 / flowDuration / 1000.0 / 1000.0
772 << " Mbps\n";
773 outFile << " Rx Bytes: " << i->second.rxBytes << "\n";
774 if (i->second.rxPackets > 0)
775 {
776 // Measure the duration of the flow from receiver's perspective
777 averageFlowThroughput += i->second.rxBytes * 8.0 / flowDuration / 1000 / 1000;
778 averageFlowDelay += 1000 * i->second.delaySum.GetSeconds() / i->second.rxPackets;
779
780 double thr = i->second.rxBytes * 8.0 / flowDuration / 1000 / 1000;
781 double delay = 1000 * i->second.delaySum.GetSeconds() / i->second.rxPackets;
782 double jitter = 1000 * i->second.jitterSum.GetSeconds() / i->second.rxPackets;
783 double packetLoss = 1 - ((double)(i->second.rxPackets) / (double)i->second.txPackets);
784
785 outFile << " Throughput: " << thr << " Mbps\n";
786 outFile << " Mean delay: " << delay << " ms\n";
787 outFile << " Mean jitter: " << jitter << " ms\n";
788
789 // we want to save to the database only the flow stats from the first flow
790 // from the first gNB-UE pair
791 if (i == stats.begin())
792 {
793 dbResults.throughputMbps = thr;
794 dbResults.delayMs = delay;
795 dbResults.jitterMs = jitter;
796 dbResults.bytesReceived = i->second.rxBytes;
797 dbResults.bytesTransmitted = i->second.txBytes;
798 dbResults.packetLoss = packetLoss;
799 }
800 }
801 else
802 {
803 outFile << " Throughput: 0 Mbps\n";
804 outFile << " Mean delay: 0 ms\n";
805 outFile << " Mean jitter: 0 ms\n";
806 }
807 outFile << " Rx Packets: " << i->second.rxPackets << "\n";
808
809 dbHelper.InsertResults(dbResults);
810 }
811
812 outFile << "\n\n Mean flow throughput: " << averageFlowThroughput / stats.size() << "\n";
813 outFile << " Mean flow delay: " << averageFlowDelay / stats.size() << "\n";
814 outFile << " Mean rank: " << dbResults.rank << "\n";
815 outFile << " Mean MCS: " << dbResults.mcs << "\n";
816
817 outFile.close();
818 std::ifstream f(filename.c_str());
819 if (f.is_open())
820 {
821 std::cout << f.rdbuf();
822 }
823
824 Simulator::Destroy();
825 return 0;
826}
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.
@ 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_LOW_LAT_EMBB
Non-GBR Low Latency eMBB applications.
A helper to make it easier to instantiate an ns3::TrafficGenerator types of applications on a set of ...
void SetAttribute(std::string name, const AttributeValue &value)
ApplicationContainer Install(NodeContainer c) const
std::vector< std::reference_wrapper< BandwidthPartInfoPtr > > BandwidthPartInfoPtrVector
vector of unique_ptr of BandwidthPartInfo
Minimum configuration requirements for a OperationBand.
uint16_t localPortStart
start of the port number range of the UE
Definition nr-epc-tft.h:118
uint16_t localPortEnd
end of the port number range of the UE
Definition nr-epc-tft.h:119
parameters of the gNB or UE antenna arrays
Definition nr-helper.h:854
size_t nAntRows
Number of antenna element rows (vertical height)
Definition nr-helper.h:857
bool isDualPolarized
true if antennas are cross-polarized (dual-polarized)
Definition nr-helper.h:858
double bearingAngle
Bearing angle in radians.
Definition nr-helper.h:861
std::string antennaElem
Antenna type.
Definition nr-helper.h:855
size_t nHorizPorts
Number of antenna ports in horizontal direction.
Definition nr-helper.h:859
size_t nVertPorts
Number of antenna ports in vertical direction.
Definition nr-helper.h:860
size_t nAntCols
Number of antenna element columns (horizontal width)
Definition nr-helper.h:856
double polSlantAngle
Polarization slant angle in radians.
Definition nr-helper.h:862
parameters for the search of optimal rank and precoding matrix indicator (RI, PMI)
Definition nr-helper.h:868
double rankThreshold
Limits the selection of ranks determined by SVD decomposition.
Definition nr-helper.h:873
std::string downsamplingTechnique
Sub-band compression technique.
Definition nr-helper.h:877
uint8_t subbandSize
Number of PRBs per subband for downsampling.
Definition nr-helper.h:876
std::string rankTechnique
Select technique that determines ranks in non-exhaustive search.
Definition nr-helper.h:875
std::string fullSearchCb
Codebook when using full-search algorithm.
Definition nr-helper.h:870
std::string pmSearchMethod
Precoding matrix search algorithm.
Definition nr-helper.h:869
Operation band information structure.