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>
48 0.0447, -0.0447, 0.1413, -0.1413, 0.2492, -0.2492, 0.3715, -0.3715, 0.5129, -0.5129,
49 0.6797, -0.6797, 0.8844, -0.8844, 1.1481, -1.1481, 1.5195, -1.5195, 2.1551, -2.1551,
61 {1, 0, 0, 0, 0, 0, 0},
62 {0, 1, 0, 0, 0, 0, 0},
63 {-0.5, 0, 0.866025, 0, 0, 0, 0},
64 {0, 0, 0, 1, 0, 0, 0},
65 {0, 0, 0, 0, 1, 0, 0},
66 {0.01, 0, -0.0519615, 0.73, -0.2, 0.651383, 0},
67 {-0.17, -0.02, 0.21362, -0.14, 0.24, 0.142773, 0.909661},
81 {-0.5, 0.866025, 0, 0, 0, 0},
82 {0.6, -0.11547, 0.791623, 0, 0, 0},
84 {-0.04, -0.138564, 0.540662, -0.18, 0.809003, 0},
85 {-0.25, -0.606218, -0.240013, 0.26, -0.231685, 0.625392},
100 {0, 0, -0.7, 0.714143, 0, 0},
101 {0, 0, 0.66, -0.123225, 0.741091, 0},
102 {0, 0, 0.47, 0.152631, -0.393194, 0.775373},
114 {1, 0, 0, 0, 0, 0, 0},
115 {0, 1, 0, 0, 0, 0, 0},
116 {-0.4, -0.4, 0.824621, 0, 0, 0, 0},
117 {-0.5, 0, 0.242536, 0.83137, 0, 0, 0},
118 {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0},
119 {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0},
120 {-0.8, 0, -0.388057, -0.367926, 0.238537, -3.58949e-15, 0.130931},
134 {-0.4, 0.916515, 0, 0, 0, 0},
135 {-0.6, 0.174574, 0.78072, 0, 0, 0},
136 {0, 0.654654, 0.365963, 0.661438, 0, 0},
137 {0, -0.545545, 0.762422, 0.118114, 0.327327, 0},
138 {-0.4, -0.174574, -0.396459, 0.392138, 0.49099, 0.507445},
151 {-0.5, 0.866025, 0, 0, 0, 0},
152 {0.2, 0.57735, 0.791623, 0, 0, 0},
153 {0, 0.46188, -0.336861, 0.820482, 0, 0},
154 {0, -0.69282, 0.252646, 0.493742, 0.460857, 0},
155 {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515},
168 {1, 0, 0, 0, 0, 0, 0},
169 {0.5, 0.866025, 0, 0, 0, 0, 0},
170 {-0.4, -0.57735, 0.711805, 0, 0, 0, 0},
171 {-0.5, 0.057735, 0.468293, 0.726201, 0, 0, 0},
172 {-0.4, -0.11547, 0.805464, -0.23482, 0.350363, 0, 0},
173 {0, 0, 0, 0.688514, 0.461454, 0.559471, 0},
174 {0, 0, 0.280976, 0.231921, -0.490509, 0.11916, 0.782603},
188 {-0.7, 0.714143, 0, 0, 0, 0},
190 {-0.4, 0.168034, 0, 0.90098, 0, 0},
191 {0, -0.70014, 0.5, 0.130577, 0.4927, 0},
192 {0, 0, 0.5, 0.221981, -0.566238, 0.616522},
205 {-0.5, 0.866025, 0, 0, 0, 0},
206 {0.2, 0.57735, 0.791623, 0, 0, 0},
207 {0, 0.46188, -0.336861, 0.820482, 0, 0},
208 {0, -0.69282, 0.252646, 0.493742, 0.460857, 0},
209 {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515},
221 {1, 0, 0, 0, 0, 0, 0},
222 {0.5, 0.866025, 0, 0, 0, 0, 0},
223 {-0.8, -0.11547, 0.588784, 0, 0, 0, 0},
224 {-0.4, 0.23094, 0.520847, 0.717903, 0, 0, 0},
225 {-0.5, 0.288675, 0.73598, -0.348236, 0.0610847, 0, 0},
226 {0.2, -0.11547, 0.418943, 0.541106, 0.219905, 0.655744, 0},
227 {0.3, -0.057735, 0.73598, -0.348236, 0.0610847, -0.304997, 0.383375},
241 {-0.5, 0.866025, 0, 0, 0, 0},
242 {0, 0.46188, 0.886942, 0, 0, 0},
243 {-0.4, -0.23094, 0.120263, 0.878751, 0, 0},
244 {0, -0.311769, 0.55697, -0.249198, 0.728344, 0},
245 {0, -0.069282, 0.295397, 0.430696, 0.468462, 0.709214},
251 m_uniformRv = CreateObject<UniformRandomVariable>();
255 m_normalRv = CreateObject<NormalRandomVariable>();
282 TypeId(
"ns3::ThreeGppChannelModel")
285 .AddConstructor<ThreeGppChannelModel>()
286 .AddAttribute(
"Frequency",
287 "The operating Frequency in Hz",
291 MakeDoubleChecker<double>())
294 "The 3GPP scenario (RMa, UMa, UMi-StreetCanyon, InH-OfficeOpen, InH-OfficeMixed)",
299 .AddAttribute(
"ChannelConditionModel",
300 "Pointer to the channel condition model",
304 MakePointerChecker<ChannelConditionModel>())
305 .AddAttribute(
"UpdatePeriod",
306 "Specify the channel coherence time",
311 .AddAttribute(
"Blockage",
312 "Enable blockage model A (sec 7.6.4.1)",
316 .AddAttribute(
"NumNonselfBlocking",
317 "number of non-self-blocking regions",
320 MakeIntegerChecker<uint16_t>())
321 .AddAttribute(
"PortraitMode",
322 "true for portrait mode, false for landscape mode",
326 .AddAttribute(
"BlockerSpeed",
327 "The speed of moving blockers, the unit is m/s",
330 MakeDoubleChecker<double>())
331 .AddAttribute(
"vScatt",
332 "Maximum speed of the vehicle in the layout (see 3GPP TR 37.885 v15.3.0, "
334 "Used to compute the additional contribution for the Doppler of"
335 "delayed (reflected) paths",
338 MakeDoubleChecker<double>(0.0))
363 "Frequency should be between 0.5 and 100 GHz but is " <<
f);
378 NS_ASSERT_MSG(scenario ==
"RMa" || scenario ==
"UMa" || scenario ==
"UMi-StreetCanyon" ||
379 scenario ==
"InH-OfficeOpen" || scenario ==
"InH-OfficeMixed" ||
380 scenario ==
"V2V-Urban" || scenario ==
"V2V-Highway",
381 "Unknown scenario, choose between: RMa, UMa, UMi-StreetCanyon, "
382 "InH-OfficeOpen, InH-OfficeMixed, V2V-Urban or V2V-Highway");
397 double distance2D)
const
408 bool los = channelCondition->IsLos();
409 bool o2i = channelCondition->IsO2i();
418 table3gpp->m_numOfCluster = 11;
419 table3gpp->m_raysPerCluster = 20;
420 table3gpp->m_uLgDS = -7.49;
421 table3gpp->m_sigLgDS = 0.55;
422 table3gpp->m_uLgASD = 0.90;
423 table3gpp->m_sigLgASD = 0.38;
424 table3gpp->m_uLgASA = 1.52;
425 table3gpp->m_sigLgASA = 0.24;
426 table3gpp->m_uLgZSA = 0.47;
427 table3gpp->m_sigLgZSA = 0.40;
428 table3gpp->m_uLgZSD = 0.34;
429 table3gpp->m_sigLgZSD =
430 std::max(-1.0, -0.17 * (distance2D / 1000.0) - 0.01 * (hUT - 1.5) + 0.22);
431 table3gpp->m_offsetZOD = 0;
432 table3gpp->m_cDS = 3.91e-9;
433 table3gpp->m_cASD = 2;
434 table3gpp->m_cASA = 3;
435 table3gpp->m_cZSA = 3;
437 table3gpp->m_sigK = 4;
438 table3gpp->m_rTau = 3.8;
439 table3gpp->m_uXpr = 12;
440 table3gpp->m_sigXpr = 4;
441 table3gpp->m_perClusterShadowingStd = 3;
443 for (uint8_t row = 0; row < 7; row++)
445 for (uint8_t column = 0; column < 7; column++)
447 table3gpp->m_sqrtC[row][column] =
sqrtC_RMa_LOS[row][column];
451 else if (!los && !o2i)
453 table3gpp->m_numOfCluster = 10;
454 table3gpp->m_raysPerCluster = 20;
455 table3gpp->m_uLgDS = -7.43;
456 table3gpp->m_sigLgDS = 0.48;
457 table3gpp->m_uLgASD = 0.95;
458 table3gpp->m_sigLgASD = 0.45;
459 table3gpp->m_uLgASA = 1.52;
460 table3gpp->m_sigLgASA = 0.13;
461 table3gpp->m_uLgZSA = 0.58;
462 table3gpp->m_sigLgZSA = 0.37;
463 table3gpp->m_uLgZSD =
464 std::max(-1.0, -0.19 * (distance2D / 1000.0) - 0.01 * (hUT - 1.5) + 0.28);
465 table3gpp->m_sigLgZSD = 0.30;
466 table3gpp->m_offsetZOD = atan((35 - 3.5) / distance2D) - atan((35 - 1.5) / distance2D);
467 table3gpp->m_cDS = 3.91e-9;
468 table3gpp->m_cASD = 2;
469 table3gpp->m_cASA = 3;
470 table3gpp->m_cZSA = 3;
472 table3gpp->m_sigK = 0;
473 table3gpp->m_rTau = 1.7;
474 table3gpp->m_uXpr = 7;
475 table3gpp->m_sigXpr = 3;
476 table3gpp->m_perClusterShadowingStd = 3;
478 for (uint8_t row = 0; row < 6; row++)
480 for (uint8_t column = 0; column < 6; column++)
488 table3gpp->m_numOfCluster = 10;
489 table3gpp->m_raysPerCluster = 20;
490 table3gpp->m_uLgDS = -7.47;
491 table3gpp->m_sigLgDS = 0.24;
492 table3gpp->m_uLgASD = 0.67;
493 table3gpp->m_sigLgASD = 0.18;
494 table3gpp->m_uLgASA = 1.66;
495 table3gpp->m_sigLgASA = 0.21;
496 table3gpp->m_uLgZSA = 0.93;
497 table3gpp->m_sigLgZSA = 0.22;
498 table3gpp->m_uLgZSD =
499 std::max(-1.0, -0.19 * (distance2D / 1000.0) - 0.01 * (hUT - 1.5) + 0.28);
500 table3gpp->m_sigLgZSD = 0.30;
501 table3gpp->m_offsetZOD = atan((35 - 3.5) / distance2D) - atan((35 - 1.5) / distance2D);
502 table3gpp->m_cDS = 3.91e-9;
503 table3gpp->m_cASD = 2;
504 table3gpp->m_cASA = 3;
505 table3gpp->m_cZSA = 3;
507 table3gpp->m_sigK = 0;
508 table3gpp->m_rTau = 1.7;
509 table3gpp->m_uXpr = 7;
510 table3gpp->m_sigXpr = 3;
511 table3gpp->m_perClusterShadowingStd = 3;
513 for (uint8_t row = 0; row < 6; row++)
515 for (uint8_t column = 0; column < 6; column++)
517 table3gpp->m_sqrtC[row][column] =
sqrtC_RMa_O2I[row][column];
526 table3gpp->m_numOfCluster = 12;
527 table3gpp->m_raysPerCluster = 20;
528 table3gpp->m_uLgDS = -6.955 - 0.0963 * log10(fcGHz);
529 table3gpp->m_sigLgDS = 0.66;
530 table3gpp->m_uLgASD = 1.06 + 0.1114 * log10(fcGHz);
531 table3gpp->m_sigLgASD = 0.28;
532 table3gpp->m_uLgASA = 1.81;
533 table3gpp->m_sigLgASA = 0.20;
534 table3gpp->m_uLgZSA = 0.95;
535 table3gpp->m_sigLgZSA = 0.16;
536 table3gpp->m_uLgZSD =
537 std::max(-0.5, -2.1 * distance2D / 1000.0 - 0.01 * (hUT - 1.5) + 0.75);
538 table3gpp->m_sigLgZSD = 0.40;
539 table3gpp->m_offsetZOD = 0;
540 table3gpp->m_cDS =
std::max(0.25, -3.4084 * log10(fcGHz) + 6.5622) * 1e-9;
541 table3gpp->m_cASD = 5;
542 table3gpp->m_cASA = 11;
543 table3gpp->m_cZSA = 7;
545 table3gpp->m_sigK = 3.5;
546 table3gpp->m_rTau = 2.5;
547 table3gpp->m_uXpr = 8;
548 table3gpp->m_sigXpr = 4;
549 table3gpp->m_perClusterShadowingStd = 3;
551 for (uint8_t row = 0; row < 7; row++)
553 for (uint8_t column = 0; column < 7; column++)
555 table3gpp->m_sqrtC[row][column] =
sqrtC_UMa_LOS[row][column];
561 double uLgZSD =
std::max(-0.5, -2.1 * distance2D / 1000.0 - 0.01 * (hUT - 1.5) + 0.9);
563 double afc = 0.208 * log10(fcGHz) - 0.782;
565 double cfc = -0.13 * log10(fcGHz) + 2.03;
566 double efc = 7.66 * log10(fcGHz) - 5.96;
568 double offsetZOD = efc - std::pow(10, afc * log10(
std::max(bfc, distance2D)) + cfc);
572 table3gpp->m_numOfCluster = 20;
573 table3gpp->m_raysPerCluster = 20;
574 table3gpp->m_uLgDS = -6.28 - 0.204 * log10(fcGHz);
575 table3gpp->m_sigLgDS = 0.39;
576 table3gpp->m_uLgASD = 1.5 - 0.1144 * log10(fcGHz);
577 table3gpp->m_sigLgASD = 0.28;
578 table3gpp->m_uLgASA = 2.08 - 0.27 * log10(fcGHz);
579 table3gpp->m_sigLgASA = 0.11;
580 table3gpp->m_uLgZSA = -0.3236 * log10(fcGHz) + 1.512;
581 table3gpp->m_sigLgZSA = 0.16;
582 table3gpp->m_uLgZSD = uLgZSD;
583 table3gpp->m_sigLgZSD = 0.49;
584 table3gpp->m_offsetZOD = offsetZOD;
585 table3gpp->m_cDS =
std::max(0.25, -3.4084 * log10(fcGHz) + 6.5622) * 1e-9;
586 table3gpp->m_cASD = 2;
587 table3gpp->m_cASA = 15;
588 table3gpp->m_cZSA = 7;
590 table3gpp->m_sigK = 0;
591 table3gpp->m_rTau = 2.3;
592 table3gpp->m_uXpr = 7;
593 table3gpp->m_sigXpr = 3;
594 table3gpp->m_perClusterShadowingStd = 3;
596 for (uint8_t row = 0; row < 6; row++)
598 for (uint8_t column = 0; column < 6; column++)
606 table3gpp->m_numOfCluster = 12;
607 table3gpp->m_raysPerCluster = 20;
608 table3gpp->m_uLgDS = -6.62;
609 table3gpp->m_sigLgDS = 0.32;
610 table3gpp->m_uLgASD = 1.25;
611 table3gpp->m_sigLgASD = 0.42;
612 table3gpp->m_uLgASA = 1.76;
613 table3gpp->m_sigLgASA = 0.16;
614 table3gpp->m_uLgZSA = 1.01;
615 table3gpp->m_sigLgZSA = 0.43;
616 table3gpp->m_uLgZSD = uLgZSD;
617 table3gpp->m_sigLgZSD = 0.49;
618 table3gpp->m_offsetZOD = offsetZOD;
619 table3gpp->m_cDS = 11e-9;
620 table3gpp->m_cASD = 5;
621 table3gpp->m_cASA = 8;
622 table3gpp->m_cZSA = 3;
624 table3gpp->m_sigK = 0;
625 table3gpp->m_rTau = 2.2;
626 table3gpp->m_uXpr = 9;
627 table3gpp->m_sigXpr = 5;
628 table3gpp->m_perClusterShadowingStd = 4;
630 for (uint8_t row = 0; row < 6; row++)
632 for (uint8_t column = 0; column < 6; column++)
634 table3gpp->m_sqrtC[row][column] =
sqrtC_UMa_O2I[row][column];
644 table3gpp->m_numOfCluster = 12;
645 table3gpp->m_raysPerCluster = 20;
646 table3gpp->m_uLgDS = -0.24 * log10(1 + fcGHz) - 7.14;
647 table3gpp->m_sigLgDS = 0.38;
648 table3gpp->m_uLgASD = -0.05 * log10(1 + fcGHz) + 1.21;
649 table3gpp->m_sigLgASD = 0.41;
650 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.73;
651 table3gpp->m_sigLgASA = 0.014 * log10(1 + fcGHz) + 0.28;
652 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
653 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
654 table3gpp->m_uLgZSD =
655 std::max(-0.21, -14.8 * distance2D / 1000.0 + 0.01 * std::abs(hUT - hBS) + 0.83);
656 table3gpp->m_sigLgZSD = 0.35;
657 table3gpp->m_offsetZOD = 0;
658 table3gpp->m_cDS = 5e-9;
659 table3gpp->m_cASD = 3;
660 table3gpp->m_cASA = 17;
661 table3gpp->m_cZSA = 7;
663 table3gpp->m_sigK = 5;
664 table3gpp->m_rTau = 3;
665 table3gpp->m_uXpr = 9;
666 table3gpp->m_sigXpr = 3;
667 table3gpp->m_perClusterShadowingStd = 3;
669 for (uint8_t row = 0; row < 7; row++)
671 for (uint8_t column = 0; column < 7; column++)
673 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
680 std::max(-0.5, -3.1 * distance2D / 1000.0 + 0.01 *
std::max(hUT - hBS, 0.0) + 0.2);
681 double offsetZOD = -1 * std::pow(10, -1.5 * log10(
std::max(10.0, distance2D)) + 3.3);
684 table3gpp->m_numOfCluster = 19;
685 table3gpp->m_raysPerCluster = 20;
686 table3gpp->m_uLgDS = -0.24 * log10(1 + fcGHz) - 6.83;
687 table3gpp->m_sigLgDS = 0.16 * log10(1 + fcGHz) + 0.28;
688 table3gpp->m_uLgASD = -0.23 * log10(1 + fcGHz) + 1.53;
689 table3gpp->m_sigLgASD = 0.11 * log10(1 + fcGHz) + 0.33;
690 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
691 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
692 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
693 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
694 table3gpp->m_uLgZSD = uLgZSD;
695 table3gpp->m_sigLgZSD = 0.35;
696 table3gpp->m_offsetZOD = offsetZOD;
697 table3gpp->m_cDS = 11e-9;
698 table3gpp->m_cASD = 10;
699 table3gpp->m_cASA = 22;
700 table3gpp->m_cZSA = 7;
702 table3gpp->m_sigK = 0;
703 table3gpp->m_rTau = 2.1;
704 table3gpp->m_uXpr = 8;
705 table3gpp->m_sigXpr = 3;
706 table3gpp->m_perClusterShadowingStd = 3;
708 for (uint8_t row = 0; row < 6; row++)
710 for (uint8_t column = 0; column < 6; column++)
718 table3gpp->m_numOfCluster = 12;
719 table3gpp->m_raysPerCluster = 20;
720 table3gpp->m_uLgDS = -6.62;
721 table3gpp->m_sigLgDS = 0.32;
722 table3gpp->m_uLgASD = 1.25;
723 table3gpp->m_sigLgASD = 0.42;
724 table3gpp->m_uLgASA = 1.76;
725 table3gpp->m_sigLgASA = 0.16;
726 table3gpp->m_uLgZSA = 1.01;
727 table3gpp->m_sigLgZSA = 0.43;
728 table3gpp->m_uLgZSD = uLgZSD;
729 table3gpp->m_sigLgZSD = 0.35;
730 table3gpp->m_offsetZOD = offsetZOD;
731 table3gpp->m_cDS = 11e-9;
732 table3gpp->m_cASD = 5;
733 table3gpp->m_cASA = 8;
734 table3gpp->m_cZSA = 3;
736 table3gpp->m_sigK = 0;
737 table3gpp->m_rTau = 2.2;
738 table3gpp->m_uXpr = 9;
739 table3gpp->m_sigXpr = 5;
740 table3gpp->m_perClusterShadowingStd = 4;
742 for (uint8_t row = 0; row < 6; row++)
744 for (uint8_t column = 0; column < 6; column++)
746 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_O2I[row][column];
754 NS_ASSERT_MSG(!o2i,
"The indoor scenario does out support outdoor to indoor");
757 table3gpp->m_numOfCluster = 15;
758 table3gpp->m_raysPerCluster = 20;
759 table3gpp->m_uLgDS = -0.01 * log10(1 + fcGHz) - 7.692;
760 table3gpp->m_sigLgDS = 0.18;
761 table3gpp->m_uLgASD = 1.60;
762 table3gpp->m_sigLgASD = 0.18;
763 table3gpp->m_uLgASA = -0.19 * log10(1 + fcGHz) + 1.781;
764 table3gpp->m_sigLgASA = 0.12 * log10(1 + fcGHz) + 0.119;
765 table3gpp->m_uLgZSA = -0.26 * log10(1 + fcGHz) + 1.44;
766 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.264;
767 table3gpp->m_uLgZSD = -1.43 * log10(1 + fcGHz) + 2.228;
768 table3gpp->m_sigLgZSD = 0.13 * log10(1 + fcGHz) + 0.30;
769 table3gpp->m_offsetZOD = 0;
770 table3gpp->m_cDS = 3.91e-9;
771 table3gpp->m_cASD = 5;
772 table3gpp->m_cASA = 8;
773 table3gpp->m_cZSA = 9;
775 table3gpp->m_sigK = 4;
776 table3gpp->m_rTau = 3.6;
777 table3gpp->m_uXpr = 11;
778 table3gpp->m_sigXpr = 4;
779 table3gpp->m_perClusterShadowingStd = 6;
781 for (uint8_t row = 0; row < 7; row++)
783 for (uint8_t column = 0; column < 7; column++)
791 table3gpp->m_numOfCluster = 19;
792 table3gpp->m_raysPerCluster = 20;
793 table3gpp->m_uLgDS = -0.28 * log10(1 + fcGHz) - 7.173;
794 table3gpp->m_sigLgDS = 0.1 * log10(1 + fcGHz) + 0.055;
795 table3gpp->m_uLgASD = 1.62;
796 table3gpp->m_sigLgASD = 0.25;
797 table3gpp->m_uLgASA = -0.11 * log10(1 + fcGHz) + 1.863;
798 table3gpp->m_sigLgASA = 0.12 * log10(1 + fcGHz) + 0.059;
799 table3gpp->m_uLgZSA = -0.15 * log10(1 + fcGHz) + 1.387;
800 table3gpp->m_sigLgZSA = -0.09 * log10(1 + fcGHz) + 0.746;
801 table3gpp->m_uLgZSD = 1.08;
802 table3gpp->m_sigLgZSD = 0.36;
803 table3gpp->m_offsetZOD = 0;
804 table3gpp->m_cDS = 3.91e-9;
805 table3gpp->m_cASD = 5;
806 table3gpp->m_cASA = 11;
807 table3gpp->m_cZSA = 9;
809 table3gpp->m_sigK = 0;
810 table3gpp->m_rTau = 3;
811 table3gpp->m_uXpr = 10;
812 table3gpp->m_sigXpr = 4;
813 table3gpp->m_perClusterShadowingStd = 3;
815 for (uint8_t row = 0; row < 6; row++)
817 for (uint8_t column = 0; column < 6; column++)
826 if (channelCondition->IsLos())
830 table3gpp->m_numOfCluster = 12;
831 table3gpp->m_raysPerCluster = 20;
832 table3gpp->m_uLgDS = -0.2 * log10(1 + fcGHz) - 7.5;
833 table3gpp->m_sigLgDS = 0.1;
834 table3gpp->m_uLgASD = -0.1 * log10(1 + fcGHz) + 1.6;
835 table3gpp->m_sigLgASD = 0.1;
836 table3gpp->m_uLgASA = -0.1 * log10(1 + fcGHz) + 1.6;
837 table3gpp->m_sigLgASA = 0.1;
838 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
839 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
840 table3gpp->m_uLgZSD = -0.1 * log10(1 + fcGHz) + 0.73;
841 table3gpp->m_sigLgZSD = -0.04 * log10(1 + fcGHz) + 0.34;
842 table3gpp->m_offsetZOD = 0;
843 table3gpp->m_cDS = 5;
844 table3gpp->m_cASD = 17;
845 table3gpp->m_cASA = 17;
846 table3gpp->m_cZSA = 7;
847 table3gpp->m_uK = 3.48;
848 table3gpp->m_sigK = 2;
849 table3gpp->m_rTau = 3;
850 table3gpp->m_uXpr = 9;
851 table3gpp->m_sigXpr = 3;
852 table3gpp->m_perClusterShadowingStd = 4;
854 for (uint8_t row = 0; row < 7; row++)
856 for (uint8_t column = 0; column < 7; column++)
858 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
862 else if (channelCondition->IsNlos())
864 table3gpp->m_numOfCluster = 19;
865 table3gpp->m_raysPerCluster = 20;
866 table3gpp->m_uLgDS = -0.3 * log10(1 + fcGHz) - 7;
867 table3gpp->m_sigLgDS = 0.28;
868 table3gpp->m_uLgASD = -0.08 * log10(1 + fcGHz) + 1.81;
869 table3gpp->m_sigLgASD = 0.05 * log10(1 + fcGHz) + 0.3;
870 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
871 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
872 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
873 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
874 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
875 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
876 table3gpp->m_offsetZOD = 0;
877 table3gpp->m_cDS = 11;
878 table3gpp->m_cASD = 22;
879 table3gpp->m_cASA = 22;
880 table3gpp->m_cZSA = 7;
882 table3gpp->m_sigK = 0;
883 table3gpp->m_rTau = 2.1;
884 table3gpp->m_uXpr = 8;
885 table3gpp->m_sigXpr = 3;
886 table3gpp->m_perClusterShadowingStd = 4;
888 for (uint8_t row = 0; row < 6; row++)
890 for (uint8_t column = 0; column < 6; column++)
896 else if (channelCondition->IsNlosv())
898 table3gpp->m_numOfCluster = 19;
899 table3gpp->m_raysPerCluster = 20;
900 table3gpp->m_uLgDS = -0.4 * log10(1 + fcGHz) - 7;
901 table3gpp->m_sigLgDS = 0.1;
902 table3gpp->m_uLgASD = -0.1 * log10(1 + fcGHz) + 1.7;
903 table3gpp->m_sigLgASD = 0.1;
904 table3gpp->m_uLgASA = -0.1 * log10(1 + fcGHz) + 1.7;
905 table3gpp->m_sigLgASA = 0.1;
906 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
907 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
908 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
909 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
910 table3gpp->m_offsetZOD = 0;
911 table3gpp->m_cDS = 11;
912 table3gpp->m_cASD = 22;
913 table3gpp->m_cASA = 22;
914 table3gpp->m_cZSA = 7;
916 table3gpp->m_sigK = 4.5;
917 table3gpp->m_rTau = 2.1;
918 table3gpp->m_uXpr = 8;
919 table3gpp->m_sigXpr = 3;
920 table3gpp->m_perClusterShadowingStd = 4;
922 for (uint8_t row = 0; row < 6; row++)
924 for (uint8_t column = 0; column < 6; column++)
926 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
937 if (channelCondition->IsLos())
939 table3gpp->m_numOfCluster = 12;
940 table3gpp->m_raysPerCluster = 20;
941 table3gpp->m_uLgDS = -8.3;
942 table3gpp->m_sigLgDS = 0.2;
943 table3gpp->m_uLgASD = 1.4;
944 table3gpp->m_sigLgASD = 0.1;
945 table3gpp->m_uLgASA = 1.4;
946 table3gpp->m_sigLgASA = 0.1;
947 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
948 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
949 table3gpp->m_uLgZSD = -0.1 * log10(1 + fcGHz) + 0.73;
950 table3gpp->m_sigLgZSD = -0.04 * log10(1 + fcGHz) + 0.34;
951 table3gpp->m_offsetZOD = 0;
952 table3gpp->m_cDS = 5;
953 table3gpp->m_cASD = 17;
954 table3gpp->m_cASA = 17;
955 table3gpp->m_cZSA = 7;
957 table3gpp->m_sigK = 3.5;
958 table3gpp->m_rTau = 3;
959 table3gpp->m_uXpr = 9;
960 table3gpp->m_sigXpr = 3;
961 table3gpp->m_perClusterShadowingStd = 4;
963 for (uint8_t row = 0; row < 7; row++)
965 for (uint8_t column = 0; column < 7; column++)
967 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
971 else if (channelCondition->IsNlosv())
973 table3gpp->m_numOfCluster = 19;
974 table3gpp->m_raysPerCluster = 20;
975 table3gpp->m_uLgDS = -8.3;
976 table3gpp->m_sigLgDS = 0.3;
977 table3gpp->m_uLgASD = 1.5;
978 table3gpp->m_sigLgASD = 0.1;
979 table3gpp->m_uLgASA = 1.5;
980 table3gpp->m_sigLgASA = 0.1;
981 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
982 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
983 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
984 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
985 table3gpp->m_offsetZOD = 0;
986 table3gpp->m_cDS = 11;
987 table3gpp->m_cASD = 22;
988 table3gpp->m_cASA = 22;
989 table3gpp->m_cZSA = 7;
991 table3gpp->m_sigK = 4.5;
992 table3gpp->m_rTau = 2.1;
993 table3gpp->m_uXpr = 8.0;
994 table3gpp->m_sigXpr = 3;
995 table3gpp->m_perClusterShadowingStd = 4;
997 for (uint8_t row = 0; row < 6; row++)
999 for (uint8_t column = 0; column < 6; column++)
1001 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
1005 else if (channelCondition->IsNlos())
1008 "The fast fading parameters for the NLOS condition in the Highway scenario are not "
1009 "defined in TR 37.885, use the ones defined in TDoc R1-1803671 instead");
1011 table3gpp->m_numOfCluster = 19;
1012 table3gpp->m_raysPerCluster = 20;
1013 table3gpp->m_uLgDS = -0.3 * log10(1 + fcGHz) - 7;
1014 table3gpp->m_sigLgDS = 0.28;
1015 table3gpp->m_uLgASD = -0.08 * log10(1 + fcGHz) + 1.81;
1016 table3gpp->m_sigLgASD = 0.05 * log10(1 + fcGHz) + 0.3;
1017 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
1018 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
1019 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
1020 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
1021 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
1022 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
1023 table3gpp->m_offsetZOD = 0;
1024 table3gpp->m_cDS = 11;
1025 table3gpp->m_cASD = 22;
1026 table3gpp->m_cASA = 22;
1027 table3gpp->m_cZSA = 7;
1028 table3gpp->m_uK = 0;
1029 table3gpp->m_sigK = 0;
1030 table3gpp->m_rTau = 2.1;
1031 table3gpp->m_uXpr = 8;
1032 table3gpp->m_sigXpr = 3;
1033 table3gpp->m_perClusterShadowingStd = 4;
1035 for (uint8_t row = 0; row < 6; row++)
1037 for (uint8_t column = 0; column < 6; column++)
1062 bool update =
false;
1065 if (!channelCondition->IsEqual(channelParams->m_losCondition, channelParams->m_o2iCondition))
1087 return channelParams->m_generatedTime > channelMatrix->m_generatedTime;
1099 uint64_t channelParamsKey =
1102 uint64_t channelMatrixKey =
GetKey(aAntenna->GetId(), bAntenna->GetId());
1110 bool updateParams =
false;
1111 bool updateMatrix =
false;
1112 bool notFoundParams =
false;
1113 bool notFoundMatrix =
false;
1126 notFoundParams =
true;
1129 double x = aMob->GetPosition().x - bMob->GetPosition().x;
1130 double y = aMob->GetPosition().y - bMob->GetPosition().y;
1131 double distance2D = sqrt(
x *
x + y * y);
1135 double hUt =
std::min(aMob->GetPosition().z, bMob->GetPosition().z);
1136 double hBs =
std::max(aMob->GetPosition().z, bMob->GetPosition().z);
1141 if (notFoundParams || updateParams)
1166 notFoundMatrix =
true;
1171 if (notFoundMatrix || updateMatrix)
1174 channelMatrix =
GetNewChannel(channelParams, table3gpp, aMob, bMob, aAntenna, bAntenna);
1176 std::make_pair(aAntenna->GetId(),
1184 return channelMatrix;
1193 uint64_t channelParamsKey =
1202 NS_LOG_WARN(
"Channel params map not found. Returning a nullptr.");
1217 channelParams->m_nodeIds =
1219 channelParams->m_losCondition = channelCondition->GetLosCondition();
1220 channelParams->m_o2iCondition = channelCondition->GetO2iCondition();
1225 uint8_t paramNum = 6;
1232 for (uint8_t iter = 0; iter < paramNum; iter++)
1236 for (uint8_t row = 0; row < paramNum; row++)
1239 for (uint8_t column = 0; column < paramNum; column++)
1241 temp += table3gpp->m_sqrtC[row][column] * LSPsIndep[column];
1243 LSPs.push_back(temp);
1255 kFactor = LSPs[1] * table3gpp->m_sigK + table3gpp->m_uK;
1256 DS = pow(10, LSPs[2] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1257 ASD = pow(10, LSPs[3] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1258 ASA = pow(10, LSPs[4] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1259 ZSD = pow(10, LSPs[5] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1260 ZSA = pow(10, LSPs[6] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1264 DS = pow(10, LSPs[1] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1265 ASD = pow(10, LSPs[2] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1266 ASA = pow(10, LSPs[3] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1267 ZSD = pow(10, LSPs[4] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1268 ZSA = pow(10, LSPs[5] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1276 channelParams->m_DS = DS;
1277 channelParams->m_K_factor = kFactor;
1279 NS_LOG_INFO(
"K-factor=" << kFactor <<
", DS=" << DS <<
", ASD=" << ASD <<
", ASA=" << ASA
1280 <<
", ZSD=" << ZSD <<
", ZSA=" << ZSA);
1284 double minTau = 100.0;
1285 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1292 clusterDelay.push_back(tau);
1295 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1297 clusterDelay[cIndex] -= minTau;
1299 std::sort(clusterDelay.begin(), clusterDelay.end());
1306 double powerSum = 0;
1307 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1310 exp(-1 * clusterDelay[cIndex] * (table3gpp->m_rTau - 1) / table3gpp->m_rTau / DS) *
1312 -1 *
m_normalRv->GetValue() * table3gpp->m_perClusterShadowingStd / 10.0);
1314 clusterPower.push_back(power);
1316 channelParams->m_clusterPower = clusterPower;
1318 double powerMax = 0;
1320 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1322 channelParams->m_clusterPower[cIndex] =
1323 channelParams->m_clusterPower[cIndex] / powerSum;
1330 double kLinear = pow(10, kFactor / 10.0);
1332 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1336 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1338 kLinear / (1 + kLinear));
1342 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1345 if (powerMax < clusterPowerForAngles[cIndex])
1347 powerMax = clusterPowerForAngles[cIndex];
1353 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1355 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex]);
1356 if (powerMax < clusterPowerForAngles[cIndex])
1358 powerMax = clusterPowerForAngles[cIndex];
1365 double thresh = 0.0032;
1366 for (uint8_t cIndex = table3gpp->m_numOfCluster; cIndex > 0; cIndex--)
1368 if (clusterPowerForAngles[cIndex - 1] < thresh * powerMax)
1370 clusterPowerForAngles.erase(clusterPowerForAngles.begin() + cIndex - 1);
1371 channelParams->m_clusterPower.erase(channelParams->m_clusterPower.begin() + cIndex - 1);
1372 clusterDelay.erase(clusterDelay.begin() + cIndex - 1);
1376 NS_ASSERT(channelParams->m_clusterPower.size() < UINT8_MAX);
1377 channelParams->m_reducedClusterNumber = channelParams->m_clusterPower.size();
1382 0.7705 - 0.0433 * kFactor + 2e-4 * pow(kFactor, 2) + 17e-6 * pow(kFactor, 3);
1383 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1385 clusterDelay[cIndex] = clusterDelay[cIndex] / cTau;
1394 switch (table3gpp->m_numOfCluster)
1433 double cPhi = cNlos;
1437 cPhi *= (1.1035 - 0.028 * kFactor - 2e-3 * pow(kFactor, 2) +
1438 1e-4 * pow(kFactor, 3));
1441 switch (table3gpp->m_numOfCluster)
1468 double cTheta = cNlos;
1469 if (channelCondition->IsLos())
1471 cTheta *= (1.3086 + 0.0339 * kFactor - 0.0077 * pow(kFactor, 2) +
1472 2e-4 * pow(kFactor, 3));
1479 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1481 double logCalc = -1 * log(clusterPowerForAngles[cIndex] / powerMax);
1482 double angle = 2 * sqrt(logCalc) / 1.4 / cPhi;
1483 clusterAoa.push_back(ASA * angle);
1484 clusterAod.push_back(ASD * angle);
1485 angle = logCalc / cTheta;
1486 clusterZoa.push_back(ZSA * angle);
1487 clusterZod.push_back(ZSD * angle);
1490 Angles sAngle(bMob->GetPosition(), aMob->GetPosition());
1491 Angles uAngle(aMob->GetPosition(), bMob->GetPosition());
1493 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1500 clusterAoa[cIndex] = clusterAoa[cIndex] * Xn + (
m_normalRv->GetValue() * ASA / 7.0) +
1502 clusterAod[cIndex] = clusterAod[cIndex] * Xn + (
m_normalRv->GetValue() * ASD / 7.0) +
1504 if (channelCondition->IsO2i())
1506 clusterZoa[cIndex] =
1507 clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7.0) + 90;
1511 clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7.0) +
1514 clusterZod[cIndex] = clusterZod[cIndex] * Xn + (
m_normalRv->GetValue() * ZSD / 7.0) +
1516 table3gpp->m_offsetZOD;
1528 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1530 clusterAoa[cIndex] -= diffAoa;
1531 clusterAod[cIndex] -= diffAod;
1532 clusterZoa[cIndex] -= diffZsa;
1533 clusterZod[cIndex] -= diffZsd;
1537 double sizeTemp = clusterZoa.size();
1538 for (uint8_t ind = 0; ind < 4; ind++)
1544 angleDegree = clusterAoa;
1547 angleDegree = clusterZoa;
1550 angleDegree = clusterAod;
1553 angleDegree = clusterZod;
1558 for (uint8_t nIndex = 0; nIndex < sizeTemp; nIndex++)
1560 while (angleDegree[nIndex] > 360)
1562 angleDegree[nIndex] -= 360;
1565 while (angleDegree[nIndex] < 0)
1567 angleDegree[nIndex] += 360;
1570 if (ind == 1 || ind == 3)
1572 if (angleDegree[nIndex] > 180)
1574 angleDegree[nIndex] = 360 - angleDegree[nIndex];
1581 clusterAoa = angleDegree;
1584 clusterZoa = angleDegree;
1587 clusterAod = angleDegree;
1590 clusterZod = angleDegree;
1601 for (uint8_t cInd = 0; cInd < channelParams->m_reducedClusterNumber; cInd++)
1603 channelParams->m_clusterPower[cInd] =
1604 channelParams->m_clusterPower[cInd] / pow(10, attenuationDb[cInd] / 10.0);
1609 attenuationDb.push_back(0);
1613 channelParams->m_attenuation_dB = attenuationDb;
1618 channelParams->m_reducedClusterNumber,
1622 channelParams->m_reducedClusterNumber,
1626 channelParams->m_reducedClusterNumber,
1630 channelParams->m_reducedClusterNumber,
1634 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1636 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1638 double tempAoa = clusterAoa[nInd] + table3gpp->m_cASA *
offSetAlpha[mInd];
1639 double tempZoa = clusterZoa[nInd] + table3gpp->m_cZSA *
offSetAlpha[mInd];
1640 std::tie(rayAoaRadian[nInd][mInd], rayZoaRadian[nInd][mInd]) =
1643 double tempAod = clusterAod[nInd] + table3gpp->m_cASD *
offSetAlpha[mInd];
1644 double tempZod = clusterZod[nInd] +
1645 0.375 * pow(10, table3gpp->m_uLgZSD) *
offSetAlpha[mInd];
1646 std::tie(rayAodRadian[nInd][mInd], rayZodRadian[nInd][mInd]) =
1651 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1653 Shuffle(&rayAodRadian[cIndex][0], &rayAodRadian[cIndex][table3gpp->m_raysPerCluster]);
1654 Shuffle(&rayAoaRadian[cIndex][0], &rayAoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1655 Shuffle(&rayZodRadian[cIndex][0], &rayZodRadian[cIndex][table3gpp->m_raysPerCluster]);
1656 Shuffle(&rayZoaRadian[cIndex][0], &rayZoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1660 channelParams->m_rayAodRadian = rayAodRadian;
1661 channelParams->m_rayAoaRadian = rayAoaRadian;
1662 channelParams->m_rayZodRadian = rayZodRadian;
1663 channelParams->m_rayZoaRadian = rayZoaRadian;
1670 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1675 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1677 double uXprLinear = pow(10, table3gpp->m_uXpr / 10.0);
1678 double sigXprLinear = pow(10, table3gpp->m_sigXpr / 10.0);
1681 std::pow(10, (
m_normalRv->GetValue() * sigXprLinear + uXprLinear) / 10.0));
1683 for (uint8_t pInd = 0; pInd < 4; pInd++)
1687 temp2.push_back(temp3);
1689 crossPolarizationPowerRatios.push_back(temp);
1690 clusterPhase.push_back(temp2);
1693 channelParams->m_clusterPhase = clusterPhase;
1694 channelParams->m_crossPolarizationPowerRatios = crossPolarizationPowerRatios;
1696 uint8_t cluster1st = 0;
1697 uint8_t cluster2nd = 0;
1698 double maxPower = 0;
1699 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1701 if (maxPower < channelParams->m_clusterPower[cIndex])
1703 maxPower = channelParams->m_clusterPower[cIndex];
1704 cluster1st = cIndex;
1707 channelParams->m_cluster1st = cluster1st;
1709 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1711 if (maxPower < channelParams->m_clusterPower[cIndex] && cluster1st != cIndex)
1713 maxPower = channelParams->m_clusterPower[cIndex];
1714 cluster2nd = cIndex;
1717 channelParams->m_cluster2nd = cluster2nd;
1719 NS_LOG_INFO(
"1st strongest cluster:" << +cluster1st
1720 <<
", 2nd strongest cluster:" << +cluster2nd);
1723 if (cluster1st == cluster2nd)
1725 clusterDelay.push_back(clusterDelay[cluster1st] + 1.28 * table3gpp->m_cDS);
1726 clusterDelay.push_back(clusterDelay[cluster1st] + 2.56 * table3gpp->m_cDS);
1728 clusterAoa.push_back(clusterAoa[cluster1st]);
1729 clusterAoa.push_back(clusterAoa[cluster1st]);
1731 clusterZoa.push_back(clusterZoa[cluster1st]);
1732 clusterZoa.push_back(clusterZoa[cluster1st]);
1734 clusterAod.push_back(clusterAod[cluster1st]);
1735 clusterAod.push_back(clusterAod[cluster1st]);
1737 clusterZod.push_back(clusterZod[cluster1st]);
1738 clusterZod.push_back(clusterZod[cluster1st]);
1744 if (cluster1st < cluster2nd)
1754 clusterDelay.push_back(clusterDelay[
min] + 1.28 * table3gpp->m_cDS);
1755 clusterDelay.push_back(clusterDelay[
min] + 2.56 * table3gpp->m_cDS);
1756 clusterDelay.push_back(clusterDelay[
max] + 1.28 * table3gpp->m_cDS);
1757 clusterDelay.push_back(clusterDelay[
max] + 2.56 * table3gpp->m_cDS);
1759 clusterAoa.push_back(clusterAoa[
min]);
1760 clusterAoa.push_back(clusterAoa[
min]);
1761 clusterAoa.push_back(clusterAoa[
max]);
1762 clusterAoa.push_back(clusterAoa[
max]);
1764 clusterZoa.push_back(clusterZoa[
min]);
1765 clusterZoa.push_back(clusterZoa[
min]);
1766 clusterZoa.push_back(clusterZoa[
max]);
1767 clusterZoa.push_back(clusterZoa[
max]);
1769 clusterAod.push_back(clusterAod[
min]);
1770 clusterAod.push_back(clusterAod[
min]);
1771 clusterAod.push_back(clusterAod[
max]);
1772 clusterAod.push_back(clusterAod[
max]);
1774 clusterZod.push_back(clusterZod[
min]);
1775 clusterZod.push_back(clusterZod[
min]);
1776 clusterZod.push_back(clusterZod[
max]);
1777 clusterZod.push_back(clusterZod[
max]);
1780 channelParams->m_delay = clusterDelay;
1781 channelParams->m_angle.clear();
1782 channelParams->m_angle.push_back(clusterAoa);
1783 channelParams->m_angle.push_back(clusterZoa);
1784 channelParams->m_angle.push_back(clusterAod);
1785 channelParams->m_angle.push_back(clusterZod);
1803 uint8_t updatedClusterNumber = (channelParams->m_reducedClusterNumber == 1)
1804 ? channelParams->m_reducedClusterNumber + 2
1805 : channelParams->m_reducedClusterNumber + 4;
1807 for (uint8_t cIndex = 0; cIndex < updatedClusterNumber; cIndex++)
1816 dopplerTermAlpha.push_back(alpha);
1817 dopplerTermD.push_back(D);
1819 channelParams->m_alpha = dopplerTermAlpha;
1820 channelParams->m_D = dopplerTermD;
1822 return channelParams;
1844 bool isSameDirection = (channelParams->m_nodeIds == channelMatrix->
m_nodeIds);
1855 if (isSameDirection)
1857 rayAodRadian = channelParams->m_rayAodRadian;
1858 rayAoaRadian = channelParams->m_rayAoaRadian;
1859 rayZodRadian = channelParams->m_rayZodRadian;
1860 rayZoaRadian = channelParams->m_rayZoaRadian;
1864 rayAodRadian = channelParams->m_rayAoaRadian;
1865 rayAoaRadian = channelParams->m_rayAodRadian;
1866 rayZodRadian = channelParams->m_rayZoaRadian;
1867 rayZoaRadian = channelParams->m_rayZodRadian;
1873 size_t uSize = uAntenna->GetNumElems();
1874 size_t sSize = sAntenna->GetNumElems();
1880 uint16_t numOverallCluster = (channelParams->m_cluster1st != channelParams->m_cluster2nd)
1881 ? channelParams->m_reducedClusterNumber + 4
1882 : channelParams->m_reducedClusterNumber + 2;
1884 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPhase.size());
1885 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPower.size());
1886 NS_ASSERT(channelParams->m_reducedClusterNumber <=
1887 channelParams->m_crossPolarizationPowerRatios.size());
1888 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZoaRadian.size());
1889 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZodRadian.size());
1890 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAoaRadian.size());
1891 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAodRadian.size());
1892 NS_ASSERT(table3gpp->m_raysPerCluster <= channelParams->m_clusterPhase[0].size());
1893 NS_ASSERT(table3gpp->m_raysPerCluster <=
1894 channelParams->m_crossPolarizationPowerRatios[0].size());
1895 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZoaRadian[0].size());
1896 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZodRadian[0].size());
1897 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAoaRadian[0].size());
1898 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAodRadian[0].size());
1900 double x = sMob->GetPosition().x - uMob->GetPosition().x;
1901 double y = sMob->GetPosition().y - uMob->GetPosition().y;
1902 double distance2D = sqrt(
x *
x + y * y);
1905 double hUt =
std::min(sMob->GetPosition().z, uMob->GetPosition().z);
1906 double hBs =
std::max(sMob->GetPosition().z, uMob->GetPosition().z);
1908 double distance3D = std::sqrt(distance2D * distance2D + (hBs - hUt) * (hBs - hUt));
1910 Angles sAngle(uMob->GetPosition(), sMob->GetPosition());
1911 Angles uAngle(sMob->GetPosition(), uMob->GetPosition());
1923 for (
size_t polSa = 0; polSa < sAntenna->GetNumPols(); ++polSa)
1925 for (
size_t polUa = 0; polUa < uAntenna->GetNumPols(); ++polUa)
1927 raysPreComp[std::make_pair(polSa, polUa)] =
1928 Complex2DVector(channelParams->m_reducedClusterNumber, table3gpp->m_raysPerCluster);
1933 sinCosA.resize(channelParams->m_reducedClusterNumber);
1934 sinSinA.resize(channelParams->m_reducedClusterNumber);
1935 cosZoA.resize(channelParams->m_reducedClusterNumber);
1936 sinCosD.resize(channelParams->m_reducedClusterNumber);
1937 sinSinD.resize(channelParams->m_reducedClusterNumber);
1938 cosZoD.resize(channelParams->m_reducedClusterNumber);
1939 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1941 sinCosA[nIndex].resize(table3gpp->m_raysPerCluster);
1942 sinSinA[nIndex].resize(table3gpp->m_raysPerCluster);
1943 cosZoA[nIndex].resize(table3gpp->m_raysPerCluster);
1944 sinCosD[nIndex].resize(table3gpp->m_raysPerCluster);
1945 sinSinD[nIndex].resize(table3gpp->m_raysPerCluster);
1946 cosZoD[nIndex].resize(table3gpp->m_raysPerCluster);
1949 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1951 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
1953 DoubleVector initialPhase = channelParams->m_clusterPhase[nIndex][mIndex];
1955 double k = channelParams->m_crossPolarizationPowerRatios[nIndex][mIndex];
1959 for (uint8_t polUa = 0; polUa < uAntenna->GetNumPols(); ++polUa)
1961 auto [rxFieldPatternPhi, rxFieldPatternTheta] = uAntenna->GetElementFieldPattern(
1962 Angles(channelParams->m_rayAoaRadian[nIndex][mIndex],
1963 channelParams->m_rayZoaRadian[nIndex][mIndex]),
1965 for (uint8_t polSa = 0; polSa < sAntenna->GetNumPols(); ++polSa)
1967 auto [txFieldPatternPhi, txFieldPatternTheta] =
1968 sAntenna->GetElementFieldPattern(
1969 Angles(channelParams->m_rayAodRadian[nIndex][mIndex],
1970 channelParams->m_rayZodRadian[nIndex][mIndex]),
1972 raysPreComp[std::make_pair(polSa, polUa)](nIndex, mIndex) =
1973 std::complex<double>(cos(initialPhase[0]), sin(initialPhase[0])) *
1974 rxFieldPatternTheta * txFieldPatternTheta +
1975 std::complex<double>(cos(initialPhase[1]), sin(initialPhase[1])) *
1976 std::sqrt(1.0 /
k) * rxFieldPatternTheta * txFieldPatternPhi +
1977 std::complex<double>(cos(initialPhase[2]), sin(initialPhase[2])) *
1978 std::sqrt(1.0 /
k) * rxFieldPatternPhi * txFieldPatternTheta +
1979 std::complex<double>(cos(initialPhase[3]), sin(initialPhase[3])) *
1980 rxFieldPatternPhi * txFieldPatternPhi;
1986 double sinRayZoa = sin(rayZoaRadian[nIndex][mIndex]);
1987 double sinRayAoa = sin(rayAoaRadian[nIndex][mIndex]);
1988 double cosRayAoa = cos(rayAoaRadian[nIndex][mIndex]);
1989 sinCosA[nIndex][mIndex] = sinRayZoa * cosRayAoa;
1990 sinSinA[nIndex][mIndex] = sinRayZoa * sinRayAoa;
1991 cosZoA[nIndex][mIndex] = cos(rayZoaRadian[nIndex][mIndex]);
1995 double sinRayZod = sin(rayZodRadian[nIndex][mIndex]);
1996 double sinRayAod = sin(rayAodRadian[nIndex][mIndex]);
1997 double cosRayAod = cos(rayAodRadian[nIndex][mIndex]);
1998 sinCosD[nIndex][mIndex] = sinRayZod * cosRayAod;
1999 sinSinD[nIndex][mIndex] = sinRayZod * sinRayAod;
2000 cosZoD[nIndex][mIndex] = cos(rayZodRadian[nIndex][mIndex]);
2006 uint8_t numSubClustersAdded = 0;
2007 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
2009 for (
size_t uIndex = 0; uIndex < uSize; uIndex++)
2011 Vector uLoc = uAntenna->GetElementLocation(uIndex);
2013 for (
size_t sIndex = 0; sIndex < sSize; sIndex++)
2015 Vector sLoc = sAntenna->GetElementLocation(sIndex);
2018 if (nIndex != channelParams->m_cluster1st && nIndex != channelParams->m_cluster2nd)
2020 std::complex<double> rays(0, 0);
2021 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
2024 double rxPhaseDiff =
2026 (sinCosA[nIndex][mIndex] * uLoc.x + sinSinA[nIndex][mIndex] * uLoc.y +
2027 cosZoA[nIndex][mIndex] * uLoc.z);
2029 double txPhaseDiff =
2031 (sinCosD[nIndex][mIndex] * sLoc.x + sinSinD[nIndex][mIndex] * sLoc.y +
2032 cosZoD[nIndex][mIndex] * sLoc.z);
2035 rays += raysPreComp[std::make_pair(sAntenna->GetElemPol(sIndex),
2036 uAntenna->GetElemPol(uIndex))](nIndex,
2038 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2039 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2042 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2043 hUsn(uIndex, sIndex, nIndex) = rays;
2047 std::complex<double> raysSub1(0, 0);
2048 std::complex<double> raysSub2(0, 0);
2049 std::complex<double> raysSub3(0, 0);
2051 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
2055 double rxPhaseDiff =
2057 (sinCosA[nIndex][mIndex] * uLoc.x + sinSinA[nIndex][mIndex] * uLoc.y +
2058 cosZoA[nIndex][mIndex] * uLoc.z);
2060 double txPhaseDiff =
2062 (sinCosD[nIndex][mIndex] * sLoc.x + sinSinD[nIndex][mIndex] * sLoc.y +
2063 cosZoD[nIndex][mIndex] * sLoc.z);
2065 std::complex<double> raySub =
2066 raysPreComp[std::make_pair(sAntenna->GetElemPol(sIndex),
2067 uAntenna->GetElemPol(uIndex))](nIndex,
2069 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2070 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2094 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2096 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2098 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2099 hUsn(uIndex, sIndex, nIndex) = raysSub1;
2102 channelParams->m_reducedClusterNumber + numSubClustersAdded) = raysSub2;
2105 channelParams->m_reducedClusterNumber + numSubClustersAdded + 1) =
2110 if (nIndex == channelParams->m_cluster1st || nIndex == channelParams->m_cluster2nd)
2112 numSubClustersAdded += 2;
2119 std::complex<double> phaseDiffDueToDistance(cos(-2 * M_PI * distance3D / lambda),
2120 sin(-2 * M_PI * distance3D / lambda));
2124 const double sinUAngleAz = sin(uAngle.
GetAzimuth());
2125 const double cosUAngleAz = cos(uAngle.
GetAzimuth());
2128 const double sinSAngleAz = sin(sAngle.
GetAzimuth());
2129 const double cosSAngleAz = cos(sAngle.
GetAzimuth());
2131 for (
size_t uIndex = 0; uIndex < uSize; uIndex++)
2133 Vector uLoc = uAntenna->GetElementLocation(uIndex);
2134 double rxPhaseDiff = 2 * M_PI *
2135 (sinUAngleIncl * cosUAngleAz * uLoc.x +
2136 sinUAngleIncl * sinUAngleAz * uLoc.y + cosUAngleIncl * uLoc.z);
2138 for (
size_t sIndex = 0; sIndex < sSize; sIndex++)
2140 Vector sLoc = sAntenna->GetElementLocation(sIndex);
2141 std::complex<double> ray(0, 0);
2142 double txPhaseDiff =
2144 (sinSAngleIncl * cosSAngleAz * sLoc.x + sinSAngleIncl * sinSAngleAz * sLoc.y +
2145 cosSAngleIncl * sLoc.z);
2147 auto [rxFieldPatternPhi, rxFieldPatternTheta] = uAntenna->GetElementFieldPattern(
2149 uAntenna->GetElemPol(uIndex));
2150 auto [txFieldPatternPhi, txFieldPatternTheta] = sAntenna->GetElementFieldPattern(
2152 sAntenna->GetElemPol(sIndex));
2154 ray = (rxFieldPatternTheta * txFieldPatternTheta -
2155 rxFieldPatternPhi * txFieldPatternPhi) *
2156 phaseDiffDueToDistance *
2157 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2158 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2160 double kLinear = pow(10, channelParams->m_K_factor / 10.0);
2162 hUsn(uIndex, sIndex, 0) =
2163 sqrt(1.0 / (kLinear + 1)) * hUsn(uIndex, sIndex, 0) +
2164 sqrt(kLinear / (1 + kLinear)) * ray /
2166 channelParams->m_attenuation_dB[0] / 10.0);
2167 for (
size_t nIndex = 1; nIndex < hUsn.GetNumPages(); nIndex++)
2169 hUsn(uIndex, sIndex, nIndex) *=
2170 sqrt(1.0 / (kLinear + 1));
2176 NS_LOG_DEBUG(
"Husn (sAntenna, uAntenna):" << sAntenna->GetId() <<
", " << uAntenna->GetId());
2177 for (
size_t cIndex = 0; cIndex < hUsn.GetNumPages(); cIndex++)
2179 for (
size_t rowIdx = 0; rowIdx < hUsn.GetNumRows(); rowIdx++)
2181 for (
size_t colIdx = 0; colIdx < hUsn.GetNumCols(); colIdx++)
2183 NS_LOG_DEBUG(
" " << hUsn(rowIdx, colIdx, cIndex) <<
",");
2188 NS_LOG_INFO(
"size of coefficient matrix (rows, columns, clusters) = ("
2189 << hUsn.GetNumRows() <<
", " << hUsn.GetNumCols() <<
", " << hUsn.GetNumPages()
2192 return channelMatrix;
2195 std::pair<double, double>
2198 inclinationRad =
WrapTo2Pi(inclinationRad);
2199 if (inclinationRad > M_PI)
2202 inclinationRad -= M_PI;
2208 NS_ASSERT_MSG(0 <= inclinationRad && inclinationRad <= M_PI,
2209 "inclinationRad=" << inclinationRad <<
" not valid, should be in [0, pi]");
2211 "azimuthRad=" << azimuthRad <<
" not valid, should be in [0, 2*pi]");
2213 return std::make_pair(azimuthRad, inclinationRad);
2224 auto clusterNum = clusterAOA.size();
2237 double thetaSb = 110;
2248 if (channelParams->m_nonSelfBlocking.empty())
2259 table.push_back(90);
2266 table.push_back(90);
2268 table.push_back(10);
2270 channelParams->m_nonSelfBlocking.push_back(table);
2275 double deltaX = sqrt(pow(channelParams->m_preLocUT.x - channelParams->m_locUT.x, 2) +
2276 pow(channelParams->m_preLocUT.y - channelParams->m_locUT.y, 2));
2303 R = exp(-1 * (deltaX / corrDis +
2304 (
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()) /
2309 R = exp(-1 * (deltaX / corrDis));
2314 <<
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()
2315 <<
" correlation:" << R);
2325 if (R * R * (-0.069) + R * 1.074 - 0.002 <
2328 R = R * R * (-0.069) + R * 1.074 - 0.002;
2333 channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] =
2334 R * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] +
2341 for (std::size_t cInd = 0; cInd < clusterNum; cInd++)
2343 NS_ASSERT_MSG(clusterAOA[cInd] >= 0 && clusterAOA[cInd] <= 360,
2344 "the AOA should be the range of [0,360]");
2345 NS_ASSERT_MSG(clusterZOA[cInd] >= 0 && clusterZOA[cInd] <= 180,
2346 "the ZOA should be the range of [0,180]");
2349 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiSb - xSb / 2.0 <<
","
2350 << phiSb + xSb / 2.0 <<
"]");
2351 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaSb - ySb / 2.0 <<
","
2352 << thetaSb + ySb / 2.0 <<
"]");
2353 if (std::abs(clusterAOA[cInd] - phiSb) < (xSb / 2.0) &&
2354 std::abs(clusterZOA[cInd] - thetaSb) < (ySb / 2.0))
2356 powerAttenuation[cInd] += 30;
2358 <<
"] is blocked by self blocking region and reduce 30 dB power,"
2359 "the attenuation is ["
2360 << powerAttenuation[cInd] <<
" dB]");
2368 (0.5 * erfc(-1 * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] / sqrt(2))) *
2380 double xK = channelParams->m_nonSelfBlocking[blockInd][
X_INDEX];
2381 double thetaK = channelParams->m_nonSelfBlocking[blockInd][
THETA_INDEX];
2382 double yK = channelParams->m_nonSelfBlocking[blockInd][
Y_INDEX];
2384 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiK - xK <<
","
2385 << phiK + xK <<
"]");
2386 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaK - yK <<
","
2387 << thetaK + yK <<
"]");
2389 if (std::abs(clusterAOA[cInd] - phiK) < (xK) &&
2390 std::abs(clusterZOA[cInd] - thetaK) < (yK))
2392 double A1 = clusterAOA[cInd] - (phiK + xK / 2.0);
2393 double A2 = clusterAOA[cInd] - (phiK - xK / 2.0);
2394 double Z1 = clusterZOA[cInd] - (thetaK + yK / 2.0);
2395 double Z2 = clusterZOA[cInd] - (thetaK - yK / 2.0);
2402 if (xK / 2.0 < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= xK)
2410 if (-1 * xK < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= -1 * xK / 2.0)
2419 if (yK / 2.0 < clusterZOA[cInd] - thetaK && clusterZOA[cInd] - thetaK <= yK)
2427 if (-1 * yK < clusterZOA[cInd] - thetaK &&
2428 clusterZOA[cInd] - thetaK <= -1 * yK / 2.0)
2438 atan(signA1 * M_PI / 2.0 *
2439 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2443 atan(signA2 * M_PI / 2.0 *
2444 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2448 atan(signZ1 * M_PI / 2.0 *
2449 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2453 atan(signZ2 * M_PI / 2.0 *
2454 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2457 double lDb = -20 * log10(1 - (fA1 + fA2) * (fZ1 + fZ2));
2458 powerAttenuation[cInd] += lDb;
2459 NS_LOG_INFO(
"Cluster[" << +cInd <<
"] is blocked by no-self blocking, the loss is ["
2464 return powerAttenuation;
2470 for (
auto i = (last -
first) - 1; i > 0; --i)
double f(double x, void *params)
Class holding the azimuth and inclination angles of spherical coordinates.
double GetInclination() const
Getter for inclination angle.
double GetAzimuth() const
Getter for azimuth angle.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Hold a signed integer type.
MatrixArray class inherits ValArray class and provides additional interfaces to ValArray which enable...
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,...
Hold objects of type Ptr<T>.
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.
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...
#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.
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
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 ...
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
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 ...
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
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...
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
static const double sqrtC_RMa_LOS[7][7]
The square root matrix for RMa LOS, which is generated using the Cholesky decomposition according to ...
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
double DegreesToRadians(double degrees)
converts degrees to radians
void swap(UUID &uuid1, UUID &uuid2) noexcept
Ptr< const AttributeChecker > MakeStringChecker()
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
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
Complex3DVector m_channel
Channel matrix H[u][s][n].
std::pair< uint32_t, uint32_t > m_antennaPair
The first element is the ID of the antenna of the s-node (the antenna of the transmitter when the cha...
Time m_generatedTime
Generation time.
std::pair< uint32_t, uint32_t > m_nodeIds
The first element is the s-node ID (the transmitter when the channel was generated),...