|
1 | 1 | """
|
2 | 2 | $(TYPEDEF)
|
3 |
| - $(TYPEDSIGNATURES) |
| 3 | + AnalysisPoint(input, name::Symbol, outputs::Vector) |
4 | 4 |
|
5 | 5 | Create an AnalysisPoint for linear analysis. Analysis points can be created by calling
|
6 | 6 |
|
7 | 7 | ```
|
8 | 8 | connect(in, :ap_name, out...)
|
9 | 9 | ```
|
10 | 10 |
|
11 |
| -Where `in` is the input to the connection, and `out...` are the outputs. In the context of |
12 |
| -ModelingToolkitStandardLibrary.jl, `in` is a `RealOutput` connector and `out...` are all |
13 |
| -`RealInput` connectors. All involved connectors are required to either have an unknown named |
| 11 | +Where `in` is the input to the connection, and `out...` are the outputs. All involved |
| 12 | +connectors (input and outputs) are required to either have an unknown named |
14 | 13 | `u` or a single unknown, all of which should have the same size.
|
| 14 | +
|
| 15 | +See also [`get_sensitivity`](@ref), [`get_comp_sensitivity`](@ref), [`get_looptransfer`](@ref), [`open_loop`](@ref) |
| 16 | +
|
| 17 | +# Fields |
| 18 | +
|
| 19 | +$(TYPEDFIELDS) |
| 20 | +
|
| 21 | +# Example |
| 22 | +
|
| 23 | +```julia |
| 24 | +using ModelingToolkit |
| 25 | +using ModelingToolkitStandardLibrary.Blocks |
| 26 | +using ModelingToolkit: t_nounits as t |
| 27 | +
|
| 28 | +@named P = FirstOrder(k = 1, T = 1) |
| 29 | +@named C = Gain(; k = -1) |
| 30 | +t = ModelingToolkit.get_iv(P) |
| 31 | +
|
| 32 | +eqs = [connect(P.output, C.input) |
| 33 | + connect(C.output, :plant_input, P.input)] |
| 34 | +sys = ODESystem(eqs, t, systems = [P, C], name = :feedback_system) |
| 35 | +
|
| 36 | +matrices_S, _ = get_sensitivity(sys, :plant_input) # Compute the matrices of a state-space representation of the (input) sensitivity function. |
| 37 | +matrices_T, _ = get_comp_sensitivity(sys, :plant_input) |
| 38 | +``` |
| 39 | +
|
| 40 | +Continued linear analysis and design can be performed using ControlSystemsBase.jl. |
| 41 | +Create `ControlSystemsBase.StateSpace` objects using |
| 42 | +
|
| 43 | +```julia |
| 44 | +using ControlSystemsBase, Plots |
| 45 | +S = ss(matrices_S...) |
| 46 | +T = ss(matrices_T...) |
| 47 | +bodeplot([S, T], lab = ["S" "T"]) |
| 48 | +``` |
| 49 | +
|
| 50 | +The sensitivity functions obtained this way should be equivalent to the ones obtained with the code below |
| 51 | +
|
| 52 | +```julia |
| 53 | +using ControlSystemsBase |
| 54 | +P = tf(1.0, [1, 1]) |
| 55 | +C = 1 # Negative feedback assumed in ControlSystems |
| 56 | +S = sensitivity(P, C) # or feedback(1, P*C) |
| 57 | +T = comp_sensitivity(P, C) # or feedback(P*C) |
| 58 | +``` |
15 | 59 | """
|
16 | 60 | struct AnalysisPoint
|
| 61 | + """ |
| 62 | + The input to the connection. In the context of ModelingToolkitStandardLibrary.jl, |
| 63 | + this is a `RealOutput` connector. |
| 64 | + """ |
17 | 65 | input::Any
|
| 66 | + """ |
| 67 | + The name of the analysis point. |
| 68 | + """ |
18 | 69 | name::Symbol
|
| 70 | + """ |
| 71 | + The outputs of the connection. In the context of ModelingToolkitStandardLibrary.jl, |
| 72 | + these are all `RealInput` connectors. |
| 73 | + """ |
19 | 74 | outputs::Union{Nothing, Vector{Any}}
|
20 | 75 | end
|
21 | 76 |
|
22 | 77 | AnalysisPoint() = AnalysisPoint(nothing, Symbol(), nothing)
|
| 78 | +""" |
| 79 | + $(TYPEDSIGNATURES) |
| 80 | +
|
| 81 | +Create an `AnalysisPoint` with the given name, with no input or outputs specified. |
| 82 | +""" |
23 | 83 | AnalysisPoint(name::Symbol) = AnalysisPoint(nothing, name, nothing)
|
24 | 84 |
|
25 | 85 | Base.nameof(ap::AnalysisPoint) = ap.name
|
@@ -78,9 +138,35 @@ function Symbolics.connect(in, ap::AnalysisPoint, outs...)
|
78 | 138 | end
|
79 | 139 |
|
80 | 140 | """
|
81 |
| - $(TYPEDSIGNATURES) |
| 141 | + connect(output_connector, ap_name::Symbol, input_connector; verbose = true) |
| 142 | + connect(output_connector, ap::AnalysisPoint, input_connector; verbose = true) |
| 143 | +
|
| 144 | +Connect `output_connector` and `input_connector` with an [`AnalysisPoint`](@ref) inbetween. |
| 145 | +The incoming connection `output_connector` is expected to be an output connector (for |
| 146 | +example, `ModelingToolkitStandardLibrary.Blocks.RealOutput`), and vice versa. |
82 | 147 |
|
83 |
| -Create an `AnalysisPoint` connection connecting `in` to `outs...`. |
| 148 | +*PLEASE NOTE*: The connection is assumed to be *causal*, meaning that |
| 149 | +
|
| 150 | +```julia |
| 151 | +@named P = FirstOrder(k = 1, T = 1) |
| 152 | +@named C = Gain(; k = -1) |
| 153 | +connect(C.output, :plant_input, P.input) |
| 154 | +``` |
| 155 | +
|
| 156 | +is correct, whereas |
| 157 | +
|
| 158 | +```julia |
| 159 | +connect(P.input, :plant_input, C.output) |
| 160 | +``` |
| 161 | +
|
| 162 | +typically is not (unless the model is an inverse model). |
| 163 | +
|
| 164 | +# Arguments: |
| 165 | +
|
| 166 | + - `output_connector`: An output connector |
| 167 | + - `input_connector`: An input connector |
| 168 | + - `ap`: An explicitly created [`AnalysisPoint`](@ref) |
| 169 | + - `ap_name`: If a name is given, an [`AnalysisPoint`](@ref) with the given name will be created automatically. |
84 | 170 | """
|
85 | 171 | function Symbolics.connect(in::AbstractSystem, name::Symbol, out, outs...)
|
86 | 172 | return AnalysisPoint() ~ AnalysisPoint(in, name, [out; collect(outs)])
|
@@ -724,12 +810,6 @@ for f in [:get_sensitivity, :get_comp_sensitivity, :get_looptransfer]
|
724 | 810 | sys, ap, args...; loop_openings, system_modifier, kwargs...)
|
725 | 811 | ModelingToolkit.linearize(ssys, lin_fun; kwargs...), ssys
|
726 | 812 | end
|
727 |
| - @eval @doc """ |
728 |
| - $(TYPEDSIGNATURES) |
729 |
| -
|
730 |
| - Call `$($utility_fun)` and perform the linearization. All keyword arguments are |
731 |
| - forwarded to `$($utility_fun)` and subsequently `linearize`. |
732 |
| - """ $f |
733 | 813 | end
|
734 | 814 |
|
735 | 815 | """
|
@@ -785,3 +865,59 @@ function linearization_function(sys::AbstractSystem,
|
785 | 865 |
|
786 | 866 | return linearization_function(system_modifier(sys), input_vars, output_vars; kwargs...)
|
787 | 867 | end
|
| 868 | + |
| 869 | +@doc """ |
| 870 | + get_sensitivity(sys, ap::AnalysisPoint; kwargs) |
| 871 | + get_sensitivity(sys, ap_name::Symbol; kwargs) |
| 872 | +
|
| 873 | +Compute the sensitivity function in analysis point `ap`. The sensitivity function is obtained by introducing an infinitesimal perturbation `d` at the input of `ap`, linearizing the system and computing the transfer function between `d` and the output of `ap`. |
| 874 | +
|
| 875 | +!!! danger "Experimental" |
| 876 | +
|
| 877 | + The analysis-point interface is currently experimental and at any time subject to breaking changes not respecting semantic versioning. |
| 878 | +
|
| 879 | +# Arguments: |
| 880 | +
|
| 881 | + - `kwargs`: Are sent to `ModelingToolkit.linearize` |
| 882 | +
|
| 883 | +See also [`get_comp_sensitivity`](@ref), [`get_looptransfer`](@ref). |
| 884 | +""" get_sensitivity |
| 885 | + |
| 886 | +@doc """ |
| 887 | + get_comp_sensitivity(sys, ap::AnalysisPoint; kwargs) |
| 888 | + get_comp_sensitivity(sys, ap_name::Symbol; kwargs) |
| 889 | +
|
| 890 | +Compute the complementary sensitivity function in analysis point `ap`. The complementary sensitivity function is obtained by introducing an infinitesimal perturbation `d` at the output of `ap`, linearizing the system and computing the transfer function between `d` and the input of `ap`. |
| 891 | +
|
| 892 | +!!! danger "Experimental" |
| 893 | +
|
| 894 | + The analysis-point interface is currently experimental and at any time subject to breaking changes not respecting semantic versioning. |
| 895 | +
|
| 896 | +# Arguments: |
| 897 | +
|
| 898 | + - `kwargs`: Are sent to `ModelingToolkit.linearize` |
| 899 | +
|
| 900 | +See also [`get_sensitivity`](@ref), [`get_looptransfer`](@ref). |
| 901 | +""" get_comp_sensitivity |
| 902 | + |
| 903 | +@doc """ |
| 904 | + get_looptransfer(sys, ap::AnalysisPoint; kwargs) |
| 905 | + get_looptransfer(sys, ap_name::Symbol; kwargs) |
| 906 | +
|
| 907 | +Compute the (linearized) loop-transfer function in analysis point `ap`, from `ap.out` to `ap.in`. |
| 908 | +
|
| 909 | +!!! info "Negative feedback" |
| 910 | +
|
| 911 | + Feedback loops often use negative feedback, and the computed loop-transfer function will in this case have the negative feedback included. Standard analysis tools often assume a loop-transfer function without the negative gain built in, and the result of this function may thus need negation before use. |
| 912 | +
|
| 913 | +
|
| 914 | +!!! danger "Experimental" |
| 915 | +
|
| 916 | + The analysis-point interface is currently experimental and at any time subject to breaking changes not respecting semantic versioning. |
| 917 | +
|
| 918 | +# Arguments: |
| 919 | +
|
| 920 | + - `kwargs`: Are sent to `ModelingToolkit.linearize` |
| 921 | +
|
| 922 | +See also [`get_sensitivity`](@ref), [`get_comp_sensitivity`](@ref), [`open_loop`](@ref). |
| 923 | +""" get_looptransfer |
0 commit comments