Instalacion NILMTK con Anaconda 2021


EL NILM o Non-Intrusive Load Monitoring, es decir la desagregación no intrusiva de la demanda . es una técnica computacional para la estimación del consumo individual de diversos dispositivos utilizando para ello la lectura agregada de un único medidor de energía (Smart Meter, SM). Gracias a las ventajas en cuanto instalación , coste e implementación, éste concepto ha tomado relevancia en los últimos años en el ámbito de las Smart Grids, al aportar una estimación de los hábitos de consumo de los clientes sin la necesidad de un despliegue masivo de contadores inteligentes en cada punto de consumo.

En este contexto vamos a ver una herramienta o toolkit open software llamado NILMTK que nos va a ayudar a comparar algoritmos para implementar la desagregación ( además particularmente no contempla un uso diferente a este)

Para el análisis de la desagregación , necesitamos recolectar datos del consumo centralizado , lo cual nos va permitir a creación de un nuevo dataset el cual puede ser analizado usando las funciones de NILMTK lo que permite, por ejemplo, visualizar los datos de potencia en un determinado periodo u obtener estadísticas de energía del dataset.

Posteriormente, en la etapa de preprocesamiento se toman decisiones en línea con los análisis realizados, con el objetivo de preparar correctamente los datos para del entrenamiento de los modelos de desagregación. Básicamente, el entrenamiento de un modelo consiste en enseñarle a reconocer por separado las características de los dispositivos para luego identificarlos dentro de una señal agregada. El entrenamiento contempla el uso de los algoritmos Combinatorial Optimization (CO) y Factorial Hidden Markov Model (FHMM).

El formato de almacenamiento de datos HDF5

HDF5 es un formato de datos jerárquico que se usar en el NILMTK como fuente datos basado en HDF4 y NetCDF (otros dos formatos de datos jerárquicos).El formato de datos jerárquico, versión 5 (HDF5), es un formato de archivo de código abierto que admite datos grandes, complejos y heterogéneos. HDF5 utiliza una estructura similar a un “directorio de archivos” que le permite organizar los datos dentro del archivo de muchas formas estructuradas diferentes, como lo haría con los archivos en su computadora. El formato HDF5 también permite la incrustación de metadatos, lo que lo hace autodescriptivo .

Las organizaciones utilizan HDF5 para diversas necesidades de datos, acceso, informática y redes.

Estructura jerárquica: un directorio de archivos dentro de un archivo

El formato HDF5 se puede considerar como un sistema de archivos contenido y descrito en un solo archivo. Piense en los archivos y carpetas almacenados en su computadora. Es posible que tenga un directorio de datos con algunos datos de temperatura para varios sitios de campo. Estos datos de temperatura se recopilan cada minuto y se resumen cada hora, día y semana. Dentro de un archivo HDF5, puede almacenar un conjunto de datos similar organizado de la misma manera que podría organizar archivos y carpetas en su computadora. Sin embargo, en un archivo HDF5, lo que llamamos “directorios” o “carpetas” en nuestras computadoras, se llaman groupsy lo que llamamos archivos en nuestra computadora datasets.

2 Términos importantes de HDF5

  • Grupo: un elemento similar a una carpeta dentro de un archivo HDF5 que puede contener otros grupos O conjuntos de datos dentro de él.
  • Conjunto de datos: los datos reales contenidos en el archivo HDF5. Los conjuntos de datos se almacenan a menudo (pero no es necesario) dentro de grupos en el archivo.
Una ilustración de una estructura de archivo HDF5 que contiene grupos, conjuntos de datos y metadatos asociados
Un ejemplo de estructura de archivo HDF5 que contiene grupos, conjuntos de datos y metadatos asociados.

Un archivo HDF5 que contiene conjuntos de datos podría estructurarse así:

La ilustración HDF5 de arriba, pero los grupos son sitios NEON y los tipos de sensores y conjuntos de datos se incluyen en los tipos de sensores.
Un ejemplo de estructura de archivo HDF5 que contiene datos para varios sitios de campo y también contiene varios conjuntos de datos (promediados en diferentes intervalos de tiempo).

HDF5 es un formato autodescriptivo

El formato HDF5 es autodescriptivo. Esto significa que cada archivo, grupo y conjunto de datos puede tener metadatos asociados que describen exactamente cuáles son los datos. Siguiendo el ejemplo anterior, podemos incrustar información sobre cada sitio en el archivo, como por ejemplo:

  • El nombre completo y la ubicación X, Y del sitio.
  • Descripción del sitio.
  • Cualquier documentación de interés.

De manera similar, podríamos agregar información sobre cómo se recopilaron los datos en el conjunto de datos, como descripciones del sensor utilizado para recopilar los datos de temperatura. También podemos adjuntar información, a cada conjunto de datos dentro del grupo de sitios, sobre cómo se realizó el promedio y durante qué período de tiempo están disponibles los datos.

Un beneficio clave de tener metadatos adjuntos a cada archivo, grupo y conjunto de datos es que esto facilita la automatización sin la necesidad de un documento de metadatos separado (y adicional). Usando un lenguaje de programación, como R o Python, podemos obtener información de los metadatos que ya están asociados con el conjunto de datos y que podríamos necesitar para procesar el conjunto de datos.

Una ilustración de una estructura de archivos HDF5 con un grupo que contiene dos conjuntos de datos y todos los metadatos asociados
Los archivos HDF5 son autodescriptivos, lo que significa que todos los elementos (el archivo en sí, los grupos y los conjuntos de datos) pueden tener metadatos asociados que describen la información contenida en el elemento.

Subconjunto comprimido y eficiente

El formato HDF5 es un formato comprimido. El tamaño de todos los datos contenidos en HDF5 está optimizado, lo que reduce el tamaño general del archivo. Sin embargo, incluso cuando están comprimidos, los archivos HDF5 a menudo contienen grandes volúmenes de datos y, por lo tanto, pueden ser bastante grandes. Un atributo poderoso de HDF5 es data slicingmediante el cual se puede extraer un subconjunto particular de un conjunto de datos para su procesamiento. Esto significa que no es necesario leer el conjunto de datos completo en la memoria (RAM); muy útil para permitirnos trabajar de manera más eficiente con conjuntos de datos muy grandes (gigabytes o más).

Almacenamiento de datos heterogéneos

Los archivos HDF5 pueden almacenar muchos tipos diferentes de datos dentro del mismo archivo. Por ejemplo, un grupo puede contener un conjunto de conjuntos de datos para contener datos enteros (numéricos) y de texto (cadenas). O bien, un conjunto de datos puede contener tipos de datos heterogéneos (por ejemplo, tanto texto como datos numéricos en un conjunto de datos). Esto significa que HDF5 puede almacenar cualquiera de los siguientes (y más) en un archivo:

  • Datos de temperatura, precipitación y PAR (radiación fotosintética activa) para un sitio o para muchos sitios
  • Un conjunto de imágenes que cubren una o más áreas (cada imagen puede tener asociada información espacial específica, todo en el mismo archivo)
  • Un conjunto de datos espaciales multi o hiperespectral que contiene cientos de bandas.
  • Datos de campo para varios sitios que caracterizan insectos, mamíferos, vegetación y clima.
  • Un conjunto de imágenes que cubren una o más áreas (cada imagen puede tener asociada información espacial única)
  • ¡Y mucho más!

Formato abierto

El formato HDF5 es abierto y de uso gratuito. Las bibliotecas de apoyo (y un visor gratuito) se pueden descargar desde el sitio web de HDF Group . Como tal, HDF5 es ampliamente compatible con una gran cantidad de programas, incluidos lenguajes de programación de código abierto como R y Python, y herramientas de programación comerciales como MatlabIDL. Los datos espaciales que se almacenan en formato HDF5 se pueden utilizar en los programas de SIG y de imagen que incluyen QGISArcGISENVI.

