| Directory: | src/ |
|---|---|
| File: | src/Interpolation.cpp |
| Date: | 2026-09-03 17:04:53 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 65 | 74 | 87.8% |
| Branches: | 51 | 107 | 47.7% |
| 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/Interpolation.h" | ||
| 24 | |||
| 25 | #include "Base.h" | ||
| 26 | |||
| 27 | #include <iostream> | ||
| 28 | #include <map> | ||
| 29 | #include <sstream> | ||
| 30 | #include <stdexcept> | ||
| 31 | |||
| 32 | using std::function; | ||
| 33 | using std::invalid_argument; | ||
| 34 | using std::lower_bound; | ||
| 35 | using std::make_unique; | ||
| 36 | using std::map; | ||
| 37 | using std::shared_ptr; | ||
| 38 | using std::string; | ||
| 39 | using std::stringstream; | ||
| 40 | using std::vector; | ||
| 41 | |||
| 42 | using std::cout; | ||
| 43 | using std::endl; | ||
| 44 | |||
| 45 | using namespace Reta; | ||
| 46 | |||
| 47 | /****************************************************************************/ | ||
| 48 | |||
| 49 | 32 | struct RETA_LOCAL Interpolation::Impl : public Base | |
| 50 | { | ||
| 51 | Impl(shared_ptr<Task> task, | ||
| 52 | const string &prefix, | ||
| 53 | const double tableInit[][2], | ||
| 54 | unsigned int tableRows, | ||
| 55 | unsigned int width); | ||
| 56 | |||
| 57 | void update(const vector<double> &); | ||
| 58 | |||
| 59 | 86 | unsigned int size() const { return output.size(); } | |
| 60 | |||
| 61 | shared_ptr<Task> task; | ||
| 62 | |||
| 63 | map<double, double> table; | ||
| 64 | unsigned int tableRows; | ||
| 65 | |||
| 66 | vector<double> input; | ||
| 67 | vector<double> output; | ||
| 68 | }; | ||
| 69 | |||
| 70 | /****************************************************************************/ | ||
| 71 | |||
| 72 | 34 | Interpolation::Impl::Impl( | |
| 73 | shared_ptr<Task> task, | ||
| 74 | const string &prefix, | ||
| 75 | const double tableInit[][2], | ||
| 76 | unsigned int tableRows, | ||
| 77 | 34 | unsigned int width) : | |
| 78 | Base {prefix}, | ||
| 79 | task {task}, | ||
| 80 | tableRows {tableRows}, | ||
| 81 | input(width, 0.0), | ||
| 82 |
2/4✓ Branch 5 taken 34 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 34 times.
✗ Branch 11 not taken.
|
36 | output(width, 0.0) |
| 83 | { | ||
| 84 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | checkZeroWidth(width); |
| 85 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 32 times.
|
34 | if (tableRows < 2) { |
| 86 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | stringstream str; |
| 87 | str << __PRETTY_FUNCTION__ << " : " << prefix | ||
| 88 |
4/8✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
|
2 | << " Need at least 2 rows for the table!"; |
| 89 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
2 | throw invalid_argument(str.str()); |
| 90 | } | ||
| 91 | |||
| 92 |
1/2✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
32 | pdserv *pdserv {task->getPdServ()}; |
| 93 |
1/2✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
32 | pdtask *pdtask {task->getPdTask()}; |
| 94 | |||
| 95 |
1/2✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
|
64 | pdserv_signal( |
| 96 |
1/2✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
64 | pdtask, 1, (prefix + "/Input").c_str(), pd_double_T, input.data(), |
| 97 | input.size(), NULL); | ||
| 98 |
1/2✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
|
64 | pdserv_signal( |
| 99 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
64 | pdtask, 1, (prefix + "/Output").c_str(), pd_double_T, |
| 100 | 32 | output.data(), output.size(), NULL); | |
| 101 | |||
| 102 |
2/2✓ Branch 0 taken 128 times.
✓ Branch 1 taken 32 times.
|
160 | for (unsigned int i = 0; i < tableRows; i++) { |
| 103 |
1/2✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
|
128 | table[tableInit[i][0]] = tableInit[i][1]; |
| 104 | |||
| 105 | { | ||
| 106 |
2/4✓ Branch 2 taken 128 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 128 times.
✗ Branch 7 not taken.
|
256 | stringstream parameterPath, signalPath; |
| 107 |
3/6✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 128 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 128 times.
✗ Branch 8 not taken.
|
128 | parameterPath << prefix << "/Value/" << i; |
| 108 |
3/6✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 128 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 128 times.
✗ Branch 8 not taken.
|
128 | signalPath << prefix << "/ValueSignal/" << i; |
| 109 | |||
| 110 |
1/2✓ Branch 2 taken 128 times.
✗ Branch 3 not taken.
|
128 | pdserv_parameter( |
| 111 |
1/2✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
|
256 | pdserv, parameterPath.str().c_str(), 0666, pd_double_T, |
| 112 |
1/2✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
|
128 | &table[tableInit[i][0]], 1, NULL, NULL, NULL); |
| 113 | |||
| 114 |
1/2✓ Branch 2 taken 128 times.
✗ Branch 3 not taken.
|
128 | pdserv_signal( |
| 115 |
1/2✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
|
256 | pdtask, 1, signalPath.str().c_str(), pd_double_T, |
| 116 |
1/2✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
|
128 | &table[tableInit[i][0]], 1, NULL); |
| 117 | } | ||
| 118 | } | ||
| 119 | 32 | } | |
| 120 | |||
| 121 | /****************************************************************************/ | ||
| 122 | |||
| 123 | 32 | Interpolation::~Interpolation() | |
| 124 | 32 | {} | |
| 125 | |||
| 126 | /****************************************************************************/ | ||
| 127 | |||
| 128 | /** Interpolation. | ||
| 129 | * In the update method, the associated y-value is calculated for a given | ||
| 130 | * x-value. Extrapolation is not possible. In case of a value outside the | ||
| 131 | * given table limits, the respective limit value is returned. | ||
| 132 | */ | ||
| 133 | 26 | void Interpolation::Impl::update(const vector<double> &inputValueIn) | |
| 134 | { | ||
| 135 | 26 | checkSize(inputValueIn, input); | |
| 136 | 24 | input = inputValueIn; | |
| 137 | |||
| 138 |
2/2✓ Branch 1 taken 48 times.
✓ Branch 2 taken 24 times.
|
72 | for (unsigned int i = 0; i < size(); i++) { |
| 139 |
2/4✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
|
48 | auto iterator = table.lower_bound(input.at(i)); |
| 140 | |||
| 141 |
2/2✓ Branch 2 taken 13 times.
✓ Branch 3 taken 35 times.
|
61 | if (iterator == table.begin()) { |
| 142 |
1/2✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
13 | output.at(i) = table.begin()->second; |
| 143 | 27 | continue; | |
| 144 | } | ||
| 145 | |||
| 146 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 34 times.
|
36 | if (iterator == table.end()) { |
| 147 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | output.at(i) = table.rbegin()->second; |
| 148 | 1 | continue; | |
| 149 | } | ||
| 150 | |||
| 151 | |||
| 152 | 34 | auto upperValue = iterator; | |
| 153 | 34 | auto lowerValue = --iterator; | |
| 154 | |||
| 155 | 34 | double dx = upperValue->first - lowerValue->first; | |
| 156 | 34 | double dy = upperValue->second - lowerValue->second; | |
| 157 | |||
| 158 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | if (dx > 0.0) { |
| 159 |
1/2✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
68 | output.at(i) = lowerValue->second |
| 160 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | + dy / dx * (input.at(i) - lowerValue->first); |
| 161 | } | ||
| 162 | } | ||
| 163 | 24 | } | |
| 164 | |||
| 165 | /****************************************************************************/ | ||
| 166 | |||
| 167 | 34 | Interpolation::Interpolation( | |
| 168 | shared_ptr<Task> task, | ||
| 169 | const string &prefix, | ||
| 170 | const double tableInit[][2], | ||
| 171 | unsigned int tableRows, | ||
| 172 | 34 | unsigned int width) : | |
| 173 | 34 | impl {make_unique<Impl>(task, prefix, tableInit, tableRows, width)} | |
| 174 | 32 | {} | |
| 175 | |||
| 176 | /****************************************************************************/ | ||
| 177 | |||
| 178 | 14 | void Interpolation::update(double input) | |
| 179 | { | ||
| 180 |
2/4✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
|
14 | impl->update(vector<double> {input}); |
| 181 | 14 | } | |
| 182 | |||
| 183 | /****************************************************************************/ | ||
| 184 | |||
| 185 | 12 | void Interpolation::update(const vector<double> &input) | |
| 186 | { | ||
| 187 | 12 | impl->update(input); | |
| 188 | 10 | } | |
| 189 | |||
| 190 | /****************************************************************************/ | ||
| 191 | |||
| 192 | ✗ | void Interpolation::update(function<double(unsigned int)> input) | |
| 193 | { | ||
| 194 | ✗ | vector<double> inputVector(size()); | |
| 195 | |||
| 196 | ✗ | for (unsigned int i = 0; i < size(); i++) { | |
| 197 | ✗ | inputVector.at(i) = input(i); | |
| 198 | } | ||
| 199 | |||
| 200 | ✗ | impl->update(inputVector); | |
| 201 | } | ||
| 202 | |||
| 203 | /****************************************************************************/ | ||
| 204 | |||
| 205 | 53 | double Interpolation::getOutput(unsigned int i) const | |
| 206 | { | ||
| 207 | 53 | return impl->output.at(i); | |
| 208 | } | ||
| 209 | |||
| 210 | /****************************************************************************/ | ||
| 211 | |||
| 212 | ✗ | vector<double> Interpolation::getOutputVector() const | |
| 213 | { | ||
| 214 | ✗ | return impl->output; | |
| 215 | } | ||
| 216 | |||
| 217 | /****************************************************************************/ | ||
| 218 | |||
| 219 | 14 | unsigned int Interpolation::size() const | |
| 220 | { | ||
| 221 | 14 | return impl->size(); | |
| 222 | } | ||
| 223 | |||
| 224 | /****************************************************************************/ | ||
| 225 | |||
| 226 | ✗ | unsigned int Interpolation::rows() const | |
| 227 | { | ||
| 228 | ✗ | return impl->tableRows; | |
| 229 | 6 | } | |
| 230 | |||
| 231 | /****************************************************************************/ | ||
| 232 |