Mr RB
Well-Known Member
It's common to need to scale a microcontroller ADC result to give a value in some other scale. One example is to scale the ADC to read in actual volts like read from 0.00v -> 5.00v.
People sometimes use ADC *500 /1023 as this gives a reading of 500 (5.00v) for the top ADC value of 1023.
Doing that math; *x/(n-1) or *x/1023 does perform a kind of rounding function, but it "fudges" the rounding and gives both scaling and rounding errors.
The correct scaling math; *x/n or *x/1024 correctly scales all the output data in size, but gives an average rounding error of 0.5 ADC counts (always rounding down).
To magnify and show the errors caused by *x/(n-1) this table shows a simple ADC that has 5 values. (This is just like a PIC ADC but has 5 possible ADC values, not 1024).
Note that for the 5 possible ADC values, the output scale now has 6 values (0-5) and the value 4 can never occur! And although the average error might look to be nicely distributed +/- the centre of scale, the actual output result proves to be much uglier.
So if you had a slowly increasing voltage, the ADC would read; 0, 1, 2, 3, 5!!
The maximum error in real world use is 2v, because that very tiny change of 3.999v - 4.001v would cause an output change of 3v -> 5v or a change of 2v!
All output values are properly scaled and all are represented. The average error is never greater than 0.5 (no more average error than the /(n-1) example), and the average error is always one fixed value (-0.5) making it very easy to compensate (see below).
The maximum error at any time is 1v, this is half the max error of the /(n-1) example, which can introduce extra error up to 1 in high value ADC readings.
Understanding the *x/(n-1) problem.
The problem with /(n-1) is that it corrupts the SCALING of data. Because it forces the top ADC unit value to be the top of the scale the scale no longer is an accurate conversion of data.
**broken link removed**
This corruption means the true scale of 1024:5 is being represented as 1023:5 so the data on the output is now larger than life;
**broken link removed**
However if the correct scaling is used; ADC*5/1024, then any input data is correctly represented at the output;
**broken link removed**
All data is rounded down to the nearest ADC unit, so all the output data is correctly scaled but will have an average error of -0.5 ADC units.
This error is actually a property of the ADC module hardware AND the ratio scaling math. This is because the ADC hardware rounds all voltages down to the nearest ADC unit, and because the integer division (/1024) also rounds data down. (More on compensating for this later).
People sometimes use ADC *500 /1023 as this gives a reading of 500 (5.00v) for the top ADC value of 1023.
Doing that math; *x/(n-1) or *x/1023 does perform a kind of rounding function, but it "fudges" the rounding and gives both scaling and rounding errors.
The correct scaling math; *x/n or *x/1024 correctly scales all the output data in size, but gives an average rounding error of 0.5 ADC counts (always rounding down).
To magnify and show the errors caused by *x/(n-1) this table shows a simple ADC that has 5 values. (This is just like a PIC ADC but has 5 possible ADC values, not 1024).
Code:
[b]First the incorrect *x/(n-1) math;[/b]
input ADC math result average output
voltage value ADC*x/(n-1) error result
4.00-4.99 4 *5 /4 5.00 +0.50 5
3.00-3.99 3 *5 /4 3.75 +0.25 3
2.00-2.99 2 *5 /4 2.50 0.00 2
1.00-1.99 1 *5 /4 1.25 -0.25 1
0.00-0.99 0 *5 /4 0.00 -0.50 0
Note that for the 5 possible ADC values, the output scale now has 6 values (0-5) and the value 4 can never occur! And although the average error might look to be nicely distributed +/- the centre of scale, the actual output result proves to be much uglier.
So if you had a slowly increasing voltage, the ADC would read; 0, 1, 2, 3, 5!!
The maximum error in real world use is 2v, because that very tiny change of 3.999v - 4.001v would cause an output change of 3v -> 5v or a change of 2v!
Code:
[b]Here is the correct scaling math *x/n;[/b]
input ADC math result average output
voltage value ADC*x/n error result
4.00-4.99 4 *5 /5 4.00 -0.50 4
3.00-3.99 3 *5 /5 3.00 -0.50 3
2.00-2.99 2 *5 /5 2.00 -0.50 2
1.00-1.99 1 *5 /5 1.00 -0.50 1
0.00-0.99 0 *5 /5 0.00 -0.50 0
All output values are properly scaled and all are represented. The average error is never greater than 0.5 (no more average error than the /(n-1) example), and the average error is always one fixed value (-0.5) making it very easy to compensate (see below).
The maximum error at any time is 1v, this is half the max error of the /(n-1) example, which can introduce extra error up to 1 in high value ADC readings.
Understanding the *x/(n-1) problem.
The problem with /(n-1) is that it corrupts the SCALING of data. Because it forces the top ADC unit value to be the top of the scale the scale no longer is an accurate conversion of data.
**broken link removed**
This corruption means the true scale of 1024:5 is being represented as 1023:5 so the data on the output is now larger than life;
**broken link removed**
However if the correct scaling is used; ADC*5/1024, then any input data is correctly represented at the output;
**broken link removed**
All data is rounded down to the nearest ADC unit, so all the output data is correctly scaled but will have an average error of -0.5 ADC units.
This error is actually a property of the ADC module hardware AND the ratio scaling math. This is because the ADC hardware rounds all voltages down to the nearest ADC unit, and because the integer division (/1024) also rounds data down. (More on compensating for this later).