A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
three-gpp-channel-test-suite.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 SIGNET Lab, Department of Information Engineering,
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18#include "ns3/abort.h"
19#include "ns3/angles.h"
20#include "ns3/channel-condition-model.h"
21#include "ns3/config.h"
22#include "ns3/constant-position-mobility-model.h"
23#include "ns3/double.h"
24#include "ns3/ism-spectrum-value-helper.h"
25#include "ns3/isotropic-antenna-model.h"
26#include "ns3/log.h"
27#include "ns3/node-container.h"
28#include "ns3/pointer.h"
29#include "ns3/rng-seed-manager.h"
30#include "ns3/simple-net-device.h"
31#include "ns3/simulator.h"
32#include "ns3/spectrum-signal-parameters.h"
33#include "ns3/string.h"
34#include "ns3/test.h"
35#include "ns3/three-gpp-antenna-model.h"
36#include "ns3/three-gpp-channel-model.h"
37#include "ns3/three-gpp-spectrum-propagation-loss-model.h"
38#include "ns3/uinteger.h"
39#include "ns3/uniform-planar-array.h"
40
41#include <valarray>
42
43using namespace ns3;
44
45NS_LOG_COMPONENT_DEFINE("ThreeGppChannelTestSuite");
46
47/**
48 * \ingroup spectrum-tests
49 *
50 * Test case for the ThreeGppChannelModel class.
51 * 1) check if the channel matrix has the correct dimensions
52 * 2) check if the channel matrix is correctly normalized
53 */
55{
56 public:
57 /**
58 *Constructor
59 * \param txAntennaElements the number of rows and columns of the antenna array of the
60 * transmitter
61 * \param rxAntennaElements the number of rows and columns of the antenna array of
62 * \param txPorts the number of vertical and horizontal ports of the antenna array
63 * of the transmitter
64 * \param rxPorts the number of vertical and horizontal ports of the antenna
65 * array of the receiver
66 */
68 uint32_t rxAntennaElements = 2,
69 uint32_t txPorts = 1,
70 uint32_t rxPorts = 1);
71
72 /**
73 * Destructor
74 */
76
77 private:
78 /**
79 * Build the test scenario
80 */
81 void DoRun() override;
82
83 /**
84 * Compute the Frobenius norm of the channel matrix and stores it in m_normVector
85 * \param channelModel the ThreeGppChannelModel object used to generate the channel matrix
86 * \param txMob the mobility model of the first node
87 * \param rxMob the mobility model of the second node
88 * \param txAntenna the antenna object associated to the first node
89 * \param rxAntenna the antenna object associated to the second node
90 */
94 Ptr<PhasedArrayModel> txAntenna,
95 Ptr<PhasedArrayModel> rxAntenna);
96
97 std::vector<double> m_normVector; //!< each element is the norm of a channel realization
98 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
99 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
100 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
101 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
102};
103
105 uint32_t txAntennaElements,
106 uint32_t rxAntennaElements,
107 uint32_t txPorts,
108 uint32_t rxPorts)
109 : TestCase("Check the dimensions and the norm of the channel matrix")
110{
111 m_txAntennaElements = txAntennaElements;
112 m_rxAntennaElements = rxAntennaElements;
113 m_txPorts = txPorts;
114 m_rxPorts = rxPorts;
115}
116
118{
119}
120
121void
123 Ptr<MobilityModel> txMob,
124 Ptr<MobilityModel> rxMob,
125 Ptr<PhasedArrayModel> txAntenna,
126 Ptr<PhasedArrayModel> rxAntenna)
127{
128 uint64_t txAntennaElements = txAntenna->GetNumElems();
129 uint64_t rxAntennaElements = rxAntenna->GetNumElems();
130
132 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
133
134 double channelNorm = 0;
135 uint16_t numTotalClusters = channelMatrix->m_channel.GetNumPages();
136 for (uint16_t cIndex = 0; cIndex < numTotalClusters; cIndex++)
137 {
138 double clusterNorm = 0;
139 for (uint64_t sIndex = 0; sIndex < txAntennaElements; sIndex++)
140 {
141 for (uint64_t uIndex = 0; uIndex < rxAntennaElements; uIndex++)
142 {
143 clusterNorm +=
144 std::pow(std::abs(channelMatrix->m_channel(uIndex, sIndex, cIndex)), 2);
145 }
146 }
147 channelNorm += clusterNorm;
148 }
149 m_normVector.push_back(channelNorm);
150}
151
152void
154{
157 // Build the scenario for the test
158 uint32_t updatePeriodMs = 100; // update period in ms
159
160 // create the channel condition model
161 Ptr<ChannelConditionModel> channelConditionModel =
162 CreateObject<NeverLosChannelConditionModel>();
163
164 // create the ThreeGppChannelModel object used to generate the channel matrix
165 Ptr<ThreeGppChannelModel> channelModel = CreateObject<ThreeGppChannelModel>();
166 channelModel->SetAttribute("Frequency", DoubleValue(60.0e9));
167 channelModel->SetAttribute("Scenario", StringValue("RMa"));
168 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
169 channelModel->SetAttribute("UpdatePeriod", TimeValue(MilliSeconds(updatePeriodMs - 1)));
170 channelModel->AssignStreams(1);
171
172 // create the tx and rx nodes
174 nodes.Create(2);
175
176 // create the tx and rx devices
177 Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
178 Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
179
180 // associate the nodes and the devices
181 nodes.Get(0)->AddDevice(txDev);
182 txDev->SetNode(nodes.Get(0));
183 nodes.Get(1)->AddDevice(rxDev);
184 rxDev->SetNode(nodes.Get(1));
185
186 // create the tx and rx mobility models and set their positions
187 Ptr<MobilityModel> txMob = CreateObject<ConstantPositionMobilityModel>();
188 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
189 Ptr<MobilityModel> rxMob = CreateObject<ConstantPositionMobilityModel>();
190 rxMob->SetPosition(Vector(100.0, 0.0, 10.0));
191
192 // associate the nodes and the mobility models
193 nodes.Get(0)->AggregateObject(txMob);
194 nodes.Get(1)->AggregateObject(rxMob);
195
196 // create the tx and rx antennas and set the their dimensions
197 Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
198 "NumColumns",
200 "NumRows",
202 "AntennaElement",
203 PointerValue(CreateObject<IsotropicAntennaModel>()),
204 "NumVerticalPorts",
206 "NumHorizontalPorts",
208
209 Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
210 "NumColumns",
212 "NumRows",
214 "AntennaElement",
215 PointerValue(CreateObject<IsotropicAntennaModel>()),
216 "NumVerticalPorts",
218 "NumHorizontalPorts",
220 // generate the channel matrix
222 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
223
224 // check the channel matrix dimensions, expected H[cluster][rx][tx]
226 channelMatrix->m_channel.GetNumCols(),
228 "The third dimension of H should be equal to the number of tx antenna elements");
230 channelMatrix->m_channel.GetNumRows(),
232 "The second dimension of H should be equal to the number of rx antenna elements");
233
234 // test if the channel matrix is correctly generated
235 uint16_t numIt = 1000;
236 for (uint16_t i = 0; i < numIt; i++)
237 {
238 Simulator::Schedule(MilliSeconds(updatePeriodMs * i),
240 this,
241 channelModel,
242 txMob,
243 rxMob,
244 txAntenna,
245 rxAntenna);
246 }
247
249
250 // compute the sample mean
251 double sampleMean = 0;
252 for (auto i : m_normVector)
253 {
254 sampleMean += i;
255 }
256 sampleMean /= numIt;
257
258 // compute the sample standard deviation
259 double sampleStd = 0;
260 for (auto i : m_normVector)
261 {
262 sampleStd += ((i - sampleMean) * (i - sampleMean));
263 }
264 sampleStd = std::sqrt(sampleStd / (numIt - 1));
265
266 // perform the one sample t-test with a significance level of 0.05 to test
267 // the hypothesis "E [|H|^2] = M*N, where |H| indicates the Frobenius norm of
268 // H, M is the number of transmit antenna elements, and N is the number of
269 // the receive antenna elements"
270 double t = (sampleMean - m_txAntennaElements * m_txAntennaElements * m_rxAntennaElements *
272 (sampleStd / std::sqrt(numIt));
273
274 // Using a significance level of 0.05, we reject the null hypothesis if |t| is
275 // greater than the critical value from a t-distribution with df = numIt-1
277 std::abs(t),
278 0,
279 1.65,
280 "We reject the hypothesis E[|H|^2] = M*N with a significance level of 0.05");
281
283}
284
285/**
286 * \ingroup spectrum-tests
287 *
288 * Test case for the ThreeGppChannelModel class.
289 * It checks if the channel realizations are correctly updated during the
290 * simulation.
291 */
293{
294 public:
295 /**
296 *Constructor
297 * \param txAntennaElements the number of rows and columns of the antenna array of the
298 * transmitter
299 * \param rxAntennaElements the number of rows and columns of the antenna array of
300 * \param txPorts the number of vertical and horizontal ports of the antenna array
301 * of the transmitter
302 * \param rxPorts the number of vertical and horizontal ports of the antenna
303 * array of the receiver
304 */
305 ThreeGppChannelMatrixUpdateTest(uint32_t txAntennaElements = 2,
306 uint32_t rxAntennaElements = 4,
307 uint32_t txPorts = 1,
308 uint32_t rxPorts = 1);
309
310 /**
311 * Destructor
312 */
314
315 private:
316 /**
317 * Build the test scenario
318 */
319 void DoRun() override;
320
321 /**
322 * This method is used to schedule the channel matrix computation at different
323 * time instants and to check if it correctly updated
324 * \param channelModel the ThreeGppChannelModel object used to generate the channel matrix
325 * \param txMob the mobility model of the first node
326 * \param rxMob the mobility model of the second node
327 * \param txAntenna the antenna object associated to the first node
328 * \param rxAntenna the antenna object associated to the second node
329 * \param update whether if the channel matrix should be updated or not
330 */
331 void DoGetChannel(Ptr<ThreeGppChannelModel> channelModel,
332 Ptr<MobilityModel> txMob,
333 Ptr<MobilityModel> rxMob,
334 Ptr<PhasedArrayModel> txAntenna,
335 Ptr<PhasedArrayModel> rxAntenna,
336 bool update);
337
339 m_currentChannel; //!< used by DoGetChannel to store the current channel matrix
340 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
341 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
342 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
343 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
344};
345
347 uint32_t rxAntennaElements,
348 uint32_t txPorts,
349 uint32_t rxPorts)
350 : TestCase("Check if the channel realizations are correctly updated during the simulation")
351{
352 m_txAntennaElements = txAntennaElements;
353 m_rxAntennaElements = rxAntennaElements;
354 m_txPorts = txPorts;
355 m_rxPorts = rxPorts;
356}
357
359{
360}
361
362void
364 Ptr<MobilityModel> txMob,
365 Ptr<MobilityModel> rxMob,
366 Ptr<PhasedArrayModel> txAntenna,
367 Ptr<PhasedArrayModel> rxAntenna,
368 bool update)
369{
370 // retrieve the channel matrix
372 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
373
374 if (!m_currentChannel)
375 {
376 // this is the first time we compute the channel matrix, we initialize
377 // m_currentChannel
378 m_currentChannel = channelMatrix;
379 }
380 else
381 {
382 // compare the old and the new channel matrices
383 NS_TEST_ASSERT_MSG_EQ((m_currentChannel->m_channel != channelMatrix->m_channel),
384 update,
386 << " The channel matrix is not correctly updated");
387 }
388}
389
390void
392{
393 // Build the scenario for the test
394 uint32_t updatePeriodMs = 100; // update period in ms
395
396 // create the channel condition model
397 Ptr<ChannelConditionModel> channelConditionModel =
398 CreateObject<AlwaysLosChannelConditionModel>();
399
400 // create the ThreeGppChannelModel object used to generate the channel matrix
401 Ptr<ThreeGppChannelModel> channelModel = CreateObject<ThreeGppChannelModel>();
402 channelModel->SetAttribute("Frequency", DoubleValue(60.0e9));
403 channelModel->SetAttribute("Scenario", StringValue("UMa"));
404 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
405 channelModel->SetAttribute("UpdatePeriod", TimeValue(MilliSeconds(updatePeriodMs)));
406
407 // create the tx and rx nodes
409 nodes.Create(2);
410
411 // create the tx and rx devices
412 Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
413 Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
414
415 // associate the nodes and the devices
416 nodes.Get(0)->AddDevice(txDev);
417 txDev->SetNode(nodes.Get(0));
418 nodes.Get(1)->AddDevice(rxDev);
419 rxDev->SetNode(nodes.Get(1));
420
421 // create the tx and rx mobility models and set their positions
422 Ptr<MobilityModel> txMob = CreateObject<ConstantPositionMobilityModel>();
423 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
424 Ptr<MobilityModel> rxMob = CreateObject<ConstantPositionMobilityModel>();
425 rxMob->SetPosition(Vector(100.0, 0.0, 1.6));
426
427 // associate the nodes and the mobility models
428 nodes.Get(0)->AggregateObject(txMob);
429 nodes.Get(1)->AggregateObject(rxMob);
430
431 // create the tx and rx antennas and set the their dimensions
432 Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
433 "NumColumns",
435 "NumRows",
437 "AntennaElement",
438 PointerValue(CreateObject<IsotropicAntennaModel>()),
439 "NumVerticalPorts",
441 "NumHorizontalPorts",
443
444 Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
445 "NumColumns",
447 "NumRows",
449 "AntennaElement",
450 PointerValue(CreateObject<IsotropicAntennaModel>()),
451 "NumVerticalPorts",
453 "NumHorizontalPorts",
455
456 // check if the channel matrix is correctly updated
457
458 // compute the channel matrix for the first time
459 uint32_t firstTimeMs =
460 1; // time instant at which the channel matrix is generated for the first time
463 this,
464 channelModel,
465 txMob,
466 rxMob,
467 txAntenna,
468 rxAntenna,
469 true);
470
471 // call GetChannel before the update period is exceeded, the channel matrix
472 // should not be updated
473 Simulator::Schedule(MilliSeconds(firstTimeMs + updatePeriodMs / 2),
475 this,
476 channelModel,
477 txMob,
478 rxMob,
479 txAntenna,
480 rxAntenna,
481 false);
482
483 // call GetChannel when the update period is exceeded, the channel matrix
484 // should be recomputed
485 Simulator::Schedule(MilliSeconds(firstTimeMs + updatePeriodMs + 1),
487 this,
488 channelModel,
489 txMob,
490 rxMob,
491 txAntenna,
492 rxAntenna,
493 true);
494
497}
498
499/**
500 * \ingroup spectrum-tests
501 * \brief A structure that holds the parameters for the function
502 * CheckLongTermUpdate. In this way the problem with the limited
503 * number of parameters of method Schedule is avoided.
504 */
506{
508 lossModel; //!< the ThreeGppSpectrumPropagationLossModel object used to compute the rx PSD
509 Ptr<SpectrumSignalParameters> txParams; //!< the params of the tx signal
510 Ptr<MobilityModel> txMob; //!< the mobility model of the tx device
511 Ptr<MobilityModel> rxMob; //!< the mobility model of the rx device
512 Ptr<SpectrumValue> rxPsdOld; //!< the previously received PSD
513 Ptr<PhasedArrayModel> txAntenna; //!< the antenna array of the tx device
514 Ptr<PhasedArrayModel> rxAntenna; //!< the antenna array of the rx device
515};
516
517/**
518 * \ingroup spectrum-tests
519 *
520 * Test case for the ThreeGppSpectrumPropagationLossModelTest class.
521 * 1) checks if the long term components for the direct and the reverse link
522 * are the same
523 * 2) checks if the long term component is updated when changing the beamforming
524 * vectors
525 * 3) checks if the long term is updated when changing the channel matrix
526 */
528{
529 public:
530 /**
531 * Constructor
532 * \param txAntennaElements the number of rows and columns of the antenna array of the
533 * transmitter
534 * \param rxAntennaElements the number of rows and columns of the antenna array of
535 * the receiver
536 * \param txPorts the number of vertical and horizontal ports of the antenna array
537 * of the transmitter
538 * \param rxPorts the number of vertical and horizontal ports of the antenna
539 * array of the receiver
540 */
542 uint32_t rxAntennaElements = 4,
543 uint32_t txPorts = 1,
544 uint32_t rxPorts = 1);
545 /**
546 * Destructor
547 */
549
550 private:
551 /**
552 * Build the test scenario
553 */
554 void DoRun() override;
555
556 /**
557 * Points the beam of thisDevice towards otherDevice
558 * \param thisDevice the device to configure
559 * \param thisAntenna the antenna object associated to thisDevice
560 * \param otherDevice the device to communicate with
561 * \param otherAntenna the antenna object associated to otherDevice
562 */
563 void DoBeamforming(Ptr<NetDevice> thisDevice,
564 Ptr<PhasedArrayModel> thisAntenna,
565 Ptr<NetDevice> otherDevice,
566 Ptr<PhasedArrayModel> otherAntenna);
567
568 /**
569 * Test of the long term component is correctly updated when the channel
570 * matrix is recomputed
571 * \param params a structure that contains the set of parameters needed by CheckLongTermUpdate
572 * in order to perform calculations
573 */
575
576 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
577 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
578 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
579 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
580};
581
583 uint32_t txAntennaElements,
584 uint32_t rxAntennaElements,
585 uint32_t txPorts,
586 uint32_t rxPorts)
587 : TestCase("Test case for the ThreeGppSpectrumPropagationLossModel class")
588{
589 m_txAntennaElements = txAntennaElements;
590 m_rxAntennaElements = rxAntennaElements;
591 m_txPorts = txPorts;
592 m_rxPorts = rxPorts;
593}
594
596{
597}
598
599void
601 Ptr<PhasedArrayModel> thisAntenna,
602 Ptr<NetDevice> otherDevice,
603 Ptr<PhasedArrayModel> otherAntenna)
604{
605 Vector aPos = thisDevice->GetNode()->GetObject<MobilityModel>()->GetPosition();
606 Vector bPos = otherDevice->GetNode()->GetObject<MobilityModel>()->GetPosition();
607
608 // compute the azimuth and the elevation angles
609 Angles completeAngle(bPos, aPos);
610
611 PhasedArrayModel::ComplexVector antennaWeights =
612 thisAntenna->GetBeamformingVector(completeAngle);
613 thisAntenna->SetBeamformingVector(antennaWeights);
614}
615
616void
618 const CheckLongTermUpdateParams& params)
619{
620 auto rxPsdNewParams = params.lossModel->DoCalcRxPowerSpectralDensity(params.txParams,
621 params.txMob,
622 params.rxMob,
623 params.txAntenna,
624 params.rxAntenna);
625 NS_TEST_ASSERT_MSG_EQ((*params.rxPsdOld == *rxPsdNewParams->psd),
626 false,
627 "The long term is not updated when the channel matrix is recomputed");
628}
629
630void
632{
633 // Build the scenario for the test
634 Config::SetDefault("ns3::ThreeGppChannelModel::UpdatePeriod", TimeValue(MilliSeconds(100)));
635
636 // create the ChannelConditionModel object to be used to retrieve the
637 // channel condition
638 Ptr<ChannelConditionModel> condModel = CreateObject<AlwaysLosChannelConditionModel>();
639
640 // create the ThreeGppSpectrumPropagationLossModel object, set frequency,
641 // scenario and channel condition model to be used
643 CreateObject<ThreeGppSpectrumPropagationLossModel>();
644 lossModel->SetChannelModelAttribute("Frequency", DoubleValue(2.4e9));
645 lossModel->SetChannelModelAttribute("Scenario", StringValue("UMa"));
646 lossModel->SetChannelModelAttribute(
647 "ChannelConditionModel",
648 PointerValue(condModel)); // create the ThreeGppChannelModel object used to generate the
649 // channel matrix
650
651 // create the tx and rx nodes
653 nodes.Create(2);
654
655 // create the tx and rx devices
656 Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
657 Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
658
659 // associate the nodes and the devices
660 nodes.Get(0)->AddDevice(txDev);
661 txDev->SetNode(nodes.Get(0));
662 nodes.Get(1)->AddDevice(rxDev);
663 rxDev->SetNode(nodes.Get(1));
664
665 // create the tx and rx mobility models and set their positions
666 Ptr<MobilityModel> txMob = CreateObject<ConstantPositionMobilityModel>();
667 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
668 Ptr<MobilityModel> rxMob = CreateObject<ConstantPositionMobilityModel>();
669 rxMob->SetPosition(
670 Vector(15.0, 0.0, 10.0)); // in this position the channel condition is always LOS
671
672 // associate the nodes and the mobility models
673 nodes.Get(0)->AggregateObject(txMob);
674 nodes.Get(1)->AggregateObject(rxMob);
675
676 // create the tx and rx antennas and set the their dimensions
677 Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
678 "NumColumns",
680 "NumRows",
682 "AntennaElement",
683 PointerValue(CreateObject<IsotropicAntennaModel>()),
684 "NumVerticalPorts",
686 "NumHorizontalPorts",
688
689 Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
690 "NumColumns",
692 "NumRows",
694 "AntennaElement",
695 PointerValue(CreateObject<IsotropicAntennaModel>()),
696 "NumVerticalPorts",
698 "NumHorizontalPorts",
700
701 // set the beamforming vectors
702 DoBeamforming(txDev, txAntenna, rxDev, rxAntenna);
703 DoBeamforming(rxDev, rxAntenna, txDev, txAntenna);
704
705 // create the tx psd
707 double txPower = 0.1; // Watts
708 uint32_t channelNumber = 1;
709 Ptr<SpectrumValue> txPsd = sf.CreateTxPowerSpectralDensity(txPower, channelNumber);
710 Ptr<SpectrumSignalParameters> txParams = Create<SpectrumSignalParameters>();
711 txParams->psd = txPsd->Copy();
712
713 // compute the rx psd
714 auto rxParamsOld =
715 lossModel->DoCalcRxPowerSpectralDensity(txParams, txMob, rxMob, txAntenna, rxAntenna);
716
717 // 1) check that the rx PSD is equal for both the direct and the reverse channel
718 auto rxParamsNew =
719 lossModel->DoCalcRxPowerSpectralDensity(txParams, rxMob, txMob, rxAntenna, txAntenna);
720 NS_TEST_ASSERT_MSG_EQ((*rxParamsOld->psd == *rxParamsNew->psd),
721 true,
722 "The long term for the direct and the reverse channel are different");
723
724 // 2) check if the long term is updated when changing the BF vector
725 // change the position of the rx device and recompute the beamforming vectors
726 rxMob->SetPosition(Vector(10.0, 5.0, 10.0));
727 PhasedArrayModel::ComplexVector txBfVector = txAntenna->GetBeamformingVector();
728 txBfVector[0] = std::complex<double>(0.0, 0.0);
729 txAntenna->SetBeamformingVector(txBfVector);
730
731 rxParamsNew =
732 lossModel->DoCalcRxPowerSpectralDensity(txParams, rxMob, txMob, rxAntenna, txAntenna);
733 NS_TEST_ASSERT_MSG_EQ((*rxParamsOld->psd == *rxParamsNew->psd),
734 false,
735 "Changing the BF vectors the rx PSD does not change");
736
738 (*rxParamsOld->spectrumChannelMatrix == *rxParamsNew->spectrumChannelMatrix),
739 false,
740 "Changing the BF should change de frequency domain channel matrix");
741
742 // update rxPsdOld
743 rxParamsOld = rxParamsNew;
744
745 // 3) check if the long term is updated when the channel matrix is recomputed
747 params{lossModel, txParams, txMob, rxMob, rxParamsOld->psd, txAntenna, rxAntenna};
750 this,
751 params);
752
755}
756
757/**
758 * \ingroup spectrum-tests
759 *
760 * Test case that test the correct use of the multi-port antennas in spectrum.
761 * The test does the following:
762 * 1) Generates a time domain channel matrix of a fixed size
763 * (num gNB elements = 32 (4x8), num UE elements = 16 (4x4), num Clusters).
764 * This matrix is called channelMatrixM0.
765 * 2) Divides gNB antenna and UE antenna into ports using a fixed element to port
766 * mapping (gNB: 1 vertical port, 4 horizontal ports, UE: 1 vertical port,
767 * 2 horizontal ports). Using the channelMatrixM0, it generates port to port
768 * long term channel matrix using the both gNB and UE having beams directed towards the other.
769 * The resulting long term matrix dimensions are gNBports = 4, UE ports = 2, num Clusters.
770 * This channel matrix is called matrixA.
771 * 3) Constructs a single port to single port long term channel matrix
772 * using the initial time domain channel matrix (channelMatrixM0) and beams
773 * from gNB and UE towards each other. Single port mapping means gNB: 1 vertical port,
774 * 1 horizontal port, UE: 1 vertical port, 1 horizontal port.
775 * Matrix dimensions are: gNBports = 1, UE ports = 1, num Clusters. This long
776 * term channel matrix is called matrixB.
777 * 4) Creates a single port to single port long term channel matrix between
778 * two virtual gNB and UE antenna by using matrixA and beam facing each other.
779 * Matrix dimension of the resulting matrix are gNBports = 1, UE ports = 1, num Clusters.
780 * This long term channel matrix is called matrixC.
781 * 5) Checks that matrixB and matrixC are identical.
782 */
784{
785 public:
786 /**
787 * Constructor
788 */
790
791 /**
792 * Destructor
793 */
795
796 private:
797 /**
798 * Build the test scenario
799 */
800 void DoRun() override;
801};
802
804 : TestCase("Check long term channel matrix generation when multiple ports at TX and RX are "
805 "being used.")
806{
807}
808
810{
811}
812
813void
815{
816 // create the channel condition model
817 Ptr<ChannelConditionModel> channelConditionModel =
818 CreateObject<AlwaysLosChannelConditionModel>();
819
820 // create the ThreeGppChannelModel object used to generate the channel matrix
821 Ptr<ThreeGppChannelModel> channelModel = CreateObject<ThreeGppChannelModel>();
822 channelModel->SetAttribute("Frequency", DoubleValue(2.0e9));
823 channelModel->SetAttribute("Scenario", StringValue("RMa"));
824 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
825
826 // create the tx and rx nodes
828 nodes.Create(2);
829
830 // create the tx and rx devices
831 Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
832 Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
833
834 // associate the nodes and the devices
835 nodes.Get(0)->AddDevice(txDev);
836 txDev->SetNode(nodes.Get(0));
837 nodes.Get(1)->AddDevice(rxDev);
838 rxDev->SetNode(nodes.Get(1));
839
840 // create the tx and rx mobility models and set their positions
841 Ptr<MobilityModel> txMob = CreateObject<ConstantPositionMobilityModel>();
842 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
843 Ptr<MobilityModel> rxMob = CreateObject<ConstantPositionMobilityModel>();
844 rxMob->SetPosition(Vector(10.0, 0.0, 10.0));
845
846 // associate the nodes and the mobility models
847 nodes.Get(0)->AggregateObject(txMob);
848 nodes.Get(1)->AggregateObject(rxMob);
849
850 // create the tx and rx antennas and set the their dimensions
851 Ptr<PhasedArrayModel> txAntenna1 = CreateObjectWithAttributes<UniformPlanarArray>(
852 "NumColumns",
853 UintegerValue(8),
854 "NumRows",
855 UintegerValue(4),
856 "AntennaElement",
857 PointerValue(CreateObject<IsotropicAntennaModel>()),
858 "NumVerticalPorts",
859 UintegerValue(1),
860 "NumHorizontalPorts",
861 UintegerValue(4));
862
863 Ptr<PhasedArrayModel> rxAntenna1 = CreateObjectWithAttributes<UniformPlanarArray>(
864 "NumColumns",
865 UintegerValue(4),
866 "NumRows",
867 UintegerValue(4),
868 "AntennaElement",
869 PointerValue(CreateObject<IsotropicAntennaModel>()),
870 "NumVerticalPorts",
871 UintegerValue(1),
872 "NumHorizontalPorts",
873 UintegerValue(2));
874
875 // compute the azimuth and the elevation angles
876 Angles completeAngleTxRx(rxMob->GetPosition(), txMob->GetPosition());
877 Angles completeAngleRxTx(txMob->GetPosition(), rxMob->GetPosition());
878
879 txAntenna1->SetBeamformingVector(txAntenna1->GetBeamformingVector(completeAngleTxRx));
880 rxAntenna1->SetBeamformingVector(rxAntenna1->GetBeamformingVector(completeAngleRxTx));
881
882 // generate the channel matrix
884 channelModel->GetChannel(txMob, rxMob, txAntenna1, rxAntenna1);
885
886 // create ThreeGppSpectrumPropagationLossModel instance so that we
887 // can call CalcLongTerm
889 CreateObject<ThreeGppSpectrumPropagationLossModel>();
890
892 threeGppSplm->CalcLongTerm(channelMatrixM0, txAntenna1, rxAntenna1);
893
894 // create the tx and rx antennas and set the their dimensions
895 Ptr<PhasedArrayModel> txAntenna2 = CreateObjectWithAttributes<UniformPlanarArray>(
896 "NumColumns",
897 UintegerValue(8),
898 "NumRows",
899 UintegerValue(4),
900 "AntennaElement",
901 PointerValue(CreateObject<IsotropicAntennaModel>()),
902 "NumVerticalPorts",
903 UintegerValue(1),
904 "NumHorizontalPorts",
905 UintegerValue(1));
906
907 Ptr<PhasedArrayModel> rxAntenna2 = CreateObjectWithAttributes<UniformPlanarArray>(
908 "NumColumns",
909 UintegerValue(4),
910 "NumRows",
911 UintegerValue(4),
912 "AntennaElement",
913 PointerValue(CreateObject<IsotropicAntennaModel>()),
914 "NumVerticalPorts",
915 UintegerValue(1),
916 "NumHorizontalPorts",
917 UintegerValue(1));
918
919 txAntenna2->SetBeamformingVector(txAntenna2->GetBeamformingVector(completeAngleTxRx));
920 rxAntenna2->SetBeamformingVector(rxAntenna2->GetBeamformingVector(completeAngleRxTx));
921
923 threeGppSplm->CalcLongTerm(channelMatrixM0, txAntenna2, rxAntenna2);
924
925 // create the tx and rx antennas and set the their dimensions
926 Ptr<PhasedArrayModel> txAntenna3 = CreateObjectWithAttributes<UniformPlanarArray>(
927 "NumColumns",
928 UintegerValue(4),
929 "NumRows",
930 UintegerValue(1),
931 "AntennaElement",
932 PointerValue(CreateObject<IsotropicAntennaModel>()),
933 "NumVerticalPorts",
934 UintegerValue(1),
935 "NumHorizontalPorts",
936 UintegerValue(1),
937 "AntennaHorizontalSpacing",
938 DoubleValue(1));
939
940 Ptr<PhasedArrayModel> rxAntenna3 = CreateObjectWithAttributes<UniformPlanarArray>(
941 "NumColumns",
942 UintegerValue(2),
943 "NumRows",
944 UintegerValue(1),
945 "AntennaElement",
946 PointerValue(CreateObject<IsotropicAntennaModel>()),
947 "NumVerticalPorts",
948 UintegerValue(1),
949 "NumHorizontalPorts",
950 UintegerValue(1),
951 "AntennaHorizontalSpacing",
952 DoubleValue(1));
953
955 Create<ThreeGppChannelModel::ChannelMatrix>();
956 channelMatrixMA->m_channel = *matrixA;
957
958 txAntenna3->SetBeamformingVector(txAntenna3->GetBeamformingVector(completeAngleTxRx));
959 rxAntenna3->SetBeamformingVector(rxAntenna3->GetBeamformingVector(completeAngleRxTx));
960
962 threeGppSplm->CalcLongTerm(channelMatrixMA, txAntenna3, rxAntenna3);
963
964 NS_TEST_ASSERT_MSG_EQ(matrixB->IsAlmostEqual(*matrixC, 1e-6),
965 true,
966 "Matrix B and Matrix C should be equal.");
967
970}
971
972/**
973 * Structure that contains some of the main configuration parameters of the antenna
974 * array that are used in the ThreeGppMimoPolarizationTest
975 */
977{
978 uint32_t m_rows = 1; //!< the number of rows of antenna array
979 uint32_t m_cols = 2; //!< the number of columns of antenna array
980 uint32_t m_vPorts = 1; //!< the number of vertical ports of antenna array
981 uint32_t m_hPorts = 2; //!< the number of horizontal ports of antenna array
982 bool m_isotropic = false; //!< defines whether the antenna elements are isotropic
983 double m_polSlantAngle = 0; //!< polarization angle of the antenna array
984 double m_bearingAngle = 0; //!< bearing angle of the antenna array
985
986 /**
987 * Constructor
988 * Currently only configurable through constructor are polSlantAngle and bearingAngle.
989 * \param isotropic whether the antenna elements are isotropic, or 3GPP
990 * \param polSlantAngle the polarization slant angle
991 * \param bearingAngle the bearing angle
992 */
993 MimoPolarizationAntennaParams(bool isotropic, double polSlantAngle = 0, double bearingAngle = 0)
994 : m_isotropic(isotropic),
995 m_polSlantAngle(polSlantAngle),
996 m_bearingAngle(bearingAngle)
997 {
998 }
999};
1000
1001/**
1002 * \ingroup spectrum-tests
1003 * This test tests that the channel matrix is correctly generated when dual-polarized
1004 * antennas are being used at TX and RX. In the conditions in which the channel between
1005 * the TX and Rx device is LOS channel, and the beams of the transmitter and the
1006 * receiver are pointing one towards the other, then in the presence of multiple ports
1007 * at the TX and RX, and the antenna array at the TX and RX are dual polarized,
1008 * the channel matrix should exhibit the strong symmetry between the two polarizations.
1009 * E.g. if we have 1x2 antenna elements and two polarizations at both TX and RX,
1010 * and the 1x2 ports at the TX and RX, then the channel matrix will have the
1011 * structure as:
1012 *
1013 * ch00 ch01 |ch02 ch03
1014 * Hvv Hvh ch10 ch11 |ch12 ch13
1015 * = --------------------
1016 * Hhv Hhh ch20 ch21 |ch22 ch23
1017 * ch30 ch31 |ch32 ch33
1018 *
1019 * We test different cases of the polarization slant angles of the TX and RX,
1020 * e.g., 0, 30, 45, 90.
1021 * In each of these setups we check if the channel matrix in its strongest
1022 * cluster experiences strong symmetry, and if the values appear in pairs.
1023 * We also test additional cases in which we change the bearing angle and
1024 * the height of the TX. In these cases we also observe strong symmetry, with
1025 * the difference that in these cases we can observe different values in the
1026 * pairs. We can still observe strong impact of the dual polarization on the
1027 * channel matrix.
1028 */
1030{
1031 public:
1032 /**
1033 * Constructor that receives MIMO polarization parameters of TX and RX
1034 * devices
1035 * \param testCaseName the test case name
1036 * \param txLoc the position of the transmitter
1037 * \param txAntennaParams the antenna parameters of the transmitter
1038 * \param rxLoc the position of the receiver
1039 * \param rxAntennaParams the antenna parameters of the receiver
1040 * \param testChannel the test matrix that represent the strongest cluster
1041 * \param tolerance the tolerance to be used when testing
1042 */
1043 ThreeGppMimoPolarizationTest(std::string testCaseName,
1044 Vector txLoc,
1045 const MimoPolarizationAntennaParams& txAntennaParams,
1046 Vector rxLoc,
1047 const MimoPolarizationAntennaParams& rxAntennaParams,
1048 std::valarray<std::complex<double>> testChannel,
1049 double tolerance);
1050
1051 /**
1052 * Destructor
1053 */
1055
1056 private:
1057 /**
1058 * Build the test scenario
1059 */
1060 void DoRun() override;
1061
1062 /**
1063 * @brief Function that can be used to configure the antenna using the set of
1064 * parameters.
1065 *
1066 * @param params The parameters to be set to the antenna
1067 * @return A pointer to the antenna that is created and configured by using input params
1068 */
1070
1071 Vector m_txLoc; //!< Position of the TX device
1072 MimoPolarizationAntennaParams m_txParams; //!< Parameters used to configure the TX antenna array
1073 Vector m_rxLoc; //!< Position of the RX device
1074 MimoPolarizationAntennaParams m_rxParams; //!< Parameters used to configure the RX antenna array
1075 std::valarray<std::complex<double>>
1076 m_testChannel; //!< The test value for the matrix representing the strongest cluster
1077 double m_tolerance; //!< The tolerance to be used when comparing the channel matrix with the
1078 //!< test matrix
1079};
1080
1082 std::string testCaseName,
1083 Vector txLoc,
1084 const MimoPolarizationAntennaParams& txParams,
1085 Vector rxLoc,
1086 const MimoPolarizationAntennaParams& rxParams,
1087 std::valarray<std::complex<double>> testChannel,
1088 double tolerance)
1089 : TestCase("Test MIMO using dual polarization." + testCaseName),
1090 m_txLoc(txLoc),
1091 m_txParams(txParams),
1092 m_rxLoc(rxLoc),
1093 m_rxParams(rxParams),
1094 m_testChannel(testChannel),
1095 m_tolerance(tolerance)
1096{
1097}
1098
1100{
1101}
1102
1105{
1106 NS_LOG_FUNCTION(this);
1107 Ptr<AntennaModel> antenna;
1108 if (params.m_isotropic)
1109 {
1110 antenna = CreateObject<IsotropicAntennaModel>();
1111 }
1112 else
1113 {
1114 antenna = CreateObject<ThreeGppAntennaModel>();
1115 }
1116 // create the tx and rx antennas and set the their dimensions
1117 return CreateObjectWithAttributes<UniformPlanarArray>("NumColumns",
1118 UintegerValue(params.m_cols),
1119 "NumRows",
1120 UintegerValue(params.m_rows),
1121 "AntennaElement",
1122 PointerValue(antenna),
1123 "NumVerticalPorts",
1124 UintegerValue(params.m_vPorts),
1125 "NumHorizontalPorts",
1126 UintegerValue(params.m_hPorts),
1127 "BearingAngle",
1128 DoubleValue(params.m_bearingAngle),
1129 "PolSlantAngle",
1130 DoubleValue(params.m_polSlantAngle),
1131 "IsDualPolarized",
1132 BooleanValue(true));
1133}
1134
1135void
1137{
1140 // create the ThreeGppChannelModel object used to generate the channel matrix
1141 Ptr<ThreeGppChannelModel> channelModel = CreateObject<ThreeGppChannelModel>();
1142 channelModel->SetAttribute("Frequency", DoubleValue(60e9));
1143 channelModel->SetAttribute("Scenario", StringValue("RMa"));
1144 channelModel->SetAttribute("ChannelConditionModel",
1145 PointerValue(CreateObject<AlwaysLosChannelConditionModel>()));
1146
1147 int64_t randomStream = 1;
1148 randomStream += channelModel->AssignStreams(randomStream);
1149
1150 // create the tx and rx nodes
1152 nodes.Create(2);
1153
1154 // create the tx and rx devices
1155 Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
1156 Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
1157
1158 // associate the nodes and the devices
1159 nodes.Get(0)->AddDevice(txDev);
1160 txDev->SetNode(nodes.Get(0));
1161 nodes.Get(1)->AddDevice(rxDev);
1162 rxDev->SetNode(nodes.Get(1));
1163
1164 // create the tx and rx mobility models and set their positions
1165 Ptr<MobilityModel> txMob = CreateObject<ConstantPositionMobilityModel>();
1166 txMob->SetPosition(m_txLoc);
1167 Ptr<MobilityModel> rxMob = CreateObject<ConstantPositionMobilityModel>();
1168 rxMob->SetPosition(m_rxLoc);
1169
1170 // associate the nodes and the mobility models
1171 nodes.Get(0)->AggregateObject(txMob);
1172 nodes.Get(1)->AggregateObject(rxMob);
1173
1174 // create the tx and rx antennas and set the their dimensions
1177
1178 // configure direct beamforming vectors to point to each other
1179 txAntenna->SetBeamformingVector(
1180 txAntenna->GetBeamformingVector(Angles(rxMob->GetPosition(), txMob->GetPosition())));
1181 rxAntenna->SetBeamformingVector(
1182 rxAntenna->GetBeamformingVector(Angles(txMob->GetPosition(), rxMob->GetPosition())));
1183
1184 // generate the time domain channel matrix
1186 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
1187
1188 // test whether the channel matrix for the first cluster experiences strong
1189 // symmetry that is caused by existence of dual polarized ports at the
1190 // transmitter and the receiver
1191 const std::complex<double>* strongestClusterPtr = channelMatrix->m_channel.GetPagePtr(0);
1192 size_t matrixSize =
1193 channelMatrix->m_channel.GetNumRows() * channelMatrix->m_channel.GetNumCols();
1194
1196 channelMatrix->m_channel.GetNumRows(),
1197 channelMatrix->m_channel.GetNumCols(),
1198 std::valarray<std::complex<double>>(strongestClusterPtr, matrixSize));
1199
1200 MatrixBasedChannelModel::Complex2DVector testChannel(channelMatrix->m_channel.GetNumRows(),
1201 channelMatrix->m_channel.GetNumCols(),
1203
1204 NS_LOG_INFO("Channel matrix:" << strongestCluster);
1205 NS_LOG_INFO("Test channel matrix: " << testChannel);
1206
1208 strongestCluster.IsAlmostEqual(testChannel, m_tolerance),
1209 true,
1210 "The strongest cluster and the test channel matrix should be almost equal");
1211
1214}
1215
1216/**
1217 * \ingroup spectrum-tests
1218 *
1219 * Test suite for the ThreeGppChannelModel class
1220 */
1222{
1223 public:
1224 /**
1225 * Constructor
1226 */
1228};
1229
1231 : TestSuite("three-gpp-channel", Type::UNIT)
1232{
1233 AddTestCase(new ThreeGppChannelMatrixComputationTest(2, 2, 1, 1), TestCase::Duration::QUICK);
1234 AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 2, 1, 1), TestCase::Duration::QUICK);
1235 AddTestCase(new ThreeGppChannelMatrixComputationTest(2, 2, 2, 2), TestCase::Duration::QUICK);
1236 AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 4, 2, 2), TestCase::Duration::QUICK);
1237 AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 2, 2, 1), TestCase::Duration::QUICK);
1238 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 4, 1, 1), TestCase::Duration::QUICK);
1239 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 1, 1), TestCase::Duration::QUICK);
1240 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 4, 2, 2), TestCase::Duration::QUICK);
1241 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 2, 2), TestCase::Duration::QUICK);
1243 TestCase::Duration::QUICK);
1245 TestCase::Duration::QUICK);
1247 TestCase::Duration::QUICK);
1249 TestCase::Duration::QUICK);
1250 AddTestCase(new ThreeGppCalcLongTermMultiPortTest(), TestCase::Duration::QUICK);
1251
1252 /**
1253 * The TX and RX antennas are configured face-to-face.
1254 * When polarization slant angles are 0 and 0 at TX and RX,
1255 * we expect the strongest cluster to be similar to the following matrix:
1256 * (5.9,0) (5.9,0) (0,0) (0,0)
1257 * (5.9,0) (5.9,0) (0,0) (0,0)
1258 * (0,0) (0,0) (-5.8,) (-5.8,0)
1259 * (0,0) (0,0) (-5.8,0) (-5.8,0)
1260 */
1261 std::valarray<std::complex<double>> testChannel1 =
1262 {5.9, 5.9, 0, 0, 5.9, 5.9, 0, 0, 0, 0, -5.8, -5.8, 0, 0, -5.8, -5.8};
1263 AddTestCase(new ThreeGppMimoPolarizationTest("Face-to-face. 0 and 0 pol. slant angles.",
1264 Vector{0, 0, 3},
1265 MimoPolarizationAntennaParams(false, 0, 0),
1266 Vector{9, 0, 3},
1267 MimoPolarizationAntennaParams(false, 0, M_PI),
1268 testChannel1,
1269 0.9),
1270 TestCase::Duration::QUICK);
1271
1272 /**
1273 * The TX and RX antennas are configured face-to-face.
1274 * When polarization slant angles are 30 and 0 at TX and RX,
1275 * we expect the strongest cluster to be similar to the following matrix:
1276 * (5,0) (5,0) (3,0) (3,0)
1277 * (5,0) (5,0) (3,0) (3,0)
1278 * (3,0) (3,0) (-5,0) (-5,0)
1279 * (3,0) (3,0) (-5,0) (-5,0)
1280 */
1282 new ThreeGppMimoPolarizationTest("Face-to-face. 30 and 0 pol. slant angles.",
1283 Vector{0, 0, 3},
1284 MimoPolarizationAntennaParams(false, M_PI / 6, 0),
1285 Vector{6, 0, 3},
1286 MimoPolarizationAntennaParams(false, 0, M_PI),
1287 {5, 5, 3, 3, 5, 5, 3, 3, 3, 3, -5, -5, 3, 3, -5, -5},
1288 0.8),
1289 TestCase::Duration::QUICK);
1290
1291 /**
1292 * The TX and RX antennas are configured face-to-face.
1293 * When polarization slant angles are 45 and 0 at TX and RX,
1294 * we expect the strongest cluster to be similar to the following matrix:
1295 * (4,0) (4,0) (4,0) (4,0)
1296 * (4,0) (4,0) (4,0) (4,0)
1297 * (4,0) (4,0) (4,0) (4,0)
1298 * (4,0) (4,0) (4,0) (4,0)
1299 */
1301 new ThreeGppMimoPolarizationTest("Face-to-face. 45 and 0 pol. slant angles.",
1302 Vector{0, 0, 3},
1303 MimoPolarizationAntennaParams(false, M_PI / 4, 0),
1304 Vector{6, 0, 3},
1305 MimoPolarizationAntennaParams(false, 0, M_PI),
1306 {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -4, -4, 4, 4, -4, -4},
1307 0.7),
1308 TestCase::Duration::QUICK);
1309
1310 /**
1311 * The TX and RX antennas are configured face-to-face.
1312 * When polarization slant angles are 45 and 0 at TX and RX,
1313 * we expect the strongest cluster to be similar to the following matrix:
1314 * (0,0) (0,0) (5.9,0) (5.9,0)
1315 * (0,0) (0,0) (5.9,0) (5.9,0)
1316 * (5.8,0) (5.8,0) (0,0) (0,0)
1317 * (5.8,0) (5.8,0) (0,0) (0,0)
1318 */
1320 "Face-to-face. 90 and 0 pol. slant angles.",
1321 Vector{0, 0, 3},
1322 MimoPolarizationAntennaParams(false, M_PI / 2, 0),
1323 Vector{6, 0, 3},
1324 MimoPolarizationAntennaParams(false, 0, M_PI),
1325 {0, 0, 5.8, 5.8, 0, 0, 5.8, 5.8, 5.9, 5.9, 0, 0, 5.9, 5.9, 0, 0},
1326 0.9),
1327 TestCase::Duration::QUICK);
1328
1329 /**
1330 * The TX and RX antennas are face to face. We test the configuration of
1331 * the bearing angle along with the configuration of the different position
1332 * of the RX antenna, and the bearing angles.
1333 * When polarization slant angles are 0 and 0 at TX and RX,
1334 * we expect the strongest cluster to be similar to the following matrix:
1335 * (5.9,0) (5.9,0) (0,0) (0,0)
1336 * (5.9,0) (5.9,0) (0,0) (0,0)
1337 * (0,0) (0,0) (-5.8,) (-5.8,0)
1338 * (0,0) (0,0) (-5.8,0) (-5.8,0)
1339 * Notice that we expect almost the same matrix as in the first case in
1340 * which
1341 */
1343 new ThreeGppMimoPolarizationTest("Face-to-face. Different positions. Different bearing "
1344 "angles. 0 and 0 pol. slant angles.",
1345 Vector{0, 0, 3},
1346 MimoPolarizationAntennaParams(false, 0, M_PI / 4),
1347 Vector{6.363961031, 6.363961031, 3},
1348 MimoPolarizationAntennaParams(false, 0, -(M_PI / 4) * 3),
1349 testChannel1,
1350 0.9),
1351 TestCase::Duration::QUICK);
1352
1353 /**
1354 * The TX and RX antenna have different height.
1355 * Bearing angle is configured to point one toward the other.
1356 * When polarization slant angles are 0 and 0 at TX and RX,
1357 * we expect the strongest cluster to be similar to the following matrix:
1358 * (2.5,-4.7) (2.5,-4.7) (0,0) (0,0)
1359 * (2.5,-4.7) (2.5,-4.7) (0,0) (0,0)
1360 * (0,0) (0,0) (-2.4,4) (-2.4,4)
1361 * (0,0) (0,0) (-2.4,4) (-2.4,4)
1362 */
1364 "Not face-to-face. Different heights. 0 and 0 pol. slant angles.",
1365 Vector{0, 0, 10},
1366 MimoPolarizationAntennaParams(false, 0, 0),
1367 Vector{30, 0, 3},
1368 MimoPolarizationAntennaParams(false, 0, M_PI),
1369 {{2.5, -4.7},
1370 {2.5, -4.7},
1371 0,
1372 0,
1373 {2.5, -4.7},
1374 {2.5, -4.7},
1375 0,
1376 0,
1377 0,
1378 0,
1379 {-2.4, 4},
1380 {-2.4, 4},
1381 0,
1382 0,
1383 {-2.4, 4},
1384 {-2.4, 4}},
1385 0.5),
1386 TestCase::Duration::QUICK);
1387}
1388
1389/// Static variable for test initialization
Test case that test the correct use of the multi-port antennas in spectrum.
void DoRun() override
Build the test scenario.
Test case for the ThreeGppChannelModel class.
ThreeGppChannelMatrixComputationTest(uint32_t txAntennaElements=2, uint32_t rxAntennaElements=2, uint32_t txPorts=1, uint32_t rxPorts=1)
Constructor.
void DoRun() override
Build the test scenario.
uint32_t m_rxPorts
number of horizontal and vertical ports of rx antenna array
std::vector< double > m_normVector
each element is the norm of a channel realization
void DoComputeNorm(Ptr< ThreeGppChannelModel > channelModel, Ptr< MobilityModel > txMob, Ptr< MobilityModel > rxMob, Ptr< PhasedArrayModel > txAntenna, Ptr< PhasedArrayModel > rxAntenna)
Compute the Frobenius norm of the channel matrix and stores it in m_normVector.
uint32_t m_rxAntennaElements
number of rows and columns of rx antenna array
uint32_t m_txAntennaElements
number of rows and columns of tx antenna array
uint32_t m_txPorts
number of horizontal and vertical ports of tx antenna array
Test case for the ThreeGppChannelModel class.
void DoGetChannel(Ptr< ThreeGppChannelModel > channelModel, Ptr< MobilityModel > txMob, Ptr< MobilityModel > rxMob, Ptr< PhasedArrayModel > txAntenna, Ptr< PhasedArrayModel > rxAntenna, bool update)
This method is used to schedule the channel matrix computation at different time instants and to chec...
ThreeGppChannelMatrixUpdateTest(uint32_t txAntennaElements=2, uint32_t rxAntennaElements=4, uint32_t txPorts=1, uint32_t rxPorts=1)
Constructor.
uint32_t m_txAntennaElements
number of rows and columns of tx antenna array
void DoRun() override
Build the test scenario.
uint32_t m_rxPorts
number of horizontal and vertical ports of rx antenna array
Ptr< const ThreeGppChannelModel::ChannelMatrix > m_currentChannel
used by DoGetChannel to store the current channel matrix
uint32_t m_txPorts
number of horizontal and vertical ports of tx antenna array
uint32_t m_rxAntennaElements
number of rows and columns of rx antenna array
Test suite for the ThreeGppChannelModel class.
This test tests that the channel matrix is correctly generated when dual-polarized antennas are being...
void DoRun() override
Build the test scenario.
Vector m_txLoc
Position of the TX device.
Vector m_rxLoc
Position of the RX device.
Ptr< PhasedArrayModel > CreateAndConfigureAntenna(const MimoPolarizationAntennaParams &params)
Function that can be used to configure the antenna using the set of parameters.
MimoPolarizationAntennaParams m_txParams
Parameters used to configure the TX antenna array.
double m_tolerance
The tolerance to be used when comparing the channel matrix with the test matrix.
std::valarray< std::complex< double > > m_testChannel
The test value for the matrix representing the strongest cluster.
ThreeGppMimoPolarizationTest(std::string testCaseName, Vector txLoc, const MimoPolarizationAntennaParams &txAntennaParams, Vector rxLoc, const MimoPolarizationAntennaParams &rxAntennaParams, std::valarray< std::complex< double > > testChannel, double tolerance)
Constructor that receives MIMO polarization parameters of TX and RX devices.
MimoPolarizationAntennaParams m_rxParams
Parameters used to configure the RX antenna array.
Test case for the ThreeGppSpectrumPropagationLossModelTest class.
ThreeGppSpectrumPropagationLossModelTest(uint32_t txAntennaElements=4, uint32_t rxAntennaElements=4, uint32_t txPorts=1, uint32_t rxPorts=1)
Constructor.
void DoRun() override
Build the test scenario.
uint32_t m_txPorts
number of horizontal and vertical ports of tx antenna array
uint32_t m_rxAntennaElements
number of rows and columns of rx antenna array
uint32_t m_rxPorts
number of horizontal and vertical ports of rx antenna array
void CheckLongTermUpdate(const CheckLongTermUpdateParams &params)
Test of the long term component is correctly updated when the channel matrix is recomputed.
void DoBeamforming(Ptr< NetDevice > thisDevice, Ptr< PhasedArrayModel > thisAntenna, Ptr< NetDevice > otherDevice, Ptr< PhasedArrayModel > otherAntenna)
Points the beam of thisDevice towards otherDevice.
uint32_t m_txAntennaElements
number of rows and columns of tx antenna array
Class holding the azimuth and inclination angles of spherical coordinates.
Definition: angles.h:118
AttributeValue implementation for Boolean.
Definition: boolean.h:37
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
Keep track of the current position and velocity of an object.
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
uint32_t AddDevice(Ptr< NetDevice > device)
Associate a NetDevice to this node.
Definition: node.cc:135
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition: object.cc:309
AttributeValue implementation for Pointer.
Definition: pointer.h:48
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static void Run()
Run the simulation.
Definition: simulator.cc:178
Implements Wifi SpectrumValue for the 2.4 GHz ISM band only, with a 5 MHz spectrum resolution.
virtual Ptr< SpectrumValue > CreateTxPowerSpectralDensity(double txPower, uint8_t channel)
Creates a SpectrumValue instance that represents the TX Power Spectral Density of a wifi device corre...
Hold variables of type string.
Definition: string.h:56
encapsulates test code
Definition: test.h:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
int64_t GetMilliSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:408
AttributeValue implementation for Time.
Definition: nstime.h:1406
Hold an unsigned integer type.
Definition: uinteger.h:45
bool IsAlmostEqual(const ValArray< T > &rhs, T tol) const
Compare Valarray up to a given absolute tolerance.
Definition: val-array.h:689
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:894
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:145
#define NS_TEST_ASSERT_MSG_EQ_TOL(actual, limit, tol, msg)
Test that actual and expected (limit) values are equal to plus or minus some tolerance and report and...
Definition: test.h:338
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1331
NodeContainer nodes
Every class exported by the ns3 library is enclosed in the ns3 namespace.
A structure that holds the parameters for the function CheckLongTermUpdate.
Ptr< ThreeGppSpectrumPropagationLossModel > lossModel
the ThreeGppSpectrumPropagationLossModel object used to compute the rx PSD
Ptr< MobilityModel > txMob
the mobility model of the tx device
Ptr< SpectrumValue > rxPsdOld
the previously received PSD
Ptr< SpectrumSignalParameters > txParams
the params of the tx signal
Ptr< PhasedArrayModel > rxAntenna
the antenna array of the rx device
Ptr< MobilityModel > rxMob
the mobility model of the rx device
Ptr< PhasedArrayModel > txAntenna
the antenna array of the tx device
Structure that contains some of the main configuration parameters of the antenna array that are used ...
uint32_t m_rows
the number of rows of antenna array
double m_bearingAngle
bearing angle of the antenna array
MimoPolarizationAntennaParams(bool isotropic, double polSlantAngle=0, double bearingAngle=0)
Constructor Currently only configurable through constructor are polSlantAngle and bearingAngle.
bool m_isotropic
defines whether the antenna elements are isotropic
uint32_t m_hPorts
the number of horizontal ports of antenna array
double m_polSlantAngle
polarization angle of the antenna array
uint32_t m_cols
the number of columns of antenna array
uint32_t m_vPorts
the number of vertical ports of antenna array
Complex3DVector m_channel
Channel matrix H[u][s][n].
static ThreeGppChannelTestSuite myTestSuite
Static variable for test initialization.