Solving convolutions in Matlab using `conv` or `fft` - matlab

This is follow-up question to my other SO post about performing multiple convolutions like
where the functions are defined in my code below.
I need to rescale the result of the convolution with respect to the number of time steps in the calculation, N.
N = 1000;
t = linspace(-10,10,N);
x = t.*exp(-t.^2);
y = exp(-4*t.^2).*cos(t);
z = (t-2)/((t-2).^2+3^2);
w = exp(-3*t.^2).*exp(2i*t);
% convolution
u = conv(conv(conv(x,y)/N,z)/N,w)/N;
% Fourier transform
L_x=fft(x)/N;
L_y=fft(y)/N;
L_z=fft(z)/N;
L_w=fft(w)/N;
L_u=L_x.*L_y.*L_z.*L_w; %convolution on frequency domain
v=ifft(L_u)*N;
figure(1)
ax1 = subplot(2,1,1);
ax2 = subplot(2,1,2);
plot(ax1,1:length(u),real(u))
title(ax1,'conv')
hold off
plot(ax2,t,real(v))
title(ax2,'fft')
xlabel(ax2,'t')
How do I scale the convolution correctly? (N.B. If I change to N=1e5 timesteps, the y-values decrease).
How do I ensure that the conv output spans the same time region as the fft output? Graph of real part of convolution below:

Related

MATLAB: How to apply ifft correctly to bring a "filtered" signal back to the time doamin?

