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 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include "ns3/abort.h"
8#include "ns3/angles.h"
9#include "ns3/channel-condition-model.h"
10#include "ns3/config.h"
11#include "ns3/constant-position-mobility-model.h"
12#include "ns3/double.h"
13#include "ns3/ism-spectrum-value-helper.h"
14#include "ns3/isotropic-antenna-model.h"
15#include "ns3/log.h"
16#include "ns3/node-container.h"
17#include "ns3/pointer.h"
18#include "ns3/rng-seed-manager.h"
19#include "ns3/simple-net-device.h"
20#include "ns3/simulator.h"
21#include "ns3/spectrum-signal-parameters.h"
22#include "ns3/string.h"
23#include "ns3/test.h"
24#include "ns3/three-gpp-antenna-model.h"
25#include "ns3/three-gpp-channel-model.h"
26#include "ns3/three-gpp-spectrum-propagation-loss-model.h"
27#include "ns3/uinteger.h"
28#include "ns3/uniform-planar-array.h"
29
30#include <valarray>
31
32using namespace ns3;
33
34NS_LOG_COMPONENT_DEFINE("ThreeGppChannelTestSuite");
35
36/**
37 * \ingroup spectrum-tests
38 *
39 * Test case for the ThreeGppChannelModel class.
40 * 1) check if the channel matrix has the correct dimensions
41 * 2) check if the channel matrix is correctly normalized
42 */
44{
45 public:
46 /**
47 *Constructor
48 * \param txAntennaElements the number of rows and columns of the antenna array of the
49 * transmitter
50 * \param rxAntennaElements the number of rows and columns of the antenna array of
51 * \param txPorts the number of vertical and horizontal ports of the antenna array
52 * of the transmitter
53 * \param rxPorts the number of vertical and horizontal ports of the antenna
54 * array of the receiver
55 */
57 uint32_t rxAntennaElements = 2,
58 uint32_t txPorts = 1,
59 uint32_t rxPorts = 1);
60
61 /**
62 * Destructor
63 */
65
66 private:
67 /**
68 * Build the test scenario
69 */
70 void DoRun() override;
71
72 /**
73 * Compute the Frobenius norm of the channel matrix and stores it in m_normVector
74 * \param channelModel the ThreeGppChannelModel object used to generate the channel matrix
75 * \param txMob the mobility model of the first node
76 * \param rxMob the mobility model of the second node
77 * \param txAntenna the antenna object associated to the first node
78 * \param rxAntenna the antenna object associated to the second node
79 */
83 Ptr<PhasedArrayModel> txAntenna,
84 Ptr<PhasedArrayModel> rxAntenna);
85
86 std::vector<double> m_normVector; //!< each element is the norm of a channel realization
87 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
88 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
89 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
90 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
91};
92
94 uint32_t txAntennaElements,
95 uint32_t rxAntennaElements,
96 uint32_t txPorts,
97 uint32_t rxPorts)
98 : TestCase("Check the dimensions and the norm of the channel matrix")
99{
100 m_txAntennaElements = txAntennaElements;
101 m_rxAntennaElements = rxAntennaElements;
102 m_txPorts = txPorts;
103 m_rxPorts = rxPorts;
104}
105
109
110void
112 Ptr<MobilityModel> txMob,
113 Ptr<MobilityModel> rxMob,
114 Ptr<PhasedArrayModel> txAntenna,
115 Ptr<PhasedArrayModel> rxAntenna)
116{
117 uint64_t txAntennaElements = txAntenna->GetNumElems();
118 uint64_t rxAntennaElements = rxAntenna->GetNumElems();
119
121 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
122
123 double channelNorm = 0;
124 uint16_t numTotalClusters = channelMatrix->m_channel.GetNumPages();
125 for (uint16_t cIndex = 0; cIndex < numTotalClusters; cIndex++)
126 {
127 double clusterNorm = 0;
128 for (uint64_t sIndex = 0; sIndex < txAntennaElements; sIndex++)
129 {
130 for (uint64_t uIndex = 0; uIndex < rxAntennaElements; uIndex++)
131 {
132 clusterNorm +=
133 std::pow(std::abs(channelMatrix->m_channel(uIndex, sIndex, cIndex)), 2);
134 }
135 }
136 channelNorm += clusterNorm;
137 }
138 m_normVector.push_back(channelNorm);
139}
140
141void
143{
146 // Build the scenario for the test
147 uint32_t updatePeriodMs = 100; // update period in ms
148
149 // create the channel condition model
150 Ptr<ChannelConditionModel> channelConditionModel =
152
153 // create the ThreeGppChannelModel object used to generate the channel matrix
155 channelModel->SetAttribute("Frequency", DoubleValue(60.0e9));
156 channelModel->SetAttribute("Scenario", StringValue("RMa"));
157 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
158 channelModel->SetAttribute("UpdatePeriod", TimeValue(MilliSeconds(updatePeriodMs - 1)));
159 channelModel->AssignStreams(1);
160
161 // create the tx and rx nodes
163 nodes.Create(2);
164
165 // create the tx and rx devices
168
169 // associate the nodes and the devices
170 nodes.Get(0)->AddDevice(txDev);
171 txDev->SetNode(nodes.Get(0));
172 nodes.Get(1)->AddDevice(rxDev);
173 rxDev->SetNode(nodes.Get(1));
174
175 // create the tx and rx mobility models and set their positions
177 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
179 rxMob->SetPosition(Vector(100.0, 0.0, 10.0));
180
181 // associate the nodes and the mobility models
182 nodes.Get(0)->AggregateObject(txMob);
183 nodes.Get(1)->AggregateObject(rxMob);
184
185 // create the tx and rx antennas and set the their dimensions
187 "NumColumns",
189 "NumRows",
191 "AntennaElement",
193 "NumVerticalPorts",
195 "NumHorizontalPorts",
197
199 "NumColumns",
201 "NumRows",
203 "AntennaElement",
205 "NumVerticalPorts",
207 "NumHorizontalPorts",
209 // generate the channel matrix
211 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
212
213 // check the channel matrix dimensions, expected H[cluster][rx][tx]
215 channelMatrix->m_channel.GetNumCols(),
217 "The third dimension of H should be equal to the number of tx antenna elements");
219 channelMatrix->m_channel.GetNumRows(),
221 "The second dimension of H should be equal to the number of rx antenna elements");
222
223 // test if the channel matrix is correctly generated
224 uint16_t numIt = 1000;
225 for (uint16_t i = 0; i < numIt; i++)
226 {
227 Simulator::Schedule(MilliSeconds(updatePeriodMs * i),
229 this,
230 channelModel,
231 txMob,
232 rxMob,
233 txAntenna,
234 rxAntenna);
235 }
236
238
239 // compute the sample mean
240 double sampleMean = 0;
241 for (auto i : m_normVector)
242 {
243 sampleMean += i;
244 }
245 sampleMean /= numIt;
246
247 // compute the sample standard deviation
248 double sampleStd = 0;
249 for (auto i : m_normVector)
250 {
251 sampleStd += ((i - sampleMean) * (i - sampleMean));
252 }
253 sampleStd = std::sqrt(sampleStd / (numIt - 1));
254
255 // perform the one sample t-test with a significance level of 0.05 to test
256 // the hypothesis "E [|H|^2] = M*N, where |H| indicates the Frobenius norm of
257 // H, M is the number of transmit antenna elements, and N is the number of
258 // the receive antenna elements"
259 double t = (sampleMean - m_txAntennaElements * m_txAntennaElements * m_rxAntennaElements *
261 (sampleStd / std::sqrt(numIt));
262
263 // Using a significance level of 0.05, we reject the null hypothesis if |t| is
264 // greater than the critical value from a t-distribution with df = numIt-1
266 std::abs(t),
267 0,
268 1.65,
269 "We reject the hypothesis E[|H|^2] = M*N with a significance level of 0.05");
270
272}
273
274/**
275 * \ingroup spectrum-tests
276 *
277 * Test case for the ThreeGppChannelModel class.
278 * It checks if the channel realizations are correctly updated during the
279 * simulation.
280 */
282{
283 public:
284 /**
285 *Constructor
286 * \param txAntennaElements the number of rows and columns of the antenna array of the
287 * transmitter
288 * \param rxAntennaElements the number of rows and columns of the antenna array of
289 * \param txPorts the number of vertical and horizontal ports of the antenna array
290 * of the transmitter
291 * \param rxPorts the number of vertical and horizontal ports of the antenna
292 * array of the receiver
293 */
294 ThreeGppChannelMatrixUpdateTest(uint32_t txAntennaElements = 2,
295 uint32_t rxAntennaElements = 4,
296 uint32_t txPorts = 1,
297 uint32_t rxPorts = 1);
298
299 /**
300 * Destructor
301 */
303
304 private:
305 /**
306 * Build the test scenario
307 */
308 void DoRun() override;
309
310 /**
311 * This method is used to schedule the channel matrix computation at different
312 * time instants and to check if it correctly updated
313 * \param channelModel the ThreeGppChannelModel object used to generate the channel matrix
314 * \param txMob the mobility model of the first node
315 * \param rxMob the mobility model of the second node
316 * \param txAntenna the antenna object associated to the first node
317 * \param rxAntenna the antenna object associated to the second node
318 * \param update whether if the channel matrix should be updated or not
319 */
320 void DoGetChannel(Ptr<ThreeGppChannelModel> channelModel,
321 Ptr<MobilityModel> txMob,
322 Ptr<MobilityModel> rxMob,
323 Ptr<PhasedArrayModel> txAntenna,
324 Ptr<PhasedArrayModel> rxAntenna,
325 bool update);
326
328 m_currentChannel; //!< used by DoGetChannel to store the current channel matrix
329 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
330 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
331 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
332 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
333};
334
336 uint32_t rxAntennaElements,
337 uint32_t txPorts,
338 uint32_t rxPorts)
339 : TestCase("Check if the channel realizations are correctly updated during the simulation")
340{
341 m_txAntennaElements = txAntennaElements;
342 m_rxAntennaElements = rxAntennaElements;
343 m_txPorts = txPorts;
344 m_rxPorts = rxPorts;
345}
346
350
351void
353 Ptr<MobilityModel> txMob,
354 Ptr<MobilityModel> rxMob,
355 Ptr<PhasedArrayModel> txAntenna,
356 Ptr<PhasedArrayModel> rxAntenna,
357 bool update)
358{
359 // retrieve the channel matrix
361 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
362
363 if (!m_currentChannel)
364 {
365 // this is the first time we compute the channel matrix, we initialize
366 // m_currentChannel
367 m_currentChannel = channelMatrix;
368 }
369 else
370 {
371 // compare the old and the new channel matrices
372 NS_TEST_ASSERT_MSG_EQ((m_currentChannel->m_channel != channelMatrix->m_channel),
373 update,
375 << " The channel matrix is not correctly updated");
376 }
377}
378
379void
381{
382 // Build the scenario for the test
383 uint32_t updatePeriodMs = 100; // update period in ms
384
385 // create the channel condition model
386 Ptr<ChannelConditionModel> channelConditionModel =
388
389 // create the ThreeGppChannelModel object used to generate the channel matrix
391 channelModel->SetAttribute("Frequency", DoubleValue(60.0e9));
392 channelModel->SetAttribute("Scenario", StringValue("UMa"));
393 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
394 channelModel->SetAttribute("UpdatePeriod", TimeValue(MilliSeconds(updatePeriodMs)));
395
396 // create the tx and rx nodes
398 nodes.Create(2);
399
400 // create the tx and rx devices
403
404 // associate the nodes and the devices
405 nodes.Get(0)->AddDevice(txDev);
406 txDev->SetNode(nodes.Get(0));
407 nodes.Get(1)->AddDevice(rxDev);
408 rxDev->SetNode(nodes.Get(1));
409
410 // create the tx and rx mobility models and set their positions
412 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
414 rxMob->SetPosition(Vector(100.0, 0.0, 1.6));
415
416 // associate the nodes and the mobility models
417 nodes.Get(0)->AggregateObject(txMob);
418 nodes.Get(1)->AggregateObject(rxMob);
419
420 // create the tx and rx antennas and set the their dimensions
422 "NumColumns",
424 "NumRows",
426 "AntennaElement",
428 "NumVerticalPorts",
430 "NumHorizontalPorts",
432
434 "NumColumns",
436 "NumRows",
438 "AntennaElement",
440 "NumVerticalPorts",
442 "NumHorizontalPorts",
444
445 // check if the channel matrix is correctly updated
446
447 // compute the channel matrix for the first time
448 uint32_t firstTimeMs =
449 1; // time instant at which the channel matrix is generated for the first time
452 this,
453 channelModel,
454 txMob,
455 rxMob,
456 txAntenna,
457 rxAntenna,
458 true);
459
460 // call GetChannel before the update period is exceeded, the channel matrix
461 // should not be updated
462 Simulator::Schedule(MilliSeconds(firstTimeMs + updatePeriodMs / 2),
464 this,
465 channelModel,
466 txMob,
467 rxMob,
468 txAntenna,
469 rxAntenna,
470 false);
471
472 // call GetChannel when the update period is exceeded, the channel matrix
473 // should be recomputed
474 Simulator::Schedule(MilliSeconds(firstTimeMs + updatePeriodMs + 1),
476 this,
477 channelModel,
478 txMob,
479 rxMob,
480 txAntenna,
481 rxAntenna,
482 true);
483
486}
487
488/**
489 * \ingroup spectrum-tests
490 *
491 * Test case for the ThreeGppChannelModel class.
492 * It checks if the channel realizations are correctly
493 * updated after a change in the number of antenna elements.
494 */
496{
497 public:
498 /**
499 * Constructor
500 */
502
503 /**
504 * Destructor
505 */
507
508 private:
509 /**
510 * Build the test scenario
511 */
512 void DoRun() override;
513
514 /**
515 * This method is used to schedule the channel matrix computation at different
516 * time instants and to check if it correctly updated
517 * \param channelModel the ThreeGppChannelModel object used to generate the channel matrix
518 * \param txMob the mobility model of the first node
519 * \param rxMob the mobility model of the second node
520 * \param txAntenna the antenna object associated to the first node
521 * \param rxAntenna the antenna object associated to the second node
522 * \param update whether if the channel matrix should be updated or not
523 */
524 void DoGetChannel(Ptr<ThreeGppChannelModel> channelModel,
525 Ptr<MobilityModel> txMob,
526 Ptr<MobilityModel> rxMob,
527 Ptr<PhasedArrayModel> txAntenna,
528 Ptr<PhasedArrayModel> rxAntenna,
529 bool update);
530
532 m_currentChannel; //!< used by DoGetChannel to store the current channel matrix
533 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
534 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
535 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
536 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
537};
538
540 : TestCase("Check if the channel realizations are correctly updated after antenna port changes "
541 "during the simulation")
542{
543}
544
548
549void
551 Ptr<MobilityModel> txMob,
552 Ptr<MobilityModel> rxMob,
553 Ptr<PhasedArrayModel> txAntenna,
554 Ptr<PhasedArrayModel> rxAntenna,
555 bool update)
556{
557 // retrieve the channel matrix
559 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
560
562 {
563 // compare the old and the new channel matrices
564 NS_TEST_ASSERT_MSG_EQ((m_currentChannel->m_channel != channelMatrix->m_channel),
565 update,
567 << " The channel matrix is not correctly updated");
568 }
569 m_currentChannel = channelMatrix;
570}
571
572void
574{
575 // Build the scenario for the test
576 uint32_t updatePeriodMs = 100; // update period in ms
577
578 // create the channel condition model
579 Ptr<ChannelConditionModel> channelConditionModel =
581
582 // create the ThreeGppChannelModel object used to generate the channel matrix
584 channelModel->SetAttribute("Frequency", DoubleValue(60.0e9));
585 channelModel->SetAttribute("Scenario", StringValue("UMa"));
586 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
587 channelModel->SetAttribute("UpdatePeriod", TimeValue(MilliSeconds(updatePeriodMs)));
588
589 // create the tx and rx nodes
591 nodes.Create(2);
592
593 // create the tx and rx devices
596
597 // associate the nodes and the devices
598 nodes.Get(0)->AddDevice(txDev);
599 txDev->SetNode(nodes.Get(0));
600 nodes.Get(1)->AddDevice(rxDev);
601 rxDev->SetNode(nodes.Get(1));
602
603 // create the tx and rx mobility models and set their positions
605 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
607 rxMob->SetPosition(Vector(100.0, 0.0, 1.6));
608
609 // associate the nodes and the mobility models
610 nodes.Get(0)->AggregateObject(txMob);
611 nodes.Get(1)->AggregateObject(rxMob);
612
613 // create the tx and rx antennas and set the their dimensions
615 "NumColumns",
617 "NumRows",
619 "AntennaElement",
621 "NumVerticalPorts",
623 "NumHorizontalPorts",
625
627 "NumColumns",
629 "NumRows",
631 "AntennaElement",
633 "NumVerticalPorts",
635 "NumHorizontalPorts",
637
638 // check if the channel matrix is correctly updated
639
640 // compute the channel matrix for the first time
643 this,
644 channelModel,
645 txMob,
646 rxMob,
647 txAntenna,
648 rxAntenna,
649 true);
650
651 // call GetChannel before the update period is exceeded, the channel matrix
652 // should not be updated
655 this,
656 channelModel,
657 txMob,
658 rxMob,
659 txAntenna,
660 rxAntenna,
661 false);
662
663 // after changing the number of antenna ports, the channel matrix
664 // should be recomputed
666 [&txAntenna]() { txAntenna->SetNumRows(txAntenna->GetNumRows() + 1); });
669 this,
670 channelModel,
671 txMob,
672 rxMob,
673 txAntenna,
674 rxAntenna,
675 true);
676
677 // after recomputing it once, the channel matrix should be cached
680 this,
681 channelModel,
682 txMob,
683 rxMob,
684 txAntenna,
685 rxAntenna,
686 false);
687
688 // after recomputing it once, the channel matrix should be cached
690 [&rxAntenna]() { rxAntenna->SetNumRows(rxAntenna->GetNumRows() + 1); });
693 this,
694 channelModel,
695 txMob,
696 rxMob,
697 txAntenna,
698 rxAntenna,
699 true);
700
701 // after recomputing it once, the channel matrix should be cached
704 this,
705 channelModel,
706 txMob,
707 rxMob,
708 txAntenna,
709 rxAntenna,
710 false);
711
714}
715
716/**
717 * \ingroup spectrum-tests
718 * \brief A structure that holds the parameters for the function
719 * CheckLongTermUpdate. In this way the problem with the limited
720 * number of parameters of method Schedule is avoided.
721 */
723{
725 lossModel; //!< the ThreeGppSpectrumPropagationLossModel object used to compute the rx PSD
726 Ptr<SpectrumSignalParameters> txParams; //!< the params of the tx signal
727 Ptr<MobilityModel> txMob; //!< the mobility model of the tx device
728 Ptr<MobilityModel> rxMob; //!< the mobility model of the rx device
729 Ptr<SpectrumValue> rxPsdOld; //!< the previously received PSD
730 Ptr<PhasedArrayModel> txAntenna; //!< the antenna array of the tx device
731 Ptr<PhasedArrayModel> rxAntenna; //!< the antenna array of the rx device
732};
733
734/**
735 * \ingroup spectrum-tests
736 *
737 * Test case for the ThreeGppSpectrumPropagationLossModelTest class.
738 * 1) checks if the long term components for the direct and the reverse link
739 * are the same
740 * 2) checks if the long term component is updated when changing the beamforming
741 * vectors
742 * 3) checks if the long term is updated when changing the channel matrix
743 */
745{
746 public:
747 /**
748 * Constructor
749 * \param txAntennaElements the number of rows and columns of the antenna array of the
750 * transmitter
751 * \param rxAntennaElements the number of rows and columns of the antenna array of
752 * the receiver
753 * \param txPorts the number of vertical and horizontal ports of the antenna array
754 * of the transmitter
755 * \param rxPorts the number of vertical and horizontal ports of the antenna
756 * array of the receiver
757 */
759 uint32_t rxAntennaElements = 4,
760 uint32_t txPorts = 1,
761 uint32_t rxPorts = 1);
762 /**
763 * Destructor
764 */
766
767 private:
768 /**
769 * Build the test scenario
770 */
771 void DoRun() override;
772
773 /**
774 * Points the beam of thisDevice towards otherDevice
775 * \param thisDevice the device to configure
776 * \param thisAntenna the antenna object associated to thisDevice
777 * \param otherDevice the device to communicate with
778 * \param otherAntenna the antenna object associated to otherDevice
779 */
780 void DoBeamforming(Ptr<NetDevice> thisDevice,
781 Ptr<PhasedArrayModel> thisAntenna,
782 Ptr<NetDevice> otherDevice,
783 Ptr<PhasedArrayModel> otherAntenna);
784
785 /**
786 * Test of the long term component is correctly updated when the channel
787 * matrix is recomputed
788 * \param params a structure that contains the set of parameters needed by CheckLongTermUpdate
789 * in order to perform calculations
790 */
792
793 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
794 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
795 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
796 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
797};
798
800 uint32_t txAntennaElements,
801 uint32_t rxAntennaElements,
802 uint32_t txPorts,
803 uint32_t rxPorts)
804 : TestCase("Test case for the ThreeGppSpectrumPropagationLossModel class")
805{
806 m_txAntennaElements = txAntennaElements;
807 m_rxAntennaElements = rxAntennaElements;
808 m_txPorts = txPorts;
809 m_rxPorts = rxPorts;
810}
811
815
816void
818 Ptr<PhasedArrayModel> thisAntenna,
819 Ptr<NetDevice> otherDevice,
820 Ptr<PhasedArrayModel> otherAntenna)
821{
822 Vector aPos = thisDevice->GetNode()->GetObject<MobilityModel>()->GetPosition();
823 Vector bPos = otherDevice->GetNode()->GetObject<MobilityModel>()->GetPosition();
824
825 // compute the azimuth and the elevation angles
826 Angles completeAngle(bPos, aPos);
827
828 PhasedArrayModel::ComplexVector antennaWeights =
829 thisAntenna->GetBeamformingVector(completeAngle);
830 thisAntenna->SetBeamformingVector(antennaWeights);
831}
832
833void
835 const CheckLongTermUpdateParams& params)
836{
837 auto rxPsdNewParams = params.lossModel->DoCalcRxPowerSpectralDensity(params.txParams,
838 params.txMob,
839 params.rxMob,
840 params.txAntenna,
841 params.rxAntenna);
842 NS_TEST_ASSERT_MSG_EQ((*params.rxPsdOld == *rxPsdNewParams->psd),
843 false,
844 "The long term is not updated when the channel matrix is recomputed");
845}
846
847void
849{
850 // Build the scenario for the test
851 Config::SetDefault("ns3::ThreeGppChannelModel::UpdatePeriod", TimeValue(MilliSeconds(100)));
852
853 // create the ChannelConditionModel object to be used to retrieve the
854 // channel condition
856
857 // create the ThreeGppSpectrumPropagationLossModel object, set frequency,
858 // scenario and channel condition model to be used
861 lossModel->SetChannelModelAttribute("Frequency", DoubleValue(2.4e9));
862 lossModel->SetChannelModelAttribute("Scenario", StringValue("UMa"));
863 lossModel->SetChannelModelAttribute(
864 "ChannelConditionModel",
865 PointerValue(condModel)); // create the ThreeGppChannelModel object used to generate the
866 // channel matrix
867
868 // create the tx and rx nodes
870 nodes.Create(2);
871
872 // create the tx and rx devices
875
876 // associate the nodes and the devices
877 nodes.Get(0)->AddDevice(txDev);
878 txDev->SetNode(nodes.Get(0));
879 nodes.Get(1)->AddDevice(rxDev);
880 rxDev->SetNode(nodes.Get(1));
881
882 // create the tx and rx mobility models and set their positions
884 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
886 rxMob->SetPosition(
887 Vector(15.0, 0.0, 10.0)); // in this position the channel condition is always LOS
888
889 // associate the nodes and the mobility models
890 nodes.Get(0)->AggregateObject(txMob);
891 nodes.Get(1)->AggregateObject(rxMob);
892
893 // create the tx and rx antennas and set the their dimensions
895 "NumColumns",
897 "NumRows",
899 "AntennaElement",
901 "NumVerticalPorts",
903 "NumHorizontalPorts",
905
907 "NumColumns",
909 "NumRows",
911 "AntennaElement",
913 "NumVerticalPorts",
915 "NumHorizontalPorts",
917
918 // set the beamforming vectors
919 DoBeamforming(txDev, txAntenna, rxDev, rxAntenna);
920 DoBeamforming(rxDev, rxAntenna, txDev, txAntenna);
921
922 // create the tx psd
924 double txPower = 0.1; // Watts
925 uint32_t channelNumber = 1;
926 Ptr<SpectrumValue> txPsd = sf.CreateTxPowerSpectralDensity(txPower, channelNumber);
928 txParams->psd = txPsd->Copy();
929
930 // compute the rx psd
931 auto rxParamsOld =
932 lossModel->DoCalcRxPowerSpectralDensity(txParams, txMob, rxMob, txAntenna, rxAntenna);
933
934 // 1) check that the rx PSD is equal for both the direct and the reverse channel
935 auto rxParamsNew =
936 lossModel->DoCalcRxPowerSpectralDensity(txParams, rxMob, txMob, rxAntenna, txAntenna);
937 NS_TEST_ASSERT_MSG_EQ((*rxParamsOld->psd == *rxParamsNew->psd),
938 true,
939 "The long term for the direct and the reverse channel are different");
940
941 // 2) check if the long term is updated when changing the BF vector
942 // change the position of the rx device and recompute the beamforming vectors
943 rxMob->SetPosition(Vector(10.0, 5.0, 10.0));
944 PhasedArrayModel::ComplexVector txBfVector = txAntenna->GetBeamformingVector();
945 txBfVector[0] = std::complex<double>(0.0, 0.0);
946 txAntenna->SetBeamformingVector(txBfVector);
947
948 rxParamsNew =
949 lossModel->DoCalcRxPowerSpectralDensity(txParams, rxMob, txMob, rxAntenna, txAntenna);
950 NS_TEST_ASSERT_MSG_EQ((*rxParamsOld->psd == *rxParamsNew->psd),
951 false,
952 "Changing the BF vectors the rx PSD does not change");
953
955 (*rxParamsOld->spectrumChannelMatrix == *rxParamsNew->spectrumChannelMatrix),
956 false,
957 "Changing the BF should change de frequency domain channel matrix");
958
959 // update rxPsdOld
960 rxParamsOld = rxParamsNew;
961
962 // 3) check if the long term is updated when the channel matrix is recomputed
964 params{lossModel, txParams, txMob, rxMob, rxParamsOld->psd, txAntenna, rxAntenna};
967 this,
968 params);
969
972}
973
974/**
975 * \ingroup spectrum-tests
976 *
977 * Test case that test the correct use of the multi-port antennas in spectrum.
978 * The test does the following:
979 * 1) Generates a time domain channel matrix of a fixed size
980 * (num gNB elements = 32 (4x8), num UE elements = 16 (4x4), num Clusters).
981 * This matrix is called channelMatrixM0.
982 * 2) Divides gNB antenna and UE antenna into ports using a fixed element to port
983 * mapping (gNB: 1 vertical port, 4 horizontal ports, UE: 1 vertical port,
984 * 2 horizontal ports). Using the channelMatrixM0, it generates port to port
985 * long term channel matrix using the both gNB and UE having beams directed towards the other.
986 * The resulting long term matrix dimensions are gNBports = 4, UE ports = 2, num Clusters.
987 * This channel matrix is called matrixA.
988 * 3) Constructs a single port to single port long term channel matrix
989 * using the initial time domain channel matrix (channelMatrixM0) and beams
990 * from gNB and UE towards each other. Single port mapping means gNB: 1 vertical port,
991 * 1 horizontal port, UE: 1 vertical port, 1 horizontal port.
992 * Matrix dimensions are: gNBports = 1, UE ports = 1, num Clusters. This long
993 * term channel matrix is called matrixB.
994 * 4) Creates a single port to single port long term channel matrix between
995 * two virtual gNB and UE antenna by using matrixA and beam facing each other.
996 * Matrix dimension of the resulting matrix are gNBports = 1, UE ports = 1, num Clusters.
997 * This long term channel matrix is called matrixC.
998 * 5) Checks that matrixB and matrixC are identical.
999 */
1001{
1002 public:
1003 /**
1004 * Constructor
1005 */
1007
1008 /**
1009 * Destructor
1010 */
1012
1013 private:
1014 /**
1015 * Build the test scenario
1016 */
1017 void DoRun() override;
1018};
1019
1021 : TestCase("Check long term channel matrix generation when multiple ports at TX and RX are "
1022 "being used.")
1023{
1024}
1025
1029
1030void
1032{
1033 // create the channel condition model
1034 Ptr<ChannelConditionModel> channelConditionModel =
1036
1037 // create the ThreeGppChannelModel object used to generate the channel matrix
1039 channelModel->SetAttribute("Frequency", DoubleValue(2.0e9));
1040 channelModel->SetAttribute("Scenario", StringValue("RMa"));
1041 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
1042
1043 // create the tx and rx nodes
1045 nodes.Create(2);
1046
1047 // create the tx and rx devices
1050
1051 // associate the nodes and the devices
1052 nodes.Get(0)->AddDevice(txDev);
1053 txDev->SetNode(nodes.Get(0));
1054 nodes.Get(1)->AddDevice(rxDev);
1055 rxDev->SetNode(nodes.Get(1));
1056
1057 // create the tx and rx mobility models and set their positions
1059 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
1061 rxMob->SetPosition(Vector(10.0, 0.0, 10.0));
1062
1063 // associate the nodes and the mobility models
1064 nodes.Get(0)->AggregateObject(txMob);
1065 nodes.Get(1)->AggregateObject(rxMob);
1066
1067 // create the tx and rx antennas and set the their dimensions
1069 "NumColumns",
1070 UintegerValue(8),
1071 "NumRows",
1072 UintegerValue(4),
1073 "AntennaElement",
1075 "NumVerticalPorts",
1076 UintegerValue(1),
1077 "NumHorizontalPorts",
1078 UintegerValue(4));
1079
1081 "NumColumns",
1082 UintegerValue(4),
1083 "NumRows",
1084 UintegerValue(4),
1085 "AntennaElement",
1087 "NumVerticalPorts",
1088 UintegerValue(1),
1089 "NumHorizontalPorts",
1090 UintegerValue(2));
1091
1092 // compute the azimuth and the elevation angles
1093 Angles completeAngleTxRx(rxMob->GetPosition(), txMob->GetPosition());
1094 Angles completeAngleRxTx(txMob->GetPosition(), rxMob->GetPosition());
1095
1096 txAntenna1->SetBeamformingVector(txAntenna1->GetBeamformingVector(completeAngleTxRx));
1097 rxAntenna1->SetBeamformingVector(rxAntenna1->GetBeamformingVector(completeAngleRxTx));
1098
1099 // generate the channel matrix
1101 channelModel->GetChannel(txMob, rxMob, txAntenna1, rxAntenna1);
1102
1103 // create ThreeGppSpectrumPropagationLossModel instance so that we
1104 // can call CalcLongTerm
1107
1109 threeGppSplm->CalcLongTerm(channelMatrixM0, txAntenna1, rxAntenna1);
1110
1111 // create the tx and rx antennas and set the their dimensions
1113 "NumColumns",
1114 UintegerValue(8),
1115 "NumRows",
1116 UintegerValue(4),
1117 "AntennaElement",
1119 "NumVerticalPorts",
1120 UintegerValue(1),
1121 "NumHorizontalPorts",
1122 UintegerValue(1));
1123
1125 "NumColumns",
1126 UintegerValue(4),
1127 "NumRows",
1128 UintegerValue(4),
1129 "AntennaElement",
1131 "NumVerticalPorts",
1132 UintegerValue(1),
1133 "NumHorizontalPorts",
1134 UintegerValue(1));
1135
1136 txAntenna2->SetBeamformingVector(txAntenna2->GetBeamformingVector(completeAngleTxRx));
1137 rxAntenna2->SetBeamformingVector(rxAntenna2->GetBeamformingVector(completeAngleRxTx));
1138
1140 threeGppSplm->CalcLongTerm(channelMatrixM0, txAntenna2, rxAntenna2);
1141
1142 // create the tx and rx antennas and set the their dimensions
1144 "NumColumns",
1145 UintegerValue(4),
1146 "NumRows",
1147 UintegerValue(1),
1148 "AntennaElement",
1150 "NumVerticalPorts",
1151 UintegerValue(1),
1152 "NumHorizontalPorts",
1153 UintegerValue(1),
1154 "AntennaHorizontalSpacing",
1155 DoubleValue(1));
1156
1158 "NumColumns",
1159 UintegerValue(2),
1160 "NumRows",
1161 UintegerValue(1),
1162 "AntennaElement",
1164 "NumVerticalPorts",
1165 UintegerValue(1),
1166 "NumHorizontalPorts",
1167 UintegerValue(1),
1168 "AntennaHorizontalSpacing",
1169 DoubleValue(1));
1170
1173 channelMatrixMA->m_channel = *matrixA;
1174
1175 txAntenna3->SetBeamformingVector(txAntenna3->GetBeamformingVector(completeAngleTxRx));
1176 rxAntenna3->SetBeamformingVector(rxAntenna3->GetBeamformingVector(completeAngleRxTx));
1177
1179 threeGppSplm->CalcLongTerm(channelMatrixMA, txAntenna3, rxAntenna3);
1180
1181 NS_TEST_ASSERT_MSG_EQ(matrixB->IsAlmostEqual(*matrixC, 1e-6),
1182 true,
1183 "Matrix B and Matrix C should be equal.");
1184
1187}
1188
1189/**
1190 * Structure that contains some of the main configuration parameters of the antenna
1191 * array that are used in the ThreeGppMimoPolarizationTest
1192 */
1194{
1195 uint32_t m_rows = 1; //!< the number of rows of antenna array
1196 uint32_t m_cols = 2; //!< the number of columns of antenna array
1197 uint32_t m_vPorts = 1; //!< the number of vertical ports of antenna array
1198 uint32_t m_hPorts = 2; //!< the number of horizontal ports of antenna array
1199 bool m_isotropic = false; //!< defines whether the antenna elements are isotropic
1200 double m_polSlantAngle = 0; //!< polarization angle of the antenna array
1201 double m_bearingAngle = 0; //!< bearing angle of the antenna array
1202
1203 /**
1204 * Constructor
1205 * Currently only configurable through constructor are polSlantAngle and bearingAngle.
1206 * \param isotropic whether the antenna elements are isotropic, or 3GPP
1207 * \param polSlantAngle the polarization slant angle
1208 * \param bearingAngle the bearing angle
1209 */
1210 MimoPolarizationAntennaParams(bool isotropic, double polSlantAngle = 0, double bearingAngle = 0)
1211 : m_isotropic(isotropic),
1212 m_polSlantAngle(polSlantAngle),
1213 m_bearingAngle(bearingAngle)
1214 {
1215 }
1216};
1217
1218/**
1219 * \ingroup spectrum-tests
1220 * This test tests that the channel matrix is correctly generated when dual-polarized
1221 * antennas are being used at TX and RX. In the conditions in which the channel between
1222 * the TX and Rx device is LOS channel, and the beams of the transmitter and the
1223 * receiver are pointing one towards the other, then in the presence of multiple ports
1224 * at the TX and RX, and the antenna array at the TX and RX are dual polarized,
1225 * the channel matrix should exhibit the strong symmetry between the two polarizations.
1226 * E.g. if we have 1x2 antenna elements and two polarizations at both TX and RX,
1227 * and the 1x2 ports at the TX and RX, then the channel matrix will have the
1228 * structure as:
1229 *
1230 * ch00 ch01 |ch02 ch03
1231 * Hvv Hvh ch10 ch11 |ch12 ch13
1232 * = --------------------
1233 * Hhv Hhh ch20 ch21 |ch22 ch23
1234 * ch30 ch31 |ch32 ch33
1235 *
1236 * We test different cases of the polarization slant angles of the TX and RX,
1237 * e.g., 0, 30, 45, 90.
1238 * In each of these setups we check if the channel matrix in its strongest
1239 * cluster experiences strong symmetry, and if the values appear in pairs.
1240 * We also test additional cases in which we change the bearing angle and
1241 * the height of the TX. In these cases we also observe strong symmetry, with
1242 * the difference that in these cases we can observe different values in the
1243 * pairs. We can still observe strong impact of the dual polarization on the
1244 * channel matrix.
1245 */
1247{
1248 public:
1249 /**
1250 * Constructor that receives MIMO polarization parameters of TX and RX
1251 * devices
1252 * \param testCaseName the test case name
1253 * \param txLoc the position of the transmitter
1254 * \param txAntennaParams the antenna parameters of the transmitter
1255 * \param rxLoc the position of the receiver
1256 * \param rxAntennaParams the antenna parameters of the receiver
1257 * \param testChannel the test matrix that represent the strongest cluster
1258 * \param tolerance the tolerance to be used when testing
1259 */
1260 ThreeGppMimoPolarizationTest(std::string testCaseName,
1261 Vector txLoc,
1262 const MimoPolarizationAntennaParams& txAntennaParams,
1263 Vector rxLoc,
1264 const MimoPolarizationAntennaParams& rxAntennaParams,
1265 std::valarray<std::complex<double>> testChannel,
1266 double tolerance);
1267
1268 /**
1269 * Destructor
1270 */
1272
1273 private:
1274 /**
1275 * Build the test scenario
1276 */
1277 void DoRun() override;
1278
1279 /**
1280 * @brief Function that can be used to configure the antenna using the set of
1281 * parameters.
1282 *
1283 * @param params The parameters to be set to the antenna
1284 * @return A pointer to the antenna that is created and configured by using input params
1285 */
1287
1288 Vector m_txLoc; //!< Position of the TX device
1289 MimoPolarizationAntennaParams m_txParams; //!< Parameters used to configure the TX antenna array
1290 Vector m_rxLoc; //!< Position of the RX device
1291 MimoPolarizationAntennaParams m_rxParams; //!< Parameters used to configure the RX antenna array
1292 std::valarray<std::complex<double>>
1293 m_testChannel; //!< The test value for the matrix representing the strongest cluster
1294 double m_tolerance; //!< The tolerance to be used when comparing the channel matrix with the
1295 //!< test matrix
1296};
1297
1299 std::string testCaseName,
1300 Vector txLoc,
1301 const MimoPolarizationAntennaParams& txParams,
1302 Vector rxLoc,
1303 const MimoPolarizationAntennaParams& rxParams,
1304 std::valarray<std::complex<double>> testChannel,
1305 double tolerance)
1306 : TestCase("Test MIMO using dual polarization." + testCaseName),
1307 m_txLoc(txLoc),
1308 m_txParams(txParams),
1309 m_rxLoc(rxLoc),
1310 m_rxParams(rxParams),
1311 m_testChannel(testChannel),
1312 m_tolerance(tolerance)
1313{
1314}
1315
1319
1322{
1323 NS_LOG_FUNCTION(this);
1324 Ptr<AntennaModel> antenna;
1325 if (params.m_isotropic)
1326 {
1328 }
1329 else
1330 {
1332 }
1333 // create the tx and rx antennas and set the their dimensions
1335 UintegerValue(params.m_cols),
1336 "NumRows",
1337 UintegerValue(params.m_rows),
1338 "AntennaElement",
1339 PointerValue(antenna),
1340 "NumVerticalPorts",
1341 UintegerValue(params.m_vPorts),
1342 "NumHorizontalPorts",
1343 UintegerValue(params.m_hPorts),
1344 "BearingAngle",
1345 DoubleValue(params.m_bearingAngle),
1346 "PolSlantAngle",
1347 DoubleValue(params.m_polSlantAngle),
1348 "IsDualPolarized",
1349 BooleanValue(true));
1350}
1351
1352void
1354{
1357 // create the ThreeGppChannelModel object used to generate the channel matrix
1359 channelModel->SetAttribute("Frequency", DoubleValue(60e9));
1360 channelModel->SetAttribute("Scenario", StringValue("RMa"));
1361 channelModel->SetAttribute("ChannelConditionModel",
1363
1364 int64_t randomStream = 1;
1365 randomStream += channelModel->AssignStreams(randomStream);
1366
1367 // create the tx and rx nodes
1369 nodes.Create(2);
1370
1371 // create the tx and rx devices
1374
1375 // associate the nodes and the devices
1376 nodes.Get(0)->AddDevice(txDev);
1377 txDev->SetNode(nodes.Get(0));
1378 nodes.Get(1)->AddDevice(rxDev);
1379 rxDev->SetNode(nodes.Get(1));
1380
1381 // create the tx and rx mobility models and set their positions
1383 txMob->SetPosition(m_txLoc);
1385 rxMob->SetPosition(m_rxLoc);
1386
1387 // associate the nodes and the mobility models
1388 nodes.Get(0)->AggregateObject(txMob);
1389 nodes.Get(1)->AggregateObject(rxMob);
1390
1391 // create the tx and rx antennas and set the their dimensions
1394
1395 // configure direct beamforming vectors to point to each other
1396 txAntenna->SetBeamformingVector(
1397 txAntenna->GetBeamformingVector(Angles(rxMob->GetPosition(), txMob->GetPosition())));
1398 rxAntenna->SetBeamformingVector(
1399 rxAntenna->GetBeamformingVector(Angles(txMob->GetPosition(), rxMob->GetPosition())));
1400
1401 // generate the time domain channel matrix
1403 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
1404
1405 // test whether the channel matrix for the first cluster experiences strong
1406 // symmetry that is caused by existence of dual polarized ports at the
1407 // transmitter and the receiver
1408 const std::complex<double>* strongestClusterPtr = channelMatrix->m_channel.GetPagePtr(0);
1409 size_t matrixSize =
1410 channelMatrix->m_channel.GetNumRows() * channelMatrix->m_channel.GetNumCols();
1411
1413 channelMatrix->m_channel.GetNumRows(),
1414 channelMatrix->m_channel.GetNumCols(),
1415 std::valarray<std::complex<double>>(strongestClusterPtr, matrixSize));
1416
1417 MatrixBasedChannelModel::Complex2DVector testChannel(channelMatrix->m_channel.GetNumRows(),
1418 channelMatrix->m_channel.GetNumCols(),
1420
1421 NS_LOG_INFO("Channel matrix:" << strongestCluster);
1422 NS_LOG_INFO("Test channel matrix: " << testChannel);
1423
1425 strongestCluster.IsAlmostEqual(testChannel, m_tolerance),
1426 true,
1427 "The strongest cluster and the test channel matrix should be almost equal");
1428
1431}
1432
1433/**
1434 * \ingroup spectrum-tests
1435 *
1436 * Test suite for the ThreeGppChannelModel class
1437 */
1439{
1440 public:
1441 /**
1442 * Constructor
1443 */
1445};
1446
1448 : TestSuite("three-gpp-channel", Type::UNIT)
1449{
1450 AddTestCase(new ThreeGppChannelMatrixComputationTest(2, 2, 1, 1), TestCase::Duration::QUICK);
1451 AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 2, 1, 1), TestCase::Duration::QUICK);
1452 AddTestCase(new ThreeGppChannelMatrixComputationTest(2, 2, 2, 2), TestCase::Duration::QUICK);
1453 AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 4, 2, 2), TestCase::Duration::QUICK);
1454 AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 2, 2, 1), TestCase::Duration::QUICK);
1455 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 4, 1, 1), TestCase::Duration::QUICK);
1456 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 1, 1), TestCase::Duration::QUICK);
1457 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 4, 2, 2), TestCase::Duration::QUICK);
1458 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 2, 2), TestCase::Duration::QUICK);
1459 AddTestCase(new ThreeGppAntennaSetupChangedTest(), TestCase::Duration::QUICK);
1461 TestCase::Duration::QUICK);
1463 TestCase::Duration::QUICK);
1465 TestCase::Duration::QUICK);
1467 TestCase::Duration::QUICK);
1468 AddTestCase(new ThreeGppCalcLongTermMultiPortTest(), TestCase::Duration::QUICK);
1469
1470 /**
1471 * The TX and RX antennas are configured face-to-face.
1472 * When polarization slant angles are 0 and 0 at TX and RX,
1473 * we expect the strongest cluster to be similar to the following matrix:
1474 * (5.9,0) (5.9,0) (0,0) (0,0)
1475 * (5.9,0) (5.9,0) (0,0) (0,0)
1476 * (0,0) (0,0) (-5.8,) (-5.8,0)
1477 * (0,0) (0,0) (-5.8,0) (-5.8,0)
1478 */
1479 std::valarray<std::complex<double>> testChannel1 =
1480 {5.9, 5.9, 0, 0, 5.9, 5.9, 0, 0, 0, 0, -5.8, -5.8, 0, 0, -5.8, -5.8};
1481 AddTestCase(new ThreeGppMimoPolarizationTest("Face-to-face. 0 and 0 pol. slant angles.",
1482 Vector{0, 0, 3},
1483 MimoPolarizationAntennaParams(false, 0, 0),
1484 Vector{9, 0, 3},
1485 MimoPolarizationAntennaParams(false, 0, M_PI),
1486 testChannel1,
1487 0.9),
1488 TestCase::Duration::QUICK);
1489
1490 /**
1491 * The TX and RX antennas are configured face-to-face.
1492 * When polarization slant angles are 30 and 0 at TX and RX,
1493 * we expect the strongest cluster to be similar to the following matrix:
1494 * (5,0) (5,0) (3,0) (3,0)
1495 * (5,0) (5,0) (3,0) (3,0)
1496 * (3,0) (3,0) (-5,0) (-5,0)
1497 * (3,0) (3,0) (-5,0) (-5,0)
1498 */
1500 new ThreeGppMimoPolarizationTest("Face-to-face. 30 and 0 pol. slant angles.",
1501 Vector{0, 0, 3},
1502 MimoPolarizationAntennaParams(false, M_PI / 6, 0),
1503 Vector{6, 0, 3},
1504 MimoPolarizationAntennaParams(false, 0, M_PI),
1505 {5, 5, 3, 3, 5, 5, 3, 3, 3, 3, -5, -5, 3, 3, -5, -5},
1506 0.8),
1507 TestCase::Duration::QUICK);
1508
1509 /**
1510 * The TX and RX antennas are configured face-to-face.
1511 * When polarization slant angles are 45 and 0 at TX and RX,
1512 * we expect the strongest cluster to be similar to the following matrix:
1513 * (4,0) (4,0) (4,0) (4,0)
1514 * (4,0) (4,0) (4,0) (4,0)
1515 * (4,0) (4,0) (4,0) (4,0)
1516 * (4,0) (4,0) (4,0) (4,0)
1517 */
1519 new ThreeGppMimoPolarizationTest("Face-to-face. 45 and 0 pol. slant angles.",
1520 Vector{0, 0, 3},
1521 MimoPolarizationAntennaParams(false, M_PI / 4, 0),
1522 Vector{6, 0, 3},
1523 MimoPolarizationAntennaParams(false, 0, M_PI),
1524 {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -4, -4, 4, 4, -4, -4},
1525 0.7),
1526 TestCase::Duration::QUICK);
1527
1528 /**
1529 * The TX and RX antennas are configured face-to-face.
1530 * When polarization slant angles are 45 and 0 at TX and RX,
1531 * we expect the strongest cluster to be similar to the following matrix:
1532 * (0,0) (0,0) (5.9,0) (5.9,0)
1533 * (0,0) (0,0) (5.9,0) (5.9,0)
1534 * (5.8,0) (5.8,0) (0,0) (0,0)
1535 * (5.8,0) (5.8,0) (0,0) (0,0)
1536 */
1538 "Face-to-face. 90 and 0 pol. slant angles.",
1539 Vector{0, 0, 3},
1540 MimoPolarizationAntennaParams(false, M_PI / 2, 0),
1541 Vector{6, 0, 3},
1542 MimoPolarizationAntennaParams(false, 0, M_PI),
1543 {0, 0, 5.8, 5.8, 0, 0, 5.8, 5.8, 5.9, 5.9, 0, 0, 5.9, 5.9, 0, 0},
1544 0.9),
1545 TestCase::Duration::QUICK);
1546
1547 /**
1548 * The TX and RX antennas are face to face. We test the configuration of
1549 * the bearing angle along with the configuration of the different position
1550 * of the RX antenna, and the bearing angles.
1551 * When polarization slant angles are 0 and 0 at TX and RX,
1552 * we expect the strongest cluster to be similar to the following matrix:
1553 * (5.9,0) (5.9,0) (0,0) (0,0)
1554 * (5.9,0) (5.9,0) (0,0) (0,0)
1555 * (0,0) (0,0) (-5.8,) (-5.8,0)
1556 * (0,0) (0,0) (-5.8,0) (-5.8,0)
1557 * Notice that we expect almost the same matrix as in the first case in
1558 * which
1559 */
1561 new ThreeGppMimoPolarizationTest("Face-to-face. Different positions. Different bearing "
1562 "angles. 0 and 0 pol. slant angles.",
1563 Vector{0, 0, 3},
1564 MimoPolarizationAntennaParams(false, 0, M_PI / 4),
1565 Vector{6.363961031, 6.363961031, 3},
1566 MimoPolarizationAntennaParams(false, 0, -(M_PI / 4) * 3),
1567 testChannel1,
1568 0.9),
1569 TestCase::Duration::QUICK);
1570
1571 /**
1572 * The TX and RX antenna have different height.
1573 * Bearing angle is configured to point one toward the other.
1574 * When polarization slant angles are 0 and 0 at TX and RX,
1575 * we expect the strongest cluster to be similar to the following matrix:
1576 * (2.5,-4.7) (2.5,-4.7) (0,0) (0,0)
1577 * (2.5,-4.7) (2.5,-4.7) (0,0) (0,0)
1578 * (0,0) (0,0) (-2.4,4) (-2.4,4)
1579 * (0,0) (0,0) (-2.4,4) (-2.4,4)
1580 */
1582 "Not face-to-face. Different heights. 0 and 0 pol. slant angles.",
1583 Vector{0, 0, 10},
1584 MimoPolarizationAntennaParams(false, 0, 0),
1585 Vector{30, 0, 3},
1586 MimoPolarizationAntennaParams(false, 0, M_PI),
1587 {{2.5, -4.7},
1588 {2.5, -4.7},
1589 0,
1590 0,
1591 {2.5, -4.7},
1592 {2.5, -4.7},
1593 0,
1594 0,
1595 0,
1596 0,
1597 {-2.4, 4},
1598 {-2.4, 4},
1599 0,
1600 0,
1601 {-2.4, 4},
1602 {-2.4, 4}},
1603 0.5),
1604 TestCase::Duration::QUICK);
1605}
1606
1607/// Static variable for test initialization
Test case for the ThreeGppChannelModel class.
uint32_t m_rxPorts
number of horizontal and vertical ports of rx antenna array
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_txAntennaElements
number of rows and columns of tx antenna array
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...
Ptr< const ThreeGppChannelModel::ChannelMatrix > m_currentChannel
used by DoGetChannel to store the current channel matrix
void DoRun() override
Build the test scenario.
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:107
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
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:124
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition object.cc:298
AttributeValue implementation for Pointer.
Smart pointer class similar to boost::intrusive_ptr.
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:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
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:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
int64_t GetMilliSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:397
Hold an unsigned integer type.
Definition uinteger.h:34
bool IsAlmostEqual(const ValArray< T > &rhs, T tol) const
Compare Valarray up to a given absolute tolerance.
Definition val-array.h:678
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:883
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#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:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > CreateObjectWithAttributes(Args... args)
Allocate an Object on the heap and initialize with a set of attributes.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#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:134
#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:327
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
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.