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