Maths question about ADC result - Page 1
Forum section: electronics / beginners

author: odessa
author_rank: Regular Contributor
timestamp: October 15, 2017, 11:03:38 am
content: Hi,I have a voltage divider on my Geiger Counter project that sits across my 400v supply.I have R1 set 10m and R2 set 50k which should give me approx 2v at 400v .... which it does.My ADC is ref to 5.0v and the result is approx 420 which is correct for a 2v reading.I'm not that great at maths ... so can someone tell me how to convert the ADC result to reflect the actual voltage at the tube please

author: 0xdeadbeef
author_rank: Super Contributor
timestamp: October 15, 2017, 11:19:31 am
content: What is the resolution (i.e. number of bits) of your ADC? If 420 is the raw value for 2V and 5V is the reference voltage, the raw value for 5V would be 1050 which is somewhat strange.I.e. for a 10bit converter it should be 1023 ( (1<<10) -1).Anyway, the conversion is like that:v = adc_raw * V_MAX / ADC_RAW_MAXNote that in integer calculations, it's better to multiplicate before you divide, but you need to check for overflows of course.So if your the maximum voltage is 1005V (5V*(50e3+10e6)/50e3) and the ADC is 10 bit, it would look like this:v = adc_raw * 1005 / 1023So a raw value of 420 would result in 412.61V.If you controller doesn't support HW division, using "x >> 10" instead of "x / 1023" is usually a good enough approximation.Also note that you might want to use a higher resolution internally which of course changes the conversion formula.As a side note: to avoid overflow it sometimes makes sense to simplify the fraction. E.g. "1005/1023" can be also expressed as "335/341" if both sides of the fraction are divided by the greatest common divisor (gdc) which is 3 in this case. Many years ago, as I made these kind of conversions on a regular basis, I wrote my owncalculator based on fractionswhere you can simply type "fraction(x)" to display the simplified fraction of each value you calculated before.

author: Ian.M
author_rank: Super Contributor
timestamp: October 15, 2017, 11:28:35 am
content: You should never use '/1023'. Seeelectro-tech-online.com: Why ADC/1024 is correct, and ADC/1023 is just plain wrong!

author: 0xdeadbeef
author_rank: Super Contributor
timestamp: October 15, 2017, 11:41:26 am
content: Nah, "/1023" is mathematically correct and to avoid the described effect with integer calculation, it's better to round than to use a wrong divisor.Common trick is to add half of the divider before dividing which is 100% correct only if the divisor is even but usually still a good enough approximation if odd.Or, well you can multiply both sides of the fraction by two. E.g. in the given example:v = (adc_raw * 670 +341)/682gives 413 just as the correct termv = round((adc_raw* 670)/682)would...

author: Kleinstein
author_rank: Super Contributor
timestamp: October 15, 2017, 12:07:10 pm
content: /1023 usually not correct. The ADCs usually specify a LSB step size of U_ref / 2^N. A reading of 0 would stand for a value inside the lowest interval. How the extreme values are treated exactly often does not matter, as the accuracy is rarely better than 0.5 LSB.It gets more obvious if you imagine a 2 Bits ADC. Here 0 usually stands for an input of 0-0.25 and a result of 3 stands for an inputvalue of 0.75 to 1. In theory one could have 0 and 3 to stand for ranges centered around 0 and 1, but this would be unusual. So conversion to the approximate value would be analog = digital / 4 + 1/8.In the usual program there will be no divide by 1024 (or the wrong 1023) anyway, but a multiplication with a constant. This constant than could also include the exact value of the reference, external amplification and similar.

