Problem calculating Power.

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys, :D

Firstly, i just wanna say I'm a hobbyist, trying to build a power meter.

I've got a mega8 set up to read current and voltage across a light gl0be (12v), and output the data to the PC via UART.

It shows the output voltage and current to 2 decimal places with a resolution of around 3mV and 3mA.

Ive been trying to calculate the power (that is P=IV) in watts and display that in the terminal as well, however, I've got some issues :? . i want the power accuracy to be to 2 decimal places.

When it displays the power, i get a reading like x.00000 (where x is an integer from 2 - 6), no matter what my voltage or current reading are.

I cant seem to find out the problem with my code. here is the function that calculates the power.

void showDataUART(void)
{
	getADC(0b01000101);
	rawV = ADC*2.802; // uin16_t rawV. 

	getADC(0b01000001);
	rawC = ADC*3.255; // uin16_t rawC

	uint32_t watts = (rawV*rawC)/10000; /* divide by 10000, as rawC 
												and V are raw values.*/

	sprintf(buffer, "%2d.%02dV  ", rawV/100, rawV%100); 
	UARTstring(buffer);

	sprintf(buffer, "%2d.%02dA  ", rawC/100, rawC%100); 
	UARTstring(buffer);

	sprintf(buffer, "%fW  ", watts); 
	UARTstring(buffer);

	newline();
}

any help will great.

cheers.

- Tony B. Sydney, Australia.
tbaz2679@mail.usyd.edu.au

Status: Supporting the GNU

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try

uint32_t watts = (uint32_t)(rawV*rawC)/10000;

Also, you definately don't want to use %f to output a uint32_t
number.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the quick reply. ill try it.
What do you recommend i use??

- Tony B. Sydney, Australia.
tbaz2679@mail.usyd.edu.au

Status: Supporting the GNU

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can i just cast it to a double??

- Tony B. Sydney, Australia.
tbaz2679@mail.usyd.edu.au

Status: Supporting the GNU

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok tried it. and had the same problem. here is the modified code.

void showDataUART(void)
{
	getADC(0b01000101);
	rawV = ADC*2.802; // uin16_t rawV. 

	getADC(0b01000001);
	rawC = ADC*3.255; // uin16_t rawC

	uint32_t watts = (uint32_t)(rawV*rawC)/10000;

	sprintf(buffer, "%2d.%02dV  ", rawV/100, rawV%100); 
	UARTstring(buffer);

	sprintf(buffer, "%2d.%02dA  ", rawC/100, rawC%100); 
	UARTstring(buffer);

	sprintf(buffer, "%.2fW  ", (double)watts); 
	UARTstring(buffer);

	newline();
}

The terminal output shows:

15.29V   4.65A  5.00W

:S :S im puzzled.

- Tony B. Sydney, Australia.
tbaz2679@mail.usyd.edu.au

Status: Supporting the GNU

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ouch, I just notice your rawV and rawC are uint16_t. That will of
course overflow when multiplying. Since you did double calculations
on them before, I assumed they were of type double...

As you're using floating-point math anyway, why bother with uint16_t
or uint32_t intermediate results at all?

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
uint32_t watts = (uint32_t)(rawV*rawC)/10000; 

This is not doing what you think it is doing. The compiler is doing the multiply as uint16_t, dividing by uint16_t 10,000, THEN converting to uint32_t.

Instead, you want:

uint32_t watts = ((uint32_t)rawV*(uint32_t)rawC)/10000UL; 

where 10000UL is a uint32_t constant 10,000. And to print:

   sprintf(buffer, "%2d.%02dA  ", watts/10000, watts%10000);
   UARTstring(buffer);

Stu

Edit 1: Just noticed Joerg's latest post. You could just stick with floating point, as he suggests.

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Stu,

Your nearly there. i added this code:

uint32_t watts = ((uint32_t)rawV*(uint32_t)rawC);

and

sprintf(buffer, "%2d.%02dW  ", watts/10000, watts%10000);
   UARTstring(buffer); 

reason been; we cant divide by 10000 twice or the diplay value will be 10000 times smaller than what we want.

Anyways, here is the output:

15.32V   4.65A  71.00W

nearly there. just not showing the decimal part. hmmm

- Tony B. Sydney, Australia.
tbaz2679@mail.usyd.edu.au

Status: Supporting the GNU

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dl8dtl wrote:
As you're using floating-point math anyway, why bother with uint16_t
or uint32_t intermediate results at all?

I thought its more efficient. but either way, if it works, it works.

- Tony B. Sydney, Australia.
tbaz2679@mail.usyd.edu.au

Status: Supporting the GNU

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nope. Still haven't fixed it. Still cant get the decimal part to show up. Always showing x.00

- Tony B. Sydney, Australia.
tbaz2679@mail.usyd.edu.au

Status: Supporting the GNU

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I get this warning during compile.

../main.c:210: warning: format '%02d' expects type 'int', but argument 4 has type 'uint32_t'

- Tony B. Sydney, Australia.
tbaz2679@mail.usyd.edu.au

Status: Supporting the GNU

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That warning explains it. You're still using an integer number, and
only convert it to double when displaying it. Use doubles for
*everything* except the initial reading of the ADC.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Throw an "l" into your format to let printf know it's long's that are involved. (or cast the unit32_t's down to unit16_t's - but this risks losing range again)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok i got it working. here is the code:

void showDataUART(void)
{
	getADC(0b01000101);
	rawV = ADC*2.802; // uin16_t rawV. 

	getADC(0b01000001);
	rawC = ADC*3.255; // uin16_t rawC

	uint32_t rawW = ((uint32_t)rawV*(uint32_t)rawC)/100;
	uint16_t watts = rawW;

	sprintf(buffer, "%2d.%02dV  ", rawV/100, rawV%100); 
	UARTstring(buffer);

	sprintf(buffer, "%2d.%02dA  ", rawC/100, rawC%100); 
	UARTstring(buffer);

	sprintf(buffer, "%2d.%02dW  ", watts/100, watts%100);
   	UARTstring(buffer); 

	newline();
}

Basically i just converted the uint32_t value to a uint16_t. This gives me a theoretical maximum wattage of 655.36 which is way more than enough.

here is the output tested with a 12v halogen light :wink:

15.32V   4.56A   69.85W

Thanks for your help guys.

- Tony B. Sydney, Australia.
tbaz2679@mail.usyd.edu.au

Status: Supporting the GNU

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If your measurement is correct, be careful: your halogen lamp won't
last really long with that amount of over-voltage. ;-)

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lol, yeah i know. I've calibrated it with a multimeter and it is correct. I'm actually using a 15.2 volt power supply.

Anyways thanks Jörg :D

- Tony B. Sydney, Australia.
tbaz2679@mail.usyd.edu.au

Status: Supporting the GNU