Frequency spectrum of signal in Matlab - matlab

Here is the code I use to plot a function in frequency domain in Matlab:
dt = 1/10000; % sampling rate
et = 0.1; % end of the interval
t = 0:dt:et; % sampling range
y = 2+sin(2.*pi.*50.*t)+18.*sin(2.*pi.*90.*t)+6.*sin(2.*pi.*180.*t); % sample the signal
subplot(2,1,1); % first of two plots
plot(t,y); grid on % plot with grid
xlabel('Time (s)'); % time expressed in seconds
ylabel('Amplitude'); % amplitude as function of time
Y = fft(y); % compute Fourier transform
n = size(y,2)/2; % 2nd half are complex conjugates
amp_spec = abs(Y)/n; % absolute value and normalize
subplot(2,1,2); % second of two plots
freq = (0:100)/(2*n*dt); % abscissa viewing window
stem(freq,amp_spec(1:101)); grid on % plot amplitude spectrum
xlabel('Frequency (Hz)'); % 1 Herz = number of cycles/second
ylabel('Amplitude'); % amplitude as function of frequency
The problem is, when I zoom in my graph I don't see peaks exactly on 50Hz, 90Hz and 180Hz.
What did I do wrong in my code?

The problem is that in order to get perfect spectra (peaks on 50,90,180 and 0 otherwise), your interval should be a multiplier of all the frequencies.
Explanation: consider y=sin(2.*pi.*t). Use your code to plot it with:
1) et = 1-dt;
2) et = 1;
In the first case, if you zoom in, you will see that peak is perfectly on 1 Hz. In the second case it is not (also very close).
Why? Because you are working with the finite number of points, and, consequently, finite number of frequencies. If 1 Hz is among this set of frequencies (1st case), you will get perfect peak at 1 Hz at zeros at all others frequencies.
In case 2 there is no 1 Hz frequency in your set, so you will get peak on the nearest frequencies (and also it will have finite width).
Ultimately, in your original code, there are no 50, 90, 180 Hz frequencies in your full set of frequencies.

Related

Audio spectrum, pitch shift and generic audio elaboration in MATLAB

I'm writing a MATLAB program which takes the fundamental (example, la4 or A4 at 440Hz), and, after having asked to the user the frequency which frequency he/she wants, the program will produce the transposed sound. If, for example the user wants a 880Hz frequency from the original file which is 440Hz, it will double every frequency (harmonics included).
I have tried to use MIRPitch, which is not implemented here, but the function wasn't working anyway after having installed all the toolboxes.
How can I take the fundamental? How can I transpose it in other ways?
[y,Fs]=audioread("Test.wav");
[x,Fs]=audioread("LookingForHappiness.mp3");
D=0.8;
%D=(1/Fs)*length(x);
% Digital format ----------------------------------------------------------
Fs=44100; % Sampling rate (Hz)
Ts=1/Fs; % Sampling Period (s)
% Start DFT -------------------------------------------------------------
W=D; % Set the window analysis to pattern duration
N=W/Ts; % Samples in a window frame
F0=1/W; % Fourier fundamental frequency
K=Fs*W; % Total computable frequencies
for k=0:K-1 % k is the frequency index (f=K*F0)
for(n=0:N-1)
s(n+1)=sin(2*pi*k*F0*n*Ts); % n is the time index (t=n*Ts)
c(n+1)=cos(2*pi*k*F0*n*Ts); % n is the time index (t=n*Ts)
end
Xi(k+1)=0;
Xr(k+1)=0;
for (n=0:N-1)
Xi(k+1)=Xi(k+1)+x(n+1)*s(n+1);
Xr(k+1)=Xr(k+1)+x(n+1)*c(n+1);
end
Xi(k+1)=Xi(k+1)/N; % Scale by 1/N each frequency bin
Xr(k+1)=Xr(k+1)/N; % Scale by 1/N each frequency bin
end
Xi(1)=Xi(1)/2; % Frequency 0 amplitude is scaled by 1/N
Xr(1)=Xr(1)/2; % Frequency 0 amplitude is scaled by 1/N
% Show results ------------------------------------------------------------
Xa=2*sqrt(Xi.^2+Xr.^2); % Computes amplitude spectrum
Fscale=0:F0:(Fs/2);
subplot(2,1,1);
plot(Fscale,Xa(1:K/2+1)); % Plot the amplitude spectrum
xlabel ('frequency (Hz) ')
subplot(2,1,2);
plot(x(1:2)); % Plot the signal %era 1:100
xlabel ('time (s) ')
sound("L4A.mp3");

Applying bandpass in the Fourier for my signal in matlab

