Fundamental Frequency of signal - matlab

I have a signal of 100ms. Fs = 8000 Hz. nbits = 16.
fs_orig = 44100;
nbits = 16;
[signal_orig,fs_orig,nbits]=wavread('oo.wav');
y=resample(signal_orig, 8000,44100);
z=y(1:800,1);
t=(0:1/8000:0.1-1/8000);
plot(t,z);xlabel('Time(s)');ylabel('Amplitude');
How many samples there are I calculated this way
N = fs(Hz)*duration(ms)/1000
N = 8000*100/1000 = 800 samples.
Want to know how i can calculate the length of one period in matlab?
How can i see which frequencies are in the signal?
The fundamental frequency of the period I can calculate by 1/Period time?

If your signal is periodic (like a sine wave, a sawtooth pulse, etc), you can use seqperiod. If your signal is not periodic, the simplest method is to apply fourier analysis (via fft) and look for peaks in its spectrum, which correspond to the most dominant frequencies.
You should also look into this question.
Edit: if your signal varies highly with time, but is periodic for small sections (typically < 50milliseconds), like a speech signal, I would look into cepstral analysis.

Related

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

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.

How can i detect amplitude from FFT on Time-Domain signal

I have a signal of wave song and I have a problem with amplitudes.
%graph 1 time domain
song2 = song(1:size(song));
fs = 44100;
dt = 1/fs;
t = 0:dt:(length(song2)*dt)-dt;
figure();
plot(t,abs(song2)); xlabel('Seconds'); ylabel('Amplitude');
Then I put signal in FFT, because I want to get amplitude of detecting peaks(for example; 164Hz).
%graph 2 fft
L = length(song2);
NFFT = 2^nextpow2(L);
f = fs/2*linspace(0,1,NFFT/2+1);
X = fft(song2,NFFT)/L;
X = 2*abs(X(1:NFFT/2+1));
figure();
plot(f,X);
The problem appear when I get the amplitude of the signal (for example; 0.0103) but if I compare with the amplitude of the (time domain) is not the same.
My question is How in the time domain(graph 1) I detect amplitude of the of a frequency(for example; 164 with amplitude 0.0103)?
EDIT:
Hm, I will rather ask in this way. I detect frequency in frequency domain spectrum as the graph link
For example Let us take the the first signal (82hz)(amplitude:0.0075) And my question if is posible to detect position of this first signal in time-domain as the graph in link
Any help would be helpful.
Have you tried the code with a sinusoidal input?
Make a sinusoid of length 512 (any reasonable length) with amplitude 1 and frequency equal to 164 Hz.
When you run the program, I'm sure you'll see the gain at the frequency bin corresponding to 164 Hz close to one, as long as your frequency resolution isn't too bad (meaning you haven't used too few FFT points).
If the above works, then your code should work for a song too. How you're judging/verifying time-domain amplitude in the case of a multi-tonal time domain signal like music is something I don't know.
If I understand your question correctly, you can find what you want by taking the inner product of the time domain signal with a complex sinusoid at the frequency of interest. For example, using the information from your post we would something like the following:
% graph 1 time domain
song2 = song(1:size(song));
fs = 44100;
dt = 1/fs;
t = 0:dt:(length(song2)*dt)-dt;
x_164 = exp(-1j * 2*pi * 164 * t);
f_164 = x_164(:).' * song2(:); % Spectral content of the signal at 164(Hz).
If you think about what a DFT is, you'll see it's just the above process but with the frequencies chosen such that they from an orthogonal basis. However, you can use the same process to estimate the spectral content at any frequency you want.

Why it is showing multiple or varying frequency?

I was expecting the frequency component to be 1700 i.e. a spike at 1700 but the output shows multiple frequency:
fs = 44100;
t = 0:1/fs:0.001;
s = sin(2 * pi * 1700 * t);
subplot(211), stem(abs(fft(s))), title('abs(fft(s))')
subplot(212), stem(s), title('s')
Similarly when I tried the below code I did not got what I expected:
Fs = 8000;
dt = 1/Fs;
StopTime = 0.25;
t = (0:dt:StopTime-dt)';
Fc = 60;
x = cos(2*pi*Fc*t);
subplot(211), stem(abs(fft(x))), title('abs(fft(x))')
subplot(212), stem(x), title('x')
Why my frequency component are being displayed as multiples values as there should be exactly one frequency present in a signal in one steady sine / cos wave.
It's a single frequency, but it appears twice: positive and negative frequencies. You'll see this better with fftshift, which arranges the frequency samples so that they run from -fs/2 to fs/2:
subplot(211)
freq_axis = -fs/2+fs/numel(t):fs/numel(t):fs/2;
stem(freq_axis, abs(fftshift(fft(s))))
title('abs(fft(s))')
For example, in your first example this produces the following figure.
Note the two spikes around +1700 and -1700 Hz. Their location is not exact for two reasons:
Your time signal is of finite duration, which produces convolution with a sinc in the frequency domain. That is, the frequency spike is made wider.
The FFT gives frequency samples, and none of those samples falls exactly at +/-1700 Hz.
In your second example the time signal is longer (it contains more cycles), which reduces the width of the frequency spikes. This can be appreciated in your second figure (again the fftshift correction is needed to make the two spikes appear in symmetric frequency locations).
Since your signal is not an integer number of cycles there is a discontinuity (remember that the Fourier Transform assumes periodicity), which results in spectral leakage, which is visible as a "smearing" of the spectrum. To avoid this we usually apply a suitable window function (e.g. von Hann aka Hanning window)prior to the FFT - think of this as smoothing out the discontinuity. This reduces the smearing and makes peaks more distinct.
As noted in another answer, you also see a second peak because you're plotting the entire spectrum, and every component in the time domain has a positive and a negative frequency component in the frequency domain. For a real-valued signal the FFT is complex-conjugate symmetric in the frequency domain and so half of the spectrum is redundant. You would normally only plot N/2 values.

Detection of peaks in the frequency spectrum without using FFTs MATLAB

Assuming I have a signal x(t), would it be possible for me to detect the peak in the frequency spectrum (that is, the frequency with the highest energy content) without using FFTs ?
*PS - I saw something in Wavelet Decomposition called scale2freq(). I looked over that in the MATLAB help page and it ended up confusing me. Does the function have anything to do with frequency representations? If yes, how do I find peak frequencies using it?
What you probably want is called a pitch detection algorithm and there is a variety of them in time-domain or frequency-domain (or both of them). Please search google for "pitch detection algorithms" for further reference or check selected links for a quick overview:
http://en.wikipedia.org/wiki/Pitch_detection_algorithm
http://sound.eti.pg.gda.pl/student/eim/synteza/leszczyna/index_ang.htm
In time-domain some simple approach is to locate peaks of autocorrelation function. Indeed autocorrelation is maximal at t=0 and then next peaks gives an estimation of the main period:
ncount = 10000;
Ts = 0.0001; % Sampling period
t = (1:ncount) * Ts; % Sampling times
f = sin(2*pi*60*t) + 0.1*sin(2*pi*200*t) + 0.01 * randn(1, length(t)); % Signal
R = xcorr(f);
[~, locs] = findpeaks(R);
meanLag = Ts * mean(diff(locs));
pitch = 1 / meanLag; ===> Will be around 60 Hz
This approach is ok for very basic signals, you'll probably have to refine it upon you situation (noise level, periodicity, multi-tone, etc...). See above references for more refined algorithms.