Welcome to Solarduino , A blog about DIY Solar PV and Arduino projects

How to measure Power Factor and Phase Angle with Arduino?

In Alternating Current (AC) electrical system, wave patterns are involved where values are oscillate with time. Today we would like to talk about Phase Angle or Phase Shift. Phase shift is a small difference of oscillation time between two waves pattern. It is a delay between two waves that have same period or frequency. Phase shift is expressed in positive or negative angle which is within -180 to 180 degree and we called it Phase Angle.

Phase shift can be applied between Voltage and Current wave of a particular electrical system. It is often applied by metering system to obtain the quality of the loads / generator. By knowing the phase angle between the Voltage and Current waves, terms such as Power Factor, Real Power, Apparent Power and Reactive Power can be defined. 

Phase shift can also be used between Voltage and Voltage wave in a 3-Phase system. It is an important electrical parameter to determine the phase sequence for 3 phase system. Each of the voltage phase is co-relate with adjacent phases by 120 degree phase angle according to right rotation angle. By messing up the phase sequence, there might be issues with your 3-phase loads especially with loads using motor or compressor operation.

For the phase angle comparison, the first wave is taken as a reference to the other. The wave that always taken as reference is always the voltage wave as current wave is always altered based on the applied load. You can also compare between 2 or even 3 voltage waves for a 3-phase system.

Warning ! You are now dealing with high power source ! We assumed that you have the basic electrical knowledge and know what you are dealing with. You may need guidance from experienced guys if you are new to electrical work. Safety and Precaution must be always have in mind. We shall not be responsible for anything happening to you.

The 2 common methods

There are 2 methods to determine the phase angle. The first method is by measuring the time difference to reach peak value (or 0 value) between both waves while using the same starting time or point. This method is direct and simpler method to obtain phase angle. This method is measured based on 2 reference point only (the starting point and peak value point) and it is suitable for pure wave and distorted or high disturbance wave. This method required to measure the period of wave in order to determine the angle value. This post will be using this method for calculation.

The second method is going through calculation by comparing values between averaged instantaneous value and product of RMS values. Phase angle is related to power factor which can be obtained by dividing averaged instantaneous of product values (multiplication of every instantaneous value of wave A and B and average them) and RMS product values (multiplication of RMS wave A and RMS wave B). It is more complicated compared to the previous method as many calculation is involved. This method is more like an average value as each segment of wave also involved for phase angle calculation. Wave frequency or period is not required over a large quantity of sample readings. This method may not be accurate on highly disordered wave or have a lot of electrical noises. We will reserve this method for other post : how to measure AC Power with Arduino. You can check it out here

Arduino UNO (compatible board)

If you still not yet own an Arduino Micro-controller Board, you can get it cheap at our affiliate link here !!!

Arduino has the ability to measure AC voltage or AC current using analog input pin. For Arduino UNO, there are 6 analog input pins (A0-A5) where you can use one of the pins. Arduino NANO has 8 pins while Arduino MEGA has 16 input pins. The analog input pins will map input voltages between 0 and 5V into integer values between 0 and 1023 with resolution of 4.9mV per unit (5.00V / 1024 units). In order to measure phase angle, 2 Analog input pins are required.

Single Phase AC Voltage Module

This module is equipped with ZMPT101B high-precision voltage transformer and op amp circuit. It can measures AC voltage within 250V. The corresponding output signal can be adjusted using the trimmer potentiometer. You can grab this module at our affiliate link here !!!

Hall-Effect Split-Core HSTS016L AC current sensor module. 

This Hall-Effect Split Core Sensor can measure AC current and do not need to make re-wiring or adjustment of existing wiring unlike ACS712 current module. The model ranges from 10A up to 200A. You can get it via our affiliate link here !!! The output voltage of this sensor is 2.5V +/- 0.625V with decent accuracy. I highly recommend this sensor for measuring AC current.

ACS712 Current Sensor Module 

This is a AC or DC current sensor rated at 5A, 20A and 30A which are suitable to most applications. You may get them by our affiliate link here !!! The 5A module has the resolution of 185mV/ampere, 20A module has 100mV/ampere while 30A module has the resolution of 66mV/ampere.

Signals detected by Arduino are in analog values. Below are the signals being detected by the voltage (Blue) and current sensor (Red). You can copy the below code to try your own. You can see the waveform in Serial Plotter. You can print-screen the waves image and measured manually in drawing software such as Autocad to pre-estimate the phase angle.The phase shift or phase difference between voltage and current also subject to applied load. Connect Voltage module in A2 pin of Arduino while Current module in A3 pin. The magnitude of voltage and current are not a concerned here as we only need to measure the wave difference with respect to time.

