Calculating kwh using arduino, doesn't match utility meter

Hello, I have a single utility feed to the house utility meter that splits off and feeds two breaker panels, both are 240V (i’m in USA). I put a total of 4 CTs on the system, one CT on each hot leg of the two panels. Then i used one voltage transformer. All of these signals goes into an arduino. I’m able to calibrate all 4 of the CTs referencing it to a clamp on ammeter and they match well.
The problem i’m having is trying to calculate kilowatt hours for the entire system. I can’t get it to match the utility kwh rate. Mine seems to be slower for some reason. Could you look at my arduino code and see if i’m doing something wrong?


#include "EmonLib.h"  //use power monitor (openenergymonitor.org)

//define variables for powermonitor:
float watts1;
float watts2;
float Irms1;
float Irms2;
float VA1;
float VA2;
float voltage;

//variables to use in kWh calculation:
unsigned long sample1=0;
unsigned long time1=0.0;  
unsigned long timeM1 = millis(); 
unsigned long wattseconds1=0;  
unsigned long watthours1=0.0;  

unsigned long sample2=0;
unsigned long time2=0.0;
unsigned long timeM2 = millis();
unsigned long wattseconds2=0;  
unsigned long watthours2=0;   

unsigned long kwh=128200;

//Create an instance of the energymonitor:
//emon1 and emon2 for left breaker panel
//emon3 and emon4 for right breaker panel
EnergyMonitor emon1;
EnergyMonitor emon2;
EnergyMonitor emon3;
EnergyMonitor emon4;

void setup() //run once, when the sketch starts.
{
  Serial.begin(38400);  

  emon1.voltage(1,117.5,2); //voltage: input pin, calibration, phase_shift 
  emon1.current(2,88);  
  
  emon2.voltage(1,117.5,2); 
  emon2.current(3,88);  
  
  emon3.voltage(1,117.5,1.28); 
  emon3.current(6,49);  
  
  emon4.voltage(1,117.5,1.28); 
  emon4.current(7,48.6);  
 
  delay(1000);
 
  

}

void loop()
{

         emon1.calcVI(20,2000); //calculate all (No of wavelengths or crossings, time-out)
         emon1.serialprint();   //print out all variables. 

         emon2.calcVI(20,2000);
         emon2.serialprint();
  
         emon3.calcVI(20,2000);
         emon3.serialprint();
     
         emon4.calcVI(20,2000);
         emon4.serialprint();

    
         watts1=emon1.realPower; + emon2.realPower;
         watts2=emon3.realPower + emon4.realPower;
         Irms1=emon1.Irms + emon2.Irms;
         Irms2=emon3.Irms + emon4.Irms;
         VA1=emon1.apparentPower + emon2.apparentPower;
         VA2=emon3.apparentPower + emon4.apparentPower;
         voltage=emon1.Vrms;


         if (abs(Irms1) >= 0.1) 
         {
         
            time1 = millis() - timeM1;    
            timeM1 = millis();
            sample1 = sample1 + 1;  
            wattseconds1 = wattseconds1 + (abs(watts1) * time1/1000);  

             for(wattseconds1; wattseconds1 >= 3600; wattseconds1 = wattseconds1 - 3600) 
            {
              watthours1 = watthours1 + 1;
              
            }
         }
      
         if (abs(Irms2) >=0.1) 
         {
            time2 = millis() - timeM2;    
            timeM2 = millis();
            sample2 = sample2 + 1;  
            wattseconds2 = wattseconds2 + (abs(watts2) * time2/1000);  
            for(wattseconds2; wattseconds2 >= 3600; wattseconds2 = wattseconds2 - 3600) 
            {
              watthours2 = watthours2 + 1;
            }
         }

         kwh = kwh + (watthours1/1000 + watthours2/1000);

         Serial.print("wattseconds1: ");
         Serial.println(wattseconds1);
         Serial.print("wattseconds2: ");
         Serial.println(wattseconds2);
 

         Serial.print("watthours1: ");
         Serial.println(watthours1);
         Serial.print("watthours2: ");
         Serial.println(watthours2);

         Serial.print("kwh: ");
         Serial.println(kwh);

}//end loop

Welcome, Mike, to the OEM forum.

How much slower? Are you chasing a 1% error or a 100% error? What are the numbers you get?

and

but did you also calibrate the PHASECAL for each c.t?

