问题描述
我有一个函数,我检测到了这个函数的峰值。我取了每个峰高度的一半,现在我想找到交点,仅在左侧,函数与经过峰高一半的线之间的交点。
请注意,在下图中,这条线并未完全经过峰的一半。实际上,每个峰都有一个特定的中间高度值,我需要找到左侧与该值的交点。
我的函数值是:
data= [2.50075550e+01 2.68589513e+01 2.88928569e+01 3.05468408e+01
3.17558878e+01 3.28585597e+01 3.41860820e+01 3.56781188e+01
3.68868815e+01 3.72671655e+01 3.65050587e+01 3.47342596e+01
3.24647483e+01 3.02772213e+01 2.84592589e+01 2.68653782e+01
2.51627240e+01 2.33132310e+01 2.18235229e+01 ...]
我使用 SciPy 的 find_peaks 得到了一半的高度
heights.append(signal.find_peaks(data,height=height)[1]['peak_heights'])
#Then calculating the half of each peak
解决方法
以下代码使用 How to find the exact intersection of a curve with y==0? 中的函数 find_roots
。此函数搜索与给定半值对应的精确内插 x 值。该段仅限于前一个峰值和当前峰值之间的间隔,并从结果列表中获取最后一个根(如果有)。
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
def find_roots(x,y):
s = np.abs(np.diff(np.sign(y))).astype(bool)
return x[:-1][s] + np.diff(x)[s] / (np.abs(y[1:][s] / y[:-1][s]) + 1)
np.random.seed(11235)
x = np.linspace(0,20,500)
data = np.convolve(1.1 ** np.random.randn(x.size).cumsum(),np.ones(40),'same')
data -= data.min()
plt.plot(x,data,c='dodgerblue')
peaks,_ = signal.find_peaks(data,height=40,distance=50)
plt.scatter(x[peaks],data[peaks],color='turquoise')
for p,prev in zip(peaks,np.append(0,peaks)):
half = data[p] / 2
roots = find_roots(x[prev:p],data[prev:p] - half)
if len(roots) > 0:
plt.scatter(roots[-1],half,color='crimson')
plt.ylim(ymin=0)
plt.show()
,
我将简单地解释一下通用算法。基本逻辑是,简单地遍历一遍time[s]
值,根据迭代的time[s]
值找到高度值。您需要的唯一数据是该值,无论该值是否等于或大于您想要的相交线值,您都将使用该值。如果信号的高度等于或大于给定的 height
值,则表示存在交点,如果没有,则信号高度肯定小于您想要与信号相交的线值.