You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# For each system, if it has a name, append the system name to the x names. If neither system has a name, append gensym names to both systems' x names.
34
+
systemnames = [s.name for s in systems]
35
+
x_names =ifany(isempty(s.name) for s in systems) ||length(unique(systemnames)) <length(systemnames)
36
+
# Any name is empty or more than one system has the same name
37
+
[gensym(string(x)) for x in x_names]
38
+
else
39
+
reduce(vcat, [[Symbol(string(s.name)*string(x)) for x in s.x] for s in systems])
40
+
end
41
+
@assertallunique(x_names)
42
+
x_names
27
43
end
28
44
end
29
45
46
+
30
47
import ControlSystemsBase as CS
31
48
import ControlSystemsBase: nstates, blockdiag
32
49
@@ -175,6 +192,9 @@ function named_ss(sys::AbstractStateSpace{T};
175
192
name::String="",
176
193
unique =true,
177
194
) where T
195
+
if sys isa NamedStateSpace
196
+
error("Cannot wrap a named statespace in a named statespace")
197
+
end
178
198
x =expand_symbol(x, sys.nx)
179
199
u =expand_symbol(u, size(sys,2)) # size is used instead of sys.nu for ExtendedStateSpace
180
200
y =expand_symbol(y, size(sys,1))
@@ -185,10 +205,10 @@ function named_ss(sys::AbstractStateSpace{T};
185
205
length(y) ==size(sys,1) ||
186
206
throw(ArgumentError("Length of output names must match size(sys,1) ($(size(sys,1))), got length $(length(y))"))
187
207
188
-
@check_unique x"x"
189
-
@check_unique y"y"
208
+
check_unique(x,"x", "Cannot create a NamedStateSpace system with more than one variable with the same name")
209
+
check_unique(y,"y", "Cannot create a NamedStateSpace system with more than one variable with the same name")
190
210
if unique
191
-
@check_unique u"u""To allow connecting a single input signal to several inputs with the same name, pass `unique = false`."
211
+
check_unique(u,"u","To allow connecting a single input signal to several inputs with the same name, pass `unique = false`.")
192
212
end
193
213
194
214
NamedStateSpace{T, typeof(sys)}(sys, x, u, y, name)
@@ -281,7 +301,7 @@ function Base.:+(s1::NamedStateSpace{T,S}, s2::NamedStateSpace{T,S}) where {T <:
281
301
end
282
302
283
303
function Base.:*(s1::NamedStateSpace{T}, s2::NamedStateSpace{T}) where {T <:CS.TimeEvolution}
284
-
@check_all_unique s1 s2
304
+
x_names =generate_unique_x_names(s1, s2)
285
305
if s1.u != s2.y
286
306
connection_map =join(["$y -> $u"for (u,y) inzip(s1.u, s2.y) if u != y], '\n')
287
307
@warn"Connected signals have different names\n$connection_map" maxlog=2
@@ -290,7 +310,7 @@ function Base.:*(s1::NamedStateSpace{T}, s2::NamedStateSpace{T}) where {T <: CS.
290
310
S =typeof(sys)
291
311
returnNamedStateSpace{T,S}(
292
312
sys,
293
-
[s1.x; s2.x],
313
+
x_names,
294
314
s2.u,
295
315
s1.y,
296
316
"",
@@ -360,10 +380,9 @@ end
360
380
##
361
381
362
382
function Base.hcat(systems::NamedStateSpace{T,S}...) where {T,S}
363
-
x =reduce(vcat, getproperty.(systems, :x))
383
+
x =generate_unique_x_names(systems...)
364
384
u =reduce(vcat, getproperty.(systems, :u))
365
-
@check_unique x
366
-
@check_unique u
385
+
check_unique(u, "u")
367
386
returnNamedStateSpace{T,S}(
368
387
hcat(getproperty.(systems, :sys)...),
369
388
x,
@@ -374,10 +393,9 @@ function Base.hcat(systems::NamedStateSpace{T,S}...) where {T,S}
374
393
end
375
394
376
395
function Base.vcat(systems::NamedStateSpace{T,S}...) where {T,S}
377
-
x =reduce(vcat, getproperty.(systems, :x))
396
+
x =generate_unique_x_names(systems...)
378
397
y =reduce(vcat, getproperty.(systems, :y))
379
-
@check_unique x
380
-
@check_unique y
398
+
check_unique(y, "y")
381
399
returnNamedStateSpace{T,S}(
382
400
vcat(getproperty.(systems, :sys)...),
383
401
x,
@@ -467,6 +485,9 @@ All signal sets `w1,u1,z1,y1,u2,y2,w2,z2` have the same meaning as for the advan
467
485
The added signal set `r` is used to optionally provide a new name for the input of the feedback loop.
468
486
469
487
To simplify creating complicated feedback interconnections, see `connect`.
488
+
489
+
If not all inputs and outputs are connected, the returned system may not be a minimal realization.
490
+
Use `sminreal` (possibly also `minreal`) to simplify the system if only the input-output map is of interest.
470
491
"""
471
492
function ControlSystemsBase.feedback(s1::NamedStateSpace{T}, s2::NamedStateSpace{T};
472
493
u1=:, w1=:,z1=:,y1=:,u2=:,y2=:,w2=[],z2=[], unique =true, kwargs...) where {T <:CS.TimeEvolution}
@@ -493,14 +514,13 @@ function ControlSystemsBase.feedback(s1::NamedStateSpace{T}, s2::NamedStateSpace
ControlSystemsBase.feedback(s1::NamedStateSpace{T}, s2::AbstractStateSpace{T}; kwargs...) where {T <:CS.TimeEvolution} =feedback(s1, named_ss(s2); kwargs...)
@@ -513,28 +533,28 @@ function connect(systems; u1::Vector{Symbol}, y1::Vector{Symbol}, external_input
513
533
w1 =something(external_inputs, w1)
514
534
w1 ===nothing&&error("The keyword argument `external_inputs` must be provided")
515
535
if unique
516
-
@check_unique u1"Connected inputs not unique. If you want to connect several signals to the same input, use a summation node, e.g., named_ss(ss([1 1]), u=[:u1, :u2], y=:usum)"
517
-
@check_uniquefull.u "system inputs""To allow connecting a single input signal to several inputs with the same name, pass `unique = false`."
536
+
check_unique(u1, "u1","Connected inputs not unique. If you want to connect several signals to the same input, use a summation node, e.g., named_ss(ss([1 1]), u=[:u1, :u2], y=:usum)")
537
+
check_unique(full.u,"system inputs""To allow connecting a single input signal to several inputs with the same name, pass `unique = false`.")
518
538
end
519
539
520
-
@check_uniquefull.y "system outputs"
540
+
check_unique(full.y,"system outputs")
521
541
522
542
if verbose
523
543
leftover_inputs =setdiff(full.u, [u1; w1])
524
-
isempty(leftover_inputs) ||@warn("The following inputs were unconnected $leftover_inputs, ignore this warning if you rely on prefix matching")
544
+
isempty(leftover_inputs) ||@warn("The following inputs were unconnected $leftover_inputs, ignore this warning if you rely on prefix matching. Turn off this warning by passing `verbose = false`.")
isempty(leftover_outputs) ||@warn("The following outputs were unconnected $leftover_outputs, ignore this warning if you rely on prefix matching")
546
+
isempty(leftover_outputs) ||@warn("The following outputs were unconnected $leftover_outputs, ignore this warning if you rely on prefix matching. Turn off this warning by passing `verbose = false`.")
0 commit comments