258 lines
4.8 KiB
C++
Raw Normal View History

//
// FILE: Correlation.cpp
2021-01-29 12:31:58 +01:00
// AUTHOR: Rob Tillaart
2021-12-14 16:39:48 +01:00
// VERSION: 0.2.1
// PURPOSE: Arduino Library to determine correlation between X and Y dataset
//
2021-01-29 12:31:58 +01:00
// HISTORY:
2021-12-14 16:39:48 +01:00
// 0.2.1 2021-12-14 update library.json, license, minor edits
// 0.2.0 2021-08-26 Add flags to skip Rsquared and Esquared calculation
2021-08-27 16:16:35 +02:00
// will improve performance calculate
// fixed sign of R correlation coefficient
2021-08-26 17:18:52 +02:00
//
2021-08-27 16:16:35 +02:00
// 0.1.4 2021-08-26 improve performance calculate
// 0.1.3 2021-01-16 add size in constructor,
2021-01-29 12:31:58 +01:00
// add statistical + debug functions
2021-12-14 16:39:48 +01:00
// 0.1.2 2020-12-17 add Arduino-CI + unit tests
2021-01-29 12:31:58 +01:00
// + size() + getAvgX() + getAvgY()
// 0.1.1 2020-06-05 fix library.json
// 0.1.0 2020-05-17 initial version
#include "Correlation.h"
2021-01-29 12:31:58 +01:00
Correlation::Correlation(uint8_t size)
{
2021-08-27 16:16:35 +02:00
_size = 20;
if (size > 0) _size = size;
2021-01-29 12:31:58 +01:00
_x = (float *) malloc(_size * sizeof(float));
_y = (float *) malloc(_size * sizeof(float));
clear();
}
2021-01-29 12:31:58 +01:00
Correlation::~Correlation()
{
2021-08-27 16:16:35 +02:00
if (_x) free(_x);
if (_y) free(_y);
2021-01-29 12:31:58 +01:00
}
void Correlation::clear()
{
2021-01-29 12:31:58 +01:00
_count = 0;
2021-12-14 16:39:48 +01:00
_index = 0;
_needRecalculate = true;
2021-01-29 12:31:58 +01:00
_runningMode = false;
_avgX = 0;
_avgY = 0;
_a = 0;
_b = 0;
2021-08-27 16:16:35 +02:00
_r = 0;
2021-01-29 12:31:58 +01:00
_sumErrorSquare = 0;
_sumXiYi = 0;
_sumXi2 = 0;
_sumYi2 = 0;
2021-08-27 16:16:35 +02:00
_doR2 = true;
_doE2 = true;
}
2021-01-29 12:31:58 +01:00
bool Correlation::add(float x, float y)
{
2021-01-29 12:31:58 +01:00
if ( (_count < _size) || _runningMode)
{
2021-12-14 16:39:48 +01:00
_x[_index] = x;
_y[_index] = y;
_index++;
if (_index >= _size) _index = 0;
2021-01-29 12:31:58 +01:00
if (_count < _size) _count++;
_needRecalculate = true;
return true;
}
return false;
}
2021-01-29 12:31:58 +01:00
2021-08-27 16:16:35 +02:00
bool Correlation::calculate(bool forced)
{
if (_count == 0) return false;
2021-08-27 16:16:35 +02:00
if (! (_needRecalculate || forced)) return true;
// CALC AVERAGE X, AVERAGE Y
2021-08-26 17:18:52 +02:00
float avgx = 0;
float avgy = 0;
for (uint8_t i = 0; i < _count; i++)
{
2021-08-26 17:18:52 +02:00
avgx += _x[i];
avgy += _y[i];
}
2021-08-26 17:18:52 +02:00
avgx /= _count;
avgy /= _count;
2021-08-27 16:16:35 +02:00
2021-08-26 17:18:52 +02:00
_avgX = avgx;
_avgY = avgy;
// CALC A and B ==> formula Y = A + B*X
2021-08-26 17:18:52 +02:00
float sumXiYi = 0;
float sumXi2 = 0;
float sumYi2 = 0;
for (uint8_t i = 0; i < _count; i++)
{
2021-08-26 17:18:52 +02:00
float xi = _x[i] - avgx;
float yi = _y[i] - avgy;
sumXiYi += (xi * yi);
sumXi2 += (xi * xi);
sumYi2 += (yi * yi);
}
2021-08-26 17:18:52 +02:00
float b = sumXiYi / sumXi2;
float a = avgy - b * avgx;
2021-08-27 16:16:35 +02:00
2021-08-26 17:18:52 +02:00
_a = a;
_b = b;
2021-08-27 16:16:35 +02:00
_sumXiYi = sumXiYi;
_sumXi2 = sumXi2;
_sumYi2 = sumYi2;
2021-08-26 17:18:52 +02:00
2021-08-27 16:16:35 +02:00
if (_doR2 == true)
{
// R is calculated instead of rSquared so we do not loose the sign.
2021-12-14 16:39:48 +01:00
// Rsquared from R is much faster than R from Rsquared.
2021-08-27 16:16:35 +02:00
_r = sumXiYi / sqrt(sumXi2 * sumYi2);
}
if (_doE2 == true)
{
2021-08-27 16:16:35 +02:00
float sumErrorSquare = 0;
for (uint8_t i = 0; i < _count; i++)
{
float EY = a + b * _x[i];
float ei = _y[i] - EY;
sumErrorSquare += (ei * ei);
}
_sumErrorSquare = sumErrorSquare;
}
_needRecalculate = false;
return true;
}
2021-01-29 12:31:58 +01:00
float Correlation::getEstimateY(float x)
{
if (_count == 0) return NAN;
if (_needRecalculate) calculate();
return _a + _b * x;
}
2021-01-29 12:31:58 +01:00
float Correlation::getEstimateX(float y)
{
if (_count == 0) return NAN;
if (_needRecalculate) calculate();
return (y - _a) / _b;
}
2021-01-29 12:31:58 +01:00
//////////////////////////////////////////////////////
//
// STATISTICAL
//
float Correlation::getMaxX()
{
if (_count == 0) return NAN;
float rv = _x[0];
for (uint8_t i = 1; i < _count; i++)
{
if (_x[i] > rv) rv = _x[i];
}
return rv;
}
2021-12-14 16:39:48 +01:00
2021-01-29 12:31:58 +01:00
float Correlation::getMinX()
{
if (_count == 0) return NAN;
float rv = _x[0];
for (uint8_t i = 1; i < _count; i++)
{
if (_x[i] < rv) rv = _x[i];
}
return rv;
}
2021-12-14 16:39:48 +01:00
2021-01-29 12:31:58 +01:00
float Correlation::getMaxY()
{
if (_count == 0) return NAN;
float rv = _y[0];
for (uint8_t i = 1; i < _count; i++)
{
if (_y[i] > rv) rv = _y[i];
}
return rv;
}
2021-12-14 16:39:48 +01:00
2021-01-29 12:31:58 +01:00
float Correlation::getMinY()
{
if (_count == 0) return NAN;
float rv = _y[0];
for (uint8_t i = 1; i < _count; i++)
{
if (_y[i] < rv) rv = _y[i];
}
return rv;
}
2021-12-14 16:39:48 +01:00
2021-01-29 12:31:58 +01:00
//////////////////////////////////////////////////////
//
// DEBUGGING - access to internal arrays.
//
2021-12-14 16:39:48 +01:00
bool Correlation::setXY(uint8_t index, float x, float y)
2021-01-29 12:31:58 +01:00
{
2021-12-14 16:39:48 +01:00
if (index >= _count) return false;
_x[index] = x;
_y[index] = y;
2021-01-29 12:31:58 +01:00
_needRecalculate = true;
return true;
}
2021-12-14 16:39:48 +01:00
bool Correlation::setX(uint8_t index, float x)
2021-01-29 12:31:58 +01:00
{
2021-12-14 16:39:48 +01:00
if (index >= _count) return false;
_x[index] = x;
2021-01-29 12:31:58 +01:00
_needRecalculate = true;
return true;
}
2021-12-14 16:39:48 +01:00
float Correlation::getX(uint8_t index)
2021-01-29 12:31:58 +01:00
{
2021-12-14 16:39:48 +01:00
if (index >= _count) return NAN;
return _x[index];
2021-01-29 12:31:58 +01:00
}
2021-12-14 16:39:48 +01:00
bool Correlation::setY(uint8_t index, float y)
2021-01-29 12:31:58 +01:00
{
2021-12-14 16:39:48 +01:00
if (index >= _count) return false;
_y[index] = y;
2021-01-29 12:31:58 +01:00
_needRecalculate = true;
return true;
}
2021-12-14 16:39:48 +01:00
float Correlation::getY(uint8_t index)
2021-01-29 12:31:58 +01:00
{
2021-12-14 16:39:48 +01:00
if (index > _count) return NAN;
return _y[index];
2021-01-29 12:31:58 +01:00
}
2021-12-14 16:39:48 +01:00
// -- END OF FILE --
2021-12-14 16:39:48 +01:00