Calculating convolution of two function in matlab - matlab

I need to calculate convolution of functions:
f(x)=1 when -1< x <2, 0 otherwise
g(x)=sgn(x)*dirac(abs(x)-1)
I've got this code:
Fs=1;
t=-10:1/Fs:10;
d=dirac(abs(t)-1);
s=sign(t);
x=d.*s;
x2=1*(t>-1 & t<2);
spl=conv(x,x2,'same');
disp(spl);
But what I get is a lot of NaN values.
Where is my mistake? What should I change?

The following is a way of estimating the solution in discrete-time domain. This requires a couple of changes to your code:
Increase the sample rate Fs to preserve more bandwidth. I used 100x below.
Replace Dirac delta function by Kronecker delta to enable discrete-time modeling.
The modified code and the results are as follows:
Fs=100; % use higher sampling rate
t=-10:1/Fs:10;
d=(abs(t)-1)==0; % use kronecker delta function for discrete-time simulation
s=sign(t);
x=d.*s;
x2=1*(t>-1 & t<2);
spl=conv(x,x2,'same');
% plots to visualize the results
figure;
subplot(3,1,1);
plot(t, x2);
ylabel('f(x)');
subplot(3,1,2);
plot(t, x);
ylabel('g(x)');
subplot(3,1,3);
plot(t, spl);
xlabel('Time');
ylabel('convolution');

Try this code:
Fs=1;
t=-10:1/Fs:10;
g=t;
g(g~=1)=0; %g function
s=sign(t);
x=g.*s;
f=t;
f(f>-1 & f<2)=1;
f(f~=1)=0; %f function
x2=f;
spl=conv(x,x2,'same');
disp(spl)

Related

Why convolution obtained from matlab differs from what is obtained theoretically?

Theoretical result for convolution of an exponential function with a sinusoidal function is shown below.
When I plot the function directly using matlab, I get this,
However Matlab conv command yields this,
The two plots look similar but they are not the same, see the scales. The matlab yield is ten times of the theoretical result. Why?
The matlab code is here.
clc;
clear all;
close all;
t = 0:0.1:50;
x1 = exp(-t);
x2 = sin(t);
x = conv(x1,x2);
x_theory = 0.5.*(exp(-t) + sin(t) - cos(t));
figure(1)
subplot(313), plot(t, x(1:length(t))); subplot(311), plot(t, x1(1:length(t))); subplot(312), plot(t, x2(1:length(t)))
figure(2)
subplot(313), plot(t, x_theory); subplot(311), plot(t, x1(1:length(t))); subplot(312), plot(t, x2(1:length(t)))
conv does discrete-time convolution, it does not do the mathematical integral function. Numerically, this basically means multiplying and adding the result of the two signals many times, once for each point, with a small shift of one of the signals.
If you think about this, you will realize that the sampling of the signals will have an effect. i.e. if you have a point every 0.1 values, or 0.001 values, the amount of points you multiply is different, and thus the result is different in value (not in shape).
Therefore, every time you do numerical convolution, you always need to multiply with the sampling rate, to "normalize" the operation.
Just change your code to do
sampling_rate= 0.1;
t = 0:sampling_rate:50;
x = conv(x1,x2)*sampling_rate;

Matlab Fourier Deconvolution

I tried to deconvolute a measured spectrum (Sm) with the pure spectrum (S0) to get the apodization and instrument line shape. Here are the files: Sm and S0
However, I found that the result of my ifft of Sm and S0 are similar. It should give me Gaussian line shape, but I got triangular. What is my mistake and how to solve it?
Thank you in advance.
close all
clear all
clc
sm=load('n2o_gaussian.txt'); %loading spectrum with gaussian ILS
s0=load('n2o_noapodization.txt'); %loading pure spectrum
v=s0(:,1); %wavenumber of pure spectrum
s0_y=s0(:,2); %y component of S0
L=length(v); %length of data
n=2^(nextpow2(L)*2); %number of the next power of two data for FFT
vm=sm(:,1); %wavenumber of measured spectrum
v0=2217.241; %v0 is peak location
vv0=v*ones(1,length(v0))-ones(length(v),1)*v0; %vv0 is wavenumber difference
sm_interpl=interp1( vm, sm, v, 'spline',0); %fit the measured spectrum to match the grid
%pure spectrum
sm_interpl_y=sm_interpl(:,2); %y component of Sm
%y-deconvolution of Sm with S0
s0_y_ift=ifft(s0_y,n,'symmetric'); %inverse FFT of pure spectrum, the symmetric option
enforces imaginary part should be zero in DFT
s0_y_ift=fftshift(s0_y_ift);
sm_interpl_ift=ifft(sm_interpl_y,n,'symmetric'); %inverse FFT of measured spectrum, without
symmetric, half of amplitude will lost
sm_interpl_ift=fftshift(sm_interpl_ift);
apo_y=(sm_interpl_ift)./(s0_y_ift); %get the apodization function from division of sm
and s0
ILS_y=fft(apo_y,n); %get the ILS
ILS_y2=fftshift(ILS_y);
%normalize the area of ILS
area=trapz(f,ILS_y2);
ILS_y2_normalized=ILS_y2./area;
%showing spectra and spline result
figure (1)
plot (sm(:,1),sm(:,2),'o');
hold on;
plot (sm_interpl(:,1),sm_interpl(:,2));
hold on
plot (s0(:,1),s0(:,2));
legend('Measured spectrum','fitted spectrum','pure spectrum')
hold on;
%showing interferogram results
figure (2)
plot(real(sm_interpl_ift))
hold on
plot(real(s0_y_ift))
legend('interferogram of Sm','interferogram of S0')
hold on
%showing apodization function
figure (3)
plot(real(apo_y))
legend('apodization function')
hold on
%showing retrieved ILS
figure (4);
plot(f,real(ILS_y2_normalized));
xlim([-0.0001 0.0001]);
legend('ILS');
hold on;

