scipy 如何对指数函数进行正确的曲线拟合?

ufj5ltwl  于 2022-12-13  发布在  其他
关注(0)|答案(1)|浏览(236)

在一个实验中,我测量了通过二极管的电压(V)和电流(I),最终计算出玻尔兹曼常数。
其结果是一个指数函数,由关系式I = a(e^(bV)-1)得出。
当我创建一个曲线拟合通过我的测量,y轴(I)在一个对数刻度,它没有通过他们在所有。这是我的代码:

V=np.array([0.015,0.060,0.108,0.162,0.214,0.268,0.313,0.351,0.381,0.417,0.455,0.517,0.545,0.582,0.604])
I=np.array([0.0200,0.0800,0.2000,0.6200,1.6900,4.8400,11.5800,24.5000,44.3400,90.4000,183.3000,505.5000,744.3800,1149.0500,1346.6000])/1000000

def func(x,a,b,c):
    y = a*(np.exp(b*x)-1)
    return y

popt,pcov = curve_fit(func,V,I,p0=[3.651e-9,19.77])

V_cf = np.linspace(np.min(V),np.max(V),1000)
I_cf = func(V_cf,*popt)

plt.figure()
plt.plot(V,I,'k.', label='Measurements')
plt.plot(V_cf,I_cf,'m--',linewidth=1)
plt.xlabel("$V$ (V)")
plt.ylabel("$I$ (A)")
plt.yscale('log')
plt.grid()
plt.legend(loc='upper left')
plt.show()

我如何使它在我的图中正确地通过我的测量点?为什么曲线拟合在我的图中不会成为一条直线,y在对数刻度上?
我的测量图和曲线拟合x1c 0d1x
通过添加p0=[3.651e-9,19.77]

改进绘图

k75qkfdt

k75qkfdt1#

您的示例不起作用,因为您的函数采用了三个参数abc(尽管未使用c),但您仅通过scipy.optimize.curve_fitp0参数给予了两个初始猜测。
除此之外,您不能期望函数$f(x)= a当取两边的对数时,得到$\log{f} = \log{\exp{-bx}- 1} + log{a}$,它不像直线的形式,$y = mx + c$。移除$-1$将给予一条斜率为$-B$且截距为$\log{a}$的直线:$\log{f} = -bx + \log{a}$.
下面的代码能完成您想要的任务吗?

import numpy as np
from matplotlib import pyplot as plt
from scipy.optimize import curve_fit

voltage = np.array([0.015, 0.060, 0.108, 0.162, 0.214, 0.268, 0.313, 0.351, .381, 0.417, 0.455, 0.517, 0.545, 0.582, 0.604])
current = np.array([0.0200, 0.0800, 0.2000, 0.6200, 1.6900, 4.8400, 11.5800, 24.5000, 44.3400, 90.4000, 183.3000, 505.5000, 744.3800, 1149.0500, 1346.6000]) / 1e6

def fexp(x, a, b):
    return a * np.exp(b * x)

def fexp_yshift(x, a, b):
    return a * (np.exp(b * x) - 1)

popt, pcov = curve_fit(fexp, xdata=voltage, ydata=current, p0=[3.651e-9, 19.77])
popt_shift, pcov_shift = curve_fit(fexp_yshift, xdata=voltage, ydata=current, p0=[3.651e-9, 19.77])

x = np.linspace(np.min(voltage), np.max(voltage), 1000)
fit = fexp(x, *popt)
fit_shift = fexp_yshift(x, *popt_shift)

plt.plot(voltage, current, "k.", label="Measurement")
plt.plot(x, fit, "m--", label="Model")
plt.plot(x, fit_shift, "c-.", label="Model with Shift")
plt.xlabel("Voltage $V$ / V")
plt.ylabel("Current $I$ / A")
plt.grid()
plt.legend(loc='upper left')
plt.show()

plt.plot(voltage, current, "k.", label="Measurement")
plt.plot(x, fit, "m--", label="Model")
plt.plot(x, fit_shift, "c-.", label="Model with Shift")
plt.xlabel("Voltage $V$ / V")
plt.ylabel("Current $I$ / A")
plt.yscale('log')
plt.grid()
plt.legend(loc='upper left')
plt.show()

输出量:

对不起,我不知道如何添加数学公式堆栈溢出后。

EDIT:我刚刚意识到这并没有回答如何提高拟合的质量。要得到更好的拟合,直接用直线拟合电流的对数:

import numpy as np
from matplotlib import pyplot as plt
from scipy.optimize import curve_fit

voltage = np.array([0.015, 0.060, 0.108, 0.162, 0.214, 0.268, 0.313, 0.351, .381, 0.417, 0.455, 0.517, 0.545, 0.582, 0.604])
current = np.array([0.0200, 0.0800, 0.2000, 0.6200, 1.6900, 4.8400, 11.5800, 24.5000, 44.3400, 90.4000, 183.3000, 505.5000, 744.3800, 1149.0500, 1346.6000]) / 1e6
current_log = np.log10(current)

def line(x, m, c):
    return m * x + c

popt, pcov = curve_fit(line, xdata=voltage, ydata=current_log)
fit = line(voltage, *popt)

plt.plot(voltage, current_log, "k.", label="Measurement")
plt.plot(voltage, fit, "m--", label="Model")
plt.xlabel("Voltage $V$ / V")
plt.ylabel("Logarithmic Current $\log{(I / \mathrm{A})}$")
plt.grid()
plt.legend(loc='upper left')
plt.show()

输出量:

相关问题