Skip to content

Commit 5bcbe29

Browse files
committed
Fix waveletdiff: use spectral differentiation of denoised signal
1 parent 68f9255 commit 5bcbe29

1 file changed

Lines changed: 12 additions & 6 deletions

File tree

pynumdiff/basis_fit.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -245,19 +245,25 @@ def waveletdiff(x, dt, wavelet='db4', level=None, threshold=1.0, axis=0, mode='p
245245
# the vectorised operations above have already moved all Python-level
246246
# arithmetic outside this loop.
247247
#
248-
# After wavelet denoising we have a smooth, noise-free signal. np.gradient
249-
# applies a second-order central finite difference to that clean signal,
250-
# which gives an accurate derivative. This is appropriate here because the
251-
# heavy lifting (noise removal) has already been done by the wavelet
252-
# thresholding step; np.gradient on a smooth signal converges at O(dt^2).
248+
# After wavelet denoising we have a smooth, noise-free signal. We
249+
# differentiate it analytically in the Fourier domain: multiplying the
250+
# FFT by i*omega is equivalent to applying the derivative operator exactly,
251+
# with no finite-difference truncation error. This keeps the two concerns
252+
# cleanly separated — wavelets handle denoising, Fourier handles
253+
# differentiation.
253254
x_hat_flat = np.empty_like(x_flat)
254255
dxdt_hat_flat = np.empty_like(x_flat)
255256

257+
# Angular frequency axis for a length-N signal sampled at dt.
258+
# fftfreq returns cycles/sample; multiplying by 2*pi/dt gives rad/s.
259+
k = np.fft.fftfreq(N, d=dt) * 2 * np.pi
260+
256261
for col in range(M):
257262
col_coeffs = [coeffs_denoised[i][:, col] for i in range(n_levels)]
258263
x_hat_col = pywt.waverec(col_coeffs, wavelet, mode=mode)[:N]
259264
x_hat_flat[:, col] = x_hat_col
260-
dxdt_hat_flat[:, col] = np.gradient(x_hat_col, dt)
265+
X = np.fft.fft(x_hat_col)
266+
dxdt_hat_flat[:, col] = np.real(np.fft.ifft(1j * k * X))
261267

262268
# Restore original shape and axis order.
263269
x_hat = np.moveaxis(x_hat_flat.reshape(shape), 0, axis)

0 commit comments

Comments
 (0)