FFT faulty results for high frequencies? - matlab

I have sampled the 50Hz output current of an inverter with sampling frequency of 50 KHz for 1 minute. I am supposed to divide the time to 200ms packages(0.2s or 10 periods of the main signal)and do the FFT on each package. So it means that I have 10000 samples in each package (if not I zero pad or truncate ,that does not make a big difference). I am also supposed to extract the frequency spectrum up to 9 KHz. Results are ok for low frequencies but I have wrong results (the values are the half of what for high frequency). Could you help me to understand what am I doing wrong?!
I have an idea, maybe some thing like the code below is happening to my FFT. Just change SF to 10000 and look how the results will be changed !
in this code if you change the SF(sampling frequency) from 30000 to 10000,
the results for high frequncies will be distorted and disordered . why ?
SF = 30000; %sampling frequency
% signal
t = 0:1/SF:1-1/SF; % sample points
wave=15*sin(2*pi*1*t)+1*sin(2*pi*123*t)+2*sin(2*pi*203*t)+3*sin(2*pi*223*t)+4*sin(2*pi*331*t)+5*sin(2*pi*2812*t)+6*sin(2*pi*5752*t)+7*sin(2*pi*7993*t);
wavefft = fft(wave);
L=floor(size(wave,2)/2)+1; % removing the mirror side of spectrum
MagSpec = abs(wavefft(1:L))/(SF/2); %% removing the mirror side of the spectrum
and ranging the domain
plot(MagSpec);

What you are observing is aliasing.
As you can see by comparing the results using a sampling rate of 50kHz
and that of using a sampling rate of 10kHz
The sinusoidals signals whose frequency where below half the sampling rate of 10kHz (Nyquist frequency), that is the sinusoidals at 1Hz, 123Hz, 203Hz, 223Hz, 331Hz and 2812Hz are not affected. The ones at 5752Hz and 7993Hz are aliased to 4248Hz and 2007Hz respectively.
You can still perform the FFT on 200ms or 10000 samples, but the sampling rate remains the same at 50kHz. That is you would have:
SF = 50000; %sampling frequency
% signal
t = 0:1/SF:1-1/SF; % sample points
wave=15*sin(2*pi*1*t)+1*sin(2*pi*123*t)+2*sin(2*pi*203*t)+3*sin(2*pi*223*t)+4*sin(2*pi*331*t)+5*sin(2*pi*2812*t)+6*sin(2*pi*5752*t)+7*sin(2*pi*7993*t);
for the signal generation, but you would split the resulting wave signal in chunks for your processing:
for i=1:floor(length(wave)/10000)
wavefft = fft(wave(1+(i-1)*10000:i*10000))
% do somthing with the wavefft result
end

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

FFT: How to find the single sided spectrum when there are less than fs/2 samples

I am writing a piece of code that figures out what frequencies(notes) are being played at any given time of a song (note currently I am testing it grabbing only the first second of the song). To do this I break the first second of the audio file into 8 different chunks. Then I perform an FFT on each chunk and plot it with the following code:
% Taking a second of an audio file and breaking it into n many chunks and
% figuring out what frequencies make up each of those chunks
clear all;
% Read Audio
fs = 44100; % sample frequency (Hz)
full = audioread('song.wav');
% Perform fft and get frequencies
chunks = 8; % How many chunks to break wave into
for i = 1:chunks
beginningChunk = (i-1)*fs/chunks+1
endChunk = i*fs/chunks
x = full(beginningChunk:endChunk);
y = fft(x);
n = length(x); % number of samples in chunk
amp = abs(y)/n; % amplitude of the DFT
%%%amp = amp(1:fs/2/chunks); % note this is my attempt that I think is wrong
f = (0:n-1)*(fs/n); % frequency range
%%%f = f(1:fs/2/chunks); % note this is my attempt that I think is wrong
figure(i);
plot(f,amp)
xlabel('Frequency')
ylabel('amplitude')
end
When I do that I get graphs that look like these:
It looks like I am plotting too many points because the frequencies go up in magnitude at the far right of graphs so I think I am using the double sided spectrum. I think I need to only use the samples from 1:fs/2, the problem is I don't have a big enough matrix to grab that many points. I tried going from 1:fs/2/chunks, but I am unconvinced those are the right values so I commented those out. How can I find the single sided spectrum when there are less than fs/2 samples?
As a side note when I plot all the graphs I notice the frequencies given are almost exactly the same. This is surprising to me because I thought I made the chunks small enough that only the frequency that's happening at the exact time should be grabbed -- and therefore I would be getting the current note being played. If anyone knows how I can single out what note is being played at each time better that information would be greatly appreciated.
For a single-sided FT simply take the first half of the output of the FFT algorithm. The other half (the nagative frequencies) is redundant given that your input is real-valued.
1/8 second is quite long. Note that relevant frequencies are around 160-1600 Hz, if I remeber correctly (music is not my specialty). Those will be in the left-most region of your FT. The highest frequency you compute (after dropping the right half of FFT) is half your sampling frequency, 44.1/2 kHz. The lowest frequency, and the distance between samples, is given by the length of your transform (44.1 kHz / number of samples).

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.

Why doesn't matlab give me an 8KHz sinewave for 16KHz sampling frequency?

