Finding peaks in FFT magnitude spectra from wav files

  • Topic: MATLAB 
  • Thread starter Thread starter Ophyron
  • Start date Start date
  • Tags Tags
    Matlab
Join the discussion
Registration is free. Start your own thread to ask a follow-up.
5 replies · 16K views
Ophyron
Messages
1
Reaction score
0
hi,

i'm pretty new to MATLAB - but I've been using it to perform FFT's on .wav files to graph frequency and amplitude. I've been using the following code to generate the graphs:
Matlab:
[h,Fs] = wavread('x.wav');

H = fft(h);
N = length(h);
f = (0:(N-1))*(Fs/N);
t = (0:(N-1))/Fs;

figure(1);

clf;
plot(f,20*log10(abs(H)));

grid;

xlabel('Frequency (Hz)');
ylabel('Amplitude (dB)');

is there any way i can find the frequency at which peaks appear, and the amplitude of these peaks with code? I'm only really interested in the peaks in the first 5000Hz or so, above about 20dB. anyone got any ideas? any pointers would be much appreciated! thanks

take care

Nick
 
Last edited by a moderator:
Physics news on Phys.org
When you say peaks, do you mean the events in time that are the loudest or the places on a FFT plotted frequency spectrum where certain frequency have higher incidences.

In the case of the second example, you could programmatically walk through the array of frequencies and list only those above the 20db mark and zero the others so that they show up more clearly in your plot.

Here's more on using the FFT function:

https://www.mathworks.com/help/matlab/ref/fft.html?searchHighlight=fft&s_tid=doc_srchtitle
 
This may not be a complete specification of what you mean by "peak", but you can write a vector statement that picks out points that are greater than their immediate neighbors to either side.

First of all, your H is complex. You probably want the amplitude X = abs(H);

OK, now there's a really useful trick in Matlab called logical indexing. If you have a vector I of 1's and 0's the same length as X, then X(I) will pick out the elements corresponding to the 1's. Of course, you probably want the locations of those elements for your question. find(I) will do that.

OK, so now I'm going to build a statement which will generate such a vector of 1's and 0's. I'll append the value ##+\infty## to each end of X so that the peaks don't occur there. The expression X > [X(2:end),inf] compares each element of X to the element to its immediate right. The insertion of inf is to pad out the second vector to the right length, and choosing the value ##\infty## as I said guarantees that the comparison will fail at the endpoint.

Finally, I'll use element-wise AND (a single ampersand) to combine this comparison with the one in the other direction. Thus, the whole statement is this:

Peaks = find( (X > [X(2:end), inf]) & (X > [inf, X(1:end-1)] );

As I said, you might decide you need to add other criteria to define your peaks, also connected with "&".

Disclaimer: I don't have Matlab on this computer to test that I got all the syntax right.
 
Last edited:
  • Like
Likes   Reactions: jedishrfu
The command find(max()) will return the indices of the max of an array.
 
First you need to unwrap your fft with fftshift. Then you can use the findpeaks command to find and label peaks. You can then compare to a threshold that you set so as to ignore small peaks.