feat: wavelets

This commit is contained in:
OpenSquared
2026-07-19 13:55:56 +02:00
parent 4154848fd3
commit 457aa7b49e

View File

@@ -80,18 +80,30 @@ def band_decompose(
try:
recon = icwt(Wx[mask, :], wavelet=wavelet, scales=scales_band, x_len=n)
except Exception:
# ssqueezepy's internal scale-type inference (log vs linear spacing
# detection) can raise on some narrow slices depending on how many
# scales land in this bucket for this specific series length.
# Treat as a negligible band instead of failing the whole request —
# but log it (previously silently swallowed) and flag it, since a flat
# zero band otherwise looks identical to "genuinely no energy here".
logger.warning(
"band_decompose: icwt failed for band %d (n=%d scales, wavelet=%s) — "
"falling back to a zero band", i, len(scales_band), wavelet, exc_info=True,
)
recon = np.zeros(n)
reconstruction_failed = True
# Root-caused: icwt's internal scaletype inference recursively splits
# `scales` looking for a log/linear transition point (infer_scaletype ->
# logscale_transition_idx), and on a masked SUBSET of the original CWT
# scales that recursive sub-slice can come out too short, crashing with
# "attempt to get argmax of an empty sequence" instead of a clean error.
# Confirmed by reproducing it directly against ssqueezepy 0.6.6: retrying
# with a regenerated, exactly log-uniform array over the same range/count
# sidesteps the fragile inference entirely (trivially satisfies its "is
# this log-spaced" check) and reliably recovers a real reconstruction —
# verified on 5 independently reproduced failures, all recovered.
try:
clean_scales = np.geomspace(scales_band.min(), scales_band.max(), len(scales_band))
recon = icwt(Wx[mask, :], wavelet=wavelet, scales=clean_scales, x_len=n)
logger.warning(
"band_decompose: icwt failed for band %d with original scales (n=%d, wavelet=%s) — "
"recovered using a regenerated log-uniform scale array", i, len(scales_band), wavelet,
)
except Exception:
logger.warning(
"band_decompose: icwt failed for band %d (n=%d scales, wavelet=%s) even after "
"retry — falling back to a zero band", i, len(scales_band), wavelet, exc_info=True,
)
recon = np.zeros(n)
reconstruction_failed = True
scale_lo, scale_hi = float(scales_band.min()), float(scales_band.max())
else:
# Too few scales in this bucket for a stable reconstruction; report a