Vanetza
 
Loading...
Searching...
No Matches
limeric.cpp
1#include "limeric.hpp"
2#include <vanetza/common/runtime.hpp>
3#include <cassert>
4#include <cmath>
5#include <numeric>
6
7namespace vanetza
8{
9namespace dcc
10{
11
12static const Limeric::Parameters limericDefaultParams;
13
14Limeric::Limeric(Runtime& rt) : Limeric(rt, limericDefaultParams)
15{
16}
17
18Limeric::Limeric(Runtime& rt, const Parameters& params) :
19 on_duty_cycle_change(m_duty_cycle_change), m_runtime(rt), m_params(params),
20 m_duty_cycle(mean(params.delta_max, params.delta_min)), m_cbr(2)
21{
22 assert(m_cbr.empty());
23 schedule();
24}
25
26Limeric::~Limeric()
27{
28 m_runtime.cancel(this);
29}
30
31ChannelLoad Limeric::average_cbr() const
32{
33 if (m_cbr.full()) {
34 return 0.5 * mean(m_cbr.begin(), m_cbr.end()) + 0.5 * m_channel_load;
35 } else {
36 return m_channel_load;
37 }
38}
39
40void Limeric::update_cbr(ChannelLoad cbr)
41{
42 const bool full = m_cbr.full();
43 m_cbr.push_back(cbr);
44 if (!full) {
45 m_channel_load = mean(m_cbr.begin(), m_cbr.end());
46 }
47}
48
49UnitInterval Limeric::calculate_duty_cycle() const
50{
51 const double cbr_delta = m_params.cbr_target.value() - m_channel_load.value();
52 double delta_offset = 0.0;
53 if (cbr_delta > 0.0) {
54 delta_offset = std::min(m_params.beta.value() * cbr_delta, m_params.g_plus_max);
55 } else {
56 delta_offset = std::max(m_params.beta.value() * cbr_delta, m_params.g_minus_max);
57 }
58 UnitInterval delta = m_params.alpha.complement() * m_duty_cycle + delta_offset;
59 delta = std::min(std::max(delta, m_params.delta_min), m_params.delta_max);
60
61 if (m_dual_alpha) {
62 if (m_duty_cycle - delta > m_dual_alpha->threshold) {
63 delta = m_dual_alpha->alternate_alpha.complement() * m_duty_cycle + delta_offset;
64 delta = std::min(std::max(delta, m_params.delta_min), m_params.delta_max);
65 }
66 }
67 return delta;
68}
69
70void Limeric::calculate(Clock::time_point tp)
71{
72 m_channel_load = average_cbr();
73 m_duty_cycle = calculate_duty_cycle(); // uses m_channel_load
74 m_duty_cycle_change(this, tp);
75 schedule();
76}
77
78void Limeric::schedule()
79{
80 // schedule for next possible modulo 2 * cbr_interval (usually 200ms) time point
81 const Clock::duration scheduling_interval = 2 * m_params.cbr_interval;
82 Clock::time_point tp = m_runtime.now() + scheduling_interval;
83 const Clock::duration scheduling_bias = tp.time_since_epoch() % scheduling_interval;
84 if (scheduling_bias > m_params.cbr_interval) {
85 tp += scheduling_interval - scheduling_bias;
86 } else if (scheduling_bias > Clock::duration::zero()) {
87 tp -= scheduling_bias;
88 }
89 m_runtime.schedule(tp, [this](Clock::time_point tp) {
90 this->calculate(tp);
91 });
92}
93
94void Limeric::configure_dual_alpha(const boost::optional<DualAlphaParameters>& params)
95{
96 m_dual_alpha = params;
97}
98
99} // namespace dcc
100} // namespace vanetza