Skip to content

Replace spectraldiff's extension hyperparameters with detrend + odd extension? #231

Description

@pavelkomarov

Idea

spectraldiff currently manages the FFT's implicit periodicity with two boolean hyperparameters, even_extension and pad_to_zero_dxdt, the second of which pads 100 samples on each end and smooths them in. Section 7.5.1 of the taxonomy paper already notes the weakness: an even extension removes the value discontinuity across the wrap but "can still result in a corner if the signal edges are not flat," and a corner in the signal is a jump in its derivative.

A more principled treatment removes both problems in three steps, each with a reason:

  1. Detrend — subtract the straight line joining the endpoints, so x[0] == x[N-1] and the periodic wrap closes.
  2. Odd-extend through the last endpointx[N+k] = 2*x[N-1] - x[N-2-k], which continues value and slope, so no corner. Reflecting x[0] as well would repeat it across the wrap, a flat spot rather than a continuation, so that one sample is left out and the extension is 2N-2.
  3. Differentiate, then add the slope back — exact, since the derivative of a line is a constant.

This drops both hyperparameters and the padding block, and the extension is 2N-2 rather than the 2N of even extension.

Results

On noiseless analytic signals at a fixed cutoff_freq=0.2, it is much better (max relative error):

signal even + pad detrend + odd ext
sin 1.52e+00 5.66e-15
ramp + wiggle 1.47e+00 2.00e-02
exp 1.41e+00 6.80e-03
quadratic 1.43e+00 3.38e-03

But that is not the case that matters, and the honest result is worse. Optimizing both variants with pynumdiff.optimize over six sims x two step sizes x two noise levels, the new version is a slight net loss: geometric mean of new/old RMSE 1.028, better in 11 of 24, median ratio 1.029. It wins clearly on lin_auto (0.495, 0.593) and on coarse dt generally, and loses worst on cruise at high noise (2.063) and pop_dyn (1.396, 1.576).

The reconciliation: on noisy data with the cutoff optimized, the low-pass filter dominates and edge treatment is second order, while the two booleans give the optimizer freedom to pick whichever treatment suits each signal. Removing two degrees of freedom costs about what the better extension gains.

Open questions

  • Keep the odd extension but retain a flag, so the optimizer can still choose? Recovers the freedom, keeps some complexity.
  • Is detrending alone the win, independent of the extension change? It has the cleanest justification and may be carrying the lin_auto improvement by itself.
  • Six error-bound cells move in each direction, so spectraldiff's test bounds need regenerating either way.

A branch, spectraldiff-odd-extension, has a working implementation with the search space trimmed and bounds regenerated; 210 tests pass. Not merged, given the above.


Investigated by Claude Opus 5 (Claude Code) on behalf of @pavelkomarov, PyNumDiff maintainer.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

idea💡researchwhen a task requires some experimentation or diving into papers and math

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions