Learning about Power Spectral Density - matlab

I am sorry to ask a basic question. I am new in signal processing and want to know about the difference between PSD and fft.
I have a audio signal. Which I convert into PSD by using pwelch in matlab. But, when I plot this signal, I want to see the frequency (hz) in x axis and energy (db) in y axis.
But, it doesn't show like this way.
Can anybody explain me the relationship between PSD and FFT and also please let me know, how to plot these two things.
Thanks

To put things simply (for the first pass), the FFT is an algorithm that implements the Discrete Fourier Transform (DFT). The DFT takes N points of the input signal and performs a fourier transform. Power spectrum of the signal is got after you plot the square of the magnitude of the FFT output.
So, the DFT takes N points as input and spits out N points as the output. If you think of the signal as a frame of N samples, the DFT finds statistics using only one frame (N points).
However, the pwelch method is an average statistic over multiple frames. The signal can be a very long signal of length (say L) where its length is many times greater than N. The pwelch method starts off by calculating the DFT of the first N samples, then moves ahead to look at the next N samples and so on until all the "frames" have been looked at. So, what you are left with is the DFTs of every frame of sample size N of the signal of length N. Say, N is 256 points and the L is 44100 points.
Therefore, pwelch takes L points (L > N) and spits out N points for each "frame" of length N of a signal of length L.
There are more details involving windowing and whether you want consecutive frames to have some samples that overlap with each other and so on.
I hope this helps as a first pass explanation.

Related

How do i get all the numbers of fft bins in a defined frequency band?

I use the matlab software. To my question.
I have a audio signal, on which i am applying a STFT. I take a segment
(46 ms, specifially chosen) out of my signal y(audio signal) and use a FFT on it. Then i go to the next segment, until to end of my audio signal.
My WAV-File is 10.8526 seconds long. If I have a sample frequency of
44100Hz, this means my y is 10.8526*fs = 478599.66 which is
shown in the workspace as 478 6000 x2 double.
The length of my fft is 2048. My signal are differentiated under lower frequency band [0 300], mfb [301 5000] and hfb [5001 22050(fs/2)].
The bands are just an example and not the actual matlab code. Basicall what i want (or what I am trying to do), is to get the values of my bins in the defined frequency band and do a arithmetic mean on it.
I chose 46 ms because, I want it as long as the fft length, or nearly as long as the fft. (It is not exact).Afterwards, I want to try plotting it, but that is not important right now. Any help is appreciated.
Fourier transform of a signal in time domain in a vector of size n will return another vector of size n of same signal but in frequency domain.
Frequency domain will be from 0 (dc offset) to your sampling frequency. But you will only be able to use half of that. Second half would have same values but mirrored.
You can obtain the center frequency of each useful bin with:
f = Fs*(0:(n/2))/n;

Sampling at exactly Nyquist rate in Matlab

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.

What is NFFT used in fft() function in matlab?

