Picaxe Maths Help

retepsnikrep

Senior Member
I have read with interest Jeremy's 32 bit maths routine, but maths is not my strong point, and I can't understand what i need to do to utilise it.

Basically my problem is this

I have a state of charge indicator which goes from 0-100%.

I am using the number 10,000 to represent the value 100 with two pseudo decimal places.

Now I also have a curent sensor which gives a reading every second between 0-100A. This current reading is used to calculate the Soc on a second by second basis.

I'm happy with the formula. The following discharge rates per second mean I need to deduct the following amounts from my 10,000 value to get the remaining Soc for my 40ah battery.

`1A discharge from 40ah cell = 0.07 per second when 100% (40ah) = 10,000
`40A discharge from 40ah cell = 2.78 per second when 100% (40ah) = 10,000
`50A discharge from 40ah cell = 3.50 per second when 100% (40ah) = 10,000
`100A discharge from 40ah cell = 7.00 per second when 100% (40ah) = 10,000

For example if the battery is discharging at 40A then it should last 1hr before it is exhausted (ignore any puekert stuff here) so 2.78 x 3600 (seconds/1hr) = 10008 near enough to 10,000 or 100%

The problem is of course I can't work with 2.78 or the other decimal values, and if I multiply both sides of the formula then I quickly exceed the 16 bit integer limit.

It seems an ideal candidate for the 32 bit maths unless anyone else has any ideas? I have previously used the average current per minute which worked but I want to update the soc every second so need much bigger integer numbers.

Jeremy can you guide me a bit as to how to use your routines?

If I could multiply both sides by 1000 then the problem is solved.

So my starting Soc would be 1000000 and 40A discharge would be 278

1000000 - 278 would give me the soc after one seconds discharge at 40ah.

Grateful as ever for ideas/help.
 
Last edited:

womai

Senior Member
Maybe the Picaxe Basic's ** operator could help? It returns the two high bytes of a 16bit x 16bit multiplication, i.e. gives you access the upper 16 bits of the 32 bit result.
 

papaof2

Senior Member
Now I also have a curent sensor which gives a reading every second between 0-100A. This current reading is used to calculate the Soc on a second by second basis.

I'm happy with the formula. The following discharge rates per second mean I need to deduct the following amounts from my 10,000 value to get the remaining Soc for my 40ah battery.

`1A discharge from 40ah cell = 0.07 per second when 100% (40ah) = 10,000
`40A discharge from 40ah cell = 2.78 per second when 100% (40ah) = 10,000
`50A discharge from 40ah cell = 3.50 per second when 100% (40ah) = 10,000
`100A discharge from 40ah cell = 7.00 per second when 100% (40ah) = 10,000

For example if the battery is discharging at 40A then it should last 1hr before it is exhausted (ignore any puekert stuff here) so 2.78 x 3600 (seconds/1hr) = 10008 near enough to 10,000 or 100%
I think you need to review the manufacturer specs of your battery and the intended use.

Most battery AH ratings are a 10 or 20 hour rating - for your battery that would be 4 amps for 10 hours or 2 amps for 20 hours. Current draws greater than the value used for the AH rating will reduce the battery capacity - you need the manufacturer's data sheet to see how much it will be reduced.

Here's the chart for a representative good quality sealed lead acid (SLA) battery, the Yuasa 12 volt, 38AH battery: http://www.batterywholesale.com/specs/yuasa/NP38-12.pdf
Note that the full 38 AH is only available at the 20 hour rate of 1.9 amps. At 3.5 amps the battery lasts 10 hours (35AH) and at 22.8 amps the battery lasts about an hour (22.8AH, but at a lower endpoint voltage). The maximum allowed discharge current is 200 amps, which will deplete the battery in a couple of minutes.

Your second-by-second state-of-charge must include correction factors for the way your battery behaves under various loads. You *might* be able to extrapolate a correction factor from the manufacturer's datasheet - perhaps as close as every 5 amps. Just remember that higher currents RAPIDLY decrease the battery capacity. Based on the Yuasa specs, my guess is that the 100 amp draw would deplete the battery in 6 minutes or less (100 amps * 0.1 hour = 10AH).