I am trying to get the output of a Gaussian pulse going through a coax cable. I made a vector that represents a coax cable; I got attenuation and phase delay information online and used Euler's equation to create a complex array.
I FFTed my Gaussian vector and convoluted it with my cable. The issue is, I can't figure out how to properly iFFT the convolution. I read about iFFt in MathWorks and looked at other people's questions. Someone had a similar problem and in the answers, someone suggested to remove n = 2^nextpow2(L) and FFT over length(t) instead. I was able to get more reasonable plot from that and it made sense to why that is the case. I am confused about whether or not I should be using the symmetry option in iFFt. It is making a big difference in my plots. The main reason I added the symmetry it is because I was getting complex numbers in the iFFTed convolution (timeHF). I would truly appreciate some help, thanks!
clc, clear
Fs = 14E12; %1 sample per pico seconds
tlim = 4000E-12;
t = -tlim:1/Fs:tlim; %in pico seconds
ag = 0.5; %peak of guassian
bg = 0; %peak location
wg = 50E-12; %FWHM
x = ag.*exp(-4 .* log(2) .* (t-bg).^2 / (wg).^2); %Gauss. in terms of FWHM
Ly = x;
L = length(t);
%n = 2^nextpow2(L); %test output in time domain with and without as suggested online
fNum = fft(Ly,L);
frange = Fs/L*(0:(L/2)); %half of the spectrum
fNumMag = abs(fNum/L); %divide by n to normalize
% COAX modulation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%phase data
mu = 4*pi*1E-7;
sigma_a = 2.9*1E7;
sigma_b = 5.8*1E6;
a = 0.42E-3;
b = 1.75E-3;
er = 1.508;
vf = 0.66;
c = 3E8;
l = 1;
Lso = sqrt(mu) /(4*pi^3/2) * (1/(sqrt(sigma_a)*a) + 1/(b*sqrt(sigma_b)));
Lo = mu/(2*pi) * log(b/a);
%to = l/(vf*c);
to = 12E-9; %measured
phase = -pi*to*(frange + 1/2 * Lso/Lo * sqrt(frange));
%attenuation Data
k1 = 0.34190;
k2 = 0.00377;
len = 1;
mldb = (k1 .* sqrt(frange) + k2 .* frange) ./ 100 .* len ./1E6;
mldb1 = mldb ./ 0.3048; %original eqaution is in inch
tfMag = 10.^(mldb1./-10);
% combine to make in complex form
tfC = [];
for ii = 1: L/2 + 1
tfC(ii) = tfMag(ii) * (cosd(phase(ii)) + 1j*sind(phase(ii)));
end
%END ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%convolute both h and signal
fNum = fNum(1:L/2+1);
convHF = tfC.*fNum;
convHFMag = abs(convHF/L);
timeHF = ifft(convHF, length(t), 'symmetric'); %this is the part im confused about
% Ignore,
% tfC(numel(fNum)) = 0;
% convHF = tfC.*fNum;
% convHFMag = abs(convHF/n);
% timeHF = ifft(convHF);
%% plotting
% subplot(2, 2, 1);
% plot(t, Ly)
% title('Gaussian input');
% xlabel('time in seconds')
% ylabel('V')
% grid
subplot(2, 2, 1)
plot(frange, abs(tfC(1: L/2 + 1)));
set(gca, 'Xscale', 'log')
title('coax cable model')
xlabel('Hz')
ylabel('|H(s)|V/V')
grid
ylim([0 1.1])
subplot(2, 2, 2);
plot(frange, convHFMag(1:L/2+1), '.-', frange, fNumMag(1:L/2+1)) %make both range and function the same lenght
title('The input signal Vs its convolution with coax');
xlabel('Hz')
ylabel('V')
legend('Convolution','Lorentzian in frequecuency domain');
xlim([0, 5E10])
grid
subplot(2, 2, [3, 4]);
plot(t, Ly, t, timeHF)
% plot(t, real(timeHF(1:length(t)))) %make both range and function the same lenght
legend('Input', 'Output')
title('Signal at the output')
xlabel('time in seconds')
ylabel('V')
grid
It's important to understand deeply the principles of the FFT to use it correctly.
When you apply Fourier transform to a real signal, the coefficients at negative frequencies are the conjugate of the ones at positive frequencies. When you apply FFT to a real numerical signal, you can show mathematically that the conjugates of the coefficients that should be at negative frequencies (-f) will now appear at (Fsampling-f) where Fsampling=1/dt is the sampling frequency and dt the sampling period. This behavior is called aliasing and is present when you apply fft to a discrete time signal and the sampling period should be chosen small enaough for those two spectra not to overlap Shannon criteria.
When you want to apply a frequency filter to a signal, we say that we keep the first half of the spectrum because the high frequencies (>Fsampling/2) are due to aliasing and are not characteristics of the original signal. To do so, we put zeros on the second half of the spectra before multiplying by the filter. However, by doing so you also lose half of the amplitude of the original signal that you will not recover with ifft. The option 'symmetric' enable to recover it by adding in high frequencis (>Fsampling/2) the conjugate of the coefficients at lower ones (<Fsampling/2).
I simplified the code to explain briefly what's happening and implemented for you at line 20 a hand-made symmetrisation. Note that I reduced the sampling period from one to 100 picoseconds for the spectrum to display correctly:
close all
clc, clear
Fs = 14E10; %1 sample per pico seconds % CHANGED to 100ps
tlim = 4000E-12;
t = -tlim:1/Fs:tlim; %in pico seconds
ag = 0.5; %peak of guassian
bg = 0; %peak location
wg = 50E-12; %FWHM
NT = length(t);
x_i = ag.*exp(-4 .* log(2) .* (t-bg).^2 / (wg).^2); %Gauss. in terms of FWHM
fftx_i = fft(x_i);
f = 1/(2*tlim)*(0:NT-1);
fftx_r = fftx_i;
fftx_r(floor(NT/2):end) = 0; % The removal of high frequencies due to aliasing leads to losing half the amplitude
% HER YOU APPLY FILTER
x_r1 = ifft(fftx_r); % without symmetrisation (half the amplitude lost)
x_r2 = ifft(fftx_r, 'symmetric'); % with symmetrisation
x_r3 = ifft(fftx_r+[0, conj(fftx_r(end:-1:2))]); % hand-made symmetrisation
figure();
subplot(211)
hold on
plot(t, x_i, 'r')
plot(t, x_r2, 'r-+')
plot(t, x_r3, 'r-o')
plot(t, x_r1, 'k--')
hold off
legend('Initial', 'Matlab sym', 'Hand made sym', 'No sym')
title('Time signals')
xlabel('time in seconds')
ylabel('V')
grid
subplot(212)
hold on
plot(f, abs(fft(x_i)), 'r')
plot(f, abs(fft(x_r2)), 'r-+')
plot(f, abs(fft(x_r3)), 'r-o')
plot(f, abs(fft(x_r1)), 'k--')
hold off
legend('Initial', 'Matlab sym', 'Hand made sym', 'No sym')
title('Power spectra')
xlabel('frequency in hertz')
ylabel('V')
grid
Plots the result:
Do not hesitate if you have further questions. Good luck!
---------- EDIT ----------
The amplitude of discrete Fourier transform is not the same as the continuous one. If you are interested in showing signal in frequency domain, you will need to apply a normalization based on the convention you have chosen. In general, you use the convention that the amplitude of the Fourier transform of a Dirac delta function has amplitude one everywhere.
A numerical Dirac delta function has an amplitude of one at an index and zeros elsewhere and leads to a power spectrum equal to one everywhere. However in your case, the time axis has sample period dt, the integral over time of a numerical Dirac in that case is not 1 but dt. You must normalize your frequency domain signal by multiplying it by a factor dt (=1picoseceond in your case) to respect the convention. You can also note that this makes the frequency domain signal homogeneous to [unit of the original multiplied by a time] which is the correct unit of a Fourier transform.

