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