Source code for canari.component.bounded_autoregression_component

from typing import Optional
import numpy as np
from canari.component.base_component import BaseComponent


[docs] class BoundedAutoregression(BaseComponent): """ `BoundedAutoregression` class, inheriting from Canari's `BaseComponent`. It models residuals following a univariate AR(1) process with optional constrains defined by a coefficient (gamma), which scales the standard deviation of the stationary AR. Parameters: std_error ([float]): Known standard deviation of the process noise. phi ([float]): Known autoregressive coefficient. gamma (Optional[float]): Coefficient to scale the standard deviation of the stationary AR. If none, no constraint is applied. mu_states (Optional[list[float]]): Initial mean of the hidden state. Defaults: initialized to zeros. var_states (Optional[list[float]]): Initial variance of the hidden state. Defaults: initialized to zeros. Behavior: - Adds 1 extra state, i.e. `X^{BAR}`, if gamma is provided. Otherwise no constraint is applied. References: Xin, Z. and Goulet, J.-A. (2024). `Enhancing structural anomaly detection using a bounded autoregressive component <https://www.sciencedirect.com/science/article/pii/S0888327024001778>`_. Mechanical Systems and Signal Processing. Volume 212, pp.111279. Examples: >>> from canari.component import BoundedAutoregression >>> # with gamma >>> bar = BoundedAutoregression(std_error=1, phi=0.75, gamma=0.5) >>> # without gamma >>> bar_1 = BoundedAutoregression(std_error=1, phi=0.75) """ def __init__( self, std_error: float, phi: float, gamma: Optional[float] = None, mu_states: Optional[list[float]] = None, var_states: Optional[list[float]] = None, ): self.std_error = std_error self.phi = phi self.gamma = gamma self._mu_states = mu_states self._var_states = var_states super().__init__()
[docs] def initialize_component_name(self): self._component_name = "bounded autoregression"
[docs] def initialize_num_states(self): self._num_states = 2 if self.gamma is None: self._num_states = 1
[docs] def initialize_states_name(self): self._states_name = ["autoregression", "bounded autoregression"] if self.gamma is None: self._states_name = ["autoregression"]
[docs] def initialize_transition_matrix(self): self._transition_matrix = np.array([[0, self.phi], [0, 0]]) if self.gamma is None: self._transition_matrix = np.array([[self.phi]])
[docs] def initialize_observation_matrix(self): self._observation_matrix = np.array([[1, 0]]) if self.gamma is None: self._observation_matrix = np.array([[1]])
[docs] def initialize_process_noise_matrix(self): self._process_noise_matrix = np.array([[self.std_error**2, 0], [0, 0]]) if self.gamma is None: self._process_noise_matrix = np.array([[self.std_error**2]])
[docs] def initialize_mu_states(self): if self._mu_states is None: self._mu_states = np.zeros((self._num_states, 1)) elif len(self._mu_states) == self._num_states: self._mu_states = np.atleast_2d(self._mu_states).T else: raise ValueError( "Incorrect mu_states dimension for the autoregression component." )
[docs] def initialize_var_states(self): if self._var_states is None: self._var_states = np.zeros((self._num_states, 1)) elif len(self._var_states) == self._num_states: self._var_states = np.atleast_2d(self._var_states).T else: raise ValueError( "Incorrect var_states dimension for the autoregression component." )