# Mass Spring Damper with BlockSystems.jl

How does one add a proportional constant k and a damping constant b to this IOBlock to setup a spring mass damper transfer function?

``````using BlockSystems
using ModelingToolkit

@parameters t M F(t)
@variables x(t) v(t)
D = Differential(t)

msd = IOBlock([D(v) ~ F/M, D(x) ~ v], # define the equation
[F], # inputs of the system
[x], # outputs of the system
name = :msd)
``````

You’d have to modify those equations to include the stiffness and damping terms.

Alternatively, if you want to use a component-based modeling approach, you could use ModelingToolkit directly. An example building a MSD system can be found here

1 Like

This is what I came up with.

``````spacecraft = IOBlock([D(v) ~ -(KK/M)*x + -(B/M)*v + (F/M), D(x) ~ v], # define the equation
[F], # inputs of the system
[x], # outputs of the system
name = :spacecraft)
``````

Now how do I set the K and B variables in the ODE Solver? They go in the p vector right? But what determines the ordering?

From the spacecraft example:

``````p = [0.5, 1.0] # K, m  # Here we need to add KK and B
u0 = [0.0, 0.0] # altitude, v
tspan = (0.0, 30.0)
prob = ODEProblem(odefun, u0, tspan, p)
sol = solve(prob, Tsit5())
``````

I’ve created `BlockSystems.jl` at a time where component based modeling was far more complicated in vanilla MTK than it is now. Since it is/was highly specialized for my specific usecase I would not necessarily recommend it for starting a new project now – i think it is worth using MTK directly. Eventually I want to revisit BlockSystems to make it a much thinner MTK wrapper than it is now, but that for sure will be quite breaking.

If you still want to use BlockSystems: in order to solve the system you always have to generate a callable Julia function based on the symbolic model. You can use `generate_io_function` for a low level interface or

``````odefun = ODEFunction(iob::IOBlock; f_states=Symbol[], f_params=Symbol[])
``````

for a more high level interface. The ordering of states and parameters can be passed explicitly. Otherwise they’ll match the order of `iob.iparams` (the internal parameters) and `states = vcat(iob.outputs, iob.istates)` (stacked vector of output states and internal states).

However in order to create a ODEFunction/ODEProblem you need to close all the inputs first. There are plenty options to do that, either create other blocks and connect them or use something like

``````@variables t
@parameters omega
closed_spacecraft = set_input(spacecraft, F => sin(omega * t))
``````

to direclty close the input with that specific function. Now `closed_spacecraft.iparams` should show `[:omega, :KK, :B]` in some order.

If you don’t want to specify the parameters at solve time you may also bake them into the generated code by something like

``````closed_spacecraft = replace_vars(closed_spacecraft, :omega=>10, :B=>4)
``````

which would leave you with a single free parameter `:KK` and so on.

Thanks for the info. Im also looking at ControlSystems.jl and related libs.

Will have to try what you have suggested.