use linear regression for preduction
This commit is contained in:
		| @ -2,6 +2,7 @@ | ||||
| #include "freertos/task.h" | ||||
| #include "driver/gpio.h" | ||||
| #include <string.h> | ||||
| #include <math.h> | ||||
| #include "esp_log.h" | ||||
| #include <ds18x20.h> | ||||
|  | ||||
| @ -35,6 +36,7 @@ void taskInput(void *pvParameters); | ||||
| void initMeasurement(sMeasurement *pMeasurement); | ||||
| void updateAverage(sMeasurement *pMeasurement); | ||||
| void updatePrediction(sMeasurement *pMeasurement); | ||||
| float linearRegressionPredict(const float *samples, size_t count, float futureIndex); | ||||
|  | ||||
| void initInputs(void) | ||||
| { | ||||
| @ -82,6 +84,9 @@ void initInputs(void) | ||||
|  | ||||
| void initMeasurement(sMeasurement *pMeasurement) | ||||
| { | ||||
|     if (!pMeasurement) | ||||
|         return; | ||||
|  | ||||
|     pMeasurement->state = MEASUREMENT_FAULT; | ||||
|     pMeasurement->fCurrentValue = 0.0f; | ||||
|  | ||||
| @ -95,11 +100,6 @@ void initMeasurement(sMeasurement *pMeasurement) | ||||
|     pMeasurement->average60s.bufferIndex = 0U; | ||||
|     memset(pMeasurement->average60s.samples, 0U, AVG60_SAMPLE_SIZE); | ||||
|  | ||||
|     pMeasurement->predict10s.fValue = 0.0f; | ||||
|     pMeasurement->predict10s.bufferCount = 0U; | ||||
|     pMeasurement->predict10s.bufferIndex = 0U; | ||||
|     memset(pMeasurement->predict10s.samples, 0U, PRED10_SAMPLE_SIZE); | ||||
|  | ||||
|     pMeasurement->predict60s.fValue = 0.0f; | ||||
|     pMeasurement->predict60s.bufferCount = 0U; | ||||
|     pMeasurement->predict60s.bufferIndex = 0U; | ||||
| @ -107,7 +107,11 @@ void initMeasurement(sMeasurement *pMeasurement) | ||||
| } | ||||
|  | ||||
| void updateAverage(sMeasurement *pMeasurement) | ||||
| { /* Average form the last 10sec */ | ||||
| { | ||||
|     if (!pMeasurement) | ||||
|         return; | ||||
|  | ||||
|     // Average form the last 10sec | ||||
|     pMeasurement->average10s.samples[pMeasurement->average10s.bufferIndex] = pMeasurement->fCurrentValue; | ||||
|     pMeasurement->average10s.bufferIndex = (pMeasurement->average10s.bufferIndex + 1) % AVG10_SAMPLE_SIZE; | ||||
|  | ||||
| @ -124,7 +128,7 @@ void updateAverage(sMeasurement *pMeasurement) | ||||
|  | ||||
|     pMeasurement->average10s.fValue = sum / pMeasurement->average10s.bufferCount; | ||||
|  | ||||
|     /* Average form the last 60sec */ | ||||
|     // Average form the last 60sec | ||||
|     pMeasurement->average60s.samples[pMeasurement->average60s.bufferIndex] = pMeasurement->fCurrentValue; | ||||
|     pMeasurement->average60s.bufferIndex = (pMeasurement->average60s.bufferIndex + 1) % AVG60_SAMPLE_SIZE; | ||||
|  | ||||
| @ -148,35 +152,22 @@ void updateAverage(sMeasurement *pMeasurement) | ||||
| } | ||||
|  | ||||
| void updatePrediction(sMeasurement *pMeasurement) | ||||
| { /* Prediction of the value in 10sec */ | ||||
|     pMeasurement->predict10s.samples[pMeasurement->predict10s.bufferIndex] = pMeasurement->fCurrentValue; | ||||
|     pMeasurement->predict10s.bufferIndex = (pMeasurement->predict10s.bufferIndex + 1) % PRED10_SAMPLE_SIZE; | ||||
| { | ||||
|     if (!pMeasurement) | ||||
|         return; | ||||
|  | ||||
|     if (pMeasurement->predict10s.bufferCount < PRED10_SAMPLE_SIZE) | ||||
|     { | ||||
|         pMeasurement->predict10s.bufferCount++; | ||||
|     } | ||||
|     // Update predict60s buffer | ||||
|     sPredict *predict60s = &pMeasurement->predict60s; | ||||
|     predict60s->samples[predict60s->bufferIndex] = pMeasurement->fCurrentValue; | ||||
|     predict60s->bufferIndex = (predict60s->bufferIndex + 1) % PRED60_SAMPLE_SIZE; | ||||
|     if (predict60s->bufferCount < PRED60_SAMPLE_SIZE) | ||||
|         predict60s->bufferCount++; | ||||
|  | ||||
|     float delta10s = pMeasurement->predict10s.samples[(pMeasurement->predict10s.bufferIndex - 1) % PRED10_SAMPLE_SIZE] - pMeasurement->predict10s.samples[pMeasurement->predict10s.bufferIndex]; | ||||
|     if (delta10s != 0.0) | ||||
|     { | ||||
|         pMeasurement->predict10s.fValue = pMeasurement->fCurrentValue + (delta10s * pMeasurement->predict10s.bufferCount); | ||||
|     } | ||||
|  | ||||
|     /* Prediction of the value in 60sec */ | ||||
|     pMeasurement->predict60s.samples[pMeasurement->predict60s.bufferIndex] = pMeasurement->fCurrentValue; | ||||
|     pMeasurement->predict60s.bufferIndex = (pMeasurement->predict60s.bufferIndex + 1) % PRED60_SAMPLE_SIZE; | ||||
|  | ||||
|     if (pMeasurement->predict60s.bufferCount < PRED60_SAMPLE_SIZE) | ||||
|     { | ||||
|         pMeasurement->predict60s.bufferCount++; | ||||
|     } | ||||
|  | ||||
|     float delta60s = pMeasurement->predict60s.samples[(pMeasurement->predict60s.bufferIndex - 1) % PRED60_SAMPLE_SIZE] - pMeasurement->predict60s.samples[pMeasurement->predict60s.bufferIndex]; | ||||
|     if (delta60s != 0.0) | ||||
|     { | ||||
|         pMeasurement->predict60s.fValue = pMeasurement->fCurrentValue + (delta60s * pMeasurement->predict60s.bufferCount); | ||||
|     } | ||||
|     // Predict 60s future value using linear regression | ||||
|     predict60s->fValue = linearRegressionPredict( | ||||
|         predict60s->samples, | ||||
|         predict60s->bufferCount, | ||||
|         predict60s->bufferCount + 60.0f); | ||||
| } | ||||
|  | ||||
| void taskInput(void *pvParameters) | ||||
| @ -275,6 +266,36 @@ void taskInput(void *pvParameters) | ||||
|     } | ||||
| } | ||||
|  | ||||
| float linearRegressionPredict(const float *samples, size_t count, float futureIndex) | ||||
| { | ||||
|     if (count == 0) | ||||
|         return 0.0f; // No prediction possible with no data | ||||
|  | ||||
|     float sumX = 0.0f, sumY = 0.0f, sumXY = 0.0f, sumX2 = 0.0f; | ||||
|  | ||||
|     for (size_t i = 0; i < count; i++) | ||||
|     { | ||||
|         float x = (float)i;   // Time index | ||||
|         float y = samples[i]; // Sample value | ||||
|  | ||||
|         sumX += x; | ||||
|         sumY += y; | ||||
|         sumXY += x * y; | ||||
|         sumX2 += x * x; | ||||
|     } | ||||
|  | ||||
|     // Calculate slope (m) and intercept (b) of the line: y = mx + b | ||||
|     float denominator = (count * sumX2 - sumX * sumX); | ||||
|     if (fabs(denominator) < 1e-6)  // Avoid division by zero | ||||
|         return samples[count - 1]; // Return last value as prediction | ||||
|  | ||||
|     float m = (count * sumXY - sumX * sumY) / denominator; | ||||
|     float b = (sumY - m * sumX) / count; | ||||
|  | ||||
|     // Predict value at futureIndex | ||||
|     return m * futureIndex + b; | ||||
| } | ||||
|  | ||||
| sMeasurement getChamberTemperature(void) | ||||
| { | ||||
|     sMeasurement ret; | ||||
|  | ||||
| @ -3,7 +3,6 @@ | ||||
| #define MAX(a, b) ((a) > (b) ? (a) : (b)) | ||||
| #define AVG10_SAMPLE_SIZE 10U | ||||
| #define AVG60_SAMPLE_SIZE 60U | ||||
| #define PRED10_SAMPLE_SIZE 10U | ||||
| #define PRED60_SAMPLE_SIZE 60U | ||||
|  | ||||
| typedef enum _BurnerErrorState | ||||
| @ -29,7 +28,7 @@ typedef struct _Average | ||||
| typedef struct _Predict | ||||
| { | ||||
|     float fValue; | ||||
|     float samples[MAX(PRED10_SAMPLE_SIZE, PRED60_SAMPLE_SIZE)]; | ||||
|     float samples[PRED60_SAMPLE_SIZE]; | ||||
|     size_t bufferIndex; | ||||
|     size_t bufferCount; | ||||
| } sPredict; | ||||
| @ -39,7 +38,6 @@ typedef struct _Measurement | ||||
|     float fCurrentValue; | ||||
|     sAverage average10s; | ||||
|     sAverage average60s; | ||||
|     sPredict predict10s; | ||||
|     sPredict predict60s; | ||||
|     eMeasurementErrorState state; | ||||
| } sMeasurement; | ||||
|  | ||||
| @ -128,12 +128,6 @@ void taskMetrics(void *pvParameters) | ||||
|         aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().average60s.fValue; | ||||
|         u16MetricCounter++; | ||||
|  | ||||
|         // Chamber Temperature Predict 10s | ||||
|         strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_pred10"); | ||||
|         aMetrics[u16MetricCounter].type = FLOAT; | ||||
|         aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().predict10s.fValue; | ||||
|         u16MetricCounter++; | ||||
|  | ||||
|         // Chamber Temperature Predict 60s | ||||
|         strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_pred60"); | ||||
|         aMetrics[u16MetricCounter].type = FLOAT; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user