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