1,371 views (last 30 days)

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.

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.

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
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.

Opportunities for recent engineering grads.

Apply Today
## 1 Comment

## Direct link to this comment

https://www.mathworks.com/matlabcentral/answers/121579-curve-fitting-to-a-sinusoidal-function#comment_346318

⋮## Direct link to this comment

https://www.mathworks.com/matlabcentral/answers/121579-curve-fitting-to-a-sinusoidal-function#comment_346318

Sign in to comment.