Split step Fourier propagation - Beam propagation method - matlab

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')

Related

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.

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

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:

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.

surfnorm function more efficient way Matlab

After constructing the point cloud I want to get the normal of each point and I used the built-in matlab function surfnorm but its takes a lot of processing time. So if anyone could assist me do this a better and more efficient way.
I wonder if the following code would help you. There are three steps here.
Create 500 randomly spaced points (x,y), and compute a corresponding value z (the height of the surface) for which I chose a sinc like function
Resample the random points using the TriScatteredInterp function - this permits me to obtain points on an evenly sampled grid that "roughly correspond" to the initial surface
Compute the normal to "some points" on that grid (since there are 480x640 points, computing the normal at every point would just create an impossibly dense "forest of vectors"; by sampling "every 10th point" you can actually see what you are doing
The code I used was as follows:
randomX = rand(1,500);
randomY = rand(1,500);
r = 5*sqrt(randomX.^2 + randomY.^2);
randomZ = sin(r) ./ r;
% resample the data:
[xx yy] = meshgrid(linspace(0,1,640), linspace(0,1,480));
F = TriScatteredInterp(randomX(:), randomY(:), randomZ(:));
zz = F(xx, yy);
%% at each point, the normal is cross product of vectors to neighbors
xyz=reshape([xx yy zz],[size(xx) 3]);
xv = 10:30:479; yv = 10:30:639; % points at which to compute normals
dx = xyz(xv, yv+1, :) - xyz(xv, yv, :);
dy = xyz(xv+1, yv, :) - xyz(xv, yv, :);
normVecs = cross(dx, dy); % here we compute the normals.
normVecs = normVecs ./ repmat(sqrt(sum(normVecs.^2, 3)), [1 1 3]);
figure;
quiver3(xx(xv, yv), yy(xv, yv), zz(xv, yv), ...
normVecs(:,:,1), normVecs(:,:,2), normVecs(:,:,3));
axis equal
view([56 22]);
And the resulting plot: