5G-LENA nr-v3.1-69-g2dd513a7
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-radio-environment-map-helper.cc
1// Copyright (c) 2020 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4
5#include "nr-radio-environment-map-helper.h"
6
7#include "nr-spectrum-value-helper.h"
8
9#include <ns3/abort.h>
10#include <ns3/beamforming-vector.h>
11#include <ns3/buildings-module.h>
12#include <ns3/config.h>
13#include <ns3/double.h>
14#include <ns3/enum.h>
15#include <ns3/log.h>
16#include <ns3/mobility-model.h>
17#include <ns3/node.h>
18#include <ns3/nr-gnb-net-device.h>
19#include <ns3/nr-spectrum-phy.h>
20#include <ns3/nr-ue-net-device.h>
21#include <ns3/pointer.h>
22#include <ns3/simulator.h>
23#include <ns3/spectrum-converter.h>
24#include <ns3/string.h>
25#include <ns3/uinteger.h>
26
27#include <fstream>
28#include <limits>
29
30namespace ns3
31{
32
33NS_LOG_COMPONENT_DEFINE("NrRadioEnvironmentMapHelper");
34
35NS_OBJECT_ENSURE_REGISTERED(NrRadioEnvironmentMapHelper);
36
41
45
46void
47NrRadioEnvironmentMapHelper::DoDispose()
48{
49 NS_LOG_FUNCTION(this);
50}
51
52TypeId
54{
55 NS_LOG_FUNCTION("NrRadioEnvironmentMapHelper::GetTypeId");
56 static TypeId tid =
57 TypeId("ns3::NrRadioEnvironmentMapHelper")
58 .SetParent<Object>()
59 .SetGroupName("Nr")
60 .AddConstructor<NrRadioEnvironmentMapHelper>()
61 .AddAttribute("SimTag",
62 "simulation tag that will be concatenated to output file names"
63 "in order to distinguish them, for example: nr-rem-${SimTag}.out. "
64 "nr-rem-${SimTag}-ues.txt, nr-rem-${SimTag}-gnbs.txt, "
65 "nr-rem-${SimTag}-buildings.txt.",
66 StringValue(""),
67 MakeStringAccessor(&NrRadioEnvironmentMapHelper::SetSimTag),
68 MakeStringChecker())
69 .AddAttribute("XMin",
70 "The min x coordinate of the map.",
71 DoubleValue(0.0),
72 MakeDoubleAccessor(&NrRadioEnvironmentMapHelper::SetMinX,
74 MakeDoubleChecker<double>())
75 .AddAttribute("YMin",
76 "The min y coordinate of the map.",
77 DoubleValue(0.0),
78 MakeDoubleAccessor(&NrRadioEnvironmentMapHelper::SetMinY,
80 MakeDoubleChecker<double>())
81 .AddAttribute("XMax",
82 "The max x coordinate of the map.",
83 DoubleValue(0.0),
84 MakeDoubleAccessor(&NrRadioEnvironmentMapHelper::SetMaxX,
86 MakeDoubleChecker<double>())
87 .AddAttribute("YMax",
88 "The max y coordinate of the map.",
89 DoubleValue(0.0),
90 MakeDoubleAccessor(&NrRadioEnvironmentMapHelper::SetMaxY,
92 MakeDoubleChecker<double>())
93 .AddAttribute("XRes",
94 "The resolution (number of points) of the"
95 "map along the x axis.",
96 UintegerValue(100),
97 MakeUintegerAccessor(&NrRadioEnvironmentMapHelper::SetResX,
99 MakeUintegerChecker<uint32_t>(2, std::numeric_limits<uint16_t>::max()))
100 .AddAttribute("YRes",
101 "The resolution (number of points) of the"
102 "map along the y axis.",
103 UintegerValue(100),
104 MakeUintegerAccessor(&NrRadioEnvironmentMapHelper::SetResY,
106 MakeUintegerChecker<uint16_t>(2, std::numeric_limits<uint16_t>::max()))
107 .AddAttribute("Z",
108 "The value of the z coordinate for which"
109 "the map is to be generated.",
110 DoubleValue(1.5),
111 MakeDoubleAccessor(&NrRadioEnvironmentMapHelper::SetZ,
113 MakeDoubleChecker<double>())
114 .AddAttribute("IterForAverage",
115 "Number of iterations for the calculation"
116 "of the average rem value.",
117 UintegerValue(1),
119 //&NrRadioEnvironmentMapHelper::GetMaxPointsPerIt),
120 MakeUintegerChecker<uint16_t>())
121 .AddAttribute(
122 "RemMode",
123 "There are three high level modes of Rem generation: "
124 "a) BEAM_SHAPE in which are represented the beams that are configured "
125 "in the user's script scenario, considering that the receiver always "
126 "has quasi-omni, and that all the beams point toward the UE which is "
127 "passed as UE of interest. The purpose of this map is to illustrate "
128 "the REM of the scenario that is configured."
129 "b) COVERAGE_AREA which produces two REM maps: the worst-case SINR and "
130 "best-SNR for each rem position; Worst case SINR means that all interfering "
131 "devices use for the transmission the beam towards the rem point;"
132 "and also for the best-SNR, for each transmitting device and the REM point "
133 "are used the best directional beam-pair and then is selected the best SNR."
134 "c) UE_COVERAGE which is similar as the above, although the Tx Device"
135 "is the UE (UL direction), and the Rx device is each gNB to which it is "
136 "connected each time, while the rest of gNBs (if they are present) are"
137 "pointing their beams towards the Rx gNB. In case of TDD, the SINR map"
138 "will show the interference caused by the DL of these gNBs.",
139 EnumValue(NrRadioEnvironmentMapHelper::COVERAGE_AREA),
140 MakeEnumAccessor<RemMode>(&NrRadioEnvironmentMapHelper::SetRemMode,
142 MakeEnumChecker(NrRadioEnvironmentMapHelper::BEAM_SHAPE,
143 "BeamShape",
144 NrRadioEnvironmentMapHelper::COVERAGE_AREA,
145 "CoverageArea",
146 NrRadioEnvironmentMapHelper::UE_COVERAGE,
147 "UeCoverageArea"))
148 .AddAttribute(
149 "InstallationDelay",
150 "How many time it is needed in the simulation to configure phy parameters at UE, "
151 "depends on RRC message timing.",
152 TimeValue(MilliSeconds(100)),
154 MakeTimeChecker());
155 return tid;
156}
157
158void
160{
161 m_remMode = remMode;
162}
163
164void
166{
167 m_simTag = simTag;
168}
169
170void
172{
173 m_xMin = xMin;
174}
175
176void
178{
179 m_yMin = yMin;
180}
181
182void
184{
185 m_xMax = xMax;
186}
187
188void
190{
191 m_yMax = yMax;
192}
193
194void
196{
197 m_xRes = xRes;
198}
199
200void
202{
203 m_yRes = yRes;
204}
205
206void
208{
209 m_z = z;
210}
211
212void
213NrRadioEnvironmentMapHelper::SetNumOfItToAverage(uint16_t numOfIterationsToAverage)
214{
215 m_numOfIterationsToAverage = numOfIterationsToAverage;
216}
217
218void
220{
221 m_installationDelay = installationDelay;
222}
223
224NrRadioEnvironmentMapHelper::RemMode
226{
227 return m_remMode;
228}
229
230double
232{
233 return m_xMin;
234}
235
236double
238{
239 return m_yMin;
240}
241
242double
244{
245 return m_xMax;
246}
247
248double
250{
251 return m_yMax;
252}
253
254uint16_t
256{
257 return m_xRes;
258}
259
260uint16_t
262{
263 return m_yRes;
264}
265
266double
268{
269 return m_z;
270}
271
272double
274{
275 return std::pow(10.0, 0.1 * (dBm - 30.0));
276}
277
278double
280{
281 return 10.0 * std::log10(w) + 30.0;
282}
283
284double
286{
287 return std::pow(10.0, 0.1 * dB);
288}
289
290double
292{
293 return 10.0 * std::log10(ratio);
294}
295
296void
297NrRadioEnvironmentMapHelper::ConfigureRrd(const Ptr<NetDevice>& rrdDevice)
298{
299 NS_LOG_FUNCTION(this);
300 // RTD and RRD devices should have the same spectrum model to perform calculation,
301 // if some of the RTD devices is of the different model then its transmission will have to
302 // converted into spectrum model of this device
303 m_rrd.spectrumModel = m_rrdPhy->GetSpectrumModel();
304 m_rrd.mob->SetPosition(rrdDevice->GetNode()->GetObject<MobilityModel>()->GetPosition());
305
306 std::ostringstream oss;
307 oss << "nr-rem-" << m_simTag.c_str() << "-ues.txt";
308 PrintGnuplottableUeListToFile(oss.str());
309
310 Ptr<MobilityBuildingInfo> buildingInfo = CreateObject<MobilityBuildingInfo>();
311 m_rrd.mob->AggregateObject(buildingInfo);
312
313 m_rrd.antenna = m_deviceToAntenna.find(rrdDevice)->second;
314
315 m_noisePsd = NrSpectrumValueHelper::CreateNoisePowerSpectralDensity(m_rrdPhy->GetNoiseFigure(),
316 m_rrd.spectrumModel);
317
318 ConfigurePropagationModelsFactories(
319 m_rrdPhy); // we can call only once configuration of prop.models
320}
321
322void
323NrRadioEnvironmentMapHelper::ConfigureRtdList(const NetDeviceContainer& rtdDevs)
324{
325 NS_LOG_FUNCTION(this);
326
327 for (NetDeviceContainer::Iterator netDevIt = rtdDevs.Begin(); netDevIt != rtdDevs.End();
328 ++netDevIt)
329 {
330 Ptr<NrPhy> rtdPhy = m_rtdDeviceToPhy.find(*netDevIt)->second;
331 if (rtdPhy->GetSpectrumModel() != m_rrd.spectrumModel)
332 {
333 if (rtdPhy->GetSpectrumModel()->IsOrthogonal(*m_rrd.spectrumModel))
334 {
335 NS_LOG_WARN("RTD device is configured to operate on a spectrum "
336 "that is orthogonal to the one of RRD device. Hence, "
337 "that RTD device will not be considered in the "
338 "calculation of this REM map.");
339 continue;
340 }
341 else
342 {
343 NS_LOG_WARN("RTD device with different spectrum model, this may slow "
344 "down significantly the REM map creation. Consider setting "
345 "the same frequency, bandwidth, and numerology to all "
346 "devices which are used for REM map creation.");
347 }
348 };
349
350 RemDevice rtd;
351 // Configure spectrum model which will be needed to create tx PSD
352 rtd.spectrumModel = rtdPhy->GetSpectrumModel();
353 rtd.mob->SetPosition((*netDevIt)->GetNode()->GetObject<MobilityModel>()->GetPosition());
354 Ptr<MobilityBuildingInfo> buildingInfo = CreateObject<MobilityBuildingInfo>();
355 rtd.mob->AggregateObject(buildingInfo);
356
357 rtd.antenna = m_deviceToAntenna.find(*netDevIt)->second;
358
359 rtd.txPower = rtdPhy->GetTxPower();
360
361 NS_LOG_DEBUG("power of UE: " << rtd.txPower);
362
363 NS_LOG_INFO("RTD spectrum model: "
364 << rtd.spectrumModel->GetUid() << ", RTD number of bands: "
365 << rtd.spectrumModel->GetNumBands() << ", create new RTD element... "
366 << ", rtdPhy->GetCentralFrequency () " << rtdPhy->GetCentralFrequency() / 1e6
367 << " MHz " <<
368 //", BW: " << rtdPhy->GetChannelBandwidth () / 1e6 << " MHz " <<
369 ", num: " << rtdPhy->GetNumerology());
370
371 m_remDev.push_back(rtd);
372 }
373 NS_ASSERT_MSG(!m_remDev.empty(),
374 "No RTD devices configured. Check if the RTD "
375 "devices are on the operating on the same "
376 "spectrum as RRD device.");
377}
378
379void
380NrRadioEnvironmentMapHelper::ConfigurePropagationModelsFactories(const Ptr<const NrPhy>& rtdPhy)
381{
382 NS_LOG_FUNCTION(this);
383 Ptr<const NrSpectrumPhy> txSpectrumPhy = rtdPhy->GetSpectrumPhy();
384 Ptr<SpectrumChannel> txSpectrumChannel = txSpectrumPhy->GetSpectrumChannel();
385
386 /***** configure pathloss model factory *****/
387 m_propagationLossModel = txSpectrumChannel->GetPropagationLossModel();
388 /***** configure spectrum model factory *****/
389 m_phasedArraySpectrumLossModel =
390 txSpectrumChannel->GetPhasedArraySpectrumPropagationLossModel();
391
392 /***** configure ChannelConditionModel factory if ThreeGppPropagationLossModel propagation model
393 * is being used ****/
394 Ptr<ThreeGppPropagationLossModel> propagationLossModel =
395 DynamicCast<ThreeGppPropagationLossModel>(txSpectrumChannel->GetPropagationLossModel());
396 if (propagationLossModel)
397 {
398 Ptr<ChannelConditionModel> channelConditionModel =
399 propagationLossModel->GetChannelConditionModel();
400 if (channelConditionModel)
401 {
402 m_channelConditionModelFactory = ConfigureObjectFactory(channelConditionModel);
403 }
404 else
405 {
406 NS_FATAL_ERROR(
407 "ThreeGppPropagationLossModel does not have configured ChannelConditionModel");
408 }
409 }
410 else
411 {
412 NS_LOG_WARN("RemHelper currently only knows that ThreeGppPropagationLossModel can have "
413 "ChannelConditionModel. Other models do not support it yet.");
414 }
415
416 /***** configure ThreeGppChannelModel (MatrixBasedChannelModel) factory if spectrumLossModel is
417 * ThreeGppSpectrumPropagationLossModel *****/
418 Ptr<ThreeGppSpectrumPropagationLossModel> spectrumLossModel =
419 DynamicCast<ThreeGppSpectrumPropagationLossModel>(
420 txSpectrumChannel->GetPhasedArraySpectrumPropagationLossModel());
421 if (spectrumLossModel)
422 {
423 if (spectrumLossModel->GetChannelModel())
424 {
425 m_matrixBasedChannelModelFactory =
426 ConfigureObjectFactory(spectrumLossModel->GetChannelModel());
427 }
428 else
429 {
430 NS_FATAL_ERROR("ThreeGppSpectrumPropagationLossModel does not have configured "
431 "MatrixBasedChannelModel");
432 }
433 }
434 else
435 {
436 NS_LOG_WARN("RemHelper currently only knows that ThreeGppSpectrumPropagationLossModel can "
437 "have MatrixBasedChannelModel. Other models do not support it yet.");
438 }
439}
440
441ObjectFactory
442NrRadioEnvironmentMapHelper::ConfigureObjectFactory(const Ptr<Object>& object) const
443{
444 NS_LOG_FUNCTION(this);
445 ObjectFactory objectFactory;
446 TypeId tid = object->GetInstanceTypeId();
447 objectFactory.SetTypeId(object->GetInstanceTypeId());
448
449 NS_LOG_DEBUG("Configure object factory for:" << tid.GetName());
450
451 bool hasParent = false;
452 do
453 {
454 for (size_t i = 0; i < tid.GetAttributeN(); i++)
455 {
456 ns3::TypeId::AttributeInformation attributeInfo = tid.GetAttribute(i);
457
458 if (attributeInfo.checker->GetValueTypeName() == "ns3::PointerValue")
459 {
460 if (attributeInfo.name == "ChannelConditionModel")
461 {
462 NS_LOG_INFO("Skipping to copy ChannelConditionModel."
463 "According to REM design it should be created "
464 "as a new object (not copied).");
465 }
466 else if (attributeInfo.name == "ChannelModel")
467 {
468 NS_LOG_INFO("Skipping to copy ChannelModel."
469 "According to REM design it should be created "
470 "as a new object (not copied).");
471 }
472 else
473 {
474 NS_LOG_WARN("This factory has a PointerValue attribute that "
475 "is not compatible with this REM helper version.");
476 }
477 continue;
478 }
479
480 // create initial attribute value to store attribute
481 Ptr<AttributeValue> attributeValue = attributeInfo.checker->Create();
482 // get the attribute value from the object
483 object->GetAttribute(attributeInfo.name, *attributeValue);
484 // skip pointer value attributes and warn if there is some new unexpceted attribute
485 objectFactory.Set(attributeInfo.name, *attributeValue);
486 // log current attribute name and value
487 NS_LOG_DEBUG("Copy attribute: "
488 << attributeInfo.name
489 << " value:" << attributeValue->SerializeToString(attributeInfo.checker));
490 }
491
492 if (tid.HasParent())
493 {
494 tid = tid.GetParent();
495 hasParent = true;
496 }
497 else
498 {
499 hasParent = false;
500 }
501 } while (hasParent);
502 return objectFactory;
503}
504
505void
506NrRadioEnvironmentMapHelper::CreateRem(const NetDeviceContainer& rtdNetDev,
507 const Ptr<NetDevice>& rrdDevice,
508 uint8_t bwpId)
509{
510 NS_LOG_FUNCTION(this);
511
512 for (NetDeviceContainer::Iterator netDevIt = rtdNetDev.Begin(); netDevIt != rtdNetDev.End();
513 ++netDevIt)
514 {
515 Ptr<NrGnbNetDevice> gnbRtdNetDevice = DynamicCast<NrGnbNetDevice>(*netDevIt);
516 Ptr<NrUeNetDevice> ueRtdNetDevice = DynamicCast<NrUeNetDevice>(*netDevIt);
517
518 if (gnbRtdNetDevice)
519 {
520 std::cout << "gnb is RTD (transmitter)" << std::endl;
521 m_rtdDeviceToPhy.insert(
522 std::make_pair(*netDevIt, (*netDevIt)->GetObject<NrGnbNetDevice>()->GetPhy(bwpId)));
523 }
524 else if (ueRtdNetDevice)
525 {
526 std::cout << "ue is RTD (transmitter)" << std::endl;
527 m_rtdDeviceToPhy.insert(
528 std::make_pair(*netDevIt, (*netDevIt)->GetObject<NrUeNetDevice>()->GetPhy(bwpId)));
529 }
530 else
531 {
532 NS_FATAL_ERROR("no RTD device!");
533 }
534 }
535
536 Ptr<NrGnbNetDevice> gnbRrdNetDevice = DynamicCast<NrGnbNetDevice>(rrdDevice);
537 Ptr<NrUeNetDevice> ueRrdNetDevice = DynamicCast<NrUeNetDevice>(rrdDevice);
538
539 if (gnbRrdNetDevice)
540 {
541 std::cout << "gnb is RRD (receiver)" << std::endl;
542 m_rrdPhy = (rrdDevice)->GetObject<NrGnbNetDevice>()->GetPhy(bwpId);
543 }
544 else if (ueRrdNetDevice)
545 {
546 std::cout << "ue is RRD (receiver)" << std::endl;
547 m_rrdPhy = (rrdDevice)->GetObject<NrUeNetDevice>()->GetPhy(bwpId);
548 }
549 else
550 {
551 NS_FATAL_ERROR("no RRD device!");
552 }
553
554 // save user defined beams, it is like a snapshot, because later during
555 // simulation they might change, and for the BEAM_SHAPE type of map
556 // is necessary to have a specific snapshot of beams for each device
557
558 // since we have delayed install maybe beamforming vector has changed in the RTD device
559 // we want to save beamforming vector toward UE in the case that we will
560 // need it for BEAM_SHAPE calculation
561 SaveAntennasWithUserDefinedBeams(rtdNetDev, rrdDevice);
562
563 Simulator::Schedule(m_installationDelay,
564 &NrRadioEnvironmentMapHelper::DelayedInstall,
565 this,
566 rtdNetDev,
567 rrdDevice);
568}
569
570void
571NrRadioEnvironmentMapHelper::SaveAntennasWithUserDefinedBeams(const NetDeviceContainer& rtdNetDev,
572 const Ptr<NetDevice>& rrdDevice)
573{
574 m_deviceToAntenna.insert(std::make_pair(
575 rrdDevice,
576 Copy(m_rrdPhy->GetSpectrumPhy()->GetAntenna()->GetObject<UniformPlanarArray>())));
577 for (NetDeviceContainer::Iterator rtdNetDevIt = rtdNetDev.Begin();
578 rtdNetDevIt != rtdNetDev.End();
579 ++rtdNetDevIt)
580 {
581 Ptr<NrPhy> rtdPhy = m_rtdDeviceToPhy.find(*rtdNetDevIt)->second;
582 m_deviceToAntenna.insert(std::make_pair(
583 *rtdNetDevIt,
584 Copy(rtdPhy->GetSpectrumPhy()->GetAntenna()->GetObject<UniformPlanarArray>())));
585 }
586}
587
588void
589NrRadioEnvironmentMapHelper::DelayedInstall(const NetDeviceContainer& rtdNetDev,
590 const Ptr<NetDevice>& rrdDevice)
591{
592 NS_LOG_FUNCTION(this);
593 // Save REM creation start time
594 m_remStartTime = std::chrono::system_clock::now();
595
596 ConfigureRrd(rrdDevice);
597 ConfigureRtdList(rtdNetDev);
598 CreateListOfRemPoints();
599 if (m_remMode == COVERAGE_AREA)
600 {
601 CalcCoverageAreaRemMap();
602 }
603 else if (m_remMode == BEAM_SHAPE)
604 {
605 CalcBeamShapeRemMap();
606 }
607 else if (m_remMode == UE_COVERAGE)
608 {
609 CalcUeCoverageRemMap();
610 }
611 else
612 {
613 NS_FATAL_ERROR("Unknown REM mode");
614 }
615 PrintRemToFile();
616
617 std::ostringstream ossGnbs;
618 ossGnbs << "nr-rem-" << m_simTag.c_str() << "-gnbs.txt";
619 PrintGnuplottableGnbListToFile(ossGnbs.str());
620 std::ostringstream ossBuildings;
621 ossBuildings << "nr-rem-" << m_simTag.c_str() << "-buildings.txt";
622 PrintGnuplottableBuildingListToFile(ossBuildings.str());
623}
624
625void
626NrRadioEnvironmentMapHelper::CreateListOfRemPoints()
627{
628 NS_LOG_FUNCTION(this);
629
630 // Create the list of the REM Points
631
632 m_xStep = (m_xMax - m_xMin) / (m_xRes);
633 m_yStep = (m_yMax - m_yMin) / (m_yRes);
634
635 NS_ASSERT_MSG(m_xMax > m_xMin, "xMax must be higher than xMin");
636 NS_ASSERT_MSG(m_yMax > m_yMin, "yMax must be higher than yMin");
637 NS_ASSERT_MSG(m_xRes != 0 || m_yRes != 0, "Resolution must be higher than 0");
638
639 NS_LOG_INFO("m_xStep: " << m_xStep << " m_yStep: " << m_yStep);
640
641 for (double x = m_xMin; x < m_xMax + 0.5 * m_xStep; x += m_xStep)
642 {
643 for (double y = m_yMin; y < m_yMax + 0.5 * m_yStep; y += m_yStep)
644 {
645 // In case a REM Point is in the same position as a rtd, ignore this point
646 bool isPositionRtd = false;
647 for (auto& itRtd : m_remDev)
648 {
649 if (itRtd.mob->GetPosition() == Vector(x, y, m_z))
650 {
651 isPositionRtd = true;
652 }
653 }
654
655 if (!isPositionRtd)
656 {
657 RemPoint remPoint;
658
659 remPoint.pos.x = x;
660 remPoint.pos.y = y;
661 remPoint.pos.z = m_z;
662
663 m_rem.push_back(remPoint);
664 }
665 }
666 }
667}
668
669void
670NrRadioEnvironmentMapHelper::ConfigureQuasiOmniBfv(RemDevice& device)
671{
672 NS_LOG_FUNCTION(this);
673 // configure beam on rrd antenna to be quasi-omni
674 UintegerValue numRows;
675 UintegerValue numColumns;
676 device.antenna->GetAttribute("NumRows", numRows);
677 device.antenna->GetAttribute("NumColumns", numColumns);
678 // configure RRD antenna to have quasi omni beamforming vector
679 device.antenna->SetBeamformingVector(CreateQuasiOmniBfv(device.antenna));
680}
681
682void
683NrRadioEnvironmentMapHelper::ConfigureDirectPathBfv(RemDevice& device,
684 const RemDevice& otherDevice,
685 const Ptr<const UniformPlanarArray>& antenna)
686{
687 NS_LOG_FUNCTION(this);
688 device.antenna->SetBeamformingVector(CreateDirectPathBfv(device.mob, otherDevice.mob, antenna));
689}
690
691Ptr<SpectrumValue>
692NrRadioEnvironmentMapHelper::CalcRxPsdValue(RemDevice& device, RemDevice& otherDevice) const
693{
694 PropagationModels tempPropModels = CreateTemporalPropagationModels();
695
696 std::vector<int> activeRbs;
697 for (size_t rbId = 0; rbId < device.spectrumModel->GetNumBands(); rbId++)
698 {
699 activeRbs.push_back(rbId);
700 }
701
702 Ptr<const SpectrumValue> txPsd = NrSpectrumValueHelper::CreateTxPowerSpectralDensity(
703 device.txPower,
704 activeRbs,
705 device.spectrumModel,
706 NrSpectrumValueHelper::UNIFORM_POWER_ALLOCATION_BW);
707
708 // check if RTD has the same spectrum model as RRD
709 // if they have do nothing, if they dont, then convert txPsd of RTD device so to be according to
710 // spectrum model of RRD
711
712 Ptr<const SpectrumValue> convertedTxPsd;
713 if (device.spectrumModel->GetUid() == otherDevice.spectrumModel->GetUid())
714 {
715 NS_LOG_LOGIC("no spectrum conversion needed");
716 convertedTxPsd = txPsd;
717 }
718 else
719 {
720 NS_LOG_LOGIC("Converting TXPSD of RTD device " << device.spectrumModel->GetUid() << " --> "
721 << otherDevice.spectrumModel->GetUid());
722
723 SpectrumConverter converter(device.spectrumModel, otherDevice.spectrumModel);
724 convertedTxPsd = converter.Convert(txPsd);
725 }
726
727 // Copy TX PSD to RX PSD, they are now equal rxPsd == txPsd
728 Ptr<SpectrumSignalParameters> rxParams = Create<SpectrumSignalParameters>();
729 rxParams->psd = convertedTxPsd->Copy();
730 double pathLossDb =
731 tempPropModels.remPropagationLossModelCopy->CalcRxPower(0, device.mob, otherDevice.mob);
732 double pathGainLinear = DbToRatio(pathLossDb);
733
734 NS_LOG_DEBUG("Tx power in dBm:" << WToDbm(Integral(*convertedTxPsd)));
735 NS_LOG_DEBUG("PathlosDb:" << pathLossDb);
736
737 // Apply now calculated pathloss to rxPsd, now rxPsd < txPsd because we had some losses
738 *(rxParams->psd) *= pathGainLinear;
739
740 NS_LOG_DEBUG("RX power in dBm after pathloss:" << WToDbm(Integral(*(rxParams->psd))));
741
742 // Now we call spectrum model, which in this keys add a beamforming gain
743 rxParams =
744 tempPropModels.remSpectrumLossModelCopy->DoCalcRxPowerSpectralDensity(rxParams,
745 device.mob,
746 otherDevice.mob,
747 device.antenna,
748 otherDevice.antenna);
749
750 NS_LOG_DEBUG("RX power in dBm after fading: " << WToDbm(Integral(*(rxParams->psd))));
751
752 return rxParams->psd;
753}
754
755Ptr<SpectrumValue>
756NrRadioEnvironmentMapHelper::GetMaxValue(const std::list<Ptr<SpectrumValue>>& values) const
757{
758 // TODO add this abort, if necessary add include for abort.h
759 NS_ABORT_MSG_IF(values.empty(), "Must provide a list of values.");
760
761 Ptr<SpectrumValue> maxValue = Create<SpectrumValue>(m_rrd.spectrumModel);
762 *maxValue = **(values.begin());
763
764 for (const auto& value : values)
765 {
766 if (Sum(*(value)) > Sum(*(maxValue)))
767 {
768 *maxValue = *value;
769 }
770 }
771 return maxValue;
772}
773
774double
775NrRadioEnvironmentMapHelper::CalculateMaxSnr(
776 const std::list<Ptr<SpectrumValue>>& receivedPowerList) const
777{
778 Ptr<SpectrumValue> maxSnr = GetMaxValue(receivedPowerList);
779 SpectrumValue snr = (*maxSnr) / (*m_noisePsd);
780 return RatioToDb(Sum(snr) / snr.GetSpectrumModel()->GetNumBands());
781}
782
783double
784NrRadioEnvironmentMapHelper::CalculateSnr(const Ptr<SpectrumValue>& usefulSignal) const
785{
786 SpectrumValue snr = (*usefulSignal) / (*m_noisePsd);
787
788 return RatioToDb(Sum(snr) / snr.GetSpectrumModel()->GetNumBands());
789}
790
791double
792NrRadioEnvironmentMapHelper::CalculateSinr(
793 const Ptr<SpectrumValue>& usefulSignal,
794 const std::list<Ptr<SpectrumValue>>& interferenceSignals) const
795{
796 Ptr<SpectrumValue> interferencePsd = nullptr;
797
798 if (interferenceSignals.empty())
799 {
800 return CalculateSnr(usefulSignal);
801 }
802 else
803 {
804 interferencePsd = Create<SpectrumValue>(m_rrd.spectrumModel);
805 }
806
807 // sum all interfering signals
808 for (auto rxInterfPower : interferenceSignals)
809 {
810 *interferencePsd += (*rxInterfPower);
811 }
812 // calculate sinr
813
814 SpectrumValue sinr = (*usefulSignal) / (*interferencePsd + *m_noisePsd);
815
816 // calculate average sinr over RBs, convert it from linear to dB units, and return it
817 return RatioToDb(Sum(sinr) / sinr.GetSpectrumModel()->GetNumBands());
818}
819
820double
821NrRadioEnvironmentMapHelper::CalculateSir(
822 const Ptr<SpectrumValue>& usefulSignal,
823 const std::list<Ptr<SpectrumValue>>& interferenceSignals) const
824{
825 Ptr<SpectrumValue> interferencePsd = nullptr;
826
827 if (interferenceSignals.empty())
828 {
829 // return CalculateSnr (usefulSignal);
830 SpectrumValue signal = (*usefulSignal);
831 return RatioToDb(Sum(signal) / signal.GetSpectrumModel()->GetNumBands());
832 }
833 else
834 {
835 interferencePsd = Create<SpectrumValue>(m_rrd.spectrumModel);
836 }
837
838 // sum all interfering signals
839 for (auto rxInterfPower : interferenceSignals)
840 {
841 *interferencePsd += (*rxInterfPower);
842 }
843 // calculate sinr
844
845 SpectrumValue sir = (*usefulSignal) / (*interferencePsd);
846
847 // calculate average sir over RBs, convert it from linear to dB units, and return it
848 return RatioToDb(Sum(sir) / sir.GetSpectrumModel()->GetNumBands());
849}
850
851double
852NrRadioEnvironmentMapHelper::CalculateMaxSinr(
853 const std::list<Ptr<SpectrumValue>>& receivedPowerList) const
854{
855 // we calculate sinr considering for each RTD as if it would be TX device, and the rest of RTDs
856 // interferers
857 std::list<double> sinrList;
858
859 for (std::list<Ptr<SpectrumValue>>::const_iterator it = receivedPowerList.begin();
860 it != receivedPowerList.end();
861 it++)
862 {
863 // all signals - rxPower = interference
864 std::list<Ptr<SpectrumValue>> interferenceSignals;
865 std::list<Ptr<SpectrumValue>>::const_iterator tempit = it;
866
867 if (it != receivedPowerList.begin())
868 {
869 interferenceSignals.insert(interferenceSignals.begin(), receivedPowerList.begin(), it);
870 }
871
872 interferenceSignals.insert(interferenceSignals.end(), ++tempit, receivedPowerList.end());
873 NS_ASSERT(interferenceSignals.size() == receivedPowerList.size() - 1);
874 sinrList.push_back(CalculateSinr(*it, interferenceSignals));
875 }
876 return GetMaxValue(sinrList);
877}
878
879double
880NrRadioEnvironmentMapHelper::CalculateMaxSir(
881 const std::list<Ptr<SpectrumValue>>& receivedPowerList) const
882{
883 // we calculate sinr considering for each RTD as if it would be TX device, and the rest of RTDs
884 // interferers
885 std::list<double> sirList;
886
887 for (std::list<Ptr<SpectrumValue>>::const_iterator it = receivedPowerList.begin();
888 it != receivedPowerList.end();
889 it++)
890 {
891 // all signals - rxPower = interference
892 std::list<Ptr<SpectrumValue>> interferenceSignals;
893 std::list<Ptr<SpectrumValue>>::const_iterator tempit = it;
894
895 if (it != receivedPowerList.begin())
896 {
897 interferenceSignals.insert(interferenceSignals.begin(), receivedPowerList.begin(), it);
898 }
899
900 interferenceSignals.insert(interferenceSignals.end(), ++tempit, receivedPowerList.end());
901 NS_ASSERT(interferenceSignals.size() == receivedPowerList.size() - 1);
902 sirList.push_back(CalculateSir(*it, interferenceSignals));
903 }
904 return GetMaxValue(sirList);
905}
906
907void
908NrRadioEnvironmentMapHelper::CalcBeamShapeRemMap()
909{
910 NS_LOG_FUNCTION(this);
911
912 uint32_t remSizeNextReport = m_rem.size() / 100;
913 uint32_t remPointCounter = 0;
914
915 for (std::list<RemPoint>::iterator itRemPoint = m_rem.begin(); itRemPoint != m_rem.end();
916 ++itRemPoint)
917 {
918 // perform calculation m_numOfIterationsToAverage times and get the average value
919 double sumSnr = 0.0;
920 double sumSinr = 0.0;
921 double sumSir = 0.0;
922 std::list<double> rxPsdsListPerIt; // list to save the summed rxPower in each RemPoint for
923 // each Iteration (linear)
924 m_rrd.mob->SetPosition(itRemPoint->pos);
925
926 Ptr<MobilityBuildingInfo> buildingInfo = m_rrd.mob->GetObject<MobilityBuildingInfo>();
927 buildingInfo->MakeConsistent(m_rrd.mob);
928 NS_ASSERT_MSG(buildingInfo, "buildingInfo is null");
929
930 for (uint16_t i = 0; i < m_numOfIterationsToAverage; i++)
931 {
932 std::list<Ptr<SpectrumValue>>
933 receivedPowerList; // RTD node id, rxPsd of the signal coming from that node
934
935 for (auto& itRtd : m_remDev)
936 {
937 // calculate received power from the current RTD device
938 receivedPowerList.push_back(CalcRxPsdValue(itRtd, m_rrd));
939 } // end for std::list<RemDev>::iterator (RTDs)
940
941 sumSnr += CalculateMaxSnr(receivedPowerList);
942 sumSinr += CalculateMaxSinr(receivedPowerList);
943 sumSir += CalculateMaxSir(receivedPowerList);
944
945 // Sum all the rxPowers (for this RemPoint) and put the result to the list for each
946 // Iteration (linear)
947 rxPsdsListPerIt.push_back(CalculateAggregatedIpsd(receivedPowerList));
948
949 receivedPowerList.clear();
950 } // end for m_numOfIterationsToAverage (Average)
951
952 // Sum the rxPower for all the Iterations (linear)
953 double rxPsdsAllIt = SumListElements(rxPsdsListPerIt);
954
955 itRemPoint->avgSnrDb = sumSnr / static_cast<double>(m_numOfIterationsToAverage);
956 itRemPoint->avgSinrDb = sumSinr / static_cast<double>(m_numOfIterationsToAverage);
957 itRemPoint->avgSirDb = sumSir / static_cast<double>(m_numOfIterationsToAverage);
958 // do the average (for the rxPowers in each RemPoint) in linear and then convert to dBm
959 itRemPoint->avRxPowerDbm =
960 WToDbm(rxPsdsAllIt / static_cast<double>(m_numOfIterationsToAverage));
961
962 NS_LOG_INFO("Avg snr value saved:" << itRemPoint->avgSnrDb);
963 NS_LOG_INFO("Avg sinr value saved:" << itRemPoint->avgSinrDb);
964 NS_LOG_INFO("Avg ipsd value saved (dBm):" << itRemPoint->avRxPowerDbm);
965
966 if (++remPointCounter == remSizeNextReport)
967 {
968 PrintProgressReport(&remSizeNextReport);
969 }
970
971 } // end for std::list<RemPoint>::iterator (RemPoints)
972
973 auto remEndTime = std::chrono::system_clock::now();
974 std::chrono::duration<double> remElapsedSeconds = remEndTime - m_remStartTime;
975 NS_LOG_INFO("REM map created. Total time needed to create the REM map:"
976 << remElapsedSeconds.count() / 60 << " minutes.");
977}
978
979double
980NrRadioEnvironmentMapHelper::GetMaxValue(const std::list<double>& listOfValues) const
981{
982 NS_ABORT_MSG_IF(listOfValues.empty(),
983 "GetMaxValue should not be called "
984 "with an empty list.");
985
986 double maxValue = *(listOfValues.begin());
987 // start from second element, the first is already taken into account
988 for (auto it = ++listOfValues.begin(); it != listOfValues.end(); ++it)
989 {
990 if (*it > maxValue)
991 {
992 maxValue = *it;
993 }
994 }
995 return maxValue;
996}
997
998double
999NrRadioEnvironmentMapHelper::CalculateAggregatedIpsd(
1000 const std::list<Ptr<SpectrumValue>>& receivedSignals)
1001{
1002 Ptr<SpectrumValue> sumRxPowers = nullptr;
1003 sumRxPowers = Create<SpectrumValue>(m_rrd.spectrumModel);
1004
1005 // sum the received power of all the rtds
1006 for (auto rxPowersIt : receivedSignals)
1007 {
1008 *sumRxPowers += (*rxPowersIt);
1009 }
1010
1011 SpectrumValue sumRxPowersSv = (*sumRxPowers);
1012
1013 return (Integral(sumRxPowersSv));
1014}
1015
1016double
1017NrRadioEnvironmentMapHelper::SumListElements(const std::list<double>& listOfValues)
1018{
1019 NS_ABORT_MSG_IF(listOfValues.empty(),
1020 "SumListElements should not be called "
1021 "with an empty list.");
1022
1023 double sum = 0;
1024
1025 for (double listOfValue : listOfValues)
1026 {
1027 sum += listOfValue;
1028 }
1029 return sum;
1030}
1031
1032void
1033NrRadioEnvironmentMapHelper::CalcCoverageAreaRemMap()
1034{
1035 NS_LOG_FUNCTION(this);
1036 uint16_t calcRxPsdCounter = 0;
1037 uint32_t remSizeNextReport = m_rem.size() / 100;
1038 uint32_t remPointCounter = 0;
1039
1040 for (std::list<RemPoint>::iterator itRemPoint = m_rem.begin(); itRemPoint != m_rem.end();
1041 ++itRemPoint)
1042 {
1043 // perform calculation m_numOfIterationsToAverage times and get the average value
1044 double sumSnr = 0.0;
1045 double sumSinr = 0.0;
1046 m_rrd.mob->SetPosition(itRemPoint->pos);
1047
1048 // all RTDs should point toward that RemPoint with DirectPah beam, this is definition of
1049 // worst-case scenario
1050 for (auto& itRtd : m_remDev)
1051 {
1052 ConfigureDirectPathBfv(itRtd, m_rrd, itRtd.antenna);
1053 }
1054
1055 std::list<double> rxPsdsListPerIt; // list to save the summed rxPower in each RemPoint for
1056 // each Iteration (linear)
1057
1058 for (uint16_t i = 0; i < m_numOfIterationsToAverage; i++)
1059 {
1060 std::list<double> sinrsPerBeam; // vector in which we will save sinr per each RRD beam
1061 std::list<double> snrsPerBeam; // vector in which we will save snr per each RRD beam
1062
1063 std::list<Ptr<SpectrumValue>> rxPsdsList; // vector in which we will save the sum of
1064 // rxPowers per remPoint (linear)
1065
1066 // For each beam configuration at RemPoint/RRD we should calculate SINR, there are as
1067 // many beam configurations at RemPoint as many RTDs
1068 for (std::list<RemDevice>::iterator itRtdBeam = m_remDev.begin();
1069 itRtdBeam != m_remDev.end();
1070 ++itRtdBeam)
1071 {
1072 // configure RRD beam toward RTD
1073 ConfigureDirectPathBfv(m_rrd, *itRtdBeam, m_rrd.antenna);
1074
1075 // Calculate the received power from this RTD for this RemPoint
1076 Ptr<SpectrumValue> receivedPowerFromRtd = CalcRxPsdValue(*itRtdBeam, m_rrd);
1077 // and put it to the list of the received powers for this RemPoint (to sum all
1078 // later)
1079 rxPsdsList.push_back(receivedPowerFromRtd);
1080
1081 NS_LOG_DEBUG("beam node: " << itRtdBeam->dev->GetNode()->GetId()
1082 << " is Rxed in RemPoint with Rx Power in W: "
1083 << (Integral(*receivedPowerFromRtd)));
1084 NS_LOG_DEBUG("RxPower in dBm: " << WToDbm(Integral(*receivedPowerFromRtd)));
1085
1086 std::list<Ptr<SpectrumValue>> interferenceSignalsRxPsds;
1087 Ptr<SpectrumValue> usefulSignalRxPsd;
1088
1089 // For this configuration of beam at RRD, we need to calculate RX PSD,
1090 // and in order to be able to calculate SINR for that beam,
1091 // we need to calculate received PSD for each RTD using this beam at RRD
1092 for (auto& itRtdCalc : m_remDev)
1093 {
1094 // increase counter de calcRXPsd calls
1095 calcRxPsdCounter++;
1096 // calculate received power from the current RTD device
1097 Ptr<SpectrumValue> receivedPower = CalcRxPsdValue(itRtdCalc, m_rrd);
1098
1099 // is this received power useful signal (from RTD for which I configured my
1100 // beam) or is interference signal
1101
1102 if (itRtdBeam->dev->GetNode()->GetId() == itRtdCalc.dev->GetNode()->GetId())
1103 {
1104 if (usefulSignalRxPsd != nullptr)
1105 {
1106 NS_FATAL_ERROR("Already assigned usefulSignal!");
1107 }
1108 usefulSignalRxPsd = receivedPower;
1109 }
1110 else
1111 {
1112 interferenceSignalsRxPsds.push_back(receivedPower); // interference
1113 }
1114
1115 } // end for std::list<RemDev>::iterator itRtdCalc (RTDs)
1116
1117 sinrsPerBeam.push_back(CalculateSinr(usefulSignalRxPsd, interferenceSignalsRxPsds));
1118 snrsPerBeam.push_back(CalculateSnr(usefulSignalRxPsd));
1119
1120 NS_LOG_INFO("Done:" << (double)calcRxPsdCounter /
1121 (m_rem.size() * m_numOfIterationsToAverage *
1122 m_remDev.size() * m_remDev.size()) *
1123 100
1124 << " %."); // how many times will be called CalcRxPsdValues
1125
1126 } // end for std::list<RemDev>::iterator itRtdBeam (RTDs)
1127
1128 sumSnr += GetMaxValue(snrsPerBeam);
1129 sumSinr += GetMaxValue(sinrsPerBeam);
1130
1131 // Sum all the rxPowers (for this RemPoint) and put the result to the list for each
1132 // Iteration (linear)
1133 rxPsdsListPerIt.push_back(CalculateAggregatedIpsd(rxPsdsList));
1134
1135 } // end for m_numOfIterationsToAverage (Average)
1136
1137 // Sum the rxPower for all the Iterations (linear)
1138 double rxPsdsAllIt = SumListElements(rxPsdsListPerIt);
1139
1140 itRemPoint->avgSnrDb = sumSnr / static_cast<double>(m_numOfIterationsToAverage);
1141 itRemPoint->avgSinrDb = sumSinr / static_cast<double>(m_numOfIterationsToAverage);
1142 // do the average (for the rxPowers in each RemPoint) in linear and then convert to dBm
1143 itRemPoint->avRxPowerDbm =
1144 WToDbm(rxPsdsAllIt / static_cast<double>(m_numOfIterationsToAverage));
1145
1146 if (++remPointCounter == remSizeNextReport)
1147 {
1148 PrintProgressReport(&remSizeNextReport);
1149 }
1150
1151 NS_LOG_DEBUG("itRemPoint->avRxPowerDb in dB: " << itRemPoint->avRxPowerDbm);
1152
1153 } // end for std::list<RemPoint>::iterator (RemPoints)
1154
1155 auto remEndTime = std::chrono::system_clock::now();
1156 std::chrono::duration<double> remElapsedSeconds = remEndTime - m_remStartTime;
1157 NS_LOG_INFO("REM map created. Total time needed to create the REM map:"
1158 << remElapsedSeconds.count() / 60 << " minutes.");
1159}
1160
1161void
1162NrRadioEnvironmentMapHelper::PrintProgressReport(uint32_t* remSizeNextReport)
1163{
1164 auto remTimeUpToNow = std::chrono::system_clock::now();
1165 std::chrono::duration<double> remElapsedSecondsUpToNow = remTimeUpToNow - m_remStartTime;
1166 double minutesUpToNow = ((double)remElapsedSecondsUpToNow.count()) / 60;
1167 double minutesLeftEstimated =
1168 ((double)(minutesUpToNow) / *remSizeNextReport) * ((m_rem.size() - *remSizeNextReport));
1169 std::cout << "\n REM done:" << ceil(((double)*remSizeNextReport / m_rem.size()) * 100) << " %."
1170 << " Minutes up to now: " << minutesUpToNow
1171 << ". Minutes left estimated:" << minutesLeftEstimated
1172 << "."; // how many times will be called CalcRxPsdValues
1173 // we want progress report for 1%, 10%, 20%, 30%, and so on
1174 if (*remSizeNextReport < m_rem.size() / 10)
1175 {
1176 *remSizeNextReport = m_rem.size() / 10;
1177 }
1178 else
1179 {
1180 *remSizeNextReport += m_rem.size() / 10;
1181 }
1182}
1183
1184void
1185NrRadioEnvironmentMapHelper::CalcUeCoverageRemMap()
1186{
1187 NS_LOG_FUNCTION(this);
1188
1189 uint32_t remSizeNextReport = m_rem.size() / 100;
1190 uint32_t remPointCounter = 0;
1191
1192 for (auto& itRemPoint : m_rem)
1193 {
1194 // perform calculation m_numOfIterationsToAverage times and get the average value
1195 double sumSnr = 0.0;
1196 double sumSinr = 0.0;
1197 m_rrd.mob->SetPosition(itRemPoint.pos);
1198
1199 for (uint16_t i = 0; i < m_numOfIterationsToAverage; i++)
1200 {
1201 std::list<double> sinrsPerBeam; // vector in which we will save sinr per each RRD beam
1202 std::list<double> snrsPerBeam; // vector in which we will save snr per each RRD beam
1203
1204 //"Associate" UE (RemPoint) with this RTD
1205 for (auto& itRtdAssociated : m_remDev)
1206 {
1207 // configure RRD (RemPoint) beam toward RTD (itRtdAssociated)
1208 ConfigureDirectPathBfv(m_rrd, itRtdAssociated, m_rrd.antenna);
1209 // configure RTD (itRtdAssociated) beam toward RRD (RemPoint)
1210 ConfigureDirectPathBfv(itRtdAssociated, m_rrd, itRtdAssociated.antenna);
1211
1212 std::list<Ptr<SpectrumValue>> interferenceSignalsRxPsds;
1213 Ptr<SpectrumValue> usefulSignalRxPsd;
1214
1215 for (auto& itRtdInterferer : m_remDev)
1216 {
1217 if (itRtdAssociated.dev->GetNode()->GetId() !=
1218 itRtdInterferer.dev->GetNode()->GetId())
1219 {
1220 // configure RTD (itRtdInterferer) beam toward RTD (itRtdAssociated)
1221 ConfigureDirectPathBfv(itRtdInterferer,
1222 itRtdAssociated,
1223 itRtdInterferer.antenna);
1224
1225 // calculate received power (interference) from the current RTD device
1226 Ptr<SpectrumValue> receivedPower =
1227 CalcRxPsdValue(itRtdInterferer, itRtdAssociated);
1228
1229 interferenceSignalsRxPsds.push_back(receivedPower); // interference
1230 }
1231 else
1232 {
1233 // calculate received power (useful Signal) from the current RRD device
1234 Ptr<SpectrumValue> receivedPower = CalcRxPsdValue(m_rrd, itRtdAssociated);
1235 if (usefulSignalRxPsd != nullptr)
1236 {
1237 NS_FATAL_ERROR("Already assigned usefulSignal!");
1238 }
1239 usefulSignalRxPsd = receivedPower;
1240 }
1241
1242 } // end for std::list<RemDev>::iterator itRtdInterferer (RTD)
1243
1244 sinrsPerBeam.push_back(CalculateSinr(usefulSignalRxPsd, interferenceSignalsRxPsds));
1245 snrsPerBeam.push_back(CalculateSnr(usefulSignalRxPsd));
1246
1247 } // end for std::list<RemDev>::iterator itRtdAssociated (RTD)
1248
1249 sumSnr += GetMaxValue(snrsPerBeam);
1250 sumSinr += GetMaxValue(sinrsPerBeam);
1251
1252 } // end for m_numOfIterationsToAverage (Average)
1253
1254 itRemPoint.avgSnrDb = sumSnr / static_cast<double>(m_numOfIterationsToAverage);
1255 itRemPoint.avgSinrDb = sumSinr / static_cast<double>(m_numOfIterationsToAverage);
1256
1257 if (++remPointCounter == remSizeNextReport)
1258 {
1259 PrintProgressReport(&remSizeNextReport);
1260 }
1261
1262 } // end for std::list<RemPoint>::iterator (RemPoints)
1263
1264 auto remEndTime = std::chrono::system_clock::now();
1265 std::chrono::duration<double> remElapsedSeconds = remEndTime - m_remStartTime;
1266 NS_LOG_INFO("REM map created. Total time needed to create the REM map:"
1267 << remElapsedSeconds.count() / 60 << " minutes.");
1268}
1269
1270NrRadioEnvironmentMapHelper::PropagationModels
1271NrRadioEnvironmentMapHelper::CreateTemporalPropagationModels() const
1272{
1273 NS_LOG_FUNCTION(this);
1274
1275 PropagationModels propModels;
1276 // create rem copy of channel condition
1277 Ptr<ChannelConditionModel> condModelCopy =
1278 m_channelConditionModelFactory.Create<ChannelConditionModel>();
1279
1280 // create rem copy of propagation model
1281 ObjectFactory propLossModelFactory = ConfigureObjectFactory(m_propagationLossModel);
1282 propModels.remPropagationLossModelCopy =
1283 propLossModelFactory.Create<ThreeGppPropagationLossModel>();
1284 propModels.remPropagationLossModelCopy->SetChannelConditionModel(condModelCopy);
1285
1286 // create rem copy of spectrum loss model
1287 ObjectFactory spectrumLossModelFactory = ConfigureObjectFactory(m_phasedArraySpectrumLossModel);
1288 if (spectrumLossModelFactory.IsTypeIdSet())
1289 {
1290 Ptr<MatrixBasedChannelModel> channelModelCopy =
1291 m_matrixBasedChannelModelFactory.Create<MatrixBasedChannelModel>();
1292 channelModelCopy->SetAttribute("ChannelConditionModel", PointerValue(condModelCopy));
1293 spectrumLossModelFactory.Set("ChannelModel", PointerValue(channelModelCopy));
1294 propModels.remSpectrumLossModelCopy =
1295 spectrumLossModelFactory.Create<ThreeGppSpectrumPropagationLossModel>();
1296 }
1297 return propModels;
1298}
1299
1300void
1301NrRadioEnvironmentMapHelper::PrintGnuplottableGnbListToFile(const std::string& filename)
1302{
1303 NS_LOG_FUNCTION(this);
1304 std::ofstream gnbOutFile;
1305 gnbOutFile.open(filename.c_str(), std::ios_base::out | std::ios_base::trunc);
1306 if (!gnbOutFile.is_open())
1307 {
1308 NS_LOG_ERROR("Can't open file " << filename);
1309 return;
1310 }
1311
1312 for (auto& itRtd : m_remDev)
1313 {
1314 Vector pos = itRtd.dev->GetNode()->GetObject<MobilityModel>()->GetPosition();
1315
1316 gnbOutFile << "set label \"" << itRtd.dev->GetNode()->GetId() << "\" at " << pos.x << ","
1317 << pos.y
1318 << " left font \"Helvetica,4\" textcolor rgb \"white\" front point pt 2 ps 1 "
1319 "lc rgb \"white\" offset 0,0"
1320 << std::endl;
1321 }
1322
1323 gnbOutFile.close();
1324}
1325
1326void
1327NrRadioEnvironmentMapHelper::PrintGnuplottableUeListToFile(const std::string& filename)
1328{
1329 NS_LOG_FUNCTION(this);
1330 std::ofstream ueOutFile;
1331 ueOutFile.open(filename.c_str(), std::ios_base::out | std::ios_base::trunc);
1332 if (!ueOutFile.is_open())
1333 {
1334 NS_LOG_ERROR("Can't open file " << filename);
1335 return;
1336 }
1337
1338 Vector pos = m_rrd.node->GetObject<MobilityModel>()->GetPosition();
1339
1340 ueOutFile << "set label \"" << m_rrd.dev->GetNode()->GetId() << "\" at " << pos.x << ","
1341 << pos.y
1342 << " left font \"Helvetica,4\" textcolor rgb \"grey\" front point pt 1 ps 1 lc rgb "
1343 "\"grey\" offset 0,0"
1344 << std::endl;
1345
1346 ueOutFile.close();
1347}
1348
1349void
1350NrRadioEnvironmentMapHelper::PrintGnuplottableBuildingListToFile(const std::string& filename)
1351{
1352 NS_LOG_FUNCTION(this);
1353 std::ofstream outFile;
1354 outFile.open(filename.c_str(), std::ios_base::out | std::ios_base::trunc);
1355 if (!outFile.is_open())
1356 {
1357 NS_LOG_ERROR("Can't open file " << filename);
1358 return;
1359 }
1360
1361 uint32_t index = 0;
1362
1363 for (BuildingList::Iterator it = BuildingList::Begin(); it != BuildingList::End(); ++it)
1364 {
1365 ++index;
1366 Box box = (*it)->GetBoundaries();
1367 outFile << "set object " << index << " rect from " << box.xMin << "," << box.yMin << " to "
1368 << box.xMax << "," << box.yMax << " front fs empty "
1369 << " border 3 " << std::endl;
1370 }
1371
1372 outFile.close();
1373}
1374
1375void
1376NrRadioEnvironmentMapHelper::PrintRemToFile()
1377{
1378 NS_LOG_FUNCTION(this);
1379
1380 std::ostringstream oss;
1381 oss << "nr-rem-" << m_simTag.c_str() << ".out";
1382
1383 std::ofstream outFile;
1384 std::string outputFile = oss.str();
1385 outFile.open(outputFile.c_str());
1386
1387 if (!outFile.is_open())
1388 {
1389 NS_FATAL_ERROR("Can't open file " << (outputFile));
1390 return;
1391 }
1392
1393 for (auto& it : m_rem)
1394 {
1395 outFile << it.pos.x << "\t" << it.pos.y << "\t" << it.pos.z << "\t" << it.avgSnrDb << "\t"
1396 << it.avgSinrDb << "\t" << it.avRxPowerDbm << "\t" << it.avgSirDb << "\t"
1397 << std::endl;
1398 }
1399
1400 outFile.close();
1401
1402 CreateCustomGnuplotFile();
1403 Finalize();
1404}
1405
1406void
1407NrRadioEnvironmentMapHelper::CreateCustomGnuplotFile()
1408{
1409 NS_LOG_FUNCTION(this);
1410 std::ostringstream oss;
1411 oss << "nr-rem-" << m_simTag.c_str() << "-plot-rem.gnuplot";
1412 std::string filename = oss.str();
1413
1414 std::ofstream outFile;
1415 outFile.open(filename.c_str(), std::ios_base::out | std::ios_base::trunc);
1416 if (!outFile.is_open())
1417 {
1418 NS_LOG_ERROR("Can't open file " << filename);
1419 return;
1420 }
1421
1422 outFile << "set xlabel \"x-coordinate (m)\"" << std::endl;
1423 outFile << "set ylabel \"y-coordinate (m)\"" << std::endl;
1424 outFile << "set cblabel \"SNR (dB)\"" << std::endl;
1425 outFile << "set cblabel offset 3" << std::endl;
1426 outFile << "unset key" << std::endl;
1427 outFile << "set terminal png" << std::endl;
1428 outFile << "set output \"nr-rem-" << m_simTag << "-snr.png\"" << std::endl;
1429 outFile << "set size ratio -1" << std::endl;
1430 outFile << "set cbrange [-5:30]" << std::endl;
1431 outFile << "set xrange [" << m_xMin << ":" << m_xMax << "]" << std::endl;
1432 outFile << "set yrange [" << m_yMin << ":" << m_yMax << "]" << std::endl;
1433 outFile << "set xtics font \"Helvetica,17\"" << std::endl;
1434 outFile << "set ytics font \"Helvetica,17\"" << std::endl;
1435 outFile << "set cbtics font \"Helvetica,17\"" << std::endl;
1436 outFile << "set xlabel font \"Helvetica,17\"" << std::endl;
1437 outFile << "set ylabel font \"Helvetica,17\"" << std::endl;
1438 outFile << "set cblabel font \"Helvetica,17\"" << std::endl;
1439 outFile << "plot \"nr-rem-" << m_simTag << ".out\" using ($1):($2):($4) with image"
1440 << std::endl;
1441
1442 outFile << "set xlabel \"x-coordinate (m)\"" << std::endl;
1443 outFile << "set ylabel \"y-coordinate (m)\"" << std::endl;
1444 outFile << "set cblabel \"SINR (dB)\"" << std::endl;
1445 outFile << "set cblabel offset 3" << std::endl;
1446 outFile << "unset key" << std::endl;
1447 outFile << "set terminal png" << std::endl;
1448 outFile << "set output \"nr-rem-" << m_simTag << "-sinr.png\"" << std::endl;
1449 outFile << "set size ratio -1" << std::endl;
1450 outFile << "set cbrange [-5:30]" << std::endl;
1451 outFile << "set xrange [" << m_xMin << ":" << m_xMax << "]" << std::endl;
1452 outFile << "set yrange [" << m_yMin << ":" << m_yMax << "]" << std::endl;
1453 outFile << "set xtics font \"Helvetica,17\"" << std::endl;
1454 outFile << "set ytics font \"Helvetica,17\"" << std::endl;
1455 outFile << "set cbtics font \"Helvetica,17\"" << std::endl;
1456 outFile << "set xlabel font \"Helvetica,17\"" << std::endl;
1457 outFile << "set ylabel font \"Helvetica,17\"" << std::endl;
1458 outFile << "set cblabel font \"Helvetica,17\"" << std::endl;
1459 outFile << "plot \"nr-rem-" << m_simTag << ".out\" using ($1):($2):($5) with image"
1460 << std::endl;
1461
1462 outFile << "set xlabel \"x-coordinate (m)\"" << std::endl;
1463 outFile << "set ylabel \"y-coordinate (m)\"" << std::endl;
1464 outFile << "set cblabel \"IPSD (dBm)\"" << std::endl;
1465 outFile << "set cblabel offset 3" << std::endl;
1466 outFile << "unset key" << std::endl;
1467 outFile << "set terminal png" << std::endl;
1468 outFile << "set output \"nr-rem-" << m_simTag << "-ipsd.png\"" << std::endl;
1469 outFile << "set size ratio -1" << std::endl;
1470 outFile << "set cbrange [-100:-20]" << std::endl;
1471 outFile << "set xrange [" << m_xMin << ":" << m_xMax << "]" << std::endl;
1472 outFile << "set yrange [" << m_yMin << ":" << m_yMax << "]" << std::endl;
1473 outFile << "set xtics font \"Helvetica,17\"" << std::endl;
1474 outFile << "set ytics font \"Helvetica,17\"" << std::endl;
1475 outFile << "set cbtics font \"Helvetica,17\"" << std::endl;
1476 outFile << "set xlabel font \"Helvetica,17\"" << std::endl;
1477 outFile << "set ylabel font \"Helvetica,17\"" << std::endl;
1478 outFile << "set cblabel font \"Helvetica,17\"" << std::endl;
1479 outFile << "plot \"nr-rem-" << m_simTag << ".out\" using ($1):($2):($6) with image"
1480 << std::endl;
1481
1482 outFile << "set xlabel \"x-coordinate (m)\"" << std::endl;
1483 outFile << "set ylabel \"y-coordinate (m)\"" << std::endl;
1484 outFile << "set cblabel \"SIR (dB)\"" << std::endl;
1485 outFile << "set cblabel offset 3" << std::endl;
1486 outFile << "unset key" << std::endl;
1487 outFile << "set terminal png" << std::endl;
1488 outFile << "set output \"nr-rem-" << m_simTag << "-sir.png\"" << std::endl;
1489 outFile << "set size ratio -1" << std::endl;
1490 outFile << "set cbrange [-5:30]" << std::endl;
1491 outFile << "set xrange [" << m_xMin << ":" << m_xMax << "]" << std::endl;
1492 outFile << "set yrange [" << m_yMin << ":" << m_yMax << "]" << std::endl;
1493 outFile << "set xtics font \"Helvetica,17\"" << std::endl;
1494 outFile << "set ytics font \"Helvetica,17\"" << std::endl;
1495 outFile << "set cbtics font \"Helvetica,17\"" << std::endl;
1496 outFile << "set xlabel font \"Helvetica,17\"" << std::endl;
1497 outFile << "set ylabel font \"Helvetica,17\"" << std::endl;
1498 outFile << "set cblabel font \"Helvetica,17\"" << std::endl;
1499 outFile << "plot \"nr-rem-" << m_simTag << ".out\" using ($1):($2):($7) with image"
1500 << std::endl;
1501
1502 outFile.close();
1503}
1504
1505void
1506NrRadioEnvironmentMapHelper::Finalize()
1507{
1508 NS_LOG_FUNCTION(this);
1509 // TODO test if we can call this
1510 // std::ostringstream oss;
1511 // oss <<"gnuplot -p nr-"<<m_simTag.c_str()<<"-ues.txt nr-"<<m_simTag.c_str()<<"-gnbs.txt
1512 // nr-rem-"<<m_simTag.c_str()<<"-buildings.txt nr-rem-"<<m_simTag.c_str()<<"-plot-rem.gnuplot";
1513 // system(oss.str().c_str());
1514 // TODO if yes, then we can add also convert command
1515 Simulator::Stop();
1516}
1517
1518} // namespace ns3
The NrGnbNetDevice class.
void SetMaxY(double yMax)
Sets the max y coordinate of the map.
double DbToRatio(double dB) const
Convert from dB to ratio.
void SetInstallationDelay(const Time &installationDelay)
Sets the installation delay.
void SetMinX(double xMin)
Sets the min x coordinate of the map.
double WToDbm(double w) const
Convert from Watts to dBm.
void SetNumOfItToAverage(uint16_t numOfIterationsToAverage)
Sets the number of iterations to calculate the average of rem value.
RemMode GetRemMode() const
Get the type of REM Map to be generated.
void SetZ(double z)
Sets the z coordinate of the map.
void SetMinY(double yMin)
Sets the min y coordinate of the map.
void SetMaxX(double xMax)
Sets the max x coordinate of the map.
NrRadioEnvironmentMapHelper()
NrRadioEnvironmentMapHelper constructor.
double RatioToDb(double ratio) const
Convert from ratio to dB.
void SetRemMode(enum RemMode remType)
Set the type of REM Map to be generated.
void SetResY(uint16_t yRes)
Sets the resolution (number of points) of the map along the y axis.
void SetSimTag(const std::string &simTag)
Set simTag that will be concatenated to output file names.
double DbmToW(double dbm) const
Convert from dBm to Watts.
void CreateRem(const NetDeviceContainer &rtdNetDev, const Ptr< NetDevice > &rrdDevice, uint8_t bwpId)
This function is used for the creation of the REM map. When this function is called from an example,...
void SetResX(uint16_t xRes)
Sets the resolution (number of points) of the map along the x axis.
static Ptr< SpectrumValue > CreateNoisePowerSpectralDensity(double noiseFigure, const Ptr< const SpectrumModel > &spectrumModel)
Create a SpectrumValue that models the power spectral density of AWGN.
static Ptr< SpectrumValue > CreateTxPowerSpectralDensity(double powerTx, const std::vector< int > &rbIndexVector, const Ptr< const SpectrumModel > &txSm, enum PowerAllocationType allocationType)
Create SpectrumValue that will represent transmit power spectral density, and assuming that all RBs a...
The User Equipment NetDevice.
Ptr< NrUePhy > GetPhy(uint8_t index) const
Obtain a pointer to the PHY at the index specified.
PhasedArrayModel::ComplexVector CreateQuasiOmniBfv(const Ptr< const UniformPlanarArray > &antenna)
Create a quasi omni beamforming vector.