Skip to content

Commit 352776c

Browse files
authored
add symcheck macro (#161)
1 parent 50737f3 commit 352776c

File tree

6 files changed

+33
-13
lines changed

6 files changed

+33
-13
lines changed

src/Blocks/Blocks.jl

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ The module `Blocks` contains common input-output components, referred to as bloc
44
module Blocks
55
using ModelingToolkit, Symbolics
66
using IfElse: ifelse
7+
import ..@symcheck
78

89
@parameters t
910
D = Differential(t)

src/Blocks/continuous.jl

+10-8
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ A smaller `T` leads to a more ideal approximation of the derivative.
5252
- `output`
5353
"""
5454
@component function Derivative(; name, k = 1, T, x_start = 0.0)
55-
T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
55+
@symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
5656
@named siso = SISO()
5757
@unpack u, y = siso
5858
sts = @variables x(t)=x_start [description = "State of Derivative $name"]
@@ -98,7 +98,7 @@ sT + 1 - k
9898
See also [`SecondOrder`](@ref)
9999
"""
100100
@component function FirstOrder(; name, k = 1, T, x_start = 0.0, lowpass = true)
101-
T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
101+
@symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
102102
@named siso = SISO()
103103
@unpack u, y = siso
104104
sts = @variables x(t)=x_start [description = "State of FirstOrder filter $name"]
@@ -171,7 +171,7 @@ Textbook version of a PI-controller without actuator saturation and anti-windup
171171
See also [`LimPI`](@ref)
172172
"""
173173
@component function PI(; name, k = 1, T, x_start = 0.0)
174-
T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
174+
@symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
175175
@named err_input = RealInput() # control error
176176
@named ctr_output = RealOutput() # control signal
177177
@named gainPI = Gain(k)
@@ -282,9 +282,10 @@ Text-book version of a PI-controller with actuator saturation and anti-windup me
282282
- `ctr_output`
283283
"""
284284
@component function LimPI(; name, k = 1, T, u_max, u_min = -u_max, Ta, x_start = 0.0)
285-
Ta > 0 || throw(ArgumentError("Time constant `Ta` has to be strictly positive"))
286-
T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
287-
u_max u_min || throw(ArgumentError("u_min must be smaller than u_max"))
285+
@symcheck Ta > 0 ||
286+
throw(ArgumentError("Time constant `Ta` has to be strictly positive"))
287+
@symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
288+
@symcheck u_max u_min || throw(ArgumentError("u_min must be smaller than u_max"))
288289
@named err_input = RealInput() # control error
289290
@named ctr_output = RealOutput() # control signal
290291
@named gainPI = Gain(k)
@@ -367,8 +368,9 @@ where the transfer function for the derivative includes additional filtering, se
367368
(Ti 0 || throw(ArgumentError("Ti out of bounds, got $(Ti) but expected Ti ≥ 0")))
368369
!isequal(Td, false) &&
369370
(Td 0 || throw(ArgumentError("Td out of bounds, got $(Td) but expected Td ≥ 0")))
370-
u_max u_min || throw(ArgumentError("u_min must be smaller than u_max"))
371-
Nd > 0 || throw(ArgumentError("Nd out of bounds, got $(Nd) but expected Nd > 0"))
371+
@symcheck u_max u_min || throw(ArgumentError("u_min must be smaller than u_max"))
372+
@symcheck Nd > 0 ||
373+
throw(ArgumentError("Nd out of bounds, got $(Nd) but expected Nd > 0"))
372374

373375
@named reference = RealInput()
374376
@named measurement = RealInput()

src/Blocks/nonlinear.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Limit the range of a signal.
1717
- `output`
1818
"""
1919
@component function Limiter(; name, y_max, y_min = y_max > 0 ? -y_max : -Inf)
20-
y_max y_min || throw(ArgumentError("`y_min` must be smaller than `y_max`"))
20+
@symcheck y_max y_min || throw(ArgumentError("`y_min` must be smaller than `y_max`"))
2121
@named siso = SISO()
2222
@unpack u, y = siso
2323
pars = @parameters y_max=y_max [description = "Maximum allowed output of Limiter $name"] y_min=y_min [

src/Mechanical/Rotational/Rotational.jl

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module Rotational
55

66
using ModelingToolkit, Symbolics, IfElse
77
using ...Blocks: RealInput, RealOutput
8+
import ...@symcheck
89

910
@parameters t
1011
D = Differential(t)

src/Mechanical/Rotational/components.jl

+4-4
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ end
4444
@component function Inertia(; name, J, phi_start = 0.0, w_start = 0.0, a_start = 0.0)
4545
@named flange_a = Flange()
4646
@named flange_b = Flange()
47-
J > 0 || throw(ArgumentError("Expected `J` to be positive"))
47+
@symcheck J > 0 || throw(ArgumentError("Expected `J` to be positive"))
4848
@parameters J=J [description = "Moment of inertia of $name"]
4949
sts = @variables(phi(t)=phi_start, [description = "Absolute rotation angle of $name"],
5050
w(t)=w_start, [description = "Absolute angular velocity of $name"],
@@ -81,7 +81,7 @@ Linear 1D rotational spring
8181
@component function Spring(; name, c, phi_rel0 = 0.0)
8282
@named partial_comp = PartialCompliant()
8383
@unpack phi_rel, tau = partial_comp
84-
c > 0 || throw(ArgumentError("Expected `c` to be positive"))
84+
@symcheck c > 0 || throw(ArgumentError("Expected `c` to be positive"))
8585
pars = @parameters(c=c, [description = "Spring constant of $name"],
8686
phi_rel0=phi_rel0,
8787
[description = "Unstretched spring angle of $name"],)
@@ -113,7 +113,7 @@ Linear 1D rotational damper
113113
@component function Damper(; name, d)
114114
@named partial_comp = PartialCompliantWithRelativeStates()
115115
@unpack w_rel, tau = partial_comp
116-
d > 0 || throw(ArgumentError("Expected `d` to be positive"))
116+
@symcheck d > 0 || throw(ArgumentError("Expected `d` to be positive"))
117117
pars = @parameters d=d [description = "Damping constant of $name"]
118118
eqs = [tau ~ d * w_rel]
119119
extend(ODESystem(eqs, t, [], pars; name = name), partial_comp)
@@ -181,7 +181,7 @@ This element characterizes any type of gear box which is fixed in the ground and
181181
@component function IdealGear(; name, ratio, use_support = false)
182182
@named partial_element = PartialElementaryTwoFlangesAndSupport2(use_support = use_support)
183183
@unpack phi_support, flange_a, flange_b = partial_element
184-
ratio > 0 || throw(ArgumentError("Expected `ratio` to be positive"))
184+
@symcheck ratio > 0 || throw(ArgumentError("Expected `ratio` to be positive"))
185185
@parameters ratio=ratio [description = "Transmission ratio of $name"]
186186
sts = @variables phi_a(t)=0.0 [
187187
description = "Relative angle between shaft a and the support of $name",

src/ModelingToolkitStandardLibrary.jl

+16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,20 @@
11
module ModelingToolkitStandardLibrary
2+
import Symbolics: unwrap
3+
4+
"""
5+
@symcheck J > 0 || throw(ArgumentError("Expected `J` to be positive"))
6+
7+
Omits the check expression if the argument `J` is symbolic.
8+
"""
9+
macro symcheck(ex)
10+
ex.args[1].head === :call ||
11+
error("Expected an expresion on the form sym > val || error()")
12+
sym = ex.args[1].args[2]
13+
quote
14+
_issymbolic(x) = !(unwrap(x) isa Real)
15+
_issymbolic($(esc(sym))) || ($(esc(ex)))
16+
end
17+
end
218

319
include("Blocks/Blocks.jl")
420
include("Mechanical/Mechanical.jl")

0 commit comments

Comments
 (0)