Frequency : Decibel plot using FFT in MATLAB - matlab

I am trying to use MATLAB to import a WAV file and create the type of diagram shown below. I am basically trying to pull frequency information and plot it according to decibels. Here is the code I am working with, but it doesn't seem to pull the frequency information correctly:
[x fs]=wavread('filename.wav');
dt=1/fs;%% time interval
X=fft(x);
df=1/(length(x)*dt); %% frequency interval
f=(1:length(X))*df;%% frequency vector
%% frequency domain plot, freq in hertz
figure
plot(f,abs(X))
Please help! Thank you!

In your code "X" contains the waveform information, not the frequency information. To get the frequency information of the soundfile you could use the FFT function. I use this (more elaborate, but still simple) code for what you want to do:
[FileName,PathName]=uigetfile('*.wav');
[y, Fs, nbits] = wavread(fullfile(PathName,FileName));
length_y=length(y);
NFFT = 2^nextpow2(length_y); % Next power of 2 from length of y
fft_y=fft(y,NFFT)/length_y;
f = Fs/2*linspace(0,1,NFFT/2+1);
semilogy(f,abs(fft_y(1:length(f))));
title('Single-Sided Amplitude Spectrum of y(t)')
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
I hope this is useful to you. The plot will not be in steps like the one you have shown, but that can also be achieved - using the "stairs" plot function.

Related

Matlab: how to find fundamental frequency of a speech

