mirror of
https://github.com/miguel5612/MQSensorsLib.git
synced 2025-06-07 22:30:13 +03:00
Merge pull request #84 from miguel5612/codex/verificar-resolución-del-error--ovf--en-sensor-mq-3
Fix overflow for CH4 calculations
This commit is contained in:
commit
6f9b00666e
@ -5,10 +5,12 @@ Este documento resume los problemas reportados en el repositorio y las solucione
|
||||
## Abiertos
|
||||
|
||||
### #75 MQ-3 sensor and CH4 gas reading 'ovf' failure
|
||||
**Estado:** abierto
|
||||
**Estado:** resuelto en la rama `main`
|
||||
|
||||
El usuario reporta desbordamiento ("ovf") al utilizar valores muy altos en `setA` y `setB` para leer CH4 con un sensor MQ-3. La solución propuesta es revisar los valores utilizados en `setA` y `setB`, ya que `2*10^31` en C++ no corresponde a `2e31`. Se recomienda usar notación exponencial (`2e31`) o `pow(10,31)` y comprobar que los parámetros no excedan el rango de `float`.
|
||||
|
||||
**Actualización:** se añadieron validaciones de entrada, predicción de desbordamiento mediante logaritmos y verificación del resultado final para evitar valores "ovf" incluso con coeficientes muy altos. Las nuevas funciones limitan `setA` y `setB` y emplean cálculos en doble precisión.
|
||||
|
||||
### #74 possible error in the calculation formula for `_RS_Calc`
|
||||
**Estado:** resuelto en la rama `work`
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include "MQUnifiedsensor.h"
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
#define retries 2
|
||||
#define retry_interval 20
|
||||
@ -21,11 +23,39 @@ void MQUnifiedsensor::init()
|
||||
{
|
||||
pinMode(_pin, INPUT);
|
||||
}
|
||||
static inline double safePow(double base, double exp){
|
||||
if(exp == 0.0) return 1.0;
|
||||
if(exp == 1.0) return base;
|
||||
if(exp == 2.0) return base * base;
|
||||
return pow(base, exp);
|
||||
}
|
||||
static inline bool willOverflow(double log_ppm){
|
||||
static const double maxLog = log10((double)FLT_MAX);
|
||||
static const double minLog = log10((double)FLT_MIN);
|
||||
return (log_ppm > maxLog || log_ppm < minLog);
|
||||
}
|
||||
|
||||
void MQUnifiedsensor::setA(float a) {
|
||||
this->_a = a;
|
||||
if(isinf(a) || isnan(a)) {
|
||||
this->_a = 0;
|
||||
} else if(a > MQ_MAX_A) {
|
||||
this->_a = MQ_MAX_A;
|
||||
} else if(a < -MQ_MAX_A) {
|
||||
this->_a = -MQ_MAX_A;
|
||||
} else {
|
||||
this->_a = a;
|
||||
}
|
||||
}
|
||||
void MQUnifiedsensor::setB(float b) {
|
||||
this->_b = b;
|
||||
if(isinf(b) || isnan(b)) {
|
||||
this->_b = 0;
|
||||
} else if(b > MQ_MAX_B) {
|
||||
this->_b = MQ_MAX_B;
|
||||
} else if(b < -MQ_MAX_B) {
|
||||
this->_b = -MQ_MAX_B;
|
||||
} else {
|
||||
this->_b = b;
|
||||
}
|
||||
}
|
||||
void MQUnifiedsensor::setR0(float R0) {
|
||||
this->_R0 = R0;
|
||||
@ -134,20 +164,23 @@ void MQUnifiedsensor::externalADCUpdate(float volt)
|
||||
}
|
||||
float MQUnifiedsensor::validateEcuation(float ratioInput)
|
||||
{
|
||||
//Serial.print("Ratio input: "); Serial.println(ratioInput);
|
||||
//Serial.print("a: "); Serial.println(_a);
|
||||
//Serial.print("b: "); Serial.println(_b);
|
||||
//Usage of this function: Unit test on ALgorithmTester example;
|
||||
if(_regressionMethod == 1) _PPM= _a*pow(ratioInput, _b);
|
||||
else
|
||||
{
|
||||
// https://jayconsystems.com/blog/understanding-a-gas-sensor
|
||||
double ppm_log = (log10(ratioInput)-_b)/_a; //Get ppm value in linear scale according to the the ratio value
|
||||
_PPM = pow(10, ppm_log); //Convert ppm value to log scale
|
||||
double ppm;
|
||||
if(_regressionMethod == 1){
|
||||
if(ratioInput <= 0 || _a == 0) return 0;
|
||||
double logppm = log10((double)_a) + (double)_b * log10((double)ratioInput);
|
||||
if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0;
|
||||
else ppm = safePow(10.0, logppm);
|
||||
}
|
||||
//Serial.println("Regression Method: "); Serial.println(_regressionMethod);
|
||||
//Serial.println("Result: "); Serial.println(_PPM);
|
||||
return _PPM;
|
||||
else
|
||||
{
|
||||
if(ratioInput <= 0 || _a == 0) return 0;
|
||||
double logppm = (log10((double)ratioInput)-(double)_b)/(double)_a;
|
||||
if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0;
|
||||
else ppm = safePow(10.0, logppm);
|
||||
}
|
||||
if(isinf(ppm) || isnan(ppm)) ppm = FLT_MAX;
|
||||
_PPM = (float)ppm;
|
||||
return _PPM;
|
||||
}
|
||||
float MQUnifiedsensor::readSensor(bool isMQ303A, float correctionFactor, bool injected)
|
||||
{
|
||||
@ -162,14 +195,23 @@ float MQUnifiedsensor::readSensor(bool isMQ303A, float correctionFactor, bool in
|
||||
if(!injected) _ratio = _RS_Calc / this->_R0; // Get ratio RS_gas/RS_air
|
||||
_ratio += correctionFactor;
|
||||
if(_ratio <= 0) _ratio = 0; //No negative values accepted or upper datasheet recommendation.
|
||||
if(_regressionMethod == 1) _PPM= _a*pow(_ratio, _b); // <- Source excel analysis https://github.com/miguel5612/MQSensorsLib_Docs/tree/master/Internal_design_documents
|
||||
else
|
||||
{
|
||||
// https://jayconsystems.com/blog/understanding-a-gas-sensor <- Source of linear equation
|
||||
double ppm_log = (log10(_ratio)-_b)/_a; //Get ppm value in linear scale according to the the ratio value
|
||||
_PPM = pow(10, ppm_log); //Convert ppm value to log scale
|
||||
double ppm;
|
||||
if(_regressionMethod == 1){
|
||||
if(_ratio <= 0 || _a == 0) return 0;
|
||||
double logppm = log10((double)_a) + (double)_b * log10((double)_ratio);
|
||||
if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0;
|
||||
else ppm = safePow(10.0, logppm);
|
||||
}
|
||||
if(_PPM < 0) _PPM = 0; //No negative values accepted or upper datasheet recommendation.
|
||||
else
|
||||
{
|
||||
if(_ratio <= 0 || _a == 0) return 0;
|
||||
double logppm = (log10((double)_ratio)-(double)_b)/(double)_a;
|
||||
if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0;
|
||||
else ppm = safePow(10.0, logppm);
|
||||
}
|
||||
if(ppm < 0) ppm = 0; //No negative values accepted or upper datasheet recommendation.
|
||||
if(isinf(ppm) || isnan(ppm)) ppm = FLT_MAX;
|
||||
_PPM = (float)ppm;
|
||||
//if(_PPM > 10000) _PPM = 99999999; //No negative values accepted or upper datasheet recommendation.
|
||||
return _PPM;
|
||||
}
|
||||
@ -180,14 +222,23 @@ float MQUnifiedsensor::readSensorR0Rs()
|
||||
if(_RS_Calc < 0) _RS_Calc = 0; //No negative values accepted.
|
||||
_ratio = this->_R0/_RS_Calc; // Get ratio RS_air/RS_gas <- INVERTED for MQ-131 issue 28 https://github.com/miguel5612/MQSensorsLib/issues/28
|
||||
if(_ratio <= 0) _ratio = 0; //No negative values accepted or upper datasheet recommendation.
|
||||
if(_regressionMethod == 1) _PPM= _a*pow(_ratio, _b); // <- Source excel analysis https://github.com/miguel5612/MQSensorsLib_Docs/tree/master/Internal_design_documents
|
||||
else
|
||||
{
|
||||
// https://jayconsystems.com/blog/understanding-a-gas-sensor <- Source of linear equation
|
||||
double ppm_log = (log10(_ratio)-_b)/_a; //Get ppm value in linear scale according to the the ratio value
|
||||
_PPM = pow(10, ppm_log); //Convert ppm value to log scale
|
||||
double ppm;
|
||||
if(_regressionMethod == 1){
|
||||
if(_ratio <= 0 || _a == 0) return 0;
|
||||
double logppm = log10((double)_a) + (double)_b * log10((double)_ratio);
|
||||
if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0;
|
||||
else ppm = safePow(10.0, logppm);
|
||||
}
|
||||
if(_PPM < 0) _PPM = 0; //No negative values accepted or upper datasheet recommendation.
|
||||
else
|
||||
{
|
||||
if(_ratio <= 0 || _a == 0) return 0;
|
||||
double logppm = (log10((double)_ratio)-(double)_b)/(double)_a;
|
||||
if(willOverflow(logppm)) ppm = (logppm > 0) ? FLT_MAX : 0.0;
|
||||
else ppm = safePow(10.0, logppm);
|
||||
}
|
||||
if(ppm < 0) ppm = 0; //No negative values accepted or upper datasheet recommendation.
|
||||
if(isinf(ppm) || isnan(ppm)) ppm = FLT_MAX;
|
||||
_PPM = (float)ppm;
|
||||
//if(_PPM > 10000) _PPM = 99999999; //No negative values accepted or upper datasheet recommendation.
|
||||
return _PPM;
|
||||
}
|
||||
|
@ -3,6 +3,12 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <stdint.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
// Maximum coefficients allowed for the regression model
|
||||
#define MQ_MAX_A 1e30
|
||||
#define MQ_MAX_B 100.0
|
||||
|
||||
/***********************Software Related Macros************************************/
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user