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"
24 #include "three-gpp-spectrum-propagation-loss-model.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
ThreeGppSpectrumPropagationLossModel()41 ThreeGppSpectrumPropagationLossModel::ThreeGppSpectrumPropagationLossModel ()
42 {
43 NS_LOG_FUNCTION (this);
44 m_uniformRv = CreateObject<UniformRandomVariable> ();
45 }
46
~ThreeGppSpectrumPropagationLossModel()47 ThreeGppSpectrumPropagationLossModel::~ThreeGppSpectrumPropagationLossModel ()
48 {
49 NS_LOG_FUNCTION (this);
50 }
51
52 void
DoDispose()53 ThreeGppSpectrumPropagationLossModel::DoDispose ()
54 {
55 m_deviceAntennaMap.clear ();
56 m_longTermMap.clear ();
57 m_channelModel->Dispose ();
58 m_channelModel = nullptr;
59 }
60
61 TypeId
GetTypeId(void)62 ThreeGppSpectrumPropagationLossModel::GetTypeId (void)
63 {
64 static TypeId tid = TypeId ("ns3::ThreeGppSpectrumPropagationLossModel")
65 .SetParent<SpectrumPropagationLossModel> ()
66 .SetGroupName ("Spectrum")
67 .AddConstructor<ThreeGppSpectrumPropagationLossModel> ()
68 .AddAttribute("ChannelModel",
69 "The channel model. It needs to implement the MatrixBasedChannelModel interface",
70 StringValue("ns3::ThreeGppChannelModel"),
71 MakePointerAccessor (&ThreeGppSpectrumPropagationLossModel::SetChannelModel,
72 &ThreeGppSpectrumPropagationLossModel::GetChannelModel),
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),
79 MakeDoubleAccessor (&ThreeGppSpectrumPropagationLossModel::m_vScatt),
80 MakeDoubleChecker<double> (0.0))
81 ;
82 return tid;
83 }
84
85 void
SetChannelModel(Ptr<MatrixBasedChannelModel> channel)86 ThreeGppSpectrumPropagationLossModel::SetChannelModel (Ptr<MatrixBasedChannelModel> channel)
87 {
88 m_channelModel = channel;
89 }
90
91 Ptr<MatrixBasedChannelModel>
GetChannelModel() const92 ThreeGppSpectrumPropagationLossModel::GetChannelModel () const
93 {
94 return m_channelModel;
95 }
96
97 void
AddDevice(Ptr<NetDevice> n,Ptr<const PhasedArrayModel> a)98 ThreeGppSpectrumPropagationLossModel::AddDevice (Ptr<NetDevice> n, Ptr<const PhasedArrayModel> a)
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
GetFrequency() const105 ThreeGppSpectrumPropagationLossModel::GetFrequency () const
106 {
107 DoubleValue freq;
108 m_channelModel->GetAttribute ("Frequency", freq);
109 return freq.Get ();
110 }
111
112 void
SetChannelModelAttribute(const std::string & name,const AttributeValue & value)113 ThreeGppSpectrumPropagationLossModel::SetChannelModelAttribute (const std::string &name, const AttributeValue &value)
114 {
115 m_channelModel->SetAttribute (name, value);
116 }
117
118 void
GetChannelModelAttribute(const std::string & name,AttributeValue & value) const119 ThreeGppSpectrumPropagationLossModel::GetChannelModelAttribute (const std::string &name, AttributeValue &value) const
120 {
121 m_channelModel->GetAttribute (name, value);
122 }
123
124 PhasedArrayModel::ComplexVector
CalcLongTerm(Ptr<const MatrixBasedChannelModel::ChannelMatrix> params,const PhasedArrayModel::ComplexVector & sW,const PhasedArrayModel::ComplexVector & uW) const125 ThreeGppSpectrumPropagationLossModel::CalcLongTerm (Ptr<const MatrixBasedChannelModel::ChannelMatrix> params,
126 const PhasedArrayModel::ComplexVector &sW,
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.
137 PhasedArrayModel::ComplexVector longTerm;
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
157 Ptr<SpectrumValue>
CalcBeamformingGain(Ptr<SpectrumValue> txPsd,PhasedArrayModel::ComplexVector longTerm,Ptr<const MatrixBasedChannelModel::ChannelMatrix> params,const ns3::Vector & sSpeed,const ns3::Vector & uSpeed) const158 ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain (Ptr<SpectrumValue> txPsd,
159 PhasedArrayModel::ComplexVector longTerm,
160 Ptr<const MatrixBasedChannelModel::ChannelMatrix> params,
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 ();
174 PhasedArrayModel::ComplexVector doppler;
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);
192 D = m_uniformRv->GetValue (-m_vScatt, m_vScatt);
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
229 PhasedArrayModel::ComplexVector
GetLongTerm(uint32_t aId,uint32_t bId,Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix,const PhasedArrayModel::ComplexVector & aW,const PhasedArrayModel::ComplexVector & bW) const230 ThreeGppSpectrumPropagationLossModel::GetLongTerm (uint32_t aId, uint32_t bId,
231 Ptr<const MatrixBasedChannelModel::ChannelMatrix> channelMatrix,
232 const PhasedArrayModel::ComplexVector &aW,
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
239 PhasedArrayModel::ComplexVector sW, uW;
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
298 Ptr<SpectrumValue>
DoCalcRxPowerSpectralDensity(Ptr<const SpectrumValue> txPsd,Ptr<const MobilityModel> a,Ptr<const MobilityModel> b) const299 ThreeGppSpectrumPropagationLossModel::DoCalcRxPowerSpectralDensity (Ptr<const SpectrumValue> txPsd,
300 Ptr<const MobilityModel> a,
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);
314 Ptr<const PhasedArrayModel> aAntenna = m_deviceAntennaMap.at (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);
319 Ptr<const PhasedArrayModel> bAntenna = m_deviceAntennaMap.at (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
339