FFT plot in Matlab - matlab

I have a small input signal of 60Hz sine wave from signal generator, which is corrupted with 50Hz mains supply frequency. I want to measure the amplitude of the 60Hz signal using FFT because it is very small to see in the oscilloscope.
The Matlab FFT code:
y = data;
Fs = 2048;
[r, L] = size(y);
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)))
But the FFT plot doesn't give a sharp peak at 50 and 60Hz. The plot looks like this:
The consecutive points have high and low amplitude alternatively which gives a saw-tooth like plot. Why is it so? Is the amplitude of 60Hz affected by this?

Probably there are two effects
If one measures a time window of a signal, this leads unavoidable to a phase gap between the start and endpoint of the signal modes. The FFT of a gap or a rectangular signal causes high frequency oscillations. These oscillations caused by border effects can be damped due to a window function, which smooths out the signal to the borders.
There is a discrete frequency spectra in DFT. If one measures a signal which does not match to any of these discrete modes, a lot more frequencies are necessary to reconstruct the original signal.

Your 50 Hz signal may not be a pure perfect sine wave. Any differences from a perfect sine-wave (such as clipping or distortion) is equivalent to a modulation that will produce sidebands in the spectrum.
Windowing a signal whose period is not an exact sub-multiple of the FFT length will also convolve windowing artifacts with that signal.

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

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.

Plotting the magnitude and phase spectra of a wav file in the range of -fs/2 to fs/2