float vAnalogRead;
float iAnalogRead;
int voltageInputPin = A2; // Analog input pin for voltage sensor
int currentInputPin = A3; // Analog input pin for current sensor
int currentOffset = 0; // key in value for current offset setting
int voltageOffset = 0; // key in value for voltage offset setting
float virtualMagnification = 5; // to increase the magnification of current value in display

void setup()
{
Serial.begin(9600);
}

void loop()
{
vAnalogRead = analogRead(voltageInputPin) - 512 + voltageOffset;
iAnalogRead = virtualMagnification*(analogRead(currentInputPin) - 512) + currentOffset;

Serial.print(vAnalogRead);
Serial.print(" ");
Serial.println(iAnalogRead);
delay(300);

}

middle point for both waves should be technically at 512 (analog value) and it fluctuates within 0 to 1023 by default. However, I have amended the code so that the waves are oscillate at middle point 0 value between 512 and -512 for easier calculation later. Before going further, calibration are needed before the measurement as some modules might have different deviation error. You may go to individual sensor post for more info.

How the signal being processed

Before going further, let us begin with initial calibration for both sensors. We need to minimize any potential deviation error or inaccuracy as much as possible. The sensors are very sensitive, make sure to use tight connectors and cable terminals. We need calibrate the analog value for both sensor. When no value detected, both should be at middle of oscillation which is exactly at 0 value.

This calibrations can be done manually by keying the relevant values in the code or automatically if you have the LCD Display shield by pressing the SELECT Button in the LCD Display Shield and wait for about 5 seconds. Of cause you need to have the shield in order to work. You may purchase at our affiliate link here !!!

The code has few stages to make sure it when through the whole stages throughout the wave pattern to prevent miscalculation. The code uses AnalogInput1 (Wave A) as reference. It first determine the entry point to start recording time. The point is where the wave cross over or below 0 value for voltage sensor (wave A). The starting time are the same for all 3 measurement parameters (wave A, wave B and frequency of wave A).

When Wave A more than 0, it keep checking and recording the current time. The time recording is based on whether the recording analog value larger than previous measured value. If at the peak where current recording value no longer larger than previous value, recording time stops and it will be the last recording time. The same applies to wave B which separate time recording and stops at peak value. The time taken from starting point to peak value for wave A is estimate at 75% of the whole period wave (but I’m not using this simple estimation). The time difference taken between wave A and wave B to reach peak is actually the phase shift time which phase angle can be calculated. 

When the Wave A back to 0, the time recording for period or frequency is stopped. Period is the time difference between starting point and end point. At the same time, the current time is set as starting time for the next cycle of reading set and the process repeated until 50 cycles (for 50Hz) or 60 cycles (for 60 Hz)

LCD Display Shield 

This is a shield that allows the output value of your Arduino board to be displayed on the screen. Since it is a shield, you can just stack it on Arduino board without the need of extra wiring for the LCD Display. You can get the LCD Display board at our affiliate link here !!!.

The good news is you do not need to manually calibrate the offset settings if you got the LCD Display Shield with you. Below we have attached the code that utilizes the button function that could automatically calibrate by itself when you pressed the SELECT Button. You may download from the end of this page below.  

UNI-T Multimeter is a good quality with decent price. We have been using UNI-T multimeter for years has not been any issue. We were using UT33C model. You can get yours at our affiliate link here !!!

Hardware Connection

You may need to find a way to fit the AC sensor cable into the Arduino pin. The sensor cable that I purchased came with pre-soldered at the tip, making it easy to go into the Arduino pins. Open the Split Core current module and there will show an arrow symbol which signify the way of current flow. Once everything ready, make sure the split core is closed tightly.  

Make sure underneath Voltage sensor does not have exposed conductor or metal plates which may cause you accidental short circuit at the terminal of the module. You need to get the low current fast blown fuse for voltage sensor cable while MCB or fuse of sufficient current rating based on your load to protect against any potential short circuit and fire risk.

In order to connect wiring between Arduino board and module, you need the dupont line cables male to female. You can get it at our affiliate link here !!!

You need the connector that can secure cables and isolate from accidental touch. Get the fast connector at our affiliate link here !!!

You need a fuse to protect your safety and cables!! You can get it here !!

Screw Shield / Expansion Shield

