Search code examples
pythoncurve-fittingexponential

I can't fit an exponential function in a data set


I have a data set from a laboratory that I did in which I studied the characteristics of current and voltage in a solar panel. The data is a bit inconsistent but it is visible that it is an exponential function. I need to determine the exponential function for my data set.

The exponential formula is this $I=I_s(\exp{\frac{e\cdot U}{k\cdot T}}-1)$. Where e, k, and T are constants.

My code that describes the formula and the data set:

data = [
    (64.5, -2.84),
    (85.4, -2.6),
    (111.7, -2.6),
    (137.1, -2.6),
    (162.3, -2.56),
    (188.1, -2.56),
    (214, -2.56),
    (238, -2.56),
    (262.2, -2.52),
    (283.5, -2.52),
    (367.3, -1.72),
    (388, -0.92),
    (393, -0.64),
    (395, -0.48),
    (399.3, -0.38),
    (400, -0.2)
]

# unpack the data into separate arrays
U_1, I_1 = zip(*data)
def exponential(x, a, b):
    print(a*(np.exp(b*x)-1))
    return a*(np.exp(b*x)-1)

I plot it like this:

# fit the curve to the data, using the weights
params, params_covariance = curve_fit(exponential, U_1, I_1,p0=initial_params)
# plot the data and the fit
plt.plot( U_1, I_1,'bo', label='data')

# compute the fitted curve point by point
U_1_fit = np.linspace(min(U_1), max(U_1), 1000)
I_1_fit = exponential(U_1_fit, *params)
plt.plot(U_1_fit, I_1_fit, 'r', label='fit')

The exponential function was in the millions so I gave an initial parameter:

initial_params = [0, -3]

It is stuck, for some reason, on the value -1.89125. I tried different methods and they didn't work or gave me the same answer of -1.89125. I just need to be an exponential that makes sense for my data.


Solution

  • You need to add a third parameter c to make your model more flexible. Then, the initial value for b is wrong, it cannot be negative.

    import numpy as np
    from matplotlib import pyplot as plt
    from scipy.optimize import curve_fit
    
    data = [
        (64.5, -2.84),
        (85.4, -2.6),
        (111.7, -2.6),
        (137.1, -2.6),
        (162.3, -2.56),
        (188.1, -2.56),
        (214, -2.56),
        (238, -2.56),
        (262.2, -2.52),
        (283.5, -2.52),
        (367.3, -1.72),
        (388, -0.92),
        (393, -0.64),
        (395, -0.48),
        (399.3, -0.38),
        (400, -0.2)
    ]
    
    data = np.array(data)
    x = data[:, 0]
    y = data[:, 1]
    
    def f(x, a, b, c):
        return a * (np.exp(b * x) - 1) + c
    
    p0 = [1, 0.02, 0]
    popt, pcov = curve_fit(f, x, y, p0=p0)
    
    plt.scatter(x, y)
    xx = np.linspace(50, 400, 1000)
    plt.plot(xx, f(xx, *popt))
    plt.show()
    

    enter image description here