I'm having problems plotting the FFT of a wav file. I managed to plot the magnitude and phase spectrums of the signal, however I need to repeat this in range -fs/2:fs/2.
%read sound files
%'y' is the vector holding the original samples & 'fs' refers to the sampling frequency
[y,fs] = wavread('handel.wav');
ydft = fft(y); %fft to transform the original signal into frequency domain
n = length (y); %length of the original signal
% y has even length
ydft = ydft(1:length(y)/2+1);
% create a frequency vector
freq = 0:fs/length(y):fs/2;
shiftfreq = fftshift(freq);
%plot original signal in time domain;
figure;
plot ((1:n)/fs, y);
title('handel.wav in time domain');
xlabel ('second');
grid on;
% plot magnitude in frequency domain
figure;
plot(freq,abs(ydft));
title('handel.wav in frequency domain');
xlabel ('Hz');
ylabel('Magnitude');
grid on;
% plot phase in frequency domain
figure;
plot(freq,unwrap(angle(ydft)));
title ('handel.wav in frequency domain');
xlabel ('Hz');
ylabel ('Phase');
grid on;
What you are currently doing now is plotting the half spectrum, so from 0 <= f < fs/2 where fs is the sampling frequency of your signal, and so fs/2 is the Nyquist frequency. Take note that considering the half spectrum is only valid if the signal is real. This means that the negative spectra is symmetric to the positive spectra and so you don't really need to consider the negative spectra here.
However, you would like to plot the full spectrum of the magnitude and phase. Take note that when calculating the fft using MATLAB, it uses the Cooley-Tukey algorithm so when computing the N point FFT, half of result is for the frequencies from 0 Hz inclusive up to fs/2 Hz exclusive and the other half is for the frequencies from -fs/2 Hz inclusive up to 0 Hz exclusive.
As such, to plot the full spectrum, simply perform a fftshift on the full signal so that the right half and left half of the spectrum is swapped so that the 0 Hz frequency is located in the centre of the signal. Also, you must generate frequencies between -fs/2 to fs/2 to cover the full spectrum. Specifically, you need to generate N points linearly spaced between -fs/2 to fs/2. However, take note that the Nyquist frequency at fs/2 Hz is being excluded at the end, so you need to generate N+1 points between -fs/2 to fs/2 and remove the last point in order for the right step size between each frequency bin to be correct. The easiest way to generate this linear array of points is by using the linspace command where the start frequency is -fs/2, the ending frequency is fs/2 and you want N+1 points between this range and remove the last point:
freq = linspace(-fs/2, fs/2, n+1);
freq(end) = [];
As such, borrowing some parts of your code, this is what the modified code looks like to plot the full spectrum of the magnitude and phase:
%// Read in sound file
[y,fs] = wavread('handel.wav');
%// Take N-point FFT where N is the length of the signal
ydft = fft(y);
n = numel(y); %// Get N - length of signal
%// Create frequency vector - make sure you remove last point
freq = linspace(-fs/2, fs/2, n+1);
freq(end) = [];
%// Shift the spectrum
shiftSpectrum = fftshift(ydft);
%//plot original signal in time domain;
figure;
plot ((0:n-1)/fs, y); %// Note you should start from time = 0, not time = 1/fs
title('handel.wav in time domain');
xlabel ('second');
grid on;
%// plot magnitude in frequency domain
figure;
plot(freq,abs(shiftSpectrum));
title('handel.wav in frequency domain');
xlabel ('Hz');
ylabel('Magnitude');
grid on;
%// plot phase in frequency domain
figure;
plot(freq,unwrap(angle(shiftSpectrum)));
title('handel.wav in frequency domain');
xlabel('Hz');
ylabel('Phase');
grid on;
I don't have access to your handel.wav file, but I'll be using the one provided with MATLAB. You can load this in with load handel;. The sampling frequency is stored in a variable called Fs, so I had to do fs = Fs; before the code I wrote above could work. The sampling frequency for this particular file is 8192 Hz, and this is approximately a 9 second long file (numel(y) / fs = 8.9249 seconds). With that file, this is the magnitude and phase that I get:
For the discrete Fourier transform (DFT) as well as its fast implementations (FFTs), the frequencies are normalized with the sampling frequency fs, i.e., the original range -fs/2:fs/2 is changed to -pi:pi.
Besides, the DFT/FFT always starts with 0, and you can use fftshift() to shift the 0 frequency to the center. Therefore, after fftshift(), the range is -pi:pi, then, you can scale to -fs/2:fs/2.
look at the following Matlab function, it can calculate phase spectrum as well as amplitude spectrum with a perfect accuracy:
https://www.mathworks.com/matlabcentral/fileexchange/63965-amplitude-and-phase-spectra-of-a-signal--fourier-transform-
This program calculates amplitude and phase spectra of an input signal with acceptable accuracy especially in the calculation of phase spectrum.The code does three main jobs for calculation amplitude and phase spectra. First of all, it extends the input signal to infinity; because for calculation Fourier transform(FT) (fft function in Matlab), we consider our signal is periodic with an infinite wavelength, the code creates a super_signal by putting original signal next to itself until the length of super_signal is around 1000000 samples, why did I choose 1000000 samples? Actually, it is just based on try and error!! For most signals that I have tried, a supper signal with 1000000 samples has the best output.
Second, for calculating fft in Matlab you can choose different resolutions, the Mathwork document and help use NFFT=2^nextpow2(length(signal)), it definitely isn't enough for one that wants high accuracy output. Here, I choose the resolution of NFFT=100000 that works for most signals.
Third, the code filters result of FT by thresholding, it is very important step! For calculating phase spectrum, its result is very noisy because of floating rounding off error, it causes during calculation "arctan" even small rounding off error produces significant noise in the result of phase spectrum, for suppressing this kind of noise you can define a threshold value. It means if amplitude of specific frequency is less than predefined threshold value (you must define it) it put zero instead of it.
These three steps help to improve the result of amplitude and phase spectra significantly.
IF YOU USE THIS PROGRAM IN YOUR RESEARCH, PLEASE CITE THE FOLLOWING PAPER:
Afshin Aghayan, Priyank Jaiswal, and Hamid Reza Siahkoohi (2016). "Seismic denoising using the redundant lifting scheme." GEOPHYSICS, 81(3), V249-V260. https://doi.org/10.1190/geo2015-0601.1

How to know sampling frequency of a sin(x) function

Consider the following script that plots a sine wave.
t = 0:pi/100:2*pi;
y = sin(t);
plot(t,y)
grid on % Turn on grid lines for this plot
This gives me a plot of sine wave. I understand the sine wave that appears continuous, should actually be discrete (my PC cannot store infinite no. of samples of continuous signal), and the matlab plot function does some kind of interpolation to connect the dots.
So In fact I also used stem instead of plot to see the sampled values (on time axis) of sine.
Now my question is there must be some sampling frequency used here. How much is that?
The sampling interval is the time interval between two consecutive samples of your signal.
The sampling frequency means how much samples of your signal you have in a fixed time interval, and it is reciprocal to the sampling interval.
You declared:
t = 0:pi/100:2*pi;
So your sampling interval is π/100. This means that your sampling frequency is 100/π.
If you want exact units, you'll have to determine the time units for t. If t is in seconds, then your sampling frequency is 100/π Hz (1Hz = 1sec-1).
By the way, MATLAB's plot connects the sampling with straight lines, there is no additional interpolation involved.

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).