MATLAB fft vs Mathematical fourier

I am using the following code to generate a fft and mathematical Fourier transform of a signal. I want to then mathematically recreate the original signal of the fft. This works on the mathematical signal but not on the fft since it is a Discrete Transform. Does anyone know what change I can make to my inverse transform equation that will make it work for fft?
clear all; clc;
N = 1024;
N2 = 1023;
SNR = -10;
fs = 1024;
Ts = 1/fs;
t = (0:(N-1))*Ts;
x = 0.5*sawtooth(2*2*pi*t);
x1 = fft(x);
Magnitude1 = abs(x1);
Phase1 = angle(x1)*360/(2*pi);
for m = 1:1024
f(m) = m; % Sinusoidal frequencies
a = (2/N)*sum(x.*cos(2*pi*f(m)*t)); % Cosine coeff.
b = (2/N)*sum(x.*sin(2*pi*f(m)*t)); % Sine coeff
Magnitude(m) = sqrt(a^2 + b^2); % Magnitude spectrum
Phase(m) = -atan2(b,a); % Phase spectrum
end
subplot(2,1,1);
plot(f,Magnitude1./512); % Plot magnitude spectrum
......Labels and title.......
subplot(2,1,2);
plot(f,Magnitude,'k'); % Plot phase spectrum
ylabel('Phase (deg)','FontSize',14);
pause();
x2 = zeros(1,1024); % Waveform vector
for m = 1:24
f(m) = m; % Sinusoidal frequencies
x2 = (1/m)*(x2 + Magnitude1(m)*cos(2*pi*f(m)*t + Phase1(m)));
end
x3 = zeros(1,1024); % Waveform vector
for m = 1:24
f(m) = m; % Sinusoidal frequencies
x3 = (x3 + Magnitude(m)*cos(2*pi*f(m)*t + Phase(m)));
end
plot(t,x,'--k'); hold on;
plot(t,x2,'k');
plot(t,x3,'b');```
There are a few comments about the Fourier Transform, and I hope I can explain everything for you. Also, I don't know what you mean by "Mathematical Fourier transform", as none of the expressions in your code is resembles the Fourier series of the sawtooth wave.
To understand exactly what the fft function does, we can do things step by step.
First, following your code, we create and plot one period of the sawtooth wave.
n = 1024;
fs = 1024;
dt = 1/fs;
t = (0:(n-1))*dt;
x = 0.5*sawtooth(2*pi*t);
figure; plot(t,x); xlabel('t [s]'); ylabel('x');
We can now calculate a few things.
First, the Nyquist frequency, the maximum detectable frequency from the samples.
f_max = 0.5*fs
f_max =
512
Also, the minimum detectable frequency,
f_min = 1/t(end)
f_min =
1.000977517106549
Calculate now the discrete Fourier transform with MATLAB function:
X = fft(x)/n;
This function obtains the complex coefficients of each term of the discrete Fourier transform. Notice it calculates the coefficients using the exp notation, not in terms of sines and cosines. The division by n is to guarantee that the first coefficient is equal to the arithmetic mean of the samples
If you want to plot the magnitude/phase of the transformed signal, you can type:
f = linspace(f_min,f_max,n/2); % frequency vector
a0 = X(1); % constant amplitude
X(1)=[]; % we don't have to plot the first component, as it is the constant amplitude term
XP = X(1:n/2); % we get only the first half of the array, as the second half is the reflection along the y-axis
figure
subplot(2,1,1)
plot(f,abs(XP)); ylabel('Amplitude');
subplot(2,1,2)
plot(f,angle(XP)); ylabel('Phase');
xlabel('Frequency [Hz]')
What does this plot means? It shows in a figure the amplitude and phase of the complex coefficients of the terms in the Fourier series that represent the original signal (the sawtooth wave). You can use this coefficients to obtain the signal approximation in terms of a (truncated) Fourier series. Of course, to do that, we need the whole transform (not only the first half, as it is usual to plot it).
X = fft(x)/n;
amplitude = abs(X);
phase = angle(X);
f = fs*[(0:(n/2)-1)/n (-n/2:-1)/n]; % frequency vector with all components
% we calculate the value of x for each time step
for j=1:n
x_approx(j) = 0;
for k=1:n % summation done using a for
x_approx(j) = x_approx(j)+X(k)*exp(2*pi*1i/n*(j-1)*(k-1));
end
x_approx(j) = x_approx(j);
end
Notice: The code above is for clarification and does not intend to be well coded. The summation can be done in MATLAB in a much better way than using a for loop, and some warnings will pop up in the code, warning the user to preallocate each variable for speed.
The above code calculates the x(ti) for each time ti, using the terms of the truncated Fourier series. If we plot both the original signal and the approximated one, we get:
figure
plot(t,x,t,x_approx)
legend('original signal','signal from fft','location','best')
The original signal and the approximated one are nearly equal. As a matter of fact,
norm(x-x_approx)
ans =
1.997566360514140e-12
Is almost zero, but not exactly zero.
Also, the plot above will issue a warning, due to the use of complex coefficients when calculating the approximated signal:
Warning: Imaginary parts of complex X and/or Y arguments ignored
But you can check that the imaginary term is very close to zero. It is not exactly zero due to roundoff errors in the computations.
norm(imag(x_approx))
ans =
1.402648396024229e-12
Notice in the codes above how to interpret and use the results from the fft function and how they are represented in the exp form, not on terms of sines and cosines, as you coded.

How to calculate modulation transfer function of a gaussian curve in MATLAB?

I am trying to find modulation transfer function of a gaussian fitted curve by using MATLAB.
The gaussian curve is as below:
x- axis is distance(form -15mm to 15mm) and y axis is count(Magnitude).
I used the following code to find find fourier transfrom of gaussian curve
FFT_y = fft(y); %take fourier transform
FF_mag = abs(FFT_y )/(length(FFT_y )); %find magnitude
FF_mag = (FF_mag-min(FF_mag))./(max(FF_mag)-min(FF_mag)); %normalize magnitude
I cropped FF_mag by using the following codes
FF_mag_nw = FF_mag(1:(length(FF_y)/32));
plot(FF_mag_nw);
I used 32 in above code to get main portion of graph and I got MTF plot as below:
I am confused about X-axis. What will be the range of X-axis in lines per mm?
Can anyone help me give an idea to calculate X-axis of MTF plot?
Thanks in Advance!
Manu
The matlab manual is very specific about the calculation. For example, check this out
dx = 0.1
x = -15:dx:15;
Fs = 1/dx; % Sampling frequency
L = length(x); % Signal length
sigma = 5;
amp = 437500;
y = amp/sqrt(2*pi*sigma^2) * exp(-x^2/(2*sigma^2));
n = 2^nextpow2(L);
Y = fft(y,n);
f = Fs*(0:(n/2))/n;
P = abs(Y/n);
plot(f,P(1:n/2+1))
title('Gaussian Pulse in Frequency Domain')
xlabel('Frequency f [in units of 1/dx]')
ylabel('|P(f)|')
How many points did you use for the real space gaussian. If this number is N, to transform the fft x axis in (1/mm) you should divide by N.

Split step Fourier propagation - Beam propagation method

Hello I'm having a difficulty using the split step Fourier method. Assuming I want to propagate a Gaussian in free space, I'm supposed to use:
A(x,z) = F^-1 [exp((i*k^2*z)/(2*k_0))* F[A(x,0)]]
where F is the Fourier and F^-1 is the inverse Fourier.
What I want to do is plot I(x,z=0), I(x,z=3) and the intensity distribution in the x-z plane.
I tried doing it numerically (plotting I(x,z=0), I(x,z=3)) using the following code:
lambda = 0.5*10^-6;
k0 = 2*pi/lambda;
w = 10*10^-6;
N=500;
a=0.4*10^-4;
dx=a/N;
x = -a/2:dx:a/2-dx;
Dk_x = 2*pi*N/a;
dk_x=2*pi/a;
k_x=-Dk_x/2:dk_x:Dk_x/2-dk_x;
N = (k_x.^2)/(2*k0);
z = 0:(5*10^-3)/length(N):5*10^-3;
z(end) = [];
% A0 = A(x,z=0)
A0 = exp(-x.^2/w^2);
I_0 = A0.*conj(A0);
% F_A0 is the fourier of A0
F_A0 = fft(A0);
% A3 = A(x,z=3)
A3 = ifft(exp(1i*N*3).*F_A0);
I_3 = A3.*conj(A3);
figure
plot(x,I_3,x,I_0)
However, I_3 is not what I expected to receive which is another Gaussian of smaller intensity.
Also, I'm unsure how I'd plot the intensity distribution in the x-z plane. They suggest using the imagesc function which I suppose I'd use it like:
imagesc(x,z, abs(ifft(exp(1i*N.*z).*F_A0).^2)
but the third argument, which is supposed to be a matrix, is a vector in what I've written..
Can anyone please help me with this?
Thank you in advance.
here's an example for a split step free Gaussian propagation:
N=2^9; % x grid points
L=100; % box length
dx=L/N; %position grid interval
x=(-L/2+1/N):dx:L/2; %define position grid (centered around origin)
dk=2*pi/L; %momentum grid interval
k=(-N/2+1:1:N/2).*dk; %define momentum grid
A_z=exp(-x.^2); % initial gaussian
dz=0.01; % propagation step
z=0:dz:3; % propagation vector
% do the propagation using split step
for n=1:numel(z)
A_z=ifft(fftshift( exp(1i*k.^2*dz).*fftshift(fft(A_z)) ));
I_z(n,:)=abs(A_z).^2;
end
imagesc(x,z,I_z)
xlim([-20 20]);
xlabel('x'); ylabel('z')

Low pass filter implementation Correct or wrong?

I've been working on 2 sensors signals measuring vibrations of a rotating shaft. Since there is residual noise in the signal. I tried to filter it by detrending, zero padding and applying low pass filter. Below I'm attaching the graphs of the signal before and after filtering. There is a huge variation in the signal after filtering that makes me think if I'm really doing it in the right way.
My Matlab code is
X = xlsread(filename,'F:F');
Y = xlsread(filename,'G:G');
%Calculate frequency axis
fs = 1e6 ; % Sampling frequency (Hz)
NFFT = 2^nextpow2(length(X)); % Zero padding to nearest N power 2
df = fs/NFFT;
dt = 1/df;
%Frequency Axis defintion
f = (-(fs-df)/2:df:(fs-df)/2)';
X(2^ceil(log2(length(X))))=0;
Y(2^ceil(log2(length(Y))))=0;
%calculate time axis
T = (dt:dt:(length(X)*dt))';
subplot(2,2,1)
plot(T,X);
xlabel('Time(s)')
ylabel('X amplitude')
title('X signal before filtering')
subplot(2,2,2)
plot(T,Y);
xlabel('Time(s)')
ylabel('Y amplitude')
title('Y signal before filtering')
X = detrend(X,0); % Removing DC Offset
Y = detrend(Y,0); % Removing DC Offset
% Filter parameters:
M = length(X); % signal length
L = M; % filter length
fc = 2*(38000/60); % cutoff frequency
% Design the filter using the window method:
hsupp = (-(L-1)/2:(L-1)/2);
hideal = (2*fc/fs)*sinc(2*fc*hsupp/fs);
h = hamming(L)' .* hideal; % h is our filter
% Zero pad the signal and impulse response:
X(2^ceil(log2(M)))=0;
xzp = X;
hzp = [ h zeros(1,NFFT-L) ];
% Transform the signal and the filter:
X = fft(xzp);
H = fft(hzp)';
X = X .* H;
X = ifft(X);
relrmserrX = norm(imag(X))/norm(X); % checked... this for zero
X = real(X)';
% Zero pad the signal and impulse response:
Y(2^ceil(log2(M)))=0;
xzp = Y;
hzp = [ h zeros(1,NFFT-L) ];
% Transform the signal and the filter:
Y = fft(xzp);
H = fft(hzp)';
Y = Y .* H;
Y = ifft(Y);
relrmserrY = norm(imag(Y))/norm(Y); % check... should be zero
Y = real(Y)';
I plotted the after filtering and as you can see in the picture there is a clear deviation. I want to only filter noise but the signal seem to loose other components and I'm little confused if thats the right way of doing filtering.
Any suggestion, hints or ideas would be helpful.
In the end I want to plot X vs Y to give orbits of the shaft vibration. Please also find below another picture of the unfiltered and filtered orbit. As you can see in the picture there is also change in the orbits from the original one (left image with lot of noise).
P.S.: I don't have DSP tool box
There is no problem with your FFT and IFFT.
You can test your code with a simple sine wave, with a very low frequency. The final output should be (almost) the same sine wave, since you are low-pass filtering it.
You've defined X (and Y) from 0 to some value. However, you've defined H from - (L-1)/2 to some positive value. Mathematically, this is fine, but you are simply taking an fft of H. Matlab thinks this has the same time-scale as X, when you multiply the ffts together!
So, in reality, you've taken the fft of XHfft(delta(t-d)), where d is the resulting time-shift. You can either undo this time-shift in the frequency domain, or the time-domain.