Möglichkeiten zur Schätzung der Phasenverschiebung

Ich habe ein System, das zwei 50-Hz-Sinuswellen mit 1 kHz abtastet. Wie kann man die Phasenverschiebung zwischen den beiden am besten abschätzen?

Die Messungen sind etwas verrauscht und die Abtastperiode ist nicht sehr gleichmäßig. Ich kenne die Abtastzeiten in hoher Auflösung, kann sie aber nicht so steuern, dass sie gleichmäßig verteilt sind. Die Phasenverschiebung muss anhand von Datenblöcken geschätzt werden, die etwa eine Sekunde abdecken.

Das Messrauschen macht das Nulldurchgangsverfahren unzuverlässig; Wenn das Rauschen dazu führt, dass ein gemessenes Signal bei einem "echten" Nulldurchgang zweimal Null durchquert, bricht der Algorithmus etwas zusammen.

Derzeit mache ich so etwas (Python-Code):

t, v, a = [NumPY arrays of samples]
p_inst = v * a
s = numpy.sign(p_inst)
s_avg = numpy.trapz(s, x=t) / (t[-1] - t[0])
shift_fraction = s_avg / 2 + 0.5
shift_angle = (1 - shift_fraction) * numpy.pi

Hier sist das Vorzeichen des Produkts der beiden Sinuswellen. Das Ermitteln des Mittelwerts dieser Verwendung numpy.trapzergibt einen Wert, der angibt, wie oft die beiden Signale das gleiche Vorzeichen haben, wobei 1 "immer", -1 "nicht immer" und null "halbe Zeit" bedeutet. Dies wird in einen Bruchteil der Zeit umgewandelt, in der die Signale dasselbe Vorzeichen haben ( shift_fraction), und dies wird in einen Phasenverschiebungswinkel umgewandelt.

Das größte Problem dabei ist, dass es Ihnen nicht sagt, ob die Phasendifferenz voreilend oder nacheilend ist.

Hat jemand eine bessere Methode?

Bearbeiten Für diejenigen, die vorschlagen, den Korrelationspeak zu finden, gehe ich richtig in der Annahme, dass diese Methode bei 20 Abtastungen pro Zyklus die Auflösung der Schätzung zwangsläufig auf 18 Grad begrenzt? Was würden Sie davon halten, stattdessen zu berechnen numpy.correlate(v, -a), den ersten Nulldurchgang zu finden und dann zu interpolieren, um den tatsächlichen Nullpunkt zu schätzen? Ich denke, dass für sinusförmige Signale die Korrelation auch sinusförmig sein sollte, und daher sollte die Annäherung an kleine Winkel die Interpolation einigermaßen gut machen.

Kann jemand die Korrelations- und Demodulationsmethoden vergleichen?

Weiter bearbeiten Und für diejenigen, die die Demodulationsmethode angeben, habe ich Recht, wenn ich denke, dass ich dies tun kann, wenn ich mich nicht für die tatsächliche Phasendifferenz interessiere, sondern nur für den Leistungsfaktor:

s = sin(t * 2 * pi * f)
c = sin(t * 2 * pi * f)
a_s_d = s * a
v_s_d = s * v
a_c_d = c * a
v_c_d = c * v
s_a = numpy.trapz(a_s_d, t)
c_a = numpy.trapz(a_c_d, t)
s_v = numpy.trapz(v_s_d, t)
c_v = numpy.trapz(v_c_d, t)
# cos ( a - b ) = cos a * cos b + sin a * sin b
power_factor = c_a * c_v + s_a * s_v

Oder kann ich mich nicht darauf verlassen 0 < s_a, c_a, s_v, c_v < 1?

