Performing FFT on a time-domain signal using MATLAB - matlab

I have been trying to perform signal processing action (FFT) on a time-domain signal, which I have obtained from another software. However, I keep getting a wrong answer (figure 1), when I use the following code. The sampling frequency of the signal is 1600.
%Healthy engine IAS
DATAH=xlsread('IASH_5seconds_1500rpm_FS1600.xlsx');
xh=DATAH(:,1);
yh=DATAH(:,2);
plot(xh,yh);
hold on;
legend('a','b')
%% performing fft
Fs=1600;
L=length(yh);
NFFT = 2^nextpow2(L);
X = fft(yh,NFFT)/L;
f = Fs*linspace(0,1,NFFT);
plot(f,2*abs(X))
I tried with Amesime software to get its frequency spectrum, and I did right (see figure 2). But, I want to do this with MATLAB.
I don't have any clue where my mistake is. My problem becomes odder for me when I just change the signal and the code works perfectly. So, I thought my signal has a problem. Does my signal have a problem (you can see the signal in figure 3)?
Figure 1:
Figure 2:
Figure 3:

Related

Different plot shape for fft depending on time sample spacing

I am having the following issue. I am trying to analyse the input and output signal of my filter using fft. However, I am not sure if my fft is correct. My input signal is the product of a sawtooth and sine waveforms both with frequencies 6kHz and 32kHz, respectively. Both individual signals have an amplitude of 1 before being multiplied.
Depending on my time values I get different result for my fft plots. If I use values of time spaced out by the period of my sampling frequency, I get a "nice" looking graph with clear peaks as you would expect in a Fourier Transform (see Fig.1). However, if I use values of time spaced out by the period of the signal being sampled, the graph has more frequency components (see Fig. 2). I really don't know which graph is correctly displays my FFT. Also I have the problem that I used an online tutorial to achieve my FFT but I do not understand why the guy did what he did in his code which I do not understand. However, if I plot the absolute values of FFT, I get graphs with similar shapes but the amplitudes jump up to 30 or 40 more (see Fig. 3 and 4). Also for Fig.2 why is there a small wiggle at the start of the filtered signal (time domain) vs time ? Please your help in performing FFT accurately would be of great help. Thanks.
Figures are in Google Drive since website won't allow me to upload more than 1 file:
Fig. 1: https://drive.google.com/file/d/1XHc4jJfMudVOd2E8cluDB4Z8PvfKGsbt/view
Fig. 2: https://drive.google.com/file/d/1pOUhSTSFRwwrKVrwYEa-jYoahqGiYxMA/view
Fig. 3: https://drive.google.com/file/d/10346ttMYZN_Ur_WuwqvbGchYbqmQ6l1F/view
Fig. 4: https://drive.google.com/file/d/17G_FgZznGPNimwgBmGIvqvvcuRvOh80F/view
%Time values using sampling frequency period.
fsampling = 80000;
tsampling = 0:1/fsampling:5000000*Tsampling;
%Time values using sawtooth frequency period.
fsampling = 80000;
fsawtooth = 6000;
Tsawtooth = (1/fsawtooth);
tsawtooth = 0:1/fssampling:20*Tsawtooth;
%Piece of code to use FFT that I don't understand.
L0 = length(product);
NFFT0 = 2^nextpow2(L0);
Y0 = fft(product,NFFT0)/L0;
FreqDom0 = fs/2*linspace(0,1,NFFT0/2+1);
plot(FreqDom0, 2*abs(Y0(1:NFFT0/2+1)));
%Performing FFT using just abs.
IPFFT = abs(fft(product));
plot(t, IPFFT);

how to retrieve original signal from power spectrum

I have calculated power spectrum of signal. the steps are:
FFT of time signal
square of absolute value of FFT/length of signal i.e power spectrum
Now I want to convert it into time domain. What steps should I follow.
The reconstruction of the original signal from the frequency-domain requires both the magnitude and the phase information. So, as you compute the power spectrum and keep only the magnitude, you no longer have all the required information to uniquely reconstruct the original signal.
In other words, we can find examples where different signals have the exact same power spectrum. In that case retrieving which one of those different signals was the original one would thus not be possible.
As a simple illustration, let's say the original signal x is:
x = [0.862209 0.43418 0.216947544 0.14497645];
For sake of argument, let's consider some other signal y, which I've specially crafted for the purpose of this example as:
y = [-0.252234 -0.0835824 -0.826926341 -0.495571572];
As show in the following plots, those two signals might appear completely unrelated:
They do however share the same power spectrum:
f = [0:N-1]/N;
Xf = fft(x,N);
Yf = fft(y,N);
hold off; plot(f, Xf.*conj(Xf)/N, 'b');
hold on; plot(f, Yf.*conj(Yf)/N, 'r:');
xlabel('Normalized frequency');
legend('Px', 'Py')
title('Power spectrum');
As a result, someone who only sees the power spectrum and doesn't know that you started with x, could very well guess that you instead started with y.
That said, the fact that those signals have the same power spectrum could tell you that those signals aren't as unrelated as you might think. In fact those signals also share the same autocorrelation function in the time-domain:
Rx = xcorr(x);
Ry = xcorr(y);
t = [0:length(Rx)-1] - length(x) + 1;
hold off; stem(t, Rx, 'bo');
hold on; stem(t, Ry, 'rx');
legend('Rxx', 'Ryy');
xlabel('lag');
title('Autocorrelation');
This is to be expected since the autocorrelation can be obtained by computing the inverse transform (with ifft) of the power spectrum. This, however, is about as much as you can recover in the time domain. Any signal with this autocorrelation function would be as good a guess as any for the original signal. If you are very motivated you could attempt to solve the set of non-linear equations that are obtained from the definition of the autocorrelation and obtain a list of possibles signals. That would still not be sufficient to tell which one was the original, and as you noticed when comparing my example x and y, there wouldn't be a whole lot to make of it.
The easiest way to see the non-uniqueness of the power (or amplitude) spectrum for describing the time domain signal is that both white noise and the delta function in the time domain have the same power (or amplitude) spectrum - a constant - in the frequency domain.

