I want to measure the peak to peak voltage of an AC voltage signal. The voltage itself is around 220V and 60Hz. When measured through a sensor connected to an Arduino, it is scaled down to, let's say 5V to 0V.

I implemented this a few years ago with a code I found on the internet.

float getVPP(const uint8_t sensorIn)
    float result = 0;
    int readValue = 0;
    int maxValue = 0;
    int minValue = 4096;

    uint32_t start_time = millis();
    while ((millis() - start_time) < 1000)
        readValue = analogRead(sensorIn);
        if (readValue > maxValue)
            maxValue = readValue;
        if (readValue < minValue)
            minValue = readValue;
    result = ((maxValue - minValue) * 5.0) / 4096.0;
    return abs(result);

I am not sure if this is the best approach. For starters, I want to totally rid it of floats, but that is besides the point. What I'm trying to find out is, is there a better way to read the AC mains voltage? My end goal is to calculate power. I am using the same function to calculate peak to peak value of current, dividing both by 0.707 to get RMS value, and multiplying them together.

Any help would be greatly appreciated.

Edit: The act of electrically measuring the mains voltage and current itself is completely safe, and has been done using relevant sensors. The "signals" I'm referring to, are at a safe 5V level. And so this question is purely related to signal analysis.

  • 1
    $\begingroup$ This is not a DSP but electronics problem... You should make a special connection to Arduino board (and its ADC) for safety of operation and for proper signal conditioning. You should measure the current magnitude and its phase relation to the voltage, as well as voltage magnitude if it's not a fixed amplitude signal. $\endgroup$
    – Fat32
    Commented Nov 24, 2021 at 10:38
  • $\begingroup$ Thanks for the warning. I assure you that the electrical measuring part is safe. I am asking this in a purely signals and DSP perspective. $\endgroup$ Commented Nov 24, 2021 at 12:45
  • 1
    $\begingroup$ All right then; if your electrical connection is safe and proper, and your ADC data collection is error free (as possible), then yes your problem reduces to the RMS calculations, which is partly AC circuit theory, and partly DSP... :-) $\endgroup$
    – Fat32
    Commented Nov 24, 2021 at 20:44

3 Answers 3


I would agree with the OP's concerns that the given approach is not best since it is most sensitive to noise. It is reading the absolute peak to peak value, which includes the underlying "truth" of what the peak to peak signal actually is, in addition to any inevitable noise that may be on the sample.

Ideally a standard deviation calculation would be computed or equivalently a time-aligned correlation to the reference 60 Hz signal. For sub-optimum but efficient and far superior implementations when processing resources are a concern, I would suggest an mean absolute deviation (MAD) computation since this can be done with a simple moving average filter, or if further simplication is desired, a CIC filter structure. Conveniently the MAD is related to the standard deviation we seek by a constant $4/(\pi\sqrt{2})$ (The constant $\sqrt{2/\pi}$ that is given in the referenced link is specific to measuring Gaussian distributed noise, but for a sinusoidal distribution the ratio of MAD to RMS is $4/(\pi\sqrt{2}))$. As long as the harmonics are more than 15 dB down or more (very likely as this is a typical requirement for AC supplied to computer equipment but should be verified if accuracy is important), this should result in a very reasonable estimate.

When processing is not a concern, simply compute the RMS value directly (average of the sum of the squares for each sample), or if ultimately a power measurement is desired, a current measurement is also needed and the power will be the average of the products of the current and voltage samples (assuming a resistive load, read further details below on the importance of a phase measurement between the I and V waveforms for the case or reactive loads).

To compute the MAD, simply average the absolute value of each sample over a period of at least several cycles (the longer the average the more accurate the result, so this can be a trade of time versus accuracy). If further simplification is desired, then a CIC filter (which is even simpler) can be implemented. A CIC filter is just an efficient implementation of a moving average.

To convert the resulting moving average to the rms value, simply multiply it by $\pi\sqrt{2}/4$.

This will provide an efficient measurement of the rms voltage, but to measure power you will also need a measure of the current, and the phase relationship between the two (both of which can also be done very efficiently) as the average power is $V_{rms} I_{rms} \cos(\theta)$. There are plenty of low cost current sensors available that will measure the current using inductive coupling (more details on that would be more appropriate on the electronics stack-exchange site so post there if that solution is still elusive). To get an estimate of the phase between the voltage and current readings, you could multiply and scale the voltage and current readings as the average of that product is the $\cos(\theta)$ term desired above:

