floating point maths with 14m2 picaxe

jon_nic

New Member
hi, I want to do some maths where use of floating numbers is unavoidable.


if for example i have to do 5 x 0.5 , i am aware i can multiply both sides by 10 to "get rid of the decimal place" and then divide by 100 after: so 50x5 = 25 / 100 =2.5 and i can store the integer "2" in a variable by using "/" and "//" to store the remainder "0.5" in another variable

but i wonder if there is a better way?

my problem is i want to calculate RMS watts and display on a LCD. The current is a peak current reading that can range from 0.2 Amps to 70 Amps and RMS Voltage is assumed as 240V

To calculate RMS Watts i need to multiple peak current by RMS volts and multiply by 0.707 (or divide by 1.414)

lets assume peak current is 5 Amps
I could multiply by 100 first (except 240V which can be 24) so it is: (24 x 500) X 707 then divide by 10,000 to give 848.4 W . The problem is that in a word variable you can only store 256x256=65536 before it rolls over to 00000, so the above maths would not work.

any better way of doing this sort of thing. I still want to keep the decimal place of the wattage so would need to do maths for the interger and maths for the remainder.

regards jon.
 

geoff07

Senior Member
- Good luck with the co-processor. It has a serious learning curve, in effect its own language, which is why there is not much on the forum about it.

- There is some clever FP Basic code on the forum which you could look for. I don't know if it would meet your needs.

- If you really really need FP then you could use C on a native PIC with MPLABX as I do. But that is not recommended unless you already know C.
 

hippy

Technical Support
Staff member
1/(20.5) ~= 46341 / 65536

whole = I * V ** 46341
fraction = I * V * 46341
 

hippy

Technical Support
Staff member
Further to post #4; 12.3A showing as 2087.38145, which is pretty close to 2086.37922, more so than using 0.707 as a multiplier which gives 2087.064

The moral there is that it's not much use determining or keeping the decimal fraction part if other rounding errors render them meaningless.

Code:
Symbol reserveW0 = w0
Symbol reserveW1 = w1
Symbol i         = w2
Symbol whole     = w3
Symbol fract     = w4

Do

  i = 123 ; 12.3A
  
  whole = i * 24 ** 46341
  fract = i * 24 *  46341

  w1 = whole : w0 = fract : Gosub DisplayRealNumberInW1W0

Loop

