"""Pythonic aliases for the MATLAB-style :class:`~nstat.core.SignalObj`.
The canonical signal abstractions live in :mod:`nstat.core` and follow
the MATLAB ``SignalObj``/``Covariate`` API (1-based indexing,
``getSigInTimeWindow``, ``copySignal``, etc.). This module exposes
thin subclasses with Pythonic shortcuts:
- :class:`Signal` — :class:`~nstat.core.SignalObj` plus ``copy()``,
``sub_signal(i)`` (0-based), ``window(start, stop)``, and
``as_array()``.
- :class:`Covariate` — :class:`~nstat.core.Covariate` with the same
conveniences inherited from :class:`Signal`.
No MATLAB counterpart — this is a Python-only convenience layer for code
that prefers idiomatic Python over MATLAB conventions. All time values
are in **seconds**.
"""
from __future__ import annotations
from typing import Sequence
import numpy as np
from .core import Covariate as _LegacyCovariate
from .core import SignalObj as _LegacySignalObj
[docs]
class Signal(_LegacySignalObj):
"""Canonical Pythonic signal abstraction for nSTAT."""
[docs]
def copy(self) -> "Signal":
copied = self.copySignal()
return Signal(
copied.time,
copied.data,
copied.name,
copied.xlabelval,
copied.xunits,
copied.yunits,
copied.dataLabels,
)
[docs]
def sub_signal(self, index: int) -> "Signal":
"""Return one channel as a new signal.
Uses zero-based indexing in Python, unlike MATLAB's one-based indexing.
"""
if index < 0 or index >= self.dimension:
raise IndexError("Signal channel index out of range.")
out = self.getSubSignal(index + 1)
return Signal(
out.time,
out.data,
out.name,
out.xlabelval,
out.xunits,
out.yunits,
out.dataLabels,
)
[docs]
def window(self, start: float, stop: float) -> "Signal":
out = self.getSigInTimeWindow(start, stop)
return Signal(
out.time,
out.data,
out.name,
out.xlabelval,
out.xunits,
out.yunits,
out.dataLabels,
)
[docs]
def as_array(self) -> np.ndarray:
return np.asarray(self.data, dtype=float)
[docs]
class Covariate(_LegacyCovariate):
"""Canonical covariate type for model design matrices."""
[docs]
def standardize(self) -> "Covariate":
data = np.asarray(self.data, dtype=float)
mu = np.mean(data, axis=0, keepdims=True)
sigma = np.std(data, axis=0, keepdims=True)
sigma[sigma == 0.0] = 1.0
z = (data - mu) / sigma
return Covariate(
self.time,
z,
self.name,
self.xlabelval,
self.xunits,
self.yunits,
self.dataLabels,
)
[docs]
@classmethod
def from_values(
cls,
time: Sequence[float],
values: Sequence[float] | Sequence[Sequence[float]] | np.ndarray,
*,
name: str = "covariate",
units: str = "",
) -> "Covariate":
return cls(time=time, values=values, name=name, units=units)