Reputation: 3
Written this code to try and plot a a graph of y = a(1 + cos(bx - pi)) + c to our data collected but when using np.cos it tries to fit an entire cycle of cos onto the data, which doesn't fit our results. Any help on how to fit only a section of the curve to our data would be fab!
Tried to avoid using cos by using maclaurin series expansion but this still doesn't work.
x_data = w
y_data = mean
e = error
from scipy import optimize
def test_func(x, a, b, c):
y = (a/2)*(1 + (1 - (1/2)*(b*x - np.pi)**2 + (1/24)*(b*x - np.pi)**4)) + c
return y
params, params_covariance = optimize.curve_fit(test_func, x_data, y_data)
print(params)
a = params[0]
b = params[1]
c = params[2]
figure(num=None, figsize=(12, 6), dpi=80, facecolor='w', edgecolor='k')
plt.errorbar(x_data, y_data, yerr=e, fmt='o', marker='o', label='Data', markersize=3, color='k', elinewidth=1, capsize=2, markeredgewidth=1)
plt.plot(x_data, test_func(x_data, params[0], params[1], params[2]), label='Fitted function')
plt.legend(loc='best')
plt.ylabel('Interference intensity, $I$')
plt.xlabel('Rotational velocity of interferometer, $w$')
plt.show()
Upvotes: 0
Views: 2225
Reputation: 3290
Your question is "how to fit only a section of a curve to our data." This can be accomplished by defining a piece-wise function and fitting a section of your data to each corresponding piece of the function. You need to define the cut-off values that separate the parts of your data and pick which functions to fit to each part.
In order to fit a curve to only a section of the data, you need to only pass the portion of the data to curve_fit that you want to fit. Here are working examples of fitting the data to both a Maclaurin series and a cosine function:
from scipy import optimize
# Generate sample data
np.random.seed(0)
x_data = np.linspace(-np.pi,3*np.pi,101)
y_data = np.cos(x_data) + np.random.rand(len(x_data))/4
idx = (x_data < 0) | (x_data > 2*np.pi)
y_data[idx] = 1 + np.random.rand(sum(idx))/4
e = np.random.rand(len(x_data))/10
# Select part of data to fit
fit_part = ~idx
x_data_to_fit = x_data[fit_part]
y_data_to_fit = y_data[fit_part]
def test_func(x, a, b):
y = a*np.cos(b*x)
return y
params, params_covariance = optimize.curve_fit(test_func, x_data_to_fit, y_data_to_fit)
print(params)
a = params[0]
b = params[1]
plt.figure(num=None, figsize=(12, 6), dpi=80, facecolor='w', edgecolor='k')
plt.title('Cosine Function Fit')
plt.errorbar(x_data, y_data, yerr=e, fmt='o', marker='o', label='Data', markersize=3, color='k', elinewidth=1, capsize=2, markeredgewidth=1)
plt.plot(x_data_to_fit, test_func(x_data_to_fit, a, b), label='Fitted function')
plt.legend(loc='best')
plt.ylabel('Interference intensity, $I$')
plt.xlabel('Rotational velocity of interferometer, $w$')
plt.show()
def test_func(x, a, b, c):
y = (a/2)*(1 + (1 - (1/2)*(b*x - np.pi)**2 + (1/24)*(b*x - np.pi)**4)) + c
return y
params, params_covariance = optimize.curve_fit(test_func, x_data_to_fit, y_data_to_fit)
print(params)
a = params[0]
b = params[1]
c = params[2]
plt.figure(num=None, figsize=(12, 6), dpi=80, facecolor='w', edgecolor='k')
plt.title('MacLaurin Series Fit')
plt.errorbar(x_data, y_data, yerr=e, fmt='o', marker='o', label='Data', markersize=3, color='k', elinewidth=1, capsize=2, markeredgewidth=1)
plt.plot(x_data_to_fit, test_func(x_data_to_fit, a, b, c), label='Fitted function')
plt.legend(loc='best')
plt.ylabel('Interference intensity, $I$')
plt.xlabel('Rotational velocity of interferometer, $w$')
plt.show()
The cosine function matches the data better than the Maclaurin series in this case because the data was generated using a cosine function.
Upvotes: 1