24#include "ns3/double.h"
25#include "ns3/integer.h"
27#include "ns3/mobility-model.h"
29#include "ns3/phased-array-model.h"
30#include "ns3/pointer.h"
31#include "ns3/string.h"
32#include <ns3/simulator.h>
46static constexpr double DEG2RAD = M_PI / 180.0;
51 0.0447, -0.0447, 0.1413, -0.1413, 0.2492, -0.2492, 0.3715, -0.3715, 0.5129, -0.5129,
52 0.6797, -0.6797, 0.8844, -0.8844, 1.1481, -1.1481, 1.5195, -1.5195, 2.1551, -2.1551,
64 {1, 0, 0, 0, 0, 0, 0},
65 {0, 1, 0, 0, 0, 0, 0},
66 {-0.5, 0, 0.866025, 0, 0, 0, 0},
67 {0, 0, 0, 1, 0, 0, 0},
68 {0, 0, 0, 0, 1, 0, 0},
69 {0.01, 0, -0.0519615, 0.73, -0.2, 0.651383, 0},
70 {-0.17, -0.02, 0.21362, -0.14, 0.24, 0.142773, 0.909661},
84 {-0.5, 0.866025, 0, 0, 0, 0},
85 {0.6, -0.11547, 0.791623, 0, 0, 0},
87 {-0.04, -0.138564, 0.540662, -0.18, 0.809003, 0},
88 {-0.25, -0.606218, -0.240013, 0.26, -0.231685, 0.625392},
103 {0, 0, -0.7, 0.714143, 0, 0},
104 {0, 0, 0.66, -0.123225, 0.741091, 0},
105 {0, 0, 0.47, 0.152631, -0.393194, 0.775373},
117 {1, 0, 0, 0, 0, 0, 0},
118 {0, 1, 0, 0, 0, 0, 0},
119 {-0.4, -0.4, 0.824621, 0, 0, 0, 0},
120 {-0.5, 0, 0.242536, 0.83137, 0, 0, 0},
121 {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0},
122 {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0},
123 {-0.8, 0, -0.388057, -0.367926, 0.238537, -3.58949e-15, 0.130931},
137 {-0.4, 0.916515, 0, 0, 0, 0},
138 {-0.6, 0.174574, 0.78072, 0, 0, 0},
139 {0, 0.654654, 0.365963, 0.661438, 0, 0},
140 {0, -0.545545, 0.762422, 0.118114, 0.327327, 0},
141 {-0.4, -0.174574, -0.396459, 0.392138, 0.49099, 0.507445},
154 {-0.5, 0.866025, 0, 0, 0, 0},
155 {0.2, 0.57735, 0.791623, 0, 0, 0},
156 {0, 0.46188, -0.336861, 0.820482, 0, 0},
157 {0, -0.69282, 0.252646, 0.493742, 0.460857, 0},
158 {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515},
171 {1, 0, 0, 0, 0, 0, 0},
172 {0.5, 0.866025, 0, 0, 0, 0, 0},
173 {-0.4, -0.57735, 0.711805, 0, 0, 0, 0},
174 {-0.5, 0.057735, 0.468293, 0.726201, 0, 0, 0},
175 {-0.4, -0.11547, 0.805464, -0.23482, 0.350363, 0, 0},
176 {0, 0, 0, 0.688514, 0.461454, 0.559471, 0},
177 {0, 0, 0.280976, 0.231921, -0.490509, 0.11916, 0.782603},
191 {-0.7, 0.714143, 0, 0, 0, 0},
193 {-0.4, 0.168034, 0, 0.90098, 0, 0},
194 {0, -0.70014, 0.5, 0.130577, 0.4927, 0},
195 {0, 0, 0.5, 0.221981, -0.566238, 0.616522},
208 {-0.5, 0.866025, 0, 0, 0, 0},
209 {0.2, 0.57735, 0.791623, 0, 0, 0},
210 {0, 0.46188, -0.336861, 0.820482, 0, 0},
211 {0, -0.69282, 0.252646, 0.493742, 0.460857, 0},
212 {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515},
224 {1, 0, 0, 0, 0, 0, 0},
225 {0.5, 0.866025, 0, 0, 0, 0, 0},
226 {-0.8, -0.11547, 0.588784, 0, 0, 0, 0},
227 {-0.4, 0.23094, 0.520847, 0.717903, 0, 0, 0},
228 {-0.5, 0.288675, 0.73598, -0.348236, 0.0610847, 0, 0},
229 {0.2, -0.11547, 0.418943, 0.541106, 0.219905, 0.655744, 0},
230 {0.3, -0.057735, 0.73598, -0.348236, 0.0610847, -0.304997, 0.383375},
244 {-0.5, 0.866025, 0, 0, 0, 0},
245 {0, 0.46188, 0.886942, 0, 0, 0},
246 {-0.4, -0.23094, 0.120263, 0.878751, 0, 0},
247 {0, -0.311769, 0.55697, -0.249198, 0.728344, 0},
248 {0, -0.069282, 0.295397, 0.430696, 0.468462, 0.709214},
254 m_uniformRv = CreateObject<UniformRandomVariable>();
258 m_normalRv = CreateObject<NormalRandomVariable>();
285 TypeId(
"ns3::ThreeGppChannelModel")
288 .AddConstructor<ThreeGppChannelModel>()
289 .AddAttribute(
"Frequency",
290 "The operating Frequency in Hz",
294 MakeDoubleChecker<double>())
297 "The 3GPP scenario (RMa, UMa, UMi-StreetCanyon, InH-OfficeOpen, InH-OfficeMixed)",
302 .AddAttribute(
"ChannelConditionModel",
303 "Pointer to the channel condition model",
307 MakePointerChecker<ChannelConditionModel>())
308 .AddAttribute(
"UpdatePeriod",
309 "Specify the channel coherence time",
314 .AddAttribute(
"Blockage",
315 "Enable blockage model A (sec 7.6.4.1)",
319 .AddAttribute(
"NumNonselfBlocking",
320 "number of non-self-blocking regions",
323 MakeIntegerChecker<uint16_t>())
324 .AddAttribute(
"PortraitMode",
325 "true for portrait mode, false for landscape mode",
329 .AddAttribute(
"BlockerSpeed",
330 "The speed of moving blockers, the unit is m/s",
333 MakeDoubleChecker<double>())
334 .AddAttribute(
"vScatt",
335 "Maximum speed of the vehicle in the layout (see 3GPP TR 37.885 v15.3.0, "
337 "Used to compute the additional contribution for the Doppler of"
338 "delayed (reflected) paths",
341 MakeDoubleChecker<double>(0.0))
366 "Frequency should be between 0.5 and 100 GHz but is " << f);
381 NS_ASSERT_MSG(scenario ==
"RMa" || scenario ==
"UMa" || scenario ==
"UMi-StreetCanyon" ||
382 scenario ==
"InH-OfficeOpen" || scenario ==
"InH-OfficeMixed" ||
383 scenario ==
"V2V-Urban" || scenario ==
"V2V-Highway",
384 "Unknown scenario, choose between: RMa, UMa, UMi-StreetCanyon, "
385 "InH-OfficeOpen, InH-OfficeMixed, V2V-Urban or V2V-Highway");
400 double distance2D)
const
411 bool los = channelCondition->IsLos();
412 bool o2i = channelCondition->IsO2i();
421 table3gpp->m_numOfCluster = 11;
422 table3gpp->m_raysPerCluster = 20;
423 table3gpp->m_uLgDS = -7.49;
424 table3gpp->m_sigLgDS = 0.55;
425 table3gpp->m_uLgASD = 0.90;
426 table3gpp->m_sigLgASD = 0.38;
427 table3gpp->m_uLgASA = 1.52;
428 table3gpp->m_sigLgASA = 0.24;
429 table3gpp->m_uLgZSA = 0.47;
430 table3gpp->m_sigLgZSA = 0.40;
431 table3gpp->m_uLgZSD = 0.34;
432 table3gpp->m_sigLgZSD =
433 std::max(-1.0, -0.17 * (distance2D / 1000.0) - 0.01 * (hUT - 1.5) + 0.22);
434 table3gpp->m_offsetZOD = 0;
435 table3gpp->m_cDS = 3.91e-9;
436 table3gpp->m_cASD = 2;
437 table3gpp->m_cASA = 3;
438 table3gpp->m_cZSA = 3;
440 table3gpp->m_sigK = 4;
441 table3gpp->m_rTau = 3.8;
442 table3gpp->m_uXpr = 12;
443 table3gpp->m_sigXpr = 4;
444 table3gpp->m_perClusterShadowingStd = 3;
446 for (uint8_t row = 0; row < 7; row++)
448 for (uint8_t column = 0; column < 7; column++)
450 table3gpp->m_sqrtC[row][column] =
sqrtC_RMa_LOS[row][column];
454 else if (!los && !o2i)
456 table3gpp->m_numOfCluster = 10;
457 table3gpp->m_raysPerCluster = 20;
458 table3gpp->m_uLgDS = -7.43;
459 table3gpp->m_sigLgDS = 0.48;
460 table3gpp->m_uLgASD = 0.95;
461 table3gpp->m_sigLgASD = 0.45;
462 table3gpp->m_uLgASA = 1.52;
463 table3gpp->m_sigLgASA = 0.13;
464 table3gpp->m_uLgZSA = 0.58;
465 table3gpp->m_sigLgZSA = 0.37;
466 table3gpp->m_uLgZSD =
467 std::max(-1.0, -0.19 * (distance2D / 1000.0) - 0.01 * (hUT - 1.5) + 0.28);
468 table3gpp->m_sigLgZSD = 0.30;
469 table3gpp->m_offsetZOD = atan((35 - 3.5) / distance2D) - atan((35 - 1.5) / distance2D);
470 table3gpp->m_cDS = 3.91e-9;
471 table3gpp->m_cASD = 2;
472 table3gpp->m_cASA = 3;
473 table3gpp->m_cZSA = 3;
475 table3gpp->m_sigK = 0;
476 table3gpp->m_rTau = 1.7;
477 table3gpp->m_uXpr = 7;
478 table3gpp->m_sigXpr = 3;
479 table3gpp->m_perClusterShadowingStd = 3;
481 for (uint8_t row = 0; row < 6; row++)
483 for (uint8_t column = 0; column < 6; column++)
491 table3gpp->m_numOfCluster = 10;
492 table3gpp->m_raysPerCluster = 20;
493 table3gpp->m_uLgDS = -7.47;
494 table3gpp->m_sigLgDS = 0.24;
495 table3gpp->m_uLgASD = 0.67;
496 table3gpp->m_sigLgASD = 0.18;
497 table3gpp->m_uLgASA = 1.66;
498 table3gpp->m_sigLgASA = 0.21;
499 table3gpp->m_uLgZSA = 0.93;
500 table3gpp->m_sigLgZSA = 0.22;
501 table3gpp->m_uLgZSD =
502 std::max(-1.0, -0.19 * (distance2D / 1000.0) - 0.01 * (hUT - 1.5) + 0.28);
503 table3gpp->m_sigLgZSD = 0.30;
504 table3gpp->m_offsetZOD = atan((35 - 3.5) / distance2D) - atan((35 - 1.5) / distance2D);
505 table3gpp->m_cDS = 3.91e-9;
506 table3gpp->m_cASD = 2;
507 table3gpp->m_cASA = 3;
508 table3gpp->m_cZSA = 3;
510 table3gpp->m_sigK = 0;
511 table3gpp->m_rTau = 1.7;
512 table3gpp->m_uXpr = 7;
513 table3gpp->m_sigXpr = 3;
514 table3gpp->m_perClusterShadowingStd = 3;
516 for (uint8_t row = 0; row < 6; row++)
518 for (uint8_t column = 0; column < 6; column++)
520 table3gpp->m_sqrtC[row][column] =
sqrtC_RMa_O2I[row][column];
529 table3gpp->m_numOfCluster = 12;
530 table3gpp->m_raysPerCluster = 20;
531 table3gpp->m_uLgDS = -6.955 - 0.0963 * log10(fcGHz);
532 table3gpp->m_sigLgDS = 0.66;
533 table3gpp->m_uLgASD = 1.06 + 0.1114 * log10(fcGHz);
534 table3gpp->m_sigLgASD = 0.28;
535 table3gpp->m_uLgASA = 1.81;
536 table3gpp->m_sigLgASA = 0.20;
537 table3gpp->m_uLgZSA = 0.95;
538 table3gpp->m_sigLgZSA = 0.16;
539 table3gpp->m_uLgZSD =
540 std::max(-0.5, -2.1 * distance2D / 1000.0 - 0.01 * (hUT - 1.5) + 0.75);
541 table3gpp->m_sigLgZSD = 0.40;
542 table3gpp->m_offsetZOD = 0;
543 table3gpp->m_cDS = std::max(0.25, -3.4084 * log10(fcGHz) + 6.5622) * 1e-9;
544 table3gpp->m_cASD = 5;
545 table3gpp->m_cASA = 11;
546 table3gpp->m_cZSA = 7;
548 table3gpp->m_sigK = 3.5;
549 table3gpp->m_rTau = 2.5;
550 table3gpp->m_uXpr = 8;
551 table3gpp->m_sigXpr = 4;
552 table3gpp->m_perClusterShadowingStd = 3;
554 for (uint8_t row = 0; row < 7; row++)
556 for (uint8_t column = 0; column < 7; column++)
558 table3gpp->m_sqrtC[row][column] =
sqrtC_UMa_LOS[row][column];
564 double uLgZSD = std::max(-0.5, -2.1 * distance2D / 1000.0 - 0.01 * (hUT - 1.5) + 0.9);
566 double afc = 0.208 * log10(fcGHz) - 0.782;
568 double cfc = -0.13 * log10(fcGHz) + 2.03;
569 double efc = 7.66 * log10(fcGHz) - 5.96;
571 double offsetZOD = efc - std::pow(10, afc * log10(std::max(bfc, distance2D)) + cfc);
575 table3gpp->m_numOfCluster = 20;
576 table3gpp->m_raysPerCluster = 20;
577 table3gpp->m_uLgDS = -6.28 - 0.204 * log10(fcGHz);
578 table3gpp->m_sigLgDS = 0.39;
579 table3gpp->m_uLgASD = 1.5 - 0.1144 * log10(fcGHz);
580 table3gpp->m_sigLgASD = 0.28;
581 table3gpp->m_uLgASA = 2.08 - 0.27 * log10(fcGHz);
582 table3gpp->m_sigLgASA = 0.11;
583 table3gpp->m_uLgZSA = -0.3236 * log10(fcGHz) + 1.512;
584 table3gpp->m_sigLgZSA = 0.16;
585 table3gpp->m_uLgZSD = uLgZSD;
586 table3gpp->m_sigLgZSD = 0.49;
587 table3gpp->m_offsetZOD = offsetZOD;
588 table3gpp->m_cDS = std::max(0.25, -3.4084 * log10(fcGHz) + 6.5622) * 1e-9;
589 table3gpp->m_cASD = 2;
590 table3gpp->m_cASA = 15;
591 table3gpp->m_cZSA = 7;
593 table3gpp->m_sigK = 0;
594 table3gpp->m_rTau = 2.3;
595 table3gpp->m_uXpr = 7;
596 table3gpp->m_sigXpr = 3;
597 table3gpp->m_perClusterShadowingStd = 3;
599 for (uint8_t row = 0; row < 6; row++)
601 for (uint8_t column = 0; column < 6; column++)
609 table3gpp->m_numOfCluster = 12;
610 table3gpp->m_raysPerCluster = 20;
611 table3gpp->m_uLgDS = -6.62;
612 table3gpp->m_sigLgDS = 0.32;
613 table3gpp->m_uLgASD = 1.25;
614 table3gpp->m_sigLgASD = 0.42;
615 table3gpp->m_uLgASA = 1.76;
616 table3gpp->m_sigLgASA = 0.16;
617 table3gpp->m_uLgZSA = 1.01;
618 table3gpp->m_sigLgZSA = 0.43;
619 table3gpp->m_uLgZSD = uLgZSD;
620 table3gpp->m_sigLgZSD = 0.49;
621 table3gpp->m_offsetZOD = offsetZOD;
622 table3gpp->m_cDS = 11e-9;
623 table3gpp->m_cASD = 5;
624 table3gpp->m_cASA = 8;
625 table3gpp->m_cZSA = 3;
627 table3gpp->m_sigK = 0;
628 table3gpp->m_rTau = 2.2;
629 table3gpp->m_uXpr = 9;
630 table3gpp->m_sigXpr = 5;
631 table3gpp->m_perClusterShadowingStd = 4;
633 for (uint8_t row = 0; row < 6; row++)
635 for (uint8_t column = 0; column < 6; column++)
637 table3gpp->m_sqrtC[row][column] =
sqrtC_UMa_O2I[row][column];
647 table3gpp->m_numOfCluster = 12;
648 table3gpp->m_raysPerCluster = 20;
649 table3gpp->m_uLgDS = -0.24 * log10(1 + fcGHz) - 7.14;
650 table3gpp->m_sigLgDS = 0.38;
651 table3gpp->m_uLgASD = -0.05 * log10(1 + fcGHz) + 1.21;
652 table3gpp->m_sigLgASD = 0.41;
653 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.73;
654 table3gpp->m_sigLgASA = 0.014 * log10(1 + fcGHz) + 0.28;
655 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
656 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
657 table3gpp->m_uLgZSD =
658 std::max(-0.21, -14.8 * distance2D / 1000.0 + 0.01 * std::abs(hUT - hBS) + 0.83);
659 table3gpp->m_sigLgZSD = 0.35;
660 table3gpp->m_offsetZOD = 0;
661 table3gpp->m_cDS = 5e-9;
662 table3gpp->m_cASD = 3;
663 table3gpp->m_cASA = 17;
664 table3gpp->m_cZSA = 7;
666 table3gpp->m_sigK = 5;
667 table3gpp->m_rTau = 3;
668 table3gpp->m_uXpr = 9;
669 table3gpp->m_sigXpr = 3;
670 table3gpp->m_perClusterShadowingStd = 3;
672 for (uint8_t row = 0; row < 7; row++)
674 for (uint8_t column = 0; column < 7; column++)
676 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
683 std::max(-0.5, -3.1 * distance2D / 1000.0 + 0.01 * std::max(hUT - hBS, 0.0) + 0.2);
684 double offsetZOD = -1 * std::pow(10, -1.5 * log10(std::max(10.0, distance2D)) + 3.3);
687 table3gpp->m_numOfCluster = 19;
688 table3gpp->m_raysPerCluster = 20;
689 table3gpp->m_uLgDS = -0.24 * log10(1 + fcGHz) - 6.83;
690 table3gpp->m_sigLgDS = 0.16 * log10(1 + fcGHz) + 0.28;
691 table3gpp->m_uLgASD = -0.23 * log10(1 + fcGHz) + 1.53;
692 table3gpp->m_sigLgASD = 0.11 * log10(1 + fcGHz) + 0.33;
693 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
694 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
695 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
696 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
697 table3gpp->m_uLgZSD = uLgZSD;
698 table3gpp->m_sigLgZSD = 0.35;
699 table3gpp->m_offsetZOD = offsetZOD;
700 table3gpp->m_cDS = 11e-9;
701 table3gpp->m_cASD = 10;
702 table3gpp->m_cASA = 22;
703 table3gpp->m_cZSA = 7;
705 table3gpp->m_sigK = 0;
706 table3gpp->m_rTau = 2.1;
707 table3gpp->m_uXpr = 8;
708 table3gpp->m_sigXpr = 3;
709 table3gpp->m_perClusterShadowingStd = 3;
711 for (uint8_t row = 0; row < 6; row++)
713 for (uint8_t column = 0; column < 6; column++)
721 table3gpp->m_numOfCluster = 12;
722 table3gpp->m_raysPerCluster = 20;
723 table3gpp->m_uLgDS = -6.62;
724 table3gpp->m_sigLgDS = 0.32;
725 table3gpp->m_uLgASD = 1.25;
726 table3gpp->m_sigLgASD = 0.42;
727 table3gpp->m_uLgASA = 1.76;
728 table3gpp->m_sigLgASA = 0.16;
729 table3gpp->m_uLgZSA = 1.01;
730 table3gpp->m_sigLgZSA = 0.43;
731 table3gpp->m_uLgZSD = uLgZSD;
732 table3gpp->m_sigLgZSD = 0.35;
733 table3gpp->m_offsetZOD = offsetZOD;
734 table3gpp->m_cDS = 11e-9;
735 table3gpp->m_cASD = 5;
736 table3gpp->m_cASA = 8;
737 table3gpp->m_cZSA = 3;
739 table3gpp->m_sigK = 0;
740 table3gpp->m_rTau = 2.2;
741 table3gpp->m_uXpr = 9;
742 table3gpp->m_sigXpr = 5;
743 table3gpp->m_perClusterShadowingStd = 4;
745 for (uint8_t row = 0; row < 6; row++)
747 for (uint8_t column = 0; column < 6; column++)
749 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_O2I[row][column];
757 NS_ASSERT_MSG(!o2i,
"The indoor scenario does out support outdoor to indoor");
760 table3gpp->m_numOfCluster = 15;
761 table3gpp->m_raysPerCluster = 20;
762 table3gpp->m_uLgDS = -0.01 * log10(1 + fcGHz) - 7.692;
763 table3gpp->m_sigLgDS = 0.18;
764 table3gpp->m_uLgASD = 1.60;
765 table3gpp->m_sigLgASD = 0.18;
766 table3gpp->m_uLgASA = -0.19 * log10(1 + fcGHz) + 1.781;
767 table3gpp->m_sigLgASA = 0.12 * log10(1 + fcGHz) + 0.119;
768 table3gpp->m_uLgZSA = -0.26 * log10(1 + fcGHz) + 1.44;
769 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.264;
770 table3gpp->m_uLgZSD = -1.43 * log10(1 + fcGHz) + 2.228;
771 table3gpp->m_sigLgZSD = 0.13 * log10(1 + fcGHz) + 0.30;
772 table3gpp->m_offsetZOD = 0;
773 table3gpp->m_cDS = 3.91e-9;
774 table3gpp->m_cASD = 5;
775 table3gpp->m_cASA = 8;
776 table3gpp->m_cZSA = 9;
778 table3gpp->m_sigK = 4;
779 table3gpp->m_rTau = 3.6;
780 table3gpp->m_uXpr = 11;
781 table3gpp->m_sigXpr = 4;
782 table3gpp->m_perClusterShadowingStd = 6;
784 for (uint8_t row = 0; row < 7; row++)
786 for (uint8_t column = 0; column < 7; column++)
794 table3gpp->m_numOfCluster = 19;
795 table3gpp->m_raysPerCluster = 20;
796 table3gpp->m_uLgDS = -0.28 * log10(1 + fcGHz) - 7.173;
797 table3gpp->m_sigLgDS = 0.1 * log10(1 + fcGHz) + 0.055;
798 table3gpp->m_uLgASD = 1.62;
799 table3gpp->m_sigLgASD = 0.25;
800 table3gpp->m_uLgASA = -0.11 * log10(1 + fcGHz) + 1.863;
801 table3gpp->m_sigLgASA = 0.12 * log10(1 + fcGHz) + 0.059;
802 table3gpp->m_uLgZSA = -0.15 * log10(1 + fcGHz) + 1.387;
803 table3gpp->m_sigLgZSA = -0.09 * log10(1 + fcGHz) + 0.746;
804 table3gpp->m_uLgZSD = 1.08;
805 table3gpp->m_sigLgZSD = 0.36;
806 table3gpp->m_offsetZOD = 0;
807 table3gpp->m_cDS = 3.91e-9;
808 table3gpp->m_cASD = 5;
809 table3gpp->m_cASA = 11;
810 table3gpp->m_cZSA = 9;
812 table3gpp->m_sigK = 0;
813 table3gpp->m_rTau = 3;
814 table3gpp->m_uXpr = 10;
815 table3gpp->m_sigXpr = 4;
816 table3gpp->m_perClusterShadowingStd = 3;
818 for (uint8_t row = 0; row < 6; row++)
820 for (uint8_t column = 0; column < 6; column++)
829 if (channelCondition->IsLos())
833 table3gpp->m_numOfCluster = 12;
834 table3gpp->m_raysPerCluster = 20;
835 table3gpp->m_uLgDS = -0.2 * log10(1 + fcGHz) - 7.5;
836 table3gpp->m_sigLgDS = 0.1;
837 table3gpp->m_uLgASD = -0.1 * log10(1 + fcGHz) + 1.6;
838 table3gpp->m_sigLgASD = 0.1;
839 table3gpp->m_uLgASA = -0.1 * log10(1 + fcGHz) + 1.6;
840 table3gpp->m_sigLgASA = 0.1;
841 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
842 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
843 table3gpp->m_uLgZSD = -0.1 * log10(1 + fcGHz) + 0.73;
844 table3gpp->m_sigLgZSD = -0.04 * log10(1 + fcGHz) + 0.34;
845 table3gpp->m_offsetZOD = 0;
846 table3gpp->m_cDS = 5;
847 table3gpp->m_cASD = 17;
848 table3gpp->m_cASA = 17;
849 table3gpp->m_cZSA = 7;
850 table3gpp->m_uK = 3.48;
851 table3gpp->m_sigK = 2;
852 table3gpp->m_rTau = 3;
853 table3gpp->m_uXpr = 9;
854 table3gpp->m_sigXpr = 3;
855 table3gpp->m_perClusterShadowingStd = 4;
857 for (uint8_t row = 0; row < 7; row++)
859 for (uint8_t column = 0; column < 7; column++)
861 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
865 else if (channelCondition->IsNlos())
867 table3gpp->m_numOfCluster = 19;
868 table3gpp->m_raysPerCluster = 20;
869 table3gpp->m_uLgDS = -0.3 * log10(1 + fcGHz) - 7;
870 table3gpp->m_sigLgDS = 0.28;
871 table3gpp->m_uLgASD = -0.08 * log10(1 + fcGHz) + 1.81;
872 table3gpp->m_sigLgASD = 0.05 * log10(1 + fcGHz) + 0.3;
873 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
874 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
875 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
876 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
877 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
878 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
879 table3gpp->m_offsetZOD = 0;
880 table3gpp->m_cDS = 11;
881 table3gpp->m_cASD = 22;
882 table3gpp->m_cASA = 22;
883 table3gpp->m_cZSA = 7;
885 table3gpp->m_sigK = 0;
886 table3gpp->m_rTau = 2.1;
887 table3gpp->m_uXpr = 8;
888 table3gpp->m_sigXpr = 3;
889 table3gpp->m_perClusterShadowingStd = 4;
891 for (uint8_t row = 0; row < 6; row++)
893 for (uint8_t column = 0; column < 6; column++)
899 else if (channelCondition->IsNlosv())
901 table3gpp->m_numOfCluster = 19;
902 table3gpp->m_raysPerCluster = 20;
903 table3gpp->m_uLgDS = -0.4 * log10(1 + fcGHz) - 7;
904 table3gpp->m_sigLgDS = 0.1;
905 table3gpp->m_uLgASD = -0.1 * log10(1 + fcGHz) + 1.7;
906 table3gpp->m_sigLgASD = 0.1;
907 table3gpp->m_uLgASA = -0.1 * log10(1 + fcGHz) + 1.7;
908 table3gpp->m_sigLgASA = 0.1;
909 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
910 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
911 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
912 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
913 table3gpp->m_offsetZOD = 0;
914 table3gpp->m_cDS = 11;
915 table3gpp->m_cASD = 22;
916 table3gpp->m_cASA = 22;
917 table3gpp->m_cZSA = 7;
919 table3gpp->m_sigK = 4.5;
920 table3gpp->m_rTau = 2.1;
921 table3gpp->m_uXpr = 8;
922 table3gpp->m_sigXpr = 3;
923 table3gpp->m_perClusterShadowingStd = 4;
925 for (uint8_t row = 0; row < 6; row++)
927 for (uint8_t column = 0; column < 6; column++)
929 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
940 if (channelCondition->IsLos())
942 table3gpp->m_numOfCluster = 12;
943 table3gpp->m_raysPerCluster = 20;
944 table3gpp->m_uLgDS = -8.3;
945 table3gpp->m_sigLgDS = 0.2;
946 table3gpp->m_uLgASD = 1.4;
947 table3gpp->m_sigLgASD = 0.1;
948 table3gpp->m_uLgASA = 1.4;
949 table3gpp->m_sigLgASA = 0.1;
950 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
951 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
952 table3gpp->m_uLgZSD = -0.1 * log10(1 + fcGHz) + 0.73;
953 table3gpp->m_sigLgZSD = -0.04 * log10(1 + fcGHz) + 0.34;
954 table3gpp->m_offsetZOD = 0;
955 table3gpp->m_cDS = 5;
956 table3gpp->m_cASD = 17;
957 table3gpp->m_cASA = 17;
958 table3gpp->m_cZSA = 7;
960 table3gpp->m_sigK = 3.5;
961 table3gpp->m_rTau = 3;
962 table3gpp->m_uXpr = 9;
963 table3gpp->m_sigXpr = 3;
964 table3gpp->m_perClusterShadowingStd = 4;
966 for (uint8_t row = 0; row < 7; row++)
968 for (uint8_t column = 0; column < 7; column++)
970 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
974 else if (channelCondition->IsNlosv())
976 table3gpp->m_numOfCluster = 19;
977 table3gpp->m_raysPerCluster = 20;
978 table3gpp->m_uLgDS = -8.3;
979 table3gpp->m_sigLgDS = 0.3;
980 table3gpp->m_uLgASD = 1.5;
981 table3gpp->m_sigLgASD = 0.1;
982 table3gpp->m_uLgASA = 1.5;
983 table3gpp->m_sigLgASA = 0.1;
984 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
985 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
986 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
987 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
988 table3gpp->m_offsetZOD = 0;
989 table3gpp->m_cDS = 11;
990 table3gpp->m_cASD = 22;
991 table3gpp->m_cASA = 22;
992 table3gpp->m_cZSA = 7;
994 table3gpp->m_sigK = 4.5;
995 table3gpp->m_rTau = 2.1;
996 table3gpp->m_uXpr = 8.0;
997 table3gpp->m_sigXpr = 3;
998 table3gpp->m_perClusterShadowingStd = 4;
1000 for (uint8_t row = 0; row < 6; row++)
1002 for (uint8_t column = 0; column < 6; column++)
1004 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
1008 else if (channelCondition->IsNlos())
1011 "The fast fading parameters for the NLOS condition in the Highway scenario are not "
1012 "defined in TR 37.885, use the ones defined in TDoc R1-1803671 instead");
1014 table3gpp->m_numOfCluster = 19;
1015 table3gpp->m_raysPerCluster = 20;
1016 table3gpp->m_uLgDS = -0.3 * log10(1 + fcGHz) - 7;
1017 table3gpp->m_sigLgDS = 0.28;
1018 table3gpp->m_uLgASD = -0.08 * log10(1 + fcGHz) + 1.81;
1019 table3gpp->m_sigLgASD = 0.05 * log10(1 + fcGHz) + 0.3;
1020 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
1021 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
1022 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
1023 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
1024 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
1025 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
1026 table3gpp->m_offsetZOD = 0;
1027 table3gpp->m_cDS = 11;
1028 table3gpp->m_cASD = 22;
1029 table3gpp->m_cASA = 22;
1030 table3gpp->m_cZSA = 7;
1031 table3gpp->m_uK = 0;
1032 table3gpp->m_sigK = 0;
1033 table3gpp->m_rTau = 2.1;
1034 table3gpp->m_uXpr = 8;
1035 table3gpp->m_sigXpr = 3;
1036 table3gpp->m_perClusterShadowingStd = 4;
1038 for (uint8_t row = 0; row < 6; row++)
1040 for (uint8_t column = 0; column < 6; column++)
1065 bool update =
false;
1068 if (!channelCondition->IsEqual(channelParams->m_losCondition, channelParams->m_o2iCondition))
1090 return channelParams->m_generatedTime > channelMatrix->m_generatedTime;
1102 uint64_t channelParamsKey =
1105 uint64_t channelMatrixKey =
GetKey(aAntenna->GetId(), bAntenna->GetId());
1113 bool updateParams =
false;
1114 bool updateMatrix =
false;
1115 bool notFoundParams =
false;
1116 bool notFoundMatrix =
false;
1129 notFoundParams =
true;
1132 double x = aMob->GetPosition().x - bMob->GetPosition().x;
1133 double y = aMob->GetPosition().y - bMob->GetPosition().y;
1134 double distance2D = sqrt(x * x + y * y);
1138 double hUt = std::min(aMob->GetPosition().z, bMob->GetPosition().z);
1139 double hBs = std::max(aMob->GetPosition().z, bMob->GetPosition().z);
1144 if (notFoundParams || updateParams)
1169 notFoundMatrix =
true;
1174 if (notFoundMatrix || updateMatrix)
1177 channelMatrix =
GetNewChannel(channelParams, table3gpp, aMob, bMob, aAntenna, bAntenna);
1178 channelMatrix->m_antennaPair =
1179 std::make_pair(aAntenna->GetId(),
1187 return channelMatrix;
1196 uint64_t channelParamsKey =
1205 NS_LOG_WARN(
"Channel params map not found. Returning a nullptr.");
1220 channelParams->m_nodeIds =
1222 channelParams->m_losCondition = channelCondition->GetLosCondition();
1223 channelParams->m_o2iCondition = channelCondition->GetO2iCondition();
1228 uint8_t paramNum = 6;
1235 for (uint8_t iter = 0; iter < paramNum; iter++)
1239 for (uint8_t row = 0; row < paramNum; row++)
1242 for (uint8_t column = 0; column < paramNum; column++)
1244 temp += table3gpp->m_sqrtC[row][column] * LSPsIndep[column];
1246 LSPs.push_back(temp);
1258 kFactor = LSPs[1] * table3gpp->m_sigK + table3gpp->m_uK;
1259 DS = pow(10, LSPs[2] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1260 ASD = pow(10, LSPs[3] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1261 ASA = pow(10, LSPs[4] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1262 ZSD = pow(10, LSPs[5] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1263 ZSA = pow(10, LSPs[6] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1267 DS = pow(10, LSPs[1] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1268 ASD = pow(10, LSPs[2] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1269 ASA = pow(10, LSPs[3] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1270 ZSD = pow(10, LSPs[4] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1271 ZSA = pow(10, LSPs[5] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1273 ASD = std::min(ASD, 104.0);
1274 ASA = std::min(ASA, 104.0);
1275 ZSD = std::min(ZSD, 52.0);
1276 ZSA = std::min(ZSA, 52.0);
1279 channelParams->m_DS = DS;
1280 channelParams->m_K_factor = kFactor;
1282 NS_LOG_INFO(
"K-factor=" << kFactor <<
", DS=" << DS <<
", ASD=" << ASD <<
", ASA=" << ASA
1283 <<
", ZSD=" << ZSD <<
", ZSA=" << ZSA);
1287 double minTau = 100.0;
1288 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1295 clusterDelay.push_back(tau);
1298 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1300 clusterDelay[cIndex] -= minTau;
1302 std::sort(clusterDelay.begin(), clusterDelay.end());
1309 double powerSum = 0;
1310 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1313 exp(-1 * clusterDelay[cIndex] * (table3gpp->m_rTau - 1) / table3gpp->m_rTau / DS) *
1315 -1 *
m_normalRv->GetValue() * table3gpp->m_perClusterShadowingStd / 10.0);
1317 clusterPower.push_back(power);
1319 channelParams->m_clusterPower = clusterPower;
1321 double powerMax = 0;
1323 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1325 channelParams->m_clusterPower[cIndex] =
1326 channelParams->m_clusterPower[cIndex] / powerSum;
1333 double kLinear = pow(10, kFactor / 10.0);
1335 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1339 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1341 kLinear / (1 + kLinear));
1345 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1348 if (powerMax < clusterPowerForAngles[cIndex])
1350 powerMax = clusterPowerForAngles[cIndex];
1356 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1358 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex]);
1359 if (powerMax < clusterPowerForAngles[cIndex])
1361 powerMax = clusterPowerForAngles[cIndex];
1368 double thresh = 0.0032;
1369 for (uint8_t cIndex = table3gpp->m_numOfCluster; cIndex > 0; cIndex--)
1371 if (clusterPowerForAngles[cIndex - 1] < thresh * powerMax)
1373 clusterPowerForAngles.erase(clusterPowerForAngles.begin() + cIndex - 1);
1374 channelParams->m_clusterPower.erase(channelParams->m_clusterPower.begin() + cIndex - 1);
1375 clusterDelay.erase(clusterDelay.begin() + cIndex - 1);
1379 NS_ASSERT(channelParams->m_clusterPower.size() < UINT8_MAX);
1380 channelParams->m_reducedClusterNumber = channelParams->m_clusterPower.size();
1385 0.7705 - 0.0433 * kFactor + 2e-4 * pow(kFactor, 2) + 17e-6 * pow(kFactor, 3);
1386 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1388 clusterDelay[cIndex] = clusterDelay[cIndex] / cTau;
1397 switch (table3gpp->m_numOfCluster)
1436 double cPhi = cNlos;
1440 cPhi *= (1.1035 - 0.028 * kFactor - 2e-3 * pow(kFactor, 2) +
1441 1e-4 * pow(kFactor, 3));
1444 switch (table3gpp->m_numOfCluster)
1471 double cTheta = cNlos;
1472 if (channelCondition->IsLos())
1474 cTheta *= (1.3086 + 0.0339 * kFactor - 0.0077 * pow(kFactor, 2) +
1475 2e-4 * pow(kFactor, 3));
1482 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1484 double logCalc = -1 * log(clusterPowerForAngles[cIndex] / powerMax);
1485 double angle = 2 * sqrt(logCalc) / 1.4 / cPhi;
1486 clusterAoa.push_back(ASA * angle);
1487 clusterAod.push_back(ASD * angle);
1488 angle = logCalc / cTheta;
1489 clusterZoa.push_back(ZSA * angle);
1490 clusterZod.push_back(ZSD * angle);
1493 Angles sAngle(bMob->GetPosition(), aMob->GetPosition());
1494 Angles uAngle(aMob->GetPosition(), bMob->GetPosition());
1496 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1503 clusterAoa[cIndex] = clusterAoa[cIndex] * Xn + (
m_normalRv->GetValue() * ASA / 7.0) +
1505 clusterAod[cIndex] = clusterAod[cIndex] * Xn + (
m_normalRv->GetValue() * ASD / 7.0) +
1507 if (channelCondition->IsO2i())
1509 clusterZoa[cIndex] =
1510 clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7.0) + 90;
1514 clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7.0) +
1517 clusterZod[cIndex] = clusterZod[cIndex] * Xn + (
m_normalRv->GetValue() * ZSD / 7.0) +
1519 table3gpp->m_offsetZOD;
1531 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1533 clusterAoa[cIndex] -= diffAoa;
1534 clusterAod[cIndex] -= diffAod;
1535 clusterZoa[cIndex] -= diffZsa;
1536 clusterZod[cIndex] -= diffZsd;
1540 double sizeTemp = clusterZoa.size();
1541 for (uint8_t ind = 0; ind < 4; ind++)
1547 angleDegree = clusterAoa;
1550 angleDegree = clusterZoa;
1553 angleDegree = clusterAod;
1556 angleDegree = clusterZod;
1561 for (uint8_t nIndex = 0; nIndex < sizeTemp; nIndex++)
1563 while (angleDegree[nIndex] > 360)
1565 angleDegree[nIndex] -= 360;
1568 while (angleDegree[nIndex] < 0)
1570 angleDegree[nIndex] += 360;
1573 if (ind == 1 || ind == 3)
1575 if (angleDegree[nIndex] > 180)
1577 angleDegree[nIndex] = 360 - angleDegree[nIndex];
1584 clusterAoa = angleDegree;
1587 clusterZoa = angleDegree;
1590 clusterAod = angleDegree;
1593 clusterZod = angleDegree;
1604 for (uint8_t cInd = 0; cInd < channelParams->m_reducedClusterNumber; cInd++)
1606 channelParams->m_clusterPower[cInd] =
1607 channelParams->m_clusterPower[cInd] / pow(10, attenuationDb[cInd] / 10.0);
1612 attenuationDb.push_back(0);
1616 channelParams->m_attenuation_dB = attenuationDb;
1621 channelParams->m_reducedClusterNumber,
1625 channelParams->m_reducedClusterNumber,
1629 channelParams->m_reducedClusterNumber,
1633 channelParams->m_reducedClusterNumber,
1637 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1639 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1641 double tempAoa = clusterAoa[nInd] + table3gpp->m_cASA *
offSetAlpha[mInd];
1642 double tempZoa = clusterZoa[nInd] + table3gpp->m_cZSA *
offSetAlpha[mInd];
1643 std::tie(rayAoaRadian[nInd][mInd], rayZoaRadian[nInd][mInd]) =
1646 double tempAod = clusterAod[nInd] + table3gpp->m_cASD *
offSetAlpha[mInd];
1647 double tempZod = clusterZod[nInd] +
1648 0.375 * pow(10, table3gpp->m_uLgZSD) *
offSetAlpha[mInd];
1649 std::tie(rayAodRadian[nInd][mInd], rayZodRadian[nInd][mInd]) =
1654 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1656 Shuffle(&rayAodRadian[cIndex][0], &rayAodRadian[cIndex][table3gpp->m_raysPerCluster]);
1657 Shuffle(&rayAoaRadian[cIndex][0], &rayAoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1658 Shuffle(&rayZodRadian[cIndex][0], &rayZodRadian[cIndex][table3gpp->m_raysPerCluster]);
1659 Shuffle(&rayZoaRadian[cIndex][0], &rayZoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1663 channelParams->m_rayAodRadian = rayAodRadian;
1664 channelParams->m_rayAoaRadian = rayAoaRadian;
1665 channelParams->m_rayZodRadian = rayZodRadian;
1666 channelParams->m_rayZoaRadian = rayZoaRadian;
1673 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1678 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1680 double uXprLinear = pow(10, table3gpp->m_uXpr / 10.0);
1681 double sigXprLinear = pow(10, table3gpp->m_sigXpr / 10.0);
1684 std::pow(10, (
m_normalRv->GetValue() * sigXprLinear + uXprLinear) / 10.0));
1686 for (uint8_t pInd = 0; pInd < 4; pInd++)
1690 temp2.push_back(temp3);
1692 crossPolarizationPowerRatios.push_back(temp);
1693 clusterPhase.push_back(temp2);
1696 channelParams->m_clusterPhase = clusterPhase;
1697 channelParams->m_crossPolarizationPowerRatios = crossPolarizationPowerRatios;
1699 uint8_t cluster1st = 0;
1700 uint8_t cluster2nd = 0;
1701 double maxPower = 0;
1702 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1704 if (maxPower < channelParams->m_clusterPower[cIndex])
1706 maxPower = channelParams->m_clusterPower[cIndex];
1707 cluster1st = cIndex;
1710 channelParams->m_cluster1st = cluster1st;
1712 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1714 if (maxPower < channelParams->m_clusterPower[cIndex] && cluster1st != cIndex)
1716 maxPower = channelParams->m_clusterPower[cIndex];
1717 cluster2nd = cIndex;
1720 channelParams->m_cluster2nd = cluster2nd;
1722 NS_LOG_INFO(
"1st strongest cluster:" << +cluster1st
1723 <<
", 2nd strongest cluster:" << +cluster2nd);
1726 if (cluster1st == cluster2nd)
1728 clusterDelay.push_back(clusterDelay[cluster1st] + 1.28 * table3gpp->m_cDS);
1729 clusterDelay.push_back(clusterDelay[cluster1st] + 2.56 * table3gpp->m_cDS);
1731 clusterAoa.push_back(clusterAoa[cluster1st]);
1732 clusterAoa.push_back(clusterAoa[cluster1st]);
1734 clusterZoa.push_back(clusterZoa[cluster1st]);
1735 clusterZoa.push_back(clusterZoa[cluster1st]);
1737 clusterAod.push_back(clusterAod[cluster1st]);
1738 clusterAod.push_back(clusterAod[cluster1st]);
1740 clusterZod.push_back(clusterZod[cluster1st]);
1741 clusterZod.push_back(clusterZod[cluster1st]);
1747 if (cluster1st < cluster2nd)
1757 clusterDelay.push_back(clusterDelay[min] + 1.28 * table3gpp->m_cDS);
1758 clusterDelay.push_back(clusterDelay[min] + 2.56 * table3gpp->m_cDS);
1759 clusterDelay.push_back(clusterDelay[max] + 1.28 * table3gpp->m_cDS);
1760 clusterDelay.push_back(clusterDelay[max] + 2.56 * table3gpp->m_cDS);
1762 clusterAoa.push_back(clusterAoa[min]);
1763 clusterAoa.push_back(clusterAoa[min]);
1764 clusterAoa.push_back(clusterAoa[max]);
1765 clusterAoa.push_back(clusterAoa[max]);
1767 clusterZoa.push_back(clusterZoa[min]);
1768 clusterZoa.push_back(clusterZoa[min]);
1769 clusterZoa.push_back(clusterZoa[max]);
1770 clusterZoa.push_back(clusterZoa[max]);
1772 clusterAod.push_back(clusterAod[min]);
1773 clusterAod.push_back(clusterAod[min]);
1774 clusterAod.push_back(clusterAod[max]);
1775 clusterAod.push_back(clusterAod[max]);
1777 clusterZod.push_back(clusterZod[min]);
1778 clusterZod.push_back(clusterZod[min]);
1779 clusterZod.push_back(clusterZod[max]);
1780 clusterZod.push_back(clusterZod[max]);
1783 channelParams->m_delay = clusterDelay;
1784 channelParams->m_angle.clear();
1785 channelParams->m_angle.push_back(clusterAoa);
1786 channelParams->m_angle.push_back(clusterZoa);
1787 channelParams->m_angle.push_back(clusterAod);
1788 channelParams->m_angle.push_back(clusterZod);
1791 channelParams->m_cachedAngleSincos.resize(channelParams->m_angle.size());
1792 for (
size_t direction = 0; direction < channelParams->m_angle.size(); direction++)
1794 channelParams->m_cachedAngleSincos[direction].resize(
1795 channelParams->m_angle[direction].size());
1796 for (
size_t cluster = 0; cluster < channelParams->m_angle[direction].size(); cluster++)
1798 channelParams->m_cachedAngleSincos[direction][cluster] = {
1799 sin(channelParams->m_angle[direction][cluster] *
DEG2RAD),
1800 cos(channelParams->m_angle[direction][cluster] *
DEG2RAD)};
1820 uint8_t updatedClusterNumber = (channelParams->m_reducedClusterNumber == 1)
1821 ? channelParams->m_reducedClusterNumber + 2
1822 : channelParams->m_reducedClusterNumber + 4;
1824 for (uint8_t cIndex = 0; cIndex < updatedClusterNumber; cIndex++)
1833 dopplerTermAlpha.push_back(alpha);
1834 dopplerTermD.push_back(D);
1836 channelParams->m_alpha = dopplerTermAlpha;
1837 channelParams->m_D = dopplerTermD;
1839 return channelParams;
1858 channelMatrix->m_nodeIds =
1861 bool isSameDirection = (channelParams->m_nodeIds == channelMatrix->m_nodeIds);
1872 if (isSameDirection)
1874 rayAodRadian = channelParams->m_rayAodRadian;
1875 rayAoaRadian = channelParams->m_rayAoaRadian;
1876 rayZodRadian = channelParams->m_rayZodRadian;
1877 rayZoaRadian = channelParams->m_rayZoaRadian;
1881 rayAodRadian = channelParams->m_rayAoaRadian;
1882 rayAoaRadian = channelParams->m_rayAodRadian;
1883 rayZodRadian = channelParams->m_rayZoaRadian;
1884 rayZoaRadian = channelParams->m_rayZodRadian;
1890 size_t uSize = uAntenna->GetNumElems();
1891 size_t sSize = sAntenna->GetNumElems();
1897 uint16_t numOverallCluster = (channelParams->m_cluster1st != channelParams->m_cluster2nd)
1898 ? channelParams->m_reducedClusterNumber + 4
1899 : channelParams->m_reducedClusterNumber + 2;
1901 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPhase.size());
1902 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPower.size());
1903 NS_ASSERT(channelParams->m_reducedClusterNumber <=
1904 channelParams->m_crossPolarizationPowerRatios.size());
1905 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZoaRadian.size());
1906 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZodRadian.size());
1907 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAoaRadian.size());
1908 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAodRadian.size());
1909 NS_ASSERT(table3gpp->m_raysPerCluster <= channelParams->m_clusterPhase[0].size());
1910 NS_ASSERT(table3gpp->m_raysPerCluster <=
1911 channelParams->m_crossPolarizationPowerRatios[0].size());
1912 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZoaRadian[0].size());
1913 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZodRadian[0].size());
1914 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAoaRadian[0].size());
1915 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAodRadian[0].size());
1917 double x = sMob->GetPosition().x - uMob->GetPosition().x;
1918 double y = sMob->GetPosition().y - uMob->GetPosition().y;
1919 double distance2D = sqrt(x * x + y * y);
1922 double hUt = std::min(sMob->GetPosition().z, uMob->GetPosition().z);
1923 double hBs = std::max(sMob->GetPosition().z, uMob->GetPosition().z);
1925 double distance3D = std::sqrt(distance2D * distance2D + (hBs - hUt) * (hBs - hUt));
1927 Angles sAngle(uMob->GetPosition(), sMob->GetPosition());
1928 Angles uAngle(sMob->GetPosition(), uMob->GetPosition());
1940 for (
size_t polSa = 0; polSa < sAntenna->GetNumPols(); ++polSa)
1942 for (
size_t polUa = 0; polUa < uAntenna->GetNumPols(); ++polUa)
1944 raysPreComp[std::make_pair(polSa, polUa)] =
1945 Complex2DVector(channelParams->m_reducedClusterNumber, table3gpp->m_raysPerCluster);
1950 sinCosA.resize(channelParams->m_reducedClusterNumber);
1951 sinSinA.resize(channelParams->m_reducedClusterNumber);
1952 cosZoA.resize(channelParams->m_reducedClusterNumber);
1953 sinCosD.resize(channelParams->m_reducedClusterNumber);
1954 sinSinD.resize(channelParams->m_reducedClusterNumber);
1955 cosZoD.resize(channelParams->m_reducedClusterNumber);
1956 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1958 sinCosA[nIndex].resize(table3gpp->m_raysPerCluster);
1959 sinSinA[nIndex].resize(table3gpp->m_raysPerCluster);
1960 cosZoA[nIndex].resize(table3gpp->m_raysPerCluster);
1961 sinCosD[nIndex].resize(table3gpp->m_raysPerCluster);
1962 sinSinD[nIndex].resize(table3gpp->m_raysPerCluster);
1963 cosZoD[nIndex].resize(table3gpp->m_raysPerCluster);
1966 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1968 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
1970 DoubleVector initialPhase = channelParams->m_clusterPhase[nIndex][mIndex];
1972 double k = channelParams->m_crossPolarizationPowerRatios[nIndex][mIndex];
1976 for (uint8_t polUa = 0; polUa < uAntenna->GetNumPols(); ++polUa)
1978 auto [rxFieldPatternPhi, rxFieldPatternTheta] = uAntenna->GetElementFieldPattern(
1979 Angles(channelParams->m_rayAoaRadian[nIndex][mIndex],
1980 channelParams->m_rayZoaRadian[nIndex][mIndex]),
1982 for (uint8_t polSa = 0; polSa < sAntenna->GetNumPols(); ++polSa)
1984 auto [txFieldPatternPhi, txFieldPatternTheta] =
1985 sAntenna->GetElementFieldPattern(
1986 Angles(channelParams->m_rayAodRadian[nIndex][mIndex],
1987 channelParams->m_rayZodRadian[nIndex][mIndex]),
1989 raysPreComp[std::make_pair(polSa, polUa)](nIndex, mIndex) =
1990 std::complex<double>(cos(initialPhase[0]), sin(initialPhase[0])) *
1991 rxFieldPatternTheta * txFieldPatternTheta +
1992 std::complex<double>(cos(initialPhase[1]), sin(initialPhase[1])) *
1993 std::sqrt(1.0 / k) * rxFieldPatternTheta * txFieldPatternPhi +
1994 std::complex<double>(cos(initialPhase[2]), sin(initialPhase[2])) *
1995 std::sqrt(1.0 / k) * rxFieldPatternPhi * txFieldPatternTheta +
1996 std::complex<double>(cos(initialPhase[3]), sin(initialPhase[3])) *
1997 rxFieldPatternPhi * txFieldPatternPhi;
2003 double sinRayZoa = sin(rayZoaRadian[nIndex][mIndex]);
2004 double sinRayAoa = sin(rayAoaRadian[nIndex][mIndex]);
2005 double cosRayAoa = cos(rayAoaRadian[nIndex][mIndex]);
2006 sinCosA[nIndex][mIndex] = sinRayZoa * cosRayAoa;
2007 sinSinA[nIndex][mIndex] = sinRayZoa * sinRayAoa;
2008 cosZoA[nIndex][mIndex] = cos(rayZoaRadian[nIndex][mIndex]);
2012 double sinRayZod = sin(rayZodRadian[nIndex][mIndex]);
2013 double sinRayAod = sin(rayAodRadian[nIndex][mIndex]);
2014 double cosRayAod = cos(rayAodRadian[nIndex][mIndex]);
2015 sinCosD[nIndex][mIndex] = sinRayZod * cosRayAod;
2016 sinSinD[nIndex][mIndex] = sinRayZod * sinRayAod;
2017 cosZoD[nIndex][mIndex] = cos(rayZodRadian[nIndex][mIndex]);
2023 uint8_t numSubClustersAdded = 0;
2024 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
2026 for (
size_t uIndex = 0; uIndex < uSize; uIndex++)
2028 Vector uLoc = uAntenna->GetElementLocation(uIndex);
2030 for (
size_t sIndex = 0; sIndex < sSize; sIndex++)
2032 Vector sLoc = sAntenna->GetElementLocation(sIndex);
2035 if (nIndex != channelParams->m_cluster1st && nIndex != channelParams->m_cluster2nd)
2037 std::complex<double> rays(0, 0);
2038 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
2041 double rxPhaseDiff =
2043 (sinCosA[nIndex][mIndex] * uLoc.x + sinSinA[nIndex][mIndex] * uLoc.y +
2044 cosZoA[nIndex][mIndex] * uLoc.z);
2046 double txPhaseDiff =
2048 (sinCosD[nIndex][mIndex] * sLoc.x + sinSinD[nIndex][mIndex] * sLoc.y +
2049 cosZoD[nIndex][mIndex] * sLoc.z);
2052 rays += raysPreComp[std::make_pair(sAntenna->GetElemPol(sIndex),
2053 uAntenna->GetElemPol(uIndex))](nIndex,
2055 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2056 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2059 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2060 hUsn(uIndex, sIndex, nIndex) = rays;
2064 std::complex<double> raysSub1(0, 0);
2065 std::complex<double> raysSub2(0, 0);
2066 std::complex<double> raysSub3(0, 0);
2068 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
2072 double rxPhaseDiff =
2074 (sinCosA[nIndex][mIndex] * uLoc.x + sinSinA[nIndex][mIndex] * uLoc.y +
2075 cosZoA[nIndex][mIndex] * uLoc.z);
2077 double txPhaseDiff =
2079 (sinCosD[nIndex][mIndex] * sLoc.x + sinSinD[nIndex][mIndex] * sLoc.y +
2080 cosZoD[nIndex][mIndex] * sLoc.z);
2082 std::complex<double> raySub =
2083 raysPreComp[std::make_pair(sAntenna->GetElemPol(sIndex),
2084 uAntenna->GetElemPol(uIndex))](nIndex,
2086 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2087 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2111 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2113 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2115 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2116 hUsn(uIndex, sIndex, nIndex) = raysSub1;
2119 channelParams->m_reducedClusterNumber + numSubClustersAdded) = raysSub2;
2122 channelParams->m_reducedClusterNumber + numSubClustersAdded + 1) =
2127 if (nIndex == channelParams->m_cluster1st || nIndex == channelParams->m_cluster2nd)
2129 numSubClustersAdded += 2;
2136 std::complex<double> phaseDiffDueToDistance(cos(-2 * M_PI * distance3D / lambda),
2137 sin(-2 * M_PI * distance3D / lambda));
2141 const double sinUAngleAz = sin(uAngle.
GetAzimuth());
2142 const double cosUAngleAz = cos(uAngle.
GetAzimuth());
2145 const double sinSAngleAz = sin(sAngle.
GetAzimuth());
2146 const double cosSAngleAz = cos(sAngle.
GetAzimuth());
2148 for (
size_t uIndex = 0; uIndex < uSize; uIndex++)
2150 Vector uLoc = uAntenna->GetElementLocation(uIndex);
2151 double rxPhaseDiff = 2 * M_PI *
2152 (sinUAngleIncl * cosUAngleAz * uLoc.x +
2153 sinUAngleIncl * sinUAngleAz * uLoc.y + cosUAngleIncl * uLoc.z);
2155 for (
size_t sIndex = 0; sIndex < sSize; sIndex++)
2157 Vector sLoc = sAntenna->GetElementLocation(sIndex);
2158 std::complex<double> ray(0, 0);
2159 double txPhaseDiff =
2161 (sinSAngleIncl * cosSAngleAz * sLoc.x + sinSAngleIncl * sinSAngleAz * sLoc.y +
2162 cosSAngleIncl * sLoc.z);
2164 auto [rxFieldPatternPhi, rxFieldPatternTheta] = uAntenna->GetElementFieldPattern(
2166 uAntenna->GetElemPol(uIndex));
2167 auto [txFieldPatternPhi, txFieldPatternTheta] = sAntenna->GetElementFieldPattern(
2169 sAntenna->GetElemPol(sIndex));
2171 ray = (rxFieldPatternTheta * txFieldPatternTheta -
2172 rxFieldPatternPhi * txFieldPatternPhi) *
2173 phaseDiffDueToDistance *
2174 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2175 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2177 double kLinear = pow(10, channelParams->m_K_factor / 10.0);
2179 hUsn(uIndex, sIndex, 0) =
2180 sqrt(1.0 / (kLinear + 1)) * hUsn(uIndex, sIndex, 0) +
2181 sqrt(kLinear / (1 + kLinear)) * ray /
2183 channelParams->m_attenuation_dB[0] / 10.0);
2184 for (
size_t nIndex = 1; nIndex < hUsn.GetNumPages(); nIndex++)
2186 hUsn(uIndex, sIndex, nIndex) *=
2187 sqrt(1.0 / (kLinear + 1));
2193 NS_LOG_DEBUG(
"Husn (sAntenna, uAntenna):" << sAntenna->GetId() <<
", " << uAntenna->GetId());
2194 for (
size_t cIndex = 0; cIndex < hUsn.GetNumPages(); cIndex++)
2196 for (
size_t rowIdx = 0; rowIdx < hUsn.GetNumRows(); rowIdx++)
2198 for (
size_t colIdx = 0; colIdx < hUsn.GetNumCols(); colIdx++)
2200 NS_LOG_DEBUG(
" " << hUsn(rowIdx, colIdx, cIndex) <<
",");
2205 NS_LOG_INFO(
"size of coefficient matrix (rows, columns, clusters) = ("
2206 << hUsn.GetNumRows() <<
", " << hUsn.GetNumCols() <<
", " << hUsn.GetNumPages()
2208 channelMatrix->m_channel = hUsn;
2209 return channelMatrix;
2212std::pair<double, double>
2215 inclinationRad =
WrapTo2Pi(inclinationRad);
2216 if (inclinationRad > M_PI)
2219 inclinationRad -= M_PI;
2225 NS_ASSERT_MSG(0 <= inclinationRad && inclinationRad <= M_PI,
2226 "inclinationRad=" << inclinationRad <<
" not valid, should be in [0, pi]");
2228 "azimuthRad=" << azimuthRad <<
" not valid, should be in [0, 2*pi]");
2230 return std::make_pair(azimuthRad, inclinationRad);
2241 auto clusterNum = clusterAOA.size();
2254 double thetaSb = 110;
2265 if (channelParams->m_nonSelfBlocking.empty())
2276 table.push_back(90);
2283 table.push_back(90);
2285 table.push_back(10);
2287 channelParams->m_nonSelfBlocking.push_back(table);
2292 double deltaX = sqrt(pow(channelParams->m_preLocUT.x - channelParams->m_locUT.x, 2) +
2293 pow(channelParams->m_preLocUT.y - channelParams->m_locUT.y, 2));
2320 R = exp(-1 * (deltaX / corrDis +
2321 (
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()) /
2326 R = exp(-1 * (deltaX / corrDis));
2331 <<
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()
2332 <<
" correlation:" << R);
2342 if (R * R * (-0.069) + R * 1.074 - 0.002 <
2345 R = R * R * (-0.069) + R * 1.074 - 0.002;
2350 channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] =
2351 R * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] +
2358 for (std::size_t cInd = 0; cInd < clusterNum; cInd++)
2360 NS_ASSERT_MSG(clusterAOA[cInd] >= 0 && clusterAOA[cInd] <= 360,
2361 "the AOA should be the range of [0,360]");
2362 NS_ASSERT_MSG(clusterZOA[cInd] >= 0 && clusterZOA[cInd] <= 180,
2363 "the ZOA should be the range of [0,180]");
2366 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiSb - xSb / 2.0 <<
","
2367 << phiSb + xSb / 2.0 <<
"]");
2368 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaSb - ySb / 2.0 <<
","
2369 << thetaSb + ySb / 2.0 <<
"]");
2370 if (std::abs(clusterAOA[cInd] - phiSb) < (xSb / 2.0) &&
2371 std::abs(clusterZOA[cInd] - thetaSb) < (ySb / 2.0))
2373 powerAttenuation[cInd] += 30;
2375 <<
"] is blocked by self blocking region and reduce 30 dB power,"
2376 "the attenuation is ["
2377 << powerAttenuation[cInd] <<
" dB]");
2385 (0.5 * erfc(-1 * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] / sqrt(2))) *
2397 double xK = channelParams->m_nonSelfBlocking[blockInd][
X_INDEX];
2398 double thetaK = channelParams->m_nonSelfBlocking[blockInd][
THETA_INDEX];
2399 double yK = channelParams->m_nonSelfBlocking[blockInd][
Y_INDEX];
2401 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiK - xK <<
","
2402 << phiK + xK <<
"]");
2403 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaK - yK <<
","
2404 << thetaK + yK <<
"]");
2406 if (std::abs(clusterAOA[cInd] - phiK) < (xK) &&
2407 std::abs(clusterZOA[cInd] - thetaK) < (yK))
2409 double A1 = clusterAOA[cInd] - (phiK + xK / 2.0);
2410 double A2 = clusterAOA[cInd] - (phiK - xK / 2.0);
2411 double Z1 = clusterZOA[cInd] - (thetaK + yK / 2.0);
2412 double Z2 = clusterZOA[cInd] - (thetaK - yK / 2.0);
2419 if (xK / 2.0 < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= xK)
2427 if (-1 * xK < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= -1 * xK / 2.0)
2436 if (yK / 2.0 < clusterZOA[cInd] - thetaK && clusterZOA[cInd] - thetaK <= yK)
2444 if (-1 * yK < clusterZOA[cInd] - thetaK &&
2445 clusterZOA[cInd] - thetaK <= -1 * yK / 2.0)
2455 atan(signA1 * M_PI / 2.0 *
2456 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2460 atan(signA2 * M_PI / 2.0 *
2461 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2465 atan(signZ1 * M_PI / 2.0 *
2466 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2470 atan(signZ2 * M_PI / 2.0 *
2471 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2474 double lDb = -20 * log10(1 - (fA1 + fA2) * (fZ1 + fZ2));
2475 powerAttenuation[cInd] += lDb;
2476 NS_LOG_INFO(
"Cluster[" << +cInd <<
"] is blocked by no-self blocking, the loss is ["
2481 return powerAttenuation;
2487 for (
auto i = (last -
first) - 1; i > 0; --i)
Class holding the azimuth and inclination angles of spherical coordinates.
double GetInclination() const
Getter for inclination angle.
double GetAzimuth() const
Getter for azimuth angle.
AttributeValue implementation for Boolean.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Hold a signed integer type.
This is an interface for a channel model that can be described by a channel matrix,...
std::vector< double > DoubleVector
Type definition for vectors of doubles.
ComplexMatrixArray Complex2DVector
Create an alias for 2D complex vectors.
std::vector< Double2DVector > Double3DVector
Type definition for 3D matrices of doubles.
std::vector< DoubleVector > Double2DVector
Type definition for matrices of doubles.
static uint64_t GetKey(uint32_t a, uint32_t b)
Generate a unique value for the pair of unsigned integer of 32 bits, where the order does not matter,...
AttributeValue implementation for Pointer.
Smart pointer class similar to boost::intrusive_ptr.
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static Time Now()
Return the current simulation virtual time.
Hold variables of type string.
DoubleVector CalcAttenuationOfBlockage(const Ptr< ThreeGppChannelModel::ThreeGppChannelParams > channelParams, const DoubleVector &clusterAOA, const DoubleVector &clusterZOA) const
Applies the blockage model A described in 3GPP TR 38.901.
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
bool m_portraitMode
true if portrait mode, false if landscape
bool ChannelParamsNeedsUpdate(Ptr< const ThreeGppChannelParams > channelParams, Ptr< const ChannelCondition > channelCondition) const
Check if the channel params has to be updated.
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.
Ptr< NormalRandomVariable > m_normalRv
normal random variable
static const uint8_t Y_INDEX
index of the Y value in the m_nonSelfBlocking array
bool m_blockage
enables the blockage model A
Ptr< const ChannelParams > GetParams(Ptr< const MobilityModel > aMob, Ptr< const MobilityModel > bMob) const override
Looks for the channel params associated to the aMob and bMob pair in m_channelParamsMap.
~ThreeGppChannelModel() override
Destructor.
bool ChannelMatrixNeedsUpdate(Ptr< const ThreeGppChannelParams > channelParams, Ptr< const ChannelMatrix > channelMatrix)
Check if the channel matrix has to be updated (it needs update when the channel params generation tim...
static const uint8_t THETA_INDEX
index of the THETA value in the m_nonSelfBlocking array
std::unordered_map< uint64_t, Ptr< ThreeGppChannelParams > > m_channelParamsMap
map containing the common channel parameters per pair of nodes, the key of this map is reciprocal and...
static std::pair< double, double > WrapAngles(double azimuthRad, double inclinationRad)
Wrap an (azimuth, inclination) angle pair in a valid range.
ThreeGppChannelModel()
Constructor.
double m_blockerSpeed
the blocker speed
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_channelMatrixMap.
void SetFrequency(double f)
Sets the center frequency of the model.
std::unordered_map< uint64_t, Ptr< ChannelMatrix > > m_channelMatrixMap
map containing the channel realizations per pair of PhasedAntennaArray instances, the key of this map...
Ptr< UniformRandomVariable > m_uniformRv
uniform random variable
void DoDispose() override
Destructor implementation.
void SetScenario(const std::string &scenario)
Sets the propagation scenario.
void SetChannelConditionModel(Ptr< ChannelConditionModel > model)
Set the channel condition model.
Ptr< UniformRandomVariable > m_uniformRvDoppler
uniform random variable, used to compute the additional Doppler contribution
uint16_t m_numNonSelfBlocking
number of non-self-blocking regions
std::string GetScenario() const
Returns the propagation scenario.
virtual Ptr< ChannelMatrix > GetNewChannel(Ptr< const ThreeGppChannelParams > channelParams, Ptr< const ParamsTable > table3gpp, const Ptr< const MobilityModel > sMob, const Ptr< const MobilityModel > uMob, Ptr< const PhasedArrayModel > sAntenna, Ptr< const PhasedArrayModel > uAntenna) const
Compute the channel matrix between two nodes a and b, and their antenna arrays aAntenna and bAntenna ...
static const uint8_t PHI_INDEX
index of the PHI value in the m_nonSelfBlocking array
double m_frequency
the operating frequency
double m_vScatt
value used to compute the additional Doppler contribution for the delayed paths
Ptr< ChannelConditionModel > GetChannelConditionModel() const
Get the associated channel condition model.
Ptr< ChannelConditionModel > m_channelConditionModel
the channel condition model
std::string m_scenario
the 3GPP scenario
static const uint8_t R_INDEX
index of the R value in the m_nonSelfBlocking array
static TypeId GetTypeId()
Get the type ID.
void Shuffle(double *first, double *last) const
Shuffle the elements of a simple sequence container of type double.
Ptr< ThreeGppChannelParams > GenerateChannelParameters(const Ptr< const ChannelCondition > channelCondition, const Ptr< const ParamsTable > table3gpp, const Ptr< const MobilityModel > aMob, const Ptr< const MobilityModel > bMob) const
Prepare 3gpp channel parameters among the nodes a and b.
double GetFrequency() const
Returns the center frequency.
Time m_updatePeriod
the channel update period
static const uint8_t X_INDEX
index of the X value in the m_nonSelfBlocking array
Ptr< UniformRandomVariable > m_uniformRvShuffle
uniform random variable used to shuffle array in GetNewChannel
bool IsZero() const
Exactly equivalent to t == 0.
AttributeValue implementation for Time.
a unique identifier for an interface.
TypeId SetGroupName(std::string groupName)
Set the group name.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Ptr< const AttributeChecker > MakeStringChecker()
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Time Now()
create an ns3::Time instance which contains the current simulation time.
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static constexpr double DEG2RAD
Conversion factor: degrees to radians.
static const double offSetAlpha[20]
The ray offset angles within a cluster, given for rms angle spread normalized to 1.
static const double sqrtC_RMa_O2I[6][6]
The square root matrix for RMa O2I, which is generated using the Cholesky decomposition according to ...
static const double sqrtC_UMi_LOS[7][7]
The square root matrix for UMi LOS, which is generated using the Cholesky decomposition according to ...
static const double sqrtC_office_LOS[7][7]
The square root matrix for Indoor-Office LOS, which is generated using the Cholesky decomposition acc...
static const double sqrtC_UMa_O2I[6][6]
The square root matrix for UMa O2I, which is generated using the Cholesky decomposition according to ...
static const double sqrtC_RMa_NLOS[6][6]
The square root matrix for RMa NLOS, which is generated using the Cholesky decomposition according to...
static const double sqrtC_UMa_LOS[7][7]
The square root matrix for UMa LOS, which is generated using the Cholesky decomposition according to ...
static const double sqrtC_UMi_NLOS[6][6]
The square root matrix for UMi NLOS, which is generated using the Cholesky decomposition according to...
static const double sqrtC_RMa_LOS[7][7]
The square root matrix for RMa LOS, which is generated using the Cholesky decomposition according to ...
double DegreesToRadians(double degrees)
converts degrees to radians
static const double sqrtC_UMi_O2I[6][6]
The square root matrix for UMi O2I, which is generated using the Cholesky decomposition according to ...
static const double sqrtC_office_NLOS[6][6]
The square root matrix for Indoor-Office NLOS, which is generated using the Cholesky decomposition ac...
static const double sqrtC_UMa_NLOS[6][6]
The square root matrix for UMa NLOS, which is generated using the Cholesky decomposition according to...
double WrapTo2Pi(double a)
Wrap angle in [0, 2*M_PI)
double RadiansToDegrees(double radians)
converts radians to degrees