A Discrete-Event Network Simulator
API
multi-model-spectrum-channel.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 CTTC
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Nicola Baldo <nbaldo@cttc.es>
18 */
19
21
22#include <ns3/angles.h>
23#include <ns3/antenna-model.h>
24#include <ns3/double.h>
25#include <ns3/log.h>
26#include <ns3/mobility-model.h>
27#include <ns3/net-device.h>
28#include <ns3/node.h>
29#include <ns3/object.h>
30#include <ns3/packet-burst.h>
31#include <ns3/packet.h>
32#include <ns3/propagation-delay-model.h>
33#include <ns3/propagation-loss-model.h>
34#include <ns3/simulator.h>
35#include <ns3/spectrum-converter.h>
36#include <ns3/spectrum-phy.h>
37#include <ns3/spectrum-propagation-loss-model.h>
38
39#include <algorithm>
40#include <iostream>
41#include <utility>
42
43namespace ns3
44{
45
46NS_LOG_COMPONENT_DEFINE("MultiModelSpectrumChannel");
47
48NS_OBJECT_ENSURE_REGISTERED(MultiModelSpectrumChannel);
49
56std::ostream&
57operator<<(std::ostream& lhs, TxSpectrumModelInfoMap_t& rhs)
58{
59 for (TxSpectrumModelInfoMap_t::iterator it = rhs.begin(); it != rhs.end(); ++it)
60 {
61 SpectrumConverterMap_t::iterator jt;
62 for (jt = it->second.m_spectrumConverterMap.begin();
63 jt != it->second.m_spectrumConverterMap.end();
64 ++jt)
65 {
66 lhs << "(" << it->first << "," << jt->first << ") ";
67 }
68 }
69 return lhs;
70}
71
73 : m_txSpectrumModel(txSpectrumModel)
74{
75}
76
78 : m_rxSpectrumModel(rxSpectrumModel)
79{
80}
81
83 : m_numDevices{0}
84{
85 NS_LOG_FUNCTION(this);
86}
87
88void
90{
91 NS_LOG_FUNCTION(this);
95}
96
99{
100 static TypeId tid = TypeId("ns3::MultiModelSpectrumChannel")
102 .SetGroupName("Spectrum")
103 .AddConstructor<MultiModelSpectrumChannel>()
104
105 ;
106 return tid;
107}
108
109void
111{
112 NS_LOG_FUNCTION(this << phy);
113
114 // remove a previous entry of this phy if it exists
115 // we need to scan for all rxSpectrumModel values since we don't
116 // know which spectrum model the phy had when it was previously added
117 // (it's probably different than the current one)
118 for (RxSpectrumModelInfoMap_t::iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
119 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
120 ++rxInfoIterator)
121 {
122 auto phyIt = std::find(rxInfoIterator->second.m_rxPhys.begin(),
123 rxInfoIterator->second.m_rxPhys.end(),
124 phy);
125 if (phyIt != rxInfoIterator->second.m_rxPhys.end())
126 {
127 rxInfoIterator->second.m_rxPhys.erase(phyIt);
128 --m_numDevices;
129 break; // there should be at most one entry
130 }
131 }
132}
133
134void
136{
137 NS_LOG_FUNCTION(this << phy);
138
139 Ptr<const SpectrumModel> rxSpectrumModel = phy->GetRxSpectrumModel();
140
141 NS_ASSERT_MSG(rxSpectrumModel,
142 "phy->GetRxSpectrumModel () returned 0. Please check that the RxSpectrumModel is "
143 "already set for the phy before calling MultiModelSpectrumChannel::AddRx (phy)");
144
145 SpectrumModelUid_t rxSpectrumModelUid = rxSpectrumModel->GetUid();
146
147 RemoveRx(phy);
148
149 ++m_numDevices;
150
151 RxSpectrumModelInfoMap_t::iterator rxInfoIterator =
152 m_rxSpectrumModelInfoMap.find(rxSpectrumModelUid);
153
154 if (rxInfoIterator == m_rxSpectrumModelInfoMap.end())
155 {
156 // spectrum model unknown, add it to the list of RxSpectrumModels
157 std::pair<RxSpectrumModelInfoMap_t::iterator, bool> ret;
158 ret = m_rxSpectrumModelInfoMap.insert(
159 std::make_pair(rxSpectrumModelUid, RxSpectrumModelInfo(rxSpectrumModel)));
160 NS_ASSERT(ret.second);
161 // also add the phy to the newly created set of SpectrumPhy for this RxSpectrumModel
162 ret.first->second.m_rxPhys.push_back(phy);
163
164 // and create the necessary converters for all the TX spectrum models that we know of
165 for (TxSpectrumModelInfoMap_t::iterator txInfoIterator = m_txSpectrumModelInfoMap.begin();
166 txInfoIterator != m_txSpectrumModelInfoMap.end();
167 ++txInfoIterator)
168 {
169 Ptr<const SpectrumModel> txSpectrumModel = txInfoIterator->second.m_txSpectrumModel;
170 SpectrumModelUid_t txSpectrumModelUid = txSpectrumModel->GetUid();
171
172 if (rxSpectrumModelUid != txSpectrumModelUid &&
173 !txSpectrumModel->IsOrthogonal(*rxSpectrumModel))
174 {
175 NS_LOG_LOGIC("Creating converter between SpectrumModelUid "
176 << txSpectrumModel->GetUid() << " and " << rxSpectrumModelUid);
177 SpectrumConverter converter(txSpectrumModel, rxSpectrumModel);
178 std::pair<SpectrumConverterMap_t::iterator, bool> ret2;
179 ret2 = txInfoIterator->second.m_spectrumConverterMap.insert(
180 std::make_pair(rxSpectrumModelUid, converter));
181 NS_ASSERT(ret2.second);
182 }
183 }
184 }
185 else
186 {
187 // spectrum model is already known, just add the device to the corresponding list
188 rxInfoIterator->second.m_rxPhys.push_back(phy);
189 }
190}
191
192TxSpectrumModelInfoMap_t::const_iterator
194 Ptr<const SpectrumModel> txSpectrumModel)
195{
196 NS_LOG_FUNCTION(this << txSpectrumModel);
197 SpectrumModelUid_t txSpectrumModelUid = txSpectrumModel->GetUid();
198 TxSpectrumModelInfoMap_t::iterator txInfoIterator =
199 m_txSpectrumModelInfoMap.find(txSpectrumModelUid);
200
201 if (txInfoIterator == m_txSpectrumModelInfoMap.end())
202 {
203 // first time we see this TX SpectrumModel
204 // we add it to the list
205 std::pair<TxSpectrumModelInfoMap_t::iterator, bool> ret;
206 ret = m_txSpectrumModelInfoMap.insert(
207 std::make_pair(txSpectrumModelUid, TxSpectrumModelInfo(txSpectrumModel)));
208 NS_ASSERT(ret.second);
209 txInfoIterator = ret.first;
210
211 // and we create the converters for all the RX SpectrumModels that we know of
212 for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator =
214 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
215 ++rxInfoIterator)
216 {
217 Ptr<const SpectrumModel> rxSpectrumModel = rxInfoIterator->second.m_rxSpectrumModel;
218 SpectrumModelUid_t rxSpectrumModelUid = rxSpectrumModel->GetUid();
219
220 if (rxSpectrumModelUid != txSpectrumModelUid &&
221 !txSpectrumModel->IsOrthogonal(*rxSpectrumModel))
222 {
223 NS_LOG_LOGIC("Creating converter between SpectrumModelUid "
224 << txSpectrumModelUid << " and " << rxSpectrumModelUid);
225
226 SpectrumConverter converter(txSpectrumModel, rxSpectrumModel);
227 std::pair<SpectrumConverterMap_t::iterator, bool> ret2;
228 ret2 = txInfoIterator->second.m_spectrumConverterMap.insert(
229 std::make_pair(rxSpectrumModelUid, converter));
230 NS_ASSERT(ret2.second);
231 }
232 }
233 }
234 else
235 {
236 NS_LOG_LOGIC("SpectrumModelUid " << txSpectrumModelUid << " already present");
237 }
238 return txInfoIterator;
239}
240
241void
243{
244 NS_LOG_FUNCTION(this << txParams);
245
246 NS_ASSERT(txParams->txPhy);
247 NS_ASSERT(txParams->psd);
248 Ptr<SpectrumSignalParameters> txParamsTrace =
249 txParams->Copy(); // copy it since traced value cannot be const (because of potential
250 // underlying DynamicCasts)
251 m_txSigParamsTrace(txParamsTrace);
252
253 Ptr<MobilityModel> txMobility = txParams->txPhy->GetMobility();
254 SpectrumModelUid_t txSpectrumModelUid = txParams->psd->GetSpectrumModelUid();
255 NS_LOG_LOGIC("txSpectrumModelUid " << txSpectrumModelUid);
256
257 //
258 TxSpectrumModelInfoMap_t::const_iterator txInfoIteratorerator =
260 NS_ASSERT(txInfoIteratorerator != m_txSpectrumModelInfoMap.end());
261
262 NS_LOG_LOGIC("converter map for TX SpectrumModel with Uid " << txInfoIteratorerator->first);
264 "converter map size: " << txInfoIteratorerator->second.m_spectrumConverterMap.size());
265 NS_LOG_LOGIC("converter map first element: "
266 << txInfoIteratorerator->second.m_spectrumConverterMap.begin()->first);
267
268 for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
269 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
270 ++rxInfoIterator)
271 {
272 SpectrumModelUid_t rxSpectrumModelUid = rxInfoIterator->second.m_rxSpectrumModel->GetUid();
273 NS_LOG_LOGIC("rxSpectrumModelUids " << rxSpectrumModelUid);
274
275 Ptr<SpectrumValue> convertedTxPowerSpectrum;
276 if (txSpectrumModelUid == rxSpectrumModelUid)
277 {
278 NS_LOG_LOGIC("no spectrum conversion needed");
279 convertedTxPowerSpectrum = txParams->psd;
280 }
281 else
282 {
283 NS_LOG_LOGIC("converting txPowerSpectrum SpectrumModelUids "
284 << txSpectrumModelUid << " --> " << rxSpectrumModelUid);
285 SpectrumConverterMap_t::const_iterator rxConverterIterator =
286 txInfoIteratorerator->second.m_spectrumConverterMap.find(rxSpectrumModelUid);
287 if (rxConverterIterator == txInfoIteratorerator->second.m_spectrumConverterMap.end())
288 {
289 // No converter means TX SpectrumModel is orthogonal to RX SpectrumModel
290 continue;
291 }
292 convertedTxPowerSpectrum = rxConverterIterator->second.Convert(txParams->psd);
293 }
294
295 for (auto rxPhyIterator = rxInfoIterator->second.m_rxPhys.begin();
296 rxPhyIterator != rxInfoIterator->second.m_rxPhys.end();
297 ++rxPhyIterator)
298 {
299 NS_ASSERT_MSG((*rxPhyIterator)->GetRxSpectrumModel()->GetUid() == rxSpectrumModelUid,
300 "SpectrumModel change was not notified to MultiModelSpectrumChannel "
301 "(i.e., AddRx should be called again after model is changed)");
302
303 if ((*rxPhyIterator) != txParams->txPhy)
304 {
305 Ptr<NetDevice> rxNetDevice = (*rxPhyIterator)->GetDevice();
306 Ptr<NetDevice> txNetDevice = txParams->txPhy->GetDevice();
307
308 if (rxNetDevice && txNetDevice)
309 {
310 // we assume that devices are attached to a node
311 if (rxNetDevice->GetNode()->GetId() == txNetDevice->GetNode()->GetId())
312 {
314 "Skipping the pathloss calculation among different antennas of the "
315 "same node, not supported yet by any pathloss model in ns-3.");
316 continue;
317 }
318 }
319
320 NS_LOG_LOGIC("copying signal parameters " << txParams);
321 Ptr<SpectrumSignalParameters> rxParams = txParams->Copy();
322 rxParams->psd = Copy<SpectrumValue>(convertedTxPowerSpectrum);
323 Time delay = MicroSeconds(0);
324
325 Ptr<MobilityModel> receiverMobility = (*rxPhyIterator)->GetMobility();
326
327 if (txMobility && receiverMobility)
328 {
329 double txAntennaGain = 0;
330 double rxAntennaGain = 0;
331 double propagationGainDb = 0;
332 double pathLossDb = 0;
333 if (rxParams->txAntenna)
334 {
335 Angles txAngles(receiverMobility->GetPosition(), txMobility->GetPosition());
336 txAntennaGain = rxParams->txAntenna->GetGainDb(txAngles);
337 NS_LOG_LOGIC("txAntennaGain = " << txAntennaGain << " dB");
338 pathLossDb -= txAntennaGain;
339 }
340 Ptr<AntennaModel> rxAntenna =
341 DynamicCast<AntennaModel>((*rxPhyIterator)->GetAntenna());
342 if (rxAntenna)
343 {
344 Angles rxAngles(txMobility->GetPosition(), receiverMobility->GetPosition());
345 rxAntennaGain = rxAntenna->GetGainDb(rxAngles);
346 NS_LOG_LOGIC("rxAntennaGain = " << rxAntennaGain << " dB");
347 pathLossDb -= rxAntennaGain;
348 }
350 {
351 propagationGainDb =
352 m_propagationLoss->CalcRxPower(0, txMobility, receiverMobility);
353 NS_LOG_LOGIC("propagationGainDb = " << propagationGainDb << " dB");
354 pathLossDb -= propagationGainDb;
355 }
356 NS_LOG_LOGIC("total pathLoss = " << pathLossDb << " dB");
357 // Gain trace
358 m_gainTrace(txMobility,
359 receiverMobility,
360 txAntennaGain,
361 rxAntennaGain,
362 propagationGainDb,
363 pathLossDb);
364 // Pathloss trace
365 m_pathLossTrace(txParams->txPhy, *rxPhyIterator, pathLossDb);
366 if (pathLossDb > m_maxLossDb)
367 {
368 // beyond range
369 continue;
370 }
371 double pathGainLinear = std::pow(10.0, (-pathLossDb) / 10.0);
372 *(rxParams->psd) *= pathGainLinear;
373
375 {
376 delay = m_propagationDelay->GetDelay(txMobility, receiverMobility);
377 }
378 }
379
380 if (rxNetDevice)
381 {
382 // the receiver has a NetDevice, so we expect that it is attached to a Node
383 uint32_t dstNode = rxNetDevice->GetNode()->GetId();
385 delay,
387 this,
388 rxParams,
389 *rxPhyIterator);
390 }
391 else
392 {
393 // the receiver is not attached to a NetDevice, so we cannot assume that it is
394 // attached to a node
397 this,
398 rxParams,
399 *rxPhyIterator);
400 }
401 }
402 }
403 }
404}
405
406void
408{
409 NS_LOG_FUNCTION(this);
411 {
412 params->psd =
413 m_spectrumPropagationLoss->CalcRxPowerSpectralDensity(params,
414 params->txPhy->GetMobility(),
415 receiver->GetMobility());
416 }
418 {
419 Ptr<const PhasedArrayModel> txPhasedArrayModel =
420 DynamicCast<PhasedArrayModel>(params->txPhy->GetAntenna());
421 Ptr<const PhasedArrayModel> rxPhasedArrayModel =
422 DynamicCast<PhasedArrayModel>(receiver->GetAntenna());
423
424 NS_ASSERT_MSG(txPhasedArrayModel && rxPhasedArrayModel,
425 "PhasedArrayModel instances should be installed at both TX and RX "
426 "SpectrumPhy in order to use PhasedArraySpectrumPropagationLoss.");
427
428 params->psd = m_phasedArraySpectrumPropagationLoss->CalcRxPowerSpectralDensity(
429 params,
430 params->txPhy->GetMobility(),
431 receiver->GetMobility(),
432 txPhasedArrayModel,
433 rxPhasedArrayModel);
434 }
435 receiver->StartRx(params);
436}
437
438std::size_t
440{
441 return m_numDevices;
442}
443
446{
448 // this method implementation is computationally intensive. This
449 // method would be faster if we actually used a std::vector for
450 // storing devices, which we don't due to the need to have fast
451 // SpectrumModel conversions and to allow PHY devices to change a
452 // SpectrumModel at run time. Note that having this method slow is
453 // acceptable as it is not used much at run time (often not at all).
454 // On the other hand, having slow SpectrumModel conversion would be
455 // less acceptable.
456 std::size_t j = 0;
457 for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
458 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
459 ++rxInfoIterator)
460 {
461 for (const auto& phyIt : rxInfoIterator->second.m_rxPhys)
462 {
463 if (j == i)
464 {
465 return (*phyIt).GetDevice();
466 }
467 j++;
468 }
469 }
470 NS_FATAL_ERROR("m_numDevices > actual number of devices");
471 return nullptr;
472}
473
474} // namespace ns3
Class holding the azimuth and inclination angles of spherical coordinates.
Definition: angles.h:118
virtual double GetGainDb(Angles a)=0
this method is expected to be re-implemented by each antenna model
Vector GetPosition() const
This SpectrumChannel implementation can handle the presence of SpectrumPhy instances which can use di...
void RemoveRx(Ptr< SpectrumPhy > phy) override
Remove a SpectrumPhy from a channel.
Ptr< NetDevice > GetDevice(std::size_t i) const override
std::size_t GetNDevices() const override
void AddRx(Ptr< SpectrumPhy > phy) override
Add a SpectrumPhy to a channel, so it can receive packets.
TxSpectrumModelInfoMap_t m_txSpectrumModelInfoMap
Data structure holding, for each TX SpectrumModel, all the converters to any RX SpectrumModel,...
std::size_t m_numDevices
Number of devices connected to the channel.
void DoDispose() override
Destructor implementation.
void StartTx(Ptr< SpectrumSignalParameters > params) override
Used by attached PHY instances to transmit signals on the channel.
TxSpectrumModelInfoMap_t::const_iterator FindAndEventuallyAddTxSpectrumModel(Ptr< const SpectrumModel > txSpectrumModel)
This method checks if m_rxSpectrumModelInfoMap contains an entry for the given TX SpectrumModel.
static TypeId GetTypeId()
Get the type ID.
virtual void StartRx(Ptr< SpectrumSignalParameters > params, Ptr< SpectrumPhy > receiver)
Used internally to reschedule transmission after the propagation delay.
RxSpectrumModelInfoMap_t m_rxSpectrumModelInfoMap
Data structure holding, for each RX spectrum model, all the corresponding SpectrumPhy instances.
double CalcRxPower(double txPowerDbm, Ptr< MobilityModel > a, Ptr< MobilityModel > b) const
Returns the Rx Power taking into account all the PropagationLossModel(s) chained to the current one.
The Rx spectrum model information.
RxSpectrumModelInfo(Ptr< const SpectrumModel > rxSpectrumModel)
Constructor.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static void ScheduleWithContext(uint32_t context, const Time &delay, FUNC f, Ts &&... args)
Schedule an event with the given context.
Definition: simulator.h:587
Defines the interface for spectrum-aware channel implementations.
TracedCallback< Ptr< SpectrumSignalParameters > > m_txSigParamsTrace
Traced callback for SpectrumSignalParameters in StartTx requests.
void DoDispose() override
Destructor implementation.
Ptr< PropagationDelayModel > m_propagationDelay
Propagation delay model to be used with this channel.
Ptr< SpectrumPropagationLossModel > m_spectrumPropagationLoss
Frequency-dependent propagation loss model to be used with this channel.
Ptr< PhasedArraySpectrumPropagationLossModel > m_phasedArraySpectrumPropagationLoss
Frequency-dependent propagation loss model to be used with this channel.
TracedCallback< Ptr< const SpectrumPhy >, Ptr< const SpectrumPhy >, double > m_pathLossTrace
The PathLoss trace source.
TracedCallback< Ptr< const MobilityModel >, Ptr< const MobilityModel >, double, double, double, double > m_gainTrace
The Gain trace source.
Ptr< PropagationLossModel > m_propagationLoss
Single-frequency propagation loss model to be used with this channel.
double m_maxLossDb
Maximum loss [dB].
Class which implements a converter between SpectrumValue which are defined over different SpectrumMod...
bool IsOrthogonal(const SpectrumModel &other) const
Check if another SpectrumModels has bands orthogonal to our bands.
SpectrumModelUid_t GetUid() const
virtual Ptr< MobilityModel > GetMobility() const =0
Get the associated MobilityModel instance.
virtual Ptr< Object > GetAntenna() const =0
Get the AntennaModel used by this SpectrumPhy instance for transmission and/or reception.
virtual Ptr< NetDevice > GetDevice() const =0
Get the associated NetDevice instance.
virtual void StartRx(Ptr< SpectrumSignalParameters > params)=0
Notify the SpectrumPhy instance of an incoming signal.
Ptr< const SpectrumModel > GetSpectrumModel() const
SpectrumModelUid_t GetSpectrumModelUid() const
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
The Tx spectrum model information.
TxSpectrumModelInfo(Ptr< const SpectrumModel > txSpectrumModel)
Constructor.
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
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:160
#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_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#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
std::map< SpectrumModelUid_t, TxSpectrumModelInfo > TxSpectrumModelInfoMap_t
Container: SpectrumModelUid_t, TxSpectrumModelInfo.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:129
phy
Definition: third.py:82
Ptr< AntennaModel > txAntenna
The AntennaModel instance that was used to transmit this signal.
Ptr< SpectrumPhy > txPhy
The SpectrumPhy instance that is making the transmission.
virtual Ptr< SpectrumSignalParameters > Copy() const
make a "virtual" copy of this class, where "virtual" refers to the fact that if the actual object is ...
Ptr< SpectrumValue > psd
The Power Spectral Density of the waveform, in linear units.