10

我之前关于在更大的音频样本中寻找参考音频样本的问题中,有人建议我应该使用卷积。
使用DSPUtil,我能够做到这一点。我用它玩了一点,尝试了不同的音频样本组合,看看结果如何。为了可视化数据,我只是将原始音频作为数字转储到 Excel 中,并使用这些数字创建了一个图表。一个峰值可见的,但我真的不知道这对我有什么帮助。我有这些问题:

  • 我不知道,如何从峰值位置推断原始音频样本中匹配的起始位置。
  • 我不知道,我应该如何将它应用到连续的音频流中,这样我就可以在参考音频样本出现后立即做出反应。
  • 我不明白,为什么图 2 和图 4(见下文)差异如此之大,尽管它们都代表了一个与自身卷积的音频样本......

非常感谢任何帮助。

以下图片是使用Excel分析的结果:

  1. 一个较长的音频样本,参考音频(哔声)接近尾声:
  2. 哔哔声与自身卷积:
  3. 没有哔声的较长音频样本与哔声卷积:
  4. 第 3 点的较长音频样本与自身卷积:

更新和解决方案:
感谢Han的广泛帮助,我能够实现我的目标。
在我推出自己的没有 FFT 的慢速实现之后,我发现alglib提供了一种快速实现。我的问题有一个基本假设:其中一个音频样本完全包含在另一个音频样本中。
因此,以下代码返回两个音频样本中较大的样本中的偏移量以及该偏移量处的归一化互相关值。1 表示完全相关,0 表示完全不相关,-1 表示完全负相关:

private void CalcCrossCorrelation(IEnumerable<double> data1, 
                                  IEnumerable<double> data2, 
                                  out int offset, 
                                  out double maximumNormalizedCrossCorrelation)
{
    var data1Array = data1.ToArray();
    var data2Array = data2.ToArray();
    double[] result;
    alglib.corrr1d(data1Array, data1Array.Length, 
                   data2Array, data2Array.Length, out result);

    var max = double.MinValue;
    var index = 0;
    var i = 0;
    // Find the maximum cross correlation value and its index
    foreach (var d in result)
    {
        if (d > max)
        {
            index = i;
            max = d;
        }
        ++i;
    }
    // if the index is bigger than the length of the first array, it has to be
    // interpreted as a negative index
    if (index >= data1Array.Length)
    {
        index *= -1;
    }

    var matchingData1 = data1;
    var matchingData2 = data2;
    var biggerSequenceCount = Math.Max(data1Array.Length, data2Array.Length);
    var smallerSequenceCount = Math.Min(data1Array.Length, data2Array.Length);
    offset = index;
    if (index > 0)
        matchingData1 = data1.Skip(offset).Take(smallerSequenceCount).ToList();
    else if (index < 0)
    {
        offset = biggerSequenceCount + smallerSequenceCount + index;
        matchingData2 = data2.Skip(offset).Take(smallerSequenceCount).ToList();
        matchingData1 = data1.Take(smallerSequenceCount).ToList();
    }
    var mx = matchingData1.Average();
    var my = matchingData2.Average();
    var denom1 = Math.Sqrt(matchingData1.Sum(x => (x - mx) * (x - mx)));
    var denom2 = Math.Sqrt(matchingData2.Sum(y => (y - my) * (y - my)));
    maximumNormalizedCrossCorrelation = max / (denom1 * denom2);
}

赏金:
不需要新的答案!我开始赏金将其奖励给 Han,以表彰他在这个问题上的持续努力!

4

2 回答 2

4

您应该使用相关性而不是卷积。相关峰值的大小告诉您两个信号的相似程度、峰值的位置以及它们在时间上的相对位置,或者两个信号之间的延迟。

于 2011-05-01T10:08:43.330 回答
3

在这里,我们去赏金:)

要在较大的音频片段中找到特定的参考信号,您需要使用互相关算法。基本公式可以在这篇Wikipedia 文章中找到。

互相关是比较两个信号的过程。这是通过将两个信号相乘并将所有样本的结果相加来完成的。然后移动其中一个信号(通常是 1 个样本),并重复计算。如果您尝试将其可视化为非常简单的信号,例如单个脉冲(例如,1 个样本具有特定值而其余样本为零)或纯正弦波,您将看到互相关的结果确实是衡量两个信号的相似程度以及它们之间的延迟。可以在此处找到另一篇可能提供更多见解的文章。

Paul Bourke 的这篇文章还包含一个简单的时域实现的源代码。请注意,本文是针对一般信号编写的。音频具有长期平均值通常为 0 的特殊属性。这意味着 Paul Bourkes 公式(mx 和 my)中使用的平均值可以省略。还有基于 FFT 的互相关的快速实现(参见ALGLIB)。

相关性的(最大值)取决于音频信号中的样本值。然而,在 Paul Bourke 的算法中,最大值被缩放到 1.0。在一个信号完全包含在另一个信号中的情况下,最大值将达到 1。在更一般的情况下,最大值将更低,并且必须确定阈值以确定信号是否足够相似。

于 2011-05-05T09:40:45.663 回答