I'm trying to apply a bandpass around freq 0 without luck. I'd be happy to receive some help please
x=scan11(1,:)*1e-3/3e8; y=scan11(2,:);
plot(x,y) % my function
[XX,ff]=trans_fourier(y,mean(diff(x)));
plot(ff,abs(XX)) % gives the Fourier transform
I want to choose the freq around 0. let's suppose -1e13 till 1e13 and than to make ifft and to plot the signal after this filer.
How should I start doing this? the command
YY=bandpass(y,[-1e13 1e13],1/mean(diff(x)))
didn't help here unfortunately.
Since, i can't upload here files, here is also my question on matlab forum with all the files
matlab link
I am not sure what the contents of the trans_fourier function exactly are, but in 'plain matlab functions', you could attempt something along the lines of the following.
Nt = 1024; % Number of samples
Fs = 10; % Sampling frequency (samples / second)
t = (0:Nt-1)/Fs; % Time array
x = sin(t/10); % Low-frequency signal
x = x + 0.25*randn(1,Nt); % add some noise
X = fftshift(fft(x)); % FFT of signal with 0 Hz centered
fr = (-Nt/2 : Nt/2-1)/(Nt/Fs); % Frequency axis
% Filter: squared cosine (edit as desired)
fsl = 10; % Length of filter slope, in samples
filt = zeros(size(X));
filt(Nt/2+1+(-fsl:fsl)) = cos( linspace(-pi/2,pi/2,2*fsl+1) ).^2;
x_filt = real(ifft(ifftshift( filt.*X ))); % Filtered x
figure();
subplot(2,2,1); plot(t,x); ax=axis; title('original signal');
subplot(2,2,4); plot(t,x_filt); axis(ax); title('Low-pass filtered signal');
subplot(2,2,2); plot(fr,abs(X)); ax=axis; title('original amplitude spectrum');
subplot(2,2,3); plot(fr,abs(X).*filt); axis(ax); title('Filtered amplitude spectrum');
I am not sure what exactly you meant when you said
let's suppose -1e13 till 1e13
, but keep in mind that extracting a single fourier component (essentially setting all values of the spectrum to zero, except the one you are interested in) acts as a brick-wall filter, and you will get considerable artefacts if you take the inverse transform. Refer to this topic or this page if you're interested.

Do I need to call fftshift before calling fft or ifft?