Beneficios de HDF5

  • Autodescripción Los conjuntos de datos con un archivo HDF5 son autodescriptivos. Esto nos permite extraer metadatos de manera eficiente sin necesidad de un documento de metadatos adicional.
  • Admite datos heterogéneos : un archivo HDF5 puede contener diferentes tipos de conjuntos de datos.
  • Admite datos grandes y complejos : HDF5 es un formato comprimido que está diseñado para admitir conjuntos de datos grandes, heterogéneos y complejos.
  • Admite la división de datos: la “división de datos”, o la extracción de partes del conjunto de datos según sea necesario para el análisis, significa que los archivos grandes no necesitan leerse por completo en la memoria o RAM de la computadora.
  • Formato abierto: soporte amplio en las muchas herramientas : debido a que el formato HDF5 es abierto, es compatible con una gran cantidad de lenguajes y herramientas de programación, incluidos lenguajes de código abierto como R y Pythonherramientas SIG abiertas como QGIS.E

Instalación del NILTK

Básicamente aunque NILMTK se puede instalar muy fácilmente en sistemas basados en Linux , es posible instalarlo también desde Windows 11 . Resumidamente necesitaremos instalar Anaconda ( y Git si no lo tiene instalado ) y realizar la identificación de la carga, encontrar el paquete de instalación de NILMTK y registrar el proceso deliberadamente.

Veamos mas en detalle los pasos a seguir:

Instalación de GIT Windows

Hay varias maneras de instalar Git en Windows. La forma más oficial está disponible para ser descargada en el sitio web de Git. Solo tiene que visitar http://git-scm.com/download/win y la descarga empezará automáticamente. Observe que éste proyecto conocido como Git para Windows (también llamado msysGit), es diferente de Git “normal”. Para más información acerca de este proyecto visita http://msysgit.github.io/.

Otra forma de obtener Git fácilmente es mediante la instalación de GitHub para Windows. El instalador incluye la versión de línea de comandos y la interfaz de usuario de Git. Además funciona bien con Powershell y establece correctamente “caching” de credenciales y configuración CRLF adecuada. Puede descargar este instalador del sitio web de GitHub para Windows en http://windows.github.com.

Descarga e instalación de Anaconda

Los entornos virtuales hacen que la organización de paquetes de Python sea pan comido. Además, el proyecto NILMTK ofrece varias versiones de Conda Forge. Primero, consiga Anaconda aquí. 

Seguidamente nos pedira qeu nos registremos
Enseguida empezara la descarga, por lo que nos iremos a la carpeta de Descargas y ejecutaremos el instalador

Ahora deberemos aceptar la licencia para poder proseguir la instalacion

Seleccione una instalación para “Solo yo” a menos que esté instalando para todos los usuarios (lo que requiere privilegios de administrador de Windows) y haga clic en Siguiente.

Seleccione una carpeta de destino para instalar Anaconda y haga clic en el botón Siguiente. Nota: Instale Anaconda en una ruta de directorio que no contenga espacios ni caracteres Unicode..No lo instale como administrador a menos que se requieran privilegios de administrador.

Ahora nos toca Registrar Anaconda3 y mantener por defecto Python 3.8.

A menos que planee instalar y ejecutar múltiples versiones de Anaconda o múltiples versiones de Python, acepte el valor predeterminado y deje esta casilla marcada.

Haga clic en el botón Instalar. Si desea ver los paquetes que está instalando Anaconda, haga clic en Mostrar detalle

Enseguida enseguida empezara la instalacion , lo cual llevarás unos cinco minutos o menos segun el equipo donde este instalando.

Felicidades, acaba de instalar Conda.

Opcional: para instalar PyCharm para Anaconda, haga clic en el enlace a https://www.anaconda.com/pycharm .

O para instalar Anaconda sin PyCharm, haga clic en el botón Siguiente.

Después de una instalación exitosa, verá el cuadro de diálogo “Gracias por instalar Anaconda”:

Si desea leer más sobre Anaconda.org y cómo comenzar con Anaconda, marque las casillas “Tutorial de Anaconda Edición Individual” y “Aprenda más sobre Anaconda”. Haga clic en el botón Finalizar.

Verifique su instalación .Nota: Si está detrás de un proxy de la empresa, es posible que deba realizar una configuración adicional.

Abra una ventana de terminal de conda, crearemos un nuevo entorno de Conda y lo activaremos con los comandos:

conda create --name nilmtk-env 
conda activate nilmtk-env

Si aún no está presente en su instalación de Conda, agregue el conda-forge a la lista de canales:

conda config --add channels conda-forge

Finalmente, instale la última versión de NILMTK de conda-forge :

conda install -c nilmtk nilmtk=0.4.3

Observe que el signo igual no lleva espacios(piense estamos usando Python). La ejecución del comando puede tardar un rato. Mientras tanto, consulte otros paquetes en Forge de NILMTK .

Como puede experimentar algunos problemas posteriores a la instalación con NILMTK y Matplotlib., para solucionarlos, aplique el comando:

conda install matplotlib 

Verificar la instalación Para verificar que Matplotlib está instalado, intente invocar la versión de Matplotlib en Python REPL. Use desde el interprete Python los comandos a continuación que incluyen llamar a .__ version__, un atributo común a la mayoría de los paquetes de Python.

>>> import matplotlib

>>> matplotlib.__version__

Ejemplo de salida:

(nilmtk-env) C:\Users\carlo>python
Python 3.6.13 (default, Sep 7 2021, 06:39:02) [MSC v.1916 64 bit (AMD64)] on win32
Type “help”, “copyright”, “credits” or “license” for more information.

import matplotlib
matplotlib.version
‘3.1.3’

Agregar un kernel de Jupyter

Básicamente, NILMTK ahora está instalado en su ordenador. El siguiente paso involucra los cuadernos de Jupyter. Trabajar con Jupyter abre muchas posibilidades y se dice que es una herramienta imprescindible. Por lo tanto, agregue el entorno NILMTK a Jupyter:

python -m ipykernel install --user --name nilmtk-env --display-name "Python (nilmtk-env)"

Prueba de la instalación

Ha llegado el momento de comprobar su instalación. Antes que nada, cree una nueva carpeta y descargue el conjunto de prueba aleatorio de Github:

123md nilmtk_testcd nilmtk_test  wget https://raw.githubusercontent.com/nilmtk/nilmtk/master/data/random.h5

Como puede comprobar random.h5 es el fichero de de datos en en formato hdf5 .A continuación, levante Jupyter:

1notebook jupyter

Para probar su instalación, intente importar el conjunto de datos aleatorio usando NILMTK y trazar todos los medidores:https://klemenjak.medium.com/media/9ba2be16d331653a7b4093a0fe412434

La salida debe ser:

1MeterGroup (metros =   ElecMeter (instancia = 1, edificio = 1, conjunto de datos = Ninguno, electrodomésticos = [])   ElecMeter (instancia = 2, edificio = 1, conjunto de datos = Ninguno, electrodomésticos = [])   ElecMeter (instancia = 3, edificio = 1, conjunto de datos = Ninguno, electrodomésticos = [])   ElecMeter (instancia = 4, edificio = 1, conjunto de datos = Ninguno, electrodomésticos = [])   ElecMeter (instancia = 5, edificio = 1, conjunto de datos = Ninguno, electrodomésticos = []) )

¡Felicitaciones! Lo ha logrado. ¡NILMTK parece funcionar según lo previsto! 

La imagen tiene un atributo ALT vacío; su nombre de archivo es pexels-photo-5036278.jpeg

Extensión inalámbrica casera para el timbre de casa


Pensemos en personas de cierta edad  o simplemente personas que normalmente hacen su vida en alguna habitación de su vivienda que esta alejadas donde se encuentra el timbre de la puerta de acceso de la vivienda

Por ejemplo pensemos también que   esas personas están escuchando a un volumen alto la radio, su reproductor musical o simplemente están viendo la TV a un volumen alto y  suena el timbre de casa: en algunos casos , por no decir en la mayoría de los ocasiones evidentemente no lo van a oír, por lo que se hace necesario de algún modo sencillo  extender el sonido  del timbre de la cocina hasta otra sala sin necesidad de cables por ejemplo con un emisor inalámbrico dentro del timbre de la casa y un receptor-timbre  auxiliar para situarlo  donde más la convenga.

