Open dafred94 opened 1 year ago
structural_simplify(model, allow_symbolic=false)
?trans₊ry = trans₊rx = 0
? Dummy derivatives like body₊fa₊oyˍtt
don't need an initial condition but an initial guess, so it can just be set to any reasonable value and the solver will figure it out numerically. We could default them to zero.allow_symbolic=false
.trans₊ry != trans₊rx
of course runs fine no matter the revolute joint angle. However, for trans₊ry = trans₊rx = 0
, I get a similar error (basically "division by zero").The main difference I suspect is that MTK chooses, well, unfortunate continuous states like translational positions/velocities. For this choice, MTK would need to support dynamic state selection. I can't really test this hypothesis because... I don't know how to tell "dynamic states" from the other states(model)
that MTK reports.
On the other hand the Modelica tool I used just chose an angle and its derivative, effectively sidestepping the problem.
Is there any working way I could hint MTK to prefer certain variables for state selection?
Ah, I mistyped it. I meant to write allow_parameter=false
.
On the other hand the Modelica tool I used just chose an angle and its derivative, effectively sidestepping the problem. Is there any working way I could hint MTK to prefer certain variables for state selection?
Yes yes, you can write
@variables a(t) [state_priority = 100]
to tell the stat selection to prefer a
.
allow_parameter
true
> states(sys)
6-element Vector{Any}:
trans₊r0y(t)
trans₊r0yˍt(t)
body₊w(t)
body₊phi(t)
body₊fa₊oyˍtt(t)
trans₊r0xˍtt(t)
false
> states(sys)
6-element Vector{Any}:
trans₊r0y(t)
trans₊r0yˍt(t)
body₊w(t)
body₊phi(t)
body₊fa₊oyˍtt(t)
body₊phiˍtt(t)
ERROR: During the resolution of the non-linear system, the evaluation of the following equation(s) resulted in a non-finite number: [3]
> equations(sys)[3]
0 ~ trans₊r0y(t) - trans₊rx*trans₊Ry(t) - trans₊ry*trans₊Rq(t)
[state_priority = 100]
: good newstrans
. issue was solved after application to body
's angle and angular rate. (only works with allow_parameter = false
)body.z
, which however needn't be included in u0
, remains:
> states(sys)
3-element Vector{Any}:
body₊phi(t)
body₊w(t)
body₊z(t)
using ModelingToolkit, DifferentialEquations, LinearAlgebra
using GLMakie
@variables t D= Differential(t)
@connector function frame_a(;name, pos=[0., 0.], phi=0.0, _f=[0., 0.], tau=0.0)
sts = @variables ox(t)=pos[1] oy(t)=pos[2] phi(t) fx(t)=_f [connect=Flow] fy(t)=_f [connect=Flow] tau(t) [connect=Flow]
ODESystem(Equation[], t, sts, []; name=name)
end
@connector function flange_a(;name)
sts = @variables phi(t) tau(t) [connect=Flow]
ODESystem(Equation[], t, sts, []; name=name, defaults = Dict(phi => 0.0, tau => 0.0))
end
@connector function realInput(;name, x=0.0)
sts = @variables x(t) [input=true]
ODESystem(Equation[], t, sts, []; name=name)
end
@connector function realOutput(;name, x=0.0)
sts = @variables x(t) [output=true]
ODESystem(Equation[], t, sts, []; name=name)
end
function Fixed(;name, pos=[0., 0.], phi=0.0)
@named fa = frame_a()
ps = @parameters posx=pos[1] posy=pos[2] phi=phi
eqs = [
fa.ox ~ posx
fa.oy ~ posy
fa.phi ~ phi
]
compose(ODESystem(eqs, t, [], ps; name=name), fa)
end
function Revolute(;name, phi=0.0, w=0.0, z=0.0, tau=0.0)
@named fa= frame_a()
@named fb= frame_a()
@named fla= flange_a()
sts= @variables phi(t)=phi w(t)=w z(t)=z tau(t)=tau
eqs= [ D.(phi) ~ w
D.(w) ~ z
fla.phi ~ phi
fla.tau ~ tau
fa.ox ~ fb.ox
fa.oy ~ fb.oy
fa.phi + phi ~ fb.phi
fa.fx + fb.fx ~ 0
fa.fy + fb.fy ~ 0
fa.tau + fb.tau ~ 0
fa.tau ~ tau
]
compose(ODESystem(eqs, t, sts, []; name=name), [fa,fb,fla])
end
function FixedTranslation(;name, r0 =[1. , 0.])
@named fa= frame_a()
@named fb= frame_a()
ps= @parameters rx=r0[1] ry=r0[2]
sts= @variables r0x(t) r0y(t) Rx(t) Rp(t) Ry(t) Rq(t)
eqs= [
Rx ~ cos(fa.phi)
Rp ~ -sin(fa.phi)
Ry ~ sin(fa.phi)
Rq ~ cos(fa.phi)
Rx rx + Rp ry ~ r0x
Ry rx + Rq ry ~ r0y
fa.ox + r0x ~ fb.ox
fa.oy + r0y ~ fb.oy
fa.phi ~ fb.phi
fa.fx + fb.fx ~ 0
fa.fy + fb.fy ~ 0
fa.tau + fb.tau + r0x fb.fy - r0y fb.fx ~ 0
]
compose(ODESystem(eqs, t, sts, ps; name=name), [fa,fb])
end
function Body(;name, v=[0., 0.], a=[0., 0.],phi=0.0, w=0.0, z=0.0)
@named fa = frame_a()
ps = @parameters m=1.0 I=1.0
sts= @variables vx(t)=v[1] vy(t)=v[2] ax(t) ay(t) phi(t)=0.0 [state_priority = 100] w(t)=w [state_priority = 100] z(t)=z
eqs = [fa.tau ~ I * z
D.(fa.ox) ~ vx
D.(fa.oy) ~ vy
D.(vx) ~ ax
D.(vy) ~ ay
D.(phi) ~ w
D.(w) ~ z
fa.phi ~ phi
fa.fx ~ m * ax
fa.fy ~ m * ay ]
compose(ODESystem(eqs, t, sts, ps; name=name), fa)
end
function Torque(;name)
@named in = realInput()
@named flb = flange_a()
eqs = [-in.x ~ flb.tau,]
compose(ODESystem(eqs, t, [],[]; name=name), [flb,in])
end
function Constant(;name, k=1.0)
@named y = realOutput()
ps = @parameters k=k
eqs = [
y.x ~ k
]
compose(ODESystem(eqs, t, [],ps; name=name), y)
end
@named fixed = Fixed() @named revolute = Revolute() @named trans = FixedTranslation() @named body = Body() @named torque = Torque() @named const_ = Constant(k=1)
eqs = [ connect(fixed.fa, revolute.fa), connect(revolute.fb, trans.fa), connect(trans.fb, body.fa), connect(torque.flb, revolute.fla), connect(const_.y, torque.in) ]
@named model = compose( ODESystem(eqs, t, name=:tmp), [ fixed, revolute, trans, body, torque, const_ ] )
modelTorque = model
sys = structural_simplify(model, allow_parameter=false)
u0 = [
trans.rx => 1.0,
trans.ry => 0.0,
# this as well
#trans.rx => 1/sqrt(2),
#trans.ry => 1/sqrt(2),
# slim initial conditions
body.phi => 0.0,
body.w => 0.0
# despite being part of states(sys), body.z needn't be set here
]
saveat = LinRange(0, 4.5, 2^7)
prob = ODEProblem(sys, u0, (saveat[1], saveat[end])) sol = solve(prob, Rodas4(), saveat=saveat)
fig = Figure()
ax1 = Axis(fig[1, 1], xlabel="t", ylabel="body.phi") lines!(ax1, sol.t, sol[body.phi])
ax2 = Axis(fig[1, 2], xlabel="body.fa.ox", ylabel="body.fa.oy", aspect=DataAspect()) lines!(ax2, sol[body.fa.ox], sol[body.fa.oy])
display(fig)
### generated figure
![Capture](https://user-images.githubusercontent.com/53007095/218020565-cc5dacf4-e9b6-49f4-9d51-3ab079032b79.PNG)
Is this initialization? This seems like a state priority / dummy derivative thing? @YingboMa
So my student is building a model from MTK components based on the great Planarmechanics Modelica library.
simple model
One of our simpler test models is nothing but a planar pendulum which causes the error in the title. That model consists of
Here's a sketch of the system:
code to reproduce the error
observations
Search the code for "
u0 =
", where we set our initial conditions/states and parameters.> full_equations(sys)[1]
Differential(t)(trans₊r0y(t)) ~ trans₊r0yˍt(t)
> full_equations(sys)[3]
0 ~ (trans₊rx*sin(body₊phi(t)) - trans₊r0y(t)) / trans₊ry + cos(body₊phi(t))
trans₊ry
, which can be0
.# initially working parametrization [...]
sqrt(2*pi)
seconds (i.e. after a rotation bypi
)# initial conditions required by MTK
ERROR: ArgumentError: SymbolicUtils.Symbolic{Real}[body₊fa₊oyˍtt(t)] are missing from the variable map.
where the list of missing symbols grows as you comment out more "required" initial conditions.# supposedly sufficient initial conditions
should be enough to specify the (control theoretical) system state