Extraction of frequencies and there indices from FFT graph ( for DTMF Detection)

24 Ansichten (letzte 30 Tage)
Here I took fft of my input signal and from here I want to extract the two frequencies and indeces, my x function have. I am trying to implement DTMF detection. I have tried using findpeaks but was not able to get appropriate answer. Below is the part of my code.
Fs=8000
x= sin(2*pi*697*.t) + sin(2*pi*1209*.t)
X1=abs(fft(x))
w_range = -pi:2*pi/length(x):pi-1/length(x);
f_range = w_range*Fs/2/pi;
plot(f_range, abs(fftshift(X1)))
  2 Kommentare
dpb
dpb am 29 Mai 2022
Show what you tried with findpeaks; you probably will need to do some peak screening but it will undoubtedly be able to find/return the desired information.
You didn't show your t vector so we can't identically reproduce your example; there is a typo in the line defining x -- the dot operator .* is written backwards as *. . Will have to correct that to run the above code as well as define t.
I'd think for this purpose you'd be better served to also return the one-sided PSD instead of two-sided, but that's a detail.
Muhammad Awab
Muhammad Awab am 29 Mai 2022
t vector is
t=0:0.000125:0.3
also '.' with t is a typo, Basically I am implementing gui using appdesigner in my code hence defined t vector to be a property, therefore we use app.t to use the value of t.
Now here is my code (working properly, I checked)
t=0:0.000125:0.3;
Fs=8000;
x= sin(2*pi*697*t) + sin(2*pi*1209*t)
X1=abs(fft(x))
w_range = -pi:2*pi/length(x):pi-1/length(x);
f_range = w_range*Fs/2/pi;
plot(f_range, abs(fftshift(X1)))
[p,i]=findpeaks(X1) %I believe, I am not using this command correctly or there may be any other step before it.
The output my code generates is as follows.
Also the value of p and i variable is
But value of 'i' should be 697 and 1207 (I believe, not sure as using findpeaks first time and even after reading the documentation still stuck at this issue)

Melden Sie sich an, um zu kommentieren.

Akzeptierte Antwort

dpb
dpb am 29 Mai 2022
>> Y=abs(fftshift(X1));
>> [pk,fpk]=findpeaks(Y,f_range)
pk =
1156.37 1132.03 1132.03 1156.37
fpk =
-1211.16 -698.04 694.71 1207.83
>>
You didn't give findpeaks the frequency vector to use to return frequency; it returns indices into the vector otherwise; that's all it's got to work with.
Also, with the 2-sded spectrum you didn't pass it the shifted/zero-centered vector but the unshifted one instead.
Above gives the nearest frequency in the frequency; notice you're not quite symmetric around the DC bin; the negative and positive frequenies aren't quite the same numerically, despite the sign.
I'd use an even number of samples and something like
L=2048;
Fs=1/0.000125;
t=(0:L-1)/Fs;
x= sin(2*pi*697*t) + sin(2*pi*1209*t);
P2=abs(fft(x))/L;
P1=P2(1:L/2+1);
P1(2:end-1)=2*P1(2:end-1);
f=Fs*[0:(L/2)]/L;
plot(f,P1)
xlim([0 2000])
[pk,fpk]=findpeaks(P1,f)
returns
>> [pk,fpk]=findpeaks(P1,f)
pk =
0.72 0.64
fpk =
695.31 1210.94
>>
NB: the peak amplitudes aren't unity and the bins still don't precisely match because the frequency resolution isn't such that the bin peaks match the actual frequency exactly. Hence the total power is distributed across the bins containing the peak and must be integrated to get the total.
Increasing the sample time or zero-padding to interpolate a finer frequency grid would get you frequency binning that would come closer to the input frequencies if these are known and fixed.
Real signal with some noise contamination will also cause some spreading of energy, averaging over the signal span can reduce its end effect as the random noise will tend to cancel.

Weitere Antworten (1)

Voss
Voss am 29 Mai 2022
The second output from findpeaks is the location of the peaks, which are the indices in the input vector where the peaks occur. If you want to know where the peaks are in terms of frequencies, you must index your vector of frequencies f_range using those same indices.
(Also, I suspect you want to findpeaks of abs(fftshift(X1)), which is what is plotted, rather than findpeaks of X1 itself.)
t=0:0.000125:0.3;
Fs=8000;
x= sin(2*pi*697*t) + sin(2*pi*1209*t);
X1=abs(fft(x));
w_range = -pi:2*pi/length(x):pi-1/length(x);
f_range = w_range*Fs/2/pi;
plot(f_range, abs(fftshift(X1)))
% [p,i]=findpeaks(X1)
[p,i]=findpeaks(abs(fftshift(X1)))
p = 1×4
1.0e+03 * 1.1564 1.1320 1.1320 1.1564
i = 1×4
838 992 1410 1564
f_range(i) % 3rd and 4th values here are 695 and 1208, close to what's expected (1st 2 are negative of those, roughly)
ans = 1×4
1.0e+03 * -1.2112 -0.6980 0.6947 1.2078

Tags

Produkte


Version

R2021a

Community Treasure Hunt

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

Start Hunting!

Translated by