From 0d2dcd6a6e10a512be208c2d7a0de6120b9ee0f7 Mon Sep 17 00:00:00 2001
From: Albin Heimerson <albin.heimerson@control.lth.se>
Date: Tue, 10 Jan 2023 15:01:30 +0100
Subject: [PATCH] Add delay and gain to the TFs

---
 src/lib.rs                | 27 ++++++++++++++++++---------
 src/transfer_functions.rs | 26 ++++++++++++++++++++------
 2 files changed, 38 insertions(+), 15 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 450dedf..caef9aa 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -148,8 +148,17 @@ mod pole_position_app {
                 label,
                 order: Order::First,
                 display: Display::StepResponse,
-                fo: FirstOrderSystem { T: 1.0, T_lower: 0.1, T_upper: 500.0},
-                so: SecondOrderSystem { d: 0.5, w: 0.75, d_lower: 0.01, d_upper: 5.0, w_lower: 0.01, w_upper: 5.0},
+                fo: FirstOrderSystem { 
+                    T: 1.0, T_lower: 0.1, T_upper: 500.0,
+                    K: 1.0, K_lower: -2.0, K_upper: 2.0,
+                    L: 0.0, L_lower: 0.0, L_upper: 5.0,
+                },
+                so: SecondOrderSystem {
+                    d: 0.5, d_lower: 0.01, d_upper: 5.0,
+                    w: 0.75, w_lower: 0.01, w_upper: 5.0,
+                    K: 1.0, K_lower: -2.0, K_upper: 2.0,
+                    L: 0.0, L_lower: 0.0, L_upper: 5.0,
+                },
                 pole_drag_offset: None,
             }
         }
@@ -210,17 +219,17 @@ mod pole_position_app {
         fn parameter_sliders(&mut self, ui: &mut Ui) {
             match self.order {
                 Order::First => {
-                    ui.heading("G(s) = 1/(sT + 1)");
-                    ui.add(
-                        egui::Slider::new(&mut self.fo.T, self.fo.T_lower..=self.fo.T_upper)
-                            .text("T")
-                            .logarithmic(true),
-                    );
+                    ui.heading("G(s) = K * exp(-Ls) / (sT + 1)");
+                    ui.add(egui::Slider::new(&mut self.fo.T, self.fo.T_lower..=self.fo.T_upper).text("T").logarithmic(true));
+                    ui.add(egui::Slider::new(&mut self.fo.K, self.fo.K_lower..=self.fo.K_upper).text("K"));
+                    ui.add(egui::Slider::new(&mut self.fo.L, self.fo.L_lower..=self.fo.L_upper).text("L"));
                 }
                 Order::Second => {
-                    ui.heading("G(s) = ω^2/(s^2 + 2δωs + ω^2)");
+                    ui.heading("G(s) = K * exp(-Ls) * ω^2 / (s^2 + 2δωs + ω^2)");
                     ui.add(egui::Slider::new(&mut self.so.d, self.so.d_lower..=self.so.d_upper).text("δ"));
                     ui.add(egui::Slider::new(&mut self.so.w, self.so.w_lower..=self.so.w_upper).text("ω"));
+                    ui.add(egui::Slider::new(&mut self.so.K, self.so.K_lower..=self.so.K_upper).text("K"));
+                    ui.add(egui::Slider::new(&mut self.so.L, self.so.L_lower..=self.so.L_upper).text("L"));
                 }
             };
         }
diff --git a/src/transfer_functions.rs b/src/transfer_functions.rs
index 4cf45f9..7ee69e8 100644
--- a/src/transfer_functions.rs
+++ b/src/transfer_functions.rs
@@ -14,8 +14,14 @@ pub struct FirstOrderSystem {
     // pole = -1/T
     // https://www.tutorialspoint.com/control_systems/control_systems_response_first_order.htm
     pub T: f64,
+    pub K: f64,
+    pub L: f64,
     pub T_lower: f64,
     pub T_upper: f64,
+    pub K_lower: f64,
+    pub K_upper: f64,
+    pub L_lower: f64,
+    pub L_upper: f64,
 }
 
 impl TransferFunction for FirstOrderSystem {
@@ -24,7 +30,8 @@ impl TransferFunction for FirstOrderSystem {
     }
 
     fn step_response(&self, t: f64) -> f64 {
-        if t >= 0.0 {
+        let t = t - self.L;
+        self.K * if t >= 0.0 {
             1.0 - (-t / self.T).exp()
         } else {
             0.0
@@ -32,11 +39,11 @@ impl TransferFunction for FirstOrderSystem {
     }
 
     fn bode_amplitude(&self, w: f64) -> f64 {
-        1.0 / (((w * self.T).powi(2) + 1.0).sqrt())
+        self.K.abs() / (((w * self.T).powi(2) + 1.0).sqrt())
     }
 
     fn bode_phase(&self, w: f64) -> f64 {
-        -(w * self.T).atan()
+        -self.L * w - (w * self.T).atan()
     }
 
     fn adjust_poles_to(&mut self, re: f64, _im: f64) {
@@ -59,10 +66,16 @@ pub struct SecondOrderSystem {
     // https://www.tutorialspoint.com/control_systems/control_systems_response_second_order.htm
     pub d: f64,
     pub w: f64,
+    pub K: f64,
+    pub L: f64,
     pub d_lower: f64,
     pub d_upper: f64,
     pub w_lower: f64,
     pub w_upper: f64,
+    pub K_lower: f64,
+    pub K_upper: f64,
+    pub L_lower: f64,
+    pub L_upper: f64,
 }
 
 impl TransferFunction for SecondOrderSystem {
@@ -88,12 +101,13 @@ impl TransferFunction for SecondOrderSystem {
 
     fn step_response(&self, t: f64) -> f64 {
         let (d, w) = (self.d, self.w);
+        let t = t - self.L;
 
         if t < 0.0 {
             return 0.0;
         }
 
-        if d == 0.0 {
+        self.K * if d == 0.0 {
             1.0 - (w * t).cos()
         } else if (0.0 < d) && (d < 1.0) {
             let d_1_sqrt = (1.0 - d.powi(2)).sqrt();
@@ -111,7 +125,7 @@ impl TransferFunction for SecondOrderSystem {
     fn bode_amplitude(&self, w: f64) -> f64 {
         let (d, wp) = (self.d, self.w);
 
-        wp.powi(2) / ( ( (wp.powi(2) - w.powi(2)).powi(2) + (2f64*d*wp*w).powi(2) ).sqrt() )
+        self.K.abs() * wp.powi(2) / (((wp.powi(2) - w.powi(2)).powi(2) + (2f64*d*wp*w).powi(2)).sqrt())
     }
 
     fn bode_phase(&self, w: f64) -> f64 {
@@ -119,7 +133,7 @@ impl TransferFunction for SecondOrderSystem {
 
         let (d, wp) = (self.d, self.w);
 
-        let ph = -( (2f64*d*wp*w)/(wp.powi(2) - w.powi(2))  ).atan();
+        let ph = -self.L * w - (2.0*d*wp*w / (wp.powi(2) - w.powi(2))).atan();
         if ph > 0.0 {
             ph - PI
         } else {
-- 
GitLab