analogRead - divide by 1023 or 1024?

You know, I was awake at 2 a.m. this morning thinking about this. First I thought "of course you divide by 1023, that way 1023 comes out at 5V". Then I thought "of course you divide by 1024 because there are 1024 steps".

Then I thought, "if I have $10 in my pocket, half of that is $5, right?" But then I thought, but there are 11 amounts of currency I can have, $0, $1, $2 ... $9, $10. So therefore half of that is 0.5 * 10 / 11, so half of $10 is $4.50". But that's nonsense too!

Then I thought, "maybe you add 1, divide by 1024, and then subtract 1 to compensate". That way 1023 works out. "1023 + 1 = 1024, half of that is 512, subtract 1 again, and we have 511, perfect!". But then I thought of a zero reading. So let's see, you take zero, add 1, divide by 1024, then subtract 1. That's -0.99V! That can't be right!

Hi, Nick they have places for people like you who wake up at 2.00am, thinking about numbers, its called a University.

Tom.... :)

Whether its right or wrong, Im sticking to 1023

It's not merely wrong, it's slow and wrong ;D

I removed my post, I made a mistake, dangit, somebody saw it!

Just food for thought, I just was thinking this could be an answer.

1 unit of measure may be considered k to k.999... where k is an integer. The arduino just cannot measure the .xxx part and it comes out to k.

In the case of arduino, k can be 0-1023. Thus It covers (essentially) all values 0 to 1023.999... which would explain dividing by 1024, thats the range it covers (or rather divide by 1023.999...... which would be impossible).

Although, this is just 2 minutes of thinking, so take from it what you will...

Ps991:
I removed my post, I made a mistake, dangit, somebody saw it!

I can pull it back out of the bin if you like :sunglasses:

So further thinking about this for 2 hours at 3:30am I still think my answer has some grounds to it.

As you can see we are thinking the arduino can only measure in 0 to 1023, however, that would be [0,1023] which is to say 1023 units of measure + 1023.0, NOT 1024 units...

The arduino can (for simplicity's sake) measure [0,1024), note 1024 is not included. It is simply the case that accuracy is limited to integers and our results are [0,1023]. So the arduino's error can be anywhere between [0,1), note 1 is not included.

Now if we take this theory to be correct then if we measure 4.999...V (in this theory you can only measure [0,5V) never exactly 5V+), then the result would be the maximum error and the result would be 4.995V .

So what should I divide by? Well I have 2 answers. 1)You should divide by 1023.999....... 2)You would divide by 1024 to round down the error and divide by 1023 to round up the error, or just divide by 1023.5 to average the error.

Now lets take Nick Gammon's money example using answer 1. I have $10, but something is wrong with me and I am unable to count my change. Then I would have 10/10.999... my maximum amount. See the thing is, I very well could have $0.99 in change and in which case I would have 10.99/10.999... which isn't exactly what I would expect. But If a new coin came out worth $0.001, this theory prevents you have having more than 100% of what you are allowed to have.

To me, it seems that you have to decide how you like your error, high/low/middle. Simple fact of the matter is...you can include 0 or you can include 1024 but not both...

Any thoughts?

I believe you made several mistakes but I'm going to pick on just this one...

...in this theory you can only measure [0,5V)...

I'll give you some time to figure out what's wrong with that assertion.

I'm sticking with the datasheet's 1023 = Vref - 1 lsb, and therefore 1024 = Vref. I am willing to concede that from the results of tests shown in previous posts and the quantisation argument, that it should have the disclaimer "or there-abouts" appended.

There are 1024 "bins". The first bin is called "0". The last bin is called "1023". 1/1024 of the input voltage range is in the first bin, 1/1024 is in the second bin, ... and so on.

With a Vref of 5V, the voltage range is [0,5V). The first bin holds all input values in the interval [0,0.0048828125), the second bin holds all input values in the interval [0.0048828125,0.009765625), and so on up to the last bin, which holds all input values in the interval [4.9951171875,5).

With a Vref of 4.096V, the numbers are rounder. The first bin holds [0,0.004), the second holds [0.004,0.008), and the last holds [4.092,4.096).

There's a number of techniques to convert a bin number back to the measured value, depending on what you want to do with it. The simplest is to multiply the bin number by Vref/1024, which gives the lower endpoint of the bin's interval; this is an underestimate of the input (the input may be up to less than 1 LSb higher). Another simple method is to add 0.5 to the bin number and then multiply by Vref/1024, which gives the bin's midpoint; this gives the average of all possible values that can fall in a bin (the input may be 0.5LSb higher or lower than the computed value).

Yes, I think we have concluded that already. With the note that a feedback system can go wrong because the value will never be zero if 0.5 is added.

If 5.000 volts on an analog input gives a reading of 1023 and 4.995 volts (or close to it) causes the reading to change to 1022, then I prefer to use 1023 as the divisor. Why create an extra count reading error in calculations? 1024 as divisor would essentially attenuate 1 count off the top.

