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:
Biljana Bojovic
2023-02-01 22:45:00 +01:00
parent b7c3ba83fb
commit 7495938a2d
11 changed files with 94 additions and 322 deletions

View File

@@ -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 *

View File

@@ -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

View File

@@ -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 */

View File

@@ -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:
/**

View File

@@ -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];
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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] *

View File

@@ -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];
}

View File

@@ -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");