我有一个功能,可以根据信号的其余部分查找和调整峰值。我遇到的问题是,如果信号有8000点,它可以很好地运行并且非常快,并且在大约1分钟内完成,但如果它有200000点则需要一个小时+。任何想法如何加快这个功能?
%example [peaks_found,peak_sig_adj]= rtadjpeak (signal, 3,3)
function [peaks_found,peak_sig_adj] =rtadjpeak (signal, T_multi_lower, T_multi_upper)
Af=signal;
% Thresholds
T_lower = -mean(abs(signal))*T_multi_lower
T_upper =mean(abs(signal))*T_multi_upper
% initialisation
[peaks_r,peaks_c] = find( Af < T_lower | Af > T_upper);
peaks = find( Af < T_lower | Af > T_upper);
%find the mean of all the peaks
counter = 0;
while ~isempty(peaks)
peaks = find( Af < T_lower | Af > T_upper);
try
Af(peaks) = ( Af(peaks-1) + Af(peaks+1) ) / 2;
catch
if peaks(1) == 1
Af(1) = 0;
else
Af(end) = 0;
end
end
counter=counter+1;
end
peaks_found=counter
peak_sig_adj=Af;
end
PS:我使用八度音阶3.8.1
我像推荐的人一样做了探查器,但我仍然迷失了如何提高此功能的速度
profile on;
rtadjpeak(z_sig_combined_L1, 3, 3);
profile off;
>>>T_lower = -0.50551
>>>T_upper = 0.50551
>>>peaks_found = 1013
profshow (profile ("info"));
# Function Attr Time (s) Calls
---------------------------------------------
14 find 0.043 1017
5 binary < 0.023 1017
1 rtadjpeak 0.023 1
6 binary > 0.022 1019
20 binary | 0.018 1015
23 binary + 0.002 3036
22 binary - 0.002 1013
17 binary / 0.001 1013
21 isempty 0.000 1014
8 prefix ! 0.000 1016
2 abs 0.000 2
3 mean 0.000 2
16 sum 0.000 2
25 profile 0.000 1
9 false 0.000 3
4 nargin 0.000 7
13 size 0.000 2
7 isnumeric 0.000 2
10 binary == 0.000 4
11 true 0.000 2
答案 0 :(得分:2)
我认为对{200}元素的逻辑数组的find
的连续调用有点浪费资源。这里的实现(在MATLAB中测试)应该比原始实现快得多,即使它使用循环:它只传递一次的值数组, no find
调用,并动态调整的峰值:
function [peaks_found,peak_sig_adj] =rtadjpeak_fast (signal, T_multi_lower, T_multi_upper)
%// Thresholds
T_lower = - mean(abs(signal))*T_multi_lower;
T_upper = mean(abs(signal))*T_multi_upper;
%// Initial conditioning for signal
Af = signal;
if Af(1) > T_upper
Af(1) = T_upper;
elseif Af(1) < T_lower
Af(1) = T_lower;
end;
if Af(end) > T_upper
Af(end) = T_upper;
elseif Af(end) < T_lower
Af(end) = T_lower;
end;
%// Logical array of peaks
peaks = (Af < T_lower) | (Af > T_upper);
%// Find continuous peaks, in signal and replace values with average in
%// the normal range.
n_max = numel(peaks);
in_peak = false;
counter = 0;
for k = 1:n_max
if ~in_peak && (peaks(k))
% Begin of peak
n_begin = k;
in_peak = true;
elseif in_peak && ~(peaks(k))
% End of peak, a sample ago
n_end = k-1;
in_peak = false;
counter = counter + 1;
% Calculate average in between
n_length = n_end - n_begin + 1;
Af_span = Af(n_end+1) - Af(n_begin-1);
Af(n_begin:n_end) = ...
Af(n_begin-1) ...
+ (Af_span / (n_length + 1)) * (1:n_length);
end;
end;
%// Set output
peaks_found = counter;
peak_sig_adj = Af;
end
请注意%//
只是在StackOverflow代码格式化程序上正确显示注释的技巧。否则我会使用正常评论%
。
答案 1 :(得分:0)
如果您先排序Af
并保存索引,以便以后返回peak_sig_adj
以匹配原始Af
形状,我认为您可以实现更快的运行时间( )然后可以改为:
Faster version of find for sorted vectors (MATLAB)
我还没有完成分析,但我认为find()
时间随着输入的大小线性增加。因此,您希望使用不会如此快速增加的查找函数(例如二进制搜索)。
答案 2 :(得分:0)
如果您只更改了峰值,那么除了第一次以外,您不需要find
整个矩阵。我无法确定你的信号的一部分原本没有峰值可以获得一个。
所以我们这样做了一次:
peaks = find( Af < T_lower | Af > T_upper);
Then inside the loop:
new_peaks = find( Af(peaks) < T_lower | Af(peaks) > T_upper);
peaks = peaks(new_peaks); %making sure indexes match up.
peaks
的大小因此随着迭代而减小。通过对更简单的代码的粗略检查,这应该更快(多少取决于peaks
与完整信号的实际大小的比率)。