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
37namespace ns3
38{
39
40NS_LOG_COMPONENT_DEFINE("ThreeGppSpectrumPropagationLossModel");
41
42NS_OBJECT_ENSURE_REGISTERED(ThreeGppSpectrumPropagationLossModel);
43
45{
46 NS_LOG_FUNCTION(this);
47}
48
50{
51 NS_LOG_FUNCTION(this);
52}
53
54void
56{
57 m_longTermMap.clear();
58 m_channelModel->Dispose();
59 m_channelModel = nullptr;
60}
61
64{
65 static TypeId tid =
66 TypeId("ns3::ThreeGppSpectrumPropagationLossModel")
68 .SetGroupName("Spectrum")
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
80void
82{
84}
85
88{
89 return m_channelModel;
90}
91
92double
94{
95 DoubleValue freq;
96 m_channelModel->GetAttribute("Frequency", freq);
97 return freq.Get();
98}
99
100void
102 const AttributeValue& value)
103{
104 m_channelModel->SetAttribute(name, value);
105}
106
107void
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 uint16_t sAntenna = static_cast<uint16_t>(sW.size());
123 uint16_t uAntenna = static_cast<uint16_t>(uW.size());
124
125 NS_ASSERT(uAntenna == params->m_channel.size());
126 NS_ASSERT(sAntenna == params->m_channel.at(0).size());
127
128 NS_LOG_DEBUG("CalcLongTerm with sAntenna " << sAntenna << " uAntenna " << uAntenna);
129 // store the long term part to reduce computation load
130 // only the small scale fading needs to be updated if the large scale parameters and antenna
131 // weights remain unchanged.
133 uint8_t numCluster = static_cast<uint8_t>(params->m_channel[0][0].size());
134
135 NS_ASSERT(uAntenna == params->m_channel.size());
136 NS_ASSERT(sAntenna == params->m_channel.at(0).size());
137
138 for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
139 {
140 std::complex<double> txSum(0, 0);
141 for (uint16_t sIndex = 0; sIndex < sAntenna; sIndex++)
142 {
143 std::complex<double> rxSum(0, 0);
144 for (uint16_t uIndex = 0; uIndex < uAntenna; uIndex++)
145 {
146 rxSum = rxSum + uW[uIndex] * params->m_channel[uIndex][sIndex][cIndex];
147 }
148 txSum = txSum + sW[sIndex] * rxSum;
149 }
150 longTerm.push_back(txSum);
151 }
152 return longTerm;
153}
154
157 Ptr<SpectrumValue> txPsd,
161 const ns3::Vector& sSpeed,
162 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>(channelMatrix->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
178 // The following asserts might seem paranoic, but it is important to
179 // make sure that all the structures that are passed to this function
180 // are of the correct dimensions before using the operator [].
181 // If you dont understand the comment read about the difference of .at()
182 // and [] operators, ...
183 NS_ASSERT(numCluster <= channelParams->m_alpha.size());
184 NS_ASSERT(numCluster <= channelParams->m_D.size());
185 NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX].size());
186 NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX].size());
187 NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX].size());
188 NS_ASSERT(numCluster <= channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX].size());
189 NS_ASSERT(numCluster <= longTerm.size());
190
191 // check if channelParams structure is generated in direction s-to-u or u-to-s
192 bool isSameDirection = (channelParams->m_nodeIds == channelMatrix->m_nodeIds);
193
198
199 // if channel params is generated in the same direction in which we
200 // generate the channel matrix, angles and zenit od departure and arrival are ok,
201 // just set them to corresponding variable that will be used for the generation
202 // of channel matrix, otherwise we need to flip angles and zenits of departure and arrival
203 if (isSameDirection)
204 {
205 zoa = channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX];
206 zod = channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX];
207 aoa = channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX];
208 aod = channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX];
209 }
210 else
211 {
212 zod = channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX];
213 zoa = channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX];
214 aod = channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX];
215 aoa = channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX];
216 }
217
218 for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
219 {
220 // Compute alpha and D as described in 3GPP TR 37.885 v15.3.0, Sec. 6.2.3
221 // These terms account for an additional Doppler contribution due to the
222 // presence of moving objects in the sorrounding environment, such as in
223 // vehicular scenarios.
224 // This contribution is applied only to the delayed (reflected) paths and
225 // must be properly configured by setting the value of
226 // m_vScatt, which is defined as "maximum speed of the vehicle in the
227 // layout".
228 // By default, m_vScatt is set to 0, so there is no additional Doppler
229 // contribution.
230
231 double alpha = channelParams->m_alpha[cIndex];
232 double D = channelParams->m_D[cIndex];
233
234 // cluster angle angle[direction][n], where direction = 0(aoa), 1(zoa).
235 double tempDoppler =
236 factor * ((sin(zoa[cIndex] * M_PI / 180) * cos(aoa[cIndex] * M_PI / 180) * uSpeed.x +
237 sin(zoa[cIndex] * M_PI / 180) * sin(aoa[cIndex] * M_PI / 180) * uSpeed.y +
238 cos(zoa[cIndex] * M_PI / 180) * uSpeed.z) +
239 (sin(zod[cIndex] * M_PI / 180) * cos(aod[cIndex] * M_PI / 180) * sSpeed.x +
240 sin(zod[cIndex] * M_PI / 180) * sin(aod[cIndex] * M_PI / 180) * sSpeed.y +
241 cos(zod[cIndex] * M_PI / 180) * sSpeed.z) +
242 2 * alpha * D);
243 doppler.emplace_back(cos(tempDoppler), sin(tempDoppler));
244 }
245
246 NS_ASSERT(numCluster <= doppler.size());
247
248 // apply the doppler term and the propagation delay to the long term component
249 // to obtain the beamforming gain
250 auto vit = tempPsd->ValuesBegin(); // psd iterator
251 auto sbit = tempPsd->ConstBandsBegin(); // band iterator
252 while (vit != tempPsd->ValuesEnd())
253 {
254 if ((*vit) != 0.00)
255 {
256 std::complex<double> subsbandGain(0.0, 0.0);
257 double fsb = (*sbit).fc; // center frequency of the sub-band
258 for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++)
259 {
260 double delay = -2 * M_PI * fsb * (channelParams->m_delay[cIndex]);
261 subsbandGain = subsbandGain + longTerm[cIndex] * doppler[cIndex] *
262 std::complex<double>(cos(delay), sin(delay));
263 }
264 *vit = (*vit) * (norm(subsbandGain));
265 }
266 vit++;
267 sbit++;
268 }
269 return tempPsd;
270}
271
275 Ptr<const PhasedArrayModel> aPhasedArrayModel,
276 Ptr<const PhasedArrayModel> bPhasedArrayModel) const
277{
279 longTerm; // vector containing the long term component for each cluster
280
281 // check if the channel matrix was generated considering a as the s-node and
282 // b as the u-node or viceversa
285 if (!channelMatrix->IsReverse(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId()))
286 {
287 sW = aPhasedArrayModel->GetBeamformingVector();
288 uW = bPhasedArrayModel->GetBeamformingVector();
289 }
290 else
291 {
292 sW = bPhasedArrayModel->GetBeamformingVector();
293 uW = aPhasedArrayModel->GetBeamformingVector();
294 }
295
296 bool update = false; // indicates whether the long term has to be updated
297 bool notFound = false; // indicates if the long term has not been computed yet
298
299 // compute the long term key, the key is unique for each tx-rx pair
300 uint64_t longTermId =
301 MatrixBasedChannelModel::GetKey(aPhasedArrayModel->GetId(), bPhasedArrayModel->GetId());
302
303 // look for the long term in the map and check if it is valid
304 if (m_longTermMap.find(longTermId) != m_longTermMap.end())
305 {
306 NS_LOG_DEBUG("found the long term component in the map");
307 longTerm = m_longTermMap[longTermId]->m_longTerm;
308
309 // check if the channel matrix has been updated
310 // or the s beam has been changed
311 // or the u beam has been changed
312 update = (m_longTermMap[longTermId]->m_channel->m_generatedTime !=
313 channelMatrix->m_generatedTime ||
314 m_longTermMap[longTermId]->m_sW != sW || m_longTermMap[longTermId]->m_uW != uW);
315 }
316 else
317 {
318 NS_LOG_DEBUG("long term component NOT found");
319 notFound = true;
320 }
321
322 if (update || notFound)
323 {
324 NS_LOG_DEBUG("compute the long term");
325 // compute the long term component
326 longTerm = CalcLongTerm(channelMatrix, sW, uW);
327
328 // store the long term
329 Ptr<LongTerm> longTermItem = Create<LongTerm>();
330 longTermItem->m_longTerm = longTerm;
331 longTermItem->m_channel = channelMatrix;
332 longTermItem->m_sW = sW;
333 longTermItem->m_uW = uW;
334
335 m_longTermMap[longTermId] = longTermItem;
336 }
337
338 return longTerm;
339}
340
346 Ptr<const PhasedArrayModel> aPhasedArrayModel,
347 Ptr<const PhasedArrayModel> bPhasedArrayModel) const
348{
349 NS_LOG_FUNCTION(this);
350 uint32_t aId = a->GetObject<Node>()->GetId(); // id of the node a
351 uint32_t bId = b->GetObject<Node>()->GetId(); // id of the node b
352
353 NS_ASSERT(aId != bId);
354 NS_ASSERT_MSG(a->GetDistanceFrom(b) > 0.0,
355 "The position of a and b devices cannot be the same");
356
357 Ptr<SpectrumValue> rxPsd = Copy<SpectrumValue>(params->psd);
358
359 // retrieve the antenna of device a
360 NS_ASSERT_MSG(aPhasedArrayModel, "Antenna not found for node " << aId);
361 NS_LOG_DEBUG("a node " << a->GetObject<Node>() << " antenna " << aPhasedArrayModel);
362
363 // retrieve the antenna of the device b
364 NS_ASSERT_MSG(bPhasedArrayModel, "Antenna not found for device " << bId);
365 NS_LOG_DEBUG("b node " << bId << " antenna " << bPhasedArrayModel);
366
368 m_channelModel->GetChannel(a, b, aPhasedArrayModel, bPhasedArrayModel);
370 m_channelModel->GetParams(a, b);
371
372 // retrieve the long term component
374 GetLongTerm(channelMatrix, aPhasedArrayModel, bPhasedArrayModel);
375
376 // apply the beamforming gain
377 rxPsd = CalcBeamformingGain(rxPsd,
378 longTerm,
379 channelMatrix,
380 channelParams,
381 a->GetVelocity(),
382 b->GetVelocity());
383
384 return rxPsd;
385}
386
387} // 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
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:56
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: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:42
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
#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)
Definition: pointer.h:230
#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:45
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