Need help with 32bit multiplication.

Lekky1

New Member
Hi all.

First post, so please forgive any breach of etiquette.

I'm making a wattmeter for an electric bicyle & have been trying to use 32 bit multiplication to get an accurate result using * & ** on a 20X Picaxe.

I've done a search of this forum & have found explanations, but when I attempt to run them in the simulator, the results are not what I am expecting.

The bike runs at 48 volts (60 maximum) & will draw a maximum of 35 amps.

I have been able to convert the ADC values to actual voltage values & it's these values I trying to multiply. At maximum current & voltage, I'm trying to multiply 600 x 350.

Once calculation is complete, I intended to reduce the result to a four figure value.

The 32 bit math code I am using I found elsewhere on this site & is as follows:

Code:
'Program to calculate power from voltage input & current input.

Symbol LCD = 4

Main:

Readadc10 1, W0  'voltage
Readadc10 2, W1  'current


'Code needs to go here to convert adc readings to actual decimal value.


Let W2=W0*W1/100
Let W3=W0**W1/100
Let W0=W2+W3


Let b9= W0 DIG 0
Let b11= W0 DIG 1
Let b10= W0 DIG 2
Let b8= W0 DIG 3

 
Serout lcd, t2400, (254,1)

Pause 100


Serout lcd, t2400, (#b8, #b10, #b11, #b9, "Watts")

Pause 3000

Goto Main:
I am entering values using the "generic" window in the simulator (individual ADC's not working).
Consequently, I am getting the square of the numbers I enter, but this doesn't matter for testing.....

This code works fine till I enter a value over 255. The results with values over 255 indicate that the word variable has "overflowed". The result returns to zero.

I have worked out another routine that works but is variable "hungry" & I would like a more elegant solution.

Alternative code is below. Please excuse the mess! I need to "trim" the code a little.


Code:
Symbol LCD = 4

Input A.0
Input A.1
Input A.2

Let ADCsetup= 3	'enable ADC on pins 0,1,2.


Main:

Readadc10 1, W0  'current or voltage
Readadc10 2, W1  'current or voltage

'Code needs to go here to convert adc readings to actual decimal value.

Let b4 = W0//10	'leaves decimal portion of voltage value as remainder
Let b5 = W1//10	'leaves decimal portion of current value as remainder


Let b6 = W0/10	'this gives the whole number portion of the voltage value
Let b7 = W1/10	'this gives the whole number portion of the current value

Let W1 = b6*b7*100	'this combines the whole number portion of the voltage & current

Let W7 = b4*b7*10	'this multiplies decimal component of voltage by whole number portion of current
Let W8 = b5*b6*10	'this multiplies decimal component of current by whole number portion of voltage
Let W9 = b4*b5

Let W2 = W1+W7+W8+W9	'adding all values together gives final wattage value


Let b30=W2 DIG 0
Let b31=W2 DIG 1
Let b32=W2 DIG 2 
Let b33=W2 DIG 3 
  
Serout lcd, t2400, (254,1)

Pause 100

Serout lcd, t2400, (#b33, #b32, #b31, #b30, "Watts")

Pause 3000

Goto Main:
I'm at a loss!

Unfortunately math is not my strong point....

Is there an issue with ** in the simulator?

Any help would be greatly appreciated.

Cheers!
 

Pauldesign

Senior Member
Alternatively you can perform all the computation and save your results on scratchpad or internal eeprom memories by using the peek/poke or put/get commands. Have a look at the those.
 

Jeremy Leach

Senior Member
Hi
So are you reading in your values to 1 decimal place?

How accurate does the result need to be?

I think you're getting a little confused about the ** operator. The PICAXE does all calculations as Words (0 to 65535). When two numbers are multiplied together the ** operator will return the overflowed part(if there is any), and the * operator the non-overflowed part.

Analogy in decimal: Imagine we could only do calculations between 0 and 9
So if we tried to multiply 3 * 4 = 12, the result using * would be 2. But the result using ** would be 1 - ie it would tell us the overflowed part.

However in the PICAXE, this overflowed part is a Word value itself. To show the result of an overflowed multiplication, unfortunately it's not as simple as just reading out the digits.

There are a number of ways of handling 32bit values on a PICAXE, but if all you're wanting to do is display the result, then one easily understandable way might be to switch to using decimal - store all the decimal digits for your Volt and Amp values, then do 'long hand' multiplication in code, just as if you were doing it on paper.

It's a little tricky, involving carry and partial results etc, but can in theory be quite compact, elegant code. Just an idea.
 

hippy

Ex-Staff (retired)
While developing code I would recommend forgetting about READADC and other inputs, just set set variables to numbers for testing, for example -

Code:
#Picaxe 20X2

' Calculate msw:lsw = lhs * rhs

Symbol msw = w0
Symbol lsw = w1
Symbol lhs = w2
Symbol rhs = w3

lhs = 600
rhs = 350

msw = lhs ** rhs : lsw = lhs * rhs

Do : Loop
Step that throught the simulator. When it reaches the DO:LOOP, look at the variables in 'word' display as hexadecimal. You will see w0 (msw) = $0003 and w1 (lsw) = $3450.

The 32-bit result (msw:lsw) is, in hex, $0003 3450

Using Windows calculator, $00033450 = 210000 decimal, which is 600 * 350, so it's working.

The challenge then is in getting the 32-bit number, held in two separate 16-bit variables, manipulated to what you want to display.
 

Lekky1

New Member
Thank you for your input, gentlemen!

You are correct. I have not fully understood the operation of the ** operator function.

With your help, I can see that the operator ** is working & I need to figure out how to crunch the numbers to display what I want.

Jeremy, I need the result in whole numbers (2100 Watts maximum)
The values I am using have already been converted to decimal values earlier in the code (not shown).
I am multiplying both W0 & W1 by 10 earlier in the code (not shown) & dividing the final result by 100 to try to reduce integer math errors.

It would be easier if I rounded off the volts to the nearest volt, but the result would be too inaccurate for my liking.

Hippy, I was using ADC to make it simpler to change the values of the variables while the program was simulating. You suggest not to use it. Is there the potential for errors or is it just not a good idea in general?

I will use my other code that is longwinded (but works), take Pauldesigns advice & try to rewrite using put/get or peek/poke to reduce general variable usage.

Once again, thank you all very much for taking the time to respond to my questions.
 

womai

Senior Member
Multiplying each number by 10 and then dividing the result by 100 will result in diffcult code (because there is no function to divide a 32-bit number by 100).

Much easier would be to multiply by a power of 2. If you multiply each number by 16 then you need to divide the 32-bit result by 16*16=256 - in other words, shift right by 8 bits, and that actually means you just take the middle two bytes of the 32 bit number:

Assume w0 and w1 hold the original readings, and w5 is the result:

w0 = w0 * 16 ' val1 is a word (16-bit) variable
w1 = w1 * 16 ' val2 is a word (16-bit) variable

w2 = w0 ** w1
w3 = w0 * w1

' result is not in w2 (b7 and b6) and w3 (b5 and b4)

w5 = b6 << 8 + b5

Wolfgang
 

hippy

Ex-Staff (retired)
I am multiplying both W0 & W1 by 10 earlier in the code (not shown) & dividing the final result by 100 to try to reduce integer math errors.
I think you are going to have to produce your code to show us what you are doing. Simply multiplying two integers by 10 and dividing by 100 after multiplying those together will not improve accuracy. You could just be creating unnecessary work for yourself.

What are the maximum raw values you will be reading, and what do they represent ? There may be some easier way to achieve what you need.

Hippy, I was using ADC to make it simpler to change the values of the variables while the program was simulating. You suggest not to use it. Is there the potential for errors or is it just not a good idea in general?
Not so much potential for errors just the awkwardness to change multiple word variables as all READADC10 take the readings from the Generic field. It's often much better to start with fixed values every time so you can see how code changes affect the result each time. If you change the code, run with different values, it's not always so easy to narrow down a problem.
 

womai

Senior Member
hippy,

my assumption was he meant that he scales the ADC readings so they give voltage in units of 0.1V and current in units of 0.1A (as opposed to 1V and 1A), the wants to multiply them (yielding a result in units of 0.01 Watts) and then divide by 100. But I agree, seeing the actual code will take the guesswork out of the equation.

Wolfgang
 
Hi,
You didn&#8217;t state what kind of measuring accuracy you need, but you mention that you will reduce the answer to a 4 figure value. That corresponds to a measurement accuracy of 0.05%, which puts rather extreme demands on your analogue components and circuitry. In fact, the 10bit PICAXE adc resolution is twice this figure, giving +/- 2% resolution in 60V*35A=2100W, i.e. a resolution of 4W in your final result. In addition to this you can not avoid imperfections in your analogue circuitry &#8230;
The only conclusion I can see, is that you will need ad converters of AT LEAST 12bits. And a professional analogue design!
Very sorry to discourage you like this, but why not instead settle for 3 reasonably obtainable figures?
 

Jeremy Leach

Senior Member
I've just added a little routine to 'code snippets' showing how to do the 'long-hand' multiplication I mentioned.
http://www.picaxeforum.co.uk/showthread.php?p=142191#post142191

You could use this to get your result - you would just need to read out the result digits from RAM and display to LCD etc, inserting decimal point as appropriate.

It's a bit difficult talking about 'decimal'. The overflow that's captured by using the ** operator is really capturing the next 'digit' when using a 'base 65536' numbering system instead of base 10 (decimal). So in the same way that decimal digits rollover when we exceed 9, this rolls over when we exceed 65535. It's quite hard to get the head around, but basically even though the 'digits' of base 65536 can be output individually as decimal values to an LCD etc, the PICAXE doesn't work in decimal and if there are numbers > Word then it isn't simple to convert between the two number bases.
 

Jeremy Leach

Senior Member
How does that .... :)

I'm not sure either, especially as it only gives 5 decimal digit result, when a 32bit number can be up to 10 decimal digits.
 
Top