@@ -183,13 +183,13 @@ function namespaced_ap_match(x, ns, ap_names0, loop_openings)
183
183
end
184
184
end
185
185
186
- function get_perturbation_var (x:: Num )
186
+ function get_perturbation_var (x:: Num , prefix = " d " )
187
187
@variables d (t) = 0
188
- @set! d. val. f. name = Symbol (" d_ $(x) " )
188
+ @set! d. val. f. name = Symbol (" $(prefix) _ $(x) " )
189
189
d
190
190
end
191
- function get_perturbation_var (x)
192
- get_perturbation_var .(x)
191
+ function get_perturbation_var (x, args ... )
192
+ get_perturbation_var .(x, args ... )
193
193
end
194
194
195
195
function _check_and_sort! (ap_names, aps, namespaces, multiplicities)
@@ -367,49 +367,52 @@ function open_loop(sys, ap_name::Symbol; ground_input = false, kwargs...)
367
367
end
368
368
369
369
function ModelingToolkit. linearization_function (sys:: ModelingToolkit.AbstractSystem ,
370
- input_name:: Symbol , output_name:: Symbol ;
370
+ input_name:: SymOrVec , output_name:: SymOrVec ;
371
371
loop_openings = nothing ,
372
372
kwargs... )
373
373
t = get_iv (sys)
374
374
@variables u (t)= 0 [input = true ]
375
375
@variables y (t)= 0 [output = true ]
376
- find_input = namespaced_ap_match (input_name, loop_openings)
377
- find_output = namespaced_ap_match (output_name, loop_openings)
378
- find = (x, ns) -> find_input (x, ns) || find_output (x, ns)
376
+ find = namespaced_ap_match ([input_name; output_name], loop_openings)
379
377
380
- namespace_u = Ref {Union{Nothing, Symbol}} (nothing )
381
- namespace_y = Ref {Union{Nothing, Symbol}} (nothing )
382
- apr_u = Ref {Union{Nothing, AnalysisPoint}} (nothing )
383
- apr_y = Ref {Union{Nothing, AnalysisPoint}} (nothing )
384
- replace = let u = u, y = y, namespace_u = namespace_u, apr_u = apr_u,
385
- namespace_y = namespace_y, apr_y = apr_y
378
+ u = []
379
+ y = []
380
+ namespace_u = []
381
+ namespace_y = []
382
+ aps_u = []
383
+ aps_y = []
384
+ multiplicities_u = Int[]
385
+ multiplicities_y = Int[]
386
386
387
- function (ap, ns)
388
- if namespaced_ap_match (ap, ns, input_name, nothing )
389
- namespace_u[] = ns # Save the namespace to make it available for renamespace below
390
- apr_u[] = ap
391
- [ap_var (ap. out) ~ ap_var (ap. in) + u], u
392
- # input.in.u ~ 0] # We only need to ground one of the ends, hence not including this equation
393
- elseif namespaced_ap_match (ap, ns, output_name, nothing )
394
- namespace_y[] = ns # Save the namespace to make it available for renamespace below
395
- apr_y[] = ap
396
- [ap_var (ap. in) ~ y
397
- ap_var (ap. out) ~ ap_var (ap. in)], y
398
- else # loop opening
399
- [ap_var (ap. out) ~ 0 ], []
400
- end
387
+ replace = function (ap, ns)
388
+ if namespaced_ap_match (ap, ns, input_name, nothing )
389
+ push! (namespace_u, ns) # Save the namespace to make it available for renamespace below
390
+ push! (aps_u, ap)
391
+ ui = get_perturbation_var (ap_var (ap. out), " u" )
392
+ push! (multiplicities_u, length (ui)) # one ap may yield several new vars
393
+ append! (u, ui)
394
+ [ap_var (ap. out) .~ ap_var (ap. in) + ui;], ui
395
+ # input.in.u ~ 0] # We only need to ground one of the ends, hence not including this equation
396
+ elseif namespaced_ap_match (ap, ns, output_name, nothing )
397
+ push! (namespace_y, ns) # Save the namespace to make it available for renamespace below
398
+ push! (aps_y, ap)
399
+ yi = get_perturbation_var (ap_var (ap. in), " y" )
400
+ push! (multiplicities_y, length (yi))
401
+ append! (y, yi)
402
+ [ap_var (ap. in) .~ yi;
403
+ ap_var (ap. out) .~ ap_var (ap. in)], yi
404
+ else # loop opening
405
+ [ap_var (ap. out) .~ 0 ;], []
401
406
end
402
407
end
408
+
403
409
sys = expand_connections (sys, find, replace)
404
- (ap = apr_u[]) === nothing && error (" Did not find analysis point $input_name " )
405
- (ap = apr_y[]) === nothing && error (" Did not find analysis point $output_name " )
406
- if (ns = namespace_u[]) != = nothing
407
- u = ModelingToolkit. renamespace (ns, u)
408
- end
409
- if (ns = namespace_y[]) != = nothing
410
- y = ModelingToolkit. renamespace (ns, y)
411
- end
412
- ModelingToolkit. linearization_function (sys, [u], [y]; kwargs... )
410
+ permutation_u = _check_and_sort! (input_name, aps_u, namespace_u, multiplicities_u)
411
+ permutation_y = _check_and_sort! (output_name, aps_y, namespace_y, multiplicities_y)
412
+
413
+ yn = ModelingToolkit. renamespace .(namespace_u, y) # permutation applied in _check_and_sort
414
+ un = ModelingToolkit. renamespace .(namespace_y, u)
415
+ ModelingToolkit. linearization_function (sys, un, yn; kwargs... )
413
416
end
414
417
415
418
# Add a method to get_sensitivity that accepts the name of an AnalysisPoint
438
441
439
442
Linearize a system between two analysis points. To get a loop-transfer function, see [`get_looptransfer`](@ref)
440
443
"""
441
- function ModelingToolkit. linearize (sys, input_name:: Symbol , output_name:: Symbol ;
444
+ function ModelingToolkit. linearize (sys, input_name:: SymOrVec , output_name:: SymOrVec ;
442
445
loop_openings = nothing , kwargs... )
443
446
lin_fun, ssys = linearization_function (sys, input_name, output_name; loop_openings,
444
447
kwargs... )
0 commit comments