power meter using arduino due

hi, im new here..

so i've been trying to make an energy meter that will display the average power (which is also the real power,correct?) and energy in Watt-hour. im using hall effect sensor for current and 240-9 VAC transformer for voltage. both are connected to voltage divider to give an output proportional to the AC value. i intended to display average power but until now i can only measure the instantaneous power which are the product of the instantaneous voltage and current. how can i get the average value? i thought it is just simple matter of taking n-value of reading then divide it by n, but it doesnt work.

also, i have no idea how the emonlib works.

thanks in advance!

You have to sample often enough across the AC cycle, and sum the instantaneous
powers, scaling by the sample period to get energy in true units.

Say you sample at 1kHz, then sample period = 1ms, so:

  while (micros () - last_tick < 1000)
  {}
  last_tick += 1000 ;
  float instanteous_power = measure volts() * measure_amps () ;
  energy += 0.001 * instantaneous_power ;
  ...

In other words the discrete version of integrating V.I.dt

since im working with wall wart, that means the frequency must be 50-60 Hz right? if not,how can I find the sample period?
oh, and this is my code for now:

  #include <LiquidCrystal.h>// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
lcd.begin(16, 2);
Serial.begin(9600);  
}

void loop() {
  long milisec = millis(); // calculate time in milliseconds
  long time=milisec/1000; // convert milliseconds to seconds
  double sensorV = analogRead(A1);
  double sensorC = analogRead(A2);
  double voltage;
  double current;
  double energy;
  double realPower =0;
  double sum_inst_power;
  
  for (int n=0;n<1000;n++)
  {
  double inst_power=0;
  current=(sensorC*0.059333)-23.496001;
  voltage = (sensorV*0.935017)-529.219753;
  inst_power=voltage*current/2; 
  sum_inst_power=sum_inst_power+abs(inst_power);
  delay(0.05);
  }
  realPower=sum_inst_power/1000.0;
  time=millis();
  energy=(realPower*time/1000)/3600;
  delay(2);
  
  lcd.setCursor(5, 0);
  lcd.print(realPower);
  lcd.setCursor(5, 1);
  lcd.print(energy);

  Serial.print(voltage,6);
  Serial.print("V  ");
  Serial.print(current,6);
  Serial.print("Amp  ");
  Serial.print(realPower,6);
  Serial.print("Watt  ");
  Serial.print(energy,3);
  Serial.println("Wh  ");

  delay(200);
  
}

can you point out any mistakes here?thanks

feeiq90: since im working with wall wart, that means the frequency must be 50-60 Hz right? if not,how can I find the sample period?=

"often enough across the mains cycle"... The cycle is either 20ms or 16.7ms, what is often enough depends on the accuracy you want and how harmonic-rich your supply is. 1k is perhaps a minimum rate to choose, faster is better.

I see…thanks…another question,is this correct…
thanks

  for (int n=0;n<1000;n++)
  {
  double inst_power=0;
  current=(sensorC*0.059333)-23.496001;
  voltage = (sensorV*0.935017)-529.219753;
  inst_power=voltage*current/2; 
  sum_inst_power=sum_inst_power+abs(inst_power);
  delay(0.05);
  }
  realPower=sum_inst_power/1000.0;

Can’t be, you’ve a spurious divide by 2 when multiplying voltage by current, and you
are not summing the energy (energy = power x time)

  float instanteous_power = measure volts() * measure_amps () ;
  energy += sample_period * instantaneous_power ;

where sample_period is in seconds, voltage in volts, current in amps.

Your delay(0.05) is wrong, delay takes an integer number of milliseconds. You might
mean

  delay ((int) sample_period * 1000) ;

but actually this is wrong as the delay is not synchronous, you need this method
to get accurate timing:

  while (micros () - last_tick < period_us)
  {}
  last_tick += period_us ;

where period_us = (int) 1000000 * sample_period ;

sorry, i divided the inst_power by 2 since the voltage and current are the max value, so since
instantaneous power=vrmsirms,
=vm
im/2

i still dont understand this though:

while (micros () - last_tick < period_us)
  {}
  last_tick += period_us ;

i thought the delay is just to make it easier to read the value on the serial monitor

*sorry,I can be really ignorant sometimes

The delay is synchronous (its locked to the system clock without risk of drifting), and is needed to achieve consistent sample timings, so that the integration calculations are unbiased.

If you call delay() that doesn't account for the rest of the time spent going round your sampling loop (or any other code for that matter), and also if you update the last_tick variable from millis() or micros() you'll also get some drift.

thanks…i changed my coding (calculate power using Vrms and Irms) and now it works but not that accurate…i test my power meter with a 150W light bulb, and it gives a reading of 147W-152W…any idea how to increase the accuracy to 1% (148.5-151.5W)?
here’s how the code is now:

    for(int n=0;n<10000;n++)
  {
  voltage = ((analogRead(A1)*0.003255)-1.842330)*288.0492018;
  sqvolt=voltage*voltage;
  sumsqvolt += sqvolt;
  current = ((analogRead(A2)*0.003255)-1.285725)*17.0890937;
  sqcur=current*current;
  sumsqcur += sqcur;
  }
  float meansqvolt = sumsqvolt/10000;
  float rmsvolt=sqrt(meansqvolt);
  float meansqcur = sumsqcur/10000;
  float rmscur=sqrt(meansqcur);
  float power =rmsvolt*rmscur;
  float energy = (power*sec/3600)/1000;

another question,to get the rms value, i took 10,000 readings…it doesnt work however, if i change the number of reading.taking 1000 readng like you suggest earlier also works but not as accurate…does it have anything to do with due’s sampling rate?

MarkT:
The cycle is either 20ms or 16.7ms, what is often enough depends on the accuracy you
want and how harmonic-rich your supply is. 1k is perhaps a minimum rate to choose,
faster is better.