FFT does not return the amplitudes in matlab? - matlab

I have generated the following time signal:
Now I want to perform a Discrete Fourier Transform by using the matlab command fft
Here is my code:
function [ xdft, omega ] = FastFourier( t, fs )
%% Inputs from other functions %%
[P_mean, x, u] = MyWay( t ) %From here comes my signal x(t)
%% FFT %%
xdft1 = fft(x); % Perform FFT
xdft2 = abs(xdft1); % Take the absolute value of the fft results
xdft = xdft2(1:length(x)/2+1); % FFT is symmetric, second half is not needed
freq = 0:fs/length(x):fs/2; % frequency axis
plot (freq(1:100),xdft(1:100));
end
And here is the plot that I get:
And what is puzzling to me is the y axis? Shouldn't the y axis represent the amplitudes of the frequency components? Is there a way to get the amplitudes of all the frequency components?
Thanks!
EDIT:
I have found that some people do the following:
n = size(x,2)/2; %The number of components and second half can be neglected again
xdft2 = abs(xdft1)/n;
This way I seem to get the amplitude spectrum, but why do I have to divide the absolute value by n?

FFT gives you a complex pair in each Frequency Bin. The first bin in the FFT is like the DC part of your signal (around 0 Hz), the second bin is Fs / N, where Fs is the sample rate and Nis the windowsize of the FFT, next bin is 2 * Fs / N and so on.
What you calc with the abs() of such a pair is the power contained in a bin.
you might also want to check this out: Understanding Matlab FFT example

