3 views (last 30 days)

Show older comments

I have a time series data like this;

x = [555 554 100 10 36 20 17 5 51 70 101 40 13];

and independent variables as follow

L = numel(x);

fs = 4;

t=0:1/fs:(L-1)/fs;

What I want is to use spline interpolation between two consecutive point of 'x' means (xi and xi+1) if the difference between two point is greater than 25. for example from the above time series abs(x4-x3)= 10-100= 90 therefore I want to interpolate between x3 and x4 with t interval of 0.05 and return all the new time series data by using a loop. The loop have to continue until the difference between every consecutive data in “x” becomes less than 25.

Thanks for your contribution in advance

Jan
on 26 May 2021

Edited: Jan
on 26 May 2021

x = [555 554 100 10 36 20 17 5 51 70 101 40 13];

L = numel(x);

fs = 4;

t = 0:1/fs:(L-1)/fs;

ready = false;

dt = 0.05;

xx = x;

tt = t;

while ~ready

miss = find(abs(diff(xx)) > 25);

if isempty(miss)

ready = true;

else

% Insert new time values for gaps:

for k = numel(miss):-1:1

tt = [tt(1:miss(k)-1), ...

tt(miss(k)):dt:tt(miss(k)+1), ...

tt(miss(k)+2:end)];

end

xx = interp1(t, x, tt, 'spline'); % Using original x, not xx!

dt = dt / 10; % Decrease time interval for next iteration

end

end

figure;

axes;

plot(t, x, 'ro');

hold('on');

plot(tt, xx, 'b.');

J. Alex Lee
on 28 May 2021

Here's [another approximate] way to do it that will only call spline once (could as well do it with gridded interpolant)

The method I suggested above won't work with spline because the interval between t = 0.5 and t = 0.75 is not monotonic after the global spline fit.

So this method is still only approximate to satisfy dx_min.

x = [555 554 100 10 36 20 17 5 51 70 101 40 13];

L = numel(x);

fs = 4;

t = 0:1/fs:(L-1)/fs;

% do the spline fit to the whole set of points once

pp = spline(t,x)

% define the minimum gap in x you want

dxmin = 25

x_agaps = abs(diff(x))

t_agaps = abs(diff(t))

dx_mult = 1.2; % extra refinement tweak

% find the intervals where your gap is violated

intvls = find(x_agaps > 25);

% for each interval, generate

tc = cell(numel(intvls),1);

xc = cell(numel(intvls),1);

for i = 1:numel(intvls)

% for i = 2

idx = intvls(i);

% split the interval into n points such that

% ROUGHLY minimum gap is satisfied (assuming linear)

n = ceil(x_agaps(idx)/dxmin * dx_mult);

tt = linspace(t(idx),t(idx+1),2+n);

xx = ppval(pp,tt);

tc{i} = tt(2:end-1);

xc{i} = xx(2:end-1);

end

tI = horzcat(t,tc{:});

xI = horzcat(x,xc{:});

[tI,srtIdx] = sort(tI);

xI = xI(srtIdx);

% analyze violations there are...

abs(diff(xI))

idxViol = find(abs(diff(xI))>dxmin)

figure(1); cla; hold on;

plot(t,x,'.','MarkerSize',12)

plot(tI,xI,'o')

fplot(@(t)(ppval(pp,t)),t([1,end]),'-')

plot(tI(idxViol),xI(idxViol),'x','MarkerSize',9,'LineWidth',2)

Jan
on 28 May 2021

J. Alex Lee
on 28 May 2021

If you just want the points to be "appear" roughly evenly distributed, you could consider spacing in the arc length (although you'd have to re-scale one of the dimensions so that it looks "even" in the plot)

x = [555 554 100 10 36 20 17 5 51 70 101 40 13];

L = numel(x);

fs = 4;

t=0:1/fs:(L-1)/fs;

% interpolate more than you ultimately need

tI = linspace(t(1),t(end),2000)';

xI = interp1(t,x,tI,'spline');

% scale by

% scl = 200;

scl = max(xI)/max(tI)

% parameterize the ultra-refined curve w.r.t. its own arclength s

sI = [0;cumsum(sqrt(scl^2*diff(tI).^2+diff(xI).^2))];

% then interpolate both x and t w.r.t. s

% in the steepest part of the curve, dx ~ 25 corresponds to

se = linspace(sI(1),sI(end),50)';

te = interp1(sI,tI,se);

xe = interp1(sI,xI,se);

figure(1); cla; hold on;

plot(t,x,'x')

plot(te,xe,'o')

plot(tI,xI,'-')

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

Start Hunting!