When there are a lot of wiring around especially more than 1 sensor, sharing pins will be difficult as existing pins (ground and 5V) are limited. This shield provides a lot of convenient terminals for each of the input and output pins. The shield can be mounted directly on top of the Arduino Uno board or in between the shields which made it very convenient to use. You can get it at our affiliate link here !!!

Datalogger Shield

If you plan to record the data in a proper way, you may consider this Datalogger Shield. It allows your arduino to record your data in SD Card. Datalogger shield is often installed together with LCD Display shield. Please find it at our affiliate link here !!! For more about this Datalogger Shield, kindly visit our post here.

Software Codes

The final step would be adding source code onto Arduino board. I assume you have installed the Arduino Software. If you have not installed the software, the link here can bring you to the official download site. Once you have downloaded the software, you may download the code file (.ino) for this application below (right click save link). 

There is 2 source codes file attached which are source code with and without LCD display shield function. If you don’t have LCD Display shield with you, kindly choose the code that is without LCD Display Shield but you have to manually calibrate and key in the 2 offset values. However, I still highly recommend that you get a LCD Display Shield.

With LCD Display Shield, once the code is uploaded to the Arduino board, the current value will be shown on the LCD Display. We have added the auto calibrate function, once the SELECT button is pressed, the value returns to exact zero point. You only do calibration when no current and voltage in measurement. You may have to wait about 5 seconds long until all values are re-calibrated. If first press is not satisfied, you may repeat by pressing it again.

Codes for Phase Angle using AC Voltage Module and AC Current Module (with LCD Display Shield). Note: the codes shown here may not be 100% correct due to translation error. For accurate code, kindly download the .ino file. 

// Phase Angle By Solarduino

// 0- General

int decimalPrecision = 2;

//1 - Phase Angle, Frequency and Power Factor measurement

int expectedFrequency = 50;
int analogInputPin1PA = A2;
int analogInputPin2PA = A3;
float voltageAnalogOffset =0;
float currentAnalogOffset =0;
unsigned long startMicrosPA;
unsigned long vCurrentMicrosPA;
unsigned long iCurrentMicrosPA;
unsigned long periodMicrosPA;
float vAnalogValue =0;
float iAnalogValue =0;
float previousValueV =0;
float previousValueI =0;
float previousphaseAngleSample=0;
float phaseAngleSample =0;
float phaseAngleAccumulate =0;
float periodSample=0;
float periodSampleAccumulate = 0;
float phaseDifference =0;
float phaseAngle =0;
float frequency = 0;
float voltagePhaseAngle=0;
float currentPhaseAngle=0;
float averagePeriod =0;
int sampleCount = 0;
int a = 3;
float powerFactor;

// 1.1 - Phase Angle Offset

float currentOffsetRead =0;
float currentOffsetLastSample =0;
float currentOffsetSampleCount=0;
float voltageOffsetRead =0;
float voltageOffsetLastSample =0;
float voltageOffsetSampleCount=0;

// 2 - LCD Display

#include<LiquidCrystal.h>
LiquidCrystal LCD(8,9,4,5,6,7);

void setup()
{

// 0- General

Serial.begin(9600);

// 2 - LCD Display

LCD.begin(16,2);
LCD.setCursor(0,0);
}

