计算FFT相关系数
本文关键字:关系 FFT 计算 | 更新日期: 2023-09-27 18:16:39
我想用AForge 2.2.5
计算2个声音样本的相关系数。
我从这里读到了计算相互关系的公式。
这里我读到了计算相关系数的公式。
这是我目前拥有的:
在调用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的新手。如果有人能给我指出正确的方向,我将不胜感激。
与fft和Afrog进行交叉相关:
- 用零填充信号:根据AForge的fft文档:该方法只接受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.
您可以使用延迟11产生的两个信号的样本运行寿命演示结果与信号的实际延时
吻合。生成两个信号的生活演示
输出结果:
correlation Coef: 0.33867796353274 | Delay: 11| actual delay: 11