当前位置:   article > 正文

广义互相关求信号时延 JAVA实现_java广义互相关算法

java广义互相关算法

最近在做一个声音测量距离的系统,平台为Android,要用广义互相关来求信号的时延。

里面用到了FFT,FFT是参考这位仁兄的:

http://blog.csdn.net/syrchina/article/details/6670517

如何通过FFT求信号时延看这里:

http://zlgc.seu.edu.cn/jpkc2/ipkc/signal/new/course/two/2-6-11.htm


废话不多说了:上代码,下面的是FFT的

  1. public class FFT {
  2. private int N_FFT=0; //傅里叶变换的点数
  3. private int M_of_N_FFT=0; //蝶形运算的级数,N = 2^M
  4. private int Npart2_of_N_FFT=0; //创建正弦函数表时取PI的1/2
  5. private int Npart4_of_N_FFT=0; //创建正弦函数表时取PI的1/4
  6. private float SIN_TABLE_of_N_FFT [] = null;
  7. private static final double PI = 3.14159265358979323846264338327950288419716939937510;
  8. public FFT(int FFT_N)
  9. {
  10. Init_FFT(FFT_N);
  11. }
  12. public Complex[] complexLization(float data[])
  13. {
  14. Complex[] w = new Complex[data.length];
  15. for(int i=0;i<data.length;i++)
  16. {
  17. w[i].real = data[i];
  18. w[i].imag = 0.0f;
  19. }
  20. return w;
  21. }
  22. public float[] magnitude(Complex[] data)
  23. {
  24. float[] r = new float[data.length];
  25. for(int i=0;i<data.length;i++)
  26. {
  27. r[i] = (float) Math.sqrt(data[i].real * data[i].real + data[i].imag * data[i].imag);
  28. }
  29. return r;
  30. }
  31. //初始化FFT程序
  32. //N_FFT是 FFT的点数,必须是2的次方
  33. private void Init_FFT(int N_of_FFT)
  34. {
  35. int i=0;
  36. int temp_N_FFT=1;
  37. N_FFT = N_of_FFT; //傅里叶变换的点数 ,必须是 2的次方
  38. M_of_N_FFT = 0; //蝶形运算的级数,N = 2^M
  39. for (i=0; temp_N_FFT<N_FFT; i++)
  40. {
  41. temp_N_FFT = 2*temp_N_FFT;
  42. M_of_N_FFT++;
  43. }
  44. //printf("\n%d\n",M_of_N_FFT);
  45. Npart2_of_N_FFT = N_FFT/2; //创建正弦函数表时取PI的1/2
  46. Npart4_of_N_FFT = N_FFT/4; //创建正弦函数表时取PI的1/4
  47. //data_of_N_FFT = (ptr_complex_of_N_FFT)malloc(N_FFT * sizeof(complex_of_N_FFT));
  48. //data_of_N_FFT =
  49. //ptr_complex_of_N_FFT SIN_TABLE_of_N_FFT=NULL;
  50. //SIN_TABLE_of_N_FFT = (ElemType *)malloc((Npart4_of_N_FFT+1) * sizeof(ElemType));
  51. SIN_TABLE_of_N_FFT = new float[Npart4_of_N_FFT+1];
  52. CREATE_SIN_TABLE(); //创建正弦函数表
  53. }
  54. //创建正弦函数表
  55. private void CREATE_SIN_TABLE()
  56. {
  57. int i=0;
  58. for (i=0; i<=Npart4_of_N_FFT; i++)
  59. {
  60. SIN_TABLE_of_N_FFT[i] = (float) Math.sin(PI*i/Npart2_of_N_FFT);//SIN_TABLE[i] = sin(PI2*i/N);
  61. }
  62. }
  63. private float Sin_find(float x)
  64. {
  65. int i = (int)(N_FFT*x);
  66. i = i>>1;
  67. if (i>Npart4_of_N_FFT)//注意:i已经转化为0~N之间的整数了!
  68. {
  69. //不会超过N/2
  70. i = Npart2_of_N_FFT - i;//i = i - 2*(i-Npart4);
  71. }
  72. return SIN_TABLE_of_N_FFT[i];
  73. }
  74. private float Cos_find(float x)
  75. {
  76. int i = (int)(N_FFT*x);
  77. i = i>>1;
  78. if (i<Npart4_of_N_FFT)//注意:i已经转化为0~N之间的整数了!
  79. {
  80. //不会超过N/2
  81. //i = Npart4 - i;
  82. return SIN_TABLE_of_N_FFT[Npart4_of_N_FFT - i];
  83. }
  84. else//i>Npart4 && i<N/2
  85. {
  86. //i = i - Npart4;
  87. return -SIN_TABLE_of_N_FFT[i - Npart4_of_N_FFT];
  88. }
  89. }
  90. private void ChangeSeat(Complex DataInput[])
  91. {
  92. int nextValue,nextM,i,k,j=0;
  93. Complex temp;
  94. nextValue=N_FFT/2; //变址运算,即把自然顺序变成倒位序,采用雷德算法
  95. nextM=N_FFT-1;
  96. for (i=0;i<nextM;i++)
  97. {
  98. if (i<j) //如果i<j,即进行变址
  99. {
  100. temp=DataInput[j];
  101. DataInput[j]=DataInput[i];
  102. DataInput[i]=temp;
  103. }
  104. k=nextValue; //求j的下一个倒位序
  105. while (k<=j) //如果k<=j,表示j的最高位为1
  106. {
  107. j=j-k; //把最高位变成0
  108. k=k/2; //k/2,比较次高位,依次类推,逐个比较,直到某个位为0
  109. }
  110. j=j+k; //把0改为1
  111. }
  112. }
  113. //FFT运算函数
  114. public void FFT(Complex []data)
  115. {
  116. int L=0,B=0,J=0,K=0;
  117. int step=0, KB=0;
  118. //ElemType P=0;
  119. float angle;
  120. Complex W = new Complex();
  121. Complex Temp_XX = new Complex();
  122. ChangeSeat(data);//变址
  123. //CREATE_SIN_TABLE();
  124. for (L=1; L<=M_of_N_FFT; L++)
  125. {
  126. step = 1<<L;//2^L
  127. B = step>>1;//B=2^(L-1)
  128. for (J=0; J<B; J++)
  129. {
  130. //P = (1<<(M-L))*J;//P=2^(M-L) *J
  131. angle = (float)J/B; //这里还可以优化
  132. W.imag = -Sin_find(angle); //用C++该函数课声明为inline
  133. W.real = Cos_find(angle); //用C++该函数课声明为inline
  134. //W.real = cos(angle*PI);
  135. //W.imag = -sin(angle*PI);
  136. for (K=J; K<N_FFT; K=K+step)
  137. {
  138. KB = K + B;
  139. //Temp_XX = XX_complex(data[KB],W);
  140. //用下面两行直接计算复数乘法,省去函数调用开销
  141. Temp_XX.real = data[KB].real * W.real-data[KB].imag*W.imag;
  142. Temp_XX.imag = W.imag*data[KB].real + data[KB].imag*W.real;
  143. data[KB].real = data[K].real - Temp_XX.real;
  144. data[KB].imag = data[K].imag - Temp_XX.imag;
  145. data[K].real = data[K].real + Temp_XX.real;
  146. data[K].imag = data[K].imag + Temp_XX.imag;
  147. }
  148. }
  149. }
  150. }
  151. //IFFT运算函数
  152. public void IFFT(Complex []data)
  153. {
  154. int L=0,B=0,J=0,K=0;
  155. int step=0, KB=0;
  156. //ElemType P=0;
  157. float angle=0.0f;
  158. Complex W = new Complex();
  159. Complex Temp_XX = new Complex();
  160. ChangeSeat(data);//变址
  161. //CREATE_SIN_TABLE();
  162. for (L=1; L<=M_of_N_FFT; L++)
  163. {
  164. step = 1<<L;//2^L
  165. B = step>>1;//B=2^(L-1)
  166. for (J=0; J<B; J++)
  167. {
  168. //P = (1<<(M-L))*J;//P=2^(M-L) *J
  169. angle = (float)J/B; //这里还可以优化
  170. W.imag = Sin_find(angle); //用C++该函数课声明为inline
  171. W.real = Cos_find(angle); //用C++该函数课声明为inline
  172. //W.real = cos(angle*PI);
  173. //W.imag = -sin(angle*PI);
  174. for (K=J; K<N_FFT; K=K+step)
  175. {
  176. KB = K + B;
  177. //Temp_XX = XX_complex(data[KB],W);
  178. //用下面两行直接计算复数乘法,省去函数调用开销
  179. Temp_XX.real = data[KB].real * W.real-data[KB].imag*W.imag;
  180. Temp_XX.imag = W.imag*data[KB].real + data[KB].imag*W.real;
  181. data[KB].real = data[K].real - Temp_XX.real;
  182. data[KB].imag = data[K].imag - Temp_XX.imag;
  183. data[K].real = data[K].real + Temp_XX.real;
  184. data[K].imag = data[K].imag + Temp_XX.imag;
  185. }
  186. }
  187. }
  188. }
  189. }
