1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3 * Copyright (c) 2019 SIGNET Lab, Department of Information Engineering,
4 * University of Padova
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation;
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include "ns3/log.h"
21 #include "ns3/abort.h"
22 #include "ns3/test.h"
23 #include "ns3/config.h"
24 #include "ns3/double.h"
25 #include "ns3/channel-condition-model.h"
26 #include "ns3/constant-position-mobility-model.h"
27 #include "ns3/simulator.h"
28 #include "ns3/node-container.h"
29
30 using namespace ns3;
31
32 NS_LOG_COMPONENT_DEFINE ("ChannelConditionModelsTest");
33
34 /**
35 * Test case for the 3GPP channel condition models. It determines the
36 * channel condition multiple times, estimates the LOS probability and
37 * compares it with the value given by the formulas in 3GPP TR 38.901,
38 * Table Table 7.4.2-1.
39 */
40 class ThreeGppChannelConditionModelTestCase : public TestCase
41 {
42 public:
43 /**
44 * Constructor
45 */
46 ThreeGppChannelConditionModelTestCase ();
47
48 /**
49 * Destructor
50 */
51 virtual ~ThreeGppChannelConditionModelTestCase ();
52
53 private:
54 /**
55 * Builds the simulation scenario and perform the tests
56 */
57 virtual void DoRun (void);
58
59 /**
60 * Evaluates the channel condition between two nodes by calling the method
61 * GetChannelCondition on m_condModel. If the channel condition is LOS it
62 * increments m_numLos
63 * \param a the mobility model of the first node
64 * \param b the mobility model of the second node
65 */
66 void EvaluateChannelCondition (Ptr<MobilityModel> a, Ptr<MobilityModel> b);
67
68 /**
69 * Struct containing the parameters for each test
70 */
71 typedef struct
72 {
73 Vector m_positionA; //!< the position of the first node
74 Vector m_positionB; //!< the position of the second node
75 double m_pLos; //!< LOS probability
76 TypeId m_typeId; //!< the type ID of the channel condition model to be used
77 } TestVector;
78
79 TestVectors<TestVector> m_testVectors; //!< array containing all the test vectors
80 Ptr<ThreeGppChannelConditionModel> m_condModel; //!< the channel condition model
81 uint64_t m_numLos; //!< the number of LOS occurrences
82 double m_tolerance; //!< tolerance
83 };
84
ThreeGppChannelConditionModelTestCase()85 ThreeGppChannelConditionModelTestCase::ThreeGppChannelConditionModelTestCase ()
86 : TestCase ("Test case for the child classes of ThreeGppChannelConditionModel"),
87 m_testVectors (),
88 m_tolerance (2e-3)
89 {
90 }
91
~ThreeGppChannelConditionModelTestCase()92 ThreeGppChannelConditionModelTestCase::~ThreeGppChannelConditionModelTestCase ()
93 {
94 }
95
96 void
EvaluateChannelCondition(Ptr<MobilityModel> a,Ptr<MobilityModel> b)97 ThreeGppChannelConditionModelTestCase::EvaluateChannelCondition (Ptr<MobilityModel> a, Ptr<MobilityModel> b)
98 {
99 Ptr<ChannelCondition> cond = m_condModel->GetChannelCondition (a, b);
100 if (cond->GetLosCondition () == ChannelCondition::LosConditionValue::LOS)
101 {
102 m_numLos++;
103 }
104 }
105
106 void
DoRun(void)107 ThreeGppChannelConditionModelTestCase::DoRun (void)
108 {
109 // create the test vector
110 TestVector testVector;
111
112 // tests for the RMa scenario
113 testVector.m_positionA = Vector (0, 0, 35.0);
114 testVector.m_positionB = Vector (10, 0, 1.5);
115 testVector.m_pLos = 1;
116 testVector.m_typeId = ThreeGppRmaChannelConditionModel::GetTypeId ();
117 m_testVectors.Add (testVector);
118
119 testVector.m_positionA = Vector (0, 0, 35.0);
120 testVector.m_positionB = Vector (100, 0, 1.5);
121 testVector.m_pLos = exp (-(100.0 - 10.0) / 1000.0);
122 testVector.m_typeId = ThreeGppRmaChannelConditionModel::GetTypeId ();
123 m_testVectors.Add (testVector);
124
125 testVector.m_positionA = Vector (0, 0, 35.0);
126 testVector.m_positionB = Vector (1000, 0, 1.5);
127 testVector.m_pLos = exp (-(1000.0 - 10.0) / 1000.0);
128 testVector.m_typeId = ThreeGppRmaChannelConditionModel::GetTypeId ();
129 m_testVectors.Add (testVector);
130
131 // tests for the UMa scenario
132 testVector.m_positionA = Vector (0, 0, 25.0);
133 testVector.m_positionB = Vector (18, 0, 1.5);
134 testVector.m_pLos = 1;
135 testVector.m_typeId = ThreeGppUmaChannelConditionModel::GetTypeId ();
136 m_testVectors.Add (testVector);
137
138 testVector.m_positionA = Vector (0, 0, 25.0);
139 testVector.m_positionB = Vector (50, 0, 1.5);
140 testVector.m_pLos = (18.0 / 50.0 + exp (-50.0 / 63.0) * (1.0 - 18.0 / 50.0)) * (1.0 + 0);
141 testVector.m_typeId = ThreeGppUmaChannelConditionModel::GetTypeId ();
142 m_testVectors.Add (testVector);
143
144 testVector.m_positionA = Vector (0, 0, 25.0);
145 testVector.m_positionB = Vector (50, 0, 15);
146 testVector.m_pLos = (18.0 / 50.0 + exp (-50.0 / 63.0) * (1.0 - 18.0 / 50.0)) * (1.0 + pow (2.0 / 10.0, 1.5) * 5.0 / 4.0 * pow (50.0 / 100.0, 3) * exp (-50.0 / 150.0));
147 testVector.m_typeId = ThreeGppUmaChannelConditionModel::GetTypeId ();
148 m_testVectors.Add (testVector);
149
150 testVector.m_positionA = Vector (0, 0, 25.0);
151 testVector.m_positionB = Vector (100, 0, 1.5);
152 testVector.m_pLos = (18.0 / 100.0 + exp (-100.0 / 63.0) * (1.0 - 18.0 / 100.0)) * (1.0 + 0);
153 testVector.m_typeId = ThreeGppUmaChannelConditionModel::GetTypeId ();
154 m_testVectors.Add (testVector);
155
156 testVector.m_positionA = Vector (0, 0, 25.0);
157 testVector.m_positionB = Vector (100, 0, 15);
158 testVector.m_pLos = (18.0 / 100.0 + exp (-100.0 / 63.0) * (1.0 - 18.0 / 100.0)) * (1.0 + pow (2.0 / 10.0, 1.5) * 5.0 / 4.0 * 1.0 * exp (-100.0 / 150.0));
159 testVector.m_typeId = ThreeGppUmaChannelConditionModel::GetTypeId ();
160 m_testVectors.Add (testVector);
161
162 // tests for the UMi-Street Canyon scenario
163 testVector.m_positionA = Vector (0, 0, 10.0);
164 testVector.m_positionB = Vector (18, 0, 1.5);
165 testVector.m_pLos = 1;
166 testVector.m_typeId = ThreeGppUmiStreetCanyonChannelConditionModel::GetTypeId ();
167 m_testVectors.Add (testVector);
168
169 testVector.m_positionA = Vector (0, 0, 10.0);
170 testVector.m_positionB = Vector (50, 0, 1.5);
171 testVector.m_pLos = (18.0 / 50.0 + exp (-50.0 / 36.0) * (1.0 - 18.0 / 50.0));
172 testVector.m_typeId = ThreeGppUmiStreetCanyonChannelConditionModel::GetTypeId ();
173 m_testVectors.Add (testVector);
174
175 m_testVectors.Add (testVector);
176 testVector.m_positionA = Vector (0, 0, 10.0);
177 testVector.m_positionB = Vector (100, 0, 15);
178 testVector.m_pLos = (18.0 / 100.0 + exp (-100.0 / 36.0) * (1.0 - 18.0 / 100.0));
179 testVector.m_typeId = ThreeGppUmiStreetCanyonChannelConditionModel::GetTypeId ();
180 m_testVectors.Add (testVector);
181
182 // tests for the Indoor Mixed Office scenario
183 testVector.m_positionA = Vector (0, 0, 2.0);
184 testVector.m_positionB = Vector (1.2, 0, 1.5);
185 testVector.m_pLos = 1;
186 testVector.m_typeId = ThreeGppIndoorMixedOfficeChannelConditionModel::GetTypeId ();
187 m_testVectors.Add (testVector);
188
189 testVector.m_positionA = Vector (0, 0, 2.0);
190 testVector.m_positionB = Vector (5, 0, 1.5);
191 testVector.m_pLos = exp (-(5.0 - 1.2) / 4.7);
192 testVector.m_typeId = ThreeGppIndoorMixedOfficeChannelConditionModel::GetTypeId ();
193 m_testVectors.Add (testVector);
194
195 testVector.m_positionA = Vector (0, 0, 2.0);
196 testVector.m_positionB = Vector (10, 0, 1.5);
197 testVector.m_pLos = exp (-(10.0 - 6.5) / 32.6) * 0.32;
198 testVector.m_typeId = ThreeGppIndoorMixedOfficeChannelConditionModel::GetTypeId ();
199 m_testVectors.Add (testVector);
200
201 // tests for the Indoor Open Office scenario
202 testVector.m_positionA = Vector (0, 0, 3.0);
203 testVector.m_positionB = Vector (5, 0, 1.5);
204 testVector.m_pLos = 1;
205 testVector.m_typeId = ThreeGppIndoorOpenOfficeChannelConditionModel::GetTypeId ();
206 m_testVectors.Add (testVector);
207
208 testVector.m_positionA = Vector (0, 0, 3.0);
209 testVector.m_positionB = Vector (30, 0, 1.5);
210 testVector.m_pLos = exp (-(30.0 - 5.0) / 70.8);
211 testVector.m_typeId = ThreeGppIndoorOpenOfficeChannelConditionModel::GetTypeId ();
212 m_testVectors.Add (testVector);
213
214 testVector.m_positionA = Vector (0, 0, 3.0);
215 testVector.m_positionB = Vector (100, 0, 1.5);
216 testVector.m_pLos = exp (-(100.0 - 49.0) / 211.7) * 0.54;
217 testVector.m_typeId = ThreeGppIndoorOpenOfficeChannelConditionModel::GetTypeId ();
218 m_testVectors.Add (testVector);
219
220 // create the factory for the channel condition models
221 ObjectFactory condModelFactory;
222
223 // create the two nodes
224 NodeContainer nodes;
225 nodes.Create (2);
226
227 // create the mobility models
228 Ptr<MobilityModel> a = CreateObject<ConstantPositionMobilityModel> ();
229 Ptr<MobilityModel> b = CreateObject<ConstantPositionMobilityModel> ();
230
231 // aggregate the nodes and the mobility models
232 nodes.Get (0)->AggregateObject (a);
233 nodes.Get (1)->AggregateObject (b);
234
235 // Get the channel condition multiple times and compute the LOS probability
236 uint32_t numberOfReps = 500000;
237 for (uint32_t i = 0; i < m_testVectors.GetN (); ++i)
238 {
239 testVector = m_testVectors.Get (i);
240
241 // set the distance between the two nodes
242 a->SetPosition (testVector.m_positionA);
243 b->SetPosition (testVector.m_positionB);
244
245 // create the channel condition model
246 condModelFactory.SetTypeId (testVector.m_typeId);
247 m_condModel = condModelFactory.Create<ThreeGppChannelConditionModel> ();
248 m_condModel->SetAttribute ("UpdatePeriod", TimeValue (MilliSeconds (9)));
249
250 m_numLos = 0;
251 for (uint32_t j = 0; j < numberOfReps; j++)
252 {
253 Simulator::Schedule (MilliSeconds (10 * j), &ThreeGppChannelConditionModelTestCase::EvaluateChannelCondition, this, a, b);
254 }
255
256 Simulator::Run ();
257 Simulator::Destroy ();
258
259 double resultPlos = double (m_numLos) / double (numberOfReps);
260 NS_LOG_DEBUG (testVector.m_typeId << " a pos " << testVector.m_positionA << " b pos " << testVector.m_positionB << " numLos " << m_numLos << " numberOfReps " << numberOfReps << " resultPlos " << resultPlos << " ref " << testVector.m_pLos);
261 NS_TEST_EXPECT_MSG_EQ_TOL (resultPlos, testVector.m_pLos, m_tolerance, "Got unexpected LOS probability");
262 }
263 }
264
265 /**
266 * Test suite for the channel condition models
267 */
268 class ChannelConditionModelsTestSuite : public TestSuite
269 {
270 public:
271 ChannelConditionModelsTestSuite ();
272 };
273
ChannelConditionModelsTestSuite()274 ChannelConditionModelsTestSuite::ChannelConditionModelsTestSuite ()
275 : TestSuite ("propagation-channel-condition-model", UNIT)
276 {
277 AddTestCase (new ThreeGppChannelConditionModelTestCase, TestCase::QUICK);
278 }
279
280 static ChannelConditionModelsTestSuite ChannelConditionModelsTestSuite;
281