计算FFT相关系数

Sch*_*zer 4 c# fft image-processing correlation cross-correlation

我想用2来计算2个声音样本的相关系数AForge 2.2.5.

我从这里读到计算交叉相关的公式.
在这里我读过有关公式计算的相关系数.

这是我现在所拥有的:
在调用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);
}
Run Code Online (Sandbox Code Playgroud)

我不确定这是否是实现该功能(或处理数据)的正确方法,因为我是DSP的新手.如果有人能指出我正确的方向,我将非常感激.

M.H*_*san 5

与FFT和Afrog进行交叉相关:

  • 使用零填充信号:根据fft的AForge文档:该方法仅接受2n大小的数据数组,其中n可能在[1,14]范围内变化.

因此,您需要确保输入大小正确填充到2的幂,并且在指定的范围内:考虑至少一半的波是"空白"(零)

参考:

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
  • 获取最大值作为相关系数,将其索引作为延迟(信号滞后)

为什么得到的IFFT的最大值:

维基百科来看,互相关对于确定两个信号之间的时间延迟是有用的,例如用于确定声学信号在麦克风阵列上传播的时间延迟.2 [3] [需要澄清]在计算两个信号之间的互相关之后,互相关函数的最大值(或者如果信号是负相关的最小值)指示信号最佳对准的时间点,即两个信号之间的时间延迟由最大值的参数或互相关的arg max确定,如

参考: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.
Run Code Online (Sandbox Code Playgroud)

您可以使用延迟11生成的两个信号样本运行生命演示,结果与信号的实际延迟相匹配

生成两个信号的生命演示

输出结果:

 correlation Coef: 0.33867796353274 | Delay: 11| actual delay: 11
Run Code Online (Sandbox Code Playgroud)