【问题标题】:Matlab - seemingly simple instruction causes high cpu loadMatlab - 看似简单的指令导致高cpu负载
【发布时间】:2017-07-30 07:57:57
【问题描述】:

我正在编写一个实现噪声门算法的 Matlab 脚本。它遍历输入信号的长度(我在同一个脚本中创建)并逐个样本处理。该算法本身不需要太多内存(它会将两个值传递到下一次迭代,即x_peak_oldg_old)。然而,为了监控算法的内部过程,我创建了一些额外的调试向量,它们与输入信号的长度相同,并随着每个循环进行更新。我会根据需要对它们进行评论。

但是,我的问题是这些向量之一的行为很奇怪。如果我禁用此向量并点击“运行”,脚本将立即执行并完成。但是,当我在每个循环中为这个特定向量分配值并运行脚本时,需要几秒钟的时间来计算,并且我的 CPU 的一个内核在此期间处于 100% 负载。

代码如下:

clear all; close all;

% ***** Parameter *****
Fs = 44100; % Samplerate
ta = 5; % Attack time in ms
tr = 300; % Release time in ms
th = -8; % Threshold in dB
R = 0.05; % Ratio in dB/dB

% ***** Test signal *****
f0 = 20000; % Frequency in Hz
a = (0:Fs) ./ Fs;
aflip = fliplr(a);
sine = sin((2 * pi * f0 / Fs) .* (0:Fs));
sinedecay = zeros(1, Fs);
for k = 1:(Fs+1)
    sinedecay(k) = sine(k)*aflip(k);
end
zeropad = zeros(1, Fs);
% Sine only
% x = [zeropad sine sinedecay zeropad];
% Triangle Rectangle Sine
x = [zeropad a (1-a) -a a-1 zeropad ones(1, Fs) (-1).*ones(1,Fs) zeropad sine sine sinedecay zeropad];
% Dirac
%x = [zeropad 1 zeropad];
siglen = length(x);
x_axis = (1:siglen) ./ Fs;

% ***** Output signal *****
y = zeros(1, siglen);

% ***** Debug signals *****
%threshold = 10^(th/20) .* ones(1, siglen);
%xpeakt = zeros(1, siglen);
%peaklogt = zeros(1, siglen);
%ctrl_logt = zeros(1, siglen);
f_t = zeros(1, siglen);
gt = zeros(1, siglen);

% ***** Derived parameters *****

AT = 1/(1+ta*Fs/1000);
RT = 1-1/(1+tr*Fs/1000);
TH_log = log2( 10^(th/20));
S = 1 - 1/R;

% ***** Initial parameters *****

x_peak_old = 0;
g_old = 0;

% ***** Lets go! *****

for i = 1:siglen 

% Peak measurement
    p0 = abs(x(i));
    x_peak = x_peak_old * RT;
    if (p0 > x_peak)
        x_peak = p0 * AT + x_peak_old *(1-AT);
    end
    x_peak_old = x_peak;
%    xpeakt(i) = x_peak; % DEBUG
    x_peak_log = log2(x_peak);
%    peaklogt(i) = x_peak_log; % DEBUG

% Compare with threshold

    ctrl_log = TH_log - x_peak_log;
    if (ctrl_log < 0)
        ctrl_log = 0;
    end
%    ctrl_logt(i) = ctrl_log; %DEBUG

% Calculation of weight factor

    f = S * ctrl_log;
    f_t(i) = f; %DEBUG
    g = 2^f;

% Smoothing filter for weight factor
    if (g > g_old) 
        coeff = 1-AT;
    else
        coeff = 1-RT;
    end
    temp = g;    
    g = coeff * g + (1-coeff) * g_old;
    g_old = temp;

    % THE FOLLOWING LINE CAUSES PROBLEMS
    gt(i) = g; % DEBUG

% Calculation output signal
    y(i) = x(i) * g;
end

% ***** Plot input, output and debug signals *****
figure;
subplot(211);
plot(x_axis, x);
hold on; grid on;
%plot(x_axis, threshold);
%plot(x_axis, xpeakt); %DEBUG
%plot(x_axis, peaklogt); %DEBUG
%plot(x_axis, ctrl_logt); %DEBUG
plot(x_axis, f_t); %DEBUG
%plot(x_axis, gt); %DEBUG
subplot(212);
plot(x_axis, y);

导致问题的那一行是接近尾声的那一行:

gt(i) = g; % DEBUG

然而,就在几行之前,在同一个循环中,我以同样的方式为向量赋值:

f_t(i) = f; %DEBUG

两个向量的初始化方式相同。此循环中有更多向量以完全相同的方式处理,但只有 gt(i) 向量表现奇怪。

我在运行 Matlab R2014b 的两台不同机器上测试了这个脚本。是什么导致了这个问题?

【问题讨论】:

  • 呵呵....有意思
  • 我想我找到了问题的根源 - gt() 似乎也是一个等效于“>”运算符的内置函数。只需将向量 gt 重命名为其他名称即可解决它。哦!
  • @UnbescholtenerBuerger 请添加一个 asnwer。这对社区来说很有趣。Shadowing builtins 确实会大大降低速度!
  • 好的,我做到了。如果您不小心屏蔽了内置函数,有什么方法可以切换警告?
  • @UnbescholtenerBuerger,没有办法切换自动警告,但如果您怀疑变量名遮蔽了内置函数名,请在使用变量之前使用命令which,它会告诉您此名称是否映射到内置函数(甚至是您自己在搜索路径中的函数)。

标签: matlab


【解决方案1】:

只需将变量 gt 的名称更改为其他名称(内置函数的名称除外)。


我认为情况正是如此,当 Mathworks 告诉您不建议重载内置函数时会警告您。

gt 函数是简写运算符&gt; 的完整形式。

在运行脚本之前:

>> which gt
built-in (C:\TLAB13a\toolbox\matlab\ops\@double\gt)  % double method

运行脚本后:

>> which gt
gt is a variable.

我可以在 Matlab R2013a 中重现所描述的行为(带调试变量约 7.5 秒,不带调试变量为 0.1 秒)。

请注意,在 R2016a 上,此行为不存在(两个版本都约为 0.12 秒)。较新的 Matlab 引擎不会那么容易被重载的内置函数混淆。


在您的情况下,对于使用较旧 Matlab 版本的人,只需将变量名称从 gt 更改为其他任何名称(除了另一个内置函数的名称),例如 gtx,让脚本运行即使使用调试变量,也能很好且快速。

【讨论】:

    【解决方案2】:

    发现了恶作剧。显然问题是由向量的名称gt 引起的,它也是一个等效于“>”运算符的内置函数。覆盖对速度有很大影响。只需重命名向量即可解决问题。

    【讨论】:

    • 我可以确认其他几个内置函数也会发生这种情况。经验教训:隐藏内置函数会大大降低您的代码速度!
    猜你喜欢
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    • 2013-11-30
    • 1970-01-01
    • 2014-11-22
    • 2012-07-24
    • 2019-11-04
    • 1970-01-01
    相关资源
    最近更新 更多