我使用Arduino微控制器从电位器收集了一些数据。这是以500 Hz采样的数据(这是很多数据):
http://cl.ly/3D3s1U3m1R1T?_ga=1.178935463.2093327149.1426657579
如果你放大你可以看到,基本上我有一个只能来回旋转的底池,即,我应该看到线性增加然后线性减少。虽然数据的一般形状证实了这一点,但几乎每次都有一些非常令人讨厌的(有时令人惊讶的宽度)尖峰会妨碍一个非常漂亮的形状。有什么方法可以制作某种类型的算法或过滤器来解决这个问题吗?我尝试了中值滤波器,并使用百分位数,但都没有奏效。我的意思是我觉得它不应该是最困难的事情,因为我可以清楚地看到它应该是什么样的 - 基本上是尖峰出现的最小值 - 但出于某种原因我尝试的一切都很糟糕或者至少失去了它的完整性原始数据。
我很感激我能得到任何帮助。
答案 0 :(得分:4)
有很多方法可以解决您的问题。然而,它们都不会是完美的。我会在这里给你两种方法。
在Matlab中,一个简单的方法来通过"低通#34;在不必明确使用FFT的情况下过滤数据,就是使用filter
函数`(在基础包中可用,不需要任何特定的工具箱)。
为过滤器创建内核,并将其应用两次(每个方向一次),以取消引入的相移。这实际上是一个"移动平均线"具有零相移的滤波器。 内核的大小(长度)将控制平均过程的重量。
例如,2个不同的过滤器长度:
n = 100 ; %// length of the filter
kernel = ones(1,n)./n ;
q1 = filter( kernel , 1 , fliplr(p) ) ; %// apply the filter in one direction
q1 = filter( kernel , 1 , fliplr(q1) ) ; %// re-apply in the opposite direction to cancel phase shift
n = 500 ; %// length of the filter
kernel = ones(1,n)./n ;
q2 = filter( kernel , 1 , fliplr(filter( kernel , 1 , fliplr(p) )) ) ; %// same than above in one line
会产生您的数据:
如您所见,每个过滤器大小都有其优缺点。过滤得越多,取消的峰值越多,但原始信号变形的次数就越多。您可以找到最佳设置。
这是一种不同的方法。您可以在信号上观察到尖峰大多是突然的,这意味着您的信号值的变化很快,并且幸运地比正常情况更快#34;您所需信号的变化率。这意味着您可以计算信号的导数,并识别所有尖峰(导数将远高于曲线的其余部分)。
因为这只能识别"开头"和"结束"对于尖峰(不是偶尔在中间的高原),我们需要通过这种方法延长一点点被识别为有缺陷的区域。
当完成错误数据的识别时,您只需丢弃这些数据点并在原始间隔内重新插入曲线(获得对您剩余点的支持)。
%% // Method 2 - Reinterpolation of cancelled data
%// OPTIONAL slightly smooth the initial data to get a cleaner derivative
n = 10 ; kernel = ones(1,n)./n ;
ps = filter( kernel , 1 , fliplr(filter( kernel , 1 , fliplr(p) )) ) ;
%// Identify the derivative anomalies (too high or too low)
dp = [0 diff(ps)] ; %// calculate the simplest form of derivative (just the difference between consecutive points)
dpos = dp >= (std(dp)/2) ; %// identify positive derivative above a certain threshold (I choose the STD but you could choose something else)
dneg = dp <= -(std(dp)/2) ; %// identify negative derivative above the threshold
ixbad = dpos | dneg ; %// prepare a global vector of indices to cancel
%// This will cancel "nPtsOut" on the RIGHT of each POSITIVE derivative
%// point identified, and "nPtsOut" on the LEFT of each NEGATIVE derivative
nPtsOut = 100 ; %// decide how many points after/before spikes we are going to cancel
for ii=1:nPtsOut
ixbad = ixbad | circshift( dpos , [0 ii]) | circshift( dneg , [0 -ii]) ;
end
%// now we just reinterpolate the missing gaps
xp = 1:length(p) ; %// prepare a base for reinterpolation
pi = interp1( xp(~ixbad) , p(~ixbad) , xp ) ; %// do the reinterpolation
这将产生:
红色信号是上述移动平均线的结果,绿色信号是导数方法的结果 您还可以更改设置以调整此结果(衍生品的阈值,&#39; nPtsOut&#39;甚至数据的初始平滑)。
正如您所看到的,对于与移动平均方法相同的峰值消除量,它更多地考虑了初始数据的完整性。然而,它也不完美,一些间隔仍然会变形。但正如我在开始时所说,没有任何方法是完美的。
答案 1 :(得分:1)
看来你的最大和最小点附近都有很大的尖峰。例如,您可以将有效数据的范围限制在200到300之间。
另一种选择是像这样的一阶低通滤波器
alpha = 0.01 %parameter to tune!
p_filtered(1) = p(1);
for i=2:length(p)
p_filtered(i) = alpha*p(i) + (1-alpha)* p_filtered(i-1);
end
答案 2 :(得分:1)
当旋钮旋转时,POT的刮水器沿着阻力轨道反弹,引起噪音尖峰。这是他们的常见问题。将来你应该考虑在POT输出端增加一个0.1uF电容,这样可以解决问题。
对于您当前的数据,最简单的选择是只做一个简单的移动平均,并在视觉上调整平均样本数,直到峰值被充分抑制,同时不影响基础数据。请注意,移动平均线只是一个频率响应为sinc的低通滤波器。
对这类数据进行后处理的常规方法是进行FFT(使用适当的窗口函数),将感兴趣的信号上方的噪声值清零,然后进行逆FFT。这也只是低通滤波(具有sinc *窗口函数加权移动平均值),但您可以使用FFT提供的洞察来选择截止频率。如果您对这样做所涉及的数学不满意,那么只需使用简单的移动平均滤波器即可。它可以满足您的需求。