How to fit a sine curve with only the maximum and minimum values
16 views (last 30 days)
Show older comments
Hi, I am trying to plot a sine wave through the high and low water points from a measuring station in the North Sea.
The image shows the first few data points. I've tried fitting a curve, filling the gaps etc. but I can't get Matlab to acknowledge the oscillating signal.
Help will be appreciated, thank you!
this is the goal:
2 Comments
Sam Chak
on 8 Apr 2024
It might be easier to fit a custom sinusoidal waveform if the data is converted to the unit of 'seconds'. However, it is important to note that the time step in the t vector is not uniform.
where and are the time-varying amplitude and the time-varying period of the sine wave, respectively.
T = readtable("datapoints.xlsx", VariableNamingRule="preserve")
x = T{:,1}; % datetime data
t = seconds(x - x(1)); % convert to seconds
A = T{:,2}; % high and low points of the sea level
stem(t, A), grid on, xlabel('Time (sec)'), ylabel('Sea level')
title('Sea level around the North Sea from 1st to 15th, Jan 2022')
Answers (2)
Bruno Luong
on 8 Apr 2024
Edited: Bruno Luong
on 8 Apr 2024
piecewise (co)sine interpolation (not fitting).
I don't think you have extra DOF to play with if you restrict data to be local extrema and model follows a sinusoidal law.
data = readtable('https://www.mathworks.com/matlabcentral/answers/uploaded_files/1662781/datapoints.xlsx');
t=datenum(data.t_datetime);
dt = t-t(1);
y = data.t_datenum;
dti = linspace(min(dt),max(dt),1025);
yi = sininterp(dt, y, dti); % function defined below
% Ploy check result
figure
subplot(2,1,1)
dtfun = @(dt) datetime(dt+t(1),'ConvertFrom','datenum');
h = plot(dtfun(dt),y,"ob",dtfun(dti),yi,"r");
% zoom plot
ax2 = subplot(2,1,2);
h = plot(dtfun(dt),y,"ob",dtfun(dti),yi,"r");
xlim(ax2, dtfun([8 11]))
%%
function yi = sininterp(t, y, ti)
ti = ti(:);
i = discretize(ti, t);
yi = nan(size(ti));
valid = i>=1 & i<numel(ti);
i = i(valid);
y1 = y(i);
y2 = y(i+1);
ym = (y1+y2)/2;
A = (y1-y2)/2;
alpha = (ti(valid) - t(i)) .* (pi./(t(i+1)-t(i)));
yi(valid) = ym + A.*cos(alpha);
end
1 Comment
R
on 8 Apr 2024
Hi Particia,
Fitting a piecewise cubic Hermite ("pchip") curve might help with this use case. Here is an example of the same
% Read data from Excel file
data = readtable('datapoints.xlsx');
% Convert first column to string array for time labels
time = string(table2array(data(:, 1)));
% Extract water level data from second column
waterLevel = table2array(data(:, 2));
% Create index array for plotting
x=(1:58)'; % Ensure x is a column vector
% Plot water level data
plot(x,waterLevel,".");
title('Water Level vs. Time');
xticklabels(time) % Set custom x-axis tick labels
% Fit a piecewise cubic Hermite interpolating polynomial
[curve,gof,output] = fit(x,waterLevel,"pchipinterp");
% Overlay fitted curve on the plot
hold on
plot(curve)
hold off
Here is the plot I get after executing the above code:
Refer to the following link to learn more about 'pchipinterp' curve fitting model:
You can also find a list of curve fitting models that MATLAB supports in the following documentation:
0 Comments
See Also
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!