Unable to do fitting of data using curve_fit()

Viewed 59

I want to fit the function ax +blog((x-x0)/c) with data mentioned in the txt file. The x-axis is the injected current and y axis is the gain_X. I was using the function curve_fit() , but it does not works and says "Optimal parameters not found: Number of calls to function has reached maxfev = 1000000". I have attached my code below and the text file can be viewed with the link. Can you help me in fitting the data?

import matplotlib.pyplot as plt
import pandas as pd
from scipy.optimize import curve_fit
import numpy as np
import scipy.optimize as opt
def func(x, a, b, c,x0):
    return a*x+b*np.log((x-x0)/c)

data1 = pd.read_csv(r'C:\Users\TanviPradhan\OneDrive - EFFECT Photonics\Desktop\CD581379_A-12469303362S__GAIN_DIODE_TEST__2021-08-03_16.57.36.txt',skipinitialspace=True,comment="%")
print(data1)


#Creates one figure for the plots
fig =  plt.figure(figsize=(7,14))
fig.suptitle('Wafer xx')
#Creates the subplots 1x2 plots 1st plot is 121
ax_X= fig.add_subplot(211)
plt.xlabel("Injected Current (mA)")
plt.ylabel("Measured voltage (V)")
ax_X.set_title('xx')
#ax_X.set(xlim=(0, 80), ylim=(0, 1.5))
plt.grid(True)




#add plot for each chip to total plot

ax_X.plot(data1["InjectedCurrent(mA)"],data1["GAIN_X(V)"])

x = data1["InjectedCurrent(mA)"]
y = data1["GAIN_X(V)"]

#training the data
train_x = x[:80]
train_y = y[:80]

#testing the data
test_x = x[80:]
test_y = y[80:]

plt.scatter(train_x, train_y)
plt.show()


plt.scatter(test_x, test_y)
plt.show()

#fitting_data
params,popt = curve_fit(func,x,y,maxrev=1000000)
2 Answers

As @Ammon already mentioned, providing a reasonable initial guess, and boundaries (if possible) really helps a lot. Excluding values for x=0 might also help the function behave a little better.

p0 = [0.002, 0.05, 0.001, 0.0]
bounds = (
    [0.0001, 0.0001, 0.0,     0.0], # lower
    [0.1,    0.1,    0.1,     0.5], # upper
)
params, popt = curve_fit(func, x[x>0], y[x>0], p0=p0, bounds=bounds)

This results in the fitted parameters:

array([3.27556699e-03, 5.76995401e-02, 1.56406668e-05, 2.80572662e-01])

This is just an example, but already shows that with a reasonable initial guess, you get a pretty good fit, but still not perfect. Hopefully this shows you how to apply the curve_fit function.

I'm not familiar with the function you're using, so you might be able to improve by incorporating better knowledge for the initial guess and boundaries.

enter image description here

edit: Complete snippet:

Imports and reading input data:

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

data1 = pd.read_csv(r'D:\CD581379_A-12469303362S__GAIN_DIODE_TEST__2021-08-03_16.57.36.TXT', skipinitialspace=True, comment="%")
x = data1["InjectedCurrent(mA)"]
y = data1["GAIN_X(V)"]

Fitting function:

def func(x, a, b, c, x0):
    return a*x+b*np.log((x-x0)/c)

#fitting_data
p0 = [0.002, 0.05, 0.001, 0.0]
bounds = (
    [0.0001, 0.0001, 0.0,     0.0], # lower
    [0.1,    0.1,    0.1,     0.5], # upper
)
params, popt = curve_fit(func, x[x>0], y[x>0], p0=p0, bounds=bounds)

Plot result:

#Creates one figure for the plots
fig, ax =  plt.subplots(figsize=(5,5), constrained_layout=True, dpi=86, facecolor='w')
fig.suptitle('Wafer xx')

ax.set_xlabel("Injected Current (mA)")
ax.set_ylabel("Measured voltage (V)")
ax.set_title('xx')
ax.grid(True)

ax.plot(x, y, 'k--', label='all data')

ax.plot(x, func(x, *p0), label='init guess', lw=2)
ax.plot(x, func(x, *params), label='fit', lw=2)

ax.legend(loc=4)
Related