NFoursID
NFoursID is a Python library that implements the N4SID algorithm for subspace identification, along with Kalman filtering and state-space models. State-space models are versatile tools for representing multi-dimensional time series, encompassing models like ARMAX. The current version is 1.0.2. The project appears active, with its latest release (1.0.2) showing an unusual future publication date of July 24, 2025, on PyPI.
Warnings
- gotcha The `num_block_rows` parameter in the `NFourSID` constructor significantly impacts both computational complexity and the ability to correctly determine the system order. Choosing it too large increases computation, while choosing it too small may prevent accurate order determination or violate theoretical assumptions.
- gotcha For effective system order determination, it's generally recommended to call `nfoursid_estimator.subspace_identification()` before `nfoursid_estimator.system_identification()` and inspect the eigenvalues using `plot_eigenvalues`. Skipping `subspace_identification` might lead to an incorrect system order if the `rank` parameter is not chosen carefully in `system_identification`.
- gotcha The `nfoursid` library assumes a foundational understanding of subspace identification, Kalman filtering, and state-space models. Users new to these concepts may struggle with model setup, parameter interpretation, and result validation, leading to potential misapplication.
Install
-
pip install nfoursid
Imports
- NFourSID
from nfoursid.nfoursid import NFourSID
- Kalman
from nfoursid.kalman import Kalman
- StateSpace
from nfoursid.state_space import StateSpace
Quickstart
import numpy as np
import pandas as pd
from nfoursid.nfoursid import NFourSID
from nfoursid.state_space import StateSpace
from nfoursid.kalman import Kalman
# 1. Define a state-space model (example parameters)
A = np.array([[0.9, 0.1], [0, 0.9]])
B = np.array([[1], [0]])
C = np.array([[0.5, 0.5]])
D = np.array([[0]])
state_space_true = StateSpace(A, B, C, D)
# 2. Simulate some data
num_datapoints = 100
inputs = np.random.randn(num_datapoints, 1) * 0.1 # Small random inputs
outputs = []
for i in range(num_datapoints):
output_step = state_space_true.step(inputs[i].reshape(-1, 1), noise=np.random.randn(1, 1) * 0.05)
outputs.append(output_step.flatten())
data = pd.DataFrame({
'input_0': inputs.flatten(),
'output_0': np.array(outputs).flatten()
})
# 3. Perform N4SID identification
output_columns = ['output_0']
input_columns = ['input_0']
num_block_rows = 2 # See warnings regarding this parameter
nfoursid_estimator = NFourSID(
dataframe=data,
output_columns=output_columns,
input_columns=input_columns,
num_block_rows=num_block_rows
)
nfoursid_estimator.subspace_identification() # Essential before system_identification for proper order detection
# Determine system order (e.g., from eigenvalue plot, assume 2 for this example)
rank = 2
state_space_identified, covariance_matrix = nfoursid_estimator.system_identification(rank=rank)
print("Identified State-Space A matrix:\n", state_space_identified.a)
print("Identified State-Space C matrix:\n", state_space_identified.c)
# 4. Use a Kalman filter for prediction/estimation
kalman_filter = Kalman(state_space_identified, covariance_matrix)
# Simulate a few steps with the Kalman filter
filtered_outputs = []
for i in range(num_datapoints):
kalman_filter.step(data[output_columns].iloc[i].values.reshape(-1,1),
data[input_columns].iloc[i].values.reshape(-1,1))
filtered_outputs.append(kalman_filter.to_dataframe()['output_0']['filtered'].iloc[-1])
print("First 5 actual outputs:", data['output_0'].head().tolist())
print("First 5 filtered outputs:", filtered_outputs[:5])