我有一系列数据,需要在一定数量的读数(窗口大小)内检测系列中的峰值,并排除一定水平的背景“噪音”。我还需要捕捉可感知曲线的起点和终点(即,当它开始上升然后停止下降时)。
数据是高精度 float 。
以下是我在视觉上遇到的最常见场景的快速草图:
我尝试的一种方法是沿着曲线传递一个大小为 X 的窗口,向后移动以检测峰值。它开始运行良好,但我错过了很多最初没有预料到的情况。我开始研究的另一种方法是一个不断增长的窗口,它可以发现更长的持续时间曲线。另一种方法使用了一种更基于微积分的方法来观察某些速度/梯度方面。似乎都没有达到最佳状态,可能是因为我缺乏统计分析经验。
也许我需要使用某种统计分析包来覆盖我的基础而不是编写我自己的算法?或者是否有一种有效的方法可以通过某种局部最大技术直接使用 SQL 来解决这个问题?我只是不确定如何有效地解决这个问题。我尝试的每种方法似乎总是错过各种阈值、检测到太多峰值或未捕获整个事件(在读取过程中过早报告峰值数据点)。
最终这是在 Ruby 中实现的,因此,如果您能就使用 Ruby 解决此问题的最有效和正确的方法提出建议,我们将不胜感激,但是我愿意接受与语言无关的算法方法也是如此。或者是否有某个库可以解决我在这种检测最大峰值的情况下遇到的各种问题?
最佳答案
我的想法很简单,在得到你感兴趣的窗口之后,你需要找到这个窗口中的所有峰值,你可以只比较最后一个值和下一个值,之后你就会知道峰值出现的位置,你可以决定在哪里是最好的峰。
我在 matlab 中写了一个简单的源代码来展示我的想法!
我的例子是来自音频文件的 wave :-)
waveFile='Chick_eco.wav';
[y, fs, nbits]=wavread(waveFile);
subplot(2,2,1); plot(y); legend('Original signal');
startIndex=15000;
WindowSize=100;
endIndex=startIndex+WindowSize-1;
frame = y(startIndex:endIndex);
nframe=length(frame)
%find the peaks
peaks = zeros(nframe,1);
k=3;
while(k <= nframe - 1)
y1 = frame(k - 1);
y2 = frame(k);
y3 = frame(k + 1);
if (y2 > 0)
if (y2 > y1 && y2 >= y3)
peaks(k)=frame(k);
end
end
k=k+1;
end
peaks2=peaks;
peaks2(peaks2<=0)=nan;
subplot(2,2,2); plot(frame); legend('Get Window Length = 100');
subplot(2,2,3); plot(peaks); legend('Where are the PEAKS');
subplot(2,2,4); plot(frame); legend('Peaks in the Window');
hold on; plot(peaks2, '*');
for j = 1 : nframe
if (peaks(j) > 0)
fprintf('Local=%i\n', j);
fprintf('Value=%i\n', peaks(j));
end
end
%Where the Local Maxima occur
[maxivalue, maxi]=max(peaks)
您可以看到所有的峰值及其出现的位置
本地=37
值=3.266296e-001
本地=51
值=4.333496e-002
本地=65
值=5.049438e-001
本地=80
值=4.286804e-001
本地=84
值=3.110046e-001
关于mysql - 如何在半复杂场景中正确检测局部最大值和曲线窗口?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9207559/