Fitting a sine to data

11 views (last 30 days)
Felix94 on 17 Aug 2022
Edited: John D'Errico on 17 Aug 2022
Dear community,
I am trying to use MATLAB to fit a sine to random data (as a first test).
I have thrown together some code based on this previous question
However my fit works only sometimes. Most of the time it does not, although I choose almost the exact "true" parameters. The data that I later want to apply this code to will not be as nice as this.
What is the reason the fit derails so horribly although the data is pretty "obvious" ?
Am I doing something fundamentally wrong?
Can I improve it by specifying certain fitoptions?
Best regards,
clear all;
close all;
FigPosFigSize = [4 1.5 30 22.5];
f = 1;
time_stamps = rand(500, 1) * 5;
time_stamps = sort(time_stamps);
phase = 0;
amplitude = 2;
offset = 0;
y = sin((2*pi*f*time_stamps + phase))*amplitude + offset;
ft = fittype('sin((2*pi*f*x + phase))*amplitude + offset','coefficients',{'phase','amplitude','offset', 'f'}, 'independent', {'x'})
options = fitoptions('Method','NonlinearLeastSquares',...
'Algorithm', 'Levenberg-Marquardt',...
'StartPoint',[0, 1.9, 0, 0.9]);
[mdl gof output] = fit(time_stamps, y, ft, options);
x = 0:0.01:5;
fct = sin((2*pi*mdl.f* x + mdl.phase))*mdl.amplitude + mdl.offset;
f1 = figure('Units', 'centimeters', 'Position', FigPosFigSize);
hold all
s1 = scatter(time_stamps, y, 15, [0 0 0] ,'filled' );
l_fit = plot(x, fct, 'Color', [0 0 1] ,'LineWidth', 2 );
set(gca,'LineWidth', 1.25 ,'FontSize', 25);
ax = gca;
box on;
set(gcf, 'color','w')

Answers (1)

John D'Errico
John D'Errico on 17 Aug 2022
Edited: John D'Errico on 17 Aug 2022
Are you doing something fundamentally wrong? Sort of, yes.
Fitting periodic functions has a probem, in that you will need to provide intelligent starting values for the period. I'll pick an example:
x = rand(200,1)*5;
y = 4*sin(10*x + 3) + randn(size(x))/10;
So a little bit of noise. A very nice sine wave. Now let me try to fit it, using fit.
mdl = fittype('a*sin(b*x+c)','indep','x');
fittedmdl = fit(x,y,mdl)
Warning: Start point not provided, choosing random start point.
fittedmdl =
General model: fittedmdl(x) = a*sin(b*x+c) Coefficients (with 95% confidence bounds): a = 13.69 (-5.424e+04, 5.427e+04) b = 0.01773 (-70.28, 70.31) c = -0.03438 (-136.4, 136.3)
Well, that fit will look like pure crap.
hold on
hold off
So why did it fail? If you do not pass in intelligent starting values for the period of a periodic function like this, fit will use a random start point. And that start point is not chosen very intelligently. It cannot do that.
But now, let me try a fit, where the period is chosen intelligently. Let me see, over a span of x going from 0-5, I can count 8 peaks. That would suggest the period would be roughly 5/8/(2*pi). And the parameter b will be the inverse of the period. The other two parameters? The fit will be pretty insensitive to the start points I choose for them.
fittedmdl2 = fit(x,y,mdl,'start',[rand(),1/(5/8/(2*pi)),rand()])
fittedmdl2 =
General model: fittedmdl2(x) = a*sin(b*x+c) Coefficients (with 95% confidence bounds): a = -3.995 (-4.015, -3.976) b = 10 (9.996, 10) c = -0.1413 (-0.1522, -0.1305)
hold on
Note that the sign(a) was different from how I created it, but that is irrelevant, because the phase angle is also not unique.
Again, your failure results from a poor choice of starting values. Even though you provided a start point, you need to use a better start point for the period. This is a classical problem when fitting trig functions.




Community Treasure Hunt

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

Start Hunting!

Translated by