Yababaa
Yababaa

Reputation: 577

Scipy Curve_fit function uses initial guess values instead of actually fitting

Im kind of a rookie in programming and especially in curve fitting. But I tried to curve fit a model into some measurements I did with Python and Numpy.

I succeeded in plotting a "fitted" curve into one set of data. Well, it seemed like it did. It turned out that the function just uses the initial guesses and does not try to actually fit a curve. I tested this by using the same initial guesses with different data sets. This was the result:

enter image description here

and the output of fitParams are fitCovariances (which seems to be quite weird values):

[ 540.     2.5    2. ]
[[ inf  inf  inf]
 [ inf  inf  inf]
 [ inf  inf  inf]]

The output of def fitFunc() are just the initial guess values repeatedly.

I first tried my script for the 5th data set, which seemed some what alright. But you can see that every "fitted curve" is exactly the same and it just uses the initial guess.

This is the script:

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

mpl.rcParams['text.usetex']=True
mpl.rcParams['text.latex.unicode']=True

#model
def fitFunc(P_max, x, x_0, w_z):
    print P_max
    print x_0
    print w_z
    return 0.5 * P_max * (1 - scipy.special.erf((scipy.sqrt(2) * (x - x_0)) / w_z))

fig = plt.figure()

#for-loop to read and curve fit for all data sets
for n in range (1,7):
    x_model = np.linspace(-1,6,5000)
    y_model = []
    x = []
    P = []
    name = 'data_' + str(n)
    with open(name + '.csv', 'rb') as f:
        data = csv.reader(f, delimiter = ';')
        for row in data:
            x.append(float(row[1]))
            P.append(float(row[2]))
        fitParams, fitCovariances = curve_fit(fitFunc, np.array(x), np.array(P), [540, 2.5, 2])
        print fitParams
        print fitCovariances

    for i in range(0, len(x_model)):
        y_model.append(fitFunc(fitParams[0], x_model[i], fitParams[1], fitParams[2]))

    ax = fig.add_subplot(2,3,n, axisbg='white')
    ax.scatter(x,P)
    ax.plot(x_model,y_model)
    ax.set_xlim([0, 6])
    ax.set_ylim([0, 600])
    ax.set_xlabel(r'\Delta x')
    ax.set_ylabel(r'P (\mu W)')

plt.tight_layout()
plt.show()

I can't really find what Im doing wrong. I hope you guys can help me. Thanks :)

Note: you can download the data files here to try the script with the same data.

Upvotes: 0

Views: 4477

Answers (1)

Your only problem is the definition of fitFunc. From help(curve_fit):

Parameters
----------
f : callable
    The model function, f(x, ...).  It must take the independent
    variable as the first argument and the parameters to fit as
    separate remaining arguments.

This implies that you have to move your x input to become the first parameter of your function. This only affects 2 lines: your definition of fitFunc,

#def fitFunc(P_max, x, x_0, w_z): #original
def fitFunc(x, P_max, x_0, w_z):
    print(P_max)
    print(x_0)
    print(w_z)
    return 0.5 * P_max * (1 - scipy.special.erf((scipy.sqrt(2) * (x - x_0)) / w_z))

and the explicit call to fitFunc when plotting:

for i in range(0, len(x_model)):
    y_model.append(fitFunc(x_model[i], fitParams[0], fitParams[1], fitParams[2]))

Result: fixed_fits

I think both you and scipy did pretty well :)

Efficiency note:

I don't see a reason why your fitFunc wouldn't work with vector-valued x input (and it does). Which means you can spare the loop over i when plotting the fitted model, you can just say

 y_model = fitFunc(x_model, fitParams[0], fitParams[1], fitParams[2])

Upvotes: 4

Related Questions