matlab - for - identificar el cambio de fase entre señales
plot matlab (5)
He generado tres ondas idénticas con un cambio de fase en cada una. Por ejemplo:
t = 1:10800; % generate time vector
fs = 1; % sampling frequency (seconds)
A = 2; % amplitude
P = 1000; % period (seconds), the time it takes for the signal to repeat itself
f1 = 1/P; % number of cycles per second (i.e. how often the signal repeats itself every second).
y1 = A*sin(2*pi*f1*t); % signal 1
phi = 10; % phase shift
y2 = A*sin(2*pi*f1*t + phi); % signal 2
phi = 15; % phase shift
y3 = A*sin(2*pi*f1*t + phi); % signal 3
YY = [y1'',y2'',y3''];
plot(t,YY)
Ahora me gustaría usar un método para detectar este cambio de fase entre las ondas. El punto de hacer esto es para que eventualmente pueda aplicar el método a datos reales e identificar los cambios de fase entre las señales.
Hasta ahora he estado pensando en calcular los espectros cruzados entre cada onda y la primera onda (es decir, sin el cambio de fase):
for i = 1:3;
[Pxy,Freq] = cpsd(YY(:,1),YY(:,i));
coP = real(Pxy);
quadP = imag(Pxy);
phase(:,i) = atan2(coP,quadP);
end
Pero no estoy seguro de si esto tiene algún sentido.
¿Alguien más ha hecho algo similar a esto? El resultado deseado debe mostrar un cambio de fase en 10 y 15 para las ondas 2 y 3, respectivamente.
Cualquier consejo sería apreciado.
Aquí está la pequeña modificación de su código: phi = 10
está realmente en grado, luego, en la función seno, la información de la fase se expresa principalmente en radianes, por lo que necesita cambiar deg2rad(phi)
siguiente manera:
t = 1:10800; % generate time vector
fs = 1; % sampling frequency (seconds)
A = 2; % amplitude
P = 1000; % period (seconds), the time it takes for the signal to repeat itself
f1 = 1/P; % number of cycles per second (i.e. how often the signal repeats itself every second).
y1 = A*sin(2*pi*f1*t); % signal 1
phi = deg2rad(10); % phase shift
y2 = A*sin(2*pi*f1*t + phi); % signal 2
phi = deg2rad(15); % phase shift
y3 = A*sin(2*pi*f1*t + phi); % signal 3
YY = [y1'',y2'',y3''];
plot(t,YY)
entonces utilizando el método de dominio de frecuencia como se menciona chipaudette
fft_y1 = fft(y1);
fft_y2 = fft(y2);
phase_rad = angle(fft_y1(1:end/2)/fft_y2(1:end/2));
phase_deg = rad2deg(angle(fft_y1(1:end/2)/fft_y2(1:end/2)));
ahora esto le dará una estimación de cambio de fase con error = +-0.2145
Con las señales correctas:
t = 1:10800; % generate time vector
fs = 1; % sampling frequency (seconds)
A = 2; % amplitude
P = 1000; % period (seconds), the time it takes for the signal to repeat itself
f1 = 1/P; % number of cycles per second (i.e. how often the signal repeats itself every second).
y1 = A*sin(2*pi*f1*t); % signal 1
phi = 10*pi/180; % phase shift in radians
y2 = A*sin(2*pi*f1*t + phi); % signal 2
phi = 15*pi/180; % phase shift in radians
y3 = A*sin(2*pi*f1*t + phi); % signal 3
Lo siguiente debería funcionar:
>> acos(dot(y1,y2)/(norm(y1)*norm(y2)))
>> ans*180/pi
ans = 9.9332
>> acos(dot(y1,y3)/(norm(y1)*norm(y3)))
ans = 0.25980
>> ans*180/pi
ans = 14.885
Si eso es lo suficientemente bueno o no para sus señales "reales", solo usted puede decirlo.
El código de Matlab para encontrar la fase relativa utilizando la correlación cruzada:
fr = 20; % input signal freq
timeStep = 1e-4;
t = 0:timeStep:50; % time vector
y1 = sin(2*pi*t); % reference signal
ph = 0.5; % phase difference to be detected in radians
y2 = 0.9 * sin(2*pi*t + ph); % signal, the phase of which, is to be measured relative to the reference signal
[c,lag]=xcorr(y1,y2); % calc. cross-corel-n
[maxC,I]=max(c); % find max
PH = (lag(I) * timeStep) * 2 * pi; % calculated phase in radians
>> PH
PH =
0.4995
Hay varias maneras de medir el desplazamiento de fase entre señales. Entre su respuesta, los comentarios debajo de su respuesta y las otras respuestas, ha obtenido la mayoría de las opciones. La elección específica de la técnica se basa generalmente en temas como:
- Ruidoso o limpio : ¿Hay ruido en su señal?
- Componente múltiple o componente único : ¿hay más de un tipo de señal dentro de su grabación (múltiples tonos en múltiples frecuencias que se mueven en diferentes direcciones)? O, ¿hay una sola señal, como en tu ejemplo de onda sinusoidal?
- Instantáneo o promediado : ¿Busca el promedio de desfase en toda su grabación o está buscando cómo cambia la fase a lo largo de la grabación?
Dependiendo de su respuesta a estas preguntas, podría considerar las siguientes técnicas:
Correlación cruzada : use el comando a como
[c,lag]=xcorr(y1,y2);
para obtener la correlación cruzada entre las dos señales. Esto funciona en las señales de dominio de tiempo originales.[maxC,I]=max(c);
el índice dondec
es máximo ([maxC,I]=max(c);
) y luego obtienes tu valor de retraso en unidades de muestraslag = lag(I);
. Este enfoque le da el retraso de fase promedio para toda la grabación. Requiere que su señal de interés en la grabación sea más fuerte que cualquier otra cosa en su grabación ... en otras palabras, es sensible al ruido y otras interferencias.Dominio de frecuencia : aquí convierte sus señales en el dominio de frecuencia (usando
fft
ocpsd
o lo que sea). Luego, encontrará el contenedor que corresponde a la frecuencia que le interesa y obtendrá el ángulo entre las dos señales. Entonces, por ejemplo, si bin # 18 corresponde a la frecuencia de su señal, obtendría el retardo de fase en radianes a través dephase_rad = angle(fft_y1(18)/fft_y2(18));
. Si sus señales tienen una frecuencia constante, este es un enfoque excelente porque, naturalmente, rechaza todo el ruido y la interferencia en otras frecuencias. Puede tener una interferencia realmente fuerte en una frecuencia, pero aún puede obtener limpiamente su señal en otra frecuencia. Esta técnica no es la mejor para señales que cambian de frecuencia durante la ventana de análisis FFT.Transformada de Hilbert : una tercera técnica, a menudo pasada por alto, es convertir su señal de dominio de tiempo en una señal analítica a través de la transformada de Hilbert:
y1_h = hilbert(y1);
. Una vez que haces esto, tu señal es un vector de números complejos. Un vector que contenga una onda sinusoidal simple en el dominio del tiempo ahora será un vector de números complejos cuya magnitud es constante y cuya fase está cambiando en sincronía con la onda sinusoidal original. Esta técnica le permite obtener el retraso de fase instantáneo entre dos señales ... es potente:phase_rad = angle(y1_h ./ y2_h);
ophase_rad = wrap(angle(y1_h) - angle(y2_h));
. La principal limitación de este enfoque es que su señal debe ser mono-componente, lo que significa que su señal de interés debe dominar su grabación. Por lo tanto, es posible que tenga que filtrar cualquier interferencia sustancial que pueda existir.
Para dos señales sinusoidales, la fase del coeficiente de correlación complejo le proporciona lo que desea. Solo puedo darte un ejemplo de python (usando scipy) ya que no tengo un matlab para probarlo.
x1 = sin( 0.1*arange(1024) )
x2 = sin( 0.1*arange(1024) + 0.456)
x1h = hilbert(x1)
x2h = hilbert(x2)
c = inner( x1h, conj(x2h) ) / sqrt( inner(x1h,conj(x1h)) * inner(x2h,conj(x2h)) )
phase_diff = angle(c)
Hay una función corrcoeff en matlab, que también debería funcionar (el pitón uno descarta la parte imaginaria). Es decir, c = corrcoeff (x1h, x2h) debería funcionar en matlab.