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;
1100 size_t sAntNumElems = aAntenna->GetNumElems();
1101 size_t uAntNumElems = bAntenna->GetNumElems();
1102 size_t chanNumRows = channelMatrix->m_channel.GetNumRows();
1103 size_t chanNumCols = channelMatrix->m_channel.GetNumCols();
1104 return ((uAntNumElems != chanNumRows) || (sAntNumElems != chanNumCols)) &&
1105 ((uAntNumElems != chanNumCols) || (sAntNumElems != chanNumRows));
1117 uint64_t channelParamsKey =
1120 uint64_t channelMatrixKey =
GetKey(aAntenna->GetId(), bAntenna->GetId());
1128 bool updateParams =
false;
1129 bool updateMatrix =
false;
1130 bool notFoundParams =
false;
1131 bool notFoundMatrix =
false;
1144 notFoundParams =
true;
1147 double x = aMob->GetPosition().x - bMob->GetPosition().x;
1148 double y = aMob->GetPosition().y - bMob->GetPosition().y;
1149 double distance2D = sqrt(x * x + y * y);
1153 double hUt = std::min(aMob->GetPosition().z, bMob->GetPosition().z);
1154 double hBs = std::max(aMob->GetPosition().z, bMob->GetPosition().z);
1159 if (notFoundParams || updateParams)
1185 notFoundMatrix =
true;
1190 if (notFoundMatrix || updateMatrix)
1193 channelMatrix =
GetNewChannel(channelParams, table3gpp, aMob, bMob, aAntenna, bAntenna);
1194 channelMatrix->m_antennaPair =
1195 std::make_pair(aAntenna->GetId(),
1203 return channelMatrix;
1212 uint64_t channelParamsKey =
1221 NS_LOG_WARN(
"Channel params map not found. Returning a nullptr.");
1236 channelParams->m_nodeIds =
1238 channelParams->m_losCondition = channelCondition->GetLosCondition();
1239 channelParams->m_o2iCondition = channelCondition->GetO2iCondition();
1244 uint8_t paramNum = 6;
1251 for (uint8_t iter = 0; iter < paramNum; iter++)
1255 for (uint8_t row = 0; row < paramNum; row++)
1258 for (uint8_t column = 0; column < paramNum; column++)
1260 temp += table3gpp->m_sqrtC[row][column] * LSPsIndep[column];
1262 LSPs.push_back(temp);
1274 kFactor = LSPs[1] * table3gpp->m_sigK + table3gpp->m_uK;
1275 DS = pow(10, LSPs[2] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1276 ASD = pow(10, LSPs[3] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1277 ASA = pow(10, LSPs[4] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1278 ZSD = pow(10, LSPs[5] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1279 ZSA = pow(10, LSPs[6] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1283 DS = pow(10, LSPs[1] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1284 ASD = pow(10, LSPs[2] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1285 ASA = pow(10, LSPs[3] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1286 ZSD = pow(10, LSPs[4] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1287 ZSA = pow(10, LSPs[5] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1289 ASD = std::min(ASD, 104.0);
1290 ASA = std::min(ASA, 104.0);
1291 ZSD = std::min(ZSD, 52.0);
1292 ZSA = std::min(ZSA, 52.0);
1295 channelParams->m_DS = DS;
1296 channelParams->m_K_factor = kFactor;
1298 NS_LOG_INFO(
"K-factor=" << kFactor <<
", DS=" << DS <<
", ASD=" << ASD <<
", ASA=" << ASA
1299 <<
", ZSD=" << ZSD <<
", ZSA=" << ZSA);
1303 double minTau = 100.0;
1304 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1311 clusterDelay.push_back(tau);
1314 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1316 clusterDelay[cIndex] -= minTau;
1318 std::sort(clusterDelay.begin(), clusterDelay.end());
1325 double powerSum = 0;
1326 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1329 exp(-1 * clusterDelay[cIndex] * (table3gpp->m_rTau - 1) / table3gpp->m_rTau / DS) *
1331 -1 *
m_normalRv->GetValue() * table3gpp->m_perClusterShadowingStd / 10.0);
1333 clusterPower.push_back(power);
1335 channelParams->m_clusterPower = clusterPower;
1337 double powerMax = 0;
1339 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1341 channelParams->m_clusterPower[cIndex] =
1342 channelParams->m_clusterPower[cIndex] / powerSum;
1349 double kLinear = pow(10, kFactor / 10.0);
1351 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1355 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1357 kLinear / (1 + kLinear));
1361 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1364 if (powerMax < clusterPowerForAngles[cIndex])
1366 powerMax = clusterPowerForAngles[cIndex];
1372 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1374 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex]);
1375 if (powerMax < clusterPowerForAngles[cIndex])
1377 powerMax = clusterPowerForAngles[cIndex];
1384 double thresh = 0.0032;
1385 for (uint8_t cIndex = table3gpp->m_numOfCluster; cIndex > 0; cIndex--)
1387 if (clusterPowerForAngles[cIndex - 1] < thresh * powerMax)
1389 clusterPowerForAngles.erase(clusterPowerForAngles.begin() + cIndex - 1);
1390 channelParams->m_clusterPower.erase(channelParams->m_clusterPower.begin() + cIndex - 1);
1391 clusterDelay.erase(clusterDelay.begin() + cIndex - 1);
1395 NS_ASSERT(channelParams->m_clusterPower.size() < UINT8_MAX);
1396 channelParams->m_reducedClusterNumber = channelParams->m_clusterPower.size();
1401 0.7705 - 0.0433 * kFactor + 2e-4 * pow(kFactor, 2) + 17e-6 * pow(kFactor, 3);
1402 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1404 clusterDelay[cIndex] = clusterDelay[cIndex] / cTau;
1413 switch (table3gpp->m_numOfCluster)
1452 double cPhi = cNlos;
1456 cPhi *= (1.1035 - 0.028 * kFactor - 2e-3 * pow(kFactor, 2) +
1457 1e-4 * pow(kFactor, 3));
1460 switch (table3gpp->m_numOfCluster)
1487 double cTheta = cNlos;
1488 if (channelCondition->IsLos())
1490 cTheta *= (1.3086 + 0.0339 * kFactor - 0.0077 * pow(kFactor, 2) +
1491 2e-4 * pow(kFactor, 3));
1498 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1500 double logCalc = -1 * log(clusterPowerForAngles[cIndex] / powerMax);
1501 double angle = 2 * sqrt(logCalc) / 1.4 / cPhi;
1502 clusterAoa.push_back(ASA * angle);
1503 clusterAod.push_back(ASD * angle);
1504 angle = logCalc / cTheta;
1505 clusterZoa.push_back(ZSA * angle);
1506 clusterZod.push_back(ZSD * angle);
1509 Angles sAngle(bMob->GetPosition(), aMob->GetPosition());
1510 Angles uAngle(aMob->GetPosition(), bMob->GetPosition());
1512 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1519 clusterAoa[cIndex] = clusterAoa[cIndex] * Xn + (
m_normalRv->GetValue() * ASA / 7.0) +
1521 clusterAod[cIndex] = clusterAod[cIndex] * Xn + (
m_normalRv->GetValue() * ASD / 7.0) +
1523 if (channelCondition->IsO2i())
1525 clusterZoa[cIndex] =
1526 clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7.0) + 90;
1530 clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7.0) +
1533 clusterZod[cIndex] = clusterZod[cIndex] * Xn + (
m_normalRv->GetValue() * ZSD / 7.0) +
1535 table3gpp->m_offsetZOD;
1547 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1549 clusterAoa[cIndex] -= diffAoa;
1550 clusterAod[cIndex] -= diffAod;
1551 clusterZoa[cIndex] -= diffZsa;
1552 clusterZod[cIndex] -= diffZsd;
1556 double sizeTemp = clusterZoa.size();
1557 for (uint8_t ind = 0; ind < 4; ind++)
1563 angleDegree = clusterAoa;
1566 angleDegree = clusterZoa;
1569 angleDegree = clusterAod;
1572 angleDegree = clusterZod;
1577 for (uint8_t nIndex = 0; nIndex < sizeTemp; nIndex++)
1579 while (angleDegree[nIndex] > 360)
1581 angleDegree[nIndex] -= 360;
1584 while (angleDegree[nIndex] < 0)
1586 angleDegree[nIndex] += 360;
1589 if (ind == 1 || ind == 3)
1591 if (angleDegree[nIndex] > 180)
1593 angleDegree[nIndex] = 360 - angleDegree[nIndex];
1600 clusterAoa = angleDegree;
1603 clusterZoa = angleDegree;
1606 clusterAod = angleDegree;
1609 clusterZod = angleDegree;
1620 for (uint8_t cInd = 0; cInd < channelParams->m_reducedClusterNumber; cInd++)
1622 channelParams->m_clusterPower[cInd] =
1623 channelParams->m_clusterPower[cInd] / pow(10, attenuationDb[cInd] / 10.0);
1628 attenuationDb.push_back(0);
1632 channelParams->m_attenuation_dB = attenuationDb;
1637 channelParams->m_reducedClusterNumber,
1641 channelParams->m_reducedClusterNumber,
1645 channelParams->m_reducedClusterNumber,
1649 channelParams->m_reducedClusterNumber,
1653 const double pow10_uLgZSD = pow(10, table3gpp->m_uLgZSD);
1654 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1656 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1658 double tempAoa = clusterAoa[nInd] + table3gpp->m_cASA *
offSetAlpha[mInd];
1659 double tempZoa = clusterZoa[nInd] + table3gpp->m_cZSA *
offSetAlpha[mInd];
1660 std::tie(rayAoaRadian[nInd][mInd], rayZoaRadian[nInd][mInd]) =
1663 double tempAod = clusterAod[nInd] + table3gpp->m_cASD *
offSetAlpha[mInd];
1664 double tempZod = clusterZod[nInd] + 0.375 * pow10_uLgZSD *
offSetAlpha[mInd];
1665 std::tie(rayAodRadian[nInd][mInd], rayZodRadian[nInd][mInd]) =
1670 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1672 Shuffle(&rayAodRadian[cIndex][0], &rayAodRadian[cIndex][table3gpp->m_raysPerCluster]);
1673 Shuffle(&rayAoaRadian[cIndex][0], &rayAoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1674 Shuffle(&rayZodRadian[cIndex][0], &rayZodRadian[cIndex][table3gpp->m_raysPerCluster]);
1675 Shuffle(&rayZoaRadian[cIndex][0], &rayZoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1679 channelParams->m_rayAodRadian = rayAodRadian;
1680 channelParams->m_rayAoaRadian = rayAoaRadian;
1681 channelParams->m_rayZodRadian = rayZodRadian;
1682 channelParams->m_rayZoaRadian = rayZoaRadian;
1688 auto& crossPolarizationPowerRatios = channelParams->m_crossPolarizationPowerRatios;
1690 auto& clusterPhase = channelParams->m_clusterPhase;
1692 const double uXprLinear = pow(10, table3gpp->m_uXpr / 10.0);
1693 const double sigXprLinear = pow(10, table3gpp->m_sigXpr / 10.0);
1696 clusterPhase.resize(channelParams->m_reducedClusterNumber);
1697 crossPolarizationPowerRatios.resize(channelParams->m_reducedClusterNumber);
1698 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1700 clusterPhase[nInd].resize(table3gpp->m_raysPerCluster);
1701 crossPolarizationPowerRatios[nInd].resize(table3gpp->m_raysPerCluster);
1702 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1704 clusterPhase[nInd][mInd].resize(4);
1706 crossPolarizationPowerRatios[nInd][mInd] =
1707 std::pow(10, (
m_normalRv->GetValue() * sigXprLinear + uXprLinear) / 10.0);
1708 for (uint8_t pInd = 0; pInd < 4; pInd++)
1716 uint8_t cluster1st = 0;
1717 uint8_t cluster2nd = 0;
1718 double maxPower = 0;
1719 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1721 if (maxPower < channelParams->m_clusterPower[cIndex])
1723 maxPower = channelParams->m_clusterPower[cIndex];
1724 cluster1st = cIndex;
1727 channelParams->m_cluster1st = cluster1st;
1729 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1731 if (maxPower < channelParams->m_clusterPower[cIndex] && cluster1st != cIndex)
1733 maxPower = channelParams->m_clusterPower[cIndex];
1734 cluster2nd = cIndex;
1737 channelParams->m_cluster2nd = cluster2nd;
1739 NS_LOG_INFO(
"1st strongest cluster:" << +cluster1st
1740 <<
", 2nd strongest cluster:" << +cluster2nd);
1743 if (cluster1st == cluster2nd)
1745 clusterDelay.push_back(clusterDelay[cluster1st] + 1.28 * table3gpp->m_cDS);
1746 clusterDelay.push_back(clusterDelay[cluster1st] + 2.56 * table3gpp->m_cDS);
1748 clusterAoa.push_back(clusterAoa[cluster1st]);
1749 clusterAoa.push_back(clusterAoa[cluster1st]);
1751 clusterZoa.push_back(clusterZoa[cluster1st]);
1752 clusterZoa.push_back(clusterZoa[cluster1st]);
1754 clusterAod.push_back(clusterAod[cluster1st]);
1755 clusterAod.push_back(clusterAod[cluster1st]);
1757 clusterZod.push_back(clusterZod[cluster1st]);
1758 clusterZod.push_back(clusterZod[cluster1st]);
1764 if (cluster1st < cluster2nd)
1774 clusterDelay.push_back(clusterDelay[min] + 1.28 * table3gpp->m_cDS);
1775 clusterDelay.push_back(clusterDelay[min] + 2.56 * table3gpp->m_cDS);
1776 clusterDelay.push_back(clusterDelay[max] + 1.28 * table3gpp->m_cDS);
1777 clusterDelay.push_back(clusterDelay[max] + 2.56 * table3gpp->m_cDS);
1779 clusterAoa.push_back(clusterAoa[min]);
1780 clusterAoa.push_back(clusterAoa[min]);
1781 clusterAoa.push_back(clusterAoa[max]);
1782 clusterAoa.push_back(clusterAoa[max]);
1784 clusterZoa.push_back(clusterZoa[min]);
1785 clusterZoa.push_back(clusterZoa[min]);
1786 clusterZoa.push_back(clusterZoa[max]);
1787 clusterZoa.push_back(clusterZoa[max]);
1789 clusterAod.push_back(clusterAod[min]);
1790 clusterAod.push_back(clusterAod[min]);
1791 clusterAod.push_back(clusterAod[max]);
1792 clusterAod.push_back(clusterAod[max]);
1794 clusterZod.push_back(clusterZod[min]);
1795 clusterZod.push_back(clusterZod[min]);
1796 clusterZod.push_back(clusterZod[max]);
1797 clusterZod.push_back(clusterZod[max]);
1800 channelParams->m_delay = clusterDelay;
1801 channelParams->m_angle.clear();
1802 channelParams->m_angle.push_back(clusterAoa);
1803 channelParams->m_angle.push_back(clusterZoa);
1804 channelParams->m_angle.push_back(clusterAod);
1805 channelParams->m_angle.push_back(clusterZod);
1808 channelParams->m_cachedAngleSincos.resize(channelParams->m_angle.size());
1809 for (
size_t direction = 0; direction < channelParams->m_angle.size(); direction++)
1811 channelParams->m_cachedAngleSincos[direction].resize(
1812 channelParams->m_angle[direction].size());
1813 for (
size_t cluster = 0; cluster < channelParams->m_angle[direction].size(); cluster++)
1815 channelParams->m_cachedAngleSincos[direction][cluster] = {
1816 sin(channelParams->m_angle[direction][cluster] *
DEG2RAD),
1817 cos(channelParams->m_angle[direction][cluster] *
DEG2RAD)};
1837 uint8_t updatedClusterNumber = (channelParams->m_reducedClusterNumber == 1)
1838 ? channelParams->m_reducedClusterNumber + 2
1839 : channelParams->m_reducedClusterNumber + 4;
1841 for (uint8_t cIndex = 0; cIndex < updatedClusterNumber; cIndex++)
1850 dopplerTermAlpha.push_back(alpha);
1851 dopplerTermD.push_back(D);
1853 channelParams->m_alpha = dopplerTermAlpha;
1854 channelParams->m_D = dopplerTermD;
1856 return channelParams;
1875 channelMatrix->m_nodeIds =
1878 bool isSameDirection = (channelParams->m_nodeIds == channelMatrix->m_nodeIds);
1889 if (isSameDirection)
1891 rayAodRadian = channelParams->m_rayAodRadian;
1892 rayAoaRadian = channelParams->m_rayAoaRadian;
1893 rayZodRadian = channelParams->m_rayZodRadian;
1894 rayZoaRadian = channelParams->m_rayZoaRadian;
1898 rayAodRadian = channelParams->m_rayAoaRadian;
1899 rayAoaRadian = channelParams->m_rayAodRadian;
1900 rayZodRadian = channelParams->m_rayZoaRadian;
1901 rayZoaRadian = channelParams->m_rayZodRadian;
1907 size_t uSize = uAntenna->GetNumElems();
1908 size_t sSize = sAntenna->GetNumElems();
1914 uint16_t numOverallCluster = (channelParams->m_cluster1st != channelParams->m_cluster2nd)
1915 ? channelParams->m_reducedClusterNumber + 4
1916 : channelParams->m_reducedClusterNumber + 2;
1918 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPhase.size());
1919 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPower.size());
1920 NS_ASSERT(channelParams->m_reducedClusterNumber <=
1921 channelParams->m_crossPolarizationPowerRatios.size());
1922 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZoaRadian.size());
1923 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZodRadian.size());
1924 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAoaRadian.size());
1925 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAodRadian.size());
1926 NS_ASSERT(table3gpp->m_raysPerCluster <= channelParams->m_clusterPhase[0].size());
1927 NS_ASSERT(table3gpp->m_raysPerCluster <=
1928 channelParams->m_crossPolarizationPowerRatios[0].size());
1929 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZoaRadian[0].size());
1930 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZodRadian[0].size());
1931 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAoaRadian[0].size());
1932 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAodRadian[0].size());
1934 double x = sMob->GetPosition().x - uMob->GetPosition().x;
1935 double y = sMob->GetPosition().y - uMob->GetPosition().y;
1936 double distance2D = sqrt(x * x + y * y);
1939 double hUt = std::min(sMob->GetPosition().z, uMob->GetPosition().z);
1940 double hBs = std::max(sMob->GetPosition().z, uMob->GetPosition().z);
1942 double distance3D = std::sqrt(distance2D * distance2D + (hBs - hUt) * (hBs - hUt));
1944 Angles sAngle(uMob->GetPosition(), sMob->GetPosition());
1945 Angles uAngle(sMob->GetPosition(), uMob->GetPosition());
1957 for (
size_t polSa = 0; polSa < sAntenna->GetNumPols(); ++polSa)
1959 for (
size_t polUa = 0; polUa < uAntenna->GetNumPols(); ++polUa)
1961 raysPreComp[std::make_pair(polSa, polUa)] =
1962 Complex2DVector(channelParams->m_reducedClusterNumber, table3gpp->m_raysPerCluster);
1967 sinCosA.resize(channelParams->m_reducedClusterNumber);
1968 sinSinA.resize(channelParams->m_reducedClusterNumber);
1969 cosZoA.resize(channelParams->m_reducedClusterNumber);
1970 sinCosD.resize(channelParams->m_reducedClusterNumber);
1971 sinSinD.resize(channelParams->m_reducedClusterNumber);
1972 cosZoD.resize(channelParams->m_reducedClusterNumber);
1973 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1975 sinCosA[nIndex].resize(table3gpp->m_raysPerCluster);
1976 sinSinA[nIndex].resize(table3gpp->m_raysPerCluster);
1977 cosZoA[nIndex].resize(table3gpp->m_raysPerCluster);
1978 sinCosD[nIndex].resize(table3gpp->m_raysPerCluster);
1979 sinSinD[nIndex].resize(table3gpp->m_raysPerCluster);
1980 cosZoD[nIndex].resize(table3gpp->m_raysPerCluster);
1983 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1985 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
1987 DoubleVector initialPhase = channelParams->m_clusterPhase[nIndex][mIndex];
1989 double k = channelParams->m_crossPolarizationPowerRatios[nIndex][mIndex];
1993 for (uint8_t polUa = 0; polUa < uAntenna->GetNumPols(); ++polUa)
1995 auto [rxFieldPatternPhi, rxFieldPatternTheta] = uAntenna->GetElementFieldPattern(
1996 Angles(channelParams->m_rayAoaRadian[nIndex][mIndex],
1997 channelParams->m_rayZoaRadian[nIndex][mIndex]),
1999 for (uint8_t polSa = 0; polSa < sAntenna->GetNumPols(); ++polSa)
2001 auto [txFieldPatternPhi, txFieldPatternTheta] =
2002 sAntenna->GetElementFieldPattern(
2003 Angles(channelParams->m_rayAodRadian[nIndex][mIndex],
2004 channelParams->m_rayZodRadian[nIndex][mIndex]),
2006 raysPreComp[std::make_pair(polSa, polUa)](nIndex, mIndex) =
2007 std::complex<double>(cos(initialPhase[0]), sin(initialPhase[0])) *
2008 rxFieldPatternTheta * txFieldPatternTheta +
2009 std::complex<double>(cos(initialPhase[1]), sin(initialPhase[1])) *
2010 std::sqrt(1.0 / k) * rxFieldPatternTheta * txFieldPatternPhi +
2011 std::complex<double>(cos(initialPhase[2]), sin(initialPhase[2])) *
2012 std::sqrt(1.0 / k) * rxFieldPatternPhi * txFieldPatternTheta +
2013 std::complex<double>(cos(initialPhase[3]), sin(initialPhase[3])) *
2014 rxFieldPatternPhi * txFieldPatternPhi;
2020 double sinRayZoa = sin(rayZoaRadian[nIndex][mIndex]);
2021 double sinRayAoa = sin(rayAoaRadian[nIndex][mIndex]);
2022 double cosRayAoa = cos(rayAoaRadian[nIndex][mIndex]);
2023 sinCosA[nIndex][mIndex] = sinRayZoa * cosRayAoa;
2024 sinSinA[nIndex][mIndex] = sinRayZoa * sinRayAoa;
2025 cosZoA[nIndex][mIndex] = cos(rayZoaRadian[nIndex][mIndex]);
2029 double sinRayZod = sin(rayZodRadian[nIndex][mIndex]);
2030 double sinRayAod = sin(rayAodRadian[nIndex][mIndex]);
2031 double cosRayAod = cos(rayAodRadian[nIndex][mIndex]);
2032 sinCosD[nIndex][mIndex] = sinRayZod * cosRayAod;
2033 sinSinD[nIndex][mIndex] = sinRayZod * sinRayAod;
2034 cosZoD[nIndex][mIndex] = cos(rayZodRadian[nIndex][mIndex]);
2040 uint8_t numSubClustersAdded = 0;
2041 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
2043 for (
size_t uIndex = 0; uIndex < uSize; uIndex++)
2045 Vector uLoc = uAntenna->GetElementLocation(uIndex);
2047 for (
size_t sIndex = 0; sIndex < sSize; sIndex++)
2049 Vector sLoc = sAntenna->GetElementLocation(sIndex);
2052 if (nIndex != channelParams->m_cluster1st && nIndex != channelParams->m_cluster2nd)
2054 std::complex<double> rays(0, 0);
2055 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
2058 double rxPhaseDiff =
2060 (sinCosA[nIndex][mIndex] * uLoc.x + sinSinA[nIndex][mIndex] * uLoc.y +
2061 cosZoA[nIndex][mIndex] * uLoc.z);
2063 double txPhaseDiff =
2065 (sinCosD[nIndex][mIndex] * sLoc.x + sinSinD[nIndex][mIndex] * sLoc.y +
2066 cosZoD[nIndex][mIndex] * sLoc.z);
2069 rays += raysPreComp[std::make_pair(sAntenna->GetElemPol(sIndex),
2070 uAntenna->GetElemPol(uIndex))](nIndex,
2072 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2073 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2076 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2077 hUsn(uIndex, sIndex, nIndex) = rays;
2081 std::complex<double> raysSub1(0, 0);
2082 std::complex<double> raysSub2(0, 0);
2083 std::complex<double> raysSub3(0, 0);
2085 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
2089 double rxPhaseDiff =
2091 (sinCosA[nIndex][mIndex] * uLoc.x + sinSinA[nIndex][mIndex] * uLoc.y +
2092 cosZoA[nIndex][mIndex] * uLoc.z);
2094 double txPhaseDiff =
2096 (sinCosD[nIndex][mIndex] * sLoc.x + sinSinD[nIndex][mIndex] * sLoc.y +
2097 cosZoD[nIndex][mIndex] * sLoc.z);
2099 std::complex<double> raySub =
2100 raysPreComp[std::make_pair(sAntenna->GetElemPol(sIndex),
2101 uAntenna->GetElemPol(uIndex))](nIndex,
2103 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2104 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2128 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2130 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2132 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2133 hUsn(uIndex, sIndex, nIndex) = raysSub1;
2136 channelParams->m_reducedClusterNumber + numSubClustersAdded) = raysSub2;
2139 channelParams->m_reducedClusterNumber + numSubClustersAdded + 1) =
2144 if (nIndex == channelParams->m_cluster1st || nIndex == channelParams->m_cluster2nd)
2146 numSubClustersAdded += 2;
2153 std::complex<double> phaseDiffDueToDistance(cos(-2 * M_PI * distance3D / lambda),
2154 sin(-2 * M_PI * distance3D / lambda));
2158 const double sinUAngleAz = sin(uAngle.
GetAzimuth());
2159 const double cosUAngleAz = cos(uAngle.
GetAzimuth());
2162 const double sinSAngleAz = sin(sAngle.
GetAzimuth());
2163 const double cosSAngleAz = cos(sAngle.
GetAzimuth());
2165 for (
size_t uIndex = 0; uIndex < uSize; uIndex++)
2167 Vector uLoc = uAntenna->GetElementLocation(uIndex);
2168 double rxPhaseDiff = 2 * M_PI *
2169 (sinUAngleIncl * cosUAngleAz * uLoc.x +
2170 sinUAngleIncl * sinUAngleAz * uLoc.y + cosUAngleIncl * uLoc.z);
2172 for (
size_t sIndex = 0; sIndex < sSize; sIndex++)
2174 Vector sLoc = sAntenna->GetElementLocation(sIndex);
2175 std::complex<double> ray(0, 0);
2176 double txPhaseDiff =
2178 (sinSAngleIncl * cosSAngleAz * sLoc.x + sinSAngleIncl * sinSAngleAz * sLoc.y +
2179 cosSAngleIncl * sLoc.z);
2181 auto [rxFieldPatternPhi, rxFieldPatternTheta] = uAntenna->GetElementFieldPattern(
2183 uAntenna->GetElemPol(uIndex));
2184 auto [txFieldPatternPhi, txFieldPatternTheta] = sAntenna->GetElementFieldPattern(
2186 sAntenna->GetElemPol(sIndex));
2188 ray = (rxFieldPatternTheta * txFieldPatternTheta -
2189 rxFieldPatternPhi * txFieldPatternPhi) *
2190 phaseDiffDueToDistance *
2191 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2192 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2194 double kLinear = pow(10, channelParams->m_K_factor / 10.0);
2196 hUsn(uIndex, sIndex, 0) =
2197 sqrt(1.0 / (kLinear + 1)) * hUsn(uIndex, sIndex, 0) +
2198 sqrt(kLinear / (1 + kLinear)) * ray /
2200 channelParams->m_attenuation_dB[0] / 10.0);
2201 for (
size_t nIndex = 1; nIndex < hUsn.GetNumPages(); nIndex++)
2203 hUsn(uIndex, sIndex, nIndex) *=
2204 sqrt(1.0 / (kLinear + 1));
2210 NS_LOG_DEBUG(
"Husn (sAntenna, uAntenna):" << sAntenna->GetId() <<
", " << uAntenna->GetId());
2211 for (
size_t cIndex = 0; cIndex < hUsn.GetNumPages(); cIndex++)
2213 for (
size_t rowIdx = 0; rowIdx < hUsn.GetNumRows(); rowIdx++)
2215 for (
size_t colIdx = 0; colIdx < hUsn.GetNumCols(); colIdx++)
2217 NS_LOG_DEBUG(
" " << hUsn(rowIdx, colIdx, cIndex) <<
",");
2222 NS_LOG_INFO(
"size of coefficient matrix (rows, columns, clusters) = ("
2223 << hUsn.GetNumRows() <<
", " << hUsn.GetNumCols() <<
", " << hUsn.GetNumPages()
2225 channelMatrix->m_channel = hUsn;
2226 return channelMatrix;
2229std::pair<double, double>
2232 inclinationRad =
WrapTo2Pi(inclinationRad);
2233 if (inclinationRad > M_PI)
2236 inclinationRad -= M_PI;
2242 NS_ASSERT_MSG(0 <= inclinationRad && inclinationRad <= M_PI,
2243 "inclinationRad=" << inclinationRad <<
" not valid, should be in [0, pi]");
2245 "azimuthRad=" << azimuthRad <<
" not valid, should be in [0, 2*pi]");
2247 return std::make_pair(azimuthRad, inclinationRad);
2258 auto clusterNum = clusterAOA.size();
2271 double thetaSb = 110;
2282 if (channelParams->m_nonSelfBlocking.empty())
2293 table.push_back(90);
2300 table.push_back(90);
2302 table.push_back(10);
2304 channelParams->m_nonSelfBlocking.push_back(table);
2309 double deltaX = sqrt(pow(channelParams->m_preLocUT.x - channelParams->m_locUT.x, 2) +
2310 pow(channelParams->m_preLocUT.y - channelParams->m_locUT.y, 2));
2337 R = exp(-1 * (deltaX / corrDis +
2338 (
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()) /
2343 R = exp(-1 * (deltaX / corrDis));
2348 <<
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()
2349 <<
" correlation:" << R);
2359 if (R * R * (-0.069) + R * 1.074 - 0.002 <
2362 R = R * R * (-0.069) + R * 1.074 - 0.002;
2367 channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] =
2368 R * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] +
2375 for (std::size_t cInd = 0; cInd < clusterNum; cInd++)
2377 NS_ASSERT_MSG(clusterAOA[cInd] >= 0 && clusterAOA[cInd] <= 360,
2378 "the AOA should be the range of [0,360]");
2379 NS_ASSERT_MSG(clusterZOA[cInd] >= 0 && clusterZOA[cInd] <= 180,
2380 "the ZOA should be the range of [0,180]");
2383 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiSb - xSb / 2.0 <<
","
2384 << phiSb + xSb / 2.0 <<
"]");
2385 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaSb - ySb / 2.0 <<
","
2386 << thetaSb + ySb / 2.0 <<
"]");
2387 if (std::abs(clusterAOA[cInd] - phiSb) < (xSb / 2.0) &&
2388 std::abs(clusterZOA[cInd] - thetaSb) < (ySb / 2.0))
2390 powerAttenuation[cInd] += 30;
2392 <<
"] is blocked by self blocking region and reduce 30 dB power,"
2393 "the attenuation is ["
2394 << powerAttenuation[cInd] <<
" dB]");
2402 (0.5 * erfc(-1 * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] / sqrt(2))) *
2414 double xK = channelParams->m_nonSelfBlocking[blockInd][
X_INDEX];
2415 double thetaK = channelParams->m_nonSelfBlocking[blockInd][
THETA_INDEX];
2416 double yK = channelParams->m_nonSelfBlocking[blockInd][
Y_INDEX];
2418 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiK - xK <<
","
2419 << phiK + xK <<
"]");
2420 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaK - yK <<
","
2421 << thetaK + yK <<
"]");
2423 if (std::abs(clusterAOA[cInd] - phiK) < (xK) &&
2424 std::abs(clusterZOA[cInd] - thetaK) < (yK))
2426 double A1 = clusterAOA[cInd] - (phiK + xK / 2.0);
2427 double A2 = clusterAOA[cInd] - (phiK - xK / 2.0);
2428 double Z1 = clusterZOA[cInd] - (thetaK + yK / 2.0);
2429 double Z2 = clusterZOA[cInd] - (thetaK - yK / 2.0);
2436 if (xK / 2.0 < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= xK)
2444 if (-1 * xK < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= -1 * xK / 2.0)
2453 if (yK / 2.0 < clusterZOA[cInd] - thetaK && clusterZOA[cInd] - thetaK <= yK)
2461 if (-1 * yK < clusterZOA[cInd] - thetaK &&
2462 clusterZOA[cInd] - thetaK <= -1 * yK / 2.0)
2472 atan(signA1 * M_PI / 2.0 *
2473 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2477 atan(signA2 * M_PI / 2.0 *
2478 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2482 atan(signZ1 * M_PI / 2.0 *
2483 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2487 atan(signZ2 * M_PI / 2.0 *
2488 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2491 double lDb = -20 * log10(1 - (fA1 + fA2) * (fZ1 + fZ2));
2492 powerAttenuation[cInd] += lDb;
2493 NS_LOG_INFO(
"Cluster[" << +cInd <<
"] is blocked by no-self blocking, the loss is ["
2498 return powerAttenuation;
2504 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< 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 AntennaSetupChanged(Ptr< const PhasedArrayModel > aAntenna, Ptr< const PhasedArrayModel > bAntenna, Ptr< const ChannelMatrix > channelMatrix)
Check if the channel matrix has to be updated due to changes in the number of antenna ports.
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