@@ -2915,7 +2915,7 @@ static const char CALIBRATION_HTML[] PROGMEM = R"HTML(
29152915
29162916 // Check if sensor reading is valid for calibration (4-20mA range)
29172917 const isValidReading = log.sensorReading >= 4 && log.sensorReading <= 20;
2918- const sensorDisplay = log.sensorReading >= 4 && log.sensorReading <= 20
2918+ const sensorDisplay = isValidReading
29192919 ? log.sensorReading.toFixed(2) + ' mA'
29202920 : (log.sensorReading ? `${log.sensorReading.toFixed(2)} mA ⚠️` : '-- ⚠️');
29212921
@@ -7317,20 +7317,17 @@ static void recalculateCalibration(TankCalibration *cal) {
73177317 cal->learnedOffset = (sumY - cal->learnedSlope * sumX) / n;
73187318
73197319 // Calculate R-squared (coefficient of determination)
7320- // R² = 1 - (SS_residual / SS_total)
7321- // For linear regression: SS_regression = slope² * (sumX² - n * meanX²)
7322- // And: SS_residual = SS_total - SS_regression
7320+ // R² = (Covariance(X,Y))² / (Variance(X) * Variance(Y))
7321+ // Which equals: ssCovXY² / (ssX * ssTotal)
73237322 float meanX = sumX / n;
73247323 float meanY = sumY / n;
7325- float ssTotal = sumY2 - n * meanY * meanY;
7326- float ssX = sumX2 - n * meanX * meanX;
7324+ float ssTotal = sumY2 - n * meanY * meanY; // = Variance(Y) * n
7325+ float ssX = sumX2 - n * meanX * meanX; // = Variance(X) * n
7326+ float ssCovXY = sumXY - n * meanX * meanY; // = Covariance(X,Y) * n
73277327
73287328 if (ssTotal > 0 .0001f && ssX > 0 .0001f ) {
7329- // SS_regression = slope * (sumXY - n * meanX * meanY)
7330- float ssCovXY = sumXY - n * meanX * meanY;
7331- float ssRegression = cal->learnedSlope * ssCovXY;
7332- float ssResidual = ssTotal - ssRegression;
7333- cal->rSquared = 1 .0f - (ssResidual / ssTotal);
7329+ // R² = ssCovXY² / (ssX * ssTotal)
7330+ cal->rSquared = (ssCovXY * ssCovXY) / (ssX * ssTotal);
73347331 if (cal->rSquared < 0 .0f ) cal->rSquared = 0 .0f ;
73357332 if (cal->rSquared > 1 .0f ) cal->rSquared = 1 .0f ;
73367333 } else {
0 commit comments