Better AC sensing circuit for ADC conversion

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
why have you decided to return to using true rms ?
what does the extra complication give you ?

can you post your latest code and schematics please ,
its hard in this long post to keep up as to where your up to,
so a snapshot of current condition would be useful
Professor Dr. Smith, how are you ? Well come back, I thought you were on leave.
For you only post #169, #177, #212 are only dedicated.
For #212, only think there is only one sensor at A0 of Arduino Uno.
You can read post from @panic mode, can see his schematic also.
Figure out ..
1. Why relays are not active?
2. Why sensor pic read out are wrong?
3. What is the wrong in my schematic at #212, using priority secretion IC and gate driver.
 

drjohsmith

Joined Dec 13, 2021
1,615
Professor Dr. Smith, how are you ? Well come back, I thought you were on leave.
For you only post #169, #177, #212 are only dedicated.
For #212, only think there is only one sensor at A0 of Arduino Uno.
You can read post from @panic mode, can see his schematic also.
Figure out ..
1. Why relays are not active?
2. Why sensor pic read out are wrong?
3. What is the wrong in my schematic at #212, using priority secretion IC and gate driver.
hello
uhm, you seem, it could be translation, to be wanting to allocate work to otheres !
I await your replies to my questions you ignored in #261
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
hello
uhm, you seem, it could be translation, to be wanting to allocate work to others !
I await your replies to my questions you ignored in #261
Answer is very straight forward, hidden in my last questionaries. The reason why I am trying with true RMS because @Mr.AI is suggesting some good point. If you don't want to dig out posts then it will difficult to make you happy. See the post again.
 

drjohsmith

Joined Dec 13, 2021
1,615
Answer is very straight forward, hidden in my last questionaries. The reason why I am trying with true RMS because @Mr.AI is suggesting some good point. If you don't want to dig out posts then it will difficult to make you happy. See the post again.
love the wording,
"Answer is very straight forward, hidden in my last questionaries"
bit of an oxymoron !

In general I find the easier one makes it for people to help you, the better the help one receives.

its your project, if your happy you need true RMS, then great,
what level of accuracy are you aiming for, over what sort of waveform distortion ?

I assume your code and schematic has updated over time, and the posts you highlight are old and seem to contain partial answers

can you provide what your latest code is and latest schematic please, that way were all on same route of travel.

what problems do you currently have, how are you trying to debub them ?
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
love the wording,"Answer is very straight forward, hidden in my last questionaries"bit of an oxymoron !In general I find the easier one makes it for people to help you, the better the help one receives.its your project, if your happy you need true RMS, then great, what level of accuracy are you aiming for, over what sort of waveform distortion ?I assume your code and schematic has updated over time, and the posts you highlight are old and seem to contain partial answerscan you provide what your latest code is and latest schematic please, that way were all on same route of travel.what problems do you currently have, how are you trying to debub them ?
I am sorry, I have no number for accuracy. Approximately ±2 to ±2 LSB.
Only consider the schematics in #212, #79
The problem is the sensor calculate wrong AC value, perhaps, in my 16 relay system I used 2 sensors with following code, the result was not bad, but now I can not activate the 4 relays. May be need multiplication factors.

C:
invalues = analogRead(sensorA);
  float voltagea = invalues * 0.0048828125; //a a+1

  Serial.println(" ");
// Serial.println(voltagea);
  float voltin = voltagea*70.38;

// Output voltage sensing values

  outvalues = analogRead(sensorB);
  float voltageb = outvalues * 0.0048828125;
  float voltout = voltageb*51.16;

I include all RMS, zero crossing and so on, in this case circuit will be different.

C:
/* ---------------------------------------------------------
   AC RMS Measurement + Zero Crossing + 4 Relay Control
   Board: Arduino Nano (ATmega328P)
   Author: HASAN
   --------------------------------------------------------- */

#define ZC_PIN 2            // Zero-cross input (INT0)
#define ADC_PIN A0          // AC sense input
#define NUM_SAMPLES 200     // Samples per cycle (50Hz)
#define RELAY1 4
#define RELAY2 5
#define RELAY3 6
#define RELAY4 7

volatile boolean zcFlag = false;
unsigned int sampleIndex = 0;
float samples[NUM_SAMPLES];

void zeroCrossISR() {
  zcFlag = true;
}

