Discussion:
How to find a formula from a list of numbers
2009-10-04 13:24:12 UTC
Raw Message
Hi all,

Sorry for the basic question but it's been a while! I have a list of numbers:

A | B
-----+-----
0 | 0
32 | 3.6
64 | 7.6
128 | 15.6
255 | 31.5

And I need a formula such that I can put in any number (between 0 and 255
inclusive) for A, and obtain the result B. Unfortunately because this isn't
quite straightforward division I'm a bit stuck.

Just for a bit of background I'm writing a Linux driver for a USB-connected PC
power supply, and the current being drawn on the various rails is reported as
an 8-bit number (A) and for it to be of any use it will need to be converted
into amps (B). The values above are taken from the Windows driver, so there
could be some rounding issues in the values of B depending on how well that
code was written.

Annoyingly the six current rails all have slightly different values for B, so
I'd be grateful for a couple of tips so I can calculate a formula for each of
those as well.

Many thanks,
P***@aol.com
2009-10-04 13:45:26 UTC
Raw Message
On Sun, 04 Oct 2009 23:24:12 +1000, Adam Nielsen
Hi all,
A | B
-----+-----
0 | 0
32 | 3.6
64 | 7.6
128 | 15.6
255 | 31.5
And I need a formula such that I can put in any number (between 0 and 255
inclusive) for A, and obtain the result B. Unfortunately because this isn't
quite straightforward division I'm a bit stuck.
Just for a bit of background I'm writing a Linux driver for a USB-connected PC
power supply, and the current being drawn on the various rails is reported as
an 8-bit number (A) and for it to be of any use it will need to be converted
into amps (B). The values above are taken from the Windows driver, so there
could be some rounding issues in the values of B depending on how well that
code was written.
Annoyingly the six current rails all have slightly different values for B, so
I'd be grateful for a couple of tips so I can calculate a formula for each of
those as well.
Many thanks,
There infinitely many solutions to the problem and each is as correct
mathematically as any other
Barb Knox
2009-10-04 19:57:25 UTC
Raw Message
Post by P***@aol.com
On Sun, 04 Oct 2009 23:24:12 +1000, Adam Nielsen
Hi all,
A | B
-----+-----
0 | 0
32 | 3.6
64 | 7.6
128 | 15.6
255 | 31.5
And I need a formula such that I can put in any number (between 0 and 255
inclusive) for A, and obtain the result B. Unfortunately because this isn't
quite straightforward division I'm a bit stuck.
Just for a bit of background I'm writing a Linux driver for a USB-connected PC
power supply, and the current being drawn on the various rails is reported as
an 8-bit number (A) and for it to be of any use it will need to be converted
into amps (B). The values above are taken from the Windows driver, so there
could be some rounding issues in the values of B depending on how well that
code was written.
Annoyingly the six current rails all have slightly different values for B, so
I'd be grateful for a couple of tips so I can calculate a formula for each of
those as well.
Many thanks,
There infinitely many solutions to the problem and each is as correct
mathematically as any other
Yes, but this is an *applied* mathematics problem, and the engineering
domain to which it is being applied provides some additional
constraints. For example, the function should almost certainly be
monotonic, and preferably should be linear.

Inspecting the results, the differences in the successive B values for
the successive doublings of the A values are: 4, 8, 16 (actually 15.9
for slightly less than a doubling). So, a simplified formula is:
B = A/8 - 0.4

This would produce a negative B value for A < 4, so a correct formula is:
B = {A/8 - 0.4 if A >=4, 0 otherwise}

