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.
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.
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.
Si su retraso de tiempo es , y el período de la onda sinusoidal es , entonces
Esto dará fase ( ) en grados. Si 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 (hora pico a pico), y la frecuencia en Hertz es
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.
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!
En breve:
Verendra
incrustado.kyle
get_amplitude
debe seleccionar el canal multiplexor deseado y luego leer el valor ADC asociado.Verendra
incrustado.kyle
Verendra
incrustado.kyle
TCCRx
registro (incluso puede poner esta parte en lastop_timer
función y simplemente llamarla) y reinicie el conteo a ceroTCNTx = 0;
.Verendra