Skip to content

Count linearization channels per element of array-valued signals - #87

Merged
baggepinnen merged 2 commits into
masterfrom
fb/array-ap-channels
Nov 2, 2026
Merged

baggepinnen merged 2 commits into
masterfrom
fb/array-ap-channels

Conversation

@baggepinnen

@baggepinnen baggepinnen commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Related to JuliaComputing/DyadControlSystems.jl#837 ("analysis point on array applies to first element only").

Problem

named_ss, named_ss(sys, linfun, outputs) and the get_named_* functions counted one input and one output per entry of inputs and outputs. An analysis point on an array-valued connection, or an array variable, contributes one channel per element to the linearization:

  • For a 2-vector input analysis point, nu = 1 and B has two columns. The condition size(matrices.B, 2) == 2nu then holds, the second column is taken to be the derivative of the first, and causal_simplification eliminates it. The result is a one-input system that contains only the first element, together with a spurious nonzero D.
  • For other sizes, constructing the NamedStateSpace fails with Length of input names must match size(sys,2).

Changes

  • The number of channels of each input and output is determined from the variable that drives it: the analysis point's input variable, obtained through GetInput, or the variable itself.
  • Signal names are expanded to one name per channel, u1, u2, ..., following expand_symbol, so the channels of a signal remain selectable by its name (P[:y, :u]).
  • The input operating point is flattened to one entry per channel.
  • If an expanded channel name coincides with another signal's name, for example an array-valued analysis point x with two elements next to a scalar analysis point x1, an ArgumentError names the coinciding channels and the signals they originate from. Previously this would have failed in the NamedStateSpace constructor with a message that did not mention the expansion.
  • ControlSystemsMTK.signal_channel_names(sys, signals) (not exported) returns the channel names in the order used by named_ss. Downstream packages can use it to get the channel count of each signal from the model instead of inferring it from the channel names. JuliaComputing/DyadControlSystems.jl#840 uses it.

Tests

test/test_ODESystem.jl gains a testset with a 2×2 loop whose connections carry 2-vector analysis points. It checks named_ss with and without allow_input_derivatives, with array-valued and with scalar outputs, and get_named_sensitivity, as well as signal_channel_names and the error for coinciding channel names. The full test suite passes locally (60 passed, 1 broken).

Loop openings at array-valued analysis points of components built directly in MTK additionally require SciML/ModelingToolkit.jl#5349; the tests here do not use them.

Verified end-to-end on a vector-analysis-point variant of the F16 LQG tutorial (LQGAnalysis through DyadControlSystems): the resulting controller agrees with the design obtained with scalar analysis points to a relative difference of 1e-7.


Host: demeter2, session 649523b8-6ed5-4d11-864f-e0f78038c754, working directory ~/.julia/dev/ModelingToolkit/.claude/worktrees/soft-wiggling-wreath (sources edited in a scratch copy and committed through the GitHub API)

🤖 Generated with Claude Code

`named_ss` and the `get_named_*` functions counted one input and one output
per entry of `inputs` and `outputs`. An analysis point on an array-valued
connection, or an array variable, contributes one channel per element to the
linearization. For a 2-vector input analysis point, `nu = 1` and `B` has two
columns, so the second column was taken to be the derivative of the first
and eliminated by `causal_simplification`, leaving only the first element.
For other sizes, constructing the named system failed because the number of
names did not match the number of channels.

The number of channels of each signal is now determined from the variable
that drives it, and the signal names are expanded to one name per channel
(`u1, u2, ...`, following `expand_symbol`), so the channels of a signal
remain selectable by its name. The input operating point is flattened to
one entry per channel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The channels of an array-valued signal `x` with two elements are named
`x1, x2`, which coincides with the name of a scalar analysis point `x1`.
The construction of the named system then failed with a message that did
not mention the expansion of the names. `channel_names` now throws an
`ArgumentError` that names the coinciding channels and the signals they
originate from.

`signal_channel_names(sys, signals)` returns the channel names of the given
signals in the order used by `named_ss`, so that downstream packages can
obtain the number of channels of each signal from the model instead of
inferring it from the channel names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JGy8Yc1fbiPz1oWS7rSYMx
@baggepinnen
baggepinnen merged commit a126978 into master Nov 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant