The Hexabitz Single Phase Power Analyzer is a True RMS Analyzer based on H2AR3 module for monitoring active, reactive and apparent power as well as for power factor and frequency measurement in addition to its functionality as active and reactive energy meter. For less than 40 bucks, you get a low cost and friendly used power analyzer with high performance, live and accumulation monitoring, and easy-to-use features.
We'll list the tools used in this project:
1) Hexabitz AC Current and Voltage Sensor Module (H2AR3):
H2AR3x is an AC current and voltage sensor module based on bidirectional current sense amplifiers INA199B2DCKT, INA199B1DCKT, Low-Drift, Low-Power, Dual-Output Vref and Vref/2 Voltage Reference REF2033AIDDCR and STM32F0 MCU [1].
2) User Tools Kit:
This kit includes the tools that are essential for programming, debugging, and powering Hexabitz modules.
- FTDI USB to UART Serial Cable:
The 4-pin USB 2.0 to UART serial cable is an indispensable tool for Hexabitz development! It incorporates FTDI’s USB to UART interface [2].
- Hexabitz BitzClamp:
Hexabitz BitzClamp is a modified Kelvin current clamp soldered to two 2.56 mm-pitch male jumper wires [3].
- STLINK-V3MODS Programmer (H40Rx):
H40Rx is a programmer module which contains STLINK-V3MODS stand-alone debugging and programming mini probe for STM32 microcontrollers (Hexabitz modules and other MCUs) [4].
- E-Z-Hook Programming Kit:
Instead of soldering SMD connectors there, you could use a nice off-the-shelf E-Z-Hook kit that we assembled for you [5].
3) CR8400 CurrentTransformer:
CR Magnetics CR8450-1000 is a wire lead current transformer [6].
Table(1): General purpose for current transformer used in this project
We'll mention step-by-step instructions from designing to implementing this project:
1. Writing codes with STM32CubeIDE software:
If you are programming with STM32CubeIDE software for the first time, take advantage of Hexabitz WIKI from this step-by-step article.
-H2AR3x Firmware main.c code:
Clone the latest firmware of the module and start coding!
First, we define our variables:
uint16_t p;
int i=0, temp=0, elapsed=0, status;
int R_p_s, R_p_h, q_s, q_h; // Active & reactive Energy
float volt, curr ,sum ,sum_v, Ibuff[100]={0}, Vbuff[100]={0}, Pbuff[100]={0}, buff[100]={0};
float MaxV, Maxvp, MaxI, avi, avv, sumv, sumi;
float Rmsv, Rmsi, A_p, P_F, R_p, q, freq;
int i, j, indv, inda, theta, status;
uint8_t signv=0; //0:+...1:-
uint16_t buffer[255]={0};
uint8_t bufferLength = 255;
Second, in the userTask
function we read the last value stored in the EEPROM, then we specify the parameter R_p_h to get the active power in hours, and the parameter R_p_s to get it in seconds.
//Read EEPROM where the energy has been saved last time
status = EE_ReadVariable(_EE_MyVar, &p);
R_p_h=p/3600; R_p_s=p%3600; // Decomposition of total energy
Third, inside the While(1)
loop, we take the real time from Hexabitz BOS function BOS.time.seconds,
and do some startup initialization:
GetTimeDate(); temp = BOS.time.seconds; // Due to elapsed seconds in initialization
HAL_Delay(3000); // Update measurements every three seconds
sumi=0; avi=0; avv=0; Rmsi=0; Rmsv=0; A_p=0; P_F=0; R_p=0;
MaxV=0; MaxI=0; sumv=0, sumi=0; indv=0; inda=0; Maxvp=0, freq=0;
- To obtain the voltage and current values, we used the following APIs programmed in the module's firmware, then we store them in buffers:
We take advantage of BOS API StartMicroDelay
to achieve the time of the signal, which is 20 ms for 100 sample.
// Get values sequentially not simultaneously ...!
for(i=0; i<100; i++)
{
SampleV(&volt);
SampleA(&curr);
Vbuff[i]=volt;
Ibuff[i]=curr;
StartMicroDelay(135); //135+65=200u, 200u*100= 20 ms.
}
- The obtained voltage and current values are uncertain due to grid harmonics, so we will perform some calibrations. First, we calculate the average error for current and voltage and perform an online calibration for the obtained values (median filter).
for(i=0;i<100;i++) // Calc average error for current
{avi=avi+Ibuff[i];}
avi=avi/100;
for(i=0;i<100;i++) // Current online calibration
{Ibuff[i]=Ibuff[i]-avi;}
for(i=0;i<100;i++) // Calc average error for volt
{avv=avv+Vbuff[i];}
avv=avv/100;
for(i=0;i<100;i++) // Voltage online calibration
{Vbuff[i]=Vbuff[i]-avv;}
- Then the maximum peak amplitude of the voltage is determined, whether it was positive or negative, to calculate the values for frequency and RMS.
// Catch max value with indicator
if(Vbuff[0] < 0) // We need peaks maxv+ and maxv-
{MaxV = Vbuff[0]*-1;signv=1;}
else {MaxV = Vbuff[0];signv=0;}
for(i=1;i<100;i++)
{
if(Vbuff[i] < 0)
{if(MaxV < -1*Vbuff[i] ) {MaxV=-1*Vbuff[i];signv=1;indv=i;}}
else
{if(MaxV < Vbuff[i] ) {MaxV=Vbuff[i];signv=0;indv=i;}}
}
if(signv==1) MaxV *= -1; MaxV=MaxV/1.414;
- Now we calculate the frequency in a digital way by implementing a rectifier that takes only positive values, and then detect peaks and store them in the parameter
indv
, the frequency is then calculated from the distance from pick to pick.
// frequency calculation
for(i=0;i<100;i++) // Rectifier
{buff[i]=Vbuff[i];
if(buff[i] < 0) buff[i]=-buff[i];}
Maxvp = buff[0];
for(i=1;i<50;i++)
{if(Maxvp < buff[i] ) {Maxvp=buff[i];indv=i;}}
Maxvp = buff[50];
for(i=50;i<100;i++)
{if(Maxvp < buff[i] ) {Maxvp=buff[i];inda=i;}}
// freq= 5000 /(indv-inda); no need to calc in case of phase absence
for(i=0;i<100;i++) {buff[i]=0;} // Clean
- We calculate the active power with equations for discrete time:
Equation 1. Real Power Definition
U - Root-Mean-Square (RMS) voltage.
I - Root-Mean-Square (RMS) current.
Cos(φ) - Power factor.
The discrete time equivalent is:
Equation 2. Real Power Definition in Discrete Time
u(n) - sampled instance of u(t)
i(n) - sampled instance of i(t)
N - number of samples.
Real power is calculated simply as the average of N voltage-current products. It can be shown that this method is valid for both sinusoidal and distorted waveforms.
An RMS value is defined as the square root of the mean value of the squares of the instantaneous values of a periodically varying quantity, averaged over one complete cycle. The discrete time equation for calculating voltage RMS is as follows:
Equation 3. Voltage RMS Calculation in Discrete Time Domain
RMS current is calculated using the same equation, substituting voltage samples, u(n), for current samples, i(n) [7].
// Real power discrete time calculation
for(i=0; i<100; i++)
{
Pbuff[i]=Ibuff[i]*Vbuff[i];
// The acquired samples were sequential not simultaneous
sumi+=Pbuff[i];
}
R_p=sumi/100; // Watt
if(R_p<0)
R_p=-R_p;
sumi=0;
// RMS discrete time calculation
for(i=0;i<100;i++)
{
buff[i]=pow(Vbuff[i],2);
sumv+=buff[i];
}
Rmsv=sqrt(sumv/100); // We need here filter for stable values
if(Rmsv<MaxV)
Rmsv=MaxV;
for(i=0; i<100; i++)
{
buff[i]=pow(Ibuff[i],2);
sumi+=buff[i];
}
Rmsi=sqrt(sumi/100); // We need here filter for stable values
- Apparent Power and Power Factor:
Apparent power is calculated, as follows:
Apparent power = RMS Voltage x RMS current
and the power factor is calculated from the definition:
Power Factor = Real Power / Apparent Power
// Apparent power = RMS Voltage x RMS current
// Power Factor = Real Power / Apparent Power
A_p=Rmsv*Rmsi;
if(A_p<=0)
A_p=0;
P_F=R_p/A_p;
if (P_F< 0 | P_F>1)
P_F=0;
theta=acos(P_F)*180/3.14159;
q=sqrt(pow(A_p,2)-pow(R_p,2));
IND_toggle();
GetTimeDate();
elapsed=BOS.time.seconds-temp;
if(elapsed<0)
elapsed+=60;
R_p_s+=R_p*elapsed; // Watt.s (cumulative sum)
if(R_p_s>3600) {R_p_h+=R_p_s/3600;R_p_s%=3600;} // Watt.h (cumulative conversion)
q_s+=q*elapsed;
if(q_s>3600) {q_h+=q_s/3600;q_s%=3600;} // VAR.h (cumulative conversion)
p=R_p_s+(R_p_h*3600);
if (Rmsv>20)
{ status = EE_WriteVariable(_EE_MyVar,p); // No need to store energy in case of phase absence/failure
freq+= 1250 /(inda-indv);
if((freq>60)|(freq<40)) freq=50;}
- Finally, we display the parameters:
/* Send the analysis Package */
sprintf(buffer,"\n\n\rIrms: %.3f A\n\rVrms: %.2f V\n\rS : %f VA\n\rP : %f W\n\rQ : %f VAR\n\rCOS : %.2f\n\rTheta: %d deg\n\r"
"Active Energy cumulative:\n\r %d W.sec %d W.hour\n\rReactive Energy cumulative:\n\r %d VAR.sec %d VAR.hour\n\rfreq: %f Hz\n\n\r>",Rmsi,Rmsv,A_p,R_p,q,P_F,theta,R_p_s,R_p_h,q_s,q_h,freq);
writePxMutex(P1, (uint8_t*)buffer, bufferLength, 0xffff, 0xffff);
2. Updating Firmware
Once we have written our codes, we update the module's firmware with the programmer. If you are updating the module's firmware for the first time, please read this article.
3. Starting the project
Start wiring tools as shown in figure (10).
■ Connect the CT to the CT connector on the module.
■ Connect the module's voltage connector to the electric network.
■ Connect the programming pin marked with * to the serial monitor via the serial UART cable (FTDI USB):
□ Yellow (RXD) >> MCU TXD (the top communication pad)
□ Orange (TXD) >> MCU RXD (the bottom communication pad)
■ Power the module in one of the ways mentioned in this article.
■ Open any serial monitor and follow the instructions described in this article, to start monitoring values.
At the beginning of the process, the module reads the last value stored in the EEPROM, then it continues with the display of the measured values.
Here are some live experiments of our project. Have fun looking at them! More interesting projects will be presented in Hexabitz Channel.
► Future IdeasWe're working on a three-phase version of this project that will include more calculations for various industrial applications.
[1]: AC Current and Voltage Sensor (H2AR3x) – Hexabitz
[2]: 4-Pin USB-Serial Prototype Cable – Hexabitz
[3]: Hexabitz BitzClamp – Hexabitz
[4]: STLINK-V3MODS Programmer (H40Rx) – Hexabitz
[5]: E-Z-Hook Programming Kit – Hexabitz
[6]: Wire Lead (crmagnetics.com)
[7]: AC Power Theory - Advanced Maths — OpenEnergyMonitor 0.0.1 documentation
[8]: Wiki – Hexabitz
Comments
Please log in or sign up to comment.