I'm trying to understand how to perform an integration or differentiation of an FFT using MATLAB. However, I think I'm doing something wrong somewhere and would like to know what I'm missing...
Here's an example of an FFT integration that, to the best of my knowledge, should work but doesn't.
clc; clear all; close all;
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sampling period
L = 1500; % Length of signal
t = (0:L-1)*T; % Time vector
f = Fs*(0:(L/2))/L;
omega = 2*pi.*f;
S is the time signal we are going to operate the FFT on, and dS is its derivative. We're going to apply an FFT to dS, and try to integrate that transform to get the same result as S.
S = 0.7*sin(2*pi*50*t) + sin(2*pi*120*t);
dS = 70*pi*cos(2*pi*50*t) + 140*pi*cos(2*pi*120*t);
P2 = fft(S);
Y = P2(1:L/2+1);
c = fft(dS);
dm = c(1:L/2+1);
From what I found online, to integrate an FFT, you need to multiply each FFT value by the corresponding omega*1i. I'm assuming each point on the FFT result correspond to the values of my frequency vector f.
for z = 1:length(f)
dm(z) = dm(z)./(1i*omega(z));
end
figure
semilogy(f,abs(Y),'b'); hold on
semilogy(f,abs(dm),'r');
We can see on the plot that both curves don't match: the FFT of the initial time signal S is different from the integral of the FFT of the differentiated time signal dS.
The main difference between your two plots is in the noise. Because you use a logarithmic y axis, the noise gets blown up and looks important. Pay attention to the magnitudes when comparing. Anything about 1015 times smaller than the peak value should be ignored. This is the precision of the floating-point numbers used.
The relevant part of these frequency spectra is the two peaks. And the difference there between the sine and cosine is the phase. But you are plotting the magnitude, so the function and its derivative will look the same. Plot the phase also! (but only where the magnitude is above the noise level).
Related
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
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.
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.
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)
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.