Har*_*pal 19 python matplotlib
我一直试图找出蓝色峰的半峰全宽(FWHM)(见图).绿色峰和洋红色峰组合构成蓝色峰.我一直在使用以下等式来找到绿色和洋红色峰的FWHM:fwhm = 2*np.sqrt(2*(math.log(2)))*sd其中sd =标准偏差.我创建了绿色和洋红色的峰值,我知道标准偏差,这就是为什么我可以使用这个等式.
我使用以下代码创建了绿色和洋红色峰:
def make_norm_dist(self, x, mean, sd):
import numpy as np
norm = []
for i in range(x.size):
norm += [1.0/(sd*np.sqrt(2*np.pi))*np.exp(-(x[i] - mean)**2/(2*sd**2))]
return np.array(norm)
Run Code Online (Sandbox Code Playgroud)
如果我不知道蓝峰是由两个峰组成的,而我的数据中只有蓝峰,我怎么能找到FWHM?

我一直在用这段代码找到最高峰:
peak_top = 0.0e-1000
for i in x_axis:
if i > peak_top:
peak_top = i
Run Code Online (Sandbox Code Playgroud)
我可以将peak_top2 除以找到半高,然后尝试找到对应于半高的y值,但是如果没有与半高完全匹配的x值,我会遇到麻烦.
我非常确定我正在尝试的解决方案有更优雅的解决方案.
HYR*_*YRY 14
您可以使用样条曲线拟合[蓝色曲线 - 峰值/ 2],然后找到它的根:
import numpy as np
from scipy.interpolate import UnivariateSpline
def make_norm_dist(x, mean, sd):
return 1.0/(sd*np.sqrt(2*np.pi))*np.exp(-(x - mean)**2/(2*sd**2))
x = np.linspace(10, 110, 1000)
green = make_norm_dist(x, 50, 10)
pink = make_norm_dist(x, 60, 10)
blue = green + pink
# create a spline of x and blue-np.max(blue)/2
spline = UnivariateSpline(x, blue-np.max(blue)/2, s=0)
r1, r2 = spline.roots() # find the roots
import pylab as pl
pl.plot(x, blue)
pl.axvspan(r1, r2, facecolor='g', alpha=0.5)
pl.show()
Run Code Online (Sandbox Code Playgroud)
结果如下:

Fiz*_*ike 13
这在iPython中适用于我(快速和脏,可以减少到3行):
def FWHM(X,Y):
half_max = max(Y) / 2.
#find when function crosses line half_max (when sign of diff flips)
#take the 'derivative' of signum(half_max - Y[])
d = sign(half_max - array(Y[0:-1])) - sign(half_max - array(Y[1:]))
#plot(X[0:len(d)],d) #if you are interested
#find the left and right most indexes
left_idx = find(d > 0)[0]
right_idx = find(d < 0)[-1]
return X[right_idx] - X[left_idx] #return the difference (full width)
Run Code Online (Sandbox Code Playgroud)
可以进行一些添加以使分辨率更准确,但是在X轴上有许多样本并且数据不太嘈杂的限制下,这非常有效.
即使数据不是高斯数据且有点嘈杂,它对我有效(我只是采用第一次和最后一次最大半数交叉数据).
如果您的数据有噪声(并且它总是在现实世界中),那么更强大的解决方案是将高斯数据拟合到数据并从中提取FWHM:
import numpy as np
import scipy.optimize as opt
def gauss(x, p): # p[0]==mean, p[1]==stdev
return 1.0/(p[1]*np.sqrt(2*np.pi))*np.exp(-(x-p[0])**2/(2*p[1]**2))
# Create some sample data
known_param = np.array([2.0, .7])
xmin,xmax = -1.0, 5.0
N = 1000
X = np.linspace(xmin,xmax,N)
Y = gauss(X, known_param)
# Add some noise
Y += .10*np.random.random(N)
# Renormalize to a proper PDF
Y /= ((xmax-xmin)/N)*Y.sum()
# Fit a guassian
p0 = [0,1] # Inital guess is a normal distribution
errfunc = lambda p, x, y: gauss(x, p) - y # Distance to the target function
p1, success = opt.leastsq(errfunc, p0[:], args=(X, Y))
fit_mu, fit_stdev = p1
FWHM = 2*np.sqrt(2*np.log(2))*fit_stdev
print "FWHM", FWHM
Run Code Online (Sandbox Code Playgroud)

绘制的图像可以通过以下方式生成:
from pylab import *
plot(X,Y)
plot(X, gauss(X,p1),lw=3,alpha=.5, color='r')
axvspan(fit_mu-FWHM/2, fit_mu+FWHM/2, facecolor='g', alpha=0.5)
show()
Run Code Online (Sandbox Code Playgroud)
更好的近似将在拟合之前滤除低于给定阈值的噪声数据.
这是使用样条方法的一个很好的小函数.
from scipy.interpolate import splrep, sproot, splev
class MultiplePeaks(Exception): pass
class NoPeaksFound(Exception): pass
def fwhm(x, y, k=10):
"""
Determine full-with-half-maximum of a peaked set of points, x and y.
Assumes that there is only one peak present in the datasset. The function
uses a spline interpolation of order k.
"""
half_max = amax(y)/2.0
s = splrep(x, y - half_max, k=k)
roots = sproot(s)
if len(roots) > 2:
raise MultiplePeaks("The dataset appears to have multiple peaks, and "
"thus the FWHM can't be determined.")
elif len(roots) < 2:
raise NoPeaksFound("No proper peaks were found in the data set; likely "
"the dataset is flat (e.g. all zeros).")
else:
return abs(roots[1] - roots[0])
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
44320 次 |
| 最近记录: |