Source code for att.embedding.takens
"""Takens delay embedding for attractor reconstruction."""
import numpy as np
from att.embedding.delay import estimate_delay
from att.embedding.dimension import estimate_dimension
[docs]
class TakensEmbedder:
"""Reconstruct a phase-space attractor from a scalar time series.
Parameters
----------
delay : int or "auto"
Time steps between coordinates. "auto" estimates via AMI first minimum.
dimension : int or "auto"
Number of delay coordinates. "auto" estimates via FNN.
"""
[docs]
def __init__(self, delay: int | str = "auto", dimension: int | str = "auto"):
self.delay = delay
self.dimension = dimension
self.delay_: int | None = None
self.dimension_: int | None = None
[docs]
def fit(self, X: np.ndarray) -> "TakensEmbedder":
"""Estimate parameters from data. Stores .delay_ and .dimension_."""
X = np.asarray(X).ravel()
if self.delay == "auto":
self.delay_ = estimate_delay(X)
else:
self.delay_ = int(self.delay)
if self.dimension == "auto":
self.dimension_ = estimate_dimension(X, self.delay_)
else:
self.dimension_ = int(self.dimension)
return self
[docs]
def transform(self, X: np.ndarray) -> np.ndarray:
"""Embed 1D time series into delay coordinates.
Input: (n_samples,)
Output: (n_samples - (dimension-1)*delay, dimension)
"""
X = np.asarray(X).ravel()
if self.delay_ is None or self.dimension_ is None:
raise RuntimeError("Call .fit() before .transform()")
d = self.dimension_
tau = self.delay_
n = len(X) - (d - 1) * tau
if n <= 0:
raise ValueError(
f"Time series too short ({len(X)}) for delay={tau}, dim={d}. "
f"Need at least {(d - 1) * tau + 1} samples."
)
cloud = np.zeros((n, d))
for i in range(d):
cloud[:, i] = X[i * tau: i * tau + n]
return cloud
[docs]
def fit_transform(self, X: np.ndarray) -> np.ndarray:
"""Fit and transform in one call."""
return self.fit(X).transform(X)