Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix typos #858

Merged
merged 1 commit into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/src/examples/automatic_differentiation.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ plot_optimized(P, params, res.u, systemspid)
The optimized controller achieves more or less the same low peak in the sensitivity function, but does this while *both* making the step responses significantly faster *and* using much less controller gain for large frequencies (the orange sensitivity function), an altogether better tuning. The only potentially negative effect of this tuning is that the overshoot in response to a reference step increased slightly, indicated also by the slightly higher peak in the complimentary sensitivity function (green). However, the response to reference steps can (and most often should) be additionally shaped by reference pre-filtering (sometimes referred to as "feedforward" or "reference shaping"), by introducing an additional filter appearing in the feedforward path only, thus allowing elimination of the overshoot without affecting the closed-loop properties.

## Optimization-based tuning--LQG controller
We could attempt a similar automatic tuning of an LQG controller. This time, we choose to optimize the weight matrices of the LQR problem and the state covariance matrix of the noise. The synthesis of an LQR controller involves the solution of a Ricatti equation, which in turn involves performing a Schur decomposition. These steps hard hard to differentiate through in a conventional way, but we can make use of implicit differentiation using the implicit function theorem. To do so, we load the package `ImplicitDifferentiation`, and define the conditions that hold at the solution of the Ricatti equaiton:
We could attempt a similar automatic tuning of an LQG controller. This time, we choose to optimize the weight matrices of the LQR problem and the state covariance matrix of the noise. The synthesis of an LQR controller involves the solution of a Ricatti equation, which in turn involves performing a Schur decomposition. These steps hard hard to differentiate through in a conventional way, but we can make use of implicit differentiation using the implicit function theorem. To do so, we load the package `ImplicitDifferentiation`, and define the conditions that hold at the solution of the Ricatti equation:
```math
A^TX + XA - XBR^{-1}B^T X + Q = 0
```
Expand Down Expand Up @@ -308,11 +308,11 @@ The following issues are currently known to exist when using AD through ControlS

