Better AC sensing circuit for ADC conversion

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
Dear All,

I am trying to design one of the AC sensing circuit as follows, my goal is to make 5V analog to ADC's by Arduino Uno which is taking the input at A0 analog pin.

AC_source.png

C4 and C5 are used to smooth the pulsating DC com-ing from the rectifier. C4 performs the main bulk filter-ing by reducing low-frequency ripple, while C5 filters out high-frequency noise. The integrated digital voltmeter measures and shows the DC voltage after this filtering stage.R14 forms part of a feedback path or voltage divider used for voltage monitoring. The load resistors R12 and R13 are elements of an additional smoothing network. C6 further filters the output. D27 and D28 provide reverse-polarity protection and also function as part of a clamping/regulation circuit.

Kindly suggest me anything better.
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
R14 is ineffective because there is a short across it.
RV2 has to dissipate a lot of power. It will get very hot. It is better to use a stepdown transformer.
@MR Chip, thanks a lot and happy new year 2026. Yes, R14 is useless. RV is also nonpractical in real experiment. Initially I was using a basic one like as follows, but the readings were more fluctuating,
basic_AC_sensing.png
Do you want me to use an OP amp ?
Take a look on the differential amplifier-based voltage measurement for AC voltage measurement, here

basic_AC_sensing2.png
 
Last edited:

Jerry-Hat-Trick

Joined Aug 31, 2022
775
with the step down transformer you are not only reducing voltage, you also isolate your circuit from the mains supply. I question the merit of rectification as you are losing voltage across the diodes. And the Arduino ADC is easily fast enough to take multiple readings and calculate the AC voltage. Use an op amp, ideally a rail to rail which can be powered by the 5V and create a virtual ground at around 2.5V so the AC signal has a peak to peak voltage of around 4V between 0.5V and 4.5V. Let the processor do the heavy lifting!
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
with the step down transformer you are not only reducing voltage, you also isolate your circuit from the mains supply. I question the merit of rectification as you are losing voltage across the diodes. And the Arduino ADC is easily fast enough to take multiple readings and calculate the AC voltage. Use an op amp, ideally a rail to rail which can be powered by the 5V and create a virtual ground at around 2.5V so the AC signal has a peak to peak voltage of around 4V between 0.5V and 4.5V. Let the processor do the heavy lifting!
Thank you @Jerry-Hat-Trick you said well, we can not avoid voltage droop across diodes, rectifier one has little benefits but output signal is averaged rectified value (in contrast to peak or RMS value). Can I able find out in simulation if it gives sufficient smooth output or I need a higher order low pass?
 
Last edited:

Jerry-Hat-Trick

Joined Aug 31, 2022
775
I don’t think you need a filter, if you take maybe 200 readings over one cycle, save into an array and plot these on your computer screen using the Arduino IDE you will find out how smooth the curve is. You get a simplified result assuming it’s a sine wave by looking at high and low peaks but you can write a bit of code to work out the true RMS value. If you want a higher resolution you could use a dedicated A/D converter with serial interface
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
I don’t think you need a filter, if you take maybe 200 readings over one cycle, save into an array and plot these on your computer screen using the Arduino IDE you will find out how smooth the curve is. You get a simplified result assuming it’s a sine wave by looking at high and low peaks but you can write a bit of code to work out the true RMS value. If you want a higher resolution you could use a dedicated A/D converter with serial interface

Good. May be you are suggesting me to go with this idea of sensor reading, https://electrocredible.com/zmpt101b-ac-voltage-sensor-arduino/ but it has drawback here,
https://forum.arduino.cc/t/warning-about-zmpt101b-voltage-sensor-modules-with-active-output/693258

I have not try with this filtering, https://deepwiki.com/jeroendoggen/Arduino-signal-filtering-library/5.3-iir-filter-example
 

Jerry-Hat-Trick

