[導讀] 在工程應用時,有時候需要計算兩個信號序列的相似度,實際信號由於在採集過程中會混入干擾,如果簡單的依次比較各樣本是否相等或者差值,則很難判定兩個信號序列的相似程度。本文來聊聊我的一些思路。
什麼是互相關函數?
在統計學中,相關是描述兩個隨機變量序列或二元數據之間的統計關係,無論是否具有因果關係。廣義上講,相關性是統計上的關聯程度,它通常指的是兩個變量的線性相關的程度。比如商品的價格和消費者購買願意數量之間的關係,也即所謂的需求曲線。
相關性是有用的,因爲它們可以描述一種可在實踐中加以利用的預測作用。例如,根據電力需求和天氣之間的相關性,電力公司可能會在天氣涼快時候生產更少的電力。在這個例子中,有一定的因果關係存在,因爲極端天氣導致人們使用更多的電力用於取暖或製冷。然而,一般而言,相關性的存在並不足以推斷出因果關係的存在,也就是說相關性並不意味着因果關係。
連續信號裏,爲函數及的互相關函數定義爲:
ρ
x
y
=
∫
−
∞
∞
f
x
(
t
)
f
y
(
t
−
τ
)
d
t
\rho_{xy}=\int_{-\infty}^{\infty }f_x(t)f_y(t-\tau)dt
ρxy=∫−∞∞fx(t)fy(t−τ)dt
離散信號,假設兩個信號序列x(n)及y(n),每個序列的能量都是有限能量序列,則x(n)及y(n)的互相關序列爲:
ρ
x
y
=
∑
−
∞
∞
x
(
n
)
y
(
n
−
l
)
\rho_{xy}=\sum_{-\infty}^{\infty}x(n)y(n-l)
ρxy=−∞∑∞x(n)y(n−l)
那麼互相關函數就是描述在連續信號或離散序列的相關程度的一種統計度量。
什麼是相關係數?
最熟悉的度量兩個量之間的相關性的方法是皮爾遜乘積矩相關係數(PPMCC),也稱爲“皮爾遜相關係數”,通常簡稱爲“相關係數”。在數學上,它被定義爲對原始數據的最小二乘擬合的質量(擬合程度或效果)。它是由數據集兩個變量的協方差的比率,歸一化到他們的方差的平方根得到的。數學上,兩個變量的協方差除以標準差的乘積。
皮爾遜積矩相關係數試圖通過兩個隨機序列的數據集建立一條最佳擬合曲線,實質上是通過列出期望和由此產生的皮爾遜相關係數表明實際數據集離預期值有多遠。根據皮爾遜相關係數的符號,如果數據集的變量之間存在某種關係,可以得到負相關或正相關。其定義公式如下:
ρ
x
y
=
c
o
r
r
(
X
,
Y
)
=
c
o
v
(
X
,
Y
)
σ
X
σ
Y
\rho_{xy}=corr(X,Y)=\frac{cov(X,Y)}{{\sigma_{X}}{\sigma_{Y}}}
ρxy=corr(X,Y)=σXσYcov(X,Y)
上述公式展開爲:
ρ
x
y
=
E
[
(
X
−
X
‾
)
(
Y
−
Y
‾
)
]
σ
X
σ
Y
\rho_{xy}=\frac{E[(X-\overline{X})(Y-\overline{Y})]}{{\sigma_{X}}{\sigma_{Y}}}
ρxy=σXσYE[(X−X)(Y−Y)]
在根據期望計算公式展開,就得到:
ρ
x
y
=
∑
i
=
1
n
[
x
(
i
)
−
x
‾
]
∗
[
y
(
i
)
−
y
‾
]
∑
i
=
1
n
[
x
(
i
)
−
x
‾
]
2
∑
i
=
1
n
[
y
(
i
)
−
y
‾
]
2
\rho_{xy}=\frac{\sum_{i=1}^{n}[x(i)-\overline{x}]\ast[y(i)-\overline{y}]}{\sqrt{\sum_{i=1}^{n}[x(i)-\overline{x}]^2}\sqrt{\sum_{i=1}^{n}[y(i)-\overline{y}]^2}}
ρxy=∑i=1n[x(i)−x]2∑i=1n[y(i)−y]2∑i=1n[x(i)−x]∗[y(i)−y]
如果考察延遲d處的互相關
ρ
x
y
\rho_{xy}
ρxy,則上述公式就變爲:
ρ
x
y
=
∑
i
=
1
n
[
x
(
i
)
−
x
‾
]
∗
[
y
(
i
−
d
)
−
y
‾
]
∑
i
=
1
n
[
x
(
i
)
−
x
‾
]
2
∑
i
=
1
n
[
y
(
i
−
d
)
−
y
‾
]
2
\rho_{xy}=\frac{\sum_{i=1}^{n}[x(i)-\overline{x}]\ast[y(i-d)-\overline{y}]}{\sqrt{\sum_{i=1}^{n}[x(i)-\overline{x}]^2}\sqrt{\sum_{i=1}^{n}[y(i-d)-\overline{y}]^2}}
ρxy=∑i=1n[x(i)−x]2∑i=1n[y(i−d)−y]2∑i=1n[x(i)−x]∗[y(i−d)−y]
爲了方便理解,本文就不考察延遲節拍了。
相關係數有啥用?
皮爾遜相關係數的絕對值不大於1是Cauchy–Schwarz不等式的推論(有興趣的可以去找書看看)。因此,相關係數的值在[-1,1]之間。在理想的增加線性相關關係情況下,相關係數爲+1;在理想的減少(反相關)線性關係情況下,相關係數爲-1;在所有其他取值情況下,表示變量之間的線性相關程度。當它接近零時,更接近於不相關。係數越接近-1或1,變量之間的相關性越強。
故,相關係數其值範圍分佈在區間[-1,1]:
- 1表示完全正相關
- 0表示不相關
- -1表示完全負相關
爲了方便理解,假定兩個隨機序列按照下面各類情況分佈,下面的數字爲相關係數:
程序如何實現呢?
上述公式在實際編程時,當然可以直接按照公式編制代碼,如果仔細觀察會發現該公式可以進一步簡化,過程省略:
ρ
x
y
=
n
∑
x
i
y
i
−
∑
x
i
∑
y
i
[
n
∑
x
i
2
−
(
∑
x
i
)
2
]
[
n
∑
y
i
2
−
(
∑
y
i
)
2
]
\rho_{xy}=\frac{n\sum x_iy_i-\sum x_i\sum y_i}{\sqrt{[n\sum x_i^2-(\sum x_i)^2][n\sum y_i^2-(\sum y_i)^2]}}
ρxy=[n∑xi2−(∑xi)2][n∑yi2−(∑yi)2]n∑xiyi−∑xi∑yi
由這個公式就很容易編程了,乾貨在這裏,可以拿去稍加改造即可使用:
#include <stdio.h>
#include <math.h>
/* 返回值在區間: [-1,1] */
/* 如返回-10,則證明輸入參數無效 */
#define delta 0.0001f
double calculate_corss_correlation(double *s1, double *s2,int n)
{
double sum_s12 = 0.0;
double sum_s1 = 0.0;
double sum_s2 = 0.0;
double sum_s1s1 = 0.0; //s1^2
double sum_s2s2 = 0.0; //s2^2
double pxy = 0.0;
double temp1 = 0.0;
double temp2 = 0.0;
if( s1==NULL || s2==NULL || n<=0)
return -10;
for(int i=0;i<n;i++)
{
sum_s12 += s1[i]*s2[i];
sum_s1 += s1[i];
sum_s2 += s2[i];
sum_s1s1 += s1[i]*s1[i];
sum_s2s2 += s2[i]*s2[i];
}
temp1 = n*sum_s1s1-sum_s1*sum_s1;
temp2 = n*sum_s2s2-sum_s2*sum_s2;
/* 分母不可爲0 */
if( (temp1>-delta && temp1<delta) ||
(temp2>-delta && temp2<delta) ||
(temp1*temp2<=0) )
{
return -10;
}
pxy = (n*sum_s12-sum_s1*sum_s2)/sqrt(temp1*temp2);
return pxy;
}
double s1[30] = {
0.309016989,0.587785244,0.809016985,0.95105651,1,0.951056526,
0.809017016,0.587785287,0.30901704,5.35898E-08,0,0,
0,0,0,0,0,0,
0,0,0,0,0,0,
0,0,0,0,0,0
};
double s2[30] = {
0.343282816,0.686491368,0.874624132,0.99459642,1.008448609,
1.014252458,0.884609221,0.677632906,0.378334666,0.077878732,
0.050711886,0.066417083,0.088759401,0.005440732,0.04225661,
0.035349939,0.0631196,0.007566056,0.053183895,0.073143706,
0.080285063,0.030110227,0.044781145,0.01875573,0.08373928,
0.04550342,0.038880858,0.040611891,0.046116826,0.087670453
};
int main(void)
{
double pxy;
double s3[30];
pxy = calculate_corss_correlation(s1,s2,30);
printf("pxy of s1 and s2:%f\n",pxy);
pxy = calculate_corss_correlation(s1,s1,30);
printf("pxy of s1 and s1:%f\n",pxy);
for(int i=0;i<n;i++)
{
s3[i] = -1*s1[i];
}
pxy = calculate_corss_correlation(s1,s3,30);
printf("pxy of s1 and s3:%f\n",pxy);
return 0;
}
運行結果爲:
pxy of s1 and s2:0.997435
pxy of s1 and s1:1.000000
pxy of s1 and s1:-1.000000
將這三個信號繪製成波形來看看:
由圖看出:
- S1與S2非常相似,其相關係數爲0.997435,高度相似
- S1與-S1則剛好相位相反,理想反相關,其相關係數爲-1
- S1與S1則理所當然是一樣的,其相關係數爲1
再來一組信號對比一下:
其波形數據爲:
double s1[30]={
0.309016989,0.587785244,0.809016985,0.95105651,1,
0.951056526,0.809017016,0.587785287,0.30901704,5.35898E-08,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
};
double s6[30]={
0,0,0.187381311,0.368124547,0.535826787,
0.684547097,0.809016985,0.904827044,0.968583156,0.998026727,
0.992114705,0.951056526,0,0,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
};
double s7[30]={
0.187381311,0.368124547,0.535826787,0.684547097,0.809016985,
0.904827044,0.968583156,0.998026727,0.992114705,0.951056526,
0.876306697,0.770513267,0.637424022,0.481753714,0,
0,0,0,0,0,
0,0,0,0,0,
0,0,0,0,0
};
測試計算其相關係數:
pxy of s1 and s6:0.402428
pxy of s1 and s7:0.612618
可見,S6、S7與S1的相關係數越來越大,從波形上看相似度也越來越大。
總結一下
通過相關係數可以比較完美的判斷兩個信號序列,或者兩個隨機變量之間的相似度。相關係數以及互相關函數應用很廣,本文僅僅描述了一個工程上應用較多的實際栗子。事實上,該數學特性有着廣泛的應用,有興趣的可以深度學習探討一下。