Haben Sie eine Kreuzkorrelation der beiden Signale in Betracht gezogen, indem Sie numpy's correlateoder eine Bibliothek wie scipy(dh scipy.​signal.​signaltools.correlate(A, B)) verwenden? Die Zeitverschiebung der Spitze der Kreuzkorrelation erfasst die Phasendifferenz. Es gibt eine gute Antwort auf StackOverflow, die dies bespricht (es ist jedoch komplexer).
Kreuzkorrelation, aber Sie erhalten alle 2 * PI Spitzen, wenn die Signale sinusförmig sind.
Warum ist dies mit "Leistungsfaktorkorrektur" gekennzeichnet? Die Leistungsfaktorkorrektur hat mit Hochspannungsleitungen und nicht mit der Abtastung zu tun.
@KingDuken, er schätzt die Phasendifferenz zwischen Spannungs- und Stromwellenformen (basierend auf den Namen der Variablen im Pseudocode). Wahrscheinlich um den Leistungsfaktor abzuschätzen.
Filtern könnte bei dem Rauschen helfen. Vielleicht wäre der Nulldurchgang dann zuverlässiger.
@MarkoBuršič Du hast Recht. Bei zwei endlichen Sinuskurven entspricht die höchste dieser Spitzen jedoch (0 <= Zeitverschiebung < Sinusperiode). Der Rest dieser Peaks verschlechtert sich mit jeder zusätzlichen (2 * pi) Phasenverschiebung.
Wenn Sie versuchen, PF abzuschätzen, schauen Sie sich meine Antwort hier an: electronic.stackexchange.com/questions/76213/… - wenn Sie versuchen, die Leistung abzuschätzen, dann sehen Sie sich dies auch an: electronic.stackexchange.com/questions/202667/… und das: electronic.stackexchange.com/questions/82188/…

Antworten (6)

Der einfach zu befolgende, aber CPU-intensive Weg

Wenn Sie etwas wollen, das offensichtlich funktioniert und einfach zu verstehen ist, und es Ihnen nichts ausmacht, viele CPU-Zyklen darauf zu werfen (klingt so, als würden Sie es nicht tun, wenn Sie Python verwenden), dann könnten Sie einfach Sinus anpassen Wellen zu den beiden Signalen und lesen Sie die Phase aus der Anpassungsfunktion ab.

Sie möchten wahrscheinlich verwenden, scipy.optimise.curve_fit()um so etwas zu passen v = A × Sünde ( 2 π F T + ϕ ) mit ϕ als einziger freier Parameter. Dies könnte zu mehreren unterschiedlichen Werten von konvergieren ϕ , also nimm es modulo 2 π , machen Sie dasselbe für den Strom und subtrahieren Sie die beiden Werte von ϕ , achte darauf, zu addieren oder zu subtrahieren 2 π um es in den sinnvollen Bereich zu bekommen.

Dies ist viel, viel CPU-intensiver als Filtern oder Homodyne-Erkennung in Echtzeit, aber es ist einfach zu befolgen, nur wenige Zeilen lang und CPU-Zyklen sind billig.

Wenn Sie sich diese CPU-Zyklen nicht leisten können

Dann möchten Sie vielleicht versuchen, zwei Quadratur-Sinuswellen in Software zu erzeugen und sie dann zur IQ-Demodulation der beiden Signale zu verwenden. Berechnen Sie dann die Phasen und subtrahieren Sie. Dies wird nicht so einfach zu befolgen sein, könnte aber sehr schnell gemacht werden (sogar in Python) und wird sehr, sehr genau sein.

Nehmen Sie einen Datenblock, der eine ganzzahlige Anzahl von Zyklen ist (vorausgesetzt, Ihr 50-Hz-Netz ist schön und stabil, nehmen Sie einfach 1 s Daten), und multiplizieren Sie ihn Punkt für Punkt mit jeder der erzeugten Sinuswellen. Integrieren Sie dann jeweils mit , numpy.trapz()um zwei Skalare zu erhalten. Nehmen Sie diese als Argumente für numpy.arctan2(), und voila, Sie haben die Phase dieses Signals relativ zur erzeugten Sinuswelle. Machen Sie dasselbe für das zweite Signal und subtrahieren Sie die beiden, um die Differenz zu erhalten. Wie oben addieren oder subtrahieren 2 π um es in den sinnvollen Bereich zu bekommen.

