Cómo calcular el cambio de fase entre dos ondas sinusoidales

I dos señales sinusoidales 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 usando 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).

Solo conozco la amplitud (Am) y w = 2 * pi * f. Pero cómo calcular la diferencia de fase entre dos señales de onda sinusoidal conociendo la amplitud y la frecuencia. Cualquier sugerencia por favor.

Implementé la funcionalidad del temporizador para obtener puntos de cruce cero utilizando el código siguiente.

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 obtengo ningún error, pero no puedo ingresar ningún comando desde la hiperterminal. Cuando comente toda esta función, solo puedo obtener resultados y puedo ingresar comandos desde la hiperterminal. Ayúdame si hay algo con la función de temporizador de inicio y parada y reinicio y get_delay_tricks. O cualquier cosa mal con las interrupciones.

Respuestas (5)

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

El siguiente es un pseudocódigo. Te dejaré a ti implementar cada función, ya que deberían ser triviales de implementar o ya deberías tener algo similar escrito.

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 del temporizador que usará para saber cómo convertir los tics del temporizador en tiempo.

Tengo una duda. Como sabe acerca de mi concepto, estoy seleccionando la señal de entrada y salida usando un multiplexor. La salida del multiplexor es una señal analógica, pero después de eso tengo un demodulador y obtengo una señal de CC en la entrada de ADC. Entonces, ¿puedo aplicar el procedimiento de cruce por cero para calcular el cambio de fase? calcular el cambio de fase no está relacionado con la lectura de ADC? ¿Dónde debo implementar esta función porque estoy seleccionando el canal usando MULTIPLEXER y leyendo el valor del voltaje?
@verendra No sabía sobre el demodulador. Pero dijiste que conocías la amplitud de la señal sinusoidal. Entonces, ¿puede convertir esa señal demodulada en una amplitud para su onda sinusoidal? Si sabe eso, entonces debe saber cuándo la señal del seno cruza el cero o el punto medio. La función get_amplitudedebe seleccionar el canal multiplexor deseado y luego leer el valor ADC asociado.
La salida del multiplexor es una señal de onda sinusoidal, pero después de eso hay un demodulador, la salida del demodulador está dando a ADC. La salida del demodulador es una señal de CC con el voltaje máximo de la señal de salida del multiplexor.
@verendra Sin poder medir el valor instantáneo de la onda sinusoidal para encontrar los cruces por cero, no puedo pensar en una forma de encontrar el cambio de fase. Su multiplexor tiene muchos canales de entrada. ¿Por qué no poner el demodulador frente al multiplexor? Haga que los canales 1 y 2 sean la señal demodulada y los canales 3 y 4 sean la señal sinusoidal completa.
Implementé la funcionalidad del temporizador de la hoja de datos de ATmega32-AI, actualicé mi código. Pero estoy pensando en la función Reset_timer.
@verendra Es una función bastante simple. Simplemente detenga el temporizador usando el TCCRxregistro (incluso puede poner esta parte en la stop_timerfunción y simplemente llamarla) y reinicie el conteo a cero TCNTx = 0;.

Si sabe que ambas señales son senos, entonces comparar 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 ejecución libre en función de 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 te indica el período. El cambio de fase en unidades de un ciclo completo es solo el desfase de tiempo entre las dos señales dividido por su período.

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

La diferencia entre los cruces por cero de neg a pos (o pos a neg) da el período. Si solo usa cualquier cruce por cero anterior, obtiene medio ciclo, pero obviamente, ¡este es el enfoque más fácil!
@Olin Lathrop Soy muy nuevo en la programación. ¿Tiene algún código de muestra o algún procedimiento de ejemplo para hacer eso?
@Scott: Sí, asumí que se usó la misma polaridad de cruce por cero en todos los casos. El hardware de captura de temporizador en micros generalmente se puede configurar para eso. Si usa un módulo CCP de PIC 16 o PIC 18, por ejemplo, solo puede capturar en una polaridad de borde de todos modos.
Para estos fines, incluso podría ser más fácil prescindir del ADC y simplemente usar los módulos de comparación, dependiendo de para qué se usen las señales.
Pero los módulos de captura/comparación requieren una entrada digital. No funcionan bien con analógico, ya que el umbral no es configurable y puede variar. Además, conectar señales analógicas a entradas digitales es una mala idea, ya que las señales que cambian lentamente pueden provocar metaestabilidad y una gran disipación de potencia. Probablemente, algunos micros tienen un comparador analógico (aunque la detección de cruce por cero requeriría un AVSS negativo) que puede controlar el temporizador de captura, pero ¿lo hace el suyo?
En resumen, este es un gran concepto de diseño, pero requiere soporte de hardware, no puede adaptarlo a un circuito existente solo mediante cambios de software.
@BenVoigt: Por supuesto, debe usar un comparador por señal en alguna parte. Ya sea externamente para alimentar una señal digital al micro, o puede usar un micro que tenga dos comparadores incorporados y la tubería necesaria para capturar un temporizador basado en uno de los bordes. Pensé que todo esto era obvio, pero debería haberlo dicho explícitamente. Muchos micros tienen comparadores incorporados.

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

t T     =     ϕ 360

Esto dará fase ( ϕ ) en grados. Si t es negativo, eso significaría que la salida se retrasa con respecto a la entrada, y positivo es cuando la salida se adelanta a la entrada.

Si puede ver las ondas sinusoidales lo suficientemente bien como para medir el tiempo de retardo, también sabrá el período T (hora pico a pico), y la frecuencia en Hertz es 1 / T

Algorítmicamente, su tarea es más difícil. Su mejor apuesta es una correlación cruzada entre la entrada y la salida para calcular el retraso de tiempo, y una autocorrelación para averiguar la frecuencia de la entrada de wikpedia en la correlación cruzada . Si tiene el empuje computacional, puede usar FFT.

¿Me puede decir cómo encontrar el retraso de tiempo. Sé que la frecuencia de ambas señales es de 250 KHz, por lo que puedo encontrar fácilmente T, pero cómo medir el retraso de tiempo.
El valor máximo de la correlación cruzada se producirá en el tiempo de retardo entre las dos señales. Utilice números enteros más amplios al realizar estos cálculos para evitar el desbordamiento.
No puedo entender cómo aplicar la correlación cruzada entre estas dos señales porque solo conozco la amplitud y la frecuencia de ambas señales. Solo sé que he investigado la función de correlación cruzada. Si no le importa, ¿tiene algún procedimiento de ejemplo?

Si sus ondas sinusoidales son del mismo tamaño/voltaje/intensidad, entonces la forma más fácil es simplemente sumarlas y luego medir la amplitud de la onda resultante. Si el cambio de fase es de 0 grados, el resultado será una onda sinusoidal con el doble de la amplitud original. Si el cambio de fase es de 180 grados, el resultado será amplitud cero. Los cambios de fase intermedios darán como resultado, bueno, algo intermedio.

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 es así, ¡entonces este método es súper fácil!

La amplitud de las ondas sinusoidales no es igual y también hay ruido. El cambio de fase también entre "0 a 10" grados.

En breve:

  • Buscar cruces por cero es muy crudo 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 señales que son pulsos.
  • Dado que tiene ondas sinusoidales, 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 las fases. Esto utiliza toda la información disponible de ambas señales. [Según recuerdo (en este caso especial) esto es equivalente a un enfoque de Transformada Rápida de Fourier pero computacionalmente más eficiente.]
Mejores resultados, utilizando la mayor cantidad de recursos. Puede ser demasiado para el microcontrolador, especialmente si se trata de una tarea continua.