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