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"
25 #include "ns3/net-device.h"
26 #include "ns3/phased-array-model.h"
27 #include "ns3/node.h"
28 #include "ns3/channel-condition-model.h"
29 #include "ns3/double.h"
30 #include "ns3/string.h"
31 #include "ns3/simulator.h"
32 #include "ns3/pointer.h"
33 #include <map>
34 
35 namespace ns3 {
36 
37 NS_LOG_COMPONENT_DEFINE ("ThreeGppSpectrumPropagationLossModel");
38 
39 NS_OBJECT_ENSURE_REGISTERED (ThreeGppSpectrumPropagationLossModel);
40 
42 {
43  NS_LOG_FUNCTION (this);
44  m_uniformRv = CreateObject<UniformRandomVariable> ();
45 }
46 
48 {
49  NS_LOG_FUNCTION (this);
50 }
51 
52 void
54 {
55  m_deviceAntennaMap.clear ();
56  m_longTermMap.clear ();
57  m_channelModel->Dispose ();
58  m_channelModel = nullptr;
59 }
60 
61 TypeId
63 {
64  static TypeId tid = TypeId ("ns3::ThreeGppSpectrumPropagationLossModel")
66  .SetGroupName ("Spectrum")
67  .AddConstructor<ThreeGppSpectrumPropagationLossModel> ()
68  .AddAttribute("ChannelModel",
69  "The channel model. It needs to implement the MatrixBasedChannelModel interface",
70  StringValue("ns3::ThreeGppChannelModel"),
73  MakePointerChecker<MatrixBasedChannelModel> ())
74  .AddAttribute ("vScatt",
75  "Maximum speed of the vehicle in the layout (see 3GPP TR 37.885 v15.3.0, Sec. 6.2.3)."
76  "Used to compute the additional contribution for the Doppler of"
77  "delayed (reflected) paths",
78  DoubleValue (0.0),
80  MakeDoubleChecker<double> (0.0))
81  ;
82  return tid;
83 }
84 
85 void
87 {
89 }
90 
93 {
94  return m_channelModel;
95 }
96 
97 void
99 {
100  NS_ASSERT_MSG (m_deviceAntennaMap.find (n->GetNode ()->GetId ()) == m_deviceAntennaMap.end (), "Device is already present in the map");
101  m_deviceAntennaMap.insert (std::make_pair (n->GetNode ()->GetId (), a));
102 }
103 
104 double
106 {
107  DoubleValue freq;
108  m_channelModel->GetAttribute ("Frequency", freq);
109  return freq.Get ();
110 }
111 
112 void
114 {
115  m_channelModel->SetAttribute (name, value);
116 }
117 
118 void
120 {
121  m_channelModel->GetAttribute (name, value);
122 }
123 
127  const PhasedArrayModel::ComplexVector &uW) const
128 {
129  NS_LOG_FUNCTION (this);
130 
131  uint16_t sAntenna = static_cast<uint16_t> (sW.size ());
132  uint16_t uAntenna = static_cast<uint16_t> (uW.size ());
133 
134  NS_LOG_DEBUG ("CalcLongTerm with sAntenna " << sAntenna << " uAntenna " << uAntenna);
135  //store the long term part to reduce computation load
136  //only the small scale fading needs to be updated if the large scale parameters and antenna weights remain unchanged.
138  uint8_t numCluster = static_cast<uint8_t> (params->m_channel[0][0].size ());
139 
140  for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
141  {
142  std::complex<double> txSum (0,0);
143  for (uint16_t sIndex = 0; sIndex < sAntenna; sIndex++)
144  {
145  std::complex<double> rxSum (0,0);
146  for (uint16_t uIndex = 0; uIndex < uAntenna; uIndex++)
147  {
148  rxSum = rxSum + uW[uIndex] * params->m_channel[uIndex][sIndex][cIndex];
149  }
150  txSum = txSum + sW[sIndex] * rxSum;
151  }
152  longTerm.push_back (txSum);
153  }
154  return longTerm;
155 }
156 
161  const ns3::Vector &sSpeed, const ns3::Vector &uSpeed) const
162 {
163  NS_LOG_FUNCTION (this);
164 
165  Ptr<SpectrumValue> tempPsd = Copy<SpectrumValue> (txPsd);
166 
167  //channel[rx][tx][cluster]
168  uint8_t numCluster = static_cast<uint8_t> (params->m_channel[0][0].size ());
169 
170  // compute the doppler term
171  // NOTE the update of Doppler is simplified by only taking the center angle of
172  // each cluster in to consideration.
173  double slotTime = Simulator::Now ().GetSeconds ();
175  for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
176  {
177  // Compute alpha and D as described in 3GPP TR 37.885 v15.3.0, Sec. 6.2.3
178  // These terms account for an additional Doppler contribution due to the
179  // presence of moving objects in the sorrounding environment, such as in
180  // vehicular scenarios.
181  // This contribution is applied only to the delayed (reflected) paths and
182  // must be properly configured by setting the value of
183  // m_vScatt, which is defined as "maximum speed of the vehicle in the
184  // layout".
185  // By default, m_vScatt is set to 0, so there is no additional Doppler
186  // contribution.
187  double alpha = 0;
188  double D = 0;
189  if (cIndex != 0)
190  {
191  alpha = m_uniformRv->GetValue (-1, 1);
193  }
194 
195  //cluster angle angle[direction][n],where, direction = 0(aoa), 1(zoa).
196  double temp_doppler = 2 * M_PI * ((sin (params->m_angle[MatrixBasedChannelModel::ZOA_INDEX][cIndex] * M_PI / 180) * cos (params->m_angle[MatrixBasedChannelModel::AOA_INDEX][cIndex] * M_PI / 180) * uSpeed.x
197  + sin (params->m_angle[MatrixBasedChannelModel::ZOA_INDEX][cIndex] * M_PI / 180) * sin (params->m_angle[MatrixBasedChannelModel::AOA_INDEX][cIndex] * M_PI / 180) * uSpeed.y
198  + cos (params->m_angle[MatrixBasedChannelModel::ZOA_INDEX][cIndex] * M_PI / 180) * uSpeed.z)
199  + (sin (params->m_angle[MatrixBasedChannelModel::ZOD_INDEX][cIndex] * M_PI / 180) * cos (params->m_angle[MatrixBasedChannelModel::AOD_INDEX][cIndex] * M_PI / 180) * sSpeed.x
200  + sin (params->m_angle[MatrixBasedChannelModel::ZOD_INDEX][cIndex] * M_PI / 180) * sin (params->m_angle[MatrixBasedChannelModel::AOD_INDEX][cIndex] * M_PI / 180) * sSpeed.y
201  + cos (params->m_angle[MatrixBasedChannelModel::ZOD_INDEX][cIndex] * M_PI / 180) * sSpeed.z) + 2 * alpha * D)
202  * slotTime * GetFrequency () / 3e8;
203  doppler.push_back (exp (std::complex<double> (0, temp_doppler)));
204  }
205 
206  // apply the doppler term and the propagation delay to the long term component
207  // to obtain the beamforming gain
208  auto vit = tempPsd->ValuesBegin (); // psd iterator
209  auto sbit = tempPsd->ConstBandsBegin(); // band iterator
210  while (vit != tempPsd->ValuesEnd ())
211  {
212  std::complex<double> subsbandGain (0.0,0.0);
213  if ((*vit) != 0.00)
214  {
215  double fsb = (*sbit).fc; // center frequency of the sub-band
216  for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
217  {
218  double delay = -2 * M_PI * fsb * (params->m_delay[cIndex]);
219  subsbandGain = subsbandGain + longTerm[cIndex] * doppler[cIndex] * exp (std::complex<double> (0, delay));
220  }
221  *vit = (*vit) * (norm (subsbandGain));
222  }
223  vit++;
224  sbit++;
225  }
226  return tempPsd;
227 }
228 
233  const PhasedArrayModel::ComplexVector &bW) const
234 {
235  PhasedArrayModel::ComplexVector longTerm; // vector containing the long term component for each cluster
236 
237  // check if the channel matrix was generated considering a as the s-node and
238  // b as the u-node or viceversa
240  if (!channelMatrix->IsReverse (aId, bId))
241  {
242  sW = aW;
243  uW = bW;
244  }
245  else
246  {
247  sW = bW;
248  uW = aW;
249  }
250 
251  // compute the long term key, the key is unique for each tx-rx pair
252  uint32_t x1 = std::min (aId, bId);
253  uint32_t x2 = std::max (aId, bId);
254  uint32_t longTermId = MatrixBasedChannelModel::GetKey (x1, x2);
255 
256  bool update = false; // indicates whether the long term has to be updated
257  bool notFound = false; // indicates if the long term has not been computed yet
258 
259  // look for the long term in the map and check if it is valid
260  if (m_longTermMap.find (longTermId) != m_longTermMap.end ())
261  {
262  NS_LOG_DEBUG ("found the long term component in the map");
263  longTerm = m_longTermMap[longTermId]->m_longTerm;
264 
265  // check if the channel matrix has been updated
266  // or the s beam has been changed
267  // or the u beam has been changed
268  update = (m_longTermMap[longTermId]->m_channel->m_generatedTime != channelMatrix->m_generatedTime
269  || m_longTermMap[longTermId]->m_sW != sW
270  || m_longTermMap[longTermId]->m_uW != uW);
271 
272  }
273  else
274  {
275  NS_LOG_DEBUG ("long term component NOT found");
276  notFound = true;
277  }
278 
279  if (update || notFound)
280  {
281  NS_LOG_DEBUG ("compute the long term");
282  // compute the long term component
283  longTerm = CalcLongTerm (channelMatrix, sW, uW);
284 
285  // store the long term
286  Ptr<LongTerm> longTermItem = Create<LongTerm> ();
287  longTermItem->m_longTerm = longTerm;
288  longTermItem->m_channel = channelMatrix;
289  longTermItem->m_sW = sW;
290  longTermItem->m_uW = uW;
291 
292  m_longTermMap[longTermId] = longTermItem;
293  }
294 
295  return longTerm;
296 }
297 
301  Ptr<const MobilityModel> b) const
302 {
303  NS_LOG_FUNCTION (this);
304  uint32_t aId = a->GetObject<Node> ()->GetId (); // id of the node a
305  uint32_t bId = b->GetObject<Node> ()->GetId (); // id of the node b
306 
307  NS_ASSERT (aId != bId);
308  NS_ASSERT_MSG (a->GetDistanceFrom (b) > 0.0, "The position of a and b devices cannot be the same");
309 
310  Ptr<SpectrumValue> rxPsd = Copy<SpectrumValue> (txPsd);
311 
312  // retrieve the antenna of device a
313  NS_ASSERT_MSG (m_deviceAntennaMap.find (aId) != m_deviceAntennaMap.end (), "Antenna not found for node " << aId);
315  NS_LOG_DEBUG ("a node " << a->GetObject<Node> () << " antenna " << aAntenna);
316 
317  // retrieve the antenna of the device b
318  NS_ASSERT_MSG (m_deviceAntennaMap.find (bId) != m_deviceAntennaMap.end (), "Antenna not found for device " << bId);
320  NS_LOG_DEBUG ("b node " << bId << " antenna " << bAntenna);
321 
322  Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix = m_channelModel->GetChannel (a, b, aAntenna, bAntenna);
323 
324  // get the precoding and combining vectors
325  PhasedArrayModel::ComplexVector aW = aAntenna->GetBeamformingVector ();
326  PhasedArrayModel::ComplexVector bW = bAntenna->GetBeamformingVector ();
327 
328  // retrieve the long term component
329  PhasedArrayModel::ComplexVector longTerm = GetLongTerm (aId, bId, channelMatrix, aW, bW);
330 
331  // apply the beamforming gain
332  rxPsd = CalcBeamformingGain (rxPsd, longTerm, channelMatrix, a->GetVelocity (), b->GetVelocity ());
333 
334  return rxPsd;
335 }
336 
337 
338 } // namespace ns3
void SetChannelModel(Ptr< MatrixBasedChannelModel > channel)
Set the channel model object.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
std::unordered_map< uint32_t, Ptr< const LongTerm > > m_longTermMap
map containing the long term components
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Hold variables of type string.
Definition: string.h:41
#define min(a, b)
Definition: 80211b.c:42
Hold a value for an Attribute.
Definition: attribute.h:68
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:380
#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_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
PhasedArrayModel::ComplexVector m_longTerm
vector containing the long term component for each cluster
Values::iterator ValuesEnd()
std::unordered_map< uint32_t, Ptr< const PhasedArrayModel > > m_deviceAntennaMap
map containig the <node, antenna> associations
channel
Definition: third.py:92
PhasedArrayModel::ComplexVector GetLongTerm(uint32_t aId, uint32_t bId, Ptr< const MatrixBasedChannelModel::ChannelMatrix > channelMatrix, const PhasedArrayModel::ComplexVector &aW, const PhasedArrayModel::ComplexVector &bW) const
Looks for the long term component in m_longTermMap.
static const uint8_t AOD_INDEX
index of the AOD value in the m_angle array
PhasedArrayModel::ComplexVector m_sW
the beamforming vector for the node s used to compute the long term
Ptr< MatrixBasedChannelModel > GetChannelModel() const
Get the channel model object.
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 max(a, b)
Definition: 80211b.c:43
static const uint8_t ZOA_INDEX
index of the ZOA value in the m_angle array
double Get(void) const
Definition: double.cc:35
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< SpectrumValue > CalcBeamformingGain(Ptr< SpectrumValue > txPsd, PhasedArrayModel::ComplexVector longTerm, Ptr< const MatrixBasedChannelModel::ChannelMatrix > params, const Vector &sSpeed, const Vector &uSpeed) const
Computes the beamforming gain and applies it to the tx PSD.
double GetValue(double min, double max)
Get the next random value, as a double in the specified range .
static constexpr uint32_t GetKey(uint32_t x1, uint32_t x2)
Calculate the channel key using the Cantor function.
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
#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 > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: double.h:42
double m_vScatt
value used to compute the additional Doppler contribution for the delayed paths
PhasedArrayModel::ComplexVector m_uW
the beamforming vector for the node u used to compute the long term
Values::iterator ValuesBegin()
std::vector< std::complex< double > > ComplexVector
type definition for complex vectors
Ptr< const MatrixBasedChannelModel::ChannelMatrix > m_channel
pointer to the channel matrix used to compute the long term
A network Node.
Definition: node.h:56
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
Ptr< UniformRandomVariable > m_uniformRv
uniform random variable, used to compute the additional Doppler contribution
static const uint8_t AOA_INDEX
index of the AOA value in the m_angle array
const double norm
Normalization to obtain randoms on [0,1).
Definition: rng-stream.cc:64
Ptr< MatrixBasedChannelModel > m_channelModel
the model to generate the channel matrix
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) const override
Computes the received PSD.
spectrum-aware propagation loss model
PhasedArrayModel::ComplexVector CalcLongTerm(Ptr< const MatrixBasedChannelModel::ChannelMatrix > channelMatrix, const PhasedArrayModel::ComplexVector &sW, const PhasedArrayModel::ComplexVector &uW) const
Computes the long term component.
This class can be used to hold variables of floating point type such as &#39;double&#39; or &#39;float&#39;...
Definition: double.h:41
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
void AddDevice(Ptr< NetDevice > n, Ptr< const PhasedArrayModel > a)
Add a device-antenna pair.
void SetChannelModelAttribute(const std::string &name, const AttributeValue &value)
Sets the value of an attribute belonging to the associated MatrixBasedChannelModel instance...
Bands::const_iterator ConstBandsBegin() const
static const uint8_t ZOD_INDEX
index of the ZOD value in the m_angle array