author: radiogeek381
author_rank: Regular Contributor
timestamp: October 15, 2017, 12:17:29 pm
content: Quote from: 0xdeadbeef on October 15, 2017, 11:41:26 amWhen we talk about integer math approximations to the floating point (finite precision) approximations to the measured approximation to the actual value in the real world, we have to be careful. Even if all the other stuff is perfect, diiscrete arithmetic like this has lots of traps and tradeoffs.So, if you are using integer dividers, reducing X/1024 to some other canonical form A/B where the denominator is less than 1024 is just a bad idea. If you run over the range of possible values, you'll find that the max error is larger. (Because the max error is proportional to 1/B and since B < 1024, you've now made the error larger. I won't even address the average error.)The link posed earlier was compelling, well reasoned, and bang-on correct.Even if there was some advantage in divide by 1023, the cost in many integer units (especially in the simpler microcontrollers) is proportional to log2(1023) or 10 steps, where a step will involve 2 to 5 instructions with sequential dependencies (they can't be overlapped much). Yes there is SRT division, but it is rarely seen on microcontrollers, and it is still O(log2(N)). There is little magic in arithmetic.Compare this O(log2(N)) cost to the cost of a divide by a power of 2. This is a single trip through the shifter. It can even deal with the minus sign.In any case, it doesn't pay to obsess over +/- 1 bit of accuracy here. The measurements are not likely all that reproducible, and if you really cared about the measurement, you'd be averaging many readings with, perhaps, a dithered input offset and doing the math with much larger divisors.

author: odessa
author_rank: Regular Contributor
timestamp: October 15, 2017, 12:25:14 pm
content: Thanks guys,Yes its 10 bit resolution, but my figure wasn't exact.I get it now, cheers for the help

author: 0xdeadbeef
author_rank: Super Contributor
timestamp: October 15, 2017, 12:33:14 pm
content: We discussed this topic a million times at work and as I originally stated, using shift is usually a good enough approximation.There's not much value though to claim that using the approximation is better than using correct maths or arguing about other inaccuracies.It's simply that the maximum value of any common ADC is reached when you connect its reference voltage to it.Usually this doesn't really matter as the last few bits of any ADC toggle anyway, but when using the divisor in more complex terms to convert the result to other units etc., using the wrong divisor results in inaccuracies.

author: rs20
author_rank: Super Contributor
timestamp: October 15, 2017, 01:07:51 pm
content: Quote from: 0xdeadbeef on October 15, 2017, 12:33:14 pmBut x/1023 ISN'T EVEN CORRECT MATHS! x/1024 is far more correct; with x/1024 + 1/2048 being "even better". An ADC reading of 0 means "between 0 and 1/1024", an ADC reading of 1023 means "between 1023/1024 and 1024/1024". So regardless of whether you choose to represent those ranges as their low point (x/1024), their midpoint (x/1024+1/2048), or their high point (x/1024+1/1024), the divider is always /1024. Using x/1023 is just applying a totally fake 1024/1023 gain to your signal causing your signal to be artificially rounded down for low values yet artificially rounded up for large values.If your aim is to have your widget be able to output values from 0.000V to 5.000V instead of outputting, then you should be questioning your use of an ADC which output a code of 0 for voltages from 0.000V to 0.005V, yet starts outputting a code of 1023 starting from 4.995V and thus is ACTUALLY INCAPABLE of distinguishing any value from 4.995V to 4.999V (the true meaning of code 1023) and is ACTUALLY OVERFLOWING for any value a hair beyond 5.000V. Sweeping this design mistake under the rug by dividing by 1023 is a complete forgery. (Unless, of course, you're using some exotic ADC whichactuallyhas an LSB of Vref/1023, which certainly isn't going to be any standard SAR converter and I have no idea why they'd bother going out of their way to be different).

