如何找到周期性声音信号的频率?

时间:2015-09-03 08:44:18

标签: matlab audio signal-processing fft frequency

我正在研究行走模式的声音信号,它具有明显的规则模式:

Sound of a walking person, X in seconds, Y in sound signal

然后我想我可以使用FFT函数获得行走频率(距图像大约1.7Hz):

    x = walk_5; % Walking sound with a size of 711680x2 double
    Fs = 48000; % sound frquency
    L=length(x); 

    t=(1:L)/Fs; %time base
    plot(t,x);
    figure;

    NFFT=2^nextpow2(L);      
    X=fft(x,NFFT);       
    Px=X.*conj(X)/(NFFT*L); %Power of each freq components       
    fVals=Fs*(0:NFFT/2-1)/NFFT;      
    plot(fVals,Px(1:NFFT/2),'b','LineSmoothing','on','LineWidth',1);         
    title('One Sided Power Spectral Density');       
    xlabel('Frequency (Hz)')         
    ylabel('PSD');

但是它没有给我我的期望:

FFT结果:

FFT result

变焦图像有很多噪音: zoom image has lots of noises

并且1.7Hz附近没有信息 enter image description here

以下是使用

的日志域图表
    semilogy(fVals,Px(1:NFFT));

它非常对称: enter image description here

我发现我的代码没有任何问题。你有什么解决方案可以轻松地从行走模式中提取1.7Hz吗?

这是mat中音频文件的链接 https://www.dropbox.com/s/craof8qkz9n5dr1/walk_sound.mat?dl=0

非常感谢!

1 个答案:

答案 0 :(得分:3)

我建议您忘记DFT方法,因为由于许多原因您的信号不适合此类分析。即使通过查看您感兴趣的频率范围内的频谱,也无法轻松估算峰值:

enter image description here

当然你可以试试PSD / STFT和其他时髦的方法,但这是一种矫枉过正。对于这项任务,我可以想到两种相当简单的方法。

第一个仅基于自动关联功能。

  1. 计算ACF
  2. 定义它们之间的最小距离。由于您知道预期频率约为1.7Hz,因此它对应于0.58s。让我们把它作为最小距离0.5s。
  3. 计算找到的峰之间的平均距离。
  4. 这给了我大约1.72 Hz的频率。

    enter image description here

    第二种方法是基于对你的信号的观察已经有一些周期性的峰值。因此,我们可以使用findpeaks函数简单地搜索它们。

    1. 以与以前相同的方式定义最小峰值距离。
    2. 定义最小峰高。例如,最大峰值的10%。
    3. 获得平均差异。
    4. 这使我的平均频率为1.7 Hz。

      enter image description here

      简单快捷的方法。显然有些事情可以改进,例如:

      • 精炼阈值
      • 找到正峰和负峰
      • 照顾一些缺失的峰值,即由于低振幅

      无论如何,这应该让你开始,而不是陷入蹩脚的FFT和懒惰的semilogx。

      代码段:

      load walk_sound
      
      fs = 48000;
      dt = 1/fs;
      
      x = walk_5(:,1);
      x = x - mean(x);
      N = length(x);
      t = 0:dt:(N-1)*dt;
      
      % FFT based
      win = hamming(N);
      X = abs(fft(x.*win));
      X = 2*X(1:N/2+1)/sum(win);
      X = 20*log10(X/max(abs(X)));
      f = 0:fs/N:fs/2;
      
      subplot(2,1,1)
      plot(t, x)
      grid on
      xlabel('t [s]')
      ylabel('A')
      title('Time domain signal')
      
      subplot(2,1,2)
      plot(f, X)
      grid on
      xlabel('f [Hz]')
      ylabel('A [dB]')
      title('Signal Spectrum')
      
      % Autocorrelation
      [ac, lag] = xcorr(x);
      min_dist = ceil(0.5*fs);
      [pks, loc] = findpeaks(ac, 'MinPeakDistance', min_dist);
      
      % Average distance/frequency
      avg_dt = mean(gradient(loc))*dt;
      avg_f = 1/avg_dt;
      
      figure
      plot(lag*dt, ac);
      hold on
      grid on
      plot(lag(loc)*dt, pks, 'xr')
      title(sprintf('ACF - Average frequency: %.2f Hz', avg_f))
      
      
      % Simple peak finding in time domain
      [pkst, loct] = findpeaks(x, 'MinPeakDistance', min_dist, ...
                                  'MinPeakHeight', 0.1*max(x));
      
      avg_dt2 = mean(gradient(loct))*dt;
      avg_f2 = 1/avg_dt2;
      
      figure
      plot(t, x)
      grid on
      hold on
      plot(loct*dt, pkst, 'xr')
      xlabel('t [s]')
      ylabel('A')
      title(sprintf('Peak search in time domain - Average frequency: %.2f Hz', avg_f2))