Matlab FFT - Scaling y-axis

As a data basis, I have measured data the volts were recorded.
Matlab will now be used to perform an FFT.
I have the following questions:
- What unit do I have on the ordinate axis after the FFT? Also volts?
- How is scaled correctly? By hiding the negative frequencies (Nyquist), I would actually have to double the amplitude, right?
- Do I have to multiply all values of the FFT again with 20 * log10 (FFT) to represent the ordinate in db?
Thank you so much for your support!
Frank
Matlab example:
load('TimeDomain.mat')%loading of the time domain signal
L=2500; %length of the signal
Fs=500000;%sampling frequency
N=2^nextpow2(L);%scale factor
t=(0:L-1)*10^-3;%time domain array
f=linspace(0,Fs/2,length(t));%frequency domain array
FFT=abs(fft(Timedomain,N));
figure(1)
plot(f,FFT(1:2500))
Yes, after the FFT, the unit of the ordinate axis will still be volts.
You can scale it by dividing by the number of samples of your signal, then you can indeed multiplying by two (except the first and last elements that represents respectively the frequency 0 and Fs/2) if you want to plot all the spectrum in the positive side.
Then if you want to plot in dB, you can use the function mag2db which applies the formula that you said.
I found some weirdnesses in your code, so I suggest some fixes. My Timedomain signal is a 100 kHz sine at 1 V.
Fs = 500000; % sampling frequency
L = 2500; % length of the signal
t = (0:L-1)/Fs; % time domain array
f = linspace(0, Fs/2, L/2+1); % frequency domain array
Timedomain = cos(2*pi*100000*t); % Input signal
FFT = abs(fft(Timedomain)/L);
FFT(2:L/2) = 2*FFT(2:L/2);
%% Plots
subplot(2,1,1);
plot(f, FFT(1:L/2+1)); xlabel('Frequency (Hz)'); ylabel('Tension (V)');
subplot(2,1,2);
plot(f, mag2db(FFT(1:L/2+1))); xlabel('Frequency (Hz)'); ylabel('Tension (dBV)');
This returns:

Ways to Compute Spectrum Matlab

