16#include "ns3/double.h"
19#include "ns3/pointer.h"
20#include "ns3/simulator.h"
21#include "ns3/string.h"
51 TypeId(
"ns3::SionnaRtSpectrumPropagationLossModel")
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
216 const size_t numCluster = channelMatrix->m_channel.GetNumPages();
234 NS_ASSERT(numCluster <= longTerm->GetNumPages());
237 double factor = 2 * M_PI * slotTime *
GetFrequency() / 3e8;
238 for (
size_t cIndex = 0; cIndex < numCluster; cIndex++)
241 std::complex<double>(cos(sionnaRtChannelParams->m_doppler[cIndex] * factor),
242 sin(sionnaRtChannelParams->m_doppler[cIndex] * factor));
257 NS_ASSERT_MSG(rxParams->psd->GetValuesN() == rxParams->spectrumChannelMatrix->GetNumPages(),
258 "RX PSD and the spectrum channel matrix should have the same number of RBs ");
260 NS_ASSERT_MSG(!params->precodingMatrix || params->precodingMatrix->GetNumPages() ==
261 rxParams->spectrumChannelMatrix->GetNumPages(),
262 "Unexpected mismatch in the number of RBs and channel matrix and precoding "
263 "matrix. MultiModelSpectrumChannel conversion is not yet supported.");
268 if (!rxParams->precodingMatrix)
273 page.Elem(0, 0, 0) = 1.0 / sqrt(rxParams->spectrumChannelMatrix->GetNumCols());
274 for (
size_t rowI = 0; rowI < rxParams->spectrumChannelMatrix->GetNumCols(); rowI++)
276 page.Elem(rowI, 0, 0) = page.Elem(0, 0, 0);
280 page.MakeNCopies(rxParams->spectrumChannelMatrix->GetNumPages()));
284 p = rxParams->precodingMatrix;
298 for (
uint32_t rbIdx = 0; rbIdx < rxParams->psd->GetValuesN(); ++rbIdx)
300 (*rxParams->psd)[rbIdx] = 0.0;
301 for (
size_t rxPort = 0; rxPort < hP.
GetNumRows(); ++rxPort)
303 for (
size_t txStream = 0; txStream < hP.
GetNumCols(); ++txStream)
305 (*rxParams->psd)[rbIdx] +=
306 std::real(std::conj(hP(rxPort, txStream, rbIdx)) * hP(rxPort, txStream, rbIdx));
322 const bool isReverse)
324 const size_t numCluster = channelMatrix->m_channel.GetNumPages();
325 const auto numRb = inPsd->GetValuesN();
327 "Channel params delays size is smaller than number of clusters");
329 auto directionalLongTerm = isReverse ? longTerm->Transpose() : *longTerm;
334 static_cast<uint16_t
>(numRb));
340 if (
const double rbWidth = inPsd->ConstBandsBegin()->fh - inPsd->ConstBandsBegin()->fl;
341 channelParams->m_cachedDelaySincos.GetNumRows() != numRb ||
342 channelParams->m_cachedDelaySincos.GetNumCols() != numCluster ||
343 channelParams->m_cachedRbWidth != rbWidth)
345 channelParams->m_cachedRbWidth = rbWidth;
347 auto sbit = inPsd->ConstBandsBegin();
348 for (
unsigned i = 0; i < numRb; i++)
350 const double fsb = sbit->fc;
351 for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
353 const double delay = -2 * M_PI * fsb * channelParams->m_delay[cIndex];
354 channelParams->m_cachedDelaySincos(i, cIndex) =
355 std::complex(cos(delay), sin(delay));
362 auto delaySincosCopy = channelParams->m_cachedDelaySincos;
363 for (
size_t iRb = 0; iRb < inPsd->GetValuesN(); iRb++)
365 for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
367 delaySincosCopy(iRb, cIndex) *= doppler[cIndex];
375 auto vit = inPsd->ValuesBegin();
378 while (vit != inPsd->ValuesEnd())
382 auto sqrtVit = sqrt(*vit);
383 for (
auto rxPortIdx = 0; rxPortIdx < numRxPorts; rxPortIdx++)
385 for (
auto txPortIdx = 0; txPortIdx < numTxPorts; txPortIdx++)
387 std::complex subsbandGain(0.0, 0.0);
388 for (
size_t cIndex = 0; cIndex < numCluster; cIndex++)
390 subsbandGain += directionalLongTerm(rxPortIdx, txPortIdx, cIndex) *
391 delaySincosCopy(iRb, cIndex);
395 chanSpct->Elem(rxPortIdx, txPortIdx, iRb) = sqrtVit * subsbandGain;
416 const auto isReverse =
417 channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
418 const auto sAntenna = isReverse ? bPhasedArrayModel : aPhasedArrayModel;
419 const auto uAntenna = isReverse ? aPhasedArrayModel : bPhasedArrayModel;
425 sW = aPhasedArrayModel->GetBeamformingVector();
426 uW = bPhasedArrayModel->GetBeamformingVector();
430 sW = bPhasedArrayModel->GetBeamformingVector();
431 uW = aPhasedArrayModel->GetBeamformingVector();
435 bool notFound =
false;
438 const uint64_t longTermId =
444 NS_LOG_DEBUG(
"found the long term component in the map");
450 update =
m_longTermMap[longTermId]->m_channel->m_generatedTime !=
451 channelMatrix->m_generatedTime ||
460 if (update || notFound)
464 longTerm =
CalcLongTerm(channelMatrix, sAntenna, uAntenna);
466 longTermItem->m_longTerm = longTerm;
467 longTermItem->m_channel = channelMatrix;
468 longTermItem->m_sW = std::move(sW);
469 longTermItem->m_uW = std::move(uW);
487 NS_LOG_FUNCTION(
this << spectrumSignalParams << a << b << aPhasedArrayModel
488 << bPhasedArrayModel);
493 NS_ASSERT_MSG(aPhasedArrayModel,
"Antenna not found for node " << aId);
494 NS_LOG_DEBUG(
"a node " << aId <<
" antenna " << aPhasedArrayModel);
495 NS_ASSERT_MSG(bPhasedArrayModel,
"Antenna not found for node " << bId);
496 NS_LOG_DEBUG(
"b node " << bId <<
" antenna " << bPhasedArrayModel);
499 m_channelModel->GetChannel(a, b, aPhasedArrayModel, bPhasedArrayModel);
502 NS_ASSERT_MSG(channelMatrix !=
nullptr,
"Channel matrix is null");
503 NS_ASSERT_MSG(channelParams !=
nullptr,
"Channel params are null");
507 GetLongTerm(channelMatrix, aPhasedArrayModel, bPhasedArrayModel);
509 const auto isReverse =
510 channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
519 aPhasedArrayModel->GetNumPorts(),
520 bPhasedArrayModel->GetNumPorts(),
537 if (sionnaRtChannelParams)
539 sionnaRtChannelParams->SetRtPathSolverConfig(configs);
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.
3GPP Spectrum Propagation Loss Model
~SionnaRtSpectrumPropagationLossModel() override
Destructor.
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...
Ptr< const MatrixBasedChannelModel::Complex3DVector > CalcLongTerm(Ptr< const MatrixBasedChannelModel::ChannelMatrix > channelMatrix, Ptr< const PhasedArrayModel > sAnt, Ptr< const PhasedArrayModel > uAnt) const
Computes the long term component.
double GetFrequency() const
Get the operating frequency.
void GetChannelModelAttribute(const std::string &name, AttributeValue &value) const
Returns the value of an attribute belonging to the associated MatrixBasedChannelModel instance.
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.
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.
SionnaRtSpectrumPropagationLossModel()
Constructor.
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.
void SetChannelModel(Ptr< MatrixBasedChannelModel > channel)
Set 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, uint8_t numTxPorts, uint8_t numRxPorts, bool isReverse) const
Computes the beamforming gain and applies it to the TX PSD.
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.
Ptr< MatrixBasedChannelModel > m_channelModel
the model to generate the channel matrix
int64_t DoAssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model.
std::unordered_map< uint64_t, Ptr< const LongTerm > > m_longTermMap
map containing the long term components
void SetRtPathSolverConfig(SionnaRtChannelModel::RtPathSolverConfig configs)
Set the ray-tracing path solver configurations.
Hold variables of type string.
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.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
MatrixArray< std::complex< double > > ComplexMatrixArray
Create an alias for MatrixArray using complex type.
Configuration for the Sionna RT PathSolver.