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)
```