5#include "ns3/basic-data-calculators.h"
6#include "ns3/boolean.h"
9#include "ns3/flow-monitor-helper.h"
10#include "ns3/internet-stack-helper.h"
11#include "ns3/ipv4-flow-classifier.h"
12#include "ns3/ipv4-static-routing-helper.h"
13#include "ns3/mobility-helper.h"
14#include "ns3/nr-amc.h"
15#include "ns3/nr-channel-helper.h"
16#include "ns3/nr-eps-bearer.h"
17#include "ns3/nr-gnb-net-device.h"
18#include "ns3/nr-helper.h"
19#include "ns3/nr-point-to-point-epc-helper.h"
20#include "ns3/nr-ue-net-device.h"
21#include "ns3/nr-ue-phy.h"
22#include "ns3/point-to-point-helper.h"
24#include "ns3/udp-client-server-helper.h"
25#include "ns3/uinteger.h"
41struct CqiFeedbackTraceStats
43 Ptr<MinMaxAvgTotalCalculator<uint8_t>> m_ri;
44 Ptr<MinMaxAvgTotalCalculator<uint8_t>> m_mcs;
46 CqiFeedbackTraceStats()
48 m_ri = CreateObject<MinMaxAvgTotalCalculator<uint8_t>>();
49 m_mcs = CreateObject<MinMaxAvgTotalCalculator<uint8_t>>();
52 CqiFeedbackTraceStats(uint8_t rank, uint8_t mcs)
54 m_ri = CreateObject<MinMaxAvgTotalCalculator<uint8_t>>();
56 m_mcs = CreateObject<MinMaxAvgTotalCalculator<uint8_t>>();
62CqiFeedbackTracedCallback(std::map<uint16_t, CqiFeedbackTraceStats>* stats,
64 [[maybe_unused]] uint8_t cqi,
68 auto it = stats->find(rnti);
69 if (it != stats->end())
71 it->second.m_ri->Update(rank);
72 it->second.m_mcs->Update(mcs);
76 (*stats)[rnti] = CqiFeedbackTraceStats(rank, mcs);
81GetRiPmiTestCaseName(
double distanceGnbUe,
82 std::string riSelectionTechnique,
84 std::string pmiSelectionTechnique)
87 ss << distanceGnbUe <<
"-" << riSelectionTechnique <<
"-" << riThreshold <<
"-"
88 << pmiSelectionTechnique;
93class RiPmiTestCase :
public TestCase
96 RiPmiTestCase(
double distanceGnbUe,
97 std::string riSelectionTechnique,
99 std::string pmiSelectionTechnique,
104 : TestCase(GetRiPmiTestCaseName(distanceGnbUe,
105 riSelectionTechnique,
107 pmiSelectionTechnique)),
108 m_distanceGnbUe(distanceGnbUe),
109 m_riSelectionTechnique(riSelectionTechnique),
110 m_riThreshold(riThreshold),
111 m_pmiSelectionTechnique(pmiSelectionTechnique),
112 m_targetThroughput(throughput),
113 m_targetLatency(latency),
114 m_targetMeanRank(meanRank),
115 m_targetMeanMcs(meanMcs)
120 void DoRun()
override;
121 double m_distanceGnbUe;
122 std::string m_riSelectionTechnique;
123 double m_riThreshold;
124 std::string m_pmiSelectionTechnique;
125 double m_targetThroughput;
126 double m_targetLatency;
127 double m_targetMeanRank;
128 double m_targetMeanMcs;
132RiPmiTestCase::DoRun()
134 NrHelper::AntennaParams apUe;
135 NrHelper::AntennaParams apGnb;
136 apUe.antennaElem =
"ns3::ThreeGppAntennaModel";
139 apUe.nHorizPorts = 2;
141 apUe.isDualPolarized =
true;
142 apGnb.antennaElem =
"ns3::ThreeGppAntennaModel";
145 apGnb.nHorizPorts = 2;
146 apGnb.nVertPorts = 1;
147 apGnb.isDualPolarized =
true;
148 double downtiltAngleGnb = 10;
151 double polSlantAngleGnb = 0.0;
152 double polSlantAngleUe = 0.0;
154 double bearingAngleGnb = 0.0;
155 double bearingAngleUe = 180.0;
158 uint32_t udpPacketSize = 1000;
159 Time packetInterval = NanoSeconds(40000);
160 Time udpAppStartTime = MilliSeconds(400);
163 Time simTime = MilliSeconds(1400);
164 uint16_t numerology = 0;
165 double centralFrequency = 3.5e9;
166 double bandwidth = 10e6;
167 double txPowerGnb = 23;
168 double txPowerUe = 23;
169 uint16_t updatePeriodMs = 100;
170 std::string errorModel =
"ns3::NrEesmIrT2";
171 std::string scheduler =
"ns3::NrMacSchedulerTdmaRR";
172 std::string beamformingMethod =
"ns3::DirectPathBeamforming";
174 uint32_t wbPmiUpdateIntervalMs = 10;
175 uint32_t sbPmiUpdateIntervalMs = 2;
177 NrHelper::MimoPmiParams mimoPmiParams;
178 mimoPmiParams.rankLimit = 4;
179 mimoPmiParams.subbandSize = 4;
180 mimoPmiParams.fullSearchCb =
"ns3::NrCbTypeOneSp";
181 mimoPmiParams.pmSearchMethod = m_pmiSelectionTechnique;
182 if (!m_riSelectionTechnique.empty())
184 mimoPmiParams.rankTechnique = m_riSelectionTechnique;
185 mimoPmiParams.rankThreshold = m_riThreshold;
189 apUe.bearingAngle = bearingAngleUe * (M_PI / 180);
190 apUe.polSlantAngle = polSlantAngleUe * (M_PI / 180);
191 apGnb.bearingAngle = bearingAngleGnb * (M_PI / 180);
192 apGnb.polSlantAngle = polSlantAngleGnb * (M_PI / 180);
194 Config::SetDefault(
"ns3::NrRlcUm::MaxTxBufferSize", UintegerValue(999999999));
195 Config::SetDefault(
"ns3::ThreeGppChannelModel::UpdatePeriod",
196 TimeValue(MilliSeconds(updatePeriodMs)));
198 uint16_t pairsToCreate = 1;
199 NodeContainer gnbContainer;
200 gnbContainer.Create(pairsToCreate);
201 NodeContainer ueContainer;
202 ueContainer.Create(pairsToCreate);
212 MobilityHelper mobility;
213 mobility.SetMobilityModel(
"ns3::ConstantPositionMobilityModel");
214 Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
215 positionAlloc->Add(Vector(0.0, 0.0, 25.0));
216 positionAlloc->Add(Vector(m_distanceGnbUe, 0.0, 1.5));
217 mobility.SetPositionAllocator(positionAlloc);
218 mobility.Install(gnbContainer.Get(0));
219 mobility.Install(ueContainer.Get(0));
224 Ptr<NrPointToPointEpcHelper> epcHelper = CreateObject<NrPointToPointEpcHelper>();
225 Ptr<IdealBeamformingHelper> idealBeamformingHelper = CreateObject<IdealBeamformingHelper>();
226 Ptr<NrHelper> nrHelper = CreateObject<NrHelper>();
227 nrHelper->SetBeamformingHelper(idealBeamformingHelper);
228 nrHelper->SetEpcHelper(epcHelper);
232 Ptr<NrChannelHelper> channelHelper = CreateObject<NrChannelHelper>();
233 channelHelper->ConfigureFactories(
"UMa",
"LOS",
"ThreeGpp");
234 channelHelper->SetPathlossAttribute(
"ShadowingEnabled", BooleanValue(
false));
237 CcBwpCreator ccBwpCreator;
238 const uint8_t numCcPerBand = 1;
239 CcBwpCreator::SimpleOperationBandConf bandConf(centralFrequency, bandwidth, numCcPerBand);
240 OperationBandInfo band = ccBwpCreator.CreateOperationBandContiguousCc(bandConf);
241 channelHelper->AssignChannelsToBands({band});
245 nrHelper->SetDlErrorModel(errorModel);
246 nrHelper->SetUlErrorModel(errorModel);
249 nrHelper->SetSchedulerTypeId(TypeId::LookupByName(scheduler));
250 idealBeamformingHelper->SetAttribute(
"BeamformingMethod",
251 TypeIdValue(TypeId::LookupByName(beamformingMethod)));
253 epcHelper->SetAttribute(
"S1uLinkDelay", TimeValue(MilliSeconds(0)));
255 nrHelper->SetupMimoPmi(mimoPmiParams);
256 nrHelper->SetupGnbAntennas(apGnb);
257 nrHelper->SetGnbAntennaAttribute(
"DowntiltAngle", DoubleValue(downtiltAngleGnb * M_PI / 180.0));
258 nrHelper->SetupUeAntennas(apUe);
260 nrHelper->SetGnbPhyAttribute(
"Numerology", UintegerValue(numerology));
261 nrHelper->SetGnbPhyAttribute(
"TxPower", DoubleValue(txPowerGnb));
262 nrHelper->SetUePhyAttribute(
"TxPower", DoubleValue(txPowerUe));
263 nrHelper->SetUePhyAttribute(
"WbPmiUpdateInterval",
264 TimeValue(MilliSeconds(wbPmiUpdateIntervalMs)));
265 nrHelper->SetUePhyAttribute(
"SbPmiUpdateInterval",
266 TimeValue(MilliSeconds(sbPmiUpdateIntervalMs)));
270 nrHelper->SetGnbBwpManagerAlgorithmAttribute(
"NGBR_LOW_LAT_EMBB", UintegerValue(bwpId));
272 nrHelper->SetUeBwpManagerAlgorithmAttribute(
"NGBR_LOW_LAT_EMBB", UintegerValue(bwpId));
282 NetDeviceContainer enbNetDev = nrHelper->InstallGnbDevice(gnbContainer, allBwps);
283 NetDeviceContainer ueNetDev = nrHelper->InstallUeDevice(ueContainer, allBwps);
285 int64_t randomStream = 1;
286 randomStream += nrHelper->AssignStreams(enbNetDev, randomStream);
287 randomStream += nrHelper->AssignStreams(ueNetDev, randomStream);
289 std::map<uint16_t, CqiFeedbackTraceStats> cqiTraces;
290 for (
auto it = ueNetDev.Begin(); it != ueNetDev.End(); ++it)
292 auto cqiCb = MakeBoundCallback(&CqiFeedbackTracedCallback, &cqiTraces);
293 nrHelper->GetUePhy(*it, 0)->TraceConnectWithoutContext(
"CqiFeedbackTrace", cqiCb);
298 auto [remoteHost, remoteHostIpv4Address] =
299 epcHelper->SetupRemoteHost(
"100Gb/s", 2500, Seconds(0.000));
301 InternetStackHelper internet;
302 Ipv4InterfaceContainer ueIpIface;
303 internet.Install(ueContainer);
304 ueIpIface = epcHelper->AssignUeIpv4Address(NetDeviceContainer(ueNetDev));
307 nrHelper->AttachToGnb(ueNetDev.Get(0), enbNetDev.Get(0));
311 uint16_t dlPort = 1234;
312 ApplicationContainer serverApps;
314 UdpServerHelper dlPacketSink(dlPort);
316 serverApps.Add(dlPacketSink.Install(ueContainer));
321 UdpClientHelper dlClient;
322 dlClient.SetAttribute(
"MaxPackets", UintegerValue(0xFFFFFFFF));
323 dlClient.SetAttribute(
"PacketSize", UintegerValue(udpPacketSize));
324 dlClient.SetAttribute(
"Interval", TimeValue(packetInterval));
330 Ptr<NrEpcTft> dlTft = Create<NrEpcTft>();
331 NrEpcTft::PacketFilter dlPktFilter;
332 dlPktFilter.localPortStart = dlPort;
333 dlPktFilter.localPortEnd = dlPort;
334 dlTft->Add(dlPktFilter);
339 ApplicationContainer clientApps;
341 for (uint32_t i = 0; i < ueContainer.GetN(); ++i)
343 Ptr<Node> ue = ueContainer.Get(i);
344 Ptr<NetDevice> ueDevice = ueNetDev.Get(i);
345 Address ueAddress = ueIpIface.GetAddress(i);
349 dlClient.SetAttribute(
352 InetSocketAddress(Ipv4Address::ConvertFrom(ueAddress), dlPort).ConvertTo()));
353 clientApps.Add(dlClient.Install(remoteHost));
356 nrHelper->ActivateDedicatedEpsBearer(ueDevice, epsBearer, dlTft);
360 serverApps.Start(udpAppStartTime);
361 clientApps.Start(udpAppStartTime);
362 serverApps.Stop(simTime);
363 clientApps.Stop(simTime);
366 nrHelper->EnableTraces();
368 FlowMonitorHelper flowmonHelper;
369 NodeContainer endpointNodes;
370 endpointNodes.Add(remoteHost);
371 endpointNodes.Add(ueContainer);
373 Ptr<ns3::FlowMonitor> monitor = flowmonHelper.Install(endpointNodes);
374 monitor->SetAttribute(
"DelayBinWidth", DoubleValue(0.001));
375 monitor->SetAttribute(
"JitterBinWidth", DoubleValue(0.001));
376 monitor->SetAttribute(
"PacketSizeBinWidth", DoubleValue(20));
378 Simulator::Stop(simTime);
382 monitor->CheckForLostPackets();
383 Ptr<Ipv4FlowClassifier> classifier =
384 DynamicCast<Ipv4FlowClassifier>(flowmonHelper.GetClassifier());
385 FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats();
387 double averageFlowThroughput = 0.0;
388 double averageFlowDelay = 0.0;
389 double averageMcsForAllUes = 0.0;
390 double averageRiForAllUes = 0.0;
391 for (
const auto& ue : cqiTraces)
393 averageRiForAllUes += ue.second.m_ri->getMean();
394 averageMcsForAllUes += ue.second.m_mcs->getMean();
397 NS_TEST_ASSERT_MSG_EQ(ueNetDev.GetN(),
399 "Not all UEs have generated CQI feedback.");
401 double flowDuration = (simTime - udpAppStartTime).GetSeconds();
402 for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i = stats.begin();
406 if (i->second.rxPackets > 0)
409 averageFlowThroughput += i->second.rxBytes * 8.0 / flowDuration / 1000 / 1000;
410 averageFlowDelay += 1000 * i->second.delaySum.GetSeconds() / i->second.rxPackets;
415 NS_TEST_EXPECT_MSG_EQ_TOL(averageFlowThroughput,
417 m_targetThroughput * 0.05,
418 "Throughput is out of the expected range");
419 NS_TEST_EXPECT_MSG_EQ_TOL(averageFlowDelay,
421 m_targetLatency * 0.05,
422 "Delay is out of the expected range");
423 NS_TEST_EXPECT_MSG_EQ_TOL(averageRiForAllUes,
425 m_targetMeanRank * 0.05,
426 "Rank is out of the expected range");
427 NS_TEST_EXPECT_MSG_EQ_TOL(averageMcsForAllUes,
429 m_targetMeanMcs * 0.05,
430 "MCS is out of the expected range");
432 Simulator::Destroy();
436class TestRiPmiSystem :
public TestSuite
440 : TestSuite(
"nr-test-ri-pmi-system", Type::SYSTEM)
446 AddTestCase(
new RiPmiTestCase( 20,
"", 0.0,
"ns3::NrPmSearchFull", 133.0, 150.0, 3.1, 25.0), Duration::QUICK);
447 AddTestCase(
new RiPmiTestCase(500,
"", 0.0,
"ns3::NrPmSearchFull", 104.0, 243.7, 2.3, 26.6), Duration::QUICK);
448 AddTestCase(
new RiPmiTestCase( 20,
"", 0.0,
"ns3::NrPmSearchIdeal", 154.0, 71.4, 3.5, 25.3), Duration::QUICK);
449 AddTestCase(
new RiPmiTestCase(500,
"", 0.0,
"ns3::NrPmSearchIdeal", 106.2, 205.4, 2.9, 24.0), Duration::QUICK);
450 AddTestCase(
new RiPmiTestCase( 20,
"SVD", 0.0,
"ns3::NrPmSearchFast", 114.4, 165.9, 4.0, 17.0), Duration::QUICK);
451 AddTestCase(
new RiPmiTestCase( 20,
"SVD", 0.5,
"ns3::NrPmSearchFast", 86.1, 291.1, 1.7, 27.0), Duration::EXTENSIVE);
452 AddTestCase(
new RiPmiTestCase( 20,
"SVD", 0.9,
"ns3::NrPmSearchFast", 51.0, 376.5, 1.0, 27.0), Duration::EXTENSIVE);
453 AddTestCase(
new RiPmiTestCase(500,
"SVD", 0.0,
"ns3::NrPmSearchFast", 62.4, 284.4, 4.0, 9.6), Duration::QUICK);
454 AddTestCase(
new RiPmiTestCase(500,
"SVD", 0.5,
"ns3::NrPmSearchFast", 96.9, 250.8, 1.9, 27.0), Duration::EXTENSIVE);
455 AddTestCase(
new RiPmiTestCase(500,
"SVD", 0.9,
"ns3::NrPmSearchFast", 53.0, 400.3, 1.1, 27.0), Duration::EXTENSIVE);
456 AddTestCase(
new RiPmiTestCase( 20,
"WaterFilling", 10.0,
"ns3::NrPmSearchFast", 126.4, 157.6, 3.6, 20.5), Duration::QUICK);
457 AddTestCase(
new RiPmiTestCase( 20,
"WaterFilling", 50.0,
"ns3::NrPmSearchFast", 128.2, 156.9, 3.3, 23.0), Duration::EXTENSIVE);
458 AddTestCase(
new RiPmiTestCase( 20,
"WaterFilling", 75.0,
"ns3::NrPmSearchFast", 129.5, 155.7, 3.1, 24.5), Duration::EXTENSIVE);
459 AddTestCase(
new RiPmiTestCase( 20,
"WaterFilling", 90.0,
"ns3::NrPmSearchFast", 129.5, 155.7, 3.1, 24.5), Duration::EXTENSIVE);
460 AddTestCase(
new RiPmiTestCase(500,
"WaterFilling", 10.0,
"ns3::NrPmSearchFast", 92.0, 282.9, 3.1, 18.5), Duration::QUICK);
461 AddTestCase(
new RiPmiTestCase(500,
"WaterFilling", 50.0,
"ns3::NrPmSearchFast", 99.8, 268.1, 2.3, 24.7), Duration::QUICK);
462 AddTestCase(
new RiPmiTestCase(500,
"WaterFilling", 75.0,
"ns3::NrPmSearchFast", 101.8, 260.8, 2.2, 27.0), Duration::EXTENSIVE);
463 AddTestCase(
new RiPmiTestCase(500,
"WaterFilling", 90.0,
"ns3::NrPmSearchFast", 101.8, 260.8, 2.2, 27.0), Duration::EXTENSIVE);
464 AddTestCase(
new RiPmiTestCase( 20,
"Sasaoka", 0.0,
"ns3::NrPmSearchFast", 124.3, 170.3, 3.1, 23.0), Duration::QUICK);
465 AddTestCase(
new RiPmiTestCase( 20,
"Sasaoka", 0.0,
"ns3::NrPmSearchSasaoka", 117.6, 153.9, 3.1, 23.0), Duration::QUICK);
466 AddTestCase(
new RiPmiTestCase(500,
"Sasaoka", 0.0,
"ns3::NrPmSearchFast", 75.9, 299.2, 3.1, 15.0), Duration::QUICK);
467 AddTestCase(
new RiPmiTestCase(500,
"Sasaoka", 0.0,
"ns3::NrPmSearchSasaoka", 76.5, 301.5, 3.1, 15.0), Duration::QUICK);
471 AddTestCase(
new RiPmiTestCase( 20,
"", 0.0,
"ns3::NrPmSearchMaleki", 120.2, 169.8, 2.6, 27.0), Duration::QUICK);
472 AddTestCase(
new RiPmiTestCase(500,
"", 0.0,
"ns3::NrPmSearchMaleki", 104.9, 242.7, 2.2, 27.0), Duration::QUICK);
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)
@ NGBR_LOW_LAT_EMBB
Non-GBR Low Latency eMBB applications.
std::vector< std::reference_wrapper< BandwidthPartInfoPtr > > BandwidthPartInfoPtrVector
vector of unique_ptr of BandwidthPartInfo
static TestRiPmiSystem g_testRiPmiSystem
RI/PMI system tests.