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