Have you ever seen the battery bank for a solar or wind power installation? It's not unusual for the batteries to be rated at 200AH or more to be able to handle even small household loads when the sun/wind isn't available. Those battery sizes are small compared to some telephone exchanges which had 36-48 hours of battery backup in case of problems with both commercial power and the backup generator - big offices aften had multiple backup generators (one Georgia office I visited had 3 diesel generators of 50-100KW). In the bigger battery plants, a single CELL (2 volts) was about the size of a 30 gallon garbage can (yes, cylindrical lead-acid cells) and the AH ratings were probably in the thousands. No wire in the battery area - everything was done wth copper bus bar, typically 1/2 inch thick and 3 inches wide.

If you have the datasheet, you might get a better s-o-c indication from a battery voltage at each current draw - 12 volts at a 5 amp load is good, 11 volts at a 5 amp load is getting low. The big battery plants monitored voltage (overall), total load current, and temperature (each cell), plus specific gravity for the non-sealed cells.

John
 

retepsnikrep

Senior Member
John

Thanks for your input but i'm happy with the chemistry/specs/application of my lithium cells etc, it's fitting my calculations into the maths i'm concerned about here. There is no direct/easy corelation between terminal voltage of lithium cells and capacity remaining which is why I am doing ampere hour counting in/out. I agree I might need to add some compensation in later for high current draws.

Thanks Peter
 
Last edited:

Taniwha

Senior Member
John

Thanks for your input but i'm happy with the chemistry/specs/application of my lithium cells etc, it's fitting my calculations into the maths i'm concerned about here. There is no direct/easy corelation between terminal voltage of lithium cells and capacity remaining which is why I am doing ampere hour counting in/out. I agree I might need to add some compensation in later for high current draws.

Thanks Peter
Do lithiums not have an "end voltage" requirement? I will be interested in your outcome and whether it can be adapted for SLA batteries.
 

retepsnikrep

Senior Member
Yes they have an upper and lower voltage limit but inbetween this there is no/little corelation between voltage and capacity remaining.

Jeremy help!!!
 

Dippy

Moderator
That would be a good idea. In many cases it's possible to work with 16 bit with a bit of jiggery pokery (i.e. planning).
 

Jeremy Leach

Senior Member
Hi ...I've only just noticed this, sorry. I must say, I don't think you need to use my routines. I've worked this through for my own benefit (just taking it on face value) ..

40Ah cell lasts 1 hour at 40 Amps (in theory!) So it lasts...

= (BAh/I) hours, where BAh is the Battery Ah and I is the current
= (BAH/I) * 3600 seconds

So for a new battery at 100% charge, the battery will be flat (0%) after (BAH/I) * 3600 seconds

So the discharge rate = 100/[(BAH/I) * 3600] % per second

If working with a percent value of 0 to 10000, the formula becomes ...
Rate = 10000/[(BAH/I) * 3600] which simplifies to Rate = (25 /9)*(I/BAh)

You're working with a 40Ah battery, so Rate = (25/9) * (I / 40)
So this formula becomes Rate = (5 * I) / 72 % per second.

So after S seconds, your percentage value should have dropped: S * (5 * I)/72

The way I'd do it with the picaxe maths is to keep a track of the seconds, then do this multiplication each time you want to work out the SOC. This is MUCH better than trying to work with decimals and trimming a little bit off the SOC each second. If you trim bits off the errors are just going to accumulate.

So now we're left with figuring out when this formula might overflow. Well it depends on your maximum discharge current. You've listed 100A in your example so let's assume this is the maximum.

So at I = 100A the formula is Rate = S * 500 / 72
So S can be anything up to (65535/500) before this overflows. i.e 131 seconds.

If this is good enough then the code to work out the discharge is simply:
Code:
SOC = S * 5 * I / 72
If you need to be able to track this for more seconds then we need a rethink , but it'll be ok;)

Hope I haven't messed up with these formulae ....
 
Last edited:

retepsnikrep

Senior Member
Jeremy

Thanks for that.

Yes 100A is my maximum charge/discharge current.

