AC Energy Meter calculation using ACS712

Thread Starter

deepak4you

Joined May 1, 2010
46
Experts! Shout for help again!

I'm trying to build an AC power/energy meter for some project of mine. I'm using the ACS712 Hall Effect current sensor for this project due to its compact size and very high output linearity. I'm using the 30A version of this sensor. I use the ADS1115 16bit ADC to read the output from ACS712 and process it in the code.

I'm building this on an ESP8266 microprocessor board using Arduino IDE. Below is my code for calculating the power. As a starting point, I've taken the code for now from:

https://www.instructables.com/id/Arduino-Energy-Meter-V20/

C:
// Arduino Energy Meter V2.0
// This code is for This code is for Wemos(ESP8266) based Energy monitoring Device
// This code is a modified version of sample code from https://github.com/pieman64/ESPecoMon
// Last updated on 30.05.2018
#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

Adafruit_ADS1115 ads(0x48);  /* Use this for the 16-bit version */


#define SERIAL_BAUD 115200
int ledPower = 12;
// ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV (default)
// ads.setGain(GAIN_ONE);     // 1x gain   +/- 4.096V  1 bit = 2mV
// ads.setGain(GAIN_TWO);     // 2x gain   +/- 2.048V  1 bit = 1mV
// ads.setGain(GAIN_FOUR);    // 4x gain   +/- 1.024V  1 bit = 0.5mV
// ads.setGain(GAIN_EIGHT);   // 8x gain   +/- 0.512V  1 bit = 0.25mV
// ads.setGain(GAIN_SIXTEEN); // 16x gain  +/- 0.256V  1 bit = 0.125mV

unsigned int Sensitivity = 66;   // 185mV/A for 5A, 100 mV/A for 20A and 66mV/A for 30A Module
float Vpp = 0; // peak-peak voltage
float Vrms = 0; // rms voltage
float Irms = 0; // rms current
float Supply_Voltage = 247.0;           // reading from DMM
float Vcc = 5.0;         // ADC reference voltage // voltage at 5V pin
float power = 0;         // power in watt            
float Wh =0 ;             // Energy in kWh
unsigned long last_time =0;
unsigned long current_time =0;
unsigned long interval = 100;
unsigned int calibration = 12;  // V2 slider calibrates this
unsigned int pF = 85;           // Power Factor default 95


void getACS712() {  // for AC
  Vpp = getVPP();
  Vrms = (Vpp/2.0) *0.707;
  Vrms = Vrms - (calibration / 10000.0);     // calibtrate to zero with slider
  Irms = (Vrms * 1000)/Sensitivity ;
  if((Irms > -0.015) && (Irms < 0.008)){  // remove low end chatter
    Irms = 0.0;
  }
  power= (Supply_Voltage * Irms) * (pF / 100.0);
  last_time = current_time;
  current_time = millis();  
  Wh = Wh+  power *(( current_time -last_time) /3600000.0) ; // calculating energy in Watt-Hour

  Serial.print("Irms:  ");
  Serial.print(String(Irms, 3));
  Serial.println(" A");
  Serial.print("Power: "); 
  Serial.print(String(power, 3));
  Serial.print(" W");
  Serial.print("\t Energy Unit(s) (KWh): ");
  Serial.println(String((Wh/1000), 4));

}

float getVPP()
{
  int16_t adc1;
  float result;
  int readValue;              
  int maxValue = 0;           
  int minValue = 32768;        
  uint32_t start_time = millis();



  while((millis()-start_time) < 950) //read every 0.95 Sec
  {
     readValue = ads.readADC_SingleEnded(1);  
     if (readValue > maxValue)
     {       
         maxValue = readValue;
     }
     if (readValue < minValue)
     {        
         minValue = readValue;
     }
  }
   result = ((maxValue - minValue) * Vcc) / 32768.0;
   Serial.print("\nVp-p:  ");
   Serial.println(String(result, 3));
 
   return result;
}


void setup() {

  Serial.begin(115200);
  Serial.println("\n Rebooted");
  Serial.begin(SERIAL_BAUD);

  while(!Serial) {} // Wait
  Wire.begin(D3,D4); //Changed defaults to match ESP8266 pin connections: 23 - SDA, 24 - SCL
  ads.begin();

  WiFi.begin("Tulsani", "homenetwork");
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());

  pinMode(ledPower,OUTPUT);

}

void loop()
{

  getACS712();
  delay (2000);
}
For testing, I'm using a 200W filament bulb as load.

