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 * Copyright (c) 2026, Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include "ns3/abort.h"
8#include "ns3/angles.h"
9#include "ns3/boolean.h"
10#include "ns3/channel-condition-model.h"
11#include "ns3/config.h"
12#include "ns3/constant-position-mobility-model.h"
13#include "ns3/constant-velocity-mobility-model.h"
14#include "ns3/double.h"
15#include "ns3/ism-spectrum-value-helper.h"
16#include "ns3/isotropic-antenna-model.h"
17#include "ns3/log.h"
18#include "ns3/node-container.h"
19#include "ns3/pointer.h"
20#include "ns3/rng-seed-manager.h"
21#include "ns3/simulator.h"
22#include "ns3/spectrum-signal-parameters.h"
23#include "ns3/string.h"
24#include "ns3/test.h"
25#include "ns3/three-gpp-antenna-model.h"
26#include "ns3/three-gpp-channel-model.h"
27#include "ns3/three-gpp-spectrum-propagation-loss-model.h"
28#include "ns3/uinteger.h"
29#include "ns3/uniform-planar-array.h"
30
31#include <valarray>
32
33using namespace ns3;
34
35NS_LOG_COMPONENT_DEFINE("ThreeGppChannelTestSuite");
36
37/**
38 * @ingroup spectrum-tests
39 *
40 * Test case for the ThreeGppChannelModel class.
41 * 1) check if the channel matrix has the correct dimensions
42 * 2) check if the channel matrix is correctly normalized
43 */
45{
46 public:
47 /**
48 *Constructor
49 * @param txAntennaElements the number of rows and columns of the antenna array of the
50 * transmitter
51 * @param rxAntennaElements the number of rows and columns of the antenna array of
52 * @param txPorts the number of vertical and horizontal ports of the antenna array
53 * of the transmitter
54 * @param rxPorts the number of vertical and horizontal ports of the antenna
55 * array of the receiver
56 */
58 uint32_t rxAntennaElements = 2,
59 uint32_t txPorts = 1,
60 uint32_t rxPorts = 1);
61
62 /**
63 * Destructor
64 */
66
67 private:
68 /**
69 * Build the test scenario
70 */
71 void DoRun() override;
72
73 /**
74 * Compute the Frobenius norm of the channel matrix and stores it in m_normVector
75 * @param channelModel the ThreeGppChannelModel object used to generate the channel matrix
76 * @param txMob the mobility model of the first node
77 * @param rxMob the mobility model of the second node
78 * @param txAntenna the antenna object associated to the first node
79 * @param rxAntenna the antenna object associated to the second node
80 */
84 Ptr<PhasedArrayModel> txAntenna,
85 Ptr<PhasedArrayModel> rxAntenna);
86
87 std::vector<double> m_normVector; //!< each element is the norm of a channel realization
88 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
89 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
90 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
91 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
92};
93
95 uint32_t txAntennaElements,
96 uint32_t rxAntennaElements,
97 uint32_t txPorts,
98 uint32_t rxPorts)
99 : TestCase("Check the dimensions and the norm of the channel matrix")
100{
101 m_txAntennaElements = txAntennaElements;
102 m_rxAntennaElements = rxAntennaElements;
103 m_txPorts = txPorts;
104 m_rxPorts = rxPorts;
105}
106
110
111void
113 Ptr<MobilityModel> txMob,
114 Ptr<MobilityModel> rxMob,
115 Ptr<PhasedArrayModel> txAntenna,
116 Ptr<PhasedArrayModel> rxAntenna)
117{
118 uint64_t txAntennaElements = txAntenna->GetNumElems();
119 uint64_t rxAntennaElements = rxAntenna->GetNumElems();
120
122 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
123
124 double channelNorm = 0;
125 uint16_t numTotalClusters = channelMatrix->m_channel.GetNumPages();
126 for (uint16_t cIndex = 0; cIndex < numTotalClusters; cIndex++)
127 {
128 double clusterNorm = 0;
129 for (uint64_t sIndex = 0; sIndex < txAntennaElements; sIndex++)
130 {
131 for (uint64_t uIndex = 0; uIndex < rxAntennaElements; uIndex++)
132 {
133 clusterNorm +=
134 std::pow(std::abs(channelMatrix->m_channel(uIndex, sIndex, cIndex)), 2);
135 }
136 }
137 channelNorm += clusterNorm;
138 }
139 m_normVector.push_back(channelNorm);
140}
141
142void
144{
147 // Build the scenario for the test
148 uint32_t updatePeriodMs = 100; // update period in ms
149
150 // create the channel condition model
151 Ptr<ChannelConditionModel> channelConditionModel =
153
154 // create the ThreeGppChannelModel object used to generate the channel matrix
156 channelModel->SetAttribute("Frequency", DoubleValue(60.0e9));
157 channelModel->SetAttribute("Scenario", StringValue("RMa"));
158 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
159 channelModel->SetAttribute("UpdatePeriod", TimeValue(MilliSeconds(updatePeriodMs)));
160 channelModel->AssignStreams(1);
161
162 // create the tx and rx nodes
164 nodes.Create(2);
165
166 // create the tx and rx mobility models and set their positions
168 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
170 rxMob->SetPosition(Vector(30.0, 0.0, 10.0));
171 rxMob->SetVelocity(Vector(50, 0, 0));
172
173 // associate the nodes and the mobility models
174 nodes.Get(0)->AggregateObject(txMob);
175 nodes.Get(1)->AggregateObject(rxMob);
176
177 // create the tx and rx antennas and set their dimensions
179 "NumColumns",
181 "NumRows",
183 "AntennaElement",
185 "NumVerticalPorts",
187 "NumHorizontalPorts",
189
191 "NumColumns",
193 "NumRows",
195 "AntennaElement",
197 "NumVerticalPorts",
199 "NumHorizontalPorts",
201 // generate the channel matrix
203 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
204
205 // check the channel matrix dimensions, expected H[cluster][rx][tx]
207 channelMatrix->m_channel.GetNumCols(),
209 "The third dimension of H should be equal to the number of tx antenna elements");
211 channelMatrix->m_channel.GetNumRows(),
213 "The second dimension of H should be equal to the number of rx antenna elements");
214
215 // test if the channel matrix is correctly generated
216 uint16_t numIt = 2000;
217 for (uint16_t i = 0; i < numIt; i++)
218 {
219 Simulator::Schedule(MilliSeconds(updatePeriodMs * i + i),
221 this,
222 channelModel,
223 txMob,
224 rxMob,
225 txAntenna,
226 rxAntenna);
227 }
228
230
231 // compute the sample mean
232 double sampleMean = 0;
233 for (auto i : m_normVector)
234 {
235 sampleMean += i;
236 }
237 sampleMean /= numIt;
238
239 // compute the sample standard deviation
240 double sampleStd = 0;
241 for (auto i : m_normVector)
242 {
243 const double diff = i - sampleMean;
244 sampleStd += diff * diff;
245 }
246 sampleStd = std::sqrt(sampleStd / (numIt - 1));
247
248 NS_TEST_ASSERT_MSG_NE(sampleStd,
249 0,
250 "The STD should be different from zero. Channel matrix not updated");
251
252 if (sampleStd != 0)
253 {
254 // perform the one sample t-test with a significance level of 0.05 to test
255 // the hypothesis "E [|H|^2] = M*N, where |H| indicates the Frobenius norm of
256 // H, M is the number of transmit antenna elements, and N is the number of
257 // the receive antenna elements"
258 double t = (sampleMean - m_txAntennaElements * m_txAntennaElements * m_rxAntennaElements *
260 (sampleStd / std::sqrt(numIt));
261
262 // Using a significance level of 0.05, we reject the null hypothesis if |t| is
263 // greater than the critical value from a t-distribution with df = numIt-1
264
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 }
271
273}
274
275/**
276 * @ingroup spectrum-tests
277 *
278 * Test case for the ThreeGppChannelModel class.
279 * It checks if the channel realizations are correctly updated during the
280 * simulation.
281 */
283{
284 public:
285 /**
286 *Constructor
287 * @param txAntennaElements the number of rows and columns of the antenna array of the
288 * transmitter
289 * @param rxAntennaElements the number of rows and columns of the antenna array of
290 * @param txPorts the number of vertical and horizontal ports of the antenna array
291 * of the transmitter
292 * @param rxPorts the number of vertical and horizontal ports of the antenna
293 * array of the receiver
294 */
295 ThreeGppChannelMatrixUpdateTest(uint32_t txAntennaElements = 2,
296 uint32_t rxAntennaElements = 4,
297 uint32_t txPorts = 1,
298 uint32_t rxPorts = 1);
299
300 /**
301 * Destructor
302 */
304
305 private:
306 /**
307 * Build the test scenario
308 */
309 void DoRun() override;
310
311 /**
312 * This method first slightly moves the user and then calculates the channel matrix.
313 * This function is used for channel matrix computation at different time instants
314 * and to check if whether the channel matrix is updated following the updatePeriod
315 * configuration.
316 * @param channelModel the ThreeGppChannelModel object used to generate the channel matrix
317 * @param txMob the mobility model of the first node
318 * @param rxMob the mobility model of the second node
319 * @param txAntenna the antenna object associated to the first node
320 * @param rxAntenna the antenna object associated to the second node
321 * @param update whether if the channel matrix should be updated or not
322 */
324 Ptr<MobilityModel> txMob,
325 Ptr<MobilityModel> rxMob,
326 Ptr<PhasedArrayModel> txAntenna,
327 Ptr<PhasedArrayModel> rxAntenna,
328 bool update);
329
331 m_currentChannel; //!< used by DoGetChannel to store the current channel matrix
332 bool m_initialized{false}; //!< tracks whether previous matrix snapshot is set
333 ComplexMatrixArray m_previousChannelMatrix; //!< snapshot of previous channel matrix
334 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
335 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
336 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
337 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
338};
339
341 uint32_t rxAntennaElements,
342 uint32_t txPorts,
343 uint32_t rxPorts)
344 : TestCase("Check if the channel realizations are correctly updated during the simulation")
345{
346 m_txAntennaElements = txAntennaElements;
347 m_rxAntennaElements = rxAntennaElements;
348 m_txPorts = txPorts;
349 m_rxPorts = rxPorts;
350}
351
355
356void
358 Ptr<MobilityModel> txMob,
359 Ptr<MobilityModel> rxMob,
360 Ptr<PhasedArrayModel> txAntenna,
361 Ptr<PhasedArrayModel> rxAntenna,
362 bool update)
363{
364 // 3GPP channel update is activated only if the UE displacement is at least 1e-6, hence we
365 // add this minor movement to allow triggering of the channel update per the configured channel
366 // update period
367 rxMob->SetPosition(Vector(rxMob->GetPosition().x + 0.01,
368 rxMob->GetPosition().y + 0.01,
369 rxMob->GetPosition().z));
370
371 // retrieve the channel matrix
373 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
374
375 // For in-place updates, the ChannelMatrix pointer may remain the same.
376 // Deep-compare the matrix values with a small tolerance.
377 if (!m_initialized)
378 {
379 m_previousChannelMatrix = newChannelMatrix->m_channel; // deep copy
380 m_currentChannel = newChannelMatrix;
381 m_initialized = true;
382 return;
383 }
384
385 // Use absolute tolerance on complex values (magnitude comparison)
386 std::complex<double> tol(1e-12, 0.0);
387 bool equal = m_previousChannelMatrix.IsAlmostEqual(newChannelMatrix->m_channel, tol);
388 bool changed = !equal;
389
391 changed,
392 update,
393 Simulator::Now().GetMilliSeconds()
394 << " The channel matrix is not updated respecting the updatePeriod configuration");
395
396 // Update the previous snapshot if an update was expected and occurred
397 if (changed)
398 {
399 m_previousChannelMatrix = newChannelMatrix->m_channel;
400 m_currentChannel = newChannelMatrix;
401 }
402}
403
404void
406{
407 m_initialized = false;
409 m_currentChannel = nullptr;
410
411 // Build the scenario for the test
412 uint32_t updatePeriodMs = 100; // update period in ms
413
414 // create the channel condition model
415 Ptr<ChannelConditionModel> channelConditionModel =
417
418 // create the ThreeGppChannelModel object used to generate the channel matrix
420 channelModel->SetAttribute("Frequency", DoubleValue(60.0e9));
421 channelModel->SetAttribute("Scenario", StringValue("UMa"));
422 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
423 channelModel->SetAttribute("UpdatePeriod", TimeValue(MilliSeconds(updatePeriodMs)));
424
425 // create the tx and rx nodes
427 nodes.Create(2);
428
429 // create the tx and rx mobility models and set their positions
431 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
433 rxMob->SetPosition(Vector(100.0, 0.0, 1.6));
434
435 // associate the nodes and the mobility models
436 nodes.Get(0)->AggregateObject(txMob);
437 nodes.Get(1)->AggregateObject(rxMob);
438
439 // create the tx and rx antennas and set the their dimensions
441 "NumColumns",
443 "NumRows",
445 "AntennaElement",
447 "NumVerticalPorts",
449 "NumHorizontalPorts",
451
453 "NumColumns",
455 "NumRows",
457 "AntennaElement",
459 "NumVerticalPorts",
461 "NumHorizontalPorts",
463
464 // check if the channel matrix is correctly updated
465
466 // compute the channel matrix for the first time
467 uint32_t firstTimeMs =
468 1; // time instant at which the channel matrix is generated for the first time
471 this,
472 channelModel,
473 txMob,
474 rxMob,
475 txAntenna,
476 rxAntenna,
477 true);
478
479 // call GetChannel before the update period is exceeded, the channel matrix
480 // should not be updated
481 Simulator::Schedule(MilliSeconds(firstTimeMs + updatePeriodMs / 2),
483 this,
484 channelModel,
485 txMob,
486 rxMob,
487 txAntenna,
488 rxAntenna,
489 false);
490
491 // call GetChannel when the update period is exceeded, the channel matrix
492 // should be recomputed
493 Simulator::Schedule(MilliSeconds(firstTimeMs + updatePeriodMs + 1),
495 this,
496 channelModel,
497 txMob,
498 rxMob,
499 txAntenna,
500 rxAntenna,
501 true);
502
505}
506
507/**
508 * @ingroup spectrum-tests
509 *
510 * Test case for channel consistency Procedure A (according to 3GPP 38.901 Section 7.6.3.)
511 *
512 * This test verifies that the consistent channel updates produce smoother changes in the channel
513 * matrix than generating a completely new channel. The test checks both channel condition LOS and
514 * NLOS. This is very important because, according to the Procedure A, the per-cluster variables
515 * updates are performed differently for LOS and NLOS. For example, there are different formulas for
516 * different channel conditions for cluster delay update (eq. 7.6-9) and cluster departure/arrival
517 * angles (eq. 7.6-10b and 7.6-10c). The test allows configuring different speeds and frequencies.
518 * Based on these parameters is calculated the channel coherence time and the channel update period
519 * is set based on this value.
520 *
521 * The test verifies that the evolution of the general metric like the Frobenius channel norm, and
522 * per-cluster variables such as cluster delay, cluster power, and cluster angles (AOA and ZOA) is
523 * smoother with channel updates than with the new channel realizations. For the cluster metrics is
524 * selected the third cluster as defined in Table 7.8.5 for the calibration of the channel
525 * consistency.
526 *
527 * The test checks that the channel consistent updates according 3GPP 38.901 Procedure A result in a
528 * channel that evolves more smoothly than generating a completely new channel. Variations are at
529 * least 5 times lower than these of new channel realizations.
530 *
531 * To be able to get the results not only for the updated channel but also for the new channel
532 * realizations, we create new nodes that are tracking the update positions of the original node for
533 * which the channel updates are being generated. New nodes are forcing new channel realizations.
534 */
536{
537 public:
538 /**
539 *Constructor
540 */
542 double speedKmh,
543 double freqHz);
544
545 /**
546 * Destructor
547 */
549
550 /**
551 * ChannelConsistencyMetrics structure contains the metrics that are needed to test the channel
552 * consistency.
553 */
555 {
556 //! the channel norm value
558 //! the third cluster power in dB
560 //! the third cluster delay
562 //! the third cluster AOA
564 //! the third cluster ZOA
566
567 /**
568 * Operator + for easier calculations of the other metrics (e.g., mean values).
569 * @param other the other object of ChannelConsistencyMetrics
570 * @return the sum of the metrics
571 */
580
581 /**
582 * Operator += for easier calculations of the other metrics (e.g., mean)
583 * @param other the other object of the channel consistency metrics
584 * @return the sum of the metrics
585 */
587 {
588 this->channelNorm = this->channelNorm + other.channelNorm;
589 this->thirdClusterPower_dB = this->thirdClusterPower_dB + other.thirdClusterPower_dB;
590 this->thirdClusterDelay = this->thirdClusterDelay + other.thirdClusterDelay;
591 this->thirdClusterAoa = this->thirdClusterAoa + other.thirdClusterAoa;
592 this->thirdClusterZoa = this->thirdClusterZoa + other.thirdClusterZoa;
593 return *this;
594 }
595
596 /**
597 * Operator / used for easier calculations of the statistics, and test conditions.
598 * @param iterations The value with which will be divided each metric.
599 * @return the new object with the metrics that are divided by the given value.
600 */
601 ChannelConsistencyMetrics operator/(double iterations) const
602 {
604 result.channelNorm = this->channelNorm / iterations;
605 result.thirdClusterPower_dB = this->thirdClusterPower_dB / iterations;
606 result.thirdClusterDelay = this->thirdClusterDelay / iterations;
607 result.thirdClusterAoa = this->thirdClusterAoa / iterations;
608 result.thirdClusterZoa = this->thirdClusterZoa / iterations;
609 return result;
610 }
611
612 /**
613 * Operator /= used for easier calculations of the statistics, and test conditions.
614 * @param iterations The value with which will be divided each metric.
615 * @return the new object with the metrics that are divided by the given value.s
616 */
618 {
619 *this = *this / iterations;
620 return *this;
621 }
622
623 /**
624 *Used for easier calculations of the statistics, and test conditions.
625 *@return the new object with the absolute values of all the metrics
626 */
628 {
629 return ChannelConsistencyMetrics{std::abs(channelNorm),
630 std::abs(thirdClusterPower_dB),
631 std::abs(thirdClusterDelay),
632 std::abs(thirdClusterAoa),
633 std::abs(thirdClusterZoa)};
634 }
635
636 /**
637 * Used for checking the channel consistency test condition.
638 * @param other the values of the object containing the set of consistency metric
639 * @return true if the metrics of this object have lower values than these of the other
640 * object
641 */
642 bool operator<(const ChannelConsistencyMetrics& other) const
643 {
644 return (this->channelNorm < other.channelNorm) &&
645 (this->thirdClusterPower_dB < other.thirdClusterPower_dB) &&
646 (this->thirdClusterDelay < other.thirdClusterDelay) &&
647 (this->thirdClusterAoa < other.thirdClusterAoa) &&
648 (this->thirdClusterZoa < other.thirdClusterZoa);
649 }
650 };
651
652 /**
653 * Used for the calculation of the delta of all the metrics between 2 channel consistency metric
654 * objects. Returns a new object containing these delta values for each of the metrics.
655 * @param metrics1 The first channel consistency metrics object.
656 * @param metrics2 The second channel consistency metrics object.
657 * @return The channel consistency object containing the deltas of each of the metrics between
658 * the first and the second object.
659 */
662 {
664 deltas.channelNorm = metrics1.channelNorm - metrics2.channelNorm;
666 deltas.thirdClusterDelay = metrics1.thirdClusterDelay - metrics2.thirdClusterDelay;
667 deltas.thirdClusterAoa = metrics1.thirdClusterAoa - metrics2.thirdClusterAoa;
668 deltas.thirdClusterZoa = metrics1.thirdClusterZoa - metrics2.thirdClusterZoa;
669 return deltas;
670 }
671
672 private:
673 /**
674 * Build the test scenario
675 */
676 void DoRun() override;
677
678 /**
679 * Compute the channel consistency metrics to evaluate the varying rate of general channel
680 * metrics like:
681 * - Frobenius norm of the channel matrix and stores it in m_normVector, and per-cluster
682 * metrics like:
683 * - Cluster power (of the third cluster as per Table 7.8.5 from 38.901 for the calibration
684 * of the channel consistency)
685 * - Cluster delay (of the third cluster as per Table 7.8.5 from 38.901 for the calibration
686 * of the channel consistency)
687 * - Cluster AOA and ZOA (of the third cluster as per Table 7.8.5 from 38.901 for the
688 * calibration of the channel consistency)
689 *
690 * @param channelModel the ThreeGppChannelModel object used to generate the channel matrix
691 * @param txMob the mobility model of the first node
692 * @param rxMob the mobility model of the second node
693 * @param txAntenna the antenna object associated to the first node
694 * @param rxAntenna the antenna object associated to the second node
695 * @param metricsVectorToBeUsed the metrics vector to be used as the output of the function
696 * @param distancesVectorToBeUsed the metrics distances vector to be used as the output of the
697 * function
698 */
700 Ptr<ThreeGppChannelModel> channelModel,
701 Ptr<MobilityModel> txMob,
702 Ptr<MobilityModel> rxMob,
703 Ptr<PhasedArrayModel> txAntenna,
704 Ptr<PhasedArrayModel> rxAntenna,
705 std::vector<ChannelConsistencyMetrics>* metricsVectorToBeUsed,
706 std::vector<ChannelConsistencyMetrics>* distancesVectorToBeUsed);
707
708 //! consistency metrics for the channel updates
709 std::vector<ChannelConsistencyMetrics> m_consistencyMetricsChannelUpdates;
710 //! consistency metrics for the new channel realizations
711 std::vector<ChannelConsistencyMetrics> m_consistencyMetricsNewChannelRealizations;
712 //! consistency metric deltas for the channel updates
713 std::vector<ChannelConsistencyMetrics> m_consistencyMetricsDeltasChannelUpdates;
714 //! consistency metric deltas for the new channel realizations
715 std::vector<ChannelConsistencyMetrics> m_consistencyMetricsDeltasNewChannelRealizations;
716
717 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
718 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
719 //! The type of channel condition to be set; can be LOS or NLOS
721 //! The speed of the user to be used in the test case
722 double m_speedKmh{30.0};
723 //! The carrier frequency to be used in the test case
724 double m_freqHz{4.0e9};
725};
726
727/**
728 * ThreeGppChannelConsistency constructor
729 * @param losCondition the LOS condition to be used in the test setup
730 * @param speedKmh the speed of the user to be used in the test setup
731 * @param freqHz the central carrier frequency to be used in the test setup
732 */
735 double speedKmh,
736 double freqHz)
737 : TestCase(std::string("Check the channel consistency feature for losCondition ") +
738 ((losCondition == ChannelCondition::LOS) ? "LOS" : "NLOS") +
739 ", speed=" + std::to_string(speedKmh) +
740 " kmph, and freq=" + std::to_string(freqHz / 1e9) + " GHz.")
741{
742 m_losCondition = losCondition;
743 m_speedKmh = speedKmh;
744 m_freqHz = freqHz;
745}
746
750
751void
753 Ptr<ThreeGppChannelModel> channelModel,
754 Ptr<MobilityModel> txMob,
755 Ptr<MobilityModel> rxMob,
756 Ptr<PhasedArrayModel> txAntenna,
757 Ptr<PhasedArrayModel> rxAntenna,
758 std::vector<ChannelConsistencyMetrics>* metricsVectorToBeUsed,
759 std::vector<ChannelConsistencyMetrics>* distancesVectorToBeUsed)
760{
761 uint64_t txAntennaElements = txAntenna->GetNumElems();
762 uint64_t rxAntennaElements = rxAntenna->GetNumElems();
763
765 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
766
767 double channelNorm = 0;
768 uint16_t numTotalClusters = channelMatrix->m_channel.GetNumPages();
769 for (uint16_t cIndex = 0; cIndex < numTotalClusters; cIndex++)
770 {
771 double clusterNorm = 0;
772 for (uint64_t sIndex = 0; sIndex < txAntennaElements; sIndex++)
773 {
774 for (uint64_t uIndex = 0; uIndex < rxAntennaElements; uIndex++)
775 {
776 clusterNorm +=
777 std::pow(std::abs(channelMatrix->m_channel(uIndex, sIndex, cIndex)), 2);
778 }
779 }
780 channelNorm += clusterNorm;
781 }
782
784 channelModel->GetParams(txMob, rxMob);
787
788 double thirdClusterPower_dB = std::numeric_limits<double>::quiet_NaN();
789 // delay of the third cluster
790 double thirdClusterDelay = std::numeric_limits<double>::quiet_NaN();
791 // AOA of the third cluster
792 double thirdClusterAoa = std::numeric_limits<double>::quiet_NaN();
793 // ZOA of the third cluster
794 double thirdClusterZoa = std::numeric_limits<double>::quiet_NaN();
795
796 if (channelParams->m_clusterPower.size() > 2)
797 {
798 uint8_t thirdClusterIndex = 2; // the index of the third cluster
799 thirdClusterPower_dB = 10 * log10(channelParams->m_clusterPower.at(thirdClusterIndex));
800 // delay of the third cluster
801 thirdClusterDelay = channelParams->m_delay.at(thirdClusterIndex);
802 // AOA of the third cluster
803 thirdClusterAoa = channelParams->m_angle.at(0).at(thirdClusterIndex);
804 // ZOA of the third cluster
805 thirdClusterZoa = channelParams->m_angle.at(1).at(thirdClusterIndex);
806 }
807
808 metricsVectorToBeUsed->push_back(
809 {channelNorm, thirdClusterPower_dB, thirdClusterDelay, thirdClusterAoa, thirdClusterZoa});
810
811 if (metricsVectorToBeUsed->size() > 1)
812 {
814 ComputeDeltas(metricsVectorToBeUsed->at(metricsVectorToBeUsed->size() - 2),
815 metricsVectorToBeUsed->at(metricsVectorToBeUsed->size() - 1));
816 // we calculate the absolute value of the difference between the last two norms
817 distancesVectorToBeUsed->push_back(deltas);
818 }
819}
820
821void
823{
826 double speedMps = m_speedKmh * 1000 / 3600;
827 // calculate doppler spread
828 double fDoppler = (speedMps * m_freqHz) / 3e8;
829 // calculate channel coherence time
830 Time cTime = Seconds(1 / fDoppler);
831 // set update period
832 const Time& updatePeriod = cTime;
833
834 uint16_t iterations = 100;
835 m_consistencyMetricsChannelUpdates.reserve(iterations);
837 m_consistencyMetricsDeltasChannelUpdates.reserve(iterations - 1);
839
840 // create the channel condition model
841 Ptr<ChannelConditionModel> channelConditionModel;
842
844 {
845 channelConditionModel = CreateObject<AlwaysLosChannelConditionModel>();
846 }
847 else
848 {
849 channelConditionModel = CreateObject<NeverLosChannelConditionModel>();
850 }
851
852 // create the ThreeGppChannelModel object used to generate the channel matrix
854 channelModel->SetAttribute("Frequency", DoubleValue(m_freqHz));
855 channelModel->SetAttribute("Scenario", StringValue("RMa"));
856 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
857 channelModel->SetAttribute("UpdatePeriod", TimeValue(updatePeriod));
858 channelModel->AssignStreams(1);
859
860 // create the tx and rx nodes
861 NodeContainer nodeTx;
862 NodeContainer nodeRx;
863 NodeContainer nodesRxOther;
864 // we compare the channel update between the TX1 and RX1, and the independent channel
865 // generations between the same TX and 100 different RX that are at the time instant of the
866 // channel generation at the same position as the RX1
867 nodeTx.Create(1);
868 nodeRx.Create(1);
869 nodesRxOther.Create(100);
870
871 // create the tx and rx mobility models and set their positions
873 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
875 rxMob->SetPosition(Vector(30.0, 0.0, 1.0));
876 rxMob->SetVelocity(Vector(speedMps, 0, 0));
877
878 // associate the nodes and the mobility models
879 nodeTx.Get(0)->AggregateObject(txMob);
880 nodeRx.Get(0)->AggregateObject(rxMob);
881
882 std::vector<Ptr<ConstantVelocityMobilityModel>> rxMobCopies{100};
883 rxMobCopies.reserve(100);
884
885 for (uint32_t i = 0; i < 100; i++)
886 {
889 rxMobCopy->SetPosition(Vector(30.0, 0.0, 1.0));
890 rxMobCopy->SetVelocity(Vector(speedMps, 0, 0));
891 nodesRxOther.Get(i)->AggregateObject(rxMobCopy);
892 rxMobCopies[i] = rxMobCopy;
893 }
894
895 // create the tx and rx antennas and set the their dimensions
897 "NumColumns",
899 "NumRows",
901 "AntennaElement",
903 "BearingAngle",
904 DoubleValue(0));
905
907 "NumColumns",
909 "NumRows",
911 "AntennaElement",
913 "BearingAngle",
914 DoubleValue(M_PI));
915
916 // test if the channel matrix is correctly updated
917 for (uint16_t i = 0; i < iterations; i++)
918 {
919 Simulator::Schedule(updatePeriod * i + NanoSeconds(1),
921 this,
922 channelModel,
923 txMob,
924 rxMob,
925 txAntenna,
926 rxAntenna,
929
930 Simulator::Schedule(updatePeriod * i + NanoSeconds(1),
932 this,
933 channelModel,
934 txMob,
935 rxMobCopies[i],
936 txAntenna,
937 rxAntenna,
940 }
941
943
944 // compute the sample mean of the channel updates
945 ChannelConsistencyMetrics metricMeanChannelUpdates =
947 ChannelConsistencyMetrics metricMeanNewChannelRealizations =
949
951 {
952 metricMeanChannelUpdates += i.abs();
953 }
954 metricMeanChannelUpdates /= m_consistencyMetricsDeltasChannelUpdates.size();
955
957 {
958 metricMeanNewChannelRealizations += i.abs();
959 }
960 metricMeanNewChannelRealizations /= m_consistencyMetricsDeltasNewChannelRealizations.size();
961
962 NS_TEST_ASSERT_MSG_EQ(metricMeanChannelUpdates < metricMeanNewChannelRealizations / 5,
963 true,
964 "Check that the average distances between the consistency metrics of "
965 "the consecutive channel updates "
966 " are lower than of the consecutive new channel generations.");
968}
969
970/**
971 * @ingroup spectrum-tests
972 *
973 * Test case for the ThreeGppChannelModel class.
974 * It checks if the channel realizations are correctly
975 * updated after a change in the number of antenna elements.
976 */
978{
979 public:
980 /**
981 * Constructor
982 */
984
985 /**
986 * Destructor
987 */
989
990 private:
991 /**
992 * Build the test scenario
993 */
994 void DoRun() override;
995
996 /**
997 * This method is used to schedule the channel matrix computation at different
998 * time instants and to check if it correctly updated
999 * @param channelModel the ThreeGppChannelModel object used to generate the channel matrix
1000 * @param txMob the mobility model of the first node
1001 * @param rxMob the mobility model of the second node
1002 * @param txAntenna the antenna object associated to the first node
1003 * @param rxAntenna the antenna object associated to the second node
1004 * @param update whether if the channel matrix should be updated or not
1005 */
1006 void DoGetChannel(Ptr<ThreeGppChannelModel> channelModel,
1007 Ptr<MobilityModel> txMob,
1008 Ptr<MobilityModel> rxMob,
1009 Ptr<PhasedArrayModel> txAntenna,
1010 Ptr<PhasedArrayModel> rxAntenna,
1011 bool update);
1012
1014 m_currentChannel; //!< used by DoGetChannel to store the current channel matrix
1015 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
1016 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
1017 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
1018 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
1019};
1020
1022 : TestCase("Check if the channel realizations are correctly updated after antenna port changes "
1023 "during the simulation")
1024{
1025}
1026
1030
1031void
1033 Ptr<MobilityModel> txMob,
1034 Ptr<MobilityModel> rxMob,
1035 Ptr<PhasedArrayModel> txAntenna,
1036 Ptr<PhasedArrayModel> rxAntenna,
1037 bool update)
1038{
1039 // retrieve the channel matrix
1041 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
1042
1043 if (m_currentChannel)
1044 {
1045 // compare the old and the new channel matrices
1046 NS_TEST_ASSERT_MSG_EQ((m_currentChannel->m_channel != channelMatrix->m_channel),
1047 update,
1048 Simulator::Now().GetMilliSeconds()
1049 << " The channel matrix is not correctly updated");
1050 }
1051 m_currentChannel = channelMatrix;
1052}
1053
1054void
1056{
1057 // Build the scenario for the test
1058 uint32_t updatePeriodMs = 100; // update period in ms
1059
1060 // create the channel condition model
1061 Ptr<ChannelConditionModel> channelConditionModel =
1063
1064 // create the ThreeGppChannelModel object used to generate the channel matrix
1066 channelModel->SetAttribute("Frequency", DoubleValue(60.0e9));
1067 channelModel->SetAttribute("Scenario", StringValue("UMa"));
1068 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
1069 channelModel->SetAttribute("UpdatePeriod", TimeValue(MilliSeconds(updatePeriodMs)));
1070
1071 // create the tx and rx nodes
1073 nodes.Create(2);
1074
1075 // create the tx and rx mobility models and set their positions
1077 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
1079 rxMob->SetPosition(Vector(100.0, 0.0, 1.6));
1080
1081 // associate the nodes and the mobility models
1082 nodes.Get(0)->AggregateObject(txMob);
1083 nodes.Get(1)->AggregateObject(rxMob);
1084
1085 // create the tx and rx antennas and set the their dimensions
1087 "NumColumns",
1089 "NumRows",
1091 "AntennaElement",
1093 "NumVerticalPorts",
1095 "NumHorizontalPorts",
1097
1099 "NumColumns",
1101 "NumRows",
1103 "AntennaElement",
1105 "NumVerticalPorts",
1107 "NumHorizontalPorts",
1109
1110 // check if the channel matrix is correctly updated
1111
1112 // compute the channel matrix for the first time
1115 this,
1116 channelModel,
1117 txMob,
1118 rxMob,
1119 txAntenna,
1120 rxAntenna,
1121 true);
1122
1123 // call GetChannel before the update period is exceeded, the channel matrix
1124 // should not be updated
1127 this,
1128 channelModel,
1129 txMob,
1130 rxMob,
1131 txAntenna,
1132 rxAntenna,
1133 false);
1134
1135 // after changing the number of antenna ports, the channel matrix
1136 // should be recomputed
1138 [&txAntenna]() { txAntenna->SetNumRows(txAntenna->GetNumRows() + 1); });
1141 this,
1142 channelModel,
1143 txMob,
1144 rxMob,
1145 txAntenna,
1146 rxAntenna,
1147 true);
1148
1149 // after recomputing it once, the channel matrix should be cached
1152 this,
1153 channelModel,
1154 txMob,
1155 rxMob,
1156 txAntenna,
1157 rxAntenna,
1158 false);
1159
1160 // after recomputing it once, the channel matrix should be cached
1162 [&rxAntenna]() { rxAntenna->SetNumRows(rxAntenna->GetNumRows() + 1); });
1165 this,
1166 channelModel,
1167 txMob,
1168 rxMob,
1169 txAntenna,
1170 rxAntenna,
1171 true);
1172
1173 // after recomputing it once, the channel matrix should be cached
1176 this,
1177 channelModel,
1178 txMob,
1179 rxMob,
1180 txAntenna,
1181 rxAntenna,
1182 false);
1183
1186}
1187
1188/**
1189 * @ingroup spectrum-tests
1190 * @brief A structure that holds the parameters for the function
1191 * CheckLongTermUpdate. In this way the problem with the limited
1192 * number of parameters of method Schedule is avoided.
1193 */
1195{
1197 lossModel; //!< the ThreeGppSpectrumPropagationLossModel object used to compute the rx PSD
1198 Ptr<SpectrumSignalParameters> txParams; //!< the params of the tx signal
1199 Ptr<MobilityModel> txMob; //!< the mobility model of the tx device
1200 Ptr<MobilityModel> rxMob; //!< the mobility model of the rx device
1201 Ptr<SpectrumValue> rxPsdOld; //!< the previously received PSD
1203 rxSpectrumChannelMatrix; //!< the spectrum channel matrix of the received signal
1204 Ptr<PhasedArrayModel> txAntenna; //!< the antenna array of the tx device
1205 Ptr<PhasedArrayModel> rxAntenna; //!< the antenna array of the rx device
1206};
1207
1208/**
1209 * @ingroup spectrum-tests
1210 *
1211 * Test case for the ThreeGppSpectrumPropagationLossModelTest class.
1212 * 1) checks if the long term components for the direct and the reverse link
1213 * are the same
1214 * 2) checks if the long term component is updated when changing the beamforming
1215 * vectors
1216 * 3) checks if the long term is updated when changing the channel matrix
1217 */
1219{
1220 public:
1221 /**
1222 * Constructor
1223 * @param txAntennaElements the number of rows and columns of the antenna array of the
1224 * transmitter
1225 * @param rxAntennaElements the number of rows and columns of the antenna array of
1226 * the receiver
1227 * @param txPorts the number of vertical and horizontal ports of the antenna array
1228 * of the transmitter
1229 * @param rxPorts the number of vertical and horizontal ports of the antenna
1230 * array of the receiver
1231 */
1233 uint32_t rxAntennaElements = 4,
1234 uint32_t txPorts = 1,
1235 uint32_t rxPorts = 1);
1236 /**
1237 * Destructor
1238 */
1240
1241 private:
1242 /**
1243 * Build the test scenario
1244 */
1245 void DoRun() override;
1246
1247 /**
1248 * Perform beamforming from this node towards the other node
1249 * @param thisMob the mobility model of this device
1250 * @param thisAntenna the antenna object associated to thisDevice
1251 * @param otherMob the mobility model of the other device
1252 * @param otherAntenna the antenna array object of to otherDevice
1253 */
1254 void DoBeamforming(Ptr<MobilityModel> thisMob,
1255 Ptr<PhasedArrayModel> thisAntenna,
1256 Ptr<MobilityModel> otherMob,
1257 Ptr<PhasedArrayModel> otherAntenna);
1258
1259 /**
1260 * Test of the long-term component is correctly updated when the positions and beamforming
1261 * change
1262 * @param params a structure that contains the set of parameters needed by
1263 * CheckUpdateAfterChangingPositionsAndBeamforming in order to perform calculations
1264 */
1266
1267 /**
1268 * Test of the long-term component is correctly updated when the update period expires.
1269 * This function slightly moves the position of the tx node to allow the update to be performed.
1270 * @param params a structure that contains the set of parameters needed by CheckLongTermUpdate
1271 * in order to perform calculations
1272 */
1274
1275 uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
1276 uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
1277 uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
1278 uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
1279 //! used as the input for the long-term update check after the update period expires
1281};
1282
1284 uint32_t txAntennaElements,
1285 uint32_t rxAntennaElements,
1286 uint32_t txPorts,
1287 uint32_t rxPorts)
1288 : TestCase("Test case for the ThreeGppSpectrumPropagationLossModel class")
1289{
1290 m_txAntennaElements = txAntennaElements;
1291 m_rxAntennaElements = rxAntennaElements;
1292 m_txPorts = txPorts;
1293 m_rxPorts = rxPorts;
1294}
1295
1299
1300void
1302 Ptr<PhasedArrayModel> thisAntenna,
1303 Ptr<MobilityModel> otherMob,
1304 Ptr<PhasedArrayModel> otherAntenna)
1305{
1306 Vector aPos = thisMob->GetPosition();
1307 Vector bPos = otherMob->GetPosition();
1308
1309 // compute the azimuth and the elevation angles
1310 Angles completeAngle(bPos, aPos);
1311
1312 PhasedArrayModel::ComplexVector antennaWeights =
1313 thisAntenna->GetBeamformingVector(completeAngle);
1314 thisAntenna->SetBeamformingVector(antennaWeights);
1315}
1316
1317void
1319 const CheckLongTermUpdateParams& params)
1320{
1321 // Reciprocity check: evaluate reverse direction after changing positions/beamforming.
1322 auto rxPsdNewParams = params.lossModel->DoCalcRxPowerSpectralDensity(params.txParams,
1323 params.rxMob,
1324 params.txMob,
1325 params.rxAntenna,
1326 params.txAntenna);
1327
1328 NS_TEST_ASSERT_MSG_EQ((*params.rxPsdOld == *rxPsdNewParams->psd),
1329 false,
1330 "Changing the positions and BF vectors the rx PSD does not change");
1331
1333 (*params.rxSpectrumChannelMatrix == *rxPsdNewParams->spectrumChannelMatrix),
1334 false,
1335 "Changing the BF should change de frequency domain channel matrix");
1336
1337 m_rxParamsOld = rxPsdNewParams;
1338}
1339
1340void
1342{
1343 // we need to slightly move the node to allow the channel to be updated upon the update period,
1344 // but less than 1 meter, which would trigger new channel generation
1345 params.txMob->SetPosition(Vector(params.txMob->GetPosition().x + 0.1,
1346 params.txMob->GetPosition().y,
1347 params.txMob->GetPosition().z));
1348
1349 auto rxPsdNewParams = params.lossModel->DoCalcRxPowerSpectralDensity(params.txParams,
1350 params.txMob,
1351 params.rxMob,
1352 params.txAntenna,
1353 params.rxAntenna);
1354 NS_TEST_ASSERT_MSG_EQ((*m_rxParamsOld->psd == *rxPsdNewParams->psd),
1355 false,
1356 "The long term is not updated when the channel matrix is recomputed");
1357}
1358
1359void
1361{
1362 // Build the scenario for the test
1363 Config::SetDefault("ns3::ThreeGppChannelModel::UpdatePeriod", TimeValue(MilliSeconds(100)));
1364
1365 // create the ChannelConditionModel object to be used to retrieve the
1366 // channel condition
1368
1369 // create the ThreeGppSpectrumPropagationLossModel object, set frequency,
1370 // scenario and channel condition model to be used
1373 lossModel->SetChannelModelAttribute("Frequency", DoubleValue(2.4e9));
1374 lossModel->SetChannelModelAttribute("Scenario", StringValue("UMa"));
1375 lossModel->SetChannelModelAttribute(
1376 "ChannelConditionModel",
1377 PointerValue(condModel)); // create the ThreeGppChannelModel object used to generate the
1378 // channel matrix
1379
1380 // create the tx and rx nodes
1382 nodes.Create(2);
1383
1384 // create the tx and rx mobility models and set their positions
1386 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
1388 rxMob->SetPosition(
1389 Vector(15.0, 0.0, 10.0)); // in this position the channel condition is always LOS
1390
1391 // associate the nodes and the mobility models
1392 nodes.Get(0)->AggregateObject(txMob);
1393 nodes.Get(1)->AggregateObject(rxMob);
1394
1395 // create the tx and rx antennas and set the their dimensions
1397 "NumColumns",
1399 "NumRows",
1401 "AntennaElement",
1403 "NumVerticalPorts",
1405 "NumHorizontalPorts",
1407
1409 "NumColumns",
1411 "NumRows",
1413 "AntennaElement",
1415 "NumVerticalPorts",
1417 "NumHorizontalPorts",
1419
1420 // set the beamforming vectors
1421 DoBeamforming(txMob, txAntenna, rxMob, rxAntenna);
1422 DoBeamforming(rxMob, rxAntenna, txMob, txAntenna);
1423
1424 // create the tx psd
1426 double txPower = 0.1; // Watts
1427 uint32_t channelNumber = 1;
1428 Ptr<SpectrumValue> txPsd = sf.CreateTxPowerSpectralDensity(txPower, channelNumber);
1430 txParams->psd = txPsd->Copy();
1431
1432 // compute the rx psd
1433 auto rxParamsOld =
1434 lossModel->DoCalcRxPowerSpectralDensity(txParams, txMob, rxMob, txAntenna, rxAntenna);
1435
1436 // 1) check reciprocity: rx PSD is equal for both the direct and the reverse channel
1437 auto rxParamsNew =
1438 lossModel->DoCalcRxPowerSpectralDensity(txParams, rxMob, txMob, rxAntenna, txAntenna);
1439 if ((rxParamsOld->spectrumChannelMatrix->GetNumCols() ==
1440 rxParamsNew->spectrumChannelMatrix->GetNumCols()) &&
1441 (rxParamsOld->spectrumChannelMatrix->GetNumRows() ==
1442 rxParamsNew->spectrumChannelMatrix->GetNumRows()) &&
1443 (rxParamsOld->spectrumChannelMatrix->GetNumCols() == 1) &&
1444 (rxParamsOld->spectrumChannelMatrix->GetNumRows() == 1))
1445 {
1446 // this is only really true in case of SISO (1x1 non-polarized port array)
1447 const auto& oldValues = rxParamsOld->psd->GetValues();
1448 const auto& newValues = rxParamsNew->psd->GetValues();
1449
1450 NS_TEST_ASSERT_MSG_EQ(oldValues.size(),
1451 newValues.size(),
1452 "The long term for the direct and the reverse channel are different");
1453 for (size_t i = 0; i < oldValues.size(); i++)
1454 {
1456 oldValues.at(i),
1457 newValues.at(i),
1458 1e-9,
1459 "The long term for the direct and the reverse channel are different");
1460 }
1461 }
1462
1463 // 2) check if the long term is updated when changing the BF vector
1464 // change the position of the rx device and recompute the beamforming vectors
1465 rxMob->SetPosition(Vector(10.0, 5.0, 10.0));
1466 PhasedArrayModel::ComplexVector txBfVector = txAntenna->GetBeamformingVector();
1467 txBfVector[0] = std::complex<double>(0.0, 0.0);
1468 txAntenna->SetBeamformingVector(txBfVector);
1469 CheckLongTermUpdateParams paramsPositionUpdate{lossModel,
1470 txParams,
1471 rxMob,
1472 txMob,
1473 rxParamsOld->psd,
1474 rxParamsOld->spectrumChannelMatrix,
1475 rxAntenna,
1476 txAntenna};
1478 MilliSeconds(50),
1480 this,
1481 paramsPositionUpdate);
1482
1483 // 3) check if the long term is updated when the channel matrix is recomputed
1484 CheckLongTermUpdateParams params{lossModel,
1485 txParams,
1486 txMob,
1487 rxMob,
1488 rxParamsOld->psd,
1489 rxParamsOld->spectrumChannelMatrix,
1490 txAntenna,
1491 rxAntenna};
1494 this,
1495 params);
1496
1499}
1500
1501/**
1502 * @ingroup spectrum-tests
1503 *
1504 * Test case that test the correct use of the multi-port antennas in spectrum.
1505 * The test does the following:
1506 * 1) Generates a time domain channel matrix of a fixed size
1507 * (num gNB elements = 32 (4x8), num UE elements = 16 (4x4), num Clusters).
1508 * This matrix is called channelMatrixM0.
1509 * 2) Divides gNB antenna and UE antenna into ports using a fixed element to port
1510 * mapping (gNB: 1 vertical port, 4 horizontal ports, UE: 1 vertical port,
1511 * 2 horizontal ports). Using the channelMatrixM0, it generates port to port
1512 * long term channel matrix using the both gNB and UE having beams directed towards the other.
1513 * The resulting long term matrix dimensions are gNBports = 4, UE ports = 2, num Clusters.
1514 * This channel matrix is called matrixA.
1515 * 3) Constructs a single port to single port long term channel matrix
1516 * using the initial time domain channel matrix (channelMatrixM0) and beams
1517 * from gNB and UE towards each other. Single port mapping means gNB: 1 vertical port,
1518 * 1 horizontal port, UE: 1 vertical port, 1 horizontal port.
1519 * Matrix dimensions are: gNBports = 1, UE ports = 1, num Clusters. This long
1520 * term channel matrix is called matrixB.
1521 * 4) Creates a single port to single port long term channel matrix between
1522 * two virtual gNB and UE antenna by using matrixA and beam facing each other.
1523 * Matrix dimension of the resulting matrix are gNBports = 1, UE ports = 1, num Clusters.
1524 * This long term channel matrix is called matrixC.
1525 * 5) Checks that matrixB and matrixC are identical.
1526 */
1528{
1529 public:
1530 /**
1531 * Constructor
1532 */
1534
1535 /**
1536 * Destructor
1537 */
1539
1540 private:
1541 /**
1542 * Build the test scenario
1543 */
1544 void DoRun() override;
1545};
1546
1548 : TestCase("Check long term channel matrix generation when multiple ports at TX and RX are "
1549 "being used.")
1550{
1551}
1552
1556
1557void
1559{
1560 // create the channel condition model
1561 Ptr<ChannelConditionModel> channelConditionModel =
1563
1564 // create the ThreeGppChannelModel object used to generate the channel matrix
1566 channelModel->SetAttribute("Frequency", DoubleValue(2.0e9));
1567 channelModel->SetAttribute("Scenario", StringValue("RMa"));
1568 channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
1569
1570 // create the tx and rx nodes
1572 nodes.Create(2);
1573
1574 // create the tx and rx mobility models and set their positions
1576 txMob->SetPosition(Vector(0.0, 0.0, 10.0));
1578 rxMob->SetPosition(Vector(10.0, 0.0, 10.0));
1579
1580 // associate the nodes and the mobility models
1581 nodes.Get(0)->AggregateObject(txMob);
1582 nodes.Get(1)->AggregateObject(rxMob);
1583
1584 // create the tx and rx antennas and set the their dimensions
1586 "NumColumns",
1587 UintegerValue(8),
1588 "NumRows",
1589 UintegerValue(4),
1590 "AntennaElement",
1592 "NumVerticalPorts",
1593 UintegerValue(1),
1594 "NumHorizontalPorts",
1595 UintegerValue(4));
1596
1598 "NumColumns",
1599 UintegerValue(4),
1600 "NumRows",
1601 UintegerValue(4),
1602 "AntennaElement",
1604 "NumVerticalPorts",
1605 UintegerValue(1),
1606 "NumHorizontalPorts",
1607 UintegerValue(2));
1608
1609 // compute the azimuth and the elevation angles
1610 Angles completeAngleTxRx(rxMob->GetPosition(), txMob->GetPosition());
1611 Angles completeAngleRxTx(txMob->GetPosition(), rxMob->GetPosition());
1612
1613 txAntenna1->SetBeamformingVector(txAntenna1->GetBeamformingVector(completeAngleTxRx));
1614 rxAntenna1->SetBeamformingVector(rxAntenna1->GetBeamformingVector(completeAngleRxTx));
1615
1616 // generate the channel matrix
1618 channelModel->GetChannel(txMob, rxMob, txAntenna1, rxAntenna1);
1619
1620 // create ThreeGppSpectrumPropagationLossModel instance so that we
1621 // can call CalcLongTerm
1624
1626 threeGppSplm->CalcLongTerm(channelMatrixM0, txAntenna1, rxAntenna1);
1627
1628 // create the tx and rx antennas and set the their dimensions
1630 "NumColumns",
1631 UintegerValue(8),
1632 "NumRows",
1633 UintegerValue(4),
1634 "AntennaElement",
1636 "NumVerticalPorts",
1637 UintegerValue(1),
1638 "NumHorizontalPorts",
1639 UintegerValue(1));
1640
1642 "NumColumns",
1643 UintegerValue(4),
1644 "NumRows",
1645 UintegerValue(4),
1646 "AntennaElement",
1648 "NumVerticalPorts",
1649 UintegerValue(1),
1650 "NumHorizontalPorts",
1651 UintegerValue(1));
1652
1653 txAntenna2->SetBeamformingVector(txAntenna2->GetBeamformingVector(completeAngleTxRx));
1654 rxAntenna2->SetBeamformingVector(rxAntenna2->GetBeamformingVector(completeAngleRxTx));
1655
1657 threeGppSplm->CalcLongTerm(channelMatrixM0, txAntenna2, rxAntenna2);
1658
1659 // create the tx and rx antennas and set the their dimensions
1661 "NumColumns",
1662 UintegerValue(4),
1663 "NumRows",
1664 UintegerValue(1),
1665 "AntennaElement",
1667 "NumVerticalPorts",
1668 UintegerValue(1),
1669 "NumHorizontalPorts",
1670 UintegerValue(1),
1671 "AntennaHorizontalSpacing",
1672 DoubleValue(1));
1673
1675 "NumColumns",
1676 UintegerValue(2),
1677 "NumRows",
1678 UintegerValue(1),
1679 "AntennaElement",
1681 "NumVerticalPorts",
1682 UintegerValue(1),
1683 "NumHorizontalPorts",
1684 UintegerValue(1),
1685 "AntennaHorizontalSpacing",
1686 DoubleValue(1));
1687
1690 channelMatrixMA->m_channel = *matrixA;
1691
1692 txAntenna3->SetBeamformingVector(txAntenna3->GetBeamformingVector(completeAngleTxRx));
1693 rxAntenna3->SetBeamformingVector(rxAntenna3->GetBeamformingVector(completeAngleRxTx));
1694
1696 threeGppSplm->CalcLongTerm(channelMatrixMA, txAntenna3, rxAntenna3);
1697
1698 NS_TEST_ASSERT_MSG_EQ(matrixB->IsAlmostEqual(*matrixC, 1e-6),
1699 true,
1700 "Matrix B and Matrix C should be equal.");
1701
1704}
1705
1706/**
1707 * Structure that contains some of the main configuration parameters of the antenna
1708 * array that are used in the ThreeGppMimoPolarizationTest
1709 */
1711{
1712 uint32_t m_rows = 1; //!< the number of rows of antenna array
1713 uint32_t m_cols = 2; //!< the number of columns of antenna array
1714 uint32_t m_vPorts = 1; //!< the number of vertical ports of antenna array
1715 uint32_t m_hPorts = 2; //!< the number of horizontal ports of antenna array
1716 bool m_isotropic = false; //!< defines whether the antenna elements are isotropic
1717 double m_polSlantAngle = 0; //!< polarization angle of the antenna array
1718 double m_bearingAngle = 0; //!< bearing angle of the antenna array
1719
1720 /**
1721 * Constructor
1722 * Currently only configurable through constructor are polSlantAngle and bearingAngle.
1723 * @param isotropic whether the antenna elements are isotropic, or 3GPP
1724 * @param polSlantAngle the polarization slant angle
1725 * @param bearingAngle the bearing angle
1726 */
1727 MimoPolarizationAntennaParams(bool isotropic, double polSlantAngle = 0, double bearingAngle = 0)
1728 : m_isotropic(isotropic),
1729 m_polSlantAngle(polSlantAngle),
1730 m_bearingAngle(bearingAngle)
1731 {
1732 }
1733};
1734
1735/**
1736 * @ingroup spectrum-tests
1737 * This test tests that the channel matrix is correctly generated when dual-polarized
1738 * antennas are being used at TX and RX. In the conditions in which the channel between
1739 * the TX and Rx device is LOS channel, and the beams of the transmitter and the
1740 * receiver are pointing one towards the other, then in the presence of multiple ports
1741 * at the TX and RX, and the antenna array at the TX and RX are dual polarized,
1742 * the channel matrix should exhibit the strong symmetry between the two polarizations.
1743 * E.g. if we have 1x2 antenna elements and two polarizations at both TX and RX,
1744 * and the 1x2 ports at the TX and RX, then the channel matrix will have the
1745 * structure as:
1746 *
1747 * ch00 ch01 |ch02 ch03
1748 * Hvv Hvh ch10 ch11 |ch12 ch13
1749 * = --------------------
1750 * Hhv Hhh ch20 ch21 |ch22 ch23
1751 * ch30 ch31 |ch32 ch33
1752 *
1753 * We test different cases of the polarization slant angles of the TX and RX,
1754 * e.g., 0, 30, 45, 90.
1755 * In each of these setups we check if the channel matrix in its strongest
1756 * cluster experiences strong symmetry, and if the values appear in pairs.
1757 * We also test additional cases in which we change the bearing angle and
1758 * the height of the TX. In these cases we also observe strong symmetry, with
1759 * the difference that in these cases we can observe different values in the
1760 * pairs. We can still observe strong impact of the dual polarization on the
1761 * channel matrix.
1762 */
1764{
1765 public:
1766 /**
1767 * Constructor that receives MIMO polarization parameters of TX and RX
1768 * devices
1769 * @param testCaseName the test case name
1770 * @param txLoc the position of the transmitter
1771 * @param txAntennaParams the antenna parameters of the transmitter
1772 * @param rxLoc the position of the receiver
1773 * @param rxAntennaParams the antenna parameters of the receiver
1774 * @param testChannel the test matrix that represent the strongest cluster
1775 * @param tolerance the tolerance to be used when testing
1776 */
1777 ThreeGppMimoPolarizationTest(std::string testCaseName,
1778 Vector txLoc,
1779 const MimoPolarizationAntennaParams& txAntennaParams,
1780 Vector rxLoc,
1781 const MimoPolarizationAntennaParams& rxAntennaParams,
1782 std::valarray<std::complex<double>> testChannel,
1783 double tolerance);
1784
1785 /**
1786 * Destructor
1787 */
1789
1790 private:
1791 /**
1792 * Build the test scenario
1793 */
1794 void DoRun() override;
1795
1796 /**
1797 * @brief Function that can be used to configure the antenna using the set of
1798 * parameters.
1799 *
1800 * @param params The parameters to be set to the antenna
1801 * @return A pointer to the antenna that is created and configured by using input params
1802 */
1804
1805 Vector m_txLoc; //!< Position of the TX device
1806 MimoPolarizationAntennaParams m_txParams; //!< Parameters used to configure the TX antenna array
1807 Vector m_rxLoc; //!< Position of the RX device
1808 MimoPolarizationAntennaParams m_rxParams; //!< Parameters used to configure the RX antenna array
1809 std::valarray<std::complex<double>>
1810 m_testChannel; //!< The test value for the matrix representing the strongest cluster
1811 double m_tolerance; //!< The tolerance to be used when comparing the channel matrix with the
1812 //!< test matrix
1813};
1814
1816 std::string testCaseName,
1817 Vector txLoc,
1818 const MimoPolarizationAntennaParams& txParams,
1819 Vector rxLoc,
1820 const MimoPolarizationAntennaParams& rxParams,
1821 std::valarray<std::complex<double>> testChannel,
1822 double tolerance)
1823 : TestCase("Test MIMO using dual polarization." + testCaseName),
1824 m_txLoc(txLoc),
1825 m_txParams(txParams),
1826 m_rxLoc(rxLoc),
1827 m_rxParams(rxParams),
1828 m_testChannel(testChannel),
1829 m_tolerance(tolerance)
1830{
1831}
1832
1836
1839{
1840 NS_LOG_FUNCTION(this);
1841 Ptr<AntennaModel> antenna;
1842 if (params.m_isotropic)
1843 {
1845 }
1846 else
1847 {
1849 }
1850 // create the tx and rx antennas and set the their dimensions
1852 UintegerValue(params.m_cols),
1853 "NumRows",
1854 UintegerValue(params.m_rows),
1855 "AntennaElement",
1856 PointerValue(antenna),
1857 "NumVerticalPorts",
1858 UintegerValue(params.m_vPorts),
1859 "NumHorizontalPorts",
1860 UintegerValue(params.m_hPorts),
1861 "BearingAngle",
1862 DoubleValue(params.m_bearingAngle),
1863 "PolSlantAngle",
1864 DoubleValue(params.m_polSlantAngle),
1865 "IsDualPolarized",
1866 BooleanValue(true));
1867}
1868
1869void
1871{
1874 // create the ThreeGppChannelModel object used to generate the channel matrix
1876 channelModel->SetAttribute("Frequency", DoubleValue(60e9));
1877 channelModel->SetAttribute("Scenario", StringValue("RMa"));
1878 channelModel->SetAttribute("ChannelConditionModel",
1880
1881 int64_t randomStream = 1;
1882 randomStream += channelModel->AssignStreams(randomStream);
1883
1884 // create the tx and rx nodes
1886 nodes.Create(2);
1887
1888 // create the tx and rx mobility models and set their positions
1890 txMob->SetPosition(m_txLoc);
1892 rxMob->SetPosition(m_rxLoc);
1893
1894 // associate the nodes and the mobility models
1895 nodes.Get(0)->AggregateObject(txMob);
1896 nodes.Get(1)->AggregateObject(rxMob);
1897
1898 // create the tx and rx antennas and set the their dimensions
1901
1902 // configure direct beamforming vectors to point to each other
1903 txAntenna->SetBeamformingVector(
1904 txAntenna->GetBeamformingVector(Angles(rxMob->GetPosition(), txMob->GetPosition())));
1905 rxAntenna->SetBeamformingVector(
1906 rxAntenna->GetBeamformingVector(Angles(txMob->GetPosition(), rxMob->GetPosition())));
1907
1908 // generate the time domain channel matrix
1910 channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
1911
1912 // test whether the channel matrix for the first cluster experiences strong
1913 // symmetry that is caused by existence of dual polarized ports at the
1914 // transmitter and the receiver
1915 const std::complex<double>* strongestClusterPtr = channelMatrix->m_channel.GetPagePtr(0);
1916 size_t matrixSize =
1917 channelMatrix->m_channel.GetNumRows() * channelMatrix->m_channel.GetNumCols();
1918
1920 channelMatrix->m_channel.GetNumRows(),
1921 channelMatrix->m_channel.GetNumCols(),
1922 std::valarray<std::complex<double>>(strongestClusterPtr, matrixSize));
1923
1924 MatrixBasedChannelModel::Complex2DVector testChannel(channelMatrix->m_channel.GetNumRows(),
1925 channelMatrix->m_channel.GetNumCols(),
1927
1928 NS_LOG_INFO("Channel matrix:" << strongestCluster);
1929 NS_LOG_INFO("Test channel matrix: " << testChannel);
1930
1932 strongestCluster.IsAlmostEqual(testChannel, m_tolerance),
1933 true,
1934 "The strongest cluster and the test channel matrix should be almost equal");
1935
1938}
1939
1940/**
1941 * @ingroup spectrum-tests
1942 *
1943 * Test suite for the ThreeGppChannelModel class
1944 */
1946{
1947 public:
1948 /**
1949 * Constructor
1950 */
1952};
1953
1955 : TestSuite("three-gpp-channel", Type::UNIT)
1956{
1981
1994
2001
2003
2004 /**
2005 * The TX and RX antennas are configured face-to-face.
2006 * When polarization slant angles are 0 and 0 at TX and RX,
2007 * we expect the strongest cluster to be similar to the following matrix:
2008 * (5.9,0) (5.9,0) (0,0) (0,0)
2009 * (5.9,0) (5.9,0) (0,0) (0,0)
2010 * (0,0) (0,0) (-5.8,) (-5.8,0)
2011 * (0,0) (0,0) (-5.8,0) (-5.8,0)
2012 */
2013
2014 std::valarray<std::complex<double>> testChannel1 =
2015 {5.9, 5.9, 0, 0, 5.9, 5.9, 0, 0, 0, 0, -5.8, -5.8, 0, 0, -5.8, -5.8};
2016 AddTestCase(new ThreeGppMimoPolarizationTest("Face-to-face. 0 and 0 pol. slant angles.",
2017 Vector{0, 0, 3},
2018 MimoPolarizationAntennaParams(false, 0, 0),
2019 Vector{9, 0, 3},
2020 MimoPolarizationAntennaParams(false, 0, M_PI),
2021 testChannel1,
2022 0.9),
2024
2025 /**
2026 * The TX and RX antennas are configured face-to-face.
2027 * When polarization slant angles are 30 and 0 at TX and RX,
2028 * we expect the strongest cluster to be similar to the following matrix:
2029 * (5,0) (5,0) (3,0) (3,0)
2030 * (5,0) (5,0) (3,0) (3,0)
2031 * (3,0) (3,0) (-5,0) (-5,0)
2032 * (3,0) (3,0) (-5,0) (-5,0)
2033 */
2034
2036 new ThreeGppMimoPolarizationTest("Face-to-face. 30 and 0 pol. slant angles.",
2037 Vector{0, 0, 3},
2038 MimoPolarizationAntennaParams(false, M_PI / 6, 0),
2039 Vector{6, 0, 3},
2040 MimoPolarizationAntennaParams(false, 0, M_PI),
2041 {5, 5, 3, 3, 5, 5, 3, 3, 3, 3, -5, -5, 3, 3, -5, -5},
2042 0.8),
2044
2045 /**
2046 * The TX and RX antennas are configured face-to-face.
2047 * When polarization slant angles are 45 and 0 at TX and RX,
2048 * we expect the strongest cluster to be similar to the following matrix:
2049 * (4,0) (4,0) (4,0) (4,0)
2050 * (4,0) (4,0) (4,0) (4,0)
2051 * (4,0) (4,0) (4,0) (4,0)
2052 * (4,0) (4,0) (4,0) (4,0)
2053 */
2054
2056 new ThreeGppMimoPolarizationTest("Face-to-face. 45 and 0 pol. slant angles.",
2057 Vector{0, 0, 3},
2058 MimoPolarizationAntennaParams(false, M_PI / 4, 0),
2059 Vector{6, 0, 3},
2060 MimoPolarizationAntennaParams(false, 0, M_PI),
2061 {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -4, -4, 4, 4, -4, -4},
2062 0.7),
2064
2065 /**
2066 * The TX and RX antennas are configured face-to-face.
2067 * When polarization slant angles are 45 and 0 at TX and RX,
2068 * we expect the strongest cluster to be similar to the following matrix:
2069 * (0,0) (0,0) (5.9,0) (5.9,0)
2070 * (0,0) (0,0) (5.9,0) (5.9,0)
2071 * (5.8,0) (5.8,0) (0,0) (0,0)
2072 * (5.8,0) (5.8,0) (0,0) (0,0)
2073 */
2074
2076 "Face-to-face. 90 and 0 pol. slant angles.",
2077 Vector{0, 0, 3},
2078 MimoPolarizationAntennaParams(false, M_PI / 2, 0),
2079 Vector{6, 0, 3},
2080 MimoPolarizationAntennaParams(false, 0, M_PI),
2081 {0, 0, 5.8, 5.8, 0, 0, 5.8, 5.8, 5.9, 5.9, 0, 0, 5.9, 5.9, 0, 0},
2082 0.9),
2084
2085 /**
2086 * The TX and RX antennas are face to face. We test the configuration of
2087 * the bearing angle along with the configuration of the different position
2088 * of the RX antenna, and the bearing angles.
2089 * When polarization slant angles are 0 and 0 at TX and RX,
2090 * we expect the strongest cluster to be similar to the following matrix:
2091 * (5.9,0) (5.9,0) (0,0) (0,0)
2092 * (5.9,0) (5.9,0) (0,0) (0,0)
2093 * (0,0) (0,0) (-5.8,) (-5.8,0)
2094 * (0,0) (0,0) (-5.8,0) (-5.8,0)
2095 * Notice that we expect almost the same matrix as in the first case in
2096 * which
2097 */
2098
2100 new ThreeGppMimoPolarizationTest("Face-to-face. Different positions. Different bearing "
2101 "angles. 0 and 0 pol. slant angles.",
2102 Vector{0, 0, 3},
2103 MimoPolarizationAntennaParams(false, 0, M_PI / 4),
2104 Vector{6.363961031, 6.363961031, 3},
2105 MimoPolarizationAntennaParams(false, 0, -(M_PI / 4) * 3),
2106 testChannel1,
2107 0.9),
2109
2110 /**
2111 * The TX and RX antenna have different height.
2112 * Bearing angle is configured to point one toward the other.
2113 * When polarization slant angles are 0 and 0 at TX and RX,
2114 * we expect the strongest cluster to be similar to the following matrix:
2115 * (2.5,-4.7) (2.5,-4.7) (0,0) (0,0)
2116 * (2.5,-4.7) (2.5,-4.7) (0,0) (0,0)
2117 * (0,0) (0,0) (-2.4,4) (-2.4,4)
2118 * (0,0) (0,0) (-2.4,4) (-2.4,4)
2119 */
2121 "Not face-to-face. Different heights. 0 and 0 pol. slant angles.",
2122 Vector{0, 0, 10},
2123 MimoPolarizationAntennaParams(false, 0, 0),
2124 Vector{30, 0, 3},
2125 MimoPolarizationAntennaParams(false, 0, M_PI),
2126 {{2.5, -4.7},
2127 {2.5, -4.7},
2128 0,
2129 0,
2130 {2.5, -4.7},
2131 {2.5, -4.7},
2132 0,
2133 0,
2134 0,
2135 0,
2136 {-2.4, 4},
2137 {-2.4, 4},
2138 0,
2139 0,
2140 {-2.4, 4},
2141 {-2.4, 4}},
2142 0.5),
2144}
2145
2146/// Static variable for test initialization
return result
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 channel consistency Procedure A (according to 3GPP 38.901 Section 7....
void DoComputeConsistencyMetrics(Ptr< ThreeGppChannelModel > channelModel, Ptr< MobilityModel > txMob, Ptr< MobilityModel > rxMob, Ptr< PhasedArrayModel > txAntenna, Ptr< PhasedArrayModel > rxAntenna, std::vector< ChannelConsistencyMetrics > *metricsVectorToBeUsed, std::vector< ChannelConsistencyMetrics > *distancesVectorToBeUsed)
Compute the channel consistency metrics to evaluate the varying rate of general channel metrics like:
double m_freqHz
The carrier frequency to be used in the test case.
std::vector< ChannelConsistencyMetrics > m_consistencyMetricsDeltasNewChannelRealizations
consistency metric deltas for the new channel realizations
ChannelConsistencyMetrics ComputeDeltas(ChannelConsistencyMetrics metrics1, ChannelConsistencyMetrics metrics2)
Used for the calculation of the delta of all the metrics between 2 channel consistency metric objects...
void DoRun() override
Build the test scenario.
std::vector< ChannelConsistencyMetrics > m_consistencyMetricsChannelUpdates
consistency metrics for the channel updates
ThreeGppChannelConsistencyTest(ChannelCondition::LosConditionValue losCondition, double speedKmh, double freqHz)
Constructor.
uint32_t m_txAntennaElements
number of rows and columns of tx antenna array
uint32_t m_rxAntennaElements
number of rows and columns of rx antenna array
double m_speedKmh
The speed of the user to be used in the test case.
ChannelCondition::LosConditionValue m_losCondition
The type of channel condition to be set; can be LOS or NLOS.
std::vector< ChannelConsistencyMetrics > m_consistencyMetricsDeltasChannelUpdates
consistency metric deltas for the channel updates
std::vector< ChannelConsistencyMetrics > m_consistencyMetricsNewChannelRealizations
consistency metrics for the new channel realizations
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 MoveRxAndComputerSnr(Ptr< ThreeGppChannelModel > channelModel, Ptr< MobilityModel > txMob, Ptr< MobilityModel > rxMob, Ptr< PhasedArrayModel > txAntenna, Ptr< PhasedArrayModel > rxAntenna, bool update)
This method first slightly moves the user and then calculates the channel matrix.
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.
bool m_initialized
tracks whether previous matrix snapshot is set
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
ComplexMatrixArray m_previousChannelMatrix
snapshot of previous channel matrix
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
Ptr< SpectrumSignalParameters > m_rxParamsOld
used as the input for the long-term update check after the update period expires
uint32_t m_rxAntennaElements
number of rows and columns of rx antenna array
void CheckUpdateAfterChangingPositionsAndBeamforming(const CheckLongTermUpdateParams &params)
Test of the long-term component is correctly updated when the positions and beamforming change.
uint32_t m_rxPorts
number of horizontal and vertical ports of rx antenna array
void DoBeamforming(Ptr< MobilityModel > thisMob, Ptr< PhasedArrayModel > thisAntenna, Ptr< MobilityModel > otherMob, Ptr< PhasedArrayModel > otherAntenna)
Perform beamforming from this node towards the other node.
void CheckLongTermUpdate(CheckLongTermUpdateParams &params)
Test of the long-term component is correctly updated when the update period expires.
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
AttributeValue implementation for Boolean.
Definition boolean.h:26
Carries information about the LOS/NLOS channel state.
LosConditionValue
Possible values for Line-of-Sight condition.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
ComplexMatrixArray Complex2DVector
Create an alias for 2D complex vectors.
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.
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition object.cc:295
ComplexMatrixArray ComplexVector
the underlying Valarray
AttributeValue implementation for Pointer.
Definition pointer.h:37
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
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:580
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:125
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static void Run()
Run the simulation.
Definition simulator.cc:161
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
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
@ QUICK
Fast test.
Definition test.h:1057
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
Type
Type of test.
Definition test.h:1271
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
AttributeValue implementation for Time.
Definition nstime.h:1375
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:886
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#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:267
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
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:454
#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:133
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition test.h:553
#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:326
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1324
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1290
NodeContainer nodes
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605
MatrixArray< std::complex< double > > ComplexMatrixArray
Create an alias for MatrixArray using complex type.
STL 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< const ComplexMatrixArray > rxSpectrumChannelMatrix
the spectrum channel matrix of the received signal
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
ChannelConsistencyMetrics structure contains the metrics that are needed to test the channel consiste...
ChannelConsistencyMetrics operator+(const ChannelConsistencyMetrics &other) const
Operator + for easier calculations of the other metrics (e.g., mean values).
ChannelConsistencyMetrics operator/=(double iterations)
Operator /= used for easier calculations of the statistics, and test conditions.
bool operator<(const ChannelConsistencyMetrics &other) const
Used for checking the channel consistency test condition.
ChannelConsistencyMetrics operator+=(const ChannelConsistencyMetrics &other)
Operator += for easier calculations of the other metrics (e.g., mean).
ChannelConsistencyMetrics operator/(double iterations) const
Operator / used for easier calculations of the statistics, and test conditions.
ChannelConsistencyMetrics abs() const
Used for easier calculations of the statistics, and test conditions.
static ThreeGppChannelTestSuite myTestSuite
Static variable for test initialization.