There’s one potential problem I’ve spotted: you’ll be suffering integer truncation in that line (and the other one like it): it will do the multiplication and division OK, but then throw away any fractional part. Depending on how fast you do the main loop - and because you have no delays in the loop, it might be repeated in less than 1 second, the missing fraction could be significant.

[Edit]
I’m also not sure about the first expression in the for loop: it’s equivalent to the assignment
wattseconds1 = ;
and I’m not sure how the compiler will handle it. All the expressions in the for statement are optional. This might be the error you’re looking for. You can make the whole statement more succinct too:

for( ; wattseconds1 >= 3600; wattseconds1 -= 3600, watthours1++) ;

but my preference - it just “reads better” to me - would be

while (wattseconds1 >= 3600)
{
  wattseconds1 -= 3600;
  watthours1++;
}

[/Edit]

You might want to look at emonLibCM - this calculates energy for you, but it’s not a direct substitute for emonLib. I don’t own an Arduino, so it’s not been tested on one; but with correct initialisation (notably ADCCal) and calibration, it ought to work. The latest version is here: EmonLibCM - Version 2.2.2
Even with emonLibCM, my experience is you’ll never get a perfect match all the time on all loads - at least with our default 100 A c.t’s., and that’s because the c.t’s phase error changes according to the current. You may fare better with different c.t’s.

[emonLibCM carries over the integer truncation into the next report.]

Robert,
Thanks for the review. Over a period of 24 hours the utility meter shows that 76kwh were used, while my program shows that 60kWh were used.

However, I did just find an error in the following line, that extra semicolon shouldn’t be there, not sure why the compiler didn’t catch it:

watts1=emon1.realPower; + emon2.realPower;

I also added some code for the fractional part of the wattseconds that would be cut off by the integer truncation, code is below. If there is a better way to do this, let me know.

For the PHASECAL, all I did was downloaded and run the sketch “phasecalcheckertool” by calypso_rae that i found on open energy forum, then turn off everything in the house, then turn on my electric heater, and got a 0.99 pf, this occurred when the PHASECAL was at 1, so that’s what i ended up using. Not sure if this is the best approach since i’m using air conditioners most of the time that use more reactive power?

also, how would i get the overall power factor for the house since i have 4 CT measurements and 4 calcVI statements, should i take the average of the 4 power factor results?

I’ll monitor this for a while and see if there is any improvement.
Here is a section the next rev of the code:

if (abs(Irms1) >= 0.1)
         {
            wattsec_measured1 = ((abs(watts1) * time1)/1000);  
            wattsec_measured_fract1 = wattsec_measured_fract1 + (wattsec_measured1 - int(wattsec_measured1)); //only gives fractional part of the result
            wattseconds1 = wattseconds1 + wattsec_measured1;  
 
            while (wattsec_measured_fract1 >=1)
            {
                wattseconds1 ++;
                wattsec_measured_fract1--;
            }
 
            while (wattseconds1 >=3600)
            {
                wattseconds1 = wattseconds1 - 3600;
                watthours1 = watthours1 + 1;
            }
         }

note that wattsec_measured1 and wattsec_measured_fract1 are floats.

Because there’s nothing wrong with it! It wasn’t what you wanted, but is is two separate statements:

watts1=emon1.realPower; 
+ emon2.realPower;

The first assigns the value of realPower to watts1, the second does nothing. (Had it been ++emon2.realPower; it would have incremented it by one.)
[And I missed it too :cry: ]

It’s the only approach. If you adjust using your aircon as the load, it’s like using an elastic tape measure - you can make the measurement whatever you want it to be. If you’ve got a very poor power factor most of the time, it’s more important than ever to get it calibrated accurately on a purely resistive load, and ideally using a current nearer to the current that these loads draw (but then your high power loads might be in error - it’s a matter of juggling the numbers to get it least bad for everything.

You must calibrate each c.t. separately. If you want the overall power factor, then it’s total real power / total apparent power, and that’s not the same as the average of four separate power factors.

I wouldn’t have used a loop - it’s just 3 lines:

double wattsec_measured1 = 0;
static double wattsec_carried forward1 = 0;
long wattseconds1 = 0;

...

wattsec_measured1 = ((abs(watts1) * time1)/1000) + wattsec_carriedforward1;  
wattseconds1 = (int)wattsec_measured1;
wattsec_carriedforward1 = wattsec_measured1 - wattseconds1;