9 December 2015

Measuring AC Voltage Using Arduino: Maximum Voltage Method

A voltage sensor is used to measure AC and DC voltage, however the use of measurement algorithms are different. The DC voltage is constant so that the measurement is relatively easy, in contrast with AC voltage that varies according to a sine wave form and has a voltage magnitude in the positive and negative quadrant. AC effective voltage magnitude can be determined if the maximum voltage / peak known. By using the right algorithms and mathematical equations, the maximum value and the effective value of the AC voltage can be found.

Problems and significance
A voltage sensor is a device that is commonly used in electronic equipment. basically, a voltage sensor can be obtained through the design of the voltage divider circuit as shown in Figure 1a, and also can be designed using the transformer as shown in Figure 1b. Sensor voltage with the voltage divider technique can be used on AC and DC voltage, while the voltage sensor which uses a transformer can only be used for reading AC voltage. 

Figure 1. AC voltage sensor. a). using a voltage divider technique
b. using a transformer
(source)

Regardless the type of voltage sensor is used, in the microprocessor-based applications the algorithms of AC and DC voltage reading is very different. DC voltage as shown in Figure 2 has a relatively constant value properties, the DC voltage is generally always be in one quadrant (only positive or only negative). By the voltage characteristic as has been described, DC voltage reading becomes easy to apply. Unlike the AC voltage, the voltage is not in constant shape but continued to follow the shape of a sine wave. In addition, the AC voltage is in two quadrants, positive or negative, so it can not be given directly to the input pin of the microprocessor, which can only receive a voltage between 0 to 5 VDC.

Figure 2. The shape of the DC and AC voltages (Source)
(source)
This tutorial is focus to describes the AC voltage reading technique using a voltage sensor with transformer-based as shown in Figure 1b.
Technique and Algorithm
This experiment uses an analog voltage sensor as shown in Figure 1b. The generated signal will be used as an analog input (A0 pin) of ATmega328P microprocessor which integrated in the Arduino Uno development board . To be able to read the AC voltage, such program script as the following can be used:
double sensorValue=0;
double sensorValue1=0;
int crosscount=0;
int climbhill=0;
double VmaxD=0;
double VeffD;
double Veff;
void setup() {
Serial.begin(115200);
}
void loop() {
sensorValue1=sensorValue;
delay(100);
sensorValue = analogRead(A0);
if (sensorValue>sensorValue1 && sensorValue>511){
  climbhill=1;
  VmaxD=sensorValue;
  }
if (sensorValue<sensorValue1 && climbhill==1){
  climbhill=0;
  VmaxD=sensorValue1;
  VeffD=VmaxD/sqrt(2);
  Veff=(((VeffD-420.76)/-90.24)*-210.2)+210.2;
  Serial.println(Veff);
  VmaxD=0;
}
}
The principle of the script being used is to find the maximum voltage Vm of the measured sine wave. Maximum voltage Vm can be found by continuously observing the sinusoidal voltage, if the maximum voltage Vm is smaller than the previous maximum voltage Vm-1, then Vm-1 is the maximum voltage expected, (theoretically it happened only on the peak of AC signal). In script above Vm-1 is "sensorValue1" and Vm is "SensorValue".
sensorValue1=sensorValue;
delay(100);
sensorValue = analogRead(A0);
 The maximum voltage is converted into a effective voltage using equation (1)
 In a program script it written as follow
     VeffD=VmaxD/sqrt(2);
Where VeffD is the effective value in digital number. To get the actual effective voltage a calibration process is required, it is by comparing the digital values to the actual voltage value and integrate it into a linear equation as follows:
     Veff=(((VeffD-420.76)/-90.24)*-210.2)+210.2;
if completed, do not forget to compile and upload the program to the Arduino board, and plug the voltage sensor cables according to the rules on the datasheet. If there is no error (should not be) just click on the serial monitor in the top right corner of the Arduino IDE, the voltage value readout will appear. You can compare it with the reading of the voltmeter. 
Calibration may be better and appear accurately when not using the linear equation but rather uses the n-order polynomial equation. I will discuss this polynomial technique next time.

Potential Applications
  • Power quality data logger
  • Digital Power meter (KWh Meter)
  • Control of electricity protection system
