Loading...
Searching...
No Matches
satellite-default-superframe-allocator.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2014 Magister Solutions Ltd
4 * Copyright (c) 2019 CNES
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation;
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * Author: Sami Rantanen <sami.rantanen@magister.fi>
20 * Author: Joaquin Muguerza <jmuguerza@viveris.fr>
21 */
22
24
25#include "satellite-utils.h"
26
27#include "ns3/boolean.h"
28#include "ns3/double.h"
29#include "ns3/log.h"
30
31#include <algorithm>
32#include <limits>
33#include <map>
34#include <utility>
35
36NS_LOG_COMPONENT_DEFINE("SatDefaultSuperframeAllocator");
37
38namespace ns3
39{
40
41NS_OBJECT_ENSURE_REGISTERED(SatDefaultSuperframeAllocator);
42
43TypeId
45{
46 static TypeId tid =
47 TypeId("ns3::SatDefaultSuperframeAllocator")
48 .SetParent<SatSuperframeAllocator>()
49 .AddAttribute("TargetLoad",
50 "Target load limits upper bound of the symbols in a frame.",
51 DoubleValue(0.9),
53 MakeDoubleChecker<double>())
54 .AddAttribute("FcaEnabled",
55 "Free capacity allocation (FCA) enable status.",
56 BooleanValue(false),
58 MakeBooleanChecker())
59 .AddAttribute(
60 "RcBasedAllocationEnabled",
61 "Time slot generated per RC symbols instead of sum of UT symbols.",
62 BooleanValue(false),
64 MakeBooleanChecker());
65 return tid;
66}
67
69 : SatSuperframeAllocator(superFrameConf),
70 m_targetLoad(0.0),
71 m_fcaEnabled(false),
76{
77 NS_LOG_FUNCTION(this << superFrameConf);
78
79 uint32_t currentMinCarrierPayloadInBytes = std::numeric_limits<uint32_t>::max();
80 uint32_t currentMostRobustSlotPayloadInBytes = std::numeric_limits<uint32_t>::max();
81
82 Ptr<SatFrameConf> parentFrameConf = nullptr;
83 Ptr<SatFrameAllocator> parentFrameAllocator = nullptr;
84 for (uint8_t i = 0; i < superFrameConf->GetFrameCount(); i++)
85 {
86 Ptr<SatFrameConf> frameConf = superFrameConf->GetFrameConf(i);
87 if (!frameConf->IsRandomAccess())
88 {
89 Ptr<SatFrameConf> parentConf = frameConf->GetParent();
90 if (parentConf != parentFrameConf)
91 {
92 NS_ASSERT_MSG(parentConf == nullptr,
93 "Wrong ordering of frame confs. Need to have subdivided ones right "
94 "after their parents.");
95 parentFrameAllocator = nullptr;
96 }
97 parentFrameConf = frameConf;
98
99 Ptr<SatFrameAllocator> frameAllocator =
100 Create<SatFrameAllocator>(frameConf,
101 i,
102 superFrameConf->GetConfigType(),
103 parentFrameAllocator);
104 m_frameAllocators.push_back(frameAllocator);
105 parentFrameAllocator = frameAllocator;
106
107 uint32_t minCarrierPayloadInBytes = frameAllocator->GetCarrierMinPayloadInBytes();
108
109 if (minCarrierPayloadInBytes < currentMinCarrierPayloadInBytes)
110 {
111 currentMinCarrierPayloadInBytes = minCarrierPayloadInBytes;
112 m_minCarrierPayloadInBytes = minCarrierPayloadInBytes;
113 }
114
115 uint32_t mostRobustSlotPayloadInBytes =
116 frameAllocator->GetMostRobustWaveform()->GetPayloadInBytes();
117
118 if (mostRobustSlotPayloadInBytes < currentMostRobustSlotPayloadInBytes)
119 {
120 currentMostRobustSlotPayloadInBytes = mostRobustSlotPayloadInBytes;
121 m_mostRobustSlotPayloadInBytes = mostRobustSlotPayloadInBytes;
122 }
123
125 frameAllocator->GetCarrierCount() * minCarrierPayloadInBytes;
126 m_totalBandwidth += frameAllocator->GetCarrierBandwidthHz(true);
127 }
128 }
129}
130
135
136void
139{
140 NS_LOG_FUNCTION(this << &allocReqs);
141
142 std::map<Ptr<SatFrameAllocator>, uint32_t> wsrDemand;
143
144 NS_LOG_LOGIC("Select best carrier for each terminal request");
145 for (auto& allocRequest : allocReqs)
146 {
147 uint32_t bestWaveFormId = 0;
148 Ptr<SatFrameAllocator> selectedFrameAllocator =
149 SelectBestCarrier(allocRequest->m_cno, bestWaveFormId);
150 if (selectedFrameAllocator != nullptr)
151 {
152 for (auto& request : allocRequest->m_reqPerRc)
153 {
154 wsrDemand[selectedFrameAllocator] +=
155 request.m_craBytes + std::max(request.m_minRbdcBytes, request.m_rbdcBytes) +
156 request.m_vbdcBytes;
157 }
158 }
159 else
160 {
161 NS_LOG_WARN("SatDefaultSuperframeAllocator::SelectCarriers: No suitable frame and "
162 "waveform found for "
163 "terminal at "
164 << allocRequest->m_address << " with C/N0 of " << allocRequest->m_cno
165 << ". "
166 "Ignoring this terminal in carrier selection.");
167 }
168 }
169
170 NS_LOG_LOGIC("Calculate Load Coefficient");
171 double requestedBandwidth = 0.0;
172 for (auto& demand : wsrDemand)
173 {
174 requestedBandwidth +=
175 demand.first->GetCarrierBandwidthHz() * demand.second / demand.first->GetVolumeBytes();
176 }
177 double loadCoefficient = std::min(std::max(0.1, m_totalBandwidth / requestedBandwidth), 10.0);
178 NS_LOG_INFO("" << allocReqs.size() << " requested " << requestedBandwidth << "Hz through "
179 << wsrDemand.size() << " subdivision levels; giving a load coefficient of "
180 << loadCoefficient);
181
182 std::map<Ptr<SatFrameAllocator>, double, SatFrameAllocator::BandwidthComparator> scaledDemand;
183 for (auto& demand : wsrDemand)
184 {
185 scaledDemand[demand.first] =
186 loadCoefficient * demand.second / demand.first->GetVolumeBytes() + 1;
187 }
188
189 NS_LOG_LOGIC("Zero-out old carrier selection");
190 for (auto& frameAllocator : m_frameAllocators)
191 {
192 uint16_t zeroReference = 0;
193 frameAllocator->SelectCarriers(zeroReference, 0);
194 }
195
196 NS_LOG_LOGIC("Allocate carriers in subdivision levels");
197 while (!scaledDemand.empty())
198 {
199 NS_LOG_LOGIC("Find bandwidth of the original frame");
200 Ptr<SatFrameAllocator> frameAllocator = scaledDemand.begin()->first;
201 while (frameAllocator->GetParent() != nullptr)
202 {
203 frameAllocator = frameAllocator->GetParent();
204 }
205 double remainingBandwidth = frameAllocator->GetCarrierBandwidthHz(true);
206 NS_ASSERT_MSG(remainingBandwidth != 0.0, "Could not find bandwidth of original frame");
207
208 // Select carriers from the most subdivided version of the frame up to the original
209 frameAllocator = scaledDemand.begin()->first;
210 uint16_t offset = 0;
211 while (frameAllocator != nullptr)
212 {
213 auto frameDemand = scaledDemand.find(frameAllocator);
214 uint16_t demand = 0;
215 if (frameDemand != scaledDemand.end())
216 {
217 demand = frameDemand->second;
218 scaledDemand.erase(frameDemand);
219 }
220 NS_LOG_LOGIC(demand << " carriers requested on (subdivided) frame "
221 << frameAllocator->GetCarrierBandwidthHz());
222 uint16_t carriersCount = 0;
223 double carrierBandwidth = frameAllocator->GetCarrierBandwidthHz();
224 if (frameAllocator->GetParent() != nullptr)
225 {
226 // Select requested carriers of subdivided frames
227 uint16_t remainingCarriers = remainingBandwidth / carrierBandwidth;
228 carriersCount = std::max(uint16_t(0), std::min(demand, remainingCarriers));
229 }
230
231 frameAllocator->SelectCarriers(carriersCount, offset);
232 remainingBandwidth -= carriersCount * carrierBandwidth;
233 NS_LOG_INFO("Remaining bandwidth on non-subdivided frame: " << remainingBandwidth);
234 offset = (carriersCount + offset) / 2;
235 frameAllocator = frameAllocator->GetParent();
236 }
237
238 if (remainingBandwidth < 0.0)
239 {
240 NS_FATAL_ERROR(
241 "SatDefaultSuperframeAllocator::SelectCarriers: remaining bandwidth is negative");
242 }
243 }
244}
245
246Ptr<SatFrameAllocator>
247SatDefaultSuperframeAllocator::SelectBestCarrier(double cno, uint32_t& bestWaveFormId)
248{
249 NS_LOG_FUNCTION(this << cno);
250
251 double cnoDiff = std::numeric_limits<double>::infinity();
252 Ptr<SatFrameAllocator> selectedFrameAllocator = nullptr;
253
254 for (auto& frameAllocator : m_frameAllocators)
255 {
256 uint32_t waveFormId;
257 double waveformCNo;
258 if (frameAllocator->GetBestWaveform(cno, waveFormId, waveformCNo))
259 {
260 double diff = cno - waveformCNo;
261 if (diff < cnoDiff)
262 {
263 cnoDiff = diff;
264 bestWaveFormId = waveFormId;
265 selectedFrameAllocator = frameAllocator;
266 }
267 }
268 }
269
270 return selectedFrameAllocator;
271}
272
273void
275{
276 NS_LOG_FUNCTION(this);
277
278 for (FrameAllocatorContainer_t::iterator it = m_frameAllocators.begin();
279 it != m_frameAllocators.end();
280 it++)
281 {
282 (*it)->Reset();
283 }
284}
285
286void
289 uint32_t maxSizeInBytes,
291 TracedCallback<uint32_t> waveformTrace,
292 TracedCallback<uint32_t, uint32_t> utLoadTrace,
293 TracedCallback<uint32_t, double> loadTrace)
294{
295 NS_LOG_FUNCTION(this);
296
297 if (tbtpContainer.empty())
298 {
299 NS_FATAL_ERROR("TBTP container must contain at least one message.");
300 }
301
302 for (FrameAllocatorContainer_t::iterator it = m_frameAllocators.begin();
303 it != m_frameAllocators.end();
304 it++)
305 {
306 (*it)->GenerateTimeSlots(tbtpContainer,
307 maxSizeInBytes,
308 utAllocContainer,
310 waveformTrace,
311 utLoadTrace,
312 loadTrace);
313 }
314}
315
316void
319{
320 NS_LOG_FUNCTION(this);
321
323 {
324 SelectCarriers(allocReqs);
325 }
326
328
329 for (SatFrameAllocator::SatFrameAllocContainer_t::iterator itReq = allocReqs.begin();
330 itReq != allocReqs.end();
331 itReq++)
332 {
333 AllocateToFrame(*itReq);
334 }
335
336 for (FrameAllocatorContainer_t::iterator it = m_frameAllocators.begin();
337 it != m_frameAllocators.end();
338 it++)
339 {
340 (*it)->PreAllocateSymbols(m_targetLoad, m_fcaEnabled);
341 }
342}
343
344void
346 bool controlSlotsEnabled)
347{
348 NS_LOG_FUNCTION(this << minimumRateBytes);
349
350 uint32_t rateBasedByteToCheck = minimumRateBytes;
351
352 if (controlSlotsEnabled)
353 {
354 rateBasedByteToCheck += m_mostRobustSlotPayloadInBytes;
355 }
356
357 if (rateBasedByteToCheck > m_minCarrierPayloadInBytes)
358 {
359 NS_FATAL_ERROR("Minimum requested bytes ("
360 << minimumRateBytes << ") for UT is greater than bytes in minimum carrier ("
362 }
363 else if (rateBasedByteToCheck > m_minimumRateBasedBytesLeft)
364 {
365 NS_FATAL_ERROR("Minimum requested bytes ("
366 << minimumRateBytes << ") for UT is greater than minimum bytes left ("
368 }
369 else
370 {
371 m_minimumRateBasedBytesLeft -= minimumRateBytes;
372 }
373}
374
375void
377 bool controlSlotsEnabled)
378{
379 NS_LOG_FUNCTION(this << minimumRateBytes);
380
381 uint32_t rateBasedByteToCheck = minimumRateBytes;
382
383 if (controlSlotsEnabled)
384 {
385 rateBasedByteToCheck += m_mostRobustSlotPayloadInBytes;
386 }
387
388 if (rateBasedByteToCheck > m_minCarrierPayloadInBytes)
389 {
390 NS_FATAL_ERROR("Minimum released bytes ("
391 << minimumRateBytes << ") for UT is greater than bytes in minimum carrier ("
393 }
394 else
395 {
396 m_minimumRateBasedBytesLeft += minimumRateBytes;
397 }
398}
399
400bool
402{
403 NS_LOG_FUNCTION(this);
404
405 bool allocated = false;
406
407 SupportedFramesMap_t supportedFrames;
408
409 // find supported symbol rates (frames)
410 for (auto& frameAllocator : m_frameAllocators)
411 {
412 uint32_t waveformId = 0;
413 double cnoThreshold = std::numeric_limits<double>::quiet_NaN();
414 if (frameAllocator->GetCarrierCount() &&
415 frameAllocator->GetBestWaveform(allocReq->m_cno, waveformId, cnoThreshold))
416 {
417 supportedFrames.insert(std::make_pair(frameAllocator, waveformId));
418 }
419 }
420
421 NS_LOG_INFO("Terminal with C/N0 of " << allocReq->m_cno << " found " << supportedFrames.size()
422 << " supported frames.");
423
424 if (!supportedFrames.empty())
425 {
426 // allocate with CC level CRA + RBDC + VBDC
427 allocated =
429
430 if (!allocated)
431 {
432 // allocate with CC level CRA + RBDC
433 allocated =
435
436 if (!allocated)
437 {
438 // allocate with CC level CRA + MIM RBDC
440 allocReq,
441 supportedFrames);
442
443 if (!allocated)
444 {
445 // allocate with CC level CRA
447 allocReq,
448 supportedFrames);
449 }
450 }
451 }
452 }
453
454 return allocated;
455}
456
457bool
460 const SupportedFramesMap_t& frames)
461{
462 NS_LOG_FUNCTION(this << ccLevel);
463
464 double loadInSymbols = 0;
465 SupportedFramesMap_t::const_iterator selectedFrame = frames.begin();
466
467 if (frames.empty())
468 {
469 NS_FATAL_ERROR("Tried to allocate without frames!!!");
470 }
471
472 // find the lowest load frame
473 for (SupportedFramesMap_t::const_iterator it = frames.begin(); it != frames.end(); it++)
474 {
475 if (it == frames.begin())
476 {
477 loadInSymbols = it->first->GetCcLoad(ccLevel);
478 }
479 else if (it->first->GetCcLoad(ccLevel) < loadInSymbols)
480 {
481 selectedFrame = it;
482 loadInSymbols = it->first->GetCcLoad(ccLevel);
483 }
484 }
485
486 return selectedFrame->first->Allocate(ccLevel, allocReq, selectedFrame->second);
487}
488
489} // namespace ns3
helper class for Satellite Beam Scheduler.
bool AllocateBasedOnCc(SatFrameAllocator::CcLevel_t ccLevel, SatFrameAllocator::SatFrameAllocReq *allocReq, const SupportedFramesMap_t &frames)
Allocate given request according to type.
bool AllocateToFrame(SatFrameAllocator::SatFrameAllocReq *allocReq)
Allocate a request to a frame.
void PreAllocateSymbols(SatFrameAllocator::SatFrameAllocContainer_t &allocReqs)
Preallocate symbols for given to UTs in superframe.
void ReleaseMinimumRate(uint32_t minimumRateBytes, bool controlSlotsEnabled)
Release minimum rate from the allocator.
SatDefaultSuperframeAllocator(Ptr< SatSuperframeConf > superFrameConf)
Construct SatDefaultSuperframeAllocator.
void RemoveAllocations()
Remove allocations from all frames maintained by frame allocator.
Ptr< SatFrameAllocator > SelectBestCarrier(double cno, uint32_t &bestWaveFormId)
Select which carrier is the best suited for handling requests of a terminal communicating at the give...
void SelectCarriers(SatFrameAllocator::SatFrameAllocContainer_t &allocReqs)
Select which carriers to use from the underlying frames.
void GenerateTimeSlots(SatFrameAllocator::TbtpMsgContainer_t &tbtpContainer, uint32_t maxSizeInBytes, SatFrameAllocator::UtAllocInfoContainer_t &utAllocContainer, TracedCallback< uint32_t > waveformTrace, TracedCallback< uint32_t, uint32_t > utLoadTrace, TracedCallback< uint32_t, double > loadTrace)
Generate time slots in TBTP(s) for the UT/RC.
~SatDefaultSuperframeAllocator()
Destruct SatDefaultSuperframeAllocator.
std::map< Ptr< SatFrameAllocator >, uint32_t > SupportedFramesMap_t
Container for the supported SatFrameAllocator (frames).
void ReserveMinimumRate(uint32_t minimumRateBytes, bool controlSlotsEnabled)
Reserve minimum rate from the allocator.
SatFrameAllocReq is used to define frame allocation parameters when requesting allocation from SatFra...
std::vector< SatFrameAllocReq * > SatFrameAllocContainer_t
Container to store SatFrameAllocReq item pointers.
std::vector< Ptr< SatTbtpMessage > > TbtpMsgContainer_t
Container to store generated TBTP messages.
@ CC_LEVEL_CRA_RBDC
CC level CRA + RBDC.
@ CC_LEVEL_CRA_RBDC_VBDC
CC level CRA + RBDC + VBDC.
@ CC_LEVEL_CRA_MIN_RBDC
CC level CRA + Minimum RBDC.
std::map< Address, UtAllocInfoItem_t > UtAllocInfoContainer_t
Map container to store UT allocation information.
SatSuperframeAllocator(Ptr< SatSuperframeConf > superFrameConf)
Construct SatSuperframeAllocator.
@ CONFIG_TYPE_3
Configuration type 3.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.
BandwidthComparator is a custom functor meant as comparison function for std::map.