1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2009 CTTC
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Author: Nicola Baldo <nbaldo@cttc.es>
19  */
20 
21 #include <algorithm>
22 #include <iostream>
23 #include <utility>
24 #include <ns3/object.h>
25 #include <ns3/simulator.h>
26 #include <ns3/log.h>
27 #include <ns3/packet.h>
28 #include <ns3/packet-burst.h>
29 #include <ns3/net-device.h>
30 #include <ns3/node.h>
31 #include <ns3/double.h>
32 #include <ns3/mobility-model.h>
33 #include <ns3/spectrum-phy.h>
34 #include <ns3/spectrum-converter.h>
35 #include <ns3/spectrum-propagation-loss-model.h>
36 #include <ns3/propagation-loss-model.h>
37 #include <ns3/propagation-delay-model.h>
38 #include <ns3/antenna-model.h>
39 #include <ns3/angles.h>
40 #include "multi-model-spectrum-channel.h"
41 
42 namespace ns3 {
43 
44 NS_LOG_COMPONENT_DEFINE ("MultiModelSpectrumChannel");
45 
46 NS_OBJECT_ENSURE_REGISTERED (MultiModelSpectrumChannel);
47 
48 /**
49  * \brief Output stream operator
50  * \param lhs output stream
51  * \param rhs the TxSpectrumModelInfoMap to print
52  * \return an output stream
53  */
operator <<(std::ostream & lhs,TxSpectrumModelInfoMap_t & rhs)54 std::ostream& operator<< (std::ostream& lhs, TxSpectrumModelInfoMap_t& rhs)
55 {
56   for (TxSpectrumModelInfoMap_t::iterator it = rhs.begin ();
57        it != rhs.end ();
58        ++it)
59     {
60       SpectrumConverterMap_t::iterator jt;
61       for (jt = it->second.m_spectrumConverterMap.begin ();
62            jt != it->second.m_spectrumConverterMap.end ();
63            ++jt)
64         {
65           lhs << "(" << it->first << "," << jt->first << ") ";
66         }
67     }
68   return lhs;
69 }
70 
TxSpectrumModelInfo(Ptr<const SpectrumModel> txSpectrumModel)71 TxSpectrumModelInfo::TxSpectrumModelInfo (Ptr<const SpectrumModel> txSpectrumModel)
72   : m_txSpectrumModel (txSpectrumModel)
73 {
74 }
75 
RxSpectrumModelInfo(Ptr<const SpectrumModel> rxSpectrumModel)76 RxSpectrumModelInfo::RxSpectrumModelInfo (Ptr<const SpectrumModel> rxSpectrumModel)
77   : m_rxSpectrumModel (rxSpectrumModel)
78 {
79 }
80 
MultiModelSpectrumChannel()81 MultiModelSpectrumChannel::MultiModelSpectrumChannel ()
82   : m_numDevices {0}
83 {
84   NS_LOG_FUNCTION (this);
85 }
86 
87 void
DoDispose()88 MultiModelSpectrumChannel::DoDispose ()
89 {
90   NS_LOG_FUNCTION (this);
91   m_txSpectrumModelInfoMap.clear ();
92   m_rxSpectrumModelInfoMap.clear ();
93   SpectrumChannel::DoDispose ();
94 }
95 
96 TypeId
GetTypeId(void)97 MultiModelSpectrumChannel::GetTypeId (void)
98 {
99   static TypeId tid = TypeId ("ns3::MultiModelSpectrumChannel")
100     .SetParent<SpectrumChannel> ()
101     .SetGroupName ("Spectrum")
102     .AddConstructor<MultiModelSpectrumChannel> ()
103 
104   ;
105   return tid;
106 }
107 
108 void
AddRx(Ptr<SpectrumPhy> phy)109 MultiModelSpectrumChannel::AddRx (Ptr<SpectrumPhy> phy)
110 {
111   NS_LOG_FUNCTION (this << phy);
112 
113   Ptr<const SpectrumModel> rxSpectrumModel = phy->GetRxSpectrumModel ();
114 
115   NS_ASSERT_MSG ((0 != rxSpectrumModel), "phy->GetRxSpectrumModel () returned 0. Please check that the RxSpectrumModel is already set for the phy before calling MultiModelSpectrumChannel::AddRx (phy)");
116 
117   SpectrumModelUid_t rxSpectrumModelUid = rxSpectrumModel->GetUid ();
118 
119   // remove a previous entry of this phy if it exists
120   // we need to scan for all rxSpectrumModel values since we don't
121   // know which spectrum model the phy had when it was previously added
122   // (it's probably different than the current one)
123   for (RxSpectrumModelInfoMap_t::iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin ();
124        rxInfoIterator !=  m_rxSpectrumModelInfoMap.end ();
125        ++rxInfoIterator)
126     {
127       auto phyIt = std::find (rxInfoIterator->second.m_rxPhys.begin(), rxInfoIterator->second.m_rxPhys.end(), phy);
128       if (phyIt != rxInfoIterator->second.m_rxPhys.end ())
129         {
130           rxInfoIterator->second.m_rxPhys.erase (phyIt);
131           --m_numDevices;
132           break; // there should be at most one entry
133         }
134     }
135 
136   ++m_numDevices;
137 
138   RxSpectrumModelInfoMap_t::iterator rxInfoIterator = m_rxSpectrumModelInfoMap.find (rxSpectrumModelUid);
139 
140   if (rxInfoIterator == m_rxSpectrumModelInfoMap.end ())
141     {
142       // spectrum model unknown, add it to the list of RxSpectrumModels
143       std::pair<RxSpectrumModelInfoMap_t::iterator, bool> ret;
144       ret = m_rxSpectrumModelInfoMap.insert (std::make_pair (rxSpectrumModelUid, RxSpectrumModelInfo (rxSpectrumModel)));
145       NS_ASSERT (ret.second);
146       // also add the phy to the newly created set of SpectrumPhy for this RxSpectrumModel
147       ret.first->second.m_rxPhys.push_back (phy);
148 
149       // and create the necessary converters for all the TX spectrum models that we know of
150       for (TxSpectrumModelInfoMap_t::iterator txInfoIterator = m_txSpectrumModelInfoMap.begin ();
151            txInfoIterator != m_txSpectrumModelInfoMap.end ();
152            ++txInfoIterator)
153         {
154           Ptr<const SpectrumModel> txSpectrumModel = txInfoIterator->second.m_txSpectrumModel;
155           SpectrumModelUid_t txSpectrumModelUid = txSpectrumModel->GetUid ();
156 
157           if (rxSpectrumModelUid != txSpectrumModelUid && !txSpectrumModel->IsOrthogonal (*rxSpectrumModel))
158             {
159               NS_LOG_LOGIC ("Creating converter between SpectrumModelUid " << txSpectrumModel->GetUid () << " and " << rxSpectrumModelUid);
160               SpectrumConverter converter (txSpectrumModel, rxSpectrumModel);
161               std::pair<SpectrumConverterMap_t::iterator, bool> ret2;
162               ret2 = txInfoIterator->second.m_spectrumConverterMap.insert (std::make_pair (rxSpectrumModelUid, converter));
163               NS_ASSERT (ret2.second);
164             }
165         }
166     }
167   else
168     {
169       // spectrum model is already known, just add the device to the corresponding list
170       rxInfoIterator->second.m_rxPhys.push_back (phy);
171     }
172 }
173 
174 TxSpectrumModelInfoMap_t::const_iterator
FindAndEventuallyAddTxSpectrumModel(Ptr<const SpectrumModel> txSpectrumModel)175 MultiModelSpectrumChannel::FindAndEventuallyAddTxSpectrumModel (Ptr<const SpectrumModel> txSpectrumModel)
176 {
177   NS_LOG_FUNCTION (this << txSpectrumModel);
178   SpectrumModelUid_t txSpectrumModelUid = txSpectrumModel->GetUid ();
179   TxSpectrumModelInfoMap_t::iterator txInfoIterator = m_txSpectrumModelInfoMap.find (txSpectrumModelUid);
180 
181   if (txInfoIterator == m_txSpectrumModelInfoMap.end ())
182     {
183       // first time we see this TX SpectrumModel
184       // we add it to the list
185       std::pair<TxSpectrumModelInfoMap_t::iterator, bool> ret;
186       ret = m_txSpectrumModelInfoMap.insert (std::make_pair (txSpectrumModelUid, TxSpectrumModelInfo (txSpectrumModel)));
187       NS_ASSERT (ret.second);
188       txInfoIterator = ret.first;
189 
190       // and we create the converters for all the RX SpectrumModels that we know of
191       for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin ();
192            rxInfoIterator != m_rxSpectrumModelInfoMap.end ();
193            ++rxInfoIterator)
194         {
195           Ptr<const SpectrumModel> rxSpectrumModel = rxInfoIterator->second.m_rxSpectrumModel;
196           SpectrumModelUid_t rxSpectrumModelUid = rxSpectrumModel->GetUid ();
197 
198           if (rxSpectrumModelUid != txSpectrumModelUid && !txSpectrumModel->IsOrthogonal (*rxSpectrumModel))
199             {
200               NS_LOG_LOGIC ("Creating converter between SpectrumModelUid " << txSpectrumModelUid << " and " << rxSpectrumModelUid);
201 
202               SpectrumConverter converter (txSpectrumModel, rxSpectrumModel);
203               std::pair<SpectrumConverterMap_t::iterator, bool> ret2;
204               ret2 = txInfoIterator->second.m_spectrumConverterMap.insert (std::make_pair (rxSpectrumModelUid, converter));
205               NS_ASSERT (ret2.second);
206             }
207         }
208     }
209   else
210     {
211       NS_LOG_LOGIC ("SpectrumModelUid " << txSpectrumModelUid << " already present");
212     }
213   return txInfoIterator;
214 }
215 
216 void
StartTx(Ptr<SpectrumSignalParameters> txParams)217 MultiModelSpectrumChannel::StartTx (Ptr<SpectrumSignalParameters> txParams)
218 {
219   NS_LOG_FUNCTION (this << txParams);
220 
221   NS_ASSERT (txParams->txPhy);
222   NS_ASSERT (txParams->psd);
223   Ptr<SpectrumSignalParameters> txParamsTrace = txParams->Copy (); // copy it since traced value cannot be const (because of potential underlying DynamicCasts)
224   m_txSigParamsTrace (txParamsTrace);
225 
226   Ptr<MobilityModel> txMobility = txParams->txPhy->GetMobility ();
227   SpectrumModelUid_t txSpectrumModelUid = txParams->psd->GetSpectrumModelUid ();
228   NS_LOG_LOGIC ("txSpectrumModelUid " << txSpectrumModelUid);
229 
230   //
231   TxSpectrumModelInfoMap_t::const_iterator txInfoIteratorerator = FindAndEventuallyAddTxSpectrumModel (txParams->psd->GetSpectrumModel ());
232   NS_ASSERT (txInfoIteratorerator != m_txSpectrumModelInfoMap.end ());
233 
234   NS_LOG_LOGIC ("converter map for TX SpectrumModel with Uid " << txInfoIteratorerator->first);
235   NS_LOG_LOGIC ("converter map size: " << txInfoIteratorerator->second.m_spectrumConverterMap.size ());
236   NS_LOG_LOGIC ("converter map first element: " << txInfoIteratorerator->second.m_spectrumConverterMap.begin ()->first);
237 
238   for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin ();
239        rxInfoIterator != m_rxSpectrumModelInfoMap.end ();
240        ++rxInfoIterator)
241     {
242       SpectrumModelUid_t rxSpectrumModelUid = rxInfoIterator->second.m_rxSpectrumModel->GetUid ();
243       NS_LOG_LOGIC ("rxSpectrumModelUids " << rxSpectrumModelUid);
244 
245       Ptr <SpectrumValue> convertedTxPowerSpectrum;
246       if (txSpectrumModelUid == rxSpectrumModelUid)
247         {
248           NS_LOG_LOGIC ("no spectrum conversion needed");
249           convertedTxPowerSpectrum = txParams->psd;
250         }
251       else
252         {
253           NS_LOG_LOGIC ("converting txPowerSpectrum SpectrumModelUids " << txSpectrumModelUid << " --> " << rxSpectrumModelUid);
254           SpectrumConverterMap_t::const_iterator rxConverterIterator = txInfoIteratorerator->second.m_spectrumConverterMap.find (rxSpectrumModelUid);
255           if (rxConverterIterator == txInfoIteratorerator->second.m_spectrumConverterMap.end ())
256             {
257               // No converter means TX SpectrumModel is orthogonal to RX SpectrumModel
258               continue;
259             }
260           convertedTxPowerSpectrum = rxConverterIterator->second.Convert (txParams->psd);
261         }
262 
263       for (auto rxPhyIterator = rxInfoIterator->second.m_rxPhys.begin ();
264            rxPhyIterator != rxInfoIterator->second.m_rxPhys.end ();
265            ++rxPhyIterator)
266         {
267           NS_ASSERT_MSG ((*rxPhyIterator)->GetRxSpectrumModel ()->GetUid () == rxSpectrumModelUid,
268                          "SpectrumModel change was not notified to MultiModelSpectrumChannel (i.e., AddRx should be called again after model is changed)");
269 
270           if ((*rxPhyIterator) != txParams->txPhy)
271             {
272               NS_LOG_LOGIC ("copying signal parameters " << txParams);
273               Ptr<SpectrumSignalParameters> rxParams = txParams->Copy ();
274               rxParams->psd = Copy<SpectrumValue> (convertedTxPowerSpectrum);
275               Time delay = MicroSeconds (0);
276 
277               Ptr<MobilityModel> receiverMobility = (*rxPhyIterator)->GetMobility ();
278 
279               if (txMobility && receiverMobility)
280                 {
281                   double txAntennaGain = 0;
282                   double rxAntennaGain = 0;
283                   double propagationGainDb = 0;
284                   double pathLossDb = 0;
285                   if (rxParams->txAntenna != 0)
286                     {
287                       Angles txAngles (receiverMobility->GetPosition (), txMobility->GetPosition ());
288                       txAntennaGain = rxParams->txAntenna->GetGainDb (txAngles);
289                       NS_LOG_LOGIC ("txAntennaGain = " << txAntennaGain << " dB");
290                       pathLossDb -= txAntennaGain;
291                     }
292                   Ptr<AntennaModel> rxAntenna = (*rxPhyIterator)->GetRxAntenna ();
293                   if (rxAntenna != 0)
294                     {
295                       Angles rxAngles (txMobility->GetPosition (), receiverMobility->GetPosition ());
296                       rxAntennaGain = rxAntenna->GetGainDb (rxAngles);
297                       NS_LOG_LOGIC ("rxAntennaGain = " << rxAntennaGain << " dB");
298                       pathLossDb -= rxAntennaGain;
299                     }
300                   if (m_propagationLoss)
301                     {
302                       propagationGainDb = m_propagationLoss->CalcRxPower (0, txMobility, receiverMobility);
303                       NS_LOG_LOGIC ("propagationGainDb = " << propagationGainDb << " dB");
304                       pathLossDb -= propagationGainDb;
305                     }
306                   NS_LOG_LOGIC ("total pathLoss = " << pathLossDb << " dB");
307                   // Gain trace
308                   m_gainTrace (txMobility, receiverMobility, txAntennaGain, rxAntennaGain, propagationGainDb, pathLossDb);
309                   // Pathloss trace
310                   m_pathLossTrace (txParams->txPhy, *rxPhyIterator, pathLossDb);
311                   if (pathLossDb > m_maxLossDb)
312                     {
313                       // beyond range
314                       continue;
315                     }
316                   double pathGainLinear = std::pow (10.0, (-pathLossDb) / 10.0);
317                   *(rxParams->psd) *= pathGainLinear;
318 
319                   if (m_spectrumPropagationLoss)
320                     {
321                       rxParams->psd = m_spectrumPropagationLoss->CalcRxPowerSpectralDensity (rxParams->psd, txMobility, receiverMobility);
322                     }
323 
324                   if (m_propagationDelay)
325                     {
326                       delay = m_propagationDelay->GetDelay (txMobility, receiverMobility);
327                     }
328                 }
329 
330               Ptr<NetDevice> netDev = (*rxPhyIterator)->GetDevice ();
331               if (netDev)
332                 {
333                   // the receiver has a NetDevice, so we expect that it is attached to a Node
334                   uint32_t dstNode =  netDev->GetNode ()->GetId ();
335                   Simulator::ScheduleWithContext (dstNode, delay, &MultiModelSpectrumChannel::StartRx, this,
336                                                   rxParams, *rxPhyIterator);
337                 }
338               else
339                 {
340                   // the receiver is not attached to a NetDevice, so we cannot assume that it is attached to a node
341                   Simulator::Schedule (delay, &MultiModelSpectrumChannel::StartRx, this,
342                                        rxParams, *rxPhyIterator);
343                 }
344             }
345         }
346 
347     }
348 
349 }
350 
351 void
StartRx(Ptr<SpectrumSignalParameters> params,Ptr<SpectrumPhy> receiver)352 MultiModelSpectrumChannel::StartRx (Ptr<SpectrumSignalParameters> params, Ptr<SpectrumPhy> receiver)
353 {
354   NS_LOG_FUNCTION (this);
355   receiver->StartRx (params);
356 }
357 
358 std::size_t
GetNDevices(void) const359 MultiModelSpectrumChannel::GetNDevices (void) const
360 {
361   return m_numDevices;
362 }
363 
364 Ptr<NetDevice>
GetDevice(std::size_t i) const365 MultiModelSpectrumChannel::GetDevice (std::size_t i) const
366 {
367   NS_ASSERT (i < m_numDevices);
368   // this method implementation is computationally intensive. This
369   // method would be faster if we actually used a std::vector for
370   // storing devices, which we don't due to the need to have fast
371   // SpectrumModel conversions and to allow PHY devices to change a
372   // SpectrumModel at run time. Note that having this method slow is
373   // acceptable as it is not used much at run time (often not at all).
374   // On the other hand, having slow SpectrumModel conversion would be
375   // less acceptable.
376   std::size_t j = 0;
377   for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin ();
378        rxInfoIterator !=  m_rxSpectrumModelInfoMap.end ();
379        ++rxInfoIterator)
380     {
381       for (const auto &phyIt : rxInfoIterator->second.m_rxPhys)
382         {
383           if (j == i)
384             {
385               return (*phyIt).GetDevice ();
386             }
387           j++;
388         }
389     }
390   NS_FATAL_ERROR ("m_numDevices > actual number of devices");
391   return 0;
392 }
393 
394 } // namespace ns3
395