I have a question while computing the spectrum of a time series in Matlab. I have read the documentations concerning 'fft' function. However I have seen two ways of implementation and both wgive me different results. I would appreciate to have some answer about this difference:
1st Method:
nPoints=length(timeSeries);
Time specifications:
Fs = 1; % samples per second
Fs = 50;
freq = 0:nPoints-1; %Numerators of frequency series
freq = freq.*Fs./nPoints;
% Fourier Transform:
X = fft(timeSeries)/nPoints; % normalize the data
% find find nuquist frequency
cutOff = ceil(nPoints./2);
% take only the first half of the spectrum
X = abs(X(1:cutOff));
% Frequency specifications:
freq = freq(1:cutOff);
%Plot spectrum
semilogy(handles.plotLoadSeries,freq,X);
2nd Method:
NFFT = 2^nextpow2(nPoints); % Next power of 2 from length of y
Y = fft(timeSeries,NFFT)/nPoints;
f = 1/2*linspace(0,1,NFFT/2+1);
% % Plot single-sided amplitude spectrum.
% plot(handles.plotLoadSeries, f,2*abs(Y(1:NFFT/2+1)))
semilogy(handles.plotLoadSeries,f,2*abs(Y(1:NFFT/2+1)));
I thought that it is not necessary to use 'nextpow' function in 'fft' function in Matlab. Finally, which is the good one?
THanks
The short answer: you need windowing for spectrum analysis.
Now for the long answer... In the second approach, you are using an optimised FFT algorithm useful when the length of the input vector is a power of two. Let's assume that your original signal has 401 samples (as in my example below) from an infinitely long signal; nextpow2() will give you NFFT=512 samples. When you feed the shorter, 401-sample signal into the fft() function, it is implicitly zero-padded to match the requested length of 512 (NFFT). But (here comes the tricky part): zero-padding your signal is equivalent to multiplying an infinitely long signal by a rectangular function, an operation that in the frequency domain translates to a convolution with a sinc function. This would be the reason behind the increased noise floor at the bottom of your semilogarithmic plot.
A way to avoid this noise increase is to create manually the 512-sample signal you want to feed into fft(), using a smoother window function instead of the default rectangular one. Windowing means just multiplying your signal by a tapered, symmetric one. There are tons of literature on choosing a good windowing function, but a typically accurate one with low sidelobes (low noise increase) is the Hamming function, implemented in MATLAB as hamming().
Here is a figure illustrating the issue (in the frequency domain and time domain):
...and the code to generate this figure:
clear
% Create signal
fs = 40; % sampling freq.
Ts = 1/fs; % sampling period
t = 0:Ts:10; % time vector
s = sin(2*pi*3*t); % original signal
N = length(s);
% FFT (length not power of 2)
S = abs(fft(s)/N);
freq = fs*(0:N-1)/N;
% FFT (length power of 2)
N2 = 2^nextpow2(N);
S2 = abs(fft(s, N2)/N2);
freq2 = fs*(0:N2-1)/N2;
t2 = (0:N2-1)*Ts; % longer time vector
s2 = [s,zeros(1,N2-N)]; % signal that was implicitly created for this FFT
% FFT (windowing before FFT)
s3 = [s.*hamming(N).',zeros(1,N2-N)];
S3 = abs(fft(s3, N2)/N2);
% Frequency-domain plot
figure(1)
subplot(211)
cla
semilogy(freq,S);
hold on
semilogy(freq2,S2,'r');
semilogy(freq2,S3,'g');
xlabel('Frequency [Hz]')
ylabel('FFT')
grid on
legend( 'FFT[401]', 'FFT[512]', 'FFT[512] with windowing' )
% Time-domain plot
subplot(212)
cla
plot(s)
hold on
plot(s3,'g')
xlabel('Index')
ylabel('Amplitude')
grid on
legend( 'Original samples', 'Windowed samples' )

How to plot frequency response for a transfer function of a band-pass filter in Matlab?

i want write a script to plot a graph for the transfer function [H(f)] for a band pass filter, |H(f)| against frequency and the phase of H(f) (degrees) against frequency, im very new to matlab so the syntax is not 100%, im getting confused because everything is auto formatted in matrix form.
below is my script:
% RCL circuit: band-pass filter
R=55590; L=0.9571; C=48.811*10.^(-9); % values of the Resistor and Capacitor
f=(0:60e3); w=2*pi*f; % frequency (f) range of measurements
H=(R./(sqrt(R^2+(w*L-(1./(w*C))).^2))); % Transfer Function
% Magnitude (absolute value) of the transfer function
plot(f,abs(H),'LineWidth',2); grid on; hold on
xlabel('Frequency [Hz]','FontSize',20); ylabel('|H(f)|','FontSize',20)
figure
plot(f,angle(H)*180/pi,'LineWidth',2); grid on; hold on
xlabel('Frequency [Hz]','FontSize',18);
ylabel('phase of H(f) [degrees]','FontSize',20)
this is the transfer function formula im using
below is another pic of what my experimental results were and an expected graph, i just dont understand why MATLAB isnt ploting what i want?
Are you aware of the bodeplot function?
The transfer function for a simple second order bandpass is:
You just need to insert your values into Matlab's tf function and plot it with bodeplot:
R = 55590;
L = 0.9571;
C = 48.811*10.^(-9);
% tf creates transfer function object
sys = tf( [R*C 0] , [L*C R*C 1]); % [R*C 0] vector of numerator coeffcients
% R*C*s + 0*1
% [L*C R*C 1] vector of denominator coeff.
% L*C*s^2 + R*C*s + 0*1
bodeplot(sys) % plot command to plot frequency response
% of magnitude and phase
and it plots:
Alternatively, if you need more outputs like magnitude and phase as variables, use bode, the plot is equal. But bodeplot offers more additional plot customization options.
Regarding your comment, that you need a linear axis:
you just need to add the following lines before the plot command:
P = bodeoptions; % handle to plot options
P.MagScale = 'linear';
P.MagUnits = 'abs';
bodeplot(sys,P) % plot command with custom options
so it looks as follows:
For adjusting the frequency axis limits, use:
P.XLim = [1 60e3];
or analogue for the magnitude:
P.YLim = [0 1];
I would advise against a linear frequency axis, but if you REALLY want it, you can use:
P.FreqScale = 'linear';
P.FreqUnits = 'Hz'; % optional
If you want to plot your experimental data together with the plot above, follow this example.
Use bode to get equally formatted data from your transfer function, like your experimental data and use semilogx to plot it.
freqVec = logspace(-1, 3, 5000);
[mag, phs] = bode(sys, freqVec * (2*pi));
mag = db(mag(:));
phs = phs(:);
figure;
subplot(211)
semilogx(freqVec, mag); hold on
semilogx(freqVec, experimentalDataMagnitude); hold off
grid on
title('System Bode Plot')
ylabel('Magnitude (dB)')
subplot(212)
semilogx(freqVec, phs); hold on
semilogx(freqVec, experimentalDataPhase); hold off
grid on
ylabel('Phase (deg)')
xlabel('Frequency (Hz)')