author: rs20
author_rank: Super Contributor
timestamp: October 15, 2017, 01:57:45 pm
content: Anyway, silly side debates aside... back to the OP.Odessa, most ADC datasheets will state an "LSB" or "LSB size". This is short for "Least Significant Bit", and it literally refers to how much of a voltage jump is required to hop from one ADC code to the next. So to convert from ADC code to a voltage, you basically just multiply the ADC code by the LSB voltage. In extremely specific circumstances, you might want to add little adjustments (for example, if you wanted to get the highest possible input voltage that could produce that ADC output code rather than the smallest possible input voltage), but for general use this is completely unnecessary and pointless since noise will swamp such small adjustments anyway.As a rule of thumb, the LSB will almost always be (Vref or Vsupply) / (2 ^ NumberOfBits).AsverifiedusingfiveactualdatasheetstakenfromDigikey.So in summary:InputVoltage = AdcCode * LSB = AdcCode * (Vref or Vsupply) / (2 ^ NumberOfBits)That's all well and good in pure maths terms; of course getting good results with integer arithmetic in C is a whole other can of worms. But just wanted to point out how conceptually simple this actually is; in summary, the number you need to multiply by is literally given to you in the datasheet -- the trick, as always, is just knowing the magic name you're searching for: "LSB".

author: odessa
author_rank: Regular Contributor
timestamp: October 15, 2017, 03:38:12 pm
content: Hi,I know how to convert my raw ADC reading into volts.The reading I have is 442 raw, my vref is 4.99vso 4.99 / 1023 = 0.00487442 x .00487 = 2.165v ... which is exactly what my meter reads on my A/D pin.What I'm still struggling with is how to convert these readings into the actual HV at the tube.Thing is, there is a 10m resistor before the tube, its 387v before the 10m and across the tube itself it reads exactly 200 volts. This is due to my meter acting as a divider.

author: 0xdeadbeef
author_rank: Super Contributor
timestamp: October 15, 2017, 03:42:42 pm
content: I think I answered all that in my original answer. Note that I used V_MAX and calculated it as 1005V with your voltage divider and the 5V reference voltage.So just replace 5V with 1005V and there you go.I actually even gave you the correct formula with rounding some posts before:v = (adc_raw * 670 +341)/682

author: odessa
author_rank: Regular Contributor
timestamp: October 15, 2017, 03:52:28 pm
content: Sorry, I re read your post and understand it nowThanks very much for your help ... and patience

author: StillTrying
author_rank: Super Contributor
timestamp: October 15, 2017, 05:09:54 pm
content: I bet you're sorry you asked now!I think of it as the 10M/50k potential divider multiplying your 4.99V Ref up to (4.99V X 201) = 1003VADCresult(442) / ADCFullScaleCount(1024) * FullScaleVolts(1003) = 432.9VIn interger math:ADCresult(442)* 1003+ 512 (rounding up)/ 1024= 433 V

author: odessa
author_rank: Regular Contributor
timestamp: October 15, 2017, 05:42:19 pm
content: Ha,Not at all, just wished I had payed more attention at schoolThanks for the help

author: 0xdeadbeef
author_rank: Super Contributor
timestamp: October 15, 2017, 07:12:55 pm
content: Well, I don't want to get into a religious discussion, but I have to comment one last time about that "/1024 is better than "/1023" or "Vref is not the maximum value" ideas before I leave this discussion for good.In all the ADC designs I know, the maximum ADC value (not the number of states) represents the reference voltage and if the maximum value is not reached 0.5 LSB before the reference voltage, this is considered a gain error. Which can happen of course but doesn't change the definition.So from a mathematical point of view, this is simply rule of three, so you have to divide by the maximum raw value and multiply by the physical value this internal maximum represents.To put it in other words: if you define 5V as 100%, then the rule to convert Volt to Percent (letting aside rounding) isx_pct = x_volt / 5 * 100If you'd define both voltage and percentage as integer, than the voltage would have 6 states and the percentage would have 101 states including the 0.So while the 0 is a different state, adding it to the value just doesn't make any sense. The formula is correct no matter which resolutions the voltage or percentage has.So why should the rules of mathematics suddenly be different for ADC value conversions?I agree though that even the manuals, datasheets and application notes of major HW vendors seem to struggle with the concept of N states with a maximum value of N-1.E.g. they define that Vref equals the maximum ADC value N-1 (e.g. 1023 or 4095) in one sentence but still define the resolution as Vref/N which would obviously result in a maximum value of Vref*(N-1)/N.This discrepancy usually gets lost in other (rounding, offset, conversion) errors but IMHO it's still inconsistent and plain wrong.It's actually very simple: if you have only 1023 steps to reach Vref above step 0 (which is 0V), then the magnitude of one step (and therefore the resolution) is Vref/1023 and not Vref/1024.Anyway, I'm aware lots of people will stick to that idea and either ignore its inconsistency or claim that the reference voltage can't be measured. At least the latter opinion is somewhat consistent.So OK, I made my point and step out here before it gets personal.

