2010-02-10 5 views
4

Я не уверен, возможно ли это, но мое понимание MATLAB, безусловно, может быть лучше.Векторизация для петель в MATLAB

У меня есть код, который я хочу прописать, поскольку он вызывает довольно узкое место в моей программе. Это часть процедуры оптимизации, которая имеет множество возможных конфигураций краткосрочного среднего (STA), долгосрочного среднего (LTA) и чувствительности (OnSense) для выполнения.

Время в векторном формате, FL2onSS это основные данные (ые NX1 дважды), FL2onSSSTA является его СТА (NxSTA дважды), FL2onSSThresh является его пороговое значение (NxLTAxOnSense двойной)

Идея заключается в том, чтобы вычислить красный сигнальная матрица, которая будет 4D - alarmStatexSTAxLTAxOnSense, которая используется в остальной части программы.

Red = zeros(length(FL2onSS), length(STA), length(LTA), length(OnSense), 'double'); 
for i=1:length(STA) 
    for j=1:length(LTA) 
     for k=1:length(OnSense) 
      Red(:,i,j,k) = calcRedAlarm(Time, FL2onSS, FL2onSSSTA(:,i), FL2onSSThresh(:,j,k)); 
     end 
    end 
end 

В настоящее время я получил это повторять функцию в попытке получить немного больше скорости из него, но, очевидно, это будет лучше, если все, что может быть vectorised. Другими словами, мне не нужно сохранять функцию, если есть лучшее решение.

function [Red] = calcRedAlarm(Time, FL2onSS, FL2onSSSTA, FL2onSSThresh) 

% Calculate Alarms 
% Alarm triggers when STA > Threshold 

zeroSize = length(FL2onSS); 

%Precompose 
Red = zeros(zeroSize, 1, 'double'); 

for i=2:zeroSize 
    %Because of time chunks being butted up against each other, alarms can 
    %go off when they shouldn't. To fix this, timeDiff has been 
    %calculated to check if the last date is different to the current by 5 
    %seconds. If it isn't, don't generate an alarm as there is either a 
    %validity or time gap. 
    timeDiff = etime(Time(i,:), Time(i-1,:)); 
    if FL2onSSSTA(i) > FL2onSSThresh(i) && FL2onSSThresh(i) ~= 0 && timeDiff == 5 
     %If Short Term Avg is > Threshold, Trigger 
     Red(i) = 1; 
    elseif FL2onSSSTA(i) < FL2onSSThresh(i) && FL2onSSThresh(i) ~= 0 && timeDiff == 5 
     %If Short Term Avg is < Threshold, Turn off 
     Red(i) = 0; 
    else 
     %Otherwise keep current state 
     Red(i) = Red(i-1); 
    end 
end 
end 

Код достаточно прост, поэтому я не буду его объяснять. Дайте мне знать, если вам нужно разъяснить, что делает конкретная линия.

ответ

5

Хитрость заключается в том, чтобы принести все ваши данные в той же форме, используя в основном repmat и переставлять. Тогда логика - это простая часть.

Мне понадобился неприятный трюк для реализации последней части (если ни одно из условий не выполняется, используйте последние результаты). обычно такая логика выполняется с помощью cumsum. Я должен был использовать другую матрицу 2.^n, чтобы убедиться, что значения, которые определены (так что + 1, + 1, -1 действительно дадут 1,1,0) - просто посмотрите на код :)

%// define size variables for better readability 
N = length(Time); 
M = length(STA); 
O = length(LTA); 
P = length(OnSense); 

%// transform the main data to same dimentions (3d matrices) 
%// note that I flatten FL2onSSThresh to be 2D first, to make things simpler. 
%// anyway you don't use the fact that its 3D except traversing it. 
FL2onSSThresh2 = reshape(FL2onSSThresh, [N, O*P]); 
FL2onSSThresh3 = repmat(FL2onSSThresh2, [1, 1, M]); 
FL2onSSSTA3 = permute(repmat(FL2onSSSTA, [1, 1, O*P]), [1, 3, 2]); 
timeDiff = diff(datenum(Time))*24*60*60; 
timeDiff3 = repmat(timeDiff, [1, O*P, M]); 
%// we also remove the 1st plain from each of the matrices (the vector equiv of running i=2:zeroSize 
FL2onSSThresh3 = FL2onSSThresh3(2:end, :, :); 
FL2onSSSTA3 = FL2onSSSTA3(2:end, :, :); 

Red3 = zeros(N-1, O*P, M, 'double'); 

%// now the logic in vector form 
%// note the chage of && (logical operator) to & (binary operator) 
Red3((FL2onSSSTA3 > FL2onSSThresh3) & (FL2onSSThresh3 ~= 0) & (timeDiff3 == 5)) = 1; 
Red3((FL2onSSSTA3 < FL2onSSThresh3) & (FL2onSSThresh3 ~= 0) & (timeDiff3 == 5)) = -1; 
%// now you have a matrix with +1 where alarm should start, and -1 where it should end. 

%// add the 0s at the begining 
Red3 = [zeros(1, O*P, M); Red3]; 

%// reshape back to the same shape 
Red2 = reshape(Red3, [N, O, P, M]); 
Red2 = permute(Red2, [1, 4, 2, 3]); 

%// and now some nasty trick to convert the start/end data to 1 where alarm is on, and 0 where it is off. 
Weights = 2.^repmat((1:N)', [1, M, O, P]); %// ' damn SO syntax highlighting. learn MATLAB already! 
Red = (sign(cumsum(Weights.*Red2))+1)==2; 

%// and we are done. 
%// print sum(Red(:)!=OldRed(:)), where OldRed is Red calculated in non vector form to test this. 
+0

Отлично! Благодарю Офри. Это, безусловно, займет немного времени, и мне нужно прояснить несколько моментов: Я предполагаю, что строка FL2onSSThresh3 = reshape (FL2onSSThresh, [N, O * P]); действительно должен быть связан с FL2onSSThresh2? timeDiff = etime (Time (i, :), Time (i-1, :)); Не будет работать в этом случае? Поскольку мы больше не используем i для итерации. Time is datevec, поэтому я предполагаю, что я могу просто использовать timeDiff = diff (Time) вместо вышеуказанной строки, но это дает массив с совершенно разными измерениями, а операции Red3 терпят неудачу. – Geodesic

+0

Вы правы. Я отредактирую, чтобы исправить это. –