Skip to content

Commit e1f0ffd

Browse files
committed
handle systems without states in linearize
1 parent 6236660 commit e1f0ffd

File tree

2 files changed

+39
-7
lines changed

2 files changed

+39
-7
lines changed

src/systems/abstractsystem.jl

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,13 +1027,22 @@ function linearization_function(sys::AbstractSystem, inputs, outputs; simplify =
10271027
lin_fun = let fun = fun,
10281028
h = ModelingToolkit.build_explicit_observed_function(sys, outputs)
10291029

1030-
(u, p, t) -> begin
1031-
uf = SciMLBase.UJacobianWrapper(fun, t, p)
1032-
fg_xz = ForwardDiff.jacobian(uf, u)
1033-
pf = SciMLBase.ParamJacobianWrapper(fun, t, u)
1034-
# TODO: this is very inefficient, p contains all parameters of the system
1035-
fg_u = ForwardDiff.jacobian(pf, p)[:, input_idxs]
1036-
h_xz = ForwardDiff.jacobian(xz -> h(xz, p, t), u)
1030+
function (u, p, t)
1031+
if u !== nothing # Handle systems without states
1032+
length(sts) == length(u) ||
1033+
error("Number of state variables does not match the number of input states")
1034+
uf = SciMLBase.UJacobianWrapper(fun, t, p)
1035+
fg_xz = ForwardDiff.jacobian(uf, u)
1036+
h_xz = ForwardDiff.jacobian(xz -> h(xz, p, t), u)
1037+
pf = SciMLBase.ParamJacobianWrapper(fun, t, u)
1038+
# TODO: this is very inefficient, p contains all parameters of the system
1039+
fg_u = ForwardDiff.jacobian(pf, p)[:, input_idxs]
1040+
else
1041+
length(sts) == 0 ||
1042+
error("Number of state variables does not match the number of input states")
1043+
fg_xz = zeros(0,0)
1044+
h_xz = fg_u = zeros(0, length(inputs))
1045+
end
10371046
h_u = ForwardDiff.jacobian(p -> h(u, p, t), p)[:, input_idxs]
10381047
(f_x = fg_xz[diff_idxs, diff_idxs],
10391048
f_z = fg_xz[diff_idxs, alge_idxs],

test/linearize.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,26 @@ lsys = ModelingToolkit.reorder_states(lsys, states(ssys), reverse(desired_order)
103103
@test lsys.B == [10 -10; 2 -2]
104104
@test lsys.C == [-4000 400]
105105
@test lsys.D == [4400 -4400]
106+
107+
## Test operating points
108+
109+
# The saturation has no dynamics
110+
function saturation(; y_max, y_min=y_max > 0 ? -y_max : -Inf, name)
111+
@variables u(t)=0 y(t)=0
112+
@parameters y_max=y_max y_min=y_min
113+
ie = ModelingToolkit.IfElse.ifelse
114+
eqs = [
115+
# The equation below is equivalent to y ~ clamp(u, y_min, y_max)
116+
y ~ ie(u > y_max, y_max, ie( (y_min < u) & (u < y_max), u, y_min))
117+
]
118+
ODESystem(eqs, t, name=name)
119+
end
120+
121+
@named sat = saturation(; y_max=1)
122+
# inside the linear region, the function is identity
123+
@unpack u,y = sat
124+
lsys, ssys = linearize(sat, [u], [y])
125+
@test isempty(lsys.A) # there are no differential variables in this system
126+
@test isempty(lsys.B)
127+
@test isempty(lsys.C)
128+
@test lsys.D[] == 1

0 commit comments

Comments
 (0)