Repository navigation
feat(autotune): robustness tab - #57
Merged
Merged
Conversation
Move the existing plots into a "General" tab and add a "Robustness" tab, meant to hold several robustness plots. It starts with a Nyquist plot of the loop gain showing the gain, phase and modulus margins, and the region where the modulus margin is below 0.5 (peak sensitivity above 6 dB).
Build the loop once in a LoopModel, as a two-degree-of-freedom controller u = C_r r - C_y y + sign * disturbance around the plant. The time simulation, the loop gain used for the margins and the upcoming sensitivity plots all derive from the same block diagram instead of separate hand-written formulas that must be kept in sync. No change in behavior: the step and disturbance responses and the margins match the previous implementation to machine precision. The model is covered by unit tests independent of the GUI.
Gain, phase and modulus margins only describe robustness of a stable closed loop; for an unstable one they are still computed and could be read as comfortable. Check the roots of 1 + L and show "unstable closed loop" instead of the margins in the Bode and Nyquist plots.
Plot the gang of four (S, T, PS, CS) next to the Nyquist plot, plus the setpoint-to-control response CSF, which differs from CS because the controller has two degrees of freedom (feedforward, P and D on the feedback). CS shows how the controller, in particular the D gain and filter, amplifies measurement noise into the control signal, PS how well load disturbances are rejected. The peak of |S| is the inverse of the modulus margin and is checked against the same 6dB limit.
Show how the closed-loop poles move in the z-plane when Kp is scaled with I and D fixed. As the PID is in ideal form Kp * (1 + I + D), this is exactly a root locus of the loop gain. The current poles are marked, together with the poles at the stability limit, where Kp reaches the gain margin and the locus leaves the unit circle. A grid of constant damping ratio and natural frequency helps reading the poles in terms of the specifications of a continuous-time design.
The delay margin is the additional loop delay that destabilizes the loop, the minimum of phase margin / crossover frequency over all gain crossovers. It is shown in ms and in samples, the unit of the identified delay, and is required to be at least one sample so that the loop survives the delay being underestimated by one. The balanced disk margin guarantees stability for simultaneous gain and phase variations, unlike the classical margins that each assume the other one is untouched. It is also drawn on the Nyquist plot as the exclusion disk that the loop gain must avoid.
Nyquist on the top left, root locus on the bottom left and the sensitivity functions over the full height on the right, which suits the two square z-plane plots better than a single row and gives the frequency plot the most room. Use matplotlib's constrained layout to keep the space around the plots small while leaving room for the labels. The texts and legends drawn inside the axes are excluded from the layout: otherwise, in a small window, they overflow the axes, the layout makes more room for them, and the axes shrink until the layout collapses. Stack the Nyquist margin lines in a box so that their spacing follows the font size instead of the axes height, which no longer fits five lines in the smaller axes.
Use constrained layout for the general tab as for the robustness tab, instead of the fixed and generous spacing between plots. The plots use more of the window and titles no longer overlap the labels of the plot above in smaller windows.
bresch
force-pushed
the
feat/autotune-robustness-tab
branch
from
October 5, 2026 07:53
4291f11 to
fe06b00
Compare
bresch
force-pushed
the
feat/autotune-robustness-tab
branch
from
October 5, 2026 07:54
fe06b00 to
ebf0e2b
Compare
Some controllers run outside PX4 and keep their gains in AOS settings instead of PX4 parameters. List the numeric AOS settings logged in the aos_settings info message next to the parameters, so a preset can read the flown gains from them.
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.
Adds a Robustness tab next to the existing plots, which move to a General tab. The new tab has three plots, all computed from the identified model and the current gains.
When the closed loop is unstable, all three plots show "unstable closed loop" instead of margins, which are meaningless in that case.
Extended presets with initial gains
Initial gains can be set from parameters. When the reference signal is also set, the identification can provide a closed-loop identification fit quality

Gains can now be tuned in standard/ideal or parallel form

Refactor
The closed loop now lives in a new
loop_model.py, as a two-degree-of-freedom controlleru = C_r r − C_y yaround the plant. The time simulation, the loop gain, the margins and the sensitivities all come from this single block diagram. It reproduces the previous step/disturbance responses and margins to machine precision.Testing
test_loop_model.py(28 tests, no Qt needed). It checks:logs/with no warnings.