Efficiently calculating sum-thresholds across vector

1 回表示 (過去 30 日間)
Joey Costello
Joey Costello 2020 年 9 月 22 日
編集済み: Bruno Luong 2020 年 9 月 22 日
I have a 1xN vector of samples, for which I need to calculate the indices of when a moving sum exceeds a threshold.
One could think of the samples as current that is charging a capacitor, and once the capacitor is charged to the threshold, a pulse is fired and the capacitor is reset. I need to find the times when the pulse is fired.
I have a working loop implementation below, however, it is relatively slow and I'd like to find a more efficient method. Is there a vectorized or built-in method for finding these pulse times?
samples;
threshold = 50;
pulseIdx = zeros(size(samples));
runningSum = 0;
for i = 1:length(samples)
runningSum = runningSum + samples(i);
if runningSum > threshold
pulseIdx(i) = 1;
runningSum = runningSum - threshold; % allow spillover to next cycle
end
end
  1 件のコメント
Turlough Hughes
Turlough Hughes 2020 年 9 月 22 日
Are the values in samples always positive?

サインインしてコメントする。

採用された回答

Turlough Hughes
Turlough Hughes 2020 年 9 月 22 日
編集済み: Turlough Hughes 2020 年 9 月 22 日
You could do the following but with the caveat that it assumes samples are all positive values
runningSum = cumsum(samples);
idx = find(diff(mod(runningSum,threshold))<0)+1;
Or in the case where they are not all positive, perhaps something like the following:
idx = find(diff(mod(runningSum,50))<-0.5*threshold)+1

その他の回答 (2 件)

Ameer Hamza
Ameer Hamza 2020 年 9 月 22 日
編集済み: Ameer Hamza 2020 年 9 月 22 日
Try something like this
rng(0);
samples = rand(1, 1000);
threshold = 10;
samples_sum = cumsum(samples);
idx = [];
while any(samples_sum > threshold)
i = find(samples_sum > threshold, 1);
idx = [idx i];
samples_sum = samples_sum - samples_sum(i-1);
end
idx are indexes of samples where sum exceed threshold.

Bruno Luong
Bruno Luong 2020 年 9 月 22 日
編集済み: Bruno Luong 2020 年 9 月 22 日
This works regardless the sign of sample
% Test data
samples = 5*rand(1,10000);
samples = samples+0.5*randn(size(samples)); % with noise
% Your method
threshold = 50;
pulseIdx = zeros(size(samples));
runningSum = 0;
for i = 1:length(samples)
runningSum = runningSum + samples(i);
if runningSum > threshold
pulseIdx(i) = 1;
runningSum = runningSum - threshold; % allow spillover to next cycle
end
end
% My method
cs = cummax(cumsum(samples));
n = floor(cs(end)/threshold);
bdr = (1:n)*threshold;
[~,~,loc]=histcounts(bdr,[0,cs]);
pulseIdx2 = zeros(size(samples));
pulseIdx2(loc(loc>0)) = 1;
% This should return 1, excepted when numerical errors spoil thing
isequal(pulseIdx,pulseIdx2)

製品


リリース

R2018a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by