A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
three-gpp-spectrum-propagation-loss-model.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015, NYU WIRELESS, Tandon School of Engineering,
3 * New York University
4 * Copyright (c) 2019 SIGNET Lab, Department of Information Engineering,
5 * University of Padova
6 *
7 * SPDX-License-Identifier: GPL-2.0-only
8 *
9 */
10
12
15
16#include "ns3/double.h"
17#include "ns3/log.h"
18#include "ns3/node.h"
19#include "ns3/pointer.h"
20#include "ns3/simulator.h"
21#include "ns3/string.h"
22
23namespace ns3
24{
25
26NS_LOG_COMPONENT_DEFINE("ThreeGppSpectrumPropagationLossModel");
27
29
34
39
40void
46
49{
50 static TypeId tid =
51 TypeId("ns3::ThreeGppSpectrumPropagationLossModel")
53 .SetGroupName("Spectrum")
55 .AddAttribute(
56 "ChannelModel",
57 "The channel model. It needs to implement the MatrixBasedChannelModel interface",
58 StringValue("ns3::ThreeGppChannelModel"),
62 return tid;
63}
64
65void
70
76
77double
79{
80 NS_ASSERT_MSG(m_channelModel != nullptr, "Channel model is not set");
81 DoubleValue freq;
82 m_channelModel->GetAttribute("Frequency", freq);
83 return freq.Get();
84}
85
86void
88 const AttributeValue& value)
89{
90 NS_ASSERT_MSG(m_channelModel != nullptr, "Channel model is not set");
91 m_channelModel->SetAttribute(name, value);
92}
93
94void
96 AttributeValue& value) const
97{
98 NS_ASSERT_MSG(m_channelModel != nullptr, "Channel model is not set");
99 m_channelModel->GetAttribute(name, value);
100}
101
107{
108 NS_LOG_FUNCTION(this);
109
110 NS_ASSERT_MSG(sAnt != nullptr && uAnt != nullptr, "Improper call to the method");
111 const PhasedArrayModel::ComplexVector& sW = sAnt->GetBeamformingVectorRef();
112 const PhasedArrayModel::ComplexVector& uW = uAnt->GetBeamformingVectorRef();
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());
117 NS_LOG_DEBUG("CalcLongTerm with " << uW.GetSize() << " u antenna elements and " << sW.GetSize()
118 << " s antenna elements, and with "
119 << " s ports: " << sAnt->GetNumPorts()
120 << " u ports: " << uAnt->GetNumPorts());
121 size_t numClusters = channelMatrix->m_channel.GetNumPages();
122 // create and initialize the size of the longTerm 3D matrix
125 sAnt->GetNumPorts(),
126 numClusters);
127 // Calculate long term uW * Husn * sW, the result is a matrix
128 // with the dimensions #uPorts, #sPorts, #cluster
129 for (auto sPortIdx = 0; sPortIdx < sAnt->GetNumPorts(); sPortIdx++)
130 {
131 for (auto uPortIdx = 0; uPortIdx < uAnt->GetNumPorts(); uPortIdx++)
132 {
133 for (size_t cIndex = 0; cIndex < numClusters; cIndex++)
134 {
135 longTerm->Elem(uPortIdx, sPortIdx, cIndex) =
136 CalculateLongTermComponent(channelMatrix,
137 sAnt,
138 uAnt,
139 sPortIdx,
140 uPortIdx,
141 cIndex);
142 }
143 }
144 }
145 return longTerm;
146}
147
148std::complex<double>
153 const uint16_t sPortIdx,
154 const uint16_t uPortIdx,
155 const uint16_t cIndex) const
156{
157 NS_LOG_FUNCTION(this);
158 const PhasedArrayModel::ComplexVector& sW = sAnt->GetBeamformingVectorRef();
159 const PhasedArrayModel::ComplexVector& uW = uAnt->GetBeamformingVectorRef();
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);
165 // limiting multiplication operations to the port location
166 auto sIndex = startS;
167 // The sub-array partition model is adopted for TXRU virtualization,
168 // as described in Section 5.2.2 of 3GPP TR 36.897,
169 // and so equal beam weights are used for all the ports.
170 // Support of the full-connection model for TXRU virtualization would need extensions.
171 const auto uElemsPerPort = uAnt->GetHElemsPerPort();
172 const auto sElemsPerPort = sAnt->GetHElemsPerPort();
173 for (size_t tIndex = 0; tIndex < sPortElems; tIndex++, sIndex++)
174 {
175 std::complex<double> rxSum(0, 0);
176 auto uIndex = startU;
177 for (size_t rIndex = 0; rIndex < uPortElems; rIndex++, uIndex++)
178 {
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)
182 {
183 const auto incVal = uAnt->GetNumColumns() - uElemsPerPort;
184 uIndex += incVal; // Increment by a factor to reach next column in a port
185 }
186 }
187
188 txSum += sW[sIndex - startS] * rxSum;
189 const auto testV = tIndex % sElemsPerPort;
190 if (const auto ptInc = sElemsPerPort - 1; testV == ptInc)
191 {
192 const size_t incVal = sAnt->GetNumColumns() - sElemsPerPort;
193 sIndex += incVal; // Increment by a factor to reach next column in a port
194 }
195 }
196 return txSum;
197}
198
205 const Vector& sSpeed,
206 const Vector& uSpeed,
207 const uint8_t numTxPorts,
208 const uint8_t numRxPorts,
209 const bool isReverse) const
210
211{
212 NS_LOG_FUNCTION(this);
213 Ptr<SpectrumSignalParameters> rxParams = params->Copy();
214 const size_t numCluster = channelMatrix->m_channel.GetNumPages();
215 // compute the doppler term
216 // NOTE the update of Doppler is simplified by only taking the center angle of
217 // each cluster in to consideration.
218 const double slotTime = Simulator::Now().GetSeconds();
219 const double factor = 2 * M_PI * slotTime * GetFrequency() / 3e8;
220 PhasedArrayModel::ComplexVector doppler(numCluster);
221
222 // Make sure that all the structures that are passed to this function
223 // are of the correct dimensions before using the operator [].
224 NS_ASSERT(numCluster <= channelParams->m_alpha.size());
225 NS_ASSERT(numCluster <= channelParams->m_D.size());
226 NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX].size());
227 NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX].size());
228 NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX].size());
229 NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX].size());
230 NS_ASSERT(numCluster <= longTerm->GetNumPages());
231
232 // check if channelParams structure is generated in direction s-to-u or u-to-s
233 const bool isSameDir = channelParams->m_nodeIds == channelMatrix->m_nodeIds;
234
235 // if channel params is generated in the same direction in which we
236 // generate the channel matrix, angles and zenith of departure and arrival are ok,
237 // just set them to corresponding variable that will be used for the generation
238 // of channel matrix, otherwise we need to flip angles and zeniths of departure and arrival
239 using DPV = std::vector<std::pair<double, double>>;
240 const auto& cachedAngleSincos = channelParams->m_cachedAngleSincos;
241 NS_ASSERT_MSG(cachedAngleSincos.size() > MatrixBasedChannelModel::ZOD_INDEX,
242 "Cached angle sin/cos not initialized");
243 const DPV& zoa = cachedAngleSincos[isSameDir ? MatrixBasedChannelModel::ZOA_INDEX
245 const DPV& zod = cachedAngleSincos[isSameDir ? MatrixBasedChannelModel::ZOD_INDEX
247 const DPV& aoa = cachedAngleSincos[isSameDir ? MatrixBasedChannelModel::AOA_INDEX
249 const DPV& aod = cachedAngleSincos[isSameDir ? MatrixBasedChannelModel::AOD_INDEX
251 NS_ASSERT(numCluster <= zoa.size());
252 NS_ASSERT(numCluster <= zod.size());
253 NS_ASSERT(numCluster <= aoa.size());
254 NS_ASSERT(numCluster <= aod.size());
255
256 for (size_t cIndex = 0; cIndex < numCluster; cIndex++)
257 {
258 // Compute alpha and D as described in 3GPP TR 37.885 v15.3.0, Sec. 6.2.3
259 // These terms account for an additional Doppler contribution due to the
260 // presence of moving objects in the surrounding environment, such as in
261 // vehicular scenarios.
262 // This contribution is applied only to the delayed (reflected) paths and
263 // must be properly configured by setting the value of
264 // m_vScatt, which is defined as "maximum speed of the vehicle in the
265 // layout".
266 // By default, m_vScatt is set to 0, so there is no additional Doppler
267 // contribution.
268
269 const double alpha = channelParams->m_alpha[cIndex];
270 const double D = channelParams->m_D[cIndex];
271
272 // cluster angle angle[direction][n], where direction = 0(aoa), 1(zoa).
273 const double tempDoppler =
274 factor *
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) +
279 2 * alpha * D);
280 doppler[cIndex] = std::complex(cos(tempDoppler), sin(tempDoppler));
281 }
282
283 NS_ASSERT(numCluster <= doppler.GetSize());
284
285 // set the channel matrix
286 rxParams->spectrumChannelMatrix = GenSpectrumChannelMatrix(rxParams->psd,
287 longTerm,
288 channelMatrix,
289 channelParams,
290 doppler,
291 numTxPorts,
292 numRxPorts,
293 isReverse);
294
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 ");
297
298 // Calculate RX PSD from the spectrum channel matrix H and
299 // the precoding matrix P as: PSD = (H*P)^h * (H*P)
301 if (!rxParams->precodingMatrix)
302 {
303 // When the precoding matrix P is not set, we create one with a single column
304 auto page = ComplexMatrixArray(rxParams->spectrumChannelMatrix->GetNumCols(), 1, 1);
305 // Initialize it to the inverse square of the number of txPorts
306 page.Elem(0, 0, 0) = 1.0 / sqrt(rxParams->spectrumChannelMatrix->GetNumCols());
307 for (size_t rowI = 0; rowI < rxParams->spectrumChannelMatrix->GetNumCols(); rowI++)
308 {
309 page.Elem(rowI, 0, 0) = page.Elem(0, 0, 0);
310 }
311 // Replicate vector to match the number of RBGs
313 page.MakeNCopies(rxParams->spectrumChannelMatrix->GetNumPages()));
314 }
315 else
316 {
317 p = rxParams->precodingMatrix;
318 }
319 // When we have the precoding matrix P, we first do
320 // H(rxPorts,txPorts,numRbs) x P(txPorts,txStreams,numRbs) = HxP(rxPorts,txStreams,numRbs)
321 MatrixBasedChannelModel::Complex3DVector hP = *rxParams->spectrumChannelMatrix * *p;
322
323 // Then (HxP)^h dimensions are (txStreams, rxPorts, numRbs)
324 // MatrixBasedChannelModel::Complex3DVector hPHerm = hP.HermitianTranspose();
325
326 // Finally, (HxP)^h x (HxP) = PSD(txStreams, txStreams, numRbs)
327 // MatrixBasedChannelModel::Complex3DVector psd = hPHerm * hP;
328
329 // And the received psd is the Trace(PSD).
330 // To avoid wasting computations, we only compute the main diagonal of hPHerm*hP
331 for (uint32_t rbIdx = 0; rbIdx < rxParams->psd->GetValuesN(); ++rbIdx)
332 {
333 (*rxParams->psd)[rbIdx] = 0.0;
334 for (size_t rxPort = 0; rxPort < hP.GetNumRows(); ++rxPort)
335 {
336 for (size_t txStream = 0; txStream < hP.GetNumCols(); ++txStream)
337 {
338 (*rxParams->psd)[rbIdx] +=
339 std::real(std::conj(hP(rxPort, txStream, rbIdx)) * hP(rxPort, txStream, rbIdx));
340 }
341 }
342 }
343 return rxParams;
344}
345
348 Ptr<SpectrumValue> inPsd,
353 uint8_t numTxPorts,
354 uint8_t numRxPorts,
355 const bool isReverse)
356{
357 const size_t numCluster = channelMatrix->m_channel.GetNumPages();
358 const auto numRb = inPsd->GetValuesN();
359 NS_ASSERT_MSG(numCluster <= channelParams->m_delay.size(),
360 "Channel params delays size is smaller than number of clusters");
361
362 auto directionalLongTerm = isReverse ? longTerm->Transpose() : *longTerm;
363
366 numTxPorts,
367 static_cast<uint16_t>(numRb));
368
369 // Precompute the delay until numRb, numCluster or RB width changes
370 // Whenever the channelParams is updated, the number of numRbs, numClusters
371 // and RB width (12*SCS) are reset, ensuring these values are updated too
372
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)
377 {
378 channelParams->m_cachedRbWidth = rbWidth;
379 channelParams->m_cachedDelaySincos = ComplexMatrixArray(numRb, numCluster);
380 auto sbit = inPsd->ConstBandsBegin(); // band iterator
381 for (unsigned i = 0; i < numRb; i++)
382 {
383 const double fsb = sbit->fc; // center frequency of the sub-band
384 for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
385 {
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));
389 }
390 ++sbit;
391 }
392 }
393
394 // Compute the product between the doppler and the delay sincos
395 auto delaySincosCopy = channelParams->m_cachedDelaySincos;
396 for (size_t iRb = 0; iRb < inPsd->GetValuesN(); iRb++)
397 {
398 for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
399 {
400 delaySincosCopy(iRb, cIndex) *= doppler[cIndex];
401 }
402 }
403
404 // If "params" (ChannelMatrix) and longTerm were computed for the reverse direction (e.g. this
405 // is a DL transmission but params and longTerm were last updated during UL), then the elements
406 // in longTerm start from different offsets.
407
408 auto vit = inPsd->ValuesBegin(); // psd iterator
409 size_t iRb = 0;
410 // Compute the frequency-domain channel matrix
411 while (vit != inPsd->ValuesEnd())
412 {
413 if (*vit != 0.00)
414 {
415 auto sqrtVit = sqrt(*vit);
416 for (auto rxPortIdx = 0; rxPortIdx < numRxPorts; rxPortIdx++)
417 {
418 for (auto txPortIdx = 0; txPortIdx < numTxPorts; txPortIdx++)
419 {
420 std::complex subsbandGain(0.0, 0.0);
421 for (size_t cIndex = 0; cIndex < numCluster; cIndex++)
422 {
423 subsbandGain += directionalLongTerm(rxPortIdx, txPortIdx, cIndex) *
424 delaySincosCopy(iRb, cIndex);
425 }
426 // Multiply with the square root of the input PSD so that the norm (absolute
427 // value squared) of chanSpct will be the output PSD
428 chanSpct->Elem(rxPortIdx, txPortIdx, iRb) = sqrtVit * subsbandGain;
429 }
430 }
431 }
432 ++vit;
433 ++iRb;
434 }
435 return chanSpct;
436}
437
441 Ptr<const PhasedArrayModel> aPhasedArrayModel,
442 Ptr<const PhasedArrayModel> bPhasedArrayModel) const
443{
445 longTerm; // vector containing the long term component for each cluster
446
447 // check if the channel matrix was generated considering a as the s-node and
448 // b as the u-node or vice-versa
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;
453
456 if (!isReverse)
457 {
458 sW = aPhasedArrayModel->GetBeamformingVector();
459 uW = bPhasedArrayModel->GetBeamformingVector();
460 }
461 else
462 {
463 sW = bPhasedArrayModel->GetBeamformingVector();
464 uW = aPhasedArrayModel->GetBeamformingVector();
465 }
466
467 bool update = false; // indicates whether the long term has to be updated
468 bool notFound = false; // indicates if the long term has not been computed yet
469
470 // compute the long term key, the key is unique for each tx-rx pair
471 const uint64_t longTermId =
472 MatrixBasedChannelModel::GetKey(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
473
474 // look for the long term in the map and check if it is valid
475 if (m_longTermMap.contains(longTermId))
476 {
477 NS_LOG_DEBUG("found the long term component in the map");
478 longTerm = m_longTermMap[longTermId]->m_longTerm;
479
480 // check if the channel matrix has been updated
481 // or the s beam has been changed
482 // or the u beam has been changed
483 update = m_longTermMap[longTermId]->m_channel->m_generatedTime !=
484 channelMatrix->m_generatedTime ||
485 m_longTermMap[longTermId]->m_sW != sW || m_longTermMap[longTermId]->m_uW != uW;
486 }
487 else
488 {
489 NS_LOG_DEBUG("long term component NOT found");
490 notFound = true;
491 }
492
493 if (update || notFound)
494 {
495 NS_LOG_DEBUG("compute the long term");
496 // compute the long term component
497 longTerm = CalcLongTerm(channelMatrix, sAntenna, uAntenna);
498 Ptr<LongTerm> longTermItem = Create<LongTerm>();
499 longTermItem->m_longTerm = longTerm;
500 longTermItem->m_channel = channelMatrix;
501 longTermItem->m_sW = std::move(sW);
502 longTermItem->m_uW = std::move(uW);
503 // store the long term to reduce computation load
504 // only the small scale fading needs to be updated if the large scale parameters and antenna
505 // weights remain unchanged.
506 m_longTermMap[longTermId] = longTermItem;
507 }
508
509 return longTerm;
510}
511
514 Ptr<const SpectrumSignalParameters> spectrumSignalParams,
517 Ptr<const PhasedArrayModel> aPhasedArrayModel,
518 Ptr<const PhasedArrayModel> bPhasedArrayModel) const
519{
520 NS_LOG_FUNCTION(this << spectrumSignalParams << a << b << aPhasedArrayModel
521 << bPhasedArrayModel);
522 NS_ASSERT_MSG(m_channelModel != nullptr, "Channel model is not set");
523
524 const uint32_t aId = a->GetObject<Node>()->GetId(); // id of the node a
525 const uint32_t bId = b->GetObject<Node>()->GetId(); // id of the node b
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);
530
532 m_channelModel->GetChannel(a, b, aPhasedArrayModel, bPhasedArrayModel);
534 m_channelModel->GetParams(a, b);
535 NS_ASSERT_MSG(channelMatrix != nullptr, "Channel matrix is null");
536 NS_ASSERT_MSG(channelParams != nullptr, "Channel params are null");
537
538 // retrieve the long term component
540 GetLongTerm(channelMatrix, aPhasedArrayModel, bPhasedArrayModel);
541
542 const auto isReverse =
543 channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
544
545 // apply the beamforming gain
546 return CalcBeamformingGain(spectrumSignalParams,
547 longTerm,
548 channelMatrix,
549 channelParams,
550 a->GetVelocity(),
551 b->GetVelocity(),
552 aPhasedArrayModel->GetNumPorts(),
553 bPhasedArrayModel->GetNumPorts(),
554 isReverse);
555}
556
557int64_t
559{
560 return 0;
561}
562
563} // namespace ns3
Hold a value for an Attribute.
Definition attribute.h:59
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
double Get() const
Definition double.cc:26
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,...
A network Node.
Definition node.h:46
ComplexMatrixArray ComplexVector
the underlying Valarray
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
Hold variables of type string.
Definition string.h:45
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.
std::unordered_map< uint64_t, Ptr< const LongTerm > > m_longTermMap
map containing the long-term components
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.
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.
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:398
a unique identifier for an interface.
Definition type-id.h:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
size_t GetSize() const
Definition val-array.h:394
size_t GetNumRows() const
Definition val-array.h:373
size_t GetNumCols() const
Definition val-array.h:380
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition pointer.h:250
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:273
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#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.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:454
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.