使用卷积在连续的声音流中查找参考音频样本

Dan*_*rth 9 .net c# signal-processing convolution cross-correlation

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

  • 我不知道,如何从峰值位置推断原始音频样本中匹配的起始位置.
  • 我不知道,我应该如何应用连续的音频流,所以一旦参考音频样本出现,我就能做出反应.
  • 我不明白,为什么图片2和图片4(见下文)差别如此之大,尽管两者都代表了与自身卷积的音频样本......

任何帮助都非常感谢.

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

  1. 一个较长的音频样本,附近有参考音频(哔哔声):http: //img801.imageshack.us/img801/976/values1.png
  2. 哔哔声与自己融为一体:http: //img96.imageshack.us/img96/6720/values2i.png
  3. 没有哔哔声的较长音频样本与哔哔声缠绕在一起:http: //img845.imageshack.us/img845/1091/values3.png
  4. 第3点的较长音频样本与其自身融合:http: //img38.imageshack.us/img38/1272/values4.png

更新和解决方案:
感谢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);
}
Run Code Online (Sandbox Code Playgroud)

BOUNTY:
无需新答案!我开始赏金给Han,因为他继续努力解决这个问题!

Han*_*Han 3

我们来领取赏金:)

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

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

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

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