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};
59 {1, 0, 0, 0, 0, 0, 0},
60 {0, 1, 0, 0, 0, 0, 0},
61 {-0.5, 0, 0.866025, 0, 0, 0, 0},
62 {0, 0, 0, 1, 0, 0, 0},
63 {0, 0, 0, 0, 1, 0, 0},
64 {0.01, 0, -0.0519615, 0.73, -0.2, 0.651383, 0},
65 {-0.17, -0.02, 0.21362, -0.14, 0.24, 0.142773, 0.909661},
79 {-0.5, 0.866025, 0, 0, 0, 0},
80 {0.6, -0.11547, 0.791623, 0, 0, 0},
82 {-0.04, -0.138564, 0.540662, -0.18, 0.809003, 0},
83 {-0.25, -0.606218, -0.240013, 0.26, -0.231685, 0.625392},
98 {0, 0, -0.7, 0.714143, 0, 0},
99 {0, 0, 0.66, -0.123225, 0.741091, 0},
100 {0, 0, 0.47, 0.152631, -0.393194, 0.775373},
112 {1, 0, 0, 0, 0, 0, 0},
113 {0, 1, 0, 0, 0, 0, 0},
114 {-0.4, -0.4, 0.824621, 0, 0, 0, 0},
115 {-0.5, 0, 0.242536, 0.83137, 0, 0, 0},
116 {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0},
117 {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0},
118 {-0.8, 0, -0.388057, -0.367926, 0.238537, -3.58949e-15, 0.130931},
132 {-0.4, 0.916515, 0, 0, 0, 0},
133 {-0.6, 0.174574, 0.78072, 0, 0, 0},
134 {0, 0.654654, 0.365963, 0.661438, 0, 0},
135 {0, -0.545545, 0.762422, 0.118114, 0.327327, 0},
136 {-0.4, -0.174574, -0.396459, 0.392138, 0.49099, 0.507445},
149 {-0.5, 0.866025, 0, 0, 0, 0},
150 {0.2, 0.57735, 0.791623, 0, 0, 0},
151 {0, 0.46188, -0.336861, 0.820482, 0, 0},
152 {0, -0.69282, 0.252646, 0.493742, 0.460857, 0},
153 {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515},
166 {1, 0, 0, 0, 0, 0, 0},
167 {0.5, 0.866025, 0, 0, 0, 0, 0},
168 {-0.4, -0.57735, 0.711805, 0, 0, 0, 0},
169 {-0.5, 0.057735, 0.468293, 0.726201, 0, 0, 0},
170 {-0.4, -0.11547, 0.805464, -0.23482, 0.350363, 0, 0},
171 {0, 0, 0, 0.688514, 0.461454, 0.559471, 0},
172 {0, 0, 0.280976, 0.231921, -0.490509, 0.11916, 0.782603},
186 {-0.7, 0.714143, 0, 0, 0, 0},
188 {-0.4, 0.168034, 0, 0.90098, 0, 0},
189 {0, -0.70014, 0.5, 0.130577, 0.4927, 0},
190 {0, 0, 0.5, 0.221981, -0.566238, 0.616522},
203 {-0.5, 0.866025, 0, 0, 0, 0},
204 {0.2, 0.57735, 0.791623, 0, 0, 0},
205 {0, 0.46188, -0.336861, 0.820482, 0, 0},
206 {0, -0.69282, 0.252646, 0.493742, 0.460857, 0},
207 {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515},
219 {1, 0, 0, 0, 0, 0, 0},
220 {0.5, 0.866025, 0, 0, 0, 0, 0},
221 {-0.8, -0.11547, 0.588784, 0, 0, 0, 0},
222 {-0.4, 0.23094, 0.520847, 0.717903, 0, 0, 0},
223 {-0.5, 0.288675, 0.73598, -0.348236, 0.0610847, 0, 0},
224 {0.2, -0.11547, 0.418943, 0.541106, 0.219905, 0.655744, 0},
225 {0.3, -0.057735, 0.73598, -0.348236, 0.0610847, -0.304997, 0.383375},
239 {-0.5, 0.866025, 0, 0, 0, 0},
240 {0, 0.46188, 0.886942, 0, 0, 0},
241 {-0.4, -0.23094, 0.120263, 0.878751, 0, 0},
242 {0, -0.311769, 0.55697, -0.249198, 0.728344, 0},
243 {0, -0.069282, 0.295397, 0.430696, 0.468462, 0.709214},
249 m_uniformRv = CreateObject<UniformRandomVariable>();
253 m_normalRv = CreateObject<NormalRandomVariable>();
280 TypeId(
"ns3::ThreeGppChannelModel")
283 .AddConstructor<ThreeGppChannelModel>()
284 .AddAttribute(
"Frequency",
285 "The operating Frequency in Hz",
289 MakeDoubleChecker<double>())
292 "The 3GPP scenario (RMa, UMa, UMi-StreetCanyon, InH-OfficeOpen, InH-OfficeMixed)",
297 .AddAttribute(
"ChannelConditionModel",
298 "Pointer to the channel condition model",
302 MakePointerChecker<ChannelConditionModel>())
303 .AddAttribute(
"UpdatePeriod",
304 "Specify the channel coherence time",
309 .AddAttribute(
"Blockage",
310 "Enable blockage model A (sec 7.6.4.1)",
314 .AddAttribute(
"NumNonselfBlocking",
315 "number of non-self-blocking regions",
318 MakeIntegerChecker<uint16_t>())
319 .AddAttribute(
"PortraitMode",
320 "true for portrait mode, false for landscape mode",
324 .AddAttribute(
"BlockerSpeed",
325 "The speed of moving blockers, the unit is m/s",
328 MakeDoubleChecker<double>())
329 .AddAttribute(
"vScatt",
330 "Maximum speed of the vehicle in the layout (see 3GPP TR 37.885 v15.3.0, "
332 "Used to compute the additional contribution for the Doppler of"
333 "delayed (reflected) paths",
336 MakeDoubleChecker<double>(0.0))
361 "Frequency should be between 0.5 and 100 GHz but is " <<
f);
376 NS_ASSERT_MSG(scenario ==
"RMa" || scenario ==
"UMa" || scenario ==
"UMi-StreetCanyon" ||
377 scenario ==
"InH-OfficeOpen" || scenario ==
"InH-OfficeMixed" ||
378 scenario ==
"V2V-Urban" || scenario ==
"V2V-Highway",
379 "Unknown scenario, choose between: RMa, UMa, UMi-StreetCanyon, "
380 "InH-OfficeOpen, InH-OfficeMixed, V2V-Urban or V2V-Highway");
395 double distance2D)
const
406 bool los = channelCondition->IsLos();
407 bool o2i = channelCondition->IsO2i();
416 table3gpp->m_numOfCluster = 11;
417 table3gpp->m_raysPerCluster = 20;
418 table3gpp->m_uLgDS = -7.49;
419 table3gpp->m_sigLgDS = 0.55;
420 table3gpp->m_uLgASD = 0.90;
421 table3gpp->m_sigLgASD = 0.38;
422 table3gpp->m_uLgASA = 1.52;
423 table3gpp->m_sigLgASA = 0.24;
424 table3gpp->m_uLgZSA = 0.47;
425 table3gpp->m_sigLgZSA = 0.40;
426 table3gpp->m_uLgZSD = 0.34;
427 table3gpp->m_sigLgZSD =
428 std::max(-1.0, -0.17 * (distance2D / 1000) - 0.01 * (hUT - 1.5) + 0.22);
429 table3gpp->m_offsetZOD = 0;
430 table3gpp->m_cDS = 3.91e-9;
431 table3gpp->m_cASD = 2;
432 table3gpp->m_cASA = 3;
433 table3gpp->m_cZSA = 3;
435 table3gpp->m_sigK = 4;
436 table3gpp->m_rTau = 3.8;
437 table3gpp->m_uXpr = 12;
438 table3gpp->m_sigXpr = 4;
439 table3gpp->m_perClusterShadowingStd = 3;
441 for (uint8_t row = 0; row < 7; row++)
443 for (uint8_t column = 0; column < 7; column++)
445 table3gpp->m_sqrtC[row][column] =
sqrtC_RMa_LOS[row][column];
449 else if (!los && !o2i)
451 table3gpp->m_numOfCluster = 10;
452 table3gpp->m_raysPerCluster = 20;
453 table3gpp->m_uLgDS = -7.43;
454 table3gpp->m_sigLgDS = 0.48;
455 table3gpp->m_uLgASD = 0.95;
456 table3gpp->m_sigLgASD = 0.45;
457 table3gpp->m_uLgASA = 1.52;
458 table3gpp->m_sigLgASA = 0.13;
459 table3gpp->m_uLgZSA = 0.58;
460 table3gpp->m_sigLgZSA = 0.37;
461 table3gpp->m_uLgZSD =
462 std::max(-1.0, -0.19 * (distance2D / 1000) - 0.01 * (hUT - 1.5) + 0.28);
463 table3gpp->m_sigLgZSD = 0.30;
464 table3gpp->m_offsetZOD = atan((35 - 3.5) / distance2D) - atan((35 - 1.5) / distance2D);
465 table3gpp->m_cDS = 3.91e-9;
466 table3gpp->m_cASD = 2;
467 table3gpp->m_cASA = 3;
468 table3gpp->m_cZSA = 3;
470 table3gpp->m_sigK = 0;
471 table3gpp->m_rTau = 1.7;
472 table3gpp->m_uXpr = 7;
473 table3gpp->m_sigXpr = 3;
474 table3gpp->m_perClusterShadowingStd = 3;
476 for (uint8_t row = 0; row < 6; row++)
478 for (uint8_t column = 0; column < 6; column++)
486 table3gpp->m_numOfCluster = 10;
487 table3gpp->m_raysPerCluster = 20;
488 table3gpp->m_uLgDS = -7.47;
489 table3gpp->m_sigLgDS = 0.24;
490 table3gpp->m_uLgASD = 0.67;
491 table3gpp->m_sigLgASD = 0.18;
492 table3gpp->m_uLgASA = 1.66;
493 table3gpp->m_sigLgASA = 0.21;
494 table3gpp->m_uLgZSA = 0.93;
495 table3gpp->m_sigLgZSA = 0.22;
496 table3gpp->m_uLgZSD =
497 std::max(-1.0, -0.19 * (distance2D / 1000) - 0.01 * (hUT - 1.5) + 0.28);
498 table3gpp->m_sigLgZSD = 0.30;
499 table3gpp->m_offsetZOD = atan((35 - 3.5) / distance2D) - atan((35 - 1.5) / distance2D);
500 table3gpp->m_cDS = 3.91e-9;
501 table3gpp->m_cASD = 2;
502 table3gpp->m_cASA = 3;
503 table3gpp->m_cZSA = 3;
505 table3gpp->m_sigK = 0;
506 table3gpp->m_rTau = 1.7;
507 table3gpp->m_uXpr = 7;
508 table3gpp->m_sigXpr = 3;
509 table3gpp->m_perClusterShadowingStd = 3;
511 for (uint8_t row = 0; row < 6; row++)
513 for (uint8_t column = 0; column < 6; column++)
515 table3gpp->m_sqrtC[row][column] =
sqrtC_RMa_O2I[row][column];
524 table3gpp->m_numOfCluster = 12;
525 table3gpp->m_raysPerCluster = 20;
526 table3gpp->m_uLgDS = -6.955 - 0.0963 * log10(fcGHz);
527 table3gpp->m_sigLgDS = 0.66;
528 table3gpp->m_uLgASD = 1.06 + 0.1114 * log10(fcGHz);
529 table3gpp->m_sigLgASD = 0.28;
530 table3gpp->m_uLgASA = 1.81;
531 table3gpp->m_sigLgASA = 0.20;
532 table3gpp->m_uLgZSA = 0.95;
533 table3gpp->m_sigLgZSA = 0.16;
534 table3gpp->m_uLgZSD =
535 std::max(-0.5, -2.1 * distance2D / 1000 - 0.01 * (hUT - 1.5) + 0.75);
536 table3gpp->m_sigLgZSD = 0.40;
537 table3gpp->m_offsetZOD = 0;
538 table3gpp->m_cDS =
std::max(0.25, -3.4084 * log10(fcGHz) + 6.5622) * 1e-9;
539 table3gpp->m_cASD = 5;
540 table3gpp->m_cASA = 11;
541 table3gpp->m_cZSA = 7;
543 table3gpp->m_sigK = 3.5;
544 table3gpp->m_rTau = 2.5;
545 table3gpp->m_uXpr = 8;
546 table3gpp->m_sigXpr = 4;
547 table3gpp->m_perClusterShadowingStd = 3;
549 for (uint8_t row = 0; row < 7; row++)
551 for (uint8_t column = 0; column < 7; column++)
553 table3gpp->m_sqrtC[row][column] =
sqrtC_UMa_LOS[row][column];
559 double uLgZSD =
std::max(-0.5, -2.1 * distance2D / 1000 - 0.01 * (hUT - 1.5) + 0.9);
561 double afc = 0.208 * log10(fcGHz) - 0.782;
563 double cfc = -0.13 * log10(fcGHz) + 2.03;
564 double efc = 7.66 * log10(fcGHz) - 5.96;
566 double offsetZOD = efc - std::pow(10, afc * log10(
std::max(bfc, distance2D)) + cfc);
570 table3gpp->m_numOfCluster = 20;
571 table3gpp->m_raysPerCluster = 20;
572 table3gpp->m_uLgDS = -6.28 - 0.204 * log10(fcGHz);
573 table3gpp->m_sigLgDS = 0.39;
574 table3gpp->m_uLgASD = 1.5 - 0.1144 * log10(fcGHz);
575 table3gpp->m_sigLgASD = 0.28;
576 table3gpp->m_uLgASA = 2.08 - 0.27 * log10(fcGHz);
577 table3gpp->m_sigLgASA = 0.11;
578 table3gpp->m_uLgZSA = -0.3236 * log10(fcGHz) + 1.512;
579 table3gpp->m_sigLgZSA = 0.16;
580 table3gpp->m_uLgZSD = uLgZSD;
581 table3gpp->m_sigLgZSD = 0.49;
582 table3gpp->m_offsetZOD = offsetZOD;
583 table3gpp->m_cDS =
std::max(0.25, -3.4084 * log10(fcGHz) + 6.5622) * 1e-9;
584 table3gpp->m_cASD = 2;
585 table3gpp->m_cASA = 15;
586 table3gpp->m_cZSA = 7;
588 table3gpp->m_sigK = 0;
589 table3gpp->m_rTau = 2.3;
590 table3gpp->m_uXpr = 7;
591 table3gpp->m_sigXpr = 3;
592 table3gpp->m_perClusterShadowingStd = 3;
594 for (uint8_t row = 0; row < 6; row++)
596 for (uint8_t column = 0; column < 6; column++)
604 table3gpp->m_numOfCluster = 12;
605 table3gpp->m_raysPerCluster = 20;
606 table3gpp->m_uLgDS = -6.62;
607 table3gpp->m_sigLgDS = 0.32;
608 table3gpp->m_uLgASD = 1.25;
609 table3gpp->m_sigLgASD = 0.42;
610 table3gpp->m_uLgASA = 1.76;
611 table3gpp->m_sigLgASA = 0.16;
612 table3gpp->m_uLgZSA = 1.01;
613 table3gpp->m_sigLgZSA = 0.43;
614 table3gpp->m_uLgZSD = uLgZSD;
615 table3gpp->m_sigLgZSD = 0.49;
616 table3gpp->m_offsetZOD = offsetZOD;
617 table3gpp->m_cDS = 11e-9;
618 table3gpp->m_cASD = 5;
619 table3gpp->m_cASA = 8;
620 table3gpp->m_cZSA = 3;
622 table3gpp->m_sigK = 0;
623 table3gpp->m_rTau = 2.2;
624 table3gpp->m_uXpr = 9;
625 table3gpp->m_sigXpr = 5;
626 table3gpp->m_perClusterShadowingStd = 4;
628 for (uint8_t row = 0; row < 6; row++)
630 for (uint8_t column = 0; column < 6; column++)
632 table3gpp->m_sqrtC[row][column] =
sqrtC_UMa_O2I[row][column];
642 table3gpp->m_numOfCluster = 12;
643 table3gpp->m_raysPerCluster = 20;
644 table3gpp->m_uLgDS = -0.24 * log10(1 + fcGHz) - 7.14;
645 table3gpp->m_sigLgDS = 0.38;
646 table3gpp->m_uLgASD = -0.05 * log10(1 + fcGHz) + 1.21;
647 table3gpp->m_sigLgASD = 0.41;
648 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.73;
649 table3gpp->m_sigLgASA = 0.014 * log10(1 + fcGHz) + 0.28;
650 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
651 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
652 table3gpp->m_uLgZSD =
653 std::max(-0.21, -14.8 * distance2D / 1000 + 0.01 * std::abs(hUT - hBS) + 0.83);
654 table3gpp->m_sigLgZSD = 0.35;
655 table3gpp->m_offsetZOD = 0;
656 table3gpp->m_cDS = 5e-9;
657 table3gpp->m_cASD = 3;
658 table3gpp->m_cASA = 17;
659 table3gpp->m_cZSA = 7;
661 table3gpp->m_sigK = 5;
662 table3gpp->m_rTau = 3;
663 table3gpp->m_uXpr = 9;
664 table3gpp->m_sigXpr = 3;
665 table3gpp->m_perClusterShadowingStd = 3;
667 for (uint8_t row = 0; row < 7; row++)
669 for (uint8_t column = 0; column < 7; column++)
671 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
678 std::max(-0.5, -3.1 * distance2D / 1000 + 0.01 *
std::max(hUT - hBS, 0.0) + 0.2);
679 double offsetZOD = -1 * std::pow(10, -1.5 * log10(
std::max(10.0, distance2D)) + 3.3);
682 table3gpp->m_numOfCluster = 19;
683 table3gpp->m_raysPerCluster = 20;
684 table3gpp->m_uLgDS = -0.24 * log10(1 + fcGHz) - 6.83;
685 table3gpp->m_sigLgDS = 0.16 * log10(1 + fcGHz) + 0.28;
686 table3gpp->m_uLgASD = -0.23 * log10(1 + fcGHz) + 1.53;
687 table3gpp->m_sigLgASD = 0.11 * log10(1 + fcGHz) + 0.33;
688 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
689 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
690 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
691 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
692 table3gpp->m_uLgZSD = uLgZSD;
693 table3gpp->m_sigLgZSD = 0.35;
694 table3gpp->m_offsetZOD = offsetZOD;
695 table3gpp->m_cDS = 11e-9;
696 table3gpp->m_cASD = 10;
697 table3gpp->m_cASA = 22;
698 table3gpp->m_cZSA = 7;
700 table3gpp->m_sigK = 0;
701 table3gpp->m_rTau = 2.1;
702 table3gpp->m_uXpr = 8;
703 table3gpp->m_sigXpr = 3;
704 table3gpp->m_perClusterShadowingStd = 3;
706 for (uint8_t row = 0; row < 6; row++)
708 for (uint8_t column = 0; column < 6; column++)
716 table3gpp->m_numOfCluster = 12;
717 table3gpp->m_raysPerCluster = 20;
718 table3gpp->m_uLgDS = -6.62;
719 table3gpp->m_sigLgDS = 0.32;
720 table3gpp->m_uLgASD = 1.25;
721 table3gpp->m_sigLgASD = 0.42;
722 table3gpp->m_uLgASA = 1.76;
723 table3gpp->m_sigLgASA = 0.16;
724 table3gpp->m_uLgZSA = 1.01;
725 table3gpp->m_sigLgZSA = 0.43;
726 table3gpp->m_uLgZSD = uLgZSD;
727 table3gpp->m_sigLgZSD = 0.35;
728 table3gpp->m_offsetZOD = offsetZOD;
729 table3gpp->m_cDS = 11e-9;
730 table3gpp->m_cASD = 5;
731 table3gpp->m_cASA = 8;
732 table3gpp->m_cZSA = 3;
734 table3gpp->m_sigK = 0;
735 table3gpp->m_rTau = 2.2;
736 table3gpp->m_uXpr = 9;
737 table3gpp->m_sigXpr = 5;
738 table3gpp->m_perClusterShadowingStd = 4;
740 for (uint8_t row = 0; row < 6; row++)
742 for (uint8_t column = 0; column < 6; column++)
744 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_O2I[row][column];
752 NS_ASSERT_MSG(!o2i,
"The indoor scenario does out support outdoor to indoor");
755 table3gpp->m_numOfCluster = 15;
756 table3gpp->m_raysPerCluster = 20;
757 table3gpp->m_uLgDS = -0.01 * log10(1 + fcGHz) - 7.692;
758 table3gpp->m_sigLgDS = 0.18;
759 table3gpp->m_uLgASD = 1.60;
760 table3gpp->m_sigLgASD = 0.18;
761 table3gpp->m_uLgASA = -0.19 * log10(1 + fcGHz) + 1.781;
762 table3gpp->m_sigLgASA = 0.12 * log10(1 + fcGHz) + 0.119;
763 table3gpp->m_uLgZSA = -0.26 * log10(1 + fcGHz) + 1.44;
764 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.264;
765 table3gpp->m_uLgZSD = -1.43 * log10(1 + fcGHz) + 2.228;
766 table3gpp->m_sigLgZSD = 0.13 * log10(1 + fcGHz) + 0.30;
767 table3gpp->m_offsetZOD = 0;
768 table3gpp->m_cDS = 3.91e-9;
769 table3gpp->m_cASD = 5;
770 table3gpp->m_cASA = 8;
771 table3gpp->m_cZSA = 9;
773 table3gpp->m_sigK = 4;
774 table3gpp->m_rTau = 3.6;
775 table3gpp->m_uXpr = 11;
776 table3gpp->m_sigXpr = 4;
777 table3gpp->m_perClusterShadowingStd = 6;
779 for (uint8_t row = 0; row < 7; row++)
781 for (uint8_t column = 0; column < 7; column++)
789 table3gpp->m_numOfCluster = 19;
790 table3gpp->m_raysPerCluster = 20;
791 table3gpp->m_uLgDS = -0.28 * log10(1 + fcGHz) - 7.173;
792 table3gpp->m_sigLgDS = 0.1 * log10(1 + fcGHz) + 0.055;
793 table3gpp->m_uLgASD = 1.62;
794 table3gpp->m_sigLgASD = 0.25;
795 table3gpp->m_uLgASA = -0.11 * log10(1 + fcGHz) + 1.863;
796 table3gpp->m_sigLgASA = 0.12 * log10(1 + fcGHz) + 0.059;
797 table3gpp->m_uLgZSA = -0.15 * log10(1 + fcGHz) + 1.387;
798 table3gpp->m_sigLgZSA = -0.09 * log10(1 + fcGHz) + 0.746;
799 table3gpp->m_uLgZSD = 1.08;
800 table3gpp->m_sigLgZSD = 0.36;
801 table3gpp->m_offsetZOD = 0;
802 table3gpp->m_cDS = 3.91e-9;
803 table3gpp->m_cASD = 5;
804 table3gpp->m_cASA = 11;
805 table3gpp->m_cZSA = 9;
807 table3gpp->m_sigK = 0;
808 table3gpp->m_rTau = 3;
809 table3gpp->m_uXpr = 10;
810 table3gpp->m_sigXpr = 4;
811 table3gpp->m_perClusterShadowingStd = 3;
813 for (uint8_t row = 0; row < 6; row++)
815 for (uint8_t column = 0; column < 6; column++)
824 if (channelCondition->IsLos())
828 table3gpp->m_numOfCluster = 12;
829 table3gpp->m_raysPerCluster = 20;
830 table3gpp->m_uLgDS = -0.2 * log10(1 + fcGHz) - 7.5;
831 table3gpp->m_sigLgDS = 0.1;
832 table3gpp->m_uLgASD = -0.1 * log10(1 + fcGHz) + 1.6;
833 table3gpp->m_sigLgASD = 0.1;
834 table3gpp->m_uLgASA = -0.1 * log10(1 + fcGHz) + 1.6;
835 table3gpp->m_sigLgASA = 0.1;
836 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
837 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
838 table3gpp->m_uLgZSD = -0.1 * log10(1 + fcGHz) + 0.73;
839 table3gpp->m_sigLgZSD = -0.04 * log10(1 + fcGHz) + 0.34;
840 table3gpp->m_offsetZOD = 0;
841 table3gpp->m_cDS = 5;
842 table3gpp->m_cASD = 17;
843 table3gpp->m_cASA = 17;
844 table3gpp->m_cZSA = 7;
845 table3gpp->m_uK = 3.48;
846 table3gpp->m_sigK = 2;
847 table3gpp->m_rTau = 3;
848 table3gpp->m_uXpr = 9;
849 table3gpp->m_sigXpr = 3;
850 table3gpp->m_perClusterShadowingStd = 4;
852 for (uint8_t row = 0; row < 7; row++)
854 for (uint8_t column = 0; column < 7; column++)
856 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
860 else if (channelCondition->IsNlos())
862 table3gpp->m_numOfCluster = 19;
863 table3gpp->m_raysPerCluster = 20;
864 table3gpp->m_uLgDS = -0.3 * log10(1 + fcGHz) - 7;
865 table3gpp->m_sigLgDS = 0.28;
866 table3gpp->m_uLgASD = -0.08 * log10(1 + fcGHz) + 1.81;
867 table3gpp->m_sigLgASD = 0.05 * log10(1 + fcGHz) + 0.3;
868 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
869 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
870 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
871 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
872 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
873 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
874 table3gpp->m_offsetZOD = 0;
875 table3gpp->m_cDS = 11;
876 table3gpp->m_cASD = 22;
877 table3gpp->m_cASA = 22;
878 table3gpp->m_cZSA = 7;
880 table3gpp->m_sigK = 0;
881 table3gpp->m_rTau = 2.1;
882 table3gpp->m_uXpr = 8;
883 table3gpp->m_sigXpr = 3;
884 table3gpp->m_perClusterShadowingStd = 4;
886 for (uint8_t row = 0; row < 6; row++)
888 for (uint8_t column = 0; column < 6; column++)
894 else if (channelCondition->IsNlosv())
896 table3gpp->m_numOfCluster = 19;
897 table3gpp->m_raysPerCluster = 20;
898 table3gpp->m_uLgDS = -0.4 * log10(1 + fcGHz) - 7;
899 table3gpp->m_sigLgDS = 0.1;
900 table3gpp->m_uLgASD = -0.1 * log10(1 + fcGHz) + 1.7;
901 table3gpp->m_sigLgASD = 0.1;
902 table3gpp->m_uLgASA = -0.1 * log10(1 + fcGHz) + 1.7;
903 table3gpp->m_sigLgASA = 0.1;
904 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
905 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
906 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
907 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
908 table3gpp->m_offsetZOD = 0;
909 table3gpp->m_cDS = 11;
910 table3gpp->m_cASD = 22;
911 table3gpp->m_cASA = 22;
912 table3gpp->m_cZSA = 7;
914 table3gpp->m_sigK = 4.5;
915 table3gpp->m_rTau = 2.1;
916 table3gpp->m_uXpr = 8;
917 table3gpp->m_sigXpr = 3;
918 table3gpp->m_perClusterShadowingStd = 4;
920 for (uint8_t row = 0; row < 6; row++)
922 for (uint8_t column = 0; column < 6; column++)
924 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
935 if (channelCondition->IsLos())
937 table3gpp->m_numOfCluster = 12;
938 table3gpp->m_raysPerCluster = 20;
939 table3gpp->m_uLgDS = -8.3;
940 table3gpp->m_sigLgDS = 0.2;
941 table3gpp->m_uLgASD = 1.4;
942 table3gpp->m_sigLgASD = 0.1;
943 table3gpp->m_uLgASA = 1.4;
944 table3gpp->m_sigLgASA = 0.1;
945 table3gpp->m_uLgZSA = -0.1 * log10(1 + fcGHz) + 0.73;
946 table3gpp->m_sigLgZSA = -0.04 * log10(1 + fcGHz) + 0.34;
947 table3gpp->m_uLgZSD = -0.1 * log10(1 + fcGHz) + 0.73;
948 table3gpp->m_sigLgZSD = -0.04 * log10(1 + fcGHz) + 0.34;
949 table3gpp->m_offsetZOD = 0;
950 table3gpp->m_cDS = 5;
951 table3gpp->m_cASD = 17;
952 table3gpp->m_cASA = 17;
953 table3gpp->m_cZSA = 7;
955 table3gpp->m_sigK = 3.5;
956 table3gpp->m_rTau = 3;
957 table3gpp->m_uXpr = 9;
958 table3gpp->m_sigXpr = 3;
959 table3gpp->m_perClusterShadowingStd = 4;
961 for (uint8_t row = 0; row < 7; row++)
963 for (uint8_t column = 0; column < 7; column++)
965 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
969 else if (channelCondition->IsNlosv())
971 table3gpp->m_numOfCluster = 19;
972 table3gpp->m_raysPerCluster = 20;
973 table3gpp->m_uLgDS = -8.3;
974 table3gpp->m_sigLgDS = 0.3;
975 table3gpp->m_uLgASD = 1.5;
976 table3gpp->m_sigLgASD = 0.1;
977 table3gpp->m_uLgASA = 1.5;
978 table3gpp->m_sigLgASA = 0.1;
979 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
980 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
981 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
982 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
983 table3gpp->m_offsetZOD = 0;
984 table3gpp->m_cDS = 11;
985 table3gpp->m_cASD = 22;
986 table3gpp->m_cASA = 22;
987 table3gpp->m_cZSA = 7;
989 table3gpp->m_sigK = 4.5;
990 table3gpp->m_rTau = 2.1;
991 table3gpp->m_uXpr = 8.0;
992 table3gpp->m_sigXpr = 3;
993 table3gpp->m_perClusterShadowingStd = 4;
995 for (uint8_t row = 0; row < 6; row++)
997 for (uint8_t column = 0; column < 6; column++)
999 table3gpp->m_sqrtC[row][column] =
sqrtC_UMi_LOS[row][column];
1003 else if (channelCondition->IsNlos())
1006 "The fast fading parameters for the NLOS condition in the Highway scenario are not "
1007 "defined in TR 37.885, use the ones defined in TDoc R1-1803671 instead");
1009 table3gpp->m_numOfCluster = 19;
1010 table3gpp->m_raysPerCluster = 20;
1011 table3gpp->m_uLgDS = -0.3 * log10(1 + fcGHz) - 7;
1012 table3gpp->m_sigLgDS = 0.28;
1013 table3gpp->m_uLgASD = -0.08 * log10(1 + fcGHz) + 1.81;
1014 table3gpp->m_sigLgASD = 0.05 * log10(1 + fcGHz) + 0.3;
1015 table3gpp->m_uLgASA = -0.08 * log10(1 + fcGHz) + 1.81;
1016 table3gpp->m_sigLgASA = 0.05 * log10(1 + fcGHz) + 0.3;
1017 table3gpp->m_uLgZSA = -0.04 * log10(1 + fcGHz) + 0.92;
1018 table3gpp->m_sigLgZSA = -0.07 * log10(1 + fcGHz) + 0.41;
1019 table3gpp->m_uLgZSD = -0.04 * log10(1 + fcGHz) + 0.92;
1020 table3gpp->m_sigLgZSD = -0.07 * log10(1 + fcGHz) + 0.41;
1021 table3gpp->m_offsetZOD = 0;
1022 table3gpp->m_cDS = 11;
1023 table3gpp->m_cASD = 22;
1024 table3gpp->m_cASA = 22;
1025 table3gpp->m_cZSA = 7;
1026 table3gpp->m_uK = 0;
1027 table3gpp->m_sigK = 0;
1028 table3gpp->m_rTau = 2.1;
1029 table3gpp->m_uXpr = 8;
1030 table3gpp->m_sigXpr = 3;
1031 table3gpp->m_perClusterShadowingStd = 4;
1033 for (uint8_t row = 0; row < 6; row++)
1035 for (uint8_t column = 0; column < 6; column++)
1060 bool update =
false;
1063 if (!channelCondition->IsEqual(channelParams->m_losCondition, channelParams->m_o2iCondition))
1085 if (channelParams->m_generatedTime > channelMatrix->m_generatedTime)
1104 uint64_t channelParamsKey =
1107 uint64_t channelMatrixKey =
GetKey(aAntenna->GetId(), bAntenna->GetId());
1115 bool updateParams =
false;
1116 bool updateMatrix =
false;
1117 bool notFoundParams =
false;
1118 bool notFoundMatrix =
false;
1131 notFoundParams =
true;
1134 double x = aMob->GetPosition().x - bMob->GetPosition().x;
1135 double y = aMob->GetPosition().y - bMob->GetPosition().y;
1136 double distance2D = sqrt(x * x + y * y);
1140 double hUt =
std::min(aMob->GetPosition().z, bMob->GetPosition().z);
1141 double hBs =
std::max(aMob->GetPosition().z, bMob->GetPosition().z);
1146 if (notFoundParams || updateParams)
1171 notFoundMatrix =
true;
1176 if (notFoundMatrix || updateMatrix)
1179 channelMatrix =
GetNewChannel(channelParams, table3gpp, aMob, bMob, aAntenna, bAntenna);
1181 std::make_pair(aAntenna->GetId(),
1189 return channelMatrix;
1198 uint64_t channelParamsKey =
1207 NS_LOG_WARN(
"Channel params map not found. Returning a nullptr.");
1222 channelParams->m_nodeIds =
1224 channelParams->m_losCondition = channelCondition->GetLosCondition();
1225 channelParams->m_o2iCondition = channelCondition->GetO2iCondition();
1230 uint8_t paramNum = 6;
1237 for (uint8_t iter = 0; iter < paramNum; iter++)
1241 for (uint8_t row = 0; row < paramNum; row++)
1244 for (uint8_t column = 0; column < paramNum; column++)
1246 temp += table3gpp->m_sqrtC[row][column] * LSPsIndep[column];
1248 LSPs.push_back(temp);
1260 kFactor = LSPs[1] * table3gpp->m_sigK + table3gpp->m_uK;
1261 DS = pow(10, LSPs[2] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1262 ASD = pow(10, LSPs[3] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1263 ASA = pow(10, LSPs[4] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1264 ZSD = pow(10, LSPs[5] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1265 ZSA = pow(10, LSPs[6] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1269 DS = pow(10, LSPs[1] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS);
1270 ASD = pow(10, LSPs[2] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD);
1271 ASA = pow(10, LSPs[3] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA);
1272 ZSD = pow(10, LSPs[4] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD);
1273 ZSA = pow(10, LSPs[5] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA);
1281 channelParams->m_DS = DS;
1282 channelParams->m_K_factor = kFactor;
1284 NS_LOG_INFO(
"K-factor=" << kFactor <<
", DS=" << DS <<
", ASD=" << ASD <<
", ASA=" << ASA
1285 <<
", ZSD=" << ZSD <<
", ZSA=" << ZSA);
1289 double minTau = 100.0;
1290 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1297 clusterDelay.push_back(tau);
1300 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1302 clusterDelay[cIndex] -= minTau;
1304 std::sort(clusterDelay.begin(), clusterDelay.end());
1311 double powerSum = 0;
1312 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1315 exp(-1 * clusterDelay[cIndex] * (table3gpp->m_rTau - 1) / table3gpp->m_rTau / DS) *
1317 -1 *
m_normalRv->GetValue() * table3gpp->m_perClusterShadowingStd / 10);
1319 clusterPower.push_back(power);
1321 channelParams->m_clusterPower = clusterPower;
1323 double powerMax = 0;
1325 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1327 channelParams->m_clusterPower[cIndex] =
1328 channelParams->m_clusterPower[cIndex] / powerSum;
1335 double kLinear = pow(10, kFactor / 10);
1337 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1341 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1343 kLinear / (1 + kLinear));
1347 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex] /
1350 if (powerMax < clusterPowerForAngles[cIndex])
1352 powerMax = clusterPowerForAngles[cIndex];
1358 for (uint8_t cIndex = 0; cIndex < table3gpp->m_numOfCluster; cIndex++)
1360 clusterPowerForAngles.push_back(channelParams->m_clusterPower[cIndex]);
1361 if (powerMax < clusterPowerForAngles[cIndex])
1363 powerMax = clusterPowerForAngles[cIndex];
1370 double thresh = 0.0032;
1371 for (uint8_t cIndex = table3gpp->m_numOfCluster; cIndex > 0; cIndex--)
1373 if (clusterPowerForAngles[cIndex - 1] < thresh * powerMax)
1375 clusterPowerForAngles.erase(clusterPowerForAngles.begin() + cIndex - 1);
1376 channelParams->m_clusterPower.erase(channelParams->m_clusterPower.begin() + cIndex - 1);
1377 clusterDelay.erase(clusterDelay.begin() + cIndex - 1);
1381 NS_ASSERT(channelParams->m_clusterPower.size() < UINT8_MAX);
1382 channelParams->m_reducedClusterNumber = channelParams->m_clusterPower.size();
1387 0.7705 - 0.0433 * kFactor + 2e-4 * pow(kFactor, 2) + 17e-6 * pow(kFactor, 3);
1388 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1390 clusterDelay[cIndex] = clusterDelay[cIndex] / cTau;
1399 switch (table3gpp->m_numOfCluster)
1438 double cPhi = cNlos;
1442 cPhi *= (1.1035 - 0.028 * kFactor - 2e-3 * pow(kFactor, 2) +
1443 1e-4 * pow(kFactor, 3));
1446 switch (table3gpp->m_numOfCluster)
1473 double cTheta = cNlos;
1474 if (channelCondition->IsLos())
1476 cTheta *= (1.3086 + 0.0339 * kFactor - 0.0077 * pow(kFactor, 2) +
1477 2e-4 * pow(kFactor, 3));
1484 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1486 double logCalc = -1 * log(clusterPowerForAngles[cIndex] / powerMax);
1487 double angle = 2 * sqrt(logCalc) / 1.4 / cPhi;
1488 clusterAoa.push_back(ASA * angle);
1489 clusterAod.push_back(ASD * angle);
1490 angle = logCalc / cTheta;
1491 clusterZoa.push_back(ZSA * angle);
1492 clusterZod.push_back(ZSD * angle);
1495 Angles sAngle(bMob->GetPosition(), aMob->GetPosition());
1496 Angles uAngle(aMob->GetPosition(), bMob->GetPosition());
1498 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1505 clusterAoa[cIndex] = clusterAoa[cIndex] * Xn + (
m_normalRv->GetValue() * ASA / 7) +
1507 clusterAod[cIndex] = clusterAod[cIndex] * Xn + (
m_normalRv->GetValue() * ASD / 7) +
1509 if (channelCondition->IsO2i())
1511 clusterZoa[cIndex] =
1512 clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7) + 90;
1516 clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (
m_normalRv->GetValue() * ZSA / 7) +
1519 clusterZod[cIndex] = clusterZod[cIndex] * Xn + (
m_normalRv->GetValue() * ZSD / 7) +
1521 table3gpp->m_offsetZOD;
1533 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1535 clusterAoa[cIndex] -= diffAoa;
1536 clusterAod[cIndex] -= diffAod;
1537 clusterZoa[cIndex] -= diffZsa;
1538 clusterZod[cIndex] -= diffZsd;
1542 double sizeTemp = clusterZoa.size();
1543 for (uint8_t ind = 0; ind < 4; ind++)
1549 angleDegree = clusterAoa;
1552 angleDegree = clusterZoa;
1555 angleDegree = clusterAod;
1558 angleDegree = clusterZod;
1563 for (uint8_t nIndex = 0; nIndex < sizeTemp; nIndex++)
1565 while (angleDegree[nIndex] > 360)
1567 angleDegree[nIndex] -= 360;
1570 while (angleDegree[nIndex] < 0)
1572 angleDegree[nIndex] += 360;
1575 if (ind == 1 || ind == 3)
1577 if (angleDegree[nIndex] > 180)
1579 angleDegree[nIndex] = 360 - angleDegree[nIndex];
1586 clusterAoa = angleDegree;
1589 clusterZoa = angleDegree;
1592 clusterAod = angleDegree;
1595 clusterZod = angleDegree;
1606 for (uint8_t cInd = 0; cInd < channelParams->m_reducedClusterNumber; cInd++)
1608 channelParams->m_clusterPower[cInd] =
1609 channelParams->m_clusterPower[cInd] / pow(10, attenuationDb[cInd] / 10);
1614 attenuationDb.push_back(0);
1618 channelParams->m_attenuation_dB = attenuationDb;
1623 channelParams->m_reducedClusterNumber,
1627 channelParams->m_reducedClusterNumber,
1631 channelParams->m_reducedClusterNumber,
1635 channelParams->m_reducedClusterNumber,
1639 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1641 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1643 double tempAoa = clusterAoa[nInd] + table3gpp->m_cASA *
offSetAlpha[mInd];
1644 double tempZoa = clusterZoa[nInd] + table3gpp->m_cZSA *
offSetAlpha[mInd];
1645 std::tie(rayAoaRadian[nInd][mInd], rayZoaRadian[nInd][mInd]) =
1648 double tempAod = clusterAod[nInd] + table3gpp->m_cASD *
offSetAlpha[mInd];
1649 double tempZod = clusterZod[nInd] +
1650 0.375 * pow(10, table3gpp->m_uLgZSD) *
offSetAlpha[mInd];
1651 std::tie(rayAodRadian[nInd][mInd], rayZodRadian[nInd][mInd]) =
1656 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1658 Shuffle(&rayAodRadian[cIndex][0], &rayAodRadian[cIndex][table3gpp->m_raysPerCluster]);
1659 Shuffle(&rayAoaRadian[cIndex][0], &rayAoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1660 Shuffle(&rayZodRadian[cIndex][0], &rayZodRadian[cIndex][table3gpp->m_raysPerCluster]);
1661 Shuffle(&rayZoaRadian[cIndex][0], &rayZoaRadian[cIndex][table3gpp->m_raysPerCluster]);
1665 channelParams->m_rayAodRadian = rayAodRadian;
1666 channelParams->m_rayAoaRadian = rayAoaRadian;
1667 channelParams->m_rayZodRadian = rayZodRadian;
1668 channelParams->m_rayZoaRadian = rayZoaRadian;
1675 for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
1680 for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
1682 double uXprLinear = pow(10, table3gpp->m_uXpr / 10);
1683 double sigXprLinear = pow(10, table3gpp->m_sigXpr / 10);
1685 temp.push_back(std::pow(10, (
m_normalRv->GetValue() * sigXprLinear + uXprLinear) / 10));
1687 for (uint8_t pInd = 0; pInd < 4; pInd++)
1691 temp2.push_back(temp3);
1693 crossPolarizationPowerRatios.push_back(temp);
1694 clusterPhase.push_back(temp2);
1697 channelParams->m_clusterPhase = clusterPhase;
1698 channelParams->m_crossPolarizationPowerRatios = crossPolarizationPowerRatios;
1700 uint8_t cluster1st = 0;
1701 uint8_t cluster2nd = 0;
1702 double maxPower = 0;
1703 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1705 if (maxPower < channelParams->m_clusterPower[cIndex])
1707 maxPower = channelParams->m_clusterPower[cIndex];
1708 cluster1st = cIndex;
1711 channelParams->m_cluster1st = cluster1st;
1713 for (uint8_t cIndex = 0; cIndex < channelParams->m_reducedClusterNumber; cIndex++)
1715 if (maxPower < channelParams->m_clusterPower[cIndex] && cluster1st != cIndex)
1717 maxPower = channelParams->m_clusterPower[cIndex];
1718 cluster2nd = cIndex;
1721 channelParams->m_cluster2nd = cluster2nd;
1723 NS_LOG_INFO(
"1st strongest cluster:" << +cluster1st
1724 <<
", 2nd strongest cluster:" << +cluster2nd);
1727 if (cluster1st == cluster2nd)
1729 clusterDelay.push_back(clusterDelay[cluster1st] + 1.28 * table3gpp->m_cDS);
1730 clusterDelay.push_back(clusterDelay[cluster1st] + 2.56 * table3gpp->m_cDS);
1732 clusterAoa.push_back(clusterAoa[cluster1st]);
1733 clusterAoa.push_back(clusterAoa[cluster1st]);
1735 clusterZoa.push_back(clusterZoa[cluster1st]);
1736 clusterZoa.push_back(clusterZoa[cluster1st]);
1738 clusterAod.push_back(clusterAod[cluster1st]);
1739 clusterAod.push_back(clusterAod[cluster1st]);
1741 clusterZod.push_back(clusterZod[cluster1st]);
1742 clusterZod.push_back(clusterZod[cluster1st]);
1748 if (cluster1st < cluster2nd)
1758 clusterDelay.push_back(clusterDelay[
min] + 1.28 * table3gpp->m_cDS);
1759 clusterDelay.push_back(clusterDelay[
min] + 2.56 * table3gpp->m_cDS);
1760 clusterDelay.push_back(clusterDelay[
max] + 1.28 * table3gpp->m_cDS);
1761 clusterDelay.push_back(clusterDelay[
max] + 2.56 * table3gpp->m_cDS);
1763 clusterAoa.push_back(clusterAoa[
min]);
1764 clusterAoa.push_back(clusterAoa[
min]);
1765 clusterAoa.push_back(clusterAoa[
max]);
1766 clusterAoa.push_back(clusterAoa[
max]);
1768 clusterZoa.push_back(clusterZoa[
min]);
1769 clusterZoa.push_back(clusterZoa[
min]);
1770 clusterZoa.push_back(clusterZoa[
max]);
1771 clusterZoa.push_back(clusterZoa[
max]);
1773 clusterAod.push_back(clusterAod[
min]);
1774 clusterAod.push_back(clusterAod[
min]);
1775 clusterAod.push_back(clusterAod[
max]);
1776 clusterAod.push_back(clusterAod[
max]);
1778 clusterZod.push_back(clusterZod[
min]);
1779 clusterZod.push_back(clusterZod[
min]);
1780 clusterZod.push_back(clusterZod[
max]);
1781 clusterZod.push_back(clusterZod[
max]);
1784 channelParams->m_delay = clusterDelay;
1785 channelParams->m_angle.clear();
1786 channelParams->m_angle.push_back(clusterAoa);
1787 channelParams->m_angle.push_back(clusterZoa);
1788 channelParams->m_angle.push_back(clusterAod);
1789 channelParams->m_angle.push_back(clusterZod);
1807 uint8_t updatedClusterNumber = (channelParams->m_reducedClusterNumber == 1)
1808 ? channelParams->m_reducedClusterNumber + 2
1809 : channelParams->m_reducedClusterNumber + 4;
1811 for (uint8_t cIndex = 0; cIndex < updatedClusterNumber; cIndex++)
1820 dopplerTermAlpha.push_back(alpha);
1821 dopplerTermD.push_back(D);
1823 channelParams->m_alpha = dopplerTermAlpha;
1824 channelParams->m_D = dopplerTermD;
1826 return channelParams;
1848 bool isSameDirection = (channelParams->m_nodeIds == channelMatrix->
m_nodeIds);
1859 if (isSameDirection)
1861 rayAodRadian = channelParams->m_rayAodRadian;
1862 rayAoaRadian = channelParams->m_rayAoaRadian;
1863 rayZodRadian = channelParams->m_rayZodRadian;
1864 rayZoaRadian = channelParams->m_rayZoaRadian;
1868 rayAodRadian = channelParams->m_rayAoaRadian;
1869 rayAoaRadian = channelParams->m_rayAodRadian;
1870 rayZodRadian = channelParams->m_rayZoaRadian;
1871 rayZoaRadian = channelParams->m_rayZodRadian;
1880 uint64_t uSize = uAntenna->GetNumberOfElements();
1881 uint64_t sSize = sAntenna->GetNumberOfElements();
1884 for (uint64_t uIndex = 0; uIndex < uSize; uIndex++)
1886 hUsn[uIndex].resize(sSize);
1887 for (uint64_t sIndex = 0; sIndex < sSize; sIndex++)
1889 hUsn[uIndex][sIndex].resize(channelParams->m_reducedClusterNumber);
1893 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPhase.size());
1894 NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPower.size());
1895 NS_ASSERT(channelParams->m_reducedClusterNumber <=
1896 channelParams->m_crossPolarizationPowerRatios.size());
1897 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZoaRadian.size());
1898 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayZodRadian.size());
1899 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAoaRadian.size());
1900 NS_ASSERT(channelParams->m_reducedClusterNumber <= rayAodRadian.size());
1901 NS_ASSERT(table3gpp->m_raysPerCluster <= channelParams->m_clusterPhase[0].size());
1902 NS_ASSERT(table3gpp->m_raysPerCluster <=
1903 channelParams->m_crossPolarizationPowerRatios[0].size());
1904 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZoaRadian[0].size());
1905 NS_ASSERT(table3gpp->m_raysPerCluster <= rayZodRadian[0].size());
1906 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAoaRadian[0].size());
1907 NS_ASSERT(table3gpp->m_raysPerCluster <= rayAodRadian[0].size());
1909 double x = sMob->GetPosition().x - uMob->GetPosition().x;
1910 double y = sMob->GetPosition().y - uMob->GetPosition().y;
1911 double distance2D = sqrt(x * x + y * y);
1914 double hUt =
std::min(sMob->GetPosition().z, uMob->GetPosition().z);
1915 double hBs =
std::max(sMob->GetPosition().z, uMob->GetPosition().z);
1917 double distance3D = std::sqrt(distance2D * distance2D + (hBs - hUt) * (hBs - hUt));
1919 Angles sAngle(uMob->GetPosition(), sMob->GetPosition());
1920 Angles uAngle(sMob->GetPosition(), uMob->GetPosition());
1923 for (uint64_t uIndex = 0; uIndex < uSize; uIndex++)
1925 Vector uLoc = uAntenna->GetElementLocation(uIndex);
1927 for (uint64_t sIndex = 0; sIndex < sSize; sIndex++)
1929 Vector sLoc = sAntenna->GetElementLocation(sIndex);
1931 for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++)
1935 if (nIndex != channelParams->m_cluster1st && nIndex != channelParams->m_cluster2nd)
1937 std::complex<double> rays(0, 0);
1938 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
1940 DoubleVector initialPhase = channelParams->m_clusterPhase[nIndex][mIndex];
1941 double k = channelParams->m_crossPolarizationPowerRatios[nIndex][mIndex];
1943 double rxPhaseDiff = 2 * M_PI *
1944 (sin(rayZoaRadian[nIndex][mIndex]) *
1945 cos(rayAoaRadian[nIndex][mIndex]) * uLoc.x +
1946 sin(rayZoaRadian[nIndex][mIndex]) *
1947 sin(rayAoaRadian[nIndex][mIndex]) * uLoc.y +
1948 cos(rayZoaRadian[nIndex][mIndex]) * uLoc.z);
1950 double txPhaseDiff = 2 * M_PI *
1951 (sin(rayZodRadian[nIndex][mIndex]) *
1952 cos(rayAodRadian[nIndex][mIndex]) * sLoc.x +
1953 sin(rayZodRadian[nIndex][mIndex]) *
1954 sin(rayAodRadian[nIndex][mIndex]) * sLoc.y +
1955 cos(rayZodRadian[nIndex][mIndex]) * sLoc.z);
1959 double rxFieldPatternPhi;
1960 double rxFieldPatternTheta;
1961 double txFieldPatternPhi;
1962 double txFieldPatternTheta;
1963 std::tie(rxFieldPatternPhi, rxFieldPatternTheta) =
1964 uAntenna->GetElementFieldPattern(
1965 Angles(channelParams->m_rayAoaRadian[nIndex][mIndex],
1966 channelParams->m_rayZoaRadian[nIndex][mIndex]));
1967 std::tie(txFieldPatternPhi, txFieldPatternTheta) =
1968 sAntenna->GetElementFieldPattern(
1969 Angles(channelParams->m_rayAodRadian[nIndex][mIndex],
1970 channelParams->m_rayZodRadian[nIndex][mIndex]));
1972 rays += (std::complex<double>(cos(initialPhase[0]), sin(initialPhase[0])) *
1973 rxFieldPatternTheta * txFieldPatternTheta +
1974 std::complex<double>(cos(initialPhase[1]), sin(initialPhase[1])) *
1975 std::sqrt(1 /
k) * rxFieldPatternTheta * txFieldPatternPhi +
1976 std::complex<double>(cos(initialPhase[2]), sin(initialPhase[2])) *
1977 std::sqrt(1 /
k) * rxFieldPatternPhi * txFieldPatternTheta +
1978 std::complex<double>(cos(initialPhase[3]), sin(initialPhase[3])) *
1979 rxFieldPatternPhi * txFieldPatternPhi) *
1980 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
1981 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
1984 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
1985 hUsn[uIndex][sIndex][nIndex] = rays;
1989 std::complex<double> raysSub1(0, 0);
1990 std::complex<double> raysSub2(0, 0);
1991 std::complex<double> raysSub3(0, 0);
1993 for (uint8_t mIndex = 0; mIndex < table3gpp->m_raysPerCluster; mIndex++)
1995 double k = channelParams->m_crossPolarizationPowerRatios[nIndex][mIndex];
1999 DoubleVector initialPhase = channelParams->m_clusterPhase[nIndex][mIndex];
2002 double rxPhaseDiff = 2 * M_PI *
2003 (sin(rayZoaRadian[nIndex][mIndex]) *
2004 cos(rayAoaRadian[nIndex][mIndex]) * uLoc.x +
2005 sin(rayZoaRadian[nIndex][mIndex]) *
2006 sin(rayAoaRadian[nIndex][mIndex]) * uLoc.y +
2007 cos(rayZoaRadian[nIndex][mIndex]) * uLoc.z);
2008 double txPhaseDiff = 2 * M_PI *
2009 (sin(rayZodRadian[nIndex][mIndex]) *
2010 cos(rayAodRadian[nIndex][mIndex]) * sLoc.x +
2011 sin(rayZodRadian[nIndex][mIndex]) *
2012 sin(rayAodRadian[nIndex][mIndex]) * sLoc.y +
2013 cos(rayZodRadian[nIndex][mIndex]) * sLoc.z);
2015 double rxFieldPatternPhi;
2016 double rxFieldPatternTheta;
2017 double txFieldPatternPhi;
2018 double txFieldPatternTheta;
2019 std::tie(rxFieldPatternPhi, rxFieldPatternTheta) =
2020 uAntenna->GetElementFieldPattern(
2021 Angles(rayAoaRadian[nIndex][mIndex], rayZoaRadian[nIndex][mIndex]));
2022 std::tie(txFieldPatternPhi, txFieldPatternTheta) =
2023 sAntenna->GetElementFieldPattern(
2024 Angles(rayAodRadian[nIndex][mIndex], rayZodRadian[nIndex][mIndex]));
2026 std::complex<double> raySub =
2027 (std::complex<double>(cos(initialPhase[0]), sin(initialPhase[0])) *
2028 rxFieldPatternTheta * txFieldPatternTheta +
2029 std::complex<double>(cos(initialPhase[1]), sin(initialPhase[1])) *
2030 sqrt(1 /
k) * rxFieldPatternTheta * txFieldPatternPhi +
2031 std::complex<double>(cos(initialPhase[2]), sin(initialPhase[2])) *
2032 sqrt(1 /
k) * rxFieldPatternPhi * txFieldPatternTheta +
2033 std::complex<double>(cos(initialPhase[3]), sin(initialPhase[3])) *
2034 rxFieldPatternPhi * txFieldPatternPhi) *
2035 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2036 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2060 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2062 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2064 sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster);
2065 hUsn[uIndex][sIndex][nIndex] = raysSub1;
2066 hUsn[uIndex][sIndex].push_back(raysSub2);
2067 hUsn[uIndex][sIndex].push_back(raysSub3);
2073 std::complex<double> ray(0, 0);
2074 double rxPhaseDiff =
2079 double txPhaseDiff =
2085 double rxFieldPatternPhi;
2086 double rxFieldPatternTheta;
2087 double txFieldPatternPhi;
2088 double txFieldPatternTheta;
2089 std::tie(rxFieldPatternPhi, rxFieldPatternTheta) = uAntenna->GetElementFieldPattern(
2091 std::tie(txFieldPatternPhi, txFieldPatternTheta) = sAntenna->GetElementFieldPattern(
2096 ray = (rxFieldPatternTheta * txFieldPatternTheta -
2097 rxFieldPatternPhi * txFieldPatternPhi) *
2098 std::complex<double>(cos(-2 * M_PI * distance3D / lambda),
2099 sin(-2 * M_PI * distance3D / lambda)) *
2100 std::complex<double>(cos(rxPhaseDiff), sin(rxPhaseDiff)) *
2101 std::complex<double>(cos(txPhaseDiff), sin(txPhaseDiff));
2103 double kLinear = pow(10, channelParams->m_K_factor / 10);
2105 hUsn[uIndex][sIndex][0] =
2106 sqrt(1 / (kLinear + 1)) * hUsn[uIndex][sIndex][0] +
2107 sqrt(kLinear / (1 + kLinear)) * ray /
2108 pow(10, channelParams->m_attenuation_dB[0] / 10);
2109 double tempSize = hUsn[uIndex][sIndex].size();
2110 for (uint8_t nIndex = 1; nIndex < tempSize; nIndex++)
2112 hUsn[uIndex][sIndex][nIndex] *=
2113 sqrt(1 / (kLinear + 1));
2119 NS_LOG_DEBUG(
"Husn (sAntenna, uAntenna):" << sAntenna->GetId() <<
", " << uAntenna->GetId());
2120 for (
auto& i : hUsn)
2130 NS_LOG_INFO(
"size of coefficient matrix =[" << hUsn.size() <<
"][" << hUsn[0].size() <<
"]["
2131 << hUsn[0][0].size() <<
"]");
2133 return channelMatrix;
2136std::pair<double, double>
2139 inclinationRad =
WrapTo2Pi(inclinationRad);
2140 if (inclinationRad > M_PI)
2143 inclinationRad -= M_PI;
2149 NS_ASSERT_MSG(0 <= inclinationRad && inclinationRad <= M_PI,
2150 "inclinationRad=" << inclinationRad <<
" not valid, should be in [0, pi]");
2152 "azimuthRad=" << azimuthRad <<
" not valid, should be in [0, 2*pi]");
2154 return std::make_pair(azimuthRad, inclinationRad);
2166 uint8_t clusterNum = clusterAOA.size();
2167 for (uint8_t cInd = 0; cInd < clusterNum; cInd++)
2169 powerAttenuation.push_back(0);
2179 double thetaSb = 110;
2190 if (channelParams->m_nonSelfBlocking.size() == 0)
2201 table.push_back(90);
2208 table.push_back(90);
2210 table.push_back(10);
2212 channelParams->m_nonSelfBlocking.push_back(table);
2217 double deltaX = sqrt(pow(channelParams->m_preLocUT.x - channelParams->m_locUT.x, 2) +
2218 pow(channelParams->m_preLocUT.y - channelParams->m_locUT.y, 2));
2245 R = exp(-1 * (deltaX / corrDis +
2246 (
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()) /
2251 R = exp(-1 * (deltaX / corrDis));
2256 <<
Now().GetSeconds() - channelParams->m_generatedTime.GetSeconds()
2257 <<
" correlation:" << R);
2267 if (R * R * (-0.069) + R * 1.074 - 0.002 <
2270 R = R * R * (-0.069) + R * 1.074 - 0.002;
2275 channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] =
2276 R * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] +
2283 for (uint8_t cInd = 0; cInd < clusterNum; cInd++)
2285 NS_ASSERT_MSG(clusterAOA[cInd] >= 0 && clusterAOA[cInd] <= 360,
2286 "the AOA should be the range of [0,360]");
2287 NS_ASSERT_MSG(clusterZOA[cInd] >= 0 && clusterZOA[cInd] <= 180,
2288 "the ZOA should be the range of [0,180]");
2291 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiSb - xSb / 2 <<
","
2292 << phiSb + xSb / 2 <<
"]");
2293 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaSb - ySb / 2 <<
","
2294 << thetaSb + ySb / 2 <<
"]");
2295 if (std::abs(clusterAOA[cInd] - phiSb) < (xSb / 2) &&
2296 std::abs(clusterZOA[cInd] - thetaSb) < (ySb / 2))
2298 powerAttenuation[cInd] += 30;
2300 <<
"] is blocked by self blocking region and reduce 30 dB power,"
2301 "the attenuation is ["
2302 << powerAttenuation[cInd] <<
" dB]");
2310 (0.5 * erfc(-1 * channelParams->m_nonSelfBlocking[blockInd][
PHI_INDEX] / sqrt(2))) *
2322 double xK = channelParams->m_nonSelfBlocking[blockInd][
X_INDEX];
2323 double thetaK = channelParams->m_nonSelfBlocking[blockInd][
THETA_INDEX];
2324 double yK = channelParams->m_nonSelfBlocking[blockInd][
Y_INDEX];
2326 NS_LOG_INFO(
"AOA=" << clusterAOA[cInd] <<
" Block Region[" << phiK - xK <<
","
2327 << phiK + xK <<
"]");
2328 NS_LOG_INFO(
"ZOA=" << clusterZOA[cInd] <<
" Block Region[" << thetaK - yK <<
","
2329 << thetaK + yK <<
"]");
2331 if (std::abs(clusterAOA[cInd] - phiK) < (xK) &&
2332 std::abs(clusterZOA[cInd] - thetaK) < (yK))
2334 double A1 = clusterAOA[cInd] - (phiK + xK / 2);
2335 double A2 = clusterAOA[cInd] - (phiK - xK / 2);
2336 double Z1 = clusterZOA[cInd] - (thetaK + yK / 2);
2337 double Z2 = clusterZOA[cInd] - (thetaK - yK / 2);
2344 if (xK / 2 < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= xK)
2352 if (-1 * xK < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= -1 * xK / 2)
2361 if (yK / 2 < clusterZOA[cInd] - thetaK && clusterZOA[cInd] - thetaK <= yK)
2369 if (-1 * yK < clusterZOA[cInd] - thetaK && clusterZOA[cInd] - thetaK <= -1 * yK / 2)
2379 atan(signA1 * M_PI / 2 *
2380 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2384 atan(signA2 * M_PI / 2 *
2385 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2389 atan(signZ1 * M_PI / 2 *
2390 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2394 atan(signZ2 * M_PI / 2 *
2395 sqrt(M_PI / lambda * channelParams->m_nonSelfBlocking[blockInd][
R_INDEX] *
2398 double lDb = -20 * log10(1 - (fA1 + fA2) * (fZ1 + fZ2));
2399 powerAttenuation[cInd] += lDb;
2400 NS_LOG_INFO(
"Cluster[" << +cInd <<
"] is blocked by no-self blocking, the loss is ["
2405 return powerAttenuation;
2411 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.
This is an interface for a channel model that can be described by a channel matrix,...
std::vector< Complex2DVector > Complex3DVector
type definition for complex 3D matrices
std::vector< DoubleVector > Double2DVector
type definition for matrices of doubles
std::vector< double > DoubleVector
type definition for vectors 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,...
std::vector< Double2DVector > Double3DVector
type definition for 3D matrices of doubles
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 potrait 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 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...
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),...