A Discrete-Event Network Simulator
API
three-gpp-spectrum-propagation-loss-model.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2015, NYU WIRELESS, Tandon School of Engineering,
4  * New York University
5  * Copyright (c) 2019 SIGNET Lab, Department of Information Engineering,
6  * University of Padova
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation;
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  */
22 
23 #include "ns3/log.h"
26 #include "ns3/net-device.h"
27 #include "ns3/node.h"
28 #include "ns3/double.h"
29 #include "ns3/string.h"
30 #include "ns3/simulator.h"
31 #include "ns3/pointer.h"
32 #include <map>
33 
34 namespace ns3 {
35 
36 NS_LOG_COMPONENT_DEFINE ("ThreeGppSpectrumPropagationLossModel");
37 
38 NS_OBJECT_ENSURE_REGISTERED (ThreeGppSpectrumPropagationLossModel);
39 
41 {
42  NS_LOG_FUNCTION (this);
43 }
44 
46 {
47  NS_LOG_FUNCTION (this);
48 }
49 
50 void
52 {
53  m_longTermMap.clear ();
54  m_channelModel->Dispose ();
55  m_channelModel = nullptr;
56 }
57 
58 TypeId
60 {
61  static TypeId tid = TypeId ("ns3::ThreeGppSpectrumPropagationLossModel")
63  .SetGroupName ("Spectrum")
64  .AddConstructor<ThreeGppSpectrumPropagationLossModel> ()
65  .AddAttribute("ChannelModel",
66  "The channel model. It needs to implement the MatrixBasedChannelModel interface",
67  StringValue("ns3::ThreeGppChannelModel"),
70  MakePointerChecker<MatrixBasedChannelModel> ())
71  ;
72  return tid;
73 }
74 
75 void
77 {
79 }
80 
83 {
84  return m_channelModel;
85 }
86 
87 double
89 {
90  DoubleValue freq;
91  m_channelModel->GetAttribute ("Frequency", freq);
92  return freq.Get ();
93 }
94 
95 void
97 {
98  m_channelModel->SetAttribute (name, value);
99 }
100 
101 void
103 {
104  m_channelModel->GetAttribute (name, value);
105 }
106 
110  const PhasedArrayModel::ComplexVector &uW) const
111 {
112  NS_LOG_FUNCTION (this);
113 
114  uint16_t sAntenna = static_cast<uint16_t> (sW.size ());
115  uint16_t uAntenna = static_cast<uint16_t> (uW.size ());
116 
117  NS_ASSERT (uAntenna == params->m_channel.size ());
118  NS_ASSERT (sAntenna == params->m_channel.at (0).size());
119 
120  NS_LOG_DEBUG ("CalcLongTerm with sAntenna " << sAntenna << " uAntenna " << uAntenna);
121  //store the long term part to reduce computation load
122  //only the small scale fading needs to be updated if the large scale parameters and antenna weights remain unchanged.
124  uint8_t numCluster = static_cast<uint8_t> (params->m_channel[0][0].size ());
125 
126  NS_ASSERT (uAntenna == params->m_channel.size ());
127  NS_ASSERT (sAntenna == params->m_channel.at (0).size());
128 
129  for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
130  {
131  std::complex<double> txSum (0, 0);
132  for (uint16_t sIndex = 0; sIndex < sAntenna; sIndex++)
133  {
134  std::complex<double> rxSum (0, 0);
135  for (uint16_t uIndex = 0; uIndex < uAntenna; uIndex++)
136  {
137  rxSum = rxSum + uW[uIndex] * params->m_channel[uIndex][sIndex][cIndex];
138  }
139  txSum = txSum + sW[sIndex] * rxSum;
140  }
141  longTerm.push_back (txSum);
142  }
143  return longTerm;
144 }
145 
151  const ns3::Vector &sSpeed, const ns3::Vector &uSpeed) const
152 {
153  NS_LOG_FUNCTION (this);
154 
155  Ptr<SpectrumValue> tempPsd = Copy<SpectrumValue> (txPsd);
156 
157  //channel[rx][tx][cluster]
158  uint8_t numCluster = static_cast<uint8_t> (channelMatrix->m_channel[0][0].size ());
159 
160  // compute the doppler term
161  // NOTE the update of Doppler is simplified by only taking the center angle of
162  // each cluster in to consideration.
163  double slotTime = Simulator::Now ().GetSeconds ();
164  double factor = 2 * M_PI * slotTime * GetFrequency () / 3e8;
166 
167  // The following asserts might seem paranoic, but it is important to
168  // make sure that all the structures that are passed to this function
169  // are of the correct dimensions before using the operator [].
170  // If you dont understand the comment read about the difference of .at()
171  // and [] operators, ...
172  NS_ASSERT (numCluster <= channelParams->m_alpha.size ());
173  NS_ASSERT (numCluster <= channelParams->m_D.size());
174  NS_ASSERT (numCluster <= channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX].size());
175  NS_ASSERT (numCluster <= channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX].size());
176  NS_ASSERT (numCluster <= channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX].size());
177  NS_ASSERT (numCluster <= channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX].size());
178  NS_ASSERT (numCluster <= longTerm.size());
179 
180  // check if channelParams structure is generated in direction s-to-u or u-to-s
181  bool isSameDirection = (channelParams->m_nodeIds == channelMatrix->m_nodeIds);
182 
187 
188  // if channel params is generated in the same direction in which we
189  // generate the channel matrix, angles and zenit od departure and arrival are ok,
190  // just set them to corresponding variable that will be used for the generation
191  // of channel matrix, otherwise we need to flip angles and zenits of departure and arrival
192  if (isSameDirection)
193  {
194  zoa = channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX];
195  zod = channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX];
196  aoa = channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX];
197  aod = channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX];
198  }
199  else
200  {
201  zod = channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX];
202  zoa = channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX];
203  aod = channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX];
204  aoa = channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX];
205  }
206 
207  for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
208  {
209  // Compute alpha and D as described in 3GPP TR 37.885 v15.3.0, Sec. 6.2.3
210  // These terms account for an additional Doppler contribution due to the
211  // presence of moving objects in the sorrounding environment, such as in
212  // vehicular scenarios.
213  // This contribution is applied only to the delayed (reflected) paths and
214  // must be properly configured by setting the value of
215  // m_vScatt, which is defined as "maximum speed of the vehicle in the
216  // layout".
217  // By default, m_vScatt is set to 0, so there is no additional Doppler
218  // contribution.
219 
220  double alpha = channelParams->m_alpha [cIndex];
221  double D = channelParams->m_D [cIndex];
222 
223  //cluster angle angle[direction][n], where direction = 0(aoa), 1(zoa).
224  double tempDoppler = factor * ((sin (zoa [cIndex] * M_PI / 180) * cos (aoa [cIndex] * M_PI / 180) * uSpeed.x
225  + sin (zoa [cIndex] * M_PI / 180) * sin (aoa [cIndex] * M_PI / 180) * uSpeed.y
226  + cos (zoa [cIndex] * M_PI / 180) * uSpeed.z)
227  + (sin (zod [cIndex] * M_PI / 180) * cos (aod [cIndex] * M_PI / 180) * sSpeed.x
228  + sin (zod [cIndex] * M_PI / 180) * sin (aod [cIndex] * M_PI / 180) * sSpeed.y
229  + cos (zod [cIndex] * M_PI / 180) * sSpeed.z) + 2 * alpha * D);
230  doppler.push_back (std::complex<double> (cos (tempDoppler), sin (tempDoppler)));
231  }
232 
233  NS_ASSERT (numCluster <= doppler.size());
234 
235  // apply the doppler term and the propagation delay to the long term component
236  // to obtain the beamforming gain
237  auto vit = tempPsd->ValuesBegin (); // psd iterator
238  auto sbit = tempPsd->ConstBandsBegin (); // band iterator
239  while (vit != tempPsd->ValuesEnd ())
240  {
241  if ((*vit) != 0.00)
242  {
243  std::complex<double> subsbandGain (0.0, 0.0);
244  double fsb = (*sbit).fc; // center frequency of the sub-band
245  for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
246  {
247  double delay = -2 * M_PI * fsb * (channelParams->m_delay[cIndex]);
248  subsbandGain = subsbandGain + longTerm[cIndex] * doppler[cIndex] * std::complex<double> (cos (delay), sin (delay));
249  }
250  *vit = (*vit) * (norm (subsbandGain));
251  }
252  vit++;
253  sbit++;
254  }
255  return tempPsd;
256 }
257 
260  Ptr<const PhasedArrayModel> aPhasedArrayModel,
261  Ptr<const PhasedArrayModel> bPhasedArrayModel) const
262 {
263  PhasedArrayModel::ComplexVector longTerm; // vector containing the long term component for each cluster
264 
265  // check if the channel matrix was generated considering a as the s-node and
266  // b as the u-node or viceversa
268  if (!channelMatrix->IsReverse (aPhasedArrayModel->GetId (), bPhasedArrayModel->GetId ()))
269  {
270  sW = aPhasedArrayModel->GetBeamformingVector ();
271  uW = bPhasedArrayModel->GetBeamformingVector ();
272  }
273  else
274  {
275  sW = bPhasedArrayModel->GetBeamformingVector ();
276  uW = aPhasedArrayModel->GetBeamformingVector ();
277  }
278 
279  bool update = false; // indicates whether the long term has to be updated
280  bool notFound = false; // indicates if the long term has not been computed yet
281 
282  // compute the long term key, the key is unique for each tx-rx pair
283  uint64_t longTermId = 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 != channelMatrix->m_generatedTime
295  || m_longTermMap[longTermId]->m_sW != sW
296  || m_longTermMap[longTermId]->m_uW != uW);
297 
298  }
299  else
300  {
301  NS_LOG_DEBUG ("long term component NOT found");
302  notFound = true;
303  }
304 
305  if (update || notFound)
306  {
307  NS_LOG_DEBUG ("compute the long term");
308  // compute the long term component
309  longTerm = CalcLongTerm (channelMatrix, sW, uW);
310 
311  // store the long term
312  Ptr<LongTerm> longTermItem = Create<LongTerm> ();
313  longTermItem->m_longTerm = longTerm;
314  longTermItem->m_channel = channelMatrix;
315  longTermItem->m_sW = sW;
316  longTermItem->m_uW = uW;
317 
318  m_longTermMap[longTermId] = longTermItem;
319  }
320 
321  return longTerm;
322 }
323 
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, "The position of a and b devices cannot be the same");
337 
338  Ptr<SpectrumValue> rxPsd = Copy<SpectrumValue> (txPsd);
339 
340  // retrieve the antenna of device a
341  NS_ASSERT_MSG (aPhasedArrayModel, "Antenna not found for node " << aId);
342  NS_LOG_DEBUG ("a node " << a->GetObject<Node> () << " antenna " << aPhasedArrayModel);
343 
344  // retrieve the antenna of the device b
345  NS_ASSERT_MSG (bPhasedArrayModel, "Antenna not found for device " << bId);
346  NS_LOG_DEBUG ("b node " << bId << " antenna " << bPhasedArrayModel);
347 
348  Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix = m_channelModel->GetChannel (a, b, aPhasedArrayModel, bPhasedArrayModel);
349  Ptr<const MatrixBasedChannelModel::ChannelParams> channelParams = m_channelModel->GetParams (a, b);
350 
351  // retrieve the long term component
352  PhasedArrayModel::ComplexVector longTerm = GetLongTerm (channelMatrix, aPhasedArrayModel, bPhasedArrayModel);
353 
354  // apply the beamforming gain
355  rxPsd = CalcBeamformingGain (rxPsd, longTerm, channelMatrix, channelParams, a->GetVelocity (), b->GetVelocity ());
356 
357  return rxPsd;
358 }
359 
360 
361 } // namespace ns3
Hold a value for an Attribute.
Definition: attribute.h:69
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:41
double Get(void) const
Definition: double.cc:35
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
std::vector< double > DoubleVector
type definition for vectors of doubles
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:57
std::vector< std::complex< double > > ComplexVector
type definition for complex vectors
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:74
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
Values::iterator ValuesBegin()
Bands::const_iterator ConstBandsBegin() const
Values::iterator ValuesEnd()
Hold variables of type string.
Definition: string.h:41
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 SpectrumValue > txPsd, 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(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:379
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:67
#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:88
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:227
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#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:45
const double norm
Normalization to obtain randoms on [0,1).
Definition: rng-stream.cc:64
Every class exported by the ns3 library is enclosed in the ns3 namespace.
float alpha
Plot alpha value (transparency)
channel
Definition: third.py:92