我有一个噪声很大的数据,我试图计算出信号的高低包络,有点像MATLAB中的这个例子:
http://uk.mathworks.com/help/signal/examples/signal-smoothing.html
在“提取峰值包络”中。Python中有类似的函数可以做到这一点吗?我的整个项目都是用Python编写的,最坏的情况是我可以提取我的numpy数组并将其扔入MATLAB并使用那个示例。但我更喜欢matplotlib的外观...以及真正的cba在MATLAB和Python之间做所有这些I/O...
谢谢你,
6条答案
按热度按时间06odsfpq1#
第一次尝试是利用scipy Hilbert transform来确定幅度包络,但在许多情况下并不符合预期,主要原因如下:
希尔伯特包络,也称为能量-时间曲线(ETC),只适用于窄带波动。产生一个分析信号,然后取其绝对值,是一个线性运算,所以它平等地对待信号的所有频率。如果你给它一个纯正弦波,它确实会返回给你一条直线。但是,当你给它白噪声,你可能会得到噪声回来。
从那时起,由于其他的答案都是使用三次样条插值法,而且往往会变得很麻烦,有点不稳定(寄生振荡),而且对于非常长和嘈杂的数据阵列来说很耗时,我将在这里提供一个简单而有效的版本,看起来工作得很好:
18867925
样本的复杂得多的信号(此处不包括):ttisahbt2#
Python中是否有类似的函数可以做到这一点?
据我所知,Numpy/Scipy/Python中没有这样的函数,但是创建一个并不困难,大致思路如下:
给定一个值向量:
1.求(s)的峰的位置,我们称之为(u)
1.求s的波谷位置,记为(l)。
1.将模型拟合到(u)值对,我们称之为(u_p)
1.对(l)个值对拟合一个模型,我们称之为(l_p)
1.在(s)的定义域上求(u_p),得到上包络的插值(我们称之为(q_u))
1.在(s)的定义域上求(l_p),得到下包络的插值(我们称之为(q_l))。
如您所见,这是三个步骤(查找位置、拟合模型、评估模型)的序列,但应用了两次,一次用于封套的上部,一次用于封套的下部。
要收集(s)的"峰值",您需要定位(s)的斜率从正变为负的点;要收集(s)的"谷值",您需要定位(s)的斜率从负变为正的点。
峰值示例:s =[4,5,4] 5 - 4为正4 - 5为负
Flume示例:s =[5,4,5] 4 - 5为负值5 - 4为正值
下面是一个示例脚本,让您开始使用大量的内联注解:
这将生成以下输出:
进一步改进的要点:
1.上述代码不 * 过滤 * 峰或谷,这些峰或谷可能出现在比某个阈值"距离"(Tl)(例如时间)更近的地方。这类似于
envelope
的第二个参数。不过,通过检查u_x,u_y
的连续值之间的差异,很容易添加它。1.但是,对前面提到的一个快速改进是使用移动平均滤波器对数据进行低通滤波在插值上下包络函数之前。(s)与一个合适的移动平均滤波器。这里不去太多的细节(如果需要,可以这样做),要产生一个在N个连续样本上运行的移动平均滤波器,您可以这样做:
s_filtered = numpy.convolve(s, numpy.ones((1,N))/float(N)
。(N)值越大,数据显示越平滑。但请注意,由于平滑滤波器的group delay,这会将值向右移动(N/2)个样本(s_filtered
)。有关移动平均值的详细信息,请参阅this link。希望这个有用。
(如果提供了有关原始应用程序的更多信息,我很乐意修改回复。也许可以用更合适的方式对数据进行预处理(?))
czfnxgou3#
基于@A_A的答案,用nim/max测试替换符号检查,使其更健壮。
如果您希望函数递增,请尝试:
用于下包络。
yqlxgs2m4#
或者你用Pandas。这里我只需要两行代码:
nhaq1z215#
您可能想看看希尔伯特变换,它可能是MATLAB中包络函数背后的实际代码。scipy的信号子模块内置希尔伯特变换,文档中有一个很好的示例,其中提取了振荡信号的包络:https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.hilbert.html
23c0lvtd6#
我发现使用scipy函数的组合比其他替代方法性能更好