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 *
502 * Test case for the ThreeGppChannelModel class.
503 * It checks if the channel realizations are correctly
504 * updated after a change in the number of antenna elements.
505 */
507{
508 public:
509 /**
510 * Constructor
511 */
513
514 /**
515 * Destructor
516 */
518
519 private:
520 /**
521 * Build the test scenario
522 */
523 void DoRun() override;
524
525 /**
526 * This method is used to schedule the channel matrix computation at different
527 * time instants and to check if it correctly updated
528 * \param channelModel the ThreeGppChannelModel object used to generate the channel matrix
529 * \param txMob the mobility model of the first node
530 * \param rxMob the mobility model of the second node
531 * \param txAntenna the antenna object associated to the first node
532 * \param rxAntenna the antenna object associated to the second node
533 * \param update whether if the channel matrix should be updated or not
534 */
535 void DoGetChannel(Ptr<ThreeGppChannelModel> channelModel,
536 Ptr<MobilityModel> txMob,
537 Ptr<MobilityModel> rxMob,
538 Ptr<PhasedArrayModel> txAntenna,
539 Ptr<PhasedArrayModel> rxAntenna,
540 bool update);
541
543 m_currentChannel; //!< used by DoGetChannel to store the current channel matrix
544 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
545 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
546 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
547 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
548};
549
551 : TestCase("Check if the channel realizations are correctly updated after antenna port changes "
552 "during the simulation")
553{
554}
555
557{
558}
559
560void
562 Ptr<MobilityModel> txMob,
563 Ptr<MobilityModel> rxMob,
564 Ptr<PhasedArrayModel> txAntenna,
565 Ptr<PhasedArrayModel> rxAntenna,
566 bool update)
567{
568 // retrieve the channel matrix
570 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
571
573 {
574 // compare the old and the new channel matrices
575 NS_TEST_ASSERT_MSG_EQ((m_currentChannel->m_channel != channelMatrix->m_channel),
576 update,
578 << " The channel matrix is not correctly updated");
579 }
580 m_currentChannel = channelMatrix;
581}
582
583void
585{
586 // Build the scenario for the test
587 uint32_t updatePeriodMs = 100; // update period in ms
588
589 // create the channel condition model
590 Ptr<ChannelConditionModel> channelConditionModel =
591 CreateObject<AlwaysLosChannelConditionModel>();
592
593 // create the ThreeGppChannelModel object used to generate the channel matrix
594 Ptr<ThreeGppChannelModel> channelModel = CreateObject<ThreeGppChannelModel>();
595 channelModel->SetAttribute("Frequency", DoubleValue(60.0e9));
596 channelModel->SetAttribute("Scenario", StringValue("UMa"));
597 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
598 channelModel->SetAttribute("UpdatePeriod", TimeValue(MilliSeconds(updatePeriodMs)));
599
600 // create the tx and rx nodes
602 nodes.Create(2);
603
604 // create the tx and rx devices
605 Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
606 Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
607
608 // associate the nodes and the devices
609 nodes.Get(0)->AddDevice(txDev);
610 txDev->SetNode(nodes.Get(0));
611 nodes.Get(1)->AddDevice(rxDev);
612 rxDev->SetNode(nodes.Get(1));
613
614 // create the tx and rx mobility models and set their positions
615 Ptr<MobilityModel> txMob = CreateObject<ConstantPositionMobilityModel>();
616 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
617 Ptr<MobilityModel> rxMob = CreateObject<ConstantPositionMobilityModel>();
618 rxMob->SetPosition(Vector(100.0, 0.0, 1.6));
619
620 // associate the nodes and the mobility models
621 nodes.Get(0)->AggregateObject(txMob);
622 nodes.Get(1)->AggregateObject(rxMob);
623
624 // create the tx and rx antennas and set the their dimensions
625 Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
626 "NumColumns",
628 "NumRows",
630 "AntennaElement",
631 PointerValue(CreateObject<IsotropicAntennaModel>()),
632 "NumVerticalPorts",
634 "NumHorizontalPorts",
636
637 Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
638 "NumColumns",
640 "NumRows",
642 "AntennaElement",
643 PointerValue(CreateObject<IsotropicAntennaModel>()),
644 "NumVerticalPorts",
646 "NumHorizontalPorts",
648
649 // check if the channel matrix is correctly updated
650
651 // compute the channel matrix for the first time
654 this,
655 channelModel,
656 txMob,
657 rxMob,
658 txAntenna,
659 rxAntenna,
660 true);
661
662 // call GetChannel before the update period is exceeded, the channel matrix
663 // should not be updated
666 this,
667 channelModel,
668 txMob,
669 rxMob,
670 txAntenna,
671 rxAntenna,
672 false);
673
674 // after changing the number of antenna ports, the channel matrix
675 // should be recomputed
677 [&txAntenna]() { txAntenna->SetNumRows(txAntenna->GetNumRows() + 1); });
680 this,
681 channelModel,
682 txMob,
683 rxMob,
684 txAntenna,
685 rxAntenna,
686 true);
687
688 // after recomputing it once, the channel matrix should be cached
691 this,
692 channelModel,
693 txMob,
694 rxMob,
695 txAntenna,
696 rxAntenna,
697 false);
698
699 // after recomputing it once, the channel matrix should be cached
701 [&rxAntenna]() { rxAntenna->SetNumRows(rxAntenna->GetNumRows() + 1); });
704 this,
705 channelModel,
706 txMob,
707 rxMob,
708 txAntenna,
709 rxAntenna,
710 true);
711
712 // after recomputing it once, the channel matrix should be cached
715 this,
716 channelModel,
717 txMob,
718 rxMob,
719 txAntenna,
720 rxAntenna,
721 false);
722
725}
726
727/**
728 * \ingroup spectrum-tests
729 * \brief A structure that holds the parameters for the function
730 * CheckLongTermUpdate. In this way the problem with the limited
731 * number of parameters of method Schedule is avoided.
732 */
734{
736 lossModel; //!< the ThreeGppSpectrumPropagationLossModel object used to compute the rx PSD
737 Ptr<SpectrumSignalParameters> txParams; //!< the params of the tx signal
738 Ptr<MobilityModel> txMob; //!< the mobility model of the tx device
739 Ptr<MobilityModel> rxMob; //!< the mobility model of the rx device
740 Ptr<SpectrumValue> rxPsdOld; //!< the previously received PSD
741 Ptr<PhasedArrayModel> txAntenna; //!< the antenna array of the tx device
742 Ptr<PhasedArrayModel> rxAntenna; //!< the antenna array of the rx device
743};
744
745/**
746 * \ingroup spectrum-tests
747 *
748 * Test case for the ThreeGppSpectrumPropagationLossModelTest class.
749 * 1) checks if the long term components for the direct and the reverse link
750 * are the same
751 * 2) checks if the long term component is updated when changing the beamforming
752 * vectors
753 * 3) checks if the long term is updated when changing the channel matrix
754 */
756{
757 public:
758 /**
759 * Constructor
760 * \param txAntennaElements the number of rows and columns of the antenna array of the
761 * transmitter
762 * \param rxAntennaElements the number of rows and columns of the antenna array of
763 * the receiver
764 * \param txPorts the number of vertical and horizontal ports of the antenna array
765 * of the transmitter
766 * \param rxPorts the number of vertical and horizontal ports of the antenna
767 * array of the receiver
768 */
770 uint32_t rxAntennaElements = 4,
771 uint32_t txPorts = 1,
772 uint32_t rxPorts = 1);
773 /**
774 * Destructor
775 */
777
778 private:
779 /**
780 * Build the test scenario
781 */
782 void DoRun() override;
783
784 /**
785 * Points the beam of thisDevice towards otherDevice
786 * \param thisDevice the device to configure
787 * \param thisAntenna the antenna object associated to thisDevice
788 * \param otherDevice the device to communicate with
789 * \param otherAntenna the antenna object associated to otherDevice
790 */
791 void DoBeamforming(Ptr<NetDevice> thisDevice,
792 Ptr<PhasedArrayModel> thisAntenna,
793 Ptr<NetDevice> otherDevice,
794 Ptr<PhasedArrayModel> otherAntenna);
795
796 /**
797 * Test of the long term component is correctly updated when the channel
798 * matrix is recomputed
799 * \param params a structure that contains the set of parameters needed by CheckLongTermUpdate
800 * in order to perform calculations
801 */
803
804 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
805 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
806 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
807 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
808};
809
811 uint32_t txAntennaElements,
812 uint32_t rxAntennaElements,
813 uint32_t txPorts,
814 uint32_t rxPorts)
815 : TestCase("Test case for the ThreeGppSpectrumPropagationLossModel class")
816{
817 m_txAntennaElements = txAntennaElements;
818 m_rxAntennaElements = rxAntennaElements;
819 m_txPorts = txPorts;
820 m_rxPorts = rxPorts;
821}
822
824{
825}
826
827void
829 Ptr<PhasedArrayModel> thisAntenna,
830 Ptr<NetDevice> otherDevice,
831 Ptr<PhasedArrayModel> otherAntenna)
832{
833 Vector aPos = thisDevice->GetNode()->GetObject<MobilityModel>()->GetPosition();
834 Vector bPos = otherDevice->GetNode()->GetObject<MobilityModel>()->GetPosition();
835
836 // compute the azimuth and the elevation angles
837 Angles completeAngle(bPos, aPos);
838
839 PhasedArrayModel::ComplexVector antennaWeights =
840 thisAntenna->GetBeamformingVector(completeAngle);
841 thisAntenna->SetBeamformingVector(antennaWeights);
842}
843
844void
846 const CheckLongTermUpdateParams& params)
847{
848 auto rxPsdNewParams = params.lossModel->DoCalcRxPowerSpectralDensity(params.txParams,
849 params.txMob,
850 params.rxMob,
851 params.txAntenna,
852 params.rxAntenna);
853 NS_TEST_ASSERT_MSG_EQ((*params.rxPsdOld == *rxPsdNewParams->psd),
854 false,
855 "The long term is not updated when the channel matrix is recomputed");
856}
857
858void
860{
861 // Build the scenario for the test
862 Config::SetDefault("ns3::ThreeGppChannelModel::UpdatePeriod", TimeValue(MilliSeconds(100)));
863
864 // create the ChannelConditionModel object to be used to retrieve the
865 // channel condition
866 Ptr<ChannelConditionModel> condModel = CreateObject<AlwaysLosChannelConditionModel>();
867
868 // create the ThreeGppSpectrumPropagationLossModel object, set frequency,
869 // scenario and channel condition model to be used
871 CreateObject<ThreeGppSpectrumPropagationLossModel>();
872 lossModel->SetChannelModelAttribute("Frequency", DoubleValue(2.4e9));
873 lossModel->SetChannelModelAttribute("Scenario", StringValue("UMa"));
874 lossModel->SetChannelModelAttribute(
875 "ChannelConditionModel",
876 PointerValue(condModel)); // create the ThreeGppChannelModel object used to generate the
877 // channel matrix
878
879 // create the tx and rx nodes
881 nodes.Create(2);
882
883 // create the tx and rx devices
884 Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
885 Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
886
887 // associate the nodes and the devices
888 nodes.Get(0)->AddDevice(txDev);
889 txDev->SetNode(nodes.Get(0));
890 nodes.Get(1)->AddDevice(rxDev);
891 rxDev->SetNode(nodes.Get(1));
892
893 // create the tx and rx mobility models and set their positions
894 Ptr<MobilityModel> txMob = CreateObject<ConstantPositionMobilityModel>();
895 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
896 Ptr<MobilityModel> rxMob = CreateObject<ConstantPositionMobilityModel>();
897 rxMob->SetPosition(
898 Vector(15.0, 0.0, 10.0)); // in this position the channel condition is always LOS
899
900 // associate the nodes and the mobility models
901 nodes.Get(0)->AggregateObject(txMob);
902 nodes.Get(1)->AggregateObject(rxMob);
903
904 // create the tx and rx antennas and set the their dimensions
905 Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
906 "NumColumns",
908 "NumRows",
910 "AntennaElement",
911 PointerValue(CreateObject<IsotropicAntennaModel>()),
912 "NumVerticalPorts",
914 "NumHorizontalPorts",
916
917 Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
918 "NumColumns",
920 "NumRows",
922 "AntennaElement",
923 PointerValue(CreateObject<IsotropicAntennaModel>()),
924 "NumVerticalPorts",
926 "NumHorizontalPorts",
928
929 // set the beamforming vectors
930 DoBeamforming(txDev, txAntenna, rxDev, rxAntenna);
931 DoBeamforming(rxDev, rxAntenna, txDev, txAntenna);
932
933 // create the tx psd
935 double txPower = 0.1; // Watts
936 uint32_t channelNumber = 1;
937 Ptr<SpectrumValue> txPsd = sf.CreateTxPowerSpectralDensity(txPower, channelNumber);
938 Ptr<SpectrumSignalParameters> txParams = Create<SpectrumSignalParameters>();
939 txParams->psd = txPsd->Copy();
940
941 // compute the rx psd
942 auto rxParamsOld =
943 lossModel->DoCalcRxPowerSpectralDensity(txParams, txMob, rxMob, txAntenna, rxAntenna);
944
945 // 1) check that the rx PSD is equal for both the direct and the reverse channel
946 auto rxParamsNew =
947 lossModel->DoCalcRxPowerSpectralDensity(txParams, rxMob, txMob, rxAntenna, txAntenna);
948 NS_TEST_ASSERT_MSG_EQ((*rxParamsOld->psd == *rxParamsNew->psd),
949 true,
950 "The long term for the direct and the reverse channel are different");
951
952 // 2) check if the long term is updated when changing the BF vector
953 // change the position of the rx device and recompute the beamforming vectors
954 rxMob->SetPosition(Vector(10.0, 5.0, 10.0));
955 PhasedArrayModel::ComplexVector txBfVector = txAntenna->GetBeamformingVector();
956 txBfVector[0] = std::complex<double>(0.0, 0.0);
957 txAntenna->SetBeamformingVector(txBfVector);
958
959 rxParamsNew =
960 lossModel->DoCalcRxPowerSpectralDensity(txParams, rxMob, txMob, rxAntenna, txAntenna);
961 NS_TEST_ASSERT_MSG_EQ((*rxParamsOld->psd == *rxParamsNew->psd),
962 false,
963 "Changing the BF vectors the rx PSD does not change");
964
966 (*rxParamsOld->spectrumChannelMatrix == *rxParamsNew->spectrumChannelMatrix),
967 false,
968 "Changing the BF should change de frequency domain channel matrix");
969
970 // update rxPsdOld
971 rxParamsOld = rxParamsNew;
972
973 // 3) check if the long term is updated when the channel matrix is recomputed
975 params{lossModel, txParams, txMob, rxMob, rxParamsOld->psd, txAntenna, rxAntenna};
978 this,
979 params);
980
983}
984
985/**
986 * \ingroup spectrum-tests
987 *
988 * Test case that test the correct use of the multi-port antennas in spectrum.
989 * The test does the following:
990 * 1) Generates a time domain channel matrix of a fixed size
991 * (num gNB elements = 32 (4x8), num UE elements = 16 (4x4), num Clusters).
992 * This matrix is called channelMatrixM0.
993 * 2) Divides gNB antenna and UE antenna into ports using a fixed element to port
994 * mapping (gNB: 1 vertical port, 4 horizontal ports, UE: 1 vertical port,
995 * 2 horizontal ports). Using the channelMatrixM0, it generates port to port
996 * long term channel matrix using the both gNB and UE having beams directed towards the other.
997 * The resulting long term matrix dimensions are gNBports = 4, UE ports = 2, num Clusters.
998 * This channel matrix is called matrixA.
999 * 3) Constructs a single port to single port long term channel matrix
1000 * using the initial time domain channel matrix (channelMatrixM0) and beams
1001 * from gNB and UE towards each other. Single port mapping means gNB: 1 vertical port,
1002 * 1 horizontal port, UE: 1 vertical port, 1 horizontal port.
1003 * Matrix dimensions are: gNBports = 1, UE ports = 1, num Clusters. This long
1004 * term channel matrix is called matrixB.
1005 * 4) Creates a single port to single port long term channel matrix between
1006 * two virtual gNB and UE antenna by using matrixA and beam facing each other.
1007 * Matrix dimension of the resulting matrix are gNBports = 1, UE ports = 1, num Clusters.
1008 * This long term channel matrix is called matrixC.
1009 * 5) Checks that matrixB and matrixC are identical.
1010 */
1012{
1013 public:
1014 /**
1015 * Constructor
1016 */
1018
1019 /**
1020 * Destructor
1021 */
1023
1024 private:
1025 /**
1026 * Build the test scenario
1027 */
1028 void DoRun() override;
1029};
1030
1032 : TestCase("Check long term channel matrix generation when multiple ports at TX and RX are "
1033 "being used.")
1034{
1035}
1036
1038{
1039}
1040
1041void
1043{
1044 // create the channel condition model
1045 Ptr<ChannelConditionModel> channelConditionModel =
1046 CreateObject<AlwaysLosChannelConditionModel>();
1047
1048 // create the ThreeGppChannelModel object used to generate the channel matrix
1049 Ptr<ThreeGppChannelModel> channelModel = CreateObject<ThreeGppChannelModel>();
1050 channelModel->SetAttribute("Frequency", DoubleValue(2.0e9));
1051 channelModel->SetAttribute("Scenario", StringValue("RMa"));
1052 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
1053
1054 // create the tx and rx nodes
1056 nodes.Create(2);
1057
1058 // create the tx and rx devices
1059 Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
1060 Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
1061
1062 // associate the nodes and the devices
1063 nodes.Get(0)->AddDevice(txDev);
1064 txDev->SetNode(nodes.Get(0));
1065 nodes.Get(1)->AddDevice(rxDev);
1066 rxDev->SetNode(nodes.Get(1));
1067
1068 // create the tx and rx mobility models and set their positions
1069 Ptr<MobilityModel> txMob = CreateObject<ConstantPositionMobilityModel>();
1070 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
1071 Ptr<MobilityModel> rxMob = CreateObject<ConstantPositionMobilityModel>();
1072 rxMob->SetPosition(Vector(10.0, 0.0, 10.0));
1073
1074 // associate the nodes and the mobility models
1075 nodes.Get(0)->AggregateObject(txMob);
1076 nodes.Get(1)->AggregateObject(rxMob);
1077
1078 // create the tx and rx antennas and set the their dimensions
1079 Ptr<PhasedArrayModel> txAntenna1 = CreateObjectWithAttributes<UniformPlanarArray>(
1080 "NumColumns",
1081 UintegerValue(8),
1082 "NumRows",
1083 UintegerValue(4),
1084 "AntennaElement",
1085 PointerValue(CreateObject<IsotropicAntennaModel>()),
1086 "NumVerticalPorts",
1087 UintegerValue(1),
1088 "NumHorizontalPorts",
1089 UintegerValue(4));
1090
1091 Ptr<PhasedArrayModel> rxAntenna1 = CreateObjectWithAttributes<UniformPlanarArray>(
1092 "NumColumns",
1093 UintegerValue(4),
1094 "NumRows",
1095 UintegerValue(4),
1096 "AntennaElement",
1097 PointerValue(CreateObject<IsotropicAntennaModel>()),
1098 "NumVerticalPorts",
1099 UintegerValue(1),
1100 "NumHorizontalPorts",
1101 UintegerValue(2));
1102
1103 // compute the azimuth and the elevation angles
1104 Angles completeAngleTxRx(rxMob->GetPosition(), txMob->GetPosition());
1105 Angles completeAngleRxTx(txMob->GetPosition(), rxMob->GetPosition());
1106
1107 txAntenna1->SetBeamformingVector(txAntenna1->GetBeamformingVector(completeAngleTxRx));
1108 rxAntenna1->SetBeamformingVector(rxAntenna1->GetBeamformingVector(completeAngleRxTx));
1109
1110 // generate the channel matrix
1112 channelModel->GetChannel(txMob, rxMob, txAntenna1, rxAntenna1);
1113
1114 // create ThreeGppSpectrumPropagationLossModel instance so that we
1115 // can call CalcLongTerm
1117 CreateObject<ThreeGppSpectrumPropagationLossModel>();
1118
1120 threeGppSplm->CalcLongTerm(channelMatrixM0, txAntenna1, rxAntenna1);
1121
1122 // create the tx and rx antennas and set the their dimensions
1123 Ptr<PhasedArrayModel> txAntenna2 = CreateObjectWithAttributes<UniformPlanarArray>(
1124 "NumColumns",
1125 UintegerValue(8),
1126 "NumRows",
1127 UintegerValue(4),
1128 "AntennaElement",
1129 PointerValue(CreateObject<IsotropicAntennaModel>()),
1130 "NumVerticalPorts",
1131 UintegerValue(1),
1132 "NumHorizontalPorts",
1133 UintegerValue(1));
1134
1135 Ptr<PhasedArrayModel> rxAntenna2 = CreateObjectWithAttributes<UniformPlanarArray>(
1136 "NumColumns",
1137 UintegerValue(4),
1138 "NumRows",
1139 UintegerValue(4),
1140 "AntennaElement",
1141 PointerValue(CreateObject<IsotropicAntennaModel>()),
1142 "NumVerticalPorts",
1143 UintegerValue(1),
1144 "NumHorizontalPorts",
1145 UintegerValue(1));
1146
1147 txAntenna2->SetBeamformingVector(txAntenna2->GetBeamformingVector(completeAngleTxRx));
1148 rxAntenna2->SetBeamformingVector(rxAntenna2->GetBeamformingVector(completeAngleRxTx));
1149
1151 threeGppSplm->CalcLongTerm(channelMatrixM0, txAntenna2, rxAntenna2);
1152
1153 // create the tx and rx antennas and set the their dimensions
1154 Ptr<PhasedArrayModel> txAntenna3 = CreateObjectWithAttributes<UniformPlanarArray>(
1155 "NumColumns",
1156 UintegerValue(4),
1157 "NumRows",
1158 UintegerValue(1),
1159 "AntennaElement",
1160 PointerValue(CreateObject<IsotropicAntennaModel>()),
1161 "NumVerticalPorts",
1162 UintegerValue(1),
1163 "NumHorizontalPorts",
1164 UintegerValue(1),
1165 "AntennaHorizontalSpacing",
1166 DoubleValue(1));
1167
1168 Ptr<PhasedArrayModel> rxAntenna3 = CreateObjectWithAttributes<UniformPlanarArray>(
1169 "NumColumns",
1170 UintegerValue(2),
1171 "NumRows",
1172 UintegerValue(1),
1173 "AntennaElement",
1174 PointerValue(CreateObject<IsotropicAntennaModel>()),
1175 "NumVerticalPorts",
1176 UintegerValue(1),
1177 "NumHorizontalPorts",
1178 UintegerValue(1),
1179 "AntennaHorizontalSpacing",
1180 DoubleValue(1));
1181
1183 Create<ThreeGppChannelModel::ChannelMatrix>();
1184 channelMatrixMA->m_channel = *matrixA;
1185
1186 txAntenna3->SetBeamformingVector(txAntenna3->GetBeamformingVector(completeAngleTxRx));
1187 rxAntenna3->SetBeamformingVector(rxAntenna3->GetBeamformingVector(completeAngleRxTx));
1188
1190 threeGppSplm->CalcLongTerm(channelMatrixMA, txAntenna3, rxAntenna3);
1191
1192 NS_TEST_ASSERT_MSG_EQ(matrixB->IsAlmostEqual(*matrixC, 1e-6),
1193 true,
1194 "Matrix B and Matrix C should be equal.");
1195
1198}
1199
1200/**
1201 * Structure that contains some of the main configuration parameters of the antenna
1202 * array that are used in the ThreeGppMimoPolarizationTest
1203 */
1205{
1206 uint32_t m_rows = 1; //!< the number of rows of antenna array
1207 uint32_t m_cols = 2; //!< the number of columns of antenna array
1208 uint32_t m_vPorts = 1; //!< the number of vertical ports of antenna array
1209 uint32_t m_hPorts = 2; //!< the number of horizontal ports of antenna array
1210 bool m_isotropic = false; //!< defines whether the antenna elements are isotropic
1211 double m_polSlantAngle = 0; //!< polarization angle of the antenna array
1212 double m_bearingAngle = 0; //!< bearing angle of the antenna array
1213
1214 /**
1215 * Constructor
1216 * Currently only configurable through constructor are polSlantAngle and bearingAngle.
1217 * \param isotropic whether the antenna elements are isotropic, or 3GPP
1218 * \param polSlantAngle the polarization slant angle
1219 * \param bearingAngle the bearing angle
1220 */
1221 MimoPolarizationAntennaParams(bool isotropic, double polSlantAngle = 0, double bearingAngle = 0)
1222 : m_isotropic(isotropic),
1223 m_polSlantAngle(polSlantAngle),
1224 m_bearingAngle(bearingAngle)
1225 {
1226 }
1227};
1228
1229/**
1230 * \ingroup spectrum-tests
1231 * This test tests that the channel matrix is correctly generated when dual-polarized
1232 * antennas are being used at TX and RX. In the conditions in which the channel between
1233 * the TX and Rx device is LOS channel, and the beams of the transmitter and the
1234 * receiver are pointing one towards the other, then in the presence of multiple ports
1235 * at the TX and RX, and the antenna array at the TX and RX are dual polarized,
1236 * the channel matrix should exhibit the strong symmetry between the two polarizations.
1237 * E.g. if we have 1x2 antenna elements and two polarizations at both TX and RX,
1238 * and the 1x2 ports at the TX and RX, then the channel matrix will have the
1239 * structure as:
1240 *
1241 * ch00 ch01 |ch02 ch03
1242 * Hvv Hvh ch10 ch11 |ch12 ch13
1243 * = --------------------
1244 * Hhv Hhh ch20 ch21 |ch22 ch23
1245 * ch30 ch31 |ch32 ch33
1246 *
1247 * We test different cases of the polarization slant angles of the TX and RX,
1248 * e.g., 0, 30, 45, 90.
1249 * In each of these setups we check if the channel matrix in its strongest
1250 * cluster experiences strong symmetry, and if the values appear in pairs.
1251 * We also test additional cases in which we change the bearing angle and
1252 * the height of the TX. In these cases we also observe strong symmetry, with
1253 * the difference that in these cases we can observe different values in the
1254 * pairs. We can still observe strong impact of the dual polarization on the
1255 * channel matrix.
1256 */
1258{
1259 public:
1260 /**
1261 * Constructor that receives MIMO polarization parameters of TX and RX
1262 * devices
1263 * \param testCaseName the test case name
1264 * \param txLoc the position of the transmitter
1265 * \param txAntennaParams the antenna parameters of the transmitter
1266 * \param rxLoc the position of the receiver
1267 * \param rxAntennaParams the antenna parameters of the receiver
1268 * \param testChannel the test matrix that represent the strongest cluster
1269 * \param tolerance the tolerance to be used when testing
1270 */
1271 ThreeGppMimoPolarizationTest(std::string testCaseName,
1272 Vector txLoc,
1273 const MimoPolarizationAntennaParams& txAntennaParams,
1274 Vector rxLoc,
1275 const MimoPolarizationAntennaParams& rxAntennaParams,
1276 std::valarray<std::complex<double>> testChannel,
1277 double tolerance);
1278
1279 /**
1280 * Destructor
1281 */
1283
1284 private:
1285 /**
1286 * Build the test scenario
1287 */
1288 void DoRun() override;
1289
1290 /**
1291 * @brief Function that can be used to configure the antenna using the set of
1292 * parameters.
1293 *
1294 * @param params The parameters to be set to the antenna
1295 * @return A pointer to the antenna that is created and configured by using input params
1296 */
1298
1299 Vector m_txLoc; //!< Position of the TX device
1300 MimoPolarizationAntennaParams m_txParams; //!< Parameters used to configure the TX antenna array
1301 Vector m_rxLoc; //!< Position of the RX device
1302 MimoPolarizationAntennaParams m_rxParams; //!< Parameters used to configure the RX antenna array
1303 std::valarray<std::complex<double>>
1304 m_testChannel; //!< The test value for the matrix representing the strongest cluster
1305 double m_tolerance; //!< The tolerance to be used when comparing the channel matrix with the
1306 //!< test matrix
1307};
1308
1310 std::string testCaseName,
1311 Vector txLoc,
1312 const MimoPolarizationAntennaParams& txParams,
1313 Vector rxLoc,
1314 const MimoPolarizationAntennaParams& rxParams,
1315 std::valarray<std::complex<double>> testChannel,
1316 double tolerance)
1317 : TestCase("Test MIMO using dual polarization." + testCaseName),
1318 m_txLoc(txLoc),
1319 m_txParams(txParams),
1320 m_rxLoc(rxLoc),
1321 m_rxParams(rxParams),
1322 m_testChannel(testChannel),
1323 m_tolerance(tolerance)
1324{
1325}
1326
1328{
1329}
1330
1333{
1334 NS_LOG_FUNCTION(this);
1335 Ptr<AntennaModel> antenna;
1336 if (params.m_isotropic)
1337 {
1338 antenna = CreateObject<IsotropicAntennaModel>();
1339 }
1340 else
1341 {
1342 antenna = CreateObject<ThreeGppAntennaModel>();
1343 }
1344 // create the tx and rx antennas and set the their dimensions
1345 return CreateObjectWithAttributes<UniformPlanarArray>("NumColumns",
1346 UintegerValue(params.m_cols),
1347 "NumRows",
1348 UintegerValue(params.m_rows),
1349 "AntennaElement",
1350 PointerValue(antenna),
1351 "NumVerticalPorts",
1352 UintegerValue(params.m_vPorts),
1353 "NumHorizontalPorts",
1354 UintegerValue(params.m_hPorts),
1355 "BearingAngle",
1356 DoubleValue(params.m_bearingAngle),
1357 "PolSlantAngle",
1358 DoubleValue(params.m_polSlantAngle),
1359 "IsDualPolarized",
1360 BooleanValue(true));
1361}
1362
1363void
1365{
1368 // create the ThreeGppChannelModel object used to generate the channel matrix
1369 Ptr<ThreeGppChannelModel> channelModel = CreateObject<ThreeGppChannelModel>();
1370 channelModel->SetAttribute("Frequency", DoubleValue(60e9));
1371 channelModel->SetAttribute("Scenario", StringValue("RMa"));
1372 channelModel->SetAttribute("ChannelConditionModel",
1373 PointerValue(CreateObject<AlwaysLosChannelConditionModel>()));
1374
1375 int64_t randomStream = 1;
1376 randomStream += channelModel->AssignStreams(randomStream);
1377
1378 // create the tx and rx nodes
1380 nodes.Create(2);
1381
1382 // create the tx and rx devices
1383 Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
1384 Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
1385
1386 // associate the nodes and the devices
1387 nodes.Get(0)->AddDevice(txDev);
1388 txDev->SetNode(nodes.Get(0));
1389 nodes.Get(1)->AddDevice(rxDev);
1390 rxDev->SetNode(nodes.Get(1));
1391
1392 // create the tx and rx mobility models and set their positions
1393 Ptr<MobilityModel> txMob = CreateObject<ConstantPositionMobilityModel>();
1394 txMob->SetPosition(m_txLoc);
1395 Ptr<MobilityModel> rxMob = CreateObject<ConstantPositionMobilityModel>();
1396 rxMob->SetPosition(m_rxLoc);
1397
1398 // associate the nodes and the mobility models
1399 nodes.Get(0)->AggregateObject(txMob);
1400 nodes.Get(1)->AggregateObject(rxMob);
1401
1402 // create the tx and rx antennas and set the their dimensions
1405
1406 // configure direct beamforming vectors to point to each other
1407 txAntenna->SetBeamformingVector(
1408 txAntenna->GetBeamformingVector(Angles(rxMob->GetPosition(), txMob->GetPosition())));
1409 rxAntenna->SetBeamformingVector(
1410 rxAntenna->GetBeamformingVector(Angles(txMob->GetPosition(), rxMob->GetPosition())));
1411
1412 // generate the time domain channel matrix
1414 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
1415
1416 // test whether the channel matrix for the first cluster experiences strong
1417 // symmetry that is caused by existence of dual polarized ports at the
1418 // transmitter and the receiver
1419 const std::complex<double>* strongestClusterPtr = channelMatrix->m_channel.GetPagePtr(0);
1420 size_t matrixSize =
1421 channelMatrix->m_channel.GetNumRows() * channelMatrix->m_channel.GetNumCols();
1422
1424 channelMatrix->m_channel.GetNumRows(),
1425 channelMatrix->m_channel.GetNumCols(),
1426 std::valarray<std::complex<double>>(strongestClusterPtr, matrixSize));
1427
1428 MatrixBasedChannelModel::Complex2DVector testChannel(channelMatrix->m_channel.GetNumRows(),
1429 channelMatrix->m_channel.GetNumCols(),
1431
1432 NS_LOG_INFO("Channel matrix:" << strongestCluster);
1433 NS_LOG_INFO("Test channel matrix: " << testChannel);
1434
1436 strongestCluster.IsAlmostEqual(testChannel, m_tolerance),
1437 true,
1438 "The strongest cluster and the test channel matrix should be almost equal");
1439
1442}
1443
1444/**
1445 * \ingroup spectrum-tests
1446 *
1447 * Test suite for the ThreeGppChannelModel class
1448 */
1450{
1451 public:
1452 /**
1453 * Constructor
1454 */
1456};
1457
1459 : TestSuite("three-gpp-channel", Type::UNIT)
1460{
1461 AddTestCase(new ThreeGppChannelMatrixComputationTest(2, 2, 1, 1), TestCase::Duration::QUICK);
1462 AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 2, 1, 1), TestCase::Duration::QUICK);
1463 AddTestCase(new ThreeGppChannelMatrixComputationTest(2, 2, 2, 2), TestCase::Duration::QUICK);
1464 AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 4, 2, 2), TestCase::Duration::QUICK);
1465 AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 2, 2, 1), TestCase::Duration::QUICK);
1466 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 4, 1, 1), TestCase::Duration::QUICK);
1467 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 1, 1), TestCase::Duration::QUICK);
1468 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 4, 2, 2), TestCase::Duration::QUICK);
1469 AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 2, 2), TestCase::Duration::QUICK);
1470 AddTestCase(new ThreeGppAntennaSetupChangedTest(), TestCase::Duration::QUICK);
1472 TestCase::Duration::QUICK);
1474 TestCase::Duration::QUICK);
1476 TestCase::Duration::QUICK);
1478 TestCase::Duration::QUICK);
1479 AddTestCase(new ThreeGppCalcLongTermMultiPortTest(), TestCase::Duration::QUICK);
1480
1481 /**
1482 * The TX and RX antennas are configured face-to-face.
1483 * When polarization slant angles are 0 and 0 at TX and RX,
1484 * we expect the strongest cluster to be similar to the following matrix:
1485 * (5.9,0) (5.9,0) (0,0) (0,0)
1486 * (5.9,0) (5.9,0) (0,0) (0,0)
1487 * (0,0) (0,0) (-5.8,) (-5.8,0)
1488 * (0,0) (0,0) (-5.8,0) (-5.8,0)
1489 */
1490 std::valarray<std::complex<double>> testChannel1 =
1491 {5.9, 5.9, 0, 0, 5.9, 5.9, 0, 0, 0, 0, -5.8, -5.8, 0, 0, -5.8, -5.8};
1492 AddTestCase(new ThreeGppMimoPolarizationTest("Face-to-face. 0 and 0 pol. slant angles.",
1493 Vector{0, 0, 3},
1494 MimoPolarizationAntennaParams(false, 0, 0),
1495 Vector{9, 0, 3},
1496 MimoPolarizationAntennaParams(false, 0, M_PI),
1497 testChannel1,
1498 0.9),
1499 TestCase::Duration::QUICK);
1500
1501 /**
1502 * The TX and RX antennas are configured face-to-face.
1503 * When polarization slant angles are 30 and 0 at TX and RX,
1504 * we expect the strongest cluster to be similar to the following matrix:
1505 * (5,0) (5,0) (3,0) (3,0)
1506 * (5,0) (5,0) (3,0) (3,0)
1507 * (3,0) (3,0) (-5,0) (-5,0)
1508 * (3,0) (3,0) (-5,0) (-5,0)
1509 */
1511 new ThreeGppMimoPolarizationTest("Face-to-face. 30 and 0 pol. slant angles.",
1512 Vector{0, 0, 3},
1513 MimoPolarizationAntennaParams(false, M_PI / 6, 0),
1514 Vector{6, 0, 3},
1515 MimoPolarizationAntennaParams(false, 0, M_PI),
1516 {5, 5, 3, 3, 5, 5, 3, 3, 3, 3, -5, -5, 3, 3, -5, -5},
1517 0.8),
1518 TestCase::Duration::QUICK);
1519
1520 /**
1521 * The TX and RX antennas are configured face-to-face.
1522 * When polarization slant angles are 45 and 0 at TX and RX,
1523 * we expect the strongest cluster to be similar to the following matrix:
1524 * (4,0) (4,0) (4,0) (4,0)
1525 * (4,0) (4,0) (4,0) (4,0)
1526 * (4,0) (4,0) (4,0) (4,0)
1527 * (4,0) (4,0) (4,0) (4,0)
1528 */
1530 new ThreeGppMimoPolarizationTest("Face-to-face. 45 and 0 pol. slant angles.",
1531 Vector{0, 0, 3},
1532 MimoPolarizationAntennaParams(false, M_PI / 4, 0),
1533 Vector{6, 0, 3},
1534 MimoPolarizationAntennaParams(false, 0, M_PI),
1535 {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -4, -4, 4, 4, -4, -4},
1536 0.7),
1537 TestCase::Duration::QUICK);
1538
1539 /**
1540 * The TX and RX antennas are configured face-to-face.
1541 * When polarization slant angles are 45 and 0 at TX and RX,
1542 * we expect the strongest cluster to be similar to the following matrix:
1543 * (0,0) (0,0) (5.9,0) (5.9,0)
1544 * (0,0) (0,0) (5.9,0) (5.9,0)
1545 * (5.8,0) (5.8,0) (0,0) (0,0)
1546 * (5.8,0) (5.8,0) (0,0) (0,0)
1547 */
1549 "Face-to-face. 90 and 0 pol. slant angles.",
1550 Vector{0, 0, 3},
1551 MimoPolarizationAntennaParams(false, M_PI / 2, 0),
1552 Vector{6, 0, 3},
1553 MimoPolarizationAntennaParams(false, 0, M_PI),
1554 {0, 0, 5.8, 5.8, 0, 0, 5.8, 5.8, 5.9, 5.9, 0, 0, 5.9, 5.9, 0, 0},
1555 0.9),
1556 TestCase::Duration::QUICK);
1557
1558 /**
1559 * The TX and RX antennas are face to face. We test the configuration of
1560 * the bearing angle along with the configuration of the different position
1561 * of the RX antenna, and the bearing angles.
1562 * When polarization slant angles are 0 and 0 at TX and RX,
1563 * we expect the strongest cluster to be similar to the following matrix:
1564 * (5.9,0) (5.9,0) (0,0) (0,0)
1565 * (5.9,0) (5.9,0) (0,0) (0,0)
1566 * (0,0) (0,0) (-5.8,) (-5.8,0)
1567 * (0,0) (0,0) (-5.8,0) (-5.8,0)
1568 * Notice that we expect almost the same matrix as in the first case in
1569 * which
1570 */
1572 new ThreeGppMimoPolarizationTest("Face-to-face. Different positions. Different bearing "
1573 "angles. 0 and 0 pol. slant angles.",
1574 Vector{0, 0, 3},
1575 MimoPolarizationAntennaParams(false, 0, M_PI / 4),
1576 Vector{6.363961031, 6.363961031, 3},
1577 MimoPolarizationAntennaParams(false, 0, -(M_PI / 4) * 3),
1578 testChannel1,
1579 0.9),
1580 TestCase::Duration::QUICK);
1581
1582 /**
1583 * The TX and RX antenna have different height.
1584 * Bearing angle is configured to point one toward the other.
1585 * When polarization slant angles are 0 and 0 at TX and RX,
1586 * we expect the strongest cluster to be similar to the following matrix:
1587 * (2.5,-4.7) (2.5,-4.7) (0,0) (0,0)
1588 * (2.5,-4.7) (2.5,-4.7) (0,0) (0,0)
1589 * (0,0) (0,0) (-2.4,4) (-2.4,4)
1590 * (0,0) (0,0) (-2.4,4) (-2.4,4)
1591 */
1593 "Not face-to-face. Different heights. 0 and 0 pol. slant angles.",
1594 Vector{0, 0, 10},
1595 MimoPolarizationAntennaParams(false, 0, 0),
1596 Vector{30, 0, 3},
1597 MimoPolarizationAntennaParams(false, 0, M_PI),
1598 {{2.5, -4.7},
1599 {2.5, -4.7},
1600 0,
1601 0,
1602 {2.5, -4.7},
1603 {2.5, -4.7},
1604 0,
1605 0,
1606 0,
1607 0,
1608 {-2.4, 4},
1609 {-2.4, 4},
1610 0,
1611 0,
1612 {-2.4, 4},
1613 {-2.4, 4}},
1614 0.5),
1615 TestCase::Duration::QUICK);
1616}
1617
1618/// 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:118
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:302
A suite of tests to run.
Definition: test.h:1273
Type
Type of test.
Definition: test.h:1280
int64_t GetMilliSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:408
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.