I zwei Sinussignale mit gleicher Frequenz. Ich möchte die Phasenverschiebung zwischen zwei Signalen messen. Es wird eine kleine Phasendifferenz zwischen zwei Signalen geben. Ich verwende den Mikrocontroller ATmega32-A und den externen ADC AD7798, um die Spannung beider Signale zu lesen. Ich kann beide Signalspannungen über SPI-Kommunikation lesen. So finden Sie die Phasendifferenz zwischen zwei Sinussignalen. Ich verwende den CodeVisionAVR-Compiler.
Ich weiß, dass die Phasenverschiebung zwischen zwei Signalen mit der folgenden Formel ermittelt werden kann.
A(t)= Am sin(Wt+/-theta).
Ich kenne nur Amplitude(Am) und w =2*pi*f. Aber wie man die Phasendifferenz zwischen zwei Sinuswellensignalen mit bekannter Amplitude und Frequenz berechnet. Irgendwelche Vorschläge bitte.
Ich habe eine Timer-Funktionalität implementiert, um Nulldurchgangspunkte mit dem folgenden Code zu erhalten.
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;
}
Wenn ich diesen Code ausführe, erhalte ich keine Fehler, aber ich kann keinen Befehl vom Hyperterminal eingeben. Wenn Sie diese ganze Funktion kommentieren, kann nur ich eine Ausgabe erhalten und Befehle vom Hyperterminal eingeben. Helfen Sie mir, wenn irgendetwas mit Timer-Funktion starten und stoppen und zurücksetzen und get_delay_tricks. Oder etwas falsch mit Interrupts.
Sie müssen Olins Idee verwenden, die Nulldurchgänge der Signale zu bestimmen, um die Zeitverzögerung zu erhalten. Setzen Sie dann die Zeitverzögerung in Scotts Gleichung ein, um die Phasenverzögerung zu erhalten.
Das Folgende ist Pseudo-Code. Ich überlasse es Ihnen, jede Funktion zu implementieren, da sie entweder trivial zu implementieren sein sollte oder Sie bereits etwas Ähnliches geschrieben haben sollten.
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 ist wichtig, die Dokumentation zu dem Timer zu lesen, den Sie verwenden werden, damit Sie wissen, wie Sie Timer-Ticks in Zeit umwandeln.
Wenn Sie wissen, dass beide Signale Sinussignale sind, ist der Vergleich der Zeitdifferenz ihrer Nulldurchgänge wahrscheinlich der einfachste Ansatz. Viele Mikros verfügen über Hardware, die es ermöglicht, einen frei laufenden Timer basierend auf einer externen Flanke zu erfassen. Die Differenz zwischen den beiden Timer-Schnappschüssen gibt Ihnen die Zeit zwischen den Nulldurchgängen an. Die Differenz zwischen dem Nulldurchgang desselben Signals gibt Ihnen die Periode an. Die Phasenverschiebung in Einheiten eines ganzen Zyklus ist dann nur der Zeitversatz zwischen den beiden Signalen dividiert durch ihre Periode.
Wenn Sie diesen Wert für die direkte Benutzeranzeige in Grad benötigen, multiplizieren Sie ihn mit 360. Es besteht jedoch keine Notwendigkeit, sonst Grad oder eine andere bestimmte Einheit im Mikro zu verwenden. Tatsächlich besteht die nützlichste Methode zur Darstellung von Winkeln in einem Mikro darin, den gesamten Bereich der bequemsten vorzeichenlosen Ganzzahl zu verwenden, um einen vollständigen Kreis darzustellen. Auf diese Weise funktionieren zusätzliche Winkel und Wraparounds ohne zusätzliche Logik. Es macht es auch einfach, in eine Tabelle zu indizieren, um beispielsweise Sinus oder Cosinus zu berechnen.
Wenn Ihre Zeitverzögerung ist , und die Periode der Sinuswelle ist , Dann
Dies gibt Phase ( ) in Grad. Wenn negativ ist, bedeutet dies, dass der Ausgang dem Eingang nacheilt, und positiv ist, wenn der Ausgang dem Eingang vorauseilt.
Wenn Sie die Sinuswellen gut genug sehen können, um die Zeitverzögerung zu messen, kennen Sie auch die Periode (Peak-to-Peak-Zeit) und Frequenz in Hertz ist
Algorithmisch ist Ihre Aufgabe schwieriger. Ihre beste Wette ist eine Kreuzkorrelation zwischen Eingang und Ausgang, um die Zeitverzögerung zu berechnen, und eine Autokorrelation, um den Wikipedia-Eintrag zur Häufigkeit der Kreuzkorrelation zu ermitteln . Wenn Sie über Rechenleistung verfügen, können Sie FFTs verwenden.
Wenn Ihre Sinuswellen die gleiche Größe/Spannung/Intensität haben, ist es am einfachsten, sie einfach zu addieren und dann die Amplitude der resultierenden Welle zu messen. Wenn die Phasenverschiebung 0 Grad beträgt, ist das Ergebnis eine Sinuswelle mit der doppelten ursprünglichen Amplitude. Wenn die Phasenverschiebung 180 Grad beträgt, ist das Ergebnis eine Nullamplitude. Phasenverschiebungen dazwischen werden zu etwas dazwischen führen.
Wenn Ihre Sinuswellen nicht die gleiche Amplitude haben oder Rauschen in den Sinuswellen vorhanden ist, ist dies möglicherweise nicht der beste Weg, dies zu tun. Aber wenn doch, dann ist diese Methode super einfach!
Zusamenfassend:
verendra
eingebettet.kyle
get_amplitude
sollte den gewünschten Multiplexerkanal auswählen und dann den zugehörigen ADC-Wert lesen.verendra
eingebettet.kyle
verendra
eingebettet.kyle
TCCRx
Register (Sie können diesen Teil sogar in diestop_timer
Funktion einfügen und diese einfach aufrufen) und setzen Sie den Zähler auf Null zurückTCNTx = 0;
.verendra