1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3 * Copyright (c) 2012 CTTC
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Nicola Baldo <nbaldo@cttc.es>
19 */
20
21
22 #include "radio-environment-map-helper.h"
23
24 #include <ns3/abort.h>
25 #include <ns3/log.h>
26 #include <ns3/double.h>
27 #include <ns3/integer.h>
28 #include <ns3/uinteger.h>
29 #include <ns3/string.h>
30 #include <ns3/boolean.h>
31 #include <ns3/pointer.h>
32 #include <ns3/spectrum-channel.h>
33 #include <ns3/config.h>
34 #include <ns3/rem-spectrum-phy.h>
35 #include <ns3/mobility-building-info.h>
36 #include <ns3/constant-position-mobility-model.h>
37 #include <ns3/simulator.h>
38 #include <ns3/node.h>
39 #include <ns3/buildings-helper.h>
40 #include <ns3/lte-spectrum-value-helper.h>
41
42 #include <fstream>
43 #include <limits>
44
45 namespace ns3 {
46
47 NS_LOG_COMPONENT_DEFINE ("RadioEnvironmentMapHelper");
48
49 NS_OBJECT_ENSURE_REGISTERED (RadioEnvironmentMapHelper);
50
RadioEnvironmentMapHelper()51 RadioEnvironmentMapHelper::RadioEnvironmentMapHelper ()
52 {
53 }
54
55
~RadioEnvironmentMapHelper()56 RadioEnvironmentMapHelper::~RadioEnvironmentMapHelper ()
57 {
58 }
59
60
61
62 void
DoDispose()63 RadioEnvironmentMapHelper::DoDispose ()
64 {
65 NS_LOG_FUNCTION (this);
66 }
67
68 TypeId
GetTypeId(void)69 RadioEnvironmentMapHelper::GetTypeId (void)
70 {
71 NS_LOG_FUNCTION ("RadioEnvironmentMapHelper::GetTypeId");
72 static TypeId tid = TypeId ("ns3::RadioEnvironmentMapHelper")
73 .SetParent<Object> ()
74 .SetGroupName("Lte")
75 .AddConstructor<RadioEnvironmentMapHelper> ()
76 .AddAttribute ("Channel",
77 "The DL spectrum channel for which the RadioEnvironment Map is to be generated. "
78 "Alternatively ChannelPath attribute can be used."
79 "Only one of the two (Channel or ChannelPath) should be set.",
80 PointerValue (nullptr),
81 MakePointerAccessor (&RadioEnvironmentMapHelper::m_channel),
82 MakePointerChecker<SpectrumChannel> ())
83 .AddAttribute ("ChannelPath", "The path to the channel for which the Radio Environment Map is to be generated."
84 "This attribute is an alternative to Channel attribute and is only used if Channel is not set (equal to nullptr). "
85 "Only one of the two (Channel or ChannelPath) should be set.",
86 StringValue ("/ChannelList/0"),
87 MakeStringAccessor (&RadioEnvironmentMapHelper::m_channelPath),
88 MakeStringChecker ())
89 .AddAttribute ("OutputFile", "the filename to which the Radio Environment Map is saved",
90 StringValue ("rem.out"),
91 MakeStringAccessor (&RadioEnvironmentMapHelper::m_outputFile),
92 MakeStringChecker ())
93 .AddAttribute ("XMin", "The min x coordinate of the map.",
94 DoubleValue (0.0),
95 MakeDoubleAccessor (&RadioEnvironmentMapHelper::m_xMin),
96 MakeDoubleChecker<double> ())
97 .AddAttribute ("YMin", "The min y coordinate of the map.",
98 DoubleValue (0.0),
99 MakeDoubleAccessor (&RadioEnvironmentMapHelper::m_yMin),
100 MakeDoubleChecker<double> ())
101 .AddAttribute ("XMax", "The max x coordinate of the map.",
102 DoubleValue (1.0),
103 MakeDoubleAccessor (&RadioEnvironmentMapHelper::m_xMax),
104 MakeDoubleChecker<double> ())
105 .AddAttribute ("YMax", "The max y coordinate of the map.",
106 DoubleValue (1.0),
107 MakeDoubleAccessor (&RadioEnvironmentMapHelper::m_yMax),
108 MakeDoubleChecker<double> ())
109 .AddAttribute ("XRes", "The resolution (number of points) of the map along the x axis.",
110 UintegerValue (100),
111 MakeUintegerAccessor (&RadioEnvironmentMapHelper::m_xRes),
112 MakeUintegerChecker<uint32_t> (2,std::numeric_limits<uint16_t>::max ()))
113 .AddAttribute ("YRes", "The resolution (number of points) of the map along the y axis.",
114 UintegerValue (100),
115 MakeUintegerAccessor (&RadioEnvironmentMapHelper::m_yRes),
116 MakeUintegerChecker<uint16_t> (2,std::numeric_limits<uint16_t>::max ()))
117 .AddAttribute ("Z", "The value of the z coordinate for which the map is to be generated",
118 DoubleValue (0.0),
119 MakeDoubleAccessor (&RadioEnvironmentMapHelper::m_z),
120 MakeDoubleChecker<double> ())
121 .AddAttribute ("StopWhenDone", "If true, Simulator::Stop () will be called as soon as the REM has been generated",
122 BooleanValue (true),
123 MakeBooleanAccessor (&RadioEnvironmentMapHelper::m_stopWhenDone),
124 MakeBooleanChecker ())
125 .AddAttribute ("NoisePower",
126 "the power of the measuring instrument noise, in Watts. Default to a kT of -174 dBm with a noise figure of 9 dB and a bandwidth of 25 LTE Resource Blocks",
127 DoubleValue (1.4230e-13),
128 MakeDoubleAccessor (&RadioEnvironmentMapHelper::m_noisePower),
129 MakeDoubleChecker<double> ())
130 .AddAttribute ("MaxPointsPerIteration", "Maximum number of REM points to be calculated per iteration. Every point consumes approximately 5KB of memory.",
131 UintegerValue (20000),
132 MakeUintegerAccessor (&RadioEnvironmentMapHelper::m_maxPointsPerIteration),
133 MakeUintegerChecker<uint32_t> (1,std::numeric_limits<uint32_t>::max ()))
134 .AddAttribute ("Earfcn",
135 "E-UTRA Absolute Radio Frequency Channel Number (EARFCN) "
136 "as per 3GPP 36.101 Section 5.7.3. ",
137 UintegerValue (100),
138 MakeUintegerAccessor (&RadioEnvironmentMapHelper::m_earfcn),
139 MakeUintegerChecker<uint16_t> ())
140 .AddAttribute ("Bandwidth",
141 "Transmission Bandwidth Configuration (in number of RBs) over which the SINR will be calculated",
142 UintegerValue (25),
143 MakeUintegerAccessor (&RadioEnvironmentMapHelper::SetBandwidth,
144 &RadioEnvironmentMapHelper::GetBandwidth),
145 MakeUintegerChecker<uint16_t> ())
146 .AddAttribute ("UseDataChannel",
147 "If true, REM will be generated for PDSCH and for PDCCH otherwise ",
148 BooleanValue (false),
149 MakeBooleanAccessor (&RadioEnvironmentMapHelper::m_useDataChannel),
150 MakeBooleanChecker ())
151 .AddAttribute ("RbId",
152 "Resource block Id, for which REM will be generated,"
153 "default value is -1, what means REM will be averaged from all RBs",
154 IntegerValue (-1),
155 MakeIntegerAccessor (&RadioEnvironmentMapHelper::m_rbId),
156 MakeIntegerChecker<int32_t> ())
157 ;
158 return tid;
159 }
160
161
162 uint16_t
GetBandwidth() const163 RadioEnvironmentMapHelper::GetBandwidth () const
164 {
165 return m_bandwidth;
166 }
167
168 void
SetBandwidth(uint16_t bw)169 RadioEnvironmentMapHelper::SetBandwidth (uint16_t bw)
170 {
171 switch (bw)
172 {
173 case 6:
174 case 15:
175 case 25:
176 case 50:
177 case 75:
178 case 100:
179 m_bandwidth = bw;
180 break;
181
182 default:
183 NS_FATAL_ERROR ("invalid bandwidth value " << bw);
184 break;
185 }
186 }
187
188
189
190 void
Install()191 RadioEnvironmentMapHelper::Install ()
192 {
193 NS_LOG_FUNCTION (this);
194 if (!m_rem.empty ())
195 {
196 NS_FATAL_ERROR ("only one REM supported per instance of RadioEnvironmentMapHelper");
197 }
198
199 if (m_channel == nullptr) // if Channel attribute is not set, then use the ChannelPath attribute
200 {
201 Config::MatchContainer match = Config::LookupMatches (m_channelPath);
202 if (match.GetN () != 1)
203 {
204 NS_FATAL_ERROR ("Lookup " << m_channelPath << " should have exactly one match");
205 }
206 m_channel = match.Get (0)->GetObject<SpectrumChannel> ();
207 NS_ABORT_MSG_IF (m_channel == 0, "object at " << m_channelPath << " is not of type SpectrumChannel");
208 }
209
210 m_outFile.open (m_outputFile.c_str ());
211 if (!m_outFile.is_open ())
212 {
213 NS_FATAL_ERROR ("Can't open file " << (m_outputFile));
214 return;
215 }
216
217 double startDelay = 0.0026;
218
219 if (m_useDataChannel)
220 {
221 //need time to start transmission of data channel
222 startDelay = 0.5001;
223 }
224
225 Simulator::Schedule (Seconds (startDelay),
226 &RadioEnvironmentMapHelper::DelayedInstall,
227 this);
228 }
229
230
231 void
DelayedInstall()232 RadioEnvironmentMapHelper::DelayedInstall ()
233 {
234 NS_LOG_FUNCTION (this);
235 m_xStep = (m_xMax - m_xMin)/(m_xRes-1);
236 m_yStep = (m_yMax - m_yMin)/(m_yRes-1);
237
238 if ((double)m_xRes * (double) m_yRes < (double) m_maxPointsPerIteration)
239 {
240 m_maxPointsPerIteration = m_xRes * m_yRes;
241 }
242
243 for (uint32_t i = 0; i < m_maxPointsPerIteration; ++i)
244 {
245 RemPoint p;
246 p.phy = CreateObject<RemSpectrumPhy> ();
247 p.bmm = CreateObject<ConstantPositionMobilityModel> ();
248 Ptr<MobilityBuildingInfo> buildingInfo = CreateObject<MobilityBuildingInfo> ();
249 p.bmm->AggregateObject (buildingInfo); // operation usually done by BuildingsHelper::Install
250 p.phy->SetRxSpectrumModel (LteSpectrumValueHelper::GetSpectrumModel (m_earfcn, m_bandwidth));
251 p.phy->SetMobility (p.bmm);
252 p.phy->SetUseDataChannel (m_useDataChannel);
253 p.phy->SetRbId (m_rbId);
254 m_channel->AddRx (p.phy);
255 m_rem.push_back (p);
256 }
257
258 double remIterationStartTime = 0.0001;
259 double xMinNext = m_xMin;
260 double yMinNext = m_yMin;
261 uint32_t numPointsCurrentIteration = 0;
262 bool justScheduled = false;
263 for (double x = m_xMin; x < m_xMax + 0.5*m_xStep; x += m_xStep)
264 {
265 for (double y = m_yMin; y < m_yMax + 0.5*m_yStep ; y += m_yStep)
266 {
267 if (justScheduled)
268 {
269 xMinNext = x;
270 yMinNext = y;
271 justScheduled = false;
272 }
273
274 ++numPointsCurrentIteration;
275 if ((numPointsCurrentIteration == m_maxPointsPerIteration)
276 || ((x > m_xMax - 0.5*m_xStep) && (y > m_yMax - 0.5*m_yStep)) )
277 {
278 Simulator::Schedule (Seconds (remIterationStartTime),
279 &RadioEnvironmentMapHelper::RunOneIteration,
280 this, xMinNext, x, yMinNext, y);
281 remIterationStartTime += 0.001;
282 justScheduled = true;
283 numPointsCurrentIteration = 0;
284 }
285 }
286 }
287
288 Simulator::Schedule (Seconds (remIterationStartTime),
289 &RadioEnvironmentMapHelper::Finalize,
290 this);
291 }
292
293
294 void
RunOneIteration(double xMin,double xMax,double yMin,double yMax)295 RadioEnvironmentMapHelper::RunOneIteration (double xMin, double xMax, double yMin, double yMax)
296 {
297 NS_LOG_FUNCTION (this << xMin << xMax << yMin << yMax);
298 std::list<RemPoint>::iterator remIt = m_rem.begin ();
299 double x = 0.0;
300 double y = 0.0;
301 for (x = xMin; x < xMax + 0.5*m_xStep; x += m_xStep)
302 {
303 for (y = (x == xMin) ? yMin : m_yMin;
304 y < ((x == xMax) ? yMax : m_yMax) + 0.5*m_yStep;
305 y += m_yStep)
306 {
307 NS_ASSERT (remIt != m_rem.end ());
308 remIt->bmm->SetPosition (Vector (x, y, m_z));
309 Ptr <MobilityBuildingInfo> buildingInfo = (remIt->bmm)->GetObject <MobilityBuildingInfo> ();
310 buildingInfo->MakeConsistent (remIt->bmm);
311 ++remIt;
312 }
313 }
314
315 if (remIt != m_rem.end ())
316 {
317 NS_ASSERT ((x > m_xMax - 0.5*m_xStep) && (y > m_yMax - 0.5*m_yStep));
318 NS_LOG_LOGIC ("deactivating RemSpectrumPhys that are unneeded in the last iteration");
319 while (remIt != m_rem.end ())
320 {
321 remIt->phy->Deactivate ();
322 ++remIt;
323 }
324 }
325
326 Simulator::Schedule (Seconds (0.0005), &RadioEnvironmentMapHelper::PrintAndReset, this);
327 }
328
329 void
PrintAndReset()330 RadioEnvironmentMapHelper::PrintAndReset ()
331 {
332 NS_LOG_FUNCTION (this);
333
334 for (std::list<RemPoint>::iterator it = m_rem.begin ();
335 it != m_rem.end ();
336 ++it)
337 {
338 if (!(it->phy->IsActive ()))
339 {
340 // should occur only upon last iteration when some RemPoint
341 // at the end of the list can be unused
342 break;
343 }
344 Vector pos = it->bmm->GetPosition ();
345 NS_LOG_LOGIC ("output: " << pos.x << "\t"
346 << pos.y << "\t"
347 << pos.z << "\t"
348 << it->phy->GetSinr (m_noisePower));
349 m_outFile << pos.x << "\t"
350 << pos.y << "\t"
351 << pos.z << "\t"
352 << it->phy->GetSinr (m_noisePower)
353 << std::endl;
354 it->phy->Reset ();
355 }
356 }
357
358 void
Finalize()359 RadioEnvironmentMapHelper::Finalize ()
360 {
361 NS_LOG_FUNCTION (this);
362 m_outFile.close ();
363 if (m_stopWhenDone)
364 {
365 Simulator::Stop ();
366 }
367 }
368
369
370 } // namespace ns3
371