CATIA-Systems / FMIKit-Simulink

Import and export Functional Mock-up Units with Simulink
Other
155 stars 50 forks source link

Pulse generator issue #456

Open nl78 opened 9 months ago

nl78 commented 9 months ago

Hello, I face a tricky issue with a very simple model:

image

This simple pulse is configured with 2secs period. Matlab solver is Fixed Discrete with ts=0.005s : image

Using FMIKit-3.1, the pulse period depends on communication step time managed by FMPy. Note that the paramaters exposed by FMU are: image

To workaround this issue, I introduced Clock block: image

With this model, pulse period is always 2secs whatever the communication step time. Note that the parameters exposed by FMU are slightly different:

image

Is it a FMIKit issue? a Simulink issue?

kind regards

t-sommer commented 9 months ago

Can you share the model and some code to reproduce the problem?

nl78 commented 9 months ago

Steps to reproduce:

  1. buggy model: pulse_timebased.slx

    • ts=5ms, compile it as FMU
    • run it with FMPy at 5ms: output signal period is 2 secs (as expected)
    • run it with FMPy at 10ms: output signal period is 4 secs ! (2 secs is expected)
  2. working model: pulse_externaltime.slx

    • ts=5ms, compile it as FMU
    • run it with FMPy at 5ms: period is 2secs (as expected)
    • run it with FMPy at 10ms: period is still 2 secs (as expected).

Matlab version: 2020b update 8

NOTE: setting outport sample time of pluse_timebased.slx to 0 (instead of default -1) seems to fix the issue !?

pulse_issue.zip

nl78 commented 9 months ago

After investigations: the first pusle generator model is 'discrete'. At compilation time, rtmGetT is not available. In fmi2function.c this case is handled by calling only once DoFixedStep(s_instance->S); which may be insufficient.

I suggest a patch like:

#ifdef rtmGetT
    time_T tNext = currentCommunicationPoint + communicationStepSize;
    double epsilon = (1.0 + fabs(rtmGetT(s_instance->S))) * 2 * DBL_EPSILON;

    while (rtmGetT(s_instance->S) < tNext + epsilon)
#else
    const int steps = ceil(communicationStepSize / FUNDAMENTAL_STEP_SIZE);
    for(int i=0; i<steps; i+=1)
#endif

And add FUNDAMENTAL_STEP_SIZE definition via fmiwrapper.inc. It works well when communication step size is greater or equal to internal fmu step size. Otherwise, this patch does not help.