4
votes

I would like to calculate the correlation coefficient of 2 sound samples using AForge 2.2.5.

I've read from here the formula to calculate Cross Correlation.
And here I've read about the formula to calculate the correlation coefficient.

This is currently what I have:
Prior to calling CrossCorrelation(), FFT has been performed.

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);
}

I'm not sure if that is the right way to implement the function (or handling the data) as I'm very new to DSP. Will greatly appreciate it if someone could point me to the right direction.

1
Did you try it with test data? Does it return the expected results? Write some unit tests for each function that pass specific inputs and compare the actual results against the expected values. You don't need to pass an entire sound file, just create some small arrays that you can calculate by hand (or using another program) - Panagiotis Kanavos
I agree with Panagiotis Kanavos. You know for example that the correlation between two identical signals will give you correlation of 1. - Amitay Nachmani
I think you will need a root square before returning the result ( given in the second link formula ), here you have the square coefficient - Antoine Bergamaschi

1 Answers

5
votes

To do Cross-correlation with FFTs and Afrog:

  • Padding Signals with zeros: As per AForge documentation of fft: 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: taking into account at least half of the wave is "blank" (zeros)

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

  • take the FFT of both signals
  • multiply one with conjugate of the other (element-wise multiplication)
  • do the inverse FFT
  • get max value as a corellation coefficient and its index as the delay(signal lag)

Why Max value of the resultant IFFT:

from wikipedia, Cross-correlations are useful for determining the time delay between two signals, e.g. for determining time delays for the propagation of acoustic signals across a microphone array.2[3][clarification needed] After calculating the cross-correlation between the two signals, the maximum (or minimum if the signals are negatively correlated) of the cross-correlation function indicates the point in time where the signals are best aligned, i.e. the time delay between the two signals is determined by the argument of the maximum, or arg max of the cross-correlation, as in

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

Based on the above points, the Cross Calculation is calculated using the following code:

  //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.

You can run life demo with sample of two signal generated with delay 11 and the result match the actual delay of the signal

Life demo with two signals generated

The output result:

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