Además, por cierto, esta solución emisor-receptor  inalámbrica que vamos a proponer también es aplicable a los  timbres de los porteros automáticos con llamada zumbador convencionales de entrada a la vivienda compartiendo el receptor   variando únicamente la conexión del transmisor que deberá ser diferente, básicamente porque las  tensiones de disparo son muy diferentes   (220v de los timbre de la casa  frente   a los 8v a 24v de los porteros  automáticos ).   Precisamente esta solución  permite por ejemplo usar  melodías diferentes para  diferenciar  una llamada  de otro  en un mismo receptor, pero cuidado porque esta solución en caso de querer implementarla en un portero automático, NO servirá para sistemas con llamada electrónica aunque si funcionara perfectamente en porteros automáticos con llamada por zumbador si sustituimos la fuente de 220v 5vDC por un sencillo puente de diodos de 24V y un regulador 7805.

Uso en Timbre del Hogar

El conjunto transmisor y timbre inalámbrico se adaptan a la perfección a su cometido de conseguir que el timbre del portero electrónico con llamada por zumbador o el timbre de la vivienda se oigan donde sea necesario (por ejemplo en el comedor, en la terraza, en el dormitorio, etc.).

Observe  que vamos a adaptar  un circuito comercial para una finalidad concreta ( un timbre de casa inalámbrico) para conectarlo al timbre de acceso a nuestra vivienda y por tanto que se alimenta de la red de c.a.  de 220V por lo que debe extremar las precauciones

Como base vamos a usar un modulo recptor/emisor de buena relacion calidad precio modelo Electra Line 59199 de Timbre inalámbrico Timbre de Puerta, con Enchufe 10 A, 36 melodías Ajustable, Blanco que podemos comprar por unos 14€

Estas son algunas de las características:

  • Wireless.
  • Con el enchufe 10A.
  • 36 melodías ajustables.
  • 80 metros de alcance.
  • Incluyendo las baterías.

En el caso de necesitar extender el timbre de la vivienda vamos a necesitar reducir la tensión del timbre 220V AC en unos 5V DC para hacer funcionar el transmisor, el cual esta alimentado en origen con una pila compacta de 12V.

Obviamente al alimentar el emisor no basta para activar la señal que envía el transmisor, por lo que para que al alimentarlo envíe dicha señal, cortocircuitaremos los contactos del pulsador para que se ponga el trasmisor inmediatamente a enviar la señal de llamada en cuanto este alimentado el circuito emisor.

Empezaremos desmontado cualquier fuente conmutada de 220V/ 5V de las usadas para los cargadores USB dado que prescindiremos del enchufe al ir conectado estos hilos en paralelo con las conexiones del timbre, por lo que precisamente soldaremos un para de hilos justo en esas dos conexiones ( donde harían contacto los extremos del enchufe de AC)

Seguidamente dejaremos el capuchón frontal para proteger la electrónica, y cubriremos por ejemplo con cinta americana el lado opuesto de la placa para evitar cualquier contacto accidental con este

Ahora toca modificar el emisor para alimentarlo directamente con la fuente que hemos preparado soldando directamente los dos hilos de salida de 5v DC a los correspondientes del emisor ( cuidado no confundir los hilos pues quemaríamos el circuito)

Como toque interesante para ayudar la descarga de la fuente una vez haya dejado de pulsarse el timbre, podemos conectar una carga de 4 leds rojos en serie para intentar cortar el transmisor en cuanto se haya dejado de alimentar este

Otro aspecto a destacar, son los hilos del pulsador que deberemos cortocircuitar para activar la emisión ( hilos blanco y naranja en la imagen).

Solo nos queda colocar ambos componentes en el interior del timbre de la forma mas compacta posible , eso si aislando muy bien ambos componentes por ejemplo con cinta americana

Y una vez ubicadas ambas partes en el interior del timbre solo queda conectar los hilos de la fuente en paralelo con las conexiones AC del timbre ( mucho cuidado con los contactos accidentales pues podemos tener prsente uan fase aunque no se haya pulsado el timbre )

Finalmente un opción si no hay demasiado espacio es ubicar la fuente en el interior del timbre y el emisor fuera en un lateral

Uso en un portero automático

Vamos a describir para usar esta misma idea en un portero automático con llamada por zumbador, En efecto conseguiremos tener un segundo tono de llamada por ejemplo en un Urmet 1130. Sólo necesitamos desoldar la batería y el switch que se pasara por alto cortocircuitamos sus terminales como hemos hecho en la solución anteior.

En la imagen vemos el pequeño emisor que introduciremos en el telefonillo o en el propio timbre .  En este caso, los cables negro y azul se conectarán en paralelo con el timbre mecánico.  El cable blanco es para la antena emisora  que lógicamente, no se conecta a ningún sitio.

Respecto al resto de la electrónica montaremos un puente de diodos de 24V AC y 12DC, un pequeño regulador de tensión ( por ejemplo un 7805) a la salida DC del puente .

¿Cómo medir la potencia real de CA y la potencia aparente con Arduino?


Cuando se habla de potencia en corriente alterna (CA), es más complicado, ya que implica forma de onda y diferencia de fase, pero básicamente, hay 3 términos para la alimentación de CA: la potencia aparente , la potencia activa y la potencia reactiva . 

  • La potencia aparente se refiere a la potencia total en un circuito de CA que incluye la potencia disipada y absorbida. Este término es importante para el diseño de generadores de energía y cables para asegurarse de que todo el cableado y la energía puedan soportar todo tipo de cargas. La potencia aparente se puede calcular multiplicando el valor de voltaje de raíz cuadrada media (RMS) y el valor de corriente (RMS).
  • El segundo término es el Poder Activo / Real . Es la potencia real consumida por la carga. La potencia activa se puede calcular promediando el producto de los valores instantáneos de forma de onda de voltaje y corriente. 
  • El tercer término es la potencia reactiva, que se refiere a la potencia que se desperdicia y que la carga no utiliza como trabajo útil debido a la diferencia de fase entre las formas de onda de voltaje y corriente. Cuando la potencia reactiva se suma a la potencia activa, le dará la potencia aparente. 

Usaremos un Arduino para medir la  potencia aparente y la potencia real por lo que para medir la energía de CA , necesitamos usar 2 sensores separados que son el módulo de voltaje de CA monofásico y el módulo de corriente de CA. 

Cada módulo puede encajar en el pin de entrada analógica Arduino  . Para un Arduino UNO, hay  6 pines de entrada analógicas  (A0-A5)pero para un Arduino NANO tiene 8 pines, mientras que Arduino MEGA tiene 16 pines de entrada. Los pines de entrada analógica asignarán voltajes de entrada entre 0 y 5 V en valores enteros entre 0 y 1023 con una resolución de 4,9 mV por unidad (5,00 V / 1024 unidades). 

!Cuidado ! Asumimos que tiene los conocimientos básicos de electricidad y sabe a qué se enfrenta. Es posible que necesite la orientación de personas con experiencia si es nuevo en el trabajo eléctrico. La seguridad y la precaución deben tenerse siempre en cuenta. No seremos responsables de nada que le suceda.

Puede medir voltaje CA como 110Vac, 220Vac y 240Vac mediante el uso de la disposición en el mercado  individual  Fase V de CA módulo de voltaje. Puede detectar la forma de onda instantánea para el valor de voltaje. La señal se puede utilizar con el sensor de corriente CA para determinar más información útil, como el  factor de potencia, la dirección del flujo de corriente, la potencia real y la potencia aparente. 

Es posible que deba precalibrar el módulo. Mediante el uso del potenciómetro trimpot, se puede ajustar la amplitud de la forma de onda de voltaje. Se recomienda utilizar un segundo medidor que lea el voltaje RMS para facilitar la calibración. 

Módulo de voltaje CA monofásico

Este módulo ZMPT101 B está equipado con un transformador de voltaje de alta precisión ZMPT101B y un circuito de amplificador operacional. Puede medir voltaje CA dentro de 250V. La señal de salida correspondiente se puede ajustar utilizando el potenciómetro de ajuste. 

La imagen tiene un atributo ALT vacío; su nombre de archivo es 51tDdSO3u+L._AC_SL1000_.jpg

Estas resumidamente algunas de sus características:

  • Módulo de transformador de voltaje monofásico activo Sensor de voltaje de salida de CA
  • Equipado con la serie ZMPT101B de transformador de voltaje de alta precisión y corriente de amplificador operacional de alta precisión, fácil de 250V dentro de la adquisición de señal de alimentación de CA
  • Transformador de voltaje: Transformador de micro voltaje de precisión a bordo
  • Salida de voltaje de modo: el módulo puede medir el voltaje de CA dentro de 250 V, el modo de salida correspondiente se puede ajustar
  • Circuito amplificador operacional: circuito amplificador integrado de alta precisión, la señal para hacer el muestreo exacto y la compensación adecuada y otras funciones

