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

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;

Related

Confusion on how the frequency axis when plotting the FFT magnitude is created

This code takes FFT of a signal and plots it on a new frequency axis.
f=600;
Fs=6000;
t=0:1/Fs:0.3;
n=0:1:length(t);
x=cos(2*pi*(400/Fs)*n)+2*sin(2*pi*(1100/Fs)*n);
y=fft(x,512);
freqaxis=Fs*(linspace(-0.5,0.5, length(y)));
subplot(211)
plot(freqaxis,fftshift(abs(y)));
I understand why we used fftshift because we wanted to see the signal centered at the 0 Hz (DC) value and it is better for observation.
However I seem to be confused about how the frequency axis is defined. Specifically, why did we especially multiply the range of [-0.5 0.5] with Fs and we obtain the [-3000 3000] range? It could be [-0.25 0.25].
The reason why the range is between [-Fs/2,Fs/2] is because Fs/2 is the Nyquist frequency. This is the largest possible frequency that has the ability of being visualized and what is ultimately present in your frequency decomposition. I also disagree with your comment where the range "could be between [-0.25,0.25]". This is contrary to the definition of the Nyquist frequency.
From signal processing theory, we know that we must sample by at least twice the bandwidth of the signal in order to properly reconstruct the signal. The bandwidth is defined as the largest possible frequency component that can be seen in your signal, which is also called the Nyquist Frequency. In other words:
Fs = 2*BW
The upper limit of where we can visualize the spectrum and ultimately the bandwidth / Nyquist frequency is defined as:
BW = Fs / 2;
Therefore because your sampling frequency is 6000 Hz, this means the Nyquist frequency is 3000 Hz, so the range of visualization is [-3000,3000] Hz which is correct in your magnitude graph.
BTW, your bin centres for each of the frequencies is incorrect. You specified the total number of bins in the FFT to be 512, yet the way you are specifying the bins is with respect to the total length of the signal. I'm surprised why you don't get a syntax error because the output of the fft function should give you 512 points yet your frequency axis variable will be an array that is larger than 512. In any case, that is not correct. The frequency at each bin i is supposed to be:
f = i * Fs / N, for i = 0, 1, 2, ..., N-1
N is the total number of points you have in your FFT, which is 512. You originally had it as length(y) and that is not correct... so this is probably why you have a source of confusion when examining the frequency axis. You can read up about why this is the case by referencing user Paul R's wonderful post here: How do I obtain the frequencies of each value in an FFT?
Note that we only specify bins from 0 up to N - 1. To account for this when you specify the bin centres of each frequency, you usually specify an additional point in your linspace command and remove the last point:
freqaxis=Fs*(linspace(-0.5,0.5, 513); %// Change
freqaxis(end) = []; %// Change
BTW, the way you've declared freqaxis is a bit obfuscated to me. This to me is more readable:
freqaxis = linspace(-Fs/2, Fs/2, 513);
freqaxis(end) = [];
I personally hate using length and I favour numel more.
In any case, when I run the corrected code to specify the bin centres, I now get this plot. Take note that I inserted multiple data cursors where the peaks of the spectrum are, which correspond to the frequencies for each of the cosines that you have declared (400 Hz and 1100 Hz):
You see that there are some slight inaccuracies, primarily due to the number of bins you have specified (i.e. 512). If you increased the total number of bins, you will see that the frequencies at each of the peaks will get more accurate.

Using pwelch to a set of signals: some questions (Matlab)

I would like to use pwelch on a set of signals and I have some questions.
First, let's say that we have 32 (EEG) signals of 30 seconds duration. The sampling frequency is fs=256 samples/sec, and thus each signal has length 7680. I would like to use pwelch in order to estimate the power spectral density (PSD) of those signals.
Question 1:
Based on the pwelch's documentation,
pxx = pwelch(x) returns the power spectral density (PSD) estimate, pxx, of the input signal, x, found using Welch's overlapped segment averaging estimator. When x is a vector, it is treated as a single channel. When x is a matrix, the PSD is computed independently for each column and stored in the corresponding column of pxx.
However, if call pwelch as follows
% ch_signals: 7680x32; one channel signal per each column
[pxx,f] = pwelch(ch_signals);
the resulting pxx is of size 1025x1, not 1025x32 as I would expect, since the documentation states that if x is a matrix the PSD is computed independently for each column and stored in the corresponding column of pxx.
Question 2:
Let's say that I overcome this problem, and I compute the PSD of each signal independently (by applying pwelch to each column of ch_signals), I would like to know what is the best way of doing so. Granted that the signal is a 30-second signal in time with sampling frequency fs=256, how should I call pwelch (with what arguments?) such that the PSD is meaningful?
Question 3: If I need to split each of my 32 signals into windows and apply pwech to each one of those windows, what would be the best approach? Let's say that I would like to split each of my 30-second signals into windows of 3 seconds with an overlap of 2 seconds. How should I call pwelch for each one of those windows?
Here is an example, just like your case,
The results show that the algorithm indicates the signal frequencies just right.
Each column of matrix, y is a sinusoidal to check how it works.
The windows are 3 seconds with 2 seconds of overlapping,
Fs = 256;
T = 1/Fs;
t = (0:30*Fs-1)*T;
y = sin(2 * pi * repmat(linspace(1,100,32)',1,length(t)).*repmat(t,32,1))';
for i = 1 : 32
[pxx(:,i), freq] = pwelch(y(:,i),3*Fs,2*Fs,[],Fs); %#ok
end
plot(freq,pxx);
xlabel('Frequency (Hz)');
ylabel('Spectral Density (Hz^{-1})');

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.

Channel vocoder using FFT - what to do about DC Component and Nyquist frequency?

I am trying to implement a channel vocoder using the iOS Accelerate vDSP FFT algorithms. I am having trouble figuring out how to treat the DC component and Nyquist frequency.
The modulator and carrier signals are both float arrays of length n. On each, I perform a forward FFT and am returned a frequency plot (call it bin[]) of length n/2.
As per the vDSP specifications, bin[1] contains the first frequency above 0Hz, bin[2] the second, etc... bin[0] contains the DC Component in the real part and the Nyquist frequency (which would normally be in bin[n/2]) in the imaginary part. vDSP essentially packs the frequency plot into as little space as possible (the imaginary part for bin[0] and bin[n/2] should always be zero before the packing).
I split the frequency plot for both carrier and modulator into k bands. My goal is to multiply each frequency in carrier.band[x] by the total magnitude of the frequencies in modulator.band[x]. Essentially, increasing the intensity of those frequencies in the carrier that are also present in the modulator.
So if n=8 and k=2, the second band for the modulator would contain contain bin[2] and bin[3]. Simple enough to find the total magnitude, simply sum the magnitudes of each bin (for example mag[2] = sqrt( bin[2].real*bin[2]*real + bin[2].imag*bin[2]*imag )).
That works great for all bands except the first one, because the first band contains the weird bin[0] with the DC component and Nyquist frequency.
How do I handle that first bin when calculating the total magnitude of a band? Do I just assume the magnitude for the first bin is JUST the DC component by itself? Do I discard the Nyquist frequency?
Thank you to anyone who can provide some guidance! I appreciate it.
I suggest you ignore 0 Hz and Nyquist since they contain no useful information in the case of an audio signal.