Am Ende habe ich Ihre Quadraturdemodulationsmethode verwendet - es tut mir leid, dass die Anerkennung so lange gedauert hat!

Ich werde zwei Möglichkeiten geben. Ich weiß nicht, was bessere Ergebnisse liefert.

  1. Interpolieren Sie Ihre Daten auf ein regelmäßiges Zeitraster. Verwenden Sie dann alle verschiedenen bekannten Methoden zur Phasenschätzung (Nulldurchgänge, Kreuzkorrelation, ...), die Sie und andere Antworten erwähnt haben.

  2. Konstruieren Sie ein neues Sinus- und Cosinus-Array auf Ihrem Zeitraster. Schätzen

A = 0 T F ( T ) Sünde ( 2 π F T ) D T
Und
B = 0 T F ( T ) cos ( 2 π F T ) D T

für jedes Ihrer beiden Signale, indem Sie so vorgehen, trapzwie Sie es getan haben, um die durchschnittliche Leistung zu schätzen.

Nun kann die Phase jedes Signals relativ zum Referenzkosinus abgeschätzt werden bräunen 1 ( A B ) , oder in Python numpy.arctan2(B, A). Und die Phasendifferenz zwischen den zwei Signalen kann durch Subtraktion erhalten werden.

Vorbehalt: Es besteht die Möglichkeit, dass ich oben einen Fehler gemacht habe, der einen Fehler von ergibt π / 2 in den Phasenschätzungen der einzelnen Signale. Seien Sie auch vorsichtig 2 π Wrap-Around in der letzten Subtraktion. Überprüfen Sie Ihre Ergebnisse auf Angemessenheit, bevor Sie sie verwenden.

In der Welt der Signalverarbeitung wird die Phasendifferenz üblicherweise durch die Kreuzkorrelation zweier Signale geschätzt; nennen wir sie a(t) und b(t). Da a(t) und b(t) ähnlich geformte Wellenformen sind, sollte Kreuzkorrelation ein zuverlässiger Ansatz sein.

Hier ist ein Python-Skript (von dem ein Teil von dieser SO-Antwort inspiriert wurde ), das die correlatein der Bibliothek gefundene Funktion verwendet numpy, um die Phasenverschiebung zwischen zwei Sinuswellen , a(t) und b(t), zu berechnen. Sie sollten den Inhalt dieses Skripts für Ihre eigene Anwendung extrapolieren können:

import numpy as np

# Create the time axis (seconds)
num_samples = 10001
samples_per_second = 1000
freq_Hz = 50.0
t = np.linspace(0.0, ((num_samples - 1) / samples_per_second), num_samples)
# Create a sine wave, a(t), with a frequency of 1 Hz
a = np.sin((2.0 * np.pi) * freq_Hz * t)
# Create b(t), a (pi / 2.0) phase-shifted replica of a(t)
b_shift = (np.pi / 2.0)
b = np.sin((2.0 * np.pi) * freq_Hz * t + b_shift)

# Cross-correlate the signals, a(t) & b(t)
ab_corr = np.correlate(a, b, "full")
dt = np.linspace(-t[-1], t[-1], (2 * num_samples) - 1)
# Calculate time & phase shifts
t_shift_alt = (1.0 / samples_per_second) * ab_corr.argmax() - t[-1]
t_shift = dt[ab_corr.argmax()]
# Limit phase_shift to [-pi, pi]
phase_shift = ((2.0 * np.pi) * ((t_shift / (1.0 / freq_Hz)) % 1.0)) - np.pi

manual_t_shift = (b_shift / (2.0 * np.pi)) / freq_Hz

