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 += std::conj(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 ");
298 NS_ASSERT_MSG(!params->precodingMatrix || (params->precodingMatrix &&
299 params->precodingMatrix->GetNumPages() ==
300 rxParams->spectrumChannelMatrix->GetNumPages()),
301 "Unexpected mismatch in the number of RBs and channel matrix and precoding "
302 "matrix. MultiModelSpectrumChannel conversion is not yet supported.");
307 if (!rxParams->precodingMatrix)
312 page.Elem(0, 0, 0) = 1.0 / sqrt(rxParams->spectrumChannelMatrix->GetNumCols());
313 for (
size_t rowI = 0; rowI < rxParams->spectrumChannelMatrix->GetNumCols(); rowI++)
315 page.Elem(rowI, 0, 0) = page.Elem(0, 0, 0);
319 page.MakeNCopies(rxParams->spectrumChannelMatrix->GetNumPages()));
323 p = rxParams->precodingMatrix;
337 for (
uint32_t rbIdx = 0; rbIdx < rxParams->psd->GetValuesN(); ++rbIdx)
339 (*rxParams->psd)[rbIdx] = 0.0;
340 for (
size_t rxPort = 0; rxPort < hP.
GetNumRows(); ++rxPort)
342 for (
size_t txStream = 0; txStream < hP.
GetNumCols(); ++txStream)
344 (*rxParams->psd)[rbIdx] +=
345 std::real(std::conj(hP(rxPort, txStream, rbIdx)) * hP(rxPort, txStream, rbIdx));
361 const bool isReverse)
363 const size_t numCluster = channelMatrix->m_channel.GetNumPages();
364 const auto numRb = inPsd->GetValuesN();
366 "Channel params delays size is smaller than number of clusters");
368 auto directionalLongTerm = isReverse ? longTerm->Transpose() : *longTerm;
373 static_cast<uint16_t
>(numRb));
379 if (
const double rbWidth = inPsd->ConstBandsBegin()->fh - inPsd->ConstBandsBegin()->fl;
380 channelParams->m_cachedDelaySincos.GetNumRows() != numRb ||
381 channelParams->m_cachedDelaySincos.GetNumCols() != numCluster ||
382 channelParams->m_cachedRbWidth != rbWidth)
384 channelParams->m_cachedRbWidth = rbWidth;
386 auto sbit = inPsd->ConstBandsBegin();
387 for (
unsigned i = 0; i < numRb; i++)
389 const double fsb = sbit->fc;
390 for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
392 const double delay = -2 * M_PI * fsb * channelParams->m_delay[cIndex];
393 channelParams->m_cachedDelaySincos(i, cIndex) =
394 std::complex(cos(delay), sin(delay));
401 auto delaySincosCopy = channelParams->m_cachedDelaySincos;
402 for (
size_t iRb = 0; iRb < inPsd->GetValuesN(); iRb++)
404 for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
406 delaySincosCopy(iRb, cIndex) *= doppler[cIndex];
414 auto vit = inPsd->ValuesBegin();
417 while (vit != inPsd->ValuesEnd())
421 auto sqrtVit = sqrt(*vit);
422 for (
auto rxPortIdx = 0; rxPortIdx < numRxPorts; rxPortIdx++)
424 for (
auto txPortIdx = 0; txPortIdx < numTxPorts; txPortIdx++)
426 std::complex subsbandGain(0.0, 0.0);
427 for (
size_t cIndex = 0; cIndex < numCluster; cIndex++)
429 subsbandGain += directionalLongTerm(rxPortIdx, txPortIdx, cIndex) *
430 delaySincosCopy(iRb, cIndex);
434 chanSpct->Elem(rxPortIdx, txPortIdx, iRb) = sqrtVit * subsbandGain;
455 const auto isReverse =
456 channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
457 const auto sAntenna = isReverse ? bPhasedArrayModel : aPhasedArrayModel;
458 const auto uAntenna = isReverse ? aPhasedArrayModel : bPhasedArrayModel;
464 sW = aPhasedArrayModel->GetBeamformingVector();
465 uW = bPhasedArrayModel->GetBeamformingVector();
469 sW = bPhasedArrayModel->GetBeamformingVector();
470 uW = aPhasedArrayModel->GetBeamformingVector();
474 bool notFound =
false;
477 const uint64_t longTermId =
483 NS_LOG_DEBUG(
"found the long term component in the map");
489 update =
m_longTermMap[longTermId]->m_channel->m_generatedTime !=
490 channelMatrix->m_generatedTime ||
499 if (update || notFound)
503 longTerm =
CalcLongTerm(channelMatrix, sAntenna, uAntenna);
505 longTermItem->m_longTerm = longTerm;
506 longTermItem->m_channel = channelMatrix;
507 longTermItem->m_sW = std::move(sW);
508 longTermItem->m_uW = std::move(uW);
526 NS_LOG_FUNCTION(
this << spectrumSignalParams << a << b << aPhasedArrayModel
527 << bPhasedArrayModel);
532 NS_ASSERT_MSG(aPhasedArrayModel,
"Antenna not found for node " << aId);
533 NS_LOG_DEBUG(
"a node " << aId <<
" antenna " << aPhasedArrayModel);
534 NS_ASSERT_MSG(bPhasedArrayModel,
"Antenna not found for node " << bId);
535 NS_LOG_DEBUG(
"b node " << bId <<
" antenna " << bPhasedArrayModel);
538 m_channelModel->GetChannel(a, b, aPhasedArrayModel, bPhasedArrayModel);
541 NS_ASSERT_MSG(channelMatrix !=
nullptr,
"Channel matrix is null");
542 NS_ASSERT_MSG(channelParams !=
nullptr,
"Channel params are null");
546 GetLongTerm(channelMatrix, aPhasedArrayModel, bPhasedArrayModel);
548 const auto isReverse =
549 channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
558 aPhasedArrayModel->GetNumPorts(),
559 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.