emonTx realPower vs apparentPower, and the effect of input noise

Hello all,

am designing a customized emonTx using the Arduino Uno ATmega328 uController, I have built a prototype on a breadboard and will like the community to help me valid the data am getting as regards the realPower and apparentPower.

I get two different reading of the real and apparent power when a load is connect and when no load is connect, am not sure if it suppose to be so

Here is the serial print output with load: (Electric Iron rated 220-240v, 2000-2400w)

1392.37 1397.43 214.79 6.51 1.00
1381.77 1384.42 214.07 6.47 1.00
1390.55 1392.04 214.84 6.48 1.00
1392.25 1393.25 214.89 6.48 1.00
1391.87 1392.41 214.89 6.48 1.00
1389.64 1390.21 214.84 6.47 1.00
1393.16 1393.65 214.96 6.48 1.00
1392.06 1392.27 214.91 6.48 1.00
1381.37 1381.65 214.18 6.45 1.00
1390.65 1391.04 214.97 6.47 1.00
1394.57 1394.78 215.11 6.48 1.00
1391.34 1391.62 214.87 6.48 1.00
1380.94 1381.31 214.23 6.45 1.00
1395.58 1395.83 215.18 6.49 1.00

and here without load:

0.20 8.46 223.86 0.04 0.02
-0.34 5.97 223.33 0.03 -0.06
0.69 9.93 222.45 0.04 0.07
0.28 4.16 223.61 0.02 0.07
-0.07 5.15 222.73 0.02 -0.01
-0.27 3.72 223.43 0.02 -0.07
-0.18 7.22 222.49 0.03 -0.03
0.11 5.24 223.93 0.02 0.02
0.27 3.77 222.61 0.02 0.07
0.70 6.33 223.31 0.03 0.11
-0.01 0.98 222.84 0.00 -0.01
-0.20 5.20 222.82 0.02 -0.04
-0.56 7.28 223.43 0.03 -0.08
0.08 3.82 223.44 0.02 0.02

as can be seen the real and apparent power is same and a power factor of 1.0 with load connected
and not so without load.

am about to order the PCB but am a bit concern about the difference in readings
is this the expected behavior or am I missing something

Unfortunately, this is the expected behaviour because what you are seeing under no-load conditions is noise from the digital circuits in the processor getting into the analogue input. Then, when you calculate the rms current, the noise is rectified by the maths and appears as a (relatively) large apparent power, whereas when you multiply each sample of voltage and current to get real power, the noise, not being rectified, tends to get averaged out.

Under a normal load, the noise is swamped and you don’t see it.

Anecdotally, most complaints about front-end noise have been from users of Arduino boards. The emonTx V3.4 seems to perform better than most alternative processor boards because great care was taken with the pcb layout.

Other than making sure your analogue front end obeys all the design rules of best practice, and trying to find an Arduino board or a clone that has the best filtering in the power supplies (because we think the way the noise gets in is from the digital circuits, into the supply, then into the analogue reference), there is probably little that you can do to minimise the problem.

You’ll find a lot in the old forums about this.

That was a quick reply - thanks

Will using an external ADC chip help

cause when no load my Energy computation (kWh) after awhile jump to 1193kWh every time it jump it jumps to the same value 1193 always. my kWh computation is done here:

unsigned long JoulesPerkWh = 3600000; // Joules per kWh

unsigned long KiloWh;
unsigned long Joules;


Joules += (emon.realPower * COMPUTEINTERVAL); // COMPUTEINTERVAL time btw reading in seconds
KiloWh += (Joules / JoulesPerkWh);
Joules = (Joules % JoulesPerkWh);

EnergykWh = KiloWh + (Joules * 1.0 / JoulesPerkWh);  // EnergykWh is defined as double

and since the system is free running with or without load it mean it’s not reliable - I have checked and checked where the error is coming from with out luck

the value have remained constant but can occur anytime (without load) and after that one time it never happens again no matter how long I allow the system to run with out load

If you do it properly, and you get the layout right - probably. But you will of course need to modify emonLib so that you drive the external multiplexer (I assume you will have one, either in front of or inside your ADC), and you’ll need to send the values to the Arduino presumably via I2C for onward transmission to wherever.