author: KL27x
author_rank: Super Contributor
timestamp: October 15, 2017, 09:33:45 pm
content: QuoteSeems to me you're treating ADC reading of 0 as a special case which means 0.0000000000000000000000000000000000000000000V. (Or treating 1023 as special case which means exactly Vref.) Maybe this is how ADC's are made, but I wouldn't think this is the case. Unless datasheet is explicit, I would think 0 (or 1023) has the same meaning as all the other values; that these value cover the same spread/resolution as all the other values between 0 and 1023. I would imagine there are 1024 values/steps, 0-1023. If you want to call is 1-1024, that is fine, too.Take example of 1 bit ADC. And ADC reading of 0 means something between 0-2.499999999V. Reading of 1 means 2.500000-V.Now take Vref/N-1. You end up with a single step of 5V resolution. This is not very correct, IMO.Vref/N gives you 2 steps of 2.5V, which is correcter, IMO.Each "step" is not a mark on a ruler. It's the space between 2 marks. And there are 1024 of these spaces. Which means there are 1025 marks in a 10 bit ADC, if you want to extrapolate the ruler. Take 1 bit example, you have 3 marks on a imaginary ruler at 0, 2.5, and 5.0. But there is no way to denote those. You get 2 readings which denote the area between those 3 marks.Again, maybe I'm wrong and ADC are manufactured with special meaning to either 0 or to the max value. So 10 bit ADC actually has resolution of 1023 steps. Maybe there is some practical reason this would be the case.

author: Rick Law
author_rank: Super Contributor
timestamp: October 15, 2017, 09:46:58 pm
content: Quote from: KL27x on October 15, 2017, 09:33:45 pmI agree with you here - denominator wise. But I disagree with your conclusion of 2.5V being the correct result:Following your 1-bit ADC, a 1 would really mean not 2.5V but 2.5V to 5V. So, one should really interpret it as the mid point:(2.5V+5V)/2 = 3.75VAnd in the 1/2 bit uncertainty and with each bit being 2.5V, the result would be 3.75V +- 1.25V.

author: KL27x
author_rank: Super Contributor
timestamp: October 15, 2017, 09:50:40 pm
content: ^Yeah, thanks. I didn't get that far, lol. I just meant 2.5V spread/resolution for each step. Yeah, you would want to take the middle value as the average.I wonder if 0xdeadbeef knows something about how ADC are made. It sounds like he feels like either max value or 0 is a special case for some/all manufacturers. E.g, a 1 bit ADC made the same way might turn out to mean that1. 0 indicates a voltage of 0V or lower, and 1 means a value between 0 and Vref.or2. 0 means a value between 0V and Vref, and 1 indicates voltage of at least Vref or greater.QuoteIm not positive I am reading this correctly, but maybe he is suggesting that scenario #2 is how ADC are made. I'm not sure what LSB stands for. I would think least significant bit, but he is applying it to the voltage, not the reading. And 0.5 x least significant bit doesn't mean anything to me.

