我认为没有现成的解决方案来查找干扰,但这里有一种(非标准)解决问题的方法。使用此方法,我可以找到大多数间隔,并且只有少量误报,但算法肯定需要进行一些微调。
我的想法是找到偏离样本的起始点和结束点。第一步应该是使这些点更清晰地突出。这可以通过对数据取对数并计算相邻值之间的差异来完成。
在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](https://istack.dev59.com/Oga2m.webp)
我们得到:
![diff-log-data](https://istack.dev59.com/7mqkH.webp)
我们正在寻找的区间以正负尖峰形式突出。例如,在对数差异图中放大最大正值,我们得到以下两个图像。一个是原始数据:
![Original data zoomed](https://istack.dev59.com/Jdb4B.webp)
还有一个关于对数差的:
![Diff-log-data zoomed](https://istack.dev59.com/OIyUy.webp)
这个图可以帮助手动找到区域,但理想情况下我们希望使用算法来找到它们。我采用的方法是取大小为6的移动窗口,计算窗口的平均值(除最小值外的所有点),并将其与最大值进行比较。如果最大点是唯一超过平均值且至少是平均值的两倍大的点,则将其视为正极端值。
然后我使用了一个计数阈值,至少有一半的移动窗口在该值上检测到它作为极端值,才能被接受。
将所有点乘以(-1),然后再次运行此算法以检测最小值。
用“o”标记正极端值,“*”标记负极端值,我们得到以下两个图。其中一个是用于对数差异的:
![diff-log-data with found extremes](https://istack.dev59.com/66xlX.webp)
还有一个用于原始数据的:
![original data with found extremes](https://istack.dev59.com/anygR.webp)
放大图中左侧显示对数差异的部分,我们可以看到大多数极端值位于:
![diff-log-data with found extremes zoomed](https://istack.dev59.com/wS57b.webp)
似乎大多数间隔都被找到了,只有很少的误报。例如,在“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之间)
![Original data zommed out](https://istack.dev59.com/VzPA3.webp)
当我检查数值时,你关于数据被镜像到负值的理论似乎并不完全符合模式。但无论如何,我的想法只是去除差异显然是不正确的。由于周围的点似乎没有受到干扰,我可能会回到最初的想法,即不信任受影响区域内的点,而是使用周围的数据进行某种插值。在大多数情况下,简单的线性插值似乎是一个相当好的近似值。