DisplayRealNumberInW1W0:
  SerTxd( #w1 )
  w1 = 0
  If bit14 = 1 Then : w1 = w1 + 25000 : End If
  If bit13 = 1 Then : w1 = w1 + 12500 : End If
  If bit12 = 1 Then : w1 = w1 + 06250 : End If
  If bit11 = 1 Then : w1 = w1 + 03125 : End If
  If bit10 = 1 Then : w1 = w1 + 01562 : End If
  If bit9  = 1 Then : w1 = w1 + 00781 : End If
  If bit8  = 1 Then : w1 = w1 + 00390 : End If
  If bit7  = 1 Then : w1 = w1 + 00195 : End If
  If bit6  = 1 Then : w1 = w1 + 00097 : End If
  If bit5  = 1 Then : w1 = w1 + 00048 : End If
  If bit4  = 1 Then : w1 = w1 + 00024 : End If
  If bit3  = 1 Then : w1 = w1 + 00012 : End If
  If bit2  = 1 Then : w1 = w1 + 00006 : End If
  If bit1  = 1 Then : w1 = w1 + 00003 : End If
  If bit0  = 1 Then : w1 = w1 + 00001 : End If
  BinToAscii w1, b15,b14,b13,b12,b11
  If bit15 = 1 Then
    b15 = b15 + 5
  End If
  SerTxd( ".",b15,b14,b13,b12,b11, CR, LF )
  Return
 

Armp

Senior Member
The current is a peak current reading that can range from 0.2 Amps to 70 Amps and RMS Voltage is assumed as 240V
The moral there is that it's not much use determining or keeping the decimal fraction part if other rounding errors render them meaningless.

I would suggest the 'constant 240V' assumption will limit the accuracy to 2 significant figures at best.
 

jon_nic

New Member
thanks hippy, your method may be good enough for what i want.

another way i belive i can do it after reading some more threads from this forum is:

assume i want to multiply 550 Watts by 0.707 =388.85
it can be achieved as


w1 = 550* 7 / 10 ;(=385)
w2 = 550 * 7 / 1000 ;( =3)
wremainder= 550 *7 // 1000 ;(=85)

w3=w1+w2 ;=388

;then to display on screen i can use :
sertxd (#w3,".",#wremainder) ; which displays "388.85"
 

geezer88

Senior Member
- Good luck with the co-processor. It has a serious learning curve, in effect its own language, which is why there is not much on the forum about it.
So, here's a place where the RevEd folks could make a big contribution. If an extra character of some sort could be added to math symbols when floating point was desired, then let the compiler create the commands to drive the floating point chip. The user would not need to know any more than which calculations needed the floating point treatment, and the compiler could do the heavy lifting.

While I appreciate the nice system that RevEd has created, it does seem sad that floats have been left behind. Others have pointed out that, especially with measured values, the accuracy seldom needs to be more than two or three digits. On the other hand, the higher resolution of more digits is frequently useful for seeing changes in a value.

tom
 

papaof2

Senior Member
I think the idea of 'automatic' floating point might have to be limited to larger chips because of the amount of memory the added BASIC code would take. It would also use some number of variables which are sometimes already in short supply.

The uM-FPU does have its own language, but simple calculations don't require much code and it's not difficult to set up two-way I2C with the chip. It you need more FP than the work-arounds already offered, the uM-FPU might be worth the learning curve. I didn't learn the language, just set up the chip for someone else and ran some of the sample code for it.
 

hippy

Technical Support
Staff member
another way i belive i can do it after reading some more threads from this forum is: ... which displays "388.85"
The problem there is that 0.707 is only an approximation to 1/(20.5) so 388.85 is some way from the calculator answer I get of 388.90873. My methods gets 388.90913 displayed, with the 'fract' actually holding a value equivalent to 0.909149169921875

The question is what accuracy or resolution you are looking for or need. And that perhaps depends on how the numbers are to be used, simply for displaying or in further calculations.

sertxd (#w3,".",#wremainder) ; which displays "388.85"
Watch out for when wremainder contains a number less than 10, for example 5, and shows XXX.5 rather than XXX.05
 

westaust55

Moderator
@jon_nic,

If you consider the FPU route then the MicroMega FPUs as sold by Revolution Education on their PICAXE website are certainly able to perform the math you require.
However you will incur a lot of code to send the data and commands to the FPU and speed will as a consequence be reduced. A way to improve the compactness of the PICAXE code and speed is to program the FPU with function blocks so that the constants and math functions/commands are predefined.

I have previously done some work with the microMega FPU V2 (although there are later FPUs with greater functionality and speed). See my tutorial work here:
http://www.picaxeforum.co.uk/showthread.php?15195-Adding-a-uM-FPU-V2-chip-to-your-PICAXE

The PICAXE store has the V2 and V3 chips
http://www.picaxestore.com/index.php/en_gb/catalogsearch/result/?q=FPU

microMega website has FPU IDE's to help develop the code for each FPU chip they have developed.
For the V2 chip see: http://www.micromegacorp.com/ide-v2.html
For the V3 chip see: http://www.micromegacorp.com/ide-v3.html
These IDE software packages help you develop code for the PICAE to drive the FPU and write funciton blocks to the FPU chip (direct from your PC to FPU)
 

srnet

Senior Member
So, here's a place where the RevEd folks could make a big contribution. If an extra character of some sort could be added to math symbols when floating point was desired, then let the compiler create the commands to drive the floating point chip. The user would not need to know any more than which calculations needed the floating point treatment, and the compiler could do the heavy lifting
Its not a compiler though.

The firmware itself in the PICAXE would need to know how to drive the FPU, and as suggested by others, this takes up a lot of space, so you have to decide which parts of the Firmware code should be removed to allow the facility to drive the FPU ?
 

peterthegrate

New Member
Not a solution to the problem, but don't forget that watts is only equal to volts x amps in an AC system when both volts & amps are in phase. True watts is the sum of many samples of instantaneous volts & instantaneous amps, or the time integral volts x amps if you prefer the strict mathematical definition; both divided by the time over which the samples (or integral) are taken. Also note that rms amps is waveform dependent, & the 0.707 multiplier is only valid for sinusoidal current. I'm not exactly sure what your project is about, but I'd consider the many samples method over a single mains cycle. Hope this is not too confusing!
 

BeanieBots

Moderator
Absolutely peterthegrate!
This is especially true when dealing with dimmers, motors and the recently more abundant CFL & LED lights.
Switching supplies such as those found in PCs & Laptops can play havoc with 'simple' power calculations based on I*V.
Not for the fainthearted but I always resort to analogue multipliers when accuracy is required.
There are also many dedicated chips for AC power measurments available these days.
 

geoff07

Senior Member
you have to decide which parts of the Firmware code should be removed to allow the facility to drive the FPU
Very good question. But there is a way forward if RevEd wanted to produce a chip with FP. A 40X3 could to be created based on the PIC18F46K22 rather than the PIC18F45K22 that underpins the X2. The F46 has twice the space in all of the memory areas but is otherwise identical. It wouldn't need the FPU as there is room for native maths to be coded. That would be a serious chip. They are about £4 more expensive in the dip version for one off, presumably much less in volume. Other Picaxe sizes might also have a similar upgrade path, though I haven't checked.
 

srnet

Senior Member
A 40X3 could to be created based on the PIC18F46K22 rather than the PIC18F45K22 that underpins the X2.
Or a use a 18F26k22 for an X3, which also has twice the space.

The price difference between the 5 and 6 versions is actually very small, only 53p in one off pricing.

I suspect there is far more to adding FP than we realise, probably involving a substantial re-write of the entire firmware.

And someone would have to pay for all the extra coding and testing work .....................
 

oracacle

Senior Member
I have done a fair amount of work with the V3.1 FPU too
http://www.picaxeforum.co.uk/showthread.php?25059-uM-FPU-V3-1

however all this can be null and void without knowing how the information is going to be coded, this can affect how this information is dealt with in first place, and if you went the FPU route it will dictate how that information is passed to the FPU, but it could most likely handle any conversions that are needed

it may also be worth noting that the result may not be entirely passed to the PICAXE unless you need it to, the result can be rea directly character by character from the FPU through the picaxe onto to the display.

this (24 x 500) X 707 could be something like
Code:
	hi2cout 0, (selecta, rms, FTOA, "0.707", 0, fset0)    'load RMS constant, only needs to be done once at start of programme
	
	'//now load voltage and current, convert if needed\\
	'//once complete, tun maths\\
	hi2cout 0, (selecta, result, fset, volt, fmul, current, fmul, rms)
	
	'//now read, or convert to interger and read\\
	gosub read_float                                                'read strait from fpu with no conversion
this piece of code presume you have set the hicout perameter and all symbols pertaining to the maths. parethesis (brackets) are needed as the sum will execute in order from left to right as only mulitplication is used, it also presume all subprocedure that are reguired for correct FPU operation are in place and have and can be executed is needed
 

flyingnunrt

Senior Member
I too have had some success with the uM-FPU V3.1
Yes it does have its own language, but a lot of that is taken care of by using the IDE which compiles your formulas into micromega code to suit the PICAXE.
You will have a bit of reading ahead of you to make sense of it though.
Pain = Gain
They do work, but it depends on what accuracy you are really trying to achieve.
 

oracacle

Senior Member
as for accuracy, the FPU would be the way to go. i have had it producing number and using number into the 10s of thousnds and well down into 4 decimal places.

The ide can make it easier, however the nice thing is, you can give it the maths to do, goand do something else, and then read the answer back, so in this case you could give it the maths, take the next reading, read the previous result and dsiplay, give it the new sums to do - rinse and repeat, however at 10ms completeltion time for most sum, the wait for the sum to finish is hardly worth mentioning
 

elektriker

New Member
Hallo jon_nik,
try this code. its from Jeremy Leach in this forum date:03-09-2008
Code:
setfreq M32								
#no_data

Symbol WordA	   	 = W0			'Result = WordA * Faktor = WordA * (WordB / WordC)
Symbol WordB		    = W1			'16Bit * 16Bit / 16Bit
Symbol LessThanWordC	 = W1			'max.Result = 16bit(65535)
Symbol WordC		    = W2
Symbol ResultWhole	 = W3			'WordB = 65535, wenn Faktor > 1    (65535/WordC)
Symbol ResultRemainder= W4
Symbol LSW			    = W5			'WordC = 65535, wenn Faktor < 1    (WordB/65535)
Symbol TempRemainder	 = W5				
Symbol MSW			    = W6			 

do
	ResultWhole = 0					
	ResultRemainder = 0				 
												
	WordA = 123*240	  	'123 Amp * 240 Volt=29520Watt														
	WordB = 13860		 				
	WordC = 19601			'13860/19601 = 0.70710678    = 1 / SQR(2)			
   	
	Do
		LSW = WordA * WordB
		MSW = WordA ** WordB
		ResultWhole = -1 / WordC * MSW + ResultWhole
		ResultWhole = LSW / WordC + ResultWhole
		TempRemainder = LSW // WordC
		LessThanWordC = WordC - ResultRemainder 
		ResultRemainder = ResultRemainder + TempRemainder
			If TempRemainder >= LessThanWordC Then
				ResultRemainder = ResultRemainder - WordC 
				Inc ResultWhole
			EndIf
		WordA = - 1 // WordC + 1
		WordB = MSW
	Loop Until WordB = 0 	 						

	SerTxd ("Power= ",#ResultWhole," Watt   Rest= ",#ResultRemainder,cr,lf)
	
	
loop
 
Last edited by a moderator:

Armp

Senior Member
The current is a peak current reading that can range from 0.2 Amps to 70 Amps
How are you getting the value of the peak current?
Is it an n-bit binary value, or an analog signal, or a 32bit IEEE format, or other?
 

AllyCat

Senior Member
Hi,

my problem is i want to calculate RMS watts and display on a LCD. The current is a peak current reading that can range from 0.2 Amps to 70 Amps and RMS Voltage is assumed as 240V
IMHO, if that's all you want to do then a coprocessor, or even floating point maths is totally unnecessary. 70 amps is slightly "inconvenient" (because 65535 mA would fit in a single word), but "units" of 10 mA should give adequate accuracy, particularly if you plan to "assume" 240 volts (which it probably isn't).

As hippy has said (in #4), the "root 2 over 2" (.707) can be represented as 46341 / 65536 so the power calulation can be simply I ** 46341 * V, or you can combine any other constants (e.g. the 240v) with the 46341. The main limitation of PICaxe maths is division, which can often be replaced by multiplication (as here). But if not, then there are Jeremy's 16.16 bit routines, or I have submitted a simple 31 bit by 15 bit divison routine in the code snippetts section (which uses only about 30 bytes of codespace).

However, as others have asked, is the load purely resistive ? If the load is non-linear (e.g. a diode, perhaps charging a capacitor) then you need to calculate, sum and average instantaneous values (1 ms sampling might be sufficient and possible with a PICaxe). But if the load is reactive (capacitive and/or inductive) then you also need to measure / calculate negative (including transient power) values. That may be getting beyond a PICaxe, with or without a coprocessor.

Cheers, Alan.
 

jon_nic

New Member
Hi,

70 amps is slightly "inconvenient" (because 65535 mA would fit in a single word), but "units" of 10 mA should give adequate accuracy, particularly if you plan to "assume" 240 volts (which it probably isn't).

Cheers, Alan.
hi thanks,
I'll adjust the max current so that it is 65Amps when AtoD is "255 " by adjusting the burden resistor on the current transformer i am using to measure AC current (peak value) . so to calculate peak current i read in the AtoD and multiply by 255. the word then contains the current multiplied by 1000, so i divide off by /1000 to get whole current value and ignore the rest of mA

Current(word)= AtoD_reading(byte) *255 '255 is set for 65 Amps
current(word)=Current(word) /1000

to get the milliamps i could //1000 to store the values less than 1 amp

then i multiply current by voltage RMS and then i'll use method described by Hippy and others here to get the RMS watts.
 

Armp

Senior Member
I'll adjust the max current so that it is 65Amps when AtoD is "255 " by adjusting the burden resistor on the current transformer i am using to measure AC current (peak value).
You're using a 8bit ADC??? The resolution of such will be 1 lsb or about 1/4 of an amp, and the accuracy probably twice that.

So your power will have 255 discrete steps of about 43 watts...
 

jon_nic

New Member
You're using a 8bit ADC??? The resolution of such will be 1 lsb or about 1/4 of an amp, and the accuracy probably twice that.

So your power will have 255 discrete steps of about 43 watts...
hi, yes thats correct, thats good enough for now, to prove concept and get maths working. I do intend to use 10 or even 12 bit at later date and add Voltage monitoring with reacitve /real power monitoring, for now I dont need any of that
 

EPAIII

Member
You stated that the Voltage is constant at 240 Volts. If that is so, you can multiply that by 0.707 EXTERNALLY to the program and get 169.68. Then just use that factor or a rounded version of it instead of multiplying 240 by 0.707 every time you need to do the calculation.

I highly doubt that you need that level of accuracy if you are considering the Voltage to be constant. So, the above factor can be rounded to 169.7 with a 0.01% error or even to 170 with just a 0.19% error. Then you only need to multiply up by 10 or not at all. If you need to multiply the amperage up by a factor of 10, then you are only 10 or 100 times up and the 16 bit word can probably handle it.

If you find that you need to correct the above for Voltages differences, measure them as a difference from your assumed value of 240 and calculate the factor of that difference. Express it as a fraction xxxx/10000. Then multiply the result of the above calculation by that factor.
 

jon_nic

New Member
..you can multiply that by 0.707 EXTERNALLY to the program and get 169.68. Then just use that factor or a rounded version of it instead of multiplying 240 by 0.707 every time you need to do the calculation.
hi, yes thanks i came to this conclusion too and it works pretty well. I found also that the ratio between expected RMS current and AtoD value was 10.38 so I multiply AtoD value by 104 then divide by 10 and the RMS value is found, work with enough accuracy i need.
 
Last edited:
Top