Conclusion
AC voltage has a sinusoidal pattern whose value keeps changing as a function of time and had a magnitude of the voltage in positive and negative territory. If the maximum voltage of the AC signal is known, the effective voltage also can be known. The maximum voltage is determined by comparing the actual value of the voltage (Vm) to the previous voltage value (Vm-1), if Vm-1 is greater than Vm,  the maximum voltage is equal to Vm-1 value.

AC voltage can also be searched by measuring the area of sinus signal, once again I will discuss-developed-design this measurement technique later, be patient :D

Reference
[1] http://images.tutorvista.com/content/electricity/ac-dc-voltage-time-graph.gif
[2] https://fisikakontekstual.wordpress.com/materi-arus-dan-tegangan-listrik-bolak-balik/

86 comments:

  1. Please can you elaborate as to how you got that calibration equation- Veff=(((VeffD-420.76)/-90.24)*-210.2)+210.2;
    And what was the AC voltage you choose while doing this project.

    ReplyDelete
  2. hey Deepak Joshi, thanks you for reading this post. I use linear line equation with two point for calibration, the basic equation is (Y-y1)/(y2-y1)=(X-x1)/(x2-x1), where ....

    Y is Veff,
    X is VeffD,
    (x1,y1) is the first random point
    (x2,y2) is the second random point

    The random points was taken from experiment, I use ordinary AC voltage, and autotransformer of course so i can step it up/down to get two different point

    So, from my equation above we know that
    (210.2,420.76) was the first random point (at 210.2 volt)
    (0,511) was the second random point (at 0 volt)

    Btw, this is not the only solution, You can find and choose any point you want in the range of 0 VAC - 250 VAC (or 240 VAC if you want) with your own voltage sensor.

    ReplyDelete
    Replies
    1. Thanks for replying so quickly.
      1) Now that you have mentioned about the random points , I wonder if the y-axis points are the analog readings (form the arduino board) that you obtained while measuring say 210.2 volts.
      I meant since the range of analog reading on an arduino board lies btw 0-1024 values, is the value obtained 420.76 an analog value?


      2) Also my project deals with reading and comparing AC voltage profiles up to 500v. Would the above mentioned code be sufficient to read the voltages with ACCURACY.

      Delete
    2. 1. Yes that's how I done it, the Y-axis are the analog reading (ADC). And NOW I remembering something, ADC number is an integer not a float type such, I give a little compensation (try and error) so that's why the ADC number became a float (420.76). I done this to get a better accuracy

      2. I don't think so. For a better accuracy i suggest that you implement a polinomial method, not a linear line equation method. i have seen my collegue done it and achieve accuracy under 5%. You can use excel to get an appropriate polynomial equation easily

      Delete
    3. correction: I mean a better accuracy with error under 5%

      Delete
    4. 1) Please could you tell me as to how you integrated the voltage sensor with the arduino?

      2)In earlier posts I have seen that you have mentioned about polynomial eqaution for calibration. Please elaborate as to how you did it using polynomial equation.

      Thanks for the reply in advance


      Delete
    5. Dear Anirudh Shetty
      1. that is the most easiest part, the voltage sensor have 3 pins, vcc, ground, and signal. So, put vcc to arduino vcc, ground to arduino vcc, and signal to analog pin (A0, for example), no special tihngs.

      2. linear equation can be done with only 2 sample (x1,y1) and (x2,y2), but in polynomial we need more (x1,y1),(x2,y2),(xn,yn) where n>2 (you can choose n as you like, higher is better). So, to this simple step!

      a. First set your hardware, connect arduino to voltage sensor
      b. Use autotransformer, set to zero voltage
      c. connect the autotransformer output to the voltage sensor
      d. increase autotransformer output every 50 VAC, 0,50,100,150,200,250 (my voltage sensor capability was limited under 250 VAC, so i stop at this voltage point)
      e. read the digital number converted by the arduino ADC for each voltage point, and make a note.
      f. now you have 5 sample (0, ADC1),(50, ADC2),...,(250,ADC5)
      g. bring the points to Ms. Excel, and follow the step on this link to generate the polynomial equation

      https://av8rdas.wordpress.com/2012/09/05/excels-linest-function-little-things-can-make-a-big-difference/

      Delete
    6. Dear Muhammad Ikhsan,
      Can you please elaborate as to why did you use "uphill" statement.

      Also please can you tell if this code is applicable for reading AC voltages that are continuously varying with varying frequency?

      Thanks for the reply in advance..

      Delete
    7. I use "Uphill" statement because the logic(or the algorithm) is scanning the sine waves (in 1 periode) and search the most highest value, So i have to scan the hill from under and keep going to the top (iteration) to find the highest peak.

      i think so, as long as the voltage is in sine wave you can use it on any frequencies

      Delete
    8. Assalamualaikum bang... bang mau tanya untuk rumus (Y-y1) / (y2-y1) = (X-x1) / (x2-x1) kok bisa di sederhanakan jadi Veff = ((VeffD-420.76) / - 90.24) * - 210.2) +210.2;, minta tolong nilai dari tersebut bisa disamakan dengan rumus yang menggunakan y, y1 dll ?

      Delete
    9. rumus saya itu asalnya dari rumus yang kamu tuliskan itu :), rumus yang kamu tuliskan itu adalah rumus garis lurus melalui dua titik dalam koordinat kartesian kan. Coba2 saja Mas PLC DROID, VeffD adalah X dan Veff adalah Y, X1 adalah 420.76 dan seterusnya.....

      Delete
    10. Assalam o Alaikum brother plz tell me about the bult in potential meter on the sensor what does it do?

      Delete
    11. Something is not correct here... How can your point at 210v give you a lower ADC reading than at 0 volt??
      You said your points are:
      "(210.2,420.76) was the first random point (at 210.2 volt)
      (0,511) was the second random point (at 0 volt)"

      ...but this is not logical!

      Delete
  3. Sir,
    can you please elaborate your code as I cannot understand the logic you are using.

    Also when I tried your code with my calibration value I got dummy values like alphabets..

    Please reply at earliest....

    ReplyDelete
    Replies
    1. dear depak Joshi,

      really? don't forget to check the baud Rate, I used 115200, not 9600, you must have the same Baud Rate setting in your Arduino code and serial monitor. If not, an alphabetic things will appear

      Delete
    2. This comment has been removed by the author.

      Delete
  4. I cross-checked the baud rate.. It was same.. Still I was getting the error.

    Also, with the polynomial equation of degree 3 , the program was taking a lot of time.

    ReplyDelete
    Replies
    1. Maybe you can paste your arduino code here in the comment, so i can see it.

      And try to delete "delay(100);" it can improve the computation speed

      Delete
  5. 1) The following is my code-

    double sensorValue=0;
    double sensorValue1=0;
    int crosscount=0;
    int climbhill=0;
    double VmaxD=0;
    double VeffD;
    double Veff;
    void setup() {
    Serial.begin(115200);
    }
    void loop() {
    sensorValue1=sensorValue;
    delay(100);
    sensorValue = analogRead(A0);
    if (sensorValue>sensorValue1 && sensorValue>280){
    climbhill=1;
    VmaxD=sensorValue;
    }
    if (sensorValue<sensorValue1 && climbhill==1){
    climbhill=0;
    VmaxD=sensorValue1;
    VeffD=VmaxD/sqrt(2);
    Veff=0.01*pow(VeffD,2) + 1.856*pow(VeffD,1) + 282.35;
    Serial.println(Veff);
    VmaxD=0;
    }
    }



    2) Link for the polynomial equation used-(NOTE- All voltages are in volts)

    https://drive.google.com/file/d/0B0MU7F-BCXkiSnpFT283eVZmWEk/view?usp=sharing

    ReplyDelete
    Replies
    1. Is it correct your code for ac voltage measurement?

      Delete
  6. Can you simplify this line:

    Veff=0.01*pow(VeffD,2) + 1.856*pow(VeffD,1) + 282.35;

    to:

    Veff=(0.01*VeffD*VeffD)+(1.856*VeffD)+282.35;

    And when you validate the device try to limit the maximum voltage not more than 100 VAC, because your polynomial maximum value is 100 VAC

    So, is it working?

    ReplyDelete
    Replies
    1. hi sir , I want to ask about your code , why the sensor keep reading a data voltage ac when power off?

      Delete
  7. Hey,
    Thanks for explaining the workings of ZMPT101B
    I have a doubt. I have a set of other sensors to use which runs in 9600 baud rate. I need the data of other sensors and the voltage data from the voltage calculated from the module in the same file. Can you guide me as to how to proceed?

    ReplyDelete
  8. Hi Sannidhya Sahu,
    Your welcome
    So, you have another kind of voltage sensor (other than ZMPT101B), and you need appropriate voltage equation for that sensor in order to measuring the voltage accurately, is that correct?

    ReplyDelete
  9. hello I have the ZMPT101B I introduce CODE TO MY ARDUINO ONE AND I DO NOT SEND THE VOLTAGE AT THE TERMINALS LINE AND NEUTRAL plugged HOW SHOULD BE AND ITS TERMINALS WILL PUT 120VAC AND ME NO SALE IN SERIAL MONITOR THAT IS THE VOLTAGE ME LEAVES MUCH LESS STRANGE THING VOLTAGE 120 AVER IF I CAN HELP ???

    ReplyDelete
    Replies
    1. hello Unknown, i can't understood what you say, hahaha... :D

      Delete
  10. Hey, your article proved to be very useful. But i am also finding out power factor. I am using a CT and PT (same as yours) sensor for that. For pf , i need the time difference between current peak and voltage peak. I tried to find out these peaks but soon realized that there are multiple peaks (around 10 in 20ms) in voltage. Is the output of your sensor is sinusoidal? bcoz mine one is not

    ReplyDelete
    Replies
    1. Hello. Did you manage to find a solution?

      Delete
    2. hi Devvrat, very sorry for my very very late post. Yes, I detect my Voltage was sinusoidal. if you find a multiple peaks I suggest that you also put the statistic library (use average function). I think it will be better if you use it.

      Delete
  11. Asslamm M.ikhsan

    hasil pengukuran dengan sensor tegangan zmpt101b ini bisakah digabung dengan sensor arus SCT-013 untuk mendapatkan faktor daya?

    ReplyDelete
    Replies
    1. waalaikumsalam wr.wb. secara coding menurut saya bisa Pak Wahyudi, walaupun saya belum pernah coba tapı saya yakin itu bisa, apalagi kalau untuk hıtung cos pi

      Delete
  12. Thus, you can invest in a good digital Multimeter and can solve a lot of other problems for which you would otherwise have to call a qualified electrician. The Multimeter Guide

    ReplyDelete
  13. Hlw everyone...
    I want to detect the completion of circuit..for that can i use zmpt101b module..What is it return if the AC circuit is breaked?

    ReplyDelete
    Replies
    1. sorry Ashwani, i dont understand what you mean

      Delete
  14. WORKED FOR ME FROM THE FIRST TIME, YOU ARE AMAZING SIR. THANK YOU VERY MUCH.

    ReplyDelete
  15. This comment has been removed by the author.

    ReplyDelete
  16. Hi Ikhsan,
    Your method and algorithm to use zmpt101b module for AC voltage measurement is superb. But I was wondering if one can use a diode bridge rectifier along with the capacitive/resistive filter on the output pin of the module and then convert it to constant DC to be read on Arduino ADC Pin. Kindly comment.
    regards,
    Noman

    ReplyDelete
    Replies
    1. hey Norman, i think that will work, but the use of capacitive element will cause a little time delay. but of course (maybe) it will not become an issue for a low switching frequency application

      Delete
  17. Hello to everyone,can some one help me because when i upload this code and go to serial monitor he show me some weird symbols but when i put Serial.begin(9600); it works but i don't get a good results :exp for 220V it gives me 190V and for 44V gives me 88V :S . i was put autotransformator in sensor....sorry for bad english

    ReplyDelete
    Replies
    1. make sure that you use the same baudRate as it wrote on your voidsetup. Hmm.... from my experience there is no corellation between accuracy and baudrate. You can increase the accuracy by modify the linear ecuation. Autotransformer for the sensor? so you dont use the same sensor as mention? how you do it wıth an Autotransformer?

      Delete
  18. This comment has been removed by a blog administrator.

    ReplyDelete
  19. mas numpang nanya dong masih pemuula nih mas. kok hasilnya di serial monitor ama pake avo meter beda ya mas. tolong penjelasannya mas

    ReplyDelete
    Replies
    1. bisa jadi karena:
      1. rumus yang dipakai belum sesuai atau belum di kalibrasi dengan baik
      2. bisa jadi tegangan yang di ukur bukan sinusoidal murni, pendekatan rumus yang sayagunakan sebenarnya hanya berlaku untuk sinusoidal murni saja. kalau zaman now kan banyak harmonisa dan terkadang sinyal ACnya dalam bentuk square

      Delete
  20. This comment has been removed by a blog administrator.

    ReplyDelete
  21. Hi!! I have a question, why do you put a delay (100 milliseconds) if the frequency of the line is 50/60HZ that means 50/60 times per second -> that means the period of the sinusoidal lasts 16.67 milliseconds. Then you would not be able to know if it is rising or decreasing.

    Thanks!!!! You were very helpful!!!
    Gonzalo

    ReplyDelete
    Replies
    1. it is okay to delete that 100 milliseconds, I think nothing will be change, I am a little forgot about the reason, but maybe my reason is only for the SerialPrint issue.

      Delete
  22. permisi mau bertanya, kalau potensio treletak dalam modul apakah mempunyai fungsi tertentu? terima kasih

    ReplyDelete
    Replies
    1. didalam modul apa? kalau potensionya ada didalam modul motor servo biasanya digunakan untuk sistem feedback motor tersebut

      Delete
    2. This comment has been removed by the author.

      Delete
  23. Ihsan brother kindly upload the code with polynomial regression involved.

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Inzamam Brother, right now I do not have the code, but for the polynomial regression, you can use Excel and follow the instruction bellow (open the link). See step number 4, picture on the left, they put a mark on "Display Equation on Chart". https://www.extendoffice.com/documents/excel/2642-excel-best-fit-line-curve-function.html

      Delete
  24. Permisi gan kenapa , darimana ya rumus Veff itu mas kemudian kalo misalnya tidak dibuat delay maka data keluaran nya tidak sesuai dengan hasil pengukuran avo meter

    ReplyDelete
  25. Permisi gan kenapa , darimana ya rumus Veff itu mas kemudian kalo misalnya tidak dibuat delay maka data keluaran nya tidak sesuai dengan hasil pengukuran avo meter

    ReplyDelete
    Replies
    1. Mas Bryan, metode yang saya paparkan diatas itu hanya berlaku untuk pengukuran tegangan yang sinusoidal murni. Coba ukur sumber tegangan PLN langsung, seharusnya penghapusan delay tidak mengubah apapun selain mempercepat pembacaan data

      Delete
  26. mas Bryan, rumus Veff itu dari sini.., tegangan rms. http://www.tespenku.com/2017/12/tegangan-rms.html

    ReplyDelete
  27. hello sir
    I am working on voltage measurement project and could not able to calibrate my voltage sensor ZMPT101B. I need to measure ordinary AC voltage 0-250 rms.Could you please suggest me the calibration process please...

    ReplyDelete
  28. Selamun aleykum

    It measures the iron correctly but what is the reason why it does not measure the bulb at all?

    My Arduino code:

    double sensorValue=0;
    double sensorValue1=0;
    int crosscount=0;
    int climbhill=0;
    double VmaxD=0;
    double VeffD;
    double Veff;
    void setup() {
    Serial.begin(9600);
    }
    void loop() {
    sensorValue1=sensorValue;
    delay(100);
    sensorValue = analogRead(A0);
    if (sensorValue>sensorValue1 && sensorValue>280){
    climbhill=1;
    VmaxD=sensorValue;
    }
    if (sensorValue<sensorValue1 && climbhill==1){
    climbhill=0;
    VmaxD=sensorValue1;
    VeffD=VmaxD/sqrt(2);
    Veff=0.01*pow(VeffD,2) + 1.856*pow(VeffD,1) + 282.35;
    Serial.println(Veff);
    VmaxD=0;
    }
    }

    ReplyDelete
  29. Terima kasih pencerahan nya mas. Saya mau tanya kenapa tegangan terukur nya sekitar 250 ya? Input ZNPT saya dapat dari PLN dengan tegangan sekitar 218 (diukur dg multimeter). bisakah code nya menghasilkan teg yg sama? tks

    ReplyDelete
  30. Kemudian crosscount utk apa ya

    ReplyDelete
    Replies
    1. saya baru sadar, ternyata crosscount tidak diperlukan, terima kasih untuk pertanyaannya

      Delete
  31. Nice Post sir...
    Can you tell me how to measure 3 different voltages using arduino and how to compare them with a predefined reference value?

    ReplyDelete
    Replies
    1. do you want to make three phase voltage measurement? you can add more analog input on the program, it is possible

      Delete
  32. mira tengo un problema con un sensor y es que al conectarlo a 110 me aroja 0 no me aroja mas datos entonces no se si sera problema de calibracion o mala conexion por si tienes una foto del montaje y el boceto te lo agradeceria ya que se me ha echo imposible medir el voltaje

    ReplyDelete
    Replies
    1. Hi, did you asking about the wiring diagram?? (google translate), check this picture..., it is easy. https://www.sfe-electronics.com/img/cms/SFE%20Produk/Skema%20Tutorial/Skema%20ZMPT101B.PNG

      Delete
  33. If I want to measure 125VAC, VEFF = (veffd-420.76) / -90.24) * -210.2) 210.2; How do you make a change?

    ReplyDelete
  34. HELLO please teach me If I want to measure 125VAC, VEFF = (veffd-420.76) / -90.24) * -210.2) 210.2; How do you make a change?

    ReplyDelete
  35. How to change the equation to measure 220 Vac ? Thanks for this code.

    ReplyDelete
  36. can we use this sensor to measure voltage of Gas Metal Arc Welding which is interface with arduino?

    ReplyDelete
  37. sir, can u help me how did you get the first random point and second random point? is that by adjusting the potentiometer?

    ReplyDelete
  38. Do you have the code to just measure AC voltage?

    ReplyDelete
  39. hello sir ..
    I need program for interfacing of 8051 (AT89S52) with zmpt101B

    ReplyDelete
  40. Hi,
    Do i need to calibrate with values after uploading your code or first take readings using simple analogueRead() function and then make polinomial equation which will fit in your code to be upload later.

    ReplyDelete
  41. Assalammua'laikum.. kang iksan..
    Zmpt ini bisa dipake buat ngecek PLN mati sama nyala ga kang... kalo bisa Cara nya gimana yaak..
    Soale pas coba... selalu ada data dari analog read nya nya walaupun belum di sambung ke PLN. Hiks

    ReplyDelete
  42. Sir i am getting different analog values for one voltage....how to get a single analog value for one. Voltage point

    ReplyDelete
  43. misi bang saya pemula ini , program diatas ini untuk yang sudah di kalibrasi atau belum ya bang?, kalau belum boleh minta pencerahannya ga masalah kalibrasi sensor ini? hehe

    ReplyDelete
  44. Thanks, very interesting and useful. I made my linear equation ad adapted to a NodeMCU. It is working quite well. I'm just trying to get it more stable (the program is plotting not constant Veff (+/- 5%) while the multimeter is constant).

    ReplyDelete
  45. Pretty cool, I used a Energy Metering IC to measure AC

    ReplyDelete
  46. Permisi gan.
    hasil pengecekan sy dengan multi tester 212,5 VAC, sedangkan dengan sensor 271,7 V.apakadih jika dimasukan ke rumus Veff jadi Veff=(((VeffD-271,7)/-98.75)*-212.5)+212.5; ?

    ReplyDelete
  47. hi can anyone help me with a code for voltage sensing using the same voltage sensor but for raspberry pi interfaced with mcp3008.

    ReplyDelete
  48. Hello...playing with this sensor. I only do need to measure if 230V is ON or OFF (so no specific value). Any suggestions?

    ReplyDelete
  49. Hi ...thank you for such useful information
    I need code with polynomial regression involved

    ReplyDelete
  50. I am having an issue with ac voltage monitoring.i am using ZMPT101B and Sim800l GSM module. The purpose of the code is to send the present AC voltage whenever a message "VOLTAGE" is send to GSM module.
    But i get random reading with values above 300 and 400 as response. Can you help me with any suggestions possible.
    (Reading are ok when not requesting the voltage).
    Thanks in advance

    ReplyDelete