Fitting sine curve to data

Dear matlab community,
I'm tring to fit a few data points to the following equation (i.e.: "y = a+b*sin(x-c)")
my "x" and "y" values are:
x = [0,15,30,45,60,75,90,105,120,135,150,165,180,195,210,225,240,255,270,285,300,315,330,345,360];
y = [-0.267268221867135,-0.224927234804625,-0.189541103134544,-0.138342286610894,-0.0566423048346959,0.00234570638697967,0.0651873879993542,0.127045214064366,0.187359039666987,0.221423324938789,0.256601680672827,0.255278492431207,0.267669889966578,0.232962110292877,0.197299723252563,0.130461415017413,0.0624973744048143,-0.00389440045935707,-0.0720465871266569,-0.132628373295696,-0.194175941787212,-0.234779045975818,-0.254184352991033,-0.252575588397041,-0.245570829777601];
So far I tried to use the custom equation from the curve fitting tool. Yet, the curve is not properly adjusted. Yet, by using the "sum of sin" fitting tool, it works well. However with a diferent equations ("y = a*sin(b*x+1)").
I found some information posted by @Star Strinder showing a way to fit the data to an equation like a +b*sin(2*pi*x./c + d). The code works fine. Yet the equation is still diferent from the one I want.
Is it possible to rearrange the code to get the equation I want?
The code is below:
yu = max(y);
yl = min(y);
yr = (yu-yl); % Range of ‘y’
yz = y-yu+(yr/2);
zx = x(yz .* circshift(yz,[0 1]) <= 0); % Find zero-crossings
per = 2*mean(diff(zx)); % Estimate period
ym = mean(y); % Estimate offset
fit = @(b,x) b(1).*(sin(2*pi*x./b(2) + 2*pi/b(3))) + b(4); % Function to fit
fcn = @(b) sum((fit(b,x) - y).^2); % Least-Squares cost function
s = fminsearch(fcn, [yr; per; -1; ym]) % Minimise Least-Squares
xp = linspace(min(x),max(x));
figure(1)
plot(x,y,'b', xp,fit(s,xp), 'r')
grid

 Accepted Answer

Is it possible to rearrange the code to get the equation I want?
Yes, however it is not as good a fit as with the original ‘fit’ function —
x = [0,15,30,45,60,75,90,105,120,135,150,165,180,195,210,225,240,255,270,285,300,315,330,345,360];
y = [-0.267268221867135,-0.224927234804625,-0.189541103134544,-0.138342286610894,-0.0566423048346959,0.00234570638697967,0.0651873879993542,0.127045214064366,0.187359039666987,0.221423324938789,0.256601680672827,0.255278492431207,0.267669889966578,0.232962110292877,0.197299723252563,0.130461415017413,0.0624973744048143,-0.00389440045935707,-0.0720465871266569,-0.132628373295696,-0.194175941787212,-0.234779045975818,-0.254184352991033,-0.252575588397041,-0.245570829777601];
yu = max(y);
yl = min(y);
yr = (yu-yl); % Range of ‘y’
yz = y-yu+(yr/2);
zx = x(yz .* circshift(yz,[0 1]) <= 0); % Find zero-crossings
per = 2*mean(diff(zx)); % Estimate period
ym = mean(y); % Estimate offset
% fit = @(b,x) b(1).*(sin(2*pi*x./b(2) + 2*pi/b(3))) + b(4); % Function to fit
fit = @(b,x) b(1) + b(2).*sin(b(3)*x+1);
% fcn = @(b) sum((fit(b,x) - y).^2); % Least-Squares cost function
% s = fminsearch(fcn, [yr; per; -1; ym]) % Minimise Least-Squares
s = fminsearch(@(b) norm(y-fit(b,x)), [ym yr 1/per])
s = 1×3
-2.8924 3.0816 0.0033
xp = linspace(min(x),max(x));
figure(1)
plot(x,y,'b', xp,fit(s,xp), 'r')
grid
text(70, -0.18, sprintf('$y = %.3f + %.3f\\ sin(%.6f\\cdot x+1)$', s), 'Interpreter','latex')
Make appropriate changes to get different results.
.

4 Comments

Dear Star Strinder,
thank you for your reply.
The fit you provided is not the one I'm looking for, that is: "y = a+b*sin(x-c)"
The one you provide is the one I found in the "sum of sine", present in the curve fitting tool, "y = a*sin(b*x+c)".
Do you think that this equation will now fit the data?
However with a diferent equations ("y = a*sin(b*x+1)").
is the function yuou specified in your Question. The code I wrote fits it (as well as it can).
The one you are looking for, "y = a+b*sin(x-c)", will not fit the data because it is missing the frequency term. Unless you are extremely lucky (and you are not in this instance, since the frequency is about -0.0094, not 1), that model will noit fit the data.
I will delete my Answer is a few minutes, since there is absolutely no possibility the model you want will fit the data you posted.
.
Dear Star Strider,
Thank you again for your response. I pick up the equation from a journal paper without thinking on it. You are right, this equation makes no sense for data where the frequency is different than 1.
I will try to use your old code for fitting the equation.
Then try this —
x = [0,15,30,45,60,75,90,105,120,135,150,165,180,195,210,225,240,255,270,285,300,315,330,345,360];
y = [-0.267268221867135,-0.224927234804625,-0.189541103134544,-0.138342286610894,-0.0566423048346959,0.00234570638697967,0.0651873879993542,0.127045214064366,0.187359039666987,0.221423324938789,0.256601680672827,0.255278492431207,0.267669889966578,0.232962110292877,0.197299723252563,0.130461415017413,0.0624973744048143,-0.00389440045935707,-0.0720465871266569,-0.132628373295696,-0.194175941787212,-0.234779045975818,-0.254184352991033,-0.252575588397041,-0.245570829777601];
yu = max(y);
yl = min(y);
yr = (yu-yl); % Range of ‘y’
yz = y-yu+(yr/2);
zx = x(yz .* circshift(yz,[0 1]) <= 0); % Find zero-crossings
per = 2*mean(diff(zx)); % Estimate period
ym = mean(y); % Estimate offset
fit = @(b,x) b(1).*(sin(2*pi*x./b(2) + 2*pi/b(3))) + b(4); % Function to fit
fcn = @(b) norm(fit(b,x) - y); % Least-Squares cost function
s = fminsearch(fcn, [yr; per; -1; ym]) % Minimise Least-Squares
s = 4×1
0.2635 355.3359 -0.8237 0.0029
xp = linspace(min(x),max(x));
figure(1)
plot(x,y,'.b', xp,fit(s,xp), 'r')
grid
legend('Data', 'Fitted Curve', 'Location','best')
text(46, -0.21, sprintf('$y = %.3f\\ sin(%.6f\\cdot x %+.3f) %+.5f$', [s(1); 1./s([2 3]); s(4)]), 'Interpreter','latex')
In the text call, the arguments are the inverses of the ‘s’ values, so they are radian frequencies rather than periods (returned by the fminsearch call).
.

Sign in to comment.

More Answers (0)

Categories

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!