Joined Aug 31, 2022
775
I've taken a quick look and my immediate reaction is - do not use the LM358, it's nice and cheap but it doesn't go rail to rail so it'll distort badly if you go for maximum resolution. I recommend the MCP6002 dual op amp and use one of them to make a robust voltage follower to provide the 2.5V virtual ground for the second op amp. I confess I lose interest when I read the word "module" - you just need a transformer to provide a low voltage which you feed into the decoupling capacitor. You can then use a resistive voltage divider (tied to the virtual ground) to reduce this votage if necessary (to make sure your peak to peak is no higher than about 4.5V). I've realised the Arduino UNO can only do about 9,000 ADC conversions a second to if you sample at 5,000 you'll only get 100 samples per cycle which should still suffice. In code you could maybe add successive cycles to get a better result. For a better result, use a fast 12 bit ADC IC with serial communication with the Arduino. I'd get it working first with the Arduino ADC. I'd honestly leave filtering to later - possible in the code by ignoring measured values which vary too much from their immedaite neighbour. It's important to try to understand the detail - the web is full of bad advice, maybe even from me!
 

Ian0

Joined Aug 7, 2020
13,097
Dear All,

I am trying to design one of the AC sensing circuit as follows, my goal is to make 5V analog to ADC's by Arduino Uno which is taking the input at A0 analog pin.

View attachment 361525

C4 and C5 are used to smooth the pulsating DC com-ing from the rectifier. C4 performs the main bulk filter-ing by reducing low-frequency ripple, while C5 filters out high-frequency noise. The integrated digital voltmeter measures and shows the DC voltage after this filtering stage.R14 forms part of a feedback path or voltage divider used for voltage monitoring. The load resistors R12 and R13 are elements of an additional smoothing network. C6 further filters the output. D27 and D28 provide reverse-polarity protection and also function as part of a clamping/regulation circuit.

Kindly suggest me anything better.
How do you propose to isolate it from live mains?
 

Ian0

Joined Aug 7, 2020
13,097
I would suggest the ZMPT101B, and use the application circuit in the datasheet.
200k (two 100k resistors in series to keep within the maximum voltage of a surface mount resistor) is about the right drive.

