Running external c-code function in MTK model

Hi community,

I am new to Julia and in particular MTK.
My goal is to simulate a battery cell and couple it with external C-code to run an extended Kalman filter for SOC estimation at a fixed sampling rate.

Somehow this kind of problem does not seem to be something many people deal with in Julia, at least documentation is very limited here. I guess FMU would be a possibility. However, the FMI.jl package hasn’t beed updated for a while and so far it does not support array inputs/outputs (which I ultimately need). Even then, how would the finite sampling time be realized, using events?

Is there another possibility to run external C-code functions using ccall and add the call at a certain rate to a symbolic system description? Ideally connecting it using inputs and outputs of the MTK system?

I would be grateful for general advice on best practices here.

Thanks in advance!

Edit: Just saw that FMI.jl has been updated 2 weeks ago.

Just register the function. See @register_symbolic

this is a discrete-time system and it requires the in-development support for synchronous programming

which is not quite available yet. You can still perform state estimation for MTK models in other ways, for example

Thanks, this seems to work!

That’s an interesting talk! Is there a timeline when this feature is to be published? How does this relate to tutorials → discrete_system (sorry I cannot add a link here)? Until the feature in the presentation is released, can I use events instead, specifically make ccalls in an event callback?

This is only for systems that are only discrete time, no continuous time dynamics.

Yes, it’s slightly cumbersome but not too bad if you have a single discrete-time component only

1 Like

Alright, i have a follow-up question.

I had a minimal example running where a continuous event would directly call a c function that was registered symbolic.

Now, my C-code wrapper has structures as inputs and outputs, i.e. I need to set those first, before doing the actual C-call.

This is my event inside @mtkmodel environment

@continuous_events begin
        [timer_wrapper ~ 1.0] =>
            [
                timer_wrapper ~ 0.0,
                soc_bat_est ~ wrapper_execute!(i_set, Tuple([Pre(getproperty(base_ecm, Symbol("cells_$i")).u_cg) for i in 1:n_series]))
            ]
    end

This is the Wrapper function

function wrapper_execute!(i_set::Real, u_cell::NTuple{NUM_CELLS, Real})
    inputs = WrapperInputs(current = Cfloat(i_set),
                           cellVoltages = ntuple(j -> Cfloat(u_cell[j]), NUM_CELLS))
    outputs = WrapperOutputs()
    retval = @ccall LIB_PATH.wrapper_execute(Ref(inputs)::Ptr{WrapperInputs},
                                           Ref(outputs)::Ptr{WrapperOutputs})::WrapperError

    return outputs.socMean
end

@register_symbolic wrapper_execute!(i_set, u_cell)

(instead of

wrapper_execute(val1, val2) = ... # ccall with val1 and val2 as doubles
@register_symbolic wrapper_execute(val1, val2)

)

Somehow, using the struct arguments this does not work, because the ccall in this case does not receive numeric values, but symbolic. What am I missing? Is there a workaround?

Cheers

Using a continuous event is probably suboptimal if you want a periodic execution, this is what discrete periodic callbacks are for. Having said that, you should hopefully be able to use what you have if you do

@register_symbolic wrapper_execute!(i_set::Real, u_cell::NTuple{NUM_CELLS, Real})