PDA

View Full Version : PbPro Maths Help



retepsnikrep
- 6th July 2010, 10:11
I'm a real PbPro Maths dunce and am asking for members advice on converting the following maths
routines into code.

Baiscally i have a byte array of hex data BD[11] recieved via a serial interface. I'm happy with this and the data recd.

Now taking bytes from array BD [4] and BD [5] as an example i need to perform the following calcu
lation on the bytes.


(Multiply 1st number by 128, add result to 2nd number, take off 2048, divide the result by 20.48)

I appreciate the decimal point will cause an issue. Any examples of code that would perform this.

I came up with



Result = (((BD[4] * 128) + BD[5]) - 2048) / 20

But this losses the accuracy of the end part of the formula?

Also for a second formula involving BD [2] & BD [3] I need to


(Multiply the right hand digit of 1st hex number by 128, add result to 2nd number)

I'm stuck on extracting a value for the right hand digit of the hex number?

Acetronics2
- 6th July 2010, 11:11
I'm a real PbPro Maths dunce ...

Baiscally i have a byte array of hex data BD[11] recieved via a serial interface. I'm happy with this and the data recd.

Now taking bytes from array BD [4] and BD [5] as an example i need to perform the following calcu
lation on the bytes.



I appreciate the decimal point will cause an issue. Any examples of code that would perform this.

I came up with



Result = (((BD[4] * 128) + BD[5]) - 2048) / 20.48

But this losses the accuracy of the end part of the formula?

...

Also for a second formula involving BD [2] & BD [3] I need to

I'm stuck on extracting a value for the right hand digit of the hex number?


Hi,

1) Result = (((BD[4] * 128) + BD[5]) - 2048) / 20.48

lets write it ...

20.48 = 512 /25 ... ; 2048 = 100 * 20.48 ...

result = ((((BD[4] << 7) + BD[5] ) * 25) >> 9) - 100

not so good as a calculation ... don't you have a better formula ???
( BTW... I'm curious to see your project ...) :confused:

BD[5] obviously is a word ( or smaller !!! ) ... so, at least, its 4 lower digits are lost in the calculation ... :o


2) It's a typical "masking" job ... ( I suppose it's a HEX digit, you look for ? ) ...

so, you could use ...

Ldigit = Res & $000F( for a Word )

Ldigit = Res & $0000000F ( for a LONG )


Alain

retepsnikrep
- 6th July 2010, 11:59
BD is a byte array. All the values are hex bytes. Thanks for the ideas so far.

retepsnikrep
- 6th July 2010, 16:14
(Multiply the right hand digit of 1st hex number by 128, add result to 2nd number)

In the second example if we assume That the first hex byte number is 1E how do i extract the value for the E to use in the above? Sorry if i'm being thick.

retepsnikrep
- 6th July 2010, 16:51
In the first example it may help if i explain the range of values my forumla will encounter, for BD[4] it is $00-$18 and for BD[5] it is $00-$7F. The application is a current sensor data stream which measures from -100 to +50A

This i think will allow me multiply the result by 10 and still fit in a WORD before performing the divide by 20.48 increasing integer accuracy as I can divide by 205 :confused:

