可视化fft-signal__Waterplot

时间:2017-01-30 11:30:48

标签: matlab

这是我想象的那种情节。

https://de.mathworks.com/help/matlab/ref/waterfall.html

好的,我不想解释太多,我的代码是如何工作的。这需要太多时间。只需自己尝试第二个代码。拿你能找到的任何小wav文件。编译代码时,您可以看到三个频段,并看到每30ms绘制一个频谱。如果您对我的代码有一个具体的问题,它是如何工作的,请在评论中问我。

我希望每个频谱,至少从一个频段,在三维图中绘制它。简而言之,第一个光谱的坐标是什么,第二个,第三个,第四个等等。 我的时间段是fft应用,长度为30毫秒。 x轴上的第一个点是30 ms,下一个是60 ms,下一个是90 ms,依此类推。 30ms的y坐标是多少?这将在频率轴或y轴上。 z轴将是某个时间点(或在给定的滑动窗口帧)的频率分量之外的幅度。 我该怎么做?我怎么写呢?我在这件事上遇到了大麻烦。而且由于每种解释都使用另一种语言,因此对我来说更难。

你可能知道,我有一个音频文件(音乐),我在其上计算STFT。我想要想象它。请参阅我的代码中的以下说明。阅读评论!

我的第一个想法就是使用函数“mesh”或类似的东西。

这是我的网格代码:

X=1:10;
Y=1:15;
Z = [];

% Here i would define the number of time segments
% See the next following code, to understand, what i mean. 
for i = 1:length(X)

    % Here in this line, i want to compute my short fft
    %

    % number of frequencies
    for j = 1: length(Y)
        Z(j,i) = 1.0/(i*j);
    end
end

mesh(X,Y,Z)

这段代码给我画了一个网格,我只是想知道自己是如何工作的。无论如何请注意,我很确定我不知道,“网格”功能如何发挥最大作用,但我认为,我理解其中的大部分内容。 我需要提到的另一件事是,我在下面的代码中定义了频段。我这样做了,因为我注意到,我的振幅非常高,范围从1到1000Hz,这就是为什么我定义了3个频段。没有必要绘制所有这些,但我想要想象至少一个。不能从音频信号中可视化整个频率范围,而只能看到特定选择的频段。

%% MATLAB
%_________________________________________
[y,fs]=audioread('dontstopmenow.wav');
% audioread = Read WAV-file
% y = Vector, which contains audio signal 
% fs = Sample Rate
% 'dontstopmenow' = WAV-file
%_________________________________________


%PARAMETER FOR STFT
%_________________________________________ 
t_seg=0.03; % Length of segment in ms

fftlen = 4096; %FFT-Points

%Defining the length of my frequency bands
f_LOW= 1:200;    % contain lower frequencies
f_MEDIUM= 201:600;  % contain medium frequencies
f_HIGH= 601:1000; % contain higher frequencies

%_______________________________________________________

segl =floor(t_seg*fs); 
% Length of segment, on which we use the fft
% "floor" rounds off the result
windowshift=segl/2; 
% size of window which goes to the next segment
window=hann(segl); 
%hann function
window=window.'; 
% From a row vector to a column vector
si=1; 
%Start index
ei=segl; 
%End index

N= length(y)/windowshift - 1;
% Number of time segements in audio signal

f1=figure;
    % New window

    f=0:1:fftlen-1;
    f=f/(fftlen-1)*fs;
    % frequency vector

    Ya=zeros(1,fftlen);
  %Plotting time segments!         
for m= 1:1:N 

    y_a = y(si:ei);
    y_a= y_a.*window;
    Ya=fft(y_a, fftlen);
    Ya=abs(Ya(1:end/2));  
      %One-sided-spectrum

      drawnow; %Updates graphical objects

    figure(f1);
    plot(f(1:end/2), 20*log10(Ya));
    %STFT __ plots the whole audio signal after a stft, every 30ms

    %% L,M,H - Bands
    subplot(3,1,1)
    y_low = Ya(f_LOW);
    plot(f_LOW,y_low);
    ylim([-20 60]);
    title('Spektrum (LOW)');
    xlabel('f(Hz)');
    ylabel('dB');
    grid on

    subplot(3,1,2)
    y_medium = Ya(f_MEDIUM);
    plot(f_MEDIUM,y_medium);
    ylim([-20 30]);
    title('Spektrum (MEDIUM)');
    xlabel('f(Hz)');
    ylabel('dB');
    grid on

    subplot(3,1,3)
    y_high = Ya(f_HIGH);
    plot(f_HIGH,y_high);
    ylim([-20 30]);
    title('Spektrum (HIGH)');
    xlabel('f(Hz)');
    ylabel('dB');
    grid on;


    si=si+windowshift; 
    % start index updated    
    ei=ei+windowshift; 
    % end index updated

end

1 个答案:

答案 0 :(得分:0)

以下是您可以添加到代码中以生成瀑布图的语句列表:

让我们将所有STFT输出存储在名为Yb的矩阵中。首先,通过在for循环之前添加此行来分配内存。

Yb = NaN(N, fftlen/2);

接下来,在for循环中,保存每个段的fft结果。这可以通过在完成Ya的计算(在drawnow之前)之后添加以下行来完成。

Yb(m,:) = Ya;

现在您已准备好生成瀑布图。这可以通过在for循环结束后添加以下代码来完成。

figure; 
waterfall(f(f_LOW), (1:N)*windowshift/fs, Yb(:,f_LOW));
xlabel('Frequency (Hz)');
ylabel('Time (s)');

希望这能达到你想要的效果。

以下与主要问题无关:我还提出以下建议以改进代码的其他方面:

(1)频率网格f的计算具有小的缩放误差。它应该是:

f=f/fftlen*fs;

(2)根据您使用的WAV文件,您的代码可能会在windowshiftN中获得小数值,但它们都需要是整数。因此,在计算它们时使用适当的舍入方法。我建议如下:

windowshift = round(segl/2); 
N = floor(length(y)/windowshift);

(3)在for循环中,您只绘制整个fft以立即覆盖子图。该行应删除。