diff --git a/src/propagation/CMakeLists.txt b/src/propagation/CMakeLists.txt index 666b96a2e..e21429e0d 100644 --- a/src/propagation/CMakeLists.txt +++ b/src/propagation/CMakeLists.txt @@ -40,5 +40,5 @@ build_lib( test/probabilistic-v2v-channel-condition-model-test.cc test/propagation-loss-model-test-suite.cc test/three-gpp-propagation-loss-model-test-suite.cc - test/three-gpp-propagation-loss-model-test-suite.cc + test/three-gpp-ntn-propagation-loss-model-test-suite.cc ) diff --git a/src/propagation/doc/propagation.rst b/src/propagation/doc/propagation.rst index 1eb5ce137..42bea1f72 100644 --- a/src/propagation/doc/propagation.rst +++ b/src/propagation/doc/propagation.rst @@ -42,6 +42,10 @@ The following propagation loss models are implemented: * ThreeGppUMaPropagationLossModel * ThreeGppUmiStreetCanyonPropagationLossModel * ThreeGppIndoorOfficePropagationLossModel + * ThreeGppNTNDenseUrbanPropagationLossModel + * ThreeGppNTNUrbanPropagationLossModel + * ThreeGppNTNSuburbanPropagationLossModel + * ThreeGppNTNRuralPropagationLossModel Other models could be available thanks to other modules, e.g., the ``building`` module. @@ -746,6 +750,47 @@ The test cases :cpp:class:`ThreeGppRmaPropagationLossModelTestCase`, :cpp:class:`ThreeGppIndoorOfficePropagationLossModelTestCase` compute the path loss between two nodes and compares it with the value obtained using the formulas in 3GPP TR 38.901 [38901]_, Table 7.4.1-1. The test case :cpp:class:`ThreeGppShadowingTestCase` checks if the shadowing is correctly computed by testing the deviation of the overall propagation loss from the path loss. The test is carried out for all the scenarios, both in LOS and NLOS condition. +ThreeGppNTNPropagationLossModel +=============================== + +Four different classes have been derived from the base class :cpp:class:`ThreeGppPropagationLossModel` +to support Non-Terrestrial Networks, one for each scenario presented in 3GPP TR 38.811 [38811]_, i.e., +dense urban, urban, suburban and rural. + +*Implemented features:* + + * Line of Sight and Not Line of Sight (LOS/NLOS) probability models (3GPP TR 38.811, Sec. 6.6.1) + * Path loss, shadowing models and clutter loss (3GPP TR 38.811, Sec. 6.6.2) + * Atmospheric absorption model (3GPP TR 38.811, Sec. 6.6.4) + * Ionospheric and tropospheric scintillation (3GPP TR 38.811, Sec. 6.6.6) + * All the features already implemented in `ThreeGppPropagationLossModel `_ + + +ThreeGppNTNDenseUrbanPropagationLossModel +````````````````````````````````````````` +This class implements the LOS/NLOS path loss and shadow fading models described in 3GPP +TR 38.811 [38811]_, Table 6.6.2-1 for the Dense Urban scenario. It +supports frequencies between 0.5 and 100 GHz. + +ThreeGppNTNUrbanPropagationLossModel +```````````````````````````````````` +This class implements the LOS/NLOS path loss and shadow fading models described in 3GPP +TR 38.811 [38811]_, Table 6.6.2-2 for the Urban scenario. It +supports frequencies between 0.5 and 100 GHz. + +ThreeGppNTNSuburbanPropagationLossModel +``````````````````````````````````````` +This class implements the LOS/NLOS path loss and shadow fading models described in 3GPP +TR 38.811 [38811]_, Table 6.6.2-3 for the Suburban scenario. It +supports frequencies between 0.5 and 100 GHz. + +ThreeGppNTNRuralPropagationLossModel +```````````````````````````````````` +This class implements the LOS/NLOS path loss and shadow fading models described in 3GPP +TR 38.811 [38811]_, Table 6.6.2-3 for the Rural scenario. It +supports frequencies between 0.5 and 100 GHz. + + ChannelConditionModel ********************* @@ -778,30 +823,60 @@ The two approach are coded, respectively, in the classes: ThreeGppChannelConditionModel ============================= This is the base class for the 3GPP channel condition models. -It provides the possibility to updated the condition of each channel periodically, +It provides the possibility to update the condition of each channel periodically, after a given time period which can be configured through the attribute "UpdatePeriod". If "UpdatePeriod" is set to 0, the channel condition is never updated. It has five derived classes implementing the channel condition models described in 3GPP TR 38.901 [38901]_ for different propagation scenarios. ThreeGppRmaChannelConditionModel ```````````````````````````````` -This implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the RMa scenario. +This class implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the RMa scenario. ThreeGppUmaChannelConditionModel ```````````````````````````````` -This implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the UMa scenario. +This class implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the UMa scenario. ThreeGppUmiStreetCanyonChannelConditionModel ```````````````````````````````````````````` -This implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the UMi-Street Canyon scenario. +This class implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the UMi-Street Canyon scenario. ThreeGppIndoorMixedOfficeChannelConditionModel `````````````````````````````````````````````` -This implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the Indoor-Mixed office scenario. +This class implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the Indoor-Mixed office scenario. ThreeGppIndoorOpenOfficeChannelConditionModel ````````````````````````````````````````````` -This implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the Indoor-Open office scenario. +This class implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the Indoor-Open office scenario. + +ThreeGppNTNChannelConditionModel +================================ +This is the base class for the 3GPP NTN channel condition models. +It provides the possibility to update the condition of each channel periodically, +after a given time period which can be configured through the attribute "UpdatePeriod". +If "UpdatePeriod" is set to 0, the channel condition is never updated. +It has four derived classes implementing the channel condition models described in 3GPP TR 38.811 [38811]_ +for the different propagation scenarios. i.e., dense urban, urban, suburban and rural. + +ThreeGppDenseUrbanChannelConditionModel +``````````````````````````````````````` +This class implements the statistical channel condition model described in 3GPP TR 38.811 [38811]_, +Table 6.6.1-1, for the Dense Urban scenario. + +ThreeGppUrbanChannelConditionModel +`````````````````````````````````` +This class implements the statistical channel condition model described in 3GPP TR 38.811 [38811]_, +Table 6.6.1-1, for the Urban scenario. + +ThreeGppSuburbanStreetCanyonChannelConditionModel +````````````````````````````````````````````````` +This class implements the statistical channel condition model described in 3GPP TR 38.811 [38811]_, +Table 6.6.1-1, for the Suburban scenario. + +ThreeGppRuralChannelConditionModel +`````````````````````````````````` +This class implements the statistical channel condition model described in 3GPP TR 38.811 [38811]_, +Table 6.6.1-1, for the Rural office scenario. + Testing ======= @@ -1036,3 +1111,5 @@ References .. [Boban2016Modeling] M. Boban, X. Gong, and W. Xu, “Modeling the evolution of line-of-sight blockage for V2V channels,” in IEEE 84th Vehicular Technology Conference (VTC-Fall), 2016. + +.. [38811] 3GPP. 2018. TR 38.811, Study on New Radio (NR) to support non-terrestrial networks, V15.4.0. (2020-09). diff --git a/src/propagation/model/channel-condition-model.cc b/src/propagation/model/channel-condition-model.cc index 34d9b0839..da7b5a552 100644 --- a/src/propagation/model/channel-condition-model.cc +++ b/src/propagation/model/channel-condition-model.cc @@ -20,14 +20,60 @@ #include "ns3/boolean.h" #include "ns3/double.h" +#include "ns3/geocentric-constant-position-mobility-model.h" #include "ns3/log.h" #include "ns3/mobility-model.h" #include "ns3/node.h" +#include "ns3/pointer.h" #include "ns3/simulator.h" #include "ns3/string.h" #include +namespace +{ + +/// NTN Dense Urban LOS probabilities from table 6.6.1-1 of 3GPP 38.811 +const std::map DenseUrbanLOSProb{ + {10, {28.2}}, + {20, {33.1}}, + {30, {39.8}}, + {40, {46.8}}, + {50, {53.7}}, + {60, {61.2}}, + {70, {73.8}}, + {80, {82.0}}, + {90, {98.1}}, +}; + +/// NTN Urban LOS probabilities from table 6.6.1-1 of 3GPP 38.811 +const std::map UrbanLOSProb{ + {10, {24.6}}, + {20, {38.6}}, + {30, {49.3}}, + {40, {61.3}}, + {50, {72.6}}, + {60, {80.5}}, + {70, {91.9}}, + {80, {96.8}}, + {90, {99.2}}, +}; + +/// NTN Suburban LOS probabilities from table 6.6.1-1 of 3GPP 38.811 +const std::map SuburbanRuralLOSProb{ + {10, {78.2}}, + {20, {86.9}}, + {30, {91.9}}, + {40, {92.9}}, + {50, {93.5}}, + {60, {94.0}}, + {70, {94.9}}, + {80, {95.2}}, + {90, {99.8}}, +}; + +} // namespace + namespace ns3 { @@ -537,6 +583,29 @@ ThreeGppChannelConditionModel::GetKey(Ptr a, Ptr +ThreeGppChannelConditionModel::GetQuantizedElevationAngle(Ptr a, + Ptr b) +{ + Ptr aMobNonConst = ConstCast(a); + Ptr bMobNonConst = ConstCast(b); + + // check if aMob and bMob are of type GeocentricConstantPositionMobilityModel + auto aNTNMob = DynamicCast(aMobNonConst); + auto bNTNMob = DynamicCast(bMobNonConst); + NS_ASSERT_MSG(aNTNMob && bNTNMob, + "Mobility Models need to be of type Geocentric for NTN scenarios"); + + double elevAngle = aNTNMob->GetElevationAngle(bNTNMob); + // Round the elevation angle into a two-digits integer between 10 and 90, as specified in + // Sec. 6.6.1, 3GPP TR 38.811 v15.4.0 + int elevAngleQuantized = (elevAngle < 10) ? 10 : round(elevAngle / 10) * 10; + NS_ASSERT_MSG((elevAngleQuantized >= 10) && (elevAngleQuantized <= 90), + "Invalid elevation angle!"); + + return std::make_tuple(elevAngle, elevAngleQuantized); +}; + // ------------------------------------------------------------------------- // NS_OBJECT_ENSURE_REGISTERED(ThreeGppRmaChannelConditionModel); @@ -829,4 +898,100 @@ ThreeGppIndoorOpenOfficeChannelConditionModel::ComputePlos(Ptr() + .SetGroupName("Propagation") + .AddConstructor(); + return tid; +} + +double +ThreeGppNTNDenseUrbanChannelConditionModel::ComputePlos(Ptr a, + Ptr b) const +{ + // Compute the LOS probability (see 3GPP TR 38.811, Table 6.6.1-1). + // The elevation angle is first quantized to one of the reference angles. + auto [elevAngle, quantizedElevAngle] = GetQuantizedElevationAngle(a, b); + return DenseUrbanLOSProb.at(quantizedElevAngle); +} + +// ------------------------------------------------------------------------- // + +NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNUrbanChannelConditionModel); + +TypeId +ThreeGppNTNUrbanChannelConditionModel::GetTypeId() +{ + static TypeId tid = TypeId("ns3::ThreeGppNTNUrbanChannelConditionModel") + .SetParent() + .SetGroupName("Propagation") + .AddConstructor(); + return tid; +} + +double +ThreeGppNTNUrbanChannelConditionModel::ComputePlos(Ptr a, + Ptr b) const +{ + // Compute the LOS probability (see 3GPP TR 38.811, Table 6.6.1-1). + // The elevation angle is first quantized to one of the reference angles. + auto [elevAngle, quantizedElevAngle] = GetQuantizedElevationAngle(a, b); + return UrbanLOSProb.at(quantizedElevAngle); +} + +// ------------------------------------------------------------------------- // + +NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNSuburbanChannelConditionModel); + +TypeId +ThreeGppNTNSuburbanChannelConditionModel::GetTypeId() +{ + static TypeId tid = TypeId("ns3::ThreeGppNTNSuburbanChannelConditionModel") + .SetParent() + .SetGroupName("Propagation") + .AddConstructor(); + return tid; +} + +double +ThreeGppNTNSuburbanChannelConditionModel::ComputePlos(Ptr a, + Ptr b) const +{ + // Compute the LOS probability (see 3GPP TR 38.811, Table 6.6.1-1). + // The elevation angle is first quantized to one of the reference angles. + auto [elevAngle, quantizedElevAngle] = GetQuantizedElevationAngle(a, b); + return SuburbanRuralLOSProb.at(quantizedElevAngle); +} + +// ------------------------------------------------------------------------- // + +NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNRuralChannelConditionModel); + +TypeId +ThreeGppNTNRuralChannelConditionModel::GetTypeId() +{ + static TypeId tid = TypeId("ns3::ThreeGppNTNRuralChannelConditionModel") + .SetParent() + .SetGroupName("Propagation") + .AddConstructor(); + return tid; +} + +double +ThreeGppNTNRuralChannelConditionModel::ComputePlos(Ptr a, + Ptr b) const +{ + // Compute the LOS probability (see 3GPP TR 38.811, Table 6.6.1-1). + // The elevation angle is first quantized to one of the reference angles. + auto [elevAngle, quantizedElevAngle] = GetQuantizedElevationAngle(a, b); + return SuburbanRuralLOSProb.at(quantizedElevAngle); +} + } // end namespace ns3 diff --git a/src/propagation/model/channel-condition-model.h b/src/propagation/model/channel-condition-model.h index 73865c075..6f63e9abc 100644 --- a/src/propagation/model/channel-condition-model.h +++ b/src/propagation/model/channel-condition-model.h @@ -24,6 +24,7 @@ #include "ns3/random-variable-stream.h" #include "ns3/vector.h" +#include #include namespace ns3 @@ -483,6 +484,27 @@ class ThreeGppChannelConditionModel : public ChannelConditionModel */ int64_t AssignStreams(int64_t stream) override; + /** + * Computes and quantizes the elevation angle to a two-digits integer in [10, 90]. + * Asserts that the provided mobility models are of the expected type, i.e., + * GeocentricConstantPositionMobilityModel, and that the quantized + * angle is in the expected range [10, 90]. + * + * \param a mobility model + * \param b mobility model + * \return the tuple [elevation angle, quantized elevation angle] between a and b + */ + static std::tuple GetQuantizedElevationAngle(Ptr a, + Ptr b); + + /** + * \brief Computes the 2D distance between two 3D vectors + * \param a the first 3D vector + * \param b the second 3D vector + * \return the 2D distance between a and b + */ + static double Calculate2dDistance(const Vector& a, const Vector& b); + protected: void DoDispose() override; @@ -497,14 +519,6 @@ class ThreeGppChannelConditionModel : public ChannelConditionModel INVALID }; - /** - * \brief Computes the 2D distance between two 3D vectors - * \param a the first 3D vector - * \param b the second 3D vector - * \return the 2D distance between a and b - */ - static double Calculate2dDistance(const Vector& a, const Vector& b); - Ptr m_uniformVar; //!< uniform random variable private: @@ -782,6 +796,154 @@ class ThreeGppIndoorOpenOfficeChannelConditionModel : public ThreeGppChannelCond double ComputePlos(Ptr a, Ptr b) const override; }; +/** + * \ingroup propagation + * + * \brief Computes the channel condition for the NTN Dense Urban Scenario + * + * Computes the channel condition following the specifications for the + * Indoor Mixed Office scenario reported in Table 6.6.1-1 of 3GPP TR 38.811 + */ +class ThreeGppNTNDenseUrbanChannelConditionModel : public ThreeGppChannelConditionModel +{ + public: + /** + * Register this type. + * \return The object TypeId. + */ + static TypeId GetTypeId(); + + /** + * Constructor for the ThreeGppNTNDenseUrbanChannelConditionModel class + */ + ThreeGppNTNDenseUrbanChannelConditionModel() = default; + + /** + * Destructor for the ThreeGppNTNDenseUrbanChannelConditionModel class + */ + ~ThreeGppNTNDenseUrbanChannelConditionModel() override = default; + + private: + /** + * \copydoc ThreeGppChannelConditionModel::ComputePlos + * + * Compute the LOS probability as specified in Table 6.6.1-1 of 3GPP TR 38.811 + * for the NTN Dense Urban scenario. + */ + double ComputePlos(Ptr a, Ptr b) const override; +}; + +/** + * \ingroup propagation + * + * \brief Computes the channel condition for the NTN Urban Scenario + * + * Computes the channel condition following the specifications for the + * Indoor Mixed Office scenario reported in Table 6.6.1-1 of 3GPP TR 38.811 + */ +class ThreeGppNTNUrbanChannelConditionModel : public ThreeGppChannelConditionModel +{ + public: + /** + * Register this type. + * \return The object TypeId. + */ + static TypeId GetTypeId(); + + /** + * Constructor for the ThreeGppNTNUrbanChannelConditionModel class + */ + ThreeGppNTNUrbanChannelConditionModel() = default; + + /** + * Destructor for the ThreeGppNTNUrbanChannelConditionModel class + */ + ~ThreeGppNTNUrbanChannelConditionModel() override = default; + + private: + /** + * \copydoc ThreeGppChannelConditionModel::ComputePlos + * + * Compute the LOS probability as specified in Table 6.6.1-1 of 3GPP TR 38.811 + * for the NTN Urban scenario. + */ + double ComputePlos(Ptr a, Ptr b) const override; +}; + +/** + * \ingroup propagation + * + * \brief Computes the channel condition for the NTN Suburban Scenario + * + * Computes the channel condition following the specifications for the + * Indoor Mixed Office scenario reported in Table 6.6.1-1 of 3GPP TR 38.811 + */ +class ThreeGppNTNSuburbanChannelConditionModel : public ThreeGppChannelConditionModel +{ + public: + /** + * Register this type. + * \return The object TypeId. + */ + static TypeId GetTypeId(); + + /** + * Constructor for the ThreeGppNTNSuburbanChannelConditionModel class + */ + ThreeGppNTNSuburbanChannelConditionModel() = default; + + /** + * Destructor for the ThreeGppNTNSuburbanChannelConditionModel class + */ + ~ThreeGppNTNSuburbanChannelConditionModel() override = default; + + private: + /** + * \copydoc ThreeGppChannelConditionModel::ComputePlos + * + * Compute the LOS probability as specified in Table 6.6.1-1 of 3GPP TR 38.811 + * for the NTN Suburban scenario. + */ + double ComputePlos(Ptr a, Ptr b) const override; +}; + +/** + * \ingroup propagation + * + * \brief Computes the channel condition for the NTN Rural Scenario + * + * Computes the channel condition following the specifications for the + * Indoor Mixed Office scenario reported in Table 6.6.1-1 of 3GPP TR 38.811 + */ +class ThreeGppNTNRuralChannelConditionModel : public ThreeGppChannelConditionModel +{ + public: + /** + * Register this type. + * \return The object TypeId. + */ + static TypeId GetTypeId(); + + /** + * Constructor for the ThreeGppNTNRuralChannelConditionModel class + */ + ThreeGppNTNRuralChannelConditionModel() = default; + + /** + * Destructor for the ThreeGppNTNRuralChannelConditionModel class + */ + ~ThreeGppNTNRuralChannelConditionModel() override = default; + + private: + /** + * \copydoc ThreeGppChannelConditionModel::ComputePlos + * + * Compute the LOS probability as specified in Table 6.6.1-1 of 3GPP TR 38.811 + * for the NTN Rural scenario. + */ + double ComputePlos(Ptr a, Ptr b) const override; +}; + } // namespace ns3 #endif /* CHANNEL_CONDITION_MODEL_H */ diff --git a/src/propagation/model/three-gpp-propagation-loss-model.cc b/src/propagation/model/three-gpp-propagation-loss-model.cc index b6a210816..39f294e37 100644 --- a/src/propagation/model/three-gpp-propagation-loss-model.cc +++ b/src/propagation/model/three-gpp-propagation-loss-model.cc @@ -22,6 +22,7 @@ #include "ns3/boolean.h" #include "ns3/double.h" +#include "ns3/geocentric-constant-position-mobility-model.h" #include "ns3/log.h" #include "ns3/mobility-model.h" #include "ns3/node.h" @@ -30,15 +31,247 @@ #include +namespace +{ +/** + * The enumerator used for code clarity when performing parameter assignment in the GetLoss Methods + */ +enum SFCL_params +{ + S_LOS_sigF, + S_NLOS_sigF, + S_NLOS_CL, + Ka_LOS_sigF, + Ka_NLOS_sigF, + Ka_NLOS_CL, +}; + +/** + * The map containing the 3GPP value regarding Shadow Fading and Clutter Loss tables for the + * NTN Dense Urban scenario + */ +const std::map> SFCL_DenseUrban{ + {10, {3.5, 15.5, 34.3, 2.9, 17.1, 44.3}}, + {20, {3.4, 13.9, 30.9, 2.4, 17.1, 39.9}}, + {30, {2.9, 12.4, 29.0, 2.7, 15.6, 37.5}}, + {40, {3.0, 11.7, 27.7, 2.4, 14.6, 35.8}}, + {50, {3.1, 10.6, 26.8, 2.4, 14.2, 34.6}}, + {60, {2.7, 10.5, 26.2, 2.7, 12.6, 33.8}}, + {70, {2.5, 10.1, 25.8, 2.6, 12.1, 33.3}}, + {80, {2.3, 9.2, 25.5, 2.8, 12.3, 33.0}}, + {90, {1.2, 9.2, 25.5, 0.6, 12.3, 32.9}}, +}; + +/** + * The map containing the 3GPP value regarding Shadow Fading and Clutter Loss tables for the + * NTN Urban scenario + */ +const std::map> SFCL_Urban{ + {10, {4, 6, 34.3, 4, 6, 44.3}}, + {20, {4, 6, 30.9, 4, 6, 39.9}}, + {30, {4, 6, 29.0, 4, 6, 37.5}}, + {40, {4, 6, 27.7, 4, 6, 35.8}}, + {50, {4, 6, 26.8, 4, 6, 34.6}}, + {60, {4, 6, 26.2, 4, 6, 33.8}}, + {70, {4, 6, 25.8, 4, 6, 33.3}}, + {80, {4, 6, 25.5, 4, 6, 33.0}}, + {90, {4, 6, 25.5, 4, 6, 32.9}}, +}; + +/** + * The map containing the 3GPP value regarding Shadow Fading and Clutter Loss tables for the + * NTN Suburban and Rural scenarios + */ +const std::map> SFCL_SuburbanRural{ + {10, {1.79, 8.93, 19.52, 1.9, 10.7, 29.5}}, + {20, {1.14, 9.08, 18.17, 1.6, 10.0, 24.6}}, + {30, {1.14, 8.78, 18.42, 1.9, 11.2, 21.9}}, + {40, {0.92, 10.25, 18.28, 2.3, 11.6, 20.0}}, + {50, {1.42, 10.56, 18.63, 2.7, 11.8, 18.7}}, + {60, {1.56, 10.74, 17.68, 3.1, 10.8, 17.8}}, + {70, {0.85, 10.17, 16.5, 3.0, 10.8, 17.2}}, + {80, {0.72, 11.52, 16.3, 3.6, 10.8, 16.9}}, + {90, {0.72, 11.52, 16.3, 0.4, 10.8, 16.8}}, +}; + +/** + * Array containing the attenuation given by atmospheric absorption. 100 samples are selected for + * frequencies from 1GHz to 100GHz. In order to get the atmospheric absorption loss for a given + * frequency f: 1- round f to the closest integer between 0 and 100. 2- use the obtained integer to + * access the corresponding element in the array, that will give the attenuation at that frequency. + * Data is obtained form ITU-R P.676 Figure 6. + */ +const double atmosphericAbsorption[101] = { + 0, 0.0300, 0.0350, 0.0380, 0.0390, 0.0410, 0.0420, 0.0450, 0.0480, 0.0500, + 0.0530, 0.0587, 0.0674, 0.0789, 0.0935, 0.1113, 0.1322, 0.1565, 0.1841, 0.2153, + 0.2500, 0.3362, 0.4581, 0.5200, 0.5200, 0.5000, 0.4500, 0.3850, 0.3200, 0.2700, + 0.2500, 0.2517, 0.2568, 0.2651, 0.2765, 0.2907, 0.3077, 0.3273, 0.3493, 0.3736, + 0.4000, 0.4375, 0.4966, 0.5795, 0.6881, 0.8247, 0.9912, 1.1900, 1.4229, 1.6922, + 2.0000, 4.2654, 10.1504, 19.2717, 31.2457, 45.6890, 62.2182, 80.4496, 100.0000, 140.0205, + 170.0000, 100.0000, 78.1682, 59.3955, 43.5434, 30.4733, 20.0465, 12.1244, 6.5683, 3.2397, + 2.0000, 1.7708, 1.5660, 1.3858, 1.2298, 1.0981, 0.9905, 0.9070, 0.8475, 0.8119, + 0.8000, 0.8000, 0.8000, 0.8000, 0.8000, 0.8000, 0.8000, 0.8000, 0.8000, 0.8000, + 0.8000, 0.8029, 0.8112, 0.8243, 0.8416, 0.8625, 0.8864, 0.9127, 0.9408, 0.9701, + 1.0000}; + +/** + * Map containing the Tropospheric attenuation in dB with 99% probability at 20 GHz in Toulouse + * used for tropospheric scintillation losses. From Table 6.6.6.2.1-1 of 3GPP TR 38.811. + */ +const std::map troposphericScintillationLoss{ + {10, {1.08}}, + {20, {0.48}}, + {30, {0.30}}, + {40, {0.22}}, + {50, {0.17}}, + {60, {0.13}}, + {70, {0.12}}, + {80, {0.12}}, + {90, {0.12}}, +}; + +/** + * @brief Get the base station and user terminal relative distances and heights + * + * @param a the mobility model of terminal a + * @param b the mobility model of terminal b + * + * @return The tuple [dist2D, dist3D, hBs, hUt], where dist2D and dist3D + * are the 2D and 3D distances between a and b, respectively, hBs is the bigger + * height and hUt the smallest. + */ +std::tuple +GetBsUtDistancesAndHeights(ns3::Ptr a, + ns3::Ptr b) +{ + auto aPos = a->GetPosition(); + auto bPos = b->GetPosition(); + double distance2D = ns3::ThreeGppChannelConditionModel::Calculate2dDistance(aPos, bPos); + double distance3D = ns3::CalculateDistance(aPos, bPos); + double hBs = std::max(aPos.z, bPos.z); + double hUt = std::min(aPos.z, bPos.z); + return std::make_tuple(distance2D, distance3D, hBs, hUt); +}; + +/** + * @brief Get the base station and user terminal heights for the UmiStreetCanyon scenario + * + * @param heightA the first height in meters + * @param heightB the second height in meters + * + * @return The tuple [hBs, hUt], where hBs is assumed to be = 10 and hUt other height. + */ +std::tuple +GetBsUtHeightsUmiStreetCanyon(double heightA, double heightB) +{ + double hBs = (heightA == 10) ? heightA : heightB; + double hUt = (heightA == 10) ? heightB : heightA; + return std::make_tuple(hBs, hUt); +}; + +/** + * @brief Computes the free-space path loss using the formula described in 3GPP TR 38.811, + * Table 6.6.2 + * + * @param freq the operating frequency + * @param dist3d the 3D distance between the communicating nodes + * + * @return the path loss for NTN scenarios + */ +double +ComputeNtnPathloss(double freq, double dist3d) +{ + return 32.45 + 20 * log10(freq / 1e9) + 20 * log10(dist3d); +}; + +/** + * @brief Computes the atmospheric absorption loss using the formula described in 3GPP TR 38.811, + * Sec 6.6.4 + * + * @param freq the operating frequency + * @param elevAngle the elevation angle between the communicating nodes + * + * @return the atmospheric absorption loss for NTN scenarios + */ +double +ComputeAtmosphericAbsorptionLoss(double freq, double elevAngle) +{ + double loss = 0; + if ((elevAngle < 10 && freq > 1e9) || freq >= 10e9) + { + int roundedFreq = round(freq / 10e8); + loss += atmosphericAbsorption[roundedFreq] / sin(elevAngle * (M_PI / 180)); + } + + return loss; +}; + +/** + * @brief Computes the ionospheric plus tropospheric scintillation loss using the formulas + * described in 3GPP TR 38.811, Sec 6.6.6.1-4 and 6.6.6.2, respectively. + * + * @param freq the operating frequency + * @param elevAngleQuantized the quantized elevation angle between the communicating nodes + * + * @return the ionospheric plus tropospheric scintillation loss for NTN scenarios + */ +double +ComputeIonosphericPlusTroposphericScintillationLoss(double freq, double elevAngleQuantized) +{ + double loss = 0; + if (freq < 6e9) + { + // Ionospheric + loss = 6.22 / (pow(freq / 1e9, 1.5)); + } + else + { + // Tropospheric + loss = troposphericScintillationLoss.at(elevAngleQuantized); + } + return loss; +}; + +/** + * @brief Computes the clutter loss using the formula + * described in 3GPP TR 38.811, Sec 6.6.6.1-4 and 6.6.6.2, respectively. + * + * @param freq the operating frequency + * @param elevAngleQuantized the quantized elevation angle between the communicating nodes + * @param sfcl the nested map containing the Shadow Fading and + * Clutter Loss values for the NTN Suburban and Rural scenario + * + * @return the clutter loss for NTN scenarios + */ +double +ComputeClutterLoss(double freq, + const std::map>* sfcl, + double elevAngleQuantized) +{ + double loss = 0; + if (freq < 13.0e9) + { + loss += (*sfcl).at(elevAngleQuantized)[SFCL_params::S_NLOS_CL]; // Get the Clutter Loss for + // the S Band + } + else + { + loss += (*sfcl).at(elevAngleQuantized)[SFCL_params::Ka_NLOS_CL]; // Get the Clutter Loss for + // the Ka Band + } + + return loss; +}; + +static const double M_C = 3.0e8; //!< propagation velocity in free space + +} // namespace + namespace ns3 { NS_LOG_COMPONENT_DEFINE("ThreeGppPropagationLossModel"); -static const double M_C = 3.0e8; //!< propagation velocity in free space - -// ------------------------------------------------------------------------- // - NS_OBJECT_ENSURE_REGISTERED(ThreeGppPropagationLossModel); TypeId @@ -165,17 +398,8 @@ ThreeGppPropagationLossModel::DoCalcRxPower(double txPowerDbm, NS_ASSERT_MSG(m_channelConditionModel, "First set the channel condition model"); Ptr cond = m_channelConditionModel->GetChannelCondition(a, b); - // compute the 2D distance between a and b - double distance2d = Calculate2dDistance(a->GetPosition(), b->GetPosition()); - - // compute the 3D distance between a and b - double distance3d = CalculateDistance(a->GetPosition(), b->GetPosition()); - - // compute hUT and hBS - std::pair heights = GetUtAndBsHeights(a->GetPosition().z, b->GetPosition().z); - double rxPow = txPowerDbm; - rxPow -= GetLoss(cond, distance2d, distance3d, heights.first, heights.second); + rxPow -= GetLoss(cond, a, b); if (m_shadowingEnabled) { @@ -203,28 +427,24 @@ ThreeGppPropagationLossModel::DoCalcRxPower(double txPowerDbm, double ThreeGppPropagationLossModel::GetLoss(Ptr cond, - double distance2d, - double distance3d, - double hUt, - double hBs) const + Ptr a, + Ptr b) const { NS_LOG_FUNCTION(this); double loss = 0; - if (cond->GetLosCondition() == ChannelCondition::LosConditionValue::LOS) - { - loss = GetLossLos(distance2d, distance3d, hUt, hBs); - } - else if (cond->GetLosCondition() == ChannelCondition::LosConditionValue::NLOSv) - { - loss = GetLossNlosv(distance2d, distance3d, hUt, hBs); - } - else if (cond->GetLosCondition() == ChannelCondition::LosConditionValue::NLOS) - { - loss = GetLossNlos(distance2d, distance3d, hUt, hBs); - } - else + switch (cond->GetLosCondition()) { + case ChannelCondition::LosConditionValue::LOS: + loss = GetLossLos(a, b); + break; + case ChannelCondition::LosConditionValue::NLOSv: + loss = GetLossNlosv(a, b); + break; + case ChannelCondition::LosConditionValue::NLOS: + loss = GetLossNlos(a, b); + break; + default: NS_FATAL_ERROR("Unknown channel condition"); } @@ -391,10 +611,7 @@ ThreeGppPropagationLossModel::DoIsO2iLowPenetrationLoss(Ptr a, Ptr b) const { NS_LOG_FUNCTION(this); NS_FATAL_ERROR("Unsupported channel condition (NLOSv)"); @@ -458,17 +675,6 @@ ThreeGppPropagationLossModel::GetShadowing(Ptr a, return shadowingValue; } -std::pair -ThreeGppPropagationLossModel::GetUtAndBsHeights(double za, double zb) const -{ - // The default implementation assumes that the tallest node is the BS and the - // smallest is the UT. - double hUt = std::min(za, zb); - double hBs = std::max(za, zb); - - return std::pair(hUt, hBs); -} - int64_t ThreeGppPropagationLossModel::DoAssignStreams(int64_t stream) { @@ -579,15 +785,14 @@ ThreeGppRmaPropagationLossModel::DoIsO2iLowPenetrationLoss(Ptr a, Ptr b) const { NS_LOG_FUNCTION(this); NS_ASSERT_MSG(m_frequency <= 30.0e9, "RMa scenario is valid for frequencies between 0.5 and 30 GHz."); + auto [distance2D, distance3D, hBs, hUt] = GetBsUtDistancesAndHeights(a, b); + // check if hBS and hUT are within the specified validity range if (hUt < 1.0 || hUt > 10.0) { @@ -643,15 +848,14 @@ ThreeGppRmaPropagationLossModel::GetLossLos(double distance2D, } double -ThreeGppRmaPropagationLossModel::GetLossNlos(double distance2D, - double distance3D, - double hUt, - double hBs) const +ThreeGppRmaPropagationLossModel::GetLossNlos(Ptr a, Ptr b) const { NS_LOG_FUNCTION(this); NS_ASSERT_MSG(m_frequency <= 30.0e9, "RMa scenario is valid for frequencies between 0.5 and 30 GHz."); + auto [distance2D, distance3D, hBs, hUt] = GetBsUtDistancesAndHeights(a, b); + // check if hBs and hUt are within the validity range if (hUt < 1.0 || hUt > 10.0) { @@ -688,7 +892,7 @@ ThreeGppRmaPropagationLossModel::GetLossNlos(double distance2D, (43.42 - 3.1 * log10(hBs)) * (log10(distance3D) - 3.0) + 20.0 * log10(m_frequency / 1e9) - (3.2 * pow(log10(11.75 * hUt), 2) - 4.97); - double loss = std::max(GetLossLos(distance2D, distance3D, hUt, hBs), plNlos); + double loss = std::max(GetLossLos(a, b), plNlos); NS_LOG_DEBUG("Loss " << loss); @@ -839,13 +1043,12 @@ ThreeGppUmaPropagationLossModel::GetBpDistance(double hUt, double hBs, double di } double -ThreeGppUmaPropagationLossModel::GetLossLos(double distance2D, - double distance3D, - double hUt, - double hBs) const +ThreeGppUmaPropagationLossModel::GetLossLos(Ptr a, Ptr b) const { NS_LOG_FUNCTION(this); + auto [distance2D, distance3D, hBs, hUt] = GetBsUtDistancesAndHeights(a, b); + // check if hBS and hUT are within the validity range if (hUt < 1.5 || hUt > 22.5) { @@ -907,14 +1110,13 @@ ThreeGppUmaPropagationLossModel::GetO2iDistance2dIn() const } double -ThreeGppUmaPropagationLossModel::GetLossNlos(double distance2D, - double distance3D, - double hUt, - double hBs) const +ThreeGppUmaPropagationLossModel::GetLossNlos(Ptr a, Ptr b) const { NS_LOG_FUNCTION(this); - // check if hBS and hUT are within the vaalidity range + auto [distance2D, distance3D, hBs, hUt] = GetBsUtDistancesAndHeights(a, b); + + // check if hBS and hUT are within the validity range if (hUt < 1.5 || hUt > 22.5) { NS_ABORT_MSG_IF(m_enforceRanges, "Uma UT height out of range"); @@ -946,7 +1148,7 @@ ThreeGppUmaPropagationLossModel::GetLossNlos(double distance2D, // compute the pathloss double plNlos = 13.54 + 39.08 * log10(distance3D) + 20.0 * log10(m_frequency / 1e9) - 0.6 * (hUt - 1.5); - double loss = std::max(GetLossLos(distance2D, distance3D, hUt, hBs), plNlos); + double loss = std::max(GetLossLos(a, b), plNlos); NS_LOG_DEBUG("Loss " << loss); return loss; @@ -1063,13 +1265,15 @@ ThreeGppUmiStreetCanyonPropagationLossModel::GetO2iDistance2dIn() const } double -ThreeGppUmiStreetCanyonPropagationLossModel::GetLossLos(double distance2D, - double distance3D, - double hUt, - double hBs) const +ThreeGppUmiStreetCanyonPropagationLossModel::GetLossLos(Ptr a, + Ptr b) const { NS_LOG_FUNCTION(this); + double distance2D = Calculate2dDistance(a->GetPosition(), b->GetPosition()); + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + auto [hBs, hUt] = GetBsUtHeightsUmiStreetCanyon(a->GetPosition().z, b->GetPosition().z); + // check if hBS and hUT are within the validity range if (hUt < 1.5 || hUt >= 10.0) { @@ -1124,13 +1328,15 @@ ThreeGppUmiStreetCanyonPropagationLossModel::GetLossLos(double distance2D, } double -ThreeGppUmiStreetCanyonPropagationLossModel::GetLossNlos(double distance2D, - double distance3D, - double hUt, - double hBs) const +ThreeGppUmiStreetCanyonPropagationLossModel::GetLossNlos(Ptr a, + Ptr b) const { NS_LOG_FUNCTION(this); + double distance2D = Calculate2dDistance(a->GetPosition(), b->GetPosition()); + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + auto [hBs, hUt] = GetBsUtHeightsUmiStreetCanyon(a->GetPosition().z, b->GetPosition().z); + // check if hBS and hUT are within the validity range if (hUt < 1.5 || hUt >= 10.0) { @@ -1164,42 +1370,12 @@ ThreeGppUmiStreetCanyonPropagationLossModel::GetLossNlos(double distance2D, // compute the pathloss double plNlos = 22.4 + 35.3 * log10(distance3D) + 21.3 * log10(m_frequency / 1e9) - 0.3 * (hUt - 1.5); - double loss = std::max(GetLossLos(distance2D, distance3D, hUt, hBs), plNlos); + double loss = std::max(GetLossLos(a, b), plNlos); NS_LOG_DEBUG("Loss " << loss); return loss; } -std::pair -ThreeGppUmiStreetCanyonPropagationLossModel::GetUtAndBsHeights(double za, double zb) const -{ - NS_LOG_FUNCTION(this); - // TR 38.901 specifies hBS = 10 m and 1.5 <= hUT <= 22.5 - double hBs; - double hUt; - if (za == 10.0) - { - // node A is the BS and node B is the UT - hBs = za; - hUt = zb; - } - else if (zb == 10.0) - { - // node B is the BS and node A is the UT - hBs = zb; - hUt = za; - } - else - { - // We cannot know who is the BS and who is the UT, we assume that the - // tallest node is the BS and the smallest is the UT - hBs = std::max(za, zb); - hUt = std::min(za, zb); - } - - return std::pair(hUt, hBs); -} - double ThreeGppUmiStreetCanyonPropagationLossModel::GetShadowingStd( Ptr /* a */, @@ -1284,13 +1460,13 @@ ThreeGppIndoorOfficePropagationLossModel::GetO2iDistance2dIn() const } double -ThreeGppIndoorOfficePropagationLossModel::GetLossLos(double /* distance2D */, - double distance3D, - double /* hUt */, - double /* hBs */) const +ThreeGppIndoorOfficePropagationLossModel::GetLossLos(Ptr a, + Ptr b) const { NS_LOG_FUNCTION(this); + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + // check if the distance is outside the validity range if (distance3D < 1.0 || distance3D > 150.0) { @@ -1308,13 +1484,13 @@ ThreeGppIndoorOfficePropagationLossModel::GetLossLos(double /* distance2D */, } double -ThreeGppIndoorOfficePropagationLossModel::GetLossNlos(double distance2D, - double distance3D, - double hUt, - double hBs) const +ThreeGppIndoorOfficePropagationLossModel::GetLossNlos(Ptr a, + Ptr b) const { NS_LOG_FUNCTION(this); + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + // check if the distance is outside the validity range if (distance3D < 1.0 || distance3D > 150.0) { @@ -1325,7 +1501,7 @@ ThreeGppIndoorOfficePropagationLossModel::GetLossNlos(double distance2D, // compute the pathloss double plNlos = 17.3 + 38.3 * log10(distance3D) + 24.9 * log10(m_frequency / 1e9); - double loss = std::max(GetLossLos(distance2D, distance3D, hUt, hBs), plNlos); + double loss = std::max(GetLossLos(a, b), plNlos); NS_LOG_DEBUG("Loss " << loss); @@ -1382,4 +1558,591 @@ ThreeGppIndoorOfficePropagationLossModel::GetShadowingCorrelationDistance( return correlationDistance; } +NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNDenseUrbanPropagationLossModel); + +TypeId +ThreeGppNTNDenseUrbanPropagationLossModel::GetTypeId() +{ + static TypeId tid = TypeId("ns3::ThreeGppNTNDenseUrbanPropagationLossModel") + .SetParent() + .SetGroupName("Propagation") + .AddConstructor(); + return tid; +} + +ThreeGppNTNDenseUrbanPropagationLossModel::ThreeGppNTNDenseUrbanPropagationLossModel() + : ThreeGppPropagationLossModel(), + m_SFCL_DenseUrban(&SFCL_DenseUrban) +{ + NS_LOG_FUNCTION(this); + m_channelConditionModel = CreateObject(); +} + +ThreeGppNTNDenseUrbanPropagationLossModel::~ThreeGppNTNDenseUrbanPropagationLossModel() +{ + NS_LOG_FUNCTION(this); +} + +double +ThreeGppNTNDenseUrbanPropagationLossModel::GetO2iDistance2dIn() const +{ + abort(); +} + +double +ThreeGppNTNDenseUrbanPropagationLossModel::GetLossLos(Ptr a, + Ptr b) const +{ + NS_LOG_FUNCTION(this); + NS_ASSERT_MSG(m_frequency <= 100.0e9, + "NTN communications are valid for frequencies between 0.5 and 100 GHz."); + + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2) + double loss = ComputeNtnPathloss(m_frequency, distance3D); + + // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4 + loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle); + + // Apply Ionospheric plus Tropospheric Scintillation Loss + loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized); + + NS_LOG_DEBUG("Loss " << loss); + return loss; +} + +double +ThreeGppNTNDenseUrbanPropagationLossModel::GetLossNlos(Ptr a, + Ptr b) const +{ + NS_LOG_FUNCTION(this); + NS_ASSERT_MSG(m_frequency <= 100.0e9, + "NTN communications are valid for frequencies between 0.5 and 100 GHz."); + + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2) + double loss = ComputeNtnPathloss(m_frequency, distance3D); + + // Apply Clutter Loss + loss += ComputeClutterLoss(m_frequency, m_SFCL_DenseUrban, elevAngleQuantized); + + // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4 + loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle); + + // Apply Ionospheric plus Tropospheric Scintillation Loss + loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized); + + NS_LOG_DEBUG("Loss " << loss); + return loss; +} + +double +ThreeGppNTNDenseUrbanPropagationLossModel::GetShadowingStd( + Ptr a, + Ptr b, + ChannelCondition::LosConditionValue cond) const +{ + NS_LOG_FUNCTION(this); + double shadowingStd; + + std::string freqBand = (m_frequency < 13.0e9) ? "S" : "Ka"; + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // Assign Shadowing Standard Deviation according to table 6.6.2-1 + if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "S") + { + shadowingStd = (*m_SFCL_DenseUrban).at(elevAngleQuantized)[SFCL_params::S_LOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "Ka") + { + shadowingStd = (*m_SFCL_DenseUrban).at(elevAngleQuantized)[SFCL_params::Ka_LOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "S") + { + shadowingStd = (*m_SFCL_DenseUrban).at(elevAngleQuantized)[SFCL_params::S_NLOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "Ka") + { + shadowingStd = (*m_SFCL_DenseUrban).at(elevAngleQuantized)[SFCL_params::Ka_NLOS_sigF]; + } + else + { + NS_FATAL_ERROR("Unknown channel condition"); + } + + return shadowingStd; +} + +double +ThreeGppNTNDenseUrbanPropagationLossModel::GetShadowingCorrelationDistance( + ChannelCondition::LosConditionValue cond) const +{ + NS_LOG_FUNCTION(this); + double correlationDistance; + + // See 3GPP TR 38.811, Table 6.7.2-1a/b and Table 6.7.2-2a/b + if (cond == ChannelCondition::LosConditionValue::LOS) + { + correlationDistance = 37; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS) + { + correlationDistance = 50; + } + else + { + NS_FATAL_ERROR("Unknown channel condition"); + } + + return correlationDistance; +} + +// ------------------------------------------------------------------------- // + +NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNUrbanPropagationLossModel); + +TypeId +ThreeGppNTNUrbanPropagationLossModel::GetTypeId() +{ + static TypeId tid = TypeId("ns3::ThreeGppNTNUrbanPropagationLossModel") + .SetParent() + .SetGroupName("Propagation") + .AddConstructor(); + return tid; +} + +ThreeGppNTNUrbanPropagationLossModel::ThreeGppNTNUrbanPropagationLossModel() + : ThreeGppPropagationLossModel(), + m_SFCL_Urban(&SFCL_Urban) +{ + NS_LOG_FUNCTION(this); + m_channelConditionModel = CreateObject(); +} + +ThreeGppNTNUrbanPropagationLossModel::~ThreeGppNTNUrbanPropagationLossModel() +{ + NS_LOG_FUNCTION(this); +} + +double +ThreeGppNTNUrbanPropagationLossModel::GetO2iDistance2dIn() const +{ + abort(); +} + +double +ThreeGppNTNUrbanPropagationLossModel::GetLossLos(Ptr a, Ptr b) const +{ + NS_LOG_FUNCTION(this); + NS_ASSERT_MSG(m_frequency <= 100.0e9, + "NTN communications are valid for frequencies between 0.5 and 100 GHz."); + + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2) + double loss = ComputeNtnPathloss(m_frequency, distance3D); + + // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4 + loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle); + + // Apply Ionospheric plus Tropospheric Scintillation Loss + loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized); + + NS_LOG_DEBUG("Loss " << loss); + return loss; +} + +double +ThreeGppNTNUrbanPropagationLossModel::GetLossNlos(Ptr a, Ptr b) const +{ + NS_LOG_FUNCTION(this); + NS_ASSERT_MSG(m_frequency <= 100.0e9, + "NTN communications are valid for frequencies between 0.5 and 100 GHz."); + + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2) + double loss = ComputeNtnPathloss(m_frequency, distance3D); + + // Apply Clutter Loss + loss += ComputeClutterLoss(m_frequency, m_SFCL_Urban, elevAngleQuantized); + + // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4 + loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle); + + // Apply Ionospheric plus Tropospheric Scintillation Loss + loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized); + + NS_LOG_DEBUG("Loss " << loss); + return loss; +} + +double +ThreeGppNTNUrbanPropagationLossModel::GetShadowingStd( + Ptr a, + Ptr b, + ChannelCondition::LosConditionValue cond) const +{ + NS_LOG_FUNCTION(this); + double shadowingStd; + + std::string freqBand = (m_frequency < 13.0e9) ? "S" : "Ka"; + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // Assign Shadowing Standard Deviation according to table 6.6.2-1 + if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "S") + { + shadowingStd = (*m_SFCL_Urban).at(elevAngleQuantized)[SFCL_params::S_LOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "Ka") + { + shadowingStd = (*m_SFCL_Urban).at(elevAngleQuantized)[SFCL_params::Ka_LOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "S") + { + shadowingStd = (*m_SFCL_Urban).at(elevAngleQuantized)[SFCL_params::S_NLOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "Ka") + { + shadowingStd = (*m_SFCL_Urban).at(elevAngleQuantized)[SFCL_params::Ka_NLOS_sigF]; + } + else + { + NS_FATAL_ERROR("Unknown channel condition"); + } + + return shadowingStd; +} + +double +ThreeGppNTNUrbanPropagationLossModel::GetShadowingCorrelationDistance( + ChannelCondition::LosConditionValue cond) const +{ + NS_LOG_FUNCTION(this); + double correlationDistance; + + // See 3GPP TR 38.811, Table 6.7.2-3a/b and Table 6.7.2-3a/b + if (cond == ChannelCondition::LosConditionValue::LOS) + { + correlationDistance = 37; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS) + { + correlationDistance = 50; + } + else + { + NS_FATAL_ERROR("Unknown channel condition"); + } + + return correlationDistance; +} + +// ------------------------------------------------------------------------- // + +NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNSuburbanPropagationLossModel); + +TypeId +ThreeGppNTNSuburbanPropagationLossModel::GetTypeId() +{ + static TypeId tid = TypeId("ns3::ThreeGppNTNSuburbanPropagationLossModel") + .SetParent() + .SetGroupName("Propagation") + .AddConstructor(); + return tid; +} + +ThreeGppNTNSuburbanPropagationLossModel::ThreeGppNTNSuburbanPropagationLossModel() + : ThreeGppPropagationLossModel(), + m_SFCL_SuburbanRural(&SFCL_SuburbanRural) +{ + NS_LOG_FUNCTION(this); + m_channelConditionModel = CreateObject(); +} + +ThreeGppNTNSuburbanPropagationLossModel::~ThreeGppNTNSuburbanPropagationLossModel() +{ + NS_LOG_FUNCTION(this); +} + +double +ThreeGppNTNSuburbanPropagationLossModel::GetO2iDistance2dIn() const +{ + abort(); +} + +double +ThreeGppNTNSuburbanPropagationLossModel::GetLossLos(Ptr a, + Ptr b) const +{ + NS_LOG_FUNCTION(this); + NS_ASSERT_MSG(m_frequency <= 100.0e9, + "NTN communications are valid for frequencies between 0.5 and 100 GHz."); + + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2) + double loss = ComputeNtnPathloss(m_frequency, distance3D); + + // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4 + loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle); + + // Apply Ionospheric plus Tropospheric Scintillation Loss + loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized); + + NS_LOG_DEBUG("Loss " << loss); + + return loss; +} + +double +ThreeGppNTNSuburbanPropagationLossModel::GetLossNlos(Ptr a, + Ptr b) const +{ + NS_LOG_FUNCTION(this); + NS_ASSERT_MSG(m_frequency <= 100.0e9, + "NTN communications are valid for frequencies between 0.5 and 100 GHz."); + + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2) + double loss = ComputeNtnPathloss(m_frequency, distance3D); + + // Apply Clutter Loss + loss += ComputeClutterLoss(m_frequency, m_SFCL_SuburbanRural, elevAngleQuantized); + + // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4 + loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle); + + // Apply Ionospheric plus Tropospheric Scintillation Loss + loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized); + + NS_LOG_DEBUG("Loss " << loss); + return loss; +} + +double +ThreeGppNTNSuburbanPropagationLossModel::GetShadowingStd( + Ptr a, + Ptr b, + ChannelCondition::LosConditionValue cond) const +{ + NS_LOG_FUNCTION(this); + double shadowingStd; + + std::string freqBand = (m_frequency < 13.0e9) ? "S" : "Ka"; + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // Assign Shadowing Standard Deviation according to table 6.6.2-1 + if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "S") + { + shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::S_LOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "Ka") + { + shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::Ka_LOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "S") + { + shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::S_NLOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "Ka") + { + shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::Ka_NLOS_sigF]; + } + else + { + NS_FATAL_ERROR("Unknown channel condition"); + } + + return shadowingStd; +} + +double +ThreeGppNTNSuburbanPropagationLossModel::GetShadowingCorrelationDistance( + ChannelCondition::LosConditionValue cond) const +{ + NS_LOG_FUNCTION(this); + double correlationDistance; + + // See 3GPP TR 38.811, Table 6.7.2-5a/b and Table 6.7.2-6a/b + if (cond == ChannelCondition::LosConditionValue::LOS) + { + correlationDistance = 37; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS) + { + correlationDistance = 50; + } + else + { + NS_FATAL_ERROR("Unknown channel condition"); + } + + return correlationDistance; +} + +// ------------------------------------------------------------------------- // + +NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNRuralPropagationLossModel); + +TypeId +ThreeGppNTNRuralPropagationLossModel::GetTypeId() +{ + static TypeId tid = TypeId("ns3::ThreeGppNTNRuralPropagationLossModel") + .SetParent() + .SetGroupName("Propagation") + .AddConstructor(); + return tid; +} + +ThreeGppNTNRuralPropagationLossModel::ThreeGppNTNRuralPropagationLossModel() + : ThreeGppPropagationLossModel(), + m_SFCL_SuburbanRural(&SFCL_SuburbanRural) +{ + NS_LOG_FUNCTION(this); + m_channelConditionModel = CreateObject(); +} + +ThreeGppNTNRuralPropagationLossModel::~ThreeGppNTNRuralPropagationLossModel() +{ + NS_LOG_FUNCTION(this); +} + +double +ThreeGppNTNRuralPropagationLossModel::GetO2iDistance2dIn() const +{ + abort(); +} + +double +ThreeGppNTNRuralPropagationLossModel::GetLossLos(Ptr a, Ptr b) const +{ + NS_LOG_FUNCTION(this); + NS_ASSERT_MSG(m_frequency <= 100.0e9, + "NTN communications are valid for frequencies between 0.5 and 100 GHz."); + + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2) + double loss = ComputeNtnPathloss(m_frequency, distance3D); + + // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4 + loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle); + + // Apply Ionospheric plus Tropospheric Scintillation Loss + loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized); + + NS_LOG_DEBUG("Loss " << loss); + return loss; +} + +double +ThreeGppNTNRuralPropagationLossModel::GetLossNlos(Ptr a, Ptr b) const +{ + NS_LOG_FUNCTION(this); + NS_ASSERT_MSG(m_frequency <= 100.0e9, + "NTN communications are valid for frequencies between 0.5 and 100 GHz."); + + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2) + double loss = ComputeNtnPathloss(m_frequency, distance3D); + + // Apply Clutter Loss + loss += ComputeClutterLoss(m_frequency, m_SFCL_SuburbanRural, elevAngleQuantized); + + // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4 + loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle); + + // Apply Ionospheric plus Tropospheric Scintillation Loss + loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized); + + NS_LOG_DEBUG("Loss " << loss); + return loss; +} + +double +ThreeGppNTNRuralPropagationLossModel::GetShadowingStd( + Ptr a, + Ptr b, + ChannelCondition::LosConditionValue cond) const +{ + NS_LOG_FUNCTION(this); + double shadowingStd; + + std::string freqBand = (m_frequency < 13.0e9) ? "S" : "Ka"; + auto [elevAngle, elevAngleQuantized] = + ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b); + + // Assign Shadowing Standard Deviation according to table 6.6.2-1 + if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "S") + { + shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::S_LOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "Ka") + { + shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::Ka_LOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "S") + { + shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::S_NLOS_sigF]; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "Ka") + { + shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::Ka_NLOS_sigF]; + } + else + { + NS_FATAL_ERROR("Unknown channel condition"); + } + + return shadowingStd; +} + +double +ThreeGppNTNRuralPropagationLossModel::GetShadowingCorrelationDistance( + ChannelCondition::LosConditionValue cond) const +{ + NS_LOG_FUNCTION(this); + double correlationDistance; + + // See 3GPP TR 38.811, Table 6.7.2-7a/b and Table 6.7.2-8a/b + if (cond == ChannelCondition::LosConditionValue::LOS) + { + correlationDistance = 37; + } + else if (cond == ChannelCondition::LosConditionValue::NLOS) + { + correlationDistance = 120; + } + else + { + NS_FATAL_ERROR("Unknown channel condition"); + } + + return correlationDistance; +} + } // namespace ns3 diff --git a/src/propagation/model/three-gpp-propagation-loss-model.h b/src/propagation/model/three-gpp-propagation-loss-model.h index 646b77dd2..99f84aaec 100644 --- a/src/propagation/model/three-gpp-propagation-loss-model.h +++ b/src/propagation/model/three-gpp-propagation-loss-model.h @@ -105,31 +105,29 @@ class ThreeGppPropagationLossModel : public PropagationLossModel /** * \brief Computes the pathloss between a and b * \param cond the channel condition - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a tx mobility model + * \param b rx mobility model * \return pathloss value in dB */ - double GetLoss(Ptr cond, - double distance2D, - double distance3D, - double hUt, - double hBs) const; + double GetLoss(Ptr cond, Ptr a, Ptr b) const; /** * \brief Computes the pathloss between a and b considering that the line of * sight is not obstructed - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a tx mobility model + * \param b rx mobility model * \return pathloss value in dB */ - virtual double GetLossLos(double distance2D, - double distance3D, - double hUt, - double hBs) const = 0; + virtual double GetLossLos(Ptr a, Ptr b) const = 0; + + /** + * \brief Computes the pathloss between a and b considering that the line of + * sight is obstructed + * \param a tx mobility model + * \param b rx mobility model + * \return pathloss value in dB + */ + virtual double GetLossNlos(Ptr a, Ptr b) const = 0; /** * \brief Returns the minimum of the two independently generated distances @@ -195,41 +193,15 @@ class ThreeGppPropagationLossModel : public PropagationLossModel */ virtual bool DoIsO2iLowPenetrationLoss(Ptr cond) const; - /** - * \brief Computes the pathloss between a and b considering that the line of - * sight is obstructed - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters - * \return pathloss value in dB - */ - virtual double GetLossNlos(double distance2D, - double distance3D, - double hUt, - double hBs) const = 0; - /** * \brief Computes the pathloss between a and b considering that the line of * sight is obstructed by a vehicle. By default it raises an error to * avoid misuse. - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a tx mobility model + * \param b rx mobility model * \return pathloss value in dB */ - virtual double GetLossNlosv(double distance2D, double distance3D, double hUt, double hBs) const; - - /** - * \brief Determines hUT and hBS. The default implementation assumes that - * the tallest node is the BS and the smallest is the UT. The derived classes - * can change the default behavior by overriding this method. - * \param za the height of the first node in meters - * \param zb the height of the second node in meters - * \return std::pair of heights in meters, the first element is hUt and the second is hBs - */ - virtual std::pair GetUtAndBsHeights(double za, double zb) const; + virtual double GetLossNlosv(Ptr a, Ptr b) const; /** * \brief Retrieves the shadowing value by looking at m_shadowingMap. @@ -374,13 +346,11 @@ class ThreeGppRmaPropagationLossModel : public ThreeGppPropagationLossModel /** * \brief Computes the pathloss between a and b considering that the line of * sight is not obstructed - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a tx mobility model + * \param b rx mobility model * \return pathloss value in dB */ - double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override; + double GetLossLos(Ptr a, Ptr b) const override; /** * \brief Returns the minimum of the two independently generated distances @@ -407,13 +377,11 @@ class ThreeGppRmaPropagationLossModel : public ThreeGppPropagationLossModel /** * \brief Computes the pathloss between a and b considering that the line of * sight is obstructed - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a tx mobility model + * \param b rx mobility model * \return pathloss value in dB */ - double GetLossNlos(double distance2D, double distance3D, double hUt, double hBs) const override; + double GetLossNlos(Ptr a, Ptr b) const override; /** * \brief Returns the shadow fading standard deviation @@ -491,13 +459,11 @@ class ThreeGppUmaPropagationLossModel : public ThreeGppPropagationLossModel /** * \brief Computes the pathloss between a and b considering that the line of * sight is not obstructed - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a tx mobility model + * \param b rx mobility model * \return pathloss value in dB */ - double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override; + double GetLossLos(Ptr a, Ptr b) const override; /** * \brief Returns the minimum of the two independently generated distances @@ -516,13 +482,11 @@ class ThreeGppUmaPropagationLossModel : public ThreeGppPropagationLossModel /** * \brief Computes the pathloss between a and b considering that the line of * sight is obstructed. - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a tx mobility model + * \param b rx mobility model * \return pathloss value in dB */ - double GetLossNlos(double distance2D, double distance3D, double hUt, double hBs) const override; + double GetLossNlos(Ptr a, Ptr b) const override; /** * \brief Returns the shadow fading standard deviation @@ -590,13 +554,11 @@ class ThreeGppUmiStreetCanyonPropagationLossModel : public ThreeGppPropagationLo /** * \brief Computes the pathloss between a and b considering that the line of * sight is not obstructed - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a tx mobility model + * \param b rx mobility model * \return pathloss value in dB */ - double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override; + double GetLossLos(Ptr a, Ptr b) const override; /** * \brief Returns the minimum of the two independently generated distances @@ -615,13 +577,11 @@ class ThreeGppUmiStreetCanyonPropagationLossModel : public ThreeGppPropagationLo /** * \brief Computes the pathloss between a and b considering that the line of * sight is obstructed. - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a tx mobility model + * \param b rx mobility model * \return pathloss value in dB */ - double GetLossNlos(double distance2D, double distance3D, double hUt, double hBs) const override; + double GetLossNlos(Ptr a, Ptr b) const override; /** * \brief Returns the shadow fading standard deviation @@ -649,14 +609,6 @@ class ThreeGppUmiStreetCanyonPropagationLossModel : public ThreeGppPropagationLo * \return the breakpoint distance in meters */ double GetBpDistance(double hUt, double hBs, double distance2D) const; - - /** - * \brief Determines hUT and hBS. Overrides the default implementation. - * \param za the height of the first node in meters - * \param zb the height of the second node in meters - * \return std::pair, the first element is hUt and the second is hBs - */ - std::pair GetUtAndBsHeights(double za, double zb) const override; }; /** @@ -694,13 +646,11 @@ class ThreeGppIndoorOfficePropagationLossModel : public ThreeGppPropagationLossM /** * \brief Computes the pathloss between a and b considering that the line of * sight is not obstructed - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a tx mobility model + * \param b rx mobility model * \return pathloss value in dB */ - double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override; + double GetLossLos(Ptr a, Ptr b) const override; /** * \brief Returns the minimum of the two independently generated distances @@ -719,13 +669,11 @@ class ThreeGppIndoorOfficePropagationLossModel : public ThreeGppPropagationLossM /** * \brief Computes the pathloss between a and b considering that the line of * sight is obstructed - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a tx mobility model + * \param b rx mobility model * \return pathloss value in dB */ - double GetLossNlos(double distance2D, double distance3D, double hUt, double hBs) const override; + double GetLossNlos(Ptr a, Ptr b) const override; /** * \brief Returns the shadow fading standard deviation @@ -746,6 +694,260 @@ class ThreeGppIndoorOfficePropagationLossModel : public ThreeGppPropagationLossM double GetShadowingCorrelationDistance(ChannelCondition::LosConditionValue cond) const override; }; +/** + * \ingroup propagation + * + * \brief Implements the pathloss model defined in 3GPP TR 38.811, Table ???? + * for the NTN Dense Urban scenario. + */ +class ThreeGppNTNDenseUrbanPropagationLossModel : public ThreeGppPropagationLossModel +{ + public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId(); + + /** + * Constructor + */ + ThreeGppNTNDenseUrbanPropagationLossModel(); + + /** + * Destructor + */ + ~ThreeGppNTNDenseUrbanPropagationLossModel() override; + + /** + * \copydoc ThreeGppPropagationLossModel::GetO2iDistance2dIn + * Does nothing in NTN scenarios. + */ + double GetO2iDistance2dIn() const override; + + /** + * \brief Copy constructor + * + * Deleted in base class + */ + ThreeGppNTNDenseUrbanPropagationLossModel(const ThreeGppNTNDenseUrbanPropagationLossModel&) = + delete; + + /** + * \brief Copy constructor + * + * Deleted in base class + * \returns the ThreeGppNTNDenseUrbanPropagationLossModel instance + */ + ThreeGppNTNDenseUrbanPropagationLossModel& operator=( + const ThreeGppNTNDenseUrbanPropagationLossModel&) = delete; + + private: + // Inherited + double GetLossLos(Ptr a, Ptr b) const override; + double GetLossNlos(Ptr a, Ptr b) const override; + double GetShadowingStd(Ptr a, + Ptr b, + ChannelCondition::LosConditionValue cond) const override; + double GetShadowingCorrelationDistance(ChannelCondition::LosConditionValue cond) const override; + + /** + * \brief The nested map containing the Shadow Fading and + * Clutter Loss values for the NTN Dense Urban scenario + */ + const std::map>* m_SFCL_DenseUrban; +}; + +/** + * \ingroup propagation + * + * \brief Implements the pathloss model defined in 3GPP TR 38.811, Table ???? + * for the NTN Urban scenario. + */ +class ThreeGppNTNUrbanPropagationLossModel : public ThreeGppPropagationLossModel +{ + public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId(); + + /** + * Constructor + */ + ThreeGppNTNUrbanPropagationLossModel(); + + /** + * Destructor + */ + ~ThreeGppNTNUrbanPropagationLossModel() override; + + /** + * \copydoc ThreeGppPropagationLossModel::GetO2iDistance2dIn + * Does nothing in NTN scenarios. + */ + double GetO2iDistance2dIn() const override; + + /** + * \brief Copy constructor + * + * Deleted in base class + */ + ThreeGppNTNUrbanPropagationLossModel(const ThreeGppNTNUrbanPropagationLossModel&) = delete; + + /** + * \brief Copy constructor + * + * Deleted in base class + * \returns the ThreeGppNTNUrbanPropagationLossModel instance + */ + ThreeGppNTNUrbanPropagationLossModel& operator=(const ThreeGppNTNUrbanPropagationLossModel&) = + delete; + + private: + // Inherited + double GetLossLos(Ptr a, Ptr b) const override; + double GetLossNlos(Ptr a, Ptr b) const override; + double GetShadowingStd(Ptr a, + Ptr b, + ChannelCondition::LosConditionValue cond) const override; + double GetShadowingCorrelationDistance(ChannelCondition::LosConditionValue cond) const override; + + /** + * \brief The nested map containing the Shadow Fading and + * Clutter Loss values for the NTN Urban scenario + */ + const std::map>* m_SFCL_Urban; +}; + +/** + * \ingroup propagation + * + * \brief Implements the pathloss model defined in 3GPP TR 38.811, Table ???? + * for the NTN Suburban scenario. + */ +class ThreeGppNTNSuburbanPropagationLossModel : public ThreeGppPropagationLossModel +{ + public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId(); + + /** + * Constructor + */ + ThreeGppNTNSuburbanPropagationLossModel(); + + /** + * Destructor + */ + ~ThreeGppNTNSuburbanPropagationLossModel() override; + + /** + * \copydoc ThreeGppPropagationLossModel::GetO2iDistance2dIn + * Does nothing in NTN scenarios. + */ + double GetO2iDistance2dIn() const override; + + /** + * \brief Copy constructor + * + * Deleted in base class + */ + ThreeGppNTNSuburbanPropagationLossModel(const ThreeGppNTNSuburbanPropagationLossModel&) = + delete; + + /** + * \brief Copy constructor + * + * Deleted in base class + * \returns the ThreeGppNTNSuburbanPropagationLossModel instance + */ + ThreeGppNTNSuburbanPropagationLossModel& operator=( + const ThreeGppNTNSuburbanPropagationLossModel&) = delete; + + private: + // Inherited + double GetLossLos(Ptr a, Ptr b) const override; + double GetLossNlos(Ptr a, Ptr b) const override; + double GetShadowingStd(Ptr a, + Ptr b, + ChannelCondition::LosConditionValue cond) const override; + double GetShadowingCorrelationDistance(ChannelCondition::LosConditionValue cond) const override; + + /** + * \brief The nested map containing the Shadow Fading and + * Clutter Loss values for the NTN Suburban and Rural scenario + */ + const std::map>* m_SFCL_SuburbanRural; +}; + +/** + * \ingroup propagation + * + * \brief Implements the pathloss model defined in 3GPP TR 38.811, Table ???? + * for the NTN Rural scenario. + */ +class ThreeGppNTNRuralPropagationLossModel : public ThreeGppPropagationLossModel +{ + public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId(); + + /** + * Constructor + */ + ThreeGppNTNRuralPropagationLossModel(); + + /** + * Destructor + */ + ~ThreeGppNTNRuralPropagationLossModel() override; + + /** + * \copydoc ThreeGppPropagationLossModel::GetO2iDistance2dIn + * Does nothing in NTN scenarios. + */ + double GetO2iDistance2dIn() const override; + + /** + * \brief Copy constructor + * + * Deleted in base class + */ + ThreeGppNTNRuralPropagationLossModel(const ThreeGppNTNRuralPropagationLossModel&) = delete; + + /** + * \brief Copy constructor + * + * Deleted in base class + * \returns the ThreeGppNTNRuralPropagationLossModel instance + */ + ThreeGppNTNRuralPropagationLossModel& operator=(const ThreeGppNTNRuralPropagationLossModel&) = + delete; + + private: + // Inherited + double GetLossLos(Ptr a, Ptr b) const override; + double GetLossNlos(Ptr a, Ptr b) const override; + double GetShadowingStd(Ptr a, + Ptr b, + ChannelCondition::LosConditionValue cond) const override; + double GetShadowingCorrelationDistance(ChannelCondition::LosConditionValue cond) const override; + + /** + * \brief The nested map containing the Shadow Fading and + * Clutter Loss values for the NTN Suburban and Rural scenario + */ + const std::map>* m_SFCL_SuburbanRural; +}; + } // namespace ns3 #endif /* THREE_GPP_PROPAGATION_LOSS_MODEL_H */ diff --git a/src/propagation/model/three-gpp-v2v-propagation-loss-model.cc b/src/propagation/model/three-gpp-v2v-propagation-loss-model.cc index 2f1005204..ec2b65fdf 100644 --- a/src/propagation/model/three-gpp-v2v-propagation-loss-model.cc +++ b/src/propagation/model/three-gpp-v2v-propagation-loss-model.cc @@ -66,13 +66,12 @@ ThreeGppV2vUrbanPropagationLossModel::~ThreeGppV2vUrbanPropagationLossModel() } double -ThreeGppV2vUrbanPropagationLossModel::GetLossLos(double /* distance2D */, - double distance3D, - double /* hUt */, - double /* hBs */) const +ThreeGppV2vUrbanPropagationLossModel::GetLossLos(Ptr a, Ptr b) const { NS_LOG_FUNCTION(this); + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + // compute the pathloss (see 3GPP TR 37.885, Table 6.2.1-1) double loss = 38.77 + 16.7 * log10(distance3D) + 18.2 * log10(m_frequency / 1e9); @@ -88,26 +87,25 @@ ThreeGppV2vUrbanPropagationLossModel::GetO2iDistance2dIn() const } double -ThreeGppV2vUrbanPropagationLossModel::GetLossNlosv(double distance2D, - double distance3D, - double hUt, - double hBs) const +ThreeGppV2vUrbanPropagationLossModel::GetLossNlosv(Ptr a, Ptr b) const { NS_LOG_FUNCTION(this); // compute the pathloss (see 3GPP TR 37.885, Table 6.2.1-1) - double loss = - GetLossLos(distance2D, distance3D, hUt, hBs) + GetAdditionalNlosvLoss(distance3D, hUt, hBs); + double loss = GetLossLos(a, b) + GetAdditionalNlosvLoss(a, b); return loss; } double -ThreeGppV2vUrbanPropagationLossModel::GetAdditionalNlosvLoss(double distance3D, - double hUt, - double hBs) const +ThreeGppV2vUrbanPropagationLossModel::GetAdditionalNlosvLoss(Ptr a, + Ptr b) const { NS_LOG_FUNCTION(this); + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + double hBs = std::max(a->GetPosition().z, b->GetPosition().z); + double hUt = std::min(a->GetPosition().z, b->GetPosition().z); + // From TR 37.885 v15.2.0 // When a V2V link is in NLOSv, additional vehicle blockage loss is // added as follows: @@ -166,13 +164,12 @@ ThreeGppV2vUrbanPropagationLossModel::GetAdditionalNlosvLoss(double distance3D, } double -ThreeGppV2vUrbanPropagationLossModel::GetLossNlos(double /* distance2D */, - double distance3D, - double /* hUt */, - double /* hBs */) const +ThreeGppV2vUrbanPropagationLossModel::GetLossNlos(Ptr a, Ptr b) const { NS_LOG_FUNCTION(this); + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + double loss = 36.85 + 30 * log10(distance3D) + 18.9 * log10(m_frequency / 1e9); return loss; @@ -266,13 +263,12 @@ ThreeGppV2vHighwayPropagationLossModel::~ThreeGppV2vHighwayPropagationLossModel( } double -ThreeGppV2vHighwayPropagationLossModel::GetLossLos(double /* distance2D */, - double distance3D, - double /* hUt */, - double /* hBs */) const +ThreeGppV2vHighwayPropagationLossModel::GetLossLos(Ptr a, Ptr b) const { NS_LOG_FUNCTION(this); + double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition()); + // compute the pathloss (see 3GPP TR 37.885, Table 6.2.1-1) double loss = 32.4 + 20 * log10(distance3D) + 20 * log10(m_frequency / 1e9); diff --git a/src/propagation/model/three-gpp-v2v-propagation-loss-model.h b/src/propagation/model/three-gpp-v2v-propagation-loss-model.h index ecd67a84d..eeddd7f8b 100644 --- a/src/propagation/model/three-gpp-v2v-propagation-loss-model.h +++ b/src/propagation/model/three-gpp-v2v-propagation-loss-model.h @@ -21,6 +21,9 @@ #include "three-gpp-propagation-loss-model.h" +#include "ns3/deprecated.h" +#include + namespace ns3 { @@ -49,7 +52,6 @@ class ThreeGppV2vUrbanPropagationLossModel : public ThreeGppPropagationLossModel */ ~ThreeGppV2vUrbanPropagationLossModel() override; - // Delete copy constructor and assignment operator to avoid misuse ThreeGppV2vUrbanPropagationLossModel(const ThreeGppV2vUrbanPropagationLossModel&) = delete; ThreeGppV2vUrbanPropagationLossModel& operator=(const ThreeGppV2vUrbanPropagationLossModel&) = delete; @@ -58,13 +60,11 @@ class ThreeGppV2vUrbanPropagationLossModel : public ThreeGppPropagationLossModel /** * \brief Computes the pathloss between a and b considering that the line of * sight is not obstructed - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a mobility model of one of the two communicating nodes + * \param b mobility model of one of the two communicating nodes * \return pathloss value in dB */ - double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override; + double GetLossLos(Ptr a, Ptr b) const override; /** * \brief Returns the minimum of the two independently generated distances @@ -86,41 +86,33 @@ class ThreeGppV2vUrbanPropagationLossModel : public ThreeGppPropagationLossModel /** * \brief Computes the pathloss between a and b considering that the line of * sight is obstructed by a vehicle - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a mobility model of one of the two communicating nodes + * \param b mobility model of one of the two communicating nodes * \return pathloss value in dB */ - double GetLossNlosv(double distance2D, - double distance3D, - double hUt, - double hBs) const override; + double GetLossNlosv(Ptr a, Ptr b) const override; /** * \brief Computes the pathloss between a and b considering that the line of * sight is obstructed by a building - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a mobility model of one of the two communicating nodes + * \param b mobility model of one of the two communicating nodes * \return pathloss value in dB */ - double GetLossNlos(double distance2D, double distance3D, double hUt, double hBs) const override; + double GetLossNlos(Ptr a, Ptr b) const override; /** * \brief Computes the additional loss due to an obstruction caused by a vehicle - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a mobility model of one of the two communicating nodes + * \param b mobility model of one of the two communicating nodes * \return pathloss value in dB */ - double GetAdditionalNlosvLoss(double distance3D, double hUt, double hBs) const; + double GetAdditionalNlosvLoss(Ptr a, Ptr b) const; /** * \brief Returns the shadow fading standard deviation - * \param a tx mobility model - * \param b rx mobility model + * \param a mobility model of one of the two communicating nodes + * \param b mobility model of one of the two communicating nodes * \param cond the LOS/NLOS channel condition * \return shadowing std in dB */ @@ -171,13 +163,11 @@ class ThreeGppV2vHighwayPropagationLossModel : public ThreeGppV2vUrbanPropagatio /** * \brief Computes the pathloss between a and b considering that the line of * sight is not obstructed - * \param distance2D the 2D distance between tx and rx in meters - * \param distance3D the 3D distance between tx and rx in meters - * \param hUt the height of the UT in meters - * \param hBs the height of the BS in meters + * \param a mobility model of one of the two communicating nodes + * \param b mobility model of one of the two communicating nodes * \return pathloss value in dB */ - double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override; + double GetLossLos(Ptr a, Ptr b) const override; }; } // namespace ns3 diff --git a/src/propagation/test/three-gpp-ntn-propagation-loss-model-test-suite.cc b/src/propagation/test/three-gpp-ntn-propagation-loss-model-test-suite.cc new file mode 100644 index 000000000..a4e6ee45d --- /dev/null +++ b/src/propagation/test/three-gpp-ntn-propagation-loss-model-test-suite.cc @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2023 SIGNET Lab, Department of Information Engineering, + * University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ns3/abort.h" +#include "ns3/boolean.h" +#include "ns3/channel-condition-model.h" +#include "ns3/config.h" +#include "ns3/constant-position-mobility-model.h" +#include "ns3/constant-velocity-mobility-model.h" +#include "ns3/double.h" +#include "ns3/geocentric-constant-position-mobility-model.h" +#include "ns3/log.h" +#include "ns3/mobility-helper.h" +#include "ns3/simulator.h" +#include "ns3/test.h" +#include "ns3/three-gpp-propagation-loss-model.h" +#include "ns3/three-gpp-v2v-propagation-loss-model.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE("ThreeGppNTNPropagationLossModelsTest"); + +/** + * \ingroup propagation-tests + * + * Test case for the ThreeGppNTNPropagationLossModel classes. + * It computes the path loss between two nodes and compares it with the value + * obtained using the results provided in 3GPP TR 38.821. + */ +class ThreeGppNTNPropagationLossModelTestCase : public TestCase +{ + public: + ThreeGppNTNPropagationLossModelTestCase(); + + /** + * Description of a single test point + */ + struct TestPoint + { + /** + * @brief Constructor + * + * @param distance 2D distance between the test nodes + * @param isLos whether to compute the path loss for a channel LOS condition + * @param frequency carrier frequency in Hz + * @param pwrRxDbm expected received power in dBm + * @param lossModel the propagation loss model to test + */ + TestPoint(double distance, + bool isLos, + double frequency, + double pwrRxDbm, + Ptr lossModel) + : m_distance(distance), + m_isLos(isLos), + m_frequency(frequency), + m_pwrRxDbm(pwrRxDbm), + m_propagationLossModel(lossModel) + { + } + + double m_distance; //!< 2D distance between test nodes, in meters + bool m_isLos; //!< if true LOS, if false NLOS + double m_frequency; //!< carrier frequency in Hz + double m_pwrRxDbm; //!< received power in dBm + Ptr m_propagationLossModel; //!< the path loss model to test + }; + + private: + /** + * Build the simulation scenario and run the tests + */ + void DoRun() override; + + /** + * Test the channel gain for a specific parameter configuration, + * by comparing the antenna gain obtained using CircularApertureAntennaModel::GetGainDb + * and the one of manually computed test instances. + * + * @param testPoint the parameter configuration to be tested + */ + void TestChannelGain(TestPoint testPoint); +}; + +ThreeGppNTNPropagationLossModelTestCase::ThreeGppNTNPropagationLossModelTestCase() + : TestCase("Creating ThreeGppNTNPropagationLossModelTestCase") + +{ +} + +void +ThreeGppNTNPropagationLossModelTestCase::DoRun() +{ + // Create the PLMs and disable shadowing to obtain deterministic results + Ptr denseUrbanModel = + CreateObject(); + denseUrbanModel->SetAttribute("ShadowingEnabled", BooleanValue(false)); + Ptr urbanModel = + CreateObject(); + urbanModel->SetAttribute("ShadowingEnabled", BooleanValue(false)); + Ptr suburbanModel = + CreateObject(); + suburbanModel->SetAttribute("ShadowingEnabled", BooleanValue(false)); + Ptr ruralModel = + CreateObject(); + ruralModel->SetAttribute("ShadowingEnabled", BooleanValue(false)); + + // Vector of test points + std::vector testPoints = { + // LOS, test points are identical for all path loss models, since the LOS path loss + // is independent from the specific class. + // Dense-Urban LOS + {35786000, true, 20.0e9, -209.915, denseUrbanModel}, + {35786000, true, 30.0e9, -213.437, denseUrbanModel}, + {35786000, true, 2.0e9, -191.744, denseUrbanModel}, + {600000, true, 20.0e9, -174.404, denseUrbanModel}, + {600000, true, 30.0e9, -177.925, denseUrbanModel}, + {600000, true, 2.0e9, -156.233, denseUrbanModel}, + {1200000, true, 20.0e9, -180.424, denseUrbanModel}, + {1200000, true, 30.0e9, -183.946, denseUrbanModel}, + {1200000, true, 2.0e9, -162.253, denseUrbanModel}, + // Urban LOS + {35786000, true, 20.0e9, -209.915, urbanModel}, + {35786000, true, 30.0e9, -213.437, urbanModel}, + {35786000, true, 2.0e9, -191.744, urbanModel}, + {600000, true, 20.0e9, -174.404, urbanModel}, + {600000, true, 30.0e9, -177.925, urbanModel}, + {600000, true, 2.0e9, -156.233, urbanModel}, + {1200000, true, 20.0e9, -180.424, urbanModel}, + {1200000, true, 30.0e9, -183.946, urbanModel}, + {1200000, true, 2.0e9, -162.253, urbanModel}, + // Suburban LOS + {35786000, true, 20.0e9, -209.915, suburbanModel}, + {35786000, true, 30.0e9, -213.437, suburbanModel}, + {35786000, true, 2.0e9, -191.744, suburbanModel}, + {600000, true, 20.0e9, -174.404, suburbanModel}, + {600000, true, 30.0e9, -177.925, suburbanModel}, + {600000, true, 2.0e9, -156.233, suburbanModel}, + {1200000, true, 20.0e9, -180.424, suburbanModel}, + {1200000, true, 30.0e9, -183.946, suburbanModel}, + {1200000, true, 2.0e9, -162.253, suburbanModel}, + // Rural LOS + {35786000, true, 20.0e9, -209.915, ruralModel}, + {35786000, true, 30.0e9, -213.437, ruralModel}, + {35786000, true, 2.0e9, -191.744, ruralModel}, + {600000, true, 20.0e9, -174.404, ruralModel}, + {600000, true, 30.0e9, -177.925, ruralModel}, + {600000, true, 2.0e9, -156.233, ruralModel}, + {1200000, true, 20.0e9, -180.424, ruralModel}, + {1200000, true, 30.0e9, -183.946, ruralModel}, + {1200000, true, 2.0e9, -162.253, ruralModel}}; + + // Call TestChannelGain on each test point + for (auto& point : testPoints) + { + TestChannelGain(point); + } +} + +void +ThreeGppNTNPropagationLossModelTestCase::TestChannelGain(TestPoint testPoint) +{ + // Create the nodes for BS and UT + NodeContainer nodes; + nodes.Create(2); + + // Create the mobility models + Ptr a = CreateObject(); + nodes.Get(0)->AggregateObject(a); + Ptr b = CreateObject(); + nodes.Get(1)->AggregateObject(b); + + // Set fixed position of one of the nodes + Vector posA = Vector(0.0, 0.0, 0.0); + a->SetPosition(posA); + Vector posB = Vector(0.0, 0.0, testPoint.m_distance); + b->SetPosition(posB); + + // Declare condition model + Ptr conditionModel; + + // Set the channel condition using a deterministic channel condition model + if (testPoint.m_isLos) + { + conditionModel = CreateObject(); + } + else + { + conditionModel = CreateObject(); + } + + testPoint.m_propagationLossModel->SetChannelConditionModel(conditionModel); + testPoint.m_propagationLossModel->SetAttribute("Frequency", DoubleValue(testPoint.m_frequency)); + NS_TEST_EXPECT_MSG_EQ_TOL(testPoint.m_propagationLossModel->CalcRxPower(0.0, a, b), + testPoint.m_pwrRxDbm, + 5e-3, + "Obtained unexpected received power"); + + Simulator::Destroy(); +} + +/** + * \ingroup propagation-tests + * + * \brief 3GPP NTN Propagation models TestSuite + * + * This TestSuite tests the following models: + * - ThreeGppNTNDenseUrbanPropagationLossModel + * - ThreeGppNTNUrbanPropagationLossModel + * - ThreeGppNTNSuburbanPropagationLossModel + * - ThreeGppNTNRuralPropagationLossModel + */ +class ThreeGppNTNPropagationLossModelsTestSuite : public TestSuite +{ + public: + ThreeGppNTNPropagationLossModelsTestSuite(); +}; + +ThreeGppNTNPropagationLossModelsTestSuite::ThreeGppNTNPropagationLossModelsTestSuite() + : TestSuite("three-gpp-ntn-propagation-loss-model", Type::UNIT) +{ + AddTestCase(new ThreeGppNTNPropagationLossModelTestCase(), Duration::QUICK); +} + +/// Static variable for test initialization +static ThreeGppNTNPropagationLossModelsTestSuite g_propagationLossModelsTestSuite; diff --git a/src/propagation/test/three-gpp-propagation-loss-model-test-suite.cc b/src/propagation/test/three-gpp-propagation-loss-model-test-suite.cc index 91cc1c3de..91e7764fd 100644 --- a/src/propagation/test/three-gpp-propagation-loss-model-test-suite.cc +++ b/src/propagation/test/three-gpp-propagation-loss-model-test-suite.cc @@ -167,10 +167,8 @@ ThreeGppRmaPropagationLossModelTestCase::DoRun() CreateObject(); lossModel->SetAttribute("ShadowingEnabled", BooleanValue(false)); // disable the shadow fading - for (std::size_t i = 0; i < m_testVectors.GetN(); i++) + for (const auto& testVector : m_testVectors) { - TestVector testVector = m_testVectors.Get(i); - Vector posBs = Vector(0.0, 0.0, 35.0); Vector posUt = Vector(testVector.m_distance, 0.0, 1.5); diff --git a/src/spectrum/doc/spectrum.rst b/src/spectrum/doc/spectrum.rst index a292eff00..0f658e645 100644 --- a/src/spectrum/doc/spectrum.rst +++ b/src/spectrum/doc/spectrum.rst @@ -1101,3 +1101,41 @@ References Mattias Frenne, Farshid Ghasemzadeh, Måns Hagström et al. Advanced Antenna Systems for 5G Network Deployments: Bridging the Gap Between Theory and Practice. Academic Press, 2020. + + +3GPP TR 38.811 Non-Terrestrial Networks +======================================= +3GPP with [3GPPTR38811]_ has extended the channel model presented in [3GPPTR38901]_ to support the so called Non-Terrestrial Networks +(NTN), i.e. communication scenarios where the propagation of the signal travels through the atmosphere. +The channel spectrum estimation procedure is the same as the one described in [3GPPTR38901]_, with a new set of parameters. + + +Use-cases +######### +The use-cases for this channel model include simulations in 3D/vertical environments with communicating nodes placed +in different types of orbit, in the atmosphere and/or on the ground. + +Implementation +############## +The channel spectrum estimation procedure is already implemented (as described in [ns3Zugno]_ ) into the classes +ThreeGppChannelModel and ThreeGppSpectrumPropagationLossModel, that have been extended to support NTN through the +introduction of the appropriate parameters. +3GPP considers two frequencies of interest: S-band (2GHz) and Ka-band (20/30GHz). Many channel parameters are dependent +on the frequency band in use, but no specific range of frequencies of these bands has been given by 3GPP. Hence, this +implementation considers S-band anything below 13GHz, and Ka-band anything above it. +Four propagation scenarios are identified, in decreasing order of building height and density: Dense Urban, Urban, +Suburban and Rural. Channel estimation parameters are scenario-dependent. +**Note**: For satellite, the parameters that describe the departure angle spread are 0. Thus, in the logarithmic scale +at which these parameters are represented is :math:`-\infty`. + +References +########## + +.. [ns3Zugno] Zugno Tommaso, Michele Polese, Natale Patriciello, Biljana Bojović, + Sandra Lagen, Michele Zorzi. "Implementation of a spatial channel model for ns-3." + In Proceedings of the 2020 Workshop on ns-3, pp. 49-56. 2020. + +.. [3GPPTR38901] 3GPP. 2018. TR 38.901. Study on channel for frequencies from 0.5 to + 100 GHz. V.15.0.0. (2018-06). + +.. [3GPPTR38811] 3GPP. 2018. TR 38.811, Study on New Radio (NR) to support non-terrestrial networks, V15.4.0. (2020-09). diff --git a/src/spectrum/examples/CMakeLists.txt b/src/spectrum/examples/CMakeLists.txt index 457466589..ed55bcb87 100644 --- a/src/spectrum/examples/CMakeLists.txt +++ b/src/spectrum/examples/CMakeLists.txt @@ -65,3 +65,12 @@ build_lib_example( ${libmobility} ${libspectrum} ) + +build_lib_example( + NAME three-gpp-ntn-channel-example + SOURCE_FILES three-gpp-ntn-channel-example.cc + LIBRARIES_TO_LINK + ${libcore} + ${libmobility} + ${libspectrum} +) diff --git a/src/spectrum/examples/three-gpp-ntn-channel-example.cc b/src/spectrum/examples/three-gpp-ntn-channel-example.cc new file mode 100644 index 000000000..960c435f0 --- /dev/null +++ b/src/spectrum/examples/three-gpp-ntn-channel-example.cc @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2023 SIGNET Lab, Department of Information Engineering, + * University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * \file + * This example is a modified version of "three-gpp-channel-example", to include + * the 3GPP NTN channel model. + * Specifically, most changes (which are also highlighted throughout the code) + * impact the main method, and comprise: + * - the configuration of ad-hoc propagation and channel condition models; + * - the use of GeocentricConstantPositionMobilityModel for the nodes mobility. + * The pre-configured parameters are the one provided by 3GPP in TR 38.821, + * more specifically scenario 10 in down-link mode. + * Two static nodes, one on the ground and one in orbit, communicate with each other. + * The carrier frequency is set at 20GHz with 400MHz bandwidth. + * The result is the SNR of the signal and the path loss, saved in the ntn-snr-trace.txt file. + */ + +#include "ns3/channel-condition-model.h" +#include "ns3/constant-position-mobility-model.h" +#include "ns3/core-module.h" +#include "ns3/geocentric-constant-position-mobility-model.h" +#include "ns3/isotropic-antenna-model.h" +#include "ns3/mobility-model.h" +#include "ns3/net-device.h" +#include "ns3/node-container.h" +#include "ns3/node.h" +#include "ns3/parabolic-antenna-model.h" +#include "ns3/simple-net-device.h" +#include "ns3/spectrum-signal-parameters.h" +#include "ns3/three-gpp-channel-model.h" +#include "ns3/three-gpp-propagation-loss-model.h" +#include "ns3/three-gpp-spectrum-propagation-loss-model.h" +#include "ns3/uniform-planar-array.h" +#include + +#include + +NS_LOG_COMPONENT_DEFINE("NTNChannelExample"); + +using namespace ns3; + +static Ptr + m_propagationLossModel; //!< the PropagationLossModel object +static Ptr + m_spectrumLossModel; //!< the SpectrumPropagationLossModel object + +/** + * @brief Create the PSD for the TX + * + * @param fcHz the carrier frequency in Hz + * @param pwrDbm the transmission power in dBm + * @param bwHz the bandwidth in Hz + * @param rbWidthHz the Resource Block (RB) width in Hz + * + * @return the pointer to the PSD + */ +Ptr +CreateTxPowerSpectralDensity(double fcHz, double pwrDbm, double bwHz, double rbWidthHz) +{ + unsigned int numRbs = std::floor(bwHz / rbWidthHz); + double f = fcHz - (numRbs * rbWidthHz / 2.0); + double powerTx = pwrDbm; // dBm power + + Bands rbs; // A vector representing each resource block + for (uint32_t numrb = 0; numrb < numRbs; ++numrb) + { + BandInfo rb; + rb.fl = f; + f += rbWidthHz / 2; + rb.fc = f; + f += rbWidthHz / 2; + rb.fh = f; + + rbs.push_back(rb); + } + Ptr model = Create(rbs); + Ptr txPsd = Create(model); + + double powerTxW = std::pow(10., (powerTx - 30) / 10); // Get Tx power in Watts + double txPowerDensity = (powerTxW / bwHz); + + for (auto psd = txPsd->ValuesBegin(); psd != txPsd->ValuesEnd(); ++psd) + { + *psd = txPowerDensity; + } + + return txPsd; // [W/Hz] +} + +/** + * @brief Create the noise PSD for the + * + * @param fcHz the carrier frequency in Hz + * @param noiseFigureDb the noise figure in dB + * @param bwHz the bandwidth in Hz + * @param rbWidthHz the Resource Block (RB) width in Hz + * + * @return the pointer to the noise PSD + */ +Ptr +CreateNoisePowerSpectralDensity(double fcHz, double noiseFigureDb, double bwHz, double rbWidthHz) +{ + unsigned int numRbs = std::floor(bwHz / rbWidthHz); + double f = fcHz - (numRbs * rbWidthHz / 2.0); + + Bands rbs; // A vector representing each resource block + std::vector rbsId; // A vector representing the resource block IDs + for (uint32_t numrb = 0; numrb < numRbs; ++numrb) + { + BandInfo rb; + rb.fl = f; + f += rbWidthHz / 2; + rb.fc = f; + f += rbWidthHz / 2; + rb.fh = f; + + rbs.push_back(rb); + rbsId.push_back(numrb); + } + Ptr model = Create(rbs); + Ptr txPsd = Create(model); + + // see "LTE - From theory to practice" + // Section 22.4.4.2 Thermal Noise and Receiver Noise Figure + const double ktDbmHz = -174.0; // dBm/Hz + double ktWHz = std::pow(10.0, (ktDbmHz - 30) / 10.0); // W/Hz + double noiseFigureLinear = std::pow(10.0, noiseFigureDb / 10.0); + + double noisePowerSpectralDensity = ktWHz * noiseFigureLinear; + + for (auto rbId : rbsId) + { + (*txPsd)[rbId] = noisePowerSpectralDensity; + } + + return txPsd; // W/Hz +} + +/** + * \brief A structure that holds the parameters for the + * ComputeSnr function. In this way the problem with the limited + * number of parameters of method Schedule is avoided. + */ +struct ComputeSnrParams +{ + Ptr txMob; //!< the tx mobility model + Ptr rxMob; //!< the rx mobility model + double txPow; //!< the tx power in dBm + double noiseFigure; //!< the noise figure in dB + Ptr txAntenna; //!< the tx antenna array + Ptr rxAntenna; //!< the rx antenna array + double frequency; //!< the carrier frequency in Hz + double bandwidth; //!< the total bandwidth in Hz + double resourceBlockBandwidth; //!< the Resource Block bandwidth in Hz + + /** + * \brief Constructor + * \param pTxMob the tx mobility model + * \param pRxMob the rx mobility model + * \param pTxPow the tx power in dBm + * \param pNoiseFigure the noise figure in dB + * \param pTxAntenna the tx antenna array + * \param pRxAntenna the rx antenna array + * \param pFrequency the carrier frequency in Hz + * \param pBandwidth the total bandwidth in Hz + * \param pResourceBlockBandwidth the Resource Block bandwidth in Hz + */ + ComputeSnrParams(Ptr pTxMob, + Ptr pRxMob, + double pTxPow, + double pNoiseFigure, + Ptr pTxAntenna, + Ptr pRxAntenna, + double pFrequency, + double pBandwidth, + double pResourceBlockBandwidth) + { + txMob = pTxMob; + rxMob = pRxMob; + txPow = pTxPow; + noiseFigure = pNoiseFigure; + txAntenna = pTxAntenna; + rxAntenna = pRxAntenna; + frequency = pFrequency; + bandwidth = pBandwidth; + resourceBlockBandwidth = pResourceBlockBandwidth; + } +}; + +/** + * Perform the beamforming using the DFT beamforming method + * \param thisDevice the device performing the beamforming + * \param thisAntenna the antenna object associated to thisDevice + * \param otherDevice the device towards which point the beam + */ +static void +DoBeamforming(Ptr thisDevice, + Ptr thisAntenna, + Ptr otherDevice) +{ + // retrieve the position of the two devices + Vector aPos = thisDevice->GetNode()->GetObject()->GetPosition(); + Vector bPos = otherDevice->GetNode()->GetObject()->GetPosition(); + + // compute the azimuth and the elevation angles + Angles completeAngle(bPos, aPos); + double hAngleRadian = completeAngle.GetAzimuth(); + double vAngleRadian = completeAngle.GetInclination(); // the elevation angle + + // retrieve the number of antenna elements and resize the vector + uint64_t totNoArrayElements = thisAntenna->GetNumElems(); + PhasedArrayModel::ComplexVector antennaWeights(totNoArrayElements); + + // the total power is divided equally among the antenna elements + double power = 1.0 / sqrt(totNoArrayElements); + + // compute the antenna weights + const double sinVAngleRadian = sin(vAngleRadian); + const double cosVAngleRadian = cos(vAngleRadian); + const double sinHAngleRadian = sin(hAngleRadian); + const double cosHAngleRadian = cos(hAngleRadian); + + for (uint64_t ind = 0; ind < totNoArrayElements; ind++) + { + Vector loc = thisAntenna->GetElementLocation(ind); + double phase = -2 * M_PI * + (sinVAngleRadian * cosHAngleRadian * loc.x + + sinVAngleRadian * sinHAngleRadian * loc.y + cosVAngleRadian * loc.z); + antennaWeights[ind] = exp(std::complex(0, phase)) * power; + } + + // store the antenna weights + thisAntenna->SetBeamformingVector(antennaWeights); +} + +/** + * Compute the average SNR + * \param params A structure that holds the parameters that are needed to perform calculations in + * ComputeSnr + */ +static void +ComputeSnr(ComputeSnrParams& params) +{ + Ptr txPsd = CreateTxPowerSpectralDensity(params.frequency, + params.txPow, + params.bandwidth, + params.resourceBlockBandwidth); + Ptr rxPsd = txPsd->Copy(); + NS_LOG_DEBUG("Average tx power " << 10 * log10(Sum(*txPsd) * params.resourceBlockBandwidth) + << " dB"); + + // create the noise PSD + Ptr noisePsd = CreateNoisePowerSpectralDensity(params.frequency, + params.noiseFigure, + params.bandwidth, + params.resourceBlockBandwidth); + NS_LOG_DEBUG("Average noise power " + << 10 * log10(Sum(*noisePsd) * params.resourceBlockBandwidth) << " dB"); + + // apply the pathloss + double propagationGainDb = m_propagationLossModel->CalcRxPower(0, params.txMob, params.rxMob); + NS_LOG_DEBUG("Pathloss " << -propagationGainDb << " dB"); + double propagationGainLinear = std::pow(10.0, (propagationGainDb) / 10.0); + *(rxPsd) *= propagationGainLinear; + + NS_ASSERT_MSG(params.txAntenna, "params.txAntenna is nullptr!"); + NS_ASSERT_MSG(params.rxAntenna, "params.rxAntenna is nullptr!"); + + Ptr rxSsp = Create(); + rxSsp->psd = rxPsd; + rxSsp->txAntenna = + ConstCast(params.txAntenna->GetAntennaElement()); + + // apply the fast fading and the beamforming gain + rxSsp = m_spectrumLossModel->CalcRxPowerSpectralDensity(rxSsp, + params.txMob, + params.rxMob, + params.txAntenna, + params.rxAntenna); + NS_LOG_DEBUG("Average rx power " << 10 * log10(Sum(*rxSsp->psd) * params.bandwidth) << " dB"); + + // compute the SNR + NS_LOG_DEBUG("Average SNR " << 10 * log10(Sum(*rxSsp->psd) / Sum(*noisePsd)) << " dB"); + + // print the SNR and pathloss values in the ntn-snr-trace.txt file + std::ofstream f; + f.open("ntn-snr-trace.txt", std::ios::out | std::ios::app); + f << Simulator::Now().GetSeconds() << " " << 10 * log10(Sum(*rxSsp->psd) / Sum(*noisePsd)) + << " " << propagationGainDb << std::endl; + f.close(); +} + +int +main(int argc, char* argv[]) +{ + uint32_t simTimeMs = 1000; // simulation time in milliseconds + uint32_t timeResMs = 10; // time resolution in milliseconds + + // Start changes with respect to three-gpp-channel-example + // SCENARIO 10 DL of TR 38.321 + // This parameters can be set accordingly to 3GPP TR 38.821 or arbitrarily modified + std::string scenario = "NTN-Suburban"; // 3GPP propagation scenario + // All available NTN scenarios: DenseUrban, Urban, Suburban, Rural. + + double frequencyHz = 20e9; // operating frequency in Hz + double bandwidthHz = 400e6; // Hz + double RbBandwidthHz = 120e3; // Hz + + // Satellite parameters + double satEIRPDensity = 40; // dBW/MHz + double satAntennaGainDb = 58.5; // dB + + // UE Parameters + double vsatAntennaGainDb = 39.7; // dB + double vsatAntennaNoiseFigureDb = 1.2; // dB + // End changes with respect to three-gpp-channel-example + + /* Command line argument parser setup. */ + CommandLine cmd(__FILE__); + cmd.AddValue("scenario", + "The 3GPP NTN scenario to use. Valid options are: " + "NTN-DenseUrban, NTN-Urban, NTN-Suburban, and NTN-Rural", + scenario); + cmd.AddValue("frequencyHz", "The carrier frequency in Hz", frequencyHz); + cmd.AddValue("bandwidthHz", "The bandwidth in Hz", bandwidthHz); + cmd.AddValue("satEIRPDensity", "The satellite EIRP density in dBW/MHz", satEIRPDensity); + cmd.AddValue("satAntennaGainDb", "The satellite antenna gain in dB", satAntennaGainDb); + cmd.AddValue("vsatAntennaGainDb", "The UE VSAT antenna gain in dB", vsatAntennaGainDb); + cmd.AddValue("vsatAntennaNoiseFigureDb", + "The UE VSAT antenna noise figure in dB", + vsatAntennaNoiseFigureDb); + cmd.Parse(argc, argv); + + // Calculate transmission power in dBm using EIRPDensity + 10*log10(Bandwidth) - AntennaGain + + // 30 + double txPowDbm = (satEIRPDensity + 10 * log10(bandwidthHz / 1e6) - satAntennaGainDb) + 30; + + NS_LOG_DEBUG("Transmitting power: " << txPowDbm << "dBm, (" << pow(10., (txPowDbm - 30) / 10) + << "W)"); + + Config::SetDefault("ns3::ThreeGppChannelModel::UpdatePeriod", + TimeValue(MilliSeconds(10))); // update the channel at every 10 ms + Config::SetDefault("ns3::ThreeGppChannelConditionModel::UpdatePeriod", + TimeValue(MilliSeconds(0.0))); // do not update the channel condition + + RngSeedManager::SetSeed(1); + RngSeedManager::SetRun(1); + + // create and configure the factories for the channel condition and propagation loss models + ObjectFactory propagationLossModelFactory; + ObjectFactory channelConditionModelFactory; + + // Start changes with respect to three-gpp-channel-example + if (scenario == "NTN-DenseUrban") + { + propagationLossModelFactory.SetTypeId( + ThreeGppNTNDenseUrbanPropagationLossModel::GetTypeId()); + channelConditionModelFactory.SetTypeId( + ThreeGppNTNDenseUrbanChannelConditionModel::GetTypeId()); + } + else if (scenario == "NTN-Urban") + { + propagationLossModelFactory.SetTypeId(ThreeGppNTNUrbanPropagationLossModel::GetTypeId()); + channelConditionModelFactory.SetTypeId(ThreeGppNTNUrbanChannelConditionModel::GetTypeId()); + } + else if (scenario == "NTN-Suburban") + { + propagationLossModelFactory.SetTypeId(ThreeGppNTNSuburbanPropagationLossModel::GetTypeId()); + channelConditionModelFactory.SetTypeId( + ThreeGppNTNSuburbanChannelConditionModel::GetTypeId()); + } + else if (scenario == "NTN-Rural") + { + propagationLossModelFactory.SetTypeId(ThreeGppNTNRuralPropagationLossModel::GetTypeId()); + channelConditionModelFactory.SetTypeId(ThreeGppNTNRuralChannelConditionModel::GetTypeId()); + } + else + { + NS_FATAL_ERROR("Unknown NTN scenario"); + } + // End changes with respect to three-gpp-channel-example + + // create the propagation loss model + m_propagationLossModel = propagationLossModelFactory.Create(); + m_propagationLossModel->SetAttribute("Frequency", DoubleValue(frequencyHz)); + m_propagationLossModel->SetAttribute("ShadowingEnabled", BooleanValue(true)); + + // create the spectrum propagation loss model + m_spectrumLossModel = CreateObject(); + m_spectrumLossModel->SetChannelModelAttribute("Frequency", DoubleValue(frequencyHz)); + m_spectrumLossModel->SetChannelModelAttribute("Scenario", StringValue(scenario)); + + // create the channel condition model and associate it with the spectrum and + // propagation loss model + Ptr condModel = + channelConditionModelFactory.Create(); + m_spectrumLossModel->SetChannelModelAttribute("ChannelConditionModel", PointerValue(condModel)); + m_propagationLossModel->SetChannelConditionModel(condModel); + + // create the tx and rx nodes + NodeContainer nodes; + nodes.Create(2); + + // create the tx and rx devices + Ptr txDev = CreateObject(); + Ptr rxDev = CreateObject(); + + // associate the nodes and the devices + nodes.Get(0)->AddDevice(txDev); + txDev->SetNode(nodes.Get(0)); + nodes.Get(1)->AddDevice(rxDev); + rxDev->SetNode(nodes.Get(1)); + + // Start changes with respect to three-gpp-channel-example, here a mobility model + // tailored to NTN scenarios is used (GeocentricConstantPositionMobilityModel) + // create the tx and rx mobility models, set the positions + Ptr txMob = + CreateObject(); + Ptr rxMob = + CreateObject(); + + txMob->SetGeographicPosition(Vector(45.40869, 11.89448, 35786000)); // GEO over Padova + rxMob->SetGeographicPosition(Vector(45.40869, 11.89448, 14.0)); // Padova Coordinates + + // This is not strictly necessary, but is useful to have "sensible" values when using + // GetPosition() + txMob->SetCoordinateTranslationReferencePoint( + Vector(45.40869, 11.89448, 0.0)); // Padova Coordinates without altitude + rxMob->SetCoordinateTranslationReferencePoint( + Vector(45.40869, 11.89448, 0.0)); // Padova Coordinates without altitude + // End changes with respect to three-gpp-channel-example, + + NS_LOG_DEBUG("TX Position: " << txMob->GetPosition()); + NS_LOG_DEBUG("RX Position: " << rxMob->GetPosition()); + + // assign the mobility models to the nodes + nodes.Get(0)->AggregateObject(txMob); + nodes.Get(1)->AggregateObject(rxMob); + + // Start changes with respect to three-gpp-channel-example, + // Here antenna models mimic the gain achieved by the CircularApertureAntennaModel, + // which is not used to avoid inheriting the latter's dependence on either libstdc++ + // or Boost. + Ptr txAntenna = CreateObjectWithAttributes( + "NumColumns", + UintegerValue(1), + "NumRows", + UintegerValue(1), + "AntennaElement", + PointerValue( + CreateObjectWithAttributes("Gain", + DoubleValue(satAntennaGainDb)))); + + Ptr rxAntenna = CreateObjectWithAttributes( + "NumColumns", + UintegerValue(1), + "NumRows", + UintegerValue(1), + "AntennaElement", + PointerValue( + CreateObjectWithAttributes("Gain", + DoubleValue(vsatAntennaGainDb)))); + // End changes with respect to three-gpp-channel-example + + // set the beamforming vectors + DoBeamforming(rxDev, rxAntenna, txDev); + DoBeamforming(txDev, txAntenna, rxDev); + + for (int i = 0; i < floor(simTimeMs / timeResMs); i++) + { + Simulator::Schedule(MilliSeconds(timeResMs * i), + &ComputeSnr, + ComputeSnrParams(txMob, + rxMob, + txPowDbm, + vsatAntennaNoiseFigureDb, + txAntenna, + rxAntenna, + frequencyHz, + bandwidthHz, + RbBandwidthHz)); + } + + Simulator::Run(); + Simulator::Destroy(); + return 0; +} diff --git a/src/spectrum/model/three-gpp-channel-model.cc b/src/spectrum/model/three-gpp-channel-model.cc index 86cf05c1d..041ab4c69 100644 --- a/src/spectrum/model/three-gpp-channel-model.cc +++ b/src/spectrum/model/three-gpp-channel-model.cc @@ -22,6 +22,7 @@ #include "three-gpp-channel-model.h" #include "ns3/double.h" +#include "ns3/geocentric-constant-position-mobility-model.h" #include "ns3/integer.h" #include "ns3/log.h" #include "ns3/mobility-model.h" @@ -248,6 +249,1240 @@ static const double sqrtC_office_NLOS[6][6] = { {0, -0.069282, 0.295397, 0.430696, 0.468462, 0.709214}, }; +/** + * The square root matrix for NTN Dense Urban LOS, which is generated + * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-1 and follows + * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA]. + * + * The Matlab file to generate the matrices can be found in + * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m + */ +static const double sqrtC_NTN_DenseUrban_LOS[7][7] = { + {1, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 0}, + {-0.4, -0.4, 0.824621, 0, 0, 0, 0}, + {-0.5, 0, 0.242536, 0.83137, 0, 0, 0}, + {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0}, + {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0}, + {-0.8, 0, -0.388057, -0.367926, 0.238537, -4.09997e-15, 0.130931}, +}; + +/** + * The square root matrix for NTN Dense Urban NLOS, which is generated + * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-2 and follows + * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA]. + * + * The Matlab file to generate the matrices can be found in + * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m + */ +static const double sqrtC_NTN_DenseUrban_NLOS[6][6] = { + {1, 0, 0, 0, 0, 0}, + {-0.4, 0.916515, 0, 0, 0, 0}, + {-0.6, 0.174574, 0.78072, 0, 0, 0}, + {0, 0.654654, 0.365963, 0.661438, 0, 0}, + {0, -0.545545, 0.762422, 0.118114, 0.327327, 0}, + {-0.4, -0.174574, -0.396459, 0.392138, 0.49099, 0.507445}, +}; + +/** + * The square root matrix for NTN Urban LOS, which is generated + * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-3 and follows + * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA]. + * + * The Matlab file to generate the matrices can be found in + * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m + */ +static const double sqrtC_NTN_Urban_LOS[7][7] = { + {1, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 0}, + {-0.4, -0.4, 0.824621, 0, 0, 0, 0}, + {-0.5, 0, 0.242536, 0.83137, 0, 0, 0}, + {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0}, + {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0}, + {-0.8, 0, -0.388057, -0.367926, 0.238537, -4.09997e-15, 0.130931}, +}; + +/** + * The square root matrix for NTN Urban NLOS, which is generated + * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-4 and follows + * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA]. + * + * The square root matrix is dependent on the elevation angle, thus requiring a map. + * + * The Matlab file to generate the matrices can be found in + * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m + */ +static const std::map>> sqrtC_NTN_Urban_NLOS{ + {10, + { + {1, 0, 0, 0, 0, 0}, + {-0.21, 0.977701, 0, 0, 0, 0}, + {-0.48, 0.459445, 0.747335, 0, 0, 0}, + {-0.05, 0.377927, 0.28416, 0.879729, 0, 0}, + {-0.02, 0.691213, 0.258017, 0.073265, 0.670734, 0}, + {-0.31, -0.00521632, -0.115615, 0.0788023, 0.00218104, 0.940368}, + }}, + {20, + { + {1, 0, 0, 0, 0, 0}, + {-0.25, 0.968246, 0, 0, 0, 0}, + {-0.52, 0.35115, 0.778648, 0, 0, 0}, + {-0.04, 0.371806, 0.345008, 0.860889, 0, 0}, + {0, 0.743613, 0.281102, 0.0424415, 0.605161, 0}, + {-0.32, 0.0206559, -0.0689057, 0.154832, 0.061865, 0.929852}, + }}, + {30, + { + {1, 0, 0, 0, 0, 0}, + {-0.21, 0.977701, 0, 0, 0, 0}, + {-0.52, 0.450853, 0.725487, 0, 0, 0}, + {-0.04, 0.288023, 0.260989, 0.920504, 0, 0}, + {0.01, 0.697657, 0.386856, 0.0418183, 0.601472, 0}, + {-0.33, 0.0416283, -0.0694268, 0.166137, 0.139937, 0.915075}, + }}, + {40, + { + {1, 0, 0, 0, 0, 0}, + {-0.26, 0.965609, 0, 0, 0, 0}, + {-0.53, 0.395813, 0.749955, 0, 0, 0}, + {-0.04, 0.299914, 0.320139, 0.897754, 0, 0}, + {0.01, 0.696556, 0.372815, 0.0580784, 0.610202, 0}, + {-0.33, 0.0457742, -0.0173584, 0.154417, 0.129332, 0.920941}, + }}, + {50, + { + {1, 0, 0, 0, 0, 0}, + {-0.25, 0.968246, 0, 0, 0, 0}, + {-0.57, 0.420864, 0.705672, 0, 0, 0}, + {-0.03, 0.229797, 0.235501, 0.943839, 0, 0}, + {0.03, 0.679063, 0.384466, 0.0681379, 0.6209, 0}, + {-0.41, -0.147173, -0.229228, 0.270707, 0.293002, 0.773668}, + }}, + {60, + { + {1, 0, 0, 0, 0, 0}, + {-0.2, 0.979796, 0, 0, 0, 0}, + {-0.53, 0.473568, 0.703444, 0, 0, 0}, + {-0.05, 0.204124, 0.109225, 0.971547, 0, 0}, + {0.03, 0.68994, 0.411073, 0.0676935, 0.591202, 0}, + {-0.4, -0.224537, -0.292371, 0.275609, 0.301835, 0.732828}, + }}, + {70, + { + {1, 0, 0, 0, 0, 0}, + {-0.19, 0.981784, 0, 0, 0, 0}, + {-0.5, 0.524555, 0.689088, 0, 0, 0}, + {-0.03, 0.228462, 0.18163, 0.955989, 0, 0}, + {-0.02, 0.637818, 0.428725, 0.00608114, 0.639489, 0}, + {-0.36, -0.18171, -0.282523, 0.106726, 0.123808, 0.854894}, + }}, + {80, + { + {1, 0, 0, 0, 0, 0}, + {-0.2, 0.979796, 0, 0, 0, 0}, + {-0.49, 0.502145, 0.712566, 0, 0, 0}, + {-0.01, 0.232702, 0.151916, 0.960558, 0, 0}, + {-0.05, 0.612372, 0.376106, 0.0206792, 0.693265, 0}, + {-0.37, -0.320475, -0.365405, -0.00376264, 0.0364343, 0.790907}, + }}, + {90, + { + {1, 0, 0, 0, 0, 0}, + {-0.19, 0.981784, 0, 0, 0, 0}, + {-0.38, 0.58852, 0.713613, 0, 0, 0}, + {-0.03, 0.360874, 0.12082, 0.924269, 0, 0}, + {-0.12, 0.526796, 0.34244, 0.0594196, 0.766348, 0}, + {-0.33, -0.257389, -0.24372, -0.257035, -0.176521, 0.817451}, + }}, +}; + +/** + * The square root matrix for NTN Suburban LOS, which is generated + * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-5 and follows + * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA]. + * + * The Matlab file to generate the matrices can be found in + * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m + */ +static const double sqrtC_NTN_Suburban_LOS[7][7] = { + {1, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 0}, + {-0.4, -0.4, 0.824621, 0, 0, 0, 0}, + {-0.5, 0, 0.242536, 0.83137, 0, 0, 0}, + {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0}, + {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0}, + {-0.8, 0, -0.388057, -0.367926, 0.238537, -4.09997e-15, 0.130931}, +}; + +/** + * The square root matrix for NTN Suburban NLOS, which is generated + * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-6 and follows + * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA]. + * + * The Matlab file to generate the matrices can be found in + * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m + */ +static const double sqrtC_NTN_Suburban_NLOS[6][6] = { + {1, 0, 0, 0, 0, 0}, + {-0.4, 0.916515, 0, 0, 0, 0}, + {-0.6, 0.174574, 0.78072, 0, 0, 0}, + {0, 0.654654, 0.365963, 0.661438, 0, 0}, + {0, -0.545545, 0.762422, 0.118114, 0.327327, 0}, + {-0.4, -0.174574, -0.396459, 0.392138, 0.49099, 0.507445}, +}; + +/** + * The square root matrix for NTN Rural LOS, which is generated + * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-7 and follows + * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA]. + * + * The Matlab file to generate the matrices can be found in + * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m + */ +static const double sqrtC_NTN_Rural_LOS[7][7] = { + {1, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 0}, + {-0.5, 0, 0.866025, 0, 0, 0, 0}, + {0, 0, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 1, 0, 0}, + {0.01, 0, -0.0519615, 0.73, -0.2, 0.651383, 0}, + {-0.17, -0.02, 0.21362, -0.14, 0.24, 0.142773, 0.909661}, +}; + +/** + * The square root matrix for NTN Rural NLOS S Band, which is generated + * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-8a and follows + * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA]. + * + * The square root matrix is dependent on the elevation angle, thus requiring a map. + * + * The Matlab file to generate the matrices can be found in + * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m + */ +static const std::map>> sqrtC_NTN_Rural_NLOS_S{ + {10, + { + {1, 0, 0, 0, 0, 0}, + {-0.36, 0.932952, 0, 0, 0, 0}, + {0.45, 0.516639, 0.728412, 0, 0, 0}, + {0.02, 0.329277, 0.371881, 0.867687, 0, 0}, + {-0.06, 0.59853, 0.436258, -0.0324062, 0.668424, 0}, + {-0.07, 0.0373009, 0.305087, -0.0280496, -0.225204, 0.921481}, + }}, + {20, + { + {1, 0, 0, 0, 0, 0}, + {-0.39, 0.920815, 0, 0, 0, 0}, + {0.52, 0.426579, 0.740021, 0, 0, 0}, + {0, 0.347518, -0.0381664, 0.936896, 0, 0}, + {-0.04, 0.710675, 0.172483, 0.116993, 0.670748, 0}, + {-0.17, -0.0394216, 0.115154, 0.243458, -0.0702635, 0.944498}, + }}, + {30, + { + {1, 0, 0, 0, 0, 0}, + {-0.41, 0.912086, 0, 0, 0, 0}, + {0.54, 0.49491, 0.680782, 0, 0, 0}, + {0, 0.350844, -0.152231, 0.923977, 0, 0}, + {-0.04, 0.694672, 0.0702137, 0.0832998, 0.709903, 0}, + {-0.19, -0.0854087, 0.0805978, 0.283811, -0.137441, 0.922318}, + }}, + {40, + { + {1, 0, 0, 0, 0, 0}, + {-0.37, 0.929032, 0, 0, 0, 0}, + {0.53, 0.480177, 0.698949, 0, 0, 0}, + {0.01, 0.434538, 0.00864797, 0.900556, 0, 0}, + {-0.05, 0.765851, -0.0303947, 0.0421641, 0.63896, 0}, + {-0.17, -0.16458, 0.0989022, 0.158081, -0.150425, 0.941602}, + }}, + {50, + { + {1, 0, 0, 0, 0, 0}, + {-0.4, 0.916515, 0, 0, 0, 0}, + {0.55, 0.403703, 0.731111, 0, 0, 0}, + {0.02, 0.499719, -0.0721341, 0.862947, 0, 0}, + {-0.06, 0.835775, -0.156481, 0.0373835, 0.521534, 0}, + {-0.19, -0.301141, 0.145082, 0.144564, -0.0238067, 0.911427}, + }}, + {60, + { + {1, 0, 0, 0, 0, 0}, + {-0.41, 0.912086, 0, 0, 0, 0}, + {0.56, 0.339442, 0.755764, 0, 0, 0}, + {0.02, 0.436582, -0.0256617, 0.899076, 0, 0}, + {-0.07, 0.856608, -0.12116, 0.0715303, 0.491453, 0}, + {-0.2, -0.331109, 0.15136, 0.036082, 0.031313, 0.908391}, + }}, + {70, + { + {1, 0, 0, 0, 0, 0}, + {-0.4, 0.916515, 0, 0, 0, 0}, + {0.56, 0.386246, 0.732949, 0, 0, 0}, + {0.04, 0.573913, -0.0601289, 0.815726, 0, 0}, + {-0.11, 0.813953, -0.0720183, 0.0281118, 0.565158, 0}, + {-0.19, -0.432071, 0.236423, -0.0247788, -0.0557206, 0.847113}, + }}, + {80, + { + {1, 0, 0, 0, 0, 0}, + {-0.46, 0.887919, 0, 0, 0, 0}, + {0.58, 0.469412, 0.665772, 0, 0, 0}, + {0.01, 0.309262, -0.286842, 0.90663, 0, 0}, + {-0.05, 0.762457, -0.268721, -0.0467443, 0.584605, 0}, + {-0.23, -0.580909, 0.399665, 0.0403629, 0.326208, 0.584698}, + }}, + {90, + { + {1, 0, 0, 0, 0, 0}, + {-0.3, 0.953939, 0, 0, 0, 0}, + {0.47, 0.81871, 0.329868, 0, 0, 0}, + {0.06, 0.0712834, -0.595875, 0.797654, 0, 0}, + {-0.1, 0.408831, -0.0233859, 0.0412736, 0.905873, 0}, + {-0.13, -0.407783, 0.439436, -0.0768289, -0.212875, 0.756631}, + }}, +}; + +/** + * The square root matrix for NTN Rural NLOS Ka Band, which is generated + * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-8b and follows + * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA]. + * + * The square root matrix is dependent on the elevation angle, which acts as the corresponding map's + * key.. + * + * The Matlab file to generate the matrices can be found in + * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m + */ +static const std::map>> sqrtC_NTN_Rural_NLOS_Ka{ + {10, + { + {1, 0, 0, 0, 0, 0}, + {-0.36, 0.932952, 0, 0, 0, 0}, + {0.45, 0.527358, 0.72069, 0, 0, 0}, + {0.02, 0.350715, 0.355282, 0.866241, 0, 0}, + {-0.07, 0.562515, 0.478504, 0.0162932, 0.670406, 0}, + {-0.06, 0.0411597, 0.270982, 0.0121094, -0.159927, 0.946336}, + }}, + {20, + { + {1, 0, 0, 0, 0, 0}, + {-0.38, 0.924986, 0, 0, 0, 0}, + {0.52, 0.473088, 0.711188, 0, 0, 0}, + {0, 0.367573, -0.0617198, 0.927944, 0, 0}, + {-0.04, 0.68628, 0.149228, 0.115257, 0.701332, 0}, + {-0.16, -0.0441088, 0.118207, 0.251641, -0.0752458, 0.943131}, + }}, + {30, + { + {1, 0, 0, 0, 0, 0}, + {-0.42, 0.907524, 0, 0, 0, 0}, + {0.54, 0.48131, 0.690464, 0, 0, 0}, + {0, 0.363627, -0.137613, 0.921324, 0, 0}, + {-0.04, 0.686704, 0.117433, 0.104693, 0.708581, 0}, + {-0.19, -0.0438556, 0.0922685, 0.269877, -0.136292, 0.928469}, + }}, + {40, + { + {1, 0, 0, 0, 0, 0}, + {-0.36, 0.932952, 0, 0, 0, 0}, + {0.53, 0.483197, 0.696865, 0, 0, 0}, + {0.01, 0.464761, -0.0285153, 0.88492, 0, 0}, + {-0.05, 0.763169, 0.140255, 0.0562856, 0.626286, 0}, + {-0.16, -0.126051, 0.0942905, 0.195354, -0.217188, 0.92967}, + }}, + {50, + { + {1, 0, 0, 0, 0, 0}, + {-0.39, 0.920815, 0, 0, 0, 0}, + {0.55, 0.406705, 0.729446, 0, 0, 0}, + {0.01, 0.503793, -0.123923, 0.854831, 0, 0}, + {-0.06, 0.821664, -0.207246, 0.0245302, 0.526988, 0}, + {-0.19, -0.254231, 0.10679, 0.190931, -0.0665276, 0.920316}, + }}, + {60, + { + {1, 0, 0, 0, 0, 0}, + {-0.42, 0.907524, 0, 0, 0, 0}, + {0.56, 0.391395, 0.730213, 0, 0, 0}, + {0.02, 0.427978, -0.0393147, 0.902712, 0, 0}, + {-0.06, 0.820694, -0.119986, 0.105509, 0.545281, 0}, + {-0.2, -0.279882, 0.180145, 0.0563477, -0.0121631, 0.919723}, + }}, + {70, + { + {1, 0, 0, 0, 0, 0}, + {-0.36, 0.932952, 0, 0, 0, 0}, + {0.54, 0.519212, 0.662434, 0, 0, 0}, + {0.04, 0.412025, -0.0234416, 0.909992, 0, 0}, + {-0.09, 0.758452, -0.0682296, 0.0214276, 0.64151, 0}, + {-0.17, -0.387158, 0.306169, -0.0291255, -0.109344, 0.845378}, + }}, + {80, + { + {1, 0, 0, 0, 0, 0}, + {-0.44, 0.897998, 0, 0, 0, 0}, + {0.57, 0.43519, 0.696928, 0, 0, 0}, + {0.01, 0.316705, -0.248988, 0.915207, 0, 0}, + {-0.06, 0.805793, -0.296262, -0.0419182, 0.507514, 0}, + {-0.22, -0.497551, 0.289742, 0.0785823, 0.328773, 0.711214}, + }}, + {90, + { + {1, 0, 0, 0, 0, 0}, + {-0.27, 0.96286, 0, 0, 0, 0}, + {0.46, 0.741748, 0.488067, 0, 0, 0}, + {0.04, 0.0735309, -0.374828, 0.923308, 0, 0}, + {-0.08, 0.517624, 0.128779, 0.0795063, 0.838308, 0}, + {-0.11, -0.321646, 0.0802763, -0.131981, -0.193429, 0.907285}, + }}, +}; + +/** + * The enumerator used for code clarity when performing parameter assignment in GetThreeGppTable + */ +enum Table3gppParams +{ + uLgDS, + sigLgDS, + uLgASD, + sigLgASD, + uLgASA, + sigLgASA, + uLgZSA, + sigLgZSA, + uLgZSD, + sigLgZSD, + uK, + sigK, + rTau, + uXpr, + sigXpr, + numOfCluster, + raysPerCluster, + cDS, + cASD, + cASA, + cZSA, + perClusterShadowingStd +}; + +/** + * The nested map containing the threegpp value tables for the NTN Dense Urban LOS scenario + */ +static const std::map>> m_NTNDenseUrbanLOS{ + {"S", + { + {10, + { + -7.12, 0.8, -3.06, 0.48, 0.94, 0.7, 0.82, 0.03, -2.52, 0.5, 4.4, + 3.3, 2.5, 24.4, 3.8, 3.0, 20.0, 3.9, 0.0, 11.0, 7.0, 3.0, + }}, + {20, + { + -7.28, 0.67, -2.68, 0.36, 0.87, 0.66, 0.5, 0.09, -2.29, 0.53, 9.0, + 6.6, 2.5, 23.6, 4.7, 3.0, 20.0, 3.9, 0.0, 11.0, 7.0, 3.0, + }}, + {30, + { + -7.45, 0.68, -2.51, 0.38, 0.92, 0.68, 0.82, 0.05, -2.19, 0.58, 9.3, + 6.1, 2.5, 23.2, 4.6, 3.0, 20.0, 3.9, 0.0, 11.0, 7.0, 3.0, + }}, + {40, + { + -7.73, 0.66, -2.4, 0.32, 0.79, 0.64, 1.23, 0.03, -2.24, 0.51, 7.9, + 4.0, 2.5, 22.6, 4.9, 3.0, 20.0, 3.9, 0.0, 11.0, 7.0, 3.0, + }}, + {50, + { + -7.91, 0.62, -2.31, 0.33, 0.72, 0.63, 1.43, 0.06, -2.3, 0.46, 7.4, + 3.0, 2.5, 21.8, 5.7, 3.0, 20.0, 3.9, 0.0, 11.0, 7.0, 3.0, + }}, + {60, + { + -8.14, 0.51, -2.2, 0.39, 0.6, 0.54, 1.56, 0.05, -2.48, 0.35, 7.0, + 2.6, 2.5, 20.5, 6.9, 3.0, 20.0, 3.9, 0.0, 11.0, 7.0, 3.0, + }}, + {70, + { + -8.23, 0.45, -2.0, 0.4, 0.55, 0.52, 1.66, 0.05, -2.64, 0.31, 6.9, + 2.2, 2.5, 19.3, 8.1, 3.0, 20.0, 3.9, 0.0, 11.0, 7.0, 3.0, + }}, + {80, + { + -8.28, 0.31, -1.64, 0.32, 0.71, 0.53, 1.73, 0.02, -2.68, 0.39, 6.5, + 2.1, 2.5, 17.4, 10.3, 3.0, 20.0, 3.9, 0.0, 11.0, 7.0, 3.0, + }}, + {90, + { + -8.36, 0.08, -0.63, 0.53, 0.81, 0.62, 1.79, 0.01, -2.61, 0.28, 6.8, + 1.9, 2.5, 12.3, 15.2, 3.0, 20.0, 3.9, 0.0, 11.0, 7.0, 3.0, + }}, + }}, + {"Ka", + { + {10, + { + -7.43, 0.9, -3.43, 0.54, 0.65, 0.82, 0.82, 0.05, -2.75, 0.55, 6.1, + 2.6, 2.5, 24.7, 2.1, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {20, + { + -7.62, 0.78, -3.06, 0.41, 0.53, 0.78, 0.47, 0.11, -2.64, 0.64, 13.7, + 6.8, 2.5, 24.4, 2.8, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {30, + { + -7.76, 0.8, -2.91, 0.42, 0.6, 0.83, 0.8, 0.05, -2.49, 0.69, 12.9, + 6.0, 2.5, 24.4, 2.7, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {40, + { + -8.02, 0.72, -2.81, 0.34, 0.43, 0.78, 1.23, 0.04, -2.51, 0.57, 10.3, + 3.3, 2.5, 24.2, 2.7, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {50, + { + -8.13, 0.61, -2.74, 0.34, 0.36, 0.77, 1.42, 0.1, -2.54, 0.5, 9.2, + 2.2, 2.5, 23.9, 3.1, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {60, + { + -8.3, 0.47, -2.72, 0.7, 0.16, 0.84, 1.56, 0.06, -2.71, 0.37, 8.4, + 1.9, 2.5, 23.3, 3.9, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {70, + { + -8.34, 0.39, -2.46, 0.4, 0.18, 0.64, 1.65, 0.07, -2.85, 0.31, 8.0, + 1.5, 2.5, 22.6, 4.8, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {80, + { + -8.39, 0.26, -2.3, 0.78, 0.24, 0.81, 1.73, 0.02, -3.01, 0.45, 7.4, + 1.6, 2.5, 21.2, 6.8, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {90, + { + -8.45, 0.01, -1.11, 0.51, 0.36, 0.65, 1.79, 0.01, -3.08, 0.27, 7.6, + 1.3, 2.5, 17.6, 12.7, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + }}, +}; + +/** + * The nested map containing the threegpp value tables for the NTN Dense Urban NLOS scenario + */ +static const std::map>> m_NTNDenseUrbanNLOS{ + {"S", + { + {10, + { + -6.84, 0.82, -2.08, 0.87, 1.0, 1.6, 1.0, 0.63, -2.08, 0.58, + 2.3, 23.8, 4.4, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {20, + { + -6.81, 0.61, -1.68, 0.73, 1.44, 0.87, 0.94, 0.65, -1.66, 0.5, + 2.3, 21.9, 6.3, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {30, + { + -6.94, 0.49, -1.46, 0.53, 1.54, 0.64, 1.15, 0.42, -1.48, 0.4, + 2.3, 19.7, 8.1, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {40, + { + -7.14, 0.49, -1.43, 0.5, 1.53, 0.56, 1.35, 0.28, -1.46, 0.37, + 2.3, 18.1, 9.3, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {50, + { + -7.34, 0.51, -1.44, 0.58, 1.48, 0.54, 1.44, 0.25, -1.53, 0.47, + 2.3, 16.3, 11.5, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {60, + { + -7.53, 0.47, -1.33, 0.49, 1.39, 0.68, 1.56, 0.16, -1.61, 0.43, + 2.3, 14.0, 13.3, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {70, + { + -7.67, 0.44, -1.31, 0.65, 1.42, 0.55, 1.64, 0.18, -1.77, 0.5, + 2.3, 12.1, 14.9, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {80, + { + -7.82, 0.42, -1.11, 0.69, 1.38, 0.6, 1.7, 0.09, -1.9, 0.42, + 2.3, 8.7, 17.0, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {90, + { + -7.84, 0.55, -0.11, 0.53, 1.23, 0.6, 1.7, 0.17, -1.99, 0.5, + 2.3, 6.4, 12.3, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + }}, + {"Ka", + { + {10, + { + -6.86, 0.81, -2.12, 0.94, 1.02, 1.44, 1.01, 0.56, -2.11, 0.59, + 2.3, 23.7, 4.5, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {20, + { + -6.84, 0.61, -1.74, 0.79, 1.44, 0.77, 0.96, 0.55, -1.69, 0.51, + 2.3, 21.8, 6.3, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {30, + { + -7.0, 0.56, -1.56, 0.66, 1.48, 0.7, 1.13, 0.43, -1.52, 0.46, + 2.3, 19.6, 8.2, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {40, + { + -7.21, 0.56, -1.54, 0.63, 1.46, 0.6, 1.3, 0.37, -1.51, 0.43, + 2.3, 18.0, 9.4, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {50, + { + -7.42, 0.57, -1.45, 0.56, 1.4, 0.59, 1.4, 0.32, -1.54, 0.45, + 2.3, 16.3, 11.5, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {60, + { + -7.86, 0.55, -1.64, 0.78, 0.97, 1.27, 1.41, 0.45, -1.84, 0.63, + 2.3, 15.9, 12.4, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {70, + { + -7.76, 0.47, -1.37, 0.56, 1.33, 0.56, 1.63, 0.17, -1.86, 0.51, + 2.3, 12.3, 15.0, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {80, + { + -8.07, 0.42, -1.29, 0.76, 1.12, 1.04, 1.68, 0.14, -2.16, 0.74, + 2.3, 10.5, 15.7, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + {90, + { + -7.95, 0.59, -0.41, 0.59, 1.04, 0.63, 1.7, 0.17, -2.21, 0.61, + 2.3, 10.5, 15.7, 4.0, 20.0, 3.9, 0.0, 15.0, 7.0, 3.0, + }}, + }}, +}; + +/** + * The nested map containing the threegpp value tables for the NTN Urban LOS scenario + */ +static const std::map>> m_NTNUrbanLOS{ + {"S", + { + {10, + { + -7.97, 1.0, -2.6, 0.79, 0.18, 0.74, -0.63, 2.6, -2.54, 2.62, 31.83, + 13.84, 2.5, 8.0, 4.0, 4.0, 20.0, 3.9, 0.09, 12.55, 1.25, 3.0, + }}, + {20, + { + -8.12, 0.83, -2.48, 0.8, 0.42, 0.9, -0.15, 3.31, -2.67, 2.96, 18.78, + 13.78, 2.5, 8.0, 4.0, 3.0, 20.0, 3.9, 0.09, 12.76, 3.23, 3.0, + }}, + {30, + { + -8.21, 0.68, -2.44, 0.91, 0.41, 1.3, 0.54, 1.1, -2.03, 0.86, 10.49, + 10.42, 2.5, 8.0, 4.0, 3.0, 20.0, 3.9, 0.12, 14.36, 4.39, 3.0, + }}, + {40, + { + -8.31, 0.48, -2.6, 1.02, 0.18, 1.69, 0.35, 1.59, -2.28, 1.19, 7.46, + 8.01, 2.5, 8.0, 4.0, 3.0, 20.0, 3.9, 0.16, 16.42, 5.72, 3.0, + }}, + {50, + { + -8.37, 0.38, -2.71, 1.17, -0.07, 2.04, 0.27, 1.62, -2.48, 1.4, 6.52, + 8.27, 2.5, 8.0, 4.0, 3.0, 20.0, 3.9, 0.2, 17.13, 6.17, 3.0, + }}, + {60, + { + -8.39, 0.24, -2.76, 1.17, -0.43, 2.54, 0.26, 0.97, -2.56, 0.85, 5.47, + 7.26, 2.5, 8.0, 4.0, 3.0, 20.0, 3.9, 0.28, 19.01, 7.36, 3.0, + }}, + {70, + { + -8.38, 0.18, -2.78, 1.2, -0.64, 2.47, -0.12, 1.99, -2.96, 1.61, 4.54, + 5.53, 2.5, 8.0, 4.0, 3.0, 20.0, 3.9, 0.44, 19.31, 7.3, 3.0, + }}, + {80, + { + -8.35, 0.13, -2.65, 1.45, -0.91, 2.69, -0.21, 1.82, -3.08, 1.49, 4.03, + 4.49, 2.5, 8.0, 4.0, 3.0, 20.0, 3.9, 0.9, 22.39, 7.7, 3.0, + }}, + {90, + { + -8.34, 0.09, -2.27, 1.85, -0.54, 1.66, -0.07, 1.43, -3.0, 1.09, 3.68, + 3.14, 2.5, 8.0, 4.0, 3.0, 20.0, 3.9, 2.87, 27.8, 9.25, 3.0, + }}, + }}, + {"Ka", + { + {10, + { + -8.52, 0.92, -3.18, 0.79, -0.4, 0.77, -0.67, 2.22, -2.61, 2.41, 40.18, + 16.99, 2.5, 8.0, 4.0, 4.0, 20.0, 1.6, 0.09, 11.8, 1.14, 3.0, + }}, + {20, + { + -8.59, 0.79, -3.05, 0.87, -0.15, 0.97, -0.34, 3.04, -2.82, 2.59, 23.62, + 18.96, 2.5, 8.0, 4.0, 3.0, 20.0, 1.6, 0.09, 11.6, 2.78, 3.0, + }}, + {30, + { + -8.51, 0.65, -2.98, 1.04, -0.18, 1.58, 0.07, 1.33, -2.48, 1.02, 12.48, + 14.23, 2.5, 8.0, 4.0, 3.0, 20.0, 1.6, 0.11, 13.05, 3.87, 3.0, + }}, + {40, + { + -8.49, 0.48, -3.11, 1.06, -0.31, 1.69, -0.08, 1.45, -2.76, 1.27, 8.56, + 11.06, 2.5, 8.0, 4.0, 3.0, 20.0, 1.6, 0.15, 14.56, 4.94, 3.0, + }}, + {50, + { + -8.48, 0.46, -3.19, 1.12, -0.58, 2.13, -0.21, 1.62, -2.93, 1.38, 7.42, + 11.21, 2.5, 8.0, 4.0, 3.0, 20.0, 1.6, 0.18, 15.35, 5.41, 3.0, + }}, + {60, + { + -8.44, 0.34, -3.25, 1.14, -0.9, 2.51, -0.25, 1.06, -3.05, 0.96, 5.97, + 9.47, 2.5, 8.0, 4.0, 3.0, 20.0, 1.6, 0.27, 16.97, 6.31, 3.0, + }}, + {70, + { + -8.4, 0.27, -3.33, 1.25, -1.16, 2.47, -0.61, 1.88, -3.45, 1.51, 4.88, + 7.24, 2.5, 8.0, 4.0, 3.0, 20.0, 1.6, 0.42, 17.96, 6.66, 3.0, + }}, + {80, + { + -8.37, 0.19, -3.22, 1.35, -1.48, 2.61, -0.79, 1.87, -3.66, 1.49, 4.22, + 5.79, 2.5, 8.0, 4.0, 3.0, 20.0, 1.6, 0.86, 20.68, 7.31, 3.0, + }}, + {90, + { + -8.35, 0.14, -2.83, 1.62, -1.14, 1.7, -0.58, 1.19, -3.56, 0.89, 3.81, + 4.25, 2.5, 8.0, 4.0, 3.0, 20.0, 1.6, 2.55, 25.08, 9.23, 3.0, + }}, + }}, +}; + +/** + * The nested map containing the threegpp value tables for the NTN Urban NLOS scenario + */ +static const std::map>> m_NTNUrbanNLOS{ + {"S", + { + {10, + { + -7.24, 1.26, -1.58, 0.89, 0.13, 2.99, -1.13, 2.66, -2.87, 2.76, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.08, 14.72, 1.57, 3.0, + }}, + {20, + { + -7.7, 0.99, -1.67, 0.89, 0.19, 3.12, 0.49, 2.03, -2.68, 2.76, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.1, 14.62, 4.3, 3.0, + }}, + {30, + { + -7.82, 0.86, -1.84, 1.3, 0.44, 2.69, 0.95, 1.54, -2.12, 1.54, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.14, 16.4, 6.64, 3.0, + }}, + {40, + { + -8.04, 0.75, -2.02, 1.15, 0.48, 2.45, 1.15, 1.02, -2.27, 1.77, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.22, 17.86, 9.21, 3.0, + }}, + {50, + { + -8.08, 0.77, -2.06, 1.23, 0.56, 2.17, 1.14, 1.61, -2.5, 2.36, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.31, 19.74, 10.32, 3.0, + }}, + {60, + { + -8.1, 0.76, -1.99, 1.02, 0.55, 1.93, 1.13, 1.84, -2.47, 2.33, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.49, 19.73, 10.3, 3.0, + }}, + {70, + { + -8.16, 0.73, -2.19, 1.78, 0.48, 1.72, 1.16, 1.81, -2.83, 2.84, 0.0, + 0.0, 2.3, 7.0, 3.0, 2.0, 20.0, 1.6, 0.97, 20.5, 10.2, 3.0, + }}, + {80, + { + -8.03, 0.79, -1.88, 1.55, 0.53, 1.51, 1.28, 1.35, -2.82, 2.87, 0.0, + 0.0, 2.3, 7.0, 3.0, 2.0, 20.0, 1.6, 1.52, 26.16, 12.27, 3.0, + }}, + {90, + { + -8.33, 0.7, -2.0, 1.4, 0.32, 1.2, 1.42, 0.6, -4.55, 4.27, 0.0, + 0.0, 2.3, 7.0, 3.0, 2.0, 20.0, 1.6, 5.36, 25.83, 12.75, 3.0, + }}, + }}, + {"Ka", + { + {10, + { + -7.24, 1.26, -1.58, 0.89, 0.13, 2.99, -1.13, 2.66, -2.87, 2.76, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.08, 14.72, 1.57, 3.0, + }}, + {20, + { + -7.7, 0.99, -1.67, 0.89, 0.19, 3.12, 0.49, 2.03, -2.68, 2.76, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.1, 14.62, 4.3, 3.0, + }}, + {30, + { + -7.82, 0.86, -1.84, 1.3, 0.44, 2.69, 0.95, 1.54, -2.12, 1.54, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.14, 16.4, 6.64, 3.0, + }}, + {40, + { + -8.04, 0.75, -2.02, 1.15, 0.48, 2.45, 1.15, 1.02, -2.27, 1.77, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.22, 17.86, 9.21, 3.0, + }}, + {50, + { + -8.08, 0.77, -2.06, 1.23, 0.56, 2.17, 1.14, 1.61, -2.5, 2.36, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.31, 19.74, 10.32, 3.0, + }}, + {60, + { + -8.1, 0.76, -1.99, 1.02, 0.55, 1.93, 1.13, 1.84, -2.47, 2.33, 0.0, + 0.0, 2.3, 7.0, 3.0, 3.0, 20.0, 1.6, 0.49, 19.73, 10.3, 3.0, + }}, + {70, + { + -8.16, 0.73, -2.19, 1.78, 0.48, 1.72, 1.16, 1.81, -2.83, 2.84, 0.0, + 0.0, 2.3, 7.0, 3.0, 2.0, 20.0, 1.6, 0.97, 20.5, 10.2, 3.0, + }}, + {80, + { + -8.03, 0.79, -1.88, 1.55, 0.53, 1.51, 1.28, 1.35, -2.82, 2.87, 0.0, + 0.0, 2.3, 7.0, 3.0, 2.0, 20.0, 1.6, 1.52, 26.16, 12.27, 3.0, + }}, + {90, + { + -8.33, 0.7, -2.0, 1.4, 0.32, 1.2, 1.42, 0.6, -4.55, 4.27, 0.0, + 0.0, 2.3, 7.0, 3.0, 2.0, 20.0, 1.6, 5.36, 25.83, 12.75, 3.0, + }}, + }}, +}; + +/** + * The nested map containing the threegpp value tables for the NTN Suburban LOS scenario + */ +static const std::map>> m_NTNSuburbanLOS{ + {"S", + { + {10, + { + -8.16, 0.99, -3.57, 1.62, 0.05, 1.84, -1.78, 0.62, -1.06, 0.96, 11.4, + 6.26, 2.2, 21.3, 7.6, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {20, + { + -8.56, 0.96, -3.8, 1.74, -0.38, 1.94, -1.84, 0.81, -1.21, 0.95, 19.45, + 10.32, 3.36, 21.0, 8.9, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {30, + { + -8.72, 0.79, -3.77, 1.72, -0.56, 1.75, -1.67, 0.57, -1.28, 0.49, 20.8, + 16.34, 3.5, 21.2, 8.5, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {40, + { + -8.71, 0.81, -3.57, 1.6, -0.59, 1.82, -1.59, 0.86, -1.32, 0.79, 21.2, + 15.63, 2.81, 21.1, 8.4, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {50, + { + -8.72, 1.12, -3.42, 1.49, -0.58, 1.87, -1.55, 1.05, -1.39, 0.97, 21.6, + 14.22, 2.39, 20.7, 9.2, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {60, + { + -8.66, 1.23, -3.27, 1.43, -0.55, 1.92, -1.51, 1.23, -1.36, 1.17, 19.75, + 14.19, 2.73, 20.6, 9.8, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {70, + { + -8.38, 0.55, -3.08, 1.36, -0.28, 1.16, -1.27, 0.54, -1.08, 0.62, 12.0, + 5.7, 2.07, 20.3, 10.8, 2.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {80, + { + -8.34, 0.63, -2.75, 1.26, -0.17, 1.09, -1.28, 0.67, -1.31, 0.76, 12.85, + 9.91, 2.04, 19.8, 12.2, 2.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {90, + { + -8.34, 0.63, -2.75, 1.26, -0.17, 1.09, -1.28, 0.67, -1.31, 0.76, 12.85, + 9.91, 2.04, 19.1, 13.0, 2.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + }}, + {"Ka", + { + {10, + { + -8.07, 0.46, -3.55, 0.48, 0.89, 0.67, 0.63, 0.35, -3.37, 0.28, 8.9, + 4.4, 2.5, 23.2, 5.0, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {20, + { + -8.61, 0.45, -3.69, 0.41, 0.31, 0.78, 0.76, 0.3, -3.28, 0.27, 14.0, + 4.6, 2.5, 23.6, 4.5, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {30, + { + -8.72, 0.28, -3.59, 0.41, 0.02, 0.75, 1.11, 0.28, -3.04, 0.26, 11.3, + 3.7, 2.5, 23.5, 4.7, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {40, + { + -8.63, 0.17, -3.38, 0.35, -0.1, 0.65, 1.37, 0.23, -2.88, 0.21, 9.0, + 3.5, 2.5, 23.4, 5.2, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {50, + { + -8.54, 0.14, -3.23, 0.35, -0.19, 0.55, 1.53, 0.23, -2.83, 0.18, 7.5, + 3.0, 2.5, 23.2, 5.7, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {60, + { + -8.48, 0.15, -3.19, 0.43, -0.54, 0.96, 1.65, 0.17, -2.86, 0.17, 6.6, + 2.6, 2.5, 23.3, 5.9, 3.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {70, + { + -8.42, 0.09, -2.83, 0.33, -0.24, 0.43, 1.74, 0.11, -2.95, 0.1, 5.9, + 1.7, 2.5, 23.4, 6.2, 2.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {80, + { + -8.39, 0.05, -2.66, 0.44, -0.52, 0.93, 1.82, 0.05, -3.21, 0.07, 5.5, + 0.7, 2.5, 23.2, 7.0, 2.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + {90, + { + -8.37, 0.02, -1.22, 0.31, -0.15, 0.44, 1.87, 0.02, -3.49, 0.24, 5.4, + 0.3, 2.5, 23.1, 7.6, 2.0, 20.0, 1.6, 0.0, 11.0, 7.0, 3.0, + }}, + }}, +}; + +/** + * The nested map containing the threegpp value tables for the NTN Suburban NLOS scenario + */ +static const std::map>> m_NTNSuburbanNLOS{ + {"S", + { + {10, + { + -7.43, 0.5, -2.89, 0.41, 1.49, 0.4, 0.81, 0.36, -3.09, 0.32, 0.0, + 0.0, 2.3, 22.5, 5.0, 4.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {20, + { + -7.63, 0.61, -2.76, 0.41, 1.24, 0.82, 1.06, 0.41, -2.93, 0.47, 0.0, + 0.0, 2.3, 19.4, 8.5, 4.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {30, + { + -7.86, 0.56, -2.64, 0.41, 1.06, 0.71, 1.12, 0.4, -2.91, 0.46, 0.0, + 0.0, 2.3, 15.5, 10.0, 4.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {40, + { + -7.96, 0.58, -2.41, 0.52, 0.91, 0.55, 1.14, 0.39, -2.78, 0.54, 0.0, + 0.0, 2.3, 13.9, 10.6, 4.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {50, + { + -7.98, 0.59, -2.42, 0.7, 0.98, 0.58, 1.29, 0.35, -2.7, 0.45, 0.0, + 0.0, 2.3, 11.7, 10.0, 4.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {60, + { + -8.45, 0.47, -2.53, 0.5, 0.49, 1.37, 1.38, 0.36, -3.03, 0.36, 0.0, + 0.0, 2.3, 9.8, 9.1, 3.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {70, + { + -8.21, 0.36, -2.35, 0.58, 0.73, 0.49, 1.36, 0.29, -2.9, 0.42, 0.0, + 0.0, 2.3, 10.3, 9.1, 3.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {80, + { + -8.69, 0.29, -2.31, 0.73, -0.04, 1.48, 1.38, 0.2, -3.2, 0.3, 0.0, + 0.0, 2.3, 15.6, 9.1, 3.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {90, + { + -8.69, 0.29, -2.31, 0.73, -0.04, 1.48, 1.38, 0.2, -3.2, 0.3, 0.0, + 0.0, 2.3, 15.6, 9.1, 3.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + }}, + {"Ka", + { + {10, + { + -7.43, 0.5, -2.89, 0.41, 1.49, 0.4, 0.81, 0.36, -3.09, 0.32, 0.0, + 0.0, 2.3, 22.5, 5.0, 4.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {20, + { + -7.63, 0.61, -2.76, 0.41, 1.24, 0.82, 1.06, 0.41, -2.93, 0.47, 0.0, + 0.0, 2.3, 19.4, 8.5, 4.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {30, + { + -7.86, 0.56, -2.64, 0.41, 1.06, 0.71, 1.12, 0.4, -2.91, 0.46, 0.0, + 0.0, 2.3, 15.5, 10.0, 4.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {40, + { + -7.96, 0.58, -2.41, 0.52, 0.91, 0.55, 1.14, 0.39, -2.78, 0.54, 0.0, + 0.0, 2.3, 13.9, 10.6, 4.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {50, + { + -7.98, 0.59, -2.42, 0.7, 0.98, 0.58, 1.29, 0.35, -2.7, 0.45, 0.0, + 0.0, 2.3, 11.7, 10.0, 4.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {60, + { + -8.45, 0.47, -2.53, 0.5, 0.49, 1.37, 1.38, 0.36, -3.03, 0.36, 0.0, + 0.0, 2.3, 9.8, 9.1, 3.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {70, + { + -8.21, 0.36, -2.35, 0.58, 0.73, 0.49, 1.36, 0.29, -2.9, 0.42, 0.0, + 0.0, 2.3, 10.3, 9.1, 3.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {80, + { + -8.69, 0.29, -2.31, 0.73, -0.04, 1.48, 1.38, 0.2, -3.2, 0.3, 0.0, + 0.0, 2.3, 15.6, 9.1, 3.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + {90, + { + -8.69, 0.29, -2.31, 0.73, -0.04, 1.48, 1.38, 0.2, -3.2, 0.3, 0.0, + 0.0, 2.3, 15.6, 9.1, 3.0, 20.0, 1.6, 0.0, 15.0, 7.0, 3.0, + }}, + }}, +}; + +/** + * The nested map containing the threegpp value tables for the NTN Rural LOS scenario + */ +static const std::map>> m_NTNRuralLOS{ + {"S", + { + {10, + { + -9.55, 0.66, -3.42, 0.89, -9.45, 7.83, -4.2, 6.3, -6.03, 5.19, 24.72, + 5.07, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.39, 10.81, 1.94, 3.0, + }}, + {20, + { + -8.68, 0.44, -3.0, 0.63, -4.45, 6.86, -2.31, 5.04, -4.31, 4.18, 12.31, + 5.75, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.31, 8.09, 1.83, 3.0, + }}, + {30, + { + -8.46, 0.28, -2.86, 0.52, -2.39, 5.14, -0.28, 0.81, -2.57, 0.61, 8.05, + 5.46, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.29, 13.7, 2.28, 3.0, + }}, + {40, + { + -8.36, 0.19, -2.78, 0.45, -1.28, 3.44, -0.38, 1.16, -2.59, 0.79, 6.21, + 5.23, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.37, 20.05, 2.93, 3.0, + }}, + {50, + { + -8.29, 0.14, -2.7, 0.42, -0.99, 2.59, -0.38, 0.82, -2.59, 0.65, 5.04, + 3.95, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.61, 24.51, 2.84, 3.0, + }}, + {60, + { + -8.26, 0.1, -2.66, 0.41, -1.05, 2.42, -0.46, 0.67, -2.65, 0.52, 4.42, + 3.75, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.9, 26.35, 3.17, 3.0, + }}, + {70, + { + -8.22, 0.1, -2.53, 0.42, -0.9, 1.78, -0.49, 1.0, -2.69, 0.78, 3.92, + 2.56, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 1.43, 31.84, 3.88, 3.0, + }}, + {80, + { + -8.2, 0.05, -2.21, 0.5, -0.89, 1.65, -0.53, 1.18, -2.65, 1.01, 3.65, + 1.77, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 2.87, 36.62, 4.17, 3.0, + }}, + {90, + { + -8.19, 0.06, -1.78, 0.91, -0.81, 1.26, -0.46, 0.91, -2.65, 0.71, 3.59, + 1.77, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 5.48, 36.77, 4.29, 3.0, + }}, + }}, + {"Ka", + { + {10, + { + -9.68, 0.46, -4.03, 0.91, -9.74, 7.52, -5.85, 6.51, -7.45, 5.3, 25.43, + 7.04, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.36, 4.63, 0.75, 3.0, + }}, + {20, + { + -8.86, 0.29, -3.55, 0.7, -4.88, 6.67, -3.27, 5.36, -5.25, 4.42, 12.72, + 7.47, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.3, 6.83, 1.25, 3.0, + }}, + {30, + { + -8.59, 0.18, -3.45, 0.55, -2.6, 4.63, -0.88, 0.93, -3.16, 0.68, 8.4, + 7.18, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.25, 12.91, 1.93, 3.0, + }}, + {40, + { + -8.46, 0.19, -3.38, 0.52, -1.92, 3.45, -0.93, 0.96, -3.15, 0.73, 6.52, + 6.88, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.35, 18.9, 2.37, 3.0, + }}, + {50, + { + -8.36, 0.14, -3.33, 0.46, -1.56, 2.44, -0.99, 0.97, -3.2, 0.77, 5.24, + 5.28, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.53, 22.44, 2.66, 3.0, + }}, + {60, + { + -8.3, 0.15, -3.29, 0.43, -1.66, 2.38, -1.04, 0.83, -3.27, 0.61, 4.57, + 4.92, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 0.88, 25.69, 3.23, 3.0, + }}, + {70, + { + -8.26, 0.13, -3.24, 0.46, -1.59, 1.67, -1.17, 1.01, -3.42, 0.74, 4.02, + 3.4, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 1.39, 27.95, 3.71, 3.0, + }}, + {80, + { + -8.22, 0.03, -2.9, 0.44, -1.58, 1.44, -1.19, 1.01, -3.36, 0.79, 3.7, + 2.22, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 2.7, 31.45, 4.17, 3.0, + }}, + {90, + { + -8.21, 0.07, -2.5, 0.82, -1.51, 1.13, -1.13, 0.85, -3.35, 0.65, 3.62, + 2.28, 3.8, 12.0, 4.0, 2.0, 20.0, 0.0, 4.97, 28.01, 4.14, 3.0, + }}, + }}, +}; + +/** + * The nested map containing the threegpp value tables for the NTN Rural NLOS scenario + */ +static const std::map>> m_NTNRuralNLOS{ + {"S", + { + {10, + { + -9.01, 1.59, -2.9, 1.34, -3.33, 6.22, -0.88, 3.26, -4.92, 3.96, 0.0, + 0.0, 1.7, 7.0, 3.0, 3.0, 20.0, 0.0, 0.03, 18.16, 2.32, 3.0, + }}, + {20, + { + -8.37, 0.95, -2.5, 1.18, -0.74, 4.22, -0.07, 3.29, -4.06, 4.07, 0.0, + 0.0, 1.7, 7.0, 3.0, 3.0, 20.0, 0.0, 0.05, 26.82, 7.34, 3.0, + }}, + {30, + { + -8.05, 0.92, -2.12, 1.08, 0.08, 3.02, 0.75, 1.92, -2.33, 1.7, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 0.07, 21.99, 8.28, 3.0, + }}, + {40, + { + -7.92, 0.92, -1.99, 1.06, 0.32, 2.45, 0.72, 1.92, -2.24, 2.01, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 0.1, 22.86, 8.76, 3.0, + }}, + {50, + { + -7.92, 0.87, -1.9, 1.05, 0.53, 1.63, 0.95, 1.45, -2.24, 2.0, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 0.15, 25.93, 9.68, 3.0, + }}, + {60, + { + -7.96, 0.87, -1.85, 1.06, 0.33, 2.08, 0.97, 1.62, -2.22, 1.82, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 0.22, 27.79, 9.94, 3.0, + }}, + {70, + { + -7.91, 0.82, -1.69, 1.14, 0.55, 1.58, 1.1, 1.43, -2.19, 1.66, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 0.5, 28.5, 8.9, 3.0, + }}, + {80, + { + -7.79, 0.86, -1.46, 1.16, 0.45, 2.01, 0.97, 1.88, -2.41, 2.58, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 1.04, 37.53, 13.74, 3.0, + }}, + {90, + { + -7.74, 0.81, -1.32, 1.3, 0.4, 2.19, 1.35, 0.62, -2.45, 2.52, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 2.11, 29.23, 12.16, 3.0, + }}, + }}, + {"Ka", + { + {10, + { + -9.13, 1.91, -2.9, 1.32, -3.4, 6.28, -1.19, 3.81, -5.47, 4.39, 0.0, + 0.0, 1.7, 7.0, 3.0, 3.0, 20.0, 0.0, 0.03, 18.21, 2.13, 3.0, + }}, + {20, + { + -8.39, 0.94, -2.53, 1.18, -0.51, 3.75, -0.11, 3.33, -4.06, 4.04, 0.0, + 0.0, 1.7, 7.0, 3.0, 3.0, 20.0, 0.0, 0.05, 24.08, 6.52, 3.0, + }}, + {30, + { + -8.1, 0.92, -2.16, 1.08, 0.06, 2.95, 0.72, 1.93, -2.32, 1.54, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 0.07, 22.06, 7.72, 3.0, + }}, + {40, + { + -7.96, 0.94, -2.04, 1.09, 0.2, 2.65, 0.69, 1.91, -2.19, 1.73, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 0.09, 21.4, 8.45, 3.0, + }}, + {50, + { + -7.99, 0.89, -1.99, 1.08, 0.4, 1.85, 0.84, 1.7, -2.16, 1.5, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 0.16, 24.26, 8.92, 3.0, + }}, + {60, + { + -8.05, 0.87, -1.95, 1.06, 0.32, 1.83, 0.99, 1.27, -2.24, 1.64, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 0.22, 24.15, 8.76, 3.0, + }}, + {70, + { + -8.01, 0.82, -1.81, 1.17, 0.46, 1.57, 0.95, 1.86, -2.29, 1.66, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 0.51, 25.99, 9.0, 3.0, + }}, + {80, + { + -8.05, 1.65, -1.56, 1.2, 0.33, 1.99, 0.92, 1.84, -2.65, 2.86, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 0.89, 36.07, 13.6, 3.0, + }}, + {90, + { + -7.91, 0.76, -1.53, 1.27, 0.24, 2.18, 1.29, 0.59, -2.23, 1.12, 0.0, + 0.0, 1.7, 7.0, 3.0, 2.0, 20.0, 0.0, 1.68, 24.51, 10.56, 3.0, + }}, + }}, +}; + ThreeGppChannelModel::ThreeGppChannelModel() { NS_LOG_FUNCTION(this); @@ -294,7 +1529,8 @@ ThreeGppChannelModel::GetTypeId() MakeDoubleChecker()) .AddAttribute( "Scenario", - "The 3GPP scenario (RMa, UMa, UMi-StreetCanyon, InH-OfficeOpen, InH-OfficeMixed)", + "The 3GPP scenario (RMa, UMa, UMi-StreetCanyon, InH-OfficeOpen, InH-OfficeMixed, " + "NTN-DenseUrban, NTN-Urban, NTN-Suburban, NTN-Rural)", StringValue("UMa"), MakeStringAccessor(&ThreeGppChannelModel::SetScenario, &ThreeGppChannelModel::GetScenario), @@ -380,9 +1616,12 @@ ThreeGppChannelModel::SetScenario(const std::string& scenario) NS_LOG_FUNCTION(this); NS_ASSERT_MSG(scenario == "RMa" || scenario == "UMa" || scenario == "UMi-StreetCanyon" || scenario == "InH-OfficeOpen" || scenario == "InH-OfficeMixed" || - scenario == "V2V-Urban" || scenario == "V2V-Highway", + scenario == "V2V-Urban" || scenario == "V2V-Highway" || + scenario == "NTN-DenseUrban" || scenario == "NTN-Urban" || + scenario == "NTN-Suburban" || scenario == "NTN-Rural", "Unknown scenario, choose between: RMa, UMa, UMi-StreetCanyon, " - "InH-OfficeOpen, InH-OfficeMixed, V2V-Urban or V2V-Highway"); + "InH-OfficeOpen, InH-OfficeMixed, V2V-Urban, V2V-Highway, " + "NTN-DenseUrban, NTN-Urban, NTN-Suburban or NTN-Rural"); m_scenario = scenario; } @@ -394,13 +1633,20 @@ ThreeGppChannelModel::GetScenario() const } Ptr -ThreeGppChannelModel::GetThreeGppTable(Ptr channelCondition, - double hBS, - double hUT, - double distance2D) const +ThreeGppChannelModel::GetThreeGppTable(const Ptr aMob, + const Ptr bMob, + Ptr channelCondition) const { NS_LOG_FUNCTION(this); + // NOTE we assume hUT = min (height(a), height(b)) and + // hBS = max (height (a), height (b)) + double hUT = std::min(aMob->GetPosition().z, bMob->GetPosition().z); + double hBS = std::max(aMob->GetPosition().z, bMob->GetPosition().z); + + double distance2D = sqrt(pow(aMob->GetPosition().x - bMob->GetPosition().x, 2) + + pow(aMob->GetPosition().y - bMob->GetPosition().y, 2)); + double fcGHz = m_frequency / 1.0e9; Ptr table3gpp = Create(); // table3gpp includes the following parameters: @@ -1048,6 +2294,649 @@ ThreeGppChannelModel::GetThreeGppTable(Ptr channelCondit NS_FATAL_ERROR("Unknown channel condition"); } } + else if (m_scenario.substr(0, 3) == "NTN") + { + std::string freqBand = (fcGHz < 13) ? "S" : "Ka"; + + double elevAngle = 0; + bool isSatellite = false; // flag to indicate if one of the two nodes is a satellite + // if so, parameters will be set accordingly to NOTE 8 of + // Table 6.7.2 from 3GPP 38.811 V15.4.0 (2020-09) + + Ptr aMobNonConst = ConstCast(aMob); + Ptr bMobNonConst = ConstCast(bMob); + + if (DynamicCast( + ConstCast(aMob)) && // Transform to NS_ASSERT + DynamicCast( + ConstCast(bMob))) // check if aMob and bMob are of type + // GeocentricConstantPositionMobilityModel + { + Ptr aNTNMob = + DynamicCast(aMobNonConst); + Ptr bNTNMob = + DynamicCast(bMobNonConst); + + if (aNTNMob->GetGeographicPosition().z < + bNTNMob->GetGeographicPosition().z) // b is the HAPS/Satellite + { + elevAngle = aNTNMob->GetElevationAngle(bNTNMob); + if (bNTNMob->GetGeographicPosition().z > 50000) + { + isSatellite = true; + } + } + else // a is the HAPS/Satellite + { + elevAngle = bNTNMob->GetElevationAngle(aNTNMob); + if (aNTNMob->GetGeographicPosition().z > 50000) + { + isSatellite = true; + } + } + } + else + { + NS_FATAL_ERROR("Mobility Models needs to be of type Geocentric for NTN scenarios"); + } + + // Round the elevation angle into a two-digits integer between 10 and 90. + int elevAngleQuantized = (elevAngle < 10) ? 10 : round(elevAngle / 10) * 10; + + if (m_scenario == "NTN-DenseUrban") + { + if (channelCondition->IsLos()) + { + table3gpp->m_uLgDS = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgDS]; + table3gpp->m_sigLgDS = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgDS]; + + // table3gpp->m_uLgASD=-1.79769e+308; //FOR SATELLITES + table3gpp->m_uLgASD = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgASD]; + // table3gpp->m_sigLgASD=0; //FOR SATELLITES + table3gpp->m_sigLgASD = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASD]; + + table3gpp->m_uLgASA = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgASA]; + table3gpp->m_sigLgASA = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASA]; + table3gpp->m_uLgZSA = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgZSA]; + table3gpp->m_sigLgZSA = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSA]; + + // table3gpp->m_uLgZSD=-1.79769e+308; //FOR SATELLITES + table3gpp->m_uLgZSD = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgZSD]; + // table3gpp->m_sigLgZSD= 0; //FOR SATELLITES + table3gpp->m_sigLgZSD = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSD]; + + table3gpp->m_uK = + (*m_NTNDenseUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK]; + table3gpp->m_sigK = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigK]; + table3gpp->m_rTau = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::rTau]; + table3gpp->m_uXpr = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uXpr]; + table3gpp->m_sigXpr = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigXpr]; + table3gpp->m_numOfCluster = + (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::numOfCluster]; + table3gpp->m_raysPerCluster = + (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::raysPerCluster]; + table3gpp->m_cDS = + (*m_NTNDenseUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS]; + table3gpp->m_cASD = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::cASD]; + table3gpp->m_cASA = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::cASA]; + table3gpp->m_cZSA = (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::cZSA]; + table3gpp->m_perClusterShadowingStd = + (*m_NTNDenseUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::perClusterShadowingStd]; + + for (uint8_t row = 0; row < 7; row++) + { + for (uint8_t column = 0; column < 7; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_NTN_DenseUrban_LOS[row][column]; + } + } + } + else if (channelCondition->IsNlos()) + { + NS_LOG_UNCOND("Dense Urban NLOS"); + table3gpp->m_uLgDS = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgDS]; + table3gpp->m_sigLgDS = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgDS]; + table3gpp->m_uLgASD = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgASD]; + table3gpp->m_sigLgASD = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASD]; + table3gpp->m_uLgASA = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgASA]; + table3gpp->m_sigLgASA = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASA]; + table3gpp->m_uLgZSA = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgZSA]; + table3gpp->m_sigLgZSA = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSA]; + table3gpp->m_uLgZSD = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgZSD]; + table3gpp->m_sigLgZSD = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSD]; + table3gpp->m_rTau = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::rTau]; + table3gpp->m_uXpr = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uXpr]; + table3gpp->m_sigXpr = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigXpr]; + table3gpp->m_numOfCluster = + (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::numOfCluster]; + table3gpp->m_raysPerCluster = + (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::raysPerCluster]; + table3gpp->m_cDS = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::cDS]; + table3gpp->m_cASD = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::cASD]; + table3gpp->m_cASA = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::cASA]; + table3gpp->m_cZSA = (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::cZSA]; + table3gpp->m_perClusterShadowingStd = + (*m_NTNDenseUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::perClusterShadowingStd]; + + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_NTN_DenseUrban_NLOS[row][column]; + } + } + } + } + else if (m_scenario == "NTN-Urban") + { + if (channelCondition->IsLos()) + { + table3gpp->m_uLgDS = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS]; + table3gpp->m_sigLgDS = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS]; + table3gpp->m_uLgASD = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD]; + table3gpp->m_sigLgASD = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASD]; + table3gpp->m_uLgASA = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA]; + table3gpp->m_sigLgASA = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASA]; + table3gpp->m_uLgZSA = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA]; + table3gpp->m_sigLgZSA = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSA]; + table3gpp->m_uLgZSD = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD]; + table3gpp->m_sigLgZSD = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSD]; + table3gpp->m_uK = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK]; + table3gpp->m_sigK = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK]; + table3gpp->m_rTau = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau]; + table3gpp->m_uXpr = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr]; + table3gpp->m_sigXpr = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr]; + table3gpp->m_numOfCluster = + (*m_NTNUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::numOfCluster]; + table3gpp->m_raysPerCluster = + (*m_NTNUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::raysPerCluster]; + table3gpp->m_cDS = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS]; + table3gpp->m_cASD = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD]; + table3gpp->m_cASA = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA]; + table3gpp->m_cZSA = + (*m_NTNUrbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA]; + table3gpp->m_perClusterShadowingStd = + (*m_NTNUrbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::perClusterShadowingStd]; + + for (uint8_t row = 0; row < 7; row++) + { + for (uint8_t column = 0; column < 7; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_NTN_Urban_LOS[row][column]; + } + } + } + else if (channelCondition->IsNlos()) + { + table3gpp->m_uLgDS = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS]; + table3gpp->m_sigLgDS = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS]; + table3gpp->m_uLgASD = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD]; + table3gpp->m_sigLgASD = (*m_NTNUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASD]; + table3gpp->m_uLgASA = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA]; + table3gpp->m_sigLgASA = (*m_NTNUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASA]; + table3gpp->m_uLgZSA = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA]; + table3gpp->m_sigLgZSA = (*m_NTNUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSA]; + table3gpp->m_uLgZSD = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD]; + table3gpp->m_sigLgZSD = (*m_NTNUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSD]; + table3gpp->m_uK = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK]; + table3gpp->m_sigK = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK]; + table3gpp->m_rTau = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau]; + table3gpp->m_uXpr = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr]; + table3gpp->m_sigXpr = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr]; + table3gpp->m_numOfCluster = + (*m_NTNUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::numOfCluster]; + table3gpp->m_raysPerCluster = + (*m_NTNUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::raysPerCluster]; + table3gpp->m_cDS = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS]; + table3gpp->m_cASD = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD]; + table3gpp->m_cASA = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA]; + table3gpp->m_cZSA = + (*m_NTNUrbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA]; + table3gpp->m_perClusterShadowingStd = + (*m_NTNUrbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::perClusterShadowingStd]; + + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = + sqrtC_NTN_Urban_NLOS.at(elevAngleQuantized)[row][column]; + } + } + } + } + else if (m_scenario == "NTN-Suburban") + { + if (channelCondition->IsLos()) + { + table3gpp->m_uLgDS = + (*m_NTNSuburbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS]; + table3gpp->m_sigLgDS = (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgDS]; + table3gpp->m_uLgASD = (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgASD]; + table3gpp->m_sigLgASD = (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASD]; + table3gpp->m_uLgASA = (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgASA]; + table3gpp->m_sigLgASA = (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASA]; + table3gpp->m_uLgZSA = (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgZSA]; + table3gpp->m_sigLgZSA = (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSA]; + table3gpp->m_uLgZSD = (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgZSD]; + table3gpp->m_sigLgZSD = (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSD]; + table3gpp->m_uK = + (*m_NTNSuburbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK]; + table3gpp->m_sigK = + (*m_NTNSuburbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK]; + table3gpp->m_rTau = + (*m_NTNSuburbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau]; + table3gpp->m_uXpr = + (*m_NTNSuburbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr]; + table3gpp->m_sigXpr = (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigXpr]; + table3gpp->m_numOfCluster = + (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::numOfCluster]; + table3gpp->m_raysPerCluster = + (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::raysPerCluster]; + table3gpp->m_cDS = + (*m_NTNSuburbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS]; + table3gpp->m_cASD = + (*m_NTNSuburbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD]; + table3gpp->m_cASA = + (*m_NTNSuburbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA]; + table3gpp->m_cZSA = + (*m_NTNSuburbanLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA]; + table3gpp->m_perClusterShadowingStd = + (*m_NTNSuburbanLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::perClusterShadowingStd]; + + for (uint8_t row = 0; row < 7; row++) + { + for (uint8_t column = 0; column < 7; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_NTN_Suburban_LOS[row][column]; + } + } + } + else if (channelCondition->IsNlos()) + { + table3gpp->m_uLgDS = (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgDS]; + table3gpp->m_sigLgDS = (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgDS]; + table3gpp->m_uLgASD = (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgASD]; + table3gpp->m_sigLgASD = (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASD]; + table3gpp->m_uLgASA = (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgASA]; + table3gpp->m_sigLgASA = (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASA]; + table3gpp->m_uLgZSA = (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgZSA]; + table3gpp->m_sigLgZSA = (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSA]; + table3gpp->m_uLgZSD = (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::uLgZSD]; + table3gpp->m_sigLgZSD = (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSD]; + table3gpp->m_uK = + (*m_NTNSuburbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK]; + table3gpp->m_sigK = + (*m_NTNSuburbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK]; + table3gpp->m_rTau = + (*m_NTNSuburbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau]; + table3gpp->m_uXpr = + (*m_NTNSuburbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr]; + table3gpp->m_sigXpr = (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigXpr]; + table3gpp->m_numOfCluster = + (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::numOfCluster]; + table3gpp->m_raysPerCluster = + (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::raysPerCluster]; + table3gpp->m_cDS = + (*m_NTNSuburbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS]; + table3gpp->m_cASD = + (*m_NTNSuburbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD]; + table3gpp->m_cASA = + (*m_NTNSuburbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA]; + table3gpp->m_cZSA = + (*m_NTNSuburbanNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA]; + table3gpp->m_perClusterShadowingStd = + (*m_NTNSuburbanNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::perClusterShadowingStd]; + + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_NTN_Suburban_NLOS[row][column]; + } + } + } + } + else if (m_scenario == "NTN-Rural") + { + if (channelCondition->IsLos()) + { + table3gpp->m_uLgDS = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS]; + table3gpp->m_sigLgDS = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS]; + table3gpp->m_uLgASD = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD]; + table3gpp->m_sigLgASD = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASD]; + table3gpp->m_uLgASA = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA]; + table3gpp->m_sigLgASA = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASA]; + table3gpp->m_uLgZSA = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA]; + table3gpp->m_sigLgZSA = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSA]; + table3gpp->m_uLgZSD = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD]; + table3gpp->m_sigLgZSD = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSD]; + table3gpp->m_uK = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK]; + table3gpp->m_sigK = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK]; + table3gpp->m_rTau = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau]; + table3gpp->m_uXpr = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr]; + table3gpp->m_sigXpr = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr]; + table3gpp->m_numOfCluster = + (*m_NTNRuralLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::numOfCluster]; + table3gpp->m_raysPerCluster = + (*m_NTNRuralLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::raysPerCluster]; + table3gpp->m_cDS = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS]; + table3gpp->m_cASD = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD]; + table3gpp->m_cASA = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA]; + table3gpp->m_cZSA = + (*m_NTNRuralLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA]; + table3gpp->m_perClusterShadowingStd = + (*m_NTNRuralLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::perClusterShadowingStd]; + + for (uint8_t row = 0; row < 7; row++) + { + for (uint8_t column = 0; column < 7; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_NTN_Rural_LOS[row][column]; + } + } + } + else if (channelCondition->IsNlos()) + { + table3gpp->m_uLgDS = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS]; + table3gpp->m_sigLgDS = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS]; + table3gpp->m_uLgASD = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD]; + table3gpp->m_sigLgASD = (*m_NTNRuralNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASD]; + table3gpp->m_uLgASA = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA]; + table3gpp->m_sigLgASA = (*m_NTNRuralNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgASA]; + table3gpp->m_uLgZSA = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA]; + table3gpp->m_sigLgZSA = (*m_NTNRuralNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSA]; + table3gpp->m_uLgZSD = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD]; + table3gpp->m_sigLgZSD = (*m_NTNRuralNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::sigLgZSD]; + table3gpp->m_uK = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK]; + table3gpp->m_sigK = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK]; + table3gpp->m_rTau = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau]; + table3gpp->m_uXpr = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr]; + table3gpp->m_sigXpr = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr]; + table3gpp->m_numOfCluster = + (*m_NTNRuralNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::numOfCluster]; + table3gpp->m_raysPerCluster = + (*m_NTNRuralNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::raysPerCluster]; + table3gpp->m_cDS = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS]; + table3gpp->m_cASD = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD]; + table3gpp->m_cASA = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA]; + table3gpp->m_cZSA = + (*m_NTNRuralNLOS).at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA]; + table3gpp->m_perClusterShadowingStd = + (*m_NTNRuralNLOS) + .at(freqBand) + .at(elevAngleQuantized)[Table3gppParams::perClusterShadowingStd]; + + if (freqBand == "S") + { + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = + sqrtC_NTN_Rural_NLOS_S.at(elevAngleQuantized)[row][column]; + } + } + } + else if (freqBand == "Ka") + { + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = + sqrtC_NTN_Rural_NLOS_Ka.at(elevAngleQuantized)[row][column]; + } + } + } + } + } + // Parameters that should be set to -inf are instead set to the minimum + // value of double + if (isSatellite) + { + table3gpp->m_uLgASD = std::numeric_limits::min(); + table3gpp->m_sigLgASD = 0; + table3gpp->m_uLgZSD = std::numeric_limits::min(); + table3gpp->m_sigLgZSD = 0; + } + } else { NS_FATAL_ERROR("unknown scenarios"); @@ -1144,17 +3033,8 @@ ThreeGppChannelModel::GetChannel(Ptr aMob, notFoundParams = true; } - double x = aMob->GetPosition().x - bMob->GetPosition().x; - double y = aMob->GetPosition().y - bMob->GetPosition().y; - double distance2D = sqrt(x * x + y * y); - - // NOTE we assume hUT = min (height(a), height(b)) and - // hBS = max (height (a), height (b)) - double hUt = std::min(aMob->GetPosition().z, bMob->GetPosition().z); - double hBs = std::max(aMob->GetPosition().z, bMob->GetPosition().z); - // get the 3GPP parameters - Ptr table3gpp = GetThreeGppTable(condition, hBs, hUt, distance2D); + Ptr table3gpp = GetThreeGppTable(aMob, bMob, condition); if (notFoundParams || updateParams) { @@ -1410,8 +3290,15 @@ ThreeGppChannelModel::GenerateChannelParameters(const Ptrm_numOfCluster) // Table 7.5-2 { + case 2: + cNlos = 0.501; + break; + case 3: + cNlos = 0.680; + break; case 4: cNlos = 0.779; break; @@ -1457,8 +3344,18 @@ ThreeGppChannelModel::GenerateChannelParameters(const Ptrm_numOfCluster) // Table 7.5-4 { + case 2: + cNlos = 0.430; + break; + case 3: + cNlos = 0.594; + break; + case 4: + cNlos = 0.697; + break; case 8: cNlos = 0.889; break; diff --git a/src/spectrum/model/three-gpp-channel-model.h b/src/spectrum/model/three-gpp-channel-model.h index 33966b2ae..7d9e1ab3c 100644 --- a/src/spectrum/model/three-gpp-channel-model.h +++ b/src/spectrum/model/three-gpp-channel-model.h @@ -24,6 +24,7 @@ #include "matrix-based-channel-model.h" #include "ns3/angles.h" +#include "ns3/deprecated.h" #include #include @@ -250,11 +251,27 @@ class ThreeGppChannelModel : public MatrixBasedChannelModel * \param hUT the height of the UT * \param distance2D the 2D distance between tx and rx * \return the parameters table + * \deprecated Use GetThreeGppTable(const Ptr aMob, const Ptr bMob, Ptr channelCondition) instead */ - virtual Ptr GetThreeGppTable(Ptr channelCondition, - double hBS, - double hUT, - double distance2D) const; + NS_DEPRECATED_3_41("Use GetThreeGppTable(const Ptr, const Ptr, Ptr) instead") + Ptr GetThreeGppTable(Ptr channelCondition, + double hBS, + double hUT, + double distance2D) const; + + /** + * Get the parameters needed to apply the channel generation procedure + * \param aMob the mobility model of node A + * \param bMob the mobility model of node B + * \param channelCondition the channel condition + * \return the parameters table + */ + virtual Ptr GetThreeGppTable( + const Ptr aMob, + const Ptr bMob, + Ptr channelCondition) const; /** * Prepare 3gpp channel parameters among the nodes a and b. @@ -383,6 +400,71 @@ class ThreeGppChannelModel : public MatrixBasedChannelModel 2; //!< index of the THETA value in the m_nonSelfBlocking array static const uint8_t Y_INDEX = 3; //!< index of the Y value in the m_nonSelfBlocking array static const uint8_t R_INDEX = 4; //!< index of the R value in the m_nonSelfBlocking array + + /** + * The nested map containing the 3GPP value tables for the NTN Dense + * Urban LOS scenario. + * The outer key specifies the band (either "S" or "Ka"), while the + * inner key represents the quantized elevation angle. + * The inner vector collects the table3gpp values. + */ + const std::map>>* m_NTNDenseUrbanLOS; + + /** + * The nested map containing the 3GPP value tables for the NTN Dense Urban NLOS scenario. + * The outer key specifies the band (either "S" or "Ka"), while the + * inner key represents the quantized elevation angle. + * The inner vector collects the table3gpp values. + */ + const std::map>>* m_NTNDenseUrbanNLOS; + + /** + * The nested map containing the 3GPP value tables for the NTN Urban LOS scenario. + * The outer key specifies the band (either "S" or "Ka"), while the + * inner key represents the quantized elevation angle. + * The inner vector collects the table3gpp values. + */ + const std::map>>* m_NTNUrbanLOS; + + /** + * The nested map containing the 3GPP value tables for the NTN Urban NLOS scenario. + * The outer key specifies the band (either "S" or "Ka"), while the + * inner key represents the quantized elevation angle. + * The inner vector collects the table3gpp values. + */ + const std::map>>* m_NTNUrbanNLOS; + + /** + * The nested map containing the 3GPP value tables for the NTN Suburban LOS scenario. + * The outer key specifies the band (either "S" or "Ka"), while the + * inner key represents the quantized elevation angle. + * The inner vector collects the table3gpp values. + */ + const std::map>>* m_NTNSuburbanLOS; + + /** + * The nested map containing the 3GPP value tables for the NTN Suburban NLOS scenario. + * The outer key specifies the band (either "S" or "Ka"), while the + * inner key represents the quantized elevation angle. + * The inner vector collects the table3gpp values. + */ + const std::map>>* m_NTNSuburbanNLOS; + + /** + * The nested map containing the 3GPP value tables for the NTN Rural LOS scenario. + * The outer key specifies the band (either "S" or "Ka"), while the + * inner key represents the quantized elevation angle. + * The inner vector collects the table3gpp values. + */ + const std::map>>* m_NTNRuralLOS; + + /** + * The nested map containing the 3GPP value tables for the NTN Rural NLOS scenario + * The outer key specifies the band (either "S" or "Ka"), while the + * inner key represents the quantized elevation angle. + * The inner vector collects the table3gpp values. + */ + const std::map>>* m_NTNRuralNLOS; }; } // namespace ns3