Skip to content

add symcheck macro #161

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

Merged
merged 6 commits into from
Apr 25, 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
1 change: 1 addition & 0 deletions src/Blocks/Blocks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ The module `Blocks` contains common input-output components, referred to as bloc
module Blocks
using ModelingToolkit, Symbolics
using IfElse: ifelse
import ..@symcheck

@parameters t
D = Differential(t)
Expand Down
18 changes: 10 additions & 8 deletions src/Blocks/continuous.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ A smaller `T` leads to a more ideal approximation of the derivative.
- `output`
"""
@component function Derivative(; name, k = 1, T, x_start = 0.0)
T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
@symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
@named siso = SISO()
@unpack u, y = siso
sts = @variables x(t)=x_start [description = "State of Derivative $name"]
Expand Down Expand Up @@ -98,7 +98,7 @@ sT + 1 - k
See also [`SecondOrder`](@ref)
"""
@component function FirstOrder(; name, k = 1, T, x_start = 0.0, lowpass = true)
T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
@symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
@named siso = SISO()
@unpack u, y = siso
sts = @variables x(t)=x_start [description = "State of FirstOrder filter $name"]
Expand Down Expand Up @@ -171,7 +171,7 @@ Textbook version of a PI-controller without actuator saturation and anti-windup
See also [`LimPI`](@ref)
"""
@component function PI(; name, k = 1, T, x_start = 0.0)
T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
@symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
@named err_input = RealInput() # control error
@named ctr_output = RealOutput() # control signal
@named gainPI = Gain(k)
Expand Down Expand Up @@ -282,9 +282,10 @@ Text-book version of a PI-controller with actuator saturation and anti-windup me
- `ctr_output`
"""
@component function LimPI(; name, k = 1, T, u_max, u_min = -u_max, Ta, x_start = 0.0)
Ta > 0 || throw(ArgumentError("Time constant `Ta` has to be strictly positive"))
T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
u_max ≥ u_min || throw(ArgumentError("u_min must be smaller than u_max"))
@symcheck Ta > 0 ||
throw(ArgumentError("Time constant `Ta` has to be strictly positive"))
@symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
@symcheck u_max ≥ u_min || throw(ArgumentError("u_min must be smaller than u_max"))
@named err_input = RealInput() # control error
@named ctr_output = RealOutput() # control signal
@named gainPI = Gain(k)
Expand Down Expand Up @@ -367,8 +368,9 @@ where the transfer function for the derivative includes additional filtering, se
(Ti ≥ 0 || throw(ArgumentError("Ti out of bounds, got $(Ti) but expected Ti ≥ 0")))
!isequal(Td, false) &&
(Td ≥ 0 || throw(ArgumentError("Td out of bounds, got $(Td) but expected Td ≥ 0")))
u_max ≥ u_min || throw(ArgumentError("u_min must be smaller than u_max"))
Nd > 0 || throw(ArgumentError("Nd out of bounds, got $(Nd) but expected Nd > 0"))
@symcheck u_max ≥ u_min || throw(ArgumentError("u_min must be smaller than u_max"))
@symcheck Nd > 0 ||
throw(ArgumentError("Nd out of bounds, got $(Nd) but expected Nd > 0"))

@named reference = RealInput()
@named measurement = RealInput()
Expand Down
2 changes: 1 addition & 1 deletion src/Blocks/nonlinear.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Limit the range of a signal.
- `output`
"""
@component function Limiter(; name, y_max, y_min = y_max > 0 ? -y_max : -Inf)
y_max ≥ y_min || throw(ArgumentError("`y_min` must be smaller than `y_max`"))
@symcheck y_max ≥ y_min || throw(ArgumentError("`y_min` must be smaller than `y_max`"))
@named siso = SISO()
@unpack u, y = siso
pars = @parameters y_max=y_max [description = "Maximum allowed output of Limiter $name"] y_min=y_min [
Expand Down
1 change: 1 addition & 0 deletions src/Mechanical/Rotational/Rotational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Rotational

using ModelingToolkit, Symbolics, IfElse
using ...Blocks: RealInput, RealOutput
import ...@symcheck

@parameters t
D = Differential(t)
Expand Down
8 changes: 4 additions & 4 deletions src/Mechanical/Rotational/components.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ end
@component function Inertia(; name, J, phi_start = 0.0, w_start = 0.0, a_start = 0.0)
@named flange_a = Flange()
@named flange_b = Flange()
J > 0 || throw(ArgumentError("Expected `J` to be positive"))
@symcheck J > 0 || throw(ArgumentError("Expected `J` to be positive"))
@parameters J=J [description = "Moment of inertia of $name"]
sts = @variables(phi(t)=phi_start, [description = "Absolute rotation angle of $name"],
w(t)=w_start, [description = "Absolute angular velocity of $name"],
Expand Down Expand Up @@ -81,7 +81,7 @@ Linear 1D rotational spring
@component function Spring(; name, c, phi_rel0 = 0.0)
@named partial_comp = PartialCompliant()
@unpack phi_rel, tau = partial_comp
c > 0 || throw(ArgumentError("Expected `c` to be positive"))
@symcheck c > 0 || throw(ArgumentError("Expected `c` to be positive"))
pars = @parameters(c=c, [description = "Spring constant of $name"],
phi_rel0=phi_rel0,
[description = "Unstretched spring angle of $name"],)
Expand Down Expand Up @@ -113,7 +113,7 @@ Linear 1D rotational damper
@component function Damper(; name, d)
@named partial_comp = PartialCompliantWithRelativeStates()
@unpack w_rel, tau = partial_comp
d > 0 || throw(ArgumentError("Expected `d` to be positive"))
@symcheck d > 0 || throw(ArgumentError("Expected `d` to be positive"))
pars = @parameters d=d [description = "Damping constant of $name"]
eqs = [tau ~ d * w_rel]
extend(ODESystem(eqs, t, [], pars; name = name), partial_comp)
Expand Down Expand Up @@ -145,7 +145,7 @@ This element characterizes any type of gear box which is fixed in the ground and
@component function IdealGear(; name, ratio, use_support = false)
@named partial_element = PartialElementaryTwoFlangesAndSupport2(use_support = use_support)
@unpack phi_support, flange_a, flange_b = partial_element
ratio > 0 || throw(ArgumentError("Expected `ratio` to be positive"))
@symcheck ratio > 0 || throw(ArgumentError("Expected `ratio` to be positive"))
@parameters ratio=ratio [description = "Transmission ratio of $name"]
sts = @variables phi_a(t)=0.0 [
description = "Relative angle between shaft a and the support of $name",
Expand Down
16 changes: 16 additions & 0 deletions src/ModelingToolkitStandardLibrary.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
module ModelingToolkitStandardLibrary
import Symbolics: unwrap

"""
@symcheck J > 0 || throw(ArgumentError("Expected `J` to be positive"))

Omits the check expression if the argument `J` is symbolic.
"""
macro symcheck(ex)
ex.args[1].head === :call ||
error("Expected an expresion on the form sym > val || error()")
sym = ex.args[1].args[2]
quote
_issymbolic(x) = !(unwrap(x) isa Real)
_issymbolic($(esc(sym))) || ($(esc(ex)))
end
end

include("Blocks/Blocks.jl")
include("Mechanical/Mechanical.jl")
Expand Down