How do you do a radial Fourier transform in MATLAB?
    9 views (last 30 days)
  
       Show older comments
    
I have 'r' and a function 'f(r)' as vectors of numbers, with r ranging from 0.05 to 17.95. I want to calculate the radial Fourier transform:

which is the equation that I'm trying to calculate, except for some normalizing constants. After loading 'r' and 'fr', the latter being f(r), here's what I try so far:
    Q = linspace(0.01,17.95,1000)';
    R = linspace(0.01,17.95,1000)';
    fR = @(R) interp1(r,fr,R,'spline');
    integrand_fft = @(R,Q) (R.^2).*(fR(R)-1)./(Q.*R);
    fQ_fft_v = -imag(fft((R.^2).*integrand_fft(R,Q)));
but the result appears symmetric and does not reach and asymptotic value that I expect, so I think that I did something wrong. How do I set up this code correctly?
0 Comments
Accepted Answer
  David Goodmanson
      
      
 on 7 May 2020
        Hi S,
here is one way.  First of all, the transform pair is
q*F(q) =            Int r*F(r) sin(q*r) dr
r*F(r) = (1/(2*pi))*Int q*F(q) sin(q*r) dq 
so the basic functions are qFq = q*F(q) and rFr = r*F(r).  If you want F(r) itself you can always obtain it from rFr ./ r and similarly with q.  The code below takes r*F(r) for the domain (0,rmax) and for mathematical convenience creates an odd (antisymmetric) function on the domain (-rmax,rmax).  That means the sine terms in the fft will survive because they are odd, and the cosine terms will not because they are even.  The fft produces an antisymmetric function of q in the domain (-qmax,qmax).  For a final result you can just ignore the functions for r<0 and q<0.
The code starts with rFr, does a transform to find qFq.  Then, to test the inverse transform there is a transform back to find rFr2 and compare it with rFr.  It's the same.
% create a function for positive r
n = 2e4;
delr = .001;
r = (-n:n)*delr;
rpos = r(r>=0);
Frpos = exp(-5*rpos);    % F(r), r >=0
rFrpos = rpos.*Frpos;
% create antisymmetric function with r=0 at the center
% see plot 2
rFr = [-fliplr(rFrpos(2:end)) rFrpos];
% transform to q, multiply by delr to approximate the Riemmann integral 
N = length(r);
qFq = -imag(fftshift(fft(ifftshift(rFr))))*delr;
delq = 2*pi/(N*delr);   % golden rule for fft
q = (-n:n)*delq;
figure(1)
plot(q,qFq)
grid on
% transform back to r, multiply by delq for Riemann integral
% factor of N because the ifft divides by N and that must be canceled out
rFr2 = (1/(2*pi))*N*imag(fftshift(ifft(ifftshift(qFq))))*delq;
figure(2)
plot(r,rFr,r,rFr2)
grid on
10 Comments
  JH
 on 2 Feb 2023
				Much obliged, David! =)
You reply is very helpful and appreciated :). I'll probably be bit lazy and use an anonymous function based on your suggestion
sinc2 = @(x) sinc(x/pi);
I think to match the analytical expression with the numerical results then, one has to divide the former with  due to different conventions with FFT(?)
due to different conventions with FFT(?)
 due to different conventions with FFT(?)
due to different conventions with FFT(?)% create a function for positive r
n = 1e3;
delr = 1;
r = (-n:n)*delr;
rpos = r(r>=0);
% sinc(x) in Matlab (and numpy) is sin(pi x)/(pi x)
sinc2 = @(x) sinc(x/pi);
a = 50*delr; 
b = 3e-1/delr;
N = length(r);
delq = 2*pi/(N*delr);   % golden rule for fft
q = (-n:n)*delq;
% f(r) and analytical F(q)
Frpos = exp(-rpos/a).*sinc2(rpos*b); % F(r), r >=0    
Fq_theor = 1/(2*pi)*(8*pi*a^3./((1 + a^2*(b+q).^2).*(1 + a^2*(b-q).^2)));
rFrpos = rpos.*Frpos;
% create antisymmetric function with r=0 at the center
% see plot 2
rFr = [-fliplr(rFrpos(2:end)) rFrpos];
% transform to q, multiply by delr to approximate the Riemmann integral 
qFq = -imag(fftshift(fft(ifftshift(rFr))))*delr;
figure(1);clf; pause(0.01)
% analytical solution to the fourier transform is 
subplot(1,3,1)
    plot(rpos,Frpos)
    legend('f(r>0)')
    legend('Location','northoutside')
subplot(1,3,2)
    plot(q,qFq./q,'b-',q,Fq_theor,'r--')
    grid on; axis tight
    xlim([-1 1])
    legend('Numeric F(q)','Theoretical F(q)')
    legend('Location','northoutside')
% transform back to r, multiply by delq for Riemann integral
% factor of N because the ifft divides by N and that must be canceled out
rFr2 = (1/(2*pi))*N*imag(fftshift(ifft(ifftshift(qFq))))*delq;
subplot(1,3,3)
% visualization discarding step size (adaptive)
    s = round(length(r)/500);
    plot(r,rFr./r,'--',r(1:s:end),rFr2(1:s:end)./r(1:s:end),'o')
    grid on; axis tight
    xlim([-50 50])    
        legend('original f(r)','Back transfered f(r)')
        legend('Location','northoutside')
And the results seem to match perfectly - many thanks! =)
P.S: I forgot this thread for few days, and then also found out in another context that sinc(x) has different convention in Matlab (same as issue in numpy).
I think expressions are equivalent (using Mathematica shamelessly here)

  David Goodmanson
      
      
 on 3 Feb 2023
				
      Edited: David Goodmanson
      
      
 on 3 Feb 2023
  
			Hi JH, I see they're equivalent and modified my comment accordingly.
More Answers (1)
  N/A
 on 8 May 2020
        
      Edited: N/A
 on 8 May 2020
  
      
      5 Comments
  David Goodmanson
      
      
 on 10 May 2020
				The fft operates on functions with an array index.  It doesn't know anything about what the distance between array points is, so to create an integral you have to supply that yourself.
The r and q arrays have zero at the center, but the fft wants zero as the first element.  fftshift and ifftshift accomplish that.
See Also
Categories
				Find more on Manage Products in Help Center and File Exchange
			
	Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!












