MATLAB Answers

finding peaks at specific indices/values

조회 수: 22(최근 30일)
Michael Zhu
Michael Zhu 6 Aug 2020
편집: dpb 8 Aug 2020
Hey guys, I am given a wav file with 3 notes playing. The standard fundamental frequencies for these three notes are 196 Hz, 246.9 Hz, and 329.6 Hz. I have found the fundamental frequencies of these notes by finding the peaks within the range of these frequencies shown below. Now I need to find the amplitude of the first 5 harmonics where the fundamental is called the first harmonic, the component at twice the fundamental frequency is called the second harmonic etc. To do this I created an array of 1 through 5 and stored where the fundamental frequency of g was and multiplied it by the array giving me the harmonic frequency values. Now i was wondering if there was a way to find the peaks at these frequency values rather than a range like i did for the fundamental frequency. Below is the graph with the 3 fundamental frequencies pointed out.
%read the audio file x samples, output Fs
[x,Fs]= audioread('Guitar_notes.wav');
%take the fourier transform
xdft = fft(x);
xdft = xdft(1:length(x)/2+1);
% create a frequency vector
freq = 0:Fs/length(x):Fs/2;
%locs is now in frequency
[pks,locs] = findpeaks(20*log10(abs(xdft)));
%finds the peaks within the range of the fundamental frequency of the notes
indesiredrange = locs > 150 & locs < 500;
%gets the subsets within range
pks_subset = pks(indesiredrange);
locs_subset = locs(indesiredrange);
hold on
plot(freq(locs_subset), pks_subset, 'or')
hold off
title('FFT of signal')
%harmonics 1 through 5
k = 5;
harm = 1:k;
%points of frequencies in range
z = freq(locs_subset);
%stores fundamental frequency of note g(193.8 hz)
freqG = z(36);
%gets harmonics 1 through 5
harmG = harm*freqG;

  댓글 수: 0

댓글을 달려면 로그인하십시오.

채택된 답변

dpb 6 Aug 2020
The actual bin frequency is unlikely to match the harmonics frequencies exactly (as in they won't match) so simply selecting the bin number is likely not going to hit the peak frequency identically.
The simplest is probably to just return the closed frequency to the actual frequency of interest returned from the findpeaks function for the peaks.
If you pass the frequency vector to findpeaks, the returned locations will be in frequency so can do direct comparison.

  댓글 수: 4

표시 이전 댓글 수: 1
dpb 7 Aug 2020
>> [196 246.9 329.6].'.*[1:5]
ans =
196.00 392.00 588.00 784.00 980.00
246.90 493.80 740.70 987.60 1234.50
329.60 659.20 988.80 1318.40 1648.00
are the expected frequencies if the tones are pure and the measured waveform returned them (or nearly so).
So, then just find the nearest returned peak frequency to each of those locations -- any number of ways to do that; one would be to use interp1 with the 'nearest' option to lookup the wanted frequency from the returned frequency vector.
Michael Zhu
Michael Zhu 7 Aug 2020
Thank you for your help and I have tried implementing what you have said with the code below but I am running to an issue where the peaks are not where I want them to appear shown in the graph below.
harmonic = [1:5];
[peaks,freqs] = findpeaks(20*log10(abs(xdft)),freq);
harmB = 244.3*harmonic;
vqB = interp1(freqs,peaks,harmB, 'nearest');
hold on
plot(harmB, vqB, 'or')
hold off
title('FFT of signal');
The above code is how i coded and plotted the graph. If you could point what I did wrong or how I could get the plots to be at the desired peaks that would be appreciated as I am very new to matlab.
dpb 7 Aug 2020
Your code
[peaks,freqs] = findpeaks(20*log10(abs(xdft)),freq);
harmB = 244.3*harmonic;
vqB = interp1(freqs,peaks,harmB, 'nearest');
is returning the peak height at the nearest frequency, not the nearest frequency peak in the freqs vector...maybe it's not totally obvious but use
vqB = interp1(freqs,freqs,harmB, 'nearest');
which will then give you the closest value in the freqs vector corresponding to the nth harmonic. This will be matched with the actual peak location that was found and may not be precisely the identical value of the harmonic as discussed above owing to binning and how close the actual frequency is to the bin center.
Alternatively, if you want the location of that peak in the x-axis freq vector, use
indx = interp1(freqs,1:numel(freq),harmB, 'nearest');
which will be the index position of the nearest peak in the freq vector; the frequency of vqB above would be freq(indx) in the latter.

댓글을 달려면 로그인하십시오.

추가 답변(0개)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by