I am newbie on matlab sorry if the question is so silly. I search about it but I could not understand the issue clearly.
I want to work with interval int=(-20:20) which has 41 element on sin wave.
when I plot sin(int) it is ploting well but when I try to plot sin(50*int) evenif there must be a lot of change of y value than sin(int) there is not. When I change int=(-100:100) has 201 element, still same wrong plotting. I only take real plot when I change int=(-10:0.1:10) has again 201 element
What is the reason behind?
What you're describing is a signal processing problem called aliasing.
Basically, if you don't sample a sine wave often enough, the discretized sine wave can appear to have a lower frequency than the actual continuous wave did:
To fix this problem you must sample at least twice as often as the frequency of the signal. (See the sampling theorem.)
sin(x) has a frequency of 1 rad/s so you must sample at least as often as 2 rad/s = 0.318 Hz, or about 1 sample for every 3 units.
int=(-20:20) satisfies this requirement with a sampling rate of 1 Hz = 6.28 rad/s > 2 rad/s.
50*int, or -1000:50:1000 does not, as it has a sampling rate of 1/50 Hz = 0.1257 rad/s < 2 rads/s.
You are looking at something called "aliasing". sin is a periodic function with a period of 2*pi (because it's in radian, not in degrees). In some of your plots your "x-values" (which you don't really plot, which is not so good) are further apart than half a period.
Take a look at the following plots:
figure;
hold all;
plot(int2, sin(int2), 'o-');
plot(int1, sin(int1), 'o-');
figure;
hold all;
plot(50*int2, sin(50*int2), 'o-');
plot(50*int1, sin(50*int1), 'o-');
You'll see that in both figures, the points of int2 coincide with points of int1. In the second plot, however, linear interpolation between the few points of int1 paints a sine-wave that is not really there.
Related
I'm trying to plot a simple signal in fourier domain using Matlab. It's not plotting the correct signal. Here is my code:
clc;
clear all;
close all;
x=1:0.001:10;
f1=sin(2*pi*10*x);
f2=sin(2*pi*15*x);
f3=sin(2*pi*30*x);
f=f1+f2+f3;
plot(2*pi*x,fft(f1));
figure
plot(x,fft(f1));
I've expected a peak at 10 since the frequency is 10. But it is giving a peak at some other point
Here are the two plot images:
This is the image for plot(x,fft(f1))
This is the image for plot(2*pi*x,fft(f1))
It is not showing the peak at 10.I even tried using abs(fft(f1)). No luck :/
Isn't it the correct way to plot signal in fourier domain?
The fft function assumes unit time step. In order to correct for non unit time step you need to define the frequency component based on the nyquist rate. The following code plots the magnitude of the fft with the correct frequency axis.
clc;
clear all;
close all;
x=1:0.001:10;
% ^ this is your sampling time step
f1=sin(2*pi*10*x);
f2=sin(2*pi*15*x);
f3=sin(2*pi*30*x);
% bounds of fourier transform based on sampling rate
Fs = 1/0.001;
ff = linspace(-Fs/2,Fs/2,numel(x));
F1 = fftshift(fft(f1)/numel(x));
F2 = fftshift(fft(f2)/numel(x));
F3 = fftshift(fft(f3)/numel(x));
figure();
plot(ff,abs(F1),'-r'); hold on;
plot(ff,abs(F2),'-b');
plot(ff,abs(F3),'-k');
Edit: To answer OPs question in the comment.
Speaking in normalized frequency units (assuming sampling rate of 1). The fft function returns the frequency response from 0 to 2*pi radians, but due to some signal processing properties and the way that discrete signals are interpreted when performing an FFT, the signal is actually periodic so the pi to 2*pi section is identical to the -pi to 0 section. To display the plot with the DC component (0 frequency) in the center we use fftshift which does a circular shift equal to 1/2 the length of the signal on the data returned by fft. Before you take the ifft make sure you use ifftshift to put it back in the right place.
Edit2: The normalization term (/numel(x)) is necessary to estimate the continuous time fourier transform using the discrete fourier transform. I don't remember the precise mathematical reason off the top of my head but the examples in the MATLAB documentation also imply the necessity of this normalization.
Edit 3: The original link that I had is down. I may come back to add a more detailed answer but in the mean time I definitely recommend that anyone interested in understanding the relationship between the fundamentals of the FS, FT, DTFT, and DFT watch Professor Oppenheim's hilariously old, but amazingly informative and straightforward lectures on MIT OpenCourseWare.
I'm working on Matlab, I want to perform FFT on a wav file I previously recorded on Matlab as well.
fs = 44100; % Hz
t = 0:1/fs:1; % seconds
f = 600; % Hz
y = sin(2.*pi.*f.*t);
audiowrite('600freq.wav',y,fs)
This is the way I'm recording in the wav file.
Now to the reading and FFT part:
[y,Fs] = audioread('600freq.wav');
sound(y)
plot(fft(y))
This is the plot of the FFT I get:
Maybe I'm missing something about the FFT, but I expected two vertical lollipops.
Another thing I noticed that's wrong, is when I play the sound after reading it form the file it's longer and the pitch is significantly lower.
My guess is a sampling rate problem, but I really have no idea of what to do about it.
Thanks for any help in advance.
That's because you're not plotting the magnitude. What you are plotting are the coefficients, but these are complex valued. Because of that, the horizontal axis is the real component and the vertical axis is the imaginary component. Also, when you use sound by itself, the default sampling frequency is 8 kHz (8192 Hz to be exact) which explains why your sound is of a lower pitch. You need to use the sampling frequency as a second argument into sound, and that's given to you by the second output of audioread.
So, try placing abs after the fft call and also use Fs into sound:
[y,Fs] = audioread('600freq.wav');
sound(y, Fs);
plot(abs(fft(y)))
Also, the above code doesn't plot the horizontal axis properly. If you want to do that, make sure you fftshift your spectra after you take the Fourier transform, then label your axis properly. If you want to determine what each horizontal value is in terms of frequency, this awesome post by Paul R does the trick: How do I obtain the frequencies of each value in an FFT?
Basically, each horizontal value in your FFT is such that:
F = i * Fs / N
i is the bin number, Fs is the sampling frequency and N is the number of points you're using for the FFT. F is the interpreted frequency of the component you're looking at.
By default, fft assumes that N is the total number of points in your array. For the one-sided FFT, i goes from 0, 1, 2, up to floor((N-1)/2) due to the Nyquist sampling theorem.
Because what you're actually doing in the code you tried to write is displaying both sides of the spectrum, that's why it's nice to centre the spectrum so that the DC frequency is located in the middle and the left side is the negative spectra and the right side is the positive spectra.
We can incorporate that into your code here:
[y,Fs] = audioread('600freq.wav');
sound(y, Fs);
F = fftshift(abs(fft(y)));
f = linspace(-Fs/2, Fs/2, numel(y)+1);
f(end) = [];
plot(f, F);
The horizontal axis now reflects the correct frequency of each component as well as the vertical axis reflecting the magnitude of each component.
By running your audio generation code which generates a sine tone at 600 Hz, and then the above code to plot the spectra, I get this:
Note that I inserted a tool tip right at the positive side of the spectra... and it's about 600 Hz!
I am new to MATLAB and I wrote some code to generate a sine wave. However the graph is not correct. Here is the screenshot of my code and the plot
What is the problem? Please help!
MATLAB plots discrete points and simply draws a straight line to connect neighbouring points together. Your time points are one second (1s) in between, and you are specifying a frequency of 100 Hz. In addition, because your sampling time is a multiple of the period of your sine wave, substituting all of those values of t would thus make the sin result equal to 0, though there is some numerical imprecision. Specifically, if you look at the y-axis, you'll see that the magnitude of your numbers is around 10^{-13}. However even if you escape this, the sampling time is TOO LARGE for the specified frequency of your wave and so this huge gap in between points is visualized as that jagged wave that you see in your graph.
The solution is to simply make your sampling time smaller. Try something small, like 1e-4 for example:
t = 0:1e-4:0.05;
f = 100;
A = 2;
x = A*sin(2*pi*f*t);
plot(t,x);
We get this now:
I'm working on Matlab, I want to perform FFT on a wav file I previously recorded on Matlab as well.
fs = 44100; % Hz
t = 0:1/fs:1; % seconds
f = 600; % Hz
y = sin(2.*pi.*f.*t);
audiowrite('600freq.wav',y,fs)
This is the way I'm recording in the wav file.
Now to the reading and FFT part:
[y,Fs] = audioread('600freq.wav');
sound(y)
plot(fft(y))
This is the plot of the FFT I get:
Maybe I'm missing something about the FFT, but I expected two vertical lollipops.
Another thing I noticed that's wrong, is when I play the sound after reading it form the file it's longer and the pitch is significantly lower.
My guess is a sampling rate problem, but I really have no idea of what to do about it.
Thanks for any help in advance.
That's because you're not plotting the magnitude. What you are plotting are the coefficients, but these are complex valued. Because of that, the horizontal axis is the real component and the vertical axis is the imaginary component. Also, when you use sound by itself, the default sampling frequency is 8 kHz (8192 Hz to be exact) which explains why your sound is of a lower pitch. You need to use the sampling frequency as a second argument into sound, and that's given to you by the second output of audioread.
So, try placing abs after the fft call and also use Fs into sound:
[y,Fs] = audioread('600freq.wav');
sound(y, Fs);
plot(abs(fft(y)))
Also, the above code doesn't plot the horizontal axis properly. If you want to do that, make sure you fftshift your spectra after you take the Fourier transform, then label your axis properly. If you want to determine what each horizontal value is in terms of frequency, this awesome post by Paul R does the trick: How do I obtain the frequencies of each value in an FFT?
Basically, each horizontal value in your FFT is such that:
F = i * Fs / N
i is the bin number, Fs is the sampling frequency and N is the number of points you're using for the FFT. F is the interpreted frequency of the component you're looking at.
By default, fft assumes that N is the total number of points in your array. For the one-sided FFT, i goes from 0, 1, 2, up to floor((N-1)/2) due to the Nyquist sampling theorem.
Because what you're actually doing in the code you tried to write is displaying both sides of the spectrum, that's why it's nice to centre the spectrum so that the DC frequency is located in the middle and the left side is the negative spectra and the right side is the positive spectra.
We can incorporate that into your code here:
[y,Fs] = audioread('600freq.wav');
sound(y, Fs);
F = fftshift(abs(fft(y)));
f = linspace(-Fs/2, Fs/2, numel(y)+1);
f(end) = [];
plot(f, F);
The horizontal axis now reflects the correct frequency of each component as well as the vertical axis reflecting the magnitude of each component.
By running your audio generation code which generates a sine tone at 600 Hz, and then the above code to plot the spectra, I get this:
Note that I inserted a tool tip right at the positive side of the spectra... and it's about 600 Hz!
Today I have stumbled upon a strange outcome in matlab. Lets say I have a sine wave such that
f = 1;
Fs = 2*f;
t = linspace(0,1,Fs);
x = sin(2*pi*f*t);
plot(x)
and the outcome is in the figure.
when I set,
f = 100
outcome is in the figure below,
What is the exact reason of this? It is the Nyquist sampling theorem, thus it should have generated the sine properly. Of course when I take Fs >> f I get better results and a very good sine shape. My explenation to myself is that Matlab was having hardtime with floating numbers but I am not so sure if this is true at all. Anyone have any suggestions?
In the first case you only generate 2 samples (the third input of linspace is number of samples), so it's hard to see anything.
In the second case you generate 200 samples from time 0 to 1 (including those two values). So the sampling period is 1/199, and the sampling frequency is 199, which is slightly below the Nyquist rate. So there is aliasing: you see the original signal of frequency 100 plus its alias at frequency 99.
In other words: the following code reproduces your second figure:
t = linspace(0,1,200);
x = .5*sin(2*pi*99*t) -.5*sin(2*pi*100*t);
plot(x)
The .5 and -.5 above stem from the fact that a sine wave can be decomposed as the sum of two spectral deltas at positive and negative frequencies, and the coefficients of those deltas have opposite signs.
The sum of those two sinusoids is equivalent to amplitude modulation, namely a sine of frequency 99.5 modulated by a sine of frequency 1/2. Since time spans from 0 to 1, the modulator signal (whose frequency is 1/2) only completes half a period. That's what you see in your second figure.
To avoid aliasing you need to increase sample rate above the Nyquist rate. Then, to recover the original signal from its samples you can use an ideal low pass filter with cutoff frequency Fs/2. In your case, however, since you are sampling below the Nyquist rate, you would not recover the signal at frequency 100, but rather its alias at frequency 99.
Had you sampled above the Nyquist rate, for example Fs = 201, the orignal signal could ideally be recovered from the samples.† But that would require an almost ideal low pass filter, with a very sharp transition between passband and stopband. Namely, the alias would now be at frequency 101 and should be rejected, whereas the desired signal would be at frequency 100 and should be passed.
To relax the filter requirements you need can sample well above the Nyquist rate. That way the aliases are further appart from the signal and the filter has an easier job separating signal from aliases.
† That doesn't mean the graph looks like your original signal (see SergV's answer); it only means that after ideal lowpass filtering it will.
Your problem is not related to the Nyquist theorem and aliasing. It is simple problem of graphic representation. You can change your code that frequency of sine will be lower Nyquist limit, but graph will be as strange as before:
t = linspace(0,1,Fs+2);
plot(sin(2*pi*f*t));
Result:
To explain problem I modify your code:
Fs=100;
f=12; %f << Fs
t=0:1/Fs:0.5; % step =1/Fs
t1=0:1/(10*Fs):0.5; % step=1/(10*Fs) for precise graphic representation
subplot (2, 1, 1);
plot(t,sin(2*pi*f*t),"-b",t,sin(2*pi*f*t),"*r");
subplot (2, 1, 2);
plot(t1,sin(2*pi*f*t1),"g",t,sin(2*pi*f*t),"r*");
See result:
Red star - values of sin(2*pi*f) with sampling rate of Fs.
Blue line - lines which connect red stars. It is usual data representation of function plot() - line interpolation between data points
Green curve - sin(2*pi*f)
Your eyes and brain can easily understand that these graphs represent the sine
Change frequency to more high:
f=48; % 2*f < Fs !!!
See on blue lines and red stars. Your eyes and brain do not understand now that these graphs represent the same sine. But your "red stars" are actually valid value of sine. See on bottom graph.
Finally, there is the same graphics for sine with frequency f=50 (2*f = Fs):
P.S.
Nyquist-Shannon sampling theorem states for your case that if:
f < 2*Fs
You have infinite number of samples (red stars on our plots)
then you can reproduce values of function in any time (green curve on our plots). You must use sinc interpolation to do it.
copied from Matlab Help:
linspace
Generate linearly spaced vectors
Syntax
y = linspace(a,b)
y = linspace(a,b,n)
Description
The linspace function generates linearly spaced vectors. It is similar to the colon operator ":", but gives direct control over the number of points.
y = linspace(a,b) generates a row vector y of 100 points linearly spaced between and including a and b.
y = linspace(a,b,n) generates a row vector y of n points linearly spaced between and including a and b. For n < 2, linspace returns b.
Examples
Create a vector of 100 linearly spaced numbers from 1 to 500:
A = linspace(1,500);
Create a vector of 12 linearly spaced numbers from 1 to 36:
A = linspace(1,36,12);
linspace is not apparent for Nyquist interval, so you can use the common form:
t = 0:Ts:1;
or
t = 0:1/Fs:1;
and change the Fs values.
The first Figure is due to the approximation of '0': sin(0) and sin(2*pi). We can notice the range is in 10^(-16) level.
I wrote the function reconstruct_FFT that can recover critically sampled data even for short observation intervals if the input sequence of samples is periodic. It performs lowpass filtering in the frequency domain.