El sensor de Intensidad

El segundo sensor del que queremos hablar es el Módulo Sensor de Corriente. El sensor de corriente ampliamente utilizado que es compatible con Arduino es el módulo de sensor de corriente ACS712 . Utiliza el fenómeno de efecto hall cuyo voltaje se produce a partir del movimiento de la corriente dentro de la región del campo magnético. El voltaje producido por el efecto hall es directamente proporcional a la corriente aplicada, lo que lo hace adecuado para estimar la corriente aplicada a partir del voltaje detectado.

El módulo de sensor de corriente estándar  ACS712  se vende en tres versiones de   5A, 20A y 30A  que sons adecuadas para la mayoría de las aplicaciones.  El módulo 5A tiene una resolución de 185 mV / amperio, el módulo 20A tiene 100 mV / amperio, mientras que el módulo 30A tiene una resolución de 66 mV / amperio.

Estos módulos requieren contacto directo, lo cual podria ser un gran inconveniente pues debe conectarse en serie al valor medido . El cableado del sistema existente debe modificarse para que el módulo encaje en el sistema existente. 

Si no tiene experiencia con la alimentación de CA, personalmente no recomiendo este módulo. Este módulo es aceptable para CC de bajo voltaje, pero puede ser  peligroso en CA si no se toma en serio ,por lo que una alternativa es usar un tipo de sensor de efecto Hall con transformador de núcleo dividido (como se muestra en la imagen de la izquierda). Es el   módulo HSTS016L del sensor de núcleo dividido de efecto Hall . El modelo va desde 10A hasta 200A . Con el tipo de sensor de corriente de núcleo dividido, no se requiere alteración en el sistema existente. !!! El voltaje de salida de este sensor es de  2,5 V +/- 0,625 V  con una precisión decente. Recomiendo encarecidamente este sensor para medir la corriente alterna en caso de no tener experiencia con BT.

YHDC Hall Split Core Current Sensor HSTS016L ±10A/2.5±0.625V

Codigo arduino

Para fines de demostración, usaremos el sensor de núcleo dividido de efecto Hall que no requiere contacto eléctrico con el sistema de cableado existente, lo que definitivamente es una forma más segura  !!!Las señales detectadas por Arduino están en valores analógicos. A continuación se muestran las señales detectadas por el voltaje (azul) y el sensor de corriente (rojo). Puede copiar el siguiente código para probar el suyo. Puede ver la forma de onda en Serial Plotter. Conecte el módulo de voltaje en el pin A2 de Arduino mientras que el módulo de corriente en el pin A3 . La magnitud del voltaje (onda azul) se puede calibrar mediante el módulo de voltaje de CA utilizando el potenciómetro integrado y se puede comparar con el voltímetro RMS de referencia. Para una onda sinusoidal pura como esta, el valor RMS en el voltímetro multiplicado por la raíz cuadrada 2 es igual al voltaje máximo(magnitud desde la mitad de la oscilación). La magnitud de la onda de corriente (onda roja) está sujeta a su carga aplicada. Puede modificar el código Arduino para aumentar su magnitud con fines de visualización. El patrón de onda de CA puede no ser 100% suave como una onda de voltaje y está sujeto a la carga sobre cómo se extrae la corriente. El cambio de fase o la diferencia de fase entre el voltaje y la corriente también están sujetos a la carga aplicada.

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); 
}

 El punto medio para Ambas ondas debería estar técnicamente en 512 (valor analógico) y fluctúa entre 0 y 1023 de forma predeterminada. Sin embargo, he modificado el código para que las ondas oscilen en el punto medio del  valor 0  entre 512 y -512 para facilitar el cálculo más adelante. Antes de continuar, es necesario realizar una calibración antes de la medición,  ya que algunos módulos pueden tener un error de desviación diferente. Puede ir a la publicación de sensores individuales para obtener más información.

Cómo se procesa la señal

Necesitamos determinar los 2 valores de potencia de CA, el valor de potencia de CA RMS  y el valor de potencia de CA activa . Antes de continuar, comencemos con la calibración inicial de ambos sensores. Necesitamos minimizar cualquier error potencial de desviación o inexactitud tanto como sea posible. Los sensores son muy sensibles, asegúrese de utilizar conectores ajustados y terminales de cable. 

Necesitamos una calibración de 2 veces para cada sensor de módulo . Ambas calibraciones deben realizarse sin medir la corriente y el voltaje. La primera calibración es asegurarse de que cuando no se mide voltaje o corriente, se muestra exactamente en el punto 0. Es una calibración de valor analógico. Es posible que algunos módulos no se muestren exactamente en el valor analógico 512 (lo he cambiado al punto 0 usando el código Arduino para una fácil comprensión) cuando no se detecta ningún valor. Necesitamos agregar un valor de compensación para que esto vuelva a ajustarlo al origen cuando no se detecta ningún valor.

La segunda calibración es para eliminar aún más el valor de la señal falsa durante el cálculo RMS. Incluso después de que se realiza la primera calibración, todavía hay algún ruido fantasma o eléctrico menor incluso cuando no se miden voltaje ni corriente. Tenemos que agregar otro desplazamiento para llegar al valor cero en la etapa final de visualización. Esta segunda calibración debe realizarse solo después de que la primera calibración entre en vigor. Ambas calibraciones se pueden realizar manualmente (la forma más difícil) o automáticamente presionando el botón SELECT en el protector de la pantalla LCD y espere unos 5 segundos. Por eso es necesario tener el escudo para que funcione. ¡Puede comprar en nuestro enlace de afiliado aquí !

El cálculo de la potencia cuadrática media de la raíz

La  potencia de CA RMS  es el producto de los   valores de voltaje CA RMS  y  corriente CA RMS . El voltaje CA RMS y la corriente CA RMS se calculan por separado. Al encontrar la potencia de CA RMS, el voltaje RMS y la corriente RMS se encuentran indirectamente. 

Nuestro código está diseñado para calcular o mostrar un valor que se deriva de un  promedio de 1000 muestras por conjunto. Encontré un problema de que un tiempo de grabación de muestra más corto (menos de 1 milisegundo para 1 lectura de muestra) podría retrasar el tiempo de procesamiento, lo que hizo que el tiempo de visualización se ralentizara. He configurado que cada muestra se registre cada 1 milisegundo (0,001 segundos). En otras palabras, el conjunto completo total equivale a 50 ondas con cada onda dividida en 20 secciones o lecturas (para 50 Hz). Técnicamente, debería durar 1 segundo para 1 conjunto de lectura. También es adecuado para el sistema de 60 Hz, ya que el tiempo de medición para 1 juego de lectura es de 1 segundo.

Cada valor analógico de muestra individual se eleva al  cuadrado  inicialmente y una vez que se  acumulan los valores  de 1000 muestras , el  valor promedio de las 1000 muestras se establece   en raíz cuadrada para obtener el   valor analógico RMS (para 1 sensor). Convierta el valor analógico RMS en voltaje medido o valor actual. Realice el cálculo similar por separado para el otro sensor y multiplique ambos valores RMS para convertirlos en energía CA RMS. A continuación se muestra un ejemplo de cómo funciona el código. Tomo un  cuarto de onda como ejemplo .

En la conversión de  voltaje RMS , multiplico  el valor analógico RMS por 2 . Durante la calibración de este módulo, reduje la amplitud de onda a la mitad (es por eso que en el código es necesario multiplicar por 2) porque la onda de voltaje comenzó a distorsionarse o cortarse cerca de 250Vac, lo que puede dar inexactitud en la medición. Puede aumentar el voltaje de suministro al módulo para eliminar el efecto de corte (según el manual del módulo) pero creo que lo dejaré así ya que no voy a agregar suministro de voltaje adicional. En cuanto a la conversión de corriente RMS, el mV / A es la clasificación del sensor de corriente y lo dejo como el símbolo de la unidad. 1023 es la conversión de valor analógico, mientras que 5000 es el valor de voltaje en mV. Para obtener más información sobre esto, puede ir a mi publicación sobre el sensor de CA  aquí..