There may need to be some additional tweaking for small values of A,
which we don't yet have the measurements for.
--
---------------------------
| BBB b \ Barbara at LivingHistory stop co stop uk
| B B aa rrr b |
| BBB a a r bbb | Quidquid latine dictum sit,
| B B a a r b b | altum viditur.
| BBB aa a r bbb |
-----------------------------
2009-10-04 22:25:27 UTC
Raw Message
Post by Barb Knox
A | B
-----+-----
0 | 0
32 | 3.6
64 | 7.6
128 | 15.6
255 | 31.5
And I need a formula such that I can put in any number (between 0 and 255
inclusive) for A, and obtain the result B. Unfortunately because this isn't
quite straightforward division I'm a bit stuck.
Inspecting the results, the differences in the successive B values for
the successive doublings of the A values are: 4, 8, 16 (actually 15.9
B = A/8 - 0.4
B = {A/8 - 0.4 if A >=4, 0 otherwise}
There may need to be some additional tweaking for small values of A,
which we don't yet have the measurements for.
Thanks Barb, that's excellent! I've collected some extra values and it looks
like you're spot on:

A | B
-----+-----
0 | 0
3 | 0
4 | 0.1
6 | 0.3
8 | 0.6
16 | 1.6
32 | 3.6
64 | 7.6
128 | 15.6
192 | 23.6
255 | 31.5

The simple divide and subtract will also keep the code nice and fast. However
I'm not so sure one of the other rails will be that easy:

A | B'
-----+-----
0 | 0
1 | 0.1
4 | 0.4
8 | 0.9
16 | 1.9
32 | 3.8
48 | 5.7
64 | 7.6
96 | 11.4
128 | 15.2
160 | 19.1
192 | 22.9
208 | 24.8
224 | 26.7
255 | 30.4

Cheers,
2009-10-04 22:31:25 UTC
Raw Message
The simple divide and subtract will also keep the code nice and fast. However
A | B'
-----+-----
0 | 0
1 | 0.1
4 | 0.4
8 | 0.9
16 | 1.9
32 | 3.8
48 | 5.7
64 | 7.6
96 | 11.4
128 | 15.2
160 | 19.1
192 | 22.9
208 | 24.8
224 | 26.7
255 | 30.4
Oh having said that, I think this might work:

B' = A/10 + A/52

Not sure quite how their rounding works, so let me know if you have any better
ideas!

Cheers,
Barb Knox
2009-10-04 23:40:12 UTC
Raw Message
The simple divide and subtract will also keep the code nice and fast.
However
A | B'
-----+-----
0 | 0
1 | 0.1
4 | 0.4
8 | 0.9
16 | 1.9
32 | 3.8
48 | 5.7
64 | 7.6
96 | 11.4
128 | 15.2
160 | 19.1
192 | 22.9
208 | 24.8
224 | 26.7
255 | 30.4
B' = A/10 + A/52
Not sure quite how their rounding works, so let me know if you have any better
ideas!
Note that for A >= 16, doubling A also doubles B'.
The best fit is
B' = A/16 * 1.91, truncated to 1 decimal place.

1.91/16 = 0.119375,
and your rational approximation for that is
1/10 + 1/52 = 31/260 = 0.1192307

Note that there are closer rational approximations, but any one that
provides the correct B' values to 1 decimal place is close enough.
--
---------------------------
| BBB b \ Barbara at LivingHistory stop co stop uk
| B B aa rrr b |
| BBB a a r bbb | Quidquid latine dictum sit,
| B B a a r b b | altum viditur.
| BBB aa a r bbb |
-----------------------------
2009-10-05 11:33:13 UTC
Raw Message
Post by Barb Knox
Note that for A >= 16, doubling A also doubles B'.
The best fit is
B' = A/16 * 1.91, truncated to 1 decimal place.
1.91/16 = 0.119375,
and your rational approximation for that is
1/10 + 1/52 = 31/260 = 0.1192307
Note that there are closer rational approximations, but any one that
provides the correct B' values to 1 decimal place is close enough.
Ah, glad to see I was close! Thanks again. I've got all the current values
sorted now, but I've discovered that the fan speeds seem to be reported on
some sort of logarithmic scale:

A | B
------+---------
128 | 8943 RPM / 943 RPM *
144 | 9727 RPM *
256 | 5493 RPM
512 | 2746 RPM
1285 | 1094 RPM
4096 | 343 RPM
8192 | 171 RPM
65535 | 21 RPM

I'm not 100% sure about the first two values (marked with *) because the
values were so large I'm not sure the manufacturer's program was drawing them
on the screen properly.

I *think* this is logarithmic - I can get an approximation of the curve using
variations of -log(x), but I'm afraid that's as far I as can remember :-) If
it's possible, an approximation using "simpler" operations (+, -, *, /) would
be even better from a runtime efficiency point of view!

Thanks again,
Barb Knox
2009-10-06 01:28:11 UTC
Raw Message
Post by Barb Knox
Note that for A >= 16, doubling A also doubles B'.
The best fit is
B' = A/16 * 1.91, truncated to 1 decimal place.
1.91/16 = 0.119375,
and your rational approximation for that is
1/10 + 1/52 = 31/260 = 0.1192307
Note that there are closer rational approximations, but any one that
provides the correct B' values to 1 decimal place is close enough.
Ah, glad to see I was close! Thanks again. I've got all the current values
sorted now, but I've discovered that the fan speeds seem to be reported on
A | B
------+---------
128 | 8943 RPM / 943 RPM *
144 | 9727 RPM *
256 | 5493 RPM
512 | 2746 RPM
1285 | 1094 RPM
4096 | 343 RPM
8192 | 171 RPM
65535 | 21 RPM
I'm not 100% sure about the first two values (marked with *) because the
values were so large I'm not sure the manufacturer's program was drawing them
on the screen properly.
I *think* this is logarithmic - I can get an approximation of the curve using
variations of -log(x), but I'm afraid that's as far I as can remember :-) If
it's possible, an approximation using "simpler" operations (+, -, *, /) would
be even better from a runtime efficiency point of view!
A little hacking around in Excel shows that this is a log-log
relationship. In particular:
log_2(B) = 20.44592638 - 1.002677224*log_2(A)
with a maximum absolute error of 0.010795444

