Skip to content

Commit 186636d

Browse files
committed
istft diff applied to current master
1 parent 96201ee commit 186636d

File tree

4 files changed

+100
-17
lines changed

4 files changed

+100
-17
lines changed

doc/util.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@
2222
\hat{x}`, where :math:`\hat{x}` is the Hilbert transform of x,
2323
along the first dimension of x.
2424

25+
.. function:: istft(S, wlen, overlap; nfft=nextfastfft(wlen), window=nothing)
26+
27+
Computes the inverse short-time Fourier transform (STFT) of S (a complex
28+
matrix, as computed by `stft`). `wlen` and `overlap` are respectively the
29+
window length and overlap used for computing the STFT. `nfft` is the used
30+
FFT size (defaults to `nextfastfft(wlen)`) and `window` can be either a
31+
function or a vector with the window elements (defaults to a rectangular
32+
window).
33+
2534
.. function:: fftfreq(n, fs=1)
2635

2736
Return discrete fourier transform sample frequencies. The returned

src/periodograms.jl

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -162,19 +162,6 @@ function fft2oneortwosided!{T}(out::Array{Complex{T}}, s_fft::Vector{Complex{T}}
162162
out
163163
end
164164

165-
# Evaluate a window function at n points, returning both the window
166-
# (or nothing if no window) and the squared L2 norm of the window
167-
compute_window(::Nothing, n::Int) = (nothing, n)
168-
function compute_window(window::Function, n::Int)
169-
win = window(n)::Vector{Float64}
170-
norm2 = sumabs2(win)
171-
(win, norm2)
172-
end
173-
function compute_window(window::AbstractVector, n::Int)
174-
length(window) == n || error("length of window must match input")
175-
(window, sumabs2(window))
176-
end
177-
178165
## PERIODOGRAMS
179166
abstract TFR{T}
180167
immutable Periodogram{T,F<:Union(Frequencies,Range)} <: TFR{T}
@@ -207,7 +194,7 @@ function periodogram{T<:Number}(s::AbstractVector{T}; onesided::Bool=eltype(s)<:
207194
onesided && T <: Complex && error("cannot compute one-sided FFT of a complex signal")
208195
nfft >= length(s) || error("nfft must be >= n")
209196

210-
win, norm2 = compute_window(window, length(s))
197+
win, norm2 = Util.compute_window(window, length(s))
211198
if nfft == length(s) && win == nothing && isa(s, StridedArray)
212199
input = s # no need to pad
213200
else
@@ -286,7 +273,7 @@ function welch_pgram{T<:Number}(s::AbstractVector{T}, n::Int=length(s)>>3, nover
286273
onesided && T <: Complex && error("cannot compute one-sided FFT of a complex signal")
287274
nfft >= n || error("nfft must be >= n")
288275

289-
win, norm2 = compute_window(window, n)
276+
win, norm2 = Util.compute_window(window, n)
290277
sig_split = arraysplit(s, n, noverlap, nfft, win)
291278
out = zeros(fftabs2type(T), onesided ? (nfft >> 1)+1 : nfft)
292279
r = fs*norm2*length(sig_split)
@@ -369,7 +356,7 @@ function stft{T}(s::AbstractVector{T}, n::Int=length(s)>>3, noverlap::Int=n>>1,
369356
window::Union(Function,AbstractVector,Nothing)=nothing)
370357
onesided && T <: Complex && error("cannot compute one-sided FFT of a complex signal")
371358

372-
win, norm2 = compute_window(window, n)
359+
win, norm2 = Util.compute_window(window, n)
373360
sig_split = arraysplit(s, n, noverlap, nfft, win)
374361
nout = onesided ? (nfft >> 1)+1 : nfft
375362
out = zeros(stfttype(T, psdonly), nout, length(sig_split))

src/util.jl

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export unwrap!,
2121
rmsfft,
2222
unsafe_dot,
2323
polyfit,
24-
shiftin!
24+
shiftin!,
25+
istft
2526

2627
function unwrap!{T <: FloatingPoint}(m::Array{T}, dim::Integer=ndims(m);
2728
range::Number=2pi)
@@ -98,6 +99,57 @@ function hilbert{T<:Real}(x::AbstractArray{T})
9899
out
99100
end
100101

102+
# Evaluate a window function at n points, returning both the window
103+
# (or nothing if no window) and the squared L2 norm of the window
104+
compute_window(::Nothing, n::Int) = (nothing, n)
105+
function compute_window(window::Function, n::Int)
106+
win = window(n)::Vector{Float64}
107+
norm2 = sumabs2(win)
108+
(win, norm2)
109+
end
110+
function compute_window(window::AbstractVector, n::Int)
111+
length(window) == n || error("length of window must match input")
112+
(window, sumabs2(window))
113+
end
114+
115+
backward_plan{T<:Union(Float32, Float64)}(X::AbstractArray{Complex{T}}, Y::AbstractArray{T}) =
116+
FFTW.Plan(X, Y, 1, FFTW.ESTIMATE, FFTW.NO_TIMELIMIT).plan
117+
118+
function istft{T<:Union(Float32, Float64)}(S::AbstractMatrix{Complex{T}}, wlen::Int, overlap::Int; nfft=nextfastfft(wlen), window::Union(Function,AbstractVector,Nothing)=nothing)
119+
winc = wlen-overlap
120+
win, norm2 = compute_window(window, wlen)
121+
if win != nothing
122+
win² = win.^2
123+
end
124+
nframes = size(S,2)-1
125+
outlen = nfft + nframes*winc
126+
out = zeros(T, outlen)
127+
tmp1 = Array(eltype(S), size(S, 1))
128+
tmp2 = zeros(T, nfft)
129+
p = backward_plan(tmp1, tmp2)
130+
wsum = zeros(outlen)
131+
for k = 1:size(S,2)
132+
copy!(tmp1, 1, S, 1+(k-1)*size(S,1), length(tmp1))
133+
FFTW.execute(p, tmp1, tmp2)
134+
scale!(tmp2, FFTW.normalization(tmp2))
135+
if win != nothing
136+
ix = (k-1)*winc
137+
for n=1:nfft
138+
@inbounds out[ix+n] += tmp2[n]*win[n]
139+
@inbounds wsum[ix+n] += win²[n]
140+
end
141+
else
142+
copy!(out, 1+(k-1)*winc, tmp2, 1, nfft)
143+
end
144+
end
145+
if win != nothing
146+
for i=1:length(wsum)
147+
@inbounds wsum[i] != 0 && (out[i] /= wsum[i])
148+
end
149+
end
150+
out
151+
end
152+
101153
## FFT TYPES
102154

103155
# Get the input element type of FFT for a given type

test/util.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,41 @@ r = round(Int, rand(128)*20)
7474
# Test hilbert with 2D input
7575
@test_approx_eq h hilbert(a)
7676

77+
## ISTFT
78+
79+
# rectangular window with 50% overlap and regular sizes
80+
x1 = rand(128)
81+
X1 = stft(x1, 16, 8)
82+
y1 = istft(X1, 16, 8)
83+
@test_approx_eq x1 y1
84+
85+
# rectangular window with 50% overlap and irregular size: y will have less
86+
# elements than x unless x is zero-padded to a FFT-friendly size
87+
x2 = rand(171)
88+
X2 = stft(x2, 16, 8)
89+
y2 = istft(X2, 16, 8)
90+
@test_approx_eq x2[1:length(y2)] y2
91+
92+
# Hanning window with 25% overlap
93+
# First sample will be wrong since the first element in the window is zero
94+
function hann(M, sym=true)
95+
odd = mod(M,2) == 1
96+
if !sym && !odd
97+
M = M+1
98+
end
99+
w = [0.5-0.5*cos(2*pi*n/(M-1)) for n=0:(M-1)]
100+
if !sym && !odd
101+
return w[1:end-1]
102+
else
103+
return w
104+
end
105+
end
106+
107+
hann_periodic(M::Int) = hann(M, false)
108+
X1w = stft(x1, 16, 12; window=hann_periodic)
109+
y1w = istft(X1w, 16, 12; window=hann_periodic)
110+
@test_approx_eq x1[2:end] y1w[2:end]
111+
77112
## FFTFREQ
78113

79114
@test_approx_eq fftfreq(1) [0.]

0 commit comments

Comments
 (0)