diff --git a/Cargo.lock b/Cargo.lock index 9d2bfc08a53f8e5dfae5653d332412845e63a20d..db5a54851abd3e7554daeeea89a558b25af1cdf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.16" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "846ffacb9d0c8b879ef9e565b59e18fb76d6a61013e5bd24ecc659864e6b1a1f" +checksum = "5110f1c78cf582855d895ecd0746b653db010cec6d9f5575293f27934d980a39" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -24,17 +24,11 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - [[package]] name = "ahash" -version = "0.8.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e6e951cfbb2db8de1828d49073a113a29fd7117b1596caa781a258c7e38d72" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", "getrandom", @@ -134,7 +128,7 @@ checksum = "1b9e1f5fa78f69496407a27ae9ed989e3c3b072310286f5ef385525e4cbc24a9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -196,18 +190,18 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.48" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" dependencies = [ "cc", ] [[package]] name = "cocoa" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" dependencies = [ "bitflags", "block", @@ -330,9 +324,9 @@ dependencies = [ [[package]] name = "crossfont" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66b1c1979c4362323f03ab6bf7fb522902bfc418e0c37319ab347f9561d980f" +checksum = "21fd3add36ea31aba1520aa5288714dd63be506106753226d0eb387a93bc9c45" dependencies = [ "cocoa", "core-foundation", @@ -378,7 +372,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 1.0.109", ] [[package]] @@ -389,16 +383,7 @@ checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", - "syn", -] - -[[package]] -name = "deflate" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" -dependencies = [ - "adler32", + "syn 1.0.109", ] [[package]] @@ -544,6 +529,25 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -571,13 +575,13 @@ dependencies = [ [[package]] name = "foreign-types-macros" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8469d0d40519bc608ec6863f1cc88f3f1deee15913f2f3b3e573d81ed38cccc" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] @@ -786,9 +790,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.59" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" dependencies = [ "wasm-bindgen", ] @@ -807,9 +811,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.132" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "libloading" @@ -863,9 +867,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" -version = "0.5.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] @@ -887,11 +891,12 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", + "simd-adler32", ] [[package]] @@ -980,7 +985,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1060,7 +1065,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1109,9 +1114,9 @@ dependencies = [ [[package]] name = "owned_ttf_parser" -version = "0.15.1" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ef1a404ae479dd6906f4fa2c88b3c94028f1284beb42a47c183a7c27ee9a3e" +checksum = "706de7e2214113d63a8238d1910463cfce781129a6f263d13fdb09ff64355ba4" dependencies = [ "ttf-parser", ] @@ -1159,13 +1164,14 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "png" -version = "0.17.5" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba" +checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa" dependencies = [ "bitflags", "crc32fast", - "deflate", + "fdeflate", + "flate2", "miniz_oxide", ] @@ -1182,18 +1188,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -1257,9 +1263,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sctk-adwaita" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04b7c47a572f73de28bee5b5060d085b42b6ce1e4ee2b49c956ea7b25e94b6f0" +checksum = "61270629cc6b4d77ec1907db1033d5c2e1a404c412743621981a871dc9c12339" dependencies = [ "crossfont", "log", @@ -1281,7 +1287,7 @@ checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1324,6 +1330,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" + [[package]] name = "slotmap" version = "1.0.6" @@ -1382,9 +1394,20 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.99" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -1393,22 +1416,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.32" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.32" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] @@ -1471,9 +1494,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.36" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", @@ -1483,20 +1506,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "tracing-core" -version = "0.1.29" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -1540,9 +1563,9 @@ dependencies = [ [[package]] name = "ttf-parser" -version = "0.15.2" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" +checksum = "44dcf002ae3b32cd25400d6df128c5babec3927cd1eb7ce813cfff20eb6c3746" [[package]] name = "unicode-bidi" @@ -1614,9 +1637,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.82" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1624,16 +1647,16 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.82" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-shared", ] @@ -1651,9 +1674,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.82" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1661,33 +1684,33 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.82" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.82" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "wayland-client" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f" +checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" dependencies = [ "bitflags", "downcast-rs", "libc", - "nix 0.22.3", + "nix 0.24.2", "scoped-tls", "wayland-commons", "wayland-scanner", @@ -1696,11 +1719,11 @@ dependencies = [ [[package]] name = "wayland-commons" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e" +checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" dependencies = [ - "nix 0.22.3", + "nix 0.24.2", "once_cell", "smallvec", "wayland-sys", @@ -1719,9 +1742,9 @@ dependencies = [ [[package]] name = "wayland-egl" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83281d69ee162b59031c666385e93bde4039ec553b90c4191cdb128ceea29a3a" +checksum = "402de949f81a012926d821a2d659f930694257e76dd92b6e0042ceb27be4107d" dependencies = [ "wayland-client", "wayland-sys", @@ -1729,9 +1752,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741" +checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" dependencies = [ "bitflags", "wayland-client", @@ -1741,9 +1764,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0" +checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" dependencies = [ "proc-macro2", "quote", @@ -1752,9 +1775,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4" +checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" dependencies = [ "dlib", "lazy_static", @@ -1763,9 +1786,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.59" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" dependencies = [ "js-sys", "wasm-bindgen", @@ -1876,9 +1899,9 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "winit" -version = "0.27.2" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a8f3e9d742401efcfe833b8f84960397482ff049cb7bf59a112e14a4be97f7" +checksum = "bb796d6fbd86b2fd896c9471e6f04d39d750076ebe5680a3958f00f5ab97657c" dependencies = [ "bitflags", "cocoa", diff --git a/LICENSE b/LICENSE index 1dfd17fa0f0137452521ba4b8d9c081046f8bd40..24d743f1b46865eb7608bd89860ee24741ea930e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,6 @@ MIT License +Copyright (c) 2023 Albin Heimerson Copyright (c) 2022 Martin Morin Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/index.html b/index.html index f43944cb485915e4f14edb2f1ef86c6971be3a6e..8efa824eae12de828fd92ef4ad4a255de45c690c 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ <head> <!-- change this to your project name --> - <title>Control Web Applications</title> + <title>Control Applications</title> <!-- config for our rust wasm binary. go to https://trunkrs.dev/assets/#rust for more customization --> <link data-trunk rel="rust" data-wasm-opt="2" /> diff --git a/src/lib.rs b/src/lib.rs index 4cca943a85d85bafcc8c4d5395a728f787213cb5..4ec9fe450c45770aa79bcddb1621daca777541ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,12 +20,17 @@ trait CentralApp { impl eframe::App for ControlApp { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + // Set light theme so we don't have to mess with colors for plots + ctx.set_visuals(egui::Visuals::light()); + + /* Skip draw top panel egui::TopBottomPanel::top("app_selection_panel").show(ctx, |ui| { if self.top_bar(ui) { #[cfg(not(target_arch = "wasm32"))] // no quit on web pages! _frame.close(); } }); + */ egui::CentralPanel::default().show(ctx, |ui| { ui.centered_and_justified(|ui| { @@ -115,9 +120,11 @@ mod pole_position_app { use super::tf_plots; #[derive(PartialEq, Debug, Clone, Copy)] - enum Order { - First, - Second, + enum Systems { + FirstOrder, + RealSecondOrder, + RealSecondOrderAndZero, + ComplexSecondOrder, } #[derive(PartialEq, Debug, Clone, Copy)] @@ -130,11 +137,13 @@ mod pole_position_app { pub struct PolePos { label: String, - order: Order, + systype: Systems, display: Display, - fo: FirstOrderSystem, - so: SecondOrderSystem, + first: FirstOrderSystem, + second: RealSecondOrderSystem, + second_zero: RealSecondOrderSystemAndZero, + complex: ComplexSecondOrderSystem, pole_drag_offset: Option<(f64, f64)>, } @@ -143,28 +152,50 @@ mod pole_position_app { pub fn new(label: String) -> PolePos { PolePos { label, - order: Order::First, + systype: Systems::FirstOrder, 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}, + first: 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, + }, + second: RealSecondOrderSystem { + T1: 1.0, T2: 2.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, + }, + second_zero: RealSecondOrderSystemAndZero { + T1: 0.5, T2: 0.75, T_lower: 0.1, T_upper: 500.0, + Tz: 1.0, Tz_lower: -10.0, Tz_upper: 10.0, + K: 1.0, K_lower: -2.0, K_upper: 2.0, + L: 0.0, L_lower: 0.0, L_upper: 5.0, + }, + complex: ComplexSecondOrderSystem { + d: 0.7, d_lower: 0.01, d_upper: 1.0, + w: 1.0, w_lower: 0.01, w_upper: 10.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, } } fn pole_plot(&mut self, ui: &mut Ui, width: f32, height: f32) { - let (dragged, pointer_coordinate) = match self.order { - Order::First => - tf_plots::pole_plot(&self.fo, ui, width, height), - Order::Second => - tf_plots::pole_plot(&self.so, ui, width, height), + let (dragged, pointer_coordinate) = match self.systype { + Systems::FirstOrder => tf_plots::pole_plot(&self.first, ui, width, height), + Systems::RealSecondOrder => tf_plots::pole_plot(&self.second, ui, width, height), + Systems::RealSecondOrderAndZero => tf_plots::pole_plot(&self.second_zero, ui, width, height), + Systems::ComplexSecondOrder => tf_plots::pole_plot(&self.complex, ui, width, height), }; // Handle dragging if dragged { if let Some((re,im)) = pointer_coordinate { // This should never fail - match self.order { - Order::First => self.fo.adjust_poles_to(re, im), - Order::Second => self.so.adjust_poles_to(re, im), + match self.systype { + Systems::FirstOrder => self.first.adjust_pole_zero(re, im), + Systems::RealSecondOrder => self.second.adjust_pole_zero(re, im), + Systems::RealSecondOrderAndZero => self.second_zero.adjust_pole_zero(re, im), + Systems::ComplexSecondOrder => self.complex.adjust_pole_zero(re, im), }; } } else { @@ -173,27 +204,38 @@ mod pole_position_app { } fn step_response_plot(&mut self, ui: &mut Ui, width: f32, height: f32) { - let (_dragged, _pointer_coordinate) = match self.order { - Order::First => - tf_plots::step_response_plot(&self.fo, ui, width, height), - Order::Second => - tf_plots::step_response_plot(&self.so, ui, width, height), + let (_dragged, _pointer_coordinate) = match self.systype { + Systems::FirstOrder => tf_plots::step_response_plot(&self.first, ui, width, height), + Systems::RealSecondOrder => tf_plots::step_response_plot(&self.second, ui, width, height), + Systems::RealSecondOrderAndZero => tf_plots::step_response_plot(&self.second_zero, ui, width, height), + Systems::ComplexSecondOrder => tf_plots::step_response_plot(&self.complex, ui, width, height), }; } fn bode_plot(&mut self, ui: &mut Ui, width: f32, height: f32) { - let (_amp_dragged, _amp_pointer, _ph_dragged, _ph_pointer) = match self.order { - Order::First => tf_plots::bode_plot(&self.fo, ui, width, height), - Order::Second => tf_plots::bode_plot(&self.so, ui, width, height), + let (_amp_dragged, _amp_pointer, _ph_dragged, _ph_pointer) = match self.systype { + Systems::FirstOrder => tf_plots::bode_plot(&self.first, ui, width, height), + Systems::RealSecondOrder => tf_plots::bode_plot(&self.second, ui, width, height), + Systems::RealSecondOrderAndZero => tf_plots::bode_plot(&self.second_zero, ui, width, height), + Systems::ComplexSecondOrder => tf_plots::bode_plot(&self.complex, ui, width, height), }; } fn order_selection(&mut self, ui: &mut Ui) { - ui.heading("Select System Order"); - ui.horizontal(|ui| { - ui.radio_value(&mut self.order, Order::First, "First order"); - ui.radio_value(&mut self.order, Order::Second, "Second order"); - }); + egui::ComboBox::from_label("System type") + .selected_text(match self.systype { + Systems::FirstOrder => "First order", + Systems::RealSecondOrder => "Second order", + Systems::RealSecondOrderAndZero => "Second order with zero", + Systems::ComplexSecondOrder => "Second order complex", + }) + .show_ui(ui, |ui| { + ui.selectable_value(&mut self.systype, Systems::FirstOrder, "First order"); + ui.selectable_value(&mut self.systype, Systems::RealSecondOrder, "Second order"); + ui.selectable_value(&mut self.systype, Systems::RealSecondOrderAndZero, "Second order with zero"); + ui.selectable_value(&mut self.systype, Systems::ComplexSecondOrder, "Second order complex"); + } + ); } fn display_selection(&mut self, ui: &mut Ui) { @@ -205,19 +247,34 @@ 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), - ); + match self.systype { + Systems::FirstOrder => { + ui.heading("G(s) = K * exp(-Ls) / (s*T + 1)"); + ui.add(egui::Slider::new(&mut self.first.T, self.first.T_lower..=self.first.T_upper).text("T").logarithmic(true)); + ui.add(egui::Slider::new(&mut self.first.K, self.first.K_lower..=self.first.K_upper).text("K")); + ui.add(egui::Slider::new(&mut self.first.L, self.first.L_lower..=self.first.L_upper).text("L")); } - Order::Second => { - ui.heading("G(s) = ω^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("ω")); + Systems::RealSecondOrder => { + ui.heading("G(s) = K * exp(-Ls) / ((s*T1 + 1) * (s*T2 + 1))"); + ui.add(egui::Slider::new(&mut self.second.T1, self.second.T_lower..=self.second.T_upper).text("T1").logarithmic(true)); + ui.add(egui::Slider::new(&mut self.second.T2, self.second.T_lower..=self.second.T_upper).text("T2").logarithmic(true)); + ui.add(egui::Slider::new(&mut self.second.K, self.second.K_lower..=self.second.K_upper).text("K")); + ui.add(egui::Slider::new(&mut self.second.L, self.second.L_lower..=self.second.L_upper).text("L")); + } + Systems::RealSecondOrderAndZero => { + ui.heading("G(s) = K * exp(-Ls) * (s*Tz-1) / ((s*T1 + 1) * (s*T2 + 1))"); + ui.add(egui::Slider::new(&mut self.second_zero.T1, self.second_zero.T_lower..=self.second_zero.T_upper).text("T1").logarithmic(true)); + ui.add(egui::Slider::new(&mut self.second_zero.T2, self.second_zero.T_lower..=self.second_zero.T_upper).text("T2").logarithmic(true)); + ui.add(egui::Slider::new(&mut self.second_zero.Tz, self.second_zero.Tz_lower..=self.second_zero.Tz_upper).text("Tz")); + ui.add(egui::Slider::new(&mut self.second_zero.K, self.second_zero.K_lower..=self.second_zero.K_upper).text("K")); + ui.add(egui::Slider::new(&mut self.second_zero.L, self.second_zero.L_lower..=self.second_zero.L_upper).text("L")); + } + Systems::ComplexSecondOrder => { + ui.heading("G(s) = K * exp(-Ls) * ω^2 / (s^2 + 2δωs + ω^2)"); + ui.add(egui::Slider::new(&mut self.complex.d, self.complex.d_lower..=self.complex.d_upper).text("δ")); + ui.add(egui::Slider::new(&mut self.complex.w, self.complex.w_lower..=self.complex.w_upper).text("ω")); + ui.add(egui::Slider::new(&mut self.complex.K, self.complex.K_lower..=self.complex.K_upper).text("K")); + ui.add(egui::Slider::new(&mut self.complex.L, self.complex.L_lower..=self.complex.L_upper).text("L")); } }; } @@ -333,7 +390,7 @@ mod tf_plots { let mut plot = Plot::new(title) .allow_scroll(false) - .allow_zoom(false) + .allow_zoom(true) .allow_boxed_zoom(false) .allow_drag(false) .show_x(false) @@ -369,18 +426,13 @@ mod tf_plots { ) -> (bool, Option<(f64, f64)>) { // Plot params - let cross_radius = 10.0; + let marker_radius = 10.0; let re_bounds = -3.55..1.1; let im_bounds = -1.5..1.5; // Plot points - let points = tf.poles(); - let data = Points::new(points); - let unit_circle = Line::new(PlotPoints::from_parametric_callback( - |t| (t.sin(), t.cos()), - 0.0..(2.0 * PI), - 100, - )); + let pole_data = Points::new(tf.poles()); + let zero_data = Points::new(tf.zeros()); // Plot plot_show( @@ -392,11 +444,16 @@ mod tf_plots { im_bounds, |plot| plot.data_aspect(1.0), |plot_ui| { - plot_ui.line(unit_circle.color(Color32::GRAY)); plot_ui.points( - data.shape(MarkerShape::Cross) + pole_data.shape(MarkerShape::Cross) + .color(Color32::BLACK) + .radius(marker_radius), + ); + plot_ui.points( + zero_data.shape(MarkerShape::Circle) .color(Color32::BLACK) - .radius(cross_radius), + .radius(marker_radius) + .filled(false), ); }, ) @@ -416,7 +473,7 @@ mod tf_plots { // Calculate plot bounds let t_bounds = (0.0 - t_end * pad_ratio)..(t_end + t_end * pad_ratio); - let y_bounds = (0.0 - pad_ratio)..(1.5 + pad_ratio); + let y_bounds = (-0.5 - pad_ratio)..(1.5 + pad_ratio); // Calc plot data let step = (t_bounds.end - t_bounds.start) / ((n_samples - 1) as f64); diff --git a/src/main.rs b/src/main.rs index 66d23a8afac7de70f0eb7820f132179d1a710eb0..6af0a27c333b35a6bdbeb422596a242f0a10e63f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ fn main() { let native_options = eframe::NativeOptions::default(); eframe::run_native( - "eframe template", + "Control Applications", native_options, // Box::new(|cc| Box::new(control_web_apps::TemplateApp::new(cc))), Box::new(|cc| Box::new(control_web_apps::ControlApp::new(cc))), diff --git a/src/transfer_functions.rs b/src/transfer_functions.rs index 4cf45f9bc254d09a73d5e3f715a5c1db9fc86d58..091630c4e32d880e180359c2d2ffff33a4ec070a 100644 --- a/src/transfer_functions.rs +++ b/src/transfer_functions.rs @@ -5,17 +5,24 @@ pub trait TransferFunction { fn bode_amplitude(&self, w: f64) -> f64; fn bode_phase(&self, w: f64) -> f64; fn poles(&self) -> Vec<[f64; 2]>; - fn adjust_poles_to(&mut self, re: f64, im: f64); + fn zeros(&self) -> Vec<[f64; 2]> { vec![] } + fn adjust_pole_zero(&mut self, re: f64, im: f64); } #[derive(Debug, Clone, Copy)] pub struct FirstOrderSystem { - // first order system 1/(sT + 1) + // first order system exp(-sL)*K/(sT + 1) // 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 +31,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,14 +40,14 @@ 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) { + fn adjust_pole_zero(&mut self, re: f64, _im: f64) { let pole_bound = -1.0/self.T_upper; if re >= pole_bound { @@ -53,19 +61,148 @@ impl TransferFunction for FirstOrderSystem { #[derive(Debug, Clone, Copy)] -pub struct SecondOrderSystem { - // second order system w^2/(s^2 + 2dw s + w^2) +pub struct RealSecondOrderSystem { + // double first order system K * exp(-sL) * / ((sT1+1)*(sT2+1)) + // poles = -1/T_1, -1/T_2 + // https://www.tutorialspoint.com/control_systems/control_systems_response_first_order.htm + pub T1: f64, + pub T2: 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 RealSecondOrderSystem { + fn poles(&self) -> Vec<[f64; 2]> { + vec![[-1.0 / self.T1, 0.0], [-1.0 / self.T2, 0.0]] + } + + fn step_response(&self, t: f64) -> f64 { + let t = t - self.L; + self.K * if t >= 0.0 { + 1.0 - (-self.T1 * (-t / self.T1).exp() + self.T2 * (-t / self.T2).exp()) / (self.T2 - self.T1) + } else { + 0.0 + } + } + + fn bode_amplitude(&self, w: f64) -> f64 { + self.K.abs() / (((w * self.T1).powi(2) + 1.0).sqrt() * ((w * self.T2).powi(2) + 1.0).sqrt()) + } + + fn bode_phase(&self, w: f64) -> f64 { + -self.L * w - (w * self.T1).atan() - (w * self.T2).atan() + } + + fn adjust_pole_zero(&mut self, re: f64, _im: f64) { + let pole_bound = -1.0/self.T_upper; + let x1 = -1.0/self.T1; + let x2 = -1.0/self.T2; + + let target = if re >= pole_bound { + -1.0 / pole_bound + } else { + -1.0 / re + }; + if (re - x1).abs() < (re - x2).abs() { + self.T1 = target; + } else { + self.T2 = target; + } + } +} + + +#[derive(Debug, Clone, Copy)] +pub struct RealSecondOrderSystemAndZero { + // second order system exp(-sL) * K * (sT + 1) * w^2/(s^2 + 2dw s + w^2) + // poles = -dw +- w sqrt(d^2 - 1) + // https://www.tutorialspoint.com/control_systems/control_systems_response_second_order.htm + pub T1: f64, + pub T2: f64, + pub Tz: f64, + pub K: f64, + pub L: f64, + pub T_lower: f64, + pub T_upper: f64, + pub Tz_lower: f64, + pub Tz_upper: f64, + pub K_lower: f64, + pub K_upper: f64, + pub L_lower: f64, + pub L_upper: f64, +} + +impl TransferFunction for RealSecondOrderSystemAndZero { + fn poles(&self) -> Vec<[f64; 2]> { + vec![[-1.0 / self.T1, 0.0], [-1.0 / self.T2, 0.0]] + } + + fn zeros(&self) -> Vec<[f64; 2]> { + vec![[-1.0 / self.Tz, 0.0]] + } + + fn step_response(&self, t: f64) -> f64 { + let t = t - self.L; + let (T1, T2, Tz) = (self.T1, self.T2, self.Tz); + self.K * if t >= 0.0 { + 1.0 - ((Tz - T1) * (-t / T1).exp() + (T2 - Tz) * (-t / T2).exp()) / (T2 - T1) + } else { + 0.0 + } + } + + fn bode_amplitude(&self, w: f64) -> f64 { + self.K.abs() * ((w * self.Tz).powi(2) + 1.0).sqrt() / (((w * self.T1).powi(2) + 1.0).sqrt() * ((w * self.T2).powi(2) + 1.0).sqrt()) + } + + fn bode_phase(&self, w: f64) -> f64 { + -self.L * w + (w * self.Tz).atan() - (w * self.T1).atan() - (w * self.T2).atan() + } + + fn adjust_pole_zero(&mut self, re: f64, _im: f64) { + let x1 = -1.0/self.T1; + let x2 = -1.0/self.T2; + let xz = -1.0/self.Tz; + + if (re - xz).abs() < (re - x1).abs() && (re - xz).abs() < (re - x2).abs() { + self.Tz = -1.0 / re + } else if (re - x1).abs() < (re - x2).abs() { + self.T1 = if self.T_upper * re >= -1.0 { self.T_upper } else { -1.0 / re } + } else { + self.T2 = if self.T_upper * re >= -1.0 { self.T_upper } else { -1.0 / re } + } + } +} + + + + +#[derive(Debug, Clone, Copy)] +pub struct ComplexSecondOrderSystem { + // second order system exp(-sL) * K * w^2/(s^2 + 2dw s + w^2) // poles = -dw +- w sqrt(d^2 - 1) // 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 { +impl TransferFunction for ComplexSecondOrderSystem { fn poles(&self) -> Vec<[f64; 2]> { let (d, w) = (self.d, self.w); @@ -88,12 +225,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,23 +249,27 @@ 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 { - use std::f64::consts::PI; + //use std::f64::consts::PI; - let (d, wp) = (self.d, self.w); + //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 { ph } + */ + + -self.L * w + (-2.0*self.d*self.w*w).atan2(self.w.powi(2) - w.powi(2)) } - fn adjust_poles_to(&mut self, re: f64, im: f64) { + fn adjust_pole_zero(&mut self, re: f64, im: f64) { if re >= 0.0 { return } @@ -135,16 +277,13 @@ impl TransferFunction for SecondOrderSystem { let mut d_new = self.d; let w_new; - if self.d < 1.0 { - // two complex poles + if self.d < 1.0 { // two complex poles let (re2, im2) = (re.powi(2), im.powi(2)); d_new = (re2/(re2+im2)).sqrt(); w_new = -re/d_new; - } else if self.d == 1.0 { + } else if self.d == 1.0 { // real double pole w_new = -re; - // real double pole - } else { - // two real poles + } else { // two real poles let d2 = self.d.powi(2); let fast = -self.d*self.w + self.w*(d2 - 1.0).sqrt(); let slow = -self.d*self.w - self.w*(d2 - 1.0).sqrt(); @@ -162,3 +301,4 @@ impl TransferFunction for SecondOrderSystem { } } } +