$$V_p(\cos(\omega t)I_p(\cos(\omega t+\theta)) = \frac{V_pI_p}{2}\cos(\theta)$$

Plus a higher frequency "2f" term at $\cos(2\omega t +\theta)$ that we simply filter out (with another moving average filter!). In cases when the load is resistive or mostly so, $\theta=0$ and $\cos(\theta)=1$. We already know $V_p$ and $I_p$ from the MAD results, since the peak is related to the MAD by another constant $\pi/2$.

If the phase measurement was necessary and done as above with the sample by sample product, then the power can be computed directly by combining the phase and MAD processing, but for power line monitoring knowing if the load is reactive or not may be desirable to see as derived information from this processing.

To simplify the phase estimate, the product phase detector could be implemented with an XOR gate and RC low pass filter of the detected current and voltage signals (converted to pulses), or similarly in the Arduino using an XOR operation from the sign of those two signals. Both of these approaches will produce a linear result vs phase (when normalized linearly going from 1 to 0 as phase goes from $0$ to $\pi/2$, and from 0 to 1 as phase goes from -$\pi/2$ to $0$.

I provide more details on how a CIC filter is structured and its equivalent to a moving average filter here.

  • $\begingroup$ Thank you so much for the incredibly detailed answer. A little too detailed for my understanding, so I would have to do a little bit of research on these things to fully understand it. As for now, I think @Hilmar's approach is the one I could work with. I only wish I could implement your suggestion and benefit from its results, but I re-awakened some bad memories from seeing omega and t together :D $\endgroup$ Commented Nov 24, 2021 at 19:58
  • 1
    $\begingroup$ If you aren’t concerned with reactive loads (such that you needn’t measure phase) this is saying to just take the absolute value for each of your current and voltage readings and average over many readings — this is the MAD result, multiply that together and by $8\pi^2$ to get you power estimate. This avoids the larger error you would get with your initial solution since any noise on the one peak sample will increase the peak value in error. $\endgroup$ Commented Nov 24, 2021 at 20:11
  • $\begingroup$ And if processing is no issue then simply multiply each I sample with each V sample and take an average of that result. $\endgroup$ Commented Nov 24, 2021 at 21:01
  • $\begingroup$ I was able to gather that much. But at the same time, your answer now makes me think about measuring the phase. I feel like I should be able to calculate that as well, I just need to brush up on the things I have been actively avoiding during my degree. :D $\endgroup$ Commented Nov 25, 2021 at 5:24
  • 1
    $\begingroup$ Yes the phase measurement is simple- you can easily visually compare the signals to see that they align in which the load is resistive and no further effort is needed. But to compute it as I wrote in the formula which may appear at first confusing, simply multiply the two waveforms and divide the result by VpIp/2: this will give you the cosine of the phase (which is 1 if the phase is 0). $\endgroup$ Commented Nov 25, 2021 at 11:39

it is scaled down

This really depends on HOW the scaling is implemented. Please make sure this is done SAFELY (through in isolation transformer or something like this). 220V can do serious damage to devices and people if not managed properly.

I am using the same function to calculate peak to peak value of current, dividing both by 0.707 to get RMS value, and multiplying them together

RMS is peak to peak divided by $\sqrt{8}$. This will only work for an resistive load and give you wrong results if the load has a non trivial reactance.

To get the real power consumed, you can multiply the voltage and current waveforms directly and then lowpass filter the result. This will require you to have a sufficiently high sample rate. If line harmonics don't matter, than something like 150Hz should do it.

is there a better way to read the AC mains voltage

I suggest posting your current schematic on https://electronics.stackexchange.com/ . PLEASE make sure you heed al the safety advice you will get there.

  • $\begingroup$ Hi. Firstly, thank you for the safety warnings and due diligence. I assure you, the electrical part of it is completely safe, I myself am an engineer. :) You mentioned that the sqrt(8) thing is valid only for resistive loads, that makes sense. I will implement your suggested method, and post the results here as well. Thank you for the suggestion. $\endgroup$ Commented Nov 24, 2021 at 12:43
  • $\begingroup$ I don't believe there is a requirement to sample higher than 50 or 60 Hz, only that the sampling be incommensurate (not in any way synchronous to the line frequency). I outlined an efficient approach in my answer for measuring the power which can be done with any sampling rate that is not synchronous: for undersampled approaches, the samples will simply "walk" through the 60 Hz cycles and produce aliased sinusoids that we can just as equally measure the rms value of! What we need in any approach is enough samples for the statistical confidence we seek. $\endgroup$ Commented Nov 24, 2021 at 13:52
  • $\begingroup$ @Dan: true but it feels unnecessarily complicated. 150Hz sample rate for an Arduino should not be a problem especially if the only thing you do is multiply two samples and low-pass filter the results. $\endgroup$
    – Hilmar
    Commented Nov 24, 2021 at 14:10
  • $\begingroup$ Yes indeed- 150 Hz is easy enough to meet. Still I think it is a good point to make since there really is no further complication with going to any other rate even rates much lower (it doesn't change anything at all, the standard deviation of the sampled result is the same!), and there may be other reasons we don't want to occupy the processor on it at that rate. $\endgroup$ Commented Nov 24, 2021 at 14:13
  • 2
    $\begingroup$ @UsmanMehmood my main point was you needn’t be concerned with what rate you sample at— you can sample lower or faster and get the same result just as long as you are not synchronized to the line rate. $\endgroup$ Commented Nov 24, 2021 at 20:08

For a pure sinusoid wave, $A sin({\omega}t) $ the RMS value is $ V_{RMS} = \frac{A}{\sqrt(2)} $
While the peak-to-peak value is $V_{pk-pk} = 2A$

With these 2 relations you can find the RMS value from the peak-to-peak value. However, I don't think it's a robust implementation

First, I haven't seen your AC mains voltage curve, but on a typical AC mains there are harmonics caused by transfomer saturation and non-linear loads. These will break the relation between the RMS and peak-to-peak value. When harmonics are involved, you need to compute the RMS sample by sample.

Second, If there's significant noise, you will likely overestimate the peak-to-peak estimate.

Edit : Check this answer to see what AC mains voltage may look like. https://electronics.stackexchange.com/a/256424/155482

They measured an AC voltage of 122V RMS but a peak voltage of 165V.

If this were a pure sinusoidal wave, 122V RMS would give you a peak value of 172.5V

  • 1
    $\begingroup$ Right. And if looping over samples anyway, there's no justification for not directly computing the easily robust RMS, instead of fiddling with peak-to-peak computations and then tossing in the sinusoidal assumption just to compute an RMS. $\endgroup$ Commented Nov 25, 2021 at 6:25
  • $\begingroup$ Tossing in the sinusoidal assumption, you say? I always thought it was a sine wave. Apparently I was wrong? $\endgroup$ Commented Nov 25, 2021 at 12:54
  • $\begingroup$ Check this post. electronics.stackexchange.com/questions/256283/… The measured voltage is 122V RMS but 165 V peak. $\endgroup$
    – Ben
    Commented Nov 25, 2021 at 13:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.