Non-linear error in ADC readings - Electrical Engineering Stack Exchange most recent 30 from electronics.stackexchange.com 2019-07-18T11:53:33Z https://electronics.stackexchange.com/feeds/question/100733 http://www.creativecommons.org/licenses/by-sa/3.0/rdf https://electronics.stackexchange.com/q/100733 3 Non-linear error in ADC readings FlegmatoidZoid https://electronics.stackexchange.com/users/13966 2014-02-23T19:31:55Z 2014-02-25T14:23:20Z <p>I am measuring voltages up to 20V with my ATmega2650 MCU (10-bit ADC).</p> <p>I'm using 5V precision voltage reference (LT1021 - 0.05%).</p> <p>Voltage dividers are setup with 1% Panasonic resistors.</p> <p>Vcc->10kOhm->Measure->3.3kkOhm->GND.</p> <p>Division ratio: 3.3/13.3=0.248</p> <p>What I've noticed is the following increasing errors while measuring bigger voltages:</p> <pre><code>Vmeas ADC Err(%) 3.05 152 -0.013382929 4.09 205 -0.0075968 5.02 253 -0.002075695 6.08 308 0.003057305 7.07 359 0.0054141 8.07 410 0.00595279 9.07 461 0.00637229 10.02 510 0.007764232 11.05 563 0.008777353 12.05 615 0.01046932 13.05 665 0.008925735 14.05 717 0.010366242 15.06 769 0.010955198 16.05 820 0.011495804 17.07 872 0.011368671 18.06 923 0.011826103 19.04 973 0.011739502 19.51 998 0.01271154 19.94 1020 0.012715509 </code></pre> <p>Can someone explain what is causing such non-linearity?</p> <p>Any hints on math to estimate this (ADC features rather than poly-fit)? Any references to mathematical models would help.</p> <p>EDIT - errors through all voltage range:<br> <img src="https://i.stack.imgur.com/Dwf1U.png" alt="enter image description here"></p> <p>The calculation methodology:</p> <pre><code>#define PSU_ANALOG_CHANNELS 3 #define PSU_ANALOG_MEASURES 5 #define PSU_ANALOG_MEASURE_DELAY 1 //apply vRef to each pin to measure post-divided ADC reading const int psu_adc_corr[PSU_ANALOG_CHANNELS] = {250,251,251}; int psu_volts_raw[PSU_ANALOG_CHANNELS];//stores ADC readings float psu_volts[PSU_ANALOG_CHANNELS] = {0}; //stores final values float mvAdc[PSU_ANALOG_CHANNELS]; //stores mV per each ADC-channel (to avoid division) void calcMvADC(){ for (int i=0; i&lt;PSU_ANALOG_CHANNELS; i++) { mvAdc[i] = 5.0 / psu_adc_corr[i]; } } //returns averaged reading for each ADC channel int readAnalog(int ch) { int val = 0; for (int i=0; i&lt;PSU_ANALOG_MEASURES; i++) { val += analogRead(ch); delay(PSU_ANALOG_MEASURE_DELAY); } return val/PSU_ANALOG_MEASURES; } void readADC() { for (int i=0; i&lt;PSU_ANALOG_CHANNELS; i++) { psu_volts_raw[i]=readAnalog(i); } } /* &gt;6 &lt;=7 : -1.1% &gt;7 &lt;=9: -1.14% &gt;9 &lt;=13: -1.25% &gt;13 -1.7%: */ float corrVoltage(float V) { if (V&lt;6) return V; if (V&gt;6 &amp;&amp; V&lt;=7) return V*0.989; if (V&gt;7 &amp;&amp; V&lt;=9) return V*0.9886; if (V&gt;9 &amp;&amp; V&lt;=13) return V*0.9875; if (V&gt;13) return V*0.983; return V; } void calcVoltages() { for (int i=0; i&lt;PSU_ANALOG_CHANNELS; i++) { psu_volts[i] = psu_volts_raw[i] * mvAdc[i]; psu_volts[i] = corrVoltage(psu_volts[i]); } } void setup (){ analogReference(EXTERNAL); calcMvADC(); Serial.begin(115200); } void loop (){ readADC(); calcVoltages(); for (int i=0; i&lt;PSU_ANALOG_CHANNELS; i++) { Serial.println(psu_volts[i]); } delay(500); } </code></pre> https://electronics.stackexchange.com/questions/100733/-/100734#100734 0 Answer by Spehro Pefhany for Non-linear error in ADC readings Spehro Pefhany https://electronics.stackexchange.com/users/35530 2014-02-23T19:45:46Z 2014-02-23T21:20:30Z <p>I'm not that familiar with the Atmel ADC converter, but I suggest that maybe the acquisition time for the S&amp;H is not long enough. I think it should be 15usec or greater. </p> <p>The maximum time constant is 100K\$\Omega\cdot 14\$pF or 1.4usec, so 10 time constants is about 15usec. </p> <p>Alternately, do you have something like a 5.1V Zener diode on the input? That could easily cause errors in that range. </p> https://electronics.stackexchange.com/questions/100733/-/100741#100741 0 Answer by Andy aka for Non-linear error in ADC readings Andy aka https://electronics.stackexchange.com/users/20218 2014-02-23T20:34:48Z 2014-02-23T20:34:48Z <p>The ADC in the MCU is specified as having an absolute accuracy of up to 2.5 LSbs at a sampling rate of 200kHz. This is specified at aVref and Vcc voltage of 4V but I'm assuming it's going to be very similar at 5V. If your reference is 5V, 2.5 LSbs is about 12mV. This can manifest itself positively or negatively for a particular input voltage.</p> <p>I'm not sure how your values are obtained but at 0.248*7V on an input, 12 mV can be an error of 0.69% which is somewhere in the realm that your are seeing.</p> <p><img src="https://i.stack.imgur.com/wNIyg.jpg" alt="enter image description here"></p> <p>But if you are using a differential ADC channel this can increase to about 18 LSbs at a gain of unity because there is an internal amplifier adding an error.</p> https://electronics.stackexchange.com/questions/100733/-/100760#100760 3 Answer by SomeEE for Non-linear error in ADC readings SomeEE https://electronics.stackexchange.com/users/36603 2014-02-24T01:29:23Z 2014-02-24T01:48:20Z <p>ADCs are naturally non-linear. Roughly the transfer function starts at 0, then increases faster than the expected linear transfer function until it reaches #bits/2 and then curves back to where it should be. I can draw a diagram if this explanation is not clear.</p> <p>The main problem is that you are assuming the converter has the linear transfer function with Voltage = 5V/250*(value from ADC). It does not and the error isn't even linear, as you've already observed. Given the shape of the real transfer function, the data provided by Andy, and the way you are computing the errors at higher voltages the pattern you are seeing is as expected.</p> <p>I don't think you stated, but let me make a conjecture based on this analysis: Your ADC consistently overestimates the voltages. This is because the slope (5V/250) is near the maximal of the slope of the real transfer function. </p> <p>Edited to add: Maybe it was clear from your post they are being overestimated since Err % is always > 1. It is clear if Err%=(ATMega reading)/(real value)</p> <p>2nd edit: Actually, what you can do easily and see how the results change: Put 20V across the voltage divider. You will get a number say $N$ then define psu_adc_corr=N and myAdc = 20/psu_adc_corr=20/N. I would be interested to see what you get.</p> https://electronics.stackexchange.com/questions/100733/-/100907#100907 2 Answer by FlegmatoidZoid for Non-linear error in ADC readings FlegmatoidZoid https://electronics.stackexchange.com/users/13966 2014-02-25T14:23:20Z 2014-02-25T14:23:20Z <p>here's probably <a href="http://www.atmel.com/pt/br/Images/doc2559.pdf" rel="nofollow">the best explanation</a> I've found from the vendor</p> <p>It has a section dedicated to non-linearity with the following conclusion: "<em>Non-linearity cannot be compensated for with simple calculations. Polynomial approximations or table lookups can be used for that purpose.</em>"</p> <p>So I've made int8_t array of 14 ADC error values (that accounts for 1 volt increments). I've applied those corrections on ADC reading and yay! - I do now have the voltage readings with an error of 0 to 1mV.<br/> Furthemore, I can now use single value of mV_per_ADC_step (in respect to my previous version for which I've had dedicated mV value for each ADC channel).</p>