在我之前关于在更大的音频样本中寻找参考音频样本的问题中,有人建议我应该使用卷积。
使用DSPUtil,我能够做到这一点。我用它玩了一点,尝试了不同的音频样本组合,看看结果如何。为了可视化数据,我只是将原始音频作为数字转储到 Excel 中,并使用这些数字创建了一个图表。一个峰值是可见的,但我真的不知道这对我有什么帮助。我有这些问题:
- 我不知道,如何从峰值位置推断原始音频样本中匹配的起始位置。
- 我不知道,我应该如何将它应用到连续的音频流中,这样我就可以在参考音频样本出现后立即做出反应。
- 我不明白,为什么图 2 和图 4(见下文)差异如此之大,尽管它们都代表了一个与自身卷积的音频样本......
非常感谢任何帮助。
以下图片是使用Excel分析的结果:
更新和解决方案:
感谢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,以表彰他在这个问题上的持续努力!