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 isSameDirection = (channelParams->m_nodeIds == channelMatrix->m_nodeIds);
266 for (
size_t cIndex = 0; cIndex < numCluster; cIndex++)
279 double alpha = channelParams->m_alpha[cIndex];
280 double D = channelParams->m_D[cIndex];
284 factor * ((sin(zoa[cIndex] * M_PI / 180) * cos(aoa[cIndex] * M_PI / 180) * uSpeed.x +
285 sin(zoa[cIndex] * M_PI / 180) * sin(aoa[cIndex] * M_PI / 180) * uSpeed.y +
286 cos(zoa[cIndex] * M_PI / 180) * uSpeed.z) +
287 (sin(zod[cIndex] * M_PI / 180) * cos(aod[cIndex] * M_PI / 180) * sSpeed.x +
288 sin(zod[cIndex] * M_PI / 180) * sin(aod[cIndex] * M_PI / 180) * sSpeed.y +
289 cos(zod[cIndex] * M_PI / 180) * sSpeed.z) +
291 doppler[cIndex] = std::complex<double>(cos(tempDoppler), sin(tempDoppler));
307 if (!rxParams->precodingMatrix)
311 auto vit = rxParams->psd->ValuesBegin();
313 while (vit != rxParams->psd->ValuesEnd())
316 *vit = std::norm(rxParams->spectrumChannelMatrix->Elem(0, 0, rbIdx));
323 NS_ASSERT_MSG(rxParams->psd->GetValuesN() == rxParams->spectrumChannelMatrix->GetNumPages(),
324 "RX PSD and the spectrum channel matrix should have the same number of RBs ");
332 *rxParams->spectrumChannelMatrix * (*rxParams->precodingMatrix);
339 for (
uint32_t rbIdx = 0; rbIdx < rxParams->psd->GetValuesN(); ++rbIdx)
341 (*rxParams->psd)[rbIdx] = 0.0;
343 for (
size_t txStream = 0; txStream < psd.
GetNumRows(); ++txStream)
345 (*rxParams->psd)[rbIdx] += std::real(psd(txStream, txStream, rbIdx));
361 bool isReverse)
const
363 size_t numCluster = channelMatrix->m_channel.GetNumPages();
364 auto numRb = inPsd->GetValuesN();
366 auto directionalLongTerm = isReverse ? longTerm->Transpose() : (*longTerm);
369 Create<MatrixBasedChannelModel::Complex3DVector>(numRxPorts, numTxPorts, (uint16_t)numRb);
375 auto vit = inPsd->ValuesBegin();
376 auto sbit = inPsd->ConstBandsBegin();
379 while (vit != inPsd->ValuesEnd())
383 double fsb = (*sbit).fc;
384 for (
auto rxPortIdx = 0; rxPortIdx < numRxPorts; rxPortIdx++)
386 for (
auto txPortIdx = 0; txPortIdx < numTxPorts; txPortIdx++)
388 std::complex<double> subsbandGain(0.0, 0.0);
390 for (
size_t cIndex = 0; cIndex < numCluster; cIndex++)
392 double delay = -2 * M_PI * fsb * (channelParams->m_delay[cIndex]);
393 subsbandGain += directionalLongTerm(rxPortIdx, txPortIdx, cIndex) *
395 std::complex<double>(cos(delay), sin(delay));
399 chanSpct->Elem(rxPortIdx, txPortIdx, iRb) = sqrt(*vit) * subsbandGain;
422 channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
423 auto sAntenna = isReverse ? bPhasedArrayModel : aPhasedArrayModel;
424 auto uAntenna = isReverse ? aPhasedArrayModel : bPhasedArrayModel;
430 sW = aPhasedArrayModel->GetBeamformingVector();
431 uW = bPhasedArrayModel->GetBeamformingVector();
435 sW = bPhasedArrayModel->GetBeamformingVector();
436 uW = aPhasedArrayModel->GetBeamformingVector();
440 bool notFound =
false;
443 uint64_t longTermId =
449 NS_LOG_DEBUG(
"found the long term component in the map");
455 update = (
m_longTermMap[longTermId]->m_channel->m_generatedTime !=
456 channelMatrix->m_generatedTime ||
465 if (update || notFound)
469 longTerm =
CalcLongTerm(channelMatrix, sAntenna, uAntenna);
471 longTermItem->m_longTerm = longTerm;
472 longTermItem->m_channel = channelMatrix;
473 longTermItem->m_sW = std::move(sW);
474 longTermItem->m_uW = std::move(uW);
492 NS_LOG_FUNCTION(
this << spectrumSignalParams << a << b << aPhasedArrayModel
493 << bPhasedArrayModel);
495 if (a->GetPosition() == b->GetPosition())
497 return spectrumSignalParams->Copy();
501 NS_ASSERT_MSG(aPhasedArrayModel,
"Antenna not found for node " << aId);
502 NS_LOG_DEBUG(
"a node " << aId <<
" antenna " << aPhasedArrayModel);
503 NS_ASSERT_MSG(bPhasedArrayModel,
"Antenna not found for node " << bId);
504 NS_LOG_DEBUG(
"b node " << bId <<
" antenna " << bPhasedArrayModel);
507 m_channelModel->GetChannel(a, b, aPhasedArrayModel, bPhasedArrayModel);
513 GetLongTerm(channelMatrix, aPhasedArrayModel, bPhasedArrayModel);
516 channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
525 aPhasedArrayModel->GetNumPorts(),
526 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 class inherits ValArray class and provides additional interfaces to ValArray which enable...
MatrixArray< T > HermitianTranspose() const
Function that performs the Hermitian transpose of this MatrixArray and returns a new matrix that is t...
std::vector< double > DoubleVector
Type definition for vectors of doubles.
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.