3
\$\begingroup\$

I two sinewave signals with same frequency. I want to measure phase shift between two signals. There will be a small phase difference between two signals. I am using ATmega32-A micro controller and external ADC AD7798 to read the voltage of both signal. I am able to read both signal voltages using SPI communication. How to find Phase difference between two sine signals. I am using CodeVisionAVR compiler.

I know that phase shift between two signals can be find out using the fallowing formula.

A(t)= Am sin(Wt+/-theta).

I know only amplitude(Am) and w =2*pi*f. But How to calculate phase difference between two sinewave signals with knowing amplitude and frequency. Any suggestions please.

I have implemented timer functionality to get zero crossing points using the fallowing code.

void main(void){

    init();                                     //Initialize controller

    debug = 0;                                  //Controls output during motor running      

    while (1){

        if(rx_counter0) getCom();
        if(Command)     runCom(); 

        if(logInt > 0){
            if(now){
            if(!(unixTime % logInt)){
                    if(flag){
                    flag = 0;
                }
                now = 0;                  
               }
          }
        }

        #asm("WDR");        //Reset WD timer 

    }  // EOF "while(1)"   

   } // EOF "main(void)"

void init(void){

#asm("cli");        //Disable global interrupt

// Input/Output Ports initialization
// Port B initialization
DDRB=0xBF;
// Port C initialization
DDRC=0xC3;
// Port D initialization
DDRD=0xFC;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART0 Mode: Asynchronous
// USART Baud Rate: 9600
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x67;
UCSRA=0x00;
UCSRB=0xD8;
//UCSRC=0x86;

// ADC initialization
// ADC Clock frequency: 1000 kHz
// ADC Voltage Reference: AREF pin
// ADC Auto Trigger Source: None
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
// ADC4: On, ADC5: On
//DIDR0=0x00;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x84;

//Global enable interrupts
#asm("sei")
}

unsigned int timer_phase (void)
{
  ResetTimer1();    //reset timer to zero

  while(selcase(1) > 0)
   {
    //do nothing until input channel crosses zero
   }
  StartTimer1();    //start timer counting

  while(selcase(5) > 0)
   {
   //do nothing until output channel crosses zero
   }
  StopTimer1();    //stop timer counting

  time_delay_ticks = get_timer_ticks();    //get the number of timer ticks between zero crossings 

  time_delay = ticks_to_time(time_delay_ticks);    //need to get timer ticks into time domain

  period = 1 / WaveFreq;    //get the period from the known frequency
  phase_delay = (time_delay_ticks / period) * 360;    //calculate phase delay */  
  return phase_delay;
} 

interrupt [TIM1_COMPA] void timer1_compa_isr(void){
 unixTime++;
 now = 1;
 }

void StartTimer1(void)
{
    TCNT1H = 0x00;
    TCNT1L = 0x00;      //Start counting from 0

    OCR1AH = 0x0E;
    OCR1AL = 0x0E;      //Timer 1 reload value OCR1A = fCLK/(fOC1A*2*n)-1    REMEMBER 2 * OCR1A!

    TIMSK = 0x02;      //Enable timer 1 output compare A interrupt    

    TCCR1A = 0x00;
    TCCR1B = 0x0D;      //Start timer 1 in CTC-mode (4) with prescale 1024
}      

void StopTimer1(void)
{
   TCCR1A = 0x00;
   TCCR1B = 0x00; //Stop timer 1
    TIMSK = 0x00;  //Switch of interrupt
} 

void ResetTimer1(void)
{
   TCCR1A = 0x00;
   TCCR1B = 0x00; //Stop timer 1
    TCNT1H = 0x00;
    TCNT1L = 0x00;
    TIMSK = 0x00;  //Switch of interrupt
}

unsigned int get_timer_ticks(void)
{      
unsigned int i;
i= TCNT1H;
i= i|TCNT1L;
return i;
} 

when i run this code I am not getting any errors, But I am not able to enter any command from hyper terminal. When comment this whole function then only i am able to get output and i am able to enter commands from hyper terminal. Help me if any thing with timer function start and stop and reset and get_delay_tricks. Or any thing wrong with interrupts.

