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>
47 0.0447, -0.0447, 0.1413, -0.1413, 0.2492, -0.2492, 0.3715, -0.3715, 0.5129, -0.5129,
48 0.6797, -0.6797, 0.8844, -0.8844, 1.1481, -1.1481, 1.5195, -1.5195, 2.1551, -2.1551,
60 {1, 0, 0, 0, 0, 0, 0},
61 {0, 1, 0, 0, 0, 0, 0},
62 {-0.5, 0, 0.866025, 0, 0, 0, 0},
63 {0, 0, 0, 1, 0, 0, 0},
64 {0, 0, 0, 0, 1, 0, 0},
65 {0.01, 0, -0.0519615, 0.73, -0.2, 0.651383, 0},
66 {-0.17, -0.02, 0.21362, -0.14, 0.24, 0.142773, 0.909661},
80 {-0.5, 0.866025, 0, 0, 0, 0},
81 {0.6, -0.11547, 0.791623, 0, 0, 0},
83 {-0.04, -0.138564, 0.540662, -0.18, 0.809003, 0},
84 {-0.25, -0.606218, -0.240013, 0.26, -0.231685, 0.625392},
99 {0, 0, -0.7, 0.714143, 0, 0},
100 {0, 0, 0.66, -0.123225, 0.741091, 0},
101 {0, 0, 0.47, 0.152631, -0.393194, 0.775373},
113 {1, 0, 0, 0, 0, 0, 0},
114 {0, 1, 0, 0, 0, 0, 0},
115 {-0.4, -0.4, 0.824621, 0, 0, 0, 0},
116 {-0.5, 0, 0.242536, 0.83137, 0, 0, 0},
117 {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0},
118 {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0},
119 {-0.8, 0, -0.388057, -0.367926, 0.238537, -3.58949e-15, 0.130931},
133 {-0.4, 0.916515, 0, 0, 0, 0},
134 {-0.6, 0.174574, 0.78072, 0, 0, 0},
135 {0, 0.654654, 0.365963, 0.661438, 0, 0},
136 {0, -0.545545, 0.762422, 0.118114, 0.327327, 0},
137 {-0.4, -0.174574, -0.396459, 0.392138, 0.49099, 0.507445},
150 {-0.5, 0.866025, 0, 0, 0, 0},
151 {0.2, 0.57735, 0.791623, 0, 0, 0},
152 {0, 0.46188, -0.336861, 0.820482, 0, 0},
153 {0, -0.69282, 0.252646, 0.493742, 0.460857, 0},
154 {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515},
167 {1, 0, 0, 0, 0, 0, 0},
168 {0.5, 0.866025, 0, 0, 0, 0, 0},
169 {-0.4, -0.57735, 0.711805, 0, 0, 0, 0},
170 {-0.5, 0.057735, 0.468293, 0.726201, 0, 0, 0},
171 {-0.4, -0.11547, 0.805464, -0.23482, 0.350363, 0, 0},
172 {0, 0, 0, 0.688514, 0.461454, 0.559471, 0},
173 {0, 0, 0.280976, 0.231921, -0.490509, 0.11916, 0.782603},
187 {-0.7, 0.714143, 0, 0, 0, 0},
189 {-0.4, 0.168034, 0, 0.90098, 0, 0},
190 {0, -0.70014, 0.5, 0.130577, 0.4927, 0},
191 {0, 0, 0.5, 0.221981, -0.566238, 0.616522},
204 {-0.5, 0.866025, 0, 0, 0, 0},
205 {0.2, 0.57735, 0.791623, 0, 0, 0},
206 {0, 0.46188, -0.336861, 0.820482, 0, 0},
207 {0, -0.69282, 0.252646, 0.493742, 0.460857, 0},
208 {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515},
220 {1, 0, 0, 0, 0, 0, 0},
221 {0.5, 0.866025, 0, 0, 0, 0, 0},
222 {-0.8, -0.11547, 0.588784, 0, 0, 0, 0},
223 {-0.4, 0.23094, 0.520847, 0.717903, 0, 0, 0},
224 {-0.5, 0.288675, 0.73598, -0.348236, 0.0610847, 0, 0},
225 {0.2, -0.11547, 0.418943, 0.541106, 0.219905, 0.655744, 0},
226 {0.3, -0.057735, 0.73598, -0.348236, 0.0610847, -0.304997, 0.383375},
240 {-0.5, 0.866025, 0, 0, 0, 0},
241 {0, 0.46188, 0.886942, 0, 0, 0},
242 {-0.4, -0.23094, 0.120263, 0.878751, 0, 0},
243 {0, -0.311769, 0.55697, -0.249198, 0.728344, 0},
244 {0, -0.069282, 0.295397, 0.430696, 0.468462, 0.709214},
250 m_uniformRv = CreateObject<UniformRandomVariable>();
254 m_normalRv = CreateObject<NormalRandomVariable>();
281 TypeId(
"ns3::ThreeGppChannelModel")
284 .AddConstructor<ThreeGppChannelModel>()
285 .AddAttribute(
"Frequency",
286 "The operating Frequency in Hz",
290 MakeDoubleChecker<double>())
293 "The 3GPP scenario (RMa, UMa, UMi-StreetCanyon, InH-OfficeOpen, InH-OfficeMixed)",
298 .AddAttribute(
"ChannelConditionModel",
299 "Pointer to the channel condition model",
303 MakePointerChecker<ChannelConditionModel>())
304 .AddAttribute(
"UpdatePeriod",
305 "Specify the channel coherence time",
310 .AddAttribute(
"Blockage",
311 "Enable blockage model A (sec 7.6.4.1)",
315 .AddAttribute(
"NumNonselfBlocking",
316 "number of non-self-blocking regions",
319 MakeIntegerChecker<uint16_t>())
320 .AddAttribute(
"PortraitMode",
321 "true for portrait mode, false for landscape mode",
325 .AddAttribute(
"BlockerSpeed",
326 "The speed of moving blockers, the unit is m/s",
329 MakeDoubleChecker<double>())
330 .AddAttribute(
"vScatt",
331 "Maximum speed of the vehicle in the layout (see 3GPP TR 37.885 v15.3.0, "
333 "Used to compute the additional contribution for the Doppler of"
334 "delayed (reflected) paths",
337 MakeDoubleChecker<double>(0.0))
362 "Frequency should be between 0.5 and 100 GHz but is " <<
f);
377 NS_ASSERT_MSG(scenario ==
"RMa" || scenario ==
"UMa" || scenario ==
"UMi-StreetCanyon" ||
378 scenario ==
"InH-OfficeOpen" || scenario ==
"InH-OfficeMixed" ||
379 scenario ==
"V2V-Urban" || scenario ==
"V2V-Highway",
380 "Unknown scenario, choose between: RMa, UMa, UMi-StreetCanyon, "
381 "InH-OfficeOpen, InH-OfficeMixed, V2V-Urban or V2V-Highway");
396 double distance2D)
const
407 bool los = channelCondition->IsLos();
408 bool o2i = channelCondition->IsO2i();
417 table3gpp->m_numOfCluster = 11;
418 table3gpp->m_raysPerCluster = 20;
419 table3gpp->m_uLgDS = -7.49;
420 table3gpp->m_sigLgDS = 0.55;
421 table3gpp->m_uLgASD = 0.90;
422 table3gpp->m_sigLgASD = 0.38;
423 table3gpp->m_uLgASA = 1.52;
424 table3gpp->m_sigLgASA = 0.24;
425 table3gpp->m_uLgZSA = 0.47;
426 table3gpp->m_sigLgZSA = 0.40;
427 table3gpp->m_uLgZSD = 0.34;
428 table3gpp->m_sigLgZSD =
429 std::max(-1.0, -0.17 * (distance2D / 1000.0) - 0.01 * (hUT - 1.5) + 0.22);
430 table3gpp->m_offsetZOD = 0;
431 table3gpp->m_cDS = 3.91e-9;
432 table3gpp->m_cASD = 2;
433 table3gpp->m_cASA = 3;
434 table3gpp->m_cZSA = 3;
436 table3gpp->m_sigK = 4;
437 table3gpp->m_rTau = 3.8;
438 table3gpp->m_uXpr = 12;
439 table3gpp->m_sigXpr = 4;
440 table3gpp->m_perClusterShadowingStd = 3;
442 for (uint8_t row = 0; row < 7; row++)
444 for (uint8_t column = 0; column < 7; column++)
446 table3gpp->m_sqrtC[row][column] =
sqrtC_RMa_LOS[row][column];
450 else if (!los && !o2i)
452 table3gpp->m_numOfCluster = 10;
453 table3gpp->m_raysPerCluster = 20;
454 table3gpp->m_uLgDS = -7.43;
455 table3gpp->m_sigLgDS = 0.48;
456 table3gpp->m_uLgASD = 0.95;
457 table3gpp->m_sigLgASD = 0.45;
458 table3gpp->m_uLgASA = 1.52;
459 table3gpp->m_sigLgASA = 0.13;
460 table3gpp->m_uLgZSA = 0.58;
461 table3gpp->m_sigLgZSA = 0.37;
462 table3gpp->m_uLgZSD =
463 std::max(-1.0, -0.19 * (distance2D / 1000.0) - 0.01 * (hUT - 1.5) + 0.28);
464 table3gpp->m_sigLgZSD = 0.30;
465 table3gpp->m_offsetZOD = atan((35 - 3.5) / distance2D) - atan((35 - 1.5) / distance2D);
466 table3gpp->m_cDS = 3.91e-9;
467 table3gpp->m_cASD = 2;
468 table3gpp->m_cASA = 3;
469 table3gpp->m_cZSA = 3;
471 table3gpp->m_sigK = 0;
472 table3gpp->m_rTau = 1.7;
473 table3gpp->m_uXpr = 7;
474 table3gpp->m_sigXpr = 3;
475 table3gpp->m_perClusterShadowingStd = 3;
477 for (uint8_t row = 0; row < 6; row++)
479 for (uint8_t column = 0; column < 6; column++)
487 table3gpp->m_numOfCluster = 10;
488 table3gpp->m_raysPerCluster = 20;
489 table3gpp->m_uLgDS = -7.47;
490 table3gpp->m_sigLgDS = 0.24;
491 table3gpp->m_uLgASD = 0.67;
492 table3gpp->m_sigLgASD = 0.18;
493 table3gpp->m_uLgASA = 1.66;
494 table3gpp->m_sigLgASA = 0.21;
495 table3gpp->m_uLgZSA = 0.93;
496 table3gpp->m_sigLgZSA = 0.22;
497 table3gpp->m_uLgZSD =
498 std::max(-1.0, -0.19 * (distance2D / 1000.0) - 0.01 * (hUT - 1.5) + 0.28);
499 table3gpp->m_sigLgZSD = 0.30;
500 table3gpp->m_offsetZOD = atan((35 - 3.5) / distance2D) - atan((35 - 1.5) / distance2D);
501 table3gpp->m_cDS = 3.91e-9;
502 table3gpp->m_cASD = 2;
503 table3gpp->m_cASA = 3;
504 table3gpp->m_cZSA = 3;
506 table3gpp->m_sigK = 0;
507 table3gpp->m_rTau = 1.7;
508 table3gpp->m_uXpr = 7;
509 table3gpp->m_sigXpr = 3;
510 table3gpp->m_perClusterShadowingStd = 3;
512 for (uint8_t row = 0; row < 6; row++)
514 for (uint8_t column = 0; column < 6; column++)
516 table3gpp->m_sqrtC[row][column] =
sqrtC_RMa_O2I[row][column];
525 table3gpp->m_numOfCluster = 12;
526 table3gpp->m_raysPerCluster = 20;
527 table3gpp->m_uLgDS = -6.955 - 0.0963 * log10(fcGHz);
528 table3gpp->m_sigLgDS = 0.66;
529 table3gpp->m_uLgASD = 1.06 + 0.1114 * log10(fcGHz);
530 table3gpp->m_sigLgASD = 0.28;
531 table3gpp->m_uLgASA = 1.81;
532 table3gpp->m_sigLgASA = 0.20;
533 table3gpp->m_uLgZSA = 0.95;
534 table3gpp->m_sigLgZSA = 0.16;
535 table3gpp->m_uLgZSD =
536 std::max(-0.5, -2.1 * distance2D / 1000.0 - 0.01 * (hUT - 1.5) + 0.75);
537 table3gpp->m_sigLgZSD = 0.40;
538 table3gpp->m_offsetZOD = 0;
539 table3gpp->m_cDS =
std::max(0.25, -3.4084 * log10(fcGHz) + 6.5622) * 1e-9;
540 table3gpp->m_cASD = 5;
541 table3gpp->m_cASA = 11;
542 table3gpp->m_cZSA = 7;
544 table3gpp->m_sigK = 3.5;
545 table3gpp->m_rTau = 2.5;
546 table3gpp->m_uXpr = 8;
547 table3gpp->m_sigXpr = 4;
548 table3gpp->m_perClusterShadowingStd = 3;
550 for (uint8_t row = 0; row < 7; row++)
552 for (uint8_t column = 0; column < 7; column++)
554 table3gpp->m_sqrtC[row][column] =
sqrtC_UMa_LOS[row][column];
560 double uLgZSD =
std::max(-0.5, -2.1 * distance2D / 1000.0 - 0.01 * (hUT - 1.5) + 0.9);
562 double afc = 0.208 * log10(fcGHz) - 0.782;
564 double cfc = -0.13 * log10(fcGHz) + 2.03;
565 double efc = 7.66 * log10(fcGHz) - 5.96;
567 double offsetZOD = efc - std::pow(10, afc * log10(
std::max(bfc, distance2D)) + cfc);
571 table3gpp->m_numOfCluster = 20;
572 table3gpp->m_raysPerCluster = 20;
573 table3gpp->m_uLgDS = -6.28 - 0.204 * log10(fcGHz);
574 table3gpp->m_sigLgDS = 0.39;
575 table3gpp->m_uLgASD = 1.5 - 0.1144 * log10(fcGHz);
576 table3gpp->m_sigLgASD = 0.28;
577 table3gpp->m_uLgASA = 2.08 - 0.27 * log10(fcGHz);
578 table3gpp->m_sigLgASA = 0.11;
579 table3gpp->m_uLgZSA = -0.3236 * log10(fcGHz) + 1.512;
580 table3gpp->m_sigLgZSA = 0.16;
581 table3gpp->m_uLgZSD = uLgZSD;
582 table3gpp->m_sigLgZSD = 0.49;
583 table3gpp->m_offsetZOD = offsetZOD;
584 table3gpp->m_cDS =
std::max(0.25, -3.4084 * log10(fcGHz) + 6.5622) * 1e-9;
585 table3gpp->m_cASD = 2;
586 table3gpp->m_cASA = 15;
587 table3gpp->m_cZSA = 7;
589 table3gpp->m_sigK = 0;
590 table3gpp->m_rTau = 2.3;
591 table3gpp->m_uXpr = 7;
592 table3gpp->m_sigXpr = 3;
593 table3gpp->m_perClusterShadowingStd = 3;
595 for (uint8_t row = 0; row < 6; row++)
597 for (uint8_t column = 0; column < 6; column++)
605 table3gpp->m_numOfCluster = 12;
606 table3gpp->m_raysPerCluster = 20;
607 table3gpp->m_uLgDS = -6.62;
608 table3gpp->m_sigLgDS = 0.32;
609 table3gpp->m_uLgASD = 1.25;
610 table3gpp->m_sigLgASD = 0.42;
611 table3gpp->m_uLgASA = 1.76;
612 table3gpp->m_sigLgASA = 0.16;
613 table3gpp->m_uLgZSA = 1.01;
614 table3gpp->m_sigLgZSA = 0.43;
615 table3gpp->m_uLgZSD = uLgZSD;
616 table3gpp->m_sigLgZSD = 0.49;
617 table3gpp->m_offsetZOD = offsetZOD;
618 table3gpp->m_cDS = 11e-9;
619 table3gpp->m_cASD = 5;
620 table3gpp->m_cASA = 8;
621 table3gpp->m_cZSA = 3;
623 table3gpp->m_sigK = 0;
624 table3gpp->m_rTau = 2.2;
625 table3gpp->m_uXpr = 9;
626 table3gpp->m_sigXpr = 5;
627 table3gpp->m_perClusterShadowingStd = 4;
629 for (uint8_t row = 0; row < 6; row++)
631 for (uint8_t column = 0; column < 6; column++)
633 table3gpp->m_sqrtC[row][column] =
sqrtC_UMa_O2I[row][column];
643 table3gpp->m_numOfCluster = 12;
644 table3gpp->m_raysPerCluster = 20;
645 table3gpp->m_uLgDS = -0.24 * log10(1 + fcGHz) - 7.14;
646 table3gpp->m_sigLgDS = 0.38;
647 table3gpp->m_uLgASD = -0.05 * log10(1 + fcGHz) + 1.21;
648 table3gpp->m_sigLgASD = 0.41;
649 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.73;
650 table3gpp->m_sigLgASA = 0.014 * log10(1 + fcGHz) + 0.28;
651 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
652 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
653 table3gpp->m_uLgZSD =
654 std::max(-0.21, -14.8 * distance2D / 1000.0 + 0.01 * std::abs(hUT - hBS) + 0.83);
655 table3gpp->m_sigLgZSD = 0.35;
656 table3gpp->m_offsetZOD = 0;
657 table3gpp->m_cDS = 5e-9;
658 table3gpp->m_cASD = 3;
659 table3gpp->m_cASA = 17;
660 table3gpp->m_cZSA = 7;
662 table3gpp->m_sigK = 5;
663 table3gpp->m_rTau = 3;
664 table3gpp->m_uXpr = 9;
665 table3gpp->m_sigXpr = 3;
666 table3gpp->m_perClusterShadowingStd = 3;
668 for (uint8_t row = 0; row < 7; row++)
670 for (uint8_t column = 0; column < 7; column++)
672 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
679 std::max(-0.5, -3.1 * distance2D / 1000.0 + 0.01 *
std::max(hUT - hBS, 0.0) + 0.2);
680 double offsetZOD = -1 * std::pow(10, -1.5 * log10(
std::max(10.0, distance2D)) + 3.3);
683 table3gpp->m_numOfCluster = 19;
684 table3gpp->m_raysPerCluster = 20;
685 table3gpp->m_uLgDS = -0.24 * log10(1 + fcGHz) - 6.83;
686 table3gpp->m_sigLgDS = 0.16 * log10(1 + fcGHz) + 0.28;
687 table3gpp->m_uLgASD = -0.23 * log10(1 + fcGHz) + 1.53;
688 table3gpp->m_sigLgASD = 0.11 * log10(1 + fcGHz) + 0.33;
689 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
690 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
691 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
692 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
693 table3gpp->m_uLgZSD = uLgZSD;
694 table3gpp->m_sigLgZSD = 0.35;
695 table3gpp->m_offsetZOD = offsetZOD;
696 table3gpp->m_cDS = 11e-9;
697 table3gpp->m_cASD = 10;
698 table3gpp->m_cASA = 22;
699 table3gpp->m_cZSA = 7;
701 table3gpp->m_sigK = 0;
702 table3gpp->m_rTau = 2.1;
703 table3gpp->m_uXpr = 8;
704 table3gpp->m_sigXpr = 3;
705 table3gpp->m_perClusterShadowingStd = 3;
707 for (uint8_t row = 0; row < 6; row++)
709 for (uint8_t column = 0; column < 6; column++)
717 table3gpp->m_numOfCluster = 12;
718 table3gpp->m_raysPerCluster = 20;
719 table3gpp->m_uLgDS = -6.62;
720 table3gpp->m_sigLgDS = 0.32;
721 table3gpp->m_uLgASD = 1.25;
722 table3gpp->m_sigLgASD = 0.42;
723 table3gpp->m_uLgASA = 1.76;
724 table3gpp->m_sigLgASA = 0.16;
725 table3gpp->m_uLgZSA = 1.01;
726 table3gpp->m_sigLgZSA = 0.43;
727 table3gpp->m_uLgZSD = uLgZSD;
728 table3gpp->m_sigLgZSD = 0.35;
729 table3gpp->m_offsetZOD = offsetZOD;
730 table3gpp->m_cDS = 11e-9;
731 table3gpp->m_cASD = 5;
732 table3gpp->m_cASA = 8;
733 table3gpp->m_cZSA = 3;
735 table3gpp->m_sigK = 0;
736 table3gpp->m_rTau = 2.2;
737 table3gpp->m_uXpr = 9;
738 table3gpp->m_sigXpr = 5;
739 table3gpp->m_perClusterShadowingStd = 4;
741 for (uint8_t row = 0; row < 6; row++)
743 for (uint8_t column = 0; column < 6; column++)
745 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_O2I[row][column];
753 NS_ASSERT_MSG(!o2i,
"The indoor scenario does out support outdoor to indoor");
756 table3gpp->m_numOfCluster = 15;
757 table3gpp->m_raysPerCluster = 20;
758 table3gpp->m_uLgDS = -0.01 * log10(1 + fcGHz) - 7.692;
759 table3gpp->m_sigLgDS = 0.18;
760 table3gpp->m_uLgASD = 1.60;
761 table3gpp->m_sigLgASD = 0.18;
762 table3gpp->m_uLgASA = -0.19 * log10(1 + fcGHz) + 1.781;
763 table3gpp->m_sigLgASA = 0.12 * log10(1 + fcGHz) + 0.119;
764 table3gpp->m_uLgZSA = -0.26 * log10(1 + fcGHz) + 1.44;
765 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.264;
766 table3gpp->m_uLgZSD = -1.43 * log10(1 + fcGHz) + 2.228;
767 table3gpp->m_sigLgZSD = 0.13 * log10(1 + fcGHz) + 0.30;
768 table3gpp->m_offsetZOD = 0;
769 table3gpp->m_cDS = 3.91e-9;
770 table3gpp->m_cASD = 5;
771 table3gpp->m_cASA = 8;
772 table3gpp->m_cZSA = 9;
774 table3gpp->m_sigK = 4;
775 table3gpp->m_rTau = 3.6;
776 table3gpp->m_uXpr = 11;
777 table3gpp->m_sigXpr = 4;
778 table3gpp->m_perClusterShadowingStd = 6;
780 for (uint8_t row = 0; row < 7; row++)
782 for (uint8_t column = 0; column < 7; column++)
790 table3gpp->m_numOfCluster = 19;
791 table3gpp->m_raysPerCluster = 20;
792 table3gpp->m_uLgDS = -0.28 * log10(1 + fcGHz) - 7.173;
793 table3gpp->m_sigLgDS = 0.1 * log10(1 + fcGHz) + 0.055;
794 table3gpp->m_uLgASD = 1.62;
795 table3gpp->m_sigLgASD = 0.25;
796 table3gpp->m_uLgASA = -0.11 * log10(1 + fcGHz) + 1.863;
797 table3gpp->m_sigLgASA = 0.12 * log10(1 + fcGHz) + 0.059;
798 table3gpp->m_uLgZSA = -0.15 * log10(1 + fcGHz) + 1.387;
799 table3gpp->m_sigLgZSA = -0.09 * log10(1 + fcGHz) + 0.746;
800 table3gpp->m_uLgZSD = 1.08;
801 table3gpp->m_sigLgZSD = 0.36;
802 table3gpp->m_offsetZOD = 0;
803 table3gpp->m_cDS = 3.91e-9;
804 table3gpp->m_cASD = 5;
805 table3gpp->m_cASA = 11;
806 table3gpp->m_cZSA = 9;
808 table3gpp->m_sigK = 0;
809 table3gpp->m_rTau = 3;
810 table3gpp->m_uXpr = 10;
811 table3gpp->m_sigXpr = 4;
812 table3gpp->m_perClusterShadowingStd = 3;
814 for (uint8_t row = 0; row < 6; row++)
816 for (uint8_t column = 0; column < 6; column++)
825 if (channelCondition->IsLos())
829 table3gpp->m_numOfCluster = 12;
830 table3gpp->m_raysPerCluster = 20;
831 table3gpp->m_uLgDS = -0.2 * log10(1 + fcGHz) - 7.5;
832 table3gpp->m_sigLgDS = 0.1;
833 table3gpp->m_uLgASD = -0.1 * log10(1 + fcGHz) + 1.6;
834 table3gpp->m_sigLgASD = 0.1;
835 table3gpp->m_uLgASA = -0.1 * log10(1 + fcGHz) + 1.6;
836 table3gpp->m_sigLgASA = 0.1;
837 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
838 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
839 table3gpp->m_uLgZSD = -0.1 * log10(1 + fcGHz) + 0.73;
840 table3gpp->m_sigLgZSD = -0.04 * log10(1 + fcGHz) + 0.34;
841 table3gpp->m_offsetZOD = 0;
842 table3gpp->m_cDS = 5;
843 table3gpp->m_cASD = 17;
844 table3gpp->m_cASA = 17;
845 table3gpp->m_cZSA = 7;
846 table3gpp->m_uK = 3.48;
847 table3gpp->m_sigK = 2;
848 table3gpp->m_rTau = 3;
849 table3gpp->m_uXpr = 9;
850 table3gpp->m_sigXpr = 3;
851 table3gpp->m_perClusterShadowingStd = 4;
853 for (uint8_t row = 0; row < 7; row++)
855 for (uint8_t column = 0; column < 7; column++)
857 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
861 else if (channelCondition->IsNlos())
863 table3gpp->m_numOfCluster = 19;
864 table3gpp->m_raysPerCluster = 20;
865 table3gpp->m_uLgDS = -0.3 * log10(1 + fcGHz) - 7;
866 table3gpp->m_sigLgDS = 0.28;
867 table3gpp->m_uLgASD = -0.08 * log10(1 + fcGHz) + 1.81;
868 table3gpp->m_sigLgASD = 0.05 * log10(1 + fcGHz) + 0.3;
869 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
870 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
871 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
872 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
873 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
874 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
875 table3gpp->m_offsetZOD = 0;
876 table3gpp->m_cDS = 11;
877 table3gpp->m_cASD = 22;
878 table3gpp->m_cASA = 22;
879 table3gpp->m_cZSA = 7;
881 table3gpp->m_sigK = 0;
882 table3gpp->m_rTau = 2.1;
883 table3gpp->m_uXpr = 8;
884 table3gpp->m_sigXpr = 3;
885 table3gpp->m_perClusterShadowingStd = 4;
887 for (uint8_t row = 0; row < 6; row++)
889 for (uint8_t column = 0; column < 6; column++)
895 else if (channelCondition->IsNlosv())
897 table3gpp->m_numOfCluster = 19;
898 table3gpp->m_raysPerCluster = 20;
899 table3gpp->m_uLgDS = -0.4 * log10(1 + fcGHz) - 7;
900 table3gpp->m_sigLgDS = 0.1;
901 table3gpp->m_uLgASD = -0.1 * log10(1 + fcGHz) + 1.7;
902 table3gpp->m_sigLgASD = 0.1;
903 table3gpp->m_uLgASA = -0.1 * log10(1 + fcGHz) + 1.7;
904 table3gpp->m_sigLgASA = 0.1;
905 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
906 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
907 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
908 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
909 table3gpp->m_offsetZOD = 0;
910 table3gpp->m_cDS = 11;
911 table3gpp->m_cASD = 22;
912 table3gpp->m_cASA = 22;
913 table3gpp->m_cZSA = 7;
915 table3gpp->m_sigK = 4.5;
916 table3gpp->m_rTau = 2.1;
917 table3gpp->m_uXpr = 8;
918 table3gpp->m_sigXpr = 3;
919 table3gpp->m_perClusterShadowingStd = 4;
921 for (uint8_t row = 0; row < 6; row++)
923 for (uint8_t column = 0; column < 6; column++)
925 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
936 if (channelCondition->IsLos())
938 table3gpp->m_numOfCluster = 12;
939 table3gpp->m_raysPerCluster = 20;
940 table3gpp->m_uLgDS = -8.3;
941 table3gpp->m_sigLgDS = 0.2;
942 table3gpp->m_uLgASD = 1.4;
943 table3gpp->m_sigLgASD = 0.1;
944 table3gpp->m_uLgASA = 1.4;
945 table3gpp->m_sigLgASA = 0.1;
946 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
947 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
948 table3gpp->m_uLgZSD = -0.1 * log10(1 + fcGHz) + 0.73;
949 table3gpp->m_sigLgZSD = -0.04 * log10(1 + fcGHz) + 0.34;
950 table3gpp->m_offsetZOD = 0;
951 table3gpp->m_cDS = 5;
952 table3gpp->m_cASD = 17;
953 table3gpp->m_cASA = 17;
954 table3gpp->m_cZSA = 7;
956 table3gpp->m_sigK = 3.5;
957 table3gpp->m_rTau = 3;
958 table3gpp->m_uXpr = 9;
959 table3gpp->m_sigXpr = 3;
960 table3gpp->m_perClusterShadowingStd = 4;
962 for (uint8_t row = 0; row < 7; row++)
964 for (uint8_t column = 0; column < 7; column++)
966 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
970 else if (channelCondition->IsNlosv())
972 table3gpp->m_numOfCluster = 19;
973 table3gpp->m_raysPerCluster = 20;
974 table3gpp->m_uLgDS = -8.3;
975 table3gpp->m_sigLgDS = 0.3;
976 table3gpp->m_uLgASD = 1.5;
977 table3gpp->m_sigLgASD = 0.1;
978 table3gpp->m_uLgASA = 1.5;
979 table3gpp->m_sigLgASA = 0.1;
980 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
981 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
982 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
983 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
984 table3gpp->m_offsetZOD = 0;
985 table3gpp->m_cDS = 11;
986 table3gpp->m_cASD = 22;
987 table3gpp->m_cASA = 22;
988 table3gpp->m_cZSA = 7;
990 table3gpp->m_sigK = 4.5;
991 table3gpp->m_rTau = 2.1;
992 table3gpp->m_uXpr = 8.0;
993 table3gpp->m_sigXpr = 3;
994 table3gpp->m_perClusterShadowingStd = 4;
996 for (uint8_t row = 0; row < 6; row++)
998 for (uint8_t column = 0; column < 6; column++)
1000 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
1004 else if (channelCondition->IsNlos())
1007 "The fast fading parameters for the NLOS condition in the Highway scenario are not "
1008 "defined in TR 37.885, use the ones defined in TDoc R1-1803671 instead");
1010 table3gpp->m_numOfCluster = 19;
1011 table3gpp->m_raysPerCluster = 20;
1012 table3gpp->m_uLgDS = -0.3 * log10(1 + fcGHz) - 7;
1013 table3gpp->m_sigLgDS = 0.28;
1014 table3gpp->m_uLgASD = -0.08 * log10(1 + fcGHz) + 1.81;
1015 table3gpp->m_sigLgASD = 0.05 * log10(1 + fcGHz) + 0.3;
1016 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
1017 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
1018 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
1019 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
1020 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
1021 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
1022 table3gpp->m_offsetZOD = 0;
1023 table3gpp->m_cDS = 11;
1024 table3gpp->m_cASD = 22;
1025 table3gpp->m_cASA = 22;
1026 table3gpp->m_cZSA = 7;
1027 table3gpp->m_uK = 0;
1028 table3gpp->m_sigK = 0;
1029 table3gpp->m_rTau = 2.1;
1030 table3gpp->m_uXpr = 8;
1031 table3gpp->m_sigXpr = 3;
1032 table3gpp->m_perClusterShadowingStd = 4;
1034 for (uint8_t row = 0; row < 6; row++)
1036 for (uint8_t column = 0; column < 6; column++)
1061 bool update =
false;
1064 if (!channelCondition->IsEqual(channelParams->m_losCondition, channelParams->m_o2iCondition))
1086 if (channelParams->m_generatedTime > channelMatrix->m_generatedTime)
1105 uint64_t channelParamsKey =
1108 uint64_t channelMatrixKey =
GetKey(aAntenna->GetId(), bAntenna->GetId());
1116 bool updateParams =
false;
1117 bool updateMatrix =
false;
1118 bool notFoundParams =
false;
1119 bool notFoundMatrix =
false;
1132 notFoundParams =
true;
1135 double x = aMob->GetPosition().x - bMob->GetPosition().x;
1136 double y = aMob->GetPosition().y - bMob->GetPosition().y;
1137 double distance2D = sqrt(
x *
x + y * y);
1141 double hUt =
std::min(aMob->GetPosition().z, bMob->GetPosition().z);
1142 double hBs =
std::max(aMob->GetPosition().z, bMob->GetPosition().z);
1147 if (notFoundParams || updateParams)
1172 notFoundMatrix =
true;
1177 if (notFoundMatrix || updateMatrix)
1180 channelMatrix =
GetNewChannel(channelParams, table3gpp, aMob, bMob, aAntenna, bAntenna);
1182 std::make_pair(aAntenna->GetId(),
1190 return channelMatrix;
1199 uint64_t channelParamsKey =
1208 NS_LOG_WARN(
"Channel params map not found. Returning a nullptr.");
1223 channelParams->m_nodeIds =
1225 channelParams->m_losCondition = channelCondition->GetLosCondition();
1226 channelParams->m_o2iCondition = channelCondition->GetO2iCondition();
1231 uint8_t paramNum = 6;
1238 for (uint8_t iter = 0; iter < paramNum; iter++)
1242 for (uint8_t row = 0; row < paramNum; row++)
1245 for (uint8_t column = 0; column < paramNum; column++)
1247 temp += table3gpp->m_sqrtC[row][column] * LSPsIndep[column];
1249 LSPs.push_back(temp);
1261 kFactor = LSPs[1] * table3gpp->m_sigK + table3gpp->m_uK;
1262 DS = pow(10, LSPs[2] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1263 ASD = pow(10, LSPs[3] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1264 ASA = pow(10, LSPs[4] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1265 ZSD = pow(10, LSPs[5] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1266 ZSA = pow(10, LSPs[6] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1270 DS = pow(10, LSPs[1] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1271 ASD = pow(10, LSPs[2] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1272 ASA = pow(10, LSPs[3] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1273 ZSD = pow(10, LSPs[4] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1274 ZSA = pow(10, LSPs[5] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1282 channelParams->m_DS = DS;
1283 channelParams->m_K_factor = kFactor;
1285 NS_LOG_INFO(
"K-factor=" << kFactor <<
", DS=" << DS <<
", ASD=" << ASD <<
", ASA=" << ASA
1286 <<
", ZSD=" << ZSD <<
", ZSA=" << ZSA);
1290 double minTau = 100.0;
1291 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1298 clusterDelay.push_back(tau);
1301 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1303 clusterDelay[cIndex] -= minTau;
1305 std::sort(clusterDelay.begin(), clusterDelay.end());
1312 double powerSum = 0;
1313 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1316 exp(-1 * clusterDelay[cIndex] * (table3gpp->m_rTau - 1) / table3gpp->m_rTau / DS) *
1318 -1 *
m_normalRv->GetValue() * table3gpp->m_perClusterShadowingStd / 10.0);
1320 clusterPower.push_back(power);
1322 channelParams->m_clusterPower = clusterPower;
1324 double powerMax = 0;
1326 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1328 channelParams->m_clusterPower[cIndex] =
1329 channelParams->m_clusterPower[cIndex] / powerSum;
1336 double kLinear = pow(10, kFactor / 10.0);
1338 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1342 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1344 kLinear / (1 + kLinear));
1348 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1351 if (powerMax < clusterPowerForAngles[cIndex])
1353 powerMax = clusterPowerForAngles[cIndex];
1359 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1361 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex]);
1362 if (powerMax < clusterPowerForAngles[cIndex])
1364 powerMax = clusterPowerForAngles[cIndex];
1371 double thresh = 0.0032;
1372 for (uint8_t cIndex = table3gpp->m_numOfCluster; cIndex > 0; cIndex--)
1374 if (clusterPowerForAngles[cIndex - 1] < thresh * powerMax)
1376 clusterPowerForAngles.erase(clusterPowerForAngles.begin() + cIndex - 1);
1377 channelParams->m_clusterPower.erase(channelParams->m_clusterPower.begin() + cIndex - 1);
1378 clusterDelay.erase(clusterDelay.begin() + cIndex - 1);
1382 NS_ASSERT(channelParams->m_clusterPower.size() < UINT8_MAX);
1383 channelParams->m_reducedClusterNumber = channelParams->m_clusterPower.size();
1388 0.7705 - 0.0433 * kFactor + 2e-4 * pow(kFactor, 2) + 17e-6 * pow(kFactor, 3);
1389 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1391 clusterDelay[cIndex] = clusterDelay[cIndex] / cTau;
1400 switch (table3gpp->m_numOfCluster)
1439 double cPhi = cNlos;
1443 cPhi *= (1.1035 - 0.028 * kFactor - 2e-3 * pow(kFactor, 2) +
1444 1e-4 * pow(kFactor, 3));
1447 switch (table3gpp->m_numOfCluster)
1474 double cTheta = cNlos;
1475 if (channelCondition->IsLos())
1477 cTheta *= (1.3086 + 0.0339 * kFactor - 0.0077 * pow(kFactor, 2) +
1478 2e-4 * pow(kFactor, 3));
1485 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1487 double logCalc = -1 * log(clusterPowerForAngles[cIndex] / powerMax);
1488 double angle = 2 * sqrt(logCalc) / 1.4 / cPhi;
1489 clusterAoa.push_back(ASA * angle);
1490 clusterAod.push_back(ASD * angle);
1491 angle = logCalc / cTheta;
1492 clusterZoa.push_back(ZSA * angle);
1493 clusterZod.push_back(ZSD * angle);
1496 Angles sAngle(bMob->GetPosition(), aMob->GetPosition());
1497 Angles uAngle(aMob->GetPosition(), bMob->GetPosition());
1499 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1506 clusterAoa[cIndex] = clusterAoa[cIndex] * Xn + (
m_normalRv->GetValue() * ASA / 7.0) +
1508 clusterAod[cIndex] = clusterAod[cIndex] * Xn + (
m_normalRv->GetValue() * ASD / 7.0) +
1510 if (channelCondition->IsO2i())
1512 clusterZoa[cIndex] =
1513 clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7.0) + 90;
1517 clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7.0) +
1520 clusterZod[cIndex] = clusterZod[cIndex] * Xn + (
m_normalRv->GetValue() * ZSD / 7.0) +
1522 table3gpp->m_offsetZOD;
1534 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1536 clusterAoa[cIndex] -= diffAoa;
1537 clusterAod[cIndex] -= diffAod;
1538 clusterZoa[cIndex] -= diffZsa;
1539 clusterZod[cIndex] -= diffZsd;
1543 double sizeTemp = clusterZoa.size();
1544 for (uint8_t ind = 0; ind < 4; ind++)
1550 angleDegree = clusterAoa;
1553 angleDegree = clusterZoa;
1556 angleDegree = clusterAod;
1559 angleDegree = clusterZod;
1564 for (uint8_t nIndex = 0; nIndex < sizeTemp; nIndex++)
1566 while (angleDegree[nIndex] > 360)
1568 angleDegree[nIndex] -= 360;
1571 while (angleDegree[nIndex] < 0)
1573 angleDegree[nIndex] += 360;
1576 if (ind == 1 || ind == 3)
1578 if (angleDegree[nIndex] > 180)
1580 angleDegree[nIndex] = 360 - angleDegree[nIndex];
1587 clusterAoa = angleDegree;
1590 clusterZoa = angleDegree;
1593 clusterAod = angleDegree;
1596 clusterZod = angleDegree;
1607 for (uint8_t cInd = 0; cInd < channelParams->m_reducedClusterNumber; cInd++)
1609 channelParams->m_clusterPower[cInd] =
1610 channelParams->m_clusterPower[cInd] / pow(10, attenuationDb[cInd] / 10.0);
1615 attenuationDb.push_back(0);
1619 channelParams->m_attenuation_dB = attenuationDb;
1624 channelParams->m_reducedClusterNumber,
1628 channelParams->m_reducedClusterNumber,
1632 channelParams->m_reducedClusterNumber,
1636 channelParams->m_reducedClusterNumber,
1640 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1642 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1644 double tempAoa = clusterAoa[nInd] + table3gpp->m_cASA *
offSetAlpha[mInd];
1645 double tempZoa = clusterZoa[nInd] + table3gpp->m_cZSA *
offSetAlpha[mInd];
1646 std::tie(rayAoaRadian[nInd][mInd], rayZoaRadian[nInd][mInd]) =
1649 double tempAod = clusterAod[nInd] + table3gpp->m_cASD *
offSetAlpha[mInd];
1650 double tempZod = clusterZod[nInd] +
1651 0.375 * pow(10, table3gpp->m_uLgZSD) *
offSetAlpha[mInd];
1652 std::tie(rayAodRadian[nInd][mInd], rayZodRadian[nInd][mInd]) =
1657 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1659 Shuffle(&rayAodRadian[cIndex][0], &rayAodRadian[cIndex][table3gpp->m_raysPerCluster]);
1660 Shuffle(&rayAoaRadian[cIndex][0], &rayAoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1661 Shuffle(&rayZodRadian[cIndex][0], &rayZodRadian[cIndex][table3gpp->m_raysPerCluster]);
1662 Shuffle(&rayZoaRadian[cIndex][0], &rayZoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1666 channelParams->m_rayAodRadian = rayAodRadian;
1667 channelParams->m_rayAoaRadian = rayAoaRadian;
1668 channelParams->m_rayZodRadian = rayZodRadian;
1669 channelParams->m_rayZoaRadian = rayZoaRadian;
1676 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1681 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1683 double uXprLinear = pow(10, table3gpp->m_uXpr / 10.0);
1684 double sigXprLinear = pow(10, table3gpp->m_sigXpr / 10.0);
1687 std::pow(10, (
m_normalRv->GetValue() * sigXprLinear + uXprLinear) / 10.0));
1689 for (uint8_t pInd = 0; pInd < 4; pInd++)
1693 temp2.push_back(temp3);
1695 crossPolarizationPowerRatios.push_back(temp);
1696 clusterPhase.push_back(temp2);
1699 channelParams->m_clusterPhase = clusterPhase;
1700 channelParams->m_crossPolarizationPowerRatios = crossPolarizationPowerRatios;
1702 uint8_t cluster1st = 0;
1703 uint8_t cluster2nd = 0;
1704 double maxPower = 0;
1705 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1707 if (maxPower < channelParams->m_clusterPower[cIndex])
1709 maxPower = channelParams->m_clusterPower[cIndex];
1710 cluster1st = cIndex;
1713 channelParams->m_cluster1st = cluster1st;
1715 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1717 if (maxPower < channelParams->m_clusterPower[cIndex] && cluster1st != cIndex)
1719 maxPower = channelParams->m_clusterPower[cIndex];
1720 cluster2nd = cIndex;
1723 channelParams->m_cluster2nd = cluster2nd;
1725 NS_LOG_INFO(
"1st strongest cluster:" << +cluster1st
1726 <<
", 2nd strongest cluster:" << +cluster2nd);
1729 if (cluster1st == cluster2nd)
1731 clusterDelay.push_back(clusterDelay[cluster1st] + 1.28 * table3gpp->m_cDS);
1732 clusterDelay.push_back(clusterDelay[cluster1st] + 2.56 * table3gpp->m_cDS);
1734 clusterAoa.push_back(clusterAoa[cluster1st]);
1735 clusterAoa.push_back(clusterAoa[cluster1st]);
1737 clusterZoa.push_back(clusterZoa[cluster1st]);
1738 clusterZoa.push_back(clusterZoa[cluster1st]);
1740 clusterAod.push_back(clusterAod[cluster1st]);
1741 clusterAod.push_back(clusterAod[cluster1st]);
1743 clusterZod.push_back(clusterZod[cluster1st]);
1744 clusterZod.push_back(clusterZod[cluster1st]);
1750 if (cluster1st < cluster2nd)
1760 clusterDelay.push_back(clusterDelay[
min] + 1.28 * table3gpp->m_cDS);
1761 clusterDelay.push_back(clusterDelay[
min] + 2.56 * table3gpp->m_cDS);
1762 clusterDelay.push_back(clusterDelay[
max] + 1.28 * table3gpp->m_cDS);
1763 clusterDelay.push_back(clusterDelay[
max] + 2.56 * table3gpp->m_cDS);
1765 clusterAoa.push_back(clusterAoa[
min]);
1766 clusterAoa.push_back(clusterAoa[
min]);
1767 clusterAoa.push_back(clusterAoa[
max]);
1768 clusterAoa.push_back(clusterAoa[
max]);
1770 clusterZoa.push_back(clusterZoa[
min]);
1771 clusterZoa.push_back(clusterZoa[
min]);
1772 clusterZoa.push_back(clusterZoa[
max]);
1773 clusterZoa.push_back(clusterZoa[
max]);
1775 clusterAod.push_back(clusterAod[
min]);
1776 clusterAod.push_back(clusterAod[
min]);
1777 clusterAod.push_back(clusterAod[
max]);
1778 clusterAod.push_back(clusterAod[
max]);
1780 clusterZod.push_back(clusterZod[
min]);
1781 clusterZod.push_back(clusterZod[
min]);
1782 clusterZod.push_back(clusterZod[
max]);
1783 clusterZod.push_back(clusterZod[
max]);
1786 channelParams->m_delay = clusterDelay;
1787 channelParams->m_angle.clear();
1788 channelParams->m_angle.push_back(clusterAoa);
1789 channelParams->m_angle.push_back(clusterZoa);
1790 channelParams->m_angle.push_back(clusterAod);
1791 channelParams->m_angle.push_back(clusterZod);
1809 uint8_t updatedClusterNumber = (channelParams->m_reducedClusterNumber == 1)
1810 ? channelParams->m_reducedClusterNumber + 2
1811 : channelParams->m_reducedClusterNumber + 4;
1813 for (uint8_t cIndex = 0; cIndex < updatedClusterNumber; cIndex++)
1822 dopplerTermAlpha.push_back(alpha);
1823 dopplerTermD.push_back(D);
1825 channelParams->m_alpha = dopplerTermAlpha;
1826 channelParams->m_D = dopplerTermD;
1828 return channelParams;
1850 bool isSameDirection = (channelParams->m_nodeIds == channelMatrix->
m_nodeIds);
1861 if (isSameDirection)
1863 rayAodRadian = channelParams->m_rayAodRadian;
1864 rayAoaRadian = channelParams->m_rayAoaRadian;
1865 rayZodRadian = channelParams->m_rayZodRadian;
1866 rayZoaRadian = channelParams->m_rayZoaRadian;
1870 rayAodRadian = channelParams->m_rayAoaRadian;
1871 rayAoaRadian = channelParams->m_rayAodRadian;
1872 rayZodRadian = channelParams->m_rayZoaRadian;
1873 rayZoaRadian = channelParams->m_rayZodRadian;
1879 size_t uSize = uAntenna->GetNumberOfElements();
1880 size_t sSize = sAntenna->GetNumberOfElements();
1886 uint16_t numOverallCluster = (channelParams->m_cluster1st != channelParams->m_cluster2nd)
1887 ? channelParams->m_reducedClusterNumber + 4
1888 : channelParams->m_reducedClusterNumber + 2;
1890 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPhase.size());
1891 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPower.size());
1892 NS_ASSERT(channelParams->m_reducedClusterNumber <=
1893 channelParams->m_crossPolarizationPowerRatios.size());
1894 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZoaRadian.size());
1895 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZodRadian.size());
1896 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAoaRadian.size());
1897 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAodRadian.size());
1898 NS_ASSERT(table3gpp->m_raysPerCluster <= channelParams->m_clusterPhase[0].size());
1899 NS_ASSERT(table3gpp->m_raysPerCluster <=
1900 channelParams->m_crossPolarizationPowerRatios[0].size());
1901 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZoaRadian[0].size());
1902 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZodRadian[0].size());
1903 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAoaRadian[0].size());
1904 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAodRadian[0].size());
1906 double x = sMob->GetPosition().x - uMob->GetPosition().x;
1907 double y = sMob->GetPosition().y - uMob->GetPosition().y;
1908 double distance2D = sqrt(
x *
x + y * y);
1911 double hUt =
std::min(sMob->GetPosition().z, uMob->GetPosition().z);
1912 double hBs =
std::max(sMob->GetPosition().z, uMob->GetPosition().z);
1914 double distance3D = std::sqrt(distance2D * distance2D + (hBs - hUt) * (hBs - hUt));
1916 Angles sAngle(uMob->GetPosition(), sMob->GetPosition());
1917 Angles uAngle(sMob->GetPosition(), uMob->GetPosition());
1920 table3gpp->m_raysPerCluster);
1930 sinCosA.resize(channelParams->m_reducedClusterNumber);
1931 sinSinA.resize(channelParams->m_reducedClusterNumber);
1932 cosZoA.resize(channelParams->m_reducedClusterNumber);
1933 sinCosD.resize(channelParams->m_reducedClusterNumber);
1934 sinSinD.resize(channelParams->m_reducedClusterNumber);
1935 cosZoD.resize(channelParams->m_reducedClusterNumber);
1936 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1938 sinCosA[nIndex].resize(table3gpp->m_raysPerCluster);
1939 sinSinA[nIndex].resize(table3gpp->m_raysPerCluster);
1940 cosZoA[nIndex].resize(table3gpp->m_raysPerCluster);
1941 sinCosD[nIndex].resize(table3gpp->m_raysPerCluster);
1942 sinSinD[nIndex].resize(table3gpp->m_raysPerCluster);
1943 cosZoD[nIndex].resize(table3gpp->m_raysPerCluster);
1946 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1948 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
1950 DoubleVector initialPhase = channelParams->m_clusterPhase[nIndex][mIndex];
1952 double k = channelParams->m_crossPolarizationPowerRatios[nIndex][mIndex];
1956 auto [rxFieldPatternPhi, rxFieldPatternTheta] = uAntenna->GetElementFieldPattern(
1957 Angles(channelParams->m_rayAoaRadian[nIndex][mIndex],
1958 channelParams->m_rayZoaRadian[nIndex][mIndex]));
1959 auto [txFieldPatternPhi, txFieldPatternTheta] = sAntenna->GetElementFieldPattern(
1960 Angles(channelParams->m_rayAodRadian[nIndex][mIndex],
1961 channelParams->m_rayZodRadian[nIndex][mIndex]));
1962 raysPreComp(nIndex, mIndex) =
1963 std::complex<double>(cos(initialPhase[0]), sin(initialPhase[0])) *
1964 rxFieldPatternTheta * txFieldPatternTheta +
1965 std::complex<double>(cos(initialPhase[1]), sin(initialPhase[1])) *
1966 std::sqrt(1.0 /
k) * rxFieldPatternTheta * txFieldPatternPhi +
1967 std::complex<double>(cos(initialPhase[2]), sin(initialPhase[2])) *
1968 std::sqrt(1.0 /
k) * rxFieldPatternPhi * txFieldPatternTheta +
1969 std::complex<double>(cos(initialPhase[3]), sin(initialPhase[3])) *
1970 rxFieldPatternPhi * txFieldPatternPhi;
1974 double sinRayZoa = sin(rayZoaRadian[nIndex][mIndex]);
1975 double sinRayAoa = cos(rayAoaRadian[nIndex][mIndex]);
1976 double cosRayAoa = cos(rayAoaRadian[nIndex][mIndex]);
1977 sinCosA[nIndex][mIndex] = sinRayZoa * cosRayAoa;
1978 sinSinA[nIndex][mIndex] = sinRayZoa * sinRayAoa;
1979 cosZoA[nIndex][mIndex] = cos(rayZoaRadian[nIndex][mIndex]);
1983 double sinRayZod = sin(rayZodRadian[nIndex][mIndex]);
1984 double sinRayAod = cos(rayAodRadian[nIndex][mIndex]);
1985 double cosRayAod = cos(rayAodRadian[nIndex][mIndex]);
1986 sinCosD[nIndex][mIndex] = sinRayZod * cosRayAod;
1987 sinSinD[nIndex][mIndex] = sinRayZod * sinRayAod;
1988 cosZoD[nIndex][mIndex] = cos(rayZodRadian[nIndex][mIndex]);
1994 uint8_t numSubClustersAdded = 0;
1995 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1997 for (
size_t uIndex = 0; uIndex < uSize; uIndex++)
1999 Vector uLoc = uAntenna->GetElementLocation(uIndex);
2001 for (
size_t sIndex = 0; sIndex < sSize; sIndex++)
2003 Vector sLoc = sAntenna->GetElementLocation(sIndex);
2006 if (nIndex != channelParams->m_cluster1st && nIndex != channelParams->m_cluster2nd)
2008 std::complex<double> rays(0, 0);
2009 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
2012 double rxPhaseDiff =
2014 (sinCosA[nIndex][mIndex] * uLoc.x + sinSinA[nIndex][mIndex] * uLoc.y +
2015 cosZoA[nIndex][mIndex] * uLoc.z);
2017 double txPhaseDiff =
2019 (sinCosD[nIndex][mIndex] * sLoc.x + sinSinD[nIndex][mIndex] * sLoc.y +
2020 cosZoD[nIndex][mIndex] * sLoc.z);
2024 rays += raysPreComp(nIndex, mIndex) *
2025 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2026 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2029 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2030 hUsn(uIndex, sIndex, nIndex) = rays;
2034 std::complex<double> raysSub1(0, 0);
2035 std::complex<double> raysSub2(0, 0);
2036 std::complex<double> raysSub3(0, 0);
2038 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
2042 double rxPhaseDiff =
2044 (sinCosA[nIndex][mIndex] * uLoc.x + sinSinA[nIndex][mIndex] * uLoc.y +
2045 cosZoA[nIndex][mIndex] * uLoc.z);
2047 double txPhaseDiff =
2049 (sinCosD[nIndex][mIndex] * sLoc.x + sinSinD[nIndex][mIndex] * sLoc.y +
2050 cosZoD[nIndex][mIndex] * sLoc.z);
2052 std::complex<double> raySub =
2053 raysPreComp(nIndex, mIndex) *
2054 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2055 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2079 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2081 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2083 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2084 hUsn(uIndex, sIndex, nIndex) = raysSub1;
2087 channelParams->m_reducedClusterNumber + numSubClustersAdded) = raysSub2;
2090 channelParams->m_reducedClusterNumber + numSubClustersAdded + 1) =
2095 if (nIndex == channelParams->m_cluster1st || nIndex == channelParams->m_cluster2nd)
2097 numSubClustersAdded += 2;
2104 std::complex<double> phaseDiffDueToDistance(cos(-2 * M_PI * distance3D / lambda),
2105 sin(-2 * M_PI * distance3D / lambda));
2109 const double sinUAngleAz = sin(uAngle.
GetAzimuth());
2110 const double cosUAngleAz = cos(uAngle.
GetAzimuth());
2113 const double sinSAngleAz = sin(sAngle.
GetAzimuth());
2114 const double cosSAngleAz = cos(sAngle.
GetAzimuth());
2116 for (
size_t uIndex = 0; uIndex < uSize; uIndex++)
2118 Vector uLoc = uAntenna->GetElementLocation(uIndex);
2119 double rxPhaseDiff = 2 * M_PI *
2120 (sinUAngleIncl * cosUAngleAz * uLoc.x +
2121 sinUAngleIncl * sinUAngleAz * uLoc.y + cosUAngleIncl * uLoc.z);
2123 for (
size_t sIndex = 0; sIndex < sSize; sIndex++)
2125 Vector sLoc = sAntenna->GetElementLocation(sIndex);
2126 std::complex<double> ray(0, 0);
2127 double txPhaseDiff =
2129 (sinSAngleIncl * cosSAngleAz * sLoc.x + sinSAngleIncl * sinSAngleAz * sLoc.y +
2130 cosSAngleIncl * sLoc.z);
2132 auto [rxFieldPatternPhi, rxFieldPatternTheta] = uAntenna->GetElementFieldPattern(
2134 auto [txFieldPatternPhi, txFieldPatternTheta] = sAntenna->GetElementFieldPattern(
2137 ray = (rxFieldPatternTheta * txFieldPatternTheta -
2138 rxFieldPatternPhi * txFieldPatternPhi) *
2139 phaseDiffDueToDistance *
2140 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2141 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2143 double kLinear = pow(10, channelParams->m_K_factor / 10.0);
2145 hUsn(uIndex, sIndex, 0) =
2146 sqrt(1.0 / (kLinear + 1)) * hUsn(uIndex, sIndex, 0) +
2147 sqrt(kLinear / (1 + kLinear)) * ray /
2149 channelParams->m_attenuation_dB[0] / 10.0);
2150 for (uint16_t nIndex = 1; nIndex < hUsn.GetNumPages(); nIndex++)
2152 hUsn(uIndex, sIndex, nIndex) *=
2153 sqrt(1.0 / (kLinear + 1));
2159 NS_LOG_DEBUG(
"Husn (sAntenna, uAntenna):" << sAntenna->GetId() <<
", " << uAntenna->GetId());
2160 for (uint16_t cIndex = 0; cIndex < hUsn.GetNumPages(); cIndex++)
2162 for (uint16_t rowIdx = 0; rowIdx < hUsn.GetNumRows(); rowIdx++)
2164 for (uint16_t colIdx = 0; colIdx < hUsn.GetNumCols(); colIdx++)
2166 NS_LOG_DEBUG(
" " << hUsn(rowIdx, colIdx, cIndex) <<
",");
2171 NS_LOG_INFO(
"size of coefficient matrix (rows, columns, clusters) = ("
2172 << hUsn.GetNumRows() <<
", " << hUsn.GetNumCols() <<
", " << hUsn.GetNumPages()
2175 return channelMatrix;
2178 std::pair<double, double>
2181 inclinationRad =
WrapTo2Pi(inclinationRad);
2182 if (inclinationRad > M_PI)
2185 inclinationRad -= M_PI;
2191 NS_ASSERT_MSG(0 <= inclinationRad && inclinationRad <= M_PI,
2192 "inclinationRad=" << inclinationRad <<
" not valid, should be in [0, pi]");
2194 "azimuthRad=" << azimuthRad <<
" not valid, should be in [0, 2*pi]");
2196 return std::make_pair(azimuthRad, inclinationRad);
2208 uint8_t clusterNum = clusterAOA.size();
2209 for (uint8_t cInd = 0; cInd < clusterNum; cInd++)
2211 powerAttenuation.push_back(0);
2221 double thetaSb = 110;
2232 if (channelParams->m_nonSelfBlocking.empty())
2243 table.push_back(90);
2250 table.push_back(90);
2252 table.push_back(10);
2254 channelParams->m_nonSelfBlocking.push_back(table);
2259 double deltaX = sqrt(pow(channelParams->m_preLocUT.x - channelParams->m_locUT.x, 2) +
2260 pow(channelParams->m_preLocUT.y - channelParams->m_locUT.y, 2));
2287 R = exp(-1 * (deltaX / corrDis +
2288 (
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()) /
2293 R = exp(-1 * (deltaX / corrDis));
2298 <<
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()
2299 <<
" correlation:" << R);
2309 if (R * R * (-0.069) + R * 1.074 - 0.002 <
2312 R = R * R * (-0.069) + R * 1.074 - 0.002;
2317 channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] =
2318 R * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] +
2325 for (uint8_t cInd = 0; cInd < clusterNum; cInd++)
2327 NS_ASSERT_MSG(clusterAOA[cInd] >= 0 && clusterAOA[cInd] <= 360,
2328 "the AOA should be the range of [0,360]");
2329 NS_ASSERT_MSG(clusterZOA[cInd] >= 0 && clusterZOA[cInd] <= 180,
2330 "the ZOA should be the range of [0,180]");
2333 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiSb - xSb / 2.0 <<
","
2334 << phiSb + xSb / 2.0 <<
"]");
2335 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaSb - ySb / 2.0 <<
","
2336 << thetaSb + ySb / 2.0 <<
"]");
2337 if (std::abs(clusterAOA[cInd] - phiSb) < (xSb / 2.0) &&
2338 std::abs(clusterZOA[cInd] - thetaSb) < (ySb / 2.0))
2340 powerAttenuation[cInd] += 30;
2342 <<
"] is blocked by self blocking region and reduce 30 dB power,"
2343 "the attenuation is ["
2344 << powerAttenuation[cInd] <<
" dB]");
2352 (0.5 * erfc(-1 * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] / sqrt(2))) *
2364 double xK = channelParams->m_nonSelfBlocking[blockInd][
X_INDEX];
2365 double thetaK = channelParams->m_nonSelfBlocking[blockInd][
THETA_INDEX];
2366 double yK = channelParams->m_nonSelfBlocking[blockInd][
Y_INDEX];
2368 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiK - xK <<
","
2369 << phiK + xK <<
"]");
2370 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaK - yK <<
","
2371 << thetaK + yK <<
"]");
2373 if (std::abs(clusterAOA[cInd] - phiK) < (xK) &&
2374 std::abs(clusterZOA[cInd] - thetaK) < (yK))
2376 double A1 = clusterAOA[cInd] - (phiK + xK / 2.0);
2377 double A2 = clusterAOA[cInd] - (phiK - xK / 2.0);
2378 double Z1 = clusterZOA[cInd] - (thetaK + yK / 2.0);
2379 double Z2 = clusterZOA[cInd] - (thetaK - yK / 2.0);
2386 if (xK / 2.0 < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= xK)
2394 if (-1 * xK < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= -1 * xK / 2.0)
2403 if (yK / 2.0 < clusterZOA[cInd] - thetaK && clusterZOA[cInd] - thetaK <= yK)
2411 if (-1 * yK < clusterZOA[cInd] - thetaK &&
2412 clusterZOA[cInd] - thetaK <= -1 * yK / 2.0)
2422 atan(signA1 * M_PI / 2.0 *
2423 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2427 atan(signA2 * M_PI / 2.0 *
2428 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2432 atan(signZ1 * M_PI / 2.0 *
2433 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2437 atan(signZ2 * M_PI / 2.0 *
2438 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2441 double lDb = -20 * log10(1 - (fA1 + fA2) * (fZ1 + fZ2));
2442 powerAttenuation[cInd] += lDb;
2443 NS_LOG_INFO(
"Cluster[" << +cInd <<
"] is blocked by no-self blocking, the loss is ["
2448 return powerAttenuation;
2454 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.
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.
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.
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.
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)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeStringChecker()
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
#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 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...
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
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
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),...