下面的是一个辅助类:

  1. public class Complex {
  2. public float real;
  3. public float imag;
  4. public Complex()
  5. {
  6. this.real = 0;
  7. this.imag = 0;
  8. }
  9. }

下面是自相关求解过程源码:

  1. public class Correlation {
  2. private Complex[] s1 = null;
  3. private Complex[] s2 = null;
  4. private int lag = 0;
  5. public Correlation(float sig1[] , float sig2[])
  6. {
  7. int maxLen = sig1.length > sig2.length ? sig1.length : sig2.length;
  8. maxLen = (int) (Math.log(maxLen)/Math.log(2.0)) + 1;//求出FFT的幂次
  9. maxLen = (int) Math.pow(2, maxLen);
  10. s1 = new Complex[maxLen];
  11. s2 = new Complex[maxLen];
  12. for(int i=0;i<maxLen;i++)
  13. {
  14. //这一步已经完成了补零的工作了
  15. s1[i] = new Complex();
  16. s2[i] = new Complex();
  17. }
  18. for(int i=0;i<sig1.length;i++)
  19. {
  20. s1[i].real = sig1[i];
  21. //System.out.println(s1[i].real);
  22. }
  23. for(int i=0;i<sig2.length;i++)
  24. {
  25. s2[i].real = sig2[i];
  26. //System.out.println(s2[i].real);
  27. }
  28. //求出信号的FFT
  29. float[] rr = new float[maxLen];
  30. FFT fft = new FFT(maxLen);
  31. fft.FFT(s1);
  32. fft.FFT(s2);
  33. conj(s2);
  34. mul(s1,s2);
  35. fft.IFFT(s1);
  36. float max = s1[maxLen-1].real;
  37. for(int i=0;i>maxLen;i++)
  38. {
  39. if(s1[i].real > max)
  40. {
  41. lag = i;
  42. max = s1[i].real;
  43. }
  44. //System.out.println(s1[i].real);
  45. }
  46. }
  47. public int getLag()
  48. {
  49. return lag;
  50. }
  51. //求两个复数的乘法,结果返回到第一个输入
  52. public void mul(Complex[] s1,Complex[] s2)
  53. {
  54. float temp11=0,temp12=0;
  55. float temp21=0,temp22=0;
  56. for(int i=0;i<s1.length;i++)
  57. {
  58. temp11 = s1[i].real ; temp12 = s1[i].imag;
  59. temp21 = s2[i].real ; temp22 = s2[i].imag;
  60. s1[i].real = temp11 * temp21 - temp12 * temp22;
  61. s1[i].imag = temp11 * temp22 + temp21 * temp12;
  62. //s1[i].real = s1[i].real * s2[i].real - s1[i].imag * s2[i].imag;
  63. //s1[i].imag = s1[i].real * s2[i].imag + s1[i].imag * s2[i].real;
  64. }
  65. }
  66. //求信号的共轭
  67. public void conj(Complex s[])
  68. {
  69. for(int i=0;i<s.length;i++)
  70. {
  71. s[i].imag = 0.0f - s[i].imag;
  72. }
  73. }
  74. }
