spectrum, antenna: Change definitions of 1D, 2D, 3D complex vectors
spectrum, antenna: Remove unnecessary Eigen includes fix clang-tidy issues in three-gpp-spectrum-propagation-loss-model
This commit is contained in:
@@ -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 *
|
||||
|
||||
@@ -20,19 +20,11 @@
|
||||
|
||||
#include <ns3/angles.h>
|
||||
#include <ns3/antenna-model.h>
|
||||
#include <ns3/matrix-array.h>
|
||||
#include <ns3/object.h>
|
||||
|
||||
#include <complex>
|
||||
|
||||
// Check for Eigen3 support
|
||||
#ifdef HAVE_EIGEN3
|
||||
#include <Eigen/Dense>
|
||||
#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<std::complex<double>, 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<std::complex<double>> m_vec;
|
||||
|
||||
/**
|
||||
* Alias for std::vector<T,Allocator>::operator[]
|
||||
*
|
||||
* \param idx the index of the element to be accessed
|
||||
* \return a reference to the specified matrix element
|
||||
*/
|
||||
std::complex<double>& 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<T,Allocator>::operator[]
|
||||
*
|
||||
* \param idx the index of the element to be accessed
|
||||
* \return a constant reference to the specified vector element
|
||||
*/
|
||||
const std::complex<double>& 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<ComplexVectorIndex>(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
|
||||
|
||||
@@ -249,10 +249,10 @@ UniformPlanarArray::GetElementLocation(uint64_t index) const
|
||||
return loc;
|
||||
}
|
||||
|
||||
PhasedArrayModel::ComplexVectorIndex
|
||||
size_t
|
||||
UniformPlanarArray::GetNumberOfElements() const
|
||||
{
|
||||
return static_cast<PhasedArrayModel::ComplexVectorIndex>(m_numRows * m_numColumns);
|
||||
return m_numRows * m_numColumns;
|
||||
}
|
||||
|
||||
} /* namespace ns3 */
|
||||
|
||||
@@ -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:
|
||||
/**
|
||||
|
||||
@@ -153,14 +153,16 @@ UniformPlanarArrayTestCase::ComputeGain(Ptr<UniformPlanarArray> 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<double, double> fp = a->GetElementFieldPattern(m_direction);
|
||||
|
||||
// scalar product dot (sv, bf)
|
||||
std::complex<double> 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];
|
||||
}
|
||||
|
||||
@@ -79,8 +79,6 @@ DoBeamforming(Ptr<NetDevice> thisDevice,
|
||||
Ptr<PhasedArrayModel> thisAntenna,
|
||||
Ptr<NetDevice> otherDevice)
|
||||
{
|
||||
PhasedArrayModel::ComplexVector antennaWeights;
|
||||
|
||||
// retrieve the position of the two devices
|
||||
Vector aPos = thisDevice->GetNode()->GetObject<MobilityModel>()->GetPosition();
|
||||
Vector bPos = otherDevice->GetNode()->GetObject<MobilityModel>()->GetPosition();
|
||||
@@ -93,7 +91,7 @@ DoBeamforming(Ptr<NetDevice> 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);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#define MATRIX_BASED_CHANNEL_H
|
||||
|
||||
// #include <complex>
|
||||
#include <ns3/matrix-array.h>
|
||||
#include <ns3/nstime.h>
|
||||
#include <ns3/object.h>
|
||||
#include <ns3/phased-array-model.h>
|
||||
@@ -29,11 +30,6 @@
|
||||
|
||||
#include <tuple>
|
||||
|
||||
// Check for Eigen3 support
|
||||
#ifdef HAVE_EIGEN3
|
||||
#include <Eigen/Dense>
|
||||
#endif
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
@@ -63,140 +59,8 @@ class MatrixBasedChannelModel : public Object
|
||||
/// Type definition for 3D matrices of doubles
|
||||
using Double3DVector = std::vector<Double2DVector>;
|
||||
|
||||
#ifdef HAVE_EIGEN3
|
||||
/// Type definition for complex matrices, when the Eigen library is available
|
||||
using Complex2DVector = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic>;
|
||||
#else
|
||||
/**
|
||||
* Type definition for complex matrices
|
||||
*/
|
||||
struct Complex2DVector
|
||||
{
|
||||
/// the STL-based matrix data structure
|
||||
std::vector<std::vector<std::complex<double>>> m_vec;
|
||||
|
||||
/**
|
||||
* Alias for std::vector<T,Allocator>::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<double>& 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<T,Allocator>::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<double>& 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<PhasedArrayModel::ComplexVectorIndex>(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<PhasedArrayModel::ComplexVectorIndex>(m_vec.at(0).size());
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
/// Type definition for 3D complex matrices
|
||||
using Complex3DVector = std::vector<Complex2DVector>;
|
||||
|
||||
#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<double> 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<double> MultiplyMatByLeftAndRightVec(
|
||||
const PhasedArrayModel::ComplexVector& leftVec,
|
||||
const PhasedArrayModel::ComplexVector& rightVec,
|
||||
const Complex2DVector& mat)
|
||||
{
|
||||
std::complex<double> product(0, 0);
|
||||
for (PhasedArrayModel::ComplexVectorIndex rightIndex = 0; rightIndex < rightVec.size();
|
||||
rightIndex++)
|
||||
{
|
||||
std::complex<double> 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
|
||||
|
||||
@@ -1875,24 +1875,18 @@ ThreeGppChannelModel::GetNewChannel(Ptr<const ThreeGppChannelParams> 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<const ThreeGppChannelParams> 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<const ThreeGppChannelParams> 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<const ThreeGppChannelParams> 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<const ThreeGppChannelParams> 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<const ThreeGppChannelParams> 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<double> ray(0, 0);
|
||||
@@ -2147,14 +2142,14 @@ ThreeGppChannelModel::GetNewChannel(Ptr<const ThreeGppChannelParams> 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<const ThreeGppChannelParams> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,29 +119,19 @@ ThreeGppSpectrumPropagationLossModel::CalcLongTerm(
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
uint16_t sAntenna = static_cast<uint16_t>(sW.size());
|
||||
uint16_t uAntenna = static_cast<uint16_t>(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<uint8_t>(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<SpectrumValue>
|
||||
@@ -158,15 +148,14 @@ ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain(
|
||||
Ptr<SpectrumValue> tempPsd = Copy<SpectrumValue>(txPsd);
|
||||
|
||||
// channel[cluster][rx][tx]
|
||||
uint8_t numCluster = static_cast<uint8_t>(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<double>(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<double> 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] *
|
||||
|
||||
@@ -1052,13 +1052,11 @@ TwoRaySpectrumPropagationLossModel::CalcBeamformingGain(
|
||||
std::complex<double> 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];
|
||||
}
|
||||
|
||||
@@ -106,8 +106,8 @@ ThreeGppChannelMatrixComputationTest::DoComputeNorm(Ptr<ThreeGppChannelModel> 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<ThreeGppChannelModel> 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");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user