I have a audio signal sample at the rate of 10Khz, I need to find fourier coefficients of my signal. I saw one example in mathwork's website where they are using following code to do the fft decomposition of a signal y:
NFFT = 2^nextpow2(L);
Y = fft(y,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
where L is the length of the signal, I don't really understand why its defining the variable NFFT the way shown in the code above? Can't I just chose any value for NFFT? Also why are we taking Fs/2 in third line of the code above?
NFFT can be any positive value, but FFT computations are typically much more efficient when the number of samples can be factored into small primes. Quoting from Matlab documentation:
The execution time for fft depends on the length of the transform. It is fastest for powers of two. It is almost as fast for lengths that have only small prime factors. It is typically several times slower for lengths that are prime or which have large prime factors.
It is thus common to compute the FFT for the power of 2 which is greater or equal to the number of samples of the signal y. This is what NFFT = 2^nextpow2(L) does (in the Example from Matlab documentation y is constructed to have a length L).
When NFFT > L the signal is zero padded to the NFFT length.
As far as fs/2 goes, it is simply because the frequency spectrum of a real-valued signal has Hermitian symmetry (which means that the values spectrum above fs/2 can be obtained from the complex-conjugate of the values below fs/2), and as such is completely specifies from the first NFFT/2+1 values (with the index NFFT/2+1 corresponding to fs/2). So, instead of showing the redundant information above fs/2, the example chose to illustrate only the spectrum up to fs/2.
Output of FFT is complex for real valued input. That means for a signal sampled at Fs Hz, The fourier transform of this signal will have frequency components from -Fs/2 to Fs/2 and is symmetric at zero Hz. (Nyquist criterion states that if you have a signal with maxium frequency component at f Hz, you need to sample it with atleast 2f Hz .
You may wonder what does negative frequency mean here. If you are a mathematician you may care about the negative frequency but if you are an engineer, you may choose to ignore the notion of negative frequency and focus only on frequencies from 0 to Fs/2. (Max freq component for a signal sampled at Fs Hz is Fs/2)
Using FFT to learn more about frequency components present in your signal is cumbsrsome. You can use the function pwelch function in MATLAB to learn more frequencies present in your signal and also the power of these signals. MATLAB will automatically compute the NFFT required and return the frequencies present in your signal along with the power at each frequency. Use this syntax:
[p,f] = pwelch(x,[],[],[],Fs)
Look at the documentation of pwelch for more information.

What's the fastest way to approximate the period of data using Octave?

I have a set of data that is periodic (but not sinusoidal). I have a set of time values in one vector and a set of amplitudes in a second vector. I'd like to quickly approximate the period of the function. Any suggestions?
Specifically, here's my current code. I'd like to approximate the period of the vector x(:,2) against the vector t. Ultimately, I'd like to do this for lots of initial conditions and calculate the period of each and plot the result.
function xdot = f (x,t)
xdot(1) =x(2);
xdot(2) =-sin(x(1));
endfunction
x0=[1;1.75]; #eventually, I'd like to try lots of values for x0(2)
t = linspace (0, 50, 200);
x = lsode ("f", x0, t)
plot(x(:,1),x(:,2));
Thank you!
John
Take a look at the auto correlation function.
From Wikipedia
Autocorrelation is the
cross-correlation of a signal with
itself. Informally, it is the
similarity between observations as a
function of the time separation
between them. It is a mathematical
tool for finding repeating patterns,
such as the presence of a periodic
signal which has been buried under
noise, or identifying the missing
fundamental frequency in a signal
implied by its harmonic frequencies.
It is often used in signal processing
for analyzing functions or series of
values, such as time domain signals.
Paul Bourke has a description of how to calculate the autocorrelation function effectively based on the fast fourier transform (link).
The Discrete Fourier Transform can give you the periodicity. A longer time window gives you more frequency resolution so I changed your t definition to t = linspace(0, 500, 2000).
time domain http://img402.imageshack.us/img402/8775/timedomain.png (here's a link to the plot, it looks better on the hosting site).
You could do:
h = hann(length(x), 'periodic'); %# use a Hann window to reduce leakage
y = fft(x .* [h h]); %# window each time signal and calculate FFT
df = 1/t(end); %# if t is in seconds, df is in Hz
ym = abs(y(1:(length(y)/2), :)); %# we just want amplitude of 0..pi frequency components
semilogy(((1:length(ym))-1)*df, ym);
frequency domain http://img406.imageshack.us/img406/2696/freqdomain.png Plot link.
Looking at the graph, the first peak is at around 0.06 Hz, corresponding to the 16 second period seen in plot(t,x).
This isn't computationally that fast though. The FFT is N*log(N) operations.

Using FFT in MATLAB on multiple matrices of data to find differences within responses

I have 4 matrices of data F1,F2,O1,O2. All are neural signals collected at 1ms for a second. F1 and O1 were collected at the same time as with F2 and O2. I need to find how the data collected differes between the 2 trials and also compare the components of each trial (F1 and O1) to each other to notice and differences in respones. I'm new to MATLAB but I believe I need to use the fft function. I'm just not sure where to start, any help would be greatly appeciated.
Based on your sampling rate (1000 times per second), you will only be able to analyze signals which have frequency of up to 500 hz. Any neural signal components which have higher components will appear as signals of lower components (unless your device has highpass filter etc..)
The command for fft from Matlab Help is:
Y = fft(signal, n)
Signal is either F1 or O1 or F2 or O2 and should be a vector 1000 long. n determines how many samples your FFT have. This is essentially how finely you will split up the frequency values between 0 hz and 1000 hz (your sampling rate). For example, if you choose n =256, your Y will be a 256 long vector with a measure corresponding to the frequencies (0*1000/256 hz, 1*1000/256 hz, ... 255*1000/256 hz).
Y will be a vector of complex values. Often, you want to see the strength or power of the signal. You can use 'abs()' to find the magnitude. myPSD = abs(Y). Next because your signals are real signals, their fft's are symmetric about half the sampling rate (500hz). Thus, you should only look at the first half. Here is a code snippet to look at the first half.
Y = fft(signal, n); % choose your n
myPSD = abs(Y);
myHalfPSD = myPSD(1:ceil(n/2))
myFreqValues = [0:1000/n:500-1000/n] % both myHalfPSD and myFreqValues should be n/2 long
plot(myFreqValues, myHalfPSD)
Typically, PSD is displayed on a log scale or even decibal. So you might add a line.
Y = fft(signal, n); % choose your n
myPSD = abs(Y);
myHalfPSD = myPSD(1:ceil(n/2))
myHalfDBPSD = 20*log(myHalfPSD)
myFreqValues = [0:1000/n:500-1000/n] % both myHalfPSD and myFreqValues should be n/2 long
plot(myFreqValues, myHalfDBPSD)
If you want to plot all 4 graphs at once you might want to use something like
subplot(4,1,1), subplot(4,1,2) etc..
Hope that helps,
Chuan
If you're trying to compare the frequency spectrums of two separate acquisitions, then fft is the tool you want to use.
Mathworks has pretty good documentation on how to use the fft function, and you can probably cut and paste your data right into the example code they provide.
If you want to plot the data on the same axes, you can use the hold on command, plot different line colors (Ex: plot(x,y,'r') will plot a red line, 'b' a blue one, etc. - see lineseries properties) and include a legend to label the plots.