Issue that I'm facing is:
- When I check the current on my DMM, it shows approx 0.8A of current drawn
- Output of the ESP8266, using the above code, shows me a current drawn of approx 1A

AC voltage seen on my DMM is approx 245V (I know its on the higher side. It should be around 230V, but what to do ... its India).

Can someone help me understand/identify where am I going wrong or where the code is going wrong? Would be of immense help!

Regards,
Deepak
 

dendad

Joined Feb 20, 2016
3,075
If you want accurate readings, it is always a good idea to calibrate the readings on ADCs as a lot depends on the resistors used, and the ref volts. If your meter is accurate, just alter the calcs in your code to get the same reading.
Use at least 1% or 0.5% resistors too, or better if you can afford them. But the main thing is the stability so the readings are repeatable.
What is your circuit? Are you just using a peak rectifier or a true RMS circuit?
A schematic will help.
 

danadak

Joined Mar 10, 2018
3,611
And end to end error budget is invaluable. Vref, G accuracy, PSRR, T, V....all
effect accuracy, including the reference DVM you are using.

One way of handling this is do a sweep of V from an accucrate source, and use
that to develop a least squares error fit or power curve fitting function to take
readings and c orrect them. Do this at production test and burn corrections into
EEPROM.

upload_2018-7-22_9-51-4.png

Regards, Dana.
 

ebp

Joined Feb 8, 2018
2,332
code snippet:
Vpp = getVPP();
Vrms = (Vpp/2.0) *0.707;
Vrms = Vrms - (calibration / 10000.0); // calibtrate to zero with slider
Irms = (Vrms * 1000)/Sensitivity ;

This is just weird. RMS calculated by assuming a sine wave, and then Irms is calculated rather than measured. Maybe I'm missing something, but I don't see any code that actually measures the current, and "Sensitivity" appears to be nothing more than a constant.

If that code does what I think it does, I'm not the least bit surprised the reported value is way off.
 

ebp

Joined Feb 8, 2018
2,332
I looked at the instructables article. By and large it is a load of nonsense.

If you want to properly measure current, voltage, power and power factor you measure the instantaneous values of voltage and current some large number of times during a full line cycle and calculate them directly instead of applying constants that are meaningful only in specific well-defined circumstances.

For example, to determine RMS current you directly calculate the square root of the mean of the squares of the a large number of current samples collected over a full cycle (or multiple full cycles). The article opens with current and voltage waveforms that will produce gross error if this sort of method is not used. The power factor is low, but it has nothing whatever to do with the phase angle between voltage and current (very close to zero), rather it is because the load is very non-linear. Using phase angle is only valid for linear loads.

EDIT - be careful with those hall effect current sensor modules. Every one I have seen a photo of has been laid out very badly in terms of safety. The sensors are carefully designed to allow a layout with good isolation and every board I've seen has undone the manufacturer's intent by bad layout.
 

Thread Starter

deepak4you

Joined May 1, 2010
46
@ebp 66 comes from the specification of the ACS712 sensor i.e. 66mv/A, for the 30A version that I'm using. The output of the sensor is a voltage proportional to the current drawn. Range of the sensor output voltage is 0-5V. Hence the calculation converting the sensor output voltage to AC current to proportional to that sensor output voltage.

My load is going to be an SMPS power supply rated 5kW-6kW. Wonder how linear a load will that be.

I posted my query on Arduino forum as well. It looks like I indeed will have to take lot many samples than I'm able to take now, for which I'll have to use a different ADC.

So I seem to be having two issues to address - better code to calculate current, and a better ADC to get lot more samples than I currently am. Let me fix the latter first.

On the sidelines, is there a way other than using a step-down transformer, to measure voltage accurately for my purpose? I'm just not convinced I'll get a reliable and good quality transformer here in India to have accurate voltage readings. Reason I ask for this is that my output would be even more accurate if I can incorporate a voltage detector as well, as currently I'm hardcoding the mains voltage.
 

dendad

Joined Feb 20, 2016
3,075
On the sidelines, is there a way other than using a step-down transformer, to measure voltage accurately for my purpose? I'm just not convinced I'll get a reliable and good quality transformer here in India to have accurate voltage readings. Reason I ask for this is that my output would be even more accurate if I can incorporate a voltage detector as well, as currently I'm hardcoding the mains voltage.
A transformer should work ok. You do not need an "accurate" transformer. Just measure the input volts and the output volts while terminated with the load resistor your measuring circuit will be using and use those numbers. An old 240V to 6V analog plug pack transformer would be fine.
 