\$\endgroup\$
1
\$\begingroup\$

You need to use Olin's idea of determining the zero crossings of the signals to get the time delay. Then plug the time delay into Scott's equation to get the phase delay.

The following is pseudo-code. I'll leave it up to you to implement each function since they should either be trivial to implement or you should already have something similar written.

reset_timer();    //reset timer to zero

while(get_amplitude(INPUT_CHANNEL) > 0.0)
{
    //do nothing until input channel crosses zero
}

start_timer();    //start timer counting

while(get_amplitude(OUTPUT_CHANNEL) > 0.0)
{
    //do nothing until output channel crosses zero
}

stop_timer();    //stop timer counting

time_delay_ticks = get_timer_ticks();    //get the number of timer ticks between zero crossings 
time_delay = ticks_to_time(time_delay_ticks);    //need to get timer ticks into time domain

period = 1 / frequency;    //get the period from the known frequency

phase_delay = (time_delay / period) * 360;    //calculate phase delay

It's important to read the documentation on the timer you will be using so that you know how to convert from timer ticks into time.

\$\endgroup\$
  • \$\begingroup\$ I have one doubt. As you know about my concept, I am selecting input and output signal using multiplexer. Multiplexer output is analog signal but after that I have demodulator and I am getting DC signal at the input of ADC. So can i apply zero crossing procedure to calculate phase shift? calculating phase shift is not related to ADC reading? where should i implement this function because I am select the channel using MULTIPLEXER and reading voltage value. \$\endgroup\$ – verendra Oct 25 '12 at 19:48
  • \$\begingroup\$ @verendra I didn't know about the demodulator. But you said you knew the amplitude of the sine signal. So are you able to convert that demodulated signal into an amplitude for your sine wave? If you know that, then you should know when the sine signal crosses the zero or midpoint. The function get_amplitude should select the desired multiplexer channel and then read the associated ADC value. \$\endgroup\$ – embedded.kyle Oct 25 '12 at 20:37
  • \$\begingroup\$ Multiplexer output is sine wave signal but after that there is demodulator, demodulator output is giving to ADC. Demodulator output is a DC signal with max voltage of multiplexer output signal. \$\endgroup\$ – verendra Oct 25 '12 at 20:44
  • \$\begingroup\$ @verendra Without being able to measure the instantaneous value of the sine wave to find the zero crossings, I can't think of a way to find the phase shift. Your multiplexer has many input channels. Why not put the demodulator in front of the multiplexer? Have channels 1 and 2 be the demodulated signal and channels 3 and 4 be the full sine signal. \$\endgroup\$ – embedded.kyle Oct 26 '12 at 12:24
  • \$\begingroup\$ I have implemented timer functionality from the datasheet of ATmega32-A.I have updated my code.But i am thinking about Reset_timer function. \$\endgroup\$ – verendra Oct 26 '12 at 12:41
4
\$\begingroup\$

If you know both signals are sines, then comparing the time difference of their zero crossings is probably the easiest approach. Many micros have hardware that allows a free running timer to be captured based on some external edge. The difference between the two timer snapshots tells you the time between the zero crossings. The difference between the zero crossing of the same signal tells you the period. The phase shift in units of a whole cycle is then just the time offset between the two signals divided by their period.

If you need this value for direct user display in degrees, then multiply it by 360. However, there is no need to use degrees or any other particular unit inside the micro otherwise. In fact, the most useful way to represent angles in a micro is to use the full range of whatever the most convenient unsigned integer is to represent a full circle. That way angle additional and wraparounds just work without any additional logic. It also makes it easy to index into a table, like to get computing sine or cosine for example.

