A Discrete-Event Network Simulator
API
three-gpp-channel-model.cc
Go to the documentation of this file.
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  * Copyright (c) 2015, NYU WIRELESS, Tandon School of Engineering,
6  * New York University
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation;
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  */
22 
24 #include "ns3/log.h"
25 #include "ns3/phased-array-model.h"
26 #include "ns3/node.h"
27 #include "ns3/double.h"
28 #include "ns3/string.h"
29 #include "ns3/integer.h"
30 #include <algorithm>
31 #include <random>
32 #include "ns3/log.h"
33 #include <ns3/simulator.h>
34 #include "ns3/mobility-model.h"
35 #include "ns3/pointer.h"
36 
37 namespace ns3 {
38 
39 NS_LOG_COMPONENT_DEFINE ("ThreeGppChannelModel");
40 
41 NS_OBJECT_ENSURE_REGISTERED (ThreeGppChannelModel);
42 
43 //Table 7.5-3: Ray offset angles within a cluster, given for rms angle spread normalized to 1.
44 static const double offSetAlpha[20] = {
45  0.0447,-0.0447,0.1413,-0.1413,0.2492,-0.2492,0.3715,-0.3715,0.5129,-0.5129,0.6797,-0.6797,0.8844,-0.8844,1.1481,-1.1481,1.5195,-1.5195,2.1551,-2.1551
46 };
47 
48 /*
49  * The cross correlation matrix is constructed according to table 7.5-6.
50  * All the square root matrix is being generated using the Cholesky decomposition
51  * and following the order of [SF,K,DS,ASD,ASA,ZSD,ZSA].
52  * The parameter K is ignored in NLOS.
53  *
54  * The Matlab file to generate the matrices can be found in
55  * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m
56  *
57  */
58 static const double sqrtC_RMa_LOS[7][7] = {
59  {1, 0, 0, 0, 0, 0, 0},
60  {0, 1, 0, 0, 0, 0, 0},
61  {-0.5, 0, 0.866025, 0, 0, 0, 0},
62  {0, 0, 0, 1, 0, 0, 0},
63  {0, 0, 0, 0, 1, 0, 0},
64  {0.01, 0, -0.0519615, 0.73, -0.2, 0.651383, 0},
65  {-0.17, -0.02, 0.21362, -0.14, 0.24, 0.142773, 0.909661},
66 };
67 
68 static const double sqrtC_RMa_NLOS[6][6] = {
69  {1, 0, 0, 0, 0, 0},
70  {-0.5, 0.866025, 0, 0, 0, 0},
71  {0.6, -0.11547, 0.791623, 0, 0, 0},
72  {0, 0, 0, 1, 0, 0},
73  {-0.04, -0.138564, 0.540662, -0.18, 0.809003, 0},
74  {-0.25, -0.606218, -0.240013, 0.26, -0.231685, 0.625392},
75 };
76 
77 static const double sqrtC_RMa_O2I[6][6] = {
78  {1, 0, 0, 0, 0, 0},
79  {0, 1, 0, 0, 0, 0},
80  {0, 0, 1, 0, 0, 0},
81  {0, 0, -0.7, 0.714143, 0, 0},
82  {0, 0, 0.66, -0.123225, 0.741091, 0},
83  {0, 0, 0.47, 0.152631, -0.393194, 0.775373},
84 };
85 
86 static const double sqrtC_UMa_LOS[7][7] = {
87  {1, 0, 0, 0, 0, 0, 0},
88  {0, 1, 0, 0, 0, 0, 0},
89  {-0.4, -0.4, 0.824621, 0, 0, 0, 0},
90  {-0.5, 0, 0.242536, 0.83137, 0, 0, 0},
91  {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0},
92  {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0},
93  {-0.8, 0, -0.388057, -0.367926, 0.238537, -3.58949e-15, 0.130931},
94 };
95 
96 
97 static const double sqrtC_UMa_NLOS[6][6] = {
98  {1, 0, 0, 0, 0, 0},
99  {-0.4, 0.916515, 0, 0, 0, 0},
100  {-0.6, 0.174574, 0.78072, 0, 0, 0},
101  {0, 0.654654, 0.365963, 0.661438, 0, 0},
102  {0, -0.545545, 0.762422, 0.118114, 0.327327, 0},
103  {-0.4, -0.174574, -0.396459, 0.392138, 0.49099, 0.507445},
104 };
105 
106 static const double sqrtC_UMa_O2I[6][6] = {
107  {1, 0, 0, 0, 0, 0},
108  {-0.5, 0.866025, 0, 0, 0, 0},
109  {0.2, 0.57735, 0.791623, 0, 0, 0},
110  {0, 0.46188, -0.336861, 0.820482, 0, 0},
111  {0, -0.69282, 0.252646, 0.493742, 0.460857, 0},
112  {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515},
113 
114 };
115 
116 static const double sqrtC_UMi_LOS[7][7] = {
117  {1, 0, 0, 0, 0, 0, 0},
118  {0.5, 0.866025, 0, 0, 0, 0, 0},
119  {-0.4, -0.57735, 0.711805, 0, 0, 0, 0},
120  {-0.5, 0.057735, 0.468293, 0.726201, 0, 0, 0},
121  {-0.4, -0.11547, 0.805464, -0.23482, 0.350363, 0, 0},
122  {0, 0, 0, 0.688514, 0.461454, 0.559471, 0},
123  {0, 0, 0.280976, 0.231921, -0.490509, 0.11916, 0.782603},
124 };
125 
126 static const double sqrtC_UMi_NLOS[6][6] = {
127  {1, 0, 0, 0, 0, 0},
128  {-0.7, 0.714143, 0, 0, 0, 0},
129  {0, 0, 1, 0, 0, 0},
130  {-0.4, 0.168034, 0, 0.90098, 0, 0},
131  {0, -0.70014, 0.5, 0.130577, 0.4927, 0},
132  {0, 0, 0.5, 0.221981, -0.566238, 0.616522},
133 };
134 
135 static const double sqrtC_UMi_O2I[6][6] = {
136  {1, 0, 0, 0, 0, 0},
137  {-0.5, 0.866025, 0, 0, 0, 0},
138  {0.2, 0.57735, 0.791623, 0, 0, 0},
139  {0, 0.46188, -0.336861, 0.820482, 0, 0},
140  {0, -0.69282, 0.252646, 0.493742, 0.460857, 0},
141  {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515},
142 };
143 
144 static const double sqrtC_office_LOS[7][7] = {
145  {1, 0, 0, 0, 0, 0, 0},
146  {0.5, 0.866025, 0, 0, 0, 0, 0},
147  {-0.8, -0.11547, 0.588784, 0, 0, 0, 0},
148  {-0.4, 0.23094, 0.520847, 0.717903, 0, 0, 0},
149  {-0.5, 0.288675, 0.73598, -0.348236, 0.0610847, 0, 0},
150  {0.2, -0.11547, 0.418943, 0.541106, 0.219905, 0.655744, 0},
151  {0.3, -0.057735, 0.73598, -0.348236, 0.0610847, -0.304997, 0.383375},
152 };
153 
154 static const double sqrtC_office_NLOS[6][6] = {
155  {1, 0, 0, 0, 0, 0},
156  {-0.5, 0.866025, 0, 0, 0, 0},
157  {0, 0.46188, 0.886942, 0, 0, 0},
158  {-0.4, -0.23094, 0.120263, 0.878751, 0, 0},
159  {0, -0.311769, 0.55697, -0.249198, 0.728344, 0},
160  {0, -0.069282, 0.295397, 0.430696, 0.468462, 0.709214},
161 };
162 
164 {
165  NS_LOG_FUNCTION (this);
166  m_uniformRv = CreateObject<UniformRandomVariable> ();
167  m_uniformRvShuffle = CreateObject<UniformRandomVariable> ();
168 
169  m_normalRv = CreateObject<NormalRandomVariable> ();
170  m_normalRv->SetAttribute ("Mean", DoubleValue (0.0));
171  m_normalRv->SetAttribute ("Variance", DoubleValue (1.0));
172 }
173 
175 {
176  NS_LOG_FUNCTION (this);
177 }
178 
179 void
181 {
182  NS_LOG_FUNCTION (this);
183  m_channelMap.clear ();
185  {
186  m_channelConditionModel->Dispose ();
187  }
188  m_channelConditionModel = nullptr;
189 }
190 
191 TypeId
193 {
194  static TypeId tid = TypeId ("ns3::ThreeGppChannelModel")
195  .SetParent<Object> ()
196  .SetGroupName ("Spectrum")
197  .SetParent<MatrixBasedChannelModel> ()
198  .AddConstructor<ThreeGppChannelModel> ()
199  .AddAttribute ("Frequency",
200  "The operating Frequency in Hz",
201  DoubleValue (500.0e6),
204  MakeDoubleChecker<double> ())
205  .AddAttribute ("Scenario",
206  "The 3GPP scenario (RMa, UMa, UMi-StreetCanyon, InH-OfficeOpen, InH-OfficeMixed)",
207  StringValue ("UMa"),
211  .AddAttribute ("ChannelConditionModel",
212  "Pointer to the channel condition model",
213  PointerValue (),
216  MakePointerChecker<ChannelConditionModel> ())
217  .AddAttribute ("UpdatePeriod",
218  "Specify the channel coherence time",
219  TimeValue (MilliSeconds (0)),
221  MakeTimeChecker ())
222  // attributes for the blockage model
223  .AddAttribute ("Blockage",
224  "Enable blockage model A (sec 7.6.4.1)",
225  BooleanValue (false),
228  .AddAttribute ("NumNonselfBlocking",
229  "number of non-self-blocking regions",
230  IntegerValue (4),
232  MakeIntegerChecker<uint16_t> ())
233  .AddAttribute ("PortraitMode",
234  "true for portrait mode, false for landscape mode",
235  BooleanValue (true),
238  .AddAttribute ("BlockerSpeed",
239  "The speed of moving blockers, the unit is m/s",
240  DoubleValue (1),
242  MakeDoubleChecker<double> ())
243  ;
244  return tid;
245 }
246 
247 void
249 {
250  NS_LOG_FUNCTION (this);
251  m_channelConditionModel = model;
252 }
253 
256 {
257  NS_LOG_FUNCTION (this);
259 }
260 
261 void
263 {
264  NS_LOG_FUNCTION (this);
265  NS_ASSERT_MSG (f >= 500.0e6 && f <= 100.0e9, "Frequency should be between 0.5 and 100 GHz but is " << f);
266  m_frequency = f;
267 }
268 
269 double
271 {
272  NS_LOG_FUNCTION (this);
273  return m_frequency;
274 }
275 
276 void
277 ThreeGppChannelModel::SetScenario (const std::string &scenario)
278 {
279  NS_LOG_FUNCTION (this);
280  NS_ASSERT_MSG (scenario == "RMa" || scenario == "UMa" || scenario == "UMi-StreetCanyon"
281  || scenario == "InH-OfficeOpen" || scenario == "InH-OfficeMixed"
282  || scenario == "V2V-Urban" || scenario == "V2V-Highway",
283  "Unknown scenario, choose between RMa, UMa, UMi-StreetCanyon,"
284  "InH-OfficeOpen, InH-OfficeMixed, V2V-Urban or V2V-Highway");
285  m_scenario = scenario;
286 }
287 
288 std::string
290 {
291  NS_LOG_FUNCTION (this);
292  return m_scenario;
293 }
294 
296 ThreeGppChannelModel::GetThreeGppTable (Ptr<const ChannelCondition> channelCondition, double hBS, double hUT, double distance2D) const
297 {
298  NS_LOG_FUNCTION (this);
299 
300  double fcGHz = m_frequency / 1e9;
301  Ptr<ParamsTable> table3gpp = Create<ParamsTable> ();
302  // table3gpp includes the following parameters:
303  // numOfCluster, raysPerCluster, uLgDS, sigLgDS, uLgASD, sigLgASD,
304  // uLgASA, sigLgASA, uLgZSA, sigLgZSA, uLgZSD, sigLgZSD, offsetZOD,
305  // cDS, cASD, cASA, cZSA, uK, sigK, rTau, uXpr, sigXpr, shadowingStd
306 
307  bool los = channelCondition->IsLos ();
308  bool o2i = channelCondition->IsO2i ();
309 
310  // In NLOS case, parameter uK and sigK are not used and they are set to 0
311  if (m_scenario == "RMa")
312  {
313  if (los && !o2i)
314  {
315  // 3GPP mentioned that 3.91 ns should be used when the Cluster DS (cDS)
316  // entry is N/A.
317  table3gpp->m_numOfCluster = 11;
318  table3gpp->m_raysPerCluster = 20;
319  table3gpp->m_uLgDS = -7.49;
320  table3gpp->m_sigLgDS = 0.55;
321  table3gpp->m_uLgASD = 0.90;
322  table3gpp->m_sigLgASD = 0.38;
323  table3gpp->m_uLgASA = 1.52;
324  table3gpp->m_sigLgASA = 0.24;
325  table3gpp->m_uLgZSA = 0.47;
326  table3gpp->m_sigLgZSA = 0.40;
327  table3gpp->m_uLgZSD = 0.34;
328  table3gpp->m_sigLgZSD = std::max (-1.0, -0.17 * (distance2D / 1000) - 0.01 * (hUT - 1.5) + 0.22);
329  table3gpp->m_offsetZOD = 0;
330  table3gpp->m_cDS = 3.91e-9;
331  table3gpp->m_cASD = 2;
332  table3gpp->m_cASA = 3;
333  table3gpp->m_cZSA = 3;
334  table3gpp->m_uK = 7;
335  table3gpp->m_sigK = 4;
336  table3gpp->m_rTau = 3.8;
337  table3gpp->m_uXpr = 12;
338  table3gpp->m_sigXpr = 4;
339  table3gpp->m_perClusterShadowingStd = 3;
340 
341  for (uint8_t row = 0; row < 7; row++)
342  {
343  for (uint8_t column = 0; column < 7; column++)
344  {
345  table3gpp->m_sqrtC[row][column] = sqrtC_RMa_LOS[row][column];
346  }
347  }
348  }
349  else if (!los && !o2i)
350  {
351  table3gpp->m_numOfCluster = 10;
352  table3gpp->m_raysPerCluster = 20;
353  table3gpp->m_uLgDS = -7.43;
354  table3gpp->m_sigLgDS = 0.48;
355  table3gpp->m_uLgASD = 0.95;
356  table3gpp->m_sigLgASD = 0.45;
357  table3gpp->m_uLgASA = 1.52;
358  table3gpp->m_sigLgASA = 0.13;
359  table3gpp->m_uLgZSA = 0.58,
360  table3gpp->m_sigLgZSA = 0.37;
361  table3gpp->m_uLgZSD = std::max (-1.0, -0.19 * (distance2D / 1000) - 0.01 * (hUT - 1.5) + 0.28);
362  table3gpp->m_sigLgZSD = 0.30;
363  table3gpp->m_offsetZOD = atan ((35 - 3.5) / distance2D) - atan ((35 - 1.5) / distance2D);
364  table3gpp->m_cDS = 3.91e-9;
365  table3gpp->m_cASD = 2;
366  table3gpp->m_cASA = 3;
367  table3gpp->m_cZSA = 3;
368  table3gpp->m_uK = 0;
369  table3gpp->m_sigK = 0;
370  table3gpp->m_rTau = 1.7;
371  table3gpp->m_uXpr = 7;
372  table3gpp->m_sigXpr = 3;
373  table3gpp->m_perClusterShadowingStd = 3;
374 
375  for (uint8_t row = 0; row < 6; row++)
376  {
377  for (uint8_t column = 0; column < 6; column++)
378  {
379  table3gpp->m_sqrtC[row][column] = sqrtC_RMa_NLOS[row][column];
380  }
381  }
382  }
383  else // o2i
384  {
385  table3gpp->m_numOfCluster = 10;
386  table3gpp->m_raysPerCluster = 20;
387  table3gpp->m_uLgDS = -7.47;
388  table3gpp->m_sigLgDS = 0.24;
389  table3gpp->m_uLgASD = 0.67;
390  table3gpp->m_sigLgASD = 0.18;
391  table3gpp->m_uLgASA = 1.66;
392  table3gpp->m_sigLgASA = 0.21;
393  table3gpp->m_uLgZSA = 0.93,
394  table3gpp->m_sigLgZSA = 0.22;
395  table3gpp->m_uLgZSD = std::max (-1.0, -0.19 * (distance2D / 1000) - 0.01 * (hUT - 1.5) + 0.28);
396  table3gpp->m_sigLgZSD = 0.30;
397  table3gpp->m_offsetZOD = atan ((35 - 3.5) / distance2D) - atan ((35 - 1.5) / distance2D);
398  table3gpp->m_cDS = 3.91e-9;
399  table3gpp->m_cASD = 2;
400  table3gpp->m_cASA = 3;
401  table3gpp->m_cZSA = 3;
402  table3gpp->m_uK = 0;
403  table3gpp->m_sigK = 0;
404  table3gpp->m_rTau = 1.7;
405  table3gpp->m_uXpr = 7;
406  table3gpp->m_sigXpr = 3;
407  table3gpp->m_perClusterShadowingStd = 3;
408 
409  for (uint8_t row = 0; row < 6; row++)
410  {
411  for (uint8_t column = 0; column < 6; column++)
412  {
413  table3gpp->m_sqrtC[row][column] = sqrtC_RMa_O2I[row][column];
414  }
415  }
416  }
417  }
418  else if (m_scenario == "UMa")
419  {
420  if (los && !o2i)
421  {
422  table3gpp->m_numOfCluster = 12;
423  table3gpp->m_raysPerCluster = 20;
424  table3gpp->m_uLgDS = -6.955 - 0.0963 * log10 (fcGHz);
425  table3gpp->m_sigLgDS = 0.66;
426  table3gpp->m_uLgASD = 1.06 + 0.1114 * log10 (fcGHz);
427  table3gpp->m_sigLgASD = 0.28;
428  table3gpp->m_uLgASA = 1.81;
429  table3gpp->m_sigLgASA = 0.20;
430  table3gpp->m_uLgZSA = 0.95;
431  table3gpp->m_sigLgZSA = 0.16;
432  table3gpp->m_uLgZSD = std::max (-0.5, -2.1 * distance2D / 1000 - 0.01 * (hUT - 1.5) + 0.75);
433  table3gpp->m_sigLgZSD = 0.40;
434  table3gpp->m_offsetZOD = 0;
435  table3gpp->m_cDS = std::max (0.25, -3.4084 * log10 (fcGHz) + 6.5622) * 1e-9;
436  table3gpp->m_cASD = 5;
437  table3gpp->m_cASA = 11;
438  table3gpp->m_cZSA = 7;
439  table3gpp->m_uK = 9;
440  table3gpp->m_sigK = 3.5;
441  table3gpp->m_rTau = 2.5;
442  table3gpp->m_uXpr = 8;
443  table3gpp->m_sigXpr = 4;
444  table3gpp->m_perClusterShadowingStd = 3;
445 
446  for (uint8_t row = 0; row < 7; row++)
447  {
448  for (uint8_t column = 0; column < 7; column++)
449  {
450  table3gpp->m_sqrtC[row][column] = sqrtC_UMa_LOS[row][column];
451  }
452  }
453  }
454  else
455  {
456  double uLgZSD = std::max (-0.5, -2.1 * distance2D / 1000 - 0.01 * (hUT - 1.5) + 0.9);
457 
458  double afc = 0.208 * log10 (fcGHz) - 0.782;
459  double bfc = 25;
460  double cfc = -0.13 * log10 (fcGHz) + 2.03;
461  double efc = 7.66 * log10 (fcGHz) - 5.96;
462 
463  double offsetZOD = efc - std::pow (10, afc * log10 (std::max (bfc,distance2D)) + cfc);
464 
465  if (!los && !o2i)
466  {
467  table3gpp->m_numOfCluster = 20;
468  table3gpp->m_raysPerCluster = 20;
469  table3gpp->m_uLgDS = -6.28 - 0.204 * log10 (fcGHz);
470  table3gpp->m_sigLgDS = 0.39;
471  table3gpp->m_uLgASD = 1.5 - 0.1144 * log10 (fcGHz);
472  table3gpp->m_sigLgASD = 0.28;
473  table3gpp->m_uLgASA = 2.08 - 0.27 * log10 (fcGHz);
474  table3gpp->m_sigLgASA = 0.11;
475  table3gpp->m_uLgZSA = -0.3236 * log10 (fcGHz) + 1.512;
476  table3gpp->m_sigLgZSA = 0.16;
477  table3gpp->m_uLgZSD = uLgZSD;
478  table3gpp->m_sigLgZSD = 0.49;
479  table3gpp->m_offsetZOD = offsetZOD;
480  table3gpp->m_cDS = std::max (0.25, -3.4084 * log10 (fcGHz) + 6.5622) * 1e-9;
481  table3gpp->m_cASD = 2;
482  table3gpp->m_cASA = 15;
483  table3gpp->m_cZSA = 7;
484  table3gpp->m_uK = 0;
485  table3gpp->m_sigK = 0;
486  table3gpp->m_rTau = 2.3;
487  table3gpp->m_uXpr = 7;
488  table3gpp->m_sigXpr = 3;
489  table3gpp->m_perClusterShadowingStd = 3;
490 
491  for (uint8_t row = 0; row < 6; row++)
492  {
493  for (uint8_t column = 0; column < 6; column++)
494  {
495  table3gpp->m_sqrtC[row][column] = sqrtC_UMa_NLOS[row][column];
496  }
497  }
498  }
499  else //(o2i)
500  {
501  table3gpp->m_numOfCluster = 12;
502  table3gpp->m_raysPerCluster = 20;
503  table3gpp->m_uLgDS = -6.62;
504  table3gpp->m_sigLgDS = 0.32;
505  table3gpp->m_uLgASD = 1.25;
506  table3gpp->m_sigLgASD = 0.42;
507  table3gpp->m_uLgASA = 1.76;
508  table3gpp->m_sigLgASA = 0.16;
509  table3gpp->m_uLgZSA = 1.01;
510  table3gpp->m_sigLgZSA = 0.43;
511  table3gpp->m_uLgZSD = uLgZSD;
512  table3gpp->m_sigLgZSD = 0.49;
513  table3gpp->m_offsetZOD = offsetZOD;
514  table3gpp->m_cDS = 11e-9;
515  table3gpp->m_cASD = 5;
516  table3gpp->m_cASA = 8;
517  table3gpp->m_cZSA = 3;
518  table3gpp->m_uK = 0;
519  table3gpp->m_sigK = 0;
520  table3gpp->m_rTau = 2.2;
521  table3gpp->m_uXpr = 9;
522  table3gpp->m_sigXpr = 5;
523  table3gpp->m_perClusterShadowingStd = 4;
524 
525  for (uint8_t row = 0; row < 6; row++)
526  {
527  for (uint8_t column = 0; column < 6; column++)
528  {
529  table3gpp->m_sqrtC[row][column] = sqrtC_UMa_O2I[row][column];
530  }
531  }
532 
533  }
534 
535  }
536 
537  }
538  else if (m_scenario == "UMi-StreetCanyon")
539  {
540  if (los && !o2i)
541  {
542  table3gpp->m_numOfCluster = 12;
543  table3gpp->m_raysPerCluster = 20;
544  table3gpp->m_uLgDS = -0.24 * log10 (1 + fcGHz) - 7.14;
545  table3gpp->m_sigLgDS = 0.38;
546  table3gpp->m_uLgASD = -0.05 * log10 (1 + fcGHz) + 1.21;
547  table3gpp->m_sigLgASD = 0.41;
548  table3gpp->m_uLgASA = -0.08 * log10 (1 + fcGHz) + 1.73;
549  table3gpp->m_sigLgASA = 0.014 * log10 (1 + fcGHz) + 0.28;
550  table3gpp->m_uLgZSA = -0.1 * log10 (1 + fcGHz) + 0.73;
551  table3gpp->m_sigLgZSA = -0.04 * log10 (1 + fcGHz) + 0.34;
552  table3gpp->m_uLgZSD = std::max (-0.21, -14.8 * distance2D / 1000 + 0.01 * std::abs (hUT - hBS) + 0.83);
553  table3gpp->m_sigLgZSD = 0.35;
554  table3gpp->m_offsetZOD = 0;
555  table3gpp->m_cDS = 5e-9;
556  table3gpp->m_cASD = 3;
557  table3gpp->m_cASA = 17;
558  table3gpp->m_cZSA = 7;
559  table3gpp->m_uK = 9;
560  table3gpp->m_sigK = 5;
561  table3gpp->m_rTau = 3;
562  table3gpp->m_uXpr = 9;
563  table3gpp->m_sigXpr = 3;
564  table3gpp->m_perClusterShadowingStd = 3;
565 
566  for (uint8_t row = 0; row < 7; row++)
567  {
568  for (uint8_t column = 0; column < 7; column++)
569  {
570  table3gpp->m_sqrtC[row][column] = sqrtC_UMi_LOS[row][column];
571  }
572  }
573  }
574  else
575  {
576  double uLgZSD = std::max (-0.5, -3.1 * distance2D / 1000 + 0.01 * std::max (hUT - hBS,0.0) + 0.2);
577  double offsetZOD = -1 * std::pow (10, -1.5 * log10 (std::max (10.0, distance2D)) + 3.3);
578  if (!los && !o2i)
579  {
580  table3gpp->m_numOfCluster = 19;
581  table3gpp->m_raysPerCluster = 20;
582  table3gpp->m_uLgDS = -0.24 * log10 (1 + fcGHz) - 6.83;
583  table3gpp->m_sigLgDS = 0.16 * log10 (1 + fcGHz) + 0.28;
584  table3gpp->m_uLgASD = -0.23 * log10 (1 + fcGHz) + 1.53;
585  table3gpp->m_sigLgASD = 0.11 * log10 (1 + fcGHz) + 0.33;
586  table3gpp->m_uLgASA = -0.08 * log10 (1 + fcGHz) + 1.81;
587  table3gpp->m_sigLgASA = 0.05 * log10 (1 + fcGHz) + 0.3;
588  table3gpp->m_uLgZSA = -0.04 * log10 (1 + fcGHz) + 0.92;
589  table3gpp->m_sigLgZSA = -0.07 * log10 (1 + fcGHz) + 0.41;
590  table3gpp->m_uLgZSD = uLgZSD;
591  table3gpp->m_sigLgZSD = 0.35;
592  table3gpp->m_offsetZOD = offsetZOD;
593  table3gpp->m_cDS = 11e-9;
594  table3gpp->m_cASD = 10;
595  table3gpp->m_cASA = 22;
596  table3gpp->m_cZSA = 7;
597  table3gpp->m_uK = 0;
598  table3gpp->m_sigK = 0;
599  table3gpp->m_rTau = 2.1;
600  table3gpp->m_uXpr = 8;
601  table3gpp->m_sigXpr = 3;
602  table3gpp->m_perClusterShadowingStd = 3;
603 
604  for (uint8_t row = 0; row < 6; row++)
605  {
606  for (uint8_t column = 0; column < 6; column++)
607  {
608  table3gpp->m_sqrtC[row][column] = sqrtC_UMi_NLOS[row][column];
609  }
610  }
611  }
612  else //(o2i)
613  {
614  table3gpp->m_numOfCluster = 12;
615  table3gpp->m_raysPerCluster = 20;
616  table3gpp->m_uLgDS = -6.62;
617  table3gpp->m_sigLgDS = 0.32;
618  table3gpp->m_uLgASD = 1.25;
619  table3gpp->m_sigLgASD = 0.42;
620  table3gpp->m_uLgASA = 1.76;
621  table3gpp->m_sigLgASA = 0.16;
622  table3gpp->m_uLgZSA = 1.01;
623  table3gpp->m_sigLgZSA = 0.43;
624  table3gpp->m_uLgZSD = uLgZSD;
625  table3gpp->m_sigLgZSD = 0.35;
626  table3gpp->m_offsetZOD = offsetZOD;
627  table3gpp->m_cDS = 11e-9;
628  table3gpp->m_cASD = 5;
629  table3gpp->m_cASA = 8;
630  table3gpp->m_cZSA = 3;
631  table3gpp->m_uK = 0;
632  table3gpp->m_sigK = 0;
633  table3gpp->m_rTau = 2.2;
634  table3gpp->m_uXpr = 9;
635  table3gpp->m_sigXpr = 5;
636  table3gpp->m_perClusterShadowingStd = 4;
637 
638  for (uint8_t row = 0; row < 6; row++)
639  {
640  for (uint8_t column = 0; column < 6; column++)
641  {
642  table3gpp->m_sqrtC[row][column] = sqrtC_UMi_O2I[row][column];
643  }
644  }
645  }
646  }
647  }
648  else if (m_scenario == "InH-OfficeMixed"||m_scenario == "InH-OfficeOpen")
649  {
650  NS_ASSERT_MSG (!o2i, "The indoor scenario does out support outdoor to indoor");
651  if (los)
652  {
653  table3gpp->m_numOfCluster = 15;
654  table3gpp->m_raysPerCluster = 20;
655  table3gpp->m_uLgDS = -0.01 * log10 (1 + fcGHz) - 7.692;
656  table3gpp->m_sigLgDS = 0.18;
657  table3gpp->m_uLgASD = 1.60;
658  table3gpp->m_sigLgASD = 0.18;
659  table3gpp->m_uLgASA = -0.19 * log10 (1 + fcGHz) + 1.781;
660  table3gpp->m_sigLgASA = 0.12 * log10 (1 + fcGHz) + 0.119;
661  table3gpp->m_uLgZSA = -0.26 * log10 (1 + fcGHz) + 1.44;
662  table3gpp->m_sigLgZSA = -0.04 * log10 (1 + fcGHz) + 0.264;
663  table3gpp->m_uLgZSD = -1.43 * log10 (1 + fcGHz) + 2.228;
664  table3gpp->m_sigLgZSD = 0.13 * log10 (1 + fcGHz) + 0.30;
665  table3gpp->m_offsetZOD = 0;
666  table3gpp->m_cDS = 3.91e-9;
667  table3gpp->m_cASD = 5;
668  table3gpp->m_cASA = 8;
669  table3gpp->m_cZSA = 9;
670  table3gpp->m_uK = 7;
671  table3gpp->m_sigK = 4;
672  table3gpp->m_rTau = 3.6;
673  table3gpp->m_uXpr = 11;
674  table3gpp->m_sigXpr = 4;
675  table3gpp->m_perClusterShadowingStd = 6;
676 
677  for (uint8_t row = 0; row < 7; row++)
678  {
679  for (uint8_t column = 0; column < 7; column++)
680  {
681  table3gpp->m_sqrtC[row][column] = sqrtC_office_LOS[row][column];
682  }
683  }
684  }
685  else
686  {
687  table3gpp->m_numOfCluster = 19;
688  table3gpp->m_raysPerCluster = 20;
689  table3gpp->m_uLgDS = -0.28 * log10 (1 + fcGHz) - 7.173;
690  table3gpp->m_sigLgDS = 0.1 * log10 (1 + fcGHz) + 0.055;
691  table3gpp->m_uLgASD = 1.62;
692  table3gpp->m_sigLgASD = 0.25;
693  table3gpp->m_uLgASA = -0.11 * log10 (1 + fcGHz) + 1.863;
694  table3gpp->m_sigLgASA = 0.12 * log10 (1 + fcGHz) + 0.059;
695  table3gpp->m_uLgZSA = -0.15 * log10 (1 + fcGHz) + 1.387;
696  table3gpp->m_sigLgZSA = -0.09 * log10 (1 + fcGHz) + 0.746;
697  table3gpp->m_uLgZSD = 1.08;
698  table3gpp->m_sigLgZSD = 0.36;
699  table3gpp->m_offsetZOD = 0;
700  table3gpp->m_cDS = 3.91e-9;
701  table3gpp->m_cASD = 5;
702  table3gpp->m_cASA = 11;
703  table3gpp->m_cZSA = 9;
704  table3gpp->m_uK = 0;
705  table3gpp->m_sigK = 0;
706  table3gpp->m_rTau = 3;
707  table3gpp->m_uXpr = 10;
708  table3gpp->m_sigXpr = 4;
709  table3gpp->m_perClusterShadowingStd = 3;
710 
711  for (uint8_t row = 0; row < 6; row++)
712  {
713  for (uint8_t column = 0; column < 6; column++)
714  {
715  table3gpp->m_sqrtC[row][column] = sqrtC_office_NLOS[row][column];
716  }
717  }
718  }
719  }
720  else if (m_scenario == "V2V-Urban")
721  {
722  if (channelCondition->IsLos ())
723  {
724  // 3GPP mentioned that 3.91 ns should be used when the Cluster DS (cDS)
725  // entry is N/A.
726  table3gpp->m_numOfCluster = 12;
727  table3gpp->m_raysPerCluster = 20;
728  table3gpp->m_uLgDS = -0.2 * log10 (1 + fcGHz) - 7.5;
729  table3gpp->m_sigLgDS = 0.1;
730  table3gpp->m_uLgASD = -0.1 * log10 (1 + fcGHz) + 1.6;
731  table3gpp->m_sigLgASD = 0.1;
732  table3gpp->m_uLgASA = -0.1 * log10 (1 + fcGHz) + 1.6;
733  table3gpp->m_sigLgASA = 0.1;
734  table3gpp->m_uLgZSA = -0.1 * log10 (1 + fcGHz) + 0.73,
735  table3gpp->m_sigLgZSA = -0.04 * log10 (1 + fcGHz) + 0.34,
736  table3gpp->m_uLgZSD = -0.1 * log10 (1 + fcGHz) + 0.73;
737  table3gpp->m_sigLgZSD = -0.04 * log10 (1 + fcGHz) + 0.34;
738  table3gpp->m_offsetZOD = 0;
739  table3gpp->m_cDS = 5;
740  table3gpp->m_cASD = 17;
741  table3gpp->m_cASA = 17;
742  table3gpp->m_cZSA = 7;
743  table3gpp->m_uK = 3.48;
744  table3gpp->m_sigK = 2;
745  table3gpp->m_rTau = 3;
746  table3gpp->m_uXpr = 9;
747  table3gpp->m_sigXpr = 3;
748  table3gpp->m_perClusterShadowingStd = 4;
749 
750  for (uint8_t row = 0; row < 7; row++)
751  {
752  for (uint8_t column = 0; column < 7; column++)
753  {
754  table3gpp->m_sqrtC[row][column] = sqrtC_UMi_LOS[row][column];
755  }
756  }
757  }
758  else if (channelCondition->IsNlos ())
759  {
760  table3gpp->m_numOfCluster = 19;
761  table3gpp->m_raysPerCluster = 20;
762  table3gpp->m_uLgDS = -0.3 * log10 (1 + fcGHz) - 7;
763  table3gpp->m_sigLgDS = 0.28;
764  table3gpp->m_uLgASD = -0.08 * log10 (1 + fcGHz) + 1.81;
765  table3gpp->m_sigLgASD = 0.05 * log10 (1 + fcGHz) + 0.3;
766  table3gpp->m_uLgASA = -0.08 * log10 (1 + fcGHz) + 1.81;
767  table3gpp->m_sigLgASA = 0.05 * log10 (1 + fcGHz) + 0.3;
768  table3gpp->m_uLgZSA = -0.04 * log10 (1 + fcGHz) + 0.92,
769  table3gpp->m_sigLgZSA = -0.07 * log10 (1 + fcGHz) + 0.41;
770  table3gpp->m_uLgZSD = -0.04 * log10 (1 + fcGHz) + 0.92;
771  table3gpp->m_sigLgZSD = -0.07 * log10 (1 + fcGHz) + 0.41;
772  table3gpp->m_offsetZOD = 0;
773  table3gpp->m_cDS = 11;
774  table3gpp->m_cASD = 22;
775  table3gpp->m_cASA = 22;
776  table3gpp->m_cZSA = 7;
777  table3gpp->m_uK = 0; // N/A
778  table3gpp->m_sigK = 0; // N/A
779  table3gpp->m_rTau = 2.1;
780  table3gpp->m_uXpr = 8;
781  table3gpp->m_sigXpr = 3;
782  table3gpp->m_perClusterShadowingStd = 4;
783 
784  for (uint8_t row = 0; row < 6; row++)
785  {
786  for (uint8_t column = 0; column < 6; column++)
787  {
788  table3gpp->m_sqrtC[row][column] = sqrtC_UMi_NLOS[row][column];
789  }
790  }
791  }
792  else if (channelCondition->IsNlosv ())
793  {
794  table3gpp->m_numOfCluster = 19;
795  table3gpp->m_raysPerCluster = 20;
796  table3gpp->m_uLgDS = -0.4 * log10 (1 + fcGHz) - 7;
797  table3gpp->m_sigLgDS = 0.1;
798  table3gpp->m_uLgASD = -0.1 * log10 (1 + fcGHz) + 1.7;
799  table3gpp->m_sigLgASD = 0.1;
800  table3gpp->m_uLgASA = -0.1 * log10 (1 + fcGHz) + 1.7;
801  table3gpp->m_sigLgASA = 0.1;
802  table3gpp->m_uLgZSA = -0.04 * log10 (1 + fcGHz) + 0.92;
803  table3gpp->m_sigLgZSA = -0.07 * log10 (1 + fcGHz) + 0.41;
804  table3gpp->m_uLgZSD = -0.04 * log10 (1 + fcGHz) + 0.92;
805  table3gpp->m_sigLgZSD = -0.07 * log10 (1 + fcGHz) + 0.41;
806  table3gpp->m_offsetZOD = 0;
807  table3gpp->m_cDS = 11;
808  table3gpp->m_cASD = 22;
809  table3gpp->m_cASA = 22;
810  table3gpp->m_cZSA = 7;
811  table3gpp->m_uK = 0;
812  table3gpp->m_sigK = 4.5;
813  table3gpp->m_rTau = 2.1;
814  table3gpp->m_uXpr = 8;
815  table3gpp->m_sigXpr = 3;
816  table3gpp->m_perClusterShadowingStd = 4;
817 
818  for (uint8_t row = 0; row < 6; row++)
819  {
820  for (uint8_t column = 0; column < 6; column++)
821  {
822  table3gpp->m_sqrtC[row][column] = sqrtC_UMi_LOS[row][column];
823  }
824  }
825  }
826  else
827  {
828  NS_FATAL_ERROR ("Unknown channel condition");
829  }
830  }
831  else if (m_scenario == "V2V-Highway")
832  {
833  if (channelCondition->IsLos ())
834  {
835  table3gpp->m_numOfCluster = 12;
836  table3gpp->m_raysPerCluster = 20;
837  table3gpp->m_uLgDS = -8.3;
838  table3gpp->m_sigLgDS = 0.2;
839  table3gpp->m_uLgASD = 1.4;
840  table3gpp->m_sigLgASD = 0.1;
841  table3gpp->m_uLgASA = 1.4;
842  table3gpp->m_sigLgASA = 0.1;
843  table3gpp->m_uLgZSA = -0.1 * log10 (1 + fcGHz) + 0.73;
844  table3gpp->m_sigLgZSA = -0.04 * log10 (1 + fcGHz) + 0.34;
845  table3gpp->m_uLgZSD = -0.1 * log10 (1 + fcGHz) + 0.73;
846  table3gpp->m_sigLgZSD = -0.04 * log10 (1 + fcGHz) + 0.34;
847  table3gpp->m_offsetZOD = 0;
848  table3gpp->m_cDS = 5;
849  table3gpp->m_cASD = 17;
850  table3gpp->m_cASA = 17;
851  table3gpp->m_cZSA = 7;
852  table3gpp->m_uK = 9;
853  table3gpp->m_sigK = 3.5;
854  table3gpp->m_rTau = 3;
855  table3gpp->m_uXpr = 9;
856  table3gpp->m_sigXpr = 3;
857  table3gpp->m_perClusterShadowingStd = 4;
858 
859  for (uint8_t row = 0; row < 7; row++)
860  {
861  for (uint8_t column = 0; column < 7; column++)
862  {
863  table3gpp->m_sqrtC[row][column] = sqrtC_UMi_LOS[row][column];
864  }
865  }
866  }
867  else if (channelCondition->IsNlosv ())
868  {
869  table3gpp->m_numOfCluster = 19;
870  table3gpp->m_raysPerCluster = 20;
871  table3gpp->m_uLgDS = -8.3;
872  table3gpp->m_sigLgDS = 0.3;
873  table3gpp->m_uLgASD = 1.5;
874  table3gpp->m_sigLgASD = 0.1;
875  table3gpp->m_uLgASA = 1.5;
876  table3gpp->m_sigLgASA = 0.1;
877  table3gpp->m_uLgZSA = -0.04 * log10 (1 + fcGHz) + 0.92;
878  table3gpp->m_sigLgZSA = -0.07 * log10 (1 + fcGHz) + 0.41;
879  table3gpp->m_uLgZSD = -0.04 * log10 (1 + fcGHz) + 0.92;
880  table3gpp->m_sigLgZSD = -0.07 * log10 (1 + fcGHz) + 0.41;
881  table3gpp->m_offsetZOD = 0;
882  table3gpp->m_cDS = 11;
883  table3gpp->m_cASD = 22;
884  table3gpp->m_cASA = 22;
885  table3gpp->m_cZSA = 7;
886  table3gpp->m_uK = 0;
887  table3gpp->m_sigK = 4.5;
888  table3gpp->m_rTau = 2.1;
889  table3gpp->m_uXpr = 8.0;
890  table3gpp->m_sigXpr = 3;
891  table3gpp->m_perClusterShadowingStd = 4;
892 
893  for (uint8_t row = 0; row < 6; row++)
894  {
895  for (uint8_t column = 0; column < 6; column++)
896  {
897  table3gpp->m_sqrtC[row][column] = sqrtC_UMi_LOS[row][column];
898  }
899  }
900  }
901  else if (channelCondition->IsNlos ())
902  {
903  NS_LOG_WARN ("The fast fading parameters for the NLOS condition in the Highway scenario are not defined in TR 37.885, use the ones defined in TDoc R1-1803671 instead");
904 
905  table3gpp->m_numOfCluster = 19;
906  table3gpp->m_raysPerCluster = 20;
907  table3gpp->m_uLgDS = -0.3 * log10 (1 + fcGHz) - 7;
908  table3gpp->m_sigLgDS = 0.28;
909  table3gpp->m_uLgASD = -0.08 * log10 (1 + fcGHz) + 1.81;
910  table3gpp->m_sigLgASD = 0.05 * log10 (1 + fcGHz) + 0.3;
911  table3gpp->m_uLgASA = -0.08 * log10 (1 + fcGHz) + 1.81;
912  table3gpp->m_sigLgASA = 0.05 * log10 (1 + fcGHz) + 0.3;
913  table3gpp->m_uLgZSA = -0.04 * log10 (1 + fcGHz) + 0.92,
914  table3gpp->m_sigLgZSA = -0.07 * log10 (1 + fcGHz) + 0.41;
915  table3gpp->m_uLgZSD = -0.04 * log10 (1 + fcGHz) + 0.92;
916  table3gpp->m_sigLgZSD = -0.07 * log10 (1 + fcGHz) + 0.41;
917  table3gpp->m_offsetZOD = 0;
918  table3gpp->m_cDS = 11;
919  table3gpp->m_cASD = 22;
920  table3gpp->m_cASA = 22;
921  table3gpp->m_cZSA = 7;
922  table3gpp->m_uK = 0; // N/A
923  table3gpp->m_sigK = 0; // N/A
924  table3gpp->m_rTau = 2.1;
925  table3gpp->m_uXpr = 8;
926  table3gpp->m_sigXpr = 3;
927  table3gpp->m_perClusterShadowingStd = 4;
928 
929  for (uint8_t row = 0; row < 6; row++)
930  {
931  for (uint8_t column = 0; column < 6; column++)
932  {
933  table3gpp->m_sqrtC[row][column] = sqrtC_UMi_NLOS[row][column];
934  }
935  }
936  }
937  else
938  {
939  NS_FATAL_ERROR ("Unknown channel condition");
940  }
941  }
942  else
943  {
944  NS_FATAL_ERROR ("unkonw scenarios");
945  }
946 
947  return table3gpp;
948 }
949 
950 bool
952 {
953  NS_LOG_FUNCTION (this);
954 
955  bool update = false;
956 
957  // if the channel condition is different the channel has to be updated
958  if (!channelMatrix->m_channelCondition->IsEqual (channelCondition))
959  {
960  NS_LOG_DEBUG ("Update the channel condition");
961  update = true;
962  }
963 
964  // if the coherence time is over the channel has to be updated
965  if (!m_updatePeriod.IsZero () && Simulator::Now () - channelMatrix->m_generatedTime > m_updatePeriod)
966  {
967  NS_LOG_DEBUG ("Generation time " << channelMatrix->m_generatedTime.As (Time::NS) << " now " << Now ().As (Time::NS));
968  update = true;
969  }
970 
971  return update;
972 }
973 
979 {
980  NS_LOG_FUNCTION (this);
981 
982  // Compute the channel key. The key is reciprocal, i.e., key (a, b) = key (b, a)
983  uint32_t x1 = std::min (aMob->GetObject<Node> ()->GetId (), bMob->GetObject<Node> ()->GetId ());
984  uint32_t x2 = std::max (aMob->GetObject<Node> ()->GetId (), bMob->GetObject<Node> ()->GetId ());
985  uint32_t channelId = GetKey (x1, x2);
986 
987  // retrieve the channel condition
988  Ptr<const ChannelCondition> condition = m_channelConditionModel->GetChannelCondition (aMob, bMob);
989 
990  // Check if the channel is present in the map and return it, otherwise
991  // generate a new channel
992  bool update = false;
993  bool notFound = false;
994  Ptr<ThreeGppChannelMatrix> channelMatrix;
995  if (m_channelMap.find (channelId) != m_channelMap.end ())
996  {
997  // channel matrix present in the map
998  NS_LOG_DEBUG ("channel matrix present in the map");
999  channelMatrix = m_channelMap[channelId];
1000 
1001  // check if it has to be updated
1002  update = ChannelMatrixNeedsUpdate (channelMatrix, condition);
1003  }
1004  else
1005  {
1006  NS_LOG_DEBUG ("channel matrix not found");
1007  notFound = true;
1008  }
1009 
1010  // If the channel is not present in the map or if it has to be updated
1011  // generate a new realization
1012  if (notFound || update)
1013  {
1014  // channel matrix not found or has to be updated, generate a new one
1015  Angles txAngle (bMob->GetPosition (), aMob->GetPosition ());
1016  Angles rxAngle (aMob->GetPosition (), bMob->GetPosition ());
1017 
1018  double x = aMob->GetPosition ().x - bMob->GetPosition ().x;
1019  double y = aMob->GetPosition ().y - bMob->GetPosition ().y;
1020  double distance2D = sqrt (x * x + y * y);
1021 
1022  // NOTE we assume hUT = min (height(a), height(b)) and
1023  // hBS = max (height (a), height (b))
1024  double hUt = std::min (aMob->GetPosition ().z, bMob->GetPosition ().z);
1025  double hBs = std::max (aMob->GetPosition ().z, bMob->GetPosition ().z);
1026 
1027  // TODO this is not currently used, it is needed for the computation of the
1028  // additional blockage in case of spatial consistent update
1029  // I do not know who is the UT, I can use the relative distance between
1030  // tx and rx instead
1031  Vector locUt = Vector (0.0, 0.0, 0.0);
1032 
1033  channelMatrix = GetNewChannel (locUt, condition, aAntenna, bAntenna, rxAngle, txAngle, distance2D, hBs, hUt);
1034  channelMatrix->m_nodeIds = std::make_pair (aMob->GetObject<Node> ()->GetId (), bMob->GetObject<Node> ()->GetId ());
1035 
1036  // store or replace the channel matrix in the channel map
1037  m_channelMap[channelId] = channelMatrix;
1038  }
1039 
1040  return channelMatrix;
1041 }
1042 
1045  Ptr<const PhasedArrayModel> sAntenna,
1046  Ptr<const PhasedArrayModel> uAntenna,
1047  Angles &uAngle, Angles &sAngle,
1048  double dis2D, double hBS, double hUT) const
1049 {
1050  NS_LOG_FUNCTION (this);
1051 
1052  NS_ASSERT_MSG (m_frequency > 0.0, "Set the operating frequency first!");
1053 
1054  // get the 3GPP parameters
1055  Ptr<const ParamsTable> table3gpp = GetThreeGppTable (channelCondition, hBS, hUT, dis2D);
1056 
1057  // get the number of clusters and the number of rays per cluster
1058  uint8_t numOfCluster = table3gpp->m_numOfCluster;
1059  uint8_t raysPerCluster = table3gpp->m_raysPerCluster;
1060 
1061  // create a channel matrix instance
1062  Ptr<ThreeGppChannelMatrix> channelParams = Create<ThreeGppChannelMatrix> ();
1063  channelParams->m_channelCondition = channelCondition; // set the channel condition
1064  channelParams->m_generatedTime = Simulator::Now ();
1065 
1066  // compute the 3D distance using eq. 7.4-1
1067  double dis3D = std::sqrt (dis2D * dis2D + (hBS - hUT) * (hBS - hUT));
1068 
1069  bool los = channelCondition->IsLos ();
1070  bool o2i = channelCondition->IsO2i ();
1071 
1072  //Step 4: Generate large scale parameters. All LSPS are uncorrelated.
1073  DoubleVector LSPsIndep, LSPs;
1074  uint8_t paramNum;
1075  if (los)
1076  {
1077  paramNum = 7;
1078  }
1079  else
1080  {
1081  paramNum = 6;
1082  }
1083  //Generate paramNum independent LSPs.
1084  for (uint8_t iter = 0; iter < paramNum; iter++)
1085  {
1086  LSPsIndep.push_back (m_normalRv->GetValue ());
1087  }
1088  for (uint8_t row = 0; row < paramNum; row++)
1089  {
1090  double temp = 0;
1091  for (uint8_t column = 0; column < paramNum; column++)
1092  {
1093  temp += table3gpp->m_sqrtC[row][column] * LSPsIndep[column];
1094  }
1095  LSPs.push_back (temp);
1096  }
1097 
1098  // NOTE the shadowing is generated in the propagation loss model
1099 
1100  double DS,ASD,ASA,ZSA,ZSD,K_factor = 0;
1101  if (los)
1102  {
1103  K_factor = LSPs[1] * table3gpp->m_sigK + table3gpp->m_uK;
1104  DS = pow (10, LSPs[2] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1105  ASD = pow (10, LSPs[3] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1106  ASA = pow (10, LSPs[4] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1107  ZSD = pow (10, LSPs[5] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1108  ZSA = pow (10, LSPs[6] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1109  }
1110  else
1111  {
1112  DS = pow (10, LSPs[1] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1113  ASD = pow (10, LSPs[2] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1114  ASA = pow (10, LSPs[3] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1115  ZSD = pow (10, LSPs[4] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1116  ZSA = pow (10, LSPs[5] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1117 
1118  }
1119  ASD = std::min (ASD, 104.0);
1120  ASA = std::min (ASA, 104.0);
1121  ZSD = std::min (ZSD, 52.0);
1122  ZSA = std::min (ZSA, 52.0);
1123 
1124  channelParams->m_DS = DS;
1125  channelParams->m_K = K_factor;
1126 
1127  NS_LOG_INFO ("K-factor=" << K_factor << ",DS=" << DS << ", ASD=" << ASD << ", ASA=" << ASA << ", ZSD=" << ZSD << ", ZSA=" << ZSA);
1128 
1129  //Step 5: Generate Delays.
1130  DoubleVector clusterDelay;
1131  double minTau = 100.0;
1132  for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++)
1133  {
1134  double tau = -1 * table3gpp->m_rTau * DS * log (m_uniformRv->GetValue (0,1)); //(7.5-1)
1135  if (minTau > tau)
1136  {
1137  minTau = tau;
1138  }
1139  clusterDelay.push_back (tau);
1140  }
1141 
1142  for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++)
1143  {
1144  clusterDelay[cIndex] -= minTau;
1145  }
1146  std::sort (clusterDelay.begin (), clusterDelay.end ()); //(7.5-2)
1147 
1148  /* since the scaled Los delays are not to be used in cluster power generation,
1149  * we will generate cluster power first and resume to compute Los cluster delay later.*/
1150 
1151  //Step 6: Generate cluster powers.
1152  DoubleVector clusterPower;
1153  double powerSum = 0;
1154  for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++)
1155  {
1156  double power = exp (-1 * clusterDelay[cIndex] * (table3gpp->m_rTau - 1) / table3gpp->m_rTau / DS) *
1157  pow (10,-1 * m_normalRv->GetValue () * table3gpp->m_perClusterShadowingStd / 10); //(7.5-5)
1158  powerSum += power;
1159  clusterPower.push_back (power);
1160  }
1161  double powerMax = 0;
1162 
1163  for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++)
1164  {
1165  clusterPower[cIndex] = clusterPower[cIndex] / powerSum; //(7.5-6)
1166  }
1167 
1168  DoubleVector clusterPowerForAngles; // this power is only for equation (7.5-9) and (7.5-14), not for (7.5-22)
1169  if (los)
1170  {
1171  double K_linear = pow (10,K_factor / 10);
1172 
1173  for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++)
1174  {
1175  if (cIndex == 0)
1176  {
1177  clusterPowerForAngles.push_back (clusterPower[cIndex] / (1 + K_linear) + K_linear / (1 + K_linear)); //(7.5-8)
1178  }
1179  else
1180  {
1181  clusterPowerForAngles.push_back (clusterPower[cIndex] / (1 + K_linear)); //(7.5-8)
1182  }
1183  if (powerMax < clusterPowerForAngles[cIndex])
1184  {
1185  powerMax = clusterPowerForAngles[cIndex];
1186  }
1187  }
1188  }
1189  else
1190  {
1191  for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++)
1192  {
1193  clusterPowerForAngles.push_back (clusterPower[cIndex]); //(7.5-6)
1194  if (powerMax < clusterPowerForAngles[cIndex])
1195  {
1196  powerMax = clusterPowerForAngles[cIndex];
1197  }
1198  }
1199  }
1200 
1201  //remove clusters with less than -25 dB power compared to the maxim cluster power;
1202  //double thresh = pow(10,-2.5);
1203  double thresh = 0.0032;
1204  for (uint8_t cIndex = numOfCluster; cIndex > 0; cIndex--)
1205  {
1206  if (clusterPowerForAngles[cIndex - 1] < thresh * powerMax )
1207  {
1208  clusterPowerForAngles.erase (clusterPowerForAngles.begin () + cIndex - 1);
1209  clusterPower.erase (clusterPower.begin () + cIndex - 1);
1210  clusterDelay.erase (clusterDelay.begin () + cIndex - 1);
1211  }
1212  }
1213 
1214  NS_ASSERT (clusterPower.size () < UINT8_MAX);
1215  uint8_t numReducedCluster = clusterPower.size ();
1216 
1217  channelParams->m_numCluster = numReducedCluster;
1218  // Resume step 5 to compute the delay for LoS condition.
1219  if (los)
1220  {
1221  double C_tau = 0.7705 - 0.0433 * K_factor + 2e-4 * pow (K_factor,2) + 17e-6 * pow (K_factor,3); //(7.5-3)
1222  for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++)
1223  {
1224  clusterDelay[cIndex] = clusterDelay[cIndex] / C_tau; //(7.5-4)
1225  }
1226  }
1227 
1228  //Step 7: Generate arrival and departure angles for both azimuth and elevation.
1229 
1230  double C_NLOS, C_phi;
1231  //According to table 7.5-6, only cluster number equals to 8, 10, 11, 12, 19 and 20 is valid.
1232  //Not sure why the other cases are in Table 7.5-2.
1233  switch (numOfCluster) // Table 7.5-2
1234  {
1235  case 4:
1236  C_NLOS = 0.779;
1237  break;
1238  case 5:
1239  C_NLOS = 0.860;
1240  break;
1241  case 8:
1242  C_NLOS = 1.018;
1243  break;
1244  case 10:
1245  C_NLOS = 1.090;
1246  break;
1247  case 11:
1248  C_NLOS = 1.123;
1249  break;
1250  case 12:
1251  C_NLOS = 1.146;
1252  break;
1253  case 14:
1254  C_NLOS = 1.190;
1255  break;
1256  case 15:
1257  C_NLOS = 1.221;
1258  break;
1259  case 16:
1260  C_NLOS = 1.226;
1261  break;
1262  case 19:
1263  C_NLOS = 1.273;
1264  break;
1265  case 20:
1266  C_NLOS = 1.289;
1267  break;
1268  default:
1269  NS_FATAL_ERROR ("Invalid cluster number");
1270  }
1271 
1272  if (los)
1273  {
1274  C_phi = C_NLOS * (1.1035 - 0.028 * K_factor - 2e-3 * pow (K_factor,2) + 1e-4 * pow (K_factor,3)); //(7.5-10))
1275  }
1276  else
1277  {
1278  C_phi = C_NLOS; //(7.5-10)
1279  }
1280 
1281  double C_theta;
1282  switch (numOfCluster) //Table 7.5-4
1283  {
1284  case 8:
1285  C_NLOS = 0.889;
1286  break;
1287  case 10:
1288  C_NLOS = 0.957;
1289  break;
1290  case 11:
1291  C_NLOS = 1.031;
1292  break;
1293  case 12:
1294  C_NLOS = 1.104;
1295  break;
1296  case 15:
1297  C_NLOS = 1.1088;
1298  break;
1299  case 19:
1300  C_NLOS = 1.184;
1301  break;
1302  case 20:
1303  C_NLOS = 1.178;
1304  break;
1305  default:
1306  NS_FATAL_ERROR ("Invalid cluster number");
1307  }
1308 
1309  if (los)
1310  {
1311  C_theta = C_NLOS * (1.3086 + 0.0339 * K_factor - 0.0077 * pow (K_factor,2) + 2e-4 * pow (K_factor,3)); //(7.5-15)
1312  }
1313  else
1314  {
1315  C_theta = C_NLOS;
1316  }
1317 
1318 
1319  DoubleVector clusterAoa, clusterAod, clusterZoa, clusterZod;
1320  double angle;
1321  for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++)
1322  {
1323  angle = 2 * ASA * sqrt (-1 * log (clusterPowerForAngles[cIndex] / powerMax)) / 1.4 / C_phi; //(7.5-9)
1324  clusterAoa.push_back (angle);
1325  angle = 2 * ASD * sqrt (-1 * log (clusterPowerForAngles[cIndex] / powerMax)) / 1.4 / C_phi; //(7.5-9)
1326  clusterAod.push_back (angle);
1327  angle = -1 * ZSA * log (clusterPowerForAngles[cIndex] / powerMax) / C_theta; //(7.5-14)
1328  clusterZoa.push_back (angle);
1329  angle = -1 * ZSD * log (clusterPowerForAngles[cIndex] / powerMax) / C_theta;
1330  clusterZod.push_back (angle);
1331  }
1332 
1333  for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++)
1334  {
1335  int Xn = 1;
1336  if (m_uniformRv->GetValue (0,1) < 0.5)
1337  {
1338  Xn = -1;
1339  }
1340  clusterAoa[cIndex] = clusterAoa[cIndex] * Xn + (m_normalRv->GetValue () * ASA / 7) + RadiansToDegrees (uAngle.GetAzimuth ()); //(7.5-11)
1341  clusterAod[cIndex] = clusterAod[cIndex] * Xn + (m_normalRv->GetValue () * ASD / 7) + RadiansToDegrees (sAngle.GetAzimuth ());
1342  if (o2i)
1343  {
1344  clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (m_normalRv->GetValue () * ZSA / 7) + 90; //(7.5-16)
1345  }
1346  else
1347  {
1348  clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (m_normalRv->GetValue () * ZSA / 7) + RadiansToDegrees (uAngle.GetInclination ()); //(7.5-16)
1349  }
1350  clusterZod[cIndex] = clusterZod[cIndex] * Xn + (m_normalRv->GetValue () * ZSD / 7) + RadiansToDegrees (sAngle.GetInclination ()) + table3gpp->m_offsetZOD; //(7.5-19)
1351 
1352  }
1353 
1354  if (los)
1355  {
1356  //The 7.5-12 can be rewrite as Theta_n,ZOA = Theta_n,ZOA - (Theta_1,ZOA - Theta_LOS,ZOA) = Theta_n,ZOA - diffZOA,
1357  //Similar as AOD, ZSA and ZSD.
1358  double diffAoa = clusterAoa[0] - RadiansToDegrees (uAngle.GetAzimuth ());
1359  double diffAod = clusterAod[0] - RadiansToDegrees (sAngle.GetAzimuth ());
1360  double diffZsa = clusterZoa[0] - RadiansToDegrees (uAngle.GetInclination ());
1361  double diffZsd = clusterZod[0] - RadiansToDegrees (sAngle.GetInclination ());
1362 
1363  for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++)
1364  {
1365  clusterAoa[cIndex] -= diffAoa; //(7.5-12)
1366  clusterAod[cIndex] -= diffAod;
1367  clusterZoa[cIndex] -= diffZsa; //(7.5-17)
1368  clusterZod[cIndex] -= diffZsd;
1369 
1370  }
1371  }
1372 
1373  double rayAoa_radian[numReducedCluster][raysPerCluster]; //rayAoa_radian[n][m], where n is cluster index, m is ray index
1374  double rayAod_radian[numReducedCluster][raysPerCluster]; //rayAod_radian[n][m], where n is cluster index, m is ray index
1375  double rayZoa_radian[numReducedCluster][raysPerCluster]; //rayZoa_radian[n][m], where n is cluster index, m is ray index
1376  double rayZod_radian[numReducedCluster][raysPerCluster]; //rayZod_radian[n][m], where n is cluster index, m is ray index
1377 
1378  for (uint8_t nInd = 0; nInd < numReducedCluster; nInd++)
1379  {
1380  for (uint8_t mInd = 0; mInd < raysPerCluster; mInd++)
1381  {
1382  double tempAoa = clusterAoa[nInd] + table3gpp->m_cASA * offSetAlpha[mInd]; //(7.5-13)
1383  double tempZoa = clusterZoa[nInd] + table3gpp->m_cZSA * offSetAlpha[mInd]; //(7.5-18)
1384  std::tie (rayAoa_radian[nInd][mInd], rayZoa_radian[nInd][mInd]) = WrapAngles (DegreesToRadians (tempAoa), DegreesToRadians (tempZoa));
1385 
1386  double tempAod = clusterAod[nInd] + table3gpp->m_cASD * offSetAlpha[mInd]; //(7.5-13)
1387  double tempZod = clusterZod[nInd] + 0.375 * pow (10,table3gpp->m_uLgZSD) * offSetAlpha[mInd]; //(7.5-20)
1388  std::tie (rayAod_radian[nInd][mInd], rayZod_radian[nInd][mInd]) = WrapAngles (DegreesToRadians (tempAod), DegreesToRadians (tempZod));
1389  }
1390  }
1391  DoubleVector angle_degree;
1392  double sizeTemp = clusterZoa.size ();
1393  for (uint8_t ind = 0; ind < 4; ind++)
1394  {
1395  switch (ind)
1396  {
1397  case 0:
1398  angle_degree = clusterAoa;
1399  break;
1400  case 1:
1401  angle_degree = clusterZoa;
1402  break;
1403  case 2:
1404  angle_degree = clusterAod;
1405  break;
1406  case 3:
1407  angle_degree = clusterZod;
1408  break;
1409  default:
1410  NS_FATAL_ERROR ("Programming Error");
1411  }
1412 
1413  for (uint8_t nIndex = 0; nIndex < sizeTemp; nIndex++)
1414  {
1415  while (angle_degree[nIndex] > 360)
1416  {
1417  angle_degree[nIndex] -= 360;
1418  }
1419 
1420  while (angle_degree[nIndex] < 0)
1421  {
1422  angle_degree[nIndex] += 360;
1423  }
1424 
1425  if (ind == 1 || ind == 3)
1426  {
1427  if (angle_degree[nIndex] > 180)
1428  {
1429  angle_degree[nIndex] = 360 - angle_degree[nIndex];
1430  }
1431  }
1432  }
1433  switch (ind)
1434  {
1435  case 0:
1436  clusterAoa = angle_degree;
1437  break;
1438  case 1:
1439  clusterZoa = angle_degree;
1440  break;
1441  case 2:
1442  clusterAod = angle_degree;
1443  break;
1444  case 3:
1445  clusterZod = angle_degree;
1446  break;
1447  default:
1448  NS_FATAL_ERROR ("Programming Error");
1449  }
1450  }
1451 
1452  DoubleVector attenuation_dB;
1453  if (m_blockage)
1454  {
1455  attenuation_dB = CalcAttenuationOfBlockage (channelParams, clusterAoa, clusterZoa);
1456  for (uint8_t cInd = 0; cInd < numReducedCluster; cInd++)
1457  {
1458  clusterPower[cInd] = clusterPower[cInd] / pow (10,attenuation_dB[cInd] / 10);
1459  }
1460  }
1461  else
1462  {
1463  attenuation_dB.push_back (0);
1464  }
1465 
1466  //Step 8: Coupling of rays within a cluster for both azimuth and elevation
1467  //shuffle all the arrays to perform random coupling
1468  for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++)
1469  {
1470  Shuffle (&rayAod_radian[cIndex][0], &rayAod_radian[cIndex][raysPerCluster]);
1471  Shuffle (&rayAoa_radian[cIndex][0], &rayAoa_radian[cIndex][raysPerCluster]);
1472  Shuffle (&rayZod_radian[cIndex][0], &rayZod_radian[cIndex][raysPerCluster]);
1473  Shuffle (&rayZoa_radian[cIndex][0], &rayZoa_radian[cIndex][raysPerCluster]);
1474  }
1475 
1476  //Step 9: Generate the cross polarization power ratios
1477  //Step 10: Draw initial phases
1478  Double2DVector crossPolarizationPowerRatios; // vector containing the cross polarization power ratios, as defined by 7.5-21
1479  Double3DVector clusterPhase; //rayAoa_radian[n][m], where n is cluster index, m is ray index
1480  for (uint8_t nInd = 0; nInd < numReducedCluster; nInd++)
1481  {
1482  DoubleVector temp; // used to store the XPR values
1483  Double2DVector temp2; // used to store the PHI values for all the possible combination of polarization
1484  for (uint8_t mInd = 0; mInd < raysPerCluster; mInd++)
1485  {
1486  double uXprLinear = pow (10, table3gpp->m_uXpr / 10); // convert to linear
1487  double sigXprLinear = pow (10, table3gpp->m_sigXpr / 10); // convert to linear
1488 
1489  temp.push_back (std::pow (10, (m_normalRv->GetValue () * sigXprLinear + uXprLinear) / 10));
1490  DoubleVector temp3; // used to store the PHI valuse
1491  for (uint8_t pInd = 0; pInd < 4; pInd++)
1492  {
1493  temp3.push_back (m_uniformRv->GetValue (-1 * M_PI, M_PI));
1494  }
1495  temp2.push_back (temp3);
1496  }
1497  crossPolarizationPowerRatios.push_back (temp);
1498  clusterPhase.push_back (temp2);
1499  }
1500  channelParams->m_clusterPhase = clusterPhase;
1501 
1502  //Step 11: Generate channel coefficients for each cluster n and each receiver
1503  // and transmitter element pair u,s.
1504 
1505  Complex3DVector H_NLOS; // channel coefficients H_NLOS [u][s][n],
1506  // where u and s are receive and transmit antenna element, n is cluster index.
1507  uint64_t uSize = uAntenna->GetNumberOfElements ();
1508  uint64_t sSize = sAntenna->GetNumberOfElements ();
1509 
1510  uint8_t cluster1st = 0, cluster2nd = 0; // first and second strongest cluster;
1511  double maxPower = 0;
1512  for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++)
1513  {
1514  if (maxPower < clusterPower[cIndex])
1515  {
1516  maxPower = clusterPower[cIndex];
1517  cluster1st = cIndex;
1518  }
1519  }
1520  maxPower = 0;
1521  for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++)
1522  {
1523  if (maxPower < clusterPower[cIndex] && cluster1st != cIndex)
1524  {
1525  maxPower = clusterPower[cIndex];
1526  cluster2nd = cIndex;
1527  }
1528  }
1529 
1530  NS_LOG_INFO ("1st strongest cluster:" << (int)cluster1st << ", 2nd strongest cluster:" << (int)cluster2nd);
1531 
1532  Complex3DVector H_usn; //channel coffecient H_usn[u][s][n];
1533  // NOTE Since each of the strongest 2 clusters are divided into 3 sub-clusters,
1534  // the total cluster will be numReducedCLuster + 4.
1535 
1536  H_usn.resize (uSize);
1537  for (uint64_t uIndex = 0; uIndex < uSize; uIndex++)
1538  {
1539  H_usn[uIndex].resize (sSize);
1540  for (uint64_t sIndex = 0; sIndex < sSize; sIndex++)
1541  {
1542  H_usn[uIndex][sIndex].resize (numReducedCluster);
1543  }
1544  }
1545 
1546  // The following for loops computes the channel coefficients
1547  for (uint64_t uIndex = 0; uIndex < uSize; uIndex++)
1548  {
1549  Vector uLoc = uAntenna->GetElementLocation (uIndex);
1550 
1551  for (uint64_t sIndex = 0; sIndex < sSize; sIndex++)
1552  {
1553 
1554  Vector sLoc = sAntenna->GetElementLocation (sIndex);
1555 
1556  for (uint8_t nIndex = 0; nIndex < numReducedCluster; nIndex++)
1557  {
1558  //Compute the N-2 weakest cluster, assuming 0 slant angle and a
1559  //polarization slant angle configured in the array (7.5-22)
1560  if (nIndex != cluster1st && nIndex != cluster2nd)
1561  {
1562  std::complex<double> rays (0,0);
1563  for (uint8_t mIndex = 0; mIndex < raysPerCluster; mIndex++)
1564  {
1565  DoubleVector initialPhase = clusterPhase[nIndex][mIndex];
1566  double k = crossPolarizationPowerRatios[nIndex][mIndex];
1567  //lambda_0 is accounted in the antenna spacing uLoc and sLoc.
1568  double rxPhaseDiff = 2 * M_PI * (sin (rayZoa_radian[nIndex][mIndex]) * cos (rayAoa_radian[nIndex][mIndex]) * uLoc.x
1569  + sin (rayZoa_radian[nIndex][mIndex]) * sin (rayAoa_radian[nIndex][mIndex]) * uLoc.y
1570  + cos (rayZoa_radian[nIndex][mIndex]) * uLoc.z);
1571 
1572  double txPhaseDiff = 2 * M_PI * (sin (rayZod_radian[nIndex][mIndex]) * cos (rayAod_radian[nIndex][mIndex]) * sLoc.x
1573  + sin (rayZod_radian[nIndex][mIndex]) * sin (rayAod_radian[nIndex][mIndex]) * sLoc.y
1574  + cos (rayZod_radian[nIndex][mIndex]) * sLoc.z);
1575  // NOTE Doppler is computed in the CalcBeamformingGain function and is simplified to only account for the center anngle of each cluster.
1576 
1577  double rxFieldPatternPhi, rxFieldPatternTheta, txFieldPatternPhi, txFieldPatternTheta;
1578  std::tie (rxFieldPatternPhi, rxFieldPatternTheta) = uAntenna->GetElementFieldPattern (Angles (rayAoa_radian[nIndex][mIndex], rayZoa_radian[nIndex][mIndex]));
1579  std::tie (txFieldPatternPhi, txFieldPatternTheta) = sAntenna->GetElementFieldPattern (Angles (rayAod_radian[nIndex][mIndex], rayZod_radian[nIndex][mIndex]));
1580 
1581  rays += (exp (std::complex<double> (0, initialPhase[0])) * rxFieldPatternTheta * txFieldPatternTheta +
1582  +exp (std::complex<double> (0, initialPhase[1])) * std::sqrt (1 / k) * rxFieldPatternTheta * txFieldPatternPhi +
1583  +exp (std::complex<double> (0, initialPhase[2])) * std::sqrt (1 / k) * rxFieldPatternPhi * txFieldPatternTheta +
1584  +exp (std::complex<double> (0, initialPhase[3])) * rxFieldPatternPhi * txFieldPatternPhi)
1585  * exp (std::complex<double> (0, rxPhaseDiff))
1586  * exp (std::complex<double> (0, txPhaseDiff));
1587  }
1588  rays *= sqrt (clusterPower[nIndex] / raysPerCluster);
1589  H_usn[uIndex][sIndex][nIndex] = rays;
1590  }
1591  else //(7.5-28)
1592  {
1593  std::complex<double> raysSub1 (0,0);
1594  std::complex<double> raysSub2 (0,0);
1595  std::complex<double> raysSub3 (0,0);
1596 
1597  for (uint8_t mIndex = 0; mIndex < raysPerCluster; mIndex++)
1598  {
1599  double k = crossPolarizationPowerRatios[nIndex][mIndex];
1600 
1601  //ZML:Just remind me that the angle offsets for the 3 subclusters were not generated correctly.
1602 
1603  DoubleVector initialPhase = clusterPhase[nIndex][mIndex];
1604  double rxPhaseDiff = 2 * M_PI * (sin (rayZoa_radian[nIndex][mIndex]) * cos (rayAoa_radian[nIndex][mIndex]) * uLoc.x
1605  + sin (rayZoa_radian[nIndex][mIndex]) * sin (rayAoa_radian[nIndex][mIndex]) * uLoc.y
1606  + cos (rayZoa_radian[nIndex][mIndex]) * uLoc.z);
1607  double txPhaseDiff = 2 * M_PI * (sin (rayZod_radian[nIndex][mIndex]) * cos (rayAod_radian[nIndex][mIndex]) * sLoc.x
1608  + sin (rayZod_radian[nIndex][mIndex]) * sin (rayAod_radian[nIndex][mIndex]) * sLoc.y
1609  + cos (rayZod_radian[nIndex][mIndex]) * sLoc.z);
1610 
1611  double rxFieldPatternPhi, rxFieldPatternTheta, txFieldPatternPhi, txFieldPatternTheta;
1612  std::tie (rxFieldPatternPhi, rxFieldPatternTheta) = uAntenna->GetElementFieldPattern (Angles (rayAoa_radian[nIndex][mIndex], rayZoa_radian[nIndex][mIndex]));
1613  std::tie (txFieldPatternPhi, txFieldPatternTheta) = sAntenna->GetElementFieldPattern (Angles (rayAod_radian[nIndex][mIndex], rayZod_radian[nIndex][mIndex]));
1614 
1615  switch (mIndex)
1616  {
1617  case 9:
1618  case 10:
1619  case 11:
1620  case 12:
1621  case 17:
1622  case 18:
1623  raysSub2 += (exp (std::complex<double> (0, initialPhase[0])) * rxFieldPatternTheta * txFieldPatternTheta +
1624  +exp (std::complex<double> (0, initialPhase[1])) * std::sqrt (1 / k) * rxFieldPatternTheta * txFieldPatternPhi +
1625  +exp (std::complex<double> (0, initialPhase[2])) * std::sqrt (1 / k) * rxFieldPatternPhi * txFieldPatternTheta +
1626  +exp (std::complex<double> (0, initialPhase[3])) * rxFieldPatternPhi * txFieldPatternPhi)
1627  * exp (std::complex<double> (0, rxPhaseDiff))
1628  * exp (std::complex<double> (0, txPhaseDiff));
1629  break;
1630  case 13:
1631  case 14:
1632  case 15:
1633  case 16:
1634  raysSub3 += (exp (std::complex<double> (0, initialPhase[0])) * rxFieldPatternTheta * txFieldPatternTheta +
1635  +exp (std::complex<double> (0, initialPhase[1])) * std::sqrt (1 / k) * rxFieldPatternTheta * txFieldPatternPhi +
1636  +exp (std::complex<double> (0, initialPhase[2])) * std::sqrt (1 / k) * rxFieldPatternPhi * txFieldPatternTheta +
1637  +exp (std::complex<double> (0, initialPhase[3])) * rxFieldPatternPhi * txFieldPatternPhi)
1638  * exp (std::complex<double> (0, rxPhaseDiff))
1639  * exp (std::complex<double> (0, txPhaseDiff));
1640  break;
1641  default: //case 1,2,3,4,5,6,7,8,19,20
1642  raysSub1 += (exp (std::complex<double> (0, initialPhase[0])) * rxFieldPatternTheta * txFieldPatternTheta +
1643  +exp (std::complex<double> (0, initialPhase[1])) * std::sqrt (1 / k) * rxFieldPatternTheta * txFieldPatternPhi +
1644  +exp (std::complex<double> (0, initialPhase[2])) * std::sqrt (1 / k) * rxFieldPatternPhi * txFieldPatternTheta +
1645  +exp (std::complex<double> (0, initialPhase[3])) * rxFieldPatternPhi * txFieldPatternPhi)
1646  * exp (std::complex<double> (0, rxPhaseDiff))
1647  * exp (std::complex<double> (0, txPhaseDiff));
1648  break;
1649  }
1650  }
1651  raysSub1 *= sqrt (clusterPower[nIndex] / raysPerCluster);
1652  raysSub2 *= sqrt (clusterPower[nIndex] / raysPerCluster);
1653  raysSub3 *= sqrt (clusterPower[nIndex] / raysPerCluster);
1654  H_usn[uIndex][sIndex][nIndex] = raysSub1;
1655  H_usn[uIndex][sIndex].push_back (raysSub2);
1656  H_usn[uIndex][sIndex].push_back (raysSub3);
1657 
1658  }
1659  }
1660  if (los) //(7.5-29) && (7.5-30)
1661  {
1662  std::complex<double> ray (0,0);
1663  double rxPhaseDiff = 2 * M_PI * (sin (uAngle.GetInclination ()) * cos (uAngle.GetAzimuth ()) * uLoc.x
1664  + sin (uAngle.GetInclination ()) * sin (uAngle.GetAzimuth ()) * uLoc.y
1665  + cos (uAngle.GetInclination ()) * uLoc.z);
1666  double txPhaseDiff = 2 * M_PI * (sin (sAngle.GetInclination ()) * cos (sAngle.GetAzimuth ()) * sLoc.x
1667  + sin (sAngle.GetInclination ()) * sin (sAngle.GetAzimuth ()) * sLoc.y
1668  + cos (sAngle.GetInclination ()) * sLoc.z);
1669 
1670  double rxFieldPatternPhi, rxFieldPatternTheta, txFieldPatternPhi, txFieldPatternTheta;
1671  std::tie (rxFieldPatternPhi, rxFieldPatternTheta) = uAntenna->GetElementFieldPattern (Angles (uAngle.GetAzimuth (), uAngle.GetInclination ()));
1672  std::tie (txFieldPatternPhi, txFieldPatternTheta) = sAntenna->GetElementFieldPattern (Angles (sAngle.GetAzimuth (), sAngle.GetInclination ()));
1673 
1674  double lambda = 3e8 / m_frequency; // the wavelength of the carrier frequency
1675 
1676  ray = (rxFieldPatternTheta * txFieldPatternTheta - rxFieldPatternPhi * txFieldPatternPhi)
1677  * exp (std::complex<double> (0, -2 * M_PI * dis3D / lambda))
1678  * exp (std::complex<double> (0, rxPhaseDiff))
1679  * exp (std::complex<double> (0, txPhaseDiff));
1680 
1681  double K_linear = pow (10,K_factor / 10);
1682  // the LOS path should be attenuated if blockage is enabled.
1683  H_usn[uIndex][sIndex][0] = sqrt (1 / (K_linear + 1)) * H_usn[uIndex][sIndex][0] + sqrt (K_linear / (1 + K_linear)) * ray / pow (10,attenuation_dB[0] / 10); //(7.5-30) for tau = tau1
1684  double tempSize = H_usn[uIndex][sIndex].size ();
1685  for (uint8_t nIndex = 1; nIndex < tempSize; nIndex++)
1686  {
1687  H_usn[uIndex][sIndex][nIndex] *= sqrt (1 / (K_linear + 1)); //(7.5-30) for tau = tau2...taunN
1688  }
1689 
1690  }
1691  }
1692  }
1693 
1694  // store the delays and the angles for the subclusters
1695  if (cluster1st == cluster2nd)
1696  {
1697  clusterDelay.push_back (clusterDelay[cluster1st] + 1.28 * table3gpp->m_cDS);
1698  clusterDelay.push_back (clusterDelay[cluster1st] + 2.56 * table3gpp->m_cDS);
1699 
1700  clusterAoa.push_back (clusterAoa[cluster1st]);
1701  clusterAoa.push_back (clusterAoa[cluster1st]);
1702 
1703  clusterZoa.push_back (clusterZoa[cluster1st]);
1704  clusterZoa.push_back (clusterZoa[cluster1st]);
1705 
1706  clusterAod.push_back (clusterAod[cluster1st]);
1707  clusterAod.push_back (clusterAod[cluster1st]);
1708 
1709  clusterZod.push_back (clusterZod[cluster1st]);
1710  clusterZod.push_back (clusterZod[cluster1st]);
1711  }
1712  else
1713  {
1714  double min, max;
1715  if (cluster1st < cluster2nd)
1716  {
1717  min = cluster1st;
1718  max = cluster2nd;
1719  }
1720  else
1721  {
1722  min = cluster2nd;
1723  max = cluster1st;
1724  }
1725  clusterDelay.push_back (clusterDelay[min] + 1.28 * table3gpp->m_cDS);
1726  clusterDelay.push_back (clusterDelay[min] + 2.56 * table3gpp->m_cDS);
1727  clusterDelay.push_back (clusterDelay[max] + 1.28 * table3gpp->m_cDS);
1728  clusterDelay.push_back (clusterDelay[max] + 2.56 * table3gpp->m_cDS);
1729 
1730  clusterAoa.push_back (clusterAoa[min]);
1731  clusterAoa.push_back (clusterAoa[min]);
1732  clusterAoa.push_back (clusterAoa[max]);
1733  clusterAoa.push_back (clusterAoa[max]);
1734 
1735  clusterZoa.push_back (clusterZoa[min]);
1736  clusterZoa.push_back (clusterZoa[min]);
1737  clusterZoa.push_back (clusterZoa[max]);
1738  clusterZoa.push_back (clusterZoa[max]);
1739 
1740  clusterAod.push_back (clusterAod[min]);
1741  clusterAod.push_back (clusterAod[min]);
1742  clusterAod.push_back (clusterAod[max]);
1743  clusterAod.push_back (clusterAod[max]);
1744 
1745  clusterZod.push_back (clusterZod[min]);
1746  clusterZod.push_back (clusterZod[min]);
1747  clusterZod.push_back (clusterZod[max]);
1748  clusterZod.push_back (clusterZod[max]);
1749 
1750 
1751  }
1752 
1753  NS_LOG_INFO ("size of coefficient matrix =[" << H_usn.size () << "][" << H_usn[0].size () << "][" << H_usn[0][0].size () << "]");
1754 
1755  channelParams->m_channel = H_usn;
1756  channelParams->m_delay = clusterDelay;
1757 
1758  channelParams->m_angle.clear ();
1759  channelParams->m_angle.push_back (clusterAoa);
1760  channelParams->m_angle.push_back (clusterZoa);
1761  channelParams->m_angle.push_back (clusterAod);
1762  channelParams->m_angle.push_back (clusterZod);
1763 
1764  return channelParams;
1765 }
1766 
1767 std::pair<double, double>
1768 ThreeGppChannelModel::WrapAngles (double azimuthRad, double inclinationRad)
1769 {
1770  inclinationRad = WrapTo2Pi (inclinationRad);
1771  if (inclinationRad > M_PI)
1772  {
1773  // inclination must be in [0, M_PI]
1774  inclinationRad -= M_PI;
1775  azimuthRad += M_PI;
1776  }
1777 
1778  azimuthRad = WrapTo2Pi (azimuthRad);
1779 
1780  NS_ASSERT_MSG (0 <= inclinationRad && inclinationRad <= M_PI,
1781  "inclinationRad=" << inclinationRad << " not valid, should be in [0, pi]");
1782  NS_ASSERT_MSG (0 <= azimuthRad && azimuthRad <= 2 * M_PI,
1783  "azimuthRad=" << azimuthRad << " not valid, should be in [0, 2*pi]");
1784 
1785  return std::make_pair (azimuthRad, inclinationRad);
1786 }
1787 
1790  const DoubleVector &clusterAOA,
1791  const DoubleVector &clusterZOA) const
1792 {
1793  NS_LOG_FUNCTION (this);
1794 
1795  DoubleVector powerAttenuation;
1796  uint8_t clusterNum = clusterAOA.size ();
1797  for (uint8_t cInd = 0; cInd < clusterNum; cInd++)
1798  {
1799  powerAttenuation.push_back (0); //Initial power attenuation for all clusters to be 0 dB;
1800  }
1801  //step a: the number of non-self blocking blockers is stored in m_numNonSelfBlocking.
1802 
1803  //step b:Generate the size and location of each blocker
1804  //generate self blocking (i.e., for blockage from the human body)
1805  double phi_sb, x_sb, theta_sb, y_sb;
1806  //table 7.6.4.1-1 Self-blocking region parameters.
1807  if (m_portraitMode)
1808  {
1809  phi_sb = 260;
1810  x_sb = 120;
1811  theta_sb = 100;
1812  y_sb = 80;
1813  }
1814  else // landscape mode
1815  {
1816  phi_sb = 40;
1817  x_sb = 160;
1818  theta_sb = 110;
1819  y_sb = 75;
1820  }
1821 
1822  //generate or update non-self blocking
1823  if (params->m_nonSelfBlocking.size () == 0) //generate new blocking regions
1824  {
1825  for (uint16_t blockInd = 0; blockInd < m_numNonSelfBlocking; blockInd++)
1826  {
1827  //draw value from table 7.6.4.1-2 Blocking region parameters
1828  DoubleVector table;
1829  table.push_back (m_normalRv->GetValue ()); //phi_k: store the normal RV that will be mapped to uniform (0,360) later.
1830  if (m_scenario == "InH-OfficeMixed" || m_scenario == "InH-OfficeOpen")
1831  {
1832  table.push_back (m_uniformRv->GetValue (15, 45)); //x_k
1833  table.push_back (90); //Theta_k
1834  table.push_back (m_uniformRv->GetValue (5, 15)); //y_k
1835  table.push_back (2); //r
1836  }
1837  else
1838  {
1839  table.push_back (m_uniformRv->GetValue (5, 15)); //x_k
1840  table.push_back (90); //Theta_k
1841  table.push_back (5); //y_k
1842  table.push_back (10); //r
1843  }
1844  params->m_nonSelfBlocking.push_back (table);
1845  }
1846  }
1847  else
1848  {
1849  double deltaX = sqrt (pow (params->m_preLocUT.x - params->m_locUT.x, 2) + pow (params->m_preLocUT.y - params->m_locUT.y, 2));
1850  //if deltaX and speed are both 0, the autocorrelation is 1, skip updating
1851  if (deltaX > 1e-6 || m_blockerSpeed > 1e-6)
1852  {
1853  double corrDis;
1854  //draw value from table 7.6.4.1-4: Spatial correlation distance for different m_scenarios.
1855  if (m_scenario == "InH-OfficeMixed" || m_scenario == "InH-OfficeOpen")
1856  {
1857  //InH, correlation distance = 5;
1858  corrDis = 5;
1859  }
1860  else
1861  {
1862  if (params->m_channelCondition->IsO2i ()) // outdoor to indoor
1863  {
1864  corrDis = 5;
1865  }
1866  else //LOS or NLOS
1867  {
1868  corrDis = 10;
1869  }
1870  }
1871  double R;
1872  if (m_blockerSpeed > 1e-6) // speed not equal to 0
1873  {
1874  double corrT = corrDis / m_blockerSpeed;
1875  R = exp (-1 * (deltaX / corrDis + (Now ().GetSeconds () - params->m_generatedTime.GetSeconds ()) / corrT));
1876  }
1877  else
1878  {
1879  R = exp (-1 * (deltaX / corrDis));
1880  }
1881 
1882  NS_LOG_INFO ("Distance change:" << deltaX << " Speed:" << m_blockerSpeed
1883  << " Time difference:" << Now ().GetSeconds () - params->m_generatedTime.GetSeconds ()
1884  << " correlation:" << R);
1885 
1886  //In order to generate correlated uniform random variables, we first generate correlated normal random variables and map the normal RV to uniform RV.
1887  //Notice the correlation will change if the RV is transformed from normal to uniform.
1888  //To compensate the distortion, the correlation of the normal RV is computed
1889  //such that the uniform RV would have the desired correlation when transformed from normal RV.
1890 
1891  //The following formula was obtained from MATLAB numerical simulation.
1892 
1893  if (R * R * (-0.069) + R * 1.074 - 0.002 < 1) //transform only when the correlation of normal RV is smaller than 1
1894  {
1895  R = R * R * (-0.069) + R * 1.074 - 0.002;
1896  }
1897  for (uint16_t blockInd = 0; blockInd < m_numNonSelfBlocking; blockInd++)
1898  {
1899 
1900  //Generate a new correlated normal RV with the following formula
1901  params->m_nonSelfBlocking[blockInd][PHI_INDEX] =
1902  R * params->m_nonSelfBlocking[blockInd][PHI_INDEX] + sqrt (1 - R * R) * m_normalRv->GetValue ();
1903  }
1904  }
1905 
1906  }
1907 
1908  //step c: Determine the attenuation of each blocker due to blockers
1909  for (uint8_t cInd = 0; cInd < clusterNum; cInd++)
1910  {
1911  NS_ASSERT_MSG (clusterAOA[cInd] >= 0 && clusterAOA[cInd] <= 360, "the AOA should be the range of [0,360]");
1912  NS_ASSERT_MSG (clusterZOA[cInd] >= 0 && clusterZOA[cInd] <= 180, "the ZOA should be the range of [0,180]");
1913 
1914  //check self blocking
1915  NS_LOG_INFO ("AOA=" << clusterAOA[cInd] << " Block Region[" << phi_sb - x_sb / 2 << "," << phi_sb + x_sb / 2 << "]");
1916  NS_LOG_INFO ("ZOA=" << clusterZOA[cInd] << " Block Region[" << theta_sb - y_sb / 2 << "," << theta_sb + y_sb / 2 << "]");
1917  if ( std::abs (clusterAOA[cInd] - phi_sb) < (x_sb / 2) && std::abs (clusterZOA[cInd] - theta_sb) < (y_sb / 2))
1918  {
1919  powerAttenuation[cInd] += 30; //anttenuate by 30 dB.
1920  NS_LOG_INFO ("Cluster[" << (int)cInd << "] is blocked by self blocking region and reduce 30 dB power,"
1921  "the attenuation is [" << powerAttenuation[cInd] << " dB]");
1922  }
1923 
1924  //check non-self blocking
1925  double phiK, xK, thetaK, yK;
1926  for (uint16_t blockInd = 0; blockInd < m_numNonSelfBlocking; blockInd++)
1927  {
1928  //The normal RV is transformed to uniform RV with the desired correlation.
1929  phiK = (0.5 * erfc (-1 * params->m_nonSelfBlocking[blockInd][PHI_INDEX] / sqrt (2))) * 360;
1930  while (phiK > 360)
1931  {
1932  phiK -= 360;
1933  }
1934 
1935  while (phiK < 0)
1936  {
1937  phiK += 360;
1938  }
1939 
1940  xK = params->m_nonSelfBlocking[blockInd][X_INDEX];
1941  thetaK = params->m_nonSelfBlocking[blockInd][THETA_INDEX];
1942  yK = params->m_nonSelfBlocking[blockInd][Y_INDEX];
1943  NS_LOG_INFO ("AOA=" << clusterAOA[cInd] << " Block Region[" << phiK - xK << "," << phiK + xK << "]");
1944  NS_LOG_INFO ("ZOA=" << clusterZOA[cInd] << " Block Region[" << thetaK - yK << "," << thetaK + yK << "]");
1945 
1946  if ( std::abs (clusterAOA[cInd] - phiK) < (xK)
1947  && std::abs (clusterZOA[cInd] - thetaK) < (yK))
1948  {
1949  double A1 = clusterAOA[cInd] - (phiK + xK / 2); //(7.6-24)
1950  double A2 = clusterAOA[cInd] - (phiK - xK / 2); //(7.6-25)
1951  double Z1 = clusterZOA[cInd] - (thetaK + yK / 2); //(7.6-26)
1952  double Z2 = clusterZOA[cInd] - (thetaK - yK / 2); //(7.6-27)
1953  int signA1, signA2, signZ1, signZ2;
1954  //draw sign for the above parameters according to table 7.6.4.1-3 Description of signs
1955  if (xK / 2 < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= xK)
1956  {
1957  signA1 = -1;
1958  }
1959  else
1960  {
1961  signA1 = 1;
1962  }
1963  if (-1 * xK < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= -1 * xK / 2)
1964  {
1965  signA2 = -1;
1966  }
1967  else
1968  {
1969  signA2 = 1;
1970  }
1971 
1972  if (yK / 2 < clusterZOA[cInd] - thetaK && clusterZOA[cInd] - thetaK <= yK)
1973  {
1974  signZ1 = -1;
1975  }
1976  else
1977  {
1978  signZ1 = 1;
1979  }
1980  if (-1 * yK < clusterZOA[cInd] - thetaK && clusterZOA[cInd] - thetaK <= -1 * yK / 2)
1981  {
1982  signZ2 = -1;
1983  }
1984  else
1985  {
1986  signZ2 = 1;
1987  }
1988  double lambda = 3e8 / m_frequency;
1989  double F_A1 = atan (signA1 * M_PI / 2 * sqrt (M_PI / lambda *
1990  params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (DegreesToRadians (A1)) - 1))) / M_PI; //(7.6-23)
1991  double F_A2 = atan (signA2 * M_PI / 2 * sqrt (M_PI / lambda *
1992  params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (DegreesToRadians (A2)) - 1))) / M_PI;
1993  double F_Z1 = atan (signZ1 * M_PI / 2 * sqrt (M_PI / lambda *
1994  params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (DegreesToRadians (Z1)) - 1))) / M_PI;
1995  double F_Z2 = atan (signZ2 * M_PI / 2 * sqrt (M_PI / lambda *
1996  params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (DegreesToRadians (Z2)) - 1))) / M_PI;
1997  double L_dB = -20 * log10 (1 - (F_A1 + F_A2) * (F_Z1 + F_Z2)); //(7.6-22)
1998  powerAttenuation[cInd] += L_dB;
1999  NS_LOG_INFO ("Cluster[" << (int)cInd << "] is blocked by no-self blocking, "
2000  "the loss is [" << L_dB << "]" << " dB");
2001 
2002  }
2003  }
2004  }
2005  return powerAttenuation;
2006 }
2007 
2008 
2009 void
2010 ThreeGppChannelModel::Shuffle (double * first, double * last) const
2011 {
2012  for (auto i = (last - first) - 1; i > 0; --i)
2013  {
2014  std::swap (first[i], first[m_uniformRvShuffle->GetInteger (0, i)]);
2015  }
2016 }
2017 
2018 int64_t
2020 {
2021  NS_LOG_FUNCTION (this << stream);
2022  m_normalRv->SetStream (stream);
2023  m_uniformRv->SetStream (stream + 1);
2024  m_uniformRvShuffle->SetStream (stream + 2);
2025  return 3;
2026 }
2027 
2028 } // namespace ns3
ns3::sqrtC_office_LOS
static const double sqrtC_office_LOS[7][7]
Definition: three-gpp-channel-model.cc:144
ns3::ThreeGppChannelModel::ParamsTable::m_rTau
double m_rTau
Definition: three-gpp-channel-model.h:201
ns3::TypeId
a unique identifier for an interface.
Definition: type-id.h:59
NS_LOG_COMPONENT_DEFINE
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
ns3::sqrtC_RMa_LOS
static const double sqrtC_RMa_LOS[7][7]
Definition: three-gpp-channel-model.cc:58
ns3::ThreeGppChannelModel::ParamsTable::m_cASA
double m_cASA
Definition: three-gpp-channel-model.h:197
ns3::ThreeGppChannelModel::GetTypeId
static TypeId GetTypeId()
Get the type ID.
Definition: three-gpp-channel-model.cc:192
ns3::ThreeGppChannelModel::GetChannelConditionModel
Ptr< ChannelConditionModel > GetChannelConditionModel() const
Get the associated channel condition model.
Definition: three-gpp-channel-model.cc:255
ns3::MatrixBasedChannelModel::ChannelMatrix::m_delay
DoubleVector m_delay
cluster delay in nanoseconds.
Definition: matrix-based-channel-model.h:64
ns3::ThreeGppChannelModel::ParamsTable::m_sigLgZSA
double m_sigLgZSA
Definition: three-gpp-channel-model.h:191
ns3::ThreeGppChannelModel::~ThreeGppChannelModel
~ThreeGppChannelModel()
Destructor.
Definition: three-gpp-channel-model.cc:174
ns3::ThreeGppChannelModel::ParamsTable::m_sigLgASD
double m_sigLgASD
Definition: three-gpp-channel-model.h:187
first
Definition: first.py:1
NS_OBJECT_ENSURE_REGISTERED
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
NS_ASSERT
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:67
ns3::ThreeGppChannelModel::ParamsTable::m_offsetZOD
double m_offsetZOD
Definition: three-gpp-channel-model.h:194
ns3::ThreeGppChannelModel::GetThreeGppTable
virtual Ptr< const ParamsTable > GetThreeGppTable(Ptr< const ChannelCondition > channelCondition, double hBS, double hUT, double distance2D) const
Get the parameters needed to apply the channel generation procedure.
Definition: three-gpp-channel-model.cc:296
ns3::MakeTimeChecker
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:533
ns3::BooleanValue
AttributeValue implementation for Boolean.
Definition: boolean.h:37
ns3::ThreeGppChannelModel::GetChannel
Ptr< const ChannelMatrix > GetChannel(Ptr< const MobilityModel > aMob, Ptr< const MobilityModel > bMob, Ptr< const PhasedArrayModel > aAntenna, Ptr< const PhasedArrayModel > bAntenna) override
Looks for the channel matrix associated to the aMob and bMob pair in m_channelMap.
Definition: three-gpp-channel-model.cc:975
ns3::MakeIntegerAccessor
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: integer.h:45
ns3::ThreeGppChannelModel::m_scenario
std::string m_scenario
the 3GPP scenario
Definition: three-gpp-channel-model.h:261
ns3::Time::NS
@ NS
nanosecond
Definition: nstime.h:118
ns3::Angles::GetInclination
double GetInclination(void) const
Getter for inclination angle.
Definition: angles.cc:229
min
#define min(a, b)
Definition: 80211b.c:42
ns3::Node::GetId
uint32_t GetId(void) const
Definition: node.cc:109
ns3::ThreeGppChannelModel::ParamsTable::m_sigLgDS
double m_sigLgDS
Definition: three-gpp-channel-model.h:185
ns3::ThreeGppChannelModel::ChannelMatrixNeedsUpdate
bool ChannelMatrixNeedsUpdate(Ptr< const ThreeGppChannelMatrix > channelMatrix, Ptr< const ChannelCondition > channelCondition) const
Check if the channel matrix has to be updated.
Definition: three-gpp-channel-model.cc:951
ns3::Simulator::Now
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
ns3
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns3::ThreeGppChannelModel::ParamsTable::m_cZSA
double m_cZSA
Definition: three-gpp-channel-model.h:198
ns3::IntegerValue
Hold a signed integer type.
Definition: integer.h:44
ns3::MatrixBasedChannelModel::ChannelMatrix::m_angle
Double2DVector m_angle
cluster angle angle[direction][n], where direction = 0(AOA), 1(ZOA), 2(AOD), 3(ZOD) in degree.
Definition: matrix-based-channel-model.h:65
ns3::ThreeGppChannelModel::Shuffle
void Shuffle(double *first, double *last) const
Shuffle the elements of a simple sequence container of type double.
Definition: three-gpp-channel-model.cc:2010
ns3::ThreeGppChannelModel::ParamsTable::m_numOfCluster
uint8_t m_numOfCluster
Definition: three-gpp-channel-model.h:182
ns3::Node
A network Node.
Definition: node.h:57
ns3::MatrixBasedChannelModel::ChannelMatrix::m_channel
Complex3DVector m_channel
channel matrix H[u][s][n].
Definition: matrix-based-channel-model.h:63
ns3::ThreeGppChannelModel::ParamsTable::m_uLgZSD
double m_uLgZSD
Definition: three-gpp-channel-model.h:192
NS_LOG_WARN
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:265
ns3::ThreeGppChannelModel::SetScenario
void SetScenario(const std::string &scenario)
Sets the propagation scenario.
Definition: three-gpp-channel-model.cc:277
ns3::MatrixBasedChannelModel::Double2DVector
std::vector< DoubleVector > Double2DVector
type definition for matrices of doubles
Definition: matrix-based-channel-model.h:52
ns3::ThreeGppChannelModel::ThreeGppChannelMatrix::m_K
double m_K
K factor.
Definition: three-gpp-channel-model.h:168
ns3::PointerValue
Hold objects of type Ptr<T>.
Definition: pointer.h:37
ns3::ThreeGppChannelModel::ParamsTable::m_uK
double m_uK
Definition: three-gpp-channel-model.h:199
ns3::sqrtC_UMi_O2I
static const double sqrtC_UMi_O2I[6][6]
Definition: three-gpp-channel-model.cc:135
ns3::ThreeGppChannelModel::PHI_INDEX
static const uint8_t PHI_INDEX
index of the PHI value in the m_nonSelfBlocking array
Definition: three-gpp-channel-model.h:273
ns3::MatrixBasedChannelModel::Double3DVector
std::vector< Double2DVector > Double3DVector
type definition for 3D matrices of doubles
Definition: matrix-based-channel-model.h:53
ns3::Time::As
TimeWithUnit As(const enum Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:429
ns3::ThreeGppChannelModel::m_blockage
bool m_blockage
enables the blockage model A
Definition: three-gpp-channel-model.h:268
ns3::ThreeGppChannelModel::X_INDEX
static const uint8_t X_INDEX
index of the X value in the m_nonSelfBlocking array
Definition: three-gpp-channel-model.h:274
ns3::MakeBooleanAccessor
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: boolean.h:85
ns3::ThreeGppChannelModel::m_portraitMode
bool m_portraitMode
true if potrait mode, false if landscape
Definition: three-gpp-channel-model.h:270
ns3::ThreeGppChannelModel::m_frequency
double m_frequency
the operating frequency
Definition: three-gpp-channel-model.h:260
ns3::MatrixBasedChannelModel
This is an interface for a channel model that can be described by a channel matrix,...
Definition: matrix-based-channel-model.h:44
ns3::WrapTo2Pi
double WrapTo2Pi(double a)
Wrap angle in [0, 2*M_PI)
Definition: angles.cc:108
ns3::ThreeGppChannelModel::ParamsTable::m_uLgASA
double m_uLgASA
Definition: three-gpp-channel-model.h:188
ns3::ThreeGppChannelModel::ThreeGppChannelMatrix::m_numCluster
uint8_t m_numCluster
reduced cluster number;
Definition: three-gpp-channel-model.h:169
ns3::UniformRandomVariable::GetInteger
uint32_t GetInteger(uint32_t min, uint32_t max)
Get the next random value, as an unsigned integer in the specified range .
Definition: random-variable-stream.cc:193
ns3::ThreeGppChannelModel::SetChannelConditionModel
void SetChannelConditionModel(Ptr< ChannelConditionModel > model)
Set the channel condition model.
Definition: three-gpp-channel-model.cc:248
ns3::TypeId::SetParent
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
ns3::DoubleValue
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:41
ns3::ThreeGppChannelModel::ParamsTable::m_raysPerCluster
uint8_t m_raysPerCluster
Definition: three-gpp-channel-model.h:183
ns3::MatrixBasedChannelModel::GetKey
static constexpr uint32_t GetKey(uint32_t x1, uint32_t x2)
Calculate the channel key using the Cantor function.
Definition: matrix-based-channel-model.h:120
ns3::ThreeGppChannelModel::ParamsTable::m_sigLgASA
double m_sigLgASA
Definition: three-gpp-channel-model.h:189
ns3::sqrtC_UMa_LOS
static const double sqrtC_UMa_LOS[7][7]
Definition: three-gpp-channel-model.cc:86
ns3::sqrtC_UMi_NLOS
static const double sqrtC_UMi_NLOS[6][6]
Definition: three-gpp-channel-model.cc:126
ns3::Ptr
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
NS_FATAL_ERROR
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
ns3::ThreeGppChannelModel::ThreeGppChannelMatrix::m_channelCondition
Ptr< const ChannelCondition > m_channelCondition
the channel condition
Definition: three-gpp-channel-model.h:158
ns3::ThreeGppChannelModel::ThreeGppChannelMatrix::m_DS
double m_DS
delay spread
Definition: three-gpp-channel-model.h:167
ns3::MatrixBasedChannelModel::ChannelMatrix::m_generatedTime
Time m_generatedTime
generation time
Definition: matrix-based-channel-model.h:66
ns3::min
double min(double x, double y)
Definition: cobalt-queue-disc.cc:132
ns3::Now
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:287
bianchi11ax.k
int k
Definition: bianchi11ax.py:129
max
#define max(a, b)
Definition: 80211b.c:43
ns3::ThreeGppChannelModel::ParamsTable::m_uLgASD
double m_uLgASD
Definition: three-gpp-channel-model.h:186
ns3::Object
A base class which provides memory management and object aggregation.
Definition: object.h:88
ns3::Time::IsZero
bool IsZero(void) const
Exactly equivalent to t == 0.
Definition: nstime.h:301
ns3::ThreeGppChannelModel::ParamsTable::m_uXpr
double m_uXpr
Definition: three-gpp-channel-model.h:202
ns3::sqrtC_office_NLOS
static const double sqrtC_office_NLOS[6][6]
Definition: three-gpp-channel-model.cc:154
NS_LOG_INFO
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:281
ns3::ThreeGppChannelModel::ParamsTable::m_uLgDS
double m_uLgDS
Definition: three-gpp-channel-model.h:184
ns3::sqrtC_UMa_O2I
static const double sqrtC_UMa_O2I[6][6]
Definition: three-gpp-channel-model.cc:106
ns3::ThreeGppChannelModel::GetScenario
std::string GetScenario(void) const
Returns the propagation scenario.
Definition: three-gpp-channel-model.cc:289
ns3::sqrtC_UMa_NLOS
static const double sqrtC_UMa_NLOS[6][6]
Definition: three-gpp-channel-model.cc:97
ns3::MilliSeconds
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1297
ns3::ThreeGppChannelModel::m_blockerSpeed
double m_blockerSpeed
the blocker speed
Definition: three-gpp-channel-model.h:271
ns3::ThreeGppChannelModel::m_normalRv
Ptr< NormalRandomVariable > m_normalRv
normal random variable
Definition: three-gpp-channel-model.h:264
ns3::ThreeGppChannelModel::ThreeGppChannelMatrix::m_clusterPhase
MatrixBasedChannelModel::Double3DVector m_clusterPhase
the initial random phases
Definition: three-gpp-channel-model.h:170
ns3::ThreeGppChannelModel::AssignStreams
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
Definition: three-gpp-channel-model.cc:2019
ns3::MakeBooleanChecker
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
ns3::ThreeGppChannelModel::CalcAttenuationOfBlockage
DoubleVector CalcAttenuationOfBlockage(Ptr< ThreeGppChannelMatrix > params, const DoubleVector &clusterAOA, const DoubleVector &clusterZOA) const
Applies the blockage model A described in 3GPP TR 38.901.
Definition: three-gpp-channel-model.cc:1789
three-gpp-channel-model.h
ns3::sqrtC_RMa_O2I
static const double sqrtC_RMa_O2I[6][6]
Definition: three-gpp-channel-model.cc:77
ns3::ThreeGppChannelModel::m_uniformRv
Ptr< UniformRandomVariable > m_uniformRv
uniform random variable
Definition: three-gpp-channel-model.h:263
ns3::ThreeGppChannelModel::SetFrequency
void SetFrequency(double f)
Sets the center frequency of the model.
Definition: three-gpp-channel-model.cc:262
ns3::MatrixBasedChannelModel::ChannelMatrix::m_nodeIds
std::pair< uint32_t, uint32_t > m_nodeIds
the first element is the s-node ID (the transmitter when the channel was generated),...
Definition: matrix-based-channel-model.h:67
ns3::ThreeGppChannelModel::GetFrequency
double GetFrequency(void) const
Returns the center frequency.
Definition: three-gpp-channel-model.cc:270
NS_ASSERT_MSG
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:88
ns3::MakePointerAccessor
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: pointer.h:227
ns3::StringValue
Hold variables of type string.
Definition: string.h:41
ns3::ThreeGppChannelModel::m_updatePeriod
Time m_updatePeriod
the channel update period
Definition: three-gpp-channel-model.h:259
ns3::RadiansToDegrees
double RadiansToDegrees(double radians)
converts radians to degrees
Definition: angles.cc:45
ns3::MakeDoubleAccessor
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: double.h:42
ns3::MatrixBasedChannelModel::DoubleVector
std::vector< double > DoubleVector
type definition for vectors of doubles
Definition: matrix-based-channel-model.h:51
ns3::ThreeGppChannelModel::ParamsTable::m_uLgZSA
double m_uLgZSA
Definition: three-gpp-channel-model.h:190
ns3::Angles
Class holding the azimuth and inclination angles of spherical coordinates.
Definition: angles.h:119
ns3::ThreeGppChannelModel::Y_INDEX
static const uint8_t Y_INDEX
index of the Y value in the m_nonSelfBlocking array
Definition: three-gpp-channel-model.h:276
ns3::sqrtC_RMa_NLOS
static const double sqrtC_RMa_NLOS[6][6]
Definition: three-gpp-channel-model.cc:68
NS_LOG_DEBUG
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
ns3::Angles::GetAzimuth
double GetAzimuth(void) const
Getter for azimuth angle.
Definition: angles.cc:222
ns3::ThreeGppChannelModel::ParamsTable::m_perClusterShadowingStd
double m_perClusterShadowingStd
Definition: three-gpp-channel-model.h:204
f
double f(double x, void *params)
Definition: 80211b.c:70
ns3::MatrixBasedChannelModel::Complex3DVector
std::vector< Complex2DVector > Complex3DVector
type definition for complex 3D matrices
Definition: matrix-based-channel-model.h:55
ns3::ThreeGppChannelModel::m_numNonSelfBlocking
uint16_t m_numNonSelfBlocking
number of non-self-blocking regions
Definition: three-gpp-channel-model.h:269
ns3::TimeValue
AttributeValue implementation for Time.
Definition: nstime.h:1353
sample-rng-plot.x
list x
Definition: sample-rng-plot.py:34
ns3::ThreeGppChannelModel::m_channelConditionModel
Ptr< ChannelConditionModel > m_channelConditionModel
the channel condition model
Definition: three-gpp-channel-model.h:262
NS_LOG_FUNCTION
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Definition: log-macros-enabled.h:244
ns3::ThreeGppChannelModel::ParamsTable::m_sigXpr
double m_sigXpr
Definition: three-gpp-channel-model.h:203
ns3::ThreeGppChannelModel::m_channelMap
std::unordered_map< uint32_t, Ptr< ThreeGppChannelMatrix > > m_channelMap
map containing the channel realizations
Definition: three-gpp-channel-model.h:258
ns3::ThreeGppChannelModel::ParamsTable::m_sigK
double m_sigK
Definition: three-gpp-channel-model.h:200
ns3::ThreeGppChannelModel::ParamsTable::m_cDS
double m_cDS
Definition: three-gpp-channel-model.h:195
ns3::MakeStringChecker
Ptr< const AttributeChecker > MakeStringChecker(void)
Definition: string.cc:30
ns3::RandomVariableStream::SetStream
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
Definition: random-variable-stream.cc:100
ns3::ThreeGppChannelModel::m_uniformRvShuffle
Ptr< UniformRandomVariable > m_uniformRvShuffle
uniform random variable used to shuffle array in GetNewChannel
Definition: three-gpp-channel-model.h:265
ns3::max
double max(double x, double y)
Definition: cobalt-queue-disc.cc:137
ns3::offSetAlpha
static const double offSetAlpha[20]
Definition: three-gpp-channel-model.cc:44
ns3::ThreeGppChannelModel::R_INDEX
static const uint8_t R_INDEX
index of the R value in the m_nonSelfBlocking array
Definition: three-gpp-channel-model.h:277
ns3::ThreeGppChannelModel::GetNewChannel
Ptr< ThreeGppChannelMatrix > GetNewChannel(Vector locUT, Ptr< const ChannelCondition > channelCondition, Ptr< const PhasedArrayModel > sAntenna, Ptr< const PhasedArrayModel > uAntenna, Angles &uAngle, Angles &sAngle, double dis2D, double hBS, double hUT) const
Compute the channel matrix between two devices using the procedure described in 3GPP TR 38....
Definition: three-gpp-channel-model.cc:1044
ns3::ThreeGppChannelModel::THETA_INDEX
static const uint8_t THETA_INDEX
index of the THETA value in the m_nonSelfBlocking array
Definition: three-gpp-channel-model.h:275
ns3::ThreeGppChannelModel::ParamsTable::m_cASD
double m_cASD
Definition: three-gpp-channel-model.h:196
ns3::ThreeGppChannelModel::ThreeGppChannelModel
ThreeGppChannelModel()
Constructor.
Definition: three-gpp-channel-model.cc:163
ns3::UniformRandomVariable::GetValue
double GetValue(double min, double max)
Get the next random value, as a double in the specified range .
Definition: random-variable-stream.cc:182
ns3::ThreeGppChannelModel::ParamsTable::m_sqrtC
double m_sqrtC[7][7]
Definition: three-gpp-channel-model.h:206
ns3::ThreeGppChannelModel::DoDispose
void DoDispose() override
Destructor implementation.
Definition: three-gpp-channel-model.cc:180
ns3::ThreeGppChannelModel::WrapAngles
static std::pair< double, double > WrapAngles(double azimuthRad, double inclinationRad)
Wrap an (azimuth, inclination) angle pair in a valid range.
Definition: three-gpp-channel-model.cc:1768
ns3::DegreesToRadians
double DegreesToRadians(double degrees)
converts degrees to radians
Definition: angles.cc:38
ns3::MakeStringAccessor
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: string.h:42
ns3::MakeTimeAccessor
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: nstime.h:1354
ns3::ThreeGppChannelModel::ParamsTable::m_sigLgZSD
double m_sigLgZSD
Definition: three-gpp-channel-model.h:193
ns3::sqrtC_UMi_LOS
static const double sqrtC_UMi_LOS[7][7]
Definition: three-gpp-channel-model.cc:116