Предположите, что у Вас есть очень длинная последовательность. Что является самым эффективным способом найти интервалы, где последовательность является всеми нулями (или более точно последовательность спадает до почти нулевых значений Для простоты, позволяет, принимают следующую последовательность: Я пытаюсь получить следующую информацию: затем с помощью этой информации, мы находим интервалы с продолжительностью> = к некоторому заданному значению (сказать Та последняя часть связана с предыдущим вопросом: MATLAB: векторизованное создание массива из списка запускает/заканчивает индексы Это - то, что я имею до сих пор: Я надеюсь векторизовать/оптимизировать код, но я открыт для других решений. Я должен подчеркнуть, что эффективность пространства и времени очень важна, так как я обрабатываю большое количество длинных биосигналов.abs(X)
sig = [1 1 0 0 0 0 1 1 1 1 1 0 1 0 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 0];
startIndex EndIndex Duration
3 6 4
12 12 1
14 16 3
25 26 2
30 30 1
3
) и возврат индексов значений во всех этих объединенных интервалах:indices = [3 4 5 6 14 15 16];
sig = [1 1 0 0 0 0 1 1 1 1 1 0 1 0 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 0];
len = length(sig);
thresh = 3;
%# align the signal with itself successively shifted by one
%# v will thus contain 1 in the starting locations of the zero interval
v = true(1,len-thresh+1);
for i=1:thresh
v = v & ( sig(i:len-thresh+i) == 0 );
end
%# extend the 1's till the end of the intervals
for i=1:thresh-1
v(find(v)+1) = true;
end
%# get the final indices
v = find(v);
Вот шаги, которые я бы предпринял для решения вашей проблемы векторизованным способом, начиная с заданного вектора sig
:
Сначала задайте порог вектора, чтобы получить вектор tsig
нулей и единиц (нули, где абсолютное значение сигнала падает достаточно близко к нулю, единицы в другом месте):
tsig = (abs (sig)> = eps); % # Использование eps в качестве порога
Затем найдите начальные и конечные индексы и продолжительность каждой строки нулей с помощью функций DIFF и FIND :
dsig = diff ([1 tsig 1 ]);
startIndex = найти (dsig <0);
endIndex = найти (dsig> 0) -1;
продолжительность = endIndex-startIndex + 1;
Затем найдите строки нулей с длительностью, большей или равной некоторому значению (например, 3 в вашем примере):
stringIndex = (duration> = 3);
startIndex = startIndex (stringIndex);
endIndex = endIndex (stringIndex);
Наконец, используйте метод из моего ответа на связанный вопрос , чтобы сгенерировать окончательный набор индексов:
indices = zeros (1, max (endIndex) +1);
индексы (startIndex) = 1;
индексы (endIndex + 1) = индексы (endIndex + 1) -1;
индексы = найти (cumsum (индексы));
function indice=sigvec(sig,thresh)
%extend sig head and tail to avoid 0 head and 0 tail
exsig=[1,sig,1];
%convolution sig with extend sig
cvexsig=conv(exsig,ones(1,thresh));
tempsig=double(cvexsig==0);
indice=find(conv(tempsig,ones(1,thresh)))-thresh;
Вы можете решить это как задачу поиска строк, находя строки нулей длиной thresh
(функция STRFIND очень быстрая)
startIndex = strfind(sig, zeros(1,thresh));
Обратите внимание, что более длинные подстроки будут помечены в нескольких местах, но в конечном итоге будут объединены, когда мы добавим промежуточные места от интервалов, начинающихся в startIndex
и заканчивающихся в start+thresh-1
.
indices = unique( bsxfun(@plus, startIndex', 0:thresh-1) )';
Обратите внимание, что вы всегда можете заменить этот последний шаг на решение CUMSUM/FIND от @gnovice из связанного вопроса.
Я думаю, что наиболее MATLAB/"векторизованный" способ сделать это - вычислить свертку вашего сигнала с фильтром типа [-1 1]. Вы должны посмотреть документацию функции conv. Затем на выходе conv используйте find для получения соответствующих индексов.