A Discrete-Event Network Simulator
API
three-gpp-spectrum-propagation-loss-model.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, NYU WIRELESS, Tandon School of Engineering,
3  * New York University
4  * Copyright (c) 2019 SIGNET Lab, Department of Information Engineering,
5  * University of Padova
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation;
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
23 
26 
27 #include "ns3/double.h"
28 #include "ns3/log.h"
29 #include "ns3/net-device.h"
30 #include "ns3/node.h"
31 #include "ns3/pointer.h"
32 #include "ns3/simulator.h"
33 #include "ns3/string.h"
34 
35 #include <map>
36 
37 namespace ns3
38 {
39 
40 NS_LOG_COMPONENT_DEFINE("ThreeGppSpectrumPropagationLossModel");
41 
42 NS_OBJECT_ENSURE_REGISTERED(ThreeGppSpectrumPropagationLossModel);
43 
45 {
46  NS_LOG_FUNCTION(this);
47 }
48 
50 {
51  NS_LOG_FUNCTION(this);
52 }
53 
54 void
56 {
57  m_longTermMap.clear();
58  m_channelModel->Dispose();
59  m_channelModel = nullptr;
60 }
61 
62 TypeId
64 {
65  static TypeId tid =
66  TypeId("ns3::ThreeGppSpectrumPropagationLossModel")
68  .SetGroupName("Spectrum")
69  .AddConstructor<ThreeGppSpectrumPropagationLossModel>()
70  .AddAttribute(
71  "ChannelModel",
72  "The channel model. It needs to implement the MatrixBasedChannelModel interface",
73  StringValue("ns3::ThreeGppChannelModel"),
76  MakePointerChecker<MatrixBasedChannelModel>());
77  return tid;
78 }
79 
80 void
82 {
84 }
85 
88 {
89  return m_channelModel;
90 }
91 
92 double
94 {
95  DoubleValue freq;
96  m_channelModel->GetAttribute("Frequency", freq);
97  return freq.Get();
98 }
99 
100 void
102  const AttributeValue& value)
103 {
104  m_channelModel->SetAttribute(name, value);
105 }
106 
107 void
109  AttributeValue& value) const
110 {
111  m_channelModel->GetAttribute(name, value);
112 }
113 
118  const PhasedArrayModel::ComplexVector& uW) const
119 {
120  NS_LOG_FUNCTION(this);
121 
122  size_t uAntennaNum = uW.GetSize();
123  size_t sAntennaNum = sW.GetSize();
124 
125  NS_ASSERT(uAntennaNum == params->m_channel.GetNumRows());
126  NS_ASSERT(sAntennaNum == params->m_channel.GetNumCols());
127 
128  NS_LOG_DEBUG("CalcLongTerm with " << uAntennaNum << " u antenna elements and " << sAntennaNum
129  << " s antenna elements.");
130  // store the long term part to reduce computation load
131  // only the small scale fading needs to be updated if the large scale parameters and antenna
132  // weights remain unchanged. here we calculate long term uW * Husn * sW, the result is an array
133  // of values per cluster
134  return params->m_channel.MultiplyByLeftAndRightMatrix(uW.Transpose(), sW);
135 }
136 
139  Ptr<SpectrumValue> txPsd,
143  const ns3::Vector& sSpeed,
144  const ns3::Vector& uSpeed) const
145 {
146  NS_LOG_FUNCTION(this);
147 
148  Ptr<SpectrumValue> tempPsd = Copy<SpectrumValue>(txPsd);
149 
150  // channel[cluster][rx][tx]
151  uint16_t numCluster = channelMatrix->m_channel.GetNumPages();
152 
153  // compute the doppler term
154  // NOTE the update of Doppler is simplified by only taking the center angle of
155  // each cluster in to consideration.
156  double slotTime = Simulator::Now().GetSeconds();
157  double factor = 2 * M_PI * slotTime * GetFrequency() / 3e8;
158  PhasedArrayModel::ComplexVector doppler(numCluster);
159 
160  // The following asserts might seem paranoic, but it is important to
161  // make sure that all the structures that are passed to this function
162  // are of the correct dimensions before using the operator [].
163  // If you dont understand the comment read about the difference of .at()
164  // and [] operators, ...
165  NS_ASSERT(numCluster <= channelParams->m_alpha.size());
166  NS_ASSERT(numCluster <= channelParams->m_D.size());
167  NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX].size());
168  NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX].size());
169  NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX].size());
170  NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX].size());
171  NS_ASSERT(numCluster <= longTerm.GetSize());
172 
173  // check if channelParams structure is generated in direction s-to-u or u-to-s
174  bool isSameDirection = (channelParams->m_nodeIds == channelMatrix->m_nodeIds);
175 
180 
181  // if channel params is generated in the same direction in which we
182  // generate the channel matrix, angles and zenith od departure and arrival are ok,
183  // just set them to corresponding variable that will be used for the generation
184  // of channel matrix, otherwise we need to flip angles and zeniths of departure and arrival
185  if (isSameDirection)
186  {
187  zoa = channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX];
188  zod = channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX];
189  aoa = channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX];
190  aod = channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX];
191  }
192  else
193  {
194  zod = channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX];
195  zoa = channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX];
196  aod = channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX];
197  aoa = channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX];
198  }
199 
200  for (uint16_t cIndex = 0; cIndex < numCluster; cIndex++)
201  {
202  // Compute alpha and D as described in 3GPP TR 37.885 v15.3.0, Sec. 6.2.3
203  // These terms account for an additional Doppler contribution due to the
204  // presence of moving objects in the surrounding environment, such as in
205  // vehicular scenarios.
206  // This contribution is applied only to the delayed (reflected) paths and
207  // must be properly configured by setting the value of
208  // m_vScatt, which is defined as "maximum speed of the vehicle in the
209  // layout".
210  // By default, m_vScatt is set to 0, so there is no additional Doppler
211  // contribution.
212 
213  double alpha = channelParams->m_alpha[cIndex];
214  double D = channelParams->m_D[cIndex];
215 
216  // cluster angle angle[direction][n], where direction = 0(aoa), 1(zoa).
217  double tempDoppler =
218  factor * ((sin(zoa[cIndex] * M_PI / 180) * cos(aoa[cIndex] * M_PI / 180) * uSpeed.x +
219  sin(zoa[cIndex] * M_PI / 180) * sin(aoa[cIndex] * M_PI / 180) * uSpeed.y +
220  cos(zoa[cIndex] * M_PI / 180) * uSpeed.z) +
221  (sin(zod[cIndex] * M_PI / 180) * cos(aod[cIndex] * M_PI / 180) * sSpeed.x +
222  sin(zod[cIndex] * M_PI / 180) * sin(aod[cIndex] * M_PI / 180) * sSpeed.y +
223  cos(zod[cIndex] * M_PI / 180) * sSpeed.z) +
224  2 * alpha * D);
225  doppler[cIndex] = std::complex<double>(cos(tempDoppler), sin(tempDoppler));
226  }
227 
228  NS_ASSERT(numCluster <= doppler.GetSize());
229 
230  // apply the doppler term and the propagation delay to the long term component
231  // to obtain the beamforming gain
232  auto vit = tempPsd->ValuesBegin(); // psd iterator
233  auto sbit = tempPsd->ConstBandsBegin(); // band iterator
234  while (vit != tempPsd->ValuesEnd())
235  {
236  if ((*vit) != 0.00)
237  {
238  std::complex<double> subsbandGain(0.0, 0.0);
239  double fsb = (*sbit).fc; // center frequency of the sub-band
240  for (uint16_t cIndex = 0; cIndex < numCluster; cIndex++)
241  {
242  double delay = -2 * M_PI * fsb * (channelParams->m_delay[cIndex]);
243  subsbandGain = subsbandGain + longTerm[cIndex] * doppler[cIndex] *
244  std::complex<double>(cos(delay), sin(delay));
245  }
246  *vit = (*vit) * (norm(subsbandGain));
247  }
248  vit++;
249  sbit++;
250  }
251  return tempPsd;
252 }
253 
257  Ptr<const PhasedArrayModel> aPhasedArrayModel,
258  Ptr<const PhasedArrayModel> bPhasedArrayModel) const
259 {
261  longTerm; // vector containing the long term component for each cluster
262 
263  // check if the channel matrix was generated considering a as the s-node and
264  // b as the u-node or vice-versa
267  if (!channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId()))
268  {
269  sW = aPhasedArrayModel->GetBeamformingVector();
270  uW = bPhasedArrayModel->GetBeamformingVector();
271  }
272  else
273  {
274  sW = bPhasedArrayModel->GetBeamformingVector();
275  uW = aPhasedArrayModel->GetBeamformingVector();
276  }
277 
278  bool update = false; // indicates whether the long term has to be updated
279  bool notFound = false; // indicates if the long term has not been computed yet
280 
281  // compute the long term key, the key is unique for each tx-rx pair
282  uint64_t longTermId =
283  MatrixBasedChannelModel::GetKey(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
284 
285  // look for the long term in the map and check if it is valid
286  if (m_longTermMap.find(longTermId) != m_longTermMap.end())
287  {
288  NS_LOG_DEBUG("found the long term component in the map");
289  longTerm = m_longTermMap[longTermId]->m_longTerm;
290 
291  // check if the channel matrix has been updated
292  // or the s beam has been changed
293  // or the u beam has been changed
294  update = (m_longTermMap[longTermId]->m_channel->m_generatedTime !=
295  channelMatrix->m_generatedTime ||
296  m_longTermMap[longTermId]->m_sW != sW || m_longTermMap[longTermId]->m_uW != uW);
297  }
298  else
299  {
300  NS_LOG_DEBUG("long term component NOT found");
301  notFound = true;
302  }
303 
304  if (update || notFound)
305  {
306  NS_LOG_DEBUG("compute the long term");
307  // compute the long term component
308  longTerm = CalcLongTerm(channelMatrix, sW, uW);
309 
310  // store the long term
311  Ptr<LongTerm> longTermItem = Create<LongTerm>();
312  longTermItem->m_longTerm = longTerm;
313  longTermItem->m_channel = channelMatrix;
314  longTermItem->m_sW = sW;
315  longTermItem->m_uW = uW;
316 
317  m_longTermMap[longTermId] = longTermItem;
318  }
319 
320  return longTerm;
321 }
322 
328  Ptr<const PhasedArrayModel> aPhasedArrayModel,
329  Ptr<const PhasedArrayModel> bPhasedArrayModel) const
330 {
331  NS_LOG_FUNCTION(this);
332  uint32_t aId = a->GetObject<Node>()->GetId(); // id of the node a
333  uint32_t bId = b->GetObject<Node>()->GetId(); // id of the node b
334 
335  NS_ASSERT(aId != bId);
336  NS_ASSERT_MSG(a->GetDistanceFrom(b) > 0.0,
337  "The position of a and b devices cannot be the same");
338 
339  Ptr<SpectrumValue> rxPsd = Copy<SpectrumValue>(params->psd);
340 
341  // retrieve the antenna of device a
342  NS_ASSERT_MSG(aPhasedArrayModel, "Antenna not found for node " << aId);
343  NS_LOG_DEBUG("a node " << a->GetObject<Node>() << " antenna " << aPhasedArrayModel);
344 
345  // retrieve the antenna of the device b
346  NS_ASSERT_MSG(bPhasedArrayModel, "Antenna not found for device " << bId);
347  NS_LOG_DEBUG("b node " << bId << " antenna " << bPhasedArrayModel);
348 
350  m_channelModel->GetChannel(a, b, aPhasedArrayModel, bPhasedArrayModel);
352  m_channelModel->GetParams(a, b);
353 
354  // retrieve the long term component
356  GetLongTerm(channelMatrix, aPhasedArrayModel, bPhasedArrayModel);
357 
358  // apply the beamforming gain
359  rxPsd = CalcBeamformingGain(rxPsd,
360  longTerm,
361  channelMatrix,
362  channelParams,
363  a->GetVelocity(),
364  b->GetVelocity());
365 
366  return rxPsd;
367 }
368 
369 } // namespace ns3
Hold a value for an Attribute.
Definition: attribute.h:70
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
double Get() const
Definition: double.cc:37
MatrixArray class inherits ValArray class and provides additional interfaces to ValArray which enable...
Definition: matrix-array.h:83
MatrixArray< T > Transpose() const
This operator interprets the 3D array as an array of matrices, and performs a linear algebra operatio...
std::vector< double > DoubleVector
Type definition for vectors of doubles.
static const uint8_t AOA_INDEX
index of the AOA value in the m_angle array
static const uint8_t ZOD_INDEX
index of the ZOD value in the m_angle array
static const uint8_t AOD_INDEX
index of the AOD value in the m_angle array
static const uint8_t ZOA_INDEX
index of the ZOA value in the m_angle array
static uint64_t GetKey(uint32_t a, uint32_t b)
Generate a unique value for the pair of unsigned integer of 32 bits, where the order does not matter,...
A network Node.
Definition: node.h:56
spectrum-aware propagation loss model that is compatible with PhasedArrayModel type of ns-3 antenna
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
Values::iterator ValuesBegin()
Bands::const_iterator ConstBandsBegin() const
Values::iterator ValuesEnd()
Hold variables of type string.
Definition: string.h:56
void GetChannelModelAttribute(const std::string &name, AttributeValue &value) const
Returns the value of an attribute belonging to the associated MatrixBasedChannelModel instance.
Ptr< SpectrumValue > DoCalcRxPowerSpectralDensity(Ptr< const SpectrumSignalParameters > params, Ptr< const MobilityModel > a, Ptr< const MobilityModel > b, Ptr< const PhasedArrayModel > aPhasedArrayModel, Ptr< const PhasedArrayModel > bPhasedArrayModel) const override
Computes the received PSD.
PhasedArrayModel::ComplexVector GetLongTerm(Ptr< const MatrixBasedChannelModel::ChannelMatrix > channelMatrix, Ptr< const PhasedArrayModel > aPhasedArrayModel, Ptr< const PhasedArrayModel > bPhasedArrayModel) const
Looks for the long term component in m_longTermMap.
Ptr< MatrixBasedChannelModel > m_channelModel
the model to generate the channel matrix
void SetChannelModel(Ptr< MatrixBasedChannelModel > channel)
Set the channel model object.
std::unordered_map< uint64_t, Ptr< const LongTerm > > m_longTermMap
map containing the long term components
void SetChannelModelAttribute(const std::string &name, const AttributeValue &value)
Sets the value of an attribute belonging to the associated MatrixBasedChannelModel instance.
Ptr< MatrixBasedChannelModel > GetChannelModel() const
Get the channel model object.
Ptr< SpectrumValue > CalcBeamformingGain(Ptr< SpectrumValue > txPsd, PhasedArrayModel::ComplexVector longTerm, Ptr< const MatrixBasedChannelModel::ChannelMatrix > channelMatrix, Ptr< const MatrixBasedChannelModel::ChannelParams > channelParams, const Vector &sSpeed, const Vector &uSpeed) const
Computes the beamforming gain and applies it to the tx PSD.
PhasedArrayModel::ComplexVector CalcLongTerm(Ptr< const MatrixBasedChannelModel::ChannelMatrix > channelMatrix, const PhasedArrayModel::ComplexVector &sW, const PhasedArrayModel::ComplexVector &uW) const
Computes the long term component.
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
size_t GetSize() const
Definition: val-array.h:403
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#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:86
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: pointer.h:231
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
const double norm
Normalization to obtain randoms on [0,1).
Definition: rng-stream.cc:66
Every class exported by the ns3 library is enclosed in the ns3 namespace.
value
Definition: second.py:41
channel
Definition: third.py:81
params
Fit Fluctuating Two Ray model to the 3GPP TR 38.901 using the Anderson-Darling goodness-of-fit ##.