Parameter sharing and abstraction in MTK

I have started using ParametrizedInterpolation from the standard library in my code, and while it works fine, having to add a clock to each component that uses it tarnishes the code a bit. So I wrote this:

""" A step function, where `step_function.u` is `ys[i]` when `t = ts[i]` (and afterwards).

The point is that while `ParametrizedInterpolation` can be used directly, its interface requires an
explicit `clock`. `StepFunction` is simple: add it as a System, and access its values with `sf.u`

@mtkcompile sf = StepFunction([1,2,3], [4,5,3])
res = solve(ODEProblem(sf, [], [1,10]))
println(res.([1,1.5,2,3,4,8], idxs=sf.val))

# output
[4.0, 4.0, 5.0, 3.0, 3.0, 3.0]
 """
@component function StepFunction(ts, ys; name=:unnamed_interpolator)
    @named interp = ParametrizedInterpolation(ExtrapolatedConstantInterpolation,
                                              Float64.(ys), Float64.(ts))
    @named clk = ContinuousClock()
    @variables val(t)
    eqs = [connect(clk.output, interp.input),
           val ~ interp.output.u]
    return System(eqs, t, [val], []; name, systems=[interp, clk])
end

And it works nicely.

Question 1: is there anything wrong with that?

Questions 2: Now setting the ts parameter looks like my_motor.input.interp.ts => [1,2,10]. How can I make it like my_motor.input.ts => [1,2,10]? I’ve read Initialization of Systems · ModelingToolkit.jl, but I’m not so confident. Should I set the interp.ts to missing, and set up an equation like interp.ts ~ ts with an additional ts parameter in StepFunction?

You might want to share clocks in order to reduce the total number of clocks that need to be tracked.

You could explore using ModelingToolkitInputs.jl. This will allow you to easy change your step function, like

step = Input(sys.x, [4.0, 5.0, 3.0], [1, 2, 3])
sol = solve(sys; inputs=[step])
1 Like

Interesting! Have you used it for optimization? Given that it supports remake, it should work out?