MATLAB Answers

Curve fitting to a sinusoidal function

1,371 views (last 30 days)
Dejan
Dejan on 14 Mar 2014
Commented: Star Strider on 29 Feb 2020
I have a series of data points that are governed by a sinusoidal function.
I want to fit, plot and generate a sinusoidal function to these data points.
I do not wish to fit an nth degree polynomial to this no matter how close it is to the sinusoidal function.
I understand that there is no standard tool in the toolbox that does this. I have looked at numerous and plenty of old threads and internet posts. None of the answers help me.
Please take into account that I am new to Matlab and can only curve fit very basic data points.
What I therefore need is an exact and step by step guide in how to fit a sine curve to data points.
Please assist.

  1 Comment

Douglas Lim
Douglas Lim on 29 Feb 2016
Hi Star Strider, I have further question on this topic. May I know how to contact you for sending you the problem.

Sign in to comment.

Accepted Answer

Star Strider
Star Strider on 15 Mar 2014
Edited: Star Strider on 15 Mar 2014
Here’s my suggested solution, using only core MATLAB functions:
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
The elements of output parameter vector, s ( b in the function ) are:
s(1): sine wave amplitude (in units of y)
s(2): period (in units of x)
s(3): phase (phase is s(2)/(2*s(3)) in units of x)
s(4): offset (in units of y)
It provides a good fit.

  18 Comments

M.A.G.
M.A.G. on 29 Feb 2020
How can I interpret yz (line 4)
M.A.G.
M.A.G. on 29 Feb 2020
also, reading circshift documentation:
The default behavior of circshift(A,K) where K is a scalar changed in R2016b. To preserve the behavior of R2016a and previous releases, usecircshift(A,K,1). This syntax specifies 1 as the dimension to operate along.
should this allter the output in this case?
Star Strider
Star Strider on 29 Feb 2020
Interesting that you brought that up.
I recently updated that in another Answer, adding a reference to the ‘zci’ function that I wrote many years ago:
x = linspace(0,5*pi);
y = 100*sin(x)+700;
yu = max(y);
yl = min(y);
yr = (yu-yl); % Range of ‘y’
yz = y-yu+(yr/2);
zci = @(v) find(v(:).*circshift(v(:), 1, 1) <= 0); % Returns Approximate Zero-Crossing Indices Of Argument Vector (>= R2016b)
zx = x(zci(yz)); % 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; 1/per; -1; ym]) % Minimise Least-Squares
xp = linspace(min(x),max(x));
figure(1)
plot(x,y,'b', xp,fit(s,xp), 'r')
grid
This also changed the period representations to frequencies. Both versions will work.

Sign in to comment.

More Answers (2)

Jos (10584)
Jos (10584) on 14 Mar 2014

  1 Comment

Dejan
Dejan on 15 Mar 2014
Im relatively new to Matlab and whilst the link provided I kinda get, its not an exact step by step guide on how to fit a Sine wave.
Here are my data points:
x = [ 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 ]
y = [ 16.5 14.32 11.58 10.017 9.629 10.2 12.16 15.08 16.97 16.75 14.331 11.508 10.013 9.617 10.22 12.15 15.304 17.38 16.853 ]
I need a Sine wave to fit that data and its governing equation

Sign in to comment.


Chad Greene
Chad Greene on 21 Jul 2018
I turned this into a function called sinefit for climatological data with a periodicity of 1 year.

  0 Comments

Sign in to comment.