-1

I try to fit this experimental data with a square root function, using python and the module scipy.optimize. The code for plotting and fitting looks like this.

def curve(x, a, b): 
    return np.sqrt(a+b*x)

xaxis = np.linspace(30, 1400, 10000)
farbe = ['tab:green', 'tab:orange', 'tab:blue']
fill = ['left', 'top', 'none']

k = 0
for i in data: 
    popt, pcov = curve_fit(curve, data[i].velo, data[i].avgFR)

    plt.errorbar(data[i].velo, data[i].avgFR,data[i].avgFRError, xerr=None, 
                  fmt="o", fillstyle = fill[k],alpha = 0.9,markersize=8,
                  markeredgewidth=2,
                  linewidth=3,   # width of plot line
                  elinewidth=2,# width of error bar line
                  capsize=5,     # cap length for error bar
                  capthick=1,   # cap thickness for error bar
                  label = str(i), 
                  color = farbe[k])   
    plt.plot(xaxis, curve(xaxis, *popt),color = farbe[k], linewidth = 3)
    k += 1

#plt.xscale('log')
plt.legend()
plt.show()

If i execute the script the fit looks like this. What is going wrong? Is there a better way to fit my data with a square root function?

Edit: I get the following message:

__main__:2: RuntimeWarning: invalid value encountered in sqrt
__main__:2: RuntimeWarning: invalid value encountered in sqrt
__main__:2: RuntimeWarning: invalid value encountered in sqrt
123einhundert
  • 25
  • 1
  • 7
  • You'll get that warning when inputs to the sqrt function are negative. You will probably want to constrain the data by specifying bounds to the `curve_fit` function. – bnaecker May 14 '20 at 17:16

3 Answers3

1

What happens is: a+b*x < 0.

You can set bounds for the fit.

You can check if this inequality happens and return values very different from your data in that case.

You can can use other fitting routine, maybe lmfit will help.

rpoleski
  • 988
  • 5
  • 12
1

I suspect that during optimization for your model parameters (a,b) given you data, the optimizer is forced to evaluate a negative number under a square root ie.

f = sqrt(a+bx) where a+bx < 0

If this is the case, you can address the issue by passing the bounds argument to curve fit and enforce that b>0 (since x>0).

popt, pcov = curve_fit(curve, data[i].velo, data[i].avgFR,bounds=(0, [1, 1]))

which would constrain the problem to 0 <= a <= 1, 0 <= b <= 1. Make sure to choose these bounds appropriately for your problem. Good luck!

Douw Marx
  • 21
  • 3
0

I know it is not the most elegant solution, but at least it works. Instead of fitting the sqrt data i descided to calculate the square of the data and fit it with a linear function the result it self looks decent.

123einhundert
  • 25
  • 1
  • 7