【发布时间】:2026-01-31 21:05:02
【问题描述】:
我正在尝试从 MATLAB 中的采样信号生成一系列“听觉尖峰”,而我目前实施的方法很慢。太慢了。
尖峰是在http://patrec.cs.tu-dortmund.de/pubs/papers/Plinge2010-RNF.pdf 的第二部分 B 中生成的:检测零交叉并对每对之间信号的(平方根压缩)正部分求和。这给出了每个尖峰的高度。它们的位置是通过识别每对零交叉之间的最大值的样本来找到的。
我想过为此使用 accumarray(...) ,这让我想到了生成一个矩阵,其中每一列代表一对零交叉(一个尖峰),每一行代表一个样本。然后在相应的零交叉对之间填充每一列。
当前的实现是从实际的数据向量中填充这些列,这样我们之后就不必使用 accumarray 了。
当前实现:
function out = audspike(data)
% Find the indices of the zero crossings. Two types of zero crossing:
% * Exact, samples where data == 0
% * Change, where data(i) .* data(i+1) < 0; that is, data changes sign
% between two samples. In this implementation i+1 is returned as the
% index of the zero crossing.
zExact = (data == 0);
zChange = logical([0; data(1:end-1) .* data(2:end) < 0]);
zeroInds = find(zExact | zChange);
% Vector of the difference between each zero crossing index
z=[zeroInds(1)-1; diff(zeroInds)];
% Find the "number of zeros" it takes to move from the first sample to the
% a given zero crossing
nzeros=cumsum(z);
% If the first sample is positive, we cannot generate a spike for the first
% pair of zero crossings as this represents part of the signal that is
% negative; therefore, skip the first zero crossing and begin pairing from
% the second
if data(1) > 0
nzeros = nzeros(2:2:end);
nones = z(3:2:end)+1;
else
nzeros = nzeros(1:2:end);
nones = z(2:2:end)+1;
end
% Allocate sparse array for result
G = spalloc(length(data), length(nzeros), sum(nones));
% Loop through pairs of zero crossings. Each pair gets a column in the
% resultant matrix. The number of rows of the matrix is the number of
% samples. G(n, ii) ~= 0 indicates that sample n belongs to pair ii
for ii = 1:min(length(nzeros), length(nones))
sampleInd = nzeros(ii)+1:nzeros(ii)+nones(ii)-1;
G(sampleInd, ii) = data(sampleInd);
end
% Sum the square root-compressed positive parts of signal between each zero
% crossing
height = sum(sqrt(G), 2);
% Find the peak over average position
[~, pos] = max(G, [], 2);
out = zeros(size(data));
out(pos) = height;
end
正如我所说,这很慢,一次只能用于一个频道。缓慢的部分(不出所料)是循环。如果我将矩阵 G 的分配更改为标准 zeros(...) 而不是稀疏数组,那么由于显而易见的原因,缓慢的部分就会变成 sum(...) 和 max(...) 计算。
我怎样才能更有效地做到这一点?如果需要的话,我并不反对编写 MEX 函数。
【问题讨论】:
-
您正在进行的处理看起来适合信号的串行处理。我想这种串行处理最好在 C/C++ 中完成,而不是在 Matlab 中。你有没有考虑过这个功能?
-
如果我理解正确,sampleInd 是循环中每个点的向量。在这种情况下,如果您使用索引矩阵而不是许多向量,您可能能够消除循环。
标签: matlab optimization