如何检测这些音频异常?

时间:2013-03-08 18:55:21

标签: algorithm audio signal-processing sample-rate

iOS通过某些USB音频设备录制问题。它无法可靠地再现(分批发生在每2000个〜2000-3000个记录中并且无声地消失),我们目前手动检查我们的音频是否有任何录音问题。它导致少量样本(1-20)被移动了一小部分,听起来像是一种“噼啪声”。

他们看起来像这样:

Waveform with abnormality

接近:

enter image description here

接近:

enter image description here

同一音频文件中其他地方的另一个单一样本错误:

enter image description here

问题是,如何在算法上检测这些(假设直接访问样本),同时不会触发高频音频的误报,如下所示:

enter image description here

奖励积分:在确定尽可能多的错误后,如何“修复”音频?

更多奖励积分:iOS USB音频驱动程序/硬件可能导致此问题(假设它存在)。

5 个答案:

答案 0 :(得分:12)

我不认为有一个开箱即用的解决方案来找到干扰,但这是一种(非标准的)解决问题的方法。使用这个,我可以找到大多数间隔,我只得到少量误报,但算法当然可以使用一些微调。

我的想法是找到偏离样本的起点和终点。第一步应该是让这些要点更加突出。这可以通过获取数据的对数并获取连续值之间的差异来完成。

在MATLAB中我加载数据(在本例中我使用dirty-sample-other.wav)

y1 = wavread('dirty-sample-pictured.wav');
y2 = wavread('dirty-sample-other.wav');
y3 = wavread('clean-highfreq.wav');

data = y2;

并使用以下代码:

logdata = log(1+data);
difflogdata = diff(logdata);

所以不是原始数据的这个图:

original data

我们得到:

diff-log-data

我们寻找的时间间隔是正面和负面的峰值。例如,放大对数差异图中的最大正值,我们得到以下两个数字。一个用于原始数据:

Original data zoomed

和一个对数差异:

Diff-log-data zoomed

此图可以帮助手动查找区域,但理想情况下我们希望使用算法找到它们。我这样做的方法是采用大小为6的移动窗口,计算窗口的平均值(除了最小值之外的所有点),并将其与最大值进行比较。如果最大点是高于平均值的唯一点,并且至少是平均值的两倍,则将其计为正极值。

然后,我使用了一个计数阈值,至少有一半的窗口移动到该值,应将其检测为极值,以便接受它。

将所有点乘以(-1)然后再次运行此算法以检测最小值。

用“*”标记正极端,用“*”标记负极值,我们得到以下两个图。一个用于对数的差异:

diff-log-data with found extremes

和一个原始数据:

original data with found extremes

放大显示对数差异的图的左侧部分,我们可以看到找到了最极端的值:

diff-log-data with found extremes zoomed

似乎找到了大多数间隔,并且只有少量误报。例如,在'clean-highfreq.wav'上运行算法我只找到一个正极值和一个负极值。

错误地归类为极值的单个值也许可以通过匹配起点和终点来消除。如果你想要替换丢失的数据,你可以使用周围的数据点进行某种插值,甚至线性插值也许就足够了。

这是我使用的MATLAB代码:

function test20()
clc
clear all

y1 = wavread('dirty-sample-pictured.wav');
y2 = wavread('dirty-sample-other.wav');
y3 = wavread('clean-highfreq.wav');

data = y2;

logdata = log(1+data);
difflogdata = diff(logdata);

figure,plot(data),hold on,plot(data,'.')
figure,plot(difflogdata),hold on,plot(difflogdata,'.')

figure,plot(data),hold on,plot(data,'.'),xlim([68000,68200])
figure,plot(difflogdata),hold on,plot(difflogdata,'.'),xlim([68000,68200])

k = 6;
myData = difflogdata;
myPoints = findPoints(myData,k);

myData2 = -difflogdata;
myPoints2 = findPoints(myData2,k);

figure
plotterFunction(difflogdata,myPoints>=k,'or')
hold on
plotterFunction(difflogdata,myPoints2>=k,'*r')

figure
plotterFunction(data,myPoints>=k,'or')
hold on
plotterFunction(data,myPoints2>=k,'*r')

end

function myPoints = findPoints(myData,k)

iterationVector = k+1:length(myData);
myPoints = zeros(size(myData));
for i = iterationVector
    subVector = myData(i-k:i);
    meanSubVector = mean(subVector(subVector>min(subVector)));
    [maxSubVector, maxIndex] = max(subVector);
    if (sum(subVector>meanSubVector) == 1 && maxSubVector>2*meanSubVector)
        myPoints(i-k-1+maxIndex) = myPoints(i-k-1+maxIndex) +1;
    end
end

end

function plotterFunction(allPoints,extremeIndices,markerType)

extremePoints = NaN(size(allPoints));
extremePoints(extremeIndices) = allPoints(extremeIndices);
plot(extremePoints,markerType,'MarkerSize',15),
hold on
plot(allPoints,'.')
plot(allPoints)

end

修改 - 有关恢复原始数据的评论

以上是图3中略微缩小的视图:(干扰介于6.8和6.82之间)

Original data zommed out

当我检查这些值时,关于被反映为负值的数据的理论似乎并不完全符合模式。但无论如何,我想要消除差异当然是不正确的。由于干扰似乎没有改变周围的点,我可能会回到最初的想法,即不信任受影响区域内的点,而是使用周围数据进行某种插值。在大多数情况下,似乎简单的线性插值是一个非常好的近似。