### ForwardDiff
[ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) works for a lot of workflows without any intervention required from the user. The following known limitations exist:
- The function [`c2d`](@ref) with the default `:zoh` discretization method makes a call to `LinearAlgebra.exp!`, which is not defined for `ForwardDiff.Dual` numbers. A forward rule for this function exist in ChainRules, which can be eneabled using ForwardDiffChainRules.jl, but [this PR](https://github.com/ThummeTo/ForwardDiffChainRules.jl/pull/16) must be merged and relseased before it will work as intended. A workaround is to use the `:tustin` method instead, or [manually defining this method](https://github.com/JuliaControl/ControlSystems.jl/blob/master/docs/src/examples/automatic_differentiation.md?plain=1#LL2C1-L25C4).
- The function [`c2d`](@ref) with the default `:zoh` discretization method makes a call to `LinearAlgebra.exp!`, which is not defined for `ForwardDiff.Dual` numbers. A forward rule for this function exist in ChainRules, which can be enabled using ForwardDiffChainRules.jl, but [this PR](https://github.com/ThummeTo/ForwardDiffChainRules.jl/pull/16) must be merged and released before it will work as intended. A workaround is to use the `:tustin` method instead, or [manually defining this method](https://github.com/JuliaControl/ControlSystems.jl/blob/master/docs/src/examples/automatic_differentiation.md?plain=1#LL2C1-L25C4).
- The function `svdvals` does not have a forward rule defined. This means that the functions [`sigma`](@ref) and `opnorm` will not work for MIMO systems with ForwardDiff. SISO, MISO and SIMO systems will, however, work.
- [`hinfnorm`](@ref) requires ImplicitDifferentiation.jl and ComponentArrays.jl to be manually loaded by the user, after which there are implicit differentiation rules defined for [`hinfnorm`](@ref). The implicit rule calls `opnorm`, and is thus affected by the first limitation above for MIMO systems. [`hinfnorm`](@ref) has a reverse rule defined in RobustAndOptimalControl.jl, which is not affected by this limitation.
- [`are`](@ref), [`lqr`](@ref) and [`kalman`](@ref) all require ImplicitDifferentiation.jl and ComponentArrays.jl to be manually loaded by the user, after which there are implicit differentiation rules defined. To invoke the correct method of these functions, it is important that the second matrix (corresponding to input or measurement) has the `Dual` number type, i.e., the `R` matrix in `lqr(P, Q, R)` or `lqr(Continuous, A, B, Q, R)`
- The `schur` factorization has an implicit differentiation rule defined, but the companion function `ordschur` does not. This is the fundamental reason for requireing ImplicitDifferentiation.jl to differentiate through the Ricatti equation solver. `schur` is called in several additional places, including [`balreal`](@ref) and all [`lyap`](@ref) solvers. Many of these algorithms also call `givensAlgorithm` which has no rule either.
- The `schur` factorization has an implicit differentiation rule defined, but the companion function `ordschur` does not. This is the fundamental reason for requiring ImplicitDifferentiation.jl to differentiate through the Ricatti equation solver. `schur` is called in several additional places, including [`balreal`](@ref) and all [`lyap`](@ref) solvers. Many of these algorithms also call `givensAlgorithm` which has no rule either.
- An implicit rule is defined for continuous-time [`lyap`](@ref) and [`plyap`](@ref) solvers, but not yet for discrete-time solvers. This means that [`gram`](@ref) [`covar`](@ref) and [`norm`](@ref) (``H_2``-norm) is differentiable for continuous-time systems but not for discrete.

### Reverse-mode AD
Expand Down
6 changes: 3 additions & 3 deletions docs/src/examples/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ Tf = 1/20ω
C, kp, ki, kd, fig, CF = loopshapingPID(P, ω; Mt, ϕt, doplot=true, Tf)
fig
```
As we can see, the addition of the filter increases the high-frequency roll-off in both $T$ and $CS$, which is typically desireable.
As we can see, the addition of the filter increases the high-frequency roll-off in both $T$ and $CS$, which is typically desirable.

To get better control over the filter, it can be pre-designed and supplied to [`loopshapingPID`](@ref) with the keyword argument `F`:
```julia
Expand Down Expand Up @@ -193,12 +193,12 @@ Bm = conv(B⁺, B⁻) # In this case, keep the entire numerator polynomial of t

R,S,T = rstc(B⁺,B⁻,A,Bm,Am,Ao,AR) # Calculate the 2-DOF controller polynomials

Gcl = tf(conv(B,T),zpconv(A,R,B,S)) # Form the closed loop polynomial from reference to output, the closed-loop characteristic polynomial is AR + BS, the function zpconv takes care of the polynomial multiplication and makes sure the coefficient vectores are of equal length
Gcl = tf(conv(B,T),zpconv(A,R,B,S)) # Form the closed loop polynomial from reference to output, the closed-loop characteristic polynomial is AR + BS, the function zpconv takes care of the polynomial multiplication and makes sure the coefficient vectors are of equal length

plot(step(P, 20))
plot!(step(Gcl, 20)) # Visualize the open and closed loop responses.
save_docs_plot("ppstepplot.svg") # hide
gangoffourplot(P, tf(-S,R)) # Plot the gang of four to check that all tranfer functions are OK
gangoffourplot(P, tf(-S,R)) # Plot the gang of four to check that all transfer functions are OK
save_docs_plot("ppgofplot.svg"); # hide

# output
Expand Down
4 changes: 2 additions & 2 deletions example/example_pid_design.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ Bm = conv(B⁺, B⁻) # In this case, keep the entire numerator polynomial of t

R,S,T = rstc(B⁺,B⁻,A,Bm,Am,Ao,AR) # Calculate the 2-DOF controller polynomials

Gcl = tf(conv(B,T),zpconv(A,R,B,S)) # Form the closed loop polynomial from reference to output, the closed-loop characteristic polynomial is AR + BS, the function zpconv takes care of the polynomial multiplication and makes sure the coefficient vectores are of equal length
Gcl = tf(conv(B,T),zpconv(A,R,B,S)) # Form the closed loop polynomial from reference to output, the closed-loop characteristic polynomial is AR + BS, the function zpconv takes care of the polynomial multiplication and makes sure the coefficient vectors are of equal length

stepplot([P,Gcl]) # Visualize the open and closed loop responses.
gangoffourplot(P, tf(-S,R)) # Plot the gang of four to check that all tranfer functions are OK
gangoffourplot(P, tf(-S,R)) # Plot the gang of four to check that all transfer functions are OK
```


Expand Down
6 changes: 3 additions & 3 deletions example/symbolic_computations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ using Revise
using ControlSystems
using SymPy

# Some basic demonstations of working with symbolic LTI systems
# Some basic demonstrations of working with symbolic LTI systems
# Functionality is rather limited, and for complicated expressions the
# printing is awful.
# For additional functionality, see https://github.com/JuliaControl/SymbolicControlSystems.jl
Expand Down Expand Up @@ -33,7 +33,7 @@ end
# Define a symbolic parameter
a = symbols("a", real=true)

# Define a statespace and a trasnfer function
# Define a statespace and a transfer function
sys = ss([1 a; a 1], [0; 1], [1 0], 0)

s = tf("s")
Expand Down Expand Up @@ -73,7 +73,7 @@ real_roots = roots[SymPy.imag(roots) .== 0]
maximum([subs(sys_fr_mag, w => r) for r in real_roots])


# Compute the impulse resonse of some systems (on statespace form)
# Compute the impulse response of some systems (on statespace form)
impulse(sys)[1]
simplify(impulse(ss(G))[1])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,9 @@ const implicit_hinfnorm = ImplicitFunction(forward_hinfnorm, conditions_hinfnorm
"""
hinfnorm(sys::StateSpace{Continuous, <:Dual}; kwargs)

The H∞ norm can be differentiated through using ForwardDiff.jl, but at the time of writing, is limited to systems with *either* a signel input *or* a single output.
The H∞ norm can be differentiated through using ForwardDiff.jl, but at the time of writing, is limited to systems with *either* a single input *or* a single output.

A reverse-differention rule is defined in RobustAndOptimalControl.jl, which means that hinfnorm is differentiable using, e.g., Zygote in reverse mode.
A reverse-differentiation rule is defined in RobustAndOptimalControl.jl, which means that hinfnorm is differentiable using, e.g., Zygote in reverse mode.
"""
function hinfnorm(sys::StateSpace{Continuous, <:Dual}; kwargs...)
A,B,C,D = ssdata(sys)
Expand Down
2 changes: 1 addition & 1 deletion lib/ControlSystemsBase/src/ControlSystemsBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ include("types/Lti.jl")

include("types/SisoTf.jl")

# Transfer functions and tranfer function elemements
# Transfer functions and transfer function elements
include("types/TransferFunction.jl")
include("types/SisoTfTypes/SisoZpk.jl")
include("types/SisoTfTypes/SisoRational.jl")
Expand Down
2 changes: 1 addition & 1 deletion lib/ControlSystemsBase/src/analysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ end
Calculate the relative gain array of `G` at frequencies `w`.
G(iω) .* pinv(tranpose(G(iω)))

The RGA can be used to find input-output pairings for MIMO control using individially tuned loops. Pair the inputs and outputs such that the RGA(ωc) at the crossover frequency becomes as close to diagonal as possible. Avoid pairings such that RGA(0) contains negative diagonal elements.
The RGA can be used to find input-output pairings for MIMO control using individually tuned loops. Pair the inputs and outputs such that the RGA(ωc) at the crossover frequency becomes as close to diagonal as possible. Avoid pairings such that RGA(0) contains negative diagonal elements.

- The sum of the absolute values of the entries in the RGA is a good measure of the "true condition number" of G, the best condition number that can be achieved by input/output scaling of `G`, -Glad, Ljung.
- The RGA is invariant to input/output scaling of `G`.
Expand Down
2 changes: 1 addition & 1 deletion lib/ControlSystemsBase/src/connections.jl
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ mutable(x::StaticArray, ::Type{T}) where T = Matrix{T}(x)
feedback2dof(P,R,S,T)
feedback2dof(B,A,R,S,T)

- Return `BT/(AR+ST)` where B and A are the numerator and denomenator polynomials of `P` respectively
- Return `BT/(AR+ST)` where B and A are the numerator and denominator polynomials of `P` respectively
- Return `BT/(AR+ST)`
"""
function feedback2dof(P::TransferFunction,R,S,T)
Expand Down
4 changes: 2 additions & 2 deletions lib/ControlSystemsBase/src/delay_systems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function _bounds_and_features(sys::DelayLtiSystem, plot::Val)
return [min(ws[1], floor(extreme[1]-0.2)), max(ws[2], ceil(extreme[2]+0.2))], pz
end

# Againm we have to do something for default vectors, more or less a copy from timeresp.jl
# Again we have to do something for default vectors, more or less a copy from timeresp.jl
function _default_dt(sys::DelayLtiSystem)
if !isstable(sys.P.P)
return 0.05 # Something small
Expand Down Expand Up @@ -111,7 +111,7 @@ function _linscale(p::Polynomial, a)
return Polynomial(coeffs_scaled)
end

# Coefficeints for Padé approximations
# Coefficients for Padé approximations
# PADE_Q_COEFFS = [Polynomial([binomial(N,i)*prod(N+1:2*N-i) for i=0:N]) for N=1:10]
const PADE_Q_COEFFS = [[2, 1],
[12, 6, 1],
Expand Down
6 changes: 3 additions & 3 deletions lib/ControlSystemsBase/src/discrete.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ relative to the time constants of the system.

`method = :tustin` performs a bilinear transform with prewarp frequency `w_prewarp`.

- `w_prewarp`: Frequency (rad/s) for pre-warping when usingthe Tustin method, has no effect for other methods.
- `w_prewarp`: Frequency (rad/s) for pre-warping when using the Tustin method, has no effect for other methods.

See also `c2d_x0map`
"""
Expand All @@ -40,7 +40,7 @@ function c2d_x0map(sys::AbstractStateSpace{<:Continuous}, Ts::Real, method::Symb
Bd = M[1:nx, nx+1:nx+nu]
Cd = C
Dd = D
x0map = [Matrix{T}(I, nx, nx) zeros(nx, nu)] # Cant use I if nx==0
x0map = [Matrix{T}(I, nx, nx) zeros(nx, nu)] # Can't use I if nx==0
elseif method === :foh
M = exp!([A*Ts B*Ts zeros(nx, nu);
zeros(nu, nx + nu) Matrix{T}(I, nu, nu);
Expand Down Expand Up @@ -78,7 +78,7 @@ end

Convert discrete-time system to a continuous time system, assuming that the discrete-time system was discretized using `method`. Available methods are `:zoh, :fwdeuler´.

- `w_prewarp`: Frequency for pre-warping when usingthe Tustin method, has no effect for other methods.
- `w_prewarp`: Frequency for pre-warping when using the Tustin method, has no effect for other methods.
"""
function d2c(sys::AbstractStateSpace{<:Discrete}, method::Symbol=:zoh; w_prewarp=0)
A, B, C, D = ssdata(sys)
Expand Down
2 changes: 1 addition & 1 deletion lib/ControlSystemsBase/src/freqresp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ end
BodemagWorkspace(R::Array{Complex{T}, 3}, mag::Array{T, 3})
BodemagWorkspace{T}(ny, nu, N)

Genereate a workspace object for use with the in-place function [`bodemag!`](@ref).
Generate a workspace object for use with the in-place function [`bodemag!`](@ref).
`N` is the number of frequency points, alternatively, the input `ω` can be provided instead of `N`.
Note: for threaded applications, create one workspace object per thread.

Expand Down
2 changes: 1 addition & 1 deletion lib/ControlSystemsBase/src/hammerstein_weiner.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function _bounds_and_features(sys::HammersteinWienerSystem, plot::Val)
_bounds_and_features(sys.P.P, plot)
end

# Againm we have to do something for default vectors, more or less a copy from timeresp.jl
# Again we have to do something for default vectors, more or less a copy from timeresp.jl
function _default_dt(sys::HammersteinWienerSystem)
_default_dt(sys.P.P)
end
Expand Down
6 changes: 3 additions & 3 deletions lib/ControlSystemsBase/src/matrix_comps.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const _scaling_notice = """
Note: Gramian computations are sensitive to input-output scaling. For the result of a numerical balancing, gramian computation or truncation of MIMO systems to be meaningful, the inputs and outputs of the system must thusbe scaled in a meaningful way. A common (but not the only) approach is:
Note: Gramian computations are sensitive to input-output scaling. For the result of a numerical balancing, gramian computation or truncation of MIMO systems to be meaningful, the inputs and outputs of the system must thus be scaled in a meaningful way. A common (but not the only) approach is:
- The outputs are scaled such that the maximum allowed control error, the maximum expected reference variation, or the maximum expected variation, is unity.
- The input variables are scaled to have magnitude one. This is done by dividing each variable by its maximum expected or allowed change, i.e., ``u_{scaled} = u / u_{max}``

Expand Down Expand Up @@ -311,7 +311,7 @@ function _infnorm_two_steps_ct(sys::AbstractStateSpace, normtype::Symbol, tol=1e
# approximag is a tuning parameter: what does it mean for a number to be on the imaginary axis
# Because of this tuning for example, the relative precision that we provide on the norm computation
# is not a true guarantee, more an order of magnitude
# outputs: An approximatation of the L∞ norm and the frequency ω_peak at which it is achieved
# outputs: An approximation of the L∞ norm and the frequency ω_peak at which it is achieved
# QUESTION: The tolerance for determining if there are poles on the imaginary axis
# would not be very appropriate for systems with slow dynamics?
T = promote_type(real(numeric_type(sys)), Float64)
Expand Down Expand Up @@ -392,7 +392,7 @@ end

function _infnorm_two_steps_dt(sys::AbstractStateSpace, normtype::Symbol, tol=1e-6, maxIters=250, approxcirc=1e-8)
# Discrete-time version of linfnorm_two_steps_ct above
# Compuations are done in normalized frequency θ
# Computations are done in normalized frequency θ

on_unit_circle = z -> abs(abs(z) - 1) < approxcirc # Helper fcn for readability

Expand Down
2 changes: 1 addition & 1 deletion lib/ControlSystemsBase/src/pid_design.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ The functions `pid_tf` and `pid_ss` are also exported. They take the same parame
and is what is actually called in `pid` based on the `state_space` parameter.
"""
function pid(param_p, param_i, param_d=zero(typeof(param_p)); form=:standard, Ts=nothing, Tf=nothing, state_space=false)
C = if state_space # Type unstability? Can it be fixed easily, does it matter?
C = if state_space # Type instability? Can it be fixed easily, does it matter?
pid_ss(param_p, param_i, param_d; form, Tf)
else
pid_tf(param_p, param_i, param_d; form, Tf)
Expand Down
6 changes: 3 additions & 3 deletions lib/ControlSystemsBase/src/plotting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function setPlotScale(str::AbstractString)
end

# """
# Get atributes from xlims or ylims
# Get attributes from xlims or ylims
# default to extrema(wmag) if xlims/ylims not defined or empty
# """
# function getlims(xylims, plotattributes, wmag)
Expand Down Expand Up @@ -231,7 +231,7 @@ _processfreqplot(plottype, system::LTISystem, args...) =
_processfreqplot(plottype, [system], args...)
# Catch when system is not vector, with and without frequency input

# Cantch correct form
# Catch correct form
function _processfreqplot(plottype, systems::AbstractVector{<:LTISystem},
w = _default_freq_vector(systems, plottype))

Expand Down Expand Up @@ -378,7 +378,7 @@ end
Create a Nyquist plot of the `LTISystem`(s). A frequency vector `w` can be
optionally provided.

- `unit_circle`: if the unit circle should be displayed. The Nyquist curve crosses the unit circle at the gain corssover frequency.
- `unit_circle`: if the unit circle should be displayed. The Nyquist curve crosses the unit circle at the gain crossover frequency.
- `Ms_circles`: draw circles corresponding to given levels of sensitivity (circles around -1 with radii `1/Ms`). `Ms_circles` can be supplied as a number or a vector of numbers. A design staying outside such a circle has a phase margin of at least `2asin(1/(2Ms))` rad and a gain margin of at least `Ms/(Ms-1)`.
- `Mt_circles`: draw circles corresponding to given levels of complementary sensitivity. `Mt_circles` can be supplied as a number or a vector of numbers.
- `critical_point`: point on real axis to mark as critical for encirclements
Expand Down
Loading