author: rs20
author_rank: Super Contributor
timestamp: October 15, 2017, 10:15:26 pm
content: Quote from: Rick Law on October 15, 2017, 09:46:58 pmCorrect, except of course you have to make a choice on how to represent that range as a single number;-- You could choose the midpoint, in which case the answer would be 3.75V and that corresponds to a formula for the OP of x/1024+1/2048.-- You could choose the lowpoint, in which case the answer would be 2.5V and that corresponds to a formula for the OP of x/1024.-- You could choose the highpoint, in which case the answer would be 5V and that corresponds to a formula for the OP of x/1024+1/1024.None of these are really intrinsically right or wrong; they're all just slightly different offsets. They all become correct as long as you add comments to your variables accordingly!None of them have gain error, like x/1023 does.Quote from: KL27x on October 15, 2017, 09:50:40 pmNo, he's just putting all his stock in the vague sentences in the datasheet like "the valid input range is from VSS to VDD" and for some bizarre reason, holding that information in higher regard than the authoritative transfer characteristic graphs or tables in the very same datasheets (same ones that I linked before):If he has evidence that disproves the datasheets and crystal clear explanations that ADC codes represent ranges and not points, he should probably present that evidence rather than repeating the "the max value of an ADC happens at Vref" line, which is totally rejected by the stuff above.Bonus fun activity: find the graph above which has a fairly obvious error!

