Skip to content

Commit 93bb168

Browse files
committed
First attempt at adding nonuniform FFT.
1 parent 64d662e commit 93bb168

File tree

2 files changed

+166
-0
lines changed

2 files changed

+166
-0
lines changed

src/nufft.jl

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
2+
function nufft1_plan{T<:AbstractFloat}( x::AbstractVector{T}, ϵ::T )
3+
(s_vec, t_idx, gam) = FindAlgorithmicParameters( x )
4+
K = FindK(gam, ϵ)
5+
(u, v) = constructAK(x, K)
6+
p( c ) = (u.*(fft(Diagonal(c)*v,1)[t_idx,:]))*ones(K)
7+
end
8+
9+
function nufft2_plan{T<:AbstractFloat}( ω::AbstractVector{T}, ϵ::T )
10+
N = size(ω, 1)
11+
(s_vec, t_idx, γ) = FindAlgorithmicParameters( ω/N )
12+
K = FindK(γ, ϵ)
13+
(u, v) = constructAK/N, K)
14+
In = speye(eltype(c), N, N)
15+
p( c ) = (v.*(N*conj(ifft(In[:,t_idx]*conj(Diagonal(c)*u),1))))*ones(K)
16+
end
17+
18+
nufft1{T<:AbstractFloat}( c::AbstractVector, x::AbstractVector{T}, ϵ::T ) = nufft1_plan(x, ϵ)(c)
19+
nufft2{T<:AbstractFloat}( c::AbstractVector, ω::AbstractVector{T}, ϵ::T ) = nufft2_plan(ω, ϵ)(c)
20+
nuftt3{T<:AbstractFloat}( c::AbstractVector, x::AbstractVector{T}, ω::AbstractVector{T}, ϵ::T ) = nufft3_plan(x, ω, ϵ)(c)
21+
22+
FindK{T<:AbstractFloat}::T, ϵ::T) = Int( ceil(5.0*γ.*exp(lambertw(log(10.0/ϵ)./γ/7.0))) )
23+
24+
function FindAlgorithmicParameters{T<:AbstractFloat}( x::AbstractVector{T} )
25+
26+
N = size(x, 1)
27+
s_vec = round(N*x)
28+
t_idx = mod(round(Int64, N*x), N) + 1
29+
γ = norm(N*x - s_vec, Inf)
30+
31+
return (s_vec, t_idx, γ)
32+
end
33+
34+
function constructAK{T<:AbstractFloat}(x::AbstractVector{T}, K::Int64)
35+
# Construct a low rank approximation, using Chebyshev expansions
36+
# for AK = exp(-2*pi*1im*(x[j]-j/N)*k):
37+
38+
N = size(x, 1)
39+
(s_vec, t_idx, γ) = FindAlgorithmicParameters( x )
40+
er = N*x - s_vec
41+
scl = exp( -1im*pi*er )
42+
43+
# Chebyshev polynomials of degree 0,...,K-1 evaluated at er/gam:
44+
TT = Diagonal(scl)*ChebyshevP(K-1, er/γ)
45+
46+
# Chebyshev expansion coefficients:
47+
cfs = Bessel_coeffs(K, γ)
48+
u = zeros(eltype(cfs), N, K)
49+
50+
# Construct them now:
51+
for r = 0:K-1
52+
for j = 1:N
53+
u[j,r+1] = cfs[1,r+1]*TT[j,1]
54+
for p = (2-mod(r,2)):2:K-1
55+
u[j,r+1] += cfs[p+1,r+1]*TT[j,p+1]
56+
end
57+
end
58+
end
59+
60+
# rowspace vectors:
61+
v = ChebyshevP(K-1, 2.0*collect(0:N-1)/N - ones(N) )
62+
63+
return (u, v)
64+
end
65+
66+
67+
function Bessel_coeffs(K::Int64, γ::Float64)
68+
# Calculate the Chebyshev coefficients of exp(-2*pi*1im*x*y) on [-gam,gam]x[0,1]
69+
70+
cfs = complex(zeros( K, K ))
71+
72+
arg = -γ*pi/2
73+
for p = 0:K-1
74+
for q = mod(p,2):2:K-1
75+
cfs[p+1,q+1] = 4.0*(1im)^q*besselj(Int((p+q)/2),arg).*besselj(Int((q-p)/2),arg)
76+
end
77+
end
78+
cfs[1,:] = cfs[1,:]/2.0
79+
cfs[:,1] = cfs[:,1]/2.0
80+
81+
return cfs
82+
83+
end
84+
85+
86+
function ChebyshevP{T<:AbstractFloat}(n::Int64, x::AbstractVector{T})
87+
# Evaluate Chebyshev polynomials of degree 0,...,n at x:
88+
89+
N = size(x,1)
90+
Tcheb = zeros(eltype(x), N, n+1)
91+
92+
# T_0(x) = 1.0
93+
for j = 1:N
94+
Tcheb[j, 1] = 1.0
95+
end
96+
97+
# T_1(x) = x
98+
for k = 2:min(n+1,2)
99+
for j = 1:N
100+
Tcheb[j, 2] = x[j]
101+
end
102+
end
103+
104+
# 3-term recurrence relation:
105+
twoX = 2.0*x
106+
for k = 2:n
107+
for j = 1:N
108+
Tcheb[j, k+1] = twoX[j]*Tcheb[j, k] - Tcheb[j, k-1]
109+
end
110+
end
111+
112+
return Tcheb
113+
end

test/nufft.jl

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using FastTransforms
2+
using Base.Test
3+
4+
5+
function nudft1{T<:AbstractFloat}( c::AbstractVector, x::AbstractVector{T} )
6+
# Nonuniform discrete Fourier transform of type 1
7+
8+
N = size(x, 1)
9+
output = zeros(c)
10+
er = collect(0:N-1)
11+
for j = 1 : N
12+
output[j] = dot( exp(2*pi*1im*x[j]*er), c)
13+
end
14+
15+
return output
16+
end
17+
18+
function nudft2{T<:AbstractFloat}( c::AbstractVector, ω::AbstractVector{T})
19+
# Nonuniform discrete Fourier transform of type II
20+
21+
N = size(ω, 1)
22+
output = zeros(c)
23+
for j = 1 : N
24+
output[j] = dot( exp(2*pi*1im*(j-1)/N*ω), c)
25+
end
26+
27+
return output
28+
end
29+
30+
31+
# Test nufft1():
32+
ϵ = eps(Float64)
33+
for n = 10.^(0:4)
34+
c = complex(rand(n))
35+
x = pop!(collect(linspace(0,1,n+1)));
36+
x += 3*rand(n)/n
37+
exact = nudft1( c, x )
38+
fast = nufft1( c, x, ϵ )
39+
@test norm(exact - fast,Inf) < 500*ϵ*n*norm(c)
40+
end
41+
42+
# Test nufft2():
43+
ϵ = eps(Float64)
44+
for n = 10.^(0:4)
45+
c = complex(rand(n))
46+
ω = collect(0:n-1)
47+
ω += rand(n)
48+
exact = nudft2( c, ω )
49+
fast = nufft2( c, ω, ϵ )
50+
@test norm(exact - fast,Inf) < 500*ϵ*n*norm(c)
51+
end
52+
53+

0 commit comments

Comments
 (0)