Zero cross detector for SCT-013

I am trying to measure the phase difference between voltage and current on my arduino. I am using the emonlib successfully for other things but im interested in knowing how i would count the zero crossings on the YHDC SCT-013 100A CT. I have a simple ZCD for the voltage that just measure half cycles i.e the positive ones using a simple 4N25 circuit on the mains. it works pretty well and gives readings of 50.00 to 50.20Hz. I was wondering how i would do the same for the CT.
Im using the CT already with the Emonlib with the standard burden resistor circuit.
I wanted to use a ZCD on the voltage which is interrupt driven and wanted to use the CT to also generate a spike on zero cross possibly using the 4N25 opto isolator. Basically I would measure the time difference between the rising edge of the voltage and rising edge of the current to determine power factor and lead or lag.
Ive been looking at this simple code i found online to carry out the measurements. on a rising edge eg a zero cross the interrupt would be triggered (pin 1 voltage ) and then triggered again (pin 2 current) . the time difference would be measured. I should be able to calculate f the current is leading or lagging and the power factor using this simle formula.
(measured difference/20ms)x360 degree= degrees lead or lag. the power factor can be calculated by getting the cosine of the angle. Im just not to sure on the CT circuit I would need.
Any help would be great

volatile unsigned long time1 ;
volatile unsigned long time2 ;

volatile boolean valid1 = false ;
volatile boolean valid2 = false ;

void int1 ()
  if (!valid1)
    time1 = micros() ;
    valid1 = true ;

void int2 ()
  if (valid1 && !valid2)
    time2 = micros () ;
    valid2 = true ;

void setup ()
  attachInterrupt (0, int1, RISING) ;
  attachInterrupt (1, int2, RISING) ;
  Serial.begin (115200) ;

void loop ()
  if (valid2)
    Serial.println (time2-time1) ;
    noInterrupts () ;
    valid1 = valid2 = false ;
    interrupts () ;

There’s a problem there. What you’re saying applies if both waves are perfect sinusoids, but in practice, they are not. The presence of transformers (particularly the a.c. adapter) means that the wave shape is distorted. The most reliable way to determine phase difference is either by curve-fitting (i.e. you make a best attempt to fit a pure sine wave to each waveform, then you know the phase shift between your generated waves), or you do Fourier analysis and extract the phase of the fundamental wave that way.

If you want to use your 4N25 with a CT (presumably two 4N25s facing opposite directions), you could put them in series with the burden. The maximum forward current is 60 mA, which, unless you have more than about 80 A rms in the primary, is OK for the LED in the opto-isolator. Provided that you’re not using a stupidly large valued burden resistor, the CT will generate enough voltage to overcome the forward drop of the diodes allowing you to measure current as normal. But the timing difference you measure will have errors due (principally) to the phase error in the voltage transformer. You can see what those errors are in the report on the Ideal a.c. adapter.

[And a health warning: don’t be tempted to connect directly across the mains unless you understand the dangers and treat everything as Live - because if somebody cuts the neutral outside your house, everything including the neutral will be at full mains voltage.]

There’s a post on the old forum that talks about using the ATmega analogue comparator for zero crossing detection.

Hi Robert,
once again thank you for your assistance.
I had an idea that the current wouldnt produce a perfect sinusodial wave. As for the health warning I would be sampling from the 9v ac ac adapter.
It seems like a lot of work but I was thinking would I get any meaningful data by using my current ZCD circuit and the standard CT interface setup. my idea is as follows:

  1. detect a high pulse from the ZCD output.
  2. start the micro timer
  3. detect a zero crossing from the standard CT interface circuit using the ADC, i.e if the value of the ADC is 512 then a ZCD has occured?
  4. stop the timer.
    shouldnt this method effectively detect the time difference between the voltage and current.

Thanks Bill,
very interesting, thank you

No, that won’t work. Zero is not necessarily 512 counts (it can be a few either way). The way Robin’s diverter and emonLibCM (when it’s finally proven) works is to remove the d.c. bias offset as normal, and then check for the input changing sign. You could equally test for the raw input changing from less than 512 to equal or greater than 512.

But that won’t give you the zero crossing with any degree of precision. The ADC in free-running mode reporting its value with interrupts (i.e. NOT using analogRead( ) - that is slower) samples every 104 μs, that is every 1.872 degrees. So reading voltage and current alternately, you might be reading up to 3.7 degrees past the crossing before you knew the sign had changed. That applies to both voltage and current, then you’ve got the fixed lag between the two to consider. Even if you only read current and use the hardware voltage detector, you can still have 1.8 degrees of uncertainty in your detection of the crossing. If that’s acceptable, that’s fine.