# Print out applied & calculated shifts
print ("Manual time shift: {}".format(manual_t_shift))            --> 0.005
print ("Alternate calculated time shift: {}".format(t_shift_alt)) --> 0.005000000000000782
print ("Calculated time shift: {}".format(t_shift))               --> 0.005000000000000782                         
print ("Manual phase shift: {}".format(b_shift))                  --> 1.5707963267948966, b(t) relative to a(t)                            
print ("Calculated phase shift: {}".format(phase_shift))          --> -1.570796326794651, a(t) relative to b(t)

Wenn phase_shiftnegativ ist, dann wissen Sie, dass der 1. Signaleingang correlate()hinter dem 2. Signaleingang zurückbleibt. In unserem Fall bedeutet dies, dass a(t) b(t) um (pi / 2) nacheilt. Wenn phase_shiftpositiv, dann wissen Sie, dass der 1. Signaleingang dem 2. Signaleingang vorauseilt.

Wie Sie sehen können, kann die Kreuzkorrelation zweier Signale einfach verwendet werden, um die Phasendifferenz zwischen zwei Signalen zu erkennen. Der Fehlervektor zwischen den tatsächlichen und berechneten Zeit-/Phasenverschiebungen bleibt niedrig, solange Ihre Signale linear zusammenhängen, mit einer Rate über ihrer Nyquist-Grenze abgetastet werden und ein anständiges SNR haben.

Lustige Tatsache, Sie können die Kreuzkorrelation für diese Anwendung auch dann noch verwenden , wenn die Signale aperiodisch sind! Seien Sie vorsichtig, wenn Sie die Kreuzkorrelation zwischen zwei Signalen nehmen, die nicht linear miteinander verbunden sind.

Danke für eine ausführliche Antwort. Könnten Sie sich die Bearbeitung der Frage ansehen und antworten? In Ihrem Beispiel haben Sie 1000 Abtastungen pro Zyklus, während ich 20 habe - schränkt dies nicht die Auflösung dieser Methode ein?
Ist das Generieren eines Arrays [-t:t/num_samples:t]und Verwenden einer Indexsuche nicht auch eine verschwenderische Art, die Zeitverschiebung zu berechnen? Was ist los mit 2 * t * (ab_corr.argmax() - num_samples/2) / num_samples?
@Tom Siehe meine Ergebnisse; sie passen gut zu der (pi/2)-Phasenverschiebung, die wir erwarten. Ich glaube nicht, dass die Kreuzkorrelation durch die Abtastrate begrenzt ist, solange Sie den Satz von Nyquist befolgen (dh Ihre Signale nicht unterabtasten). In Bezug auf das dtArray; Ich habe eine alternative Methode zur Berechnung der Zeitverschiebung eingefügt, die eine Indexsuche vermeidet (und dieselbe Zeitverschiebung wie bei der dtIndexsuchmethode erzeugt). Eine Sache, die an Ihrem Vorschlag falsch ist, ist, dass er auch ein Array generiert (denken Sie daran, tist ein Array) ...

Sie erwähnen es nicht, aber basierend auf Ihren Variablen scheint es, dass Sie versuchen, die Phasenverschiebung zwischen Strom und Spannung auf einer 50-Hz-Leitung zu messen.

Um korrekte Phasenmessungen durchzuführen, ist es wichtig, dass das Signal sauber ist, und Sie haben ausdrücklich erwähnt, dass dies nicht der Fall ist. Um ein sauberes Signal zu erhalten, können Sie eine Tiefpassfilterung entweder analog vor dem ADC oder digital nach dem ADC durchführen. Natürlich muss jede Phasenverschiebung vom Filtern für beide Signale gleich sein oder der eingeführte Phasenfehler muss vorhersagbar sein.

Zwei übliche Mittel zum Implementieren eines digitalen Tiefpassfilters sind IIR- und FIR-Algorithmen. Glücklicherweise sind sie in der scipy-Bibliothek integriert. Sehen Sie sich zum Beispiel die scipy-ifilter-Funktionen an. Beachten Sie jedoch, dass Ihre Daten als uneinheitliche Zeitdaten betrachtet werden, sodass Sie Ihre Daten zunächst mit einem Spline oder einem anderen geeigneten Interpolationsalgorithmus erneut abtasten müssen.