答案 1 :(得分:9)

回答它为何会发生的问题 -

USB音频设备和主机不是时钟同步的 - 也就是说主机无法准确恢复主机本地时钟与音频接口上ADC / DAC的字时钟之间的关系。各种技术exist用于时钟恢复,具有不同程度的有效性。为了解决这个问题,总线时钟可能与两个音频时钟中的任何一个无关。

虽然您可能认为这对音频接收不是太过关注 - 当有数据时可能会发生音频捕获回调 - 音频接口通常是双向的,主机将定期渲染音频,另一端可能会以略微不同的速度消耗。

中间是几组缓冲区,可以运行过度或欠运行,这就是这里发生的事情;它发生的间隔肯定是正确的。

您可能会发现将USB音频设备更改为围绕不同芯片组(或简称为不同的本地振荡器)构建的设备会有所帮助。

除此之外,IEEE1394音频和MPEG传输流都具有相同的时钟恢复要求。它们都以一种非常可预测的方式将本地时钟参考数据包嵌入到串行比特流中,从而在另一端实现精确的时钟恢复,从而解决了这个问题。

答案 2 :(得分:2)

我认为以下算法可以应用于样本以确定潜在的误报:

首先,扫描大量高频,或者通过逐块FFT(可能是256个值),或者通过计算零上下的连续样本。后者应该跟踪最大连续高于零,最大连续低于零,零过渡的小过渡量和块的当前体积(当Audacity显示它时为0..1)。然后,如果最大连续值低于5(在44100采样,并且零是连续的,而outstsanding样本是单个,5响应4410Hz频率,这是相当高的),或者小过渡长度的总和高于某个值取决于最大连续性(我相信第一个近似值是3 * 5 *块大小/两个最大值之间的距离,大致相当于最响亮的FFT频率的周期。还应该测量高于和低于阈值,因为我们可以结束错误的峰值,可能通过低于零或高于零的最大值测量的主要速度之间的差异,也可能通过峰值的std-dev来检测。如果高频占优势,则此块仅符合零值测试,以及修复数据的特殊方法。如果高频率很重要,即检测到显性低频,我们可以搜索大于3.0 *高频音量的峰值,以及异常零点。这个街区

此外,您的差距似乎是高度扩展或纯零,高扩展为单个错误,零错误范围为1-20。因此,如果零范围的值低于0.02绝对值,其直接被0.15的值(要被微调的变量)或更高的绝对值AND包围,则将此点计为错误。如果您计算2.0*(current sample)-(previous sample)-(next sample)并且如果它高于某个阈值(0.1 +高频音量,或3.0 *高频音量,以较大者为准),则可以检测到突出的单个值,将其计为错误和平均值。

如何处理零间隙 - 我们可以复制1个周期向后和1个周期向前的值(平均值),其中“周期”是块的FFT的最重要频率。如果“周期”小于间隙(假设我们在声音的高音部分检测到零间隙),则使用两个或更多个周期,因此源数据都将有效(在这种情况下,不能进行平均,因为有可能信号2个周期从间隙向前,2个周期向后将处于反相。如果有不止一个大约相等振幅的频率,我们可以用正确的相位对这些频率进行简单采样,从而完全切断其余不太重要的频率。

优秀的样本IMO只需要平均2-4个样本,因为在你的声音文件中似乎只有一个样本。

答案 3 :(得分:2)

离散小波变换(DWT)可能是您问题的解决方案。

FFT计算在您的情况下不是很有用,因为它在信号的整个持续时间内平均表示相对频率内容,因此无法检测瞬时变化。 dicrete短时频率变换(STFT)试图通过计算信号的短连续时间块的DFT来解决这个问题,其长度由窗口的长度(和形状)决定,但是由于分辨率是DFT取决于数据/块长度,在频率或时间上的分辨率之间存在折衷,找到这个神奇的固定窗口大小可能很棘手!

你想要的是一种时频分析方法,它具有良好的高频事件时间分辨率,以及低频事件的良好频率分辨率......进入离散小波变换!

对于不同的应用程序有许多小波变换,正如您所料,它的计算量很大。 DWT可能无法解决您的问题,但值得考虑。祝你好运。一些星期五晚上的阅读:

http://klapetek.cz/wdwt.html

http://etd.lib.fsu.edu/theses/available/etd-11242003-185039/unrestricted/09_ds_chapter2.pdf

http://en.wikipedia.org/wiki/Wavelet_transform

http://en.wikipedia.org/wiki/Discrete_wavelet_transform

答案 4 :(得分:1)

你可以尝试以下超简单的方法(也许就够了):

  1. 获取波形中的每个点并减去其前一个点(查看从一个点到下一个点的更改)。
  2. 查看这些变化的分布并找出它们的标准偏差。
  3. 如果任何给定的差异超出此标准偏差的X倍(高于或低于此值),请将其标记为问题。
  4. 通过玩X来确定X的最佳值并查看其执行情况。
  5. 大多数“问题”应该是一个超出截止点的两个差异,一个上升,另一个下降。
  6. 为了坚持使用超简单方法,您可以通过在问题部分之前的最后一个优点和之后的第一个优点之间线性插值来修复数据。 (确保不要删除这些点,因为这会影响(提高)音频的音高。)