DSP

数字信号处理中的自相关和互相关计算和物理意义(二)

2019-07-13 17:00发布

在信号处理中,经常要研究两个信号的相似性,或者一个信号经过一段时间延迟后自身的相似性,以便实现信号检测、识别与提取等。 可用于研究信号相似性的方法称为相关,该方法的核心概念是相关函数和互相关函数

1 相关函数定义

无限能量信号,信号x(n)与y(n)的互相关函数定义为
等于将x(n)保持不动,y(n)左移m个抽样点后,两个序列逐点对应相乘的结果。
当x(n)与y(n)不是同一信号时,rxy中的x、y顺序是不能互换等价的。
当x(n)与y(n)为同一信号时,记
为信号x(n)的自相关函数在m时刻的值。自相关函数反映了x(n)和其自身发生m个采样点平移后的相似程度。 可以想象,当m=0时,即原信号不做任何平移,一一对应的叠加时rx(m)值最大,这个结论很重要。
对于有限能量信号或周期信号,设信号为复信号,自相关函数和互相关函数可表达为

注意: (1)m的取值范围可以从-(N-1)到(N-1),对于N点信号,rx共可计算得2N-1点相关函数结果值 (2)对于给定的m,因为实际信号总是有限长的N,所以要计算rx(m),n+m=N-1,因此实际写程序时注意n的实际可取长度为N-1-m (3)当m值越大时,对于N点有限长信号,可用于计算的信号长度越短,计算出的rx(n)性能越差,因此实际应用中常令m< (4)Matlab自带的xcorr函数可用于计算互相关,但计算结果是没有除以N的结果。

2 基于定义的相关函数计算

