How do I gapfill a vector only if gaps (NaNs) are 10 elements or less?

5 views (last 30 days)
I have a time-signal that looks something like this:
x=[1,2,3,5,7,9,10,9, NaN,Nan,5,3,2,Nan,Nan,Nan,Nan,Nan,Nan,Nan,Nan,Nan,Nan,Nan,12,13,14,15,16]
I want to use the fillgaps function to fill the gaps in the data. However, for the sake of having a quality signal at the end, I want to make sure that the function only fills gaps up to 10 numbers long. In my example, I would want it to fill the first two NaNs, but not the last 11. I can't seem to find a function in Matlab that does this, how should I do it?
tl;dr: I need to set a limit on the size of gaps that Matlab fills when using the gapfill (or a similar) function

Accepted Answer

Jan
Jan on 30 Jul 2021
Edited: Jan on 1 Aug 2021
x = [1,2,3,5,7,9,10,9, NaN,NaN,5,3,2,NaN,NaN,NaN,NaN,NaN, ...
NaN,NaN,NaN,NaN,NaN,NaN,12,13,14,15,16];
y = fillgaps(x);
% Find sequences of NaNs longer than 10:
[B, N] = RunLength(isnan(x));
B(B & N < 10) = false; % Exclude short sequences
Mask = RunLength(B, N); % Inflate again
y(Mask) = nan; % Copy original NaNs to output
ax = axes('NextPlot', 'add');
plot(ax, y);
plot(ax, x, 'o');
function [b, n] = RunLength(x, n)
% Cheap and slower version of:
% https://www.mathworks.com/matlabcentral/fileexchange/41813-runlength
if nargin == 1 % Encode: x -> b, n
d = [true; diff(x(:)) ~= 0]; % TRUE if values change
b = x(d); % Elements without repetitions
n = diff(find([d.', true])); % Number of repetitions
else % Decode: b, n -> x
len = length(n); % Number of bins
d = cumsum(n); % Cummulated run lengths
index = zeros(1, d(len)); % Pre-allocate
index(d(1:len-1)+1) = 1; % Get the indices where the value changes
index(1) = 1; % First element is treated as "changed" also
b = x(cumsum(index)); % Cummulated indices
end
end

More Answers (2)

KSSV
KSSV on 30 Jul 2021
You can use interp1. Also have a look on fillmissing.
x=[1,2,3,5,7,9,10,9, NaN,NaN,5,3,2,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,12,13,14,15,16] ;
idx = 1:length(x) ;
x_new = x ;
x_new(isnan(x)) = interp1(idx(~isnan(x)),x(~isnan(x)),idx(isnan(x))) ;
plot(idx,x,'*r',idx,x_new,'b')

Walter Roberson
Walter Roberson on 30 Jul 2021
Edited: Walter Roberson on 30 Jul 2021
format short
N = 10;
x = [1,2,3,5,7,9,10,9, NaN,NaN,5,3,2,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,12,13,14,15,16];
mask = isnan(x);
bgstarts = strfind([false mask], [0 ones(1,N)])
bgstarts = 14
bgends = strfind([mask false], [ones(1,N), 0])+N-1
bgends = 24
breakpoints = [1 reshape([bgstarts, bgends+1].',1,[]) length(x)+1]
breakpoints = 1×4
1 14 25 30
pieces = mat2cell(x, 1, diff(breakpoints))
pieces = 1×3 cell array
{[1 2 3 5 7 9 10 9 NaN NaN 5 3 2]} {[NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN]} {[12 13 14 15 16]}
pieces(1:2:end) = cellfun(@fillgaps, pieces(1:2:end), 'uniform', 0)
pieces = 1×3 cell array
{[1 2 3 5 7 9 10 9 5.6452 4.2029 5 3 2]} {[NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN]} {[12 13 14 15 16]}
cell2mat(pieces)
ans = 1×29
1.0000 2.0000 3.0000 5.0000 7.0000 9.0000 10.0000 9.0000 5.6452 4.2029 5.0000 3.0000 2.0000 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 12.0000 13.0000 14.0000 15.0000 16.0000
  1 Comment
Abigail Morton
Abigail Morton on 30 Jul 2021
Hi Walter,
Thank you for your help! This was how I was thinking of approaching the problem, but I wasn't experienced enough with Matlab to figure out how to do it. I'm going to work through your code and one of the other suggested ones and see which offers the best solution to my problem - thank you for taking the time to help me out!

Sign in to comment.

Products


Release

R2021a

Community Treasure Hunt

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

Start Hunting!