在 Java 中使用 FFT / IFFT(频域卷积)的相关性

信息处理 fft 自相关 互相关 爪哇 快速卷积
2022-02-18 16:42:36

我尝试使用 Java 中的互相关来查找两个音频文件之间的延迟。到目前为止,我已经完成了这个算法,我知道有多少样本是延迟。

  • FFT x1 -> 零填充长度:x1.length() + x2.length()
  • FFT x2 -> 零填充长度:x1.length() + x2.length()
  • X3 = FFT{x1} 乘以 FFT{2}*
  • x3 = IFFT{X3}

为了验证我的结果,我使用八度。所以我可以看到我的结果通常是正确的,但是我的图表的位置不正确。

对于测试,我使用相同的文件,因此这代表自动相关功能。在八度图中,最大相关性位于输出向量的中心,这似乎是正确的。-> 所以延迟为 0,因为相同的文件

自相关函数八度 在我的版本中,图表位于开头和结尾。

自相关函数 Java 因此,如果我使用两个不同的信号,则在八度音程中,最大相关性从中心向左/向右移动。在我的算法中,它从开始到中间或结束到中间。

所以看来我的图表计算正确,因为峰值移动了文件之间差异的样本量。但是位置不对。

看起来我必须修改我的输出向量:left half <-> right half

有什么想法是我的问题吗?

编辑:

public void execFastCrossCorrelation() throws FFTException
{
    // the used block size is N(x1) + N(x2)
    int blockSize = (x1.length+x2.length-1);

    // create & calc FFT with zero padding & get result

    // FFT x1
    FFT f1 = new FFT(x1, blockSize, 44100);
    f1.execFFT();
    Complex[] c1 = f1.getOutputData();

    // FFT x2
    FFT f2 = new FFT(x2, blockSize, 44100);
    f2.execFFT();
    Complex[] c2 = f2.getOutputData();

    // create output for cross correlation by using fast convolution : c3 = c1 multiply c2*
    Complex[] c3 = new Complex[c1.length];
    for(int i=0; i<c1.length;i++)
    {
        c3[i] = c1[i].multiply(c2[i].conjugate());
    }

    // create & calc IFFT  & get result
    IFFT f3 = new IFFT(c3, c3.length, 44100);
    f3.execIFFT();
    Complex[] corrResult = f3.getOutputData();

// search the maximum corrleation coefficient and his index
    double maxVal = 0;
    int maxIndex = 0;

    for(int i=0; i<corrResult.length;i++)
    {
        if(corrResult[i].abs() > maxVal)
        {
            maxVal = corrResult[i].abs();
            maxIndex = i;
        }
    }

所以 FFT 类是通过使用 apache-commons-math3 完成的。只需使用输入 vecotr 并为给定的 blockSize 创建一个 FFT(向上/向下舍入到 2 的幂并在必要时填充零)。

编辑:

所以现在我试图翻转输出(意味着左半边 -> 右半边和右半边 -> 左半边)

结果与八度的版本相匹配。

Java中的自动相关性翻转

如果我用不同的文件尝试这个,它也像八度一样工作,意味着最大值从中心向左/右移动。这意味着我认为必须“镜像”输出向量的想法似乎是正确的。你知道为什么吗?

2个回答

真实(非复杂)时域输入将始终给出重复(镜像)的 FFT

一些实现将执行移位以将 DC(频率 = 0Hz)项置于索引 0。否则,您将在数组的中途找到 DC 项。

默认情况下,FFT 将负频率置于正频率之后。它是由于 FFT 的特性而发生的。您可以 google Cooley-Tukye 算法并了解蝴蝶运算以获取更多详细信息。似乎,您的一个库执行输出样本的自动移位,而另一个没有。检查库文档以获取此信息。