use nalgebra as na;
use crate::model::{ContinuousStateSpaceModel, Discrete, DiscreteStateSpaceModel, StateSpaceModel};
pub fn step_for_discrete_ss(
model: &(impl StateSpaceModel + Discrete),
duration: f64,
) -> (na::DMatrix<f64>, na::DMatrix<f64>, na::DMatrix<f64>) {
let initial_state = na::DVector::<f64>::zeros(model.mat_a().nrows());
let n_samples = (duration / model.sampling_dt()).floor() as usize;
let input = na::DMatrix::from_element(1, n_samples, 1.0f64);
let (response, states) = simulate_ss_response(model, &input, &initial_state);
(response, input, states)
}
pub fn step_for_continuous_ss(
model: &ContinuousStateSpaceModel,
sampling_dt: f64,
duration: f64,
) -> (na::DMatrix<f64>, na::DMatrix<f64>, na::DMatrix<f64>) {
let discrete_model =
DiscreteStateSpaceModel::from_continuous_ss_forward_euler(model, sampling_dt);
let initial_state = na::DVector::<f64>::zeros(model.mat_a().nrows());
let n_samples = (duration / discrete_model.sampling_dt()).floor() as usize;
let input = na::DMatrix::from_element(1, n_samples, 1.0f64);
let (response, states) = simulate_ss_response(&discrete_model, &input, &initial_state);
(response, input, states)
}
fn simulate_ss_response(
model: &(impl StateSpaceModel + Discrete),
mat_u: &na::DMatrix<f64>,
x0: &na::DVector<f64>,
) -> (na::DMatrix<f64>, na::DMatrix<f64>) {
let sim_time = mat_u.ncols();
let n_state = model.mat_a().nrows();
let n_output = model.mat_c().nrows();
let mut mat_x = na::DMatrix::<f64>::zeros(n_state, sim_time + 1);
let mut mat_y = na::DMatrix::<f64>::zeros(n_output, sim_time);
for i in 0..sim_time {
if i == 0 {
mat_x.column_mut(i).copy_from(&x0);
mat_y.column_mut(i).copy_from(&(model.mat_c() * x0));
mat_x
.column_mut(i + 1)
.copy_from(&(model.mat_a() * x0 + model.mat_b() * mat_u.column(i)));
} else {
mat_y
.column_mut(i)
.copy_from(&(model.mat_c() * mat_x.column(i)));
let mat_x_slice = mat_x.column(i).into_owned();
mat_x
.column_mut(i + 1)
.copy_from(&(model.mat_a() * mat_x_slice + model.mat_b() * mat_u.column(i)));
}
}
(mat_y, mat_x)
}