如何实现互相关以证明两个音频文件相似?


58

我必须对两个音频文件进行互相关以证明它们是相似的。我已经对两个音频文件进行了FFT,并将它们的功率谱值放在单独的数组中。

我应该如何进一步使它们相互关联并证明它们相似?有更好的方法吗?任何基本想法对我学习和应用它都将有所帮助。


给定两个随机信号向量的互相关。如何在MATLAB中实现反向以获得两个向量。约翰·穆赫赫

Answers:


56

互相关和卷积密切相关。简而言之,要对FFT 进行卷积,您需要

  1. 对输入信号进行零填充(在末尾加零,以便至少一半的波形为“空白”)
  2. 对两个信号进行FFT
  3. 将结果相乘(逐元素相乘)
  4. 进行逆FFT

conv(a, b) = ifft(fft(a_and_zeros) * fft(b_and_zeros))

您需要进行零填充,因为FFT方法实际上是圆形互相关的,这意味着信号在两端回绕。因此,您添加足够的零以消除重叠,以模拟从零到无穷大的信号。

为了获得互相关而不是卷积,您需要在执行FFT之前对其中一个信号进行时间反转,或者对FFT之后的其中一个信号进行复共轭:

  • corr(a, b) = ifft(fft(a_and_zeros) * fft(b_and_zeros[reversed]))
  • corr(a, b) = ifft(fft(a_and_zeros) * conj(fft(b_and_zeros)))

使用您的硬件/软件比较容易。对于自相关(信号与自身之间的互相关),最好进行复共轭,因为这样一来,您只需计算一次FFT。

如果信号是真实的,则可以使用真实的FFT(RFFT / IRFFT),并且仅计算一半频谱即可节省一半的计算时间。

另外,您还可以通过填充较大的大小来节省计算时间,以优化FFT的大小(例如,对于FFTPACK 为5平滑数,对于FFTW为13平滑数,或者对于简单的硬件实现为2的幂)。

这是Python中与蛮力相关相比的FFT相关示例:https : //stackoverflow.com/a/1768140/125507

这将为您提供互相关函数,该函数用于衡量相似度与偏移量。为了获得波彼此“对齐”的偏移量,相关函数中将出现一个峰值:

相关函数中的峰值

峰值的x值是偏移量,可以是负值或正值。

我只看到这用于查找两个波之间的偏移。通过在峰上使用抛物线/二次插值,您可以得到更精确的偏移量估算值(优于样品的分辨率)。

要获得介于-1和1之间的相似度值(负值表示其中一个信号随着另一个信号的增加而减小),您需要根据输入的长度,FFT的长度,特定的FFT实现方式来缩放幅度。波形与其自身的自相关将为您提供最大可能匹配的值。

请注意,这仅适用于具有相同形状的波浪。如果它们是在不同的硬件上采样的,或者添加了一些噪声,但仍然具有相同的形状,则此比较将起作用,但是,如果波形已通过滤波或相移进行了更改,则它们听起来可能相同,但会获胜也没有关联。


3
零填充至少应为N = size(a)+ size(b)-1,最好取整为2的幂。要获得-1与1之间的值,请除以norm(a)* norm(b) ),它给出了给定滞后时间(即模N的圆位移)在N空间中两个向量之间的夹角的余弦值。在极端滞后,没有太多重叠的样本(在极端极端处只有一个),因此除以norm(a)* norm(b)会将这些相关偏向0(即,显示它们在N空间中的相对正交性) 。
Eryk Sun

1
我认为说明中可能有错误。难道不应该将FFT逐项相乘就得到信号卷积的FFT,而不是互相关的FFT 吗?据我了解,要获得互相关的FFT,在进行iFFT之前,有必要在逐项乘法中使用FFT矢量之一的复共轭
Dilip Sarwate

@DilipSarwate:是的,你是对的。您还可以在时间方向上反转一个信号,我将其添加到了答案中。
endlith 2011年

1
x[i]ix[±i]x[i](Ni)x[Ni]ii增加了布线成本,布线延迟(并因此降低了最大可达到的时钟速率),并且由于所有导线必须彼此交叉,因此也会引起布线问题。如果可能,应避免使用它,在这种情况下,这可以避免的。
Dilip Sarwate

1
@Leo逐元素乘法。n×1数组x n×1数组= n×1数组我在答案中称此为“逐样本”。
endlith 2014年

17

关联是在一个数字中表示两个时间序列(在您的情况下为音频样本)的相似性的一种方式。它是协方差的一种适应,其实现方式如下:

period = 1/sampleFrequency;
covariance=0;

for (iSample = 0; iSample<nSamples; iSample++)
    covariance += (timeSeries_1(iSample)*timeSeries_2(iSample))/period;
    //Dividing by `period` might not even be necessary

相关性是协方差的归一化版本,即协方差除以两个时间序列的标准偏差的乘积。当没有相关性时(完全不相似),相关性将产生0;对于整体相关性(完全相似),相关性将产生1。

您可以想象两个声音样本可能相似但不同步。这就是交叉相关性的来源。您可以计算时间序列之间的相关性,在这些时间序列中,其中一个偏移一个样本:

for (iShift=0; iShift<nSamples; iShift++)
    xcorr(iShift) = corr(timeSeries_1, timeSeries_2_shifted_one_sample);

然后找出corr系列中的最大值,就可以完成。(或者,如果您发现足够的相关性,则停止)当然还有更多的相关性。您必须实现标准偏差,并且必须执行一些内存管理并实现时移功能。如果所有音频样本的长度都相等,则可能不对协方差进行归一化而继续计算交叉协方差。

