GCC Code Coverage Report


Directory: src/
File: src/RateLimiter.cpp
Date: 2026-09-16 13:46:10
Exec Total Coverage
Lines: 0 79 0.0%
Branches: 0 63 0.0%

Line Branch Exec Source
1 /*****************************************************************************
2 *
3 * Copyright (C) 2021 Jonathan Grahl <jonathan.grahl@igh.de>
4 * 2021 Florian Pose <florian.pose@igh.de>
5 *
6 * This file is part of the reta library (realtime-automation).
7 *
8 * The reta library is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation, either version 3 of the License, or (at
11 * your option) any later version.
12 *
13 * The reta library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with the reta library. If not, see <http://www.gnu.org/licenses/>.
20 *
21 ****************************************************************************/
22
23 #include "reta/RateLimiter.h"
24
25 #include "Base.h"
26
27 #include <cmath> // fabs()
28
29 using std::fabs;
30 using std::function;
31 using std::make_unique;
32 using std::shared_ptr;
33 using std::string;
34 using std::vector;
35
36 using namespace Reta;
37
38 /****************************************************************************/
39
40 ✗ struct RETA_LOCAL RateLimiter::Impl : public Base
41 {
42 Impl(shared_ptr<Task>,
43 const string &,
44 Type,
45 double,
46 double,
47 unsigned int);
48
49 void
50 update(const vector<double> &,
51 bool,
52 const vector<double> &,
53 const vector<double> &);
54 void registerVariables(const string &);
55
56 shared_ptr<Task> task;
57
58 Type type;
59 vector<double> riseLimit;
60 vector<double> fallLimit;
61 vector<double> output;
62 };
63
64 /****************************************************************************/
65
66 ✗ RateLimiter::Impl::Impl(
67 shared_ptr<Task> task,
68 const string &prefix,
69 Type initType,
70 double rise,
71 double fall,
72 ✗ unsigned int width) :
73 Base {prefix},
74 task {task},
75 type {initType},
76 riseLimit(width, rise),
77 fallLimit(width, fall),
78 ✗ output(width, 0.0)
79 {
80 ✗ checkZeroWidth(width);
81
82 ✗ registerVariables(prefix);
83 }
84
85 /****************************************************************************/
86
87 ✗ void RateLimiter::Impl::registerVariables(const string &prefix)
88 {
89 ✗ pdserv *pdserv {task->getPdServ()};
90 ✗ pdtask *pdtask {task->getPdTask()};
91
92 ✗ if (type == Asymmetric) {
93 ✗ pdserv_parameter(
94 ✗ pdserv, (prefix + "/RiseLimit").c_str(), 0666, pd_double_T,
95 ✗ riseLimit.data(), riseLimit.size(), NULL, NULL, NULL);
96 ✗ pdserv_signal(
97 ✗ pdtask, 1, (prefix + "/RiseLimitSignal").c_str(), pd_double_T,
98 ✗ riseLimit.data(), riseLimit.size(), NULL);
99 ✗ pdserv_parameter(
100 ✗ pdserv, (prefix + "/FallLimit").c_str(), 0666, pd_double_T,
101 ✗ fallLimit.data(), fallLimit.size(), NULL, NULL, NULL);
102 ✗ pdserv_signal(
103 ✗ pdtask, 1, (prefix + "/FallLimitSignal").c_str(), pd_double_T,
104 ✗ fallLimit.data(), fallLimit.size(), NULL);
105 }
106 ✗ else if (type == Symmetric) {
107 ✗ pdserv_parameter(
108 ✗ pdserv, (prefix + "/SymmetricLimit").c_str(), 0666,
109 ✗ pd_double_T, riseLimit.data(), riseLimit.size(), NULL, NULL,
110 NULL);
111 ✗ pdserv_signal(
112 ✗ pdtask, 1, (prefix + "/SymmetricLimitSignal").c_str(),
113 ✗ pd_double_T, riseLimit.data(), riseLimit.size(), NULL);
114 }
115 // Dynamic: no persistent parameter, limit is supplied per update() call.
116
117 ✗ pdserv_signal(
118 ✗ pdtask, 1, (prefix + "/Output").c_str(), pd_double_T,
119 ✗ output.data(), output.size(), NULL);
120 }
121
122 /****************************************************************************/
123
124 ✗ void RateLimiter::Impl::update(
125 const vector<double> &input,
126 bool reset,
127 const vector<double> &resetValue,
128 const vector<double> &dynamicLimit)
129 {
130 ✗ checkSize(input, output);
131
132 ✗ for (unsigned int i = 0; i < output.size(); i++) {
133 ✗ if (!reset) {
134 ✗ double diff = (input[i] - output[i]) / task->getPeriod();
135
136 ✗ double effRiseLimit {riseLimit[i]};
137 ✗ double effFallLimit {0.0};
138 ✗ switch (type) {
139 ✗ case Symmetric:
140 ✗ effFallLimit = -riseLimit[i];
141 ✗ break;
142 ✗ case Dynamic:
143 ✗ effRiseLimit = fabs(dynamicLimit.at(i));
144 ✗ effFallLimit = -fabs(dynamicLimit.at(i));
145 ✗ break;
146 ✗ default: // Asymmetric
147 ✗ effFallLimit = fallLimit[i];
148 ✗ break;
149 }
150
151 ✗ if (diff > effRiseLimit) {
152 ✗ diff = effRiseLimit;
153 }
154 ✗ if (diff < effFallLimit) {
155 ✗ diff = effFallLimit;
156 }
157
158 ✗ output[i] += diff * task->getPeriod();
159 }
160 else {
161 ✗ output[i] = resetValue.empty() ? 0.0 : resetValue.at(i);
162 }
163 }
164 }
165
166 /****************************************************************************/
167
168 ✗ RateLimiter::RateLimiter(
169 shared_ptr<Task> task,
170 const string &prefix,
171 double rise,
172 double fall,
173 ✗ unsigned int width) :
174 ✗ impl {make_unique<Impl>(task, prefix, Asymmetric, rise, fall, width)}
175 {}
176
177 /****************************************************************************/
178
179 ✗ RateLimiter::RateLimiter(
180 shared_ptr<Task> task,
181 const string &prefix,
182 Type type,
183 double rise,
184 double fall,
185 ✗ unsigned int width) :
186 ✗ impl {make_unique<Impl>(task, prefix, type, rise, fall, width)}
187 {}
188
189 /****************************************************************************/
190
191 ✗ RateLimiter::~RateLimiter()
192 {}
193
194 /****************************************************************************/
195
196 ✗ void RateLimiter::update(
197 double input,
198 bool reset,
199 double resetValue,
200 double dynamicLimit)
201 {
202 ✗ update(vector<double> {input}, reset, vector<double> {resetValue},
203 ✗ vector<double> {dynamicLimit});
204 }
205
206 /****************************************************************************/
207
208 ✗ void RateLimiter::update(
209 const vector<double> &input,
210 bool reset,
211 const vector<double> &resetValue,
212 const vector<double> &dynamicLimit)
213 {
214 ✗ impl->update(input, reset, resetValue, dynamicLimit);
215 }
216
217 /****************************************************************************/
218
219 ✗ void RateLimiter::update(
220 function<double(unsigned int)> input,
221 bool reset,
222 double resetValue,
223 double dynamicLimit)
224 {
225 ✗ vector<double> inputVector(impl->output.size());
226 ✗ for (unsigned int i = 0; i < impl->output.size(); i++) {
227 ✗ inputVector[i] = input(i);
228 }
229
230 ✗ update(inputVector, reset,
231 ✗ vector<double>(impl->output.size(), resetValue),
232 ✗ vector<double>(impl->output.size(), dynamicLimit));
233 }
234
235 /****************************************************************************/
236
237 ✗ double RateLimiter::getOutput(unsigned int i) const
238 {
239 ✗ return impl->output.at(i);
240 }
241
242 /****************************************************************************/
243
244 ✗ vector<double> RateLimiter::getOutputVector() const
245 {
246 ✗ return impl->output;
247 }
248
249 /****************************************************************************/
250