How to remove the noisy part of a heartbeat?

I have a large pulse oxymetery signal. Some part of that is noisy and will corrupt my data if I use it. Do you have any strategy to automatically remove the noisy part? (Since the data is very long and there are many channels, I can't really do it manually).
Please find the picture attached to have a feeling of the signal.
You can filter it but you need to know the spectral characteristics of the signal so you can extract it or the spectral characteristics of the noise so you can suppress it. Do you have a signal that doesn't have noise or do you know where in the spectrum your signal of interest lies?
This might be the problem identical to removing outliers from time series.
This problem can be solved by fitting the time series with a given model as shown in the this link. For example, try the following simulation codes.
xdata = (0:0.1:2*pi)';
y0 = sin(xdata); % pure data
gnoise = y0.*randn(size(y0)); % noise component
ydata = y0 + gnoise;
f = fittype('a*sin(b*x)');
fit1 = fit(xdata,ydata,f,'StartPoint',[1 1]);
plot(fit1,'r-',xdata,ydata,'k.',outliers,'m*')
xlim([0 2*pi])

Matlab not plotting the exact fourier signal

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.

Creating audio file after doing FFT and getting Amp,Freq,Phase infos

I'm using below codes to fo FFT first and then take the first 10 bigger amplitudes of FFT and corresponding frequency and phase informations.
At the end of te code, i'm trying to rebuild the original signal as much as possible but not using ifft because of the implementation that i'm trying.
Finally, i'm trying to write the .wav but getting "too many output arguments." error always.
Could you pls let me know about your feedbacks?
close all
clear all
clc
[audio,Fs]=audioread('C:\Users\xaol\Desktop\sound.wma');
audioinfo('C:\Users\xaol\Desktop\sound.wma')
player=audioplayer(audio,44100); play(player)
length_audio=length(audio);
%plot(audio);
audio1=audio(2^16:2^17); %taking a part of audio
audio_part=2^17-2^16; %the lenght of taken part
plot(audio1);
title('original partly signal');
player=audioplayer(audio1,44100); play(player)
%% FFT
NFFT = audio_part;
Y = fft(audio1,NFFT)/length(audio1);
fs=length(audio1)/length(audio1);
f = fs/2*linspace(0,1,NFFT/2+1);
[B,IX] = sort(abs(Y(1:NFFT/2+1))); %order the amplitudes
Amplitudes=B; %find all amplitudes
Frequencies=f(IX(1+end-numel(Amplitudes):end)); %frequency of the peaks
Phases=angle(abs(Y));
%% 10 bigger amplitudes and corresponding frequency and phase are being found
A=B((length(IX)-9):(length(IX)));
F=Frequencies((length(IX)-9):(length(IX)));
P=angle(Y(IX((length(IX)-9):length(IX))))*180/pi;
FAP=[F;A;P]
%FAP is 3x10 matrix which includes frequency, amplitude and phase info
%% REBUILD ORIGINAL SIGNAL
ii=length(FAP);
org_audio=0;
t=0:length(audio1);
for i=1:1:ii
org_audio=4*FAP(2,i)*exp(j*2*pi*FAP(1,i)*t+j*(pi/180)*FAP(3,i))+org_audio;
end
figure, plot(t,org_audio)
audio_r1=abs(org_audio);
audio_r(:,1)=(audio_r1)';
audio_r(:,2)=audio_r(:,1);
filename='C:\Users\xaol\Desktop\sound2.wav';
AU=audiowrite(filename,audio_r,44100);
Well, as the error suggests you have "too many output arguments". By looking at your code I believe that the problem is that audiowrite does not return any output arguments (have a look at http://www.mathworks.com/help/matlab/ref/audiowrite.html). You should use
audiowrite(filename,audio_r,44100);
instead.
In any case, you should learn how to use the MATLAB debugger (http://www.mathworks.com/help/matlab/debugging-code.html) in order to identify where your error is.
BTW, the line Phases = angle(abs(Y)) makes on sense as the absolute values do not have phase. Did you mean Phases = angle(Y)?