With these coefficients, the B value for A=128 would be 11015.
Thanks again,
HTH
--
---------------------------
| BBB b \ Barbara at LivingHistory stop co stop uk
| B B aa rrr b |
| BBB a a r bbb | Quidquid latine dictum sit,
| B B a a r b b | altum viditur.
| BBB aa a r bbb |
-----------------------------
Barb Knox
2009-10-06 20:36:44 UTC
Raw Message
Post by Barb Knox
Post by Barb Knox
Note that for A >= 16, doubling A also doubles B'.
The best fit is
B' = A/16 * 1.91, truncated to 1 decimal place.
1.91/16 = 0.119375,
and your rational approximation for that is
1/10 + 1/52 = 31/260 = 0.1192307
Note that there are closer rational approximations, but any one that
provides the correct B' values to 1 decimal place is close enough.
Ah, glad to see I was close! Thanks again. I've got all the current values
sorted now, but I've discovered that the fan speeds seem to be reported on
A | B
------+---------
128 | 8943 RPM / 943 RPM *
144 | 9727 RPM *
256 | 5493 RPM
512 | 2746 RPM
1285 | 1094 RPM
4096 | 343 RPM
8192 | 171 RPM
65535 | 21 RPM
I'm not 100% sure about the first two values (marked with *) because the
values were so large I'm not sure the manufacturer's program was drawing them
on the screen properly.
I *think* this is logarithmic - I can get an approximation of the curve using
variations of -log(x), but I'm afraid that's as far I as can remember :-)
If
it's possible, an approximation using "simpler" operations (+, -, *, /) would
be even better from a runtime efficiency point of view!
A little hacking around in Excel shows that this is a log-log
log_2(B) = 20.44592638 - 1.002677224*log_2(A)
with a maximum absolute error of 0.010795444
With these coefficients, the B value for A=128 would be 11015.
Oh bother. I failed to appreciate the fact that -1.002677224 is
probably close enough to -1 for this problem, so the log-log power
relationship between B and A could be a simple reciprocal. And indeed,
here's an exact formula for the non-starred values that does not use
logs:
B = int(1406315/A)

With this formula, A=128 gives B=10986, and A=144 gives B=9766.
Post by Barb Knox
Thanks again,
HTH
--
---------------------------
| BBB b \ Barbara at LivingHistory stop co stop uk
| B B aa rrr b |
| BBB a a r bbb | Quidquid latine dictum sit,
| B B a a r b b | altum viditur.
| BBB aa a r bbb |
-----------------------------
2009-10-08 00:05:26 UTC
Raw Message
Post by Barb Knox
Oh bother. I failed to appreciate the fact that -1.002677224 is
probably close enough to -1 for this problem, so the log-log power
relationship between B and A could be a simple reciprocal. And indeed,
here's an exact formula for the non-starred values that does not use
B = int(1406315/A)
With this formula, A=128 gives B=10986, and A=144 gives B=9766.
Excellent, that's perfect! Thanks for all your help!

Cheers,

Barb Knox
2009-10-04 19:57:46 UTC
Raw Message
Post by P***@aol.com
On Sun, 04 Oct 2009 23:24:12 +1000, Adam Nielsen
Hi all,
A | B
-----+-----
0 | 0
32 | 3.6
64 | 7.6
128 | 15.6
255 | 31.5
And I need a formula such that I can put in any number (between 0 and 255
inclusive) for A, and obtain the result B. Unfortunately because this isn't
quite straightforward division I'm a bit stuck.
Just for a bit of background I'm writing a Linux driver for a USB-connected PC
power supply, and the current being drawn on the various rails is reported as
an 8-bit number (A) and for it to be of any use it will need to be converted
into amps (B). The values above are taken from the Windows driver, so there
could be some rounding issues in the values of B depending on how well that
code was written.
Annoyingly the six current rails all have slightly different values for B, so
I'd be grateful for a couple of tips so I can calculate a formula for each of
those as well.
Many thanks,
There infinitely many solutions to the problem and each is as correct
mathematically as any other
Yes, but this is an *applied* mathematics problem, and the engineering
domain to which it is being applied provides some additional
constraints. For example, the function should almost certainly be
monotonic, and preferably should be linear.

Inspecting the results, the differences in the successive B values for
the successive doublings of the A values are: 4, 8, 16 (actually 15.9
for slightly less than a doubling). So, a simplified formula is:
B = A/8 - 0.4

This would produce a negative B value for A < 4, so a correct formula is:
B = {A/8 - 0.4 if A >=4, 0 otherwise}

There may need to be some additional tweaking for small values of A,
which we don't yet have the measurements for.
--
---------------------------
| BBB b \ Barbara at LivingHistory stop co stop uk
| B B aa rrr b |
| BBB a a r bbb | Quidquid latine dictum sit,
| B B a a r b b | altum viditur.
| BBB aa a r bbb |
-----------------------------