%FAST COMPUTATION OF THE FRACTIONAL FOURIER TRANSFORM 
%by M. Alper Kutay, September 1996, Ankara
%Copyright 1996 M. Alper Kutay
%This code may be used for scientific and educational purposes
%provided credit is given to the publications below:
%
%Haldun M. Ozaktas, Orhan Arikan, M. Alper Kutay, and Gozde Bozdagi,
%Digital computation of the fractional Fourier transform,
%IEEE Transactions on Signal Processing, 44:2141--2150, 1996. 
%Haldun M. Ozaktas, Zeev Zalevsky, and M. Alper Kutay,
%The Fractional Fourier Transform with Applications in Optics and
%Signal Processing, Wiley, 2000, chapter 6, page 298.
%
%The several functions given below should be separately saved
%under the same directory. fracF(fc,a) is the function the user
%should call, where fc is the sample vector of the function whose
%fractional Fourier transform is to be taken, and `a' is the
%transform order. The function returns the samples of the a'th
%order fractional Fourier transform, under the assumption that
%the Wigner distribution of the function is negligible outside a
%circle whose diameter is the square root of the length of fc.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function[res]=fracF(fc,a);

% This function operates on the vector fc which is assumed to
% be the samples of a function, obtained at a rate 1/deltax 
% where the Wigner distribution of the function f is confined
% to a circle of diameter deltax around the origin. 
% (deltax^2 is the time-bandwidth product of the function f.)
% fc is assumed to have an even number of elements.
% This function maps fc to a vector, whose elements are the samples 
% of the a'th order fractional Fourier transform of the function f. 
% The lengths of the input and ouput vectors are the same if the 
% input vector has an even number of elements, as required.
% Operating interval: -2 <= a <= 2
% This function uses the `core' function corefrmod2.m

N = length(fc);
if fix(N/2) ~= N/2
  error('Length of the input vector should be even');
end;

fc = fc(:);

fc = bizinter(fc);
fc = [zeros(N,1); fc ; zeros(N,1)];

flag	= 0;

if (a>0) & (a<0.5)
   flag	= 1;
   a	= a-1;
end;
if (a>-0.5) & (a<0)
  flag	= 2;
  a	= a+1;
end;

if (a>1.5) & (a<2)
   flag	= 3;
   a	= a-1;
end;

if (a>-2) & (a<-1.5)
   flag	= 4;
   a	= a+1;
end;

res = fc;

if (flag==1) | (flag==3)
  res 	= corefrmod2(fc,1);
end;

if (flag==2) | (flag==4)
  res 	= corefrmod2(fc,-1);
end;

if (a==0)
  res	= fc;
else
if (a==2) | (a==-2)
  res	= flipud(fc);
else
  res	= corefrmod2(res,a);
end;
end;


res = res(N+1:3*N);
res = bizdec(res);
res(1) = 2*res(1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function[res]=corefrmod2(fc,a);

% Core function for computing the fractional Fourier transform.
% Valid only when 0.5 <= abs(a) <= 1.5
% Decomposition used: 
%   chirp mutiplication - chirp convolution - chirp mutiplication

deltax	= sqrt(length(fc));

phi	= a*pi/2;
N	= fix(length(fc));
deltax1 = deltax;
alpha	= 1/tan(phi);
beta	= 1/sin(phi);

x	= [-ceil(N/2):fix(N/2)-1]/deltax1;
fc	= fc(:);
fc	= fc(1:N);
f1	= exp(-i*pi*tan(phi/2)*x.*x); %multiplication by chirp!
f1	= f1(:);
fc      = fc.*f1;
x	= x(:);
clear x;
t	=[-N+1:N-1]/deltax1;
hlptc	=exp(i*pi*beta*t.*t);
clear t;
hlptc	= hlptc(:);

N2	= length(hlptc);
N3	= 2^(ceil(log(N2+N-1)/log(2)));
hlptcz	= [hlptc;zeros(N3-N2,1)];
fcz	= [fc;zeros(N3-N,1)];
Hcfft	= ifft(fft(fcz).*fft(hlptcz));  % convolution with chirp
clear hlptcz;
clear fcz;
Hc	= Hcfft(N:2*N-1);
clear Hcfft;
clear hlptc;


Aphi	= exp(-i*(pi*sign(sin(phi))/4-phi/2))/sqrt(abs(sin(phi)));
xx	= [-ceil(N/2):fix(N/2)-1]/deltax1;
f1	= f1(:);        
res	= (Aphi*f1.*Hc)/deltax1;  % multiplication by chirp!

if (fix(N/2) ~=N/2)
  res2(1:N-1) = res(2:N);
  res2(N)     = res(1);
  res     = res2;
end;

res = res(:);

clear f1
clear Hc

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function xint=bizinter(x)

N=length(x);
im = 0;
if sum(abs(imag(x)))>0
  im = 1;
  imx = imag(x);
  x  = real(x);
end;

x2=x(:);
x2=[x2.'; zeros(1,N)];
x2=x2(:);
xf=fft(x2);
if rem(N,2)==1      %N = odd
	N1=fix(N/2+1); N2=2*N-fix(N/2)+1;
	xint=2*real(ifft([xf(1:N1); zeros(N,1)  ;xf(N2:2*N)].'));
else
	xint=2*real(ifft([xf(1:N/2); zeros(N,1)  ;xf(2*N-N/2+1:2*N)].'));
end;
if ( im == 1)
 x2=imx(:);
 x2=[x2.'; zeros(1,N)];
 x2=x2(:);
 xf=fft(x2);
 if rem(N,2)==1      %N = odd
	N1=fix(N/2+1); N2=2*N-fix(N/2)+1;
	xmint=2*real(ifft([xf(1:N1); zeros(N,1)  ;xf(N2:2*N)].'));
 else
	xmint=2*real(ifft([xf(1:N/2); zeros(N,1)  ;xf(2*N-N/2+1:2*N)].'));
 end;
 xint = xint + i*xmint;
end;

xint = xint(:);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function xdec=bizdec(x)

k = 1:2:length(x);
xdec = x(k);

xdec = xdec(:);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function F2D=fracF2D(f2D,ac,ar)

[M,N] = size(f2D);
F2D = zeros(M,N);

if ac == 0
   F2D = f2D;
else
   for k = 1:N
     F2D(:,k) = fracF(f2D(:,k),ac);
   end;
end;


F2D = conj(F2D');

if ar ~= 0
	for k = 1:M
   	F2D(:,k) = fracF(F2D(:,k),ar);
	end;
end;

F2D = conj(F2D');