void setup() {
  Serial.begin(9600);

  pinMode(ZC_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(ZC_PIN), zeroCrossISR, RISING);

  pinMode(RELAY1, OUTPUT);
  pinMode(RELAY2, OUTPUT);
  pinMode(RELAY3, OUTPUT);
  pinMode(RELAY4, OUTPUT);

  digitalWrite(RELAY1, LOW);
  digitalWrite(RELAY2, LOW);
  digitalWrite(RELAY3, LOW);
  digitalWrite(RELAY4, LOW);

  Serial.println("AC RMS Measurement System Ready");
}

float calculateRMS() {
  double sumSq = 0;

  for (int i = 0; i < NUM_SAMPLES; i++) {
    float voltage = (samples[i] * (5.0 / 1023.0));  // ADC to volts
    voltage -= 2.5;                                // Remove offset
    sumSq += voltage * voltage;
  }

  float vrms = sqrt(sumSq / NUM_SAMPLES);

  // Calibration factor for your sensor (adjust as needed)
  float calibration = 220.0 / 1.0;  // Example: scale to real AC RMS

  return vrms * calibration;
}

void loop() {
  if (zcFlag) {
    zcFlag = false;

    // Sample one full cycle
    for (sampleIndex = 0; sampleIndex < NUM_SAMPLES; sampleIndex++) {
      samples[sampleIndex] = analogRead(ADC_PIN);
      delayMicroseconds(200);  // ~200 µs → 200 samples per 20ms cycle
    }

    float vrms = calculateRMS();
    Serial.print("VRMS = ");
    Serial.println(vrms);

    // -------------------------------
    // Relay Control Logic (example)
    // -------------------------------
    if (vrms > 230) {
      digitalWrite(RELAY1, HIGH);
    } else {
      digitalWrite(RELAY1, LOW);
    }

    if (vrms < 200) {
      digitalWrite(RELAY2, HIGH);
    } else {
      digitalWrite(RELAY2, LOW);
    }

    // Free to customize:
    digitalWrite(RELAY3, (vrms > 240));
    digitalWrite(RELAY4, (vrms < 180));
  }
}
 

drjohsmith

Joined Dec 13, 2021
1,615
I am sorry, I have no number for accuracy. Approximately ±2 to ±2 LSB.
Only consider the schematics in #212, #79
The problem is the sensor calculate wrong AC value, perhaps, in my 16 relay system I used 2 sensors with following code, the result was not bad, but now I can not activate the 4 relays. May be need multiplication factors.

C:
invalues = analogRead(sensorA);
  float voltagea = invalues * 0.0048828125; //a a+1

  Serial.println(" ");
// Serial.println(voltagea);
  float voltin = voltagea*70.38;

// Output voltage sensing values

  outvalues = analogRead(sensorB);
  float voltageb = outvalues * 0.0048828125;
  float voltout = voltageb*51.16;

I include all RMS, zero crossing and so on, in this case circuit will be different.

C:
/* ---------------------------------------------------------
   AC RMS Measurement + Zero Crossing + 4 Relay Control
   Board: Arduino Nano (ATmega328P)
   Author: HASAN
   --------------------------------------------------------- */

#define ZC_PIN 2            // Zero-cross input (INT0)
#define ADC_PIN A0          // AC sense input
#define NUM_SAMPLES 200     // Samples per cycle (50Hz)
#define RELAY1 4
#define RELAY2 5
#define RELAY3 6
#define RELAY4 7

volatile boolean zcFlag = false;
unsigned int sampleIndex = 0;
float samples[NUM_SAMPLES];

void zeroCrossISR() {
  zcFlag = true;
}

void setup() {
  Serial.begin(9600);

  pinMode(ZC_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(ZC_PIN), zeroCrossISR, RISING);

  pinMode(RELAY1, OUTPUT);
  pinMode(RELAY2, OUTPUT);
  pinMode(RELAY3, OUTPUT);
  pinMode(RELAY4, OUTPUT);

  digitalWrite(RELAY1, LOW);
  digitalWrite(RELAY2, LOW);
  digitalWrite(RELAY3, LOW);
  digitalWrite(RELAY4, LOW);

  Serial.println("AC RMS Measurement System Ready");
}

float calculateRMS() {
  double sumSq = 0;

  for (int i = 0; i < NUM_SAMPLES; i++) {
    float voltage = (samples[i] * (5.0 / 1023.0));  // ADC to volts
    voltage -= 2.5;                                // Remove offset
    sumSq += voltage * voltage;
  }

  float vrms = sqrt(sumSq / NUM_SAMPLES);

  // Calibration factor for your sensor (adjust as needed)
  float calibration = 220.0 / 1.0;  // Example: scale to real AC RMS

  return vrms * calibration;
}