Without seeing the rest of your sketch, it’s almost impossible to say where that is coming from. Try working backwards from 1193 to find its significance - that might give you a clue. Is it the value that’s left after a computation has overflowed? Look at the C language specification and note the order that the operations within each statement are performed, then do the sums on paper and look at the answer at each step. Also beware integer truncation.

here is the full code

#include <EmonLib.h>
#include <MsTimer2.h>
#include <Timer.h>

// Energy Monitor Analog PINs
const uint8_t  voltageADC = A0;
const uint8_t currentADC = A1;

// Energy Monitor  Calibration parameter
const double vCalibration = 179.80; // New calibration = existing calibration × (correct reading ÷ emonTx reading)
const double cCalibration = 60.6;   // CT Ratio / Burden resistance = (100A / 0.05A) / 33 Ohms = 60.6 (for the emonTx Shield)
const double pCalibration = 1.2;

// Energy Monitor Variables
const uint8_t FILTERSETTLETIME = 5;  // Seconds to allow the filters to settle before sending data
const uint8_t COMPUTEINTERVAL = 5;    // Seconds between readings

unsigned long JoulesPerkWh = 3600000; // Joules per kWh

unsigned long KiloWh;
unsigned long Joules;
double EnergykWh;

// Energy Monitor  Object
EnergyMonitor emon; 

// Multitasking Object
Timer task;

void setup()
{
  Serial.begin(115200);
  while (!Serial) {};

  // setup Energy Monitor
  emon.voltage(voltageADC, vCalibration, pCalibration);   // Voltage: input pin, calibration, phase_shift
  emon.current(currentADC, cCalibration);               // Current: input pin, calibration.

  task.after(FILTERSETTLETIME * 1000, SetupTask);   // Enable task after the filter settles
}

void SetupTask()
{
   // Setup timer to Computer Kilowatt-Hour every COMPUTEINTERVAL
  MsTimer2::set(COMPUTEINTERVAL * 1000, ComputeEnergy);
  MsTimer2::start();
}

void loop() {
  emon.calcVI(20, 2000);  // Calculate all. No.of wavelengths, time-out
  emon.serialprint();

}

void ComputeEnergy()
{
  Joules += (emon.realPower * COMPUTEINTERVAL);
  KiloWh += (Joules / JoulesPerkWh);
  Joules = (Joules % JoulesPerkWh);

  EnergykWh = KiloWh + (Joules * 1.0 / JoulesPerkWh);

  Serial.println(F(""));
  Serial.println(F("********** Energy Monitor **********"));
  Serial.print(F("       Voltage: "));  Serial.print(emon.Vrms, 2); Serial.println(F(" V"));
  Serial.print(F("       Current: "));  Serial.print(emon.Irms, 2); Serial.println(F(" A"));
  Serial.print(F("Apparent Power: "));  Serial.print(emon.apparentPower, 2);  Serial.println(F(" VA"));
  Serial.print(F("    Real Power: "));  Serial.print(emon.realPower, 2);  Serial.println(F(" W"));
  Serial.print(F("    Used Power: "));  Serial.print(EnergykWh, 5); Serial.println(F(" kWh"));
  Serial.println(F(""));

}

I also notice that if load is connected when the system starts the problem of 1193kWh never occurred ( well for the three hours it ran) and come to think about it, this prototype is on a breadboard with jumper cables so I do expect a lot of noise

I think your problem is that ComputeEnergy() runs as an IRQ (attached to the Timer2 overflow vector). It then reads all of those emon variables: realPower, Vrms etc etc. none of which are safe to be read from IRQ level. Eventually the planets align and you end up reading them right while your main loop’s call to calcVI() is updating them and so you occasionally get inconsistent values.

And doing all those Serial.prints() at elevated IRQ is probably not a great move either.

I’m completely with dBC there. I would never have guessed from your first post that the lines you quoted were inside an interrupt service routine, so it was more than a little unfair to expect anyone to point you towards a solution to your problem. The general advice for an ISR is to do the absolute minimum amount of work necessary - you seem to have done close to the maximum possible.

For what you appear to want to do, I suggest you look at the continuous monitoring sketch (the sketch, NOT the library). If you don’t want to go down that (proven) route and wish to stay with your own, then your main code needs to turn off interrupts, make a copy the pertinent variable (realPower), then turn interrupts back on. The ISR then needs to make a second copy of the first copy (YES! the first copy is updated every time calcVI completes - about every 200 ms, the ISR makes the second copy every 5 s) and then set a flag so that the rest of the code in your ISR - the calculation and the print - is then done back in the main loop once every 5 s.

