JXCT Soil Sensor 7-in-1 3.10.1
IoT система мониторинга почвы на базе ESP32
Загрузка...
Поиск...
Не найдено
calibration_math.h
См. документацию.
1#pragma once
2
3#include <Arduino.h>
4#include <vector>
5#include "calibration_data.h"
6
14public:
21 static bool calculateLinearRegression(const std::vector<ModernCalibrationPoint>& points,
22 LinearCoefficients& coefficients) {
23 if (points.size() < 2) {
24 return false;
25 }
26
27 size_t n = points.size();
28 float sum_x = 0.0f, sum_y = 0.0f, sum_xy = 0.0f, sum_x2 = 0.0f, sum_y2 = 0.0f;
29
30 // Суммируем все необходимые значения
31 for (const auto& point : points) {
32 sum_x += point.measured; // x = measured (показание датчика)
33 sum_y += point.expected; // y = expected (эталонное значение)
34 sum_xy += point.measured * point.expected;
35 sum_x2 += point.measured * point.measured;
36 sum_y2 += point.expected * point.expected;
37 }
38
39 // Рассчитываем коэффициенты: y = ax + b
40 float denominator = n * sum_x2 - sum_x * sum_x;
41
42 if (abs(denominator) < 1e-6f) {
43 // Избегаем деления на ноль
44 return false;
45 }
46
47 coefficients.slope = (n * sum_xy - sum_x * sum_y) / denominator;
48 coefficients.intercept = (sum_y - coefficients.slope * sum_x) / n;
49
50 // Рассчитываем коэффициент детерминации R²
51 coefficients.r_squared = calculateRSquared(points, coefficients.slope, coefficients.intercept);
52
53 // Проверяем разумность коэффициентов
54 coefficients.is_valid = validateCoefficients(coefficients);
55
56 return coefficients.is_valid;
57 }
58
62 static float calculateRSquared(const std::vector<ModernCalibrationPoint>& points,
63 float slope, float intercept) {
64 if (points.empty()) {
65 return 0.0f;
66 }
67
68 // Среднее значение y (expected)
69 float mean_y = 0.0f;
70 for (const auto& point : points) {
71 mean_y += point.expected;
72 }
73 mean_y /= points.size();
74
75 // Сумма квадратов остатков (SSres) и общая сумма квадратов (SStot)
76 float ss_res = 0.0f, ss_tot = 0.0f;
77
78 for (const auto& point : points) {
79 float predicted = slope * point.measured + intercept;
80 ss_res += (point.expected - predicted) * (point.expected - predicted);
81 ss_tot += (point.expected - mean_y) * (point.expected - mean_y);
82 }
83
84 if (ss_tot < 1e-6f) {
85 return 1.0f; // Все точки на одной линии
86 }
87
88 float r_squared = 1.0f - (ss_res / ss_tot);
89
90 // Ограничиваем R² в диапазоне [0, 1]
91 return constrain(r_squared, 0.0f, 1.0f);
92 }
93
97 static bool validateCoefficients(const LinearCoefficients& coefficients) {
98 // Проверяем разумность коэффициентов
99 if (isnan(coefficients.slope) || isnan(coefficients.intercept) ||
100 isnan(coefficients.r_squared)) {
101 return false;
102 }
103
104 // Проверяем, что slope не слишком экстремальный
105 if (abs(coefficients.slope) > 10.0f || abs(coefficients.slope) < 0.1f) {
106 return false;
107 }
108
109 // Проверяем качество регрессии (R² должен быть достаточно высоким)
110 if (coefficients.r_squared < 0.5f) {
111 return false;
112 }
113
114 return true;
115 }
116
120 static float applyCalibration(float raw_value, const LinearCoefficients& coefficients) {
121 if (!coefficients.is_valid) {
122 return raw_value;
123 }
124
125 return coefficients.slope * raw_value + coefficients.intercept;
126 }
127
131 static float applyOffsetCalibration(float raw_value, const OffsetCalibration& offset) {
132 if (!offset.is_valid) {
133 return raw_value;
134 }
135
136 return raw_value + offset.offset;
137 }
138
142 static bool validateCalibrationPoint(float expected, float measured, const String& sensor_type) {
143 // Общие проверки
144 if (isnan(expected) || isnan(measured) ||
145 isinf(expected) || isinf(measured)) {
146 return false;
147 }
148
149 // Специфичные проверки для разных типов датчиков
150 if (sensor_type == "ph") {
151 return (expected >= 0.0f && expected <= 14.0f &&
152 measured >= 0.0f && measured <= 14.0f);
153 }
154 else if (sensor_type == "ec") {
155 return (expected >= 0.0f && expected <= 20000.0f &&
156 measured >= 0.0f && measured <= 20000.0f);
157 }
158 else if (sensor_type == "temperature") {
159 return (expected >= -40.0f && expected <= 80.0f &&
160 measured >= -40.0f && measured <= 80.0f);
161 }
162 else if (sensor_type == "humidity") {
163 return (expected >= 0.0f && expected <= 100.0f &&
164 measured >= 0.0f && measured <= 100.0f);
165 }
166 else if (sensor_type == "npk") {
167 return (expected >= 0.0f && expected <= 2000.0f &&
168 measured >= 0.0f && measured <= 2000.0f);
169 }
170
171 return true;
172 }
173
179 static void removeOutliers(std::vector<ModernCalibrationPoint>& points, float threshold = 2.0f) {
180 if (points.size() < 3) {
181 return; // Слишком мало точек для анализа выбросов
182 }
183
184 // Рассчитываем среднее и стандартное отклонение отношений expected/measured
185 float mean_ratio = 0.0f;
186 std::vector<float> ratios;
187
188 for (const auto& point : points) {
189 if (point.measured != 0.0f) {
190 float ratio = point.expected / point.measured;
191 ratios.push_back(ratio);
192 mean_ratio += ratio;
193 }
194 }
195
196 if (ratios.empty()) {
197 return;
198 }
199
200 mean_ratio /= ratios.size();
201
202 // Рассчитываем стандартное отклонение
203 float variance = 0.0f;
204 for (float ratio : ratios) {
205 variance += (ratio - mean_ratio) * (ratio - mean_ratio);
206 }
207 variance /= ratios.size();
208 float std_dev = sqrt(variance);
209
210 // Удаляем выбросы
211 auto it = points.begin();
212 while (it != points.end()) {
213 if (it->measured != 0.0f) {
214 float ratio = it->expected / it->measured;
215 if (abs(ratio - mean_ratio) > threshold * std_dev) {
216 it = points.erase(it);
217 continue;
218 }
219 }
220 ++it;
221 }
222 }
223
234
235 static CalibrationStats getCalibrationStats(const std::vector<ModernCalibrationPoint>& points,
236 const LinearCoefficients& coefficients) {
237 CalibrationStats stats = {};
238 stats.point_count = points.size();
239 stats.r_squared = coefficients.r_squared;
240
241 if (points.empty() || !coefficients.is_valid) {
242 return stats;
243 }
244
245 float total_error = 0.0f;
246 float max_error = 0.0f;
247
248 for (const auto& point : points) {
249 float predicted = coefficients.slope * point.measured + coefficients.intercept;
250 float error = abs(point.expected - predicted);
251
252 total_error += error;
253 if (error > max_error) {
254 max_error = error;
255 }
256 }
257
258 stats.mean_error = total_error / points.size();
259 stats.max_error = max_error;
260 stats.is_reliable = (stats.r_squared > 0.8f && stats.mean_error < 0.5f);
261
262 return stats;
263 }
264};
Структуры данных для системы калибровки датчиков
Definition calibration_math.h:13
static float applyCalibration(float raw_value, const LinearCoefficients &coefficients)
Применение калибровки к значению
Definition calibration_math.h:120
static float calculateRSquared(const std::vector< ModernCalibrationPoint > &points, float slope, float intercept)
Расчет коэффициента детерминации R²
Definition calibration_math.h:62
static void removeOutliers(std::vector< ModernCalibrationPoint > &points, float threshold=2.0f)
Удаление выбросов из калибровочных точек
Definition calibration_math.h:179
static float applyOffsetCalibration(float raw_value, const OffsetCalibration &offset)
Применение offset калибровки
Definition calibration_math.h:131
static bool validateCalibrationPoint(float expected, float measured, const String &sensor_type)
Валидация калибровочной точки
Definition calibration_math.h:142
static bool validateCoefficients(const LinearCoefficients &coefficients)
Валидация коэффициентов калибровки
Definition calibration_math.h:97
static CalibrationStats getCalibrationStats(const std::vector< ModernCalibrationPoint > &points, const LinearCoefficients &coefficients)
Definition calibration_math.h:235
static bool calculateLinearRegression(const std::vector< ModernCalibrationPoint > &points, LinearCoefficients &coefficients)
Расчет коэффициентов линейной регрессии методом наименьших квадратов
Definition calibration_math.h:21
Получение статистики по калибровочным точкам
Definition calibration_math.h:227
float r_squared
Definition calibration_math.h:231
size_t point_count
Definition calibration_math.h:228
bool is_reliable
Definition calibration_math.h:232
float mean_error
Definition calibration_math.h:229
float max_error
Definition calibration_math.h:230
Коэффициенты линейной калибровки y = ax + b.
Definition calibration_data.h:30
bool is_valid
Definition calibration_data.h:34
float intercept
Definition calibration_data.h:32
float slope
Definition calibration_data.h:31
float r_squared
Definition calibration_data.h:33
Простое смещение (offset) для температуры и влажности
Definition calibration_data.h:42
float offset
Definition calibration_data.h:43
bool is_valid
Definition calibration_data.h:44