Elad Joseph
Elad Joseph

Reputation: 3058

How to force specific points in curve fitting

I want to do a curve fitting, but with constrained limits.

My data is a calibration from 0-255 values to 0-1. I want to force the fit function to go through the points (0,0) and (255,1).

My current code:

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

def model_func(x, a, b, c):    
    return a*(np.exp(x*b)) + c   

if __name__ == "__main__":
    #=== Fit Curve
    x = np.array([0, 20, 56, 65, 110, 122, 168, 179, 202, 203, 210, 211, 217, 220, 221, 223, 240, 255])
    y = np.array([0, 0.015, 0.02, 0.0 , 0.08, 0.08, 0.22, 0.28, 0.43, 0.5, 0.51, 0.64, 0.65, 0.74, 0.82, 0.84, 0.88, 1])
    popt, pcov = curve_fit(model_func, x, y, p0=(0.1 ,1e-3, 0.1))

    #=== Plot
    plt.figure()
    plt.scatter(x, y)
    xdata = np.linspace(0, 255, 1000)
    plt.plot(xdata, model_func(xdata, popt[0], popt[1], popt[2]))
    text = "$f(x)=ae^{b*x}+c$ | a=%.3f, b=%.3f, c=%.3f" % (popt[0],popt[1],popt[2])
    plt.annotate(text, xy=(0.03, 0.95), xycoords='axes fraction', fontsize=12)
    plt.xlim([0,255])
    plt.ylim([0,1])
    plt.grid()

Gives the following fit:

Fit plot

Upvotes: 3

Views: 6107

Answers (1)

Elad Joseph
Elad Joseph

Reputation: 3058

Similar to this answer, the easiest way I found is to use the sigma parameter, to give substantial higher weight to the first and last points.

I added this:

sigma = np.ones(len(x))
sigma[[0, -1]] = 0.01
popt, pcov = curve_fit(model_func, x, y, p0=(0.1 ,1e-3, 0.1), sigma=sigma)

And now my fit looks like I wanted:

enter image description here

Upvotes: 8

Related Questions