void loop()
{

// 0- General

// 0.1- Button Function

int buttonRead;
buttonRead = analogRead (0);

//Right button is pressed
if (buttonRead < 60)
{ LCD.setCursor(0,0); LCD.print ("PRESS <SELECT> "); }

// Up button is pressed
else if (buttonRead < 200)
{ LCD.setCursor(0,0); LCD.print ("PRESS <SELECT> "); }

// Down button is pressed
else if (buttonRead < 400)
{ LCD.setCursor(0,0); LCD.print ("PRESS <SELECT> "); }

// Left button is pressed
else if (buttonRead < 600)
{ LCD.setCursor(0,0); LCD.print ("PRESS <SELECT> "); }

//Select button is pressed
else if (buttonRead < 800)
{
currentOffsetRead = 1;
voltageOffsetRead = 1;
LCD.setCursor(0,0);
LCD.print ("INITIALIZING..... ");
LCD.setCursor(0,1);
LCD.print ("WAIT 5 SEC ..... ");
}

// 1 - Phase Angle, Frequency and Power Factor measurement

vAnalogValue = analogRead(analogInputPin1PA)-512 + voltageAnalogOffset;
iAnalogValue = analogRead(analogInputPin2PA)-512 + currentAnalogOffset;

if((vAnalogValue>0) && a == 3)
{
a=0;
}

if((vAnalogValue<=0) && a ==0)
{
startMicrosPA = micros();
a=1;
}

if((vAnalogValue>0) && a ==1)
{
a = 2;
previousValueV = 0;
previousValueI = 0;
}

if((vAnalogValue > previousValueV ) && a==2)
{
previousValueV = vAnalogValue ;
vCurrentMicrosPA = micros();
}

if((iAnalogValue > previousValueI) && a==2)
{
previousValueI = iAnalogValue ;
iCurrentMicrosPA = micros();
}

if((vAnalogValue <=0) && a==2)
{
periodMicrosPA = micros();
periodSample = periodMicrosPA - startMicrosPA;
periodSampleAccumulate = periodSampleAccumulate + periodSample;
voltagePhaseAngle = vCurrentMicrosPA - startMicrosPA;
currentPhaseAngle = iCurrentMicrosPA - startMicrosPA;
phaseAngleSample = currentPhaseAngle - voltagePhaseAngle;
if(phaseAngleSample>=100)
{
previousphaseAngleSample = phaseAngleSample;
}
if(phaseAngleSample<100)
{
phaseAngleSample = previousphaseAngleSample;
}
phaseAngleAccumulate = phaseAngleAccumulate + phaseAngleSample;
sampleCount = sampleCount + 1;
startMicrosPA = periodMicrosPA;
a=1;
previousValueV = 0;
previousValueI = 0;
}

if(sampleCount == expectedFrequency)
{
averagePeriod = periodSampleAccumulate/sampleCount;
frequency = 1000000 / averagePeriod;
phaseDifference = phaseAngleAccumulate / sampleCount;
phaseAngle = ((phaseDifference*360) / averagePeriod);
powerFactor = cos(phaseAngle*0.017453292);
Serial.print("Phase Angle :");
Serial.print(phaseAngle,decimalPrecision);
Serial.print("° ");
Serial.print("Frequency :");
Serial.print(frequency,decimalPrecision);
Serial.print("Hz ");
Serial.print("Power Factor :");
Serial.println(powerFactor,decimalPrecision);
sampleCount = 0;
periodSampleAccumulate = 0;
phaseAngleAccumulate =0;

// 2 - LCD Display

LCD.setCursor(0,0);
LCD.print("P. Angle =");
LCD.print(phaseAngle,decimalPrecision);
LCD.print((char)223);
LCD.print(" ");
LCD.setCursor(0,1);
LCD.print(frequency,decimalPrecision);
LCD.print("Hz ");
LCD.print(powerFactor,decimalPrecision);
LCD.print("PF ");

}

// 1.1 - Phase Angle Offset

if( voltageOffsetRead == 1)
{
voltageAnalogOffset = 0;
if(millis()>= voltageOffsetLastSample + 1)
{
voltageOffsetSampleCount = voltageOffsetSampleCount + 1;
voltageOffsetLastSample = millis();
}
if(voltageOffsetSampleCount == 1500)
{
vAnalogValue = analogRead(analogInputPin1PA)-512 + voltageAnalogOffset;
voltageAnalogOffset = -1*(vAnalogValue);
voltageOffsetRead = 0;
voltageOffsetSampleCount = 0;
}
}

if( currentOffsetRead == 1)
{
currentAnalogOffset = 0;
if(millis()>= currentOffsetLastSample + 1)
{
currentOffsetSampleCount = currentOffsetSampleCount + 1;
currentOffsetLastSample = millis();
}
if(currentOffsetSampleCount == 1500)
{
iAnalogValue = analogRead(analogInputPin2PA)-512 + currentAnalogOffset;
currentAnalogOffset = -1*(iAnalogValue);
currentOffsetRead = 0;
currentOffsetSampleCount = 0;
}
}

}

Before we end, we would like to give gratitude to you for taking the time to read the post. We would need readers like you to support us in order to keep growing. You can support us in the following ways :

Donate & Fund Raising

If you like my work, please send me a donation to encourage me to do more. Thanks

Aliexpress Affiliate

We are the member of Aliexpress affiliate marketing. Do support us by clicking the affiliate product links if you do wish to purchase them.

Like and Share

If you like our post, we need your support to like and share our posts or videos so that it can reach more and more people like you !!

Result – In Serial Monitor

 

Result – In LCD Display

For Arduino Code Files, Remember to Right Click > Save Link As … You may alter the internal code as you wish. Happy coding !! 

Phase Angle.ino
Phase Angle with LCD Display.ino