5G-LENA nr-v3.0-33-g7aea1e4
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
file-scenario-helper.cc
1/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2
3// Copyright (c) 2020 Lawrence Livermore National Laboratory
4//
5// SPDX-License-Identifier: GPL-2.0-only
6
7#include "file-scenario-helper.h"
8
9#include <ns3/core-module.h>
10#include <ns3/mobility-module.h>
11
12#include <cmath> // M_PI (but non-standard)
13#include <sstream>
14
15using namespace ns3;
16
18namespace
19{
20
32void
33PlotDeployment(const Ptr<const ListPositionAllocator>& sitePositioner,
34 const Ptr<const ListPositionAllocator>& utPositioner,
35 const std::size_t numSectors,
36 const double maxRadius,
37 const double effIsd)
38{
39 std::size_t numSites = sitePositioner->GetSize();
40 std::size_t numUts = utPositioner->GetSize();
41 std::size_t numCells = numSites * numSectors;
42
43 NS_ASSERT(numSites);
44 NS_ASSERT(numUts);
45 NS_ASSERT(numSectors > 0);
46 NS_ASSERT(maxRadius > 0);
47 NS_ASSERT(effIsd < maxRadius);
48
49 // Try to open a new GNUPLOT file
50 std::ofstream topologyOutfile;
51 std::string topologyFileRoot = "./list-topology";
52 std::string topologyFileName = topologyFileRoot + ".gnuplot";
53 topologyOutfile.open(topologyFileName.c_str(), std::ios_base::out | std::ios_base::trunc);
54 if (!topologyOutfile.is_open())
55 {
56 NS_ABORT_MSG("Can't open " << topologyFileName);
57 }
58
59 topologyOutfile << "set term pdf" << std::endl;
60 topologyOutfile << "set output \"" << topologyFileRoot << ".pdf\"" << std::endl;
61 topologyOutfile << "set style arrow 1 linecolor \"red\" linewidth 2 head filled" << std::endl;
62 // topologyOutfile << "set autoscale" << std::endl;
63
64 // Extent of the plot, 5% margin all around
65 std::size_t radius = maxRadius * 1.05;
66 topologyOutfile << "set xrange [-" << radius << ":" << radius << "]" << std::endl;
67 topologyOutfile << "set yrange [-" << radius << ":" << radius << "]" << std::endl;
68
69 // Arrow style
72 // Plo the UEs first, so the sector arrows are on top
73 for (std::size_t utId = 0; utId < numUts; ++utId)
74 {
75 Vector utPos = utPositioner->GetNext();
76 // set label at xPos, yPos, zPos "" point pointtype 7 pointsize 2
77 topologyOutfile << "set label at " << utPos.x << " , " << utPos.y
78 << " point pointtype 7 pointsize 0.5 center" << std::endl;
79 }
80
81 // Control the arrow length that indicates
82 // the orientation of the sectorized antenna.
83 // Set it to 1/3 the ISD: x ---> <--- x
84 double arrowLength = effIsd;
85
86 const double sectorSize = 2 * M_PI / numSectors;
87 std::size_t cellId = 0;
88
89 for (std::size_t siteId = 0; siteId < numSites; ++siteId)
90 {
91 Vector site = sitePositioner->GetNext();
92
93 for (std::size_t sector = 0; sector < numSectors; ++sector)
94 {
95 double angle = 0.0;
96 if (numSectors > 1)
97 {
98 std::size_t sector = cellId % numSectors;
99 // 0'th sector spans from [0, sectorSize] in degrees,
100 // centered at sectorSize / 2
101 angle = sectorSize * (sector + 0.5);
102 }
103 double rx = arrowLength * std::cos(angle);
104 double ry = arrowLength * std::sin(angle);
105
106 topologyOutfile << "set arrow " << cellId + 1 << " from " << site.x << "," << site.y
107 << " rto " << rx << "," << ry << " arrowstyle 1\n";
108
109 topologyOutfile << "set label " << cellId + 1 << " \"" << (cellId + 1) << "\" at "
110 << site.x << "," << site.y << " center" << std::endl;
111 ++cellId;
112 }
113 }
114 NS_ASSERT(cellId == numCells);
115
116 topologyOutfile << "unset key" << std::endl; // Disable plot legends
117 topologyOutfile << "plot 1/0" << std::endl; // Need to plot a function
118
119} // PlotDeployment ()
120
121} // unnamed namespace
122
123namespace ns3
124{
125
129
130void
131FileScenarioHelper::Add(const std::string filePath, char delimiter /* = ',' */)
132{
133 if (!m_bsPositioner)
134 {
135 m_bsPositioner = CreateObject<ListPositionAllocator>();
136 }
137 m_bsPositioner->Add(filePath, m_bsHeight, delimiter);
138 auto numSites = m_bsPositioner->GetSize();
139 SetSitesNumber(numSites);
140}
141
142void
143FileScenarioHelper::CheckScenario(const char* where) const
144{
145 NS_ASSERT_MSG(m_scenarioCreated,
146 "Must Add() position file and CreateScenario() "
147 "before calling "
148 << where);
149}
150
151Vector
152FileScenarioHelper::GetSitePosition(std::size_t cellId) const
153{
154 CheckScenario(__FUNCTION__);
155
156 auto node = m_bs.Get(cellId);
157 auto mob = node->GetObject<MobilityModel>();
158 return mob->GetPosition();
159}
160
161void
163{
164 NS_ASSERT_MSG(m_bsPositioner, "Must Add() a position file before CreateScenario()");
165
166 // NS_ASSERT_MSG (m_numSites > 0,
167 // "Must have at least one site location in the position file.");
168
169 NS_ASSERT_MSG(m_sectorization != NONE, "Must SetSectorization() before CreateScenario()");
170 NS_ASSERT_MSG(m_bsHeight >= 0.0, "Must SetBsHeight() before CreateScenario()");
171 NS_ASSERT_MSG(m_utHeight >= 0.0, "Must SetUtHeight() before CreateScenario()");
172
173 auto sectors = GetNumSectorsPerSite();
174 std::cout << " creating BS" << std::endl;
175 m_bs.Create(m_numBs);
176 std::cout << " creating UE" << std::endl;
177 m_ut.Create(m_numUt);
178
179 // Accumulate maxRadius and effIsd
180 double maxRadius = 0;
181 // For effective ISD we have to iterate over all pairs of towers :(
182 // so cache the positions from m_bsPositioner
183 std::cout << " reserving sitePositions" << std::endl;
184 std::vector<Vector> sitePositions;
185 sitePositions.reserve(m_numSites);
186
187 // Position the BS cells
188 std::cout << " creating bsPositions" << std::endl;
189 Ptr<ListPositionAllocator> bsPositions = CreateObject<ListPositionAllocator>();
190 std::size_t cellId = 0;
191 for (std::size_t siteId = 0; siteId < m_numSites; ++siteId)
192 {
193 Vector site = m_bsPositioner->GetNext();
194 sitePositions.push_back(site);
195
196 maxRadius = std::max(maxRadius, std::abs(site.x));
197 maxRadius = std::max(maxRadius, std::abs(site.y));
198
199 std::cout << " sectors for site " << siteId << std::endl;
200 for (std::size_t sector = 0; sector < sectors; ++sector)
201 {
202 Vector bs{site};
203 double angle = GetAntennaOrientationRadians(cellId);
204 bs.x += m_antennaOffset * cos(angle);
205 bs.y += m_antennaOffset * sin(angle);
206
207 bsPositions->Add(bs);
208 ++cellId;
209
210 } // for cell
211
212 } // for site
213 NS_ASSERT_MSG(cellId == m_numBs,
214 "Computed positions for " << cellId << " cells, expected " << m_numBs);
215
216 std::cout << " BS mobility" << std::endl;
217 MobilityHelper mobility;
218 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
219 mobility.SetPositionAllocator(m_bsPositioner);
220 mobility.Install(m_bs);
221
222 // Compute effective ISD
223 double effIsd = 0;
224 std::cout << " computing average Isd..." << std::flush;
225 for (auto v = sitePositions.begin(); v != sitePositions.end(); ++v)
226 {
227 auto w = v;
228 ++w;
229 for (; w < sitePositions.end(); ++w)
230 {
231 NS_ASSERT(w != v);
232 double range = (*w - *v).GetLength();
233 effIsd += range;
234
235 } // for w : sitePositions
236
237 } // for v : sitePositions
238 effIsd /= m_numSites * (m_numSites - 1) / 2;
239 std::cout << effIsd << std::endl;
240
241 // Position the UEs uniformly in the sector annulus
242 std::cout << " UE positions" << std::endl;
243 // equivalent for a hexagonal laydown:
244 // between m_minBsUtDistance and m_isd / sqrt (3)
245 std::cout << " radius rng..." << std::flush;
246 Ptr<UniformRandomVariable> r = CreateObject<UniformRandomVariable>();
247 std::cout << "setting stream..." << std::flush;
248 r->SetStream(RngSeedManager::GetNextStreamIndex());
249 std::cout << "done" << std::endl;
250 const double outerR = std::min(effIsd, m_isd); // / std::sqrt(3);
251 NS_ASSERT(m_minBsUtDistance < outerR);
252 // Need to weight r to get uniform in the sector wedge
253 // See https://stackoverflow.com/questions/5837572
254 r->SetAttribute("Min", DoubleValue(m_minBsUtDistance * m_minBsUtDistance));
255 r->SetAttribute("Max", DoubleValue(outerR * outerR));
256 std::cout << "[" << m_minBsUtDistance << "," << outerR << "]" << std::endl;
257 std::cout << " using effIsd " << outerR << std::endl;
258
259 std::cout << " theta rng..." << std::flush;
260 Ptr<UniformRandomVariable> theta = CreateObject<UniformRandomVariable>();
261 std::cout << "setting stream..." << std::flush;
262 theta->SetStream(RngSeedManager::GetNextStreamIndex());
263 std::cout << "done" << std::endl;
264
265 Ptr<ListPositionAllocator> utPositioner = CreateObject<ListPositionAllocator>();
266 ;
267 for (uint32_t utId = 0; utId < m_numUt; ++utId)
268 {
269 auto cellId = GetCellIndex(utId);
270 auto siteId = GetSiteIndex(cellId);
271 Vector cellPos = sitePositions[siteId];
272
273 // Need to weight r to get uniform in the sector wedge
274 // See https://stackoverflow.com/questions/5837572
275 double d = std::sqrt(r->GetValue());
276 double boreSight = GetAntennaOrientationRadians(cellId);
277 double halfWidth = 2 * M_PI / sectors / 2;
278 theta->SetAttribute("Min", DoubleValue(boreSight - halfWidth));
279 theta->SetAttribute("Max", DoubleValue(boreSight + halfWidth));
280 double t = theta->GetValue();
281
282 Vector utPos(cellPos);
283 utPos.x += d * cos(t);
284 utPos.y += d * sin(t);
285 utPos.z = m_utHeight;
286
287 utPositioner->Add(utPos);
288 }
289
290 std::cout << " UE mobility" << std::endl;
291 mobility.SetPositionAllocator(utPositioner);
292 mobility.Install(m_ut);
293
294 std::cout << " plot deployment" << std::endl;
295 PlotDeployment(m_bsPositioner, utPositioner, sectors, maxRadius, outerR);
296
297 m_scenarioCreated = true;
298}
299
300} // namespace ns3
~FileScenarioHelper() override
~FileScenarioHelper
void CreateScenario() override
Create the scenario, with the configured parameter.
void Add(const std::string filePath, char delimiter=',')
Add the positions listed in a file. The file should be a simple text file, with one position per line...
Vector GetSitePosition(std::size_t cellId) const
Get the site position corresponding to a given cell.
std::size_t m_numBs
Number of base stations to create.
uint16_t GetSiteIndex(std::size_t cellId) const
Gets the site index the queried cell id belongs to.
uint16_t GetCellIndex(std::size_t ueId) const
Get the cell (base station) index the queried UE id belongs to.
std::size_t m_numUt
Number of user terminals to create.
std::size_t m_numSites
Number of sites with base stations.
void SetSitesNumber(std::size_t n)
Set number of sites/towers.
double GetAntennaOrientationRadians(std::size_t cellId) const
Returns the orientation in radians of the antenna array for the given cellId.
double m_isd
Inter-site distance (ISD) in meters.
uint32_t GetNumSectorsPerSite() const
Gets the number of sectors per site.
SiteSectorizationType m_sectorization
Number of sectors per site.
double m_bsHeight
Height of gNB nodes.
double m_minBsUtDistance
Minimum distance between BS and UT in meters.
@ NONE
Unconfigured value.
double m_utHeight
Height of UE nodes.
double m_antennaOffset
Cell antenna offset in meters w.r.t. site location.
void PlotDeployment(const Ptr< const ListPositionAllocator > &sitePositioner, const Ptr< const ListPositionAllocator > &utPositioner, const std::size_t numSectors, const double maxRadius, const double effIsd)
Creates a GNUPLOT with the deployment including base stations (BS) and user terminals (UT)....