So you need something like this (N.B. it’s not tested).

Your ISR becomes 2 lines:

void ComputeEnergy()
{
  copy2ofrealPower = copyofrealPower;
  copyUpdated = true;
}

and then in your main loop

NoInterrupts();
copyofrealPower = emon.realPower;
interrupts();

if (copyUpdated)
{
  copyUpdated = false;
  Joules += (copy2ofrealPower * COMPUTEINTERVAL);
  … etc …
  … print statements …
}

and copyofrealPower and copyUpdated should both be declared as volatile so that the compiler doesn’t try to optimise them.

noInterrupts() prevents the ISR from running while it’s copying the variable. If the ISR wanted to run then, it’ll happen immediately interrupts are turned on again.

As long as it takes less than 5 s to do the prints etc, you should be OK.

But the code as you have it is rather pointless, because although you’re running calcVI() continually - roughly every 200 ms (depending on how long your serialprint() takes), you’re only taking a snapshot of the result every 5 s anyway. Our continuous monitoring sketch does exactly what it says, and catches power usage that’s a lot shorter than 5 s - more like a few ms.

I total forgot that hardware interrupt rules also applies to software interrupts thanks @dBC and @Robert.Wall

where can I find this sketch? as there so many out there I couldn’t keep track of which is which

Github. I think it’s under the emonTx V3.4 group. It’s got “continuous” in the name.

Most with “continuous” looks a bit too complicated, couldn’t even follow the logic and they depend on the EmonLibCM library

How about this, do you see any issue with it moving emon.calcVI() into the ISR with a compute interval of 1s and all necessary variables declearded as volatile

#include <EmonLib.h>
#include <MsTimer2.h>
#include <Timer.h>

// Energy Monitor Analog PINs
const uint8_t  voltageADC = A0;
const uint8_t currentADC = A1;

// Energy Monitor  Calibration parameter
const double vCalibration = 179.80; // New calibration = existing calibration × (correct reading ÷ emonTx reading)
const double cCalibration = 60.6;   // CT Ratio / Burden resistance = (100A / 0.05A) / 33 Ohms = 60.6 (for the emonTx Shield)
const double pCalibration = 1.2;

// Energy Monitor Variables
const uint8_t FILTERSETTLETIME = 5;  // Seconds to allow the filters to settle before sending data
const uint8_t COMPUTEINTERVAL = 1;    // Seconds between readings

unsigned long JoulesPerkWh = 3600000; // Joules per kWh

volatile unsigned long KiloWh;
volatile unsigned long Joules;
volatile double EnergykWh;

// Energy Monitor  Object
EnergyMonitor emon;

// Multitasking Object
Timer task;

void setup()
{
  Serial.begin(115200);
  while (!Serial) {};

  // setup Energy Monitor
  emon.voltage(voltageADC, vCalibration, pCalibration);   // Voltage: input pin, calibration, phase_shift
  emon.current(currentADC, cCalibration);               // Current: input pin, calibration.

  task.after(FILTERSETTLETIME * 1000, SetupTask);   // Enable task after the filter settles
}

void SetupTask()
{
  // Setup timer to Computer Kilowatt-Hour every COMPUTEINTERVAL
  MsTimer2::set(COMPUTEINTERVAL * 1000, ComputeEnergy);
  MsTimer2::start();
}

void loop() {

  // do other things here
  delay(1000);
  Serial.print(F("Used Energy"));
  Serial.println(EnergykWh);
}

