def fit_exponential(series, *, p0=(1.0, 0.01, 0.0), n0: float = None):
"""
Fits an exponential to a series. First attempts an exponential fit in linear space using p0, then falls back to a
fit in log space to attempt to find parameters p0 for a linear fit; if all else fails returns the linear fit.
"""
if n0 is None:
fit_fn = exponential
else:
def exponential_constrain_n0(x, a, b):
return a * numpy.exp(b * x) + n0
fit_fn = exponential_constrain_n0
p0 = p0[:2]
try:
popt, pcov = curve_fit(fit_fn, series.index, series.values, p0=p0, maxfev=10000)
if n0 is not None:
popt = tuple(popt) + (n0,)
except RuntimeError:
pass
else:
slope = popt[1]
intercept = numpy.log(1 / popt[0]) / slope
N0 = popt[2]
if slope >= 0:
snr = signal_noise_ratio(series, *popt)
return slope, intercept, N0, snr, False
log_series = numpy.log(series[series > 0] - (n0 or 0.0))
slope, c, *__ = linregress(log_series.index, log_series.values)
intercept = - c / slope
if n0 is None:
p0 = (numpy.exp(c), slope, 0.0)
else:
p0 = (numpy.exp(c), slope)
try:
popt, pcov = curve_fit(fit_fn, series.index, series.values, p0=p0, maxfev=10000)
if n0 is not None:
popt = tuple(popt) + (n0,)
except RuntimeError:
snr = signal_noise_ratio(series, c, slope, 0.0)
return slope, intercept, (n0 or 0.0), snr, True
else:
slope = popt[1]
intercept = numpy.log(1 / popt[0]) / slope
n0 = popt[2]
snr = signal_noise_ratio(series, *popt)
return slope, intercept, n0, snr, False
评论列表
文章目录