ebp

Joined Feb 8, 2018
2,332
A switcher in that power range will likely have active power factor correction (called active harmonic filtering in some places) that will make it look like a resistive load (the instantaneous input current will be proportional to the input voltage and the average current will be inversely proportional). If it does not have power factor correction it will be very non-linear. The current waveform in the instructables article is somewhat like what you would expect, except that waveform has a linear (resistive) component and a non-linear (capacitive) component.
That is a very large amount of power for a single-phase switcher.

OK, I see now (I think) that the code just obscures the fact that it is the current sensor that is being read because the variable names are what I would regard as inappropriate in a power measuring instrument. I would never name a variable with anything to do with current Vpp, but something like IsenseVpp so as to make it clear it is from the current sensor. To me, Vpp would be the peak to peak voltage across the load. I would also name the ADC channel according to function, not "adc1." It takes a little longer to type good variable names but it makes code a lot easier to read (I have a hatred for underscores in variable names because they really do make typing a pain, but some people use them happily; I prefer mixed-case). When I can do it in a sensible fashion, I like to make variable names match net names on a schematic (which I use quite abundantly because it makes the documentation easier to write and the schematic more self-documenting).

float Vcc = 5.0; suggests to me that the board's power supply is being used as the reference for the ADC. If that is the case you must realize that accuracy of no more about 7 or 8 bits can be justified. If you expect to use a 16 bit ADC for accuracy instead of just resolution, you will need a very good voltage reference. Getting 16 bits from a converter requires a lot of care in every part of the circuit. The temperature coefficient of resistance of common 1% tolerance resistors will render several bits meaningless (a 20°C change in temperature will amount to 0.2% change or 1 part in 500 or 1 least significant bit at 9 bits). I pay the equivalent of about 1 US dollar per resistor for resistors anywhere near adequate for even 14 bits in terms of stability with time and temperature. As dana said, an error budget is a very important thing in instrument design - important and often horribly depressing!

I see a lot of "floats" that aren't floating point - they are values represented by a fixed number of bits. Using floating point is fine if you don't mind wasting time and memory.

As dendad says, any small transformer will do a reasonable job provided the line waveform is reasonably sinusoidal without discontinuities. That is usually the case, but I've seen some pretty serious distortion due to some types of industrial loads. A transformer will introduce a little bit of distortion and a little bit of phase shift, but neither is likely to be too serious. It does mean that ADC resolution beyond 8 or 9 bits is likely to be wasted (not justified based on inherent error in what is being measured). I would load the secondary with a resistor at perhaps 5% of the rated full power of the transformer.

[edited to clean up some residual junk]
 

Thread Starter

deepak4you

Joined May 1, 2010
46
@ebp - thanks for your inputs. I'll clean up the code a little later once I have the crude design functioning well. Might be a little lazy on my side.

I also got a feedback that with ESP8266, USB power might not be enough. So I added external power and now the readings atleast are very stable.

I also got a precision voltage transformer (ZMPT107) for voltage measurement that I'll use to make my readings more accurate.

Its been going very slow amidst other tasks, but trying to get there slowly.

Regards,
Deepak
 

Thread Starter

deepak4you

Joined May 1, 2010
46
Precision voltage transformer is working now and I can get realtime voltage reading as well. Although the ADC reading for vtg and multimeter reading of vtg is differing by 5 volts (which I'm unsure of as to why), but I'll live with this for now.

Current reading using the ACS712 is still showing just about 129 watts. Tomorrow I'll integrate the current transformer to get better readings off it. Hope that works better.
 

Thread Starter

deepak4you

Joined May 1, 2010
46
Installed the CT as well and the reading is lot better now. I'm getting 177W power consumption reading for a 200W tungsten bulb. with realtime vtg and current readings.

Is there a way I can use a test load to calibrate my readings? I understand the complications of calculating current and power readings for non-resistive loads, but if there's an easy way to calibrate, please to share. Not sure if using my Mastech DMM would be a good way to calibrate?

Regards,
Deepak
 

dendad

Joined Feb 20, 2016
3,075
Is there a way I can use a test load to calibrate my readings? I understand the complications of calculating current and power readings for non-resistive loads, but if there's an easy way to calibrate, please to share. Not sure if using my Mastech DMM would be a good way to calibrate?
If you have an old electric radiator, that may be a better load than a lamp.
Calibrate at near your max current can help.
 
Top