SensESP 3.4.1-alpha
Universal Signal K sensor toolkit ESP32
Loading...
Searching...
No Matches
curveinterpolator.cpp
Go to the documentation of this file.
1#include "sensesp.h"
2
3#include "curveinterpolator.h"
4
5namespace sensesp {
6
8
9CurveInterpolator::Sample::Sample(float input, float output)
10 : input_{input}, output_{output} {}
11
13 : input_{obj["input"]}, output_{obj["output"]} {}
14
23CurveInterpolator::CurveInterpolator(std::set<Sample>* defaults,
24 const String& config_path)
25 : FloatTransform(config_path) {
26 // Load default values if no configuration present...
27 if (defaults != NULL) {
29 samples_ = *defaults;
30 }
31
32 load();
33}
34
35void CurveInterpolator::set(const float& input) {
36 if (samples_.empty()) {
37 output_ = 0; // or any default output if no samples are available
38 notify();
39 return;
40 }
41
42 std::set<Sample>::iterator it = samples_.begin();
43 float x0 = it->input_;
44 float y0 = it->output_;
45
46 // Check if the input is below the lowest sample point
47 if (input < x0) {
48 // Need to extrapolate below the first point
49 if (samples_.size() > 1) {
50 auto second_it = std::next(it);
51 float x1 = second_it->input_;
52 float y1 = second_it->output_;
53 float const gradient = (y1 - y0) / (x1 - x0);
54
55 output_ = y0 + gradient *
56 (input -
57 x0); // Extrapolate using the first segment's gradient
58 } else {
59 output_ = y0; // Only one sample, output its value
60 }
61 notify();
62 return;
63 }
64
65 // Search for the correct interval or the last sample point
66 while (it != samples_.end()) {
67 if (input > it->input_) {
68 x0 = it->input_;
69 y0 = it->output_;
70 ++it;
71 } else {
72 break;
73 }
74 }
75
76 // Interpolate or extrapolate above the highest point
77 if (it != samples_.end()) {
78 float x1 = it->input_;
79 float y1 = it->output_;
80 if (x1 == x0) {
81 // Exact hit on a sample point (e.g. the lowest one, where the search
82 // never advances past begin()) — avoid a zero-width interval divide.
83 output_ = y1;
84 } else {
85 output_ = (y0 * (x1 - input) + y1 * (input - x0)) / (x1 - x0);
86 }
87 } else {
88 // Hit the end of the table with no match, calculate output using the
89 // gradient from the last two points
90 auto last = samples_.rbegin();
91 auto second_last = std::next(last);
92 float x1 = last->input_;
93 float y1 = last->output_;
94 float x2 = second_last->input_;
95 float y2 = second_last->output_;
96 float const gradient = (y1 - y2) / (x1 - x2);
97
98 // Extrapolate using the gradient
99 output_ = y1 + gradient * (input - x1);
100 }
101
102 notify();
103}
104
105bool CurveInterpolator::to_json(JsonObject& doc) {
106 JsonArray json_samples = doc["samples"].to<JsonArray>();
107 for (auto& sample : samples_) {
108 // Add a new JsonObject to the array
109 JsonObject entry = json_samples.add<JsonObject>();
110 if (entry.isNull()) {
111 ESP_LOGE(__FILENAME__, "No memory for sample");
112 return false;
113 }
114 entry["input"] = sample.input_;
115 entry["output"] = sample.output_;
116 }
117 return true;
118}
119
120bool CurveInterpolator::from_json(const JsonObject& doc) {
121 String const expected[] = {"samples"};
122 for (auto str : expected) {
123 if (!doc[str].is<JsonVariant>()) {
124 ESP_LOGE(
125 __FILENAME__,
126 "Can not set CurveInterpolator configuration: missing json field "
127 "%s\n",
128 str.c_str());
129 return false;
130 }
131 }
132
133 JsonArray arr = doc["samples"];
134 if (arr.size() > 0) {
135 samples_.clear();
136 for (auto jentry : arr) {
137 auto json_object = jentry.as<JsonObject>();
138 Sample sample(json_object);
139 samples_.insert(sample);
140 }
141 }
142
143 return true;
144}
145
147
149 samples_.insert(sample);
150}
151
152} // namespace sensesp
void set(const float &input) override
virtual bool to_json(JsonObject &doc) override
void add_sample(const Sample &new_sample)
CurveInterpolator(std::set< Sample > *defaults=NULL, const String &config_path="")
Construct a new CurveInterpolator object.
virtual bool from_json(const JsonObject &doc) override
virtual bool clear() override
Delete the data from a persistent storage.
Definition saveable.cpp:71
virtual bool load() override
Load and populate the object from a persistent storage.
Definition saveable.cpp:8