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