27#include "ns3/double.h"
29#include "ns3/net-device.h"
31#include "ns3/pointer.h"
32#include "ns3/simulator.h"
33#include "ns3/string.h"
66 TypeId(
"ns3::ThreeGppSpectrumPropagationLossModel")
68 .SetGroupName(
"Spectrum")
72 "The channel model. It needs to implement the MatrixBasedChannelModel interface",
76 MakePointerChecker<MatrixBasedChannelModel>());
124 size_t sAntNumElems = sW.
GetSize();
125 size_t uAntNumElems = uW.
GetSize();
126 NS_ASSERT(uAntNumElems == params->m_channel.GetNumRows());
127 NS_ASSERT(sAntNumElems == params->m_channel.GetNumCols());
129 <<
" s antenna elements, and with "
130 <<
" s ports: " << sAnt->GetNumPorts()
131 <<
" u ports: " << uAnt->GetNumPorts());
132 NS_ASSERT_MSG((sAnt !=
nullptr) && (uAnt !=
nullptr),
"Improper call to the method");
133 size_t numClusters = params->m_channel.GetNumPages();
136 Create<MatrixBasedChannelModel::Complex3DVector>(uAnt->GetNumPorts(),
141 for (
auto sPortIdx = 0; sPortIdx < sAnt->GetNumPorts(); sPortIdx++)
143 for (
auto uPortIdx = 0; uPortIdx < uAnt->GetNumPorts(); uPortIdx++)
145 for (
size_t cIndex = 0; cIndex < numClusters; cIndex++)
147 longTerm->Elem(uPortIdx, sPortIdx, cIndex) =
162 uint16_t cIndex)
const
167 auto sPortElems = sAnt->GetNumElemsPerPort();
168 auto uPortElems = uAnt->GetNumElemsPerPort();
169 auto startS = sAnt->ArrayIndexFromPortIndex(sPortIdx, 0);
170 auto startU = uAnt->ArrayIndexFromPortIndex(uPortIdx, 0);
171 std::complex<double> txSum(0, 0);
173 auto sIndex = startS;
178 for (
size_t tIndex = 0; tIndex < sPortElems; tIndex++, sIndex++)
180 std::complex<double> rxSum(0, 0);
181 auto uIndex = startU;
182 for (
size_t rIndex = 0; rIndex < uPortElems; rIndex++, uIndex++)
184 rxSum += uW[uIndex - startU] * params->m_channel(uIndex, sIndex, cIndex);
185 auto testV = (rIndex % uAnt->GetHElemsPerPort());
186 auto ptInc = uAnt->GetHElemsPerPort() - 1;
189 auto incVal = uAnt->GetNumColumns() - uAnt->GetHElemsPerPort();
194 txSum += sW[sIndex - startS] * rxSum;
195 auto testV = (tIndex % sAnt->GetHElemsPerPort());
196 auto ptInc = sAnt->GetHElemsPerPort() - 1;
199 size_t incVal = sAnt->GetNumColumns() - sAnt->GetHElemsPerPort();
212 const Vector& sSpeed,
213 const ns3::Vector& uSpeed,
216 bool isReverse)
const
221 size_t numCluster = channelMatrix->m_channel.GetNumPages();
226 double factor = 2 * M_PI * slotTime *
GetFrequency() / 3e8;
231 NS_ASSERT(numCluster <= channelParams->m_alpha.size());
232 NS_ASSERT(numCluster <= channelParams->m_D.size());
237 NS_ASSERT(numCluster <= longTerm->GetNumPages());
240 bool isSameDir = (channelParams->m_nodeIds == channelMatrix->m_nodeIds);
246 using DPV = std::vector<std::pair<double, double>>;
248 const auto& cachedAngleSincos = channelParams->m_cachedAngleSincos;
249 const DPV& zoa = cachedAngleSincos[isSameDir ? MBCM::ZOA_INDEX : MBCM::ZOD_INDEX];
250 const DPV& zod = cachedAngleSincos[isSameDir ? MBCM::ZOD_INDEX : MBCM::ZOA_INDEX];
251 const DPV& aoa = cachedAngleSincos[isSameDir ? MBCM::AOA_INDEX : MBCM::AOD_INDEX];
252 const DPV& aod = cachedAngleSincos[isSameDir ? MBCM::AOD_INDEX : MBCM::AOA_INDEX];
254 for (
size_t cIndex = 0; cIndex < numCluster; cIndex++)
267 double alpha = channelParams->m_alpha[cIndex];
268 double D = channelParams->m_D[cIndex];
273 ((zoa[cIndex].first * aoa[cIndex].second * uSpeed.x +
274 zoa[cIndex].first * aoa[cIndex].first * uSpeed.y + zoa[cIndex].second * uSpeed.z) +
275 (zod[cIndex].
first * aod[cIndex].
second * sSpeed.x +
276 zod[cIndex].first * aod[cIndex].first * sSpeed.y + zod[cIndex].second * sSpeed.z) +
278 doppler[cIndex] = std::complex<double>(cos(tempDoppler), sin(tempDoppler));
294 if (!rxParams->precodingMatrix)
298 auto vit = rxParams->psd->ValuesBegin();
300 while (vit != rxParams->psd->ValuesEnd())
303 *vit = std::norm(rxParams->spectrumChannelMatrix->Elem(0, 0, rbIdx));
310 NS_ASSERT_MSG(rxParams->psd->GetValuesN() == rxParams->spectrumChannelMatrix->GetNumPages(),
311 "RX PSD and the spectrum channel matrix should have the same number of RBs ");
319 *rxParams->spectrumChannelMatrix * (*rxParams->precodingMatrix);
326 for (
uint32_t rbIdx = 0; rbIdx < rxParams->psd->GetValuesN(); ++rbIdx)
328 (*rxParams->psd)[rbIdx] = 0.0;
330 for (
size_t txStream = 0; txStream < psd.
GetNumRows(); ++txStream)
332 (*rxParams->psd)[rbIdx] += std::real(psd(txStream, txStream, rbIdx));
348 bool isReverse)
const
350 size_t numCluster = channelMatrix->m_channel.GetNumPages();
351 auto numRb = inPsd->GetValuesN();
353 auto directionalLongTerm = isReverse ? longTerm->Transpose() : (*longTerm);
356 Create<MatrixBasedChannelModel::Complex3DVector>(numRxPorts, numTxPorts, (uint16_t)numRb);
361 double rbWidth = inPsd->ConstBandsBegin()->fh - inPsd->ConstBandsBegin()->fl;
363 if (channelParams->m_cachedDelaySincos.GetNumRows() != numRb ||
364 channelParams->m_cachedDelaySincos.GetNumCols() != numCluster ||
365 channelParams->m_cachedRbWidth != rbWidth)
367 channelParams->m_cachedRbWidth = rbWidth;
369 auto sbit = inPsd->ConstBandsBegin();
370 for (
unsigned i = 0; i < numRb; i++)
372 double fsb = (*sbit).fc;
373 for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
375 double delay = -2 * M_PI * fsb * (channelParams->m_delay[cIndex]);
376 channelParams->m_cachedDelaySincos(i, cIndex) =
377 std::complex<double>(cos(delay), sin(delay));
384 auto delaySincosCopy = channelParams->m_cachedDelaySincos;
385 for (
size_t iRb = 0; iRb < inPsd->GetValuesN(); iRb++)
387 for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
389 delaySincosCopy(iRb, cIndex) *= doppler[cIndex];
397 auto vit = inPsd->ValuesBegin();
400 while (vit != inPsd->ValuesEnd())
404 auto sqrtVit = sqrt(*vit);
405 for (
auto rxPortIdx = 0; rxPortIdx < numRxPorts; rxPortIdx++)
407 for (
auto txPortIdx = 0; txPortIdx < numTxPorts; txPortIdx++)
409 std::complex<double> subsbandGain(0.0, 0.0);
410 for (
size_t cIndex = 0; cIndex < numCluster; cIndex++)
412 subsbandGain += directionalLongTerm(rxPortIdx, txPortIdx, cIndex) *
413 delaySincosCopy(iRb, cIndex);
417 chanSpct->Elem(rxPortIdx, txPortIdx, iRb) = sqrtVit * subsbandGain;
439 channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
440 auto sAntenna = isReverse ? bPhasedArrayModel : aPhasedArrayModel;
441 auto uAntenna = isReverse ? aPhasedArrayModel : bPhasedArrayModel;
447 sW = aPhasedArrayModel->GetBeamformingVector();
448 uW = bPhasedArrayModel->GetBeamformingVector();
452 sW = bPhasedArrayModel->GetBeamformingVector();
453 uW = aPhasedArrayModel->GetBeamformingVector();
457 bool notFound =
false;
460 uint64_t longTermId =
466 NS_LOG_DEBUG(
"found the long term component in the map");
472 update = (
m_longTermMap[longTermId]->m_channel->m_generatedTime !=
473 channelMatrix->m_generatedTime ||
482 if (update || notFound)
486 longTerm =
CalcLongTerm(channelMatrix, sAntenna, uAntenna);
488 longTermItem->m_longTerm = longTerm;
489 longTermItem->m_channel = channelMatrix;
490 longTermItem->m_sW = std::move(sW);
491 longTermItem->m_uW = std::move(uW);
509 NS_LOG_FUNCTION(
this << spectrumSignalParams << a << b << aPhasedArrayModel
510 << bPhasedArrayModel);
512 if (a->GetPosition() == b->GetPosition())
514 return spectrumSignalParams->Copy();
518 NS_ASSERT_MSG(aPhasedArrayModel,
"Antenna not found for node " << aId);
519 NS_LOG_DEBUG(
"a node " << aId <<
" antenna " << aPhasedArrayModel);
520 NS_ASSERT_MSG(bPhasedArrayModel,
"Antenna not found for node " << bId);
521 NS_LOG_DEBUG(
"b node " << bId <<
" antenna " << bPhasedArrayModel);
524 m_channelModel->GetChannel(a, b, aPhasedArrayModel, bPhasedArrayModel);
530 GetLongTerm(channelMatrix, aPhasedArrayModel, bPhasedArrayModel);
533 channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
542 aPhasedArrayModel->GetNumPorts(),
543 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'.
MatrixArray< T > HermitianTranspose() const
Function that performs the Hermitian transpose of this MatrixArray and returns a new matrix that is t...
This is an interface for a channel model that can be described by a channel matrix,...
static const uint8_t AOA_INDEX
index of the AOA value in the m_angle array
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,...
spectrum-aware propagation loss model that is compatible with PhasedArrayModel type of ns-3 antenna
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
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, uint8_t numTxPorts, uint8_t numRxPorts, bool isReverse) const
Computes the frequency-domain channel matrix with the dimensions numRxPorts*numTxPorts*numRBs.
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.
void DoDispose() override
Destructor implementation.
static TypeId GetTypeId()
Get the type ID.
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, uint8_t numTxPorts, uint8_t numRxPorts, bool isReverse) const
Computes the beamforming gain and applies it to the TX PSD.
std::complex< double > CalculateLongTermComponent(Ptr< const MatrixBasedChannelModel::ChannelMatrix > params, Ptr< const PhasedArrayModel > sAnt, Ptr< const PhasedArrayModel > uAnt, uint16_t sPortIdx, uint16_t uPortIdx, uint16_t cIndex) const
Computes a longTerm component from a specific port of s device to the specific port of u device and f...
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
#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)
#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.
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.