|
1 |
| -const BigFloats = Union{BigFloat,Complex{BigFloat}} |
| 1 | +const AbstractFloats = Union{AbstractFloat,Complex{T} where T<:AbstractFloat} |
2 | 2 |
|
3 | 3 | if VERSION < v"0.7-"
|
4 |
| - import Base.FFTW: fft, fft!, rfft, irfft, ifft, conv, dct, idct, dct!, idct!, |
| 4 | + import Base.FFTW: fft, fft!, rfft, irfft, ifft, ifft!, conv, dct, idct, dct!, idct!, |
5 | 5 | plan_fft!, plan_ifft!, plan_dct!, plan_idct!,
|
6 | 6 | plan_fft, plan_ifft, plan_rfft, plan_irfft, plan_dct, plan_idct
|
7 | 7 | else
|
8 |
| - import FFTW: fft, fft!, rfft, irfft, ifft, dct, idct, dct!, idct!, |
9 |
| - plan_fft!, plan_ifft!, plan_dct!, plan_idct!, |
10 |
| - plan_fft, plan_ifft, plan_rfft, plan_irfft, plan_dct, plan_idct |
| 8 | + import FFTW: dct, dct!, idct, idct!, |
| 9 | + plan_fft!, plan_ifft!, plan_dct!, plan_idct!, |
| 10 | + plan_fft, plan_ifft, plan_rfft, plan_irfft, plan_dct, plan_idct |
11 | 11 | import DSP: conv
|
12 | 12 | end
|
13 | 13 |
|
14 | 14 | # The following implements Bluestein's algorithm, following http://www.dsprelated.com/dspbooks/mdft/Bluestein_s_FFT_Algorithm.html
|
15 | 15 | # To add more types, add them in the union of the function's signature.
|
16 |
| -function fft(x::Vector{T}) where T<:BigFloats |
| 16 | + |
| 17 | +function generic_fft(x::Vector{T}) where T<:AbstractFloats |
17 | 18 | n = length(x)
|
18 |
| - ispow2(n) && return fft_pow2(x) |
| 19 | + ispow2(n) && return generic_fft_pow2(x) |
19 | 20 | ks = range(zero(real(T)),stop=n-one(real(T)),length=n)
|
20 | 21 | Wks = exp.((-im).*convert(T,π).*ks.^2 ./ n)
|
21 | 22 | xq, wq = x.*Wks, conj([exp(-im*convert(T,π)*n);reverse(Wks);Wks[2:end]])
|
22 | 23 | return Wks.*conv(xq,wq)[n+1:2n]
|
23 | 24 | end
|
24 | 25 |
|
25 | 26 |
|
26 |
| -function fft!(x::Vector{T}) where T<:BigFloats |
27 |
| - x[:] = fft(x) |
| 27 | +function generic_fft!(x::Vector{T}) where T<:AbstractFloats |
| 28 | + x[:] = generic_fft(x) |
28 | 29 | return x
|
29 | 30 | end
|
30 | 31 |
|
31 |
| -# add rfft for BigFloat, by calling fft |
| 32 | +# add rfft for AbstractFloat, by calling fft |
32 | 33 | # this creates ToeplitzMatrices.rfft, so avoids changing rfft
|
33 | 34 |
|
34 |
| -rfft(v::Vector{T}) where T<:BigFloats = fft(v)[1:div(length(v),2)+1] |
35 |
| -function irfft(v::Vector{T},n::Integer) where T<:BigFloats |
| 35 | +generic_rfft(v::Vector{T}) where T<:AbstractFloats = generic_fft(v)[1:div(length(v),2)+1] |
| 36 | + |
| 37 | +function generic_irfft(v::Vector{T},n::Integer) where T<:AbstractFloats |
36 | 38 | @assert n==2length(v)-1
|
37 |
| - r = Vector{Complex{BigFloat}}(undef, n) |
| 39 | + r = Vector{Complex{real(T)}}(undef, n) |
38 | 40 | r[1:length(v)]=v
|
39 | 41 | r[length(v)+1:end]=reverse(conj(v[2:end]))
|
40 |
| - real(ifft(r)) |
| 42 | + real(generic_ifft(r)) |
41 | 43 | end
|
42 | 44 |
|
43 |
| -ifft(x::Vector{T}) where {T<:BigFloats} = conj!(fft(conj(x)))/length(x) |
44 |
| -function ifft!(x::Vector{T}) where T<:BigFloats |
45 |
| - x[:] = ifft(x) |
| 45 | +generic_ifft(x::Vector{T}) where {T<:AbstractFloats} = conj!(generic_fft(conj(x)))/length(x) |
| 46 | +function generic_ifft!(x::Vector{T}) where T<:AbstractFloats |
| 47 | + x[:] = generic_ifft(x) |
46 | 48 | return x
|
47 | 49 | end
|
48 | 50 |
|
49 |
| -function conv(u::StridedVector{T}, v::StridedVector{T}) where T<:BigFloats |
| 51 | +function conv(u::StridedVector{T}, v::StridedVector{T}) where T<:AbstractFloats |
50 | 52 | nu,nv = length(u),length(v)
|
51 | 53 | n = nu + nv - 1
|
52 | 54 | np2 = nextpow(2,n)
|
53 | 55 | append!(u,zeros(T,np2-nu)),append!(v,zeros(T,np2-nv))
|
54 |
| - y = ifft_pow2(fft_pow2(u).*fft_pow2(v)) |
| 56 | + y = generic_ifft_pow2(generic_fft_pow2(u).*generic_fft_pow2(v)) |
55 | 57 | #TODO This would not handle Dual/ComplexDual numbers correctly
|
56 | 58 | y = T<:Real ? real(y[1:n]) : y[1:n]
|
57 | 59 | end
|
|
60 | 62 | # c_radix2.c in the GNU Scientific Library and four1 in the Numerical Recipes in C.
|
61 | 63 | # However, the trigonometric recurrence is improved for greater efficiency.
|
62 | 64 | # The algorithm starts with bit-reversal, then divides and conquers in-place.
|
63 |
| -function fft_pow2!(x::Vector{T}) where T<:BigFloat |
| 65 | +function generic_fft_pow2!(x::Vector{T}) where T<:AbstractFloat |
64 | 66 | n,big2=length(x),2one(T)
|
65 | 67 | nn,j=n÷2,1
|
66 | 68 | for i=1:2:n-1
|
@@ -96,97 +98,129 @@ function fft_pow2!(x::Vector{T}) where T<:BigFloat
|
96 | 98 | return x
|
97 | 99 | end
|
98 | 100 |
|
99 |
| -function fft_pow2(x::Vector{Complex{T}}) where T<:BigFloat |
| 101 | +function generic_fft_pow2(x::Vector{Complex{T}}) where T<:AbstractFloat |
100 | 102 | y = interlace(real(x),imag(x))
|
101 |
| - fft_pow2!(y) |
| 103 | + generic_fft_pow2!(y) |
102 | 104 | return complex.(y[1:2:end],y[2:2:end])
|
103 | 105 | end
|
104 |
| -fft_pow2(x::Vector{T}) where {T<:BigFloat} = fft_pow2(complex(x)) |
| 106 | +generic_fft_pow2(x::Vector{T}) where {T<:AbstractFloat} = generic_fft_pow2(complex(x)) |
105 | 107 |
|
106 |
| -function ifft_pow2(x::Vector{Complex{T}}) where T<:BigFloat |
| 108 | +function generic_ifft_pow2(x::Vector{Complex{T}}) where T<:AbstractFloat |
107 | 109 | y = interlace(real(x),-imag(x))
|
108 |
| - fft_pow2!(y) |
| 110 | + generic_fft_pow2!(y) |
109 | 111 | return complex.(y[1:2:end],-y[2:2:end])/length(x)
|
110 | 112 | end
|
111 | 113 |
|
112 |
| - |
113 |
| -function dct(a::AbstractVector{Complex{BigFloat}}) |
114 |
| - N = big(length(a)) |
115 |
| - c = fft([a; flipdim(a,1)]) |
| 114 | +function generic_dct(a::AbstractVector{Complex{T}}) where {T <: AbstractFloat} |
| 115 | + N = length(a) |
| 116 | + twoN = convert(T,2) * N |
| 117 | + c = generic_fft([a; flipdim(a,1)]) |
116 | 118 | d = c[1:N]
|
117 |
| - d .*= exp.((-im*big(pi)).*(0:N-1)./(2*N)) |
118 |
| - d[1] = d[1] / sqrt(big(2)) |
119 |
| - lmul!(inv(sqrt(2N)), d) |
| 119 | + d .*= exp.((-im*convert(T, pi)).*(0:N-1)./twoN) |
| 120 | + d[1] = d[1] / sqrt(convert(T, 2)) |
| 121 | + lmul!(inv(sqrt(twoN)), d) |
120 | 122 | end
|
121 | 123 |
|
122 |
| -dct(a::AbstractArray{BigFloat}) = real(dct(complex(a))) |
| 124 | +generic_dct(a::AbstractArray{T}) where {T <: AbstractFloat} = real(generic_dct(complex(a))) |
123 | 125 |
|
124 |
| -function idct(a::AbstractVector{Complex{BigFloat}}) |
125 |
| - N = big(length(a)) |
126 |
| - b = a * sqrt(2*N) |
127 |
| - b[1] = b[1] * sqrt(big(2)) |
128 |
| - shift = exp.(-im * 2 * big(pi) * (N - big(1)/2) * (0:(2N-1)) / (2 * N)) |
| 126 | +function generic_idct(a::AbstractVector{Complex{T}}) where {T <: AbstractFloat} |
| 127 | + N = length(a) |
| 128 | + twoN = convert(T,2)*N |
| 129 | + b = a * sqrt(twoN) |
| 130 | + b[1] = b[1] * sqrt(convert(T,2)) |
| 131 | + shift = exp.(-im * 2 * convert(T, pi) * (N - convert(T,1)/2) * (0:(2N-1)) / twoN) |
129 | 132 | b = [b; 0; -flipdim(b[2:end],1)] .* shift
|
130 | 133 | c = ifft(b)
|
131 | 134 | flipdim(c[1:N],1)
|
132 | 135 | end
|
133 | 136 |
|
134 |
| -idct(a::AbstractArray{BigFloat}) = real(idct(complex(a))) |
| 137 | +generic_idct(a::AbstractArray{T}) where {T <: AbstractFloat} = real(generic_idct(complex(a))) |
135 | 138 |
|
136 |
| -dct!(a::AbstractArray{T}) where {T<:BigFloats} = (b = dct(a); a[:] = b) |
137 |
| -idct!(a::AbstractArray{T}) where {T<:BigFloats} = (b = idct(a); a[:] = b) |
| 139 | +generic_dct!(a::AbstractArray{T}) where {T<:AbstractFloats} = (b = generic_dct(a); a[:] = b) |
| 140 | +generic_idct!(a::AbstractArray{T}) where {T<:AbstractFloats} = (b = generic_idct(a); a[:] = b) |
| 141 | + |
| 142 | +# These lines mimick the corresponding ones in FFTW/src/dct.jl, but with |
| 143 | +# AbstractFloat rather than fftwNumber. |
| 144 | +for f in (:dct, :dct!, :idct, :idct!) |
| 145 | + pf = Symbol("plan_", f) |
| 146 | + @eval begin |
| 147 | + $f(x::AbstractArray{<:AbstractFloats}) = $pf(x) * x |
| 148 | + $f(x::AbstractArray{<:AbstractFloats}, region) = $pf(x, region) * x |
| 149 | + end |
| 150 | +end |
138 | 151 |
|
139 | 152 | # dummy plans
|
140 | 153 | struct DummyFFTPlan{T,inplace} <: Plan{T} end
|
141 | 154 | struct DummyiFFTPlan{T,inplace} <: Plan{T} end
|
142 |
| -struct DummyrFFTPlan{T,inplace} <: Plan{T} end |
143 |
| -struct DummyirFFTPlan{T,inplace} <: Plan{T} end |
144 | 155 | struct DummyDCTPlan{T,inplace} <: Plan{T} end
|
145 | 156 | struct DummyiDCTPlan{T,inplace} <: Plan{T} end
|
| 157 | +struct DummyrFFTPlan{T,inplace} <: Plan{T} |
| 158 | + n :: Integer |
| 159 | +end |
| 160 | +struct DummyirFFTPlan{T,inplace} <: Plan{T} |
| 161 | + n :: Integer |
| 162 | +end |
146 | 163 |
|
147 | 164 | for (Plan,iPlan) in ((:DummyFFTPlan,:DummyiFFTPlan),
|
148 |
| - (:DummyrFFTPlan,:DummyirFFTPlan), |
| 165 | + # (:DummyrFFTPlan,:DummyirFFTPlan), |
149 | 166 | (:DummyDCTPlan,:DummyiDCTPlan))
|
150 | 167 | @eval begin
|
151 | 168 | Base.inv(::$Plan{T,inplace}) where {T,inplace} = $iPlan{T,inplace}()
|
152 | 169 | Base.inv(::$iPlan{T,inplace}) where {T,inplace} = $Plan{T,inplace}()
|
153 | 170 | end
|
154 | 171 | end
|
155 | 172 |
|
| 173 | +# Specific for rfft and irfft: |
| 174 | +Base.inv(::DummyirFFTPlan{T,inplace}) where {T,inplace} = DummyrFFTPlan{T,Inplace}(p.n) |
| 175 | +Base.inv(::DummyrFFTPlan{T,inplace}) where {T,inplace} = DummyirFFTPlan{T,Inplace}(p.n) |
156 | 176 |
|
157 |
| -for (Plan,ff,ff!) in ((:DummyFFTPlan,:fft,:fft!), |
158 |
| - (:DummyiFFTPlan,:ifft,:ifft!), |
159 |
| - (:DummyrFFTPlan,:rfft,:rfft!), |
160 |
| - (:DummyirFFTPlan,:irfft,:irfft!), |
161 |
| - (:DummyDCTPlan,:dct,:dct!), |
162 |
| - (:DummyiDCTPlan,:idct,:idct!)) |
| 177 | + |
| 178 | +for (Plan,ff,ff!) in ((:DummyFFTPlan,:generic_fft,:generic_fft!), |
| 179 | + (:DummyiFFTPlan,:generic_ifft,:generic_ifft!), |
| 180 | + (:DummyrFFTPlan,:generic_rfft,:generic_rfft!), |
| 181 | +# (:DummyirFFTPlan,:generic_irfft,:generic_irfft!), |
| 182 | + (:DummyDCTPlan,:generic_dct,:generic_dct!), |
| 183 | + (:DummyiDCTPlan,:generic_idct,:generic_idct!)) |
163 | 184 | @eval begin
|
164 |
| - *(p::$Plan{T,true}, x::StridedArray{T,N}) where {T,N} = $ff!(x) |
165 |
| - *(p::$Plan{T,false}, x::StridedArray{T,N}) where {T,N} = $ff(x) |
| 185 | + *(p::$Plan{T,true}, x::StridedArray{T,N}) where {T<:AbstractFloats,N} = $ff!(x) |
| 186 | + *(p::$Plan{T,false}, x::StridedArray{T,N}) where {T<:AbstractFloats,N} = $ff(x) |
166 | 187 | function LAmul!(C::StridedVector, p::$Plan, x::StridedVector)
|
167 | 188 | C[:] = $ff(x)
|
168 | 189 | C
|
169 | 190 | end
|
170 | 191 | end
|
171 | 192 | end
|
172 | 193 |
|
| 194 | +# Specific for irfft: |
| 195 | +*(p::DummyirFFTPlan{T,true}, x::StridedArray{T,N}) where {T<:AbstractFloats,N} = generic_irfft!(x, p.n) |
| 196 | +*(p::DummyirFFTPlan{T,false}, x::StridedArray{T,N}) where {T<:AbstractFloats,N} = generic_irfft(x, p.n) |
| 197 | +function LAmul!(C::StridedVector, p::DummyirFFTPlan, x::StridedVector) |
| 198 | + C[:] = generic_irfft(x, p.n) |
| 199 | + C |
| 200 | +end |
173 | 201 |
|
174 |
| - |
175 |
| - |
176 |
| -plan_fft!(x::Vector{T}) where {T<:BigFloats} = DummyFFTPlan{Complex{BigFloat},true}() |
177 |
| -plan_ifft!(x::Vector{T}) where {T<:BigFloats} = DummyiFFTPlan{Complex{BigFloat},true}() |
178 |
| - |
179 |
| -#plan_rfft!{T<:BigFloats}(x::Vector{T}) = DummyrFFTPlan{Complex{BigFloat},true}() |
180 |
| -#plan_irfft!{T<:BigFloats}(x::Vector{T},n::Integer) = DummyirFFTPlan{Complex{BigFloat},true}() |
181 |
| -plan_dct!(x::Vector{T}) where {T<:BigFloats} = DummyDCTPlan{T,true}() |
182 |
| -plan_idct!(x::Vector{T}) where {T<:BigFloats} = DummyiDCTPlan{T,true}() |
183 |
| - |
184 |
| -plan_fft(x::Vector{T}) where {T<:BigFloats} = DummyFFTPlan{Complex{BigFloat},false}() |
185 |
| -plan_ifft(x::Vector{T}) where {T<:BigFloats} = DummyiFFTPlan{Complex{BigFloat},false}() |
186 |
| -plan_rfft(x::Vector{T}) where {T<:BigFloats} = DummyrFFTPlan{Complex{BigFloat},false}() |
187 |
| -plan_irfft(x::Vector{T},n::Integer) where {T<:BigFloats} = DummyirFFTPlan{Complex{BigFloat},false}() |
188 |
| -plan_dct(x::Vector{T}) where {T<:BigFloats} = DummyDCTPlan{T,false}() |
189 |
| -plan_idct(x::Vector{T}) where {T<:BigFloats} = DummyiDCTPlan{T,false}() |
| 202 | +# We override these for AbstractFloat, so that conversion from reals to |
| 203 | +# complex numbers works for any AbstractFloat (instead of only BlasFloat's) |
| 204 | +AbstractFFTs.complexfloat(x::StridedArray{Complex{<:AbstractFloat}}) = x |
| 205 | +AbstractFFTs.realfloat(x::StridedArray{<:Real}) = x |
| 206 | +# We override this one in order to avoid throwing an error that the type is |
| 207 | +# unsupported (as defined in AbstractFFTs) |
| 208 | +AbstractFFTs._fftfloat(::Type{T}) where {T <: AbstractFloat} = T |
| 209 | + |
| 210 | +plan_fft!(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyFFTPlan{Complex{real(T)},true}() |
| 211 | +plan_ifft!(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyiFFTPlan{Complex{real(T)},true}() |
| 212 | + |
| 213 | +# plan_rfft!(x::StridedArray{T}) where {T <: AbstractFloat} = DummyrFFTPlan{Complex{real(T)},true}() |
| 214 | +# plan_irfft!(x::StridedArray{T},n::Integer) where {T <: AbstractFloat} = DummyirFFTPlan{Complex{real(T)},true}() |
| 215 | +plan_dct!(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyDCTPlan{T,true}() |
| 216 | +plan_idct!(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyiDCTPlan{T,true}() |
| 217 | + |
| 218 | +plan_fft(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyFFTPlan{Complex{real(T)},false}() |
| 219 | +plan_ifft(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyiFFTPlan{Complex{real(T)},false}() |
| 220 | +plan_rfft(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyrFFTPlan{Complex{real(T)},false}(length(x)) |
| 221 | +plan_irfft(x::StridedArray{T}, n::Integer, region) where {T <: AbstractFloats} = DummyirFFTPlan{Complex{real(T)},false}(n) |
| 222 | +plan_dct(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyDCTPlan{T,false}() |
| 223 | +plan_idct(x::StridedArray{T}, region) where {T <: AbstractFloats} = DummyiDCTPlan{T,false}() |
190 | 224 |
|
191 | 225 |
|
192 | 226 | function interlace(a::Vector{S},b::Vector{V}) where {S<:Number,V<:Number}
|
|
0 commit comments