Whitening
"""
Whiten a batch of time-series data
"""
from ml4gw.transforms import Whiten
import torch
fduration = 2
sample_rate = 2048
highpass = 20
duration = 10
whitener = Whiten(
fduration=fduration,
sample_rate=sample_rate,
highpass=highpass,
)
X = torch.randn(10, 2, duration * sample_rate)
# Apply the whitening transform. Assume `psd` is the
# power spectral density computed using, e.g., the
# `SpectralDensity` transform.
X_whitened = whitener(X, psd)
Minimum-phase whitening
For online applications, a minimum-phase filter can whiten data without depending on future samples. The dynamic transform accepts a PSD at call time:
from ml4gw.transforms import MinimumPhaseWhiten
whitener = MinimumPhaseWhiten(
fduration=2,
sample_rate=2048,
highpass=20,
)
X_whitened = whitener(X, psd)
For a fixed background, fit one PSD per channel once and reuse the stored filter:
from ml4gw.transforms import FixedMinimumPhaseWhiten
whitener = FixedMinimumPhaseWhiten(
num_channels=2,
fduration=2,
sample_rate=2048,
)
# Passing fftlength means the inputs are interpreted as timeseries.
whitener.fit(
background_h1,
background_l1,
fftlength=2,
highpass=20,
)
X_whitened = whitener(X)
The highpass and lowpass responses use the same inverse-spectrum truncation as the standard whitening transforms before the response is converted to a causal minimum-phase filter. A causal minimum-phase response has frequency-dependent group delay, and changing the target magnitude with a highpass or lowpass cutoff also changes that delay, particularly near the transition frequencies. Cropping removes the initial filter warm-up but does not compensate for this frequency-dependent delay.
By default, both transforms crop
int(fduration * sample_rate) samples from the left edge. This matches the
output length of Whiten for the even filter lengths
used by the existing transforms, but the alignment is different: standard whitening removes
half the filter duration from each edge, whereas minimum-phase whitening
removes the full duration from the left. Outputs from the two transforms
therefore should not be treated as sample-aligned.
Pass crop=False to keep the input length and retain samples computed from
zero-valued initial history. For consecutive chunks, prepend
int(fduration * sample_rate) real historical samples before calling the
transform. Directly supplied PSDs at physical strain scale should use double
precision to avoid underflow during filter construction. Both transforms
return torch.float32 outputs, matching the existing whitening transforms.
The minimum-phase transforms do not subtract a mean over the complete input
segment, since that operation would depend on future samples.