void loop() {
  if (zcFlag) {
    zcFlag = false;

    // Sample one full cycle
    for (sampleIndex = 0; sampleIndex < NUM_SAMPLES; sampleIndex++) {
      samples[sampleIndex] = analogRead(ADC_PIN);
      delayMicroseconds(200);  // ~200 µs → 200 samples per 20ms cycle
    }

    float vrms = calculateRMS();
    Serial.print("VRMS = ");
    Serial.println(vrms);

    // -------------------------------
    // Relay Control Logic (example)
    // -------------------------------
    if (vrms > 230) {
      digitalWrite(RELAY1, HIGH);
    } else {
      digitalWrite(RELAY1, LOW);
    }

    if (vrms < 200) {
      digitalWrite(RELAY2, HIGH);
    } else {
      digitalWrite(RELAY2, LOW);
    }

    // Free to customize:
    digitalWrite(RELAY3, (vrms > 240));
    digitalWrite(RELAY4, (vrms < 180));
  }
}
you say
"The problem is the sensor calculate wrong AC value"

so how are you debuging that ?
what value are you expecting and what are yoy receiving ?
Id aproach this by a simple program, to read the sencor and regularly print it out.
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
so how are you debuging that ?
From the non-realistic circuit at post #1 , RV POT allows different the input and output sensing voltage, but its not good way, rest of all the design avoiding any POT. The multiplication factor I showed you sometime depends on factor of voltage dividing ratio or voltage.

what value are you expecting and what are you receiving ?
If you look on post #169, the value ranges 2.7 to 4.16. With this code only 16 relays, #79 schematic works but as I told you need to figure out exact relay number.

Id approach this by a simple program, to read the sencor and regularly print it out.
Yes, usually I do it.
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
Hi,

A PLL loop in this context could simply mean 'syncing' the program flow to the line, not just detecting the zero crossing.
In other words, you detect a few zero crossings and then start to predict when the next one will come. If it came late one time then you subtract a little time from the stored half cycle time, and if it came early one time then you add a little time to the stored half cycle time. Eventually you get very close to the zero crossings without even having to detect them, but you do still detect them to keep the flow synced.

I don't think everyone has the time to check over long lines of code that's the problem sometimes. You have to do much of the work yourself :)
You seem to be doing very well though so don't worry too much, just test, test, and retest, you have to do that anyway.
@MrAl, I like to keep my all option open, even the A option is difficult to implement but I will follow it. I will check it either way in different circuit.
 

drjohsmith

Joined Dec 13, 2021
1,615
From the non-realistic circuit at post #1 , RV POT allows different the input and output sensing voltage, but its not good way, rest of all the design avoiding any POT. The multiplication factor I showed you sometime depends on factor of voltage dividing ratio or voltage.


If you look on post #169, the value ranges 2.7 to 4.16. With this code only 16 relays, #79 schematic works but as I told you need to figure out exact relay number.


Yes, usually I do it.
so what does your simple program just to read and print out to terminal the voltages your reading look like ?
you need to have a reliable value read in before you start calculating off it.
adding more code adds more places things can go wrong !
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
so what does your simple program just to read and print out to terminal the voltages your reading look like ?
C:
Serial.println(" ");
Serial.println(voltagea);
you need to have a reliable value read in before you start calculating off it.
adding more code adds more places things can go wrong !
Yes, well said. Did you check AC RMS Measurement + Zero Crossing + 4 Relay Control code ?
 

drjohsmith

Joined Dec 13, 2021
1,615
C:
Serial.println(" ");
Serial.println(voltagea);

Yes, well said. Did you check AC RMS Measurement + Zero Crossing + 4 Relay Control code ?
great ,

so that code in a loop ?
how often does it sample the ac input ?

if you printed out more characteres , how often would the sample period be ?

sorry , on small screen here, can you remind us please, are you converting the ac to a dc, or just sampling the ac ?
 

Thread Starter

Hasan2019

Joined Sep 5, 2019
199
so that code in a loop ?
how often does it sample the ac input ?
Loop is kind of absent in code #169, only in relay control.
If you look my recent code, sample is here,

C:
for (int i = 0; i < NUM_SAMPLES; i++) {
    float voltage = (samples[i] * (5.0 / 1023.0));  // ADC to volts
    voltage -= 2.5;                                // Remove offset
    sumSq += voltage * voltage;
  }
here I already define,
#define NUM_SAMPLES 200 // Samples per cycle (50Hz)

if you printed out more characteres , how often would the sample period be ?
sorry , on small screen here, can you remind us please, are you converting the ac to a dc, or just sampling the ac ?
Right at this moment on AC sample, may be you are talking about this formula
1769438725305.png
 

