Source code for nstat.decoding._suite

"""High-level :class:`DecoderSuite` API (moved from ``nstat/decoding.py``).

The PPLFP subpackage layout (``nstat/decoding/``) shadowed the original
flat ``nstat/decoding.py`` module, so its contents now live here and are
re-exported from :mod:`nstat.decoding` for backwards compatibility.
"""
from __future__ import annotations

import numpy as np

from ..decoding_algorithms import DecodingAlgorithms


[docs] class DecoderSuite: """Canonical decoding API for the Python nSTAT package."""
[docs] @staticmethod def linear(spike_counts: np.ndarray, stimulus: np.ndarray) -> dict[str, np.ndarray]: return DecodingAlgorithms.linear_decode(spike_counts, stimulus)
[docs] @staticmethod def kalman( observations: np.ndarray, transition: np.ndarray, observation_matrix: np.ndarray, q_cov: np.ndarray, r_cov: np.ndarray, x0: np.ndarray, p0: np.ndarray, ) -> dict[str, np.ndarray]: """Basic linear Kalman filter used for standalone decoding workflows.""" y = np.asarray(observations, dtype=float) a = np.asarray(transition, dtype=float) h = np.asarray(observation_matrix, dtype=float) q = np.asarray(q_cov, dtype=float) r = np.asarray(r_cov, dtype=float) x_prev = np.asarray(x0, dtype=float).reshape(-1) p_prev = np.asarray(p0, dtype=float) n_t = y.shape[0] n_x = x_prev.shape[0] xs = np.zeros((n_t, n_x), dtype=float) ps = np.zeros((n_t, n_x, n_x), dtype=float) for t in range(n_t): x_pred = a @ x_prev p_pred = a @ p_prev @ a.T + q innovation = y[t] - h @ x_pred s_cov = h @ p_pred @ h.T + r k_gain = p_pred @ h.T @ np.linalg.pinv(s_cov) x_post = x_pred + k_gain @ innovation p_post = (np.eye(n_x) - k_gain @ h) @ p_pred xs[t] = x_post ps[t] = p_post x_prev = x_post p_prev = p_post return {"state": xs, "cov": ps}
__all__ = ["DecoderSuite"]