diff --git a/src/antenna/model/phased-array-model.cc b/src/antenna/model/phased-array-model.cc index 95df027a6..f2af5b859 100644 --- a/src/antenna/model/phased-array-model.cc +++ b/src/antenna/model/phased-array-model.cc @@ -36,7 +36,7 @@ NS_OBJECT_ENSURE_REGISTERED(PhasedArrayModel); std::ostream& operator<<(std::ostream& os, const PhasedArrayModel::ComplexVector& cv) { - size_t N = cv.size(); + size_t N = cv.GetSize(); // empty if (N == 0) @@ -84,8 +84,8 @@ void PhasedArrayModel::SetBeamformingVector(const ComplexVector& beamformingVector) { NS_LOG_FUNCTION(this << beamformingVector); - NS_ASSERT_MSG(beamformingVector.size() == GetNumberOfElements(), - beamformingVector.size() << " != " << GetNumberOfElements()); + NS_ASSERT_MSG(beamformingVector.GetSize() == GetNumberOfElements(), + beamformingVector.GetSize() << " != " << GetNumberOfElements()); m_beamformingVector = beamformingVector; m_isBfVectorValid = true; } @@ -106,11 +106,11 @@ PhasedArrayModel::GetBeamformingVector(Angles a) const NS_LOG_FUNCTION(this << a); ComplexVector beamformingVector = GetSteeringVector(a); - double norm = beamformingVector.norm(); + double normRes = norm(beamformingVector); - for (ComplexVectorIndex i = 0; i < GetNumberOfElements(); i++) + for (size_t i = 0; i < GetNumberOfElements(); i++) { - beamformingVector[i] = std::conj(beamformingVector[i]) / norm; + beamformingVector[i] = std::conj(beamformingVector[i]) / normRes; } return beamformingVector; @@ -119,9 +119,8 @@ PhasedArrayModel::GetBeamformingVector(Angles a) const PhasedArrayModel::ComplexVector PhasedArrayModel::GetSteeringVector(Angles a) const { - ComplexVector steeringVector; - steeringVector.resize(GetNumberOfElements()); - for (ComplexVectorIndex i = 0; i < GetNumberOfElements(); i++) + ComplexVector steeringVector(GetNumberOfElements()); + for (size_t i = 0; i < GetNumberOfElements(); i++) { Vector loc = GetElementLocation(i); double phase = -2 * M_PI * diff --git a/src/antenna/model/phased-array-model.h b/src/antenna/model/phased-array-model.h index d1d66629e..d7cba8b81 100644 --- a/src/antenna/model/phased-array-model.h +++ b/src/antenna/model/phased-array-model.h @@ -20,19 +20,11 @@ #include #include +#include #include #include -// Check for Eigen3 support -#ifdef HAVE_EIGEN3 -#include -#endif - -// Enforce specific index type to make sure return types are consistent among Eigen and STL-based -// data structures -#define EIGEN_DEFAULT_DENSE_INDEX_TYPE std::ptrdiff_t - namespace ns3 { @@ -60,89 +52,24 @@ class PhasedArrayModel : public Object */ static TypeId GetTypeId(); - /// Type definition for complex vector indexes - using ComplexVectorIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE; + //!< type definition for complex vectors + using ComplexVector = ComplexMatrixArray; //!< the underlying Valarray -#ifdef HAVE_EIGEN3 - /// Type definition for complex vectors, when the Eigen library is available - using ComplexVector = Eigen::Matrix, Eigen::Dynamic, 1>; - -#else /** - * Type definitions for STL-based complex vectors + * \brief Computes the Frobenius norm of the complex vector + * + * \param complexVector on which to calculate Frobenius norm + * \return the Frobenius norm of the complex vector */ - struct ComplexVector + double norm(ComplexVector& complexVector) const { - /// the underlying STL C++ vector - std::vector> m_vec; - - /** - * Alias for std::vector::operator[] - * - * \param idx the index of the element to be accessed - * \return a reference to the specified matrix element - */ - std::complex& operator[](ComplexVectorIndex idx) + double norm = 0; + for (size_t i = 0; i < complexVector.GetSize(); i++) { - return m_vec[idx]; + norm += std::norm(complexVector[i]); } - - /** - * Read-only alias for std::vector::operator[] - * - * \param idx the index of the element to be accessed - * \return a constant reference to the specified vector element - */ - const std::complex& operator[](ComplexVectorIndex idx) const - { - return m_vec[idx]; - } - - /** - * Alias for std::vector != operator - * - * \param otherVec the other vector to compare with - * \return whether this and otherVec have the same content - */ - const bool operator!=(const ComplexVector& otherVec) const - { - return m_vec != otherVec.m_vec; - } - - /** - * Alias for std::vector::size - * \return the size of this vector - */ - ComplexVectorIndex size() const - { - return static_cast(m_vec.size()); - } - - /** - * Alias for std::vector::resize - * \param size the new size to be set - */ - void resize(PhasedArrayModel::ComplexVectorIndex size) - { - m_vec.resize(size); - } - - /** - * Computes the Frobenius norm of this vector - * \return the Frobenius norm of this vector - */ - double norm() const - { - double norm = 0; - for (const auto& v : m_vec) - { - norm += std::norm(v); - } - - return std::sqrt(norm); - } - }; -#endif + return std::sqrt(norm); + } /** * Returns the horizontal and vertical components of the antenna element field @@ -166,7 +93,7 @@ class PhasedArrayModel : public Object * Returns the number of antenna elements * \return the number of antenna elements */ - virtual ComplexVectorIndex GetNumberOfElements() const = 0; + virtual size_t GetNumberOfElements() const = 0; /** * Sets the beamforming vector to be used diff --git a/src/antenna/model/uniform-planar-array.cc b/src/antenna/model/uniform-planar-array.cc index 68118cb7a..0f5eafa6d 100644 --- a/src/antenna/model/uniform-planar-array.cc +++ b/src/antenna/model/uniform-planar-array.cc @@ -249,10 +249,10 @@ UniformPlanarArray::GetElementLocation(uint64_t index) const return loc; } -PhasedArrayModel::ComplexVectorIndex +size_t UniformPlanarArray::GetNumberOfElements() const { - return static_cast(m_numRows * m_numColumns); + return m_numRows * m_numColumns; } } /* namespace ns3 */ diff --git a/src/antenna/model/uniform-planar-array.h b/src/antenna/model/uniform-planar-array.h index ab07f2f10..70ee3ee0d 100644 --- a/src/antenna/model/uniform-planar-array.h +++ b/src/antenna/model/uniform-planar-array.h @@ -81,7 +81,7 @@ class UniformPlanarArray : public PhasedArrayModel * Returns the number of antenna elements * \return the number of antenna elements */ - ComplexVectorIndex GetNumberOfElements() const override; + size_t GetNumberOfElements() const override; private: /** diff --git a/src/antenna/test/test-uniform-planar-array.cc b/src/antenna/test/test-uniform-planar-array.cc index 4bbf5c358..22601057a 100644 --- a/src/antenna/test/test-uniform-planar-array.cc +++ b/src/antenna/test/test-uniform-planar-array.cc @@ -153,14 +153,16 @@ UniformPlanarArrayTestCase::ComputeGain(Ptr a) { // compute gain PhasedArrayModel::ComplexVector sv = a->GetSteeringVector(m_direction); - NS_TEST_EXPECT_MSG_EQ(sv.size(), a->GetNumberOfElements(), "steering vector of wrong size"); + NS_TEST_EXPECT_MSG_EQ(sv.GetSize(), a->GetNumberOfElements(), "steering vector of wrong size"); PhasedArrayModel::ComplexVector bf = a->GetBeamformingVector(m_direction); - NS_TEST_EXPECT_MSG_EQ(bf.size(), a->GetNumberOfElements(), "beamforming vector of wrong size"); + NS_TEST_EXPECT_MSG_EQ(bf.GetSize(), + a->GetNumberOfElements(), + "beamforming vector of wrong size"); std::pair fp = a->GetElementFieldPattern(m_direction); // scalar product dot (sv, bf) std::complex prod{0}; - for (PhasedArrayModel::ComplexVectorIndex i = 0; i < sv.size(); i++) + for (size_t i = 0; i < sv.GetSize(); i++) { prod += sv[i] * bf[i]; } diff --git a/src/spectrum/examples/three-gpp-channel-example.cc b/src/spectrum/examples/three-gpp-channel-example.cc index 16db88c3b..a9a945c98 100644 --- a/src/spectrum/examples/three-gpp-channel-example.cc +++ b/src/spectrum/examples/three-gpp-channel-example.cc @@ -79,8 +79,6 @@ DoBeamforming(Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice) { - PhasedArrayModel::ComplexVector antennaWeights; - // retrieve the position of the two devices Vector aPos = thisDevice->GetNode()->GetObject()->GetPosition(); Vector bPos = otherDevice->GetNode()->GetObject()->GetPosition(); @@ -93,7 +91,7 @@ DoBeamforming(Ptr thisDevice, // retrieve the number of antenna elements and resize the vector uint64_t totNoArrayElements = thisAntenna->GetNumberOfElements(); - antennaWeights.resize(totNoArrayElements); + PhasedArrayModel::ComplexVector antennaWeights(totNoArrayElements); // the total power is divided equally among the antenna elements double power = 1.0 / sqrt(totNoArrayElements); diff --git a/src/spectrum/model/matrix-based-channel-model.h b/src/spectrum/model/matrix-based-channel-model.h index 3c8ef43df..f90145657 100644 --- a/src/spectrum/model/matrix-based-channel-model.h +++ b/src/spectrum/model/matrix-based-channel-model.h @@ -22,6 +22,7 @@ #define MATRIX_BASED_CHANNEL_H // #include +#include #include #include #include @@ -29,11 +30,6 @@ #include -// Check for Eigen3 support -#ifdef HAVE_EIGEN3 -#include -#endif - namespace ns3 { @@ -63,140 +59,8 @@ class MatrixBasedChannelModel : public Object /// Type definition for 3D matrices of doubles using Double3DVector = std::vector; -#ifdef HAVE_EIGEN3 - /// Type definition for complex matrices, when the Eigen library is available - using Complex2DVector = Eigen::Matrix, Eigen::Dynamic, Eigen::Dynamic>; -#else - /** - * Type definition for complex matrices - */ - struct Complex2DVector - { - /// the STL-based matrix data structure - std::vector>> m_vec; - - /** - * Alias for std::vector::operator[] - * - * \param rowIdx the row index of the element to be accessed - * \param colIdx the column index of the element to be accessed - * - * \return a reference to the specified matrix element - */ - std::complex& operator()(PhasedArrayModel::ComplexVectorIndex rowIdx, - PhasedArrayModel::ComplexVectorIndex colIdx) - { - NS_ASSERT(rows() > rowIdx && cols() > colIdx && rowIdx >= 0 && colIdx >= 0); - return m_vec[rowIdx][colIdx]; - } - - /** - * Read-only alias for const complex matrices for std::vector::operator[] - * - * \param rowIdx the row index of the element to be accessed - * \param colIdx the column index of the element to be accessed - * - * \return a constant reference to the specified matrix element - */ - const std::complex& operator()(PhasedArrayModel::ComplexVectorIndex rowIdx, - PhasedArrayModel::ComplexVectorIndex colIdx) const - { - NS_ASSERT(rows() > rowIdx && cols() > colIdx && rowIdx >= 0 && colIdx >= 0); - return m_vec[rowIdx][colIdx]; - } - - /** - * Alias for std::vector::resize taking both matrix dimensions as arguments - * - * \param numRows the number of rows to be set - * \param numCols the number of columns to be set - */ - void resize(PhasedArrayModel::ComplexVectorIndex numRows, - PhasedArrayModel::ComplexVectorIndex numCols) - { - m_vec.resize(numRows); - for (PhasedArrayModel::ComplexVectorIndex rowIdx = 0; rowIdx < numRows; rowIdx++) - { - m_vec[rowIdx].resize(numCols); - } - } - - /** - * Alias for std::vector::size returning the size of the outermost vector - * - * \return the number of rows of the matrix - */ - PhasedArrayModel::ComplexVectorIndex rows() const - { - return static_cast(m_vec.size()); - } - - /** - * Alias for std::vector::size returning the size of the innermost vector - * - * \return the number of columns of the matrix - */ - PhasedArrayModel::ComplexVectorIndex cols() const - { - return static_cast(m_vec.at(0).size()); - } - }; -#endif - - /// Type definition for 3D complex matrices - using Complex3DVector = std::vector; - -#ifdef HAVE_EIGEN3 - /** - * Compute a product of the form a^T * B * c leveraging Eigen, - * where a and c are column vectors and B is a matrix. - * - * \param leftVec the vector a which left-multiplies B - * \param rightVec the vector c which right-multiplies B - * \param mat the matrix B - * - * \return the product a * B * c - */ - static std::complex MultiplyMatByLeftAndRightVec( - const PhasedArrayModel::ComplexVector& leftVec, - const PhasedArrayModel::ComplexVector& rightVec, - const Complex2DVector& mat) - { - return leftVec.transpose() * mat * rightVec; - } - -#else - /** - * Compute a product of the form a^T * B * c, where a and c are column - * vectors and B is a matrix, by manually iterating over the elements. - * - * \param leftVec the vector a which left-multiplies B - * \param rightVec the vector c which right-multiplies B - * \param mat the matrix B - * - * \return the product a^T * B * c - */ - static std::complex MultiplyMatByLeftAndRightVec( - const PhasedArrayModel::ComplexVector& leftVec, - const PhasedArrayModel::ComplexVector& rightVec, - const Complex2DVector& mat) - { - std::complex product(0, 0); - for (PhasedArrayModel::ComplexVectorIndex rightIndex = 0; rightIndex < rightVec.size(); - rightIndex++) - { - std::complex rxSum(0, 0); - for (PhasedArrayModel::ComplexVectorIndex leftIndex = 0; leftIndex < leftVec.size(); - leftIndex++) - { - rxSum += leftVec[leftIndex] * mat(leftIndex, rightIndex); - } - product = product + rightVec[rightIndex] * rxSum; - } - - return product; - } -#endif + using Complex2DVector = ComplexMatrixArray; //!< Create an alias for 2D complex vectors + using Complex3DVector = ComplexMatrixArray; //!< Create an alias for 3D complex vectors /** * Data structure that stores a channel realization diff --git a/src/spectrum/model/three-gpp-channel-model.cc b/src/spectrum/model/three-gpp-channel-model.cc index 7e03646c3..72954bf93 100644 --- a/src/spectrum/model/three-gpp-channel-model.cc +++ b/src/spectrum/model/three-gpp-channel-model.cc @@ -1875,24 +1875,18 @@ ThreeGppChannelModel::GetNewChannel(Ptr channelPara // Step 11: Generate channel coefficients for each cluster n and each receiver // and transmitter element pair u,s. - Complex3DVector hNus; // channel coefficient hUsn[n][u][s]; // where n is cluster index, u and s are receive and transmit antenna element. - PhasedArrayModel::ComplexVectorIndex uSize = uAntenna->GetNumberOfElements(); - PhasedArrayModel::ComplexVectorIndex sSize = sAntenna->GetNumberOfElements(); + size_t uSize = uAntenna->GetNumberOfElements(); + size_t sSize = sAntenna->GetNumberOfElements(); // NOTE: Since each of the strongest 2 clusters are divided into 3 sub-clusters, // the total cluster will generally be numReducedCLuster + 4. // However, it might be that m_cluster1st = m_cluster2nd. In this case the // total number of clusters will be numReducedCLuster + 2. - uint64_t numOverallCluster = (channelParams->m_cluster1st != channelParams->m_cluster2nd) + uint16_t numOverallCluster = (channelParams->m_cluster1st != channelParams->m_cluster2nd) ? channelParams->m_reducedClusterNumber + 4 : channelParams->m_reducedClusterNumber + 2; - hNus.resize(numOverallCluster); - for (uint64_t cIndex = 0; cIndex < numOverallCluster; cIndex++) - { - hNus[cIndex].resize(uSize, sSize); - } - + Complex3DVector hUsn(uSize, sSize, numOverallCluster); // channel coefficient hUsn (u, s, n); NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPhase.size()); NS_ASSERT(channelParams->m_reducedClusterNumber <= channelParams->m_clusterPower.size()); NS_ASSERT(channelParams->m_reducedClusterNumber <= @@ -1922,17 +1916,17 @@ ThreeGppChannelModel::GetNewChannel(Ptr channelPara Angles sAngle(uMob->GetPosition(), sMob->GetPosition()); Angles uAngle(sMob->GetPosition(), uMob->GetPosition()); - Complex2DVector raysPreComp; // stores part of the ray expression, cached as independent from - // the u- and s-indexes - Double2DVector sinCosA; // cached multiplications of sin and cos of the ZoA and AoA angles - Double2DVector sinSinA; // cached multiplications of sines of the ZoA and AoA angles - Double2DVector cosZoA; // cached cos of the ZoA angle - Double2DVector sinCosD; // cached multiplications of sin and cos of the ZoD and AoD angles - Double2DVector sinSinD; // cached multiplications of the cosines of the ZoA and AoA angles - Double2DVector cosZoD; // cached cos of the ZoD angle + Complex2DVector raysPreComp(channelParams->m_reducedClusterNumber, + table3gpp->m_raysPerCluster); // stores part of the ray expression, + // cached as independent from the u- and s-indexes + Double2DVector sinCosA; // cached multiplications of sin and cos of the ZoA and AoA angles + Double2DVector sinSinA; // cached multiplications of sines of the ZoA and AoA angles + Double2DVector cosZoA; // cached cos of the ZoA angle + Double2DVector sinCosD; // cached multiplications of sin and cos of the ZoD and AoD angles + Double2DVector sinSinD; // cached multiplications of the cosines of the ZoA and AoA angles + Double2DVector cosZoD; // cached cos of the ZoD angle // resize to appropriate dimensions - raysPreComp.resize(channelParams->m_reducedClusterNumber, table3gpp->m_raysPerCluster); sinCosA.resize(channelParams->m_reducedClusterNumber); sinSinA.resize(channelParams->m_reducedClusterNumber); cosZoA.resize(channelParams->m_reducedClusterNumber); @@ -2000,11 +1994,11 @@ ThreeGppChannelModel::GetNewChannel(Ptr channelPara uint8_t numSubClustersAdded = 0; for (uint8_t nIndex = 0; nIndex < channelParams->m_reducedClusterNumber; nIndex++) { - for (PhasedArrayModel::ComplexVectorIndex uIndex = 0; uIndex < uSize; uIndex++) + for (size_t uIndex = 0; uIndex < uSize; uIndex++) { Vector uLoc = uAntenna->GetElementLocation(uIndex); - for (PhasedArrayModel::ComplexVectorIndex sIndex = 0; sIndex < sSize; sIndex++) + for (size_t sIndex = 0; sIndex < sSize; sIndex++) { Vector sLoc = sAntenna->GetElementLocation(sIndex); // Compute the N-2 weakest cluster, assuming 0 slant angle and a @@ -2033,7 +2027,7 @@ ThreeGppChannelModel::GetNewChannel(Ptr channelPara } rays *= sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster); - hNus[nIndex](uIndex, sIndex) = rays; + hUsn(uIndex, sIndex, nIndex) = rays; } else //(7.5-28) { @@ -2087,12 +2081,13 @@ ThreeGppChannelModel::GetNewChannel(Ptr channelPara sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster); raysSub3 *= sqrt(channelParams->m_clusterPower[nIndex] / table3gpp->m_raysPerCluster); - hNus[nIndex](uIndex, sIndex) = raysSub1; - hNus[channelParams->m_reducedClusterNumber + numSubClustersAdded](uIndex, - sIndex) = - raysSub2; - hNus[channelParams->m_reducedClusterNumber + numSubClustersAdded + 1](uIndex, - sIndex) = + hUsn(uIndex, sIndex, nIndex) = raysSub1; + hUsn(uIndex, + sIndex, + channelParams->m_reducedClusterNumber + numSubClustersAdded) = raysSub2; + hUsn(uIndex, + sIndex, + channelParams->m_reducedClusterNumber + numSubClustersAdded + 1) = raysSub3; } } @@ -2118,14 +2113,14 @@ ThreeGppChannelModel::GetNewChannel(Ptr channelPara const double sinSAngleAz = sin(sAngle.GetAzimuth()); const double cosSAngleAz = cos(sAngle.GetAzimuth()); - for (PhasedArrayModel::ComplexVectorIndex uIndex = 0; uIndex < uSize; uIndex++) + for (size_t uIndex = 0; uIndex < uSize; uIndex++) { Vector uLoc = uAntenna->GetElementLocation(uIndex); double rxPhaseDiff = 2 * M_PI * (sinUAngleIncl * cosUAngleAz * uLoc.x + sinUAngleIncl * sinUAngleAz * uLoc.y + cosUAngleIncl * uLoc.z); - for (PhasedArrayModel::ComplexVectorIndex sIndex = 0; sIndex < sSize; sIndex++) + for (size_t sIndex = 0; sIndex < sSize; sIndex++) { Vector sLoc = sAntenna->GetElementLocation(sIndex); std::complex ray(0, 0); @@ -2147,14 +2142,14 @@ ThreeGppChannelModel::GetNewChannel(Ptr channelPara double kLinear = pow(10, channelParams->m_K_factor / 10.0); // the LOS path should be attenuated if blockage is enabled. - hNus[0](uIndex, sIndex) = - sqrt(1.0 / (kLinear + 1)) * hNus[0](uIndex, sIndex) + + hUsn(uIndex, sIndex, 0) = + sqrt(1.0 / (kLinear + 1)) * hUsn(uIndex, sIndex, 0) + sqrt(kLinear / (1 + kLinear)) * ray / pow(10, channelParams->m_attenuation_dB[0] / 10.0); //(7.5-30) for tau = tau1 - for (std::size_t nIndex = 1; nIndex < hNus.size(); nIndex++) + for (uint16_t nIndex = 1; nIndex < hUsn.GetNumPages(); nIndex++) { - hNus[nIndex](uIndex, sIndex) *= + hUsn(uIndex, sIndex, nIndex) *= sqrt(1.0 / (kLinear + 1)); //(7.5-30) for tau = tau2...tauN } } @@ -2162,21 +2157,21 @@ ThreeGppChannelModel::GetNewChannel(Ptr channelPara } NS_LOG_DEBUG("Husn (sAntenna, uAntenna):" << sAntenna->GetId() << ", " << uAntenna->GetId()); - for (std::size_t cIndex = 0; cIndex < hNus.size(); cIndex++) + for (uint16_t cIndex = 0; cIndex < hUsn.GetNumPages(); cIndex++) { - for (PhasedArrayModel::ComplexVectorIndex rowIdx = 0; rowIdx < hNus[cIndex].rows(); - rowIdx++) + for (uint16_t rowIdx = 0; rowIdx < hUsn.GetNumRows(); rowIdx++) { - for (PhasedArrayModel::ComplexVectorIndex colIdx = 0; colIdx < hNus[cIndex].cols(); - colIdx++) + for (uint16_t colIdx = 0; colIdx < hUsn.GetNumCols(); colIdx++) { - NS_LOG_DEBUG(" " << hNus[cIndex](rowIdx, colIdx) << ","); + NS_LOG_DEBUG(" " << hUsn(rowIdx, colIdx, cIndex) << ","); } } } - NS_LOG_INFO("size of coefficient matrix =[" << hNus.size() << "][" << hNus[0].rows() << "][" - << hNus[0].cols() << "]"); - channelMatrix->m_channel = hNus; + + NS_LOG_INFO("size of coefficient matrix (rows, columns, clusters) = (" + << hUsn.GetNumRows() << ", " << hUsn.GetNumCols() << ", " << hUsn.GetNumPages() + << ")"); + channelMatrix->m_channel = hUsn; return channelMatrix; } diff --git a/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc b/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc index c1a93f060..e428761de 100644 --- a/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc +++ b/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc @@ -119,29 +119,19 @@ ThreeGppSpectrumPropagationLossModel::CalcLongTerm( { NS_LOG_FUNCTION(this); - uint16_t sAntenna = static_cast(sW.size()); - uint16_t uAntenna = static_cast(uW.size()); + size_t uAntennaNum = uW.GetSize(); + size_t sAntennaNum = sW.GetSize(); - NS_ASSERT(uAntenna == params->m_channel.at(0).rows()); - NS_ASSERT(sAntenna == params->m_channel.at(0).cols()); + NS_ASSERT(uAntennaNum == params->m_channel.GetNumRows()); + NS_ASSERT(sAntennaNum == params->m_channel.GetNumCols()); - NS_LOG_DEBUG("CalcLongTerm with sAntenna " << sAntenna << " uAntenna " << uAntenna); + NS_LOG_DEBUG("CalcLongTerm with " << uAntennaNum << " u antenna elements and " << sAntennaNum + << " s antenna elements."); // store the long term part to reduce computation load // only the small scale fading needs to be updated if the large scale parameters and antenna - // weights remain unchanged. - PhasedArrayModel::ComplexVector longTerm; - uint8_t numCluster = static_cast(params->m_channel.size()); - longTerm.resize(numCluster); - - for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++) - { - auto txSum = - MatrixBasedChannelModel::MultiplyMatByLeftAndRightVec(uW, - sW, - params->m_channel[cIndex]); - longTerm[cIndex] = txSum; - } - return longTerm; + // weights remain unchanged. here we calculate long term uW * Husn * sW, the result is an array + // of values per cluster + return params->m_channel.MultiplyByLeftAndRightMatrix(uW.Transpose(), sW); } Ptr @@ -158,15 +148,14 @@ ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain( Ptr tempPsd = Copy(txPsd); // channel[cluster][rx][tx] - uint8_t numCluster = static_cast(channelMatrix->m_channel.size()); + uint16_t numCluster = channelMatrix->m_channel.GetNumPages(); // compute the doppler term // NOTE the update of Doppler is simplified by only taking the center angle of // each cluster in to consideration. double slotTime = Simulator::Now().GetSeconds(); double factor = 2 * M_PI * slotTime * GetFrequency() / 3e8; - PhasedArrayModel::ComplexVector doppler; - doppler.resize(numCluster); + PhasedArrayModel::ComplexVector doppler(numCluster); // The following asserts might seem paranoic, but it is important to // make sure that all the structures that are passed to this function @@ -179,7 +168,7 @@ ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain( NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX].size()); NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX].size()); NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX].size()); - NS_ASSERT(numCluster <= longTerm.size()); + NS_ASSERT(numCluster <= longTerm.GetSize()); // check if channelParams structure is generated in direction s-to-u or u-to-s bool isSameDirection = (channelParams->m_nodeIds == channelMatrix->m_nodeIds); @@ -208,7 +197,7 @@ ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain( aoa = channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX]; } - for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++) + for (uint16_t cIndex = 0; cIndex < numCluster; cIndex++) { // Compute alpha and D as described in 3GPP TR 37.885 v15.3.0, Sec. 6.2.3 // These terms account for an additional Doppler contribution due to the @@ -236,7 +225,7 @@ ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain( doppler[cIndex] = std::complex(cos(tempDoppler), sin(tempDoppler)); } - NS_ASSERT(numCluster <= doppler.size()); + NS_ASSERT(numCluster <= doppler.GetSize()); // apply the doppler term and the propagation delay to the long term component // to obtain the beamforming gain @@ -248,7 +237,7 @@ ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain( { std::complex subsbandGain(0.0, 0.0); double fsb = (*sbit).fc; // center frequency of the sub-band - for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++) + for (uint16_t cIndex = 0; cIndex < numCluster; cIndex++) { double delay = -2 * M_PI * fsb * (channelParams->m_delay[cIndex]); subsbandGain = subsbandGain + longTerm[cIndex] * doppler[cIndex] * diff --git a/src/spectrum/model/two-ray-spectrum-propagation-loss-model.cc b/src/spectrum/model/two-ray-spectrum-propagation-loss-model.cc index ec04bb228..c358a171d 100644 --- a/src/spectrum/model/two-ray-spectrum-propagation-loss-model.cc +++ b/src/spectrum/model/two-ray-spectrum-propagation-loss-model.cc @@ -1052,13 +1052,11 @@ TwoRaySpectrumPropagationLossModel::CalcBeamformingGain( std::complex bArrayOverallResponse = 0; // Compute the dot products between the array responses and the beamforming vectors - for (PhasedArrayModel::ComplexVectorIndex i = 0; i < aPhasedArrayModel->GetNumberOfElements(); - i++) + for (size_t i = 0; i < aPhasedArrayModel->GetNumberOfElements(); i++) { aArrayOverallResponse += aArrayResponse[i] * aBfVector[i]; } - for (PhasedArrayModel::ComplexVectorIndex i = 0; i < bPhasedArrayModel->GetNumberOfElements(); - i++) + for (size_t i = 0; i < bPhasedArrayModel->GetNumberOfElements(); i++) { bArrayOverallResponse += bArrayResponse[i] * bBfVector[i]; } diff --git a/src/spectrum/test/three-gpp-channel-test-suite.cc b/src/spectrum/test/three-gpp-channel-test-suite.cc index e067e60f2..e49a4f8f6 100644 --- a/src/spectrum/test/three-gpp-channel-test-suite.cc +++ b/src/spectrum/test/three-gpp-channel-test-suite.cc @@ -106,8 +106,8 @@ ThreeGppChannelMatrixComputationTest::DoComputeNorm(Ptr ch channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna); double channelNorm = 0; - std::size_t numTotalClusters = channelMatrix->m_channel.size(); - for (std::size_t cIndex = 0; cIndex < numTotalClusters; cIndex++) + uint16_t numTotalClusters = channelMatrix->m_channel.GetNumPages(); + for (uint16_t cIndex = 0; cIndex < numTotalClusters; cIndex++) { double clusterNorm = 0; for (uint64_t sIndex = 0; sIndex < txAntennaElements; sIndex++) @@ -115,7 +115,7 @@ ThreeGppChannelMatrixComputationTest::DoComputeNorm(Ptr ch for (uint64_t uIndex = 0; uIndex < rxAntennaElements; uIndex++) { clusterNorm += - std::pow(std::abs(channelMatrix->m_channel.at(cIndex)(uIndex, sIndex)), 2); + std::pow(std::abs(channelMatrix->m_channel(uIndex, sIndex, cIndex)), 2); } } channelNorm += clusterNorm; @@ -188,11 +188,11 @@ ThreeGppChannelMatrixComputationTest::DoRun() // check the channel matrix dimensions, expected H[cluster][rx][tx] NS_TEST_ASSERT_MSG_EQ( - channelMatrix->m_channel.at(0).cols(), + channelMatrix->m_channel.GetNumCols(), txAntennaElements[0] * txAntennaElements[1], "The third dimension of H should be equal to the number of tx antenna elements"); NS_TEST_ASSERT_MSG_EQ( - channelMatrix->m_channel.at(0).rows(), + channelMatrix->m_channel.GetNumRows(), rxAntennaElements[0] * rxAntennaElements[1], "The second dimension of H should be equal to the number of rx antenna elements");