El cálculo de la potencia instantánea

Active o Real Power  es más simple en comparación con RMS Power.  Es el  valor promedio  de todas las  multiplicaciones  de  voltaje instantáneo  y   valor de corriente instantánea . Los valores analógicos de tensión y corriente   se convierten primero en  valores de tensión y corriente medidos . Luego, el voltaje se multiplica por su valor de corriente instantánea y se convierte en una lectura de muestra. 

Similar al método de potencia RMS, la potencia activa también se deriva de un promedio de 1000 muestras por conjunto. Cada muestra se registra cada milisegundo, es decir, el conjunto completo total equivale a 50 ondas con cada onda dividida en 20 secciones o lecturas (para 50 Hz). 

Puede ser interesante añadir una pantalla LCD de 16X2   que se puede colocar directamente en la parte superior de la placa Arduino sin la necesidad de cableado adicional para la pantalla LCD. Sin la pantalla LCD, solo puede monitorear el valor de corriente medido en la PC a través del Monitor en serie. 

La buena noticia es que no necesita calibrar manualmente la configuración de compensación si tiene la pantalla LCD  con usted. A continuación, adjuntamos el código que utiliza la función del botón que podría  calibrarse automáticamente  por sí mismo cuando presionó el  botón SELECT . Puede descargar desde el final de esta página a continuación.  

Conexión de hardware

Es posible que deba encontrar una manera de colocar el cable del sensor de CA en el pin Arduino. El cable del sensor que compré venía presoldado en la punta, lo que facilita el acceso a los pines de Arduino. Abra el módulo de corriente Split Core y se mostrará un símbolo de flecha que indica el camino del flujo de corriente. Una vez que todo esté listo, asegúrese de que el núcleo partido esté bien cerrado.  

Asegúrese de que debajo del sensor de voltaje no haya conductores expuestos o placas de metal que puedan causarle un cortocircuito accidental en el terminal del módulo. Debe obtener el fusible rápido de baja corriente para el cable del sensor de voltaje, mientras que el MCB o el fusible de corriente nominal suficiente según su carga para protegerlo contra cualquier posible cortocircuito y riesgo de incendio.

Para conectar el cableado entre la placa Arduino y el módulo, necesita los  cables de línea dupont macho a hembra . ¡Puedes conseguirlo en nuestro enlace de afiliado aquí ! 

Necesita el conector que pueda asegurar los cables y aislarlos del contacto accidental. ¡Obtenga el  conector rápido  en nuestro enlace de afiliado  aquí  !

Código final Arduino

El paso final sería agregar el código fuente a la placa Arduino. Supongo que ha instalado el software Arduino. Si no ha instalado el software, el enlace  aquí  puede llevarlo al sitio oficial de descarga. Una vez que haya descargado el software, puede descargar el archivo de código (.ino) para esta aplicación a continuación (haga clic con el botón derecho en el enlace para guardar). 

Hay 2  archivos de códigos fuente adjuntos  que son código fuente con y sin función de protección de pantalla LCD. Si no tiene el protector de pantalla LCD con usted, elija el código que no tiene el protector de pantalla LCD, pero debe calibrar manualmente e ingresar los 2 valores de compensación para ambos sensores. Sin embargo, le recomiendo encarecidamente que obtenga un protector de pantalla LCD.

Con el protector de pantalla LCD, una vez que el código se carga en la placa Arduino, el valor actual se mostrará en la pantalla LCD. Hemos agregado la función de autocalibrado, una vez que se presiona el botón SELECT, el valor regresa al punto cero exacto. Puede que tenga que esperar entre 5 y 8 segundos hasta que se vuelvan a calibrar todos los valores. Si la primera pulsación no está satisfecha, puede repetir pulsando de nuevo .

Proceso de calibracion 

Una vez que el código se carga en el Arduino, si tiene un protector de pantalla LCD adjunto, verá la corriente, el voltaje, la potencia activa y el valor de potencia aparente. Asegúrese de apagar la fuente de voltaje de CA  que está midiendo. Presione el botón SELECT del protector de pantalla LCD y espere 5 segundos. Debería llegar a  0 voltios . Lo mismo para la corriente CA que muestra 0A . Para las personas que no tienen el protector de pantalla LCD, puede compensar manualmente ingresando el valor de compensación en el código y volver a cargarlo. Hay 2 valores de compensación (voltageOffset1 y voltageOffset2) que se deben calibrar. Haga lo mismo para el módulo de corriente CA para 2 valores de compensación (currentOffset1 y currentOffset2) y finalmente es el powerOffset.

Ajuste de voltaje de CA del potenciómetro de trimpot 

Esta configuración es para ajustar la magnitud de la onda de voltaje de CA. A diferencia de la corriente CA, calculamos y obtenemos la corriente esperada, pero para el voltaje CA, necesitamos un voltaje de referencia para el ajuste.

Una vez realizada la calibración, debería ver el valor 0 voltios cuando no se detecta voltaje. Ahora, encienda la fuente de voltaje y encienda el lector de voltaje de referencia (el multímetro o el medidor de energía). Compare ambos valores de voltaje. Gire el potenciómetro de ajuste (trimpot) con un destornillador pequeño para reducir o aumentar el valor de voltaje detectado por Arduino. Debe girar el potenciómetro hasta que el voltaje que se muestra en la pantalla LCD Shield o Monitor serial sea el mismo que el valor de referencia de voltaje en el medidor de voltaje o energía. ¡¡¡Y felicitaciones, ya está hecho !!!!

Si realmente lee los códigos, en realidad hemos reducido la amplitud de onda potencial a la mitad (en la fórmula es por 2). 

RMSVoltageMean = (sqrt (voltageMean)) * 2;

Es por eso que cuando se aplica voltaje de monitoreo, el valor medido es alto y es necesario reducirlo. La amplitud de onda completa (x 1) se distorsiona cuando está cerca de 250 V, lo que nos hizo tener esta opción para superar el problema de distorsión.

Resultado: en monitor de serie

Para archivos de código Arduino, recuerde hacer clic derecho> Guardar enlace como …  Puede modificar el código interno como desee. ¡Feliz codificación! 

AC Power.ino

// AC Power Monitoring By Solarduino 

// Note Summary
// Note :  Safety is very important when dealing with electricity. We take no responsibilities while you do it at your own risk.
// Note :  This AC Power Monitoring Code needs AC current module and AC Voltage Module to determine AC Power value. 
// Note :  This Code monitors RMS Voltage, RMS current, RMS AC Power (Apparent Power) and Instantaneous AC Power (Active Power)
// Note :  The value shown in Serial Monitor is refreshed every second, can be used for 50Hz and 60Hz.
// Note :  The frequency is measured by counting time and average it for every 50 samples taken (1 sample is 1 cycle for 50Hz by default).
// Note :  You have to manually calibrate 5 offsets readings : voltageOffset1,voltageOffset2,currentOffset1,currentOffset2 & powerOffset.  
// Note :  The unit provides reasonable accuracy and may not be comparable with other expensive branded and commercial product.
// Note :  All credit shall be given to Solarduino.

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/


        /* 0- General */

        int decimalPrecision = 2;                         // decimal places for all values shown in LED Display & Serial Monitor

        /* 1- AC Voltage Measurement */
        
        int voltageOffset1  = 0;                          // key in offset value
        int voltageOffset2  = 0;                          // key in offset value
        int VoltageAnalogInputPin = A2;                   // Which pin to measure voltage Value
        float voltageSampleRead  = 0;                     /* to read the value of a sample*/
        float voltageLastSample  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float voltageSampleSum   = 0;                     /* accumulation of sample readings */
        float voltageSampleCount = 0;                     /* to count number of sample. */
        float voltageMean ;                               /* to calculate the average value from all samples*/ 
        float RMSVoltageMean ;                            /* square roof of voltageMean*/


        /* 2- AC Current Measurement */

        int currentOffset1  = 0;                          // key in offset value
        int currentOffset2  = 0;                          // key in offset value
        int CurrentAnalogInputPin = A3;                   // Which pin to measure Current Value
        float mVperAmpValue = 31.25;                      // If using ACS712 current module : for 5A module key in 185, for 20A module key in 100, for 30A module key in 66
                                                          // If using "Hall-Effect" Current Transformer, key in value using this formula: mVperAmp = maximum voltage range (in milli volt) / current rating of CT
                                                          /* For example, a 20A Hall-Effect Current Transformer rated at 20A, 2.5V +/- 0.625V, mVperAmp will be 625 mV / 20A = 31.25mV/A */
        float currentSampleRead  = 0;                     /* to read the value of a sample*/
        float currentLastSample  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float currentSampleSum   = 0;                     /* accumulation of sample readings */
        float currentSampleCount = 0;                     /* to count number of sample. */
        float currentMean ;                               /* to calculate the average value from all samples*/ 
        float RMSCurrentMean =0 ;                         /* square roof of currentMean*/
        float FinalRMSCurrent ;                           /* the final RMS current reading*/


        /* 3- AC Power Measurement */
        
        int powerOffset =0;                               // key in offset value
        float sampleCurrent1 ;                            /* use to calculate current*/
        float sampleCurrent2 ;                            /* use to calculate current*/
        float sampleCurrent3 ;                            /* use to calculate current*/
        float apparentPower;                              /* the apparent power reading (VA) */
        float realPower = 0;                              /* the real power reading (W) */
        float powerSampleRead  = 0;                       /* to read the current X voltage value of a sample*/
        float powerLastSample   = 0;                      /* to count time for each sample. Technically 1 milli second 1 sample is taken */       
        float powerSampleCount  = 0;                      /* to count number of sample. */
        float powerSampleSum    = 0;                      /* accumulation of sample readings */         
        float powerFactor = 0;                            /* to display power factor value*/ 