float volts;

void setup() {
  Serial.begin(115200);
  volts = (1023 / 1023.0) * 5;
  Serial.print("(1023 / 1023) * 5 = ");
  Serial.println(volts, 6);
  volts = (1023 / 1024.0) * 5;
  Serial.print("(1023 / 1024) * 5 = ");
  Serial.println(volts, 6);
  Serial.println();
  volts = (1022 / 1023.0) * 5;
  Serial.print("(1022 / 1023) * 5 = ");
  Serial.println(volts, 6);
  volts = (1022 / 1024.0) * 5;
  Serial.print("(1022 / 1024) * 5 = ");
  Serial.println(volts, 6);
  Serial.println();
  volts = (1 / 1023.0) * 5;
  Serial.print("   (1 / 1023) * 5 = ");
  Serial.println(volts, 6);
  volts = (1 / 1024.0) * 5;
  Serial.print("   (1 / 1024) * 5 = ");
  Serial.println(volts, 6);
}

void loop() {
}

[quote author=Coding Badly link=msg=2110581 date=1424818687] I believe you made several mistakes but I'm going to pick on just this one...

I'll give you some time to figure out what's wrong with that assertion.

[/quote] I see nothing wrong with that assertion, reply #28 even agrees with me. Maybe you might want to elaborate a little?

@dlloyd 4.995-4.999...V is the 1024th bin (represented by 1023), the thing is both answers are right, you can round up the error (divide by 1023) or round down the error (divide by 1024), or another option is to average the error (divide by 1023.5)...

dlloyd:
If 5.000 volts on an analog input gives a reading of 1023 and 4.995 volts (or close to it) causes the reading to change to 1022, then I prefer to use 1023 as the divisor. Why create an extra count reading error in calculations?

It’s always gratifying if you can tweak the code and have 5V on the input come out as 5V in your calculation, and not have those annoying discrepancies. However …

As that guy points out, dividing by 1023 just gives a (slightly) wrong value for almost every point. So you’ve solved the 1023/1023 problem, but introduced an error everywhere else.

This certainly may not matter, and one presumes the error would be in the order of 1/1023 (or is it 1/1024?*) which is about a tenth of one percent.

* little joke there

Actually I can't quite get my head around this in the datasheet:

0x000 represents analog ground, and 0x3FF represents the selected reference voltage minus one LSB.

Are they saying 0x3FF represents 0x400? Or it represents one LSB less of the reference voltage? Presuming they mean that, then they are saying that the ADC conversion will never return a value corresponding to the reference voltage. So trying to assume that 0x3FF represents the reference voltage is now introducing an error.

[quote author=Nick Gammon link=msg=2110859 date=1424844254] Actually I can't quite get my head around this in the datasheet:

Are they saying 0x3FF represents 0x400? Or it represents one LSB less of the reference voltage? Presuming they mean that, then they are saying that the ADC conversion will never return a value corresponding to the reference voltage. So trying to assume that 0x3FF represents the reference voltage is now introducing an error. [/quote]

Spot on!

...in this theory you can only measure [0,5V)...

Is a continuous range. AVR analog-to-digital converters do not see the world as continuous. The remainder of your argument relies on the incorrect assertion they do.

@christop correctly states the converter sees the world as discontinuous ("bins").

Ps991: you can round up the error (divide by 1023) or round down the error (divide by 1024), or another option is to average the error (divide by 1023.5)...

F in math. This is how to round... https://www.google.com/search?q=how+do+i+round+numbers

What you are proposing is called something else.

[quote author=Coding Badly date=1424845078 link=msg=2110873] Is a continuous range. AVR analog-to-digital converters do not see the world as continuous. The remainder of your argument relies on the incorrect assertion they do.

@christop correctly states the converter sees the world as discontinuous ("bins").

[/quote] The theory does not apply JUST to AVRs, the theory applies to all measurements. I was simply saying you MAY measure [0,5)V BUT because the AVR rounds down, there is an error, and that error is anywhere between [0,1). 1023 does not represent 5V, it represent 4.995V because rounding down gives an error.

The theory accounts for continuous and applies to discontinuous...

@CodingBadly 1023 / (1023 / 5) = 5 1023 / (1023.5 / 5) = 4.9975574011 1023 / (1024 / 5) = 4.9951171875

5.00000000 - 4.9975574011 = 0.0024425989 4.9975574011 - 4.9951171875 = 0.0024402136

Hmmm...You may be on to something...

Ps991: Spot on!

Therefore, here: http://arduino.cc/en/Reference/AnalogRead

This statement is incorrect:

This means that it will map input voltages between 0 and 5 volts into integer values between 0 and 1023.

It does not do that. It maps input voltages between 0 and 4.995 volts into integer values between 0 and 1023.

I beg to differ, it will map input voltages [0,5) volts into integer values between 0 and 1023