Question

Je ne suis pas sûr si cela est possible, mais ma compréhension de Matlab pourrait certainement être mieux.

J'ai un code Je veux vectoriser comme cela cause un goulot d'étranglement tout à fait dans mon programme. Cela fait partie d'une routine d'optimisation qui a de nombreuses configurations possibles de moyenne à court terme (STA), moyenne à long terme (MLT) et sensibilité (OnSense) à courir à travers.

Le temps est au format vectoriel, FL2onSS est les données principales (une double-NX1), FL2onSSSTA est sa STA (NxSTA double), FL2onSSThresh est sa valeur de seuil (NxLTAxOnSense Double)

L'idée est de calculer une matrice d'alarme rouge qui sera 4D - le alarmStatexSTAxLTAxOnSense qui est utilisé dans le reste du programme.

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

Je suis actuellement eu cette répétition d'une fonction dans une tentative d'obtenir un peu plus de vitesse hors de lui, mais il est évident que ce sera mieux si peut être vectorisé la chose entière. Autrement dit, je ne ai pas besoin de garder la fonction s'il y a une meilleure solution.

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

Le code est assez simple, donc je ne l'expliquer plus loin. Si vous avez besoin sur ce elucidation une ligne particulière fait, laissez-moi savoir.

Était-ce utile?

La solution

L'astuce consiste à mettre toutes vos données à la même forme , en utilisant la plupart du temps repmat et permute . Ensuite, la logique est la partie simple.

Il me fallait un mauvais tour à mettre en œuvre la dernière partie (si aucune des conditions détenir, utiliser les derniers résultats). généralement ce genre de logique est effectuée à l'aide d'un cumsum. Je devais utiliser une autre matrice de 2. ^ n pour assurer que les valeurs définies sont utilisées (de sorte que + 1, + 1, -1 va vraiment donner 1,1,0) - il suffit de regarder le code:)

%// 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.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top