In the book "Computational Fourier Optics, A Matlab Tutorial" by David Voelz, it is written that a call to fftshift is needed before a call to fft or ifft, but in the MATLAB documentation of fftshift it's only written that this command
rearranges the outputs of fft, fft2, and fftn by moving the zero-frequency component to the center of the array.
There is no mention in documentation that this command should be called before the call to fft, and I saw some examples that call fft without a call to fftshift beforehand.
My question is: Whether or not fftshift needed to be called before a call to fft or ifft?
If fftshift doesn't need to be called before a call to fft, and only after a call to fft, then when should we use (if at all) the command ifftshift with relation to a calculation of the fft of a data set?
The matlab fft only computes half of the frequency spectrum (positive frequencies and the zero frequency if your number of samples is odd) in order to save computation time.
Then, the second half of the frequency spectrum (which is the complex conjugate of the first half) is just added at the end of this vector.
So what you get after a fft is the following vector:
0 1 2 3 ... Fs/2 -Fs/2 ... -3 -2 -1
<----------------> <------------------>
positive freq negative freq
where Fs is the frequency sample.
Now, what fftshift does is just shifting the negative frequency bins (2nd part of the frequency spectrum) at the beginning of your vector so that you can display a nice frequency spectrum starting at -Fs/2 and ending at +Fs/2.
The shifted vector becomes:
-Fs/2 ... -3 -2 -1 0 1 2 3 ... Fs/2
<------------------> <---------------->
negative freq positive freq
So, to answer your question, no you don't need to use fftshift after or before a call to fft or ifft. But if you used a fftshift on your vector, you should undo it by applying an ifftshift or fftshift. (I think both calls are equivalent.)
If you read onwards in the documentation on fftshift:
"It is useful for visualizing a Fourier transform with the zero-frequency component in the middle of the spectrum."
The shift is not necessary to perform the fft, but it is handy to visualise the Fourier transform. Whether to use fftshift or not is thus dependent upon whether you want to visualise your transform or not.
Note that ifftshift is different than fftshift because it shifts the negative back to the positive. Assume a simple 3 bin unit impulse in frequency domain before fftshift
[0, exp(-jw1), exp(-(jw1-pi)=exp(-jw1+pi)];
fftshift gives
[exp(-jw1+pi)], 0, exp(-jw1)];
you can see the discontinuity in phase. If you perform ifftshift, negative freq is shifted back to positive:
[0, exp(-jw1), exp(-jw1+pi)];
whereas, fftshift again gives:
[exp(-jw1), exp(-jw1+pi), 0];
one can see the phase monotonicity is not the same, (aka, fftshift-ifftshift case gives [decrease, increase] and fftshift-fftshift case gives [increase, decrease] in phase).
Given the title of the book you are studying, I assume you are working with images. Then the proper way is to call both fftshift and ifftshift before and after you call [i]fft.
Your code should look like
spectrum = fftshift(fft2(ifftshift(myimage))
It is quite the same when applying the inverse Fourier transform
myimage = fftshift(ifft2(ifftshift(spectrum))
The simple answer is call to fftshift not needed before a call to fft. fftshift does not influence the calculation of Fast fourier transform. fftshift rearranges values inside a matrix. For eg:
cameraman = imread('cameraman.tif');
fftshifted_cameraman = fftshift(cameraman);
subplot(1,2,1); imshow(cameraman); title('Cameraman');
subplot(1,2,2); imshow(fftshifted_cameraman); title('FFTShifted Cameraman');
It depends on what you are going to do with the transformed data. If you don't perform an fftshift before transforming, the fft result will have every other value multiplied by -1. This doesn't matter if you plan to view the magnitude or magnitude squared of the result. However, if you plan to compare adjacent spectral values and phase is important, you'll need to apply fftshift before transforming to avoid the alternating sign.
Here is a MATLAB script I use to test basic sound analysis functions of MATLAB including fftshift() in displaying the output of fft().
if ~exist('inputFile', 'var')
inputFile = 'vibe.wav';
end
[inputBuffer, Fs] = audioread(inputFile);
fileSize = length(inputBuffer);
numSamples = 2.^(ceil(log2(fileSize))); % round up to nearest power of 2
x = zeros(numSamples, 1); % zero pad if necessary
x(1:fileSize) = inputBuffer(:,1); % if multi-channel, use left channel only
clear inputBuffer; % free this memory
clear fileSize;
t = linspace(0, (numSamples-1)/Fs, numSamples)';
f = linspace(-Fs/2, Fs/2 - Fs/numSamples, numSamples)';
X = fft(x);
plot(t, x);
xlabel('time (seconds)');
ylabel('amplitude');
title(['time-domain plot of ' inputFile]);
sound(x, Fs); % play the sound
pause;
% display both positive and negative frequency spectrum
plot(f, real(fftshift(X)));
xlabel('frequency (Hz)');
ylabel('real part');
title(['real part frequency-domain plot of ' inputFile]);
pause;
plot(f, imag(fftshift(X)));
xlabel('frequency (Hz)');
ylabel('imag part');
title(['imag part frequency-domain plot of ' inputFile]);
pause;
plot(f, abs(fftshift(X))); % linear amplitude by linear freq plot
xlabel('frequency (Hz)');
ylabel('amplitude');
title(['abs frequency-domain plot of ' inputFile]);
pause;
plot(f, 20*log10(abs(fftshift(X))+1.0e-10)); % dB by linear freq plot
xlabel('frequency (Hz)');
ylabel('amplitude (dB)');
title(['dB frequency-domain plot of ' inputFile]);
pause;
% display only positive frequency spectrum for log frequency scale
semilogx(f(numSamples/2+2:numSamples), 20*log10(abs(X(2:numSamples/2)))); % dB by log freq plot
xlabel('frequency (Hz), log scale');
ylabel('amplitude (dB)');
title(['dB vs. log freq, frequency-domain plot of ' inputFile]);
pause;
semilogx(f(numSamples/2+2:numSamples), (180/pi)*angle(X(2:numSamples/2))); % phase by log freq plot
xlabel('frequency (Hz), log scale');
ylabel('phase (degrees)');
title(['phase vs. log freq, frequency-domain plot of ' inputFile]);
pause;
%
% this is an alternate method of unwrapping phase
%
% phase = cumsum([angle(X(1)); angle( X(2:numSamples/2) ./ X(1:numSamples/2-1) ) ]);
% semilogx(f(numSamples/2+2:numSamples), phase(2:numSamples/2)); % unwrapped phase by log freq plot
%
semilogx(f(numSamples/2+2:numSamples), unwrap(angle(X(2:numSamples/2)))); % unwrapped phase by log freq plot
xlabel('frequency (Hz), log scale');
ylabel('unwrapped phase (radians)');
title(['unwrapped phase vs. log freq, frequency-domain plot of ' inputFile]);
If you were windowing segments of audio and passing them to the FFT, then you should use fftshift() on the input to the FFT to define the center of the windowed segment as the t=0 point.
[x_input, Fs] = audioread('vibe.wav'); % load time-domain input
N = 2*floor(length(x_input)/2); % make sure N is even
x = x_input(1:N);
t = linspace(-N/2, N/2-1, N); % values of time in units of samples
omega = linspace(-pi, pi*(1-2/N), N); % values of (normalized) angular frequency
X = fftshift( fft( fftshift( x.*hamming(length(x)) ) ) );
[X_max k_max] = max( abs(X) );
figure(1);
plot(t, x, 'g');
figure(2);
plot(omega, abs(X), 'b');
hold on;
plot(omega(k_max), X_max, 'or');
hold off;

on the use and understanding of pwelch in matlab

I'm using the pwelch method in matlab to compute the power spectra for some wind speed measurements. So, far I have written the following code as an example:
t = 10800; % number of seconds in 3 hours
t = 1:t; % generate time vector
fs = 1; % sampling frequency (seconds)
A = 2; % amplitude
P = 1000; % period (seconds), the time it takes for the signal to repeat itself
f1 = 1/P; % number of cycles per second (i.e. how often the signal repeats itself every second).
y = A*sin(2*pi*f1*t); % signal
fh = figure(1);
set(fh,'color','white','Units', 'Inches', 'Position', [0,0,6,6],...
'PaperUnits', 'Inches', 'PaperSize', [6,6]);
[pxx, f] = pwelch(y,[],[],[],fs);
loglog(f,10*(pxx),'k','linewidth',1.2);
xlabel('log10(cycles per s)');
ylabel('Spectral Density (dB Hz^{-1})');
I cannot include the plot as I do not have enough reputation points
Does this make sense? I'm struggling with the idea of having noise at the right side of the plot. The signal which was decomposed was a sine wave with no noise, where does this noise come from? Does the fact that the values on the yaxis are negative suggest that those frequencies are negligible? Also, what would be the best way to write the units on the y axis if the wind speed is measured in m/s, can this be converted to something more meaningful for environmental scientists?
Your results are fine. dB can be confusing.
A linear plot will get a good view,
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sample time
L = 1000; % Length of signal
t = (0:L-1)*T; % Time vector
y = sin(2 * pi * 50 * t); % 50Hz signal
An fft approach,
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);
subplot(1,2,1);
plot(f,2*abs(Y(1:NFFT/2+1)))
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
pwelch approach,
subplot(1,2,2);
[pxx, freq] = pwelch(y,[],[],[],Fs);
plot(freq,10*(pxx),'k','linewidth',1.2);
xlabel('Frequency (Hz)');
ylabel('Spectral Density (Hz^{-1})');
As you can see they both have peak at 50Hz.
Using loglog for both,
So "noise" is of 1e-6 and exists in fft as well, and can be ignored.
For your second question, I don't think the axis will change it will be frequency again. For Fs you should use the sampling frequency of wind speed, like if you have 10 samples of speed in one second your Fs is 10. Higher frequencies in your graph means more changes in wind speed and lower frequencies represent less changes for the speed.

how can i fourier transform with negative frequency uncut in matlab?

clear all;
Fs=100; %sampling rate
t=-10:(1/Fs):10;
for i=1:20*Fs+1
if -10<t(i) && t(i)<-9
x(i)= -1;
elseif -9<t(i) && t(i)<-8
x(i)=1;
elseif i>2*Fs+1
x(i)=x(i-(2*Fs));
shown above is the code for rectangular function with its domain [-10 10] and period of 2
and here is my positiveFFT function
function [X,freq]=positiveFFT(x,Fs)
N=length(x); %get the number of points
k=0:N-1; %create a vector from 0 to N-1
T=N/Fs; %get the frequency interval
freq=k/T; %create the frequency range
X=fft(x)/N*2; % normalize the data
%only want the first half of the FFT, since it is redundant
cutOff = ceil(N/2);
%take only the first half of the spectrum
X = X(1:cutOff);
freq = freq(1:cutOff);`
by doing this, i made a magnitude spectrum of this rectangular wave, but only when the frequency is positive.
How can i plot a whole magnitude spectrum that includes negative frequencies??
If I understand you correctly, you want to obtain a vector of frequencies form -Fs/2 to Fs/2 and the corresponding magnitude of the spectrum. If so, you should use fftshift, for example:
N=length(x); %get the number of points
k=0:N-1; %create a vector from 0 to N-1
T=N/Fs; %get the frequency interval
freq=fftshift(k/T); %create the frequency range
X=fftshift(fft(x))/N*2; % normalize the data