However the current changes on a second by second basis so I'm a bit confused as to what you mean by keep track of the seconds? I would also need to keep track of the current for those seconds as well presumably?

I would like to calculate the soc on a second by second basis if possible.

Using you calculation with a 40ah discharge rate for one second gives us 2.77 which of course I can't use.

I dont need real decimal places just pretend ones ;) which is why I was just thinking of multiplying up both sides using your 32bit integers.

I could calculate the average current for the last minute and use that in your formula however I'm already using the Picaxe 'timer' command to tell when one second has elapsed and I don't really want to use another variable to accumulate seconds.

Or have I got confused?

I did/do have an soc charge counter working well using a minute by minute calculation but I wanted to improve on that as my program loops once per second.
 

Jeremy Leach

Senior Member
Ah I see, I varies second by second ....Duh, I should have thought that !

Ok, so Rate = (5 * I) / 72 % per second

So all we need to do is scale this up to two decimal places....

Rate = (500 * I) / 72 (e.g giving 277 for 40A)

With I at the max of 100A this still doesn't overflow...
Rate = 50000/72

So ..
Code:
Rate = 500 * I / 72
Then you just need to get the value printed to a display. E.g 277 output as "Rate = 2.77 % per second". Unless I'm missing something ...
 
Last edited:

retepsnikrep

Senior Member
Jeremy

That very good, but my Soc 100% is represented by 10,000 not 1,000,000

With your formula and a 40A discharge giving a value of 277 per second multiplied by 3600 seconds gives 1,000,000. :)

My display starts of at 100% (10,000) then as current is used or generated second by second the amount is added or subtracted from that 100% (10000), and the new Soc is displayed.

If I could represent the 100% using 1,000,000 then your formula works perfectly. Can we do that with your 32 bit maths?
 

BeanieBots

Moderator
OK, I've not looked closely at any of your numbers but I've had this very issue many times myself. I'll leave you to do the required scaling but the principle is VERY simple.
All you are doing is integrating the current with respect to time. All that involves is addition.

The method I now employ simply invloves counting 'ticks' which reperesent the current*time value.

