それぞれに位相シフトのある3つの同一の波を生成しました。例えば:
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)
この波間の位相シフトを検出する方法を使用したいと思います。これを行うポイントは、最終的にメソッドを実際のデータに適用し、信号間の位相シフトを特定できるようにするためです。
これまで、各波と最初の波の間のクロススペクトルを計算することを考えていました(つまり、位相シフトなし):
for i = 1:3;
[Pxy,Freq] = cpsd(YY(:,1),YY(:,i));
coP = real(Pxy);
quadP = imag(Pxy);
phase(:,i) = atan2(coP,quadP);
end
しかし、これが意味をなすかどうかはわかりません。
他の誰かがこれに似た何かをしましたか?望ましい結果は、それぞれ波2と3に対して10と15の位相シフトを示すはずです。
アドバイスをいただければ幸いです。
信号間の位相シフトを測定する方法はいくつかあります。回答、回答の下のコメント、およびその他の回答の間に、ほとんどのオプションがあります。テクニックの特定の選択は通常、次のような問題に基づいています。
これらの質問に対する回答に応じて、次の手法を検討できます。
相互相関:[c,lag]=xcorr(y1,y2);
などのコマンドを使用して、2つの信号間の相互相関を取得します。これは、元の時間領域信号で機能します。 c
が最大([maxC,I]=max(c);
)であるインデックスを探し、サンプルlag = lag(I);
の単位でラグ値を取得します。このアプローチにより、記録全体の平均位相遅れが得られます。録音に関心のある信号は、録音の他のどの信号よりも強いことが必要です。つまり、ノイズやその他の干渉に敏感です。
周波数領域:ここで、信号を周波数領域に変換します(fft
またはcpsd
などを使用)。次に、関心のある周波数に対応するビンを見つけ、2つの信号間の角度を取得します。したがって、たとえば、ビン#18が信号の周波数に対応する場合、phase_rad = angle(fft_y1(18)/fft_y2(18));
を介してラジアン単位で位相遅れを取得します。信号の周波数が一定の場合、これは他の周波数のすべてのノイズと干渉を自然に拒否するため、優れたアプローチです。 1つの周波数で非常に強い干渉を受ける可能性がありますが、別の周波数で信号をきれいに取得できます。この手法は、fft解析ウィンドウで周波数が変化する信号には最適ではありません。
Hilbert Transform:見落とされることが多い3番目の手法は、Hilbert変換を介して時間領域信号を分析信号に変換することです:y1_h = hilbert(y1);
。これを行うと、信号は複素数のベクトルになります。時間領域で単純な正弦波を保持するベクトルは、大きさが一定で、元の正弦波と同期して位相が変化する複素数のベクトルになります。この手法を使用すると、2つの信号間の瞬間的な位相遅れを取得できます。これは強力です:phase_rad = angle(y1_h ./ y2_h);
またはphase_rad = wrap(angle(y1_h) - angle(y2_h));
。このアプローチの主な制限は、信号が単一成分である必要があることです。つまり、目的の信号が録音を支配する必要があります。したがって、存在する可能性のある実質的な干渉を除外する必要がある場合があります。
2つの正弦波信号の場合、複素相関係数の位相によって必要なものが得られます。私はそれをテストするためのMatlabを持っていないので、pythonの例(scipyを使用して)を与えることができます。
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)
Matlabには関数corrcoeffがあり、これも動作するはずです(python oneは虚数部を破棄します)。つまり、c = corrcoeff(x1h、x2h)はmatlabで動作するはずです。
相互相関を使用して相対位相を見つけるMatlabコード:
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
正しい信号で:
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
以下が機能するはずです。
>> 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
それがあなたの「本当の」信号に十分であるかどうか、あなただけが知ることができます。
コードの小さな変更は次のとおりです。phi = 10
は実際には度数です。正弦関数では、位相情報はほとんどラジアンで表されるため、次のようにdeg2rad(phi)
を変更する必要があります。
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)
次に、言及されたチップオーデットとして周波数領域法を使用します
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)));
これで、error = +-0.2145
を使用した位相シフトの推定値が得られます