Hi Ned,
I took the time to think about this a little bit: Unfortunately I am not aware 
of useful 
literature for choosing STFT windows. Note that the concept of a dual window 
for the 
ISTFT does not seem to be widely known in the signal processing community. The 
only 
other implementation I know, which provides a dual window is LTFAT [1] 

Designing a STFT based differentiator is a bit involving, so let's discuss an 
FFT based one 
first: The continuous-time signal representation of a sampled signal of finite 
length can be 
expressed by a complex-valued Fourier series  E. g., for signal of duration 
one, we can 
write

x(t) = Sum[  X[l]  exp(2jπ(l Δ f) t ) ] with l being the summation index. 

The coefficients X[l] can be calculated with an FFT ([2] discusses this from a 
different 
angle). Differentiation with respect to time gives 

d/dt x(t) = Sum[  X[l]  2jπ(l Δ f) exp(2jπ(l Δ f) t) ] .

Note that x(t) is assumed to be periodic. Hence a discontinuity between start 
and end of 
signal produces ringing due to Gibb's phenomenon.


The key insight of the ShortTimeFFT implementation is that any signal can be 
represented 
by a series expansion of time- and frequency-shifted dual windows, i.e.,

x(t) = Sum[  S[q, p] d(t - p Δt) exp(2jπ(q Δ f) t ) ] 

with (p Δt) representing the time shift,  (q Δ f) the frequency shift, d(t) the 
dual window and 
S[p, q] the STFT coefficient (consult [3] for details).
Differentiation with respect to time gives 

d/dt x(t) = Sum[ S[q, p] 2jπ(q Δ f)  d(t - p Δt) exp(2jπ(q Δ f) t ) ]  + 
                            S[q, p] exp(2jπ(q Δ f) t )  d/dt d(t - p Δt) ] 

Note that:

* The window dependent term is parameterized by the derivative of the  dual 
window d/dt 
d(t - p Δt).

* If the signal is not periodic in each slice which is stenciled out by the 
sliding window, 
Gibb's phenomenon will strike again (this is what you probably observe in your 
simulation). Hence it is a good idea to choose a dual window, like the Hann 
window, which 
suppresses discontinuities at the beginning and end of the signal slice.  

* Not only the dual window but also its derivative needs to suppress those 
discontinuities. 

The following example shows an example of STFT based differentiation. The hop 
width is 
chosen small enough to supress Gibb's phenomenon in the dual window derivative. 
Note  
that Gibb's phenomenon  can be observed at the beginning and the end of the 
signal.

import matplotlib.pyplot as plt

import numpy as np

from scipy.signal import ShortTimeFFT

from scipy.signal import windows

from scipy.fft import rfft, rfftfreq, irfft


# Create periodic test signal and its derivative:

n, T = 1000, 1/1000  # samples and sampling interval for 1 second signal

t = np.arange(n) * T  # time stamps
# Create single frequency signal and derivative:

f = rfftfreq(n, T)
k_c = f.searchsorted(7)
omega_c = 2*np.pi*f[k_c]
X = np.zeros(len(f))
X[k_c] = n/2/omega_c
x = irfft(X, n=n)
y = irfft(2j*np.pi*f*X, n=n)  # dx / dt

# Two ShortTimeFFT instances are needed:

kw = dict(hop=10, fs=1/T,fft_mode='onesided', phase_shift=None)
SFT = ShortTimeFFT.from_dual(windows.hann(32, sym=False), **kw)

# Differentiate dual window per FFT:

diff_dual_win = irfft(rfft(SFT.dual_win) * 2j*np.pi*rfftfreq(SFT.m_num))
dSFT = ShortTimeFFT.from_dual(diff_dual_win, **kw)


# Perform the filtering:

S_x = SFT.stft(x)
dS_x = 2j*np.pi*SFT.f[:, np.newaxis] * S_x
dx = SFT.istft(dS_x, k1=n) + dSFT.istft(S_x, k1=n)


# Plot windows:

fg0, axx0 = plt.subplots(2, 1, sharex='all', tight_layout=True)
axx0[0].set(title="Windows")
axx0[1].set(title="Dual Windows")
axx0[0].plot(SFT.win, '.-', alpha=0.5, label='SFT')
axx0[0].plot(dSFT.win, '.-', alpha=0.5, label='dSFT')
axx0[1].plot(SFT.dual_win, '.-', alpha=0.5, label='SFT')
axx0[1].plot(dSFT.dual_win, '.-', alpha=0.5, label='dSFT')


# Plot signal:

fg1, ax1 = plt.subplots()
ax1.set(title=rf"STFT-based Differentiator for $f_c={f[k_c]}\,$Hz Signal",
        xlabel="Time $t$", ylabel="Amplitude")
ax1.plot(t, omega_c * x, alpha=0.5, label=r"$x(t) \cdot 2\pi f_c$")
ax1.plot(t, y, '--', alpha=0.5, label="$y = dx/dt$")

Attachment: signature.asc
Description: This is a digitally signed message part.

_______________________________________________
SciPy-Dev mailing list -- scipy-dev@python.org
To unsubscribe send an email to scipy-dev-le...@python.org
https://mail.python.org/mailman3/lists/scipy-dev.python.org/
Member address: arch...@mail-archive.com

Reply via email to