16#include "ns3/double.h"
19#include "ns3/pointer.h"
20#include "ns3/simulator.h"
21#include "ns3/string.h"
51 TypeId(
"ns3::ThreeGppSpectrumPropagationLossModel")
53 .SetGroupName(
"Spectrum")
57 "The channel model. It needs to implement the MatrixBasedChannelModel interface",
110 NS_ASSERT_MSG(sAnt !=
nullptr && uAnt !=
nullptr,
"Improper call to the method");
113 const size_t sAntNumElems = sW.
GetSize();
114 const size_t uAntNumElems = uW.
GetSize();
115 NS_ASSERT(uAntNumElems == channelMatrix->m_channel.GetNumRows());
116 NS_ASSERT(sAntNumElems == channelMatrix->m_channel.GetNumCols());
118 <<
" s antenna elements, and with "
119 <<
" s ports: " << sAnt->GetNumPorts()
120 <<
" u ports: " << uAnt->GetNumPorts());
121 size_t numClusters = channelMatrix->m_channel.GetNumPages();
129 for (
auto sPortIdx = 0; sPortIdx < sAnt->GetNumPorts(); sPortIdx++)
131 for (
auto uPortIdx = 0; uPortIdx < uAnt->GetNumPorts(); uPortIdx++)
133 for (
size_t cIndex = 0; cIndex < numClusters; cIndex++)
135 longTerm->Elem(uPortIdx, sPortIdx, cIndex) =
153 const uint16_t sPortIdx,
154 const uint16_t uPortIdx,
155 const uint16_t cIndex)
const
160 const auto sPortElems = sAnt->GetNumElemsPerPort();
161 const auto uPortElems = uAnt->GetNumElemsPerPort();
162 const auto startS = sAnt->ArrayIndexFromPortIndex(sPortIdx, 0);
163 const auto startU = uAnt->ArrayIndexFromPortIndex(uPortIdx, 0);
164 std::complex<double> txSum(0, 0);
166 auto sIndex = startS;
171 const auto uElemsPerPort = uAnt->GetHElemsPerPort();
172 const auto sElemsPerPort = sAnt->GetHElemsPerPort();
173 for (
size_t tIndex = 0; tIndex < sPortElems; tIndex++, sIndex++)
175 std::complex<double> rxSum(0, 0);
176 auto uIndex = startU;
177 for (
size_t rIndex = 0; rIndex < uPortElems; rIndex++, uIndex++)
179 rxSum += uW[uIndex - startU] * params->m_channel(uIndex, sIndex, cIndex);
180 const auto testV = rIndex % uElemsPerPort;
181 if (
const auto ptInc = uElemsPerPort - 1; testV == ptInc)
183 const auto incVal = uAnt->GetNumColumns() - uElemsPerPort;
188 txSum += sW[sIndex - startS] * rxSum;
189 const auto testV = tIndex % sElemsPerPort;
190 if (
const auto ptInc = sElemsPerPort - 1; testV == ptInc)
192 const size_t incVal = sAnt->GetNumColumns() - sElemsPerPort;
205 const Vector& sSpeed,
206 const Vector& uSpeed,
207 const uint8_t numTxPorts,
208 const uint8_t numRxPorts,
209 const bool isReverse)
const
214 const size_t numCluster = channelMatrix->m_channel.GetNumPages();
219 const double factor = 2 * M_PI * slotTime *
GetFrequency() / 3e8;
224 NS_ASSERT(numCluster <= channelParams->m_alpha.size());
225 NS_ASSERT(numCluster <= channelParams->m_D.size());
230 NS_ASSERT(numCluster <= longTerm->GetNumPages());
233 const bool isSameDir = channelParams->m_nodeIds == channelMatrix->m_nodeIds;
239 using DPV = std::vector<std::pair<double, double>>;
240 const auto& cachedAngleSincos = channelParams->m_cachedAngleSincos;
242 "Cached angle sin/cos not initialized");
256 for (
size_t cIndex = 0; cIndex < numCluster; cIndex++)
269 const double alpha = channelParams->m_alpha[cIndex];
270 const double D = channelParams->m_D[cIndex];
273 const double tempDoppler =
275 (zoa[cIndex].first * aoa[cIndex].second * uSpeed.x +
276 zoa[cIndex].first * aoa[cIndex].first * uSpeed.y + zoa[cIndex].second * uSpeed.z +
277 (zod[cIndex].first * aod[cIndex].second * sSpeed.x +
278 zod[cIndex].first * aod[cIndex].first * sSpeed.y + zod[cIndex].second * sSpeed.z) +
280 doppler[cIndex] = std::complex(cos(tempDoppler), sin(tempDoppler));
295 NS_ASSERT_MSG(rxParams->psd->GetValuesN() == rxParams->spectrumChannelMatrix->GetNumPages(),
296 "RX PSD and the spectrum channel matrix should have the same number of RBs ");
301 if (!rxParams->precodingMatrix)
306 page.Elem(0, 0, 0) = 1.0 / sqrt(rxParams->spectrumChannelMatrix->GetNumCols());
307 for (
size_t rowI = 0; rowI < rxParams->spectrumChannelMatrix->GetNumCols(); rowI++)
309 page.Elem(rowI, 0, 0) = page.Elem(0, 0, 0);
313 page.MakeNCopies(rxParams->spectrumChannelMatrix->GetNumPages()));
317 p = rxParams->precodingMatrix;
331 for (
uint32_t rbIdx = 0; rbIdx < rxParams->psd->GetValuesN(); ++rbIdx)
333 (*rxParams->psd)[rbIdx] = 0.0;
334 for (
size_t rxPort = 0; rxPort < hP.
GetNumRows(); ++rxPort)
336 for (
size_t txStream = 0; txStream < hP.
GetNumCols(); ++txStream)
338 (*rxParams->psd)[rbIdx] +=
339 std::real(std::conj(hP(rxPort, txStream, rbIdx)) * hP(rxPort, txStream, rbIdx));
355 const bool isReverse)
357 const size_t numCluster = channelMatrix->m_channel.GetNumPages();
358 const auto numRb = inPsd->GetValuesN();
360 "Channel params delays size is smaller than number of clusters");
362 auto directionalLongTerm = isReverse ? longTerm->Transpose() : *longTerm;
367 static_cast<uint16_t
>(numRb));
373 if (
const double rbWidth = inPsd->ConstBandsBegin()->fh - inPsd->ConstBandsBegin()->fl;
374 channelParams->m_cachedDelaySincos.GetNumRows() != numRb ||
375 channelParams->m_cachedDelaySincos.GetNumCols() != numCluster ||
376 channelParams->m_cachedRbWidth != rbWidth)
378 channelParams->m_cachedRbWidth = rbWidth;
380 auto sbit = inPsd->ConstBandsBegin();
381 for (
unsigned i = 0; i < numRb; i++)
383 const double fsb = sbit->fc;
384 for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
386 const double delay = -2 * M_PI * fsb * channelParams->m_delay[cIndex];
387 channelParams->m_cachedDelaySincos(i, cIndex) =
388 std::complex(cos(delay), sin(delay));
395 auto delaySincosCopy = channelParams->m_cachedDelaySincos;
396 for (
size_t iRb = 0; iRb < inPsd->GetValuesN(); iRb++)
398 for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
400 delaySincosCopy(iRb, cIndex) *= doppler[cIndex];
408 auto vit = inPsd->ValuesBegin();
411 while (vit != inPsd->ValuesEnd())
415 auto sqrtVit = sqrt(*vit);
416 for (
auto rxPortIdx = 0; rxPortIdx < numRxPorts; rxPortIdx++)
418 for (
auto txPortIdx = 0; txPortIdx < numTxPorts; txPortIdx++)
420 std::complex subsbandGain(0.0, 0.0);
421 for (
size_t cIndex = 0; cIndex < numCluster; cIndex++)
423 subsbandGain += directionalLongTerm(rxPortIdx, txPortIdx, cIndex) *
424 delaySincosCopy(iRb, cIndex);
428 chanSpct->Elem(rxPortIdx, txPortIdx, iRb) = sqrtVit * subsbandGain;
449 const auto isReverse =
450 channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
451 const auto sAntenna = isReverse ? bPhasedArrayModel : aPhasedArrayModel;
452 const auto uAntenna = isReverse ? aPhasedArrayModel : bPhasedArrayModel;
458 sW = aPhasedArrayModel->GetBeamformingVector();
459 uW = bPhasedArrayModel->GetBeamformingVector();
463 sW = bPhasedArrayModel->GetBeamformingVector();
464 uW = aPhasedArrayModel->GetBeamformingVector();
468 bool notFound =
false;
471 const uint64_t longTermId =
477 NS_LOG_DEBUG(
"found the long term component in the map");
483 update =
m_longTermMap[longTermId]->m_channel->m_generatedTime !=
484 channelMatrix->m_generatedTime ||
493 if (update || notFound)
497 longTerm =
CalcLongTerm(channelMatrix, sAntenna, uAntenna);
499 longTermItem->m_longTerm = longTerm;
500 longTermItem->m_channel = channelMatrix;
501 longTermItem->m_sW = std::move(sW);
502 longTermItem->m_uW = std::move(uW);
520 NS_LOG_FUNCTION(
this << spectrumSignalParams << a << b << aPhasedArrayModel
521 << bPhasedArrayModel);
526 NS_ASSERT_MSG(aPhasedArrayModel,
"Antenna not found for node " << aId);
527 NS_LOG_DEBUG(
"a node " << aId <<
" antenna " << aPhasedArrayModel);
528 NS_ASSERT_MSG(bPhasedArrayModel,
"Antenna not found for node " << bId);
529 NS_LOG_DEBUG(
"b node " << bId <<
" antenna " << bPhasedArrayModel);
532 m_channelModel->GetChannel(a, b, aPhasedArrayModel, bPhasedArrayModel);
535 NS_ASSERT_MSG(channelMatrix !=
nullptr,
"Channel matrix is null");
536 NS_ASSERT_MSG(channelParams !=
nullptr,
"Channel params are null");
540 GetLongTerm(channelMatrix, aPhasedArrayModel, bPhasedArrayModel);
542 const auto isReverse =
543 channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
552 aPhasedArrayModel->GetNumPorts(),
553 bPhasedArrayModel->GetNumPorts(),
Hold a value for an Attribute.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
static const uint8_t AOA_INDEX
index of the AOA value in the m_angle array
ComplexMatrixArray Complex3DVector
Create an alias for 3D complex vectors.
static const uint8_t ZOD_INDEX
index of the ZOD value in the m_angle array
static const uint8_t AOD_INDEX
index of the AOD value in the m_angle array
static const uint8_t ZOA_INDEX
index of the ZOA value in the m_angle array
static uint64_t GetKey(uint32_t a, uint32_t b)
Generate a unique value for the pair of unsigned integer of 32 bits, where the order does not matter,...
ComplexMatrixArray ComplexVector
the underlying Valarray
PhasedArraySpectrumPropagationLossModel()
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
Hold variables of type string.
3GPP Spectrum Propagation Loss Model
void GetChannelModelAttribute(const std::string &name, AttributeValue &value) const
Returns the value of an attribute belonging to the associated MatrixBasedChannelModel instance.
Ptr< SpectrumSignalParameters > DoCalcRxPowerSpectralDensity(Ptr< const SpectrumSignalParameters > spectrumSignalParams, Ptr< const MobilityModel > a, Ptr< const MobilityModel > b, Ptr< const PhasedArrayModel > aPhasedArrayModel, Ptr< const PhasedArrayModel > bPhasedArrayModel) const override
Computes the received PSD.
Ptr< MatrixBasedChannelModel > m_channelModel
the model to generate the channel matrix
std::complex< double > CalculateLongTermComponent(Ptr< const MatrixBasedChannelModel::ChannelMatrix > params, Ptr< const PhasedArrayModel > sAnt, Ptr< const PhasedArrayModel > uAnt, const uint16_t sPortIdx, const uint16_t uPortIdx, const uint16_t cIndex) const
Computes a longTerm component from a specific port of s device to the specific port of u device and f...
Ptr< const MatrixBasedChannelModel::Complex3DVector > GetLongTerm(Ptr< const MatrixBasedChannelModel::ChannelMatrix > channelMatrix, Ptr< const PhasedArrayModel > aPhasedArrayModel, Ptr< const PhasedArrayModel > bPhasedArrayModel) const
Looks for the long term component in m_longTermMap.
void SetChannelModel(Ptr< MatrixBasedChannelModel > channel)
Set the channel model object.
Ptr< const MatrixBasedChannelModel::Complex3DVector > CalcLongTerm(Ptr< const MatrixBasedChannelModel::ChannelMatrix > channelMatrix, Ptr< const PhasedArrayModel > sAnt, Ptr< const PhasedArrayModel > uAnt) const
Computes the long term component.
~ThreeGppSpectrumPropagationLossModel() override
Destructor.
std::unordered_map< uint64_t, Ptr< const LongTerm > > m_longTermMap
map containing the long-term components
double GetFrequency() const
Get the operating frequency.
int64_t DoAssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model.
void SetChannelModelAttribute(const std::string &name, const AttributeValue &value)
Sets the value of an attribute belonging to the associated MatrixBasedChannelModel instance.
Ptr< MatrixBasedChannelModel > GetChannelModel() const
Get the channel model object.
Ptr< SpectrumSignalParameters > CalcBeamformingGain(Ptr< const SpectrumSignalParameters > params, Ptr< const MatrixBasedChannelModel::Complex3DVector > longTerm, Ptr< const MatrixBasedChannelModel::ChannelMatrix > channelMatrix, Ptr< const MatrixBasedChannelModel::ChannelParams > channelParams, const Vector &sSpeed, const Vector &uSpeed, const uint8_t numTxPorts, const uint8_t numRxPorts, const bool isReverse) const
Computes the beamforming gain and applies it to the TX PSD.
void DoDispose() override
Destructor implementation.
static TypeId GetTypeId()
Get the type ID.
static Ptr< MatrixBasedChannelModel::Complex3DVector > GenSpectrumChannelMatrix(Ptr< SpectrumValue > inPsd, Ptr< const MatrixBasedChannelModel::Complex3DVector > longTerm, Ptr< const MatrixBasedChannelModel::ChannelMatrix > channelMatrix, Ptr< const MatrixBasedChannelModel::ChannelParams > channelParams, PhasedArrayModel::ComplexVector doppler, const uint8_t numTxPorts, const uint8_t numRxPorts, const bool isReverse)
Computes the frequency-domain channel matrix with the dimensions numRxPorts*numTxPorts*numRBs.
ThreeGppSpectrumPropagationLossModel()
Constructor.
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
size_t GetNumRows() const
size_t GetNumCols() const
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
MatrixArray< std::complex< double > > ComplexMatrixArray
Create an alias for MatrixArray using complex type.