use dace::*;
use ndarray_linalg::Scalar;
use std::fs::File;
use std::io::Write;
macro_rules! define_functions {
($t:ty) => {
::paste::paste! {
pub fn [<midpoint_ $t:lower>](
x0: &AlgebraicVector<$t>,
t0: f64,
t1: f64,
f: fn(&AlgebraicVector<$t>, f64) -> AlgebraicVector<$t>,
) -> AlgebraicVector<$t> {
const HMAX: f64 = 0.005;
let steps: f64 = ((t1 - t0) / HMAX).ceil();
let h: f64 = (t1 - t0) / steps;
let mut t: f64 = t0;
let mut x: AlgebraicVector<$t> = x0.to_owned();
let mut xmid: AlgebraicVector<$t>;
for _i in 0..(steps as i32) {
xmid = &x + 0.5 * h * f(&x, t);
x += h * f(&xmid, t + 0.5 * h);
t += h;
}
x
}
fn [<pendulum_rhs_ $t:lower>](x: &AlgebraicVector<$t>, _t: f64) -> AlgebraicVector<$t> {
const L: f64 = 0.61; const M1: f64 = 0.21; const M2: f64 = 0.4926; const G: f64 = 9.81;
let mut res = AlgebraicVector::<$t>::zeros(3);
let (sint, cost) = (&x[0].sin(), &x[0].cos());
res[0] = x[1].clone();
res[1] = (&x[2] + (M1 + M2) * G * sint - M1 * L* x[1].square() * sint * cost)
/ ((M1 + M2) * L + M1 * L * cost.square());
res
}
fn [<rk4_ $t:lower>](
x0: &AlgebraicVector<$t>,
t0: f64,
t1: f64,
f: fn(&AlgebraicVector<$t>, f64) -> AlgebraicVector<$t>,
) -> AlgebraicVector<$t> {
const HMAX: f64 = 0.01;
let steps = ((t1 - t0) / HMAX).ceil();
let h = (t1 - t0) / steps;
let mut t = t0;
let mut x = x0.to_owned();
for _i in 0..(steps as i32) {
let k1 = f(&x, t);
let k2 = f(&(&x + h * &k1 / 3.0), t + h / 3.0);
let k3 = f(&(&x + h * (-&k1 / 3.0 + &k2)), t + 2.0 * h / 3.0);
let k4 = f(&(&x + h * (&k1 - &k2 + &k3)), t + h);
x += h * (k1 + 3.0 * k2 + 3.0 * k3 + k4) / 8.0;
t += h;
}
x
}
}
};
}
define_functions!(DA);
define_functions!(f64);
fn ex7_1_2() {
const KP: f64 = 8.0;
const TI: f64 = 3.0;
const TD: f64 = 0.3;
const SETPT: f64 = 0.0; const DT: f64 = 0.05;
let mut file = File::create("ex7_1_2.dat").unwrap();
let mut int_err = 0.0;
let mut last_err = 0.0;
let mut t = 0.0;
let mut x = darray![0.1, 0.0, 0.0];
while t < 100.0 && x[0].abs() < 1.5 {
let err = SETPT - x[0];
let derr = (err - last_err) / DT;
int_err += last_err * DT;
last_err = err;
x[2] = KP * (err + TD * derr + int_err / TI);
writeln!(&mut file, "{} {} {}", t, x[0], x[2]).unwrap();
x = rk4_f64(&x, t, t + DT, pendulum_rhs_f64);
t += DT;
}
println!("Final angle theta: {}", x);
if x[0].abs() > 1.5 {
println!("WHOOPSY: Fell over after {} seconds.", t);
}
}
fn ex7_1_3() {
const KP: f64 = 8.0;
const TI: f64 = 3.0;
const TD: f64 = 0.3;
const SETPT: f64 = 0.0; const DT: f64 = 0.05;
let mut file = File::create("ex7_1_3.dat").unwrap();
let mut int_err = DA::new();
let mut last_err = DA::new();
let mut t = 0.0;
let mut x = AlgebraicVector::<DA>::zeros(3);
x[0] = 0.1 + 0.1 * da!(1);
while t < 40.0 && x[0].cons().abs() < 1.5 {
let err = SETPT - &x[0];
let derr = (&err - &last_err) / DT;
int_err += &last_err * DT;
last_err = err.clone();
x[2] = KP * (&err + TD * &derr + &int_err / TI);
let bx = x[0].bound();
let bu = x[2].bound();
writeln!(
&mut file,
"{} {} {} {} {} {} {} {} {} {} {}",
t,
x[0].cons(),
bx.m_ub,
bx.m_lb,
x[0].eval(-1.0),
x[0].eval(1.0),
x[2].cons(),
bu.m_ub,
bu.m_lb,
x[2].eval(-1.0),
x[2].eval(1.0)
)
.unwrap();
x = rk4_da(&x, t, t + DT, pendulum_rhs_da);
t += DT;
}
println!("Final angle theta:{}", x);
if x[0].cons().abs() > 1.5 {
println!("WHOOPSY: Fell over after {} seconds.", t);
}
}
fn ex7_1_5() {
let x = da!(1);
let y = da!(2);
let func = (&x / 2.0).sin() / (2.0 + (&y / 2.0 + &x * &x).cos());
let (mut a, b, mut c): (Interval, Interval, Interval);
let mut arg = AlgebraicVector::<f64>::zeros(2);
a = Interval {
m_lb: 9999999.0,
m_ub: -9999999.0,
};
c = a;
for i in -10..10 {
arg[0] = (i as f64) / 10.0;
for j in -10..10 {
arg[1] = (j as f64) / 10.0;
let mut r = func.eval(&arg);
a.m_lb = a.m_lb.min(r);
a.m_ub = a.m_ub.max(r);
r = (&arg[0] / 2.0).sin() / (2.0 + (&arg[1] / 2.0 + &arg[0] * &arg[0]).cos());
c.m_lb = c.m_lb.min(r);
c.m_ub = c.m_ub.max(r);
}
}
b = func.bound();
println!("func:\n{}", func);
println!("Bounds:");
println!("DA bound: [{}, {}]", b.m_lb, b.m_ub);
println!("DA raster: [{}, {}]", a.m_lb, a.m_ub);
println!("double raster: [{}, {}]", c.m_lb, c.m_ub);
}
fn pendulum_rhs_mass(x: &AlgebraicVector<DA>, _t: f64) -> AlgebraicVector<DA> {
const L: f64 = 0.61; let m = 0.21 * (1.0 + 0.1 * da!(1)); const M: f64 = 0.4926; const G: f64 = 9.81;
let mut res = AlgebraicVector::<DA>::zeros(3);
let (sint, cost) = (x[0].sin(), x[0].cos());
res[0] = x[1].clone();
res[1] = (&x[2] + (M + &m) * G * &sint - &m * L * x[1].sqr() * &sint * &cost)
/ ((M + &m) * L + &m * L * cost.sqr());
res
}
fn ex7_2_2() {
const KP: f64 = 8.0;
const TI: f64 = 3.0;
const TD: f64 = 0.3;
const SETPT: f64 = 0.0; const DT: f64 = 0.05;
let mut file = File::create("ex7_2_2.dat").unwrap();
let mut int_err = DA::new();
let mut last_err = DA::new();
let mut t = 0.0;
let mut x: AlgebraicVector<DA> = darray![0.1, 0.0, 0.0].into();
while t < 40.0 && x[0].cons().abs() < 1.5 {
let err = SETPT - &x[0];
let derr = (&err - &last_err) / DT;
int_err += &last_err * DT;
last_err = err.clone();
x[2] = KP * (&err + TD * &derr + &int_err / TI);
let bx = x[0].bound();
let bu = x[2].bound();
writeln!(
&mut file,
"{} {} {} {} {} {} {} {} {} {} {}",
t,
x[0].cons(),
bx.m_ub,
bx.m_lb,
x[0].eval(-1.0),
x[0].eval(1.0),
x[2].cons(),
bu.m_ub,
bu.m_lb,
x[2].eval(-1.0),
x[2].eval(1.0)
)
.unwrap();
x = rk4_da(&x, t, t + DT, pendulum_rhs_mass);
t += DT;
}
println!("Final angle theta:{}", x);
if x[0].cons().abs() > 1.5 {
println!("WHOOPSY: Fell over after {} seconds.", t);
}
}
fn main() {
DA::init(10, 2);
ex7_1_2();
ex7_1_3();
ex7_1_5();
ex7_2_2();
}