A problem however is that the result of a multiplication can be negative :(


If the result of a multiplication could possibly be negative, it should be
stored to a long-sized variable type to preserve the sign. If a negative
result is placed in a variable type other than long, subsequent
calculations using this value will interpret it as a positive number.


I don't know how to manage that :confused: PBL?

For the second example the range of values for BD[2] is $21 -$34 and for BD[3] it's again $00-$7F This isnt a current sensor but relates to a SOC reading probably varying from 0-100%

HenrikOlsson
- 6th July 2010, 20:45
Hi,
I don't get it.... $18 and $7F is 24 and 127 respectively. Putting these in the formula should result in "real life values" ranging from -100 to 50 representing the current in amperes, correct?

((0*128)+0-2048) / 20.48 = -100 OK
((24*128)+127-2048) / 20.48 = 56 ??

Next question is what you're going to do with the values? If you're displaying them to a human then it makes sense to scale them properly but of you're continuing to do massage the numbers it doesn't matter what "units" they are in.

Anyway, how about:

Result var WORD
Sign VAR BIT

Result = (BD[4] * 128) + BD[5] - 2048
Sign = Result.15
Result = ABS Result
Result = Result * 2500
Result = DIV32 512
If Sign = 1 Then
LCDOUT $FE, 1, "-", #RESULT/100, ".", DEC2 RESULT//100
ELSE
LCDOUT $FE, 1, #RESULT/100, ".", DEC2 RESULT//100
ENDIF

In the above, if BD[4]=3 and BD[5]=90 the correct result is -76.855 and the code displays -76.85. If BD[4]=19 and BD[5]=89 the correct result is 23.096 and the code displays 23.09. Is that close enough?

/Henrik.

retepsnikrep
- 7th July 2010, 06:49
Hi,
I don't get it.... $18 and $7F is 24 and 127 respectively. Putting these in the formula should result in "real life values" ranging from -100 to 50 representing the current in amperes, correct?

((0*128)+0-2048) / 20.48 = -100 OK
((24*128)+127-2048) / 20.48 = 56 ??
/Henrik.

Henrik and others thanks for your help.

Sorry yes the maximum value for $18 is actually $17 so thats puts the range covered within -100 to + 50.

That code looks really helpful, and is easily accurate enough, yes the answer is being displayed via a serial lcd device that's not a problem.

The second issue with the seperate lower formula is


Also for a second formula involving BD [2] & BD [3] I need to

(Multiply the right hand digit of 1st hex number by 128, add result to 2nd number)

I'm stuck on extracting a value for the right hand digit of the hex number?

As an aside it may be my formula for BD[2] & BD [3] is incorrect I suspect it should resolve to a number between 0-100% at it represents battery state of charge.
My captured range of values for BD[2] is $21 -$34 and for BD[3] it's again $00-$7F

Ignoring the first digit of BD [2] gives a range of values that seems to work

HenrikOlsson
- 7th July 2010, 08:44
Hi,
I'm confused about that second calculation....

My captured range of values for BD[2] is $21 -$34 and for BD[3] it's again $00-$7F
Ignoring the first digit of BD [2] gives a range of values that seems to work.If you just look at the "right hand" digit of BD[2] your formula will return the same result when BD[2]=$21 and $31 and so on. Let's say BD[2] is $22 and BD[3] is $10 then your formula would be 2*128+16=272. Now lets say BD[2] is $32 and BD[3] is $10, your formula returns 2*128+16= 272 - is that really correct?

/Henrik.

retepsnikrep
- 7th July 2010, 08:45
OK thanks to all i believe I have the answers now.

For the last issue masking the four bits works.

BD[2] = bd[2] AND $0F

retepsnikrep
- 27th October 2010, 10:47
Forum members kindly helped me with this code a while back.



Amps = ((BCM87[4] * 128) + BCM87[5]) - 2048 'Calculate Battery Current
if Amps.15 = 1 then 'Calculate AmpSign
AmpSign = 45 'Set AmpSign to 45 (-)
else
AmpSign = 43 'Set AmpSign to 43 (+)
endif
Amps = ABS Amps
Amps = Amps * 2500
Amps = DIV32 512


It evaluates a 16 bit hex number from an array and produces a current reading to two decimal places with a + or - sign to denote charging or discharging. It work fine.

Now I need to manipulate the current, so say the current is +10.00A i need to be able to reduce it by say 8 or 16% and then generate two new hex bytes in the correct format to overwrite those it came from.

Imagine the device sits passing through the traffic current data. it now needs to get the data evaluate, modify it by X% and squirt it out the other side.

I would be grateful for ideas as maths is not my strong point. Thanks Peter

aratti
- 27th October 2010, 11:50
The following code should work.

Cheers

Al.



Percent var byte
R_Amp var Word
I_Amp var Byte
D_Amp var Byte

main:
Percent = 8 ' set variable with your percent
gosub Calc
LDCOUT I_Amp, ".", D_Amp ' display values
goto main

Calc:
R_Amp = (100 - Percent) * Amps ' here Amps is your variable with the primitive value
I_Amp = R_Amp/100 ' integerpart
D_Amp = R_Amp//100 ' decimal part
Return

retepsnikrep
- 27th October 2010, 14:10
Thanks i think that helps with the percentage, but it's reconstructing the two hex bytes with the new data to forward on which is really tricky? If you get me?

retepsnikrep
- 28th October 2010, 00:28
In the below simplified sample code two hex bytes of incomming battery current data are
evaluated to give a display of current. The code works very well.



Amps = ((HEXBYTE1 * 128) + HEXBYTE2) - 2048 'Calculate Battery Current
if Amps.15 = 1 then 'Calculate AmpSign
AmpSign = 45 'Set AmpSign to 45 (-)
else
AmpSign = 43 'Set AmpSign to 43 (+)
endif
Amps = ABS Amps
Amps = Amps * 2500
Amps = DIV32 512


This gives current to two decimal places when divided and a polarity sign to indicate current flow
direction. All that is fine.

Now I need to reduce the Amps by say 8-16% (That's fine) and then recreate the HEXBYTES by
some reverse calculation or application of the above code. So they contain the new value and when evaluated by the above routine would give the new current and sign etc. Does that make sense? I hope somone can give me
me some ideas. Thanks

Dave
- 28th October 2010, 11:45
retepsnikrep , Why not just use the "*/" command? The variable "Amps" is a word so just multiply it by the fraction of 84 to 92 %. The "*/" command will give you the middle 16 bits of the 32 bit result. Then just put the result back into bytes.... Thats what I would do.....

Dave Purola,
N8NTA

retepsnikrep
- 28th October 2010, 22:50
Thanks for that.

How about this?

Anyway, a reverse of my code? Does it make sense.


Amps = Amps * 512
Amps DIV32 2500

if AmpSign == 45 then '-
Amps = 0 - Amps
else
? not sure here
endif

Amps = Amps + 2048
Byte2 = Amps & &7f 'split of HEXBYTE2
Amps = Amps >> 7 'Div by 128
Byte1 = Amps & 0x1f '