Matlab: how to find fundamental frequency of a speech - matlab

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.

Related

finding the frequency of signal without using FFT

I have sine signal with noise where the number of points of noise per oscillation should be the same in my code five points per oscillation) , I want to change each time the number of oscillation :2,3,4….15 ( in my code changing the vairable "random")
At each number of oscillation I shall extract the amplitude as a function of frequency < unfortunately for few oscillation FFT wouldn't work there are too few points in the signal , so I have to fit the signal ( sine with noise ) to sine wave in order to compare the frequency of new signal to the frequency of the sine wave
see my code,how can I do the fitting ,so I can extract the frequency of the signal?
%my code
random=40;
f=5; % the frequency of the sine wave also the number of points per
oscillation
%the number of oscillation is random/f
t = (1:random)';
X = ones(random,2);
y_1= sin((2*pi)/f*t);
X(:,2) = y_1;
y=y_1+randn(random,1);
y = y(:);
beta = X\y;
yhat = beta(1)+beta(2)*sin((2*pi)/f*t);
figure
plot(t,y,'.b','markersize',12);
hold on
plot(t,yhat,'r','linewidth',2);
This is a common problem. Please try the links below or other ones on Stackoverflow. In your case, you have quite a few outliers so you use methods like RANSAC to throw them out.
https://www.mathworks.com/matlabcentral/answers/121579-curve-fitting-to-a-sinusoidal-function
https://www.mathworks.com/matlabcentral/answers/195371-sine-curve-fitting-for-the-given-data

How can i use fft to find the maximum frequency of a periodic signal?

