Cómo calcular el desplazamiento de fase entre dos fases de onda sinusoidal

3

Dos señales de onda sinusoidal con la misma frecuencia. Quiero medir el cambio de fase entre dos señales. Habrá una pequeña diferencia de fase entre dos señales. Estoy usando el microcontrolador ATmega32-A y el ADC AD7798 externo para leer el voltaje de ambas señales. Puedo leer ambos voltajes de señal utilizando la comunicación SPI. Cómo encontrar la diferencia de fase entre dos señales sinusoidales. Estoy usando el compilador CodeVisionAVR.

Sé que el cambio de fase entre dos señales se puede encontrar usando la siguiente fórmula.

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

Sólo conozco la amplitud (Am) yw = 2 * pi * f. Pero ¿Cómo calcular la diferencia de fase entre dos señales de onda sinusoidal con amplitud y frecuencia conocidas? Cualquier sugerencia por favor.

He implementado la funcionalidad de temporizador para obtener cero puntos de cruce usando el siguiente código.

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;
} 

cuando ejecuto este código no recibo ningún error, pero no puedo ingresar ningún comando desde el hiperminal. Cuando comento toda esta función, solo yo puedo obtener salida y puedo ingresar comandos desde el hiperminal. Ayudarme si algo con la función de temporizador iniciar y detener y restablecer y get_delay_tricks. O cualquier cosa mal con las interrupciones.

    
pregunta verendra

5 respuestas

1

Debe utilizar la idea de Olin de determinar los cruces por cero de las señales para obtener el retardo de tiempo. Luego inserte el retardo en la ecuación de Scott para obtener el retardo de fase.

El siguiente es pseudo-código. Lo dejaré a usted para que implemente cada función, ya que deberían ser triviales de implementar o ya debería haber escrito algo similar.

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

Es importante leer la documentación sobre el temporizador que utilizará para saber cómo convertir los tics del temporizador en tiempo.

    
respondido por el embedded.kyle
4

Si sabe que ambas señales son senos, entonces la comparación de la diferencia de tiempo de sus cruces por cero es probablemente el enfoque más fácil. Muchos micros tienen hardware que permite capturar un temporizador de funcionamiento libre basado en algún borde externo. La diferencia entre las dos instantáneas del temporizador le indica el tiempo entre los cruces por cero. La diferencia entre el cruce por cero de la misma señal le indica el período. El cambio de fase en unidades de un ciclo completo es, entonces, el desplazamiento de tiempo entre las dos señales divididas por su período.

Si necesita este valor para la visualización directa del usuario en grados, multiplíquelo por 360. Sin embargo, no es necesario usar grados o cualquier otra unidad particular dentro del micro. De hecho, la forma más útil de representar ángulos en un micro es usar el rango completo de lo que sea el entero sin signo más conveniente para representar un círculo completo. De esa manera, el ángulo adicional y los envolventes funcionan sin ninguna lógica adicional. También facilita la indexación en una tabla, como la computación sinusoidal o coseno, por ejemplo.

    
respondido por el Olin Lathrop
2

Si su retraso es \ $ t \ $, y el período de la onda sinusoidal es \ $ T \ $, entonces

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

Esto dará la fase (\ $ \ phi \ $) en grados. Si \ $ t \ $ es negativo, eso significaría que la salida se retrasa en la entrada, y positivo es cuando la salida encabeza la entrada.

Si puede ver las ondas sinusoidales lo suficientemente bien como para medir el retraso, entonces también conoce el período \ $ T \ $ (tiempo pico a pico), y la frecuencia en Hertz es \ $ 1 / T \ $

Algorítmicamente, tu tarea es más difícil. Su mejor apuesta es una correlación cruzada entre la entrada y la salida para calcular el retraso, y una autocorrelación para determinar la frecuencia entrada de wikpedia en la correlación cruzada . Si tiene el código de cómputo, puede usar FFT.

    
respondido por el Scott Seidman
1

Si sus ondas sinusoidales son del mismo tamaño / voltaje / intensidad, la forma más sencilla es simplemente sumarlas y luego medir la amplitud de la onda resultante. Si el desplazamiento de fase es 0 grados, el resultado será una onda sinusoidal dos veces la amplitud original. Si el cambio de fase es de 180 grados, el resultado será una amplitud cero. Los cambios de fase en el medio resultarán, bueno, algo en el medio.

Si sus ondas sinusoidales no tienen la misma amplitud, o si hay ruido en las ondas sinusoidales, entonces esta podría no ser la mejor manera de hacerlo. Pero si lo es, ¡este método es muy fácil!

    
respondido por el user3624
0

En resumen:

  • Buscar cruces por cero es muy burdo porque utiliza la menor cantidad de información disponible de sus señales.
  • La autocorrelación es mejor y es una opción particularmente buena para las señales que son pulsos.
  • Ya que tiene curvas de seno, el ajuste de la curva de mínimos cuadrados le dará el mejor resultado. Ajuste cada curva por separado y luego compare los resultados de la fase. Esto utiliza toda la información disponible de ambas señales. [Como recuerdo (en este caso especial) esto es equivalente a un enfoque de Transformada de Fourier rápida pero computacionalmente más eficiente.]
respondido por el Neil

Lea otras preguntas en las etiquetas