Adafruit_ADS1X15
Adafruit_ADS1X15 copied to clipboard
Problem with computeVolt and compiler optimisation
Hello,
using your library to make data acquisition i noticed that sometimes computeVolt return a bad result, due to some compiler optimisation, like in this output :
Channel 1 and 2 are wrong : rms is rounded as int before calling computeVolt to get Vapp, it should be 0V !
# Channel 0 : rms=0.8519 / min=0 / max=2 / Vapp = 97897.4375V / min=0.0000V / max=0.0040V / I=5933178.0000A
# Channel 1 : rms=0.9333 / min=-1 / max=3 / Vapp = 0.0000V / min=-0.0020V / max=0.0060V / I=0.0000A
# Channel 2 : rms=0.9070 / min=0 / max=2 / Vapp = 68943856272903503872.0000V / min=0.0000V / max=0.0040V / I=4178415527426349072384.0000A
# Channel 3 : rms=0.7184 / min=-1 / max=1 / Vapp = -0.0000V / min=-0.0020V / max=0.0020V / I=-0.0000A
# Channel 4 : rms=0.9837 / min=-1 / max=3 / Vapp = -0.0000V / min=-0.0020V / max=0.0060V / I=-0.0020A
I am running on ESP32 with Arduino_ESP32 library (Arduino IDE version 2.3.2), AdaFruit latest release (2.5.0). Chips is an ADS1015 (from techniot bought on Amazon)
Original parts of the code producing random wrong value some times:
> > MainPowerChannel.RMSValue = MainPowerChannel.RMSValue / MainSampleRead;
> > MainPowerChannel.RMSValue = sqrt(MainPowerChannel.RMSValue);
> > // Convert to Volt using ADC resolution
> > MainPowerChannel.Vapp = adcComputeVolts(iMainVoltageADC, MainPowerChannel.RMSValue);
>
(source is used to get the right ADC object to used on a list of 2...)
float adcComputeVolts(int _source, int16_t value) {
if (_source >= NB_MAX_ADC_CHANNEL) return -1;
int adsid = _source / NB_CHANNEL_BY_ADC;
int adspin = _source % NB_CHANNEL_BY_ADC;
//Serial.printf("ACV? %d=(%d,%d) %d\r\n",_source,adsid,adspin,value);
//int16_t retvalue=value*1;
return ads[adsid].computeVolts(value);
}
to solve temporarly this problem i had to use the source value before calling computeVolt in my own code (using a printf or another operation. (removing one or the other comment)
reading the current library code, i found that the current operation give priority on the division of the full range value (float) by the resolution BEFORE applying current source value.
float Adafruit_ADS1015::computeVolts(int16_t counts)
{
// see data sheet Table 3
float fsRange;
switch (m_gain) {
case GAIN_TWOTHIRDS:
fsRange = 6.144f;
break;
case GAIN_ONE:
fsRange = 4.096f;
break;
case GAIN_TWO:
fsRange = 2.048f;
break;
case GAIN_FOUR:
fsRange = 1.024f;
break;
case GAIN_EIGHT:
fsRange = 0.512f;
break;
case GAIN_SIXTEEN:
fsRange = 0.256f;
break;
default:
fsRange = 0.0f;
}
return counts * (fsRange / (32768 >> m_bitShift));
}
So i changed the order of the code to do the multiplication first then the division (better for accurancy)
// Change order of operation to do upscaling before downscaling;
return (fsRange*counts) / (32768 >> m_bitShift);
And now i did'nt get any problem with the calculation.