[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. /*  
  2.  * FileName : correl.c 
  3.  * Author   : xiahouzuoxin    xiahouzuoxin@163.com 
  4.  * Date     : 2014/2/16 
  5.  * Version  : v1.0 
  6.  * Compiler : gcc 
  7.  * Brief    :  
  8.  */  
  9. #include   
  10.   
  11. typedef struct {  
  12.     float real;  
  13.     float imag;  
  14. } complex;  
  15.   
  16.   
  17. static void assert_param(int32_t x)  
  18. {  
  19.   
  20. }  
  21.   
  22. /*--------------------------------------------------------------------- 
  23.   Routine CORRE1:To estimate the biased cross-correlation function 
  24.   of complex arrays x and y. If y=x,then it is auto-correlation. 
  25.   input parameters: 
  26.      x  :n dimensioned complex array. 
  27.      y  :n dimensioned complex array. 
  28.      n  :the dimension of x and y. 
  29.      lag:point numbers of correlation. 
  30.   output parameters: 
  31.      r  :lag dimensioned complex array, the correlation function is 
  32.          stored in r(0) to r(lag-1). 
  33. ---------------------------------------------------------------------*/  
  34. void corre1(complex x[],complex y[],complex r[],int n,int lag)  
  35. {  
  36.     int m,j,k,kk;  
  37.   
  38.     assert_param(lag >= 2*n-1);  
  39.   
  40.     for (k=n-1; k>0; k--) {  /* -(N-1)~0 PART */  
  41.         kk = n-1-k;  
  42.         r[kk].real = 0.0;  
  43.         r[kk].imag = 0.0;  
  44.         for (j=k; j
  45.             r[kk].real += y[j-k].real*x[j].real+y[j-k].imag*x[j].imag;  
  46.             r[kk].imag += y[j-k].imag*x[j].real-y[j-k].real*x[j].imag;  
  47.         }  
  48. //        r[kk].real=r[kk].real/n;  
  49. //        r[kk].imag=r[kk].imag/n;  
  50.     }  
  51.     for (k=0; k/* 0~(N-1) PART */  
  52.         kk = n-1+k;  
  53.         m = n-1-k;  
  54.         r[kk].real = 0.0;  
  55.         r[kk].imag = 0.0;  
  56.         for (j=0; j<=m; j++) {  
  57.             r[kk].real += y[j+k].real*x[j].real+y[j+k].imag*x[j].imag;  
  58.             r[kk].imag += y[j+k].imag*x[j].real-y[j+k].real*x[j].imag;  
  59.         }  
  60. //        r[kk].real=r[kk].real/n;  
  61. //        r[kk].imag=r[kk].imag/n;  
  62.     }  
  63.   
  64.     return;  
  65. }  
  66.   
  67. #define SIG_N    5  
  68. complex x[SIG_N];  
  69. complex y[SIG_N];  
  70. complex r[2*SIG_N-1];  
  71.   
  72. int main(void)  
  73. {  
  74.     int i = 0;  
  75.   
  76.     x[1].real = 1;  
  77.     x[2].real = 2;  
  78.     x[3].real = 3;  
  79.     x[4].real = 4;  
  80.     x[0].real = 5;  
  81.       
  82.     x[1].imag = 0;  
  83.     x[2].imag = 0;  
  84.     x[3].imag = 0;  
  85.     x[4].imag = 0;  
  86.     x[0].imag = 0;  
  87.   
  88.     y[1].real = 2;  
  89.     y[2].real = 4;  
  90.     y[3].real = 5;  
  91.     y[4].real = 6;  
  92.     y[0].real = 1;  
  93.   
  94.     y[1].imag = 0;  
  95.     y[2].imag = 0;  
  96.     y[3].imag = 0;  
  97.     y[4].imag = 0;  
  98.     y[0].imag = 0;  
  99.   
  100.     corre1(x,y,r,5,9);  
  101.   
  102.     for (i=0; i<2*SIG_N-1; i++) {  
  103.         printf("r[%d].real=%.2f, r[%d].imag=%.2f ", i, r[i].real, i, r[i].imag);  
  104.     }  
  105. }   
运行输出结果如下,
r[0].real=4.00, r[0].imag=0.00
r[1].real=11.00, r[1].imag=0.00
r[2].real=24.00, r[2].imag=0.00
r[3].real=37.00, r[3].imag=0.00
r[4].real=54.00, r[4].imag=0.00
r[5].real=42.00, r[5].imag=0.00
r[6].real=37.00, r[6].imag=0.00
r[7].real=31.00, r[7].imag=0.00
r[8].real=30.00, r[8].imag=0.00

从0~8依次存储的是m=-(N-1)到(N-1)的结果。为验证正确性,我们不妨用matlab自带的xcorr计算 >> y = [1 2 4 5 6]
y =
     1     2     4     5     6
>> x = [5 1 2 3 4]
x =
     5     1     2     3     4
>> xcorr(x,y)
ans =
   30.0000   31.0000   37.0000   42.0000   54.0000   37.0000   24.0000   11.0000    4.0000

结果一致,只是存储顺序相反。

3 使用FFT计算相关函数

采用暴力的按定义计算信号相关的方法的计算复杂度约O(N^2),当数据点数N很大时,尤其在DSP上跑时耗时过长,因此采用FFT和IFFT计算互相关函数显得尤为重要。 那么,互相关函数与FFT之间又是一种什么样的关系呢? 设y(n)是x(n)与h(n)的互相关函数,
则,
诶,这不对啊,不是说两个信号时域的卷积才对应频域的乘积吗?难道时域的互相关和时域的卷积等价了不成?? 这里说明下,通过推倒可以得到,相关于卷积的关系满足:
不管如何,与直接卷积相差一个负号。这时,看清楚了,相关函数在频域也不完全是乘积,是一个信号的共轭再与原信号乘积,这就是与“时域卷积频域相乘不同的地方”。 所以,请记住这个有用的结论, 两个信号的互相关函数的频域等于X信号频域的共轭乘以Y信号的频域
我们就有计算互相关的新方法了:将信号x(n)和h(n)都进行FFT,将FFT的结果相乘计算得互相关函数的FFT,在进行逆变换IFFT得到互相关函数y(m)。 [cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. typedef complex TYPE_CORREL;  
  2.   
  3. /* 
  4.  * @brief  To estimate the biased cross-correlation function 
  5.  *   of TYPE_CORREL arrays x and y.  
  6.  *   the result will store in x, size of x must be >=2*m 
  7.  * @input params  
  8.      x : n dimensioned TYPE_CORREL array.  
  9.      y : n dimensioned TYPE_CORREL array. 
  10.      m : the dimension of x and y.     
  11.      n : point numbers of correlation. 
  12.      icorrel: icorrel=1, cross-correlation; icorrel=0, auto-correlation 
  13.  * @retval None 
  14.  * 
  15.  * ==== 
  16.  * TEST OK 2013.01.14 
  17.  */  
  18. void zx_xcorrel(TYPE_CORREL x[], TYPE_CORREL y[], int m, int n, int icorrel)  
  19. {  
  20.     int s,k;  
  21.     TYPE_CORREL z;  
  22.   
  23.     assert_param(n >= 2*m);  
  24.   
  25.     /* n must be power of 2 */  
  26.     s = n;  
  27.     do {  
  28.         s = s >> 1;  
  29.         k = s - 2;  
  30.     } while (k > 0);  
  31.     if (k<0) return;  
  32.   
  33.     /* Padding 0 */  
  34.     for (k=m; k
  35.         x[k].real = 0.;  
  36.         x[k].imag = 0.0f;  
  37.     }  
  38.     fft(x, n);  
  39.         
  40.     if (1 == icorrel) {    
  41.         /* Padding 0 */  
  42.         for (k=m; k
  43.             y[k].real = 0.;  
  44.             y[k].imag = 0.0f;  
  45.         }  
  46.         fft(y, n);  
  47.   
  48.         /* conjuction */  
  49.         for (k=0; k
  50.             z.real = x[k].real;   
  51.             z.imag = x[k].imag;  
  52.             x[k].real = (z.real*y[k].real + z.imag*y[k].imag)/(float)m;  
  53.             x[k].imag = (z.real*y[k].imag - z.imag*y[k].real)/(float)m;  
  54.         }   
  55.     } else {  
  56.         for (k=0; k
  57.             x[k].real = (x[k].real*x[k].real+x[k].imag*x[k].imag) / (float)(m);  
  58.             x[k].imag = 0.0f;  
  59.         }  
  60.     }  
  61.   
  62.     ifft(x, n);  
  63.   
  64.     return;     
  65. }  

FFT的程序参考本博客内博文FFT算法的完整DSP实现。 Matlab中自带的xcorr也是通过FFT实现的互相关函数计算,这将互相关函数计算的复杂度降低到

4 应用

互相关函数有许多实际的用途,比如通过不同的传感器检测不同方向到达的声音信号,通过对不同方位传感器间的信号进行互相关可计算声音到达不同传感器间的时延。自相关函数还可以用来计算周期信号的周期。对此,有时间将还会对此进行详细研究。

参考资料

[1] 《数字信号处理——理论、算法与实现》,胡广书
[2]  刘永春,陈琳. 基于广义互相关时延估计算法声源定位的研究.
[3]  金中薇,姜明顺等. 基于广义互相关时延估计算法的声发射定位技术. 传感技术学报. 第26卷11期,2013年11月.