author: KL27x
author_rank: Super Contributor
timestamp: October 15, 2017, 10:40:56 pm
content: Well, the graph really is very explicit, particularly the one right at the bottom. That one rings with clarity.And now I see what an LSB is. It's the Vref divided by 256, which I assume the 256 for an 8 bit ADC. (Not /255, notice, lol).So going back to his postQuotePerhaps he is not reading this the way I am, now. I would expect max value to be reached ideally at exactly at 1.0 LSB under Vref.* So it makes sense that 0.5 LSB below Vref is late, and any later would be considered a gain error. I would think if it reached max value more than 1.5 LSB below Vref, that this would also be considered out of calibration. And this jives with 1024 steps to me.But maybe he said it differently than he knows it.*edit: holy crap, it's even written right on the graph and highlighted in green for me. "Vdd-1LSB" on the voltage axis.**edit:If one were to infer from the quote that the transition to max value 0x3FF must occur within +- 0.5LSB of Vref (exactly Vref, on average) then he would be correct. There would technically be 1023 steps between 0 and Vref. But a smart engineer would see that this scale of reference simply clips off 0x3FF, relegating it to an "11" on a scale of 0-10; he would simply add 1LSB to Vref and use all 1024 steps. The "true Vref" would be ("arbitrary Vref" + "arbitrary Vref/1023).

author: Brumby
author_rank: Unknown
timestamp: October 15, 2017, 11:29:36 pm
content: Quote from: rs20 on October 15, 2017, 10:15:26 pmI always thought it was obvious........ unless someone is getting confused with a time axis.

author: KL27x
author_rank: Super Contributor
timestamp: October 16, 2017, 01:29:54 am
content: A side question that I ask myself, now, due to oxdeadbeef quote about max value is:Is max reading assumed to be the most variable step (in describing it's range), depending on how the ADC is tuned? That it is 1LSB plus or minus half an LSB in range? So that it not only affects the tuning of all the other steps by a frog hair, but that it, itself, may cover abnormal range of up to 50% of LSB? But that step 0 is always fairly accurate, in line with all the other intermediary steps?I have always viewed either extreme as potentially "sketchy," whenever that Vref is within 0.3V of a supply rail, in particular. But now I wonder if there's a more accurate and practical way to view it, in general.

author: rs20
author_rank: Super Contributor
timestamp: October 16, 2017, 03:50:02 am
content: Quote from: KL27x on October 16, 2017, 01:29:54 amI can't really tell what question you're actually asking here, so I'm only partially sure that the following will start to answer your questions:Theidealperformance of these ADCs is given in the graphs. If you put a voltage of X in, what code Y does the ADC produce? Well, just input your voltage X on the x axis, and read off the ADC code on the y axis. End of story. No hint of different readings being "variable" or "affecting each other" or being "sketchy".As with any component, the performance ofreal worldADCs differs from the ideal transfer characteristic. This difference is specified in the datasheet, using the DNL (explanation) and INL (explanation) specifications. There's absolutely no value in trying to guess that the INL might be greater at the extremes of the input range rather than the lower end; just check the datasheet for the actual ADC you're using -- it varies massively based on the architecture of the ADC (one classic example is major code transitions like 0111111111 -> 1000000000 which can really trip up otherwise excellent converters).

author: Rick Law
author_rank: Super Contributor
timestamp: October 17, 2017, 01:20:23 am
content: Odessa, sound like you are a novice and so am I. Let me share some novice's thought with you.I thought about this a lot when I was learning the ADC. Then, I finally realized that for the 10 bit ADC, 1024 vs 1023 as the denominator really doesn't make much difference in the end. 1023 vs 1024 is ~0.1% difference. Most of my other stuff feeding into the ADC are at best 1% parts. Worrying about 0.1% with the denominator doesn't make much sense - I went with 1024 for easy division.I mostly use ADC with my ATMega/Arduino. Mybigger headache with the ADC reading is the power source- it makes a hell of a lot bigger difference than 1%. Beside load variation, I have the USB supplying anywhere between 4.7V to 5.2V depending on which machine/port I plug it into. Beside, when USB powered, the "source selector" diode alone ensured that you don't get 5V at the MCU except cases of extreme good luck.After a while of learning, for situations where I like to have good ADC accuracy, I do the ADC and the math entirely differently: 1% TL431 is cheap. I use a dedicated TL431connected only to ADC0to give me 2.5V at ADC0, I use the other ADC to measure my target. All ADC reads begin with reading ADC0 first then the target ADC.My math for the other ADC becomes: Voltage = 2.5V * ADCnReading / ADC0Reading.For example:if ADC0 (the TL431 at 2.5V) reads 500, and ADC1 reads 600, that means ADC 1 is reading (2.5V*600/500)With that implementation, I can switch NANO/UNO power source and/or varies the loads powered by the Arduino all the while hardly affecting the ADC reading.You may ask,why not feed the TL431's 2.5V into the ADC's vrefdirectly. Feeding the TL431 into Vref mean that my ADC goes up to 2.5V only. Everything on my Arduino-powered circuit will need a voltage divider for measurement if they are >2.5V. Whereas, feeding it into ADC0 this way, everything else I need to measure can go to board's +5V (or whatever it actually is, be it 4.5V or 5.4V, I am still having a good time).Of course, most of the folks here being pros, that is probably merely an obvious solution. Me being a mere hobbyist and a novice, I was actually rather pleased with myself figuring out that solution and made that work.

author: Ian.M
author_rank: Super Contributor
timestamp: October 17, 2017, 01:52:02 am
content: While that works, it doesn't help with short-period variations of the VCC rail, which can degrade accuracy, and it halves the maximum sample rate, assuming you read ADC0 before every reading. Consider using a 4.096V reference - it gives you a decent ADC input voltage range, and 4mV per ADC count for easy maths, but remember the Atmega's AREF input also outputs its internal reference, so a 1K resistor between the reference and the pin + 0.1uF decoupling rght at the pin is strongly advises to prevent disasters if you misconfigure the ADMUX REFS bits.

author: Rick Law
author_rank: Super Contributor
timestamp: October 17, 2017, 07:37:22 pm
content: Quote from: Ian.M on October 17, 2017, 01:52:02 amre: "Consider using a 4.096V reference"I thought about that one for a while. Since my stuff is hobbyist stuff, I rework the board a lot. Adding a voltage divider to a populated board is not always easy. So I wanted an implementation that is safe to solder to anywhere on the board without having to rework an entire area to add a voltage divider. Well, of course, safe but excluding the external Vin which is known to be > board's "may be +5V".re: "...short-period variations of the VCC rail, which can degrade accuracy, and it halves the maximum sample rate..."Yeah, that bugs me but something has to give. When I really really wants best quality I can achieve, I would go over to my 16bit ADS1115 which incidentally uses an internal 4.096V reference.