A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
multi-model-spectrum-channel.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 CTTC
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Nicola Baldo <nbaldo@cttc.es>
7 */
8
10
11#include "spectrum-converter.h"
12#include "spectrum-phy.h"
15
16#include <ns3/angles.h>
17#include <ns3/antenna-model.h>
18#include <ns3/double.h>
19#include <ns3/log.h>
20#include <ns3/mobility-model.h>
21#include <ns3/net-device.h>
22#include <ns3/node.h>
23#include <ns3/object.h>
24#include <ns3/packet-burst.h>
25#include <ns3/packet.h>
26#include <ns3/propagation-delay-model.h>
27#include <ns3/propagation-loss-model.h>
28#include <ns3/simulator.h>
29
30#include <algorithm>
31#include <iostream>
32#include <utility>
33
34namespace ns3
35{
36
37NS_LOG_COMPONENT_DEFINE("MultiModelSpectrumChannel");
38
39NS_OBJECT_ENSURE_REGISTERED(MultiModelSpectrumChannel);
40
41/**
42 * @brief Output stream operator
43 * @param lhs output stream
44 * @param rhs the TxSpectrumModelInfoMap to print
45 * @return an output stream
46 */
47std::ostream&
48operator<<(std::ostream& lhs, TxSpectrumModelInfoMap_t& rhs)
49{
50 for (auto it = rhs.begin(); it != rhs.end(); ++it)
51 {
52 for (auto jt = it->second.m_spectrumConverterMap.begin();
53 jt != it->second.m_spectrumConverterMap.end();
54 ++jt)
55 {
56 lhs << "(" << it->first << "," << jt->first << ") ";
57 }
58 }
59 return lhs;
60}
61
63 : m_txSpectrumModel(txSpectrumModel)
64{
65}
66
68 : m_rxSpectrumModel(rxSpectrumModel)
69{
70}
71
77
78void
86
89{
90 static TypeId tid = TypeId("ns3::MultiModelSpectrumChannel")
92 .SetGroupName("Spectrum")
93 .AddConstructor<MultiModelSpectrumChannel>()
94
95 ;
96 return tid;
97}
98
99void
101{
102 NS_LOG_FUNCTION(this << phy);
103
104 // remove a previous entry of this phy if it exists
105 // we need to scan for all rxSpectrumModel values since we don't
106 // know which spectrum model the phy had when it was previously added
107 // (it's probably different than the current one)
108 for (auto rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
109 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
110 ++rxInfoIterator)
111 {
112 auto phyIt = std::find(rxInfoIterator->second.m_rxPhys.begin(),
113 rxInfoIterator->second.m_rxPhys.end(),
114 phy);
115 if (phyIt != rxInfoIterator->second.m_rxPhys.end())
116 {
117 rxInfoIterator->second.m_rxPhys.erase(phyIt);
118 --m_numDevices;
119 break; // there should be at most one entry
120 }
121 }
122}
123
124void
126{
127 NS_LOG_FUNCTION(this << phy);
128
129 Ptr<const SpectrumModel> rxSpectrumModel = phy->GetRxSpectrumModel();
130
131 NS_ASSERT_MSG(rxSpectrumModel,
132 "phy->GetRxSpectrumModel () returned 0. Please check that the RxSpectrumModel is "
133 "already set for the phy before calling MultiModelSpectrumChannel::AddRx (phy)");
134
135 const auto rxSpectrumModelUid = rxSpectrumModel->GetUid();
136
137 RemoveRx(phy);
138
139 ++m_numDevices;
140
141 auto [rxInfoIterator, inserted] =
142 m_rxSpectrumModelInfoMap.emplace(rxSpectrumModelUid, RxSpectrumModelInfo(rxSpectrumModel));
143
144 // rxInfoIterator points either to the newly inserted element or to the element that
145 // prevented insertion. In both cases, add the phy to the element pointed to by rxInfoIterator
146 rxInfoIterator->second.m_rxPhys.push_back(phy);
147
148 if (inserted)
149 {
150 // create the necessary converters for all the TX spectrum models that we know of
151 for (auto txInfoIterator = m_txSpectrumModelInfoMap.begin();
152 txInfoIterator != m_txSpectrumModelInfoMap.end();
153 ++txInfoIterator)
154 {
155 auto txSpectrumModel = txInfoIterator->second.m_txSpectrumModel;
156 const auto txSpectrumModelUid = txSpectrumModel->GetUid();
157
158 if (rxSpectrumModelUid != txSpectrumModelUid &&
159 !txSpectrumModel->IsOrthogonal(*rxSpectrumModel))
160 {
161 NS_LOG_LOGIC("Creating converter between SpectrumModelUid "
162 << txSpectrumModel->GetUid() << " and " << rxSpectrumModelUid);
163 SpectrumConverter converter(txSpectrumModel, rxSpectrumModel);
164 auto ret2 = txInfoIterator->second.m_spectrumConverterMap.insert(
165 std::make_pair(rxSpectrumModelUid, converter));
166 NS_ASSERT(ret2.second);
167 }
168 }
169 }
170}
171
172TxSpectrumModelInfoMap_t::const_iterator
174 Ptr<const SpectrumModel> txSpectrumModel)
175{
176 NS_LOG_FUNCTION(this << txSpectrumModel);
177 const auto txSpectrumModelUid = txSpectrumModel->GetUid();
178 auto txInfoIterator = m_txSpectrumModelInfoMap.find(txSpectrumModelUid);
179
180 if (txInfoIterator == m_txSpectrumModelInfoMap.end())
181 {
182 // first time we see this TX SpectrumModel
183 // we add it to the list
184 auto ret = m_txSpectrumModelInfoMap.insert(
185 std::make_pair(txSpectrumModelUid, TxSpectrumModelInfo(txSpectrumModel)));
186 NS_ASSERT(ret.second);
187 txInfoIterator = ret.first;
188
189 // and we create the converters for all the RX SpectrumModels that we know of
190 for (auto rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
191 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
192 ++rxInfoIterator)
193 {
194 auto rxSpectrumModel = rxInfoIterator->second.m_rxSpectrumModel;
195 const auto rxSpectrumModelUid = rxSpectrumModel->GetUid();
196
197 if (rxSpectrumModelUid != txSpectrumModelUid &&
198 !txSpectrumModel->IsOrthogonal(*rxSpectrumModel))
199 {
200 NS_LOG_LOGIC("Creating converter between SpectrumModelUid "
201 << txSpectrumModelUid << " and " << rxSpectrumModelUid);
202
203 SpectrumConverter converter(txSpectrumModel, rxSpectrumModel);
204 auto ret2 = txInfoIterator->second.m_spectrumConverterMap.insert(
205 std::make_pair(rxSpectrumModelUid, converter));
206 NS_ASSERT(ret2.second);
207 }
208 }
209 }
210 else
211 {
212 NS_LOG_LOGIC("SpectrumModelUid " << txSpectrumModelUid << " already present");
213 }
214 return txInfoIterator;
215}
216
217void
219{
220 NS_LOG_FUNCTION(this << txParams);
221
222 NS_ASSERT(txParams->txPhy);
223 NS_ASSERT(txParams->psd);
224 auto txParamsTrace = txParams->Copy(); // copy it since traced value cannot be const (because of
225 // potential underlying DynamicCasts)
226 m_txSigParamsTrace(txParamsTrace);
227
228 auto txMobility = txParams->txPhy->GetMobility();
229 const auto txSpectrumModelUid = txParams->psd->GetSpectrumModelUid();
230 NS_LOG_LOGIC("txSpectrumModelUid " << txSpectrumModelUid);
231
232 const auto txInfoIterator =
233 FindAndEventuallyAddTxSpectrumModel(txParams->psd->GetSpectrumModel());
234 NS_ASSERT(txInfoIterator != m_txSpectrumModelInfoMap.cend());
235
236 NS_LOG_LOGIC("converter map for TX SpectrumModel with Uid " << txInfoIterator->first);
237 NS_LOG_LOGIC("converter map size: " << txInfoIterator->second.m_spectrumConverterMap.size());
238 NS_LOG_LOGIC("converter map first element: "
239 << txInfoIterator->second.m_spectrumConverterMap.begin()->first);
240
241 std::map<SpectrumModelUid_t, Ptr<SpectrumValue>> convertedPsds{};
242 for (auto rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
243 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
244 ++rxInfoIterator)
245 {
246 const auto rxSpectrumModelUid = rxInfoIterator->second.m_rxSpectrumModel->GetUid();
247 NS_LOG_LOGIC("rxSpectrumModelUids " << rxSpectrumModelUid);
248
249 Ptr<SpectrumValue> convertedTxPowerSpectrum;
250 if (txSpectrumModelUid == rxSpectrumModelUid)
251 {
252 NS_LOG_LOGIC("no spectrum conversion needed");
253 convertedTxPowerSpectrum = txParams->psd;
254 }
255 else
256 {
257 NS_LOG_LOGIC("converting txPowerSpectrum SpectrumModelUids "
258 << txSpectrumModelUid << " --> " << rxSpectrumModelUid);
259 auto rxConverterIterator =
260 txInfoIterator->second.m_spectrumConverterMap.find(rxSpectrumModelUid);
261 if (rxConverterIterator == txInfoIterator->second.m_spectrumConverterMap.end())
262 {
263 // No converter means TX SpectrumModel is orthogonal to RX SpectrumModel
264 continue;
265 }
266 convertedTxPowerSpectrum = rxConverterIterator->second.Convert(txParams->psd);
267 }
268 convertedPsds.emplace(rxSpectrumModelUid, convertedTxPowerSpectrum);
269 }
270
271 for (auto rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
272 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
273 ++rxInfoIterator)
274 {
275 const auto rxSpectrumModelUid = rxInfoIterator->second.m_rxSpectrumModel->GetUid();
276
277 if ((txSpectrumModelUid != rxSpectrumModelUid) &&
278 !txInfoIterator->second.m_spectrumConverterMap.contains(rxSpectrumModelUid))
279 {
280 // No converter means TX SpectrumModel is orthogonal to RX SpectrumModel
281 continue;
282 }
283
284 for (auto rxPhyIterator = rxInfoIterator->second.m_rxPhys.begin();
285 rxPhyIterator != rxInfoIterator->second.m_rxPhys.end();
286 ++rxPhyIterator)
287 {
288 NS_ASSERT_MSG((*rxPhyIterator)->GetRxSpectrumModel()->GetUid() == rxSpectrumModelUid,
289 "SpectrumModel change was not notified to MultiModelSpectrumChannel "
290 "(i.e., AddRx should be called again after model is changed)");
291
292 auto txAntennaGain{0.0};
293 if ((*rxPhyIterator) != txParams->txPhy)
294 {
295 auto rxNetDevice = (*rxPhyIterator)->GetDevice();
296 auto txNetDevice = txParams->txPhy->GetDevice();
297
298 if (rxNetDevice && txNetDevice)
299 {
300 // we assume that devices are attached to a node
301 if (rxNetDevice->GetNode()->GetId() == txNetDevice->GetNode()->GetId())
302 {
304 "Skipping the pathloss calculation among different antennas of the "
305 "same node, not supported yet by any pathloss model in ns-3.");
306 continue;
307 }
308 }
309
310 if (m_filter && m_filter->Filter(txParams, *rxPhyIterator))
311 {
312 continue;
313 }
314
315 NS_LOG_LOGIC("copying signal parameters " << txParams);
316 auto rxParams = txParams->Copy();
317 rxParams->psd = Copy<SpectrumValue>(convertedPsds.at(rxSpectrumModelUid));
318 Time delay{0};
319
320 auto receiverMobility = (*rxPhyIterator)->GetMobility();
321
322 if (txMobility && receiverMobility)
323 {
324 if (rxParams->txAntenna)
325 {
326 Angles txAngles(receiverMobility->GetPosition(), txMobility->GetPosition());
327 txAntennaGain = rxParams->txAntenna->GetGainDb(txAngles);
328 NS_LOG_LOGIC("txAntennaGain = " << txAntennaGain << " dB");
329 }
331 {
332 delay = m_propagationDelay->GetDelay(txMobility, receiverMobility);
333 }
334 }
335
336 if (rxNetDevice)
337 {
338 // the receiver has a NetDevice, so we expect that it is attached to a Node
339 auto dstNode = rxNetDevice->GetNode()->GetId();
341 delay,
343 this,
344 txParams->psd,
345 txAntennaGain,
346 rxParams,
347 *rxPhyIterator,
348 convertedPsds);
349 }
350 else
351 {
352 // the receiver is not attached to a NetDevice, so we cannot assume that it is
353 // attached to a node
356 this,
357 txParams->psd,
358 txAntennaGain,
359 rxParams,
360 *rxPhyIterator,
361 convertedPsds);
362 }
363 }
364 }
365 }
366}
367
368void
370 Ptr<SpectrumValue> txPsd,
371 double txAntennaGain,
373 Ptr<SpectrumPhy> receiver,
374 const std::map<SpectrumModelUid_t, Ptr<SpectrumValue>>& availableConvertedPsds)
375{
376 NS_LOG_FUNCTION(this);
377
378 const auto rxSpectrumModelUid = params->psd->GetSpectrumModelUid();
379 const auto phySpectrumModelUid = receiver->GetRxSpectrumModel()->GetUid();
380 NS_LOG_LOGIC("rxSpectrumModelUid " << rxSpectrumModelUid << " phySpectrumModelUid "
381 << phySpectrumModelUid);
382
383 if (rxSpectrumModelUid != phySpectrumModelUid)
384 {
385 NS_LOG_LOGIC("SpectrumModelUid changed since TX started");
386
387 const auto itConvertedPsd = availableConvertedPsds.find(phySpectrumModelUid);
388 if (itConvertedPsd != availableConvertedPsds.cend())
389 {
390 NS_LOG_LOGIC("converted PSD already exists for " << phySpectrumModelUid);
391 params->psd = itConvertedPsd->second;
392 }
393 else
394 {
395 const auto txInfoIterator =
396 FindAndEventuallyAddTxSpectrumModel(txPsd->GetSpectrumModel());
397 NS_ASSERT(txInfoIterator != m_txSpectrumModelInfoMap.cend());
398
399 const auto txSpectrumModelUid = txPsd->GetSpectrumModelUid();
400 NS_LOG_LOGIC("converting txPowerSpectrum SpectrumModelUids "
401 << txSpectrumModelUid << " --> " << phySpectrumModelUid);
402 const auto rxConverterIterator =
403 txInfoIterator->second.m_spectrumConverterMap.find(phySpectrumModelUid);
404 if (rxConverterIterator == txInfoIterator->second.m_spectrumConverterMap.cend())
405 {
406 // No converter means TX SpectrumModel is orthogonal to current PHY SpectrumModel
407 params->psd = txPsd;
408 }
409 else
410 {
411 params->psd = rxConverterIterator->second.Convert(txPsd);
412 }
413 }
414 }
415
416 auto txMobility = params->txPhy->GetMobility();
417 auto rxMobility = receiver->GetMobility();
418 if (txMobility && rxMobility)
419 {
420 auto pathLossDb{-txAntennaGain};
421 auto rxAntennaGain{0.0};
422 auto propagationGainDb{0.0};
423
424 if (auto rxAntenna = DynamicCast<AntennaModel>(receiver->GetAntenna()))
425 {
426 Angles rxAngles(txMobility->GetPosition(), rxMobility->GetPosition());
427 rxAntennaGain = rxAntenna->GetGainDb(rxAngles);
428 NS_LOG_LOGIC("rxAntennaGain = " << rxAntennaGain << " dB");
429 pathLossDb -= rxAntennaGain;
430 }
431
432 if (m_propagationLoss && (txMobility->GetPosition() != rxMobility->GetPosition()))
433 {
434 propagationGainDb = m_propagationLoss->CalcRxPower(0, txMobility, rxMobility);
435 NS_LOG_LOGIC("propagationGainDb = " << propagationGainDb << " dB");
436 pathLossDb -= propagationGainDb;
437 }
438
439 NS_LOG_LOGIC("total pathLoss = " << pathLossDb << " dB");
440
441 // Gain trace
442 m_gainTrace(txMobility,
443 rxMobility,
444 txAntennaGain,
445 rxAntennaGain,
446 propagationGainDb,
447 pathLossDb);
448
449 // Pathloss trace
450 m_pathLossTrace(params->txPhy, receiver, pathLossDb);
451
452 if (pathLossDb > m_maxLossDb)
453 {
454 // beyond range
455 return;
456 }
457
458 const auto pathLossLinear = std::pow(10.0, (-pathLossDb) / 10.0);
459 *(params->psd) *= pathLossLinear;
460
462 {
463 params->psd = m_spectrumPropagationLoss->CalcRxPowerSpectralDensity(params,
464 txMobility,
465 rxMobility);
466 }
468 {
469 auto txPhasedArrayModel = DynamicCast<PhasedArrayModel>(params->txPhy->GetAntenna());
470 auto rxPhasedArrayModel = DynamicCast<PhasedArrayModel>(receiver->GetAntenna());
471
472 NS_ASSERT_MSG(txPhasedArrayModel && rxPhasedArrayModel,
473 "PhasedArrayModel instances should be installed at both TX and RX "
474 "SpectrumPhy in order to use PhasedArraySpectrumPropagationLoss.");
475
476 params = m_phasedArraySpectrumPropagationLoss->CalcRxPowerSpectralDensity(
477 params,
478 txMobility,
479 rxMobility,
480 txPhasedArrayModel,
481 rxPhasedArrayModel);
482 }
483 }
484
485 receiver->StartRx(params);
486}
487
488std::size_t
493
496{
498 // this method implementation is computationally intensive. This
499 // method would be faster if we actually used a std::vector for
500 // storing devices, which we don't due to the need to have fast
501 // SpectrumModel conversions and to allow PHY devices to change a
502 // SpectrumModel at run time. Note that having this method slow is
503 // acceptable as it is not used much at run time (often not at all).
504 // On the other hand, having slow SpectrumModel conversion would be
505 // less acceptable.
506 std::size_t j = 0;
507 for (auto rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
508 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
509 ++rxInfoIterator)
510 {
511 for (const auto& phyIt : rxInfoIterator->second.m_rxPhys)
512 {
513 if (j == i)
514 {
515 return (*phyIt).GetDevice();
516 }
517 j++;
518 }
519 }
520 NS_FATAL_ERROR("m_numDevices > actual number of devices");
521 return nullptr;
522}
523
524} // namespace ns3
Class holding the azimuth and inclination angles of spherical coordinates.
Definition angles.h:107
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.
virtual void StartRx(Ptr< SpectrumValue > txPsd, double txAntennaGain, Ptr< SpectrumSignalParameters > params, Ptr< SpectrumPhy > receiver, const std::map< SpectrumModelUid_t, Ptr< SpectrumValue > > &availableConvertedPsds)
Used internally to reschedule transmission after the propagation delay.
Ptr< NetDevice > GetDevice(std::size_t i) 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.
RxSpectrumModelInfoMap_t m_rxSpectrumModelInfoMap
Data structure holding, for each RX spectrum model, all the corresponding SpectrumPhy instances.
Smart pointer class similar to boost::intrusive_ptr.
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:560
static void ScheduleWithContext(uint32_t context, const Time &delay, FUNC f, Ts &&... args)
Schedule an event with the given context.
Definition simulator.h:577
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< SpectrumTransmitFilter > m_filter
Transmit filter to be used with this channel.
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...
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
The Tx spectrum model information.
TxSpectrumModelInfo(Ptr< const SpectrumModel > txSpectrumModel)
Constructor.
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#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:35
std::map< SpectrumModelUid_t, TxSpectrumModelInfo > TxSpectrumModelInfoMap_t
Container: SpectrumModelUid_t, TxSpectrumModelInfo.
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:148
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Definition ptr.h:604