I'm reading the voltage with voltage divider:
schematic
simulate this circuit – Schematic created using CircuitLab | Arduino is connected to both USB and a 9V adapter.
float r1 = 100000;
float r2 = 9980;
float adc, voltage, analog;
void setup() {
Serial.begin(9600);
analogReference(EXTERNAL);
pinMode(A0, INPUT);
}
void loop() {
for (int i = 0; i < 256; ++i) {
analog += analogRead(A0);
}
analog = analog / 256;
adc = analog * 1.228 / 1023;
voltage = adc / (r2 / (r1 + r2));
Serial.print(analogRead(A0));
Serial.print(", ");
Serial.print(analog);
Serial.print(", ");
Serial.print(adc);
Serial.print(", ");
Serial.print(voltage);
Serial.println(" ");
delay(100);
}
Here's the accuracy test result:
Input | Arduino | Difference
1V 0.89V -110mV
2V 1.90V -100mV
3V 2.92V -80mV
4V 3.93V -70mV
5V 4.95V -50mV
6V 5.97V -30mV
7V 6.98V -20mV
8V 8.00 0
9V 9.01 +10mV
10V 10.02 +20mV
11V 11.04 +40mV
12V 12.06 +60mV
The input voltages measured by DMM and was spot on voltage, like 1.000V.
I didn't test voltages above 12V but it seems the difference is gonna increase by 20mV with each 1V increase, that means at 50V voltage reading is gonna be off by ~1V!
Even with 10bit resolution of Arduino I should have had steady accuracy with some percentage of difference(right?), but as you can see the result shows that the reading is not steady at all!
Why the voltage difference decrease/increase when voltage changes at the input?
2 Answers 2
As stated by Majenko, the ADC can in principle have all sorts of errors. However, if you look at your data, you should notice that the error is essentially linear with the voltage. This means that the non-linearity error is quite small, and you are mainly seeing the offset and gain errors. This is fortunate, because these errors are easy to remove, given good calibration data.
The table you wrote in in your question happens to be a perfectly good calibration table. By fitting a straight line to it you can get a calibration function, and then correct the readings simply by adding this to your code:
voltage = 0.9848815 * voltage + 0.125354;
Or you could instead figure out the correction at the ADC level and replace
adc = analog * 1.228 / 1023;
by
adc = (analog + offset) / scale;
where offset
and scale
are computed from the calibration.
Edit: Here is how I extracted the calibration coefficients from the data.
First, I saved the data in a text file calibration.tsv and cleaned it up to remove the units and add a comment marker (#) in front of the column labels:
#Input | Arduino | Difference
1 0.89 -110e-3
2 1.90 -100e-3
...
Then I looked at the data with gnuplot. Since I want to know how to correct the readings, I plot the amount I have to add (minus column 3) v.s. the Arduino reading (column 2):
plot 'calibration.tsv' using 2:(-3ドル)
At this point it appears it's linear with what looks like mostly
quantization noise. I model this as a line of equation a*x+b
, and
compare the line with the data:
a = -1e-2
b = 0.12
plot 'calibration.tsv' using 2:(-3ドル), a*x+b
The line is quite off the data, but it's a reasonable first approximation. Now I ask gnuplot to perform a least squares fit, then take another look:
fit a*x+b 'calibration.tsv' using 2:(-3ドル) via a, b
replot
Now the fit looks quite good. When it completed the fit, gnuplot displayed:
Final set of parameters Asymptotic Standard Error
======================= ==========================
a = -0.0151185 +/- 0.0002953 (1.953%)
b = 0.125354 +/- 0.002173 (1.734%)
so now I know I can correct the data with:
voltage += -0.0151185 * volatage + 0.125354;
which is equivalent to what I wrote above.
-
How do you calculate the offset and scale?ElectronSurf– ElectronSurf2019年10月11日 11:10:34 +00:00Commented Oct 11, 2019 at 11:10
-
1@newbie, put the data in Excel/Calc, draw a chart with expected values and function and then change the offset and scale values for the function until the lines in the chart match2019年10月11日 11:27:08 +00:00Commented Oct 11, 2019 at 11:27
-
1@newbie: I am an old timer who likes text-mode programs rather than Excel, Calc and such, so I used gnuplot. See expanded answer.Edgar Bonet– Edgar Bonet2019年10月11日 12:18:12 +00:00Commented Oct 11, 2019 at 12:18
-
1@newbie, column B should have a function in cells. and the function should use two other cells with the coefficients you want to fine-tune2019年10月11日 12:47:04 +00:00Commented Oct 11, 2019 at 12:47
-
1@newbie, example github.com/jandrassy/Regulator/tree/master/util/Calc2019年10月15日 05:07:52 +00:00Commented Oct 15, 2019 at 5:07
Yes, you are right that the Arduino ADC is not accurate. If you read the datasheet (ATMega328P section 28.9, ADC Characteristics) you can see a lot of "error" and "non-linearity" characteristics.
These all add up to inaccuracies in your readings. For example the "Offset error" at your VREF could be as much as ±4.4mV, and the "Gain error" the same. Non-linearity can be as bad as 2mV, etc.
The Arduino ADC is not meant to be accurate. It's meant to be simple and cheap to implement. (It is a "Successive Approximation ADC" - approximation here is the keyword...) If you want a higher accuracy then there are more suitable ADC chips available that give that accuracy.
-
I was expecting 100mV error to be steady like 1.100V, 2.100V ... Wasted so much time calibrating this ...! beside using external ADC do you think it's good idea to switch to a PIC micro-controller with 12bit ADC. i'm asking this because PIC is cheaper.ElectronSurf– ElectronSurf2019年10月11日 11:07:51 +00:00Commented Oct 11, 2019 at 11:07
-
1I would always say use a PIC over an ATMega, but then I am a PIC junkie- however increased resolution does not equate to increased accuracy. It's still an SAR with the inherent inaccuracies which that gives you. Since the inaccuracy looks to be pretty linear you can use calibration and calculations to remove it. You have a straight line, the formula for which (if you remember school maths classes) is
y = mx + c
Majenko– Majenko2019年10月11日 11:14:08 +00:00Commented Oct 11, 2019 at 11:14 -
Re "successive approximation ADC": any measurement whatsoever is always an approximation. The keyword here is "successive": it means the ADC works by iteratively refining the approximation.Edgar Bonet– Edgar Bonet2019年10月11日 12:40:19 +00:00Commented Oct 11, 2019 at 12:40
-
@EdgarBonet And because the sampled voltage is stored in a tiny capacitor, and it's impossible to read a voltage without drawing some current, each successive comparison will affect the voltage across that capacitor making it less accurate with each bit that is approximated. So it's successively worse approximation. It's a successive approximation that can only ever be approximate.Majenko– Majenko2019年10月11日 12:45:23 +00:00Commented Oct 11, 2019 at 12:45