A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
three-gpp-ntn-channel-example.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2023 SIGNET Lab, Department of Information Engineering,
3 * University of Padova
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 */
7
8/**
9 * @file
10 * This example is a modified version of "three-gpp-channel-example", to include
11 * the 3GPP NTN channel model.
12 * Specifically, most changes (which are also highlighted throughout the code)
13 * impact the main method, and comprise:
14 * - the configuration of ad-hoc propagation and channel condition models;
15 * - the use of GeocentricConstantPositionMobilityModel for the nodes' mobility.
16 * The pre-configured parameters are the one provided by 3GPP in TR 38.821,
17 * more specifically scenario 10 in down-link mode.
18 * Two static nodes, one on the ground and one in orbit, communicate with each other.
19 * The carrier frequency is set at 20GHz with 400MHz bandwidth.
20 * The result is the SNR of the signal and the path loss, saved in the ntn-snr-trace.txt file.
21 */
22
23#include "ns3/antenna-model.h"
24#include "ns3/core-module.h"
25#include "ns3/geocentric-constant-position-mobility-model.h"
26#include "ns3/isotropic-antenna-model.h"
27#include "ns3/mobility-model.h"
28#include "ns3/node-container.h"
29#include "ns3/node.h"
30#include "ns3/spectrum-signal-parameters.h"
31#include "ns3/three-gpp-channel-model.h"
32#include "ns3/three-gpp-propagation-loss-model.h"
33#include "ns3/three-gpp-spectrum-propagation-loss-model.h"
34#include "ns3/uniform-planar-array.h"
35
36#include <fstream>
37
38NS_LOG_COMPONENT_DEFINE("NTNChannelExample");
39
40using namespace ns3;
41
43 m_propagationLossModel; //!< the PropagationLossModel object
45 m_spectrumLossModel; //!< the SpectrumPropagationLossModel object
46static std::ofstream resultsFile; //!< The results file
47
48/**
49 * @brief Create the PSD for the TX
50 *
51 * @param fcHz the carrier frequency in Hz
52 * @param pwrDbm the transmission power in dBm
53 * @param bwHz the bandwidth in Hz
54 * @param rbWidthHz the Resource Block (RB) width in Hz
55 *
56 * @return the pointer to the PSD
57 */
59CreateTxPowerSpectralDensity(double fcHz, double pwrDbm, double bwHz, double rbWidthHz)
60{
61 unsigned int numRbs = std::floor(bwHz / rbWidthHz);
62 double f = fcHz - (numRbs * rbWidthHz / 2.0);
63 double powerTx = pwrDbm; // dBm power
64
65 Bands rbs; // A vector representing each resource block
66 for (uint32_t numrb = 0; numrb < numRbs; ++numrb)
67 {
68 BandInfo rb;
69 rb.fl = f;
70 f += rbWidthHz / 2;
71 rb.fc = f;
72 f += rbWidthHz / 2;
73 rb.fh = f;
74
75 rbs.push_back(rb);
76 }
79
80 double powerTxW = std::pow(10., (powerTx - 30) / 10); // Get Tx power in Watts
81 double txPowerDensity = (powerTxW / bwHz);
82
83 for (auto psd = txPsd->ValuesBegin(); psd != txPsd->ValuesEnd(); ++psd)
84 {
85 *psd = txPowerDensity;
86 }
87
88 return txPsd; // [W/Hz]
89}
90
91/**
92 * @brief Create the noise PSD for the
93 *
94 * @param fcHz the carrier frequency in Hz
95 * @param noiseFigureDb the noise figure in dB
96 * @param bwHz the bandwidth in Hz
97 * @param rbWidthHz the Resource Block (RB) width in Hz
98 *
99 * @return the pointer to the noise PSD
100 */
102CreateNoisePowerSpectralDensity(double fcHz, double noiseFigureDb, double bwHz, double rbWidthHz)
103{
104 unsigned int numRbs = std::floor(bwHz / rbWidthHz);
105 double f = fcHz - (numRbs * rbWidthHz / 2.0);
106
107 Bands rbs; // A vector representing each resource block
108 std::vector<int> rbsId; // A vector representing the resource block IDs
109 for (uint32_t numrb = 0; numrb < numRbs; ++numrb)
110 {
111 BandInfo rb;
112 rb.fl = f;
113 f += rbWidthHz / 2;
114 rb.fc = f;
115 f += rbWidthHz / 2;
116 rb.fh = f;
117
118 rbs.push_back(rb);
119 rbsId.push_back(numrb);
120 }
123
124 // see "LTE - From theory to practice"
125 // Section 22.4.4.2 Thermal Noise and Receiver Noise Figure
126 const double ktDbmHz = -174.0; // dBm/Hz
127 double ktWHz = std::pow(10.0, (ktDbmHz - 30) / 10.0); // W/Hz
128 double noiseFigureLinear = std::pow(10.0, noiseFigureDb / 10.0);
129
130 double noisePowerSpectralDensity = ktWHz * noiseFigureLinear;
131
132 for (auto rbId : rbsId)
133 {
134 (*txPsd)[rbId] = noisePowerSpectralDensity;
135 }
136
137 return txPsd; // W/Hz
138}
139
140/**
141 * @brief A structure that holds the parameters for the
142 * ComputeSnr function. In this way the problem with the limited
143 * number of parameters of method Schedule is avoided.
144 */
145struct ComputeSnrParams
146{
147 Ptr<MobilityModel> txMob; //!< the tx mobility model
148 Ptr<MobilityModel> rxMob; //!< the rx mobility model
149 double txPow; //!< the tx power in dBm
150 double noiseFigure; //!< the noise figure in dB
151 Ptr<PhasedArrayModel> txAntenna; //!< the tx antenna array
152 Ptr<PhasedArrayModel> rxAntenna; //!< the rx antenna array
153 double frequency; //!< the carrier frequency in Hz
154 double bandwidth; //!< the total bandwidth in Hz
155 double resourceBlockBandwidth; //!< the Resource Block bandwidth in Hz
156
157 /**
158 * @brief Constructor
159 * @param pTxMob the tx mobility model
160 * @param pRxMob the rx mobility model
161 * @param pTxPow the tx power in dBm
162 * @param pNoiseFigure the noise figure in dB
163 * @param pTxAntenna the tx antenna array
164 * @param pRxAntenna the rx antenna array
165 * @param pFrequency the carrier frequency in Hz
166 * @param pBandwidth the total bandwidth in Hz
167 * @param pResourceBlockBandwidth the Resource Block bandwidth in Hz
168 */
170 Ptr<MobilityModel> pRxMob,
171 double pTxPow,
172 double pNoiseFigure,
173 Ptr<PhasedArrayModel> pTxAntenna,
174 Ptr<PhasedArrayModel> pRxAntenna,
175 double pFrequency,
176 double pBandwidth,
177 double pResourceBlockBandwidth)
178 {
179 txMob = pTxMob;
180 rxMob = pRxMob;
181 txPow = pTxPow;
182 noiseFigure = pNoiseFigure;
183 txAntenna = pTxAntenna;
184 rxAntenna = pRxAntenna;
185 frequency = pFrequency;
186 bandwidth = pBandwidth;
187 resourceBlockBandwidth = pResourceBlockBandwidth;
188 }
189};
190
191/**
192 * Perform the beamforming using the DFT beamforming method
193 * @param txMob the mobility model of the node performing the beamforming
194 * @param thisAntenna the antenna object associated to txMob
195 * @param rxMob the mobility model of the node towards which will point the beam
196 */
197static void
199{
200 // compute the azimuth and the elevation angles
201 Angles completeAngle(txMob->GetPosition(), rxMob->GetPosition());
202 double hAngleRadian = completeAngle.GetAzimuth();
203 double vAngleRadian = completeAngle.GetInclination(); // the elevation angle
204
205 // retrieve the number of antenna elements and resize the vector
206 uint64_t totNoArrayElements = thisAntenna->GetNumElems();
207 PhasedArrayModel::ComplexVector antennaWeights(totNoArrayElements);
208
209 // the total power is divided equally among the antenna elements
210 double power = 1.0 / sqrt(totNoArrayElements);
211
212 // compute the antenna weights
213 const double sinVAngleRadian = sin(vAngleRadian);
214 const double cosVAngleRadian = cos(vAngleRadian);
215 const double sinHAngleRadian = sin(hAngleRadian);
216 const double cosHAngleRadian = cos(hAngleRadian);
217
218 for (uint64_t ind = 0; ind < totNoArrayElements; ind++)
219 {
220 Vector loc = thisAntenna->GetElementLocation(ind);
221 double phase = -2 * M_PI *
222 (sinVAngleRadian * cosHAngleRadian * loc.x +
223 sinVAngleRadian * sinHAngleRadian * loc.y + cosVAngleRadian * loc.z);
224 antennaWeights[ind] = exp(std::complex<double>(0, phase)) * power;
225 }
226
227 // store the antenna weights
228 thisAntenna->SetBeamformingVector(antennaWeights);
229}
230
231/**
232 * Compute the average SNR
233 * @param params A structure that holds the parameters that are needed to perform calculations in
234 * ComputeSnr
235 */
236static void
238{
239 Ptr<SpectrumValue> txPsd = CreateTxPowerSpectralDensity(params.frequency,
240 params.txPow,
241 params.bandwidth,
242 params.resourceBlockBandwidth);
243 Ptr<SpectrumValue> rxPsd = txPsd->Copy();
244 NS_LOG_DEBUG("Average tx power " << 10 * log10(Sum(*txPsd) * params.resourceBlockBandwidth)
245 << " dB");
246
247 // create the noise PSD
248 Ptr<SpectrumValue> noisePsd = CreateNoisePowerSpectralDensity(params.frequency,
249 params.noiseFigure,
250 params.bandwidth,
251 params.resourceBlockBandwidth);
252 NS_LOG_DEBUG("Average noise power "
253 << 10 * log10(Sum(*noisePsd) * params.resourceBlockBandwidth) << " dB");
254
255 // apply the pathloss
256 double propagationGainDb = m_propagationLossModel->CalcRxPower(0, params.txMob, params.rxMob);
257 NS_LOG_DEBUG("Pathloss " << -propagationGainDb << " dB");
258 double propagationGainLinear = std::pow(10.0, (propagationGainDb) / 10.0);
259 *(rxPsd) *= propagationGainLinear;
260
261 NS_ASSERT_MSG(params.txAntenna, "params.txAntenna is nullptr!");
262 NS_ASSERT_MSG(params.rxAntenna, "params.rxAntenna is nullptr!");
263
265 rxSsp->psd = rxPsd;
266 rxSsp->txAntenna =
267 ConstCast<AntennaModel, const AntennaModel>(params.txAntenna->GetAntennaElement());
268
269 // apply the fast fading and the beamforming gain
270 rxSsp = m_spectrumLossModel->CalcRxPowerSpectralDensity(rxSsp,
271 params.txMob,
272 params.rxMob,
273 params.txAntenna,
274 params.rxAntenna);
275 NS_LOG_DEBUG("Average rx power " << 10 * log10(Sum(*rxSsp->psd) * params.bandwidth) << " dB");
276
277 // compute the SNR
278 NS_LOG_DEBUG("Average SNR " << 10 * log10(Sum(*rxSsp->psd) / Sum(*noisePsd)) << " dB");
279
280 // print the SNR and pathloss values in the output file
282 << 10 * log10(Sum(*rxSsp->psd) / Sum(*noisePsd)) << " " << propagationGainDb
283 << std::endl;
284}
285
286int
287main(int argc, char* argv[])
288{
289 uint32_t simTimeMs = 1000; // simulation time in milliseconds
290 uint32_t timeResMs = 10; // time resolution in milliseconds
291
292 // Start changes with respect to three-gpp-channel-example
293 // SCENARIO 10 DL of TR 38.321
294 // This parameters can be set accordingly to 3GPP TR 38.821 or arbitrarily modified
295 std::string scenario = "NTN-Suburban"; // 3GPP propagation scenario
296 // All available NTN scenarios: DenseUrban, Urban, Suburban, Rural.
297
298 double frequencyHz = 20e9; // operating frequency in Hz
299 double bandwidthHz = 400e6; // Hz
300 double RbBandwidthHz = 120e3; // Hz
301
302 // Satellite parameters
303 double satEIRPDensity = 40; // dBW/MHz
304 double satAntennaGainDb = 58.5; // dB
305
306 // UE Parameters
307 double vsatAntennaGainDb = 39.7; // dB
308 double vsatAntennaNoiseFigureDb = 1.2; // dB
309 // End changes with respect to three-gpp-channel-example
310
311 /* Command line argument parser setup. */
312 CommandLine cmd(__FILE__);
313 cmd.AddValue("scenario",
314 "The 3GPP NTN scenario to use. Valid options are: "
315 "NTN-DenseUrban, NTN-Urban, NTN-Suburban, and NTN-Rural",
316 scenario);
317 cmd.AddValue("frequencyHz", "The carrier frequency in Hz", frequencyHz);
318 cmd.AddValue("bandwidthHz", "The bandwidth in Hz", bandwidthHz);
319 cmd.AddValue("satEIRPDensity", "The satellite EIRP density in dBW/MHz", satEIRPDensity);
320 cmd.AddValue("satAntennaGainDb", "The satellite antenna gain in dB", satAntennaGainDb);
321 cmd.AddValue("vsatAntennaGainDb", "The UE VSAT antenna gain in dB", vsatAntennaGainDb);
322 cmd.AddValue("vsatAntennaNoiseFigureDb",
323 "The UE VSAT antenna noise figure in dB",
324 vsatAntennaNoiseFigureDb);
325 cmd.Parse(argc, argv);
326
327 // Calculate transmission power in dBm using EIRPDensity + 10*log10(Bandwidth) - AntennaGain +
328 // 30
329 double txPowDbm = (satEIRPDensity + 10 * log10(bandwidthHz / 1e6) - satAntennaGainDb) + 30;
330
331 NS_LOG_DEBUG("Transmitting power: " << txPowDbm << "dBm, (" << pow(10., (txPowDbm - 30) / 10)
332 << "W)");
333
334 Config::SetDefault("ns3::ThreeGppChannelModel::UpdatePeriod",
335 TimeValue(MilliSeconds(10))); // update the channel at every 10 ms
336 Config::SetDefault("ns3::ThreeGppChannelConditionModel::UpdatePeriod",
337 TimeValue(MilliSeconds(0))); // do not update the channel condition
338
341
342 // create and configure the factories for the channel condition and propagation loss models
343 ObjectFactory propagationLossModelFactory;
344 ObjectFactory channelConditionModelFactory;
345
346 // Start changes with respect to three-gpp-channel-example
347 if (scenario == "NTN-DenseUrban")
348 {
349 propagationLossModelFactory.SetTypeId(
351 channelConditionModelFactory.SetTypeId(
353 }
354 else if (scenario == "NTN-Urban")
355 {
356 propagationLossModelFactory.SetTypeId(ThreeGppNTNUrbanPropagationLossModel::GetTypeId());
357 channelConditionModelFactory.SetTypeId(ThreeGppNTNUrbanChannelConditionModel::GetTypeId());
358 }
359 else if (scenario == "NTN-Suburban")
360 {
362 channelConditionModelFactory.SetTypeId(
364 }
365 else if (scenario == "NTN-Rural")
366 {
367 propagationLossModelFactory.SetTypeId(ThreeGppNTNRuralPropagationLossModel::GetTypeId());
368 channelConditionModelFactory.SetTypeId(ThreeGppNTNRuralChannelConditionModel::GetTypeId());
369 }
370 else
371 {
372 NS_FATAL_ERROR("Unknown NTN scenario");
373 }
374 // End changes with respect to three-gpp-channel-example
375
376 // create the propagation loss model
377 m_propagationLossModel = propagationLossModelFactory.Create<ThreeGppPropagationLossModel>();
378 m_propagationLossModel->SetAttribute("Frequency", DoubleValue(frequencyHz));
379 m_propagationLossModel->SetAttribute("ShadowingEnabled", BooleanValue(true));
380
381 // create the spectrum propagation loss model
383 m_spectrumLossModel->SetChannelModelAttribute("Frequency", DoubleValue(frequencyHz));
384 m_spectrumLossModel->SetChannelModelAttribute("Scenario", StringValue(scenario));
385
386 // create the channel condition model and associate it with the spectrum and
387 // propagation loss model
389 channelConditionModelFactory.Create<ThreeGppChannelConditionModel>();
390 m_spectrumLossModel->SetChannelModelAttribute("ChannelConditionModel", PointerValue(condModel));
391 m_propagationLossModel->SetChannelConditionModel(condModel);
392
393 // create the tx and rx nodes
395 nodes.Create(2);
396
397 // Start changes with respect to three-gpp-channel-example, here a mobility model
398 // tailored to NTN scenarios is used (GeocentricConstantPositionMobilityModel)
399 // create the tx and rx mobility models, set the positions
404
405 txMob->SetGeographicPosition(Vector(45.40869, 11.89448, 35786000)); // GEO over Padova
406 rxMob->SetGeographicPosition(Vector(45.40869, 11.89448, 14.0)); // Padova Coordinates
407
408 // This is not strictly necessary, but is useful to have "sensible" values when using
409 // GetPosition()
410 txMob->SetCoordinateTranslationReferencePoint(
411 Vector(45.40869, 11.89448, 0.0)); // Padova Coordinates without altitude
412 rxMob->SetCoordinateTranslationReferencePoint(
413 Vector(45.40869, 11.89448, 0.0)); // Padova Coordinates without altitude
414 // End changes with respect to three-gpp-channel-example,
415
416 NS_LOG_DEBUG("TX Position: " << txMob->GetPosition());
417 NS_LOG_DEBUG("RX Position: " << rxMob->GetPosition());
418
419 // assign the mobility models to the nodes
420 nodes.Get(0)->AggregateObject(txMob);
421 nodes.Get(1)->AggregateObject(rxMob);
422
423 // Start changes with respect to three-gpp-channel-example,
424 // Here antenna models mimic the gain achieved by the CircularApertureAntennaModel,
425 // which is not used to avoid inheriting the latter's dependence on either libstdc++
426 // or Boost.
428 "NumColumns",
429 UintegerValue(1),
430 "NumRows",
431 UintegerValue(1),
432 "AntennaElement",
435 DoubleValue(satAntennaGainDb))));
436
438 "NumColumns",
439 UintegerValue(1),
440 "NumRows",
441 UintegerValue(1),
442 "AntennaElement",
445 DoubleValue(vsatAntennaGainDb))));
446 // End changes with respect to three-gpp-channel-example
447
448 // set the beamforming vectors
449 DoBeamforming(rxMob, rxAntenna, txMob);
450 DoBeamforming(txMob, txAntenna, rxMob);
451
452 // Open the output results file
453 resultsFile.open("ntn-snr-trace.txt", std::ios::out);
454 NS_ASSERT_MSG(resultsFile.is_open(), "Results file could not be created");
455
456 for (int i = 0; i < floor(simTimeMs / timeResMs); i++)
457 {
458 Simulator::Schedule(MilliSeconds(timeResMs * i),
459 &ComputeSnr,
460 ComputeSnrParams(txMob,
461 rxMob,
462 txPowDbm,
463 vsatAntennaNoiseFigureDb,
464 txAntenna,
465 rxAntenna,
466 frequencyHz,
467 bandwidthHz,
468 RbBandwidthHz));
469 }
470
473
474 resultsFile.close();
475
476 return 0;
477}
Class holding the azimuth and inclination angles of spherical coordinates.
Definition angles.h:107
double GetInclination() const
Getter for inclination angle.
Definition angles.cc:236
double GetAzimuth() const
Getter for azimuth angle.
Definition angles.cc:230
AttributeValue implementation for Boolean.
Definition boolean.h:26
Parse command-line arguments.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
keep track of a set of node pointers.
Instantiate subclasses of ns3::Object.
Ptr< Object > Create() const
Create an Object instance of the configured TypeId.
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
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
Hold variables of type string.
Definition string.h:45
Base class for the 3GPP channel condition models.
Base class for the 3GPP propagation models.
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:398
AttributeValue implementation for Time.
Definition nstime.h:1375
Hold an unsigned integer type.
Definition uinteger.h:34
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:886
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
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
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.
std::vector< BandInfo > Bands
Container of BandInfo.
Ptr< T1 > ConstCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:593
double Sum(const SpectrumValue &x)
A structure that holds the parameters for the ComputeSnr function.
ComputeSnrParams(Ptr< MobilityModel > pTxMob, Ptr< MobilityModel > pRxMob, double pTxPow, double pNoiseFigure, Ptr< PhasedArrayModel > pTxAntenna, Ptr< PhasedArrayModel > pRxAntenna, double pFrequency, double pBandwidth, double pResourceBlockBandwidth)
Constructor.
Ptr< PhasedArrayModel > txAntenna
the tx antenna array
Ptr< MobilityModel > rxMob
the rx mobility model
double bandwidth
the total bandwidth in Hz
double noiseFigure
the noise figure in dB
double resourceBlockBandwidth
the Resource Block bandwidth in Hz
double txPow
the tx power in dBm
double frequency
the carrier frequency in Hz
Ptr< PhasedArrayModel > rxAntenna
the rx antenna array
Ptr< MobilityModel > txMob
the tx mobility model
The building block of a SpectrumModel.
double fc
center frequency
double fl
lower limit of subband
double fh
upper limit of subband
Ptr< SpectrumValue > CreateNoisePowerSpectralDensity(double fcHz, double noiseFigureDb, double bwHz, double rbWidthHz)
Create the noise PSD for the.
static std::ofstream resultsFile
The results file.
static void ComputeSnr(ComputeSnrParams &params)
Compute the average SNR.
static void DoBeamforming(Ptr< MobilityModel > rxMob, Ptr< PhasedArrayModel > thisAntenna, Ptr< MobilityModel > txMob)
Perform the beamforming using the DFT beamforming method.
Ptr< SpectrumValue > CreateTxPowerSpectralDensity(double fcHz, double pwrDbm, double bwHz, double rbWidthHz)
Create the PSD for the TX.
static Ptr< ThreeGppPropagationLossModel > m_propagationLossModel
the log component
static void ComputeSnr(const ComputeSnrParams &params)
Compute the average SNR.
static Ptr< ThreeGppSpectrumPropagationLossModel > m_spectrumLossModel
the SpectrumPropagationLossModel object