\$\endgroup\$
  • \$\begingroup\$ The difference between the neg to pos zero crossings (or pos to neg) gives the period. If you just use any old zero crossing, you get a half cycle --- but obviously, this is the easiest approach! \$\endgroup\$ – Scott Seidman Oct 25 '12 at 14:49
  • \$\begingroup\$ @Olin Lathrop I am very new to programming. Do you have any sample code or any example procedure to do that. \$\endgroup\$ – verendra Oct 25 '12 at 14:51
  • \$\begingroup\$ @Scott: Yes, I was assuming the same polarity zero crossing was used in all cases. The timer capture hardware in micros can usually be set up for that. If using a CCP module of a PIC 16 or PIC 18, for example, you can only capture on one edge polarity anyway. \$\endgroup\$ – Olin Lathrop Oct 25 '12 at 14:52
  • \$\begingroup\$ For these purposes, it might even be easier to forego the ADC, and just use the comparator modules, depending on what the signals are being used for. \$\endgroup\$ – Scott Seidman Oct 25 '12 at 14:58
  • \$\begingroup\$ But capture/compare modules require a digital input. They don't work well with analog, since the threshold is not configurable and may vary. Furthermore, connecting analog signals to digital inputs is a bad idea, since slowly changing signals can cause metastability and high power dissipation. Probably some micros have an analog comparator (though zero crossing detection would require a negative AVSS) that can drive the capture timer, but does his? \$\endgroup\$ – Ben Voigt Oct 30 '12 at 16:09
2
\$\begingroup\$

If your time delay is \$t\$, and the period of the sine wave is \$T\$, then

$$\frac{t}{T} \ \ = \ \ \frac{\phi }{360}$$

This will give phase (\$\phi\$) in degrees. If \$t\$ is negative, that would mean that the output lags the input, and positive is when the output leads the input.

If you can see the sine waves well enough to measure the time delay, then you also know the period \$T\$ (peak to peak time), and frequency in Hertz is \$1/T\$

Algorithmically, your task is tougher. Your best bet is a cross correlation between the input and output to calculate the time delay, and an autocorrelation to figure out the frequency wikpedia entry on cross-correlation. If you have the computational oomph, you can use FFTs.

\$\endgroup\$
  • \$\begingroup\$ Can you tel me how to find the time delay. I know both signals frequency is 250KHz so i can find easily T, but how to measure time delay. \$\endgroup\$ – verendra Oct 25 '12 at 14:30
  • \$\begingroup\$ The peak value of the cross correlation will occur at the time delay between the two signals. Use wider integers when doing these calcs to avoid overflow. \$\endgroup\$ – Scott Seidman Oct 25 '12 at 14:34
  • \$\begingroup\$ I can't understand how to apply cross correlation between these two signals because i know only amplitude and frequency of both signals. Just know i have looked into the cross correlation function. If you don't mind do you have any example procedure. \$\endgroup\$ – verendra Oct 25 '12 at 14:46
1
\$\begingroup\$

If your sine waves are of equal size/voltage/intensity then the easiest way is to simply add them together, then measure the amplitude of the resulting wave. If the phase shift is 0 deg then the result will be a sine wave twice the original amplitude. If the phase shift is 180 deg then the result will be zero amplitude. Phase shifts in between will result in, well, something in between.

If your sine waves are not of equal amplitude, or there is noise in the sine waves, then this might not be the best way to do it. But if it is, then this method is super easy!

\$\endgroup\$
  • \$\begingroup\$ Amplitude of sine waves are not equal and also noise is there. The phase shift also in between "0 to 10" degrees. \$\endgroup\$ – verendra Oct 30 '12 at 15:53
0
\$\begingroup\$

In short:

  • Looking for zero crossings is very crude because it uses the least amount of available information from your signals.
  • Auto-correlation is better and is a particularly good choice for signals that are pulses.
  • Since you have sine waves least squares curve fitting will give you the best result. Fit each curve separately then compare the phase results. This uses all the available information from both signals. [As I recall (in this special case) this is equivalent to a Fast Fourier Transform approach but computationally more efficient.]
\$\endgroup\$
  • 1
    \$\begingroup\$ Best results, using the most resources. Might be too much for the microcontroller, especially if this is a continuous task. \$\endgroup\$ – Scott Seidman Sep 10 '16 at 10:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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