I sample at 1600Hz, square each sample then IIR filter. When I need to know the voltage, I take the square root using a interpolated lookup table (but I'm using a 32 bit processor)
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
I would suggest the ZMPT101B, and use the application circuit in the datasheet.
200k (two 100k resistors in series to keep within the maximum voltage of a surface mount resistor) is about the right drive.

I sample at 1600Hz, square each sample then IIR filter. When I need to know the voltage, I take the square root using a interpolated lookup table (but I'm using a 32 bit processor)


I think that component has some drawback, https://forum.arduino.cc/t/warning-about-zmpt101b-voltage-sensor-modules-with-active-output/693258


Show me your code, my application is 10bit.
 

Ian0

Joined Aug 7, 2020
13,097
I think that component has some drawback, https://forum.arduino.cc/t/warning-about-zmpt101b-voltage-sensor-modules-with-active-output/693258


Show me your code, my application is 10bit.
On the contrary, certain modules using it have some drawbacks! The component itself is good.
I use four 100k resistors in series, because it has the possibility of being connected across two phases of a 3 phase supply (400V). I use 1206 resistors which are rated at 200V peak (not 50V as claimed), so four in series will manage 800V: adequate to cope with 565V peak input.
It is best to use it at 1mA maximum otherwise it loses some linearity. The circuit published seems over-complex, and I certainly wouldn't use an LM358 as I do actually need accuracy! I just use the transresistance amplifier circuit from the datasheet. 28mV output is no problem for a proper op-amp, but if you insist on using the cheapest one available, which is celebrates its 50th birthday in 2026, then you're not going to get good results.
I've also used it with 51Ω burden resistors and an INA181 to amplify.

Here's the code that does the first half of the RMS, and the square-root routine.
IIR filter and square root:
.type FilterRMS,%function

.global FilterRMS                // data in R0, filter address in R1

FilterRMS:    MOV R3,R1

                MULS R0,R0,R0

                LDR R1,[R3,#4]

                SUBS R1,R1,R1,ASR#8

                ADDS R1,R1,R0,ASR#5

                STR R1,[R3,#4]

                LDR R0,[R3]

                SUBS R0,R0,R0,ASR#8

                ADDS R0,R0,R1,ASR#5

                STR R0,[R3]

                BX LR

// -----------  square root -------------------------------------------------------------------------

.type SquareRoot,%function

.global SquareRoot

SquareRoot:        CLZ R2,R0                                    // count leading zeroes

                BICS R2,R2,#1                                // make it even

                LSLS R0,R0,R2

                LDR R3,=isqrt

                LSRS R1,R0,#24

                LDRH R1,[R3,R1,LSL#1]

                UDIV R0,R0,R1

                ADDS R0,R0,R1

                LSRS R2,R2,#1

                ADDS R2,R2,#1                                // shift back

                LSRS R0,R0,R2                                // for 16-bit result

                BX LR

const uint16_t isqrt[256] = {

    0, 4096, 5793, 7094, 8192, 9159, 10033, 10837,

    11585, 12288, 12953, 13585, 14189, 14768, 15326, 15864,

    16384, 16888, 17378, 17854, 18318, 18770, 19212, 19644,

    20066, 20480, 20886, 21283, 21674, 22058, 22435, 22806,

    23170, 23530, 23884, 24232, 24576, 24915, 25249, 25580,

    25905, 26227, 26545, 26859, 27170, 27477, 27780, 28081,

    28378, 28672, 28963, 29251, 29537, 29819, 30099, 30377,

    30652, 30924, 31194, 31462, 31727, 31991, 32252, 32511,

    32768, 33023, 33276, 33527, 33776, 34024, 34270, 34514,

    34756, 34996, 35235, 35472, 35708, 35942, 36175, 36406,

    36636, 36864, 37091, 37316, 37540, 37763, 37985, 38205,

    38424, 38642, 38858, 39073, 39287, 39500, 39712, 39923,

    40132, 40341, 40548, 40755, 40960, 41164, 41368, 41570,

    41771, 41972, 42171, 42369, 42567, 42763, 42959, 43154,

    43348, 43541, 43733, 43925, 44115, 44305, 44494, 44682,

    44869, 45056, 45242, 45427, 45611, 45795, 45977, 46160,

    46341, 46522, 46702, 46881, 47059, 47237, 47415, 47591,

    47767, 47942, 48117, 48291, 48465, 48637, 48809, 48981,

    49152, 49322, 49492, 49661, 49830, 49998, 50166, 50332,

    50499, 50665, 50830, 50995, 51159, 51323, 51486, 51649,

    51811, 51972, 52134, 52294, 52454, 52614, 52773, 52932,

    53090, 53248, 53405, 53562, 53719, 53874, 54030, 54185,

    54340, 54494, 54647, 54801, 54954, 55106, 55258, 55410,

    55561, 55712, 55862, 56012, 56162, 56311, 56459, 56608,

    56756, 56903, 57051, 57198, 57344, 57490, 57636, 57781,

    57926, 58071, 58215, 58359, 58503, 58646, 58789, 58931,

    59073, 59215, 59357, 59498, 59639, 59779, 59919, 60059,

    60199, 60338, 60477, 60615, 60753, 60891, 61029, 61166,

    61303, 61440, 61576, 61712, 61848, 61984, 62119, 62254,

    62388, 62523, 62657, 62790, 62924, 63057, 63190, 63323,

    63455, 63587, 63719, 63850, 63982, 64113, 64243, 64374,

    64504, 64634, 64763, 64893, 65022, 65151, 65279, 65408

};
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
On the contrary, certain modules using it have some drawbacks! The component itself is good.
I use four 100k resistors in series, because it has the possibility of being connected across two phases of a 3 phase supply (400V). I use 1206 resistors which are rated at 200V peak (not 50V as claimed), so four in series will manage 800V: adequate to cope with 565V peak input.
It is best to use it at 1mA maximum otherwise it loses some linearity. The circuit published seems over-complex, and I certainly wouldn't use an LM358 as I do actually need accuracy! I just use the transresistance amplifier circuit from the datasheet. 28mV output is no problem for a proper op-amp, but if you insist on using the cheapest one available, which is celebrates its 50th birthday in 2026, then you're not going to get good results.
I've also used it with 51Ω burden resistors and an INA181 to amplify.

Here's the code that does the first half of the RMS, and the square-root routine.
IIR filter and square root:
.type FilterRMS,%function

.global FilterRMS                // data in R0, filter address in R1

FilterRMS:    MOV R3,R1

                MULS R0,R0,R0

                LDR R1,[R3,#4]

                SUBS R1,R1,R1,ASR#8

                ADDS R1,R1,R0,ASR#5

                STR R1,[R3,#4]

                LDR R0,[R3]

                SUBS R0,R0,R0,ASR#8

                ADDS R0,R0,R1,ASR#5

                STR R0,[R3]

                BX LR

// -----------  square root -------------------------------------------------------------------------

.type SquareRoot,%function

.global SquareRoot

SquareRoot:        CLZ R2,R0                                    // count leading zeroes

                BICS R2,R2,#1                                // make it even

                LSLS R0,R0,R2

                LDR R3,=isqrt

                LSRS R1,R0,#24

                LDRH R1,[R3,R1,LSL#1]

                UDIV R0,R0,R1

                ADDS R0,R0,R1

                LSRS R2,R2,#1

                ADDS R2,R2,#1                                // shift back

                LSRS R0,R0,R2                                // for 16-bit result

                BX LR

const uint16_t isqrt[256] = {

    0, 4096, 5793, 7094, 8192, 9159, 10033, 10837,

    11585, 12288, 12953, 13585, 14189, 14768, 15326, 15864,

    16384, 16888, 17378, 17854, 18318, 18770, 19212, 19644,

    20066, 20480, 20886, 21283, 21674, 22058, 22435, 22806,

    23170, 23530, 23884, 24232, 24576, 24915, 25249, 25580,

    25905, 26227, 26545, 26859, 27170, 27477, 27780, 28081,

    28378, 28672, 28963, 29251, 29537, 29819, 30099, 30377,

    30652, 30924, 31194, 31462, 31727, 31991, 32252, 32511,

    32768, 33023, 33276, 33527, 33776, 34024, 34270, 34514,

    34756, 34996, 35235, 35472, 35708, 35942, 36175, 36406,

    36636, 36864, 37091, 37316, 37540, 37763, 37985, 38205,

    38424, 38642, 38858, 39073, 39287, 39500, 39712, 39923,

    40132, 40341, 40548, 40755, 40960, 41164, 41368, 41570,

    41771, 41972, 42171, 42369, 42567, 42763, 42959, 43154,

    43348, 43541, 43733, 43925, 44115, 44305, 44494, 44682,

    44869, 45056, 45242, 45427, 45611, 45795, 45977, 46160,

    46341, 46522, 46702, 46881, 47059, 47237, 47415, 47591,

    47767, 47942, 48117, 48291, 48465, 48637, 48809, 48981,

    49152, 49322, 49492, 49661, 49830, 49998, 50166, 50332,

    50499, 50665, 50830, 50995, 51159, 51323, 51486, 51649,

    51811, 51972, 52134, 52294, 52454, 52614, 52773, 52932,

    53090, 53248, 53405, 53562, 53719, 53874, 54030, 54185,

    54340, 54494, 54647, 54801, 54954, 55106, 55258, 55410,

    55561, 55712, 55862, 56012, 56162, 56311, 56459, 56608,

    56756, 56903, 57051, 57198, 57344, 57490, 57636, 57781,

    57926, 58071, 58215, 58359, 58503, 58646, 58789, 58931,

    59073, 59215, 59357, 59498, 59639, 59779, 59919, 60059,

    60199, 60338, 60477, 60615, 60753, 60891, 61029, 61166,

    61303, 61440, 61576, 61712, 61848, 61984, 62119, 62254,

    62388, 62523, 62657, 62790, 62924, 63057, 63190, 63323,

    63455, 63587, 63719, 63850, 63982, 64113, 64243, 64374,

    64504, 64634, 64763, 64893, 65022, 65151, 65279, 65408

};
@Ian, seems like you have good experience, can you suggest to adpat this code into Arduino Uno, how about this link,https://deepwiki.com/jeroendoggen/Arduino-signal-filtering-library/5.3-iir-filter-example.
I won't use any LM358
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
I've taken a quick look and my immediate reaction is - do not use the LM358, it's nice and cheap but it doesn't go rail to rail so it'll distort badly if you go for maximum resolution. I recommend the MCP6002 dual op amp and use one of them to make a robust voltage follower to provide the 2.5V virtual ground for the second op amp. I confess I lose interest when I read the word "module" - you just need a transformer to provide a low voltage which you feed into the decoupling capacitor. You can then use a resistive voltage divider (tied to the virtual ground) to reduce this votage if necessary (to make sure your peak to peak is no higher than about 4.5V). I've realised the Arduino UNO can only do about 9,000 ADC conversions a second to if you sample at 5,000 you'll only get 100 samples per cycle which should still suffice. In code you could maybe add successive cycles to get a better result. For a better result, use a fast 12 bit ADC IC with serial communication with the Arduino. I'd get it working first with the Arduino ADC. I'd honestly leave filtering to later - possible in the code by ignoring measured values which vary too much from their immedaite neighbour. It's important to try to understand the detail - the web is full of bad advice, maybe even from me!
Besides your suggested solution, lets move on with opto coupler application, take alook this image,
dandakk.png

And also see another design, I was trying to simulate it.

Mains_ZCD_VoltageToPulseW_Opto.JPG
 
Last edited:

Ian0

Joined Aug 7, 2020
13,097
Besides your suggested solution, lets move on with opto coupler application, take alook this image,
View attachment 361556

And also see another design, I was trying to simulate it.

View attachment 361558
How accurate do you want it?
Pulse width might be proportional to mains voltage, but is that rms mains voltage, or peak mains voltage.
And if there is no constant of proportionality specified, is it even repeatable?

The first one is dependent on the CTR of the optoisolator, and that varies from 20% to 400%, and I can't imagine any system where that level of accuracy could be acceptable. That means that for two units connected to a 230V supply, one could read 1029V and another could read 51V.
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
How accurate do you want it?
Pulse width might be proportional to mains voltage, but is that rms mains voltage, or peak mains voltage.
And if there is no constant of proportionality specified, is it even repeatable?

The first one is dependent on the CTR of the optoisolator, and that varies from 20% to 400%, and I can't imagine any system where that level of accuracy could be acceptable. That means that for two units connected to a 230V supply, one could read 1029V and another could read 51V.
First one might have protection issues, because even R has higher value with high wattage, its directedly connected from LIVE. May be CRT is matched. Here input Vrms is 127.26 VAC. Look at the second design, number of components are more, having half bridge, transistor switching helping to get current to opto isolator, D3,D5 are may be maintaining AC source polarity, R3, R1,R2 has high droop and able to work wider AC voltage level.
 

Ian0

Joined Aug 7, 2020
13,097
@Ian, seems like you have good experience, can you suggest to adpat this code into Arduino Uno, how about this link,https://deepwiki.com/jeroendoggen/Arduino-signal-filtering-library/5.3-iir-filter-example.
I won't use any LM358
The processor I use is the one in the Arduino Uno R4 boards. I know that there are some fans of the Atmega processors on this forum, but I left 8-bit processors behind in 2013, and have never looked back. 32-bit just makes the maths so much simpler, especially if writing in assembler, and ARM code looks an awful lot like Atmega code which makes it easier to transition.
 
Top