Fit periodic sinusoidal data with offset (fittype sin1 vs same equation)

13 views (last 30 days)
Hello,
I would like to fit real data using the following equation: a1 * sin(b1 * x + c1) + d1. Using the formula feature in Matlab is helpful when it comes to postprocessing the fit. However, the fit in my script never seemed to work 100% of the time. The fit seems to partially work when I use the 'sin1' fittype, but does not work if I use the same equation instead. How do I get the offset term, d1, in the 'sin1' fit model? Or how do I get Matlab to fit the 'a1*sin(b1*x+c1)+d1' equation and understand it is a periodic signal? The 'sin1' results in correct a1, b1, and c1 values, but cannot calculate d1 (does not exist in formula).
% setup fake trace to fit
clear all
close all
clc
n = 5;
res = 0.001;
x = (0:res:n*2*pi)';
a = 30;
b = 21;
c = pi/3;
d = 10;
y = a * sin(b*x+c) + d;
% setup three fittypes with essentially the same equation using the same 'sin1' option
opts = fitoptions('sin1');
ft.eq = fittype(@(a1,b1,c1,d1,x) a1*sin(b1*x+c1)+d1,...
'coefficients', {'a1', 'b1', 'c1', 'd1'});
ft.sin1_eq = fittype(@(a1,b1,c1,x) a1*sin(b1*x+c1),...
'coefficients', {'a1', 'b1', 'c1'});
ft.sin1 = fittype('sin1');
[fitresult.eq, gof.eq, output.eq] = fit(x, y, ft.eq, opts);
[fitresult.sin1_eq, gof.sin1_eq, output.sin1_eq] = fit(x, y, ft.sin1_eq, opts);
[fitresult.sin1, gof.sin1, output.sin1] = fit(x, y, ft.sin1, opts);
fitresult.eq
fitresult.sin1_eq
fitresult.sin1
% plot the fitted results and see the differences
ax(1) = subplot(3,1,1);
plot(fitresult.eq, x, y)
ylim(([-a a]*1.5) + d)
title(formula(fitresult.eq));
ax(2) = subplot(3,1,2);
plot(fitresult.sin1_eq, x, y)
ylim(([-a a]*1.5) + d)
title(formula(fitresult.sin1_eq));
ax(2) = subplot(3,1,3);
plot(fitresult.sin1, x, y)
ylim(([-a a]*1.5) + d)
title(formula(fitresult.sin1));
linkaxes(ax, 'x');
>> fitresult.eq
ans =
General model:
ans(x) = a1*sin(b1*x+c1)+d1
Coefficients (with 95% confidence bounds):
a1 = 0.09119 (-0.2424, 0.4247)
b1 = 0.5009 (0.0911, 0.9107)
c1 = 1.56 (-5.863, 8.983)
d1 = 10 (9.761, 10.24)
>> fitresult.sin1_eq
ans =
General model:
ans(x) = a1*sin(b1*x+c1)
Coefficients (with 95% confidence bounds):
a1 = 1.814 (1.448, 2.181)
b1 = 0.6971 (0.6748, 0.7194)
c1 = 0.0969 (-0.3094, 0.5032)
>> fitresult.sin1
ans =
General model Sin1:
ans(x) = a1*sin(b1*x+c1)
Coefficients (with 95% confidence bounds):
a1 = 30 (29.84, 30.16)
b1 = 21 (21, 21)
c1 = 1.042 (1.032, 1.052)
example.png

Answers (1)

Abhaya
Abhaya on 2 Dec 2024
Edited: Abhaya on 9 Dec 2024
Hi Kenneth,
I understand you are trying to fit periodic sinusoidal data using the equation: a1 * sin(b1 * x + c1) + d1. This may not work as 'sin1' fittype because, without proper starting point, the fitting algorithm can become stuck at a local minimum, making it difficult for the model to find the exact coefficients.
The 'sin1' fittype works better because it is specifically designed for sinusoidal curves, so the start points are closer to the optimal solution. However, as you mentioned, 'sin1' fittype does not include an offset coefficient d1.
To achieve a more accurate fit, using the equation: a1 * sin(b1 * x + c1) + d1 along with initial coefficient guesses can be effective.
d1 = mean(y) % Vertical shift
a1 = (max(y) - min(y))/2 % Amplitude
b1 = 21 % Phase (Number of peaks)
c1 = 1 % Phase shift
You can use these starting points when fitting your data.
ft.eq = fittype(@(a1,b1,c1,d1,x) a1*sin(b1*x+c1)+d1,'coefficients', {'a1', 'b1', 'c1', 'd1'});
[fitresult.eq, gof.eq, output.eq] = fit(x, y, ft.eq, 'StartPoint',[a1,b1,c1,d1]);
You can visualize the fit as below.
For more information, please refer to the following MATLAB community discussions.
Hope this helps.

Categories

Find more on Linear and Nonlinear Regression in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!