Python中有没有类似的函数可以做到这一点?
据我所知,Numpy / Scipy / Python 中没有这样的功能。但是,创建一个并不难。大致思路如下:
给定一个值向量:
- 查找 (s) 峰的位置。我们就叫他们(u)
- 查找 s 波谷的位置。我们称它们为 (l)。
- 将模型拟合到 (u) 值对。我们称之为 (u_p)
- 将模型拟合到 (l) 值对。我们称之为 (l_p)
- 在 (s) 的域上评估 (u_p) 以获得上包络的插值。 (我们称它们为 (q_u))
- 在 (s) 的域上评估 (l_p) 以获得下包络的插值。 (我们称它们为 (q_l))。
如您所见,它是三个步骤(查找位置、拟合模型、评估模型)的顺序,但应用了两次,一次用于信封的上部,一次用于下部。
要收集 (s) 的“峰值”,您需要定位 (s) 的斜率从正变为负的点,并收集 (s) 的“谷”,您需要定位斜率所在的点(s) 由负变为正。
峰值示例:s = [4,5,4] 5-4 为正 4-5 为负
一个低谷示例:s = [5,4,5] 4-5 是负数 5-4 是正数
这是一个示例脚本,可帮助您开始使用大量内联 cmets:
from numpy import array, sign, zeros
from scipy.interpolate import interp1d
from matplotlib.pyplot import plot,show,hold,grid
s = array([1,4,3,5,3,2,4,3,4,5,4,3,2,5,6,7,8,7,8]) #This is your noisy vector of values.
q_u = zeros(s.shape)
q_l = zeros(s.shape)
#Prepend the first value of (s) to the interpolating values. This forces the model to use the same starting point for both the upper and lower envelope models.
u_x = [0,]
u_y = [s[0],]
l_x = [0,]
l_y = [s[0],]
#Detect peaks and troughs and mark their location in u_x,u_y,l_x,l_y respectively.
for k in xrange(1,len(s)-1):
if (sign(s[k]-s[k-1])==1) and (sign(s[k]-s[k+1])==1):
u_x.append(k)
u_y.append(s[k])
if (sign(s[k]-s[k-1])==-1) and ((sign(s[k]-s[k+1]))==-1):
l_x.append(k)
l_y.append(s[k])
#Append the last value of (s) to the interpolating values. This forces the model to use the same ending point for both the upper and lower envelope models.
u_x.append(len(s)-1)
u_y.append(s[-1])
l_x.append(len(s)-1)
l_y.append(s[-1])
#Fit suitable models to the data. Here I am using cubic splines, similarly to the MATLAB example given in the question.
u_p = interp1d(u_x,u_y, kind = 'cubic',bounds_error = False, fill_value=0.0)
l_p = interp1d(l_x,l_y,kind = 'cubic',bounds_error = False, fill_value=0.0)
#Evaluate each model over the domain of (s)
for k in xrange(0,len(s)):
q_u[k] = u_p(k)
q_l[k] = l_p(k)
#Plot everything
plot(s);hold(True);plot(q_u,'r');plot(q_l,'g');grid(True);show()
这会产生这个输出:
进一步改进的要点:
上述代码不会过滤可能出现在比某个阈值“距离”(Tl)(例如时间)更近的峰或谷。这类似于envelope的第二个参数。通过检查u_x,u_y 的连续值之间的差异,很容易添加它。
但是,对前面提到的一点的快速改进是使用移动平均滤波器在插入上包络函数和下包络函数来对数据进行低通滤波。您可以通过将您的 (s) 与合适的移动平均滤波器进行卷积来轻松做到这一点。无需在这里详细介绍(如果需要,可以这样做),要生成对 N 个连续样本进行操作的移动平均滤波器,您可以执行以下操作:s_filtered = numpy.convolve(s, numpy.ones((1,N))/float(N)。 (N) 越高,您的数据就越平滑。但是请注意,由于平滑滤波器的称为group delay 的东西,这会将您的 (s) 值 (N/2) 样本向右移动(在s_filtered 中)。有关移动平均线的更多信息,请参阅this link。
希望这会有所帮助。
(如果提供有关原始应用程序的更多信息,很高兴修改响应。也许可以以更合适的方式对数据进行预处理(?))