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 return channelParams->m_generatedTime > channelMatrix->m_generatedTime;
1098 uint64_t channelParamsKey =
1101 uint64_t channelMatrixKey =
GetKey(aAntenna->GetId(), bAntenna->GetId());
1109 bool updateParams =
false;
1110 bool updateMatrix =
false;
1111 bool notFoundParams =
false;
1112 bool notFoundMatrix =
false;
1125 notFoundParams =
true;
1128 double x = aMob->GetPosition().x - bMob->GetPosition().x;
1129 double y = aMob->GetPosition().y - bMob->GetPosition().y;
1130 double distance2D = sqrt(x * x + y * y);
1134 double hUt = std::min(aMob->GetPosition().z, bMob->GetPosition().z);
1135 double hBs = std::max(aMob->GetPosition().z, bMob->GetPosition().z);
1140 if (notFoundParams || updateParams)
1165 notFoundMatrix =
true;
1170 if (notFoundMatrix || updateMatrix)
1173 channelMatrix =
GetNewChannel(channelParams, table3gpp, aMob, bMob, aAntenna, bAntenna);
1174 channelMatrix->m_antennaPair =
1175 std::make_pair(aAntenna->GetId(),
1183 return channelMatrix;
1192 uint64_t channelParamsKey =
1201 NS_LOG_WARN(
"Channel params map not found. Returning a nullptr.");
1216 channelParams->m_nodeIds =
1218 channelParams->m_losCondition = channelCondition->GetLosCondition();
1219 channelParams->m_o2iCondition = channelCondition->GetO2iCondition();
1224 uint8_t paramNum = 6;
1231 for (uint8_t iter = 0; iter < paramNum; iter++)
1235 for (uint8_t row = 0; row < paramNum; row++)
1238 for (uint8_t column = 0; column < paramNum; column++)
1240 temp += table3gpp->m_sqrtC[row][column] * LSPsIndep[column];
1242 LSPs.push_back(temp);
1254 kFactor = LSPs[1] * table3gpp->m_sigK + table3gpp->m_uK;
1255 DS = pow(10, LSPs[2] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1256 ASD = pow(10, LSPs[3] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1257 ASA = pow(10, LSPs[4] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1258 ZSD = pow(10, LSPs[5] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1259 ZSA = pow(10, LSPs[6] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1263 DS = pow(10, LSPs[1] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1264 ASD = pow(10, LSPs[2] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1265 ASA = pow(10, LSPs[3] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1266 ZSD = pow(10, LSPs[4] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1267 ZSA = pow(10, LSPs[5] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1269 ASD = std::min(ASD, 104.0);
1270 ASA = std::min(ASA, 104.0);
1271 ZSD = std::min(ZSD, 52.0);
1272 ZSA = std::min(ZSA, 52.0);
1275 channelParams->m_DS = DS;
1276 channelParams->m_K_factor = kFactor;
1278 NS_LOG_INFO(
"K-factor=" << kFactor <<
", DS=" << DS <<
", ASD=" << ASD <<
", ASA=" << ASA
1279 <<
", ZSD=" << ZSD <<
", ZSA=" << ZSA);
1283 double minTau = 100.0;
1284 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1291 clusterDelay.push_back(tau);
1294 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1296 clusterDelay[cIndex] -= minTau;
1298 std::sort(clusterDelay.begin(), clusterDelay.end());
1305 double powerSum = 0;
1306 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1309 exp(-1 * clusterDelay[cIndex] * (table3gpp->m_rTau - 1) / table3gpp->m_rTau / DS) *
1311 -1 *
m_normalRv->GetValue() * table3gpp->m_perClusterShadowingStd / 10.0);
1313 clusterPower.push_back(power);
1315 channelParams->m_clusterPower = clusterPower;
1317 double powerMax = 0;
1319 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1321 channelParams->m_clusterPower[cIndex] =
1322 channelParams->m_clusterPower[cIndex] / powerSum;
1329 double kLinear = pow(10, kFactor / 10.0);
1331 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1335 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1337 kLinear / (1 + kLinear));
1341 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1344 if (powerMax < clusterPowerForAngles[cIndex])
1346 powerMax = clusterPowerForAngles[cIndex];
1352 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1354 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex]);
1355 if (powerMax < clusterPowerForAngles[cIndex])
1357 powerMax = clusterPowerForAngles[cIndex];
1364 double thresh = 0.0032;
1365 for (uint8_t cIndex = table3gpp->m_numOfCluster; cIndex > 0; cIndex--)
1367 if (clusterPowerForAngles[cIndex - 1] < thresh * powerMax)
1369 clusterPowerForAngles.erase(clusterPowerForAngles.begin() + cIndex - 1);
1370 channelParams->m_clusterPower.erase(channelParams->m_clusterPower.begin() + cIndex - 1);
1371 clusterDelay.erase(clusterDelay.begin() + cIndex - 1);
1375 NS_ASSERT(channelParams->m_clusterPower.size() < UINT8_MAX);
1376 channelParams->m_reducedClusterNumber = channelParams->m_clusterPower.size();
1381 0.7705 - 0.0433 * kFactor + 2e-4 * pow(kFactor, 2) + 17e-6 * pow(kFactor, 3);
1382 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1384 clusterDelay[cIndex] = clusterDelay[cIndex] / cTau;
1393 switch (table3gpp->m_numOfCluster)
1432 double cPhi = cNlos;
1436 cPhi *= (1.1035 - 0.028 * kFactor - 2e-3 * pow(kFactor, 2) +
1437 1e-4 * pow(kFactor, 3));
1440 switch (table3gpp->m_numOfCluster)
1467 double cTheta = cNlos;
1468 if (channelCondition->IsLos())
1470 cTheta *= (1.3086 + 0.0339 * kFactor - 0.0077 * pow(kFactor, 2) +
1471 2e-4 * pow(kFactor, 3));
1478 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1480 double logCalc = -1 * log(clusterPowerForAngles[cIndex] / powerMax);
1481 double angle = 2 * sqrt(logCalc) / 1.4 / cPhi;
1482 clusterAoa.push_back(ASA * angle);
1483 clusterAod.push_back(ASD * angle);
1484 angle = logCalc / cTheta;
1485 clusterZoa.push_back(ZSA * angle);
1486 clusterZod.push_back(ZSD * angle);
1489 Angles sAngle(bMob->GetPosition(), aMob->GetPosition());
1490 Angles uAngle(aMob->GetPosition(), bMob->GetPosition());
1492 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1499 clusterAoa[cIndex] = clusterAoa[cIndex] * Xn + (
m_normalRv->GetValue() * ASA / 7.0) +
1501 clusterAod[cIndex] = clusterAod[cIndex] * Xn + (
m_normalRv->GetValue() * ASD / 7.0) +
1503 if (channelCondition->IsO2i())
1505 clusterZoa[cIndex] =
1506 clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7.0) + 90;
1510 clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7.0) +
1513 clusterZod[cIndex] = clusterZod[cIndex] * Xn + (
m_normalRv->GetValue() * ZSD / 7.0) +
1515 table3gpp->m_offsetZOD;
1527 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1529 clusterAoa[cIndex] -= diffAoa;
1530 clusterAod[cIndex] -= diffAod;
1531 clusterZoa[cIndex] -= diffZsa;
1532 clusterZod[cIndex] -= diffZsd;
1536 double sizeTemp = clusterZoa.size();
1537 for (uint8_t ind = 0; ind < 4; ind++)
1543 angleDegree = clusterAoa;
1546 angleDegree = clusterZoa;
1549 angleDegree = clusterAod;
1552 angleDegree = clusterZod;
1557 for (uint8_t nIndex = 0; nIndex < sizeTemp; nIndex++)
1559 while (angleDegree[nIndex] > 360)
1561 angleDegree[nIndex] -= 360;
1564 while (angleDegree[nIndex] < 0)
1566 angleDegree[nIndex] += 360;
1569 if (ind == 1 || ind == 3)
1571 if (angleDegree[nIndex] > 180)
1573 angleDegree[nIndex] = 360 - angleDegree[nIndex];
1580 clusterAoa = angleDegree;
1583 clusterZoa = angleDegree;
1586 clusterAod = angleDegree;
1589 clusterZod = angleDegree;
1600 for (uint8_t cInd = 0; cInd < channelParams->m_reducedClusterNumber; cInd++)
1602 channelParams->m_clusterPower[cInd] =
1603 channelParams->m_clusterPower[cInd] / pow(10, attenuationDb[cInd] / 10.0);
1608 attenuationDb.push_back(0);
1612 channelParams->m_attenuation_dB = attenuationDb;
1617 channelParams->m_reducedClusterNumber,
1621 channelParams->m_reducedClusterNumber,
1625 channelParams->m_reducedClusterNumber,
1629 channelParams->m_reducedClusterNumber,
1633 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1635 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1637 double tempAoa = clusterAoa[nInd] + table3gpp->m_cASA *
offSetAlpha[mInd];
1638 double tempZoa = clusterZoa[nInd] + table3gpp->m_cZSA *
offSetAlpha[mInd];
1639 std::tie(rayAoaRadian[nInd][mInd], rayZoaRadian[nInd][mInd]) =
1642 double tempAod = clusterAod[nInd] + table3gpp->m_cASD *
offSetAlpha[mInd];
1643 double tempZod = clusterZod[nInd] +
1644 0.375 * pow(10, table3gpp->m_uLgZSD) *
offSetAlpha[mInd];
1645 std::tie(rayAodRadian[nInd][mInd], rayZodRadian[nInd][mInd]) =
1650 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1652 Shuffle(&rayAodRadian[cIndex][0], &rayAodRadian[cIndex][table3gpp->m_raysPerCluster]);
1653 Shuffle(&rayAoaRadian[cIndex][0], &rayAoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1654 Shuffle(&rayZodRadian[cIndex][0], &rayZodRadian[cIndex][table3gpp->m_raysPerCluster]);
1655 Shuffle(&rayZoaRadian[cIndex][0], &rayZoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1659 channelParams->m_rayAodRadian = rayAodRadian;
1660 channelParams->m_rayAoaRadian = rayAoaRadian;
1661 channelParams->m_rayZodRadian = rayZodRadian;
1662 channelParams->m_rayZoaRadian = rayZoaRadian;
1669 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1674 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1676 double uXprLinear = pow(10, table3gpp->m_uXpr / 10.0);
1677 double sigXprLinear = pow(10, table3gpp->m_sigXpr / 10.0);
1680 std::pow(10, (
m_normalRv->GetValue() * sigXprLinear + uXprLinear) / 10.0));
1682 for (uint8_t pInd = 0; pInd < 4; pInd++)
1686 temp2.push_back(temp3);
1688 crossPolarizationPowerRatios.push_back(temp);
1689 clusterPhase.push_back(temp2);
1692 channelParams->m_clusterPhase = clusterPhase;
1693 channelParams->m_crossPolarizationPowerRatios = crossPolarizationPowerRatios;
1695 uint8_t cluster1st = 0;
1696 uint8_t cluster2nd = 0;
1697 double maxPower = 0;
1698 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1700 if (maxPower < channelParams->m_clusterPower[cIndex])
1702 maxPower = channelParams->m_clusterPower[cIndex];
1703 cluster1st = cIndex;
1706 channelParams->m_cluster1st = cluster1st;
1708 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1710 if (maxPower < channelParams->m_clusterPower[cIndex] && cluster1st != cIndex)
1712 maxPower = channelParams->m_clusterPower[cIndex];
1713 cluster2nd = cIndex;
1716 channelParams->m_cluster2nd = cluster2nd;
1718 NS_LOG_INFO(
"1st strongest cluster:" << +cluster1st
1719 <<
", 2nd strongest cluster:" << +cluster2nd);
1722 if (cluster1st == cluster2nd)
1724 clusterDelay.push_back(clusterDelay[cluster1st] + 1.28 * table3gpp->m_cDS);
1725 clusterDelay.push_back(clusterDelay[cluster1st] + 2.56 * table3gpp->m_cDS);
1727 clusterAoa.push_back(clusterAoa[cluster1st]);
1728 clusterAoa.push_back(clusterAoa[cluster1st]);
1730 clusterZoa.push_back(clusterZoa[cluster1st]);
1731 clusterZoa.push_back(clusterZoa[cluster1st]);
1733 clusterAod.push_back(clusterAod[cluster1st]);
1734 clusterAod.push_back(clusterAod[cluster1st]);
1736 clusterZod.push_back(clusterZod[cluster1st]);
1737 clusterZod.push_back(clusterZod[cluster1st]);
1743 if (cluster1st < cluster2nd)
1753 clusterDelay.push_back(clusterDelay[
min] + 1.28 * table3gpp->m_cDS);
1754 clusterDelay.push_back(clusterDelay[
min] + 2.56 * table3gpp->m_cDS);
1755 clusterDelay.push_back(clusterDelay[
max] + 1.28 * table3gpp->m_cDS);
1756 clusterDelay.push_back(clusterDelay[
max] + 2.56 * table3gpp->m_cDS);
1758 clusterAoa.push_back(clusterAoa[
min]);
1759 clusterAoa.push_back(clusterAoa[
min]);
1760 clusterAoa.push_back(clusterAoa[
max]);
1761 clusterAoa.push_back(clusterAoa[
max]);
1763 clusterZoa.push_back(clusterZoa[
min]);
1764 clusterZoa.push_back(clusterZoa[
min]);
1765 clusterZoa.push_back(clusterZoa[
max]);
1766 clusterZoa.push_back(clusterZoa[
max]);
1768 clusterAod.push_back(clusterAod[
min]);
1769 clusterAod.push_back(clusterAod[
min]);
1770 clusterAod.push_back(clusterAod[
max]);
1771 clusterAod.push_back(clusterAod[
max]);
1773 clusterZod.push_back(clusterZod[
min]);
1774 clusterZod.push_back(clusterZod[
min]);
1775 clusterZod.push_back(clusterZod[
max]);
1776 clusterZod.push_back(clusterZod[
max]);
1779 channelParams->m_delay = clusterDelay;
1780 channelParams->m_angle.clear();
1781 channelParams->m_angle.push_back(clusterAoa);
1782 channelParams->m_angle.push_back(clusterZoa);
1783 channelParams->m_angle.push_back(clusterAod);
1784 channelParams->m_angle.push_back(clusterZod);
1802 uint8_t updatedClusterNumber = (channelParams->m_reducedClusterNumber == 1)
1803 ? channelParams->m_reducedClusterNumber + 2
1804 : channelParams->m_reducedClusterNumber + 4;
1806 for (uint8_t cIndex = 0; cIndex < updatedClusterNumber; cIndex++)
1815 dopplerTermAlpha.push_back(alpha);
1816 dopplerTermD.push_back(D);
1818 channelParams->m_alpha = dopplerTermAlpha;
1819 channelParams->m_D = dopplerTermD;
1821 return channelParams;
1840 channelMatrix->m_nodeIds =
1843 bool isSameDirection = (channelParams->m_nodeIds == channelMatrix->m_nodeIds);
1854 if (isSameDirection)
1856 rayAodRadian = channelParams->m_rayAodRadian;
1857 rayAoaRadian = channelParams->m_rayAoaRadian;
1858 rayZodRadian = channelParams->m_rayZodRadian;
1859 rayZoaRadian = channelParams->m_rayZoaRadian;
1863 rayAodRadian = channelParams->m_rayAoaRadian;
1864 rayAoaRadian = channelParams->m_rayAodRadian;
1865 rayZodRadian = channelParams->m_rayZoaRadian;
1866 rayZoaRadian = channelParams->m_rayZodRadian;
1872 size_t uSize = uAntenna->GetNumberOfElements();
1873 size_t sSize = sAntenna->GetNumberOfElements();
1879 uint16_t numOverallCluster = (channelParams->m_cluster1st != channelParams->m_cluster2nd)
1880 ? channelParams->m_reducedClusterNumber + 4
1881 : channelParams->m_reducedClusterNumber + 2;
1883 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPhase.size());
1884 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPower.size());
1885 NS_ASSERT(channelParams->m_reducedClusterNumber <=
1886 channelParams->m_crossPolarizationPowerRatios.size());
1887 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZoaRadian.size());
1888 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZodRadian.size());
1889 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAoaRadian.size());
1890 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAodRadian.size());
1891 NS_ASSERT(table3gpp->m_raysPerCluster <= channelParams->m_clusterPhase[0].size());
1892 NS_ASSERT(table3gpp->m_raysPerCluster <=
1893 channelParams->m_crossPolarizationPowerRatios[0].size());
1894 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZoaRadian[0].size());
1895 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZodRadian[0].size());
1896 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAoaRadian[0].size());
1897 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAodRadian[0].size());
1899 double x = sMob->GetPosition().x - uMob->GetPosition().x;
1900 double y = sMob->GetPosition().y - uMob->GetPosition().y;
1901 double distance2D = sqrt(x * x + y * y);
1904 double hUt = std::min(sMob->GetPosition().z, uMob->GetPosition().z);
1905 double hBs = std::max(sMob->GetPosition().z, uMob->GetPosition().z);
1907 double distance3D = std::sqrt(distance2D * distance2D + (hBs - hUt) * (hBs - hUt));
1909 Angles sAngle(uMob->GetPosition(), sMob->GetPosition());
1910 Angles uAngle(sMob->GetPosition(), uMob->GetPosition());
1913 table3gpp->m_raysPerCluster);
1923 sinCosA.resize(channelParams->m_reducedClusterNumber);
1924 sinSinA.resize(channelParams->m_reducedClusterNumber);
1925 cosZoA.resize(channelParams->m_reducedClusterNumber);
1926 sinCosD.resize(channelParams->m_reducedClusterNumber);
1927 sinSinD.resize(channelParams->m_reducedClusterNumber);
1928 cosZoD.resize(channelParams->m_reducedClusterNumber);
1929 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1931 sinCosA[nIndex].resize(table3gpp->m_raysPerCluster);
1932 sinSinA[nIndex].resize(table3gpp->m_raysPerCluster);
1933 cosZoA[nIndex].resize(table3gpp->m_raysPerCluster);
1934 sinCosD[nIndex].resize(table3gpp->m_raysPerCluster);
1935 sinSinD[nIndex].resize(table3gpp->m_raysPerCluster);
1936 cosZoD[nIndex].resize(table3gpp->m_raysPerCluster);
1939 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1941 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
1943 DoubleVector initialPhase = channelParams->m_clusterPhase[nIndex][mIndex];
1945 double k = channelParams->m_crossPolarizationPowerRatios[nIndex][mIndex];
1949 auto [rxFieldPatternPhi, rxFieldPatternTheta] = uAntenna->GetElementFieldPattern(
1950 Angles(channelParams->m_rayAoaRadian[nIndex][mIndex],
1951 channelParams->m_rayZoaRadian[nIndex][mIndex]));
1952 auto [txFieldPatternPhi, txFieldPatternTheta] = sAntenna->GetElementFieldPattern(
1953 Angles(channelParams->m_rayAodRadian[nIndex][mIndex],
1954 channelParams->m_rayZodRadian[nIndex][mIndex]));
1955 raysPreComp(nIndex, mIndex) =
1956 std::complex<double>(cos(initialPhase[0]), sin(initialPhase[0])) *
1957 rxFieldPatternTheta * txFieldPatternTheta +
1958 std::complex<double>(cos(initialPhase[1]), sin(initialPhase[1])) *
1959 std::sqrt(1.0 / k) * rxFieldPatternTheta * txFieldPatternPhi +
1960 std::complex<double>(cos(initialPhase[2]), sin(initialPhase[2])) *
1961 std::sqrt(1.0 / k) * rxFieldPatternPhi * txFieldPatternTheta +
1962 std::complex<double>(cos(initialPhase[3]), sin(initialPhase[3])) *
1963 rxFieldPatternPhi * txFieldPatternPhi;
1967 double sinRayZoa = sin(rayZoaRadian[nIndex][mIndex]);
1968 double sinRayAoa = sin(rayAoaRadian[nIndex][mIndex]);
1969 double cosRayAoa = cos(rayAoaRadian[nIndex][mIndex]);
1970 sinCosA[nIndex][mIndex] = sinRayZoa * cosRayAoa;
1971 sinSinA[nIndex][mIndex] = sinRayZoa * sinRayAoa;
1972 cosZoA[nIndex][mIndex] = cos(rayZoaRadian[nIndex][mIndex]);
1976 double sinRayZod = sin(rayZodRadian[nIndex][mIndex]);
1977 double sinRayAod = sin(rayAodRadian[nIndex][mIndex]);
1978 double cosRayAod = cos(rayAodRadian[nIndex][mIndex]);
1979 sinCosD[nIndex][mIndex] = sinRayZod * cosRayAod;
1980 sinSinD[nIndex][mIndex] = sinRayZod * sinRayAod;
1981 cosZoD[nIndex][mIndex] = cos(rayZodRadian[nIndex][mIndex]);
1987 uint8_t numSubClustersAdded = 0;
1988 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1990 for (
size_t uIndex = 0; uIndex < uSize; uIndex++)
1992 Vector uLoc = uAntenna->GetElementLocation(uIndex);
1994 for (
size_t sIndex = 0; sIndex < sSize; sIndex++)
1996 Vector sLoc = sAntenna->GetElementLocation(sIndex);
1999 if (nIndex != channelParams->m_cluster1st && nIndex != channelParams->m_cluster2nd)
2001 std::complex<double> rays(0, 0);
2002 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
2005 double rxPhaseDiff =
2007 (sinCosA[nIndex][mIndex] * uLoc.x + sinSinA[nIndex][mIndex] * uLoc.y +
2008 cosZoA[nIndex][mIndex] * uLoc.z);
2010 double txPhaseDiff =
2012 (sinCosD[nIndex][mIndex] * sLoc.x + sinSinD[nIndex][mIndex] * sLoc.y +
2013 cosZoD[nIndex][mIndex] * sLoc.z);
2017 rays += raysPreComp(nIndex, mIndex) *
2018 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2019 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2022 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2023 hUsn(uIndex, sIndex, nIndex) = rays;
2027 std::complex<double> raysSub1(0, 0);
2028 std::complex<double> raysSub2(0, 0);
2029 std::complex<double> raysSub3(0, 0);
2031 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
2035 double rxPhaseDiff =
2037 (sinCosA[nIndex][mIndex] * uLoc.x + sinSinA[nIndex][mIndex] * uLoc.y +
2038 cosZoA[nIndex][mIndex] * uLoc.z);
2040 double txPhaseDiff =
2042 (sinCosD[nIndex][mIndex] * sLoc.x + sinSinD[nIndex][mIndex] * sLoc.y +
2043 cosZoD[nIndex][mIndex] * sLoc.z);
2045 std::complex<double> raySub =
2046 raysPreComp(nIndex, mIndex) *
2047 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2048 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2072 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2074 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2076 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2077 hUsn(uIndex, sIndex, nIndex) = raysSub1;
2080 channelParams->m_reducedClusterNumber + numSubClustersAdded) = raysSub2;
2083 channelParams->m_reducedClusterNumber + numSubClustersAdded + 1) =
2088 if (nIndex == channelParams->m_cluster1st || nIndex == channelParams->m_cluster2nd)
2090 numSubClustersAdded += 2;
2097 std::complex<double> phaseDiffDueToDistance(cos(-2 * M_PI * distance3D / lambda),
2098 sin(-2 * M_PI * distance3D / lambda));
2102 const double sinUAngleAz = sin(uAngle.
GetAzimuth());
2103 const double cosUAngleAz = cos(uAngle.
GetAzimuth());
2106 const double sinSAngleAz = sin(sAngle.
GetAzimuth());
2107 const double cosSAngleAz = cos(sAngle.
GetAzimuth());
2109 for (
size_t uIndex = 0; uIndex < uSize; uIndex++)
2111 Vector uLoc = uAntenna->GetElementLocation(uIndex);
2112 double rxPhaseDiff = 2 * M_PI *
2113 (sinUAngleIncl * cosUAngleAz * uLoc.x +
2114 sinUAngleIncl * sinUAngleAz * uLoc.y + cosUAngleIncl * uLoc.z);
2116 for (
size_t sIndex = 0; sIndex < sSize; sIndex++)
2118 Vector sLoc = sAntenna->GetElementLocation(sIndex);
2119 std::complex<double> ray(0, 0);
2120 double txPhaseDiff =
2122 (sinSAngleIncl * cosSAngleAz * sLoc.x + sinSAngleIncl * sinSAngleAz * sLoc.y +
2123 cosSAngleIncl * sLoc.z);
2125 auto [rxFieldPatternPhi, rxFieldPatternTheta] = uAntenna->GetElementFieldPattern(
2127 auto [txFieldPatternPhi, txFieldPatternTheta] = sAntenna->GetElementFieldPattern(
2130 ray = (rxFieldPatternTheta * txFieldPatternTheta -
2131 rxFieldPatternPhi * txFieldPatternPhi) *
2132 phaseDiffDueToDistance *
2133 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2134 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2136 double kLinear = pow(10, channelParams->m_K_factor / 10.0);
2138 hUsn(uIndex, sIndex, 0) =
2139 sqrt(1.0 / (kLinear + 1)) * hUsn(uIndex, sIndex, 0) +
2140 sqrt(kLinear / (1 + kLinear)) * ray /
2142 channelParams->m_attenuation_dB[0] / 10.0);
2143 for (
size_t nIndex = 1; nIndex < hUsn.GetNumPages(); nIndex++)
2145 hUsn(uIndex, sIndex, nIndex) *=
2146 sqrt(1.0 / (kLinear + 1));
2152 NS_LOG_DEBUG(
"Husn (sAntenna, uAntenna):" << sAntenna->GetId() <<
", " << uAntenna->GetId());
2153 for (
size_t cIndex = 0; cIndex < hUsn.GetNumPages(); cIndex++)
2155 for (
size_t rowIdx = 0; rowIdx < hUsn.GetNumRows(); rowIdx++)
2157 for (
size_t colIdx = 0; colIdx < hUsn.GetNumCols(); colIdx++)
2159 NS_LOG_DEBUG(
" " << hUsn(rowIdx, colIdx, cIndex) <<
",");
2164 NS_LOG_INFO(
"size of coefficient matrix (rows, columns, clusters) = ("
2165 << hUsn.GetNumRows() <<
", " << hUsn.GetNumCols() <<
", " << hUsn.GetNumPages()
2167 channelMatrix->m_channel = hUsn;
2168 return channelMatrix;
2171std::pair<double, double>
2174 inclinationRad =
WrapTo2Pi(inclinationRad);
2175 if (inclinationRad > M_PI)
2178 inclinationRad -= M_PI;
2184 NS_ASSERT_MSG(0 <= inclinationRad && inclinationRad <= M_PI,
2185 "inclinationRad=" << inclinationRad <<
" not valid, should be in [0, pi]");
2187 "azimuthRad=" << azimuthRad <<
" not valid, should be in [0, 2*pi]");
2189 return std::make_pair(azimuthRad, inclinationRad);
2201 uint8_t clusterNum = clusterAOA.size();
2202 for (uint8_t cInd = 0; cInd < clusterNum; cInd++)
2204 powerAttenuation.push_back(0);
2214 double thetaSb = 110;
2225 if (channelParams->m_nonSelfBlocking.empty())
2236 table.push_back(90);
2243 table.push_back(90);
2245 table.push_back(10);
2247 channelParams->m_nonSelfBlocking.push_back(table);
2252 double deltaX = sqrt(pow(channelParams->m_preLocUT.x - channelParams->m_locUT.x, 2) +
2253 pow(channelParams->m_preLocUT.y - channelParams->m_locUT.y, 2));
2280 R = exp(-1 * (deltaX / corrDis +
2281 (
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()) /
2286 R = exp(-1 * (deltaX / corrDis));
2291 <<
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()
2292 <<
" correlation:" << R);
2302 if (R * R * (-0.069) + R * 1.074 - 0.002 <
2305 R = R * R * (-0.069) + R * 1.074 - 0.002;
2310 channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] =
2311 R * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] +
2318 for (uint8_t cInd = 0; cInd < clusterNum; cInd++)
2320 NS_ASSERT_MSG(clusterAOA[cInd] >= 0 && clusterAOA[cInd] <= 360,
2321 "the AOA should be the range of [0,360]");
2322 NS_ASSERT_MSG(clusterZOA[cInd] >= 0 && clusterZOA[cInd] <= 180,
2323 "the ZOA should be the range of [0,180]");
2326 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiSb - xSb / 2.0 <<
","
2327 << phiSb + xSb / 2.0 <<
"]");
2328 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaSb - ySb / 2.0 <<
","
2329 << thetaSb + ySb / 2.0 <<
"]");
2330 if (std::abs(clusterAOA[cInd] - phiSb) < (xSb / 2.0) &&
2331 std::abs(clusterZOA[cInd] - thetaSb) < (ySb / 2.0))
2333 powerAttenuation[cInd] += 30;
2335 <<
"] is blocked by self blocking region and reduce 30 dB power,"
2336 "the attenuation is ["
2337 << powerAttenuation[cInd] <<
" dB]");
2345 (0.5 * erfc(-1 * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] / sqrt(2))) *
2357 double xK = channelParams->m_nonSelfBlocking[blockInd][
X_INDEX];
2358 double thetaK = channelParams->m_nonSelfBlocking[blockInd][
THETA_INDEX];
2359 double yK = channelParams->m_nonSelfBlocking[blockInd][
Y_INDEX];
2361 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiK - xK <<
","
2362 << phiK + xK <<
"]");
2363 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaK - yK <<
","
2364 << thetaK + yK <<
"]");
2366 if (std::abs(clusterAOA[cInd] - phiK) < (xK) &&
2367 std::abs(clusterZOA[cInd] - thetaK) < (yK))
2369 double A1 = clusterAOA[cInd] - (phiK + xK / 2.0);
2370 double A2 = clusterAOA[cInd] - (phiK - xK / 2.0);
2371 double Z1 = clusterZOA[cInd] - (thetaK + yK / 2.0);
2372 double Z2 = clusterZOA[cInd] - (thetaK - yK / 2.0);
2379 if (xK / 2.0 < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= xK)
2387 if (-1 * xK < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= -1 * xK / 2.0)
2396 if (yK / 2.0 < clusterZOA[cInd] - thetaK && clusterZOA[cInd] - thetaK <= yK)
2404 if (-1 * yK < clusterZOA[cInd] - thetaK &&
2405 clusterZOA[cInd] - thetaK <= -1 * yK / 2.0)
2415 atan(signA1 * M_PI / 2.0 *
2416 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2420 atan(signA2 * M_PI / 2.0 *
2421 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2425 atan(signZ1 * M_PI / 2.0 *
2426 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2430 atan(signZ2 * M_PI / 2.0 *
2431 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2434 double lDb = -20 * log10(1 - (fA1 + fA2) * (fZ1 + fZ2));
2435 powerAttenuation[cInd] += lDb;
2436 NS_LOG_INFO(
"Cluster[" << +cInd <<
"] is blocked by no-self blocking, the loss is ["
2441 return powerAttenuation;
2447 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)
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Ptr< const AttributeChecker > MakeStringChecker()
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Time Now()
create an ns3::Time instance which contains the current simulation time.
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static const double offSetAlpha[20]
The ray offset angles within a cluster, given for rms angle spread normalized to 1.
static const double sqrtC_RMa_O2I[6][6]
The square root matrix for RMa O2I, which is generated using the Cholesky decomposition according to ...
static const double sqrtC_UMi_LOS[7][7]
The square root matrix for UMi LOS, which is generated using the Cholesky decomposition according to ...
static const double sqrtC_office_LOS[7][7]
The square root matrix for Indoor-Office LOS, which is generated using the Cholesky decomposition acc...
static const double sqrtC_UMa_O2I[6][6]
The square root matrix for UMa O2I, which is generated using the Cholesky decomposition according to ...
static const double sqrtC_RMa_NLOS[6][6]
The square root matrix for RMa NLOS, which is generated using the Cholesky decomposition according to...
static const double sqrtC_UMa_LOS[7][7]
The square root matrix for UMa LOS, which is generated using the Cholesky decomposition according to ...
static const double sqrtC_UMi_NLOS[6][6]
The square root matrix for UMi NLOS, which is generated using the Cholesky decomposition according to...
static const double sqrtC_RMa_LOS[7][7]
The square root matrix for RMa LOS, which is generated using the Cholesky decomposition according to ...
double DegreesToRadians(double degrees)
converts degrees to radians
static const double sqrtC_UMi_O2I[6][6]
The square root matrix for UMi O2I, which is generated using the Cholesky decomposition according to ...
static const double sqrtC_office_NLOS[6][6]
The square root matrix for Indoor-Office NLOS, which is generated using the Cholesky decomposition ac...
static const double sqrtC_UMa_NLOS[6][6]
The square root matrix for UMa NLOS, which is generated using the Cholesky decomposition according to...
double WrapTo2Pi(double a)
Wrap angle in [0, 2*M_PI)
double RadiansToDegrees(double radians)
converts radians to degrees