I am trying to fit a data set to this monster of an equation. I know this has been asked before, but I don't think initial guesses are my problem, nor can I add more terms to my fitting equation.
My fitting equation. Note the "u" in the integral is NOT the same u as defined up top.
My data set is in mA/um, by the way.
I implemented this in a function F, which takes inputs Vd,T,r, and Vt. T,r,and Vt are fitting parameters. T and r range from 0
My first few programs had horrible fits (if it could even accomplish the integral), so I decided to see if the algorithm even works. The function's implementation is as follows:
from scipy import integrate
from scipy.optimize import curve_fit
import numpy as np
import matplotlib.pyplot as plt
#Constants
eSiO2 = 3.9 #Relative dielectric constant of SiO2
tox = 2e-9 #Gate oxide thickness in m
evac = 8.854e-12 #Vacuum permittivity, F/m
em = 0.2*9.11e-31 #Effective electron mass in kg
KT = 4.11e-21 #Thermal energy in joules
Mv = 2.5 #Degeneracy factor
q = 1.6e-19 #Electron charge, coulombs
hbar = 1.054e-34 #Reduced plancks constant
Vg = 1
def F(Vd,T,r,Vt):
#Derived constants required for computation
Ci = (eSiO2*evac)/tox #Oxide capacitance per area
ved = (q*r*Vd)/(KT) #little Vd
I0 = (np.sqrt(2)*q*(KT**1.5)*Mv*np.sqrt(em))/(np.pi*hbar)**2 #Leakage Current
#Rho
rho1 = 2*np.pi*hbar**2*Ci
rho2 = q*KT*em*Mv
rhoV = Vg-Vt
rho = (rho1*rhoV)/rho2
#u
UA = 1 + np.exp(ved)
UB = np.exp(ved)*(np.exp(rho)-1)
Usq = np.sqrt(UA**2+4*UB)
u = np.log(Usq-UA)-np.log(2)
#Integrand of F(u)
def integrand1(A,x):
return (np.sqrt(A))/(1+np.exp(A-x))
#Integrand of F(u-v)
def integrand2(A,x):
return (np.sqrt(A))/(1+np.exp(A-x))
sum1 = 0
sum2 = 0
tempy1=[]
tempy2=[]
tempx2=[]
#Tempx2 = dummy variable domain
tempx2 = np.linspace(0,100,num=10000)
#Fitting parameters are determined
if Ready is True:
#Evaluate the integrands for all the Vd values
tempy1 = integrand1(tempx2,u)
tempy2 = integrand2(tempx2,u-ved)
#Fitting parameters are NOT determined
else:
print ("Calculating")
#Evaluate the integrands for all the Vd values
for i in range (0,len(u)):
tempy1 = integrand1(tempx2,u[i])
tempy2 = integrand2(tempx2,u[i]-ved[i])
#Perform integration over dummy domain
sum1 = integrate.simps(tempy1,tempx2,0.1)
sum2 = integrate.simps(tempy2,tempx2,0.1)
if Ready is False:
print ("u=%s" %u,"ved=%s" %ved)
print ("Sum1 is %s" %sum1)
return I0*T*1e-3*(sum1-sum2)
The function will compute F(x,T,r,Vt) if T,r, and Vt are specified. So I decided to make a "sample" data set to see if it will fit itself nearly perfectly:
#Create domain for reference curve
Ready = True
x = np.linspace(0,1.2,50)
y=[]
#Evaluate the reference curve domain
for j in range (0,50):
y.append(F(x[j],0.2,0.147,0.45))
Now that the reference curve is created, the curve will now attempted to be fit. Note how my p0 values are extremely close to the real values.
#Guesses for the curve fit
initial = [0.21,0.15,0.46]
Ready = False
#Attempt to fit the reference curve
popt, popc = curve_fit(F,x,y,initial,bounds=(0,1))
#Create the fit curve
fitdata=[]
Ready = True
for i in range (0,50):
fitdata.append(F(x[i],popt[0],popt[1],popt[2]))
And then plot both the reference and the fit curve. Yet, the fit curve is poor even though the p0 values are really close to the actual ones. I saw that people had problems with that in previous StackOverflow posts.
plt.plot(x,y,label='Reference')
plt.plot(x,fitdata,label='Fit')
plt.legend()
plt.show()
Here is the plot:
I've found that it's at least useful to picking some parameters to then manually guess and check with for the final fit. It's just so odd that it can't even fit itself even if curve_fit is basically with touching distance of the best fit parameters.
Due to the complexity of this fitting equation, will I have to do that? I did nearly the exact same computation with a quadratic fit (for a different project) on real data, and getting an appropriate curve was trivial.