I have the following matlab code, and I am trying to get 64 samples of various sinewave frequencies at 16KHz sampling frequency:
close all; clear; clc;
dt=1/16000;
freq = 8000;
t=-dt;
for i=1:64,
t=t+dt;a(i)=sin(2*pi*freq*t);
end
plot(a,'-o'); grid on;
for freq = 1000, the output graph is
The graph seems normal upto 2000, but at 3000, the graph is
We can see that the amplitude changes during every cycle
Again, at 4000 the graph is
Not exactly a sinewave, but the amplitude is as expected during every cycle and if I play it out it sounds like a single frequency tone
But again at 6000 we have
and at 8000 we have
Since the sampling frequency is 16000 I was assuming that I should be able to generate sinewave samples for upto 8000, and I was expecting the graph I got at 4000 to appear at 8000. Instead, even at 3000, the graph starts to look weird
If I change the sampling frequency to 32000 and the sinewave frequency to 16000, I get the same graph that I am getting now at 8000. Why does matlab behave this way?
EDIT:
at freq = 7900
This is just an artifact of aliasing. Notice how the vertical axis for the 8kHz graph only goes up to 1.5E-13? Ideally the graph should be all zeros; what you're seeing is rounding error.
Looking at the expression for computing the samples at 16kHz:
x(n) = sin(2 * pi * freq * n / 16000)
Where x is the signal, n is the integer sample number, and freq is the frequency in hertz. So, when freq is 8kHz, it's equivalent to:
x(n) = sin(2 * pi * 8000 * n / 16000) = sin(pi * n)
Because n is an integer, sin(pi * n) will always be zero. 8kHz is called the Nyquist frequency for a sampling rate of 16kHz for this reason; in general, the Nyquist frequency is always half the sample frequency.
At 3kHz, the signal "looks weird" because some of the peaks are at non-integer multiples of 16kHz, because 16 is not evenly divisible by 3. Same goes for the 6kHz signal.
The reason they still sound like pure sine tones is because of how the amplitude is interpolated between samples. The graph uses simple linear interpolation, which gives the impression of harsh edges at the samples. However, a physical loudspeaker (more precisely, the circuitry which drives it) does not use linear interpolation directly. Instead, a small filter circuit is used to smooth out those harsh edges (aka anti-aliasing) which removes the artificial frequencies above the aforementioned Nyquist frequency.
That is problem of matlab but a nature of sampling.
16KHz sampling makes 16K (16,000) sampled data per second. 8KHz signal has 8K (8000) cycles per second. So two sample data per a cycle.
Two is minimum number of data per cycle. This is know a part of "sampling theorem".
Let try to show two cycles with three points on graph, you may understand that its impossible to show two cycles by three points. In the same way, you can't show 2N cycles by (2N-1) points.
The effect seen for 8 kHz is as all other answers already mention aliasing effects and arises due to that the sine wave for 8 kHz is sin(2*pi*n*8000*1/16000) = sin(n*pi), which is explained in Drew McGovens answer. Luckily the amplitude is not the only parameter that defines the signal. The other parameter that is required to completely define the signal is the phase. This means that when doing for fourier analysis of the signal, it is still possible to find the right frequency. Try:
close all; clear; clc;
dt=1/16000;
freq = 7300;
t=-dt;
for i=1:64,
t=t+dt;a(i)=sin(2*pi*freq*t);
end
plot(a,'-o'); grid on;
figure; plot( linspace(1,16000,1000), abs(fft(a)) );
A side comment: some people might argue against using i as index variable since that can also be used as the imagiary number i. Personally I have nothing against using i since the runtime and overhead only is affected slightly and I always uses 1i. However, just make sure to use 1i consistently for the imaginary unit then.

why FFT results in high frequency range are not correct?

I am doing FFT with matlab.the time period i am doing the fft on it is 1 second and it consist of 50000 equlay spaces samples. I want to test the FFT results. so I have given an input as below (wave) which is a complex of sinosuidal waves (and I have samples it by sampling frequency of 50 KHZ)and I expect to have the frequency magnitude results as I have given in the input. the results are ok for low frequency ranges but for the higher frequency (5752 Hz and 7993 Hz) results are 5.87 and 6.7 respectively (instead of 6 and ). what Is the origin of this big mistake ? how can I improve my results ?!
Here is the code:
t = 0:1/50000:1;
wave = 100*sin(2*pi*50*t)+1*sin (2*pi*123*t)+2*sin (2*pi*203*t)+3*sin(2*pi*223*t)+4*sin(2*pi*331*t)+5*sin(2*pi*2812*t)+6*sin(2*pi*5752*t)+7*sin(2*pi*7993*t);
SPEC = fft(wave);
L = size(SPEC,2);
x= (0:L/2-1);
Half_SPEC = abs(SPEC(1:L/2))/(L/2); %% removing the mirror side and ranging the domain
plot(x,Half_SPEC);
As Oli Charlesworth has pointed out, you are taking the FFT of 50001 points, which means that the frequency spacing is 1/50001.
Typically the FFT will give you the exact magnitude of your sinusoid only if its frequency is an exact multiple of the frequency spacing. Otherwise, the energy will be spread over multiple FFT bins in a process called spectral leakage.
You may confirm this by changing the number of samples such that the frequency of your sinusoids are a multiple of the frequency spacing:
t = 0:1/50000:1-1/50000;
Windowing the input signal can also help control the amount of leakage.