How to fit a sine curve with only the maximum and minimum values

109 views (last 30 days)
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
Mann Baidi
Mann Baidi on 8 Apr 2024 at 9:40
Hi,
What type of 'fitType' are you passing in the 'fit' function?
Sam Chak
Sam Chak on 8 Apr 2024 at 10:50
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")
T = 58x2 table
t_datetime t_datenum ____________________ _________ 01-Jan-2022 03:05:00 -1.3 01-Jan-2022 09:02:00 1.5 01-Jan-2022 15:32:00 -1.4 01-Jan-2022 21:34:00 1.4 02-Jan-2022 04:08:00 -1.4 02-Jan-2022 10:06:00 1.5 02-Jan-2022 16:31:00 -1.4 02-Jan-2022 22:29:00 1.5 03-Jan-2022 05:03:00 -1.6 03-Jan-2022 11:04:00 1.5 03-Jan-2022 17:24:00 -1.4 03-Jan-2022 23:20:00 1.6 04-Jan-2022 05:56:00 -1.6 04-Jan-2022 11:59:00 1.5 04-Jan-2022 18:16:00 -1.4 05-Jan-2022 00:09:00 1.7
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')

Sign in to comment.

Answers (2)

Bruno Luong
Bruno Luong on 8 Apr 2024 at 12:28
Edited: Bruno Luong on 8 Apr 2024 at 15:52
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

R
R on 8 Apr 2024 at 10:49
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:

Community Treasure Hunt

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

Start Hunting!