Pregunta

No estoy muy seguro de si esto es posible, pero mi comprensión de MATLAB sin duda podría ser mejor.

Tengo algo de código Deseo vectorizar, ya que está causando un gran cuello de botella en mi programa. Es parte de una rutina de optimización que tiene muchas configuraciones posibles de corto plazo promedio (STA), largo plazo Promedio (LTA) y sensibilidad (OnSense) para ejecutar a través.

Tiempo está en formato vectorial, FL2onSS es los datos principales (una nx1 doble), FL2onSSSTA es su STA (NxSTA doble), FL2onSSThresh es su valor de umbral (NxLTAxOnSense doble)

La idea es calcular una matriz de alarma rojo que será 4D - alarmStatexSTAxLTAxOnSense la que se utiliza en todo el resto del programa.

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

Tengo actualmente esta repetición de una función en un intento de conseguir un poco más de velocidad fuera de él, pero es obvio que será mejor si toda la cosa puede ser vectorizado. En otras palabras, no necesito para mantener la función de si hay una solución mejor.

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

El código es bastante simple, así que no lo explicará más. Si necesita aclaraciones sobre lo que es una línea particular está haciendo, que me haga saber.

¿Fue útil?

Solución

El truco está en llevar todos sus datos a la misma forma , utilizando la mayoría de repmat y permute . A continuación, la lógica es la parte sencilla.

necesitaba una mala pasada para poner en práctica la última parte (si ninguna de las condiciones se cumplen, utilice los últimos resultados). por lo general ese tipo de lógica se realiza mediante una cumSum. Tuve que usar otra matriz de 2 ^ n para asegurarse de que los valores que se definen se utilizan (para que +1, +1, -1 será realmente dar 1,1,0) - basta con ver el código:)

%// 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.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top