Python Forum

Full Version: Using curve_fit to optimize function (TypeError)
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hey!

I have some experimental data that I know follows a certain function. My aim is to fit a function (dy) to the data points and get Python to return the offset values.

import math
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from sympy import Symbol,expand

R = 500 

angle = [30, 25, 20, 15, 10, 5]
anglea = np.array(angle)
anglep = np.radians(anglea)
mx = [-63.9995, -46.8970, -30.1635, -17.0550, -7.5885, -1.9195]
mxp = [ -i for i in mx]
rotm = [-22.9025, -17.8256, -12.5980, -7.4375, -2.3605, 2.6498]
rotmp = [ -i for i in rotm]
detx = [236.3400, 181.8725, 129.9995, 84.7125, 49.6145, 27.5625]
dety = [291.7675, 264.1505, 219.0905, 158.4570, 85.4725, 3.4855]
rotd = [45.5153, 35.4343, 25.0553, 14.8258, 4.8003, -5.1288]

#Theoretical & data plots:

#y1 = [500-2*(R/2)*math.cos(x) for x in anglep]
#plt.plot(angle, y1, label='Mx')
#plt.scatter(angle, mxp, label='Mx data')

y2 = [2*R*math.sin(x)*math.cos(x)*math.cos(x) for x in anglep]
#plt.plot(angle, y2, label='Dy')
plt.scatter(angle, dety, label='Dy data')

y3 = [2*R*math.sin(x)*math.sin(x)*math.cos(x) for x in anglep]
#plt.plot(angle, y3, label='Dx')
plt.scatter(angle, detx, label='Dx data')

def dy(x, a, b):
    y = 2*R*math.sin(x+a)*math.cos(x+a)*math.cos(x+a)+b
    return y

popt1, pcov1 = curve_fit(dy, angle, y2)
plt.plot(angle, dy(angle, *popt1), label='Dy: a=%5.3f, b=%5.3f' % tuple(popt1))

plt.xlabel('Alpha')
plt.ylabel('Distance (mm)')
plt.legend()
plt.show()
This returns a TypeError:

    y = 2*R*math.sin(x+a)*math.cos(x+a)*math.cos(x+a)+b

TypeError: only length-1 arrays can be converted to Python scalars
So defining the function this way seems to not work. I wish to get the a & b values returned by the code. x-data is the angle (I'm unsure whether to use 'anglep' which is in radians, or 'angle'), and the experimental y-data is given by y2 (x is the angle). How do I fix the TypeError and get curve_fit to work? Thanks to everyone in advance!
you haven't passed any arguments to function dy
(Aug-29-2021, 07:38 PM)Larz60+ Wrote: [ -> ]you haven't passed any arguments to function dy

You mean x, a, b? a and b I wish to get optimized by *popt1, do I still need to make some guess about the values then before using curve_fit? I suppose
popt1, pcov1 = curve_fit(dy, angle, y2)
is incorrect.
(Aug-30-2021, 05:11 AM)Laplace12 Wrote: [ -> ]
(Aug-29-2021, 07:38 PM)Larz60+ Wrote: [ -> ]you haven't passed any arguments to function dy

You mean x, a, b? a and b I wish to get optimized by *popt1, do I still need to make some guess about the values then before using curve_fit? I suppose
popt1, pcov1 = curve_fit(dy, angle, y2)
is incorrect.

Fixed the TypeError by changing math.sin/math.cos to np.sin/np.cos, apparently it vectorizes the results automatically and there is no error.

I have now defined two functions:

def dy(x, a, b):
    y = 2*R*np.sin(x+a)*np.cos(x+a)*np.cos(x+a)+b
    return y

def dx(x, a, c):
    y = 2*R*np.sin(x+a)*np.sin(x+a)*np.cos(x+a)+c
    return y

popt1, pcov1 = curve_fit(dy, angle, y2)
popt2, pcov2 = curve_fit(dx, angle, y3)

print(popt1)
print(popt2)

plt.plot(angle, dy(angle, *popt1), label='Dy: a=%5.3f, b=%5.3f' % tuple(popt1))
plt.plot(angle, dx(angle, *popt2), label='Dx: a=%5.3f, c=%5.3f' % tuple(popt2))
but I wish for the 'a' parameter to be the same for both functions (we assume that the offset is the same for both directions). How can this be done using curve_fit? Now the code returns optimized values for a for both functions, but I wish to get just one value that's the same for both.
Thank you for the info