This is a weird question. I’m sorry :D
What’s your use-case? As-in- why do you want to take a perfectly sane voltage reading and map it to a seemingly arbitrary numerical range?
Assuming a target range of 0-1023 (which is what you’d get from a 10bit ADC) and a source voltage of 0-5v (it rarely hits the extremes) then you can just figure out a scale value and simply multiply the value back up:
>>> scale = 1023/5.0
204.6
>>> int(analog.read(0) * scale)
But that’s a little ugly, so let’s talk about the guts of the system :D
###ADS1015
The ADS1015 on Enviro pHAT is configured with a 6.144v “full scale range”, this means its value maxes out at 6.144v, with a granularity of 3 mV.
The ADS1015 is 12bit double-ended (it can measure a positive voltage or a negative voltage) and 11bit single-ended (that 12th bit is the sign bit to denote positive or negative). So that’s a possible range of 0-2047. (6.144v / 2047 = 0.003v
)
You can work out how big a number you can store in a given number of bits like so: 2^11-1 = 2047
To convert it to the 10bit value you’re after (`2^10-1 = 1023) you just shift this value down once, like so:
>>> 2047 >> 1
1023
This gives you a precision of 1 == 6mV. So a value of 500 would equal 3V.
The Code
Now we dive into the library itself. Fortunately it’s not complex code and you need only worry about lines 72 to 78 of ads1015.py: https://github.com/pimoroni/enviro-phat/blob/master/library/envirophat/ads1015.py#L72-L78
value /= 2047.0
value *= float(programmable_gain)
if value > self.max_voltage:
self._over_voltage[channel] = True
return round(value / 1000.0,3)
At a full scale range of 6.144v the programmable_gain
value is simply 6144
, the max voltage stuff is irrelevant and the over_voltage stuff is cruft you probably don’t care about, so let’s simplify this to:
value /= 2047.0 # At this point the value is 0 to 2047, this converts it to: 0.0 to 1.0
value *= 6144 # Now we scale back up our range to: 0.0 to 6144.0
return round(value / 1000.0,3) # And divide by 1000 to convert the mV value to V resulting in 0.0 to 6.144
# (actually 0.0 to 5.3 since you're not supposed to put more than VDD + 0.3v into the ADC!).
# ( note, precision is also lost here because we round to 3 decimal places,
# so the multiply up answer given above is not optimal )
So to get your 0-1023 value, you can change all of this to:
return value >> 1
And that’s a good example of a complex explanation for a simple 1-line answer :D Whew.
The Problem
If you haven’t noticed already, your 0-1023 range would now be mapped to the full-scale range of the ADC. IE: 0.0v to 6.144v, but you can only input up to 5.3v. This means the biggest number you’ll ever get out of it is about 904. If you can live with that, great, otherwise… well it’s probably just easier to use the first answer :D
Alternatively, you could scale the value slightly differently.
Given that you want 0V to 5V to equate to 0 to 1023 you could come up with a new scale factor to figure out what the 6.144v overvoltage would equal under this scheme.
>>> 6144/5000
1.2288
>>> 1023 * 1.2288
1257.0624
When you input 5v (5000mV) at a precision of 1=3mV
you get: 1666.66666667
If we divide this by the full scale range, and then multiply it by our new scale factor, we get the new range:
>>> 5000/3.0
1666.66666667
>>> 1666.66666667 / 2047
0.81419964175
>>> 0.81419964175 * 1257.0624
1023.49975574
Damn it, that’s close enough! Let’s sweep some of that under the rug…
>>> int(1023.49975574)
1023
So the new code snippet becomes:
value /= 2047.0 # At this point the value is 0 to 2047, this converts it to: 0.0 to 1.0
value *= 1257.0624
return int(value)