void setup()                                              /*codes to run once */

{                                      

        /* 0- General */
        
        Serial.begin(9600);                               /* to display readings in Serial Monitor at 9600 baud rates */

}


void loop()                                                                                       /*codes to run again and again */
{                                      


        /* 1- AC Voltage Measurement */
 
        if(millis() >= voltageLastSample + 1 )                                                    /* every 1 milli second taking 1 reading */
          {
            voltageSampleRead = 2*(analogRead(VoltageAnalogInputPin)- 512) + voltageOffset1;      /* read the sample value */           
            voltageSampleSum = voltageSampleSum + sq(voltageSampleRead) ;                         /* accumulate value with older sample readings*/     
            voltageSampleCount = voltageSampleCount + 1;                                          /* to move on to the next following count */
            voltageLastSample = millis() ;                                                        /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(voltageSampleCount == 1000)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {           
            voltageMean = voltageSampleSum/voltageSampleCount;                                    /* calculate average value of all sample readings taken*/
            RMSVoltageMean = sqrt(voltageMean)+ voltageOffset2;                                   /* square root of the average value*/
            Serial.print("Voltage RMS: ");
            Serial.print(RMSVoltageMean,decimalPrecision);
            Serial.println("V  ");
            voltageSampleSum =0;                                                                  /* to reset accumulate sample values for the next cycle */
            voltageSampleCount=0;                                                                 /* to reset number of sample for the next cycle */
          }


        /* 2- AC Current Measurement */
        
        if(millis() >= currentLastSample + 1)                                                     /* every 1 milli second taking 1 reading */
          {
            currentSampleRead = analogRead(CurrentAnalogInputPin)-512 + currentOffset1;           /* read the sample value */
            currentSampleSum = currentSampleSum + sq(currentSampleRead) ;                         /* accumulate value with older sample readings*/
            currentSampleCount = currentSampleCount + 1;                                          /* to move on to the next following count */
            currentLastSample = millis();                                                         /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(currentSampleCount == 1000)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {       
            currentMean = currentSampleSum/currentSampleCount;                                    /* calculate average value of all sample readings taken*/
            RMSCurrentMean = sqrt(currentMean)+currentOffset2 ;                                   /* square root of the average value*/
            FinalRMSCurrent = (((RMSCurrentMean /1024) *5000) /mVperAmpValue);                    /* calculate the final RMS current*/
            Serial.print("Current RMS: ");
            Serial.print(FinalRMSCurrent,decimalPrecision);
            Serial.println(" A  ");
            currentSampleSum =0;                                                                  /* to reset accumulate sample values for the next cycle */
            currentSampleCount=0;                                                                 /* to reset number of sample for the next cycle */
          }

       
        /* 3- AC Power with Direction */

        if(millis() >= powerLastSample + 1)                                                       /* every 1 milli second taking 1 reading */
          {
            sampleCurrent1 = analogRead(CurrentAnalogInputPin)-512+ currentOffset1;
            sampleCurrent2 = (sampleCurrent1/1024)*5000;
            sampleCurrent3 = sampleCurrent2/mVperAmpValue;
            voltageSampleRead = 2*(analogRead(VoltageAnalogInputPin)- 512)+ voltageOffset1 ;
            powerSampleRead = voltageSampleRead * sampleCurrent3 ;                                /* real power sample value */
            powerSampleSum = powerSampleSum + powerSampleRead ;                                   /* accumulate value with older sample readings*/
            powerSampleCount = powerSampleCount + 1;                                              /* to move on to the next following count */
            powerLastSample = millis();                                                           /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(powerSampleCount == 1000)                                                              /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            realPower = ((powerSampleSum/powerSampleCount)+ powerOffset) ;                        /* calculate average value of all sample readings */
            Serial.print("Real Power (W): ");
            Serial.print(realPower);
            Serial.println(" W  ");           
            apparentPower= FinalRMSCurrent*RMSVoltageMean;                                       /*Apparent power do not need to recount as RMS current and RMS voltage values available*/
            Serial.print("Apparent Power (VA): ");
            Serial.print(apparentPower,decimalPrecision);
            Serial.println(" VA ");
            powerFactor = realPower/apparentPower;    
            if(powerFactor >1 || powerFactor<0)
            {
              powerFactor = 0;
            }
            Serial.print("Power Factor: ");
            Serial.println(powerFactor,decimalPrecision);  
            Serial.println(" ");                                           
            powerSampleSum =0;                                                                    /* to reset accumulate sample values for the next cycle */
            powerSampleCount=0;                                                                   /* to reset number of sample for the next cycle */
          }
  
}









lcd (AP Power with LCD Disply.ino)

// AC Power Monitoring with LCD By Solarduino 

// Note Summary
// Note :  Safety is very important when dealing with electricity. We take no responsibilities while you do it at your own risk.
// Note :  This AC Power Monitoring Code needs AC current module and AC Voltage Module to determine AC Power value. 
// Note :  This Code monitors RMS Voltage, RMS current, RMS AC Power (Apparent Power) and Instantaneous AC Power (Active Power)
// Note :  The value shown in Serial Monitor is refreshed every second, can be used for 50Hz and 60Hz.
// Note :  The frequency is measured by counting time and average it for every 25 samples taken (1 sample is 1 cycle).
// Note :  The auto calibration (voltageOffset1 & currentOffset1) is using averaged analogRead value of 1000 samples.
// Note :  The auto calibration (voltageOffset2 & currentOffset2) is using calculated RMS value including Offset1 value for calibration.    
// Note :  The unit provides reasonable accuracy and may not be comparable with other expensive branded and commercial product.
// Note :  All credit shall be given to Solarduino.

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/


        /* 0- General */

        int decimalPrecision = 2;                         // decimal places for all values shown in LED Display & Serial Monitor

        /* 1- AC Voltage Measurement */
        
        int VoltageAnalogInputPin = A2;                   // Which pin to measure voltage Value
        float voltageSampleRead  = 0;                     /* to read the value of a sample*/
        float voltageLastSample  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float voltageSampleSum   = 0;                     /* accumulation of sample readings */
        float voltageSampleCount = 0;                     /* to count number of sample. */
        float voltageMean ;                               /* to calculate the average value from all samples*/ 
        float RMSVoltageMean ;                            /* square roof of voltageMean*/

              /*1.1 Offset AC Voltage */
    
              int voltageOffsetRead = 0;                  /* to change the mode for offset */
              float voltageOffset1 = 0;                   // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                          // Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
                                                          // If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
              float voltageOffset2 = 0;                   // to offset value due to calculation error from squared and square root.
              float voltageSampleSumOffset =0;            /* accumulation of sample readings for offset */
              float offsetVoltageMean = 0;                /* to calculate the average value from all samples for offset, in analog values*/
              float voltageOffsetLastSample = 0;          /* to count time for each sample for offset purpose. */
              float voltageOffsetSampleCount = 0;         /* to count number of sample for offset. */


        /* 2- AC Current Measurement */

        int CurrentAnalogInputPin = A3;                   // Which pin to measure Current Value
        float mVperAmpValue = 31.25;                      // If using ACS712 current module : for 5A module key in 185, for 20A module key in 100, for 30A module key in 66
                                                          // If using "Hall-Effect" Current Transformer, key in value using this formula: mVperAmp = maximum voltage range (in milli volt) / current rating of CT
                                                          /* For example, a 20A Hall-Effect Current Transformer rated at 20A, 2.5V +/- 0.625V, mVperAmp will be 625 mV / 20A = 31.25mV/A */
        float currentSampleRead  = 0;                     /* to read the value of a sample*/
        float currentLastSample  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float currentSampleSum   = 0;                     /* accumulation of sample readings */
        float currentSampleCount = 0;                     /* to count number of sample. */
        float currentMean ;                               /* to calculate the average value from all samples*/ 
        float RMSCurrentMean =0 ;                         /* square roof of currentMean*/
        float FinalRMSCurrent ;                           /* the final RMS current reading*/


              /*2.1 Offset AC Current */
    
              int currentOffsetRead = 0;                  /* to change the mode for offset */
              float currentOffset1 = 0;                   // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                          // Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
                                                          // If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
                                                          // 26 means add 26 to all analog value measured
              float currentOffset2 = 0;                   // to offset value due to calculation error from squared and square root.
              float currentSampleSumOffset = 0;           /* accumulation of sample readings for offset */
              float offsetCurrentMean = 0;                /* to calculate the average value from all samples for offset, in analog values*/
              float currentOffsetLastSample = 0;          /* to count time for each sample for offset purpose. */
              float currentOffsetSampleCount = 0;         /* to count number of sample for offset. */


        /* 3- AC Power Measurement */
        
        float sampleCurrent1 ;                            /* use to calculate current*/
        float sampleCurrent2 ;                            /* use to calculate current*/
        float sampleCurrent3 ;                            /* use to calculate current*/
        float apparentPower;                              /* the apparent power reading (VA) */
        float realPower = 0;                              /* the real power reading (W) */
        float powerSampleRead  = 0;                       /* to read the current X voltage value of a sample*/
        float powerLastSample   = 0;                      /* to count time for each sample. Technically 1 milli second 1 sample is taken */       
        float powerSampleCount  = 0;                      /* to count number of sample. */
        float powerSampleSum    = 0;                      /* accumulation of sample readings */         
        float powerFactor = 0;                            /* to display power factor value*/ 


              /*3.1 Offset AC Power */
    
              int powerOffsetRead = 0;                    /* to change the mode for offset */
              float powerOffset = 0;                      // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                          // Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
                                                          // If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
              float powerOffsetLastSample = 0;            /* to count time for each sample for offset purpose. */
              float powerOffsetSampleCount = 0;           /* to count number of sample for offset. */

        
        /* 4 - LCD Display  */

        #include<LiquidCrystal.h>                   /* Load the liquid Crystal Library (by default already built-it with arduino solftware)*/
        LiquidCrystal LCD(8,9,4,5,6,7);             /* Creating the LiquidCrystal object named LCD. The pin may be varies based on LCD module that you use*/
        unsigned long startMillisLCD;               /* start counting time for LCD Display */
        unsigned long currentMillisLCD;             /* current counting time for LCD Display */
        const unsigned long periodLCD = 1000;       // refresh every X seconds (in seconds) in LED Display. Default 1000 = 1 second 
        int page = 1;                               /* flip page to display values*/

void setup()                                              /*codes to run once */

{                                      

        /* 0- General */
        
        Serial.begin(9600);                               /* to display readings in Serial Monitor at 9600 baud rates */

        /* 4 - LCD Display  */

        LCD.begin(16,2);                                  /* Tell Arduino that our LCD has 16 columns and 2 rows*/
        LCD.setCursor(0,0);                               /* Set LCD to start with upper left corner of display*/  
        startMillisLCD = millis();                        /* Start counting time for LCD display*/

}


void loop()                                                                                       /*codes to run again and again */
{                                      

        /* 0- General */


              /* 0.1- Button Function */
        
              int buttonRead;
              buttonRead = analogRead (0);                                                        // Read analog pin A0. Pin A0 automatically assigned for LCD Display Button function (cannot be changed)

              /*Right button is pressed */
              if (buttonRead < 60) 
              {   LCD.setCursor(0,0); LCD.print ("PRESS <SELECT>   "); }       
     
              /* Up button is pressed */
              else if (buttonRead < 200) 
              {   
              page = 1;
              }    
                 
              /* Down button is pressed */
              else if (buttonRead < 400)
              {   
              page = 2;
              }      
     
              /* 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;                                                              // to activate offset for current  
              voltageOffsetRead = 1;                                                              // to activate offset for voltage
              powerOffsetRead = 1;                                                                // to activate offset for power
              LCD.setCursor(0,0);                                                                 /* set display words starting at upper left corner*/
              LCD.print ("INITIALIZING..... ");
              LCD.setCursor(0,1);                                                                 /* set display words starting at lower left corner*/
              LCD.print ("WAIT 5 SEC ..... ");
              }


        /* 1- AC Voltage Measurement */
 
        if(millis() >= voltageLastSample + 1 )                                                    /* every 1 milli second taking 1 reading */
          {
            voltageSampleRead = 2*(analogRead(VoltageAnalogInputPin)- 512) + voltageOffset1;      /* read the sample value */
            voltageSampleSumOffset = voltageSampleSumOffset + voltageSampleRead;                  /* values accumulate for offset purpose every milli second */
            
            voltageSampleSum = voltageSampleSum + sq(voltageSampleRead) ;                         /* accumulate value with older sample readings*/     
            voltageSampleCount = voltageSampleCount + 1;                                          /* to move on to the next following count */
            voltageLastSample = millis() ;                                                        /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(voltageSampleCount == 1000)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            offsetVoltageMean = voltageSampleSumOffset/voltageSampleCount;                        /* average the offset reading*/
            
            voltageMean = voltageSampleSum/voltageSampleCount;                                    /* calculate average value of all sample readings taken*/
            RMSVoltageMean = sqrt(voltageMean)+ voltageOffset2;                                   /* square root of the average value*/
            Serial.print(" The Voltage RMS value is: ");
            Serial.print(RMSVoltageMean,decimalPrecision);
            Serial.println(" V ");
            voltageSampleSum =0;                                                                  /* to reset accumulate sample values for the next cycle */
            voltageSampleCount=0;                                                                 /* to reset number of sample for the next cycle */
            voltageSampleSumOffset=0;
          }
 

              /* 1.1 - Offset AC Voltage */
                  
              if(voltageOffsetRead == 1)                                                          /* Run this code when button SELECT is pressed */
                {
                  voltageOffset1 = 0; 
                  if(millis()>= voltageOffsetLastSample + 1)                                      /* keep countng time for offset1*/
                    {                                                                            
                      voltageOffsetSampleCount = voltageOffsetSampleCount + 1;                    /* 1 milli second add 1 count*/                                                      
                      voltageOffsetLastSample = millis();                                         /* to reset the time again so that next cycle can start again*/                                  
                    }                                                                                 
                  if(voltageOffsetSampleCount == 2000)                                            /* after 2 seconds, run this codes.  */
                    {                                                                            
                      voltageOffset1 = -1*(offsetVoltageMean);                                    /* set the offset values */
                      voltageOffsetRead = 2;                                                      /* go for second offset Settings */                     
                      voltageOffsetSampleCount = 0;                                               /* to reset the time again so that next cycle can start again */                                                             
                    } 
                }   
                    
              if(voltageOffsetRead == 2)                                                          /* Run this code after first offset done */
                {
                  voltageOffset2 = 0;                                                             /* set back currentOffset2 as default*/
                  if(millis()>= voltageOffsetLastSample + 1)                                      /* keep countng time for offset2*/
                    {                                                                            
                      voltageOffsetSampleCount = voltageOffsetSampleCount + 1;                                                                          
                      voltageOffsetLastSample = millis();                                                                          
                    }                                                                                
                  if(voltageOffsetSampleCount == 2000)                                            /* after 2 seconds, run this codes.  */
                    {                                                                            
                      voltageOffset2 = - RMSVoltageMean;                                          /* set the offset values */
                      voltageOffsetRead = 0;                                                      /* change the offset mode to original, wait until the button is pressed again */                     
                      voltageOffsetSampleCount = 0;                                               /* to reset the time again so that next cycle can start again */ 
                    }                                                                             
                } 


        /* 2- AC Current Measurement */
        
        if(millis() >= currentLastSample + 1)                                                     /* every 1 milli second taking 1 reading */
          {
            currentSampleRead = analogRead(CurrentAnalogInputPin)-512 + currentOffset1;           /* read the sample value */
            
            currentSampleSumOffset = currentSampleSumOffset + currentSampleRead;                  /* accumulate offset value */
            
            currentSampleSum = currentSampleSum + sq(currentSampleRead) ;                         /* accumulate value with older sample readings*/
            currentSampleCount = currentSampleCount + 1;                                          /* to move on to the next following count */
            currentLastSample = millis();                                                         /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(currentSampleCount == 1000)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            offsetCurrentMean = currentSampleSumOffset/currentSampleCount;                        /* average offset value*/
            
            currentMean = currentSampleSum/currentSampleCount;                                    /* calculate average value of all sample readings taken*/
            RMSCurrentMean = sqrt(currentMean)+currentOffset2 ;                                   /* square root of the average value*/
            FinalRMSCurrent = (((RMSCurrentMean /1024) *5000) /mVperAmpValue);                    /* calculate the final RMS current*/
            Serial.print(" The Current RMS value is: ");
            Serial.print(FinalRMSCurrent,decimalPrecision);
            Serial.println(" A ");
            currentSampleSum =0;                                                                  /* to reset accumulate sample values for the next cycle */
            currentSampleCount=0;                                                                 /* to reset number of sample for the next cycle */
            currentSampleSumOffset=0;                                                             /* to reset accumulate offset value for the next cycle*/
          }

              /* 2.1 - Offset AC Current */
                  
              if(currentOffsetRead == 1)                                                          /* Run this code when button SELECT is pressed */
                {
                  currentOffset1 = 0;                                                             /* set currentOffset back to default value*/
                  if(millis()>= currentOffsetLastSample + 1)                                      /* keep countng time for offset1*/
                    {                                                                            
                      currentOffsetSampleCount = currentOffsetSampleCount + 1;                                                                          
                      currentOffsetLastSample = millis();                                                                          
                    }                                                                                 
                  if(currentOffsetSampleCount == 2000)                                            /* after 2 seconds, run this codes.  */
                    {                                                                            
                      currentOffset1 = - offsetCurrentMean;                                       /* set the offset values */
                      currentOffsetRead = 2;                                                      /* go for second offset Settings */                     
                      currentOffsetSampleCount = 0;                                               /* to reset the time again so that next cycle can start again */                                                             
                    } 
                }   
                
              if(currentOffsetRead == 2)                                                          /* Run this code after first offset done */
                {
                  currentOffset2 = 0;                                                             /* set back currentOffset2 as default*/
                  if(millis()>= currentOffsetLastSample + 1)                                      /* keep countng time for offset2*/
                    {                                                                            
                      currentOffsetSampleCount = currentOffsetSampleCount + 1;                                                                          
                      currentOffsetLastSample = millis();                                                                          
                    }                                                                             
                          
                  if(currentOffsetSampleCount == 2000)                                            /* after 2 seconds, run this codes.  */
                    {                                                                            
                      currentOffset2 = - RMSCurrentMean;                                          /* set the offset values */
                      currentOffsetRead = 0;                                                      /* change the offset mode to original, wait until the button is pressed again */                     
                      currentOffsetSampleCount = 0;                                               /* to reset the time again so that next cycle can start again */ 
                    }                                                                             
                } 
       
        /* 3- AC Power with Direction */

        if(millis() >= powerLastSample + 1)                                                       /* every 1 milli second taking 1 reading */
          {
            sampleCurrent1 = analogRead(CurrentAnalogInputPin)-512+ currentOffset1;
            sampleCurrent2 = (sampleCurrent1/1024)*5000;
            sampleCurrent3 = sampleCurrent2/mVperAmpValue;
            voltageSampleRead = 2*(analogRead(VoltageAnalogInputPin)- 512)+ voltageOffset1 ;
            powerSampleRead = voltageSampleRead * sampleCurrent3 ;                                /* real power sample value */
            powerSampleSum = powerSampleSum + powerSampleRead ;                                   /* accumulate value with older sample readings*/
            powerSampleCount = powerSampleCount + 1;                                              /* to move on to the next following count */
            powerLastSample = millis();                                                           /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(powerSampleCount == 1000)                                                              /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            realPower = ((powerSampleSum/powerSampleCount)+ powerOffset) ;                        /* calculate average value of all sample readings */
            Serial.print(" The Real Power (W) is: ");
            Serial.print(realPower);
            Serial.println(" W ");           
            apparentPower= FinalRMSCurrent*RMSVoltageMean;                                       /*Apparent power do not need to recount as RMS current and RMS voltage values available*/
            Serial.print(" The Apparent Power (VA) is: ");
            Serial.print(apparentPower,decimalPrecision);
            Serial.println(" VA ");
            powerFactor = realPower/apparentPower;    
            if(powerFactor >1 || powerFactor<0)
            {
              powerFactor = 0;
            }
            Serial.print(" The Power Factor is: ");
            Serial.println(powerFactor,decimalPrecision);                                             
            powerSampleSum =0;                                                                    /* to reset accumulate sample values for the next cycle */
            powerSampleCount=0;                                                                   /* to reset number of sample for the next cycle */
          }
 

              /* 3.1 - Offset AC Power */

              if(powerOffsetRead == 1)                                                            /* Run this code after first offset done */
                {                          
                  powerOffset = 0;                                                                /* set back currentOffset2 as default*/
                  if(millis()>= powerOffsetLastSample + 1)                                        /* keep countng time for offset2*/
                    {                                                                            
                      powerOffsetSampleCount = powerOffsetSampleCount + 1;                                                                          
                      powerOffsetLastSample = millis();                                                                          
                    }                                                                                                      
                  if(powerOffsetSampleCount == 5000)                                              /* after 5 seconds, run this codes.  */
                    {                                                                            
                      powerOffset = -realPower;                                                
                      powerOffsetRead = 0;                                                        /* change the offset mode to original, wait until the button is pressed again */                     
                      powerOffsetSampleCount = 0;                                                 /* to reset the time again so that next cycle can start again */ 
                    }                                                                             
                } 


        /* 4 - LCD Display  */
        
        currentMillisLCD = millis();                                                              /* Set current counting time */
        if (currentMillisLCD - startMillisLCD >= periodLCD && page ==1)                           /* for every x seconds, run the codes below*/
          {
            LCD.setCursor(0,0);                                                                   /* Set cursor to first colum 0 and second row 1  */
            LCD.print("I=");
            LCD.print(FinalRMSCurrent,decimalPrecision);                                          /* display current value in LCD in first row  */
            LCD.print("A  ");
            LCD.print("V=");
            LCD.print(RMSVoltageMean,decimalPrecision);                                          /* display current value in LCD in first row  */
            LCD.print("V     ");   
            LCD.setCursor(0,1); 
            LCD.print(realPower,decimalPrecision);
            LCD.print("W ");
            LCD.print(apparentPower,decimalPrecision);                                            /* display current value in LCD in first row  */
            LCD.print("VA    ");
            startMillisLCD = currentMillisLCD ;                                                   /* Set the starting point again for next counting time */
          }
          
        if( currentMillisLCD - startMillisLCD >= periodLCD && page ==2)
         {
            LCD.setCursor(0,0);                                                                   /* Set cursor to first colum 0 and second row 1  */
            LCD.print("PF=");
            LCD.print(powerFactor,decimalPrecision);
            LCD.print("            "); 
            LCD.setCursor(0,1); 
            LCD.print("                "); 
            startMillisLCD = currentMillisLCD ;                                                   /* Set the starting point again for next counting time */
          }

      
    
}

Fuente : solarduino.com/how-to-measure-ac-power-with-arduino/