Most (not all) FFT libraries preserve total energy (Parseval's theorem), which means that the magnitude has to get bigger for longer FFT windows (longer stationary waveform -> more energy). So you have to divide the result by N to get a more "natural" looking magnitude height of sinewaves in the spectrum.

If you want the amplitudes of the harmonics, then you need to plot real(xdft1) and imag(xdft1). Real(xdft1) gives you coefficients of all the cosine harmonics present in your signal, from -Fs/2 to +Fs/2, (we assume your Fs is large enough to cover all frequencies in the signal) and the imag(xdft) give the amplitudes of the sines.
What you are doing is giving you the magnitude of the signal, which is the RMS value of the total energy at a bin in both the real and imaginary frequency component.
Its often the item of most interest to people looking at a spectrum.
Basics of this: (https://www.youtube.com/watch?v=ZKNzMyS9Z6s&t=1629s)

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

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

Matlab FFT - Result not understood

I try to understand a result I get on with Matlab FFT and especially with the function fftshift
I first calculate the FFT of a simple signal (y = cos (2 * pi * f_signal * t) and the inverse transform to try to find the original signal.
I compare the results with and without the "zero padding" by adding 100 points higher at the starting signal before performing the FFT.
here is the code:
% Frequency input signal and time vector
f_signal=10;
nb_points = 100;
f_sampling=nb_points*f_signal;
step_time=1/f_sampling;
t=linspace(0,1/f_signal,nb_points);
%% Original signal with 100 points
y=cos(2*pi*f_signal*t);
%% Adding 100 more points for y
n_zero_padding=100;
y_f=padarray(y,[0 n_zero_padding],'post');
% Plot Input Signal
figure(1);
plot(y);
title('Input Signal');
% Perform Forward FFT
z=real(fft(y_f));
% Center FFT
z_centered=fftshift(z);
figure(2);
plot(z_centered);
title('FFT centrered with zero padding');
% Without centering
figure(3);
plot(z);
title('FFT with zero padding');
% Perform Inverse FFT
z_inv=ifft(z);
figure(4);
plot(z_inv);
title('Inverse FFT with zero padding');
% Inverse FFT with centered spectrum
z_inv_centered=ifft(z_centered);
figure(5);
plot(z_inv_centered);
title('Inverse FFT centered with zero padding');
I do not understand the result on Figure 5 (inverse transform of a shifted spectrum with fftshift)
here is the first spectrum obtained (not shifted) (Figure (3)):
here is the first shifted spectrum with fftshift (Figure (2)):
and the inverse FT of the shifted spectrum above (Figure (5)):
I do not understand the latter figure. If I take the theory, the fact of shifting the spectrum with fftshift leads to the obtaining of two Dirac centered around f_sampling / 2, more precisely on f_sampling / 2-f_signal and f_sampling / 2 + f_signal.
So I have the sum of these two Dirac and I do Inverse FFT of this sum: so I should get for Inverse FFT 2 cosine with frequencies very closed: it seems like I get on the figure (5 ) the product of two cosine signals but I do not see where is my misinterpretation ...
If someone could explain this result?
Thank you in advance
Because the spectrum of a real signal are symmetric about the origin, we prefer to see the spectrum like this, i.e., the zero frequency in the center. However, when computing the spectrum by FFT, what in the center are is the high frequency, thus, fftshift() is used to shift the zero spectrum to the center.
Since the fftshift() is used for visual matter, you can not perform ifft() on the shifted spectrum directly. On the other hand, the shifted spectrum is the modulated version of the original signal, and you obtain the modulated signal in Fig.5.

Finding the phase from FFT on MATLAB

I know the fundamental frequency of my signal and therefore I also know the other frequencies for the harmonics, I have used the FFT command to compute the first 5 harmonics (for which I know their frequencies). Is it possible for me to find the phase with this available information?
Please note I cant be sure my signal is only one period and therefore need to calculate the phase via the known frequency values.
Code seems to be working:
L = length(te(1,:)); % Length of signal
x = te(1,:);
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Y = fft(x,NFFT)/L;
f = linspace(1,5,5);
Y(1) = []; % First Value is a sum of all harmonics
figure(1);
bar(f,2*abs(Y(1:5)), 'red')
title('Transmission Error Harmonics')
xlabel('Harmonic')
ylabel('|Y(f)|')
figure(2);
bar(f,(angle(Y(1:5))))
title('Transmission Error Phase')
xlabel('Harminic')
ylabel('Angle (radians)')
Note that if your fundamental frequency is not exactly integer periodic in the fft length, then the resulting phase (atan2(xi,xr)) will be flipping signs between adjacent bins due to the discontinuity between the fft ends (or due to the rectangular window convolution), making phase interpolation interesting. So you may want to re-reference the FFT phase estimation to the center of the data window by doing an fftshift (pre, by shift/rotating elements, or post, by flipping signs in the fft result), making phase interpolation look more reasonable.
In general your Fourier transformed is complex. So if you want to know the phase of a certain frequency you calculate it with tan(ImaginaryPart(Sample)/RealPart(Sample)). This can be done by using angle().
In your case you
1- calculate fft()
2- calculate angle() for all samples of the FFT or for the samples you are interested in (i.e. the sample at your fundamental frequency/harmonic)
EDIT: an example would be
t = [0 0 0 1 0 0 0];
f = fft(t);
phase = angle(f);
phase = angle(f(3)); % If you are interested in the phase of only one frequency
EDIT2: You should not mix up a real valued spectrum [which is basically abs(fft())] with a complex fourier transformed [which is only fft()]. But as you wrote that you calculated the fft yourself I guess you have the 'original' FFT with the complex numbers.

Frequency response using FFT in MATLAB

Here is the scenario: using a spectrum analyzer i have the input values and the output values. the number of samples is 32000 and the sampling rate is 2000 samples/sec, and the input is a sine wave of 50 hz, the input is current and the output is pressure in psi.
How do i calculate the frequency response from this data using MATLAB,
using the FFT function in MATLAB.
i was able to generate a sine wave, that gives out the the magnitude and phase angles, here is the code that i used:
%FFT Analysis to calculate the frequency response for the raw data
%The FFT allows you to efficiently estimate component frequencies in data from a discrete set of values sampled at a fixed rate
% Sampling frequency(Hz)
Fs = 2000;
% Time vector of 16 second
t = 0:1/Fs:16-1;
% Create a sine wave of 50 Hz.
x = sin(2*pi*t*50);
% Use next highest power of 2 greater than or equal to length(x) to calculate FFT.
nfft = pow2(nextpow2(length(x)))
% Take fft, padding with zeros so that length(fftx) is equal to nfft
fftx = fft(x,nfft);
% Calculate the number of unique points
NumUniquePts = ceil((nfft+1)/2);
% FFT is symmetric, throw away second half
fftx = fftx(1:NumUniquePts);
% Take the magnitude of fft of x and scale the fft so that it is not a function of the length of x
mx = abs(fftx)/length(x);
% Take the square of the magnitude of fft of x.
mx = mx.^2;
% Since we dropped half the FFT, we multiply mx by 2 to keep the same energy.
% The DC component and Nyquist component, if it exists, are unique and should not be multiplied by 2.
if rem(nfft, 2) % odd nfft excludes Nyquist point
mx(2:end) = mx(2:end)*2;
else
mx(2:end -1) = mx(2:end -1)*2;
end
% This is an evenly spaced frequency vector with NumUniquePts points.
f = (0:NumUniquePts-1)*Fs/nfft;
% Generate the plot, title and labels.
subplot(211),plot(f,mx);
title('Power Spectrum of a 50Hz Sine Wave');
xlabel('Frequency (Hz)');
ylabel('Power');
% returns the phase angles, in radians, for each element of complex array fftx
phase = unwrap(angle(fftx));
PHA = phase*180/pi;
subplot(212),plot(f,PHA),title('frequency response');
xlabel('Frequency (Hz)')
ylabel('Phase (Degrees)')
grid on
i took the frequency response from the phase plot at 90 degree phase angle, is this the right way to calculate the frequency response?
how do i compare this response to the values that is obtained from the analyzer? this is a cross check to see if the analyzer logic makes sense or not.
Looks OK at first glance, but a couple of things you're missing:
you should apply a window function to the time domain data before the FFT, see e.g. http://en.wikipedia.org/wiki/Window_function for windowing in general and http://en.wikipedia.org/wiki/Hann_window for the most commonly used window function (Hann aka Hanning).
you probably want to plot log magnitude in dB rather than just raw magnitude
You should consider looking at the cpsd() function for calculating the Frequency response. The scaling and normalisation for various window functions is handled for you.
the Frequency reponse would then be
G = cpsd (output,input) / cpsd (input,input)
then take the angle() to obtain the phase difference between the input and the output.
Your code snippet does not mention what the input and output data sets are.