I am new to Matlab and speech processing as well. I want to find the fundamental frequency of speech signal to determine the gender of the speaker. I removed the silence from the signal by analysing it within 10 msec periods.
After that I got the fft using this code :
abs(fft(input_signal_without_silences))
My plot of both the speech signal and the fft of it is below:
Now, I want to find the fundamental frequency but I could not understand which steps do I need to do this. Or do I misunderstand this concept?
As far as I have learnt, there are some methods like autocorrelation,
Since I am not familiar to both speech processing and matlab, any help and advice is very much appreciated.
The fft() help can solve most parts of your problem. I can give a brief overview of things based on the content of the help file.
At the moment what you are plotting is the two sided, unnormalized fft coefficients, which don't tell much. Use the following to get a more user informed spectral analysis of the voice signal. Using the single sided spectram you would be able to find the dominant frequency which might be the fundamental frequency of the speech signal.
y = []; %whatever your signal
T = 1e-2; % Sample time, 10 ms
Fs = 1/T; % Sampling frequency
L = length(y); % Length of signal
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Y = fft(y,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
% Plot single-sided amplitude spectrum.
plot(f,2*abs(Y(1:NFFT/2+1)))
title('Single-Sided Amplitude Spectrum of y(t)')
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
The problem is that you have a plot of Amplitude vs Sample Number instead of a plot of Amplitude vs Frequency.In order to calculate the fundamental frequency you need to find the frequency that corresponds to the highest frequency.
Matlab returns frequencies from -fs/2 to fs/2 so the frequency at index n is
f = n * (fs/N) - (fs/2)
where f = frequency, fs = sampling frequency, N = number of points in FFT.
So basically all you need to do is get the index where the plot is highest and substitute it in the equation above to get an estimate of the fundamental frequency.Make sure n > N/2 so that your fundamental frequency is positive.

Matlab fftshift not working correctly

I am trying to plot the frequency spectrum of a sinewave with frequency 77.5 kHz and amplitude 2. Only the zero-point is not correct, it is shifted to the left.
My code:
f1=77.5e3; % frequency of the sinewave
a1=2; % amplitude of the sinewave
Fs = 1.55e6; % sampling frequency
dt=1/Fs; % step size
maxtime = 5*(1/f1);
t=0:dt:maxtime; % time interval in which we want to plot
x=a1*sin(2*pi*f1*t); % the values for the sinewave
N=length(t); % this is how many samples we have in the time-domain
X=fft(x)/N;
X=fftshift(X);
f=[-N/2:1:N/2-1]*Fs/N; % creates a frequency axis
figure(1)
plot(f,abs(X))
title('Magnitude Spectrum of x(t)')
xlabel('Frequency [Hz]')
ylabel('|X(f)|')
When I run this code I get an incorrect frequency spectrum. Can anyone help me out?
Edit: the figure I get when running this code:
Besides the incorrect zero-point I also get an incorrect frequency when I count it out myself from the plot. I'm just not sure how I should plot such a sinewave with frequency 77.5kHz, amplitude 2 and sampling frequency 1.55 MHz
Your code is correct as it is. But your signal, once made periodic, is not just a sine wave (there is a discontinuity, because the 1st and last samples of x are the same).
You can try removing 1 sample at the end:
t=0:dt:maxtime; % time interval in which we want to plot
t = t(1:end-1);
Now the peak is at f1.

Convolution Theorem via the fft in MATLAB

I'm in the process attempting to convolve and export an audio signal y(t) with a frequency response h(t) in different ways for a MATLAB project. It's been straightforward for the most part, however, I've run into difficulty when trying to convolve the signals using the Convolution Theorem.
I'm able to take the Fourier Transforms of both signals easily using the fft() function, but when I multiply those two results together then use the ifft() functionto find my final signal, the program always outputs garbage. I've tried playing around with padding the input with zeros, but it hasn't done much.
Here's the gist of the code I have at the moment (plot functions were removed for readability).
Y = fft(y);
H = fft(h);
F = Y*H;
f = ifft(F);
For those who are interested, the audio file is a 38 second long .wav file with a sample rate of 22050. The impulse response is the Cosine function between -pi/2 and pi/2.
Thanks in advance, any help is greatly appreciated.
I am a bit rusty with the Convolution Theorem, so I can say something wrong; but I will highlight two things:
The product in frequency should be an element-wise multiplication, i.e.
F=Y.*H.
The frequency response should be a cosine in frequency, not in time. I guess you want a frequency response that does low-pass filtering.
I played a bit with these ideas, and this is what I got:
clear all; close all; clc;
% Signal
load handel.mat;
%sound(y,Fs)
N = numel(y);
t = linspace(0,(N-1)/Fs,N);
% Response
H = abs(cos(linspace(0,pi,N))).';
% FFT product
Y = fft(y);
h = abs(ifft(H));
F = Y.*H;
f = abs(ifft(F));
% Plot
figure('Name','Time-domain');
subplot(3,1,1); plot(t,y); title('Signal');
subplot(3,1,2); plot(t,h); title('System');
subplot(3,1,3); plot(t,f); title('Output');
figure('Name','Frequency-domain');
subplot(3,1,1); plot(abs(Y)); title('Signal');
subplot(3,1,2); plot(abs(H)); title('System');
subplot(3,1,3); plot(abs(F)); title('Output');
% Play
sound(y,Fs);
sound(f,Fs);
In the frequency domain, it looks like the low-pass filtering is working. However, if you listen to the audio, the result for the Handel track is not amazing.
Don't forget to have a look at the good answer of Luis Mendo in here.

Analyzing wav files in MATLAB

So I have this piano recording (in .wav format). I am able to do an FFT on the whole recording and identify frequencies.
However, according to some articles I read, its best if the wav file is broken down into windows, where each window would include one particular note.
For this I need to initially plot a "power envelope" of my time domain signal (considering the note average energy concept) therefore there'll be one increase and one decrease for each note and note onsets can be determined by checking the local minima.
This is where 'windows' are introduced, where each window consists of only one onset and then FFT is performed on each window.
Im having difficulty in plotting the power envelope and moving onto breaking it down into windows. Would appreciate some help with the Matlab coding for this.
The code I've used is pretty straightforward:
[wave,fs] = wavread ('c scale fast.wav'); % read file into memory */
%sound(wave,fs); % see what it sounds like */
wave = wave.*hamming(length(wave));
t = 0:1/fs:(length(wave)-1)/fs; % and get sampling frequency */
figure(2);
subplot(2,1,1);
plot(t,wave);
title('Wave File');
ylabel('Amplitude');
xlabel('Length (in seconds)');
L = length(wave);
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Y = fft(wave,NFFT)/L;
f = fs/2*linspace(0,1,NFFT/2+1);
% Plot single-sided amplitude spectrum.
subplot(2,1,2);
plot(f,2*abs(Y(1:NFFT/2+1)))
title('Single-Sided Amplitude Spectrum of y(t)')
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
After my signal (abs value of my wav file) is convolved with the Gaussian filter i try taking the 1st and 2nd derivatives, but i don't get an output when i try to plot it.
edges=fconv(abs(song),detect);
tedges=edges(P/2:N+P/2-1);
tedges=tedges/max(abs(tedges));
W= diff(tedge);
Z= diff(W);
It is when i try to plot W and Z that I don't get the output I need. My graph is empty in other words. I can't figure out what I'm doing wrong here...
Useful: http://blogs.mathworks.com/videos/2009/12/31/basics-finding-a-subset-of-a-matrix/
Basic flow:
for v=1:window_length:length(data)
data_subsection=data(v:v+window_length);
subsection_fft = fft(data_subsection);
plot(...);
end

Confusion in figuring out the relation between actual frequency values and FFT plot indexes in MATLAB

I know that there are a lot of similar questions to this, I am still unable to figure out the answer.
Let's say we have time signal in MATLAB:
t=0:1/44100:1
and a cosine signal with frequency 500Hz:
x=cos(2*pi*500*t);
Now, I am trying to plot the magnitude spectrum obtained using the fft command on signal x
FFT=abs(fft(x))
plot(FFT)
According to the theory, we should get two peaks in the plot, one at -500 Hz and the other at 500Hz.
What I don't understand is that I do get two peaks but I can't figure out at what frequencies these peaks are. I know there is a way to figure out the frequency using the FFT index, length of the input signal and the sampling frequency but I still can't calculate the frequency.
I know that there are methods to align the FFT plots so that the peaks lie at the index number of the frequency they represent by using the fftshift function, but what I want is to figure out the frequency using the the plot resulting from simply calling this function:
FFT=fft(x)
In this case, I already know that signal contains a cosine of 500Hz, but what if the signal that we want to get the FFT of is not known before time. How can we get the frequency values of the peaks in that sample using the output from the fft function?
You need to generate the frequency array yourself and plot your FFT result against it.
Like this:
function [Ycomp, fHz] = getFFT(data, Fs)
len = length(data);
NFFT = 2^nextpow2(len);
Ydouble = fft(data, NFFT)/len; % Double-sided FFT
Ycomp = Ydouble(1:NFFT/2+1); % Single-sided FFT, complex
fHz = Fs/2*linspace(0,1,NFFT/2+1); % Frequency array in Hertz.
semilogx(fHz, abs(Ycomp))
end
You will see peaks at 500 Hz and Fs - 500 Hz (i.e. 44100 - 500 = 43600 Hz in your particular case).
This is because the real-to-complex FFT output is complex conjugate symmetric - the top half of the spectrum is a "mirror image" of the bottom half when you are just looking at the magnitude and is therefore redundant.
Note that of plotting power spectra you can usually save yourself a lot of work by using MATLAB's periodogram function rather than dealing directly with all the details of FFT, window functions, plotting, etc.