I'm trying to find the maximum frequency of a periodic signal in Matlab and as i know when you convert a periodic signal to the frequency spectrum you get only delta functions however i get a few curves between the produced delta functions. Here is the code :
t=[-0.02:10^-3:0.02];
s=5.*(1+cos(2*pi*10*t)).*cos(2*pi*100*t);
figure, subplot(211), plot(t,s);
y=fft(s);
subplot(212), plot(t,y);
Here is a code-snippet to help you understand how to get the frequency-spectrum using fft in matlab.
Things to remember are:
You need to decide on a sampling frequency, which should be high enough, as per the Nyquist Criterion (You need the number of samples, at least more than twice the highest frequency or else we will have aliasing). That means, fs in this example cannot be below 2 * 110. Better to have it even higher to see a have a better appearance of the signal.
For a real signal, what you want is the power-spectrum obtained as the square of the absolute of the output of the fft() function. The imaginary part, which contains the phase should contain nothing but noise. (I didn't plot the phase here, but you can do this to check for yourself.)
Finally, we need to use fftshift to shift the signal such that we get the mirrored spectrum around the zero-frequency.
The peaks would be at the correct frequencies. Now considering only the positive frequencies, as you can see, we have the largest peak at 100Hz and two further lobs around 100Hz +- 10Hz i.e. 90Hz and 110Hz.
Apparently, 110Hz is the highest frequency, in your example.
The code:
fs = 500; % sampling frequency - Should be high enough! Remember Nyquist!
t=[-.2:1/fs:.2];
s= 5.*(1+cos(2*pi*10*t)).*cos(2*pi*100*t);
figure, subplot(311), plot(t,s);
n = length(s);
y=fft(s);
f = (0:n-1)*(fs/n); % frequency range
power = abs(y).^2/n;
subplot(312), plot(f, power);
Y = fftshift(y);
fshift = (-n/2:n/2-1)*(fs/n); % zero-centered frequency range
powershift = abs(Y).^2/n;
subplot(313), plot(fshift, powershift);
The output plots:
The first plot is the signal in the time domain
The signal in the frequency domain
The shifted fft signal

Computing and plotting the spectrum of a signal using FFT on Matlab

I am missing something in the computation of the spectrum of my signal using FFT on Matlab.
My code:
%% compute the spectrum of the data (data(t))
L = length(time); % length of the sample
NFFT = 2^(nextpow2(L)-1); % Next power of 2 from length of y
Y = fft(data,NFFT);%/NFFT;%L;
Fs = 1/(mean(time(2:end)-time(1:end-1))); % compute the sampling frequency
f = Fs/2*linspace(0,1,NFFT/2+1);
loglog(f,2*abs(Y(1:NFFT/2+1)))
title('Single-Sided Amplitude Spectrum of My Data')
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
Would you be so kind as to tell me where I messed up?
I tried to check if the algorythm works using these two sampling of the same signal (same sampling frequency ; over two different time range 0-10 and 0-100):
fs=1000;
time10 = [0:1/fs:10];
time100 = [0:1/fs:100];
data10 = sin(2*pi*0.23 .*time10)+cos(2*pi*12 .*time10);
data100 = sin(2*pi*0.23 .*time100)+cos(2*pi*12 .*time100);
I guess the two spectrum should supperpose but they don't... As seen here: https://www.dropbox.com/s/wfols9o409pr94u/FFT_spectrum_StackOverflow.png?dl=0
https://www.dropbox.com/s/a8vmzwto6x4130w/FFT_spectrum_StackOverflow.fig?dl=0
Thanks
The good news is that there is nothing wrong with your computation of the spectrum by itself.
The problem is that by looking at samples of different lengths you are effectively looking at two different samples altogether.
In the time-domain, they can be seen as the result of a multiplication of an infinitely long sinusoidal with a rectangular window of different lengths.
In the frequency-domain, the spectrum of the infinitely long continuous-time sinusoidal signal gets convoluted with the spectrum of the rectangular windows. With different window length the corresponding spectrum of those windows have different width (narrower spectrum for longer rectangular windows). As a result, the spikes in the spectrum of the infinitely long sinusoidal signal would get spread over different bandwidths. This is exactly what you are seeing.

How to find the period of a periodic function using FFT?

Assume I have a smooth function (represented as a vector):
x=0:0.1:1000;
y=sin(2*x);
and I want to find its periodicity - pi (or even its frequency -2 ) .
I have tried the following:
nfft=1024;
Y=fft(y,nfft);
Y=abs(Y(1:nfft/2));
plot(Y);
but obviously it doesn't work (the plot does not give me a peak at "2" ).
Will you please help me find a way to find the value "2"?
Thanks in advance
You have several issues here:
You are computing the fft of x when your actual signal is y
x should be in radians
You need to define a sampling rate and use that to determine the frequency values along the x axis
So once we correct all of these things, we get:
samplingRate = 1000; % Samples per period
nPeriods = 10;
nSamples = samplingRate * nPeriods;
x = linspace(0, 2*pi*nPeriods, nSamples);
y = sin(2*x);
F = fft(y);
amplitude = abs(F / nSamples);
f = samplingRate / nSamples*[0:(nSamples/2-1),-nSamples/2:-1];
plot(f, amplitude)
In general, you can't use an FFT alone to find the period of a periodic signal. That's because an FFT does sinusoidal basis decomposition (or basis transform), and lots of non-sinusoidal waveforms (signals that look absolutely nothing like a sinewave or single sinusoidal basis vector) can be repeated to form a periodic function, waveform, or signal. Thus, it's quite possible for the frequency of a periodic function or waveform to not show up at all in an FFT result (it's called the missing fundamental problem).
Only in the case of a close or near sinusoidal signal will an FFT reliably report the reciprocal of the period of that periodic function.
There are lots of pitch detection/estimation algorithms. You can use an FFT as a sub-component of some composite methods, including cepstrums or cepstral analysis, and Harmonic Product Spectrum pitch detection methods.

Getting the peak frequency of a note in MATLAB

I am trying to get the peak frequency of a musical note by using the FFT function that exists in MATLAB. I just copy-pasted the code for FFT of a mathematical function and replaced the function with the audio file.
Fs = 44100; % Sampling frequency
T = 1/Fs; % Sample time
L = 1000; % Length of signal
t = (0:L-1)*T; % Time vector
% Sum of a 50 Hz sinusoid and a 120 Hz sinusoid
y = wavread('c-note2.wav');
plot(Fs*t(1:50),y(1:50))
xlabel('time (milliseconds)')
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)|')
Here, instead of y=wavread('c-note2.wav'), we had something like y=0.15sin(5x)+0.32cos(50t)+rand(I) (To add noise to the signal).
Is what we are trying to do correct? Can we put a wavread instead of a mathematical signal?
From the graph obtained I want to get the peak frequency of the c-note and check whether it is matching with the actual frequency of a c-note, but I am getting absurd results.
The pitch of a musical note is very often different from the peak frequency returned by an FFT. Musical notes usually contain a ton of overtones, many often stronger than the pitch frequency, some possibly even slightly inharmonic in frequency. Search for pitch detection or estimation algorithms instead of just looking at the FFT spectrum.
Also, when using an FFT to look at the audio spectrum, the length of the FFT has to be longer than several periods of the lowest frequency of interest. Your FFT length appears to be much too short to resolve 50 Hz (20 mS period).