您先前的问题有一个很酷的联系:傅立叶分析只是交叉协方差的一种适应。无需移动一个时间序列并计算与另一个信号的协方差,而是计算一个信号与多个具有不同频率的(共)正弦波之间的协方差。这都是基于相同的原理。


1
您提到0是无相关性,而1是总相关性。我只想指出-1是完全负相关的。与之类似,-1表示样本1与样本2相反。如果在X,Y图上考虑它,则它是一条具有正斜率的线与一条具有负斜率的线。并且,当您接近0时,该行就会“陷落”。
Kellenjb 2010年

@kellenjb,是的,但是我可能会说一下,您可能感兴趣的相关程度。1或-1表示信号直接相互影响。
Kortuk

13

在信号处理中,互相关(MATLAB中的xcorr)是一种卷积运算,其中两个序列之一相反。由于时间反转对应于频域中的复杂共轭,因此可以使用DFT如下计算互相关:

R_xy = ifft(fft(x,N) * conj(fft(y,N)))

其中N = size(x)+ size(y)-1(最好取整为2的幂)是DFT的长度。

DFT的乘法等效于时间上的循环卷积。对两个向量进行零填充至长度N可以防止y的循环移位分量与x重叠,这使得结果与x的线性卷积和y的时间倒置相同。

滞后1是y的右循环,而滞后-1是左循环。互相关只是所有滞后的点积序列。基于标准的fft排序,它们将位于可以按以下方式访问的数组中。索引0到size(x)-1为正滞后。索引N-size(y)+1到N-1是相反顺序的负延迟。(在Python中,可以使用R_xy [-1]之类的负索引方便地访问负滞后。)

您可以将零填充的x和y视为N维向量。对于给定的滞后,x和y的点积为|x|*|y|*cos(theta)。x和y的范数对于圆形移位是恒定的,因此将它们除以仅留下角度theta的变化余弦。如果x和y(对于给定的滞后)在N空间中正交,则相关性为0(即theta = 90度)。如果它们是共线性的,则该值为1(正相关)或-1(负相关,即theta = 180度)。这导致归一化为互相关的互相关:

R_xy = ifft(fft(x,N) * conj(fft(y,N))) / (norm(x) * norm(y))

可以通过重新计算仅重叠部分的范数来实现无偏,但是您也可以在时域中进行整个计算。此外,您还将看到标准化的不同版本。有时,互相关不是通过归一化为统一的,而是通过M(有偏)进行归一化的,其中M = max(size(x),size(y))或M- | m |。(第m个时滞的无偏估计)。

为了获得最大的统计显着性,应在计算相关性之前去除均值(直流偏置)。这称为交叉协方差(MATLAB中的xcov):

x2 = x - mean(x)
y2 = y - mean(y)
phi_xy = ifft(fft(x2,N) * conj(fft(y2,N))) / (norm(x2) * norm(y2))

这是否意味着数组的最终大小应为2*size (a) + size(b) - 12*size (b) + size (a) - 1?但是无论哪种情况,两个填充数组的大小都不同。用太多的零填充的结果是什么?

2

@RobertKJ:您正在b沿着滑动a,每个班次一个输出,一个样本的最小重叠。产生size(a)正向滞后和size(b) - 1负向滞后。使用N点DFT乘积的逆变换,索引0through size(a)-1为正滞后,索引N-size(b)+1through N-1为负滞后。
Eryk Sun

3

如果您使用的是Matlab,请尝试使用互相关函数:

c= xcorr(x,y)

这是Matlab文档:

xcorr估计随机过程的互相关序列。自相关被作为特殊情况处理。

...

c = xcorr(x,y)返回长度为2 * N-1的向量中的互相关序列,其中xy是长度N向量(N > 1)。如果xy的长度不同,则将较短的向量零填充到较长向量的长度上。

相关性http://www.mathworks.com/help/toolbox/signal/ref/eqn1263487323.gif


链接似乎已断开。
Danijel

2

比较音频文件的快速简单方法。取得音频文件,复制后,在两个立体声通道中并排粘贴,在一个立体声轨道上反转相位,在缩放模式下将两个文件在开始时对齐,请确保两个文件在开始时具有相同的振幅,然后播放,如果完全静音,则两个文件相同,如果存在差异,您会清楚地听到它!


1

正如这里大多数人所写,您应该使用关联。

只需考虑以下两个因素:

  1. 如果音量的缩放比例不同,则应标准化相关性。
  2. 如果存在时间缩放,则可以使用动态时间扭曲。

0

找出差异的最简单方法是IMO,即在时域中减去两个音频信号。如果它们相等,则每个时间点的结果将为零。如果它们不相等,则它们之间的差异将在相减后保留,您可以直接收听。快速测量它们之间的相似度是该差异的RMS值。例如,这通常是在音频混合和母带制作中完成的,以收听MP3与WAV文件的差异。(将一个信号的相位反相并相加与相减相同。这是在DAW软件中完成此操作时所使用的方法。)它们必须在时间上完全对准才能起作用。如果不是,则可以开发一种算法来对齐它们,例如检测前十个峰,计算峰的平均偏移量以及移动一个信号。

像您建议的那样,转换到频域并比较信号的功率谱会忽略一些时域信息。例如,反向播放的音频在向前播放时将具有相同的频谱。因此,两个截然不同的音频信号可能具有完全相同的频谱。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.