J'ai généré trois ondes identiques avec un déphasage dans chacune. Par exemple:
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)
J'aimerais maintenant utiliser une méthode pour détecter ce déphasage entre les ondes. Le but de cette opération est que je puisse éventuellement appliquer la méthode à des données réelles et identifier les décalages de phase entre les signaux.
Jusqu'à présent, je pensais calculer les spectres croisés entre chaque onde et la première onde (c'est-à-dire sans le déphasage):
for i = 1:3;
[Pxy,Freq] = cpsd(YY(:,1),YY(:,i));
coP = real(Pxy);
quadP = imag(Pxy);
phase(:,i) = atan2(coP,quadP);
end
mais je ne suis pas sûr que cela ait un sens.
Quelqu'un a-t-il fait quelque chose de semblable à cela? Le résultat souhaité doit montrer un déphasage à 10 et 15 pour les vagues 2 et 3 respectivement.
Tout avis sera le bienvenu.
Il existe plusieurs façons de mesurer le déphasage entre les signaux. Entre votre réponse, les commentaires sous votre réponse et les autres réponses, vous avez la plupart des options. Le choix spécifique de la technique est généralement basé sur des questions telles que:
Selon votre réponse à ces questions, vous pouvez envisager les techniques suivantes:
Corrélation croisée : Utilisez la commande a telle que [c,lag]=xcorr(y1,y2);
pour obtenir la corrélation croisée entre les deux signaux. Cela fonctionne sur les signaux d'origine du domaine temporel. Vous recherchez l'index où c
est maximal ([maxC,I]=max(c);
), puis vous obtenez votre valeur de décalage en unités d'échantillons lag = lag(I);
. Cette approche vous donne le décalage de phase moyen pour tout l'enregistrement. Cela nécessite que votre signal d’intérêt pour l’enregistrement soit plus fort que tout autre élément de votre enregistrement ... en d’autres termes, il est sensible au bruit et à d’autres interférences.
Domaine de fréquence : Ici, vous convertissez vos signaux dans le domaine de fréquence (en utilisant fft
ou cpsd
ou autre). Ensuite, vous trouverez le bac qui correspond à la fréquence qui vous tient à cœur et l’angle entre les deux signaux. Ainsi, par exemple, si la case n ° 18 correspond à la fréquence de votre signal, vous obtiendrez le décalage de phase en radians via phase_rad = angle(fft_y1(18)/fft_y2(18));
. Si vos signaux ont une fréquence constante, il s'agit d'une excellente approche car elle rejette naturellement tous les bruits et les interférences des autres fréquences. Vous pouvez avoir des interférences très fortes à une fréquence, mais vous pouvez toujours obtenir votre signal proprement à une autre fréquence. Cette technique n'est pas la meilleure pour les signaux qui changent de fréquence pendant la fenêtre d'analyse fft.
Hilbert Transform : Une troisième technique, souvent négligée, consiste à convertir votre signal de domaine temporel en un signal analytique via la transformation de Hilbert: y1_h = hilbert(y1);
. Une fois que vous faites cela, votre signal est un vecteur de nombres complexes. Un vecteur contenant une onde sinusoïdale simple dans le domaine temporel sera désormais un vecteur de nombres complexes dont la magnitude est constante et dont la phase change en même temps que votre onde sinusoïdale d'origine. Cette technique vous permet d’obtenir le décalage de phase instantané entre deux signaux ... c’est puissant: phase_rad = angle(y1_h ./ y2_h);
ou phase_rad = wrap(angle(y1_h) - angle(y2_h));
. La principale limite de cette approche est que votre signal doit être mono-composant, ce qui signifie que votre signal d’intérêt doit dominer votre enregistrement. Par conséquent, vous devrez peut-être filtrer toute interférence substantielle pouvant exister.
Pour deux signaux sinusoïdaux, la phase du coefficient de corrélation complexe vous donne ce que vous voulez. Je ne peux que vous donner un exemple en python (avec scipy) car je n'ai pas de matlab pour le tester.
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)
Il existe une fonction corrcoeff dans matlab, qui devrait également fonctionner (le python élimine la partie imaginaire). C'est à dire. c = corrcoeff (x1h, x2h) devrait fonctionner dans matlab.
Le code Matlab pour trouver la phase relative en utilisant une corrélation croisée:
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
Avec les bons signaux:
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
Ce qui suit devrait fonctionner:
>> 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
Que ce soit suffisant ou non pour vos "vrais" signaux, vous seul pouvez le savoir.
Voici la petite modification de votre code: phi = 10
est en fait en degré, puis en fonction sine, les informations de phase sont principalement exprimées en radian. Vous devez donc modifier deg2rad(phi)
comme suit:
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)
puis en utilisant la méthode du domaine fréquentiel comme chipaudette mentionné
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)));
maintenant cela vous donnera une estimation de déphasage avec error = +-0.2145