2015-10-07 183 views
4

我想用AForge 2.2.5來計算2個聲音樣本的相關係數。計算FFT相關係數

我讀過here計算互相關的公式。
And here我讀過關於計算相關係數的公式。

這是我目前所擁有的:
在調用CrossCorrelation()之前,已經執行了FFT。

static Complex[] CrossCorrelation(Complex[] ffta, Complex[] fftb) 
{ 
    var conj = ffta.Select(i => new Complex(i.Re, -i.Im)).ToArray(); 

    for (int a = 0; a < conj.Length; a++) 
     conj[a] = Complex.Multiply(conj[a], fftb[a]); 

    FourierTransform.FFT(conj, FourierTransform.Direction.Backward); 

    return conj; 
} 

static double CorrelationCoefficient(Complex[] ffta, Complex[] fftb) 
{ 
    var correlation = CrossCorrelation(ffta, fftb); 
    var a = CrossCorrelation(ffta, ffta); 
    var b = CrossCorrelation(fftb, fftb); 

    // Not sure if this part is correct.. 
    var numerator = correlation.Select(i => i.SquaredMagnitude).Max(); 
    var denominatora = a.Select(i => i.Magnitude).Max(); 
    var denominatorb = b.Select(i => i.Magnitude).Max(); 

    return numerator/(denominatora * denominatorb); 
} 

我不知道這是實現該功能的正確方法(或處理數據),因爲我很新的DSP。如果有人能指出我正確的方向,將非常感激。

+3

你用測試數據試試嗎?它是否會返回預期的結果?爲每個通過特定輸入的函數編寫一些單元測試,並將實際結果與期望值進行比較。你*不需要傳遞一個完整的聲音文件,只需創建一些你可以手動計算的小數組(或使用其他程序) –

+0

我同意Panagiotis Kanavos。例如,你知道兩個相同信號之間的相關性會使你的相關性爲1. –

+0

我認爲在返回結果之前需要一個根平方(在第二個鏈接公式中給出),這裏你有平方係數 –

回答

5

做FFT和Afrog互相關:

  • 填充信號用零: 作爲每FFT的AForge文檔: 該方法接受2n個大小的數據陣列只,其中n可以在變化[1,14]範圍。

所以你需要確保輸入的內容是否正確填充到一個長度爲2的冪,並在指定範圍: 考慮到電磁波的至少一半是「空白」(零)

REF:

https://dsp.stackexchange.com/questions/741/why-should-i-zero-pad-a-signal-before-taking-the-fourier-transform

https://dsp.stackexchange.com/questions/1919/efficiently-calculating-autocorrelation-using-ffts

  • 取兩個信號的FFT
  • 乘法一個與另一個(逐元素乘法)的共軛
  • 做逆FFT
  • 獲得最大的值作爲corellation係數和它的索引作爲延遲(信號滯後)

爲什麼所得IFFT的最大值:

wikipedia,互相關是用於確定兩個信號之間的時間延遲是有用的,例如用於確定麥克風陣列上的聲信號傳播的時間延遲。 2 [3] [需要澄清] 在計算兩個信號之間的互相關之後,互相關函數的最大值(或者如果信號是負相關的話,則爲最小值)指示信號最佳對齊的時間點,即兩個信號之間的時間延遲是由最大,或Arg最大互相關的參數來確定,如在

REF: https://math.stackexchange.com/questions/1080709/why-is-the-maximum-value-of-cross-correlation-achieved-at-similar-section

基於上述點,交叉計算被計算使用下面的代碼:

//same as OP 
    public Complex[] CrossCorrelation(Complex[] ffta, Complex[] fftb) 
    { 
    var conj = ffta.Select(i => new Complex(i.Re, -i.Im)).ToArray(); 

    conj = conj.Zip(fftb, (v1, v2) => Complex.Multiply(v1, v2)).ToArray(); 
    FourierTransform.FFT(conj, FourierTransform.Direction.Backward); 

    //get that data and plot in Excel, to show the max peak 
    Console.WriteLine("---------rr[i]---------"); 
    double[] rr = new double[conj.Length]; 
    rr = conj.Select(i => i.Magnitude).ToArray(); 

    for (int i = 0; i < conj.Length; i++) 
     Console.WriteLine(rr[i]); 

    Console.WriteLine("----end-----"); 
    return conj; 
    } 

//tuble.Item1: Cor. Coefficient 
//tuble.Item2: Delay of signal (Lag) 
public Tuple<double, int> CorrelationCoefficient(Complex[] ffta, Complex[] fftb) 
{ 
    Tuple<double, int> tuble; 
    var correlation = CrossCorrelation(ffta, fftb); 
    var seq = correlation.Select(i => i.Magnitude); 
    var maxCoeff = seq.Max(); 

    int maxIndex = seq.ToList().IndexOf(maxCoeff); 
    Console.WriteLine("max: {0}", maxIndex); 
    tuble = new Tuple<double, int>(maxCoeff, maxIndex); 
    return tuble; 
} 
    // Pad signal with zeros up to 2^n and convert to complex 
    public List<Complex> ToComplexWithPadding(List<double> sample, int padding = 1) 
    { 
     //As per AForge documentation: 
     // The method accepts data array of 2n size only, where n may vary in the [1, 14] range 
     //So you would need to make sure the input size is correctly padded to a length that is a power of 2, and in the specified range: 

     double logLength = Math.Ceiling(Math.Log(sample.Count * padding, 2.0)); 
     int paddedLength = (int)Math.Pow(2.0, Math.Min(Math.Max(1.0, logLength), 14.0)); 
     Complex[] complex = new Complex[paddedLength]; 
     var samples = sample.ToArray(); 
     // copy all input samples 
     int i = 0; 
     for (; i < sample.Count; i++) 
     { 
      complex[i] = new Complex(samples[i], 0); 
      Console.WriteLine(complex[i].Re); 

     } 
     // pad with zeros 
     for (; i < paddedLength; i++) 
     { 
      complex[i] = new Complex(0, 0); 
      Console.WriteLine(complex[i].Re); 
     } 
     return complex.ToList(); 

    } 

    // extra for signal generation for testing. You can find in the link of the life demo. 

您可以用延遲11 和結果產生的兩個信號的採樣運行壽命演示匹配信號的實際延遲

Life demo with two signals generated

輸出結果:

correlation Coef: 0.33867796353274 | Delay: 11| actual delay: 11