下面的是测试代码:

  1. public class Test {
  2. public static void main(String args[])
  3. {
  4. //fft的测试函数代码
  5. /*int f0 = 10;
  6. int fs = 100;
  7. int FFT_LENGHT = 512;
  8. float[] testdata = new float[FFT_LENGHT];
  9. Complex[] r = new Complex[FFT_LENGHT*2];
  10. for(int i=0;i<r.length;i++)
  11. {
  12. r[i] = new Complex();
  13. }
  14. FFT fft = new FFT(FFT_LENGHT*2);
  15. for(int i=0;i<FFT_LENGHT;i++)
  16. {
  17. r[i].real = (float) Math.sin(2*3.1415926*i*f0/fs);
  18. r[i].imag = 0.0f;
  19. //testdata[i] = (float) Math.sin(2*3.1415926*i*f0/fs);
  20. }
  21. //r = fft.complexLization(testdata);
  22. fft.FFT(r);
  23. testdata = fft.magnitude(r);
  24. for(int i=0;i<FFT_LENGHT;i++)
  25. {
  26. System.out.println(testdata[i]);
  27. }*/
  28. //测试互相关函数
  29. int f0=10;
  30. int fs=150;
  31. int K = 50;
  32. int lag = 50;
  33. int dataLength = 16;
  34. float[] s1 = new float[dataLength];
  35. float[] s2 = new float[dataLength*2];
  36. for(int i=0;i<dataLength;i++)
  37. {
  38. //s1[i] = (float) Math.sin(2*3.14*(i*2.0/K/fs+f0)*i/fs);
  39. s1[i] = (float) Math.sin(2*3.14*f0*i/fs);
  40. //System.out.println(s1[i]);
  41. }
  42. for(int i=0;i<dataLength*1;i++)
  43. {
  44. s2[i] = 0;
  45. }
  46. for(int i=dataLength*1;i<dataLength*2;i++)
  47. {
  48. s2[i] = s1[i-dataLength*1];
  49. }
  50. Correlation correlation = new Correlation(s1, s2);
  51. //System.out.println("结果:"+correlation.getLag());
  52. }
  53. }

再来个对应结果的图吧:

从图从左往右数,最高的刚好是第16个点,再看看测试代码里面的两个信号就知道刚好延迟了一个信号周期,刚好16个点,结果太完美了。

先写到这里,后面有 成果了再上传其它的代码。

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/756200
推荐阅读
相关标签
  

闽ICP备14008679号