drjohsmith

Joined Dec 13, 2021
1,615
Loop is kind of absent in code #169, only in relay control.
If you look my recent code, sample is here,

C:
for (int i = 0; i < NUM_SAMPLES; i++) {
    float voltage = (samples[i] * (5.0 / 1023.0));  // ADC to volts
    voltage -= 2.5;                                // Remove offset
    sumSq += voltage * voltage;
  }
here I already define,
#define NUM_SAMPLES 200 // Samples per cycle (50Hz)



Right at this moment on AC sample, may be you are talking about this formula
View attachment 362726
trying to tie down this code of yours,

you say the numberes read is not correct

so can you strip your code down to just the bit thats reading analog voltage please, and post it.
idealy the code is modular so we can once its working , it can be re used in your project.
lets get that working correctly.
 

MrAl

Joined Jun 17, 2014
13,720
@MrAl, I like to keep my all option open, even the A option is difficult to implement but I will follow it. I will check it either way in different circuit.
Hi,

Yeah it might sound a little tricky but it's actually very simple.
You keep a time period stored in memory, like for a 50Hz line ideally it would be 0.010000 seconds. If your next zero crossing comes in before that (it would only be a tiny amount) then you decrease the stored time period, say 0.009900, but if it comes in after that then you change the stored period to the new value which might be 0.010100 seconds. In this manner you 'know' the next zero crossing before it even happens. In fact, you assume you know it 1/2 cycle before it actually happens. In this way you can get the timing down really close.

You can do this with a clock too that does not have perfect timing if you have another clock that has perfect timing. You store 1 second and then keep adjusting that as things change. The poor clock stays synced to the good clock within a very small margin of error, and the average time period should be really, really close, because it's being adjusted up and down relative to the average.

You don't have to do this, it's just one of those little refinements that may not even matter in your application. Get it working as is first, then think about this again later.
 

drjohsmith

Joined Dec 13, 2021
1,615
Hi,

Yeah it might sound a little tricky but it's actually very simple.
You keep a time period stored in memory, like for a 50Hz line ideally it would be 0.010000 seconds. If your next zero crossing comes in before that (it would only be a tiny amount) then you decrease the stored time period, say 0.009900, but if it comes in after that then you change the stored period to the new value which might be 0.010100 seconds. In this manner you 'know' the next zero crossing before it even happens. In fact, you assume you know it 1/2 cycle before it actually happens. In this way you can get the timing down really close.

You can do this with a clock too that does not have perfect timing if you have another clock that has perfect timing. You store 1 second and then keep adjusting that as things change. The poor clock stays synced to the good clock within a very small margin of error, and the average time period should be really, really close, because it's being adjusted up and down relative to the average.

You don't have to do this, it's just one of those little refinements that may not even matter in your application. Get it working as is first, then think about this again later.
Synchronizing the sampling is a great technique
The reason to synchronise , is to ensure you acquire a perfect single cycle . So you don't end up with say 1 1/2 cycles , which would give a varying number..
Alternatively ,
Look at the maths. If you sanoled say 128 cycles or 128 1/2 cycles and averages, the error now is 1/256 of a cycle . Probably more than good enough for your application , and you won't want to change your relays faster than that.

But
As MrAi says .
All these are after we have you sampling stable numbers.
 

MrAl

Joined Jun 17, 2014
13,720
Synchronizing the sampling is a great technique
The reason to synchronise , is to ensure you acquire a perfect single cycle . So you don't end up with say 1 1/2 cycles , which would give a varying number..
Alternatively ,
Look at the maths. If you sanoled say 128 cycles or 128 1/2 cycles and averages, the error now is 1/256 of a cycle . Probably more than good enough for your application , and you won't want to change your relays faster than that.

But
As MrAi says .
All these are after we have you sampling stable numbers.
Hi,

Did you reply to the right member?

Yeah it's a little tricky but yes I agree that sampling over 1/2 cycle is probably the best, then average a bunch of those results.
 

ericgibbs

Joined Jan 29, 2010
21,460
Apologies. .meant that to be addressed to the OP..
hi drj,
This apparent misdirection of the addressee can cause some confusion. :)

That's why I use a shortened version off 'Hi drj' etc.... to make it clear to the intended recipient.

E
 

drjohsmith

Joined Dec 13, 2021
1,615
hi drj,
This apparent misdirection of the addressee can cause some confusion. :)

That's why I use a shortened version off 'Hi drj' etc.... to make it clear to the intended recipient.

E
Totaly my mistake in not making it clear .
Luckily MrAi realised it was for the op not them.
 
Top