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 * 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#include <ns3/spectrum-transmit-filter.h>
39
40#include <algorithm>
41#include <iostream>
42#include <utility>
43
44namespace ns3
45{
46
47NS_LOG_COMPONENT_DEFINE("MultiModelSpectrumChannel");
48
49NS_OBJECT_ENSURE_REGISTERED(MultiModelSpectrumChannel);
50
57std::ostream&
58operator<<(std::ostream& lhs, TxSpectrumModelInfoMap_t& rhs)
59{
60 for (TxSpectrumModelInfoMap_t::iterator it = rhs.begin(); it != rhs.end(); ++it)
61 {
62 SpectrumConverterMap_t::iterator jt;
63 for (jt = it->second.m_spectrumConverterMap.begin();
64 jt != it->second.m_spectrumConverterMap.end();
65 ++jt)
66 {
67 lhs << "(" << it->first << "," << jt->first << ") ";
68 }
69 }
70 return lhs;
71}
72
74 : m_txSpectrumModel(txSpectrumModel)
75{
76}
77
79 : m_rxSpectrumModel(rxSpectrumModel)
80{
81}
82
84 : m_numDevices{0}
85{
86 NS_LOG_FUNCTION(this);
87}
88
89void
91{
92 NS_LOG_FUNCTION(this);
96}
97
100{
101 static TypeId tid = TypeId("ns3::MultiModelSpectrumChannel")
103 .SetGroupName("Spectrum")
104 .AddConstructor<MultiModelSpectrumChannel>()
105
106 ;
107 return tid;
108}
109
110void
112{
113 NS_LOG_FUNCTION(this << phy);
114
115 // remove a previous entry of this phy if it exists
116 // we need to scan for all rxSpectrumModel values since we don't
117 // know which spectrum model the phy had when it was previously added
118 // (it's probably different than the current one)
119 for (RxSpectrumModelInfoMap_t::iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
120 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
121 ++rxInfoIterator)
122 {
123 auto phyIt = std::find(rxInfoIterator->second.m_rxPhys.begin(),
124 rxInfoIterator->second.m_rxPhys.end(),
125 phy);
126 if (phyIt != rxInfoIterator->second.m_rxPhys.end())
127 {
128 rxInfoIterator->second.m_rxPhys.erase(phyIt);
129 --m_numDevices;
130 break; // there should be at most one entry
131 }
132 }
133}
134
135void
137{
138 NS_LOG_FUNCTION(this << phy);
139
140 Ptr<const SpectrumModel> rxSpectrumModel = phy->GetRxSpectrumModel();
141
142 NS_ASSERT_MSG(rxSpectrumModel,
143 "phy->GetRxSpectrumModel () returned 0. Please check that the RxSpectrumModel is "
144 "already set for the phy before calling MultiModelSpectrumChannel::AddRx (phy)");
145
146 SpectrumModelUid_t rxSpectrumModelUid = rxSpectrumModel->GetUid();
147
148 RemoveRx(phy);
149
150 ++m_numDevices;
151
152 auto [rxInfoIterator, inserted] =
153 m_rxSpectrumModelInfoMap.emplace(rxSpectrumModelUid, RxSpectrumModelInfo(rxSpectrumModel));
154
155 // rxInfoIterator points either to the newly inserted element or to the element that
156 // prevented insertion. In both cases, add the phy to the element pointed to by rxInfoIterator
157 rxInfoIterator->second.m_rxPhys.push_back(phy);
158
159 if (inserted)
160 {
161 // create the necessary converters for all the TX spectrum models that we know of
162 for (TxSpectrumModelInfoMap_t::iterator txInfoIterator = m_txSpectrumModelInfoMap.begin();
163 txInfoIterator != m_txSpectrumModelInfoMap.end();
164 ++txInfoIterator)
165 {
166 Ptr<const SpectrumModel> txSpectrumModel = txInfoIterator->second.m_txSpectrumModel;
167 SpectrumModelUid_t txSpectrumModelUid = txSpectrumModel->GetUid();
168
169 if (rxSpectrumModelUid != txSpectrumModelUid &&
170 !txSpectrumModel->IsOrthogonal(*rxSpectrumModel))
171 {
172 NS_LOG_LOGIC("Creating converter between SpectrumModelUid "
173 << txSpectrumModel->GetUid() << " and " << rxSpectrumModelUid);
174 SpectrumConverter converter(txSpectrumModel, rxSpectrumModel);
175 std::pair<SpectrumConverterMap_t::iterator, bool> ret2;
176 ret2 = txInfoIterator->second.m_spectrumConverterMap.insert(
177 std::make_pair(rxSpectrumModelUid, converter));
178 NS_ASSERT(ret2.second);
179 }
180 }
181 }
182}
183
184TxSpectrumModelInfoMap_t::const_iterator
186 Ptr<const SpectrumModel> txSpectrumModel)
187{
188 NS_LOG_FUNCTION(this << txSpectrumModel);
189 SpectrumModelUid_t txSpectrumModelUid = txSpectrumModel->GetUid();
190 TxSpectrumModelInfoMap_t::iterator txInfoIterator =
191 m_txSpectrumModelInfoMap.find(txSpectrumModelUid);
192
193 if (txInfoIterator == m_txSpectrumModelInfoMap.end())
194 {
195 // first time we see this TX SpectrumModel
196 // we add it to the list
197 std::pair<TxSpectrumModelInfoMap_t::iterator, bool> ret;
198 ret = m_txSpectrumModelInfoMap.insert(
199 std::make_pair(txSpectrumModelUid, TxSpectrumModelInfo(txSpectrumModel)));
200 NS_ASSERT(ret.second);
201 txInfoIterator = ret.first;
202
203 // and we create the converters for all the RX SpectrumModels that we know of
204 for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator =
206 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
207 ++rxInfoIterator)
208 {
209 Ptr<const SpectrumModel> rxSpectrumModel = rxInfoIterator->second.m_rxSpectrumModel;
210 SpectrumModelUid_t rxSpectrumModelUid = rxSpectrumModel->GetUid();
211
212 if (rxSpectrumModelUid != txSpectrumModelUid &&
213 !txSpectrumModel->IsOrthogonal(*rxSpectrumModel))
214 {
215 NS_LOG_LOGIC("Creating converter between SpectrumModelUid "
216 << txSpectrumModelUid << " and " << rxSpectrumModelUid);
217
218 SpectrumConverter converter(txSpectrumModel, rxSpectrumModel);
219 std::pair<SpectrumConverterMap_t::iterator, bool> ret2;
220 ret2 = txInfoIterator->second.m_spectrumConverterMap.insert(
221 std::make_pair(rxSpectrumModelUid, converter));
222 NS_ASSERT(ret2.second);
223 }
224 }
225 }
226 else
227 {
228 NS_LOG_LOGIC("SpectrumModelUid " << txSpectrumModelUid << " already present");
229 }
230 return txInfoIterator;
231}
232
233void
235{
236 NS_LOG_FUNCTION(this << txParams);
237
238 NS_ASSERT(txParams->txPhy);
239 NS_ASSERT(txParams->psd);
240 Ptr<SpectrumSignalParameters> txParamsTrace =
241 txParams->Copy(); // copy it since traced value cannot be const (because of potential
242 // underlying DynamicCasts)
243 m_txSigParamsTrace(txParamsTrace);
244
245 Ptr<MobilityModel> txMobility = txParams->txPhy->GetMobility();
246 SpectrumModelUid_t txSpectrumModelUid = txParams->psd->GetSpectrumModelUid();
247 NS_LOG_LOGIC("txSpectrumModelUid " << txSpectrumModelUid);
248
249 //
250 TxSpectrumModelInfoMap_t::const_iterator txInfoIteratorerator =
251 FindAndEventuallyAddTxSpectrumModel(txParams->psd->GetSpectrumModel());
252 NS_ASSERT(txInfoIteratorerator != m_txSpectrumModelInfoMap.end());
253
254 NS_LOG_LOGIC("converter map for TX SpectrumModel with Uid " << txInfoIteratorerator->first);
256 "converter map size: " << txInfoIteratorerator->second.m_spectrumConverterMap.size());
257 NS_LOG_LOGIC("converter map first element: "
258 << txInfoIteratorerator->second.m_spectrumConverterMap.begin()->first);
259
260 for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
261 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
262 ++rxInfoIterator)
263 {
264 SpectrumModelUid_t rxSpectrumModelUid = rxInfoIterator->second.m_rxSpectrumModel->GetUid();
265 NS_LOG_LOGIC("rxSpectrumModelUids " << rxSpectrumModelUid);
266
267 Ptr<SpectrumValue> convertedTxPowerSpectrum;
268 if (txSpectrumModelUid == rxSpectrumModelUid)
269 {
270 NS_LOG_LOGIC("no spectrum conversion needed");
271 convertedTxPowerSpectrum = txParams->psd;
272 }
273 else
274 {
275 NS_LOG_LOGIC("converting txPowerSpectrum SpectrumModelUids "
276 << txSpectrumModelUid << " --> " << rxSpectrumModelUid);
277 SpectrumConverterMap_t::const_iterator rxConverterIterator =
278 txInfoIteratorerator->second.m_spectrumConverterMap.find(rxSpectrumModelUid);
279 if (rxConverterIterator == txInfoIteratorerator->second.m_spectrumConverterMap.end())
280 {
281 // No converter means TX SpectrumModel is orthogonal to RX SpectrumModel
282 continue;
283 }
284 convertedTxPowerSpectrum = rxConverterIterator->second.Convert(txParams->psd);
285 }
286
287 for (auto rxPhyIterator = rxInfoIterator->second.m_rxPhys.begin();
288 rxPhyIterator != rxInfoIterator->second.m_rxPhys.end();
289 ++rxPhyIterator)
290 {
291 NS_ASSERT_MSG((*rxPhyIterator)->GetRxSpectrumModel()->GetUid() == rxSpectrumModelUid,
292 "SpectrumModel change was not notified to MultiModelSpectrumChannel "
293 "(i.e., AddRx should be called again after model is changed)");
294
295 if ((*rxPhyIterator) != txParams->txPhy)
296 {
297 Ptr<NetDevice> rxNetDevice = (*rxPhyIterator)->GetDevice();
298 Ptr<NetDevice> txNetDevice = txParams->txPhy->GetDevice();
299
300 if (rxNetDevice && txNetDevice)
301 {
302 // we assume that devices are attached to a node
303 if (rxNetDevice->GetNode()->GetId() == txNetDevice->GetNode()->GetId())
304 {
306 "Skipping the pathloss calculation among different antennas of the "
307 "same node, not supported yet by any pathloss model in ns-3.");
308 continue;
309 }
310 }
311
312 if (m_filter && m_filter->Filter(txParams, *rxPhyIterator))
313 {
314 continue;
315 }
316
317 NS_LOG_LOGIC("copying signal parameters " << txParams);
318 Ptr<SpectrumSignalParameters> rxParams = txParams->Copy();
319 rxParams->psd = Copy<SpectrumValue>(convertedTxPowerSpectrum);
320 Time delay = MicroSeconds(0);
321
322 Ptr<MobilityModel> receiverMobility = (*rxPhyIterator)->GetMobility();
323
324 if (txMobility && receiverMobility)
325 {
326 double txAntennaGain = 0;
327 double rxAntennaGain = 0;
328 double propagationGainDb = 0;
329 double pathLossDb = 0;
330 if (rxParams->txAntenna)
331 {
332 Angles txAngles(receiverMobility->GetPosition(), txMobility->GetPosition());
333 txAntennaGain = rxParams->txAntenna->GetGainDb(txAngles);
334 NS_LOG_LOGIC("txAntennaGain = " << txAntennaGain << " dB");
335 pathLossDb -= txAntennaGain;
336 }
337 Ptr<AntennaModel> rxAntenna =
338 DynamicCast<AntennaModel>((*rxPhyIterator)->GetAntenna());
339 if (rxAntenna)
340 {
341 Angles rxAngles(txMobility->GetPosition(), receiverMobility->GetPosition());
342 rxAntennaGain = rxAntenna->GetGainDb(rxAngles);
343 NS_LOG_LOGIC("rxAntennaGain = " << rxAntennaGain << " dB");
344 pathLossDb -= rxAntennaGain;
345 }
347 {
348 propagationGainDb =
349 m_propagationLoss->CalcRxPower(0, txMobility, receiverMobility);
350 NS_LOG_LOGIC("propagationGainDb = " << propagationGainDb << " dB");
351 pathLossDb -= propagationGainDb;
352 }
353 NS_LOG_LOGIC("total pathLoss = " << pathLossDb << " dB");
354 // Gain trace
355 m_gainTrace(txMobility,
356 receiverMobility,
357 txAntennaGain,
358 rxAntennaGain,
359 propagationGainDb,
360 pathLossDb);
361 // Pathloss trace
362 m_pathLossTrace(txParams->txPhy, *rxPhyIterator, pathLossDb);
363 if (pathLossDb > m_maxLossDb)
364 {
365 // beyond range
366 continue;
367 }
368 double pathGainLinear = std::pow(10.0, (-pathLossDb) / 10.0);
369 *(rxParams->psd) *= pathGainLinear;
370
372 {
373 delay = m_propagationDelay->GetDelay(txMobility, receiverMobility);
374 }
375 }
376
377 if (rxNetDevice)
378 {
379 // the receiver has a NetDevice, so we expect that it is attached to a Node
380 uint32_t dstNode = rxNetDevice->GetNode()->GetId();
382 delay,
384 this,
385 rxParams,
386 *rxPhyIterator);
387 }
388 else
389 {
390 // the receiver is not attached to a NetDevice, so we cannot assume that it is
391 // attached to a node
394 this,
395 rxParams,
396 *rxPhyIterator);
397 }
398 }
399 }
400 }
401}
402
403void
405{
406 NS_LOG_FUNCTION(this);
408 {
409 params->psd =
410 m_spectrumPropagationLoss->CalcRxPowerSpectralDensity(params,
411 params->txPhy->GetMobility(),
412 receiver->GetMobility());
413 }
415 {
416 Ptr<const PhasedArrayModel> txPhasedArrayModel =
417 DynamicCast<PhasedArrayModel>(params->txPhy->GetAntenna());
418 Ptr<const PhasedArrayModel> rxPhasedArrayModel =
419 DynamicCast<PhasedArrayModel>(receiver->GetAntenna());
420
421 NS_ASSERT_MSG(txPhasedArrayModel && rxPhasedArrayModel,
422 "PhasedArrayModel instances should be installed at both TX and RX "
423 "SpectrumPhy in order to use PhasedArraySpectrumPropagationLoss.");
424
425 params->psd = m_phasedArraySpectrumPropagationLoss->CalcRxPowerSpectralDensity(
426 params,
427 params->txPhy->GetMobility(),
428 receiver->GetMobility(),
429 txPhasedArrayModel,
430 rxPhasedArrayModel);
431 }
432 receiver->StartRx(params);
433}
434
435std::size_t
437{
438 return m_numDevices;
439}
440
443{
445 // this method implementation is computationally intensive. This
446 // method would be faster if we actually used a std::vector for
447 // storing devices, which we don't due to the need to have fast
448 // SpectrumModel conversions and to allow PHY devices to change a
449 // SpectrumModel at run time. Note that having this method slow is
450 // acceptable as it is not used much at run time (often not at all).
451 // On the other hand, having slow SpectrumModel conversion would be
452 // less acceptable.
453 std::size_t j = 0;
454 for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
455 rxInfoIterator != m_rxSpectrumModelInfoMap.end();
456 ++rxInfoIterator)
457 {
458 for (const auto& phyIt : rxInfoIterator->second.m_rxPhys)
459 {
460 if (j == i)
461 {
462 return (*phyIt).GetDevice();
463 }
464 j++;
465 }
466 }
467 NS_FATAL_ERROR("m_numDevices > actual number of devices");
468 return nullptr;
469}
470
471} // namespace ns3
Class holding the azimuth and inclination angles of spherical coordinates.
Definition: angles.h:118
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.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
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< 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:105
The Tx spectrum model information.
TxSpectrumModelInfo(Ptr< const SpectrumModel > txSpectrumModel)
Constructor.
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:936
#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:179
#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:46
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:1360
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