Clean up extended_controller: canonical 2-DOF, direct kwarg, validation#140
Merged
Conversation
…ation - Delete the unverified single-argument `extended_controller(K)` overload — it had no callers anywhere and only logged `@error` when invoked. - Make `extended_controller(P, L, K)` produce the canonical 2-DOF observer controller. With the old `B1 = 0`, the observer estimate `x̂` was biased when `xᵣ ≠ 0`; the new `B1 = (B − KD)·L` lets the reference enter the observer dynamics so `x̂` tracks `x`. For integrator-containing plants (e.g. the cartpole test), this also makes the closed-loop reference-to- output DC gain identity, so the manually-tuned `dc_gain_compensation` prefilter in `test_lqg.jl` is no longer needed; the related tests now assert `dcgain ≈ 1` directly. - Add a `direct::Bool=false` kwarg that mirrors `observer_controller`'s current-time-correction option for discrete plants. In direct mode the reference path remains feedforward-only (no canonical 2-DOF B1); the docstring records this. - Validate `size(L)` and `size(K)` at entry with a clean `ArgumentError`. - Drop the stale `# should be D21?` self-questioning comment and the misplaced `# l.D21 does not appear here, see comment in kalman` line (the latter only applied to the `LQGProblem` path). - Add a comment near the `feedback` call in the `z`-branch recording the default `pos_feedback=false` convention and the meaning of the `U2` slice. - New tests: discrete-time round-trip (Method 7), `direct=true` round-trip (Method 8), and dimension validation. - Docs: append a "2-DOF tracking with extended_controller" section to `docs/src/lqg_disturbance.md` demonstrating the controller and the DC-gain pre-compensation via `extended_controller(..., z=[...])`. DyadControlSystems was audited and has no `extended_controller` callers, so this is safe to ship without a deprecation path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #140 +/- ##
==========================================
+ Coverage 90.96% 91.55% +0.59%
==========================================
Files 20 20
Lines 3055 3056 +1
==========================================
+ Hits 2779 2798 +19
+ Misses 276 258 -18
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to the
extended_controllerreview. Five things land in one PR; tests stay green (1378 pass / 6 broken pre-existing / 0 fail).B1 = 0, meaning the observer estimatex̂was biased whenxᵣ ≠ 0and a manually-tuned reference pre-filter was required for any kind of DC tracking. With the change,B1 = (B − KD)·L— the reference enters the observer dynamics sox̂correctly tracksx. For integrator-containing plants (e.g. the cartpole test) this also makes the closed-loop reference-to-output DC gain exactly1, so the previously-neededdc_gain_compensationprefilter is no longer needed and the related tests now assertdcgain ≈ 1directly.extended_controller(K::AbstractStateSpace)overload. No callers anywhere; it only logged@error("This has not been verified")on invocation.direct::Bool=falsekwarg mirroringobserver_controller's current-time-correction option for discrete plants. The y-channel matchesobserver_controller(...; direct=true)matrix-for-matrix (sosystem_mapping(Ce) == -observer_controller(...; direct=true)). The reference path indirectmode is feedforward-only — the canonical 2-DOFB1formulation gets awkward in the direct/current-time observer form; the docstring records this caveat.size(L)andsize(K)are now checked at entry with a cleanArgumentError.# should be D21?self-questioning comment, the misplaced# l.D21 does not appear here, see comment in kalmanline, and add a comment near thez-branchfeedbackcall recording the defaultpos_feedback=falseconvention and the meaning of theU2slice.DyadControlSystemswas audited and has noextended_controllercallers, so this is safe to ship without a deprecation shim.Docs
docs/src/lqg_disturbance.mdgets a new "2-DOF tracking withextended_controller" section demonstrating the controller and how to use thezsecond return value for DC-gain pre-compensation when the plant has no free integrator.Test plan
Pkg.test()): 1378 pass / 6 broken (pre-existing) / 0 fail / 0 error.test/test_lqg.jl:system_mapping(Ce) == -observer_controller(l_d).direct = trueround-trip: same equality withdirect = true.L/KraisesArgumentError.cd docs && julia --project make.jl— clean build; the new LQG_DIST@exampleblock evaluates and produces a step response that settles on1.🤖 Generated with Claude Code