Sobald die Signale den LP-Filter durchlaufen haben, besteht die gebräuchlichste Methode zum Auffinden der Phasendifferenz darin, die Spitze jedes Signals zu finden, die Zeitdifferenz zwischen den Spitzen zu berechnen und diese in Grad oder Bogenmaß umzuwandeln.

Eigentlich wäre es genauer zu sagen, dass ich nicht sehr zuversichtlich bin, was das Rauschen in den Signalen angeht, als dass ich irgendwelche stichhaltigen Beweise dafür habe, dass es schlecht ist. Wie ist Ihre Methode zur Berechnung der Phasenverschiebung besser als die Nulldurchgangsmethode? Es scheint mir, dass die kleine Steigung an der Spitze einer Sinuskurve die Schätzung der Spitze schlechter machen würde als die Schätzung des Nulldurchgangs.
Ich habe es vorher ziemlich erfolgreich verwendet. Bei deiner hohen Abtastrate sollte das kein Problem sein.

Eine Möglichkeit besteht darin, eine phasenempfindliche Detektion zu verwenden. Bei 50 Hz mit 1000 Samples erhalten Sie 20 Samples pro Zyklus. Verwenden Sie 20-Sample-Blöcke und subtrahieren Sie die Summe der zweiten 10 Samples von der Summe der ersten 10 Samples. Dadurch erhalten Sie einen Wert, der sich auf die Phasenbeziehung zwischen der Grenze des Blocks und dem Signal durch die Sinusfunktion bezieht (Sie müssen für die Amplitude skalieren - Sie können einen Durchschnitt der PP-Spannung verwenden). Es wird eine positive Spitze haben, wenn Sie genau in Phase sind, und eine negative Spitze, wenn Sie 180 aus sind. Der Ansatz entfernt jede DC-Komponente. Sie können diesen Wert dann über viele Zyklen mitteln, um Ihr Rauschen zu mindern. Wenn Sie beide Signale mit demselben Block-Timing messen, erhalten Sie die Phasenbeziehung zwischen jedem Signal und Ihrem Abtastsystem, wodurch Sie eine Antwort erhalten. Alternative,

Funktioniert diese Methode mit unregelmäßigen Abtastintervallen?
Nein. Sie verlassen sich auf zwei Dinge: Die Zeitdauer für die positiven Samples und die Zeitdauer für die invertierten Samples sind genau gleich und sie liegen bei der interessierenden Frequenz. Ich denke, Sie können sehen, dass Sie im Grunde genommen die Daten nehmen und eine Hälfte der Samples von der anderen Hälfte subtrahieren, was für alle zufälligen Dinge Null ergeben sollte. Nur Daten, die die Eigenschaft haben, in jedem Halbzyklus bei Ihrer Blockrate einen Wert unterschiedlicher Polarität zu haben, werden auf lange Sicht eine Ausgabe liefern.

Wenn Ihr einziges Problem mit der Messung die Mehrdeutigkeit ist, können Sie es lösen, indem Sie zu den Daten zurückkehren, eine Methode anwenden, um zu nahe beieinander liegende Nulldurchgänge zu harmonisieren (nehmen Sie vielleicht ihre mittlere Ankunftszeit) und dann den Winkel berechnen mit die Nulldurchgangsmethode. Das gewünschte Ergebnis ist diejenige der beiden möglichen Phasenverschiebungen, die näher am Nulldurchgangsergebnis liegt.

Wo ich gerade beim Thema bin, eine Methode, um den Phasenwinkel zu finden, die ich noch nie ausprobiert habe, aber funktionieren sollte, die auch mehrdeutige Ergebnisse liefert, besteht darin, die Spannung jeder Sinuswelle zu messen und dann die Spannungsdifferenz zwischen ihnen zu messen. Das würde Ihnen die 3 Seiten eines Dreiecks geben und Sie können die Winkel mit dem Sinussatz / Kosinussatz finden.