如何优化需要多个带通滤波器的基于Matlab的音频可视化器?

时间:2019-04-18 03:42:29

标签: matlab signal-processing fft

问题

我已被分配使用Matlab中的FFT设计音频可视化器的任务。我已经完成了大部分与音频可视化工具有关的工作,但由于程序受处理器限制,我无法顺利运行该程序。我想用可视化工具做更多的事情,但是我不想在实现基本功能正常运行之前再实现一些功能。

背景

该程序实际上是两个部分。第一部分是音频播放器,运行一个名为CLICK_ME.m的matlab脚本。第二个是currentfft()。它吸收了歌曲中的信息,在我弄闷之前,它绘制了(频率,功率)图。但是,这是最基本的可视化工具,我的教授希望我们创建一个独特的音频可视化工具。

我的想法是绘制这些五角形中的一个五角形,其中五个点的半径是在五个频带之间过滤的功率。

自然地,我实现了matlab的bandpass()函数,并且可以做到这一点。但是,它需要的处理能力比我预期的要大得多,因此它正成为瓶颈,看起来确实很不稳定。

我尝试通过使用for循环获取其他所有或第三个值来减少必须执行计算的点数。我已经做到了这一点,减少了10到几乎没有明显的成功。如果我删除的数据多于十分之一,那么我会从matlab中收到错误消息,认为它不能对少于六个样本执行bandpass()操作。

我的教授建议采用gaussmf()rectangularPulse()来模拟接近带通滤波器的东西,但是我不确定如何实现它们,或者它们是否会更快。

function currentfft ( player, Y, FS )

sampleNumber = get( player, 'CurrentSample' );
timerVal = get( player, 'TimerPeriod' );

%Get channel one values for our window around the current sample number
s1 = Y(floor(sampleNumber-((timerVal*FS)/2)):floor(sampleNumber+((timerVal*FS)/2)),1);

n = length(s1);
p = fft(s1); % take the fourier transform

nUniquePts = ceil((n+1)/2);
p = p(1:nUniquePts);    % select just the first half since the second half
                        % is a mirror image of the first

p = abs(p);             % take the absolute value, or the magnitude

p = p/n;                % scale by the number of points so that
                        % the magnitude does not depend on the length
                        % of the signal or on its sampling frequency

p = p.^2;               % square it to get the power

% multiply by two
if rem(n, 2) % odd nfft excludes Nyquist point
    p(2:end) = p(2:end)*2;
else
    p(2:end -1) = p(2:end -1)*2;
end


% reduce the number of points actually being filtered
q = 1;
s = 1;
d = int16( length(p) );

pNew = zeros( [ d/10, 1 ] );

while q < d
    pNew(s) = p(q);
    q = q + 10;
    s = s + 1;
end

% try gaussian or rect functions instead of bandpass?

% radius of each section of the pentagon
p0 = abs( bandpass(pNew, [ 1 60 ], FS) );
p1 = abs( bandpass(pNew, [ 60 250 ], FS) );
p2 = abs( bandpass(pNew, [ 250 2e3 ], FS) );
p3 = abs( bandpass(pNew, [ 2e3 8e3 ], FS) );
p4 = abs( bandpass(pNew, [ 8e3 20e3 ], FS) );

% length( p0 )
% length( p1 )
% length( p2 )
% length( p3 )
% length( p4 )

pArr = [ p0, p1, p2, p3, p4 ];

%freqArray = (0:nUniquePts-1) * (FS / n); % create the frequency array

thetaArr = [ pi/2, 4.5*pi/5, 6.5*pi/5, 8.5*pi/5, 10.5*pi/5 ];


% calculating x and y from the radii 
x = cos(thetaArr) ./ pArr; 
y = sin(thetaArr) ./ pArr;

plot(x, y)
xlabel('Frequency (Hz)')
ylabel('Power (watts)')
title('Frequency vs. Power')
grid on;
axis([-20e9 20e9 -20e9 20e9]);

我希望这段代码能够平稳运行,而无需让处理器通过绞拧器。但是,它运行不流畅,并且在我的计算机上占用了两个线程。

1 个答案:

答案 0 :(得分:0)

bandpass函数直接过滤提供的输入样本,从而在同一域中产生“平滑”版本。在您的情况下,输入已经是频域表示,因此您将获得平滑的频域表示,这不是您要实现的目标(取而代之的是平滑时域表示的功能) )。

相反,由于您已经具有频域表示形式,因此您只需选择正确的频点(本质上就是在频域中应用矩形窗口会执行的操作)。

p0 = sum(pNew((floor(1*n/FS)+1):(floor(60*n/FS)+1)));
p1 = sum(pNew((floor(60*n/FS)+1):(floor(250*n/FS)+1)));
p2 = sum(pNew((floor(250*n/FS)+1):(floor(2e3*n/FS)+1)));
p3 = sum(pNew((floor(2e3*n/FS)+1):(floor(8e3*n/FS)+1)));
p4 = sum(pNew((floor(8e3*n/FS)+1):(floor(20e3*n/FS)+1)));

如果您仍要对FFT进行下采样,则可能想等效地(但更有效地)对较小的FFT求和:

% pad to a size that is a multiple of the block size
D = 10;
L = ceil(n/D);
M = L*D;
s2 = zeros(1,M);
s2(1:length(s1)) = s1;
% compute the downsampled FFT by summing smaller FFTs
p = zeros(1,L);
for i = 0:(D-1)
    p = p + fft(s2((1+i*L):(1+L+i*L)));
end