Measure current average over time. (let's not worry about Peukert and his mates for now).
For a fixed time duration, that represents a fixed amount of capacity.
So, simply sum the measurements over time.
Let's say they get summed into a word.
When you get to a predetermined value (determined by your scaling), subtract another predetermined value and at the same time subtract one unit of capacity from your 10,000 starting number.

In brief.
Read current every second.
Accumulate readings in word.
When word gets to above say 5000, subtract 5000 from it and ALSO subtract 1 (or maybe some other suitable scaling value) from your CAPACITY value (which starts at 10,000).

For what it's worth, I'd use 40,000 to represent the 40Ah. Then, you can scale the 'ticks' to represent 1mAhr.
 

hippy

Technical Support
Staff member
If I could represent the 100% using 1,000,000 then your formula works perfectly. Can we do that with your 32 bit maths?
Can you tell us exactly what the calculation you want to perform is and the range of values each component of that equation has ?

In reading this thread I'm getting overwhelmed by theory of operation and what the numbers represent which are largely irrelevant when it seems to me it should be a simple, "how do I do this calculation in a PICAXE". If you can give the specific calculation required it should be easier for forum members to convert that to using the 32-bit maths routines or other PICAXE code.
 

Jeremy Leach

Senior Member
Sorry, I put SOC = 500 * I / 72 in the code of my last post, have corrected to Rate = 500*I/72.

You're wanting to work out a new rate each second and then you want to subtract the rate value from the running SOC percentage.

Rate = 500 * I/72 gives the percentage change per second, multiplied by 10000. So 100% is 1,000,000 as you say. So SOC starts as 1,000,000

I'd still use this scaling up personally, to keep the accuracy going. I'd just use two word values for the SOC. Hope this doesn't confuse, but ...

Call the two SOC Word values SOC_MSW and SOC_LSW for most and least significant word. So SOC = MSW * 65536 + LSW

The subtraction routine is a piece of cake ...
Code:
Symbol SOC_MSW = W0
Symbol SOC_LSW = W1
Symbol Temp = W3
Symbol Rate = W3
 
 
SubtractRateFromSOC:
    'Subtract Rate from the LSW of SOC
    Temp = SOC_LSW - Rate
 
    'Detect borrow using a trick
    If Temp > SOC_LSW Then
        'Borrow
        Dec SOC_MSW
    EndIf
 
    'SOC_LSW = Temp
Return
Now you need a routine to convert the SOC value (0 to 1,000,000) to a percentage (0 to 100%). i.e SOC100 = SOC/10000 This is a bit tricky, but ...

SOC/10000 = [(SOC_MSW * 65536) + SOC_LSW] / 10000
= [(SOC_MSW * 65535) + SOC_MSW + SOC_LSW] /10000
= [(SOC_MSW * 65535)/10000] + [SOC_MSW/10000] + [SOC_LSW/10000]
= Term1 + Term2 + Term3

Terms 2 and 3 are easy.

Term1 = (SOC_MSW * 65535)/10000 = (SOC_MSW * 13107)/2000
13107 is tricky, so make it 13108 (very very small error)
So Term1 = (SOC_MSW * 13108)/2000 = (SOC_MSW * 3277)/500

The fact that SOC_MSW will never be above 15 (1,000,000 = 655536 * 15 + 16960) means that Term1 won't overflow.

So, all this give the resulting sub to calculate the 0 to 100% value as...
Code:
SOC100:
    'Calculates the % value 0 to 100, from the SOC value 0 to 1000000
 
    Symbol SOC100 = w4
 
    SOC100 = SOC_MSW*3277/500 'Term1
    SOC100 = SOC100 + SOC_MSW/10000 'Adding Term2
    SOC100 = SOC100 + SOC_LSW/10000 'Adding Term3
Return
Maybe this is over the top in terms of accuracy. I think I've got it right though...
 

retepsnikrep

Senior Member
Thanks to everyone for their help.

My untested code extract is below. I'll try it tomorrow. I'm not too worried about some innacuracy at low currents, because with an EV current is rarely at a low level :eek:

The variable BatCurrent is the reading from the current sensor in whole amps.
Soc is my 100% (10,000) variable.
VarC2 is my sign variable + or - so I know if the sensor reading is either charge/discharge and I can process the reading accordingly.

Code:
`1A   charge/discharge = 2.7   (3)   per second when 1A   = 100
`50A  charge/discharge = 138.8 (139) per second when 50A  = 5,000 
`100A charge/discharge = 277.7 (278) per second when 100A = 10,000 
	
`40ah Cell 100% Soc is represented by 10,000 which equals 4mah per unit.  (40 = 1 unit = 4mah)

	BatCurrent = BatCurrent * 100 / 36	;Calculate Ah to be added/subtracted in last second	
								
	if VarC2 = 43 then			;If VarC2 = "+" then Charge calculations
	peek Charge, WORD VarA			;Load Charge data from RAM location into VarA
	VarA = VarA + BatCurrent		;Add latest Current data to running Charge (VarA) total 
	do while VarA >= 40			;If VarA >= 40 then execute code in loop
	inc Soc					;Increment Soc by one unit (4ma/ah)
	VarA = VarA - 40			;Subtract (40) from VarA
	loop					;Repeat loop until VarA < 40
	poke Charge, WORD VarA			;Load Charge data into RAM location
	endif
	
	if VarC2 = 45 then			;If VarC2 = "-" then Discharge calculations
	peek Discharge, WORD VarA		;Load Discharge data from RAM location into VarA
	VarA = VarA + BatCurrent		;Add latest Current data to running Discharge (VarA) total 
	do while VarA >= 40			;If Discharge >= 40 then execute code in loop
	dec Soc					;Decrement Soc by one unit (4ma/ah)
	VarA = VarA - 40			;Subtract (40) from VarA
	loop					;Repeat loop until VarA < 40
	poke Discharge, WORD VarA		;Load Discharge data into RAM location
	endif
 
Last edited:

retepsnikrep

Senior Member
Jeremy my above code works well. A test drive today showed it counting down nicely seemingly quite accurate. I may move to your super accurate 32 bit maths as I gain experience with it all. Thanks for help and ideas.
 
Top