So berechnen Sie die Phasenverschiebung zwischen zwei Sinuswellenformen

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.

Antworten (5)

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.

Ich habe einen Zweifel. Wie Sie von meinem Konzept wissen, wähle ich das Eingangs- und Ausgangssignal mit einem Multiplexer aus. Der Multiplexerausgang ist ein analoges Signal, aber danach habe ich einen Demodulator und erhalte ein Gleichstromsignal am Eingang des ADC. Kann ich also das Nulldurchgangsverfahren anwenden, um die Phasenverschiebung zu berechnen? Die Berechnung der Phasenverschiebung hängt nicht mit dem ADC-Lesen zusammen? Wo soll ich diese Funktion implementieren, weil ich den Kanal mit MULTIPLEXER auswähle und den Spannungswert lese.
@verendra Ich wusste nichts über den Demodulator. Aber Sie sagten, Sie kennen die Amplitude des Sinussignals. Können Sie dieses demodulierte Signal in eine Amplitude für Ihre Sinuswelle umwandeln? Wenn Sie das wissen, sollten Sie wissen, wann das Sinussignal den Null- oder Mittelpunkt kreuzt. Die Funktion get_amplitudesollte den gewünschten Multiplexerkanal auswählen und dann den zugehörigen ADC-Wert lesen.
Der Multiplexerausgang ist ein Sinuswellensignal, aber danach gibt es einen Demodulator, der Demodulatorausgang gibt an ADC. Der Ausgang des Demodulators ist ein DC-Signal mit der maximalen Spannung des Multiplexer-Ausgangssignals.
@verendra Ohne den Momentanwert der Sinuswelle messen zu können, um die Nulldurchgänge zu finden, kann ich mir keine Möglichkeit vorstellen, die Phasenverschiebung zu finden. Ihr Multiplexer hat viele Eingangskanäle. Warum nicht den Demodulator vor den Multiplexer stellen? Lassen Sie die Kanäle 1 und 2 das demodulierte Signal und die Kanäle 3 und 4 das volle Sinussignal sein.
Ich habe die Timer-Funktionalität aus dem Datenblatt von ATmega32-AI implementiert und meinen Code aktualisiert. Aber ich denke über die Reset_timer-Funktion nach.
@verendra Es ist eine ziemlich einfache Funktion. Stoppen Sie einfach den Timer mit dem TCCRxRegister (Sie können diesen Teil sogar in die stop_timerFunktion einfügen und diese einfach aufrufen) und setzen Sie den Zähler auf Null zurück TCNTx = 0;.

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.

Die Differenz zwischen den Nulldurchgängen von neg zu pos (oder pos zu neg) ergibt die Periode. Wenn Sie nur einen beliebigen alten Nulldurchgang verwenden, erhalten Sie einen halben Zyklus - aber offensichtlich ist dies der einfachste Ansatz!
@Olin Lathrop Ich bin sehr neu in der Programmierung. Haben Sie einen Beispielcode oder eine Beispielprozedur dafür.
@Scott: Ja, ich ging davon aus, dass in allen Fällen der gleiche Polaritätsnulldurchgang verwendet wurde. Die Timer-Capture-Hardware in Micros kann normalerweise dafür eingerichtet werden. Wenn Sie beispielsweise ein CCP-Modul eines PIC 16 oder PIC 18 verwenden, können Sie ohnehin nur eine Flankenpolarität erfassen.
Für diese Zwecke kann es sogar einfacher sein, auf den ADC zu verzichten und nur die Komparatormodule zu verwenden, je nachdem, wofür die Signale verwendet werden.
Capture/Compare-Module erfordern jedoch einen digitalen Eingang. Sie funktionieren nicht gut mit Analog, da der Schwellenwert nicht konfigurierbar ist und variieren kann. Außerdem ist es keine gute Idee, analoge Signale an digitale Eingänge anzuschließen, da sich langsam ändernde Signale Metastabilität und hohe Verlustleistung verursachen können. Wahrscheinlich haben einige Mikros einen analogen Komparator (obwohl die Nulldurchgangserkennung ein negatives AVSS erfordern würde), der den Capture-Timer steuern kann, aber tut er das?
Zusammenfassend lässt sich sagen, dass dies ein großartiges Designkonzept ist, aber es erfordert Hardwareunterstützung, Sie können es nicht nur durch Softwareänderungen an einer vorhandenen Schaltung nachrüsten.
@BenVoigt: Natürlich muss man irgendwo einen Komparator pro Signal verwenden. Entweder extern, um ein digitales Signal in das Mikro einzuspeisen, oder Sie können ein Mikro verwenden, das über zwei eingebaute Komparatoren und die erforderlichen Leitungen verfügt, um einen Timer basierend auf einer der Flanken zu erfassen. Ich dachte, das wäre alles offensichtlich, aber ich hätte es explizit sagen sollen. Viele Mikros haben Komparatoren eingebaut.

Wenn Ihre Zeitverzögerung ist T , und die Periode der Sinuswelle ist T , Dann

T T     =     ϕ 360

Dies gibt Phase ( ϕ ) in Grad. Wenn T 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 T (Peak-to-Peak-Zeit) und Frequenz in Hertz ist 1 / T

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.

Kannst du mir sagen, wie ich die Zeitverzögerung finde? Ich weiß, dass die Frequenz beider Signale 250 kHz beträgt, sodass ich T leicht finden kann, aber wie man die Zeitverzögerung misst.
Der Spitzenwert der Kreuzkorrelation tritt bei der Zeitverzögerung zwischen den beiden Signalen auf. Verwenden Sie bei diesen Berechnungen breitere Ganzzahlen, um einen Überlauf zu vermeiden.
Ich kann nicht verstehen, wie man eine Kreuzkorrelation zwischen diesen beiden Signalen anwendet, weil ich nur Amplitude und Frequenz beider Signale kenne. Ich weiß nur, dass ich mir die Kreuzkorrelationsfunktion angesehen habe. Wenn es Ihnen nichts ausmacht, haben Sie ein Beispielverfahren.

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!

Die Amplitude der Sinuswellen ist nicht gleich und es ist auch Rauschen vorhanden. Die Phasenverschiebung liegt ebenfalls zwischen "0 und 10" Grad.

Zusamenfassend:

  • Das Suchen nach Nulldurchgängen ist sehr grob, da es die geringste Menge an verfügbaren Informationen aus Ihren Signalen verwendet.
  • Die Autokorrelation ist besser und eignet sich besonders gut für Signale, bei denen es sich um Impulse handelt.
  • Da Sie Sinuswellen haben, erhalten Sie mit der Kurvenanpassung der kleinsten Quadrate das beste Ergebnis. Passen Sie jede Kurve separat an und vergleichen Sie dann die Phasenergebnisse. Dabei werden alle verfügbaren Informationen aus beiden Signalen genutzt. [Wie ich mich erinnere (in diesem speziellen Fall) entspricht dies einem schnellen Fourier-Transformationsansatz, ist jedoch rechnerisch effizienter.]
Beste Ergebnisse mit den meisten Ressourcen. Könnte für den Mikrocontroller zu viel sein, besonders wenn dies eine kontinuierliche Aufgabe ist.