在 MATLAB 中向量化 for 循环

发布于 2024-08-21 07:36:28 字数 1809 浏览 7 评论 0原文

我不太确定这是否可行,但我对 MATLAB 的理解肯定会更好。

我有一些代码希望进行矢量化,因为它在我的程序中造成了相当大的瓶颈。它是优化例程的一部分,该例程具有多种可能的短期平均值 (STA)、长期平均值 (LTA) 和灵敏度 (OnSense) 配置可供运行。

时间采用矢量格式,FL2onSS 是主要数据(Nx1 双精度),FL2onSSSTA 是其 STA(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

我目前已经重复了一个函数,试图提高它的速度,但显然如果整个事情可以矢量化会更好。换句话说,如果有更好的解决方案,我不需要保留该功能。

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

代码很简单,所以我不会进一步解释。如果您需要说明特定线路正在做什么,请告诉我。

I'm not too sure if this is possible, but my understanding of MATLAB could certainly be better.

I have some code I wish to vectorize as it's causing quite a bottleneck in my program. It's part of an optimisation routine which has many possible configurations of Short Term Average (STA), Long Term Average (LTA) and Sensitivity (OnSense) to run through.

Time is in vector format, FL2onSS is the main data (an Nx1 double), FL2onSSSTA is its STA (NxSTA double), FL2onSSThresh is its Threshold value (NxLTAxOnSense double)

The idea is to calculate a Red alarm matrix which will be 4D - the alarmStatexSTAxLTAxOnSense that is used throughout the rest of the program.

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

I've currently got this repeating a function in an attempt to get a bit more speed out of it, but obviously it will be better if the entire thing can be vectorised. In other words I do not need to keep the function if there is a better 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

The code is simple enough so I won't explain it any further. If you need elucidation on what a particular line is doing, let me know.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

吹泡泡o 2024-08-28 07:36:28

诀窍是将所有数据转化为相同的形式,主要使用repmatpermute。那么逻辑就是简单的部分。

我需要一个令人讨厌的技巧来实现最后一部分(如果没有一个条件成立,则使用最后的结果)。通常这种逻辑是使用 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.

The trick is to bring all your data to the same form, using mostly repmat and permute. Then the logic is the simple part.

I needed a nasty trick to implement the last part (if none of the conditions hold, use the last results). usually that sort of logic is done using a cumsum. I had to use another matrix of 2.^n to make sure the values that are defined are used (so that +1,+1,-1 will really give 1,1,0) - just look at the 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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文