19

iOS 在通过某些 USB 音频设备进行录制时出现问题。它无法可靠地再现(在大约 2000-3000 条记录中每 1 条发生一次,然后默默地消失),我们目前手动检查我们的音频是否存在任何录制问题。它会导致少量样本(1-20)被移动一小部分,这听起来像是一种“噼啪声”。

它们看起来像这样:

异常波形

更接近:

在此处输入图像描述

更接近:

在此处输入图像描述

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

在此处输入图像描述

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

在此处输入图像描述

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

更多奖励点:iOS USB 音频驱动程序/硬件中可能导致此问题的原因(假设存在)。

4

5 回答 5

14

我认为没有现成的解决方案可以找到干扰,但这是解决问题的一种(非标准)方法。使用它,我可以找到大多数间隔,并且只得到少量误报,但该算法当然可以使用一些微调。

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

在 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);

因此,而不是原始数据的这个图:

原始数据

我们得到:

差异日志数据

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

原始数据放大

一个用于对数的差异:

差异日志数据缩放

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

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

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

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

发现极值的 diff-log-data

一个用于原始数据:

发现极端情况的原始数据

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

已发现极端情况的 diff-log-data 已放大

似乎找到了大多数间隔,并且只有少量误报。例如,在我运行算法时,'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

编辑 - 关于恢复原始数据的评论

这是上图三的稍微放大的视图:(扰动在 6.8 和 6.82 之间)

原始数据缩小

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

于 2013-03-14T13:51:36.187 回答
9

要回答为什么会发生的问题-

USB音频设备和主机时钟不同步——也就是说主机无法准确恢复主机本地时钟与音频接口上ADC/DAC的字时钟之间的关系。确实存在各种不同程度的有效时钟恢复技术。更糟糕的是,总线时钟可能与两个音频时钟中的任何一个都无关。

虽然您可能认为这对音频接收来说不是太大的问题 - 当有数据时可能会发生音频捕获回调 - 音频接口通常是双向的,主机将定期呈现音频,另一端是可能以稍微不同的速度消耗。

中间是几组缓冲区,它们可能会溢出或运行不足,这就是这里看起来正在发生的事情;它发生之间的间隔当然似乎是正确的。

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

顺便说一句,IEEE1394 音频和 MPEG 传输流具有相同的时钟恢复要求。它们都通过以非常可预测的方式将本地时钟参考数据包嵌入串行比特流中来解决问题,从而允许在另一端进行准确的时钟恢复。

于 2013-03-08T19:57:13.650 回答
2

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

首先,扫描大量高频,或者通过 FFT 逐个块(可能是 256 个值)对声音进行 FFT,或者通过计算高于和低于零的连续样本。后者应该跟踪大于零的最大连续数、小于零的最大连续数、零附近的小转换量和块的当前体积(Audacity 显示为 0..1)。然后,如果最大连续值低于 5(在 44100 处采样,并且零是连续的,而出色的样本是单个的,5 响应 4410Hz 频率,这是相当高的),或者小转换长度的总和高于某个值取决于最大连续(我相信第一个近似值是 3*5* 块大小/两个最大值之间的距离,这大致等于最大 FFT 频率的周期。此外,它应该在阈值之上和之下进行测量,因为我们最终可能会得到一个错误的峰值,这可能会通过在低于零或高于零的最大值上测量的主要速度之间的差异来检测,也可以通过峰值的 std-dev 来检测。如果高频占主导地位,则该块仅适用于零值测试,并且需要特殊的方法来修复数据。如果高频显着,即检测到占主导地位的低频,我们可以搜索大于3.0*高频体积的峰值,以及该块中的异常零点。并且需要一种特殊的方法来修复数据。如果高频显着,即检测到占主导地位的低频,我们可以搜索大于3.0*高频体积的峰值,以及该块中的异常零点。并且需要一种特殊的方法来修复数据。如果高频显着,即检测到占主导地位的低频,我们可以搜索大于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 个周期的信号可能处于反相)。如果有多个频率大致相等,我们可以用正确的相位对这些频率进行简单的采样,完全切除其余不太重要的频率。

出色的样本应该仅由 2-4 个周围样本平均,因为在您的声音文件中似乎只遇到过一个样本。

于 2013-03-14T12:02:33.573 回答
2

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

FFT 计算在您的情况下不是很有用,因为它是整个信号持续时间中相对频率内容的平均表示,因此无法检测到瞬时变化。离散短时频率变换 (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

于 2013-03-15T13:10:43.447 回答
1

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

  1. 取波形中的每个点并减去其前一个点(查看从一个点到下一个点的变化)。
  2. 查看这些变化的分布并找出它们的标准差。
  3. 如果任何给定的差异超过此标准偏差的 X 倍(高于或低于),则将其标记为问题。
  4. 通过使用它并查看它的性能来确定 X 的最佳值。
  5. 大多数“问题”应该是超出您的截止值的一对两个差异,一个上升,一个下降。

为了坚持超级简单的方法,您可以通过在问题部分之前的最后一个好点和之后的第一个好点之间进行线性插值来修复数据。(确保您不只是删除这些点,因为这会影响(提高)音频的音高。)

于 2013-03-15T01:08:22.373 回答