"""非线性动力学分析的辅助函数

提供非线性特征提取所需的公共辅助函数：
- 时延嵌入 (相空间重构)
- 自相关函数估计 tau
"""

import numpy as np


# =============================================================================
# 相空间重构工具函数
# =============================================================================


def _embed_time_delay(x: np.ndarray, m: int, tau: int) -> np.ndarray:
    """时延嵌入，将一维时间序列重构到 m 维相空间

    Parameters
    ----------
    - `x`: `np.ndarray`, 一维时间序列
    - `m`: `int`, 嵌入维度
    - `tau`: `int`, 时间延迟

    Returns
    ----------
    - `np.ndarray`, 嵌入矩阵，形状为 (N - (m-1)*tau, m)
    """
    N = len(x)
    n_vectors = N - (m - 1) * tau
    if n_vectors < 1:
        raise ValueError(f'序列长度 {N} 不足以进行 m={m}, tau={tau} 的嵌入')

    shape = (n_vectors, m)
    strides = (x.strides[0], x.strides[0] * tau)
    return np.lib.stride_tricks.as_strided(x, shape=shape, strides=strides).copy()


def _estimate_tau_autocorr(x: np.ndarray, max_lag: int = 100) -> int:
    """使用自相关函数第一个过零点估计时间延迟 tau

    Parameters
    ----------
    - `x`: `np.ndarray`, 一维时间序列
    - `max_lag`: `int`, 最大滞后, by default 100

    Returns
    ----------
    - `int`, 估计的 tau 值
    """
    x_centered = x - np.mean(x)
    n = len(x)
    max_lag = min(max_lag, n - 1)

    # 计算自相关（仅正滞后）
    autocorr = np.array(
        [np.sum(x_centered[: n - k] * x_centered[k:]) for k in range(max_lag + 1)]
    )
    if autocorr[0] == 0:
        return 1
    autocorr = autocorr / autocorr[0]

    # 寻找第一个过零点
    for i in range(1, max_lag):
        if autocorr[i] <= 0:
            return i

    # 如果没有过零点，返回自相关下降到 1/e 的位置
    threshold = 1.0 / np.e
    for i in range(1, max_lag):
        if autocorr[i] < threshold:
            return i

    return max_lag
