From 0578c7fe53ff287f5ff0bba9df88380b48b7fc0b Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Mon, 18 May 2026 09:12:29 +0200 Subject: [PATCH 1/2] Docs: rewire LQI load-disturbance example with advanced feedback interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the named-system `feedback(s1, s2; w1, u1, w2, u2, z1, z2, pos_feedback)` interface for the disturbance closed-loop in the LQI section, mirroring the style already used in the model-mismatch section that follows. Listing `:u_plant` in both `w1` and `u1` reuses the plant input as the summing point for the load disturbance — no augmented disturbance port on `G` — and leaving `:y_plant_r` out of both `w2` and `u2` keeps `r = 0` without padding `lsim` inputs. Time response is numerically identical to the previous wiring (verified side-by-side: max |Δ| ≈ 5e-15 over the full trajectory). Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/src/lqg_disturbance.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/src/lqg_disturbance.md b/docs/src/lqg_disturbance.md index 09fb5d11..8f878db4 100644 --- a/docs/src/lqg_disturbance.md +++ b/docs/src/lqg_disturbance.md @@ -136,14 +136,20 @@ obs = observer_predictor(G, K; output_state = true) C = lqi_controller(G, obs, Q1, Q2) # controller with inputs [r; y] and output u ``` -To inject the load disturbance from earlier (a unit step added at the plant input), we close the loop using only the measurement column of `C` and feed the disturbance into the plant input: +To inject the load disturbance from earlier (a unit step added at the plant input), we close the loop with the advanced [`feedback`](@ref) interface on named systems. Two features of that interface keep the wiring direct: +- listing `:u_plant` in both `w1` and `u1` makes the plant's input serve simultaneously as the feedback target driven by `C` and as the external summing point for the load disturbance, so no extra disturbance port has to be added to `G`; +- omitting the reference `:y_plant_r` from both `w2` and `u2` silently grounds it (equivalent to `r = 0`) without exposing it as a closed-loop input, so the original scalar `disturbance` closure can be passed to `lsim` unchanged. ```@example LQG_DIST -Cy = C[:, :y_plant] # feedback channel (r=0) -Kctrl = -Cy # equivalent negative-feedback controller -Gcl_y = feedback(G, Kctrl) # disturbance → y -Gcl_u = -Kctrl * Gcl_y # disturbance → u -Gcl = [Gcl_y; Gcl_u] +G_named = named_ss(G, u = :u_plant, y = :y_plant) +Gcl = feedback(G_named, C; + w1 = :u_plant, # external input: load disturbance at the plant input + u1 = :u_plant, # feedback path drives the same physical input → both sum + z1 = :y_plant, # keep plant output + # w2 = :y_plant_r, # uncomment to also expose the reference as a closed-loop input + u2 = :y_plant, # C feedback input ← plant output + z2 = :y_L, # keep controller output (the control signal u) + pos_feedback = true) # `lqi_controller` already bakes in the negative-feedback sign res = lsim(Gcl, disturbance, 100) @test res.y[:, end] ≈ [0, -1] atol=1e-3 plot(res, ylabel = ["y" "u"]); ylims!((-0.05, 0.3), sp = 1) From 36bc81466bee839265f08841a67fcc6eca703396 Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Mon, 18 May 2026 09:51:53 +0200 Subject: [PATCH 2/2] Update lqg_disturbance.md --- docs/src/lqg_disturbance.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/lqg_disturbance.md b/docs/src/lqg_disturbance.md index 8f878db4..6bede18e 100644 --- a/docs/src/lqg_disturbance.md +++ b/docs/src/lqg_disturbance.md @@ -137,8 +137,8 @@ C = lqi_controller(G, obs, Q1, Q2) # controller with inputs [r; y] and output ``` To inject the load disturbance from earlier (a unit step added at the plant input), we close the loop with the advanced [`feedback`](@ref) interface on named systems. Two features of that interface keep the wiring direct: -- listing `:u_plant` in both `w1` and `u1` makes the plant's input serve simultaneously as the feedback target driven by `C` and as the external summing point for the load disturbance, so no extra disturbance port has to be added to `G`; -- omitting the reference `:y_plant_r` from both `w2` and `u2` silently grounds it (equivalent to `r = 0`) without exposing it as a closed-loop input, so the original scalar `disturbance` closure can be passed to `lsim` unchanged. +- listing `:u_plant` in both `w1` and `u1` makes the plant's input serve simultaneously as the feedback control input from `C` and as the external summing point for the load disturbance, so no extra disturbance port has to be added to `G`; +- omitting the reference `:y_plant_r` from both `w2` and `u2` is equivalent to `r = 0` without exposing it as a closed-loop input, so the original scalar `disturbance` function can be passed to `lsim`. ```@example LQG_DIST G_named = named_ss(G, u = :u_plant, y = :y_plant)