Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
|
This project is an extended version of Oscillogram for Utility Grid. Beyond monitor the voltage amplitude and frequency on utility grid, the smart analyser run fft analysis on voltage and the load current, measure the power active and reactive and datas are presented to the user in real time. The datas are received from TM4C1294 LaunchPad trough serial uart interface in BeagleBone. In this, the datas are stored in.csv file by a program Energy_QoS (in C). The files created are: dataloger_0.csv (store 8 voltage cycles when a disturbance occurs), dataloger_1.csv (store the frequency, magnitude and powers each 5 seconds) and dataloger_2.csv (store the odd harmonics of voltage and current each 5 seconds). Through Node-red, the user interface was developed, where the.csv files are read and presented in the graphs by the dashboard. On TM4C1294 are connected the devices on analog input An0 and An1, wich measure de voltage and current. To monitor the voltage parameters, a software phase locked loop was implemented and fft was implemented dfft radix-4.
Energy_QoS
C/C++//gcc Energy_QoS.c -o Energy_QoS -lm -lpthread
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <signal.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <pthread.h>
#include <net/if.h>
#include <pthread.h>
#include <math.h>
#define SIZE_BUFFER 8
char buffer_tx[] = {0,0,0,0,0,0,0,0};
char buffer_rx[] = {0,0,0,0,0,0,0,0};
time_t timer;
struct tm *horarioLocal;
int dia, mes, ano, hora, min, sec;
volatile unsigned short int msg_receive = 0, nbytes = 0;
volatile unsigned short int running = 1;
unsigned short int nwrite;
unsigned short int nread;
pthread_t thread_id;
char *portname = "/dev/ttyACM0";
int handle;
int n = SIZE_BUFFER;
unsigned short int anomalias = 0;
void signal_Handler(int sign){
int o_exit = 0;
switch (sign){
case SIGINT:{
o_exit = 1;
break;
}
case SIGTERM:{
o_exit = 1;
break;
}
default:{
break;
}
}
if (o_exit == 1)
running = 0;
}
void *uart_msg_receive(void *t){
while(running){
for(n = 0; n < SIZE_BUFFER; n++){
nread = read(handle,&buffer_rx[n],1);
/*if(nread < 0){
printf("Read error\n");
}else{
printf("Data (%d) read = %d \n",n,buffer_rx[n]);
}*/
}
msg_receive = 1;
usleep(1000);
while(msg_receive);
}
}
int set_interface_attribs(int fd, int speed){
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
void set_mincount(int fd, int mcount){
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error tcgetattr: %s\n", strerror(errno));
return;
}
tty.c_cc[VMIN] = mcount ? 1 : 0;
tty.c_cc[VTIME] = 5; /* half second timer */
if (tcsetattr(fd, TCSANOW, &tty) < 0)
printf("Error tcsetattr: %s\n", strerror(errno));
}
void update_time(void){
time(&timer);
horarioLocal = localtime(&timer);
dia = horarioLocal->tm_mday;
mes = horarioLocal->tm_mon + 1;
ano = horarioLocal->tm_year + 1900;
hora = horarioLocal->tm_hour;
min = horarioLocal->tm_min;
sec = horarioLocal->tm_sec;
}
int main(void){
/////
unsigned int i = 0, count = 0;
unsigned char c = 0, wave_complete = 0, harm_ord = 1;
float v_vector[2048], f = 0, v = 0, p = 0, q =0;
float Mag_vg[53], Mag_ig[53];
/////
char query[512], str[30];
FILE *dataloger;
FILE *temperatureFile;
handle = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
if (handle < 0) {
printf("Error opening %s: %s\n", portname, strerror(errno));
return -1;
}
set_interface_attribs(handle, B115200);// baudrate 115200, 8 bits, no parity, 1 stop bit
if( pthread_create(&thread_id, NULL, &uart_msg_receive, NULL) ){
printf("\nErro thread\n");
}
for(i = 0; i < 2048; i++){
v_vector[i] = 0.0;
}
signal(SIGINT, signal_Handler);
signal(SIGTERM, signal_Handler);
time(NULL);
sleep(1);
buffer_tx[0] = 0xF0;
buffer_tx[1] = 0x01;
nwrite = write(handle,buffer_tx,8);
tcdrain(handle);
while (running){
if(msg_receive){
if( (buffer_rx[0] >> 4) == 1 ){
i = ((buffer_rx[0] & 0x07) << 8) + (buffer_rx[1] & 0xFF);
for(c = 2; c < 8; c++){
if(i < 2048){
if( (buffer_rx[c] & 0x80) == 0x80)
v_vector[i] = -0.01*( (float)((0xFF ^ buffer_rx[c]) + 1) );
else
v_vector[i] = 0.01*((float)buffer_rx[c]);
i++;
}
}
if(i == 2048){
anomalias++;
wave_complete = 1;
}
}else if( (buffer_rx[0] >> 4) == 2 ){
if( (buffer_rx[2] & 0x80) == 0x80)
v = -0.1*( (float)((( 0xFF ^ buffer_rx[2])<<8) + ( 0xFF ^ buffer_rx[3]) + 1 ) );
else
v = 0.1*( (float)((buffer_rx[2]<<8) + (buffer_rx[3]) ) );
if( (buffer_rx[4] & 0x80) == 0x80)
f = -0.01*( (float)((( 0xFF ^ buffer_rx[4])<<8) + ( 0xFF ^ buffer_rx[5]) + 1 ) );
else
f = 0.01*( (float)((buffer_rx[4]<<8) + (buffer_rx[5]) ) );
if( (buffer_rx[6] & 0x80) == 0x80)
p = -0.01*( (float)( (0xFF ^ buffer_rx[6]) + 1) );
else
p = 0.01*( (float)((int)buffer_rx[6]));
if( (buffer_rx[7] & 0x80) == 0x80)
q = -0.01*( (float)( (0xFF ^ buffer_rx[7]) + 1) );
else
q = 0.01*( (float)buffer_rx[7]);
update_time();
dataloger = fopen("dataloger_1.csv","a");
if(dataloger == NULL){
printf("\nErro dataloger\n!");
exit(1);
}
sprintf(query,"%d,%d,%d,%d,%d,%d,%.2f,%.2f,%.2f,%.2f\n",dia,mes,ano,hora,min,sec,v,f,p,q);
fprintf(dataloger,"%s",query);
fclose(dataloger);
}else if( (buffer_rx[0] >> 4) == 3 ){
for(c = 1; c < 8; c++){
Mag_vg[harm_ord] = 0.1*((float)((unsigned)buffer_rx[c]));
harm_ord = harm_ord+2;
if(harm_ord == 53){
sprintf(query,"v,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f\n",Mag_vg[1],Mag_vg[3],Mag_vg[5],Mag_vg[7],Mag_vg[9],Mag_vg[11],Mag_vg[13],Mag_vg[15],Mag_vg[17],Mag_vg[19],Mag_vg[21],Mag_vg[23],Mag_vg[25],Mag_vg[27],Mag_vg[29],Mag_vg[31],Mag_vg[33],Mag_vg[35],Mag_vg[37],Mag_vg[39],Mag_vg[41],Mag_vg[43],Mag_vg[45],Mag_vg[47],Mag_vg[49],Mag_vg[51]);
dataloger = fopen("dataloger_2.csv","a");
if(dataloger == NULL){
printf("\nErro fft dataloger\n!");
exit(1);
}else{
fprintf(dataloger,"%s",query);
}
harm_ord = 1;
fclose(dataloger);
break;
}
}
}else if( (buffer_rx[0] >> 4) == 4 ){
for(c = 1; c < 8; c++){
Mag_ig[harm_ord] = 0.1*((float) ((unsigned)buffer_rx[c]) );
harm_ord = harm_ord+2;
if(harm_ord == 53){
sprintf(query,"i,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f\n",Mag_ig[1],Mag_ig[3],Mag_ig[5],Mag_ig[7],Mag_ig[9],Mag_ig[11],Mag_ig[13],Mag_ig[15],Mag_ig[17],Mag_ig[19],Mag_ig[21],Mag_ig[23],Mag_ig[25],Mag_ig[27],Mag_ig[29],Mag_ig[31],Mag_ig[33],Mag_ig[35],Mag_ig[37],Mag_ig[39],Mag_ig[41],Mag_ig[43],Mag_ig[45],Mag_ig[47],Mag_ig[49],Mag_ig[51]);
dataloger = fopen("dataloger_2.csv","a");
if(dataloger == NULL){
printf("\nErro fft dataloger\n!");
exit(1);
}else{
fprintf(dataloger,"%s",query);
}
harm_ord = 1;
fclose(dataloger);
break;
}
}
}
memset(buffer_rx,0,sizeof(buffer_rx));
msg_receive = 0;
}
if(wave_complete){
update_time();
dataloger = fopen("dataloger_0.csv","a");
if(dataloger == NULL){
printf("\nErro dataloger\n!");
exit(1);
}
for(i = 0; i < 2048; i++){
sprintf(query,"%d,%d,%d,%d,%d,%d,%d,%.3f\n",dia,mes,ano,hora,min,sec,i,v_vector[i]);
fprintf(dataloger,"%s",query);
}
fclose(dataloger);
memset(buffer_tx,0,sizeof(buffer_rx));
buffer_tx[0] = 0xF1;
nwrite = write(handle,buffer_tx,8);
tcdrain(handle);
for(i = 0; i < 2048; i++){
v_vector[i] = 0.0;
}
wave_complete = 0;
}
usleep(2000);
count++;
if(count == 200){
count = 0;
update_time();
}
}
buffer_tx[0] = 0xF0;
buffer_tx[1] = 0x00;
nwrite = write(handle,buffer_tx,8);
tcdrain(handle);
close(handle);
printf("\nStop program\n");
return 0;
}
Tiva 1294 source code
C/C++http://www.ti.com/tool/SW-TM4C. This code samples the voltage and current at analog inputs an0 and an1. Performs calculations and sends data via serial (115200 kbs, 8bit, no parity) to beaglebone or raspberry
No preview (download only).
Node-red interface
JavaScript[{"id":"cb6abf33.b5419","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"dd5470ee.89e2a","type":"exec","z":"cb6abf33.b5419","command":"tail -n 1 /home/debian/dataloger_1.csv","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":330,"y":40,"wires":[["7c80c147.67333"],[],[]]},{"id":"e9ce267c.34c068","type":"inject","z":"cb6abf33.b5419","name":"","topic":"","payload":"1","payloadType":"num","repeat":"5","crontab":"","once":false,"onceDelay":0.1,"x":70,"y":40,"wires":[["dd5470ee.89e2a","c9f781d5.9d3a7","c1d3672c.7c3358"]]},{"id":"7c80c147.67333","type":"function","z":"cb6abf33.b5419","name":"","func":"var dados = msg.payload.split(\",\");\n\nvoltage = parseFloat(dados[6]);\nfrequency = parseFloat(dados[7]);\np_watt = parseFloat(dados[8]);\nq_var = parseFloat(dados[9]);\n\nvar msg1 = {payload: parseFloat(voltage).toFixed(2).toString()};\nvar msg2 = {payload: parseFloat(frequency).toFixed(2).toString()};\nvar msg3 = {payload: parseFloat(p_watt).toFixed(2).toString()};\nvar msg4 = {payload: parseFloat(q_var).toFixed(2).toString()};\n\nreturn [msg1, msg2, msg3, msg4];\n","outputs":4,"noerr":0,"x":570,"y":40,"wires":[["aa339d.4c91ec6"],["7c80a8fe.b6f658"],["bd3d8d6d.1781b"],["7dc336d0.6a6a88"]]},{"id":"aa339d.4c91ec6","type":"ui_gauge","z":"cb6abf33.b5419","name":"","group":"24980630.fd640a","order":1,"width":"4","height":"4","gtype":"gage","title":"Voltage","label":"V","format":"{{value}}","min":"63","max":"190","colors":["#ff0000","#00ff00","#ff0000"],"seg1":"114","seg2":"139","x":840,"y":20,"wires":[]},{"id":"7c80a8fe.b6f658","type":"ui_gauge","z":"cb6abf33.b5419","name":"","group":"24980630.fd640a","order":1,"width":"4","height":"4","gtype":"gage","title":"Frequency","label":"Hz","format":"{{value}}","min":"59","max":"61","colors":["#ff0000","#00ff00","#ff0000"],"seg1":"59.5","seg2":"60.5","x":850,"y":60,"wires":[]},{"id":"bd3d8d6d.1781b","type":"ui_gauge","z":"cb6abf33.b5419","name":"","group":"24980630.fd640a","order":1,"width":"4","height":"4","gtype":"gage","title":"Power (W)","label":"p.u.","format":"{{value}}","min":"0","max":"1.3","colors":["#00ff00","#00ff00","#00ff00"],"seg1":"0.5","seg2":"0.5","x":850,"y":100,"wires":[]},{"id":"7dc336d0.6a6a88","type":"ui_gauge","z":"cb6abf33.b5419","name":"","group":"24980630.fd640a","order":1,"width":"4","height":"4","gtype":"gage","title":"Reactive (Var)","label":"p.u.","format":"{{value}}","min":"0","max":"1.3","colors":["#ffff00","#ffff00","#ffff00"],"seg1":"0.5","seg2":"0.5","x":860,"y":140,"wires":[]},{"id":"c9f781d5.9d3a7","type":"exec","z":"cb6abf33.b5419","command":"tail -n 2 /home/debian/dataloger_2.csv","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":330,"y":200,"wires":[["b20f93cb.353eb"],[],[]]},{"id":"b20f93cb.353eb","type":"function","z":"cb6abf33.b5419","name":"","func":"var lines = msg.payload.split('\\n');\ndados = lines[0].split(\",\");\n\nv_h1 = parseFloat(dados[1]);\nv_h3 = parseFloat(dados[2]);\nv_h5 = parseFloat(dados[3]);\nv_h7 = parseFloat(dados[4]);\nv_h9 = parseFloat(dados[5]);\nv_h11 = parseFloat(dados[6]);\n\ndados = lines[1].split(\",\");\n\ni_h1 = parseFloat(dados[1]);\ni_h3 = parseFloat(dados[2]);\ni_h5 = parseFloat(dados[3]);\ni_h7 = parseFloat(dados[4]);\ni_h9 = parseFloat(dados[5]);\ni_h11 = parseFloat(dados[6]);\n\nvar msg1 = {payload: parseFloat(v_h1).toFixed(1).toString(), \"topic\": \"1h\"};\nvar msg2 = {payload: parseFloat(v_h3).toFixed(1).toString(), \"topic\": \"3h\"};\nvar msg3 = {payload: parseFloat(v_h5).toFixed(1).toString(), \"topic\": \"5h\"};\nvar msg4 = {payload: parseFloat(v_h7).toFixed(1).toString(), \"topic\": \"7h\"};\nvar msg5 = {payload: parseFloat(v_h9).toFixed(1).toString(), \"topic\": \"9h\"};\nvar msg6 = {payload: parseFloat(v_h11).toFixed(1).toString(), \"topic\": \"11h\"};\n\nvar msgi1 = {payload: parseFloat(i_h1).toFixed(1).toString(), \"topic\": \"1h\"};\nvar msgi2 = {payload: parseFloat(i_h3).toFixed(1).toString(), \"topic\": \"3h\"};\nvar msgi3 = {payload: parseFloat(i_h5).toFixed(1).toString(), \"topic\": \"5h\"};\nvar msgi4 = {payload: parseFloat(i_h7).toFixed(1).toString(), \"topic\": \"7h\"};\nvar msgi5 = {payload: parseFloat(i_h9).toFixed(1).toString(), \"topic\": \"9h\"};\nvar msgi6 = {payload: parseFloat(i_h11).toFixed(1).toString(), \"topic\": \"11h\"};\n\nreturn [msg1, msg2, msg3, msg4, msg5, msg6, msgi1, msgi2, msgi3, msgi4, msgi5, msgi6];\n","outputs":12,"noerr":0,"x":570,"y":200,"wires":[["5fd4110f.f016b"],["5fd4110f.f016b"],["5fd4110f.f016b"],["5fd4110f.f016b"],["5fd4110f.f016b"],["5fd4110f.f016b"],["94a14b40.2b4a18"],["94a14b40.2b4a18"],["94a14b40.2b4a18"],["94a14b40.2b4a18"],["94a14b40.2b4a18"],["94a14b40.2b4a18"]]},{"id":"5fd4110f.f016b","type":"ui_chart","z":"cb6abf33.b5419","name":"","group":"24980630.fd640a","order":0,"width":"8","height":"4","label":"FFT Voltage (dB)","chartType":"bar","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"20","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#1f77b4","#1f77b4","#1f77b4","#1f77b4","#1f77b4","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":830,"y":200,"wires":[[],[]]},{"id":"94a14b40.2b4a18","type":"ui_chart","z":"cb6abf33.b5419","name":"","group":"24980630.fd640a","order":0,"width":"8","height":"4","label":"FFT Current (dB)","chartType":"bar","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"20","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#ff8040","#ff8040","#ff8040","#ff8040","#ff8040","#ff8040","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":830,"y":240,"wires":[[],[]]},{"id":"c1d3672c.7c3358","type":"exec","z":"cb6abf33.b5419","command":"tail -n 2048 /home/debian/dataloger_0.csv","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":340,"y":380,"wires":[["4d9ca60e.d7bbf8"],[],[]]},{"id":"4d9ca60e.d7bbf8","type":"function","z":"cb6abf33.b5419","name":"","func":"var lines = msg.payload.split('\\n');\nvar dados = 0;\nvar chart = [{\n\"series\":[\"\"],\n\"data\":[[{\"x\":0,\"y\":0},{\"x\":0,\"y\":0}]],\n\"labels\":[\"\"]\n}];\n\nfor(i=0; i<2047; i++){\n\tdados = lines[i].split(\",\");\n chart[0].data[0][i]= { \"x\": i, \"y\": dados[7]};\n}\nmsg.payload = chart;\nreturn msg;","outputs":1,"noerr":0,"x":590,"y":360,"wires":[["8664a034.befd9"]]},{"id":"8664a034.befd9","type":"ui_chart","z":"cb6abf33.b5419","name":"","group":"24980630.fd640a","order":0,"width":"16","height":"4","label":"Disturbance on Voltage (8 cycles)","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"-1.2","ymax":"1.2","removeOlder":1,"removeOlderPoints":"2048","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#ff8040","#ff8040","#ff8040","#ff8040","#ff8040","#ff8040","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":820,"y":360,"wires":[[],[]]},{"id":"24980630.fd640a","type":"ui_group","z":"","name":"Measures","tab":"31c625fa.fdc9ea","disp":false,"width":"16","collapse":false},{"id":"31c625fa.fdc9ea","type":"ui_tab","z":"","name":"Home","icon":"dashboard"}]
Comments