Skip to content
Merged
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
128 changes: 113 additions & 15 deletions lib/ControlSystemsBase/src/freqresp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,27 @@ freqresp(G::Union{UniformScaling, AbstractMatrix, Number}, w::Real) = G
"""
sys_fr = freqresp(sys, w)

Evaluate the frequency response of a linear system
Evaluate the frequency response of a linear system.

`w -> C*((iw*im*I - A)^-1)*B + D`
For continuous systems, computes `G(jω) = C(jωI - A)^{-1}B + D`
For discrete systems, computes `G(e^{jωT}) = C(e^{jωT}I - A)^{-1}B + D`

of system `sys` over the frequency vector `w`.
# Arguments
- `sys::LTISystem`: The system to analyze
- `w::AbstractVector{<:Real}`: Frequency vector (rad/s)

# Returns
- `sys_fr`: Complex frequency response array of size `(ny, nu, length(w))`

See also [`freqresp!`](@ref), [`evalfr`](@ref), [`bode`](@ref), [`nyquist`](@ref).

# Examples
```julia
using ControlSystemsBase
sys = ss([-1 0; 0 -2], [1; 1], [1 1], 0)
w = exp10.(LinRange(-2, 2, 200))
resp = freqresp(sys, w)
```
"""
@autovec () function freqresp(sys::LTISystem, w_vec::AbstractVector{W}) where W <: Real
te = timeevol(sys)
Expand Down Expand Up @@ -299,12 +315,29 @@ end
mag, phase, w = bode(sys[, w]; unwrap=true)

Compute the magnitude and phase parts of the frequency response of system `sys`
at frequencies `w`. See also [`bodeplot`](@ref)
at frequencies `w`. The frequency response is evaluated as `G(jω)` for continuous
systems and `G(e^{jωT})` for discrete systems.

# Arguments
- `sys::LTISystem`: The system to analyze
- `w::AbstractVector`: Frequency vector (rad/s). If omitted, a default frequency range is used.
- `unwrap::Bool`: If true (default), apply phase unwrapping to avoid discontinuities

# Returns
- `mag`: Magnitude of frequency response, size `(ny, nu, length(w))`
- `phase`: Phase in degrees, size `(ny, nu, length(w))`
- `w`: Frequency vector used

`mag` and `phase` has size `(ny, nu, length(w))`.
If `unwrap` is true (default), the function `unwrap!` will be applied to the phase angles. This procedure is costly and can be avoided if the unwrapping is not required.
Note: Phase unwrapping is computationally expensive and can be disabled for better performance. For higher performance, see the function [`bodemag!`](@ref) that computes the magnitude only.

For higher performance, see the function [`bodemag!`](@ref) that computes the magnitude only.
See also [`bodeplot`](@ref), [`bodemag!`](@ref), [`freqresp`](@ref).

# Examples
```julia
using ControlSystemsBase
sys = tf(1, [1, 1])
mag, phase, w = bode(sys)
```
"""
@autovec (1, 2) function bode(sys::LTISystem, w::AbstractVector; unwrap=true)
resp = freqresp(sys, w)
Expand All @@ -330,8 +363,34 @@ end
"""
mag = bodemag!(ws::BodemagWorkspace, sys::LTISystem, w::AbstractVector)

Compute the Bode magnitude operating in-place on an instance of [`BodemagWorkspace`](@ref). Note that the returned magnitude array is aliased with `ws.mag`.
The output array `mag` is ∈ 𝐑(ny, nu, nω).
Compute the Bode magnitude operating in-place on an instance of [`BodemagWorkspace`](@ref).

# Arguments
- `ws::BodemagWorkspace`: Pre-allocated workspace created with [`BodemagWorkspace`](@ref)
- `sys::LTISystem`: The system to analyze
- `w::AbstractVector`: Frequency vector (rad/s)

# Returns
- `mag`: Magnitude of frequency response, size `(ny, nu, length(w))`.
Note: The returned array is aliased with `ws.mag`.

# Performance
This function provides significant performance benefits for repeated magnitude calculations:
- Avoids memory allocation by reusing workspace arrays
- Optimized for systems with many frequency points

For thread-safe applications, create one workspace per thread.

See also [`BodemagWorkspace`](@ref), [`bode`](@ref), [`freqresp!`](@ref).

# Examples
```julia
using ControlSystemsBase
sys = tf(1, [1, 1])
w = exp10.(LinRange(-2, 2, 200))
ws = BodemagWorkspace(sys, w)
mag = bodemag!(ws, sys, w)
```
"""
function bodemag!(ws::BodemagWorkspace, sys::LTISystem, w::AbstractVector)
freqresp!(ws.R, sys, w)
Expand All @@ -349,9 +408,28 @@ end
re, img, w = nyquist(sys[, w])

Compute the real and imaginary parts of the frequency response of system `sys`
at frequencies `w`. See also [`nyquistplot`](@ref)

`re` and `img` has size `(ny, nu, length(w))`"""
at frequencies `w`. The frequency response is evaluated as `G(jω)` for continuous
systems and `G(e^{jωT})` for discrete systems.

# Arguments
- `sys::LTISystem`: The system to analyze
- `w::AbstractVector`: Frequency vector (rad/s). If omitted, a default frequency range is used.

# Returns
- `re`: Real part of frequency response, size `(ny, nu, length(w))`
- `img`: Imaginary part of frequency response, size `(ny, nu, length(w))`
- `w`: Frequency vector used

See also [`nyquistplot`](@ref), [`freqresp`](@ref), [`bode`](@ref).

# Examples
```julia
using ControlSystems
sys = tf(1, [1, 1])
w = logspace(-2, 2, 100)
re, img, w = nyquist(sys, w)
```
"""
@autovec (1, 2) function nyquist(sys::LTISystem, w::AbstractVector)
resp = freqresp(sys, w)
return real(resp), imag(resp), w
Expand All @@ -361,10 +439,30 @@ end
"""
sv, w = sigma(sys[, w])

Compute the singular values `sv` of the frequency response of system `sys` at
frequencies `w`. See also [`sigmaplot`](@ref)
Compute the singular values of the frequency response of system `sys` at
frequencies `w`. The frequency response is evaluated as `G(jω)` for continuous
systems and `G(e^{jωT})` for discrete systems.

# Arguments
- `sys::LTISystem`: The system to analyze
- `w::AbstractVector`: Frequency vector (rad/s). If omitted, a default frequency range is used.

`sv` has size `(min(ny, nu), length(w))`"""
# Returns
- `sv`: Singular values of frequency response, size `(min(ny, nu), length(w))`
- `w`: Frequency vector used

The singular values provide information about the system's gain characteristics
across different frequencies and input/output directions.

See also [`sigmaplot`](@ref), [`freqresp`](@ref), [`bode`](@ref).

# Examples
```julia
using ControlSystems
sys = ss([-1 0; 0 -2], [1 0; 0 1], [1 1; 0 1], 0)
sv, w = sigma(sys)
```
"""
@autovec (1) function sigma(sys::LTISystem, w::AbstractVector)
resp = freqresp(sys, w)
ny, nu = size(sys)
Expand Down
Loading