void ComputeEnergy()
{
  emon.calcVI(20, 2000);  // Calculate all. No.of wavelengths, time-out

  Joules += (emon.realPower * COMPUTEINTERVAL);
  KiloWh += (Joules / JoulesPerkWh);
  Joules = (Joules % JoulesPerkWh);

  EnergykWh = KiloWh + (Joules * 1.0 / JoulesPerkWh);

NO! You must keep the ISR as short and as fast as possible.

Look again. The emonTxV3_4_continuous_kwhtotals.ino sketch I pointed you towards - and you do want energy, don’t you - does not use emonLibCM (which has serious faults anyway, so don’t try to use it at this time).

Stop and take a look at what you were actually doing. Think what you really want to do. Get paper, pencil and eraser and do some diagrams, because I think you’ve got embedded in the details and you’ve lost sight of the big scheme of things.

What you’ve now done might work, but doing more or less all the sketch in an ISR flies in the face of time-honoured programming practice, and I wouldn’t like to say it will definitely work. You still have the approximation that you’re basing your energy calcs on a single 200 ms average that represents a 5 s window. Is that what you really want to do?

Am not sure I understand this sketch well enough to be able to modify it for my use, but I noticed that the ADC is set for free running interrupting the main loop anytime its done, am wondering if the u-controller (ATmega328) will have enough time to execute the main loop and update an OLED Display and read other sensors as energy monitoring is just the second important variable the system is monitoring

for a start, since am using just one VT and CT how do adapt the ISR for 1-VT and 4-CT and then I don’t understand the calibration process

// An Interrupt Service Routine is now defined in which the ADC is instructed to perform 
// a conversion of the voltage signal and each of the signals for current.  A "data ready" 
// flag is set after each voltage conversion has been completed, it being the last one in
// the sequence.  
//   Samples for current are taken first because the phase of the waveform for current is 
// generally slightly advanced relative to the waveform for voltage.  The data ready flag 
// is cleared within loop().

// This Interrupt Service Routine is for use when the ADC is in the free-running mode.
// It is executed whenever an ADC conversion has finished, approx every 104 us.  In 
// free-running mode, the ADC has already started its next conversion by the time that
// the ISR is executed.  The ISR therefore needs to "look ahead". 
//   At the end of conversion Type N, conversion Type N+1 will start automatically.  The ISR 
// which runs at this point therefore needs to capture the results of conversion Type N , 
// and set up the conditions for conversion Type N+2, and so on.  
// 
ISR(ADC_vect)  
{                                         
  static unsigned char sample_index = 0;
  
  switch(sample_index)
  {
    case 0:
      sample_V = ADC; 
      ADMUX = 0x40 + currentSensor_CT2; // set up the next-but-one conversion
      sample_index++; // advance the control flag             
      dataReady = true; 
      break;
    case 1:
      sample_CT1 = ADC; 
      ADMUX = 0x40 + currentSensor_CT3; // for the next-but-one conversion
      sample_index++; // advance the control flag                
      break;
    case 2:
      sample_CT2 = ADC; 
      ADMUX = 0x40 + currentSensor_CT4; // for the next-but-one conversion
      sample_index++; // advance the control flag                
      break;
    case 3:
      sample_CT3 = ADC; 
      ADMUX = 0x40 + voltageSensor; // for the next-but-one conversion
      sample_index++; // advance the control flag                 
      break;
    case 4:
      sample_CT4 = ADC; 
      ADMUX = 0x40 + currentSensor_CT1; // for the next-but-one conversion
      sample_index = 0; // reset the control flag                
      break;
    default:
      sample_index = 0;                 // to prevent lockup (should never get here)      
  }  
}

I give up. You never mentioned any of that, so I’ve been wasting my time with you.

Study that sketch, figure out how the interrupts work and how the multiplexer and the ADC interact with the ISR, then make sure that you can send the data to your display and not care when it gets interrupted.

If it’s beyond you, go back to emonLib and calcVI, and just measure the time between measurements instead of trying to insist they happen at exact 5 s intervals. What difference does it make? The total energy consumed is the same if you measure it every 5 s, or every 4.9 s and 5.1 s alternately.

Or as I tried to tell you a couple of posts ago, work out what your problem really is and devise a solution on paper, without a computer in sight.

Not at all, I’ve learned through this interaction and am sure other will also learn from it in the furture.

Am explorering all the options you mentioned. On the issue of the random 1193kWh, it occurs because of the occasional negative realPower returned by emon when no load is connected and when used in this formula

	Joules += emon.realPower * COMPUTEINTERVAL;
	KiloWh += (Joules / JoulesPerkWh);
	Joules = (Joules % JoulesPerkWh);

	EnergykWh = KiloWh + (Joules * 1.0 / JoulesPerkWh);

can return an undefined EnergykWh. I’ll look for